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 Nexus::File file(descriptor.filename());
72 file.openAddress(NeXusEntry::DEFINITION);
73 std::string def = file.getStrData();
74 if (def == "muonTD" || def == "pulsedTD") {
75 return 82; // have to return 82 to "beat" the LoadMuonNexus2 algorithm,
76 // which returns 81 for this file as well
77 } else {
78 return 0;
79 }
80}
83
84 std::vector<std::string> extensions{".nxs", ".nxs_v2", ".nxs_v1"};
85 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, extensions),
86 "The name of the Nexus file to load");
87
88 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
89 "The name of the workspace to be created as the output of the\n"
90 "algorithm. For multiperiod files, one workspace will be\n"
91 "generated for each period");
92
93 auto mustBePositiveSpectra = std::make_shared<BoundedValidator<specnum_t>>();
94 mustBePositiveSpectra->setLower(0);
95 declareProperty("SpectrumMin", static_cast<specnum_t>(0), mustBePositiveSpectra);
96 declareProperty("SpectrumMax", static_cast<specnum_t>(EMPTY_INT()), mustBePositiveSpectra);
97 declareProperty(std::make_unique<ArrayProperty<specnum_t>>("SpectrumList"));
98 auto mustBePositive = std::make_shared<BoundedValidator<int64_t>>();
99 mustBePositive->setLower(0);
100 declareProperty("EntryNumber", static_cast<int64_t>(0), mustBePositive,
101 "0 indicates that every entry is loaded, into a separate "
102 "workspace within a group. "
103 "A positive number identifies one entry to be loaded, into "
104 "one workspace");
105
106 std::vector<std::string> FieldOptions{"Transverse", "Longitudinal"};
107 declareProperty("MainFieldDirection", "Transverse", std::make_shared<StringListValidator>(FieldOptions),
108 "Output the main field direction if specified in Nexus file "
109 "(default longitudinal).",
111
112 declareProperty("TimeZero", 0.0, "Time zero in units of micro-seconds (default to 0.0)", Direction::Output);
113 declareProperty("FirstGoodData", 0.0, "First good data in units of micro-seconds (default to 0.0)",
115 declareProperty("LastGoodData", 0.0, "Last good data in the OutputWorkspace's spectra", Kernel::Direction::Output);
116
117 declareProperty(std::make_unique<ArrayProperty<double>>("TimeZeroList", Direction::Output),
118 "A vector of time zero values");
119
121 std::make_unique<WorkspaceProperty<Workspace>>("TimeZeroTable", "", Direction::Output, PropertyMode::Optional),
122 "TableWorkspace containing time zero values per spectra.");
123
124 declareProperty("CorrectTime", true, "Boolean flag controlling whether time should be corrected by timezero.",
126
128 std::make_unique<WorkspaceProperty<Workspace>>("DeadTimeTable", "", Direction::Output, PropertyMode::Optional),
129 "Table or a group of tables containing detector dead times.");
130
131 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("DetectorGroupingTable", "", Direction::Output,
133 "Table or a group of tables with information about the "
134 "detector grouping.");
135}
137 // prepare nexus entry
138 m_entrynumber = getProperty("EntryNumber");
139 m_filename = getPropertyValue("Filename");
140 NXRoot root(m_filename);
142 // Create MuonNexusV2 nexus loader
143 m_nexusLoader = std::make_unique<LoadMuonNexusV2NexusHelper>(entry);
145
146 // Execute child algorithm LoadISISNexus2
147 auto outWS = runLoadISISNexus();
148 // Create appropriate loading strategy
150 m_loadMuonStrategy->loadMuonLogData();
151 m_loadMuonStrategy->loadGoodFrames();
152 auto correctTime = getProperty("CorrectTime");
153 if (correctTime) {
154 m_loadMuonStrategy->applyTimeZeroCorrection();
155 }
156 // Grouping info should be returned if user has set the property
157 if (!getPropertyValue("DetectorGroupingTable").empty()) {
158 auto loadedGrouping = m_loadMuonStrategy->loadDetectorGrouping();
159 setProperty("DetectorGroupingTable", loadedGrouping);
160 };
161 // Deadtime table should be returned if user has set the property
162 auto deadtimeTable = m_loadMuonStrategy->loadDeadTimeTable();
163 if (!getPropertyValue("DeadTimeTable").empty()) {
164 setProperty("DeadTimeTable", deadtimeTable);
165 }
166
167 // Time Zero table should be returned if found
168 if (!getPropertyValue("TimeZerotable").empty()) {
169 // Create table and set property
170 auto timeZeroTable = m_loadMuonStrategy->getTimeZeroTable();
171 setProperty("TimeZeroTable", timeZeroTable);
172 }
173}
174
180 int numberOfPeriods = m_nexusLoader->getNumberOfPeriods();
181 if (numberOfPeriods > 1) {
182 m_isFileMultiPeriod = true;
183 if (m_entrynumber == 0) {
185 }
186 } else {
187 m_isFileMultiPeriod = false;
188 m_multiPeriodsLoaded = false;
189 }
190}
197 // Here we explicit set the number of OpenMP threads, as by default
198 // LoadISISNexus spawns up a large number of threads,
199 // which is unnecessary for the size (~100 spectra) of workspaces seen here.
200 // Through profiling it was found that a single threaded call to LoadISISNexus
201 // was quicker due to the overhead of setting up the threads, which outweighs
202 // the cost of the resulting operations.
203 // To prevent the omp_set_num_threads call having side effects, we use a RAII
204 // pattern to restore the default behavior once runLoadISISNexus is complete.
205 struct ScopedNumThreadsSetter {
206 ScopedNumThreadsSetter(const int numThreads) {
207 (void)numThreads; // Treat compiler warning in OSX
208 globalNumberOfThreads = PARALLEL_GET_MAX_THREADS;
209 PARALLEL_SET_NUM_THREADS(numThreads);
210 }
211 ~ScopedNumThreadsSetter() { PARALLEL_SET_NUM_THREADS(globalNumberOfThreads); }
212 int globalNumberOfThreads;
213 };
214 ScopedNumThreadsSetter restoreDefaultThreadsOnExit(1);
215 auto childAlg = createChildAlgorithm("LoadISISNexus", 0, 1, true, 2);
216 declareProperty("LoadMonitors", "Exclude"); // we need to set this property
217 auto ISISLoader = std::dynamic_pointer_cast<API::Algorithm>(childAlg);
218 ISISLoader->copyPropertiesFrom(*this);
219 ISISLoader->execute();
220 this->copyPropertiesFrom(*ISISLoader);
221 Workspace_sptr outWS = getProperty("OutputWorkspace");
223 loadPeriodInfo(*outWS);
224 return outWS;
225}
230 // Check if single or multi period file and create appropriate loading
231 // strategy
233 WorkspaceGroup_sptr workspaceGroup = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
234 assert(workspaceGroup);
235 auto numberHistograms = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(0))->getNumberHistograms();
236 loadMuonProperties(numberHistograms);
238 std::make_unique<MultiPeriodLoadMuonStrategy>(g_log, m_filename, *m_nexusLoader, *workspaceGroup);
239
240 } else {
241 // we just have a single workspace
242 Workspace2D_sptr workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspace);
243 assert(workspace2D);
244 // Load Muon specific properties
245 loadMuonProperties(workspace2D->getNumberHistograms());
246 m_loadMuonStrategy = std::make_unique<SinglePeriodLoadMuonStrategy>(
247 g_log, m_filename, *m_nexusLoader, *workspace2D, static_cast<int>(m_entrynumber), m_isFileMultiPeriod);
248 }
249}
254void LoadMuonNexusV2::loadMuonProperties(size_t numSpectra) {
255
256 std::string mainFieldDirection = m_nexusLoader->loadMainFieldDirectionFromNexus();
257 setProperty("MainFieldDirection", mainFieldDirection);
258
259 double timeZero = m_nexusLoader->loadTimeZeroFromNexusFile();
260 setProperty("timeZero", timeZero);
261
262 auto firstGoodData = m_nexusLoader->loadFirstGoodDataFromNexus();
263 setProperty("FirstGoodData", firstGoodData);
264
265 auto lastGoodData = m_nexusLoader->loadLastGoodDataFromNexus();
266 setProperty("LastGoodData", lastGoodData);
267
268 auto timeZeroVector = m_nexusLoader->loadTimeZeroListFromNexusFile(numSpectra);
269 setProperty("TimeZeroList", timeZeroVector);
270}
271
272/*
273Changes the unit of the time axis, which is incorrect due to being loaded using
274LoadISISNexus
275*/
277 auto newUnit = std::dynamic_pointer_cast<Kernel::Units::Label>(Kernel::UnitFactory::Instance().create("Label"));
278 newUnit->setLabel("Time", Kernel::Units::Symbol::Microsecond);
279 auto workspaceGroup = dynamic_cast<WorkspaceGroup *>(&workspace);
280 if (workspaceGroup) {
281 for (int i = 0; i < workspaceGroup->getNumberOfEntries(); ++i) {
282 auto workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(i));
283 workspace2D->getAxis(0)->unit() = newUnit;
284 }
285 } else {
286 auto &workspace2D = dynamic_cast<Workspace2D &>(workspace);
287 workspace2D.getAxis(0)->unit() = newUnit;
288 }
289}
291 // get value
292 int numberOfPeriods = m_nexusLoader->getNumberOfPeriods();
293 auto labels = m_nexusLoader->getPeriodLabels();
294 auto sequences = m_nexusLoader->getPeriodSequenceString(numberOfPeriods);
295 auto types = m_nexusLoader->getPeriodTypes(numberOfPeriods);
296 auto requested = m_nexusLoader->getPeriodFramesRequested(numberOfPeriods);
297 auto rawFrames = m_nexusLoader->getPeriodRawFrames(numberOfPeriods);
298 auto output = m_nexusLoader->getPeriodOutput(numberOfPeriods);
299 auto counts = m_nexusLoader->getPeriodTotalCounts();
300 // put values into workspaces
301 auto workspaceGroup = dynamic_cast<WorkspaceGroup *>(&workspace);
302 if (workspaceGroup) {
303 for (int i = 0; i < workspaceGroup->getNumberOfEntries(); ++i) {
304 auto workspace2D = std::dynamic_pointer_cast<Workspace2D>(workspaceGroup->getItem(i));
305 auto &run = workspace2D->mutableRun();
306 run.addProperty("period_labels", labels);
307 run.addProperty("period_sequences", sequences);
308 run.addProperty("period_type", types);
309 run.addProperty("frames_period_requested", requested);
310 run.addProperty("frames_period_raw", rawFrames);
311 run.addProperty("period_output", output);
312 run.addProperty("total_counts_period", counts);
313 }
314 } else {
315 auto &workspace2D = dynamic_cast<Workspace2D &>(workspace);
316 auto &run = workspace2D.mutableRun();
317 run.addProperty("period_labels", labels);
318 run.addProperty("period_sequences", sequences);
319 run.addProperty("period_type", types);
320 run.addProperty("frames_period_requested", requested);
321 run.addProperty("frames_period_raw", rawFrames);
322 run.addProperty("period_output", output);
323 run.addProperty("total_counts_period", counts);
324 }
325}
326
327} // 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 void copyPropertiesFrom(const Algorithm &alg)
Make m_properties point to the same PropertyManager as alg.m_properties.
Definition Algorithm.h:320
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:91
virtual Axis * getAxis(const std::size_t &axisIndex) const
Get a non owning pointer to a workspace axis.
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) override
Create a Child Algorithm.
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 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::NexusDescriptor &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.
void execLoader() override
Overwrites Algorithm method.
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.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
const std::string & filename() const noexcept
Returns a copy of the current file name.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
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