Mantid
Loading...
Searching...
No Matches
LoadMuonNexusV2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 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 +
8#include "MantidAPI/Axis.h"
11#include "MantidAPI/TableRow.h"
22#include "MantidKernel/Unit.h"
26
27#include <vector>
28
29namespace Mantid::DataHandling {
30
32
33using namespace Kernel;
34using namespace API;
35using namespace Nexus;
36using namespace HistogramData;
37using std::size_t;
38using namespace DataObjects;
39
40namespace NeXusEntry {
41const std::string RAWDATA{"/raw_data_1"};
42const std::string DEFINITION{"/raw_data_1/definition"};
43const std::string BEAMLINE{"/raw_data_1/beamline"};
44} // namespace NeXusEntry
45
48 : m_filename(), m_entrynumber(0), m_isFileMultiPeriod(false), m_multiPeriodsLoaded(false) {}
49
57 // Without this entry we cannot use LoadISISNexus
58 if (!descriptor.isEntry(NeXusEntry::RAWDATA, "NXentry")) {
59 return 0;
60 }
61
62 // Check if beamline entry exists beneath raw_data_1 - /raw_data_1/beamline
63 // Necessary to differentiate between ISIS and PSI nexus files.
64 if (!descriptor.isEntry(NeXusEntry::BEAMLINE))
65 return 0;
66
67 // Check if Muon source in definition entry
68 if (!descriptor.isEntry(NeXusEntry::DEFINITION))
69 return 0;
70
71 std::string def = descriptor.getStrData(NeXusEntry::DEFINITION);
72 if (def == "muonTD" || def == "pulsedTD") {
73 return 82; // have to return 82 to "beat" the LoadMuonNexus2 algorithm,
74 // which returns 81 for this file as well
75 } else {
76 return 0;
77 }
78}
81
82 std::vector<std::string> extensions{".nxs", ".nxs_v2", ".nxs_v1"};
83 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, extensions),
84 "The name of the Nexus file to load");
85
86 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
87 "The name of the workspace to be created as the output of the\n"
88 "algorithm. For multiperiod files, one workspace will be\n"
89 "generated for each period");
90
91 auto mustBePositiveSpectra = std::make_shared<BoundedValidator<specnum_t>>();
92 mustBePositiveSpectra->setLower(0);
93 declareProperty("SpectrumMin", static_cast<specnum_t>(0), mustBePositiveSpectra);
94 declareProperty("SpectrumMax", static_cast<specnum_t>(EMPTY_INT()), mustBePositiveSpectra);
95 declareProperty(std::make_unique<ArrayProperty<specnum_t>>("SpectrumList"));
96 auto mustBePositive = std::make_shared<BoundedValidator<int64_t>>();
97 mustBePositive->setLower(0);
98 declareProperty("EntryNumber", static_cast<int64_t>(0), mustBePositive,
99 "0 indicates that every entry is loaded, into a separate "
100 "workspace within a group. "
101 "A positive number identifies one entry to be loaded, into "
102 "one workspace");
103
104 std::vector<std::string> FieldOptions{"Transverse", "Longitudinal"};
105 declareProperty("MainFieldDirection", "Transverse", std::make_shared<StringListValidator>(FieldOptions),
106 "Output the main field direction if specified in Nexus file "
107 "(default longitudinal).",
109
110 declareProperty("TimeZero", 0.0, "Time zero in units of micro-seconds (default to 0.0)", Direction::Output);
111 declareProperty("FirstGoodData", 0.0, "First good data in units of micro-seconds (default to 0.0)",
113 declareProperty("LastGoodData", 0.0, "Last good data in the OutputWorkspace's spectra", Kernel::Direction::Output);
114
115 declareProperty(std::make_unique<ArrayProperty<double>>("TimeZeroList", Direction::Output),
116 "A vector of time zero values");
117
119 std::make_unique<WorkspaceProperty<Workspace>>("TimeZeroTable", "", Direction::Output, PropertyMode::Optional),
120 "TableWorkspace containing time zero values per spectra.");
121
122 declareProperty("CorrectTime", true, "Boolean flag controlling whether time should be corrected by timezero.",
124
126 std::make_unique<WorkspaceProperty<Workspace>>("DeadTimeTable", "", Direction::Output, PropertyMode::Optional),
127 "Table or a group of tables containing detector dead times.");
128
129 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("DetectorGroupingTable", "", Direction::Output,
131 "Table or a group of tables with information about the "
132 "detector grouping.");
133}
135 // prepare nexus entry
136 m_entrynumber = getProperty("EntryNumber");
137 m_filename = getPropertyValue("Filename");
138 NXRoot root(m_filename);
140 // Create MuonNexusV2 nexus loader
141 m_nexusLoader = std::make_unique<LoadMuonNexusV2NexusHelper>(entry);
143
144 // Execute child algorithm LoadISISNexus2
145 auto outWS = runLoadISISNexus();
146 // Create appropriate loading strategy
148 m_loadMuonStrategy->loadMuonLogData();
149 m_loadMuonStrategy->loadGoodFrames();
150 auto correctTime = getProperty("CorrectTime");
151 if (correctTime) {
152 m_loadMuonStrategy->applyTimeZeroCorrection();
153 }
154 // Grouping info should be returned if user has set the property
155 if (!getPropertyValue("DetectorGroupingTable").empty()) {
156 auto loadedGrouping = m_loadMuonStrategy->loadDetectorGrouping();
157 setProperty("DetectorGroupingTable", loadedGrouping);
158 };
159 // Deadtime table should be returned if user has set the property
160 auto deadtimeTable = m_loadMuonStrategy->loadDeadTimeTable();
161 if (!getPropertyValue("DeadTimeTable").empty()) {
162 setProperty("DeadTimeTable", deadtimeTable);
163 }
164
165 // Time Zero table should be returned if found
166 if (!getPropertyValue("TimeZerotable").empty()) {
167 // Create table and set property
168 auto timeZeroTable = m_loadMuonStrategy->getTimeZeroTable();
169 setProperty("TimeZeroTable", timeZeroTable);
170 }
171}
172
178 int numberOfPeriods = m_nexusLoader->getNumberOfPeriods();
179 if (numberOfPeriods > 1) {
180 m_isFileMultiPeriod = true;
181 if (m_entrynumber == 0) {
183 }
184 } else {
185 m_isFileMultiPeriod = false;
186 m_multiPeriodsLoaded = false;
187 }
188}
195 // Here we explicit set the number of OpenMP threads, as by default
196 // LoadISISNexus spawns up a large number of threads,
197 // which is unnecessary for the size (~100 spectra) of workspaces seen here.
198 // Through profiling it was found that a single threaded call to LoadISISNexus
199 // was quicker due to the overhead of setting up the threads, which outweighs
200 // the cost of the resulting operations.
201 // To prevent the omp_set_num_threads call having side effects, we use a RAII
202 // pattern to restore the default behavior once runLoadISISNexus is complete.
203 struct ScopedNumThreadsSetter {
204 ScopedNumThreadsSetter(const int numThreads) {
205 (void)numThreads; // Treat compiler warning in OSX
206 globalNumberOfThreads = PARALLEL_GET_MAX_THREADS;
207 PARALLEL_SET_NUM_THREADS(numThreads);
208 }
209 ~ScopedNumThreadsSetter() { PARALLEL_SET_NUM_THREADS(globalNumberOfThreads); }
210 int globalNumberOfThreads;
211 };
212 ScopedNumThreadsSetter restoreDefaultThreadsOnExit(1);
213 auto childAlg = createChildAlgorithm("LoadISISNexus", 0, 1, true, 2);
214 declareProperty("LoadMonitors", "Exclude"); // we need to set this property
215 auto ISISLoader = std::dynamic_pointer_cast<API::Algorithm>(childAlg);
216 ISISLoader->copyPropertiesFrom(*this);
217 ISISLoader->execute();
218 this->copyPropertiesFrom(*ISISLoader);
219 Workspace_sptr outWS = getProperty("OutputWorkspace");
221 loadPeriodInfo(*outWS);
222 return outWS;
223}
228 // Check if single or multi period file and create appropriate loading
229 // strategy
231 WorkspaceGroup_sptr workspaceGroup = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
232 assert(workspaceGroup);
233 auto numberHistograms = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(0))->getNumberHistograms();
234 loadMuonProperties(numberHistograms);
236 std::make_unique<MultiPeriodLoadMuonStrategy>(g_log, m_filename, *m_nexusLoader, *workspaceGroup);
237
238 } else {
239 // we just have a single workspace
240 Workspace2D_sptr workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspace);
241 assert(workspace2D);
242 // Load Muon specific properties
243 loadMuonProperties(workspace2D->getNumberHistograms());
244 m_loadMuonStrategy = std::make_unique<SinglePeriodLoadMuonStrategy>(
245 g_log, m_filename, *m_nexusLoader, *workspace2D, static_cast<int>(m_entrynumber), m_isFileMultiPeriod);
246 }
247}
252void LoadMuonNexusV2::loadMuonProperties(size_t numSpectra) {
253
254 std::string mainFieldDirection = m_nexusLoader->loadMainFieldDirectionFromNexus();
255 setProperty("MainFieldDirection", mainFieldDirection);
256
257 double timeZero = m_nexusLoader->loadTimeZeroFromNexusFile();
258 setProperty("timeZero", timeZero);
259
260 auto firstGoodData = m_nexusLoader->loadFirstGoodDataFromNexus();
261 setProperty("FirstGoodData", firstGoodData);
262
263 auto lastGoodData = m_nexusLoader->loadLastGoodDataFromNexus();
264 setProperty("LastGoodData", lastGoodData);
265
266 auto timeZeroVector = m_nexusLoader->loadTimeZeroListFromNexusFile(numSpectra);
267 setProperty("TimeZeroList", timeZeroVector);
268}
269
270/*
271Changes the unit of the time axis, which is incorrect due to being loaded using
272LoadISISNexus
273*/
275 auto newUnit = std::dynamic_pointer_cast<Kernel::Units::Label>(Kernel::UnitFactory::Instance().create("Label"));
276 newUnit->setLabel("Time", Kernel::Units::Symbol::Microsecond);
277 auto workspaceGroup = dynamic_cast<WorkspaceGroup *>(&workspace);
278 if (workspaceGroup) {
279 for (int i = 0; i < workspaceGroup->getNumberOfEntries(); ++i) {
280 auto workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(i));
281 workspace2D->getAxis(0)->unit() = newUnit;
282 }
283 } else {
284 auto &workspace2D = dynamic_cast<Workspace2D &>(workspace);
285 workspace2D.getAxis(0)->unit() = newUnit;
286 }
287}
289 // get value
290 int numberOfPeriods = m_nexusLoader->getNumberOfPeriods();
291 auto labels = m_nexusLoader->getPeriodLabels();
292 auto sequences = m_nexusLoader->getPeriodSequenceString(numberOfPeriods);
293 auto types = m_nexusLoader->getPeriodTypes(numberOfPeriods);
294 auto requested = m_nexusLoader->getPeriodFramesRequested(numberOfPeriods);
295 auto rawFrames = m_nexusLoader->getPeriodRawFrames(numberOfPeriods);
296 auto output = m_nexusLoader->getPeriodOutput(numberOfPeriods);
297 auto counts = m_nexusLoader->getPeriodTotalCounts();
298 // put values into workspaces
299 auto workspaceGroup = dynamic_cast<WorkspaceGroup *>(&workspace);
300 if (workspaceGroup) {
301 for (int i = 0; i < workspaceGroup->getNumberOfEntries(); ++i) {
302 auto workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(i));
303 auto &run = workspace2D->mutableRun();
304 run.addProperty("period_labels", labels);
305 run.addProperty("period_sequences", sequences);
306 run.addProperty("period_type", types);
307 run.addProperty("frames_period_requested", requested);
308 run.addProperty("frames_period_raw", rawFrames);
309 run.addProperty("period_output", output);
310 run.addProperty("total_counts_period", counts);
311 }
312 } else {
313 auto &workspace2D = dynamic_cast<Workspace2D &>(workspace);
314 auto &run = workspace2D.mutableRun();
315 run.addProperty("period_labels", labels);
316 run.addProperty("period_sequences", sequences);
317 run.addProperty("period_type", types);
318 run.addProperty("frames_period_requested", requested);
319 run.addProperty("frames_period_raw", rawFrames);
320 run.addProperty("period_output", output);
321 run.addProperty("total_counts_period", counts);
322 }
323}
324
325} // namespace Mantid::DataHandling
IPeaksWorkspace_sptr workspace
#define PARALLEL_SET_NUM_THREADS(MaxCores)
#define PARALLEL_GET_MAX_THREADS
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
virtual void copyPropertiesFrom(const Algorithm &alg)
Make m_properties point to the same PropertyManager as alg.m_properties.
Definition Algorithm.h:320
Kernel::Logger & g_log
Definition Algorithm.h:422
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
Definition Axis.cpp:28
Run & mutableRun()
Writable version of the run object.
@ Load
allowed here which will be passed to the algorithm
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:90
virtual Axis * getAxis(const std::size_t &axisIndex) const
Get a non owning pointer to a workspace axis.
Class to hold a set of workspaces.
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:29
std::unique_ptr< LoadMuonStrategy > m_loadMuonStrategy
void isEntryMultiPeriod()
Determines whether the file is multi period If multi period the function determines whether multi per...
std::string m_filename
The name and path of the input file.
void applyTimeAxisUnitCorrection(API::Workspace &workspace)
std::unique_ptr< LoadMuonNexusV2NexusHelper > m_nexusLoader
void exec() override
Overwrites Algorithm method.
void chooseLoaderStrategy(const API::Workspace_sptr &workspace)
Determines the loading strategy used by the Algorithm.
LoadMuonNexusV2()
Empty default constructor.
int64_t m_entrynumber
The number of the input entry.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void init() override
Overwrites Algorithm method.
void loadMuonProperties(size_t numSpectra)
Loads Muon specific data from the nexus entry and sets the appropriate output properties.
API::Workspace_sptr runLoadISISNexus()
Runs the child algorithm LoadISISNexus, which loads data into an output workspace.
void loadPeriodInfo(API::Workspace &workspace)
Concrete workspace implementation.
Definition Workspace2D.h:29
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 UnitLabel Microsecond
Microsecond.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openEntry(const std::string &name)
Opens an entry – a topmost Nexus class.
std::string getStrData(std::string const &address)
Get string data from a dataset at address.
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.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
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.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54