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