Mantid
Loading...
Searching...
No Matches
LoadEmptyInstrument.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 +
16#include "MantidIndexing/IndexInfo.h"
22#include "MantidNexus/NexusFile.h"
23#include "MantidNexusGeometry/NexusGeometryParser.h"
24
25#include <filesystem>
26
27namespace Mantid::DataHandling {
28// Register the algorithm into the algorithm factory as a file loading algorithm
29DECLARE_FILELOADER_ALGORITHM(LoadEmptyInstrument)
30
31using namespace Kernel;
32using namespace API;
33using namespace Geometry;
34using namespace DataObjects;
35using namespace HistogramData;
36
37namespace {
38const std::vector<std::string> validFilenameExtensions{".xml", ".hdf5", ".nxs", ".nxs.h5"};
39enum class FilenameExtensionEnum { XML, HDF5, NXS, NXS_H5, enum_count };
40typedef EnumeratedString<FilenameExtensionEnum, &validFilenameExtensions, &compareStringsCaseInsensitive>
41 FilenameExtension;
42} // namespace
43
44// This method attempts to retrieve a valid, i.e. enumerated, instrument file name extension.
45// Possible double and single extensions are considered. If no valid file name extension could
46// be retrieved, an std::runtime_error will be thrown. For example, a file name might have a double
47// extension such as ".nxs.h5", which is valid. It may also have a double extension such as .lite.nxs,
48// which is invalid. In the latter case a single extension, .nxs, which is valid, should be retrieved.
49std::string LoadEmptyInstrument::retrieveValidInstrumentFilenameExtension(const std::string &filename) {
50 std::string ext{std::filesystem::path(filename).extension().string()};
51 std::string stem{std::filesystem::path(filename).stem().string()};
52 std::string pre_ext{std::filesystem::path(stem).extension().string()};
53
54 // Test a possible double extension
55 if (!pre_ext.empty()) {
56 try {
57 const std::string double_ext{pre_ext + ext};
58 FilenameExtension fne(double_ext);
59 return fne.c_str();
60 } catch (const std::runtime_error &) {
61 }
62 }
63
64 // Test a possible single extension
65 try {
66 FilenameExtension fne(ext);
67 return fne.c_str();
68 } catch (std::runtime_error &) {
69 }
70
71 std::ostringstream os;
72 os << "Instrument file name \"" << filename << "\" has an invalid extension.";
73 throw std::runtime_error(os.str());
74}
75
76// Return all valid instrument file name extensions
78 return validFilenameExtensions;
79}
80
88 const std::string &filePath = descriptor.filename();
89
90 int confidence(0);
91 if (descriptor.isAscii()) // Only consider an Ascii file
92 {
93 // Filename must contain "Definition"
94 std::string::size_type stripPath = filePath.find_last_of("\\/");
95 if (stripPath == std::string::npos)
96 stripPath = 0;
97 if (filePath.find("Definition", stripPath) != std::string::npos) {
98 // We have some confidence and it depends on the filetype.
99 if (descriptor.extension() == "xml") {
100 confidence = 80;
101 } else {
102 confidence = 20;
103 }
104 } // Has "Definition"
105 } // Ascii file
106 return confidence;
107}
108
111
112 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::OptionalLoad, validFilenameExtensions),
113 "Path to a file (full or relative) defining the instrument. The file could be an"
114 " IDF or a NeXus Geometry file. Note, Filename or InstrumentName must be specified, but not both.");
115 declareProperty("InstrumentName", "",
116 "Name of instrument. Can be used instead of Filename to "
117 "specify an IDF");
118 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
119 "The name of the workspace in which to store the imported instrument");
120
121 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
122 mustBePositive->setLower(0.0);
123 declareProperty("DetectorValue", 1.0, mustBePositive,
124 "This value affects the colour of the detectors in the instrument\n"
125 "display window (default 1)");
126 declareProperty("MonitorValue", 2.0, mustBePositive,
127 "This value affects the colour of the monitors in the instrument\n"
128 "display window (default 2)");
129
130 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeEventWorkspace", false),
131 "Set to True to create an EventWorkspace (with no events) "
132 "instead of a Workspace2D.");
133}
134
146 Progress prog(this, 0.0, 1.0, 10);
147
148 // load the instrument into this workspace
150 const std::string instrumentName = getPropertyValue("InstrumentName");
151 const std::string filename = getPropertyValue("Filename");
152 if (!instrumentName.empty())
153 ws = this->runLoadInstrument(filename, instrumentName);
154 else {
155 FilenameExtension enFilenameExtension{retrieveValidInstrumentFilenameExtension(filename)};
156 switch (enFilenameExtension) {
157 case FilenameExtensionEnum::XML:
158 case FilenameExtensionEnum::HDF5:
159 ws = this->runLoadInstrument(filename, instrumentName);
160 break;
161 case FilenameExtensionEnum::NXS:
162 case FilenameExtensionEnum::NXS_H5:
163 ws = this->runLoadIDFFromNexus(filename);
164 break;
165 default:
166 std::ostringstream os;
167 os << "Instrument file name has an invalid extension: "
168 << "\"" << enFilenameExtension.c_str() << "\"";
169 throw std::runtime_error(os.str());
170 }
171 }
172
173 Instrument_const_sptr instrument = ws->getInstrument();
174
175 // Get number of detectors stored in instrument
176 const size_t number_spectra = instrument->getNumberDetectors();
177
178 // Check that we have some spectra for the workspace
179 if (number_spectra == 0) {
180 g_log.error("Instrument has no detectors, unable to create workspace for it");
181 throw Kernel::Exception::InstrumentDefinitionError("No detectors found in instrument");
182 }
183
184 Indexing::IndexInfo indexInfo(number_spectra);
185 bool MakeEventWorkspace = getProperty("MakeEventWorkspace");
186 prog.reportIncrement(5, "Creating Data");
187 if (MakeEventWorkspace) {
188 setProperty("OutputWorkspace",
189 create<EventWorkspace>(instrument, indexInfo, BinEdges{0.0, std::numeric_limits<double>::min()}));
190 } else {
191 const double detector_value = getProperty("DetectorValue");
192 const double monitor_value = getProperty("MonitorValue");
193 auto ws2D = create<Workspace2D>(
194 instrument, indexInfo,
195 Histogram(BinEdges{0.0, 1.0}, Counts(1, detector_value), CountStandardDeviations(1, detector_value)));
196
197 Counts v_monitor_y(1, monitor_value);
198 CountStandardDeviations v_monitor_e(1, monitor_value);
199
200 const auto &spectrumInfo = ws2D->spectrumInfo();
201 const auto size = static_cast<int64_t>(spectrumInfo.size());
202#pragma omp parallel for
203 for (int64_t i = 0; i < size; i++) {
204 if (spectrumInfo.isMonitor(i)) {
205 ws2D->setCounts(i, v_monitor_y);
206 ws2D->setCountStandardDeviations(i, v_monitor_e);
207 }
208 }
209 setProperty("OutputWorkspace", std::move(ws2D));
210 }
211}
212
213// Call LoadInstrument as a child algorithm
215 const std::string &instrumentname) {
216 auto ws = WorkspaceFactory::Instance().create("Workspace2D", 1, 2, 1);
217
218 auto loadInst = createChildAlgorithm("LoadInstrument", 0, 0.5);
219 loadInst->setPropertyValue("Filename", filename);
220 loadInst->setPropertyValue("InstrumentName", instrumentname);
221 loadInst->setProperty("RewriteSpectraMap", OptionalBool(true));
222 loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", ws);
223
224 loadInst->execute();
225
226 return ws;
227}
228
229// Call LoadIDFFromNexus as a child algorithm
231 const std::string instrumentEntryName{"/instrument/instrument_xml"};
232 // There are two possibilities for the parent of the instrument IDF entry
233 const std::string instrumentParentEntryName_1{"mantid_workspace_1"};
234 const std::string instrumentParentEntryName_2{"raw_data_1"};
235 std::string instrumentParentEntryName{instrumentParentEntryName_1};
236
237 // Test if instrument XML definition exists in the file
238 bool foundIDF{false};
239 try {
240 Nexus::File nxsfile(filename);
241 nxsfile.openAddress("/" + instrumentParentEntryName + instrumentEntryName);
242 foundIDF = true;
243 } catch (Nexus::Exception const &) {
244 }
245
246 if (!foundIDF) {
247 instrumentParentEntryName = instrumentParentEntryName_2;
248 try {
249 Nexus::File nxsfile(filename);
250 nxsfile.openAddress("/" + instrumentParentEntryName + instrumentEntryName);
251 foundIDF = true;
252 } catch (Nexus::Exception const &) {
253 }
254 }
255
256 if (!foundIDF) {
257 throw std::runtime_error("No instrument XML definition found in " + filename + " at " +
258 instrumentParentEntryName_1 + instrumentEntryName + " or at " +
259 instrumentParentEntryName_2 + instrumentEntryName);
260 }
261
262 auto loadInst = createChildAlgorithm("LoadIDFFromNexus");
263
264 // Execute the child algorithm. Catch and log any error.
265 auto ws = WorkspaceFactory::Instance().create("Workspace2D", 1, 2, 1);
266 try {
267 loadInst->setPropertyValue("Filename", filename);
268 loadInst->setProperty<Mantid::API::MatrixWorkspace_sptr>("Workspace", ws);
269 loadInst->setPropertyValue("InstrumentParentPath", instrumentParentEntryName);
270 loadInst->execute();
271 } catch (std::invalid_argument &) {
272 getLogger().error("Invalid argument to LoadIDFFromNexus Child Algorithm ");
273 } catch (std::runtime_error &) {
274 getLogger().debug("No instrument definition found by LoadIDFFromNexus in " + filename + " at " +
275 instrumentParentEntryName + instrumentEntryName);
276 }
277
278 if (!loadInst->isExecuted())
279 getLogger().information("No IDF loaded from the Nexus file " + filename);
280
281 return ws;
282}
283} // namespace Mantid::DataHandling
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
Kernel::Logger & getLogger() const
Returns a reference to the logger.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
void init() override
Overwrites Algorithm method.
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
static const std::vector< std::string > & getValidInstrumentFilenameExtensions()
API::MatrixWorkspace_sptr runLoadInstrument(const std::string &filename, const std::string &instrumentname)
void exec() override
Overwrites Algorithm method.
API::MatrixWorkspace_sptr runLoadIDFFromNexus(const std::string &filename)
static std::string retrieveValidInstrumentFilenameExtension(const std::string &filename)
Exception for errors associated with the instrument definition.
Definition Exception.h:220
Defines a wrapper around an open file.
const std::string & filename() const
Access the filename.
static bool isAscii(const std::string &filename, const size_t nbytes=256)
Returns true if the file is considered ascii.
const std::string & extension() const
Access the file extension.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
OptionalBool : Tri-state bool.
void reportIncrement(int inc, const std::string &msg="")
Sends the progress notification and increment the loop counter by more than one.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class that provides for a standard Nexus exception.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
@ Output
An output workspace.
Definition Property.h:54