Mantid
Loading...
Searching...
No Matches
LoadNexusProcessed.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
15#include "MantidAPI/Run.h"
16#include "MantidAPI/TextAxis.h"
40
41#include <boost/algorithm/string/trim.hpp>
42#include <boost/regex.hpp>
43
44#include <algorithm>
45#include <map>
46#include <memory>
47#include <string>
48#include <vector>
49
50namespace Mantid::DataHandling {
51
52// Register the algorithm into the algorithm factory
53DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadNexusProcessed)
54
55using namespace Mantid::Nexus;
56using namespace DataObjects;
57using namespace Kernel;
58using namespace API;
60using Mantid::Types::Event::TofEvent;
61using Types::Core::DateAndTime;
62
63namespace {
64
65// Helper typedef
66using IntArray = std::vector<int>;
67
68// Struct to contain spectrum information.
69struct SpectraInfo {
70 // Number of spectra
71 int64_t nSpectra{0};
72 // Do we have any spectra
73 bool hasSpectra{false};
74 // Contains spectrum numbers for each workspace index
76 // Index of the detector in the workspace.
77 IntArray detectorIndex;
78 // Number of detectors associated with each spectra
79 IntArray detectorCount;
80 // Detector list contains a list of all of the detector numbers
81 IntArray detectorList;
82};
83
84// Helper typdef.
85using SpectraInfo_optional = std::optional<SpectraInfo>;
86
94SpectraInfo extractMappingInfo(const NXEntry &mtd_entry, Logger &logger) {
95 SpectraInfo spectraInfo;
96 // Instrument information
97
98 if (!mtd_entry.containsGroup("instrument")) {
99 logger.information() << "No NXinstrument group called `instrument` under "
100 "NXEntry. The workspace will not "
101 "contain any detector information.\n";
102 return spectraInfo;
103 }
104 NXInstrument inst = mtd_entry.openNXInstrument("instrument");
105 if (!inst.containsGroup("detector")) {
106 logger.information() << "Detector block not found. The workspace will not "
107 "contain any detector information.\n";
108 return spectraInfo;
109 }
110
111 // Populate the spectra-detector map
112 NXDetector detgroup = inst.openNXDetector("detector");
113
114 // Spectra block - Contains spectrum numbers for each workspace index
115 // This might not exist so wrap and check. If it doesn't exist create a
116 // default mapping
117 try {
118 NXInt spectra_block = detgroup.openNXInt("spectra");
119 spectra_block.load();
120 spectraInfo.spectraNumbers = spectra_block.vecBuffer();
121 spectraInfo.nSpectra = static_cast<int>(spectra_block.dim0());
122 spectraInfo.hasSpectra = true;
123 } catch (std::runtime_error &) {
124 spectraInfo.hasSpectra = false;
125 }
126
127 // Read necessary arrays from the file
128 // Detector list contains a list of all of the detector numbers. If it not
129 // present then we can't update the spectra
130 // map
131 try {
132 NXInt detlist_group = detgroup.openNXInt("detector_list");
133 detlist_group.load();
134 spectraInfo.detectorList = detlist_group.vecBuffer();
135 } catch (std::runtime_error &) {
136 logger.information() << "detector_list block not found. The workspace will "
137 "not contain any detector information.\n";
138 return spectraInfo;
139 }
140
141 // Detector count contains the number of detectors associated with each
142 // spectra
143 NXInt det_count = detgroup.openNXInt("detector_count");
144 det_count.load();
145 spectraInfo.detectorCount = det_count.vecBuffer();
146 // Detector index - contains the index of the detector in the workspace
147 NXInt det_index = detgroup.openNXInt("detector_index");
148 det_index.load();
149 spectraInfo.nSpectra = static_cast<int>(det_index.dim0());
150 spectraInfo.detectorIndex = det_index.vecBuffer();
151
152 return spectraInfo;
153}
154
162bool isMultiPeriodFile(int nWorkspaceEntries, const Workspace_sptr &sampleWS, Logger &log) {
163 bool isMultiPeriod = false;
164 if (ExperimentInfo_sptr expInfo = std::dynamic_pointer_cast<ExperimentInfo>(sampleWS)) {
165 const std::string nPeriodsLogEntryName = "nperiods";
166 const Run &run = expInfo->run();
167 if (run.hasProperty(nPeriodsLogEntryName)) {
168 const auto nPeriods = run.getPropertyValueAsType<int>(nPeriodsLogEntryName);
169 if (nPeriods == nWorkspaceEntries) {
170 isMultiPeriod = true;
171 log.information("Loading as MultiPeriod group workspace.");
172 }
173 }
174 }
175 return isMultiPeriod;
176}
177
178} // namespace
179
182 : m_shared_bins(false), m_xbins(0), m_axis1vals(), m_list(false), m_interval(false), m_spec_min(0),
183 m_spec_max(Mantid::EMPTY_INT()), m_spec_list(), m_filtered_spec_idxs(), m_nexusFile() {}
184
188
196 if (descriptor.isEntry("/mantid_workspace_1"))
197 return 80;
198 else
199 return 0;
200}
201
205
210 // Declare required input parameters for algorithm
211 const std::vector<std::string> exts{".nxs", ".nx5", ".xml"};
212 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
213 "The name of the Nexus file to read, as a full or relative path.");
214 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
215 "The name of the workspace to be created as the output of "
216 "the algorithm. A workspace of this name will be created "
217 "and stored in the Analysis Data Service. For multiperiod "
218 "files, one workspace may be generated for each period. "
219 "Currently only one workspace can be saved at a time so "
220 "multiperiod Mantid files are not generated.");
221
222 // optional
223 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
224 mustBePositive->setLower(0);
225
226 // Use a static cast as MSVC sometimes gets confused and casts as int64
227 declareProperty("SpectrumMin", static_cast<int>(1), mustBePositive, "Number of first spectrum to read.");
228 declareProperty("SpectrumMax", static_cast<int>(Mantid::EMPTY_INT()), mustBePositive,
229 "Number of last spectrum to read.");
230 declareProperty(std::make_unique<ArrayProperty<int>>("SpectrumList"), "List of spectrum numbers to read.");
231 declareProperty("EntryNumber", static_cast<int>(0), mustBePositive,
232 "0 indicates that every entry is loaded, into a separate "
233 "workspace within a group. "
234 "A positive number identifies one entry to be loaded, into "
235 "one workspace");
236 declareProperty("LoadHistory", true, "If true, the workspace history will be loaded");
237 declareProperty(std::make_unique<PropertyWithValue<bool>>("FastMultiPeriod", true, Direction::Input),
238 "For multiperiod workspaces. Copy instrument, parameter and x-data "
239 "rather than loading it directly for each workspace. Y, E and log "
240 "information is always loaded.");
241}
242
254 MatrixWorkspace_sptr &tempMatrixWorkspace,
255 const size_t nWorkspaceEntries, const size_t p) {
256
257 MatrixWorkspace_sptr periodWorkspace = WorkspaceFactory::Instance().create(tempMatrixWorkspace);
258
259 const size_t nHistograms = periodWorkspace->getNumberHistograms();
260 for (size_t i = 0; i < nHistograms; ++i) {
261 periodWorkspace->setSharedX(i, tempMatrixWorkspace->sharedX(i));
262 }
263
264 // We avoid using `openEntry` or similar here because they're just wrappers
265 // around `open`. `open` is slow for large multiperiod datasets, because it
266 // does a search upon the entire HDF5 tree. `openLocal` is *much* quicker, as
267 // it only searches the current group. It does, however, require that the
268 // parent group is currently open.
269 // Words of Warning: While the openLocal construct is an optimization,
270 // it is very dangerous. Forgetting to close an entry of an NXEntry in a
271 // completely unrelated part of the code can result in us opening the
272 // wrong NXEntry here!
273 NXEntry mtdEntry(root, entryName);
274 mtdEntry.openLocal();
275
276 NXData wsEntry(mtdEntry, "workspace");
277 if (!wsEntry.openLocal()) {
278 std::stringstream buffer;
279 buffer << "Group entry " << p - 1
280 << " is not a workspace 2D. Retry with "
281 "FastMultiPeriod option set off.\n";
282 throw std::runtime_error(buffer.str());
283 }
284
285 if (wsEntry.isValid("frac_area")) {
286 std::stringstream buffer;
287 buffer << "Group entry " << p - 1
288 << " has fractional area present. Try "
289 "reloading with FastMultiPeriod set "
290 "off.\n";
291 throw std::runtime_error(buffer.str());
292 }
293
294 NXDouble data(wsEntry, "values");
295 data.openLocal();
296 NXDouble errors(wsEntry, "errors");
297 errors.openLocal();
298
299 const int64_t nChannels = data.dim1();
300
301 int blockSize = 8; // Read block size. Set to 8 for efficiency. i.e. read
302 // 8 histograms at a time.
303 int nFullBlocks =
304 static_cast<int>(nHistograms) / blockSize; // Truncated number of full blocks to read. Remainder removed
305 const int readOptimumStop = (nFullBlocks * blockSize);
306 const int readStop = m_spec_max - 1;
307 const int finalBlockSize = readStop - readOptimumStop;
308
309 int wsIndex = 0;
310 int histIndex = m_spec_min - 1;
311
312 for (; histIndex < readStop;) {
313 if (histIndex >= readOptimumStop) {
314 blockSize = finalBlockSize;
315 }
316
317 data.load(blockSize, histIndex);
318 errors.load(blockSize, histIndex);
319
320 double *dataStart = data();
321 double *dataEnd = dataStart + nChannels;
322
323 double *errorStart = errors();
324 double *errorEnd = errorStart + nChannels;
325
326 int64_t final(histIndex + blockSize);
327 while (histIndex < final) {
328 auto &Y = periodWorkspace->mutableY(wsIndex);
329 Y.assign(dataStart, dataEnd);
330 dataStart += nChannels;
331 dataEnd += nChannels;
332 auto &E = periodWorkspace->mutableE(wsIndex);
333 E.assign(errorStart, errorEnd);
334 errorStart += nChannels;
335 errorEnd += nChannels;
336
337 ++wsIndex;
338 ++histIndex;
339 }
340 }
341
342 // We always start one layer too deep
343 // go from /workspace_{n}/{something} -> /workspace_{n}
344 m_nexusFile->closeGroup();
345
346 // Now move to the correct period group
347 // /workspace_{n} -> /workspace_{n+1}
348 m_nexusFile->closeGroup();
349 m_nexusFile->openGroup(entryName, "NXentry");
350
351 try {
352 // This loads logs, sample, and instrument.
353 periodWorkspace->loadSampleAndLogInfoNexus(m_nexusFile.get());
354 } catch (std::exception &e) {
355 g_log.information("Error loading Instrument section of nxs file");
356 g_log.information(e.what());
357 }
358
359 // We make sure to close the current entries. Failing to do this can cause
360 // strange off-by-one errors when loading the spectra.
361 wsEntry.close();
362 mtdEntry.close();
363
364 const double fractionComplete = double(p - 1) / double(nWorkspaceEntries);
365 progress(fractionComplete, "Loading multiperiod entry");
366 return periodWorkspace;
367}
368
369//-------------------------------------------------------------------------------------------------
376
377 API::Workspace_sptr tempWS;
378 size_t nWorkspaceEntries = 0;
379
380 // Check for an entry number property
381 int entryNumber = getProperty("EntryNumber");
382 Property const *const entryNumberProperty = this->getProperty("EntryNumber");
383 bool bDefaultEntryNumber = entryNumberProperty->isDefault();
384
385 // Start scoped block
386 {
387 progress(0, "Opening file...");
388
389 // Throws an appropriate exception if there is a problem with file access
390 const std::string filename = getPropertyValue("Filename");
391 NXRoot root(filename);
392
393 // "Open" the same file but with the C++ interface
394 m_nexusFile = std::make_unique<Nexus::File>(root.m_fileID);
395
396 // Find out how many NXentry groups there are in the file.
397 nWorkspaceEntries = std::count_if(root.groups().cbegin(), root.groups().cend(),
398 [](const auto &g) { return g.nxclass == "NXentry"; });
399
400 if (!bDefaultEntryNumber && static_cast<size_t>(entryNumber) > nWorkspaceEntries) {
401 g_log.error() << "Invalid entry number: " << entryNumber
402 << " specified. File only contains: " << nWorkspaceEntries << " entries.\n";
403 throw std::invalid_argument("Invalid entry number specified.");
404 }
405
406 const std::string basename = "mantid_workspace_";
407
408 std::ostringstream os;
409 if (bDefaultEntryNumber) {
410 // Set the entry number to 1 if not provided.
411 entryNumber = 1;
412 }
413 os << basename << entryNumber;
414 const std::string targetEntryName = os.str();
415
416 // Take the first real workspace obtainable. We need it even if loading
417 // groups.
418 tempWS = loadEntry(root, targetEntryName, 0, 1);
419
420 if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) {
421 // We have what we need.
422 applyLogFiltering(tempWS);
423 setProperty("OutputWorkspace", tempWS);
424 } else {
425 // We already know that this is a group workspace. Is it a true
426 // multiperiod workspace.
427 const bool bFastMultiPeriod = this->getProperty("FastMultiPeriod");
428 const bool bIsMultiPeriod = isMultiPeriodFile(static_cast<int>(nWorkspaceEntries), tempWS, g_log);
429 const Property *specListProp = this->getProperty("SpectrumList");
430 m_list = !specListProp->isDefault();
431
432 // Load all first level entries
433 auto wksp_group = std::make_shared<WorkspaceGroup>();
434 // This forms the name of the group
435 std::string base_name = getPropertyValue("OutputWorkspace");
436 // First member of group should be the group itself, for some reason!
437
438 // load names of each of the workspaces. Note that if we have duplicate
439 // names then we don't select them
440 auto names = extractWorkspaceNames(root, nWorkspaceEntries);
441
442 // remove existing workspace and replace with the one being loaded
443 bool wsExists = AnalysisDataService::Instance().doesExist(base_name);
444 if (wsExists) {
445 Algorithm_sptr alg = AlgorithmManager::Instance().createUnmanaged("DeleteWorkspace");
446 alg->initialize();
447 alg->setChild(true);
448 alg->setProperty("Workspace", base_name);
449 alg->execute();
450 }
451
452 base_name += "_";
453 const std::string prop_name = "OutputWorkspace_";
454
455 MatrixWorkspace_sptr tempMatrixWorkspace = std::dynamic_pointer_cast<Workspace2D>(tempWS);
456 bool bAccelleratedMultiPeriodLoading = false;
457 if (tempMatrixWorkspace) {
458 // We only accelerate for simple scenarios for now. Spectrum lists are
459 // too complicated to bother with.
460 bAccelleratedMultiPeriodLoading = bIsMultiPeriod && bFastMultiPeriod && !m_list;
461 // Strip out any loaded logs. That way we don't pay for copying that
462 // information around.
463 tempMatrixWorkspace->mutableRun().clearLogs();
464 }
465
466 if (bAccelleratedMultiPeriodLoading) {
467 g_log.information("Accelerated multiperiod loading");
468 } else {
469 g_log.information("Individual group loading");
470 }
471
472 for (size_t p = 1; p <= nWorkspaceEntries; ++p) {
473 const auto indexStr = std::to_string(p);
474
475 // decide what the workspace should be called
476 std::string wsName = buildWorkspaceName(names[p], base_name, p);
477
478 Workspace_sptr local_workspace;
479
480 /*
481 For multiperiod workspaces we can accelerate the loading by making
482 resonable assumptions about the differences between the workspaces
483 Only Y, E and log data entries should vary. Therefore we can clone our
484 temp workspace, and overwrite those things we are interested in.
485 */
486 if (bAccelleratedMultiPeriodLoading) {
487 local_workspace =
488 doAccelleratedMultiPeriodLoading(root, basename + indexStr, tempMatrixWorkspace, nWorkspaceEntries, p);
489 } else // Fall-back for generic loading
490 {
491 const auto nWorkspaceEntries_d = static_cast<double>(nWorkspaceEntries);
492 local_workspace = loadEntry(root, basename + indexStr, static_cast<double>(p - 1) / nWorkspaceEntries_d,
493 1. / nWorkspaceEntries_d);
494 }
495
496 applyLogFiltering(local_workspace);
498 std::make_unique<WorkspaceProperty<API::Workspace>>(prop_name + indexStr, wsName, Direction::Output));
499 wksp_group->addWorkspace(local_workspace);
500 setProperty(prop_name + indexStr, local_workspace);
501 }
502
503 // The group is the root property value
504 setProperty("OutputWorkspace", std::static_pointer_cast<Workspace>(wksp_group));
505 }
506
507 root.close();
508 m_nexusFile->close();
509 }
510
511 // All file resources should be scoped to here. All previous file handles
512 // must be cleared to release locks.
513
514 // NexusGeometry uses direct HDF5 access, and not the `NexusFileIO` methods.
515 // For this reason, a separate section is required to load the instrument[s] into the output workspace[s].
516
517 if (nWorkspaceEntries == 1 || !bDefaultEntryNumber)
518 loadNexusGeometry(*getValue<API::Workspace_sptr>("OutputWorkspace"), static_cast<size_t>(entryNumber), g_log,
519 std::string(getProperty("Filename")));
520 else {
521 for (size_t nEntry = 1; nEntry <= static_cast<size_t>(nWorkspaceEntries); ++nEntry) {
522 std::ostringstream wsPropertyName;
523 wsPropertyName << "OutputWorkspace_" << nEntry;
524 loadNexusGeometry(*getValue<API::Workspace_sptr>(wsPropertyName.str()), nEntry, g_log,
525 std::string(getProperty("Filename")));
526 }
527 }
528
529 m_axis1vals.clear();
530}
531
545std::string LoadNexusProcessed::buildWorkspaceName(const std::string &name, const std::string &baseName,
546 size_t wsIndex) {
547 std::string wsName;
548 std::string index = std::to_string(wsIndex);
549
550 if (!name.empty()) {
551 wsName = name;
552 } else {
553 // we have a common stem so rename accordingly
554 boost::smatch results;
555 const boost::regex exp(".*_(\\d+$)");
556 // if we have a common name stem then name is <OutputWorkspaceName>_n
557 if (boost::regex_search(name, results, exp)) {
558 wsName = baseName + std::string(results[1].first, results[1].second);
559 } else {
560 // if the name property wasn't defined just use <OutputWorkspaceName>_n
561 wsName = baseName + index;
562 }
563 }
564
566
567 return wsName;
568}
569
576 bool noClash(false);
577
578 for (int i = 0; !noClash; ++i) {
579 std::string wsIndex; // dont use an index if there is no other
580 // workspace
581 if (i > 0) {
582 wsIndex = "_" + std::to_string(i);
583 }
584
585 bool wsExists = AnalysisDataService::Instance().doesExist(wsName + wsIndex);
586 if (!wsExists) {
587 wsName += wsIndex;
588 noClash = true;
589 }
590 }
591}
592
599std::vector<std::string> LoadNexusProcessed::extractWorkspaceNames(NXRoot &root, size_t nWorkspaceEntries) {
600 std::vector<std::string> names(nWorkspaceEntries + 1);
601 for (size_t p = 1; p <= nWorkspaceEntries; ++p) {
602 auto period = std::to_string(p);
603 names[p] = loadWorkspaceName(root, "mantid_workspace_" + period);
604 }
605
606 // Check that there are no duplicates in the workspace name
607 // This can cause severe problems
608 auto it = std::unique(names.begin(), names.end());
609 if (it != names.end()) {
610 auto size = names.size();
611 names.clear();
612 names.resize(size);
613 }
614 return names;
615}
616
624std::string LoadNexusProcessed::loadWorkspaceName(NXRoot &root, const std::string &entry_name) {
625 NXEntry mtd_entry = root.openEntry(entry_name);
626 std::string workspaceName = std::string();
627 try {
628 workspaceName = mtd_entry.getString("workspace_name");
629 } catch (std::runtime_error &) {
630 }
631 mtd_entry.close();
632 return workspaceName;
633}
634
635//-------------------------------------------------------------------------------------------------
647 const double &progressStart, const double &progressRange) {
648 NXInt64 indices_data = wksp_cls.openNXDataSet<int64_t>("indices");
649 indices_data.load();
650 size_t numspec = indices_data.dim0() - 1;
651
652 // process optional spectrum parameters, if set
654 // Actual number of spectra in output workspace (if only a user-specified
655 // range and/or list was going to be loaded)
656 numspec = calculateWorkspaceSize(numspec, true);
657
658 auto num_xbins = xbins.dim0();
659 if (xbins.rank() == 2) {
660 num_xbins = xbins.dim1();
661 }
662 if (num_xbins < 2)
663 num_xbins = 2;
664 EventWorkspace_sptr ws = std::dynamic_pointer_cast<EventWorkspace>(
665 WorkspaceFactory::Instance().create("EventWorkspace", numspec, num_xbins, num_xbins - 1));
666
667 // Set the YUnit label
668 ws->setYUnit(indices_data.attributes("units"));
669 std::string unitLabel = indices_data.attributes("unit_label");
670 if (unitLabel.empty())
671 unitLabel = indices_data.attributes("units");
672 ws->setYUnitLabel(unitLabel);
673
674 // Handle optional fields.
675 // TODO: Handle inconsistent sizes
676 std::vector<int64_t> pulsetimes;
677 if (wksp_cls.isValid("pulsetime")) {
678 NXInt64 pulsetime = wksp_cls.openNXDataSet<int64_t>("pulsetime");
679 pulsetime.load();
680 pulsetimes = pulsetime.vecBuffer();
681 }
682
683 std::vector<double> tofs;
684 if (wksp_cls.isValid("tof")) {
685 NXDouble tof = wksp_cls.openNXDouble("tof");
686 tof.load();
687 tofs = tof.vecBuffer();
688 }
689
690 std::vector<float> error_squareds;
691 if (wksp_cls.isValid("error_squared")) {
692 NXFloat error_squared = wksp_cls.openNXFloat("error_squared");
693 error_squared.load();
694 error_squareds = error_squared.vecBuffer();
695 }
696
697 std::vector<float> weights;
698 if (wksp_cls.isValid("weight")) {
699 NXFloat weight = wksp_cls.openNXFloat("weight");
700 weight.load();
701 weights = weight.vecBuffer();
702 }
703
704 // What type of event lists?
705 EventType type = TOF;
706 if (!tofs.empty() && !pulsetimes.empty() && !weights.empty() && !error_squareds.empty())
707 type = WEIGHTED;
708 else if ((!tofs.empty() && !weights.empty() && !error_squareds.empty()))
709 type = WEIGHTED_NOTIME;
710 else if (!pulsetimes.empty() && !tofs.empty())
711 type = TOF;
712 else
713 throw std::runtime_error("Could not figure out the type of event list!");
714
715 // indices of events
716 std::vector<int64_t> indices = indices_data.vecBuffer();
717 // Create all the event lists
718 auto max = static_cast<int64_t>(m_filtered_spec_idxs.size());
719 Progress progress(this, progressStart, progressStart + progressRange, max);
721 for (int64_t j = 0; j < max; ++j) {
723 size_t wi = m_filtered_spec_idxs[j] - 1;
724 int64_t index_start = indices[wi];
725 int64_t index_end = indices[wi + 1];
726 if (index_end >= index_start) {
727 EventList &el = ws->getSpectrum(j);
728 el.switchTo(type);
729
730 // Allocate all the required memory
731 el.reserve(index_end - index_start);
732 el.clearDetectorIDs();
733
734 for (int64_t i = index_start; i < index_end; i++)
735 switch (type) {
736 case TOF:
737 el.addEventQuickly(TofEvent(tofs[i], DateAndTime(pulsetimes[i])));
738 break;
739 case WEIGHTED:
740 el.addEventQuickly(WeightedEvent(tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i]));
741 break;
742 case WEIGHTED_NOTIME:
743 el.addEventQuickly(WeightedEventNoTime(tofs[i], weights[i], error_squareds[i]));
744 break;
745 }
746
747 // Set the X axis
748 if (this->m_shared_bins)
749 el.setHistogram(this->m_xbins);
750 else {
751 MantidVec x(xbins.dim1());
752
753 for (std::size_t i = 0; i < xbins.dim1(); i++)
754 x[i] = xbins(wi, i);
755
756 // for ragged workspace we need to remove all NaN value from end of vector
757 const auto idx =
758 std::distance(x.rbegin(), std::find_if_not(x.rbegin(), x.rend(), [](auto val) { return std::isnan(val); }));
759 if (idx > 0)
760 x.resize(x.size() - idx);
761 // Workspace and el was just created, so we can just set a new histogram
762 // We can move x as it is not longer used after this point
763 el.setHistogram(HistogramData::BinEdges(std::move(x)));
764 }
765 }
766 progress.report();
768 }
770
771 return ws;
772}
773
774//-------------------------------------------------------------------------------------------------
782template <typename ColumnType, typename NexusType>
783void LoadNexusProcessed::loadNumericColumn(const Mantid::Nexus::NXData &tableData, const std::string &dataSetName,
784 const API::ITableWorkspace_sptr &tableWs, const std::string &columnType) {
785 NXDataSetTyped<NexusType> data = tableData.openNXDataSet<NexusType>(dataSetName);
786 std::string columnTitle = data.attributes("name");
787 if (!columnTitle.empty()) {
788 data.load();
789 auto length = static_cast<size_t>(data.dim0());
790 auto rowCount = tableWs->rowCount();
791 // check that the row count is OK
792 if (rowCount == 0) {
793 tableWs->setRowCount(length);
794 } else if (rowCount != length) {
795 throw std::runtime_error("Columns have different sizes.");
796 }
797 // copy the data
798 auto column = tableWs->addColumn(columnType, columnTitle);
799 for (size_t i = 0; i < length; i++) {
800 column->cell<ColumnType>(i) = static_cast<ColumnType>(*(data() + i));
801 }
802 }
803}
804
805//-------------------------------------------------------------------------------------------------
811 workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
812
813 NXData nx_tw = entry.openNXData("table_workspace");
814
815 int columnNumber = 1;
816 do {
817 std::string dataSetName = "column_" + std::to_string(columnNumber);
818
819 NXInfo info = nx_tw.getDataSetInfo(dataSetName);
820 if (!info.allGood) {
821 // Assume we done last column of table
822 break;
823 }
824
825 if (info.rank == 1) {
826 if (info.type == NXnumtype::FLOAT64) {
827 loadNumericColumn<double, double>(nx_tw, dataSetName, workspace, "double");
828 } else if (info.type == NXnumtype::INT32) {
829 loadNumericColumn<int, int32_t>(nx_tw, dataSetName, workspace, "int");
830 } else if (info.type == NXnumtype::UINT32) {
831 loadNumericColumn<uint32_t, uint32_t>(nx_tw, dataSetName, workspace, "uint");
832 } else if (info.type == NXnumtype::INT64) {
833 loadNumericColumn<int64_t, int64_t>(nx_tw, dataSetName, workspace, "long64");
834 } else if (info.type == NXnumtype::UINT64) {
835 loadNumericColumn<size_t, uint64_t>(nx_tw, dataSetName, workspace, "size_t");
836 } else if (info.type == NXnumtype::FLOAT32) {
837 loadNumericColumn<float, float>(nx_tw, dataSetName, workspace, "float");
838 } else if (info.type == NXnumtype::UINT8) {
839 loadNumericColumn<bool, bool>(nx_tw, dataSetName, workspace, "bool");
840 } else {
841 throw std::logic_error("Column with Nexus data type " + std::to_string(static_cast<int>(info.type)) +
842 " cannot be loaded.");
843 }
844 } else if (info.rank == 2) {
845 if (info.type == NXnumtype::CHAR) {
846 NXChar data = nx_tw.openNXChar(dataSetName);
847 std::string columnTitle = data.attributes("name");
848 if (!columnTitle.empty()) {
849 workspace->addColumn("str", columnTitle);
850 dimsize_t nRows = info.dims[0];
851 workspace->setRowCount(nRows);
852
853 dimsize_t const maxStr = info.dims[1];
854 data.load();
855 for (dimsize_t iR = 0; iR < nRows; ++iR) {
856 auto &cellContents = workspace->cell<std::string>(iR, columnNumber - 1);
857 auto startPoint = data() + maxStr * iR;
858 cellContents.assign(startPoint, startPoint + maxStr);
859 boost::trim_right(cellContents);
860 }
861 }
862 } else if (info.type == NXnumtype::INT32) {
863 loadVectorColumn<int32_t>(nx_tw, dataSetName, workspace, "vector_int");
864 } else if (info.type == NXnumtype::FLOAT64) {
865 auto data = nx_tw.openNXDouble(dataSetName);
866 if (data.attributes("interpret_as") == "V3D") {
868 } else {
869 loadVectorColumn<double>(nx_tw, dataSetName, workspace, "vector_double");
870 }
871 }
872 }
873
874 columnNumber++;
875
876 } while (true);
877
878 return std::static_pointer_cast<API::Workspace>(workspace);
879}
880
888template <typename Type>
889void LoadNexusProcessed::loadVectorColumn(const NXData &tableData, const std::string &dataSetName,
890 const ITableWorkspace_sptr &tableWs, const std::string &columnType) {
891 NXDataSetTyped<Type> data = tableData.openNXDataSet<Type>(dataSetName);
892 std::string columnTitle = data.attributes("name");
893 if (!columnTitle.empty()) {
894 tableWs->addColumn(columnType, columnTitle);
895
896 NXInfo info = tableData.getDataSetInfo(dataSetName);
897 const size_t rowCount = info.dims[0];
898 const size_t blockSize = info.dims[1];
899
900 // This might've been done already, but doing it twice should't do any harm
901 tableWs->setRowCount(rowCount);
902
903 data.load();
904
905 for (size_t i = 0; i < rowCount; ++i) {
906 auto &cell = tableWs->cell<std::vector<Type>>(i, tableWs->columnCount() - 1);
907
908 Type *from = data() + blockSize * i;
909
910 cell.assign(from, from + blockSize);
911
912 std::ostringstream rowSizeAttrName;
913 rowSizeAttrName << "row_size_" << i;
914
915 // This is ugly, but I can only get attribute as a string using the API
916 std::istringstream rowSizeStr(data.attributes(rowSizeAttrName.str()));
917
918 int rowSize;
919 rowSizeStr >> rowSize;
920
921 cell.resize(rowSize);
922 }
923 }
924}
925
932 std::string columnTitle = data.attributes("name");
933 if (!columnTitle.empty()) {
934 ColumnVector<V3D> col = tableWs->addColumn("V3D", columnTitle);
935
936 const int64_t rowCount = data.dim0();
937
938 // This might've been done already, but doing it twice shouldn't do any harm
939 tableWs->setRowCount(rowCount);
940
941 data.load();
942
943 for (int64_t i = 0; i < rowCount; ++i) {
944 auto &cell = col[i]; // cppcheck-suppress constVariableReference
945 cell(data(i, 0), data(i, 1), data(i, 2));
946 }
947 }
948}
949
957 g_log.notice("Load as LeanElasticPeaks");
958
959 // API::IPeaksWorkspace_sptr workspace;
960 API::ITableWorkspace_sptr tWorkspace;
961 // PeaksWorkspace_sptr workspace;
962 tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("LeanElasticPeaksWorkspace");
963
964 IPeaksWorkspace_sptr peakWS = std::dynamic_pointer_cast<LeanElasticPeaksWorkspace>(tWorkspace);
965
966 NXData nx_tw = entry.openNXData("peaks_workspace");
967
968 size_t columnNumber = 1;
969 size_t numberPeaks = 0;
970 std::vector<std::string> columnNames;
971 do {
972 std::string str = "column_" + std::to_string(columnNumber);
973
974 NXInfo info = nx_tw.getDataSetInfo(str);
975 if (!info.allGood) {
976 // Assume we done last column of table
977 break;
978 }
979
980 // store column names
981 columnNames.emplace_back(str);
982
983 // determine number of peaks
984 // here we assume that a peaks_table has always one column of doubles
985
986 if (info.type == NXnumtype::FLOAT64) {
987 NXDouble nxDouble = nx_tw.openNXDouble(str);
988 std::string columnTitle = nxDouble.attributes("name");
989 if (!columnTitle.empty() && numberPeaks == 0) {
990 numberPeaks = nxDouble.dim0();
991 }
992 }
993
994 columnNumber++;
995
996 } while (true);
997
998 // Hop to the right point /mantid_workspace_1
999 try {
1000 m_nexusFile->openAddress(entry.address()); // This is
1001 } catch (std::runtime_error &re) {
1002 throw std::runtime_error(
1003 "Error while opening a address in a Peaks entry in a Nexus processed file. This address is wrong: " +
1004 std::string(entry.address()) + ". Lower level error description: " + re.what());
1005 }
1006 try {
1007 // Get information from all but data group
1008 std::string parameterStr;
1009 // This loads logs, sample, and instrument.
1010 peakWS->loadExperimentInfoNexus(getPropertyValue("Filename"), m_nexusFile.get(), parameterStr);
1011 // Populate the instrument parameters in this workspace
1012 peakWS->readParameterMap(parameterStr);
1013 } catch (std::exception &e) {
1014 g_log.information("Error loading Instrument section of nxs file");
1015 g_log.information(e.what());
1016 }
1017
1018 // Coordinates - Older versions did not have the separate field but used a log
1019 // value
1020 const std::string peaksWSName = "peaks_workspace";
1021 try {
1022 m_nexusFile->openGroup(peaksWSName, "NXentry");
1023 } catch (std::runtime_error &re) {
1024 throw std::runtime_error("Error while opening a peaks workspace in a Nexus processed file. Cannot open group " +
1025 peaksWSName + ". Lower level error description: " + re.what());
1026 }
1027 try {
1028 uint32_t loadCoord(0);
1029 m_nexusFile->readData("coordinate_system", loadCoord);
1030 peakWS->setCoordinateSystem(static_cast<Kernel::SpecialCoordinateSystem>(loadCoord));
1031 } catch (Nexus::Exception const &) {
1032 // Check for a log value
1033 auto logs = peakWS->logs();
1034 if (logs->hasProperty("CoordinateSystem")) {
1035 auto *prop = dynamic_cast<PropertyWithValue<int> *>(logs->getProperty("CoordinateSystem"));
1036 if (prop) {
1037 int value((*prop)());
1038 peakWS->setCoordinateSystem(static_cast<Kernel::SpecialCoordinateSystem>(value));
1039 }
1040 }
1041 }
1042
1043 std::string m_QConvention = "Inelastic";
1044 try {
1045 m_nexusFile->getAttr("QConvention", m_QConvention);
1046 } catch (std::exception &) {
1047 }
1048
1049 // peaks_workspace
1050 m_nexusFile->closeGroup();
1051
1052 // Change convention of loaded file to that in Preferen
1053 double qSign = 1.0;
1054 std::string convention = ConfigService::Instance().getString("Q.convention");
1055 if (convention != m_QConvention)
1056 qSign = -1.0;
1057
1058 for (size_t r = 0; r < numberPeaks; r++) {
1059 // Create individual LeanElasticPeak
1060 const auto &goniometer = peakWS->run().getGoniometer();
1061 LeanElasticPeak peak;
1062 peak.setGoniometerMatrix(goniometer.getR());
1063 peak.setRunNumber(peakWS->getRunNumber());
1064 peakWS->addPeak(peak);
1065 }
1066
1067 for (const auto &str : columnNames) {
1068 if (str == "column_1") {
1069 NXDouble nxDouble = nx_tw.openNXDouble(str);
1070 nxDouble.load();
1071
1072 for (size_t r = 0; r < numberPeaks; r++) {
1073 double val = qSign * nxDouble[r];
1074 peakWS->getPeak(r).setH(val);
1075 }
1076 } else if (str == "column_2") {
1077 NXDouble nxDouble = nx_tw.openNXDouble(str);
1078 nxDouble.load();
1079
1080 for (size_t r = 0; r < numberPeaks; r++) {
1081 double val = qSign * nxDouble[r];
1082 peakWS->getPeak(r).setK(val);
1083 }
1084 } else if (str == "column_3") {
1085 NXDouble nxDouble = nx_tw.openNXDouble(str);
1086 nxDouble.load();
1087
1088 for (size_t r = 0; r < numberPeaks; r++) {
1089 double val = qSign * nxDouble[r];
1090 peakWS->getPeak(r).setL(val);
1091 }
1092 } else if (str == "column_4") {
1093 NXDouble nxDouble = nx_tw.openNXDouble(str);
1094 nxDouble.load();
1095
1096 for (size_t r = 0; r < numberPeaks; r++) {
1097 double val = nxDouble[r];
1098 peakWS->getPeak(r).setIntensity(val);
1099 }
1100 } else if (str == "column_5") {
1101 NXDouble nxDouble = nx_tw.openNXDouble(str);
1102 nxDouble.load();
1103
1104 for (size_t r = 0; r < numberPeaks; r++) {
1105 double val = nxDouble[r];
1106 peakWS->getPeak(r).setSigmaIntensity(val);
1107 }
1108 } else if (str == "column_6") {
1109 NXDouble nxDouble = nx_tw.openNXDouble(str);
1110 nxDouble.load();
1111
1112 for (size_t r = 0; r < numberPeaks; r++) {
1113 double val = nxDouble[r];
1114 peakWS->getPeak(r).setBinCount(val);
1115 }
1116 } else if (str == "column_7") {
1117 NXDouble nxDouble = nx_tw.openNXDouble(str);
1118 nxDouble.load();
1119
1120 for (size_t r = 0; r < numberPeaks; r++) {
1121 double val = nxDouble[r];
1122 peakWS->getPeak(r).setWavelength(val);
1123 }
1124 } else if (str == "column_10") {
1125 NXInt nxInt = nx_tw.openNXInt(str);
1126 nxInt.load();
1127
1128 for (size_t r = 0; r < numberPeaks; r++) {
1129 int ival = nxInt[r];
1130 if (ival != -1)
1131 peakWS->getPeak(r).setRunNumber(ival);
1132 }
1133 } else if (str == "column_11") {
1134 NXInt nxInt = nx_tw.openNXInt(str);
1135 nxInt.load();
1136
1137 for (size_t r = 0; r < numberPeaks; r++) {
1138 int ival = nxInt[r];
1139 peakWS->getPeak(r).setPeakNumber(ival);
1140 }
1141 } else if (str == "column_12") {
1142 NXDouble nxDouble = nx_tw.openNXDouble(str);
1143 nxDouble.load();
1144
1145 for (size_t r = 0; r < numberPeaks; r++) {
1146 double val = nxDouble[r];
1147 peakWS->getPeak(r).setAbsorptionWeightedPathLength(val);
1148 }
1149 } else if (str == "column_13") {
1150 NXDouble nxDouble = nx_tw.openNXDouble(str);
1151 nxDouble.load();
1152 Kernel::Matrix<double> gm(3, 3, false);
1153 int k = 0;
1154 for (size_t r = 0; r < numberPeaks; r++) {
1155 for (int j = 0; j < 9; j++) {
1156 double val = nxDouble[k];
1157 k++;
1158 gm[j % 3][j / 3] = val;
1159 }
1160 peakWS->getPeak(r).setGoniometerMatrix(gm);
1161 }
1162 } else if (str == "column_14") {
1163 // Read shape information
1164 using namespace Mantid::DataObjects;
1165
1166 PeakShapeFactory_sptr peakFactoryEllipsoid = std::make_shared<PeakShapeEllipsoidFactory>();
1167 PeakShapeFactory_sptr peakFactorySphere = std::make_shared<PeakShapeSphericalFactory>();
1168 PeakShapeFactory_sptr peakFactoryDetectorBin = std::make_shared<PeakShapeDetectorBinFactory>();
1169 PeakShapeFactory_sptr peakFactoryNone = std::make_shared<PeakNoShapeFactory>();
1170
1171 peakFactoryEllipsoid->setSuccessor(peakFactorySphere);
1172 peakFactorySphere->setSuccessor(peakFactoryDetectorBin);
1173 peakFactoryDetectorBin->setSuccessor(peakFactoryNone);
1174
1175 NXInfo info = nx_tw.getDataSetInfo(str);
1176 NXChar data = nx_tw.openNXChar(str);
1177
1178 dimsize_t const maxShapeJSONLength = info.dims[1];
1179 data.load();
1180 for (size_t i = 0; i < numberPeaks; ++i) {
1181
1182 // iR = peak row number
1183 auto startPoint = data() + (maxShapeJSONLength * i);
1184 std::string shapeJSON(startPoint, startPoint + maxShapeJSONLength);
1185 boost::trim_right(shapeJSON);
1186
1187 // Make the shape
1188 Mantid::Geometry::PeakShape *peakShape = peakFactoryEllipsoid->create(shapeJSON);
1189
1190 // Set the shape
1191 peakWS->getPeak(i).setPeakShape(peakShape);
1192 }
1193 } else if (str == "column_15") {
1194 NXDouble nxDouble = nx_tw.openNXDouble(str);
1195 nxDouble.load();
1196 V3D qlab;
1197 for (size_t r = 0; r < numberPeaks; ++r) {
1198 qlab = V3D(nxDouble[r * 3], nxDouble[r * 3 + 1], nxDouble[r * 3 + 2]);
1199 peakWS->getPeak(r).setQLabFrame(qlab, 0.0);
1200 }
1201 } else if (str == "column_16") {
1202 NXDouble nxDouble = nx_tw.openNXDouble(str);
1203 nxDouble.load();
1204 V3D hkl;
1205 for (size_t r = 0; r < numberPeaks; ++r) {
1206 hkl = V3D(nxDouble[r * 3], nxDouble[r * 3 + 1], nxDouble[r * 3 + 2]);
1207 peakWS->getPeak(r).setIntHKL(hkl);
1208 }
1209 } else if (str == "column_17") {
1210 NXDouble nxDouble = nx_tw.openNXDouble(str);
1211 nxDouble.load();
1212 V3D mnp;
1213 for (size_t r = 0; r < numberPeaks; ++r) {
1214 mnp = V3D(nxDouble[r * 3], nxDouble[r * 3 + 1], nxDouble[r * 3 + 2]);
1215 peakWS->getPeak(r).setIntMNP(mnp);
1216 }
1217 }
1218
1219 // After all columns read set IntHKL if not set
1220 for (size_t r = 0; r < numberPeaks; r++) {
1221 V3D intHKL = peakWS->getPeak(r).getIntHKL();
1222 if (intHKL.norm2() == 0) {
1223 intHKL = V3D(peakWS->getPeak(r).getH(), peakWS->getPeak(r).getK(), peakWS->getPeak(r).getL());
1224 peakWS->getPeak(r).setIntHKL(intHKL);
1225 }
1226 }
1227 }
1228
1229 return std::static_pointer_cast<API::Workspace>(peakWS);
1230}
1231
1232//-------------------------------------------------------------------------------------------------
1237 // API::IPeaksWorkspace_sptr workspace;
1238 API::ITableWorkspace_sptr tWorkspace;
1239 // PeaksWorkspace_sptr workspace;
1240 tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("PeaksWorkspace");
1241
1242 PeaksWorkspace_sptr peakWS = std::dynamic_pointer_cast<PeaksWorkspace>(tWorkspace);
1243
1244 NXData nx_tw = entry.openNXData("peaks_workspace");
1245
1246 size_t columnNumber = 1;
1247 size_t numberPeaks = 0;
1248 std::vector<std::string> columnNames;
1249 do {
1250 std::string str = "column_" + std::to_string(columnNumber);
1251
1252 NXInfo info = nx_tw.getDataSetInfo(str);
1253 if (!info.allGood) {
1254 // Assume we done last column of table
1255 break;
1256 }
1257
1258 // store column names
1259 columnNames.emplace_back(str);
1260
1261 // determine number of peaks
1262 // here we assume that a peaks_table has always one column of doubles
1263
1264 if (info.type == NXnumtype::FLOAT64) {
1265 NXDouble nxDouble = nx_tw.openNXDouble(str);
1266 std::string columnTitle = nxDouble.attributes("name");
1267 if (!columnTitle.empty() && numberPeaks == 0) {
1268 numberPeaks = nxDouble.dim0();
1269 }
1270 }
1271
1272 columnNumber++;
1273
1274 } while (true);
1275
1276 // Hop to the right point /mantid_workspace_1
1277 try {
1278 m_nexusFile->openAddress(entry.address()); // This is
1279 } catch (std::runtime_error &re) {
1280 throw std::runtime_error(
1281 "Error while opening a address in a Peaks entry in a Nexus processed file. This address is wrong: " +
1282 std::string(entry.address()) + ". Lower level error description: " + re.what());
1283 }
1284 try {
1285 // Get information from all but data group
1286 std::string parameterStr;
1287 // This loads logs, sample, and instrument.
1288 peakWS->loadExperimentInfoNexus(getPropertyValue("Filename"), m_nexusFile.get(), parameterStr);
1289 // Populate the instrument parameters in this workspace
1290 peakWS->readParameterMap(parameterStr);
1291 } catch (std::exception &e) {
1292 g_log.information("Error loading Instrument section of nxs file");
1293 g_log.information(e.what());
1294 }
1295
1296 // Coordinates - Older versions did not have the separate field but used a log
1297 // value
1298 const std::string peaksWSName = "peaks_workspace";
1299 try {
1300 m_nexusFile->openGroup(peaksWSName, "NXentry");
1301 } catch (std::runtime_error &re) {
1302 throw std::runtime_error("Error while opening a peaks workspace in a Nexus processed file. Cannot open group " +
1303 peaksWSName + ". Lower level error description: " + re.what());
1304 }
1305 try {
1306 uint32_t loadCoord(0);
1307 m_nexusFile->readData("coordinate_system", loadCoord);
1308 peakWS->setCoordinateSystem(static_cast<Kernel::SpecialCoordinateSystem>(loadCoord));
1309 } catch (Nexus::Exception const &) {
1310 // Check for a log value
1311 auto logs = peakWS->logs();
1312 if (logs->hasProperty("CoordinateSystem")) {
1313 auto *prop = dynamic_cast<PropertyWithValue<int> *>(logs->getProperty("CoordinateSystem"));
1314 if (prop) {
1315 int value((*prop)());
1316 peakWS->setCoordinateSystem(static_cast<Kernel::SpecialCoordinateSystem>(value));
1317 }
1318 }
1319 }
1320
1321 std::string m_QConvention = "Inelastic";
1322 try {
1323 m_nexusFile->getAttr("QConvention", m_QConvention);
1324 } catch (std::exception &) {
1325 }
1326
1327 // peaks_workspace
1328 m_nexusFile->closeGroup();
1329
1330 // Change convention of loaded file to that in Preferen
1331 double qSign = 1.0;
1332 std::string convention = ConfigService::Instance().getString("Q.convention");
1333 if (convention != m_QConvention)
1334 qSign = -1.0;
1335
1336 for (size_t r = 0; r < numberPeaks; r++) {
1337 // Warning! Do not use anything other than the default constructor here
1338 // It is currently important (10/05/17) that the DetID (set in the loop
1339 // below this one) is set before QLabFrame as this causes Peak to ray trace
1340 // to find the location of the detector, which significantly increases
1341 // loading times.
1342 const auto &goniometer = peakWS->run().getGoniometer();
1343 Peak peak;
1344 peak.setInstrument(peakWS->getInstrument());
1345 peak.setGoniometerMatrix(goniometer.getR());
1346 peak.setRunNumber(peakWS->getRunNumber());
1347 peakWS->addPeak(std::move(peak));
1348 }
1349
1350 for (const auto &str : columnNames) {
1351 if (str == "column_1") {
1352 NXInt nxInt = nx_tw.openNXInt(str);
1353 nxInt.load();
1354
1355 for (size_t r = 0; r < numberPeaks; r++) {
1356 int ival = nxInt[r];
1357 if (ival != -1)
1358 peakWS->getPeak(r).setDetectorID(ival);
1359 }
1360 } else if (str == "column_2") {
1361 NXDouble nxDouble = nx_tw.openNXDouble(str);
1362 nxDouble.load();
1363
1364 for (size_t r = 0; r < numberPeaks; r++) {
1365 double val = qSign * nxDouble[r];
1366 peakWS->getPeak(r).setH(val);
1367 }
1368 } else if (str == "column_3") {
1369 NXDouble nxDouble = nx_tw.openNXDouble(str);
1370 nxDouble.load();
1371
1372 for (size_t r = 0; r < numberPeaks; r++) {
1373 double val = qSign * nxDouble[r];
1374 peakWS->getPeak(r).setK(val);
1375 }
1376 } else if (str == "column_4") {
1377 NXDouble nxDouble = nx_tw.openNXDouble(str);
1378 nxDouble.load();
1379
1380 for (size_t r = 0; r < numberPeaks; r++) {
1381 double val = qSign * nxDouble[r];
1382 peakWS->getPeak(r).setL(val);
1383 }
1384 } else if (str == "column_5") {
1385 NXDouble nxDouble = nx_tw.openNXDouble(str);
1386 nxDouble.load();
1387
1388 for (size_t r = 0; r < numberPeaks; r++) {
1389 double val = nxDouble[r];
1390 peakWS->getPeak(r).setIntensity(val);
1391 }
1392 } else if (str == "column_6") {
1393 NXDouble nxDouble = nx_tw.openNXDouble(str);
1394 nxDouble.load();
1395
1396 for (size_t r = 0; r < numberPeaks; r++) {
1397 double val = nxDouble[r];
1398 peakWS->getPeak(r).setSigmaIntensity(val);
1399 }
1400 } else if (str == "column_7") {
1401 NXDouble nxDouble = nx_tw.openNXDouble(str);
1402 nxDouble.load();
1403
1404 for (size_t r = 0; r < numberPeaks; r++) {
1405 double val = nxDouble[r];
1406 peakWS->getPeak(r).setBinCount(val);
1407 }
1408 } else if (str == "column_10") {
1409 NXDouble nxDouble = nx_tw.openNXDouble(str);
1410 nxDouble.load();
1411
1412 for (size_t r = 0; r < numberPeaks; r++) {
1413 double val = nxDouble[r];
1414 peakWS->getPeak(r).setWavelength(val);
1415 }
1416 } else if (str == "column_14") {
1417 NXInt nxInt = nx_tw.openNXInt(str);
1418 nxInt.load();
1419
1420 for (size_t r = 0; r < numberPeaks; r++) {
1421 int ival = nxInt[r];
1422 if (ival != -1)
1423 peakWS->getPeak(r).setRunNumber(ival);
1424 }
1425 } else if (str == "column_17") {
1426 NXInt nxInt = nx_tw.openNXInt(str);
1427 nxInt.load();
1428
1429 for (size_t r = 0; r < numberPeaks; r++) {
1430 int ival = nxInt[r];
1431 peakWS->getPeak(r).setPeakNumber(ival);
1432 }
1433 } else if (str == "column_18") {
1434 NXDouble nxDouble = nx_tw.openNXDouble(str);
1435 nxDouble.load();
1436
1437 for (size_t r = 0; r < numberPeaks; r++) {
1438 double val = nxDouble[r];
1439 peakWS->getPeak(r).setAbsorptionWeightedPathLength(val);
1440 }
1441 } else if (str == "column_15") {
1442 NXDouble nxDouble = nx_tw.openNXDouble(str);
1443 nxDouble.load();
1444 Kernel::Matrix<double> gm(3, 3, false);
1445 size_t k = 0;
1446 for (size_t r = 0; r < numberPeaks; r++) {
1447 for (size_t j = 0; j < 9; j++) {
1448 double val = nxDouble[k];
1449 k++;
1450 gm[j % 3][j / 3] = val;
1451 }
1452 peakWS->getPeak(r).setGoniometerMatrix(gm);
1453 }
1454 } else if (str == "column_16") {
1455 // Read shape information
1456 using namespace Mantid::DataObjects;
1457
1458 PeakShapeFactory_sptr peakFactoryEllipsoid = std::make_shared<PeakShapeEllipsoidFactory>();
1459 PeakShapeFactory_sptr peakFactorySphere = std::make_shared<PeakShapeSphericalFactory>();
1460 PeakShapeFactory_sptr peakFactoryDetectorBin = std::make_shared<PeakShapeDetectorBinFactory>();
1461 PeakShapeFactory_sptr peakFactoryNone = std::make_shared<PeakNoShapeFactory>();
1462
1463 peakFactoryEllipsoid->setSuccessor(peakFactorySphere);
1464 peakFactorySphere->setSuccessor(peakFactoryDetectorBin);
1465 peakFactoryDetectorBin->setSuccessor(peakFactoryNone);
1466
1467 NXInfo info = nx_tw.getDataSetInfo(str);
1468 NXChar data = nx_tw.openNXChar(str);
1469
1470 dimsize_t const maxShapeJSONLength = info.dims[1];
1471 data.load();
1472 for (size_t i = 0; i < numberPeaks; ++i) {
1473
1474 // iR = peak row number
1475 auto startPoint = data() + (maxShapeJSONLength * i);
1476 std::string shapeJSON(startPoint, startPoint + maxShapeJSONLength);
1477 boost::trim_right(shapeJSON);
1478
1479 // Make the shape
1480 Mantid::Geometry::PeakShape *peakShape = peakFactoryEllipsoid->create(shapeJSON);
1481
1482 // Set the shape
1483 peakWS->getPeak(i).setPeakShape(peakShape);
1484 }
1485 } else if (str == "column_19") {
1486 NXDouble nxDouble = nx_tw.openNXDouble(str);
1487 nxDouble.load();
1488 V3D hkl;
1489 for (size_t r = 0; r < numberPeaks; ++r) {
1490 hkl = V3D(nxDouble[r * 3], nxDouble[r * 3 + 1], nxDouble[r * 3 + 2]);
1491 peakWS->getPeak(r).setIntHKL(hkl);
1492 }
1493 } else if (str == "column_20") {
1494 NXDouble nxDouble = nx_tw.openNXDouble(str);
1495 nxDouble.load();
1496 V3D mnp;
1497 for (size_t r = 0; r < numberPeaks; ++r) {
1498 mnp = V3D(nxDouble[r * 3], nxDouble[r * 3 + 1], nxDouble[r * 3 + 2]);
1499 peakWS->getPeak(r).setIntMNP(mnp);
1500 }
1501 }
1502 }
1503 // After all columns read set IntHKL if not set
1504 for (size_t r = 0; r < numberPeaks; r++) {
1505 V3D intHKL = peakWS->getPeak(r).getIntHKL();
1506 if (intHKL.norm2() == 0) {
1507 intHKL = V3D(peakWS->getPeak(r).getH(), peakWS->getPeak(r).getK(), peakWS->getPeak(r).getL());
1508 peakWS->getPeak(r).setIntHKL(intHKL);
1509 }
1510 }
1511
1512 return std::static_pointer_cast<API::Workspace>(peakWS);
1513}
1514
1515//-------------------------------------------------------------------------------------------------
1531 const double &progressStart,
1532 const double &progressRange, const NXEntry &mtd_entry,
1533 const int64_t xlength, std::string &workspaceType) {
1534 // Filter the list of spectra to process, applying min/max/list options
1535 NXDouble data = wksp_cls.openDoubleData();
1536 dimsize_t nchannels = data.dim1();
1537 size_t nspectra = data.dim0();
1538 // process optional spectrum parameters, if set
1539 checkOptionalProperties(nspectra);
1540 // Actual number of spectra in output workspace (if only a range was going to be loaded)
1541 size_t total_specs = calculateWorkspaceSize(nspectra);
1542
1543 if (nchannels == 1 && nspectra == 1) {
1544 // if there is only one value of channels and nspectra, it may be a WorkspaceSingleValue
1545 // check for instrument
1546 bool hasInstrument = mtd_entry.containsGroup("instrument");
1547 if (hasInstrument) {
1548 std::string inst_name = mtd_entry.getString("instrument/name");
1549 boost::algorithm::trim(inst_name);
1550 if (inst_name == "")
1551 hasInstrument = false;
1552 } else {
1553 // data saved with SaveNexusESS will have the instrument in a directory named after it
1554 // check for special types of instrument: "basic_rect" and "unspecified_instrument":
1555 if (mtd_entry.containsGroup("basic_rect") || mtd_entry.containsGroup("unspecified_instrument")) {
1556 hasInstrument = true;
1557 } else {
1558 // check for other possible instruments
1559 for (auto facility : ConfigService::Instance().getFacilities()) {
1560 for (auto instrumentName : facility->instruments()) {
1561 if (instrumentName.name() != "" && mtd_entry.containsGroup(instrumentName.name())) {
1562 hasInstrument = true;
1563 break;
1564 }
1565 }
1566 }
1567 }
1568 }
1569 // check for metadata
1570 bool hasMetadata = mtd_entry.containsGroup("logs");
1571 if (hasMetadata) {
1572 // if there is more than one log (called "goniometer") then it's not a single-valued ws
1573 const auto nLogs = mtd_entry.openNXGroup("logs").groups().size();
1574 if (nLogs <= 1) { // only "goniometer" group is present, thus it's a single-valued ws
1575 hasMetadata = false;
1576 }
1577 }
1578 // a workspace with no instrument and no metadata, and only one entry is a single-valued ws
1579 if (!hasInstrument && !hasMetadata)
1580 workspaceType = "WorkspaceSingleValue";
1581 }
1582 bool hasFracArea = false;
1583 if (wksp_cls.isValid("frac_area")) {
1584 // frac_area entry is the signal for a RebinnedOutput workspace
1585 hasFracArea = true;
1586 workspaceType = "RebinnedOutput";
1587 }
1588
1589 API::MatrixWorkspace_sptr local_workspace = std::dynamic_pointer_cast<API::MatrixWorkspace>(
1590 WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, nchannels));
1591 try {
1592 local_workspace->setTitle(mtd_entry.getString("title"));
1593 } catch (std::runtime_error &) {
1594 g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << '\n';
1595 }
1596
1597 // Set the YUnit label
1598 local_workspace->setYUnit(data.attributes("units"));
1599 std::string unitLabel = data.attributes("unit_label");
1600 if (unitLabel.empty())
1601 unitLabel = data.attributes("units");
1602 local_workspace->setYUnitLabel(unitLabel);
1603
1604 readBinMasking(wksp_cls, local_workspace);
1605 NXDouble errors = wksp_cls.openNXDouble("errors");
1606 NXDouble fracarea = errors;
1607 if (hasFracArea) {
1608 fracarea = wksp_cls.openNXDouble("frac_area");
1609
1610 // Set the fractional area attributes, default values consistent with
1611 // previous assumptions: finalized = true, sqrdErrs = false
1612 auto rbWS = std::dynamic_pointer_cast<RebinnedOutput>(local_workspace);
1613 auto finalizedValue = fracarea.attributes("finalized");
1614 auto finalized = (finalizedValue.empty() ? true : finalizedValue == "1");
1615 rbWS->setFinalized(finalized);
1616 auto sqrdErrsValue = fracarea.attributes("sqrd_errors");
1617 auto sqrdErrs = (sqrdErrsValue.empty() ? false : sqrdErrsValue == "1");
1618 rbWS->setSqrdErrors(sqrdErrs);
1619 }
1620
1621 // Check for x errors; as with fracArea we set it to xbins
1622 // although in this case it would never be used.
1623 auto hasXErrors = wksp_cls.isValid("xerrors");
1624 auto xErrors = hasXErrors ? wksp_cls.openNXDouble("xerrors") : errors;
1625 if (hasXErrors) {
1626 if (xErrors.dim1() == nchannels + 1)
1627 g_log.warning() << "Legacy X uncertainty found in input file, i.e., "
1628 "delta-Q for each BIN EDGE. Uncertainties will be "
1629 "re-interpreted as delta-Q of the BIN CENTRE and the "
1630 "last value will be dropped.\n";
1631 }
1632
1633 int blocksize = 8;
1634 // const int fullblocks = nspectra / blocksize;
1635 // size of the workspace
1636 // have to cast down to int as later functions require ints
1637 int fullblocks = static_cast<int>(total_specs) / blocksize;
1638 int read_stop = (fullblocks * blocksize);
1639 const double progressBegin = progressStart + 0.25 * progressRange;
1640 const double progressScaler = 0.75 * progressRange;
1641 int64_t hist_index = 0;
1642 int64_t wsIndex = 0;
1643 if (m_shared_bins) {
1644 // if spectrum min,max,list properties are set
1645 if (m_interval || m_list) {
1646 // if spectrum max,min properties are set read the data as a
1647 // block(multiple of 8) and
1648 // then read the remaining data as finalblock
1649 if (m_interval) {
1650 // specs at the min-max interval
1651 int interval_specs = m_spec_max - m_spec_min;
1652 fullblocks = (interval_specs) / blocksize;
1653 read_stop = (fullblocks * blocksize) + m_spec_min - 1;
1654
1655 if (interval_specs < blocksize) {
1656 blocksize = static_cast<int>(total_specs);
1657 read_stop = m_spec_max - 1;
1658 }
1659 hist_index = m_spec_min - 1;
1660
1661 for (; hist_index < read_stop;) {
1662 progress(progressBegin + progressScaler * static_cast<double>(hist_index) / static_cast<double>(read_stop),
1663 "Reading workspace data...");
1664 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, blocksize, nchannels, hist_index, wsIndex,
1665 local_workspace);
1666 }
1667 size_t finalblock = m_spec_max - 1 - read_stop;
1668 if (finalblock > 0) {
1669 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, finalblock, nchannels, hist_index,
1670 wsIndex, local_workspace);
1671 }
1672 }
1673 // if spectrum list property is set read each spectrum separately by
1674 // setting blocksize=1
1675 if (m_list) {
1676 for (const auto itr : m_spec_list) {
1677 int64_t specIndex = itr - 1;
1678 progress(progressBegin +
1679 progressScaler * static_cast<double>(specIndex) / static_cast<double>(m_spec_list.size()),
1680 "Reading workspace data...");
1681 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, 1, nchannels, specIndex, wsIndex,
1682 local_workspace);
1683 }
1684 }
1685 } else {
1686 for (; hist_index < read_stop;) {
1687 progress(progressBegin + progressScaler * static_cast<double>(hist_index) / static_cast<double>(read_stop),
1688 "Reading workspace data...");
1689 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, blocksize, nchannels, hist_index, wsIndex,
1690 local_workspace);
1691 }
1692 size_t finalblock = total_specs - read_stop;
1693 if (finalblock > 0) {
1694 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, finalblock, nchannels, hist_index, wsIndex,
1695 local_workspace);
1696 }
1697 }
1698
1699 } else {
1700 if (m_interval || m_list) {
1701 if (m_interval) {
1702 int interval_specs = m_spec_max - m_spec_min;
1703 fullblocks = (interval_specs) / blocksize;
1704 read_stop = (fullblocks * blocksize) + m_spec_min - 1;
1705
1706 if (interval_specs < blocksize) {
1707 blocksize = interval_specs;
1708 read_stop = m_spec_max - 1;
1709 }
1710 hist_index = m_spec_min - 1;
1711
1712 for (; hist_index < read_stop;) {
1713 progress(progressBegin + progressScaler * static_cast<double>(hist_index) / static_cast<double>(read_stop),
1714 "Reading workspace data...");
1715 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, xbins, blocksize, nchannels, hist_index,
1716 wsIndex, local_workspace);
1717 }
1718 size_t finalblock = m_spec_max - 1 - read_stop;
1719 if (finalblock > 0) {
1720 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, xbins, finalblock, nchannels, hist_index,
1721 wsIndex, local_workspace);
1722 }
1723 }
1724 //
1725 if (m_list) {
1726 for (const auto itr : m_spec_list) {
1727 int64_t specIndex = itr - 1;
1728 progress(progressBegin + progressScaler * static_cast<double>(specIndex) / static_cast<double>(read_stop),
1729 "Reading workspace data...");
1730 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, xbins, 1, nchannels, specIndex, wsIndex,
1731 local_workspace);
1732 }
1733 }
1734 } else {
1735 for (; hist_index < read_stop;) {
1736 progress(progressBegin + progressScaler * static_cast<double>(hist_index) / static_cast<double>(read_stop),
1737 "Reading workspace data...");
1738 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, xbins, blocksize, nchannels, hist_index,
1739 wsIndex, local_workspace);
1740 }
1741 size_t finalblock = total_specs - read_stop;
1742 if (finalblock > 0) {
1743 loadBlock(data, errors, fracarea, hasFracArea, xErrors, hasXErrors, xbins, finalblock, nchannels, hist_index,
1744 wsIndex, local_workspace);
1745 }
1746 }
1747
1748 // now check for NaN at end of X which would signify ragged binning
1749 for (size_t i = 0; i < local_workspace->getNumberHistograms(); i++) {
1750 const auto &x = local_workspace->readX(i);
1751 const auto idx =
1752 std::distance(x.rbegin(), std::find_if_not(x.rbegin(), x.rend(), [](auto val) { return std::isnan(val); }));
1753 if (idx > 0)
1754 local_workspace->resizeHistogram(i, local_workspace->histogramSize(i) - idx);
1755 }
1756 }
1757 return local_workspace;
1758}
1759
1760//-------------------------------------------------------------------------------------------------
1773API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot &root, const std::string &entry_name,
1774 const double &progressStart, const double &progressRange) {
1775 progress(progressStart, "Opening entry " + entry_name + "...");
1776
1777 NXEntry mtd_entry = root.openEntry(entry_name);
1778
1779 if (mtd_entry.containsGroup("table_workspace")) {
1780 return loadTableEntry(mtd_entry);
1781 }
1782
1783 if (mtd_entry.containsGroup("peaks_workspace")) {
1784 try {
1785 // try standard PeakWorkspace first
1786 return loadPeaksEntry(mtd_entry);
1787 } catch (std::exception &) {
1788 return loadLeanElasticPeaksEntry(mtd_entry);
1789 }
1790 }
1791
1792 // Determine workspace type and name of group containing workspace
1793 // characteristics
1794 bool isEvent = false;
1795 std::string workspaceType = "Workspace2D";
1796 std::string group_name = "workspace";
1797 if (mtd_entry.containsGroup("event_workspace")) {
1798 isEvent = true;
1799 group_name = "event_workspace";
1800 } else if (mtd_entry.containsGroup("offsets_workspace")) {
1801 workspaceType = "OffsetsWorkspace";
1802 group_name = "offsets_workspace";
1803 } else if (mtd_entry.containsGroup("mask_workspace")) {
1804 workspaceType = "MaskWorkspace";
1805 group_name = "mask_workspace";
1806 } else if (mtd_entry.containsGroup("grouping_workspace")) {
1807 workspaceType = "GroupingWorkspace";
1808 group_name = "grouping_workspace";
1809 }
1810
1811 // Get workspace characteristics
1812 NXData wksp_cls = mtd_entry.openNXData(group_name);
1813
1814 // Axis information
1815 // "X" axis
1816
1817 NXDouble xbins = wksp_cls.openNXDouble("axis1");
1818 xbins.load();
1819 std::string unit1 = xbins.attributes("units");
1820 // Non-uniform x bins get saved as a 2D 'axis1' dataset
1821 int64_t xlength(-1);
1822 if (xbins.rank() == 2) {
1823 xlength = xbins.dim1();
1824 m_shared_bins = false;
1825 } else if (xbins.rank() == 1) {
1826 xlength = xbins.dim0();
1827 m_shared_bins = true;
1828 xbins.load();
1829 m_xbins = HistogramData::HistogramX(xbins(), xbins() + xlength);
1830 } else {
1831 throw std::runtime_error("Unknown axis1 dimension encountered.");
1832 }
1833
1834 // MatrixWorkspace axis 1
1835 NXDouble axis2 = wksp_cls.openNXDouble("axis2");
1836 std::string unit2 = axis2.attributes("units");
1837
1838 // --- Load workspace (as event_workspace or workspace2d) ---
1839 API::MatrixWorkspace_sptr local_workspace;
1840 if (isEvent) {
1841 local_workspace = loadEventEntry(wksp_cls, xbins, progressStart, progressRange);
1842 } else {
1843 local_workspace =
1844 loadNonEventEntry(wksp_cls, xbins, progressStart, progressRange, mtd_entry, xlength, workspaceType);
1845 }
1846 size_t nspectra = local_workspace->getNumberHistograms();
1847
1848 // Units
1849 bool verticalHistogram(false);
1850 try {
1851 local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create(unit1);
1852 if (unit1 == "Label") {
1853 auto label = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(local_workspace->getAxis(0)->unit());
1854 auto ax = wksp_cls.openNXDouble("axis1");
1855 label->setLabel(ax.attributes("caption"), ax.attributes("label"));
1856 }
1857
1858 // If this doesn't throw then it is a numeric access so grab the data so
1859 // we
1860 // can set it later
1861 axis2.load();
1862 if (static_cast<size_t>(axis2.size()) == nspectra + 1)
1863 verticalHistogram = true;
1864 m_axis1vals = MantidVec(axis2(), axis2() + axis2.dim0());
1865 } catch (std::runtime_error &) {
1866 g_log.information() << "Axis 0 set to unitless quantity \"" << unit1 << "\"\n";
1867 }
1868
1869 // Setting a unit onto a TextAxis makes no sense.
1870 if (unit2 == "TextAxis") {
1871 auto newAxis = std::make_unique<Mantid::API::TextAxis>(nspectra);
1872 local_workspace->replaceAxis(1, std::move(newAxis));
1873 } else if (unit2 != "spectraNumber") {
1874 try {
1875 auto newAxis = (verticalHistogram) ? std::make_unique<API::BinEdgeAxis>(nspectra + 1)
1876 : std::make_unique<API::NumericAxis>(nspectra);
1877 auto newAxisRaw = newAxis.get();
1878 local_workspace->replaceAxis(1, std::move(newAxis));
1879 newAxisRaw->unit() = UnitFactory::Instance().create(unit2);
1880 if (unit2 == "Label") {
1881 auto label = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(newAxisRaw->unit());
1882 auto ax = wksp_cls.openNXDouble("axis2");
1883 label->setLabel(ax.attributes("caption"), ax.attributes("label"));
1884 }
1885 } catch (std::runtime_error &) {
1886 g_log.information() << "Axis 1 set to unitless quantity \"" << unit2 << "\"\n";
1887 }
1888 }
1889
1890 // Are we a distribution
1891 std::string dist = xbins.attributes("distribution");
1892 if (dist == "1") {
1893 local_workspace->setDistribution(true);
1894 } else {
1895 local_workspace->setDistribution(false);
1896 }
1897
1898 progress(progressStart + 0.05 * progressRange, "Reading the sample details...");
1899
1900 // Hop to the right point
1901 m_nexusFile->openAddress(mtd_entry.address());
1902 try {
1903 // Get information from all but data group
1904 std::string parameterStr;
1905
1906 // This loads logs, sample, and instrument.
1907 local_workspace->loadExperimentInfoNexus(getPropertyValue("Filename"), m_nexusFile.get(),
1908 parameterStr); // REQUIRED PER PERIOD
1909
1910 // Parameter map parsing only if instrument loaded OK.
1911 progress(progressStart + 0.11 * progressRange, "Reading the parameter maps...");
1912 local_workspace->readParameterMap(parameterStr);
1913 } catch (std::exception &e) {
1914 // For workspaces saved via SaveNexusESS, these warnings are not
1915 // relevant. Such workspaces will contain an `NXinstrument` entry
1916 // with the name of the instrument.
1917 const auto &entries = getFileInfo()->getAllEntries();
1918 if (version() < 2 || entries.find("NXinstrument") == entries.end()) {
1919 g_log.warning("Error loading Instrument section of nxs file");
1920 g_log.warning(e.what());
1921 g_log.warning("Try running LoadInstrument Algorithm on the Workspace to "
1922 "update the geometry");
1923 }
1924 }
1925
1926 readSpectraToDetectorMapping(mtd_entry, *local_workspace);
1927
1928 if (!local_workspace->getAxis(1)->isSpectra()) { // If not a spectra axis, load the axis data into
1929 // the workspace. (MW 25/11/10)
1930 loadNonSpectraAxis(local_workspace, wksp_cls);
1931 }
1932
1933 progress(progressStart + 0.15 * progressRange, "Reading the workspace history...");
1934 m_nexusFile->openAddress(mtd_entry.address());
1935 try {
1936 bool load_history = getProperty("LoadHistory");
1937 if (load_history)
1938 local_workspace->history().loadNexus(m_nexusFile.get());
1939 } catch (std::out_of_range &) {
1940 g_log.warning() << "Error in the workspaces algorithm list, its processing "
1941 "history is incomplete\n";
1942 }
1943
1944 progress(progressStart + 0.2 * progressRange, "Reading the workspace history...");
1945
1946 try {
1947 if (local_workspace->getTitle().empty())
1948 local_workspace->setTitle(mtd_entry.getString("title"));
1949 } catch (std::runtime_error &) {
1950 g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << '\n';
1951 }
1952
1953 return std::static_pointer_cast<API::Workspace>(local_workspace);
1954}
1955
1956//-------------------------------------------------------------------------------------------------
1963 // Get spectrum information for the current entry.
1964
1965 SpectraInfo spectraInfo = extractMappingInfo(mtd_entry, this->g_log);
1966
1967 // Now build the spectra list
1968 int index = 0;
1969 bool haveSpectraAxis = local_workspace.getAxis(1)->isSpectra();
1970
1971 for (int i = 1; i <= spectraInfo.nSpectra; ++i) {
1972 int spectrum;
1973 // prefer the spectra number from the instrument section
1974 // over anything else. If not there then use a spectra axis
1975 // number if we have one, else make one up as nothing was
1976 // written to the file. We should always set it so that
1977 // CompareWorkspaces gives the expected answer on a Save/Load
1978 // round trip.
1979 if (spectraInfo.hasSpectra) {
1980 spectrum = spectraInfo.spectraNumbers[i - 1];
1981 } else if (haveSpectraAxis && !m_axis1vals.empty()) {
1982 spectrum = static_cast<specnum_t>(m_axis1vals[i - 1]);
1983 } else {
1984 spectrum = i + 1;
1985 }
1986
1987 if ((i >= m_spec_min && i < m_spec_max) ||
1988 (m_list && find(m_spec_list.begin(), m_spec_list.end(), i) != m_spec_list.end())) {
1989 auto &spec = local_workspace.getSpectrum(index);
1990 spec.setSpectrumNo(spectrum);
1991 ++index;
1992
1993 if (!spectraInfo.detectorIndex.empty()) {
1994 const int start = spectraInfo.detectorIndex[i - 1];
1995 const int end = start + spectraInfo.detectorCount[i - 1];
1996 spec.setDetectorIDs(
1997 std::set<detid_t>(spectraInfo.detectorList.data() + start, spectraInfo.detectorList.data() + end));
1998 }
1999 }
2000 }
2001}
2002
2007std::map<std::string, std::string> LoadNexusProcessed::validateInputs() {
2008 using namespace std;
2009 map<string, string> errorList;
2010
2011 int specMin = getProperty("SpectrumMin");
2012 int specMax = getProperty("SpectrumMax");
2013
2014 // Check our range is not reversed
2015 if (specMax < specMin) {
2016 errorList["SpectrumMin"] = "SpectrumMin must be smaller than SpectrumMax";
2017 errorList["SpectrumMax"] = "SpectrumMax must be larger than SpectrumMin";
2018 }
2019
2020 // Finished testing return any errors
2021 return errorList;
2022}
2023
2024//-------------------------------------------------------------------------------------------------
2034 Axis *axis = local_workspace->getAxis(1);
2035
2036 if (axis->isNumeric()) {
2037 NXDouble axisData = data.openNXDouble("axis2");
2038 axisData.load();
2039 for (int i = 0; i < static_cast<int>(axis->length()); i++) {
2040 axis->setValue(i, axisData[i]);
2041 }
2042 } else if (axis->isText()) {
2043 NXChar axisData = data.openNXChar("axis2");
2044 std::string axisLabels;
2045 try {
2046 axisData.load();
2047 axisLabels = std::string(axisData(), axisData.dim0());
2048 } catch (std::runtime_error &) {
2049 axisLabels = "";
2050 }
2051 // Use boost::tokenizer to split up the input
2053 // We must cast the axis object to TextAxis so we may use ->setLabel
2054 auto *textAxis = static_cast<TextAxis *>(axis);
2055 int i = 0;
2056 for (const auto &tokIter : tokenizer) {
2057 textAxis->setLabel(i, tokIter);
2058 i++;
2059 }
2060 }
2061}
2062
2069bool UDlesserExecCount(const NXClassInfo &elem1, const NXClassInfo &elem2) {
2070 std::string::size_type index1, index2;
2071 std::string num1, num2;
2072 // find the number after "_" in algorithm name ( eg:MantidAlogorthm_1)
2073 index1 = elem1.nxname.find('_');
2074 if (index1 != std::string::npos) {
2075 num1 = elem1.nxname.substr(index1 + 1, elem1.nxname.length() - index1);
2076 }
2077 index2 = elem2.nxname.find('_');
2078 if (index2 != std::string::npos) {
2079 num2 = elem2.nxname.substr(index2 + 1, elem2.nxname.length() - index2);
2080 }
2081 std::stringstream is1, is2;
2082 is1 << num1;
2083 is2 << num2;
2084
2085 int execNum1 = -1;
2086 int execNum2 = -1;
2087 is1 >> execNum1;
2088 is2 >> execNum2;
2089
2090 return execNum1 < execNum2;
2091}
2092
2093//-------------------------------------------------------------------------------------------------
2103void LoadNexusProcessed::getWordsInString(const std::string &words3, std::string &w1, std::string &w2,
2104 std::string &w3) {
2106 if (data.count() != 3) {
2107 g_log.warning() << "Algorithm list line " + words3 + " is not of the correct format\n";
2108 throw std::out_of_range(words3);
2109 }
2110
2111 w1 = data[0];
2112 w2 = data[1];
2113 w3 = data[2];
2114}
2115
2116//-------------------------------------------------------------------------------------------------
2127void LoadNexusProcessed::getWordsInString(const std::string &words4, std::string &w1, std::string &w2, std::string &w3,
2128 std::string &w4) {
2130 if (data.count() != 4) {
2131 g_log.warning() << "Algorithm list line " + words4 + " is not of the correct format\n";
2132 throw std::out_of_range(words4);
2133 }
2134
2135 w1 = data[0];
2136 w2 = data[1];
2137 w3 = data[2];
2138 w4 = data[3];
2139}
2140
2141//-------------------------------------------------------------------------------------------------
2148void LoadNexusProcessed::readBinMasking(const NXData &wksp_cls, const API::MatrixWorkspace_sptr &local_workspace) {
2149 if (!wksp_cls.getDataSetInfo("masked_spectra").allGood) {
2150 return;
2151 }
2152 NXInt spec = wksp_cls.openNXInt("masked_spectra");
2153 spec.load();
2154 NXUInt64 bins = wksp_cls.openNXSize("masked_bins");
2155 bins.load();
2156 NXDouble weights = wksp_cls.openNXDouble("mask_weights");
2157 weights.load();
2158 const int64_t n = spec.dim0();
2159 const int64_t n1 = n - 1;
2160 for (int i = 0; i < n; ++i) {
2161 int64_t si = spec(i, 0);
2162 int64_t j0 = spec(i, 1);
2163 int64_t j1 = i < n1 ? spec(i + 1, 1) : bins.dim0();
2164 for (int64_t j = j0; j < j1; ++j) {
2165 local_workspace->flagMasked(si, bins[j], weights[j]);
2166 }
2167 }
2168}
2169
2186void LoadNexusProcessed::loadBlock(NXDouble &data, NXDouble &errors, NXDouble &farea, bool hasFArea, NXDouble &xErrors,
2187 bool hasXErrors, int64_t blocksize, int64_t nchannels, int64_t &hist,
2188 const API::MatrixWorkspace_sptr &local_workspace) {
2189 data.load(blocksize, hist);
2190 errors.load(blocksize, hist);
2191 double *data_start = data();
2192 double *data_end = data_start + nchannels;
2193 double *err_start = errors();
2194 double *err_end = err_start + nchannels;
2195 double *farea_start = nullptr;
2196 double *farea_end = nullptr;
2197 double *xErrors_start = nullptr;
2198 double *xErrors_end = nullptr;
2199 size_t dx_increment = nchannels;
2200 // NexusFileIO stores Dx data for all spectra (sharing not preserved) so dim0
2201 // is the histograms, dim1 is Dx length. For old files this is nchannels+1,
2202 // otherwise nchannels. See #16298.
2203 // WARNING: We are dropping the last Dx value for old files!
2204 size_t dx_input_increment = xErrors.dim1();
2205 RebinnedOutput_sptr rb_workspace;
2206 if (hasFArea) {
2207 farea.load(blocksize, hist);
2208 farea_start = farea();
2209 farea_end = farea_start + nchannels;
2210 rb_workspace = std::dynamic_pointer_cast<RebinnedOutput>(local_workspace);
2211 }
2212 if (hasXErrors) {
2213 xErrors.load(blocksize, hist);
2214 xErrors_start = xErrors();
2215 xErrors_end = xErrors_start + dx_increment;
2216 }
2217
2218 int64_t final(hist + blocksize);
2219 while (hist < final) {
2220 auto &Y = local_workspace->mutableY(hist);
2221 Y.assign(data_start, data_end);
2222 data_start += nchannels;
2223 data_end += nchannels;
2224 auto &E = local_workspace->mutableE(hist);
2225 E.assign(err_start, err_end);
2226 err_start += nchannels;
2227 err_end += nchannels;
2228 if (hasFArea) {
2229 MantidVec &F = rb_workspace->dataF(hist);
2230 F.assign(farea_start, farea_end);
2231 farea_start += nchannels;
2232 farea_end += nchannels;
2233 }
2234 if (hasXErrors) {
2235 local_workspace->setSharedDx(hist, Kernel::make_cow<HistogramData::HistogramDx>(xErrors_start, xErrors_end));
2236 xErrors_start += dx_input_increment;
2237 xErrors_end += dx_input_increment;
2238 }
2239
2240 local_workspace->setSharedX(hist, m_xbins.cowData());
2241 ++hist;
2242 }
2243}
2244
2263void LoadNexusProcessed::loadBlock(NXDouble &data, NXDouble &errors, NXDouble &farea, bool hasFArea, NXDouble &xErrors,
2264 bool hasXErrors, int64_t blocksize, int64_t nchannels, int64_t &hist,
2265 int64_t &wsIndex, const API::MatrixWorkspace_sptr &local_workspace) {
2266 data.load(blocksize, hist);
2267 errors.load(blocksize, hist);
2268 double *data_start = data();
2269 double *data_end = data_start + nchannels;
2270 double *err_start = errors();
2271 double *err_end = err_start + nchannels;
2272 double *farea_start = nullptr;
2273 double *farea_end = nullptr;
2274 double *xErrors_start = nullptr;
2275 double *xErrors_end = nullptr;
2276 size_t dx_increment = nchannels;
2277 // NexusFileIO stores Dx data for all spectra (sharing not preserved) so dim0
2278 // is the histograms, dim1 is Dx length. For old files this is nchannels+1,
2279 // otherwise nchannels. See #16298.
2280 // WARNING: We are dropping the last Dx value for old files!
2281 size_t dx_input_increment = xErrors.dim1();
2282 RebinnedOutput_sptr rb_workspace;
2283 if (hasFArea) {
2284 farea.load(blocksize, hist);
2285 farea_start = farea();
2286 farea_end = farea_start + nchannels;
2287 rb_workspace = std::dynamic_pointer_cast<RebinnedOutput>(local_workspace);
2288 }
2289 if (hasXErrors) {
2290 xErrors.load(blocksize, hist);
2291 xErrors_start = xErrors();
2292 xErrors_end = xErrors_start + dx_increment;
2293 }
2294
2295 int64_t final(hist + blocksize);
2296 while (hist < final) {
2297 auto &Y = local_workspace->mutableY(wsIndex);
2298 Y.assign(data_start, data_end);
2299 data_start += nchannels;
2300 data_end += nchannels;
2301 auto &E = local_workspace->mutableE(wsIndex);
2302 E.assign(err_start, err_end);
2303 err_start += nchannels;
2304 err_end += nchannels;
2305 if (hasFArea) {
2306 MantidVec &F = rb_workspace->dataF(wsIndex);
2307 F.assign(farea_start, farea_end);
2308 farea_start += nchannels;
2309 farea_end += nchannels;
2310 }
2311 if (hasXErrors) {
2312 local_workspace->setSharedDx(wsIndex, Kernel::make_cow<HistogramData::HistogramDx>(xErrors_start, xErrors_end));
2313 xErrors_start += dx_input_increment;
2314 xErrors_end += dx_input_increment;
2315 }
2316 local_workspace->setSharedX(wsIndex, m_xbins.cowData());
2317 ++hist;
2318 ++wsIndex;
2319 }
2320}
2321
2340void LoadNexusProcessed::loadBlock(NXDouble &data, NXDouble &errors, NXDouble &farea, bool hasFArea, NXDouble &xErrors,
2341 bool hasXErrors, NXDouble &xbins, int64_t blocksize, int64_t nchannels,
2342 int64_t &hist, int64_t &wsIndex, const API::MatrixWorkspace_sptr &local_workspace) {
2343 data.load(blocksize, hist);
2344 double *data_start = data();
2345 double *data_end = data_start + nchannels;
2346 errors.load(blocksize, hist);
2347 double *err_start = errors();
2348 double *err_end = err_start + nchannels;
2349 double *farea_start = nullptr;
2350 double *farea_end = nullptr;
2351 double *xErrors_start = nullptr;
2352 double *xErrors_end = nullptr;
2353 size_t dx_increment = nchannels;
2354 // NexusFileIO stores Dx data for all spectra (sharing not preserved) so dim0
2355 // is the histograms, dim1 is Dx length. For old files this is nchannels+1,
2356 // otherwise nchannels. See #16298.
2357 // WARNING: We are dropping the last Dx value for old files!
2358 size_t dx_input_increment = xErrors.dim1();
2359 RebinnedOutput_sptr rb_workspace;
2360 if (hasFArea) {
2361 farea.load(blocksize, hist);
2362 farea_start = farea();
2363 farea_end = farea_start + nchannels;
2364 rb_workspace = std::dynamic_pointer_cast<RebinnedOutput>(local_workspace);
2365 }
2366 xbins.load(blocksize, hist);
2367 const int64_t nxbins(xbins.dim1());
2368 double *xbin_start = xbins();
2369 double *xbin_end = xbin_start + nxbins;
2370 int64_t final(hist + blocksize);
2371
2372 if (hasXErrors) {
2373 xErrors.load(blocksize, hist);
2374 xErrors_start = xErrors();
2375 xErrors_end = xErrors_start + dx_increment;
2376 }
2377
2378 while (hist < final) {
2379 auto &Y = local_workspace->mutableY(wsIndex);
2380 Y.assign(data_start, data_end);
2381 data_start += nchannels;
2382 data_end += nchannels;
2383 auto &E = local_workspace->mutableE(wsIndex);
2384 E.assign(err_start, err_end);
2385 err_start += nchannels;
2386 err_end += nchannels;
2387 if (hasFArea) {
2388 MantidVec &F = rb_workspace->dataF(wsIndex);
2389 F.assign(farea_start, farea_end);
2390 farea_start += nchannels;
2391 farea_end += nchannels;
2392 }
2393 if (hasXErrors) {
2394 local_workspace->setSharedDx(wsIndex, Kernel::make_cow<HistogramData::HistogramDx>(xErrors_start, xErrors_end));
2395 xErrors_start += dx_input_increment;
2396 xErrors_end += dx_input_increment;
2397 }
2398 auto &X = local_workspace->mutableX(wsIndex);
2399 X.assign(xbin_start, xbin_end);
2400 xbin_start += nxbins;
2401 xbin_end += nxbins;
2402 ++hist;
2403 ++wsIndex;
2404 }
2405}
2406
2411void LoadNexusProcessed::checkOptionalProperties(const std::size_t numberofspectra) {
2412 // read in the settings passed to the algorithm
2413 m_spec_list = getProperty("SpectrumList");
2414 m_spec_max = getProperty("SpectrumMax");
2415 m_spec_min = getProperty("SpectrumMin");
2416 // Are we using a list of spectra or all the spectra in a range?
2417 m_list = !m_spec_list.empty();
2420 m_spec_max = 1;
2421
2422 // Check validity of spectra list property, if set
2423 if (m_list) {
2424 const int minlist = *min_element(m_spec_list.begin(), m_spec_list.end());
2425 const int maxlist = *max_element(m_spec_list.begin(), m_spec_list.end());
2426 // Need to check before casting
2427 if (maxlist < 0) {
2428 g_log.error("Invalid list of spectra");
2429 throw std::invalid_argument("Spectra max is less than 0");
2430 }
2431
2432 if (maxlist > static_cast<int>(numberofspectra) || minlist == 0) {
2433 g_log.error("Invalid list of spectra");
2434 throw std::invalid_argument("Inconsistent properties defined");
2435 }
2436 }
2437
2438 // Check validity of spectra range, if set
2439 if (m_interval) {
2440 m_interval = true;
2441 m_spec_min = getProperty("SpectrumMin");
2442 if (m_spec_min != 1 && m_spec_max == 1) {
2443 m_spec_max = static_cast<int>(numberofspectra);
2444 }
2445 if (m_spec_max < m_spec_min || m_spec_max > static_cast<int>(numberofspectra)) {
2446 g_log.error("Invalid Spectrum min/max properties");
2447 throw std::invalid_argument("Inconsistent properties defined");
2448 }
2449 }
2450}
2451
2465size_t LoadNexusProcessed::calculateWorkspaceSize(const std::size_t numberofspectra, bool gen_filtered_list) {
2466 // Calculate the size of a workspace, given its number of spectra to read
2467 size_t total_specs;
2468 if (m_interval || m_list) {
2469 if (m_interval) {
2470 if (m_spec_min != 1 && m_spec_max == 1) {
2471 m_spec_max = static_cast<int>(numberofspectra);
2472 }
2473 total_specs = m_spec_max - m_spec_min + 1;
2474 m_spec_max += 1;
2475
2476 if (gen_filtered_list) {
2477 m_filtered_spec_idxs.resize(total_specs);
2478 size_t j = 0;
2479 for (int si = m_spec_min; si < m_spec_max; si++, j++)
2480 m_filtered_spec_idxs[j] = si;
2481 }
2482 } else {
2483 total_specs = 0;
2484 }
2485
2486 if (m_list) {
2487 if (m_interval) {
2488 for (auto it = m_spec_list.begin(); it != m_spec_list.end();)
2489 if (*it >= m_spec_min && *it < m_spec_max) {
2490 it = m_spec_list.erase(it);
2491 } else
2492 ++it;
2493 }
2494 if (m_spec_list.empty())
2495 m_list = false;
2496 total_specs += m_spec_list.size();
2497
2498 if (gen_filtered_list) {
2499 // range list + spare indices from list
2500 // example: min: 2, max: 8, list: 3,4,5,10,12;
2501 // result: 2,3,...,7,8,10,12
2503 }
2504 }
2505 } else {
2506 total_specs = numberofspectra;
2507 m_spec_min = 1;
2508 m_spec_max = static_cast<int>(numberofspectra) + 1;
2509
2510 if (gen_filtered_list) {
2511 m_filtered_spec_idxs.resize(total_specs, 0);
2512 for (int j = 0; j < static_cast<int>(total_specs); j++)
2514 }
2515 }
2516 return total_specs;
2517}
2518
2525 auto mWorkspace = std::dynamic_pointer_cast<MatrixWorkspace>(local_workspace);
2526 if (mWorkspace) {
2527 auto run = mWorkspace->run();
2528 // check for presence of filterable logs that suggest this is ISIS data
2530 ISISRunLogs::applyLogFiltering(mWorkspace->mutableRun());
2531 }
2532 }
2533}
2534
2535} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
int64_t nSpectra
bool hasSpectra
IntArray detectorCount
IntArray detectorIndex
IntArray detectorList
IntArray spectraNumbers
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Class to represent the axis of a workspace.
Definition Axis.h:30
virtual bool isText() const
Returns true if the axis is Text.
Definition Axis.h:54
virtual std::size_t length() const =0
Get the length of the axis.
virtual void setValue(const std::size_t &index, const double &value)=0
Sets the value at the specified index.
virtual bool isNumeric() const
Returns true if the axis is numeric.
Definition Axis.h:52
virtual bool isSpectra() const
Returns true is the axis is a Spectra axis.
Definition Axis.h:50
ColumnVector gives access to the column elements without alowing its resizing.
@ Load
allowed here which will be passed to the algorithm
static void applyLogFiltering(Mantid::API::Run &exptRun)
applies log filtering for a run
void setHistogram(T &&...data)
Sets the Histogram associated with this spectrum.
Definition ISpectrum.h:96
void clearDetectorIDs()
Clear the detector IDs set.
void setSpectrumNo(specnum_t num)
Sets the spectrum number of this spectrum.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
Base MatrixWorkspace Abstract Class.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
virtual Axis * getAxis(const std::size_t &axisIndex) const
Get a non owning pointer to a workspace axis.
virtual const std::shared_ptr< Mantid::Nexus::NexusDescriptor > getFileInfo() const noexcept
Required to pass m_fileInfo to static functions Keeping it shared_ptr to match setFileInfo signature ...
Helper class for reporting progress from algorithms.
Definition Progress.h:25
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
Class to represent a text axis of a workspace.
Definition TextAxis.h:36
void setLabel(const std::size_t &index, const std::string &lbl)
Set the label at the given index.
Definition TextAxis.cpp:114
A property class for workspaces.
API::Workspace_sptr loadTableEntry(const Mantid::Nexus::NXEntry &entry)
Load a table.
int m_spec_min
The value of the spectrum_min property.
Mantid::API::Workspace_sptr doAccelleratedMultiPeriodLoading(Mantid::Nexus::NXRoot &root, const std::string &entryName, Mantid::API::MatrixWorkspace_sptr &tempMatrixWorkspace, const size_t nWorkspaceEntries, const size_t p)
Accellerated multiperiod loading.
bool m_interval
Flag set if interval of spectra to write is set.
API::Workspace_sptr loadPeaksEntry(const Mantid::Nexus::NXEntry &entry)
Load peaks.
~LoadNexusProcessed() override
Destructor.
HistogramData::BinEdges m_xbins
The cached x binning if we have bins.
API::Workspace_sptr loadEntry(Mantid::Nexus::NXRoot &root, const std::string &entry_name, const double &progressStart, const double &progressRange)
Load a single entry.
void checkOptionalProperties(const std::size_t numberofspectra)
Validates the optional 'spectra to read' properties, if they have been set.
void loadV3DColumn(Mantid::Nexus::NXDouble &data, const API::ITableWorkspace_sptr &tableWs)
Loads a V3D column to the TableWorkspace.
void correctForWorkspaceNameClash(std::string &wsName)
Add an index to the name if it already exists in the workspace.
virtual bool loadNexusGeometry(Mantid::API::Workspace &, size_t, Kernel::Logger &, const std::string &)
Load nexus geometry and apply to workspace.
void loadBlock(Mantid::Nexus::NXDouble &data, Mantid::Nexus::NXDouble &errors, Mantid::Nexus::NXDouble &farea, bool hasFArea, Mantid::Nexus::NXDouble &xErrors, bool hasXErrors, int64_t blocksize, int64_t nchannels, int64_t &hist, const API::MatrixWorkspace_sptr &local_workspace)
Load a block of data into the workspace where it is assumed that the x bins have already been cached.
void readInstrumentGroup(Mantid::Nexus::NXEntry &mtd_entry, API::MatrixWorkspace &local_workspace)
Read the spectra.
API::Workspace_sptr loadLeanElasticPeaksEntry(const Mantid::Nexus::NXEntry &entry)
Load LeanElasticPeakWorkspace.
int m_spec_max
The value of the spectrum_max property.
int confidence(Nexus::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
bool m_list
Flag set if list of spectra to save is specifed.
void getWordsInString(const std::string &words3, std::string &w1, std::string &w2, std::string &w3)
Splits a string of exactly three words into the separate words.
std::vector< int > m_filtered_spec_idxs
list of spectra filtered by min/max/list, currently used only when loading data into event_workspace
bool m_shared_bins
Does the current workspace have uniform binning.
std::string loadWorkspaceName(Mantid::Nexus::NXRoot &root, const std::string &entry_name)
Load the workspace name attribute if it exists.
std::vector< int > m_spec_list
The value of the spectrum_list property.
void loadNumericColumn(const Mantid::Nexus::NXData &tableData, const std::string &dataSetName, const API::ITableWorkspace_sptr &tableWs, const std::string &columnType)
Load a numeric column to the TableWorkspace.
API::MatrixWorkspace_sptr loadEventEntry(Mantid::Nexus::NXData &wksp_cls, Mantid::Nexus::NXDouble &xbins, const double &progressStart, const double &progressRange)
Load an event_workspace field.
std::map< std::string, std::string > validateInputs() override
Validates the input Min < Max and Max < Maximum_Int.
std::string buildWorkspaceName(const std::string &name, const std::string &baseName, size_t wsIndex)
Create the workspace name if it's part of a group workspace.
void loadVectorColumn(const Mantid::Nexus::NXData &tableData, const std::string &dataSetName, const API::ITableWorkspace_sptr &tableWs, const std::string &columnType)
Loads a vector column to the TableWorkspace.
void init() override
Overwrites Algorithm method.
MantidVec m_axis1vals
Numeric values for the second axis, if applicable.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
int version() const override
Algorithm's version for identification overriding a virtual method.
void loadNonSpectraAxis(const API::MatrixWorkspace_sptr &local_workspace, const Mantid::Nexus::NXData &data)
Load the data from a non-spectra axis (Numeric/Text) into the workspace.
std::size_t calculateWorkspaceSize(const std::size_t numberofspectra, bool gen_filtered_list=false)
calculates the workspace size
virtual void readSpectraToDetectorMapping(Mantid::Nexus::NXEntry &mtd_entry, Mantid::API::MatrixWorkspace &ws)
std::unique_ptr< Nexus::File > m_nexusFile
void execLoader() override
Overwrites Algorithm method.
API::MatrixWorkspace_sptr loadNonEventEntry(Mantid::Nexus::NXData &wksp_cls, Mantid::Nexus::NXDouble &xbins, const double &progressStart, const double &progressRange, const Mantid::Nexus::NXEntry &mtd_entry, const int64_t xlength, std::string &workspaceType)
Load a Workspace2D.
void readBinMasking(const Mantid::Nexus::NXData &wksp_cls, const API::MatrixWorkspace_sptr &local_workspace)
Read the bin masking information.
void applyLogFiltering(const Mantid::API::Workspace_sptr &local_workspace)
applies log filtering of the loaded logs if required
std::vector< std::string > extractWorkspaceNames(Mantid::Nexus::NXRoot &root, size_t nWorkspaceEntries)
Extract the workspace name.
void setRunNumber(int m_runNumber) override
Set the run number that measured this peak.
Definition BasePeak.cpp:81
void setGoniometerMatrix(const Mantid::Kernel::Matrix< double > &goniometerMatrix) override
Set the goniometer rotation matrix at which this peak was measured.
Definition BasePeak.cpp:219
A class for holding :
Definition EventList.h:57
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
void addEventQuickly(const Types::Event::TofEvent &event)
Append an event to the histogram, without clearing the cache, to make it faster.
Definition EventList.h:105
Structure describing a single-crystal peak.
Structure describing a single-crystal peak.
Definition Peak.h:34
void setInstrument(const Geometry::Instrument_const_sptr &inst)
Set the instrument (and save the source/sample pos).
Definition Peak.cpp:294
Info about a single neutron detection event, including a weight and error value, but excluding the pu...
Definition Events.h:91
Info about a single neutron detection event, including a weight and error value:
Definition Events.h:39
PeakShape : Abstract type to describes the shape of a peak.
Definition PeakShape.h:20
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
static const std::string statusLogName()
Returns the name of the log created that defines the status during a run.
Definition LogParser.h:47
static const std::string periodsLogName()
Returns the name of the log that contains all of the periods.
Definition LogParser.h:51
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
Numerical Matrix class.
Definition Matrix.h:42
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
virtual bool isDefault() const =0
Overriden function that returns if property has the same value that it was initialised with,...
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
std::size_t count() const
Get the total number of tokens.
Class for 3D vectors.
Definition V3D.h:34
constexpr double norm2() const noexcept
Vector length squared.
Definition V3D.h:271
Class that provides for a standard Nexus exception.
std::string getString(const std::string &name) const
Returns a string.
bool containsGroup(const std::string &query) const
Returns whether an individual group (or group) is present.
bool openLocal(const std::string &nxclass="")
Opens this NXClass using File::openGroup().
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
std::vector< NXClassInfo > & groups() const
Returns a list of all classes (or groups) in this NXClass.
NXClass openNXGroup(const std::string &name) const
Creates and opens an arbitrary (non-standard) class (group).
void close()
Close this class.
NXChar openNXChar(const std::string &name) const
Creates and opens a char dataset.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
NXUInt64 openNXSize(const std::string &name) const
Creates and opens a size_t dataset.
NXDouble openNXDouble(const std::string &name) const
Creates and opens a double dataset.
NXInfo getDataSetInfo(const std::string &name) const
Returns NXInfo for a dataset.
NXDataSetTyped< T > openNXDataSet(const std::string &name) const
Templated method for creating datasets.
bool isValid(const std::string &address) const
Check if a address exists relative to the current class address.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
container_T< T > & vecBuffer()
Returns a the internal buffer.
std::size_t size() const
Returns the size of the data buffer.
dimsize_t dim0() const
Returns the number of elements along the first dimension.
void openLocal()
Opens datasets faster but the parent group must be already open.
NXAttributes attributes
Attributes.
std::size_t rank() const
Returns the rank (number of dimensions) of the data. The maximum is 4.
dimsize_t dim1() const
Returns the number of elements along the second dimension.
Implements NXdata Nexus class.
NXDouble openDoubleData()
Opens data of double type.
Implements NXdetector Nexus class.
Implements NXentry Nexus class.
NXData openNXData(const std::string &name) const
Opens a NXData.
NXInstrument openNXInstrument(const std::string &name) const
Opens a NXInstrument.
Implements NXinstrument Nexus class.
NXDetector openNXDetector(const std::string &name)
Opens a NXDetector.
NexusAddress const & address() const
Returns the absolute address to the object.
std::shared_ptr< File > m_fileID
Nexus file id.
Implements NXroot Nexus class.
NXEntry openEntry(const std::string &name)
Opens an entry – a topmost Nexus class.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
static unsigned short constexpr UINT64
static unsigned short constexpr INT64
static unsigned short constexpr UINT32
static unsigned short constexpr CHAR
static unsigned short constexpr UINT8
static unsigned short constexpr INT32
static unsigned short constexpr FLOAT32
static unsigned short constexpr FLOAT64
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
Mantid::Kernel::StringTokenizer tokenizer
EventType
What kind of event list is being stored.
Definition IEventList.h:18
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
bool UDlesserExecCount(const Mantid::Nexus::NXClassInfo &elem1, const Mantid::Nexus::NXClassInfo &elem2)
to sort the algorithmhistory vector
std::shared_ptr< RebinnedOutput > RebinnedOutput_sptr
shared pointer to the RebinnedOutput class
std::shared_ptr< PeakShapeFactory > PeakShapeFactory_sptr
Helper typedef.
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
SpecialCoordinateSystem
Special coordinate systems for Q3D.
Header for a base Nexus::Exception.
NXDataSetTyped< int64_t > NXInt64
The integer dataset type.
NXDataSetTyped< char > NXChar
The char dataset type.
NXDataSetTyped< uint64_t > NXUInt64
The integer dataset type.
Helper class which provides the Collimation Length for SANS instruments.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
Eigen::Array< IntT, static_cast< int >(ND), 1 > IntArray
Definition Types.h:27
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54
Information about a Nexus class.
std::string nxname
name of the object
Structure for keeping information about a Nexus data set, such as the dimensions and the type.
bool allGood
return status
std::size_t rank
number of dimensions of the data
NXDimArray dims
sizes along each dimension
NXnumtype type
type of the data, e.g. NX_CHAR, FLOAT32; see NexusFile_fwd.h