Mantid
Loading...
Searching...
No Matches
CreateSimulationWorkspace.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 +
8#include "LoadRaw/isisraw2.h"
9#include "MantidAPI/Axis.h"
12#include "MantidAPI/Run.h"
24#include "MantidNexus/NexusFile.h"
25
26namespace {
27
28struct StartAndEndTime {
29 Mantid::Types::Core::DateAndTime startTime;
30 Mantid::Types::Core::DateAndTime endTime;
31};
32
33StartAndEndTime getStartAndEndTimesFromRawFile(const std::string &filename) {
34 FILE *rawFile = fopen(filename.c_str(), "rb");
35 if (!rawFile)
36 throw std::runtime_error("Cannot open RAW file for reading: " + filename);
37
38 ISISRAW2 isisRaw;
39 const bool fromFile(true), readData(false);
40 isisRaw.ioRAW(rawFile, fromFile, readData);
41
42 StartAndEndTime startAndEndTime;
43 startAndEndTime.startTime = Mantid::DataHandling::LoadRawHelper::extractStartTime(isisRaw);
44 startAndEndTime.endTime = Mantid::DataHandling::LoadRawHelper::extractEndTime(isisRaw);
45
46 fclose(rawFile);
47 return startAndEndTime;
48}
49
50StartAndEndTime getStartAndEndTimesFromNexusFile(const std::string &filename,
51 const Mantid::Types::Core::DateAndTime &startTimeDefault,
52 const Mantid::Types::Core::DateAndTime &endTimeDefault) {
53 StartAndEndTime startAndEndTime;
54 try {
55 startAndEndTime.startTime = Mantid::DataHandling::extractStartTime(filename);
56 startAndEndTime.endTime = Mantid::DataHandling::extractEndTime(filename);
57 } catch (...) {
58 startAndEndTime.startTime = startTimeDefault;
59 startAndEndTime.endTime = endTimeDefault;
60 }
61
62 return startAndEndTime;
63}
64} // namespace
65
66namespace Mantid::DataHandling {
67
68// Register the algorithm into the AlgorithmFactory
69DECLARE_ALGORITHM(CreateSimulationWorkspace)
70
71using namespace API;
72using namespace HistogramData;
73
74//----------------------------------------------------------------------------------------------
76const std::string CreateSimulationWorkspace::name() const { return "CreateSimulationWorkspace"; }
77
79int CreateSimulationWorkspace::version() const { return 1; }
80
82const std::string CreateSimulationWorkspace::category() const { return "Utility\\Workspaces"; }
83
84//----------------------------------------------------------------------------------------------
85
86//----------------------------------------------------------------------------------------------
90 using namespace Kernel;
91
92 declareProperty("Instrument", "", std::make_shared<MandatoryValidator<std::string>>(),
93 "An instrument name or filename ( a full path or string "
94 "containing an xml extension).",
96
98 std::make_unique<ArrayProperty<double>>("BinParams", std::make_shared<RebinParamsValidator>(), Direction::Input),
99 "A comma separated list of first bin boundary, width, last "
100 "bin boundary. See Rebin for more details");
101
102 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output), "The new workspace");
103
104 auto knownUnits = UnitFactory::Instance().getKeys();
105 declareProperty("UnitX", "DeltaE", std::make_shared<ListValidator<std::string>>(knownUnits),
106 "The unit to assign to the X axis", Direction::Input);
107
109 std::make_unique<FileProperty>("DetectorTableFilename", "", FileProperty::OptionalLoad, "", Direction::Input),
110 "An optional filename (currently RAW or ISIS NeXus) that "
111 "contains UDET & SPEC tables to access hardware grouping");
112
113 declareProperty("SetErrors", false, "Whether to set histogram bin errors to sqrt of intensity.");
114}
115
116//----------------------------------------------------------------------------------------------
122
123 setProperty("OutputWorkspace", m_outputWS);
124}
125
126//-----------------------------------------------------------------------------------------------
127// Private methods
128//-----------------------------------------------------------------------------------------------
134 const bool enableLogging(false);
135 auto loadInstrument = createChildAlgorithm("LoadInstrument", 0.0, 0.5, enableLogging);
136 MatrixWorkspace_sptr tempWS = WorkspaceFactory::Instance().create("Workspace2D", 1, 1, 1);
137
138 // We need to set the correct start date for this workspace
139 // else we might be pulling an inadequate IDF
140 setStartDate(tempWS);
141
142 loadInstrument->setProperty("Workspace", tempWS);
143 const std::string instrProp = getProperty("Instrument");
144 if (instrProp.ends_with(".xml")) {
145 loadInstrument->setPropertyValue("Filename", instrProp);
146 } else {
147 loadInstrument->setPropertyValue("InstrumentName", instrProp);
148 }
149 loadInstrument->setProperty("RewriteSpectraMap", Kernel::OptionalBool(true));
150 loadInstrument->executeAsChildAlg();
151 tempWS = loadInstrument->getProperty("Workspace");
152
153 m_instrument = tempWS->getInstrument();
154}
155
160 const size_t nhistograms = createDetectorMapping();
161 const auto binBoundaries = createBinBoundaries();
162 const size_t xlength = binBoundaries.size();
163 const size_t ylength = xlength - 1;
164 const bool setError = getProperty("SetErrors");
165
166 m_outputWS = WorkspaceFactory::Instance().create("Workspace2D", nhistograms, xlength, ylength);
167 m_outputWS->setInstrument(m_instrument);
168 m_outputWS->populateInstrumentParameters();
169
170 m_outputWS->getAxis(0)->setUnit(getProperty("UnitX"));
171 m_outputWS->setYUnit("SpectraNumber");
172
173 m_progress = std::make_shared<Progress>(this, 0.5, 0.75, nhistograms);
174
176 for (int64_t i = 0; i < static_cast<int64_t>(nhistograms); ++i) {
177 m_outputWS->setBinEdges(i, binBoundaries);
178 m_outputWS->mutableY(i) = 1.0;
179 if (setError) {
180 m_outputWS->mutableE(i).assign(m_outputWS->getNumberBins(i), sqrt(1.0));
181 }
182
183 m_progress->report("Setting X values");
184 }
186
187 // Update the instrument from the file if necessary
188 const std::string detTableFile = getProperty("DetectorTableFilename");
189 if (detTableFile.ends_with(".raw") || detTableFile.ends_with(".RAW") || detTableFile.ends_with(".nxs") ||
190 detTableFile.ends_with(".NXS")) {
191 adjustInstrument(detTableFile);
192 }
193}
194
201 const std::string detTableFile = getProperty("DetectorTableFilename");
202 if (detTableFile.empty()) {
204 } else {
205 loadMappingFromFile(detTableFile);
206 }
207 return m_detGroups.size();
208}
209
214 const std::vector<detid_t> detids = m_instrument->getDetectorIDs(true);
215 const size_t nhist = detids.size();
216
217 m_detGroups.clear();
218 for (size_t i = 0; i < nhist; ++i) {
219 std::set<detid_t> group;
220 group.insert(detids[i]);
221 m_detGroups.emplace(static_cast<specnum_t>(i + 1), group);
222 }
223}
224
229void CreateSimulationWorkspace::loadMappingFromFile(const std::string &filename) {
230 if (filename.ends_with(".raw") || filename.ends_with(".RAW")) {
231 loadMappingFromRAW(filename);
232 } else if (filename.ends_with(".nxs") || filename.ends_with(".NXS")) {
233 loadMappingFromISISNXS(filename);
234 }
235}
236
241void CreateSimulationWorkspace::loadMappingFromRAW(const std::string &filename) {
242 FILE *rawFile = fopen(filename.c_str(), "rb");
243 if (!rawFile)
244 throw std::runtime_error("Cannot open RAW file for reading: " + filename);
245
246 ISISRAW2 isisRaw;
247 const bool fromFile(true), readData(false);
248 isisRaw.ioRAW(rawFile, fromFile, readData);
249
250 int ndet = isisRaw.i_det;
251 const int *specTable = isisRaw.spec;
252 const int *udetTable = isisRaw.udet;
253 createGroupingsFromTables(specTable, udetTable, ndet);
254
255 fclose(rawFile);
256}
257
264void CreateSimulationWorkspace::loadMappingFromISISNXS(const std::string &filename) {
265 Nexus::File nxsFile(filename);
266 try {
267 nxsFile.openAddress("/raw_data_1/isis_vms_compat");
268 } catch (Nexus::Exception const &) {
269 throw std::runtime_error("Cannot find path to isis_vms_compat. Is the file an ISIS NeXus file?");
270 }
271 using NXIntArray = std::vector<int32_t>;
272
273 NXIntArray ndets;
274 nxsFile.readData("NDET", ndets);
275
276 NXIntArray specTable;
277 nxsFile.readData("SPEC", specTable);
278
279 NXIntArray udetTable;
280 nxsFile.readData("UDET", udetTable);
281
282 createGroupingsFromTables(specTable.data(), udetTable.data(), ndets[0]);
283}
284
291void CreateSimulationWorkspace::createGroupingsFromTables(const int *specTable, const int *udetTable, int ndets) {
292 m_detGroups.clear();
293 for (int i = 0; i < ndets; ++i) {
294 int specNo = specTable[i];
295 int detID = udetTable[i];
296 if (m_instrument->isMonitor(detID))
297 continue; // Skip monitors
298
299 auto iter = m_detGroups.find(specNo);
300 if (iter != m_detGroups.end()) {
301 iter->second.insert(detID);
302 } else {
303 std::set<detid_t> group;
304 group.insert(static_cast<detid_t>(detID));
305 m_detGroups.emplace(specNo, group);
306 }
307 }
308}
309
314 const std::vector<double> rbparams = getProperty("BinParams");
315 MantidVec newBins;
316 const int numBoundaries = Mantid::Kernel::VectorHelper::createAxisFromRebinParams(rbparams, newBins);
317 if (numBoundaries <= 2) {
318 throw std::invalid_argument("Error in BinParams - Gave invalid number of bin boundaries: " +
319 std::to_string(numBoundaries));
320 }
321 return BinEdges(std::move(newBins));
322}
323
328 size_t wsIndex(0);
329 for (auto &detGroup : m_detGroups) {
330 auto &spectrum = m_outputWS->getSpectrum(wsIndex);
331 spectrum.setSpectrumNo(static_cast<specnum_t>(wsIndex + 1)); // Ensure a contiguous mapping
332 spectrum.clearDetectorIDs();
333 spectrum.addDetectorIDs(detGroup.second);
334 ++wsIndex;
335 }
336}
337
342void CreateSimulationWorkspace::adjustInstrument(const std::string &filename) {
343 // If requested update the instrument to positions in the raw file
344 const auto &pmap = m_outputWS->constInstrumentParameters();
345 Geometry::Instrument_const_sptr instrument = m_outputWS->getInstrument();
346 std::shared_ptr<Geometry::Parameter> updateDets = pmap.get(instrument->getComponentID(), "det-pos-source");
347 if (!updateDets)
348 return; // No tag, use IDF
349
350 std::string value = updateDets->value<std::string>();
351 if (value.substr(0, 8) == "datafile") {
352 auto updateInst = createChildAlgorithm("UpdateInstrumentFromFile", 0.75, 1.0);
353 updateInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_outputWS);
354 updateInst->setPropertyValue("Filename", filename);
355 if (value == "datafile-ignore-phi") {
356 updateInst->setProperty("IgnorePhi", true);
357 g_log.information("Detector positions in IDF updated with positions in "
358 "the data file except for the phi values");
359 } else {
360 g_log.information("Detector positions in IDF updated with positions in the data file");
361 }
362 // We want this to throw if it fails to warn the user that the information
363 // is not correct.
364 updateInst->execute();
365 }
366}
367
374 const std::string detTableFile = getProperty("DetectorTableFilename");
375 auto hasDetTableFile = !detTableFile.empty();
376 auto &run = workspace->mutableRun();
377
378 Types::Core::DateAndTime startTime;
379 Types::Core::DateAndTime endTime;
380 try {
381 // The start and end times might not be valid, and hence can throw
382 startTime = run.startTime();
383 endTime = run.endTime();
384 } catch (std::runtime_error &) {
385 startTime = Types::Core::DateAndTime::getCurrentTime();
386 endTime = Types::Core::DateAndTime::getCurrentTime();
387 }
388
389 if (hasDetTableFile) {
390 if (detTableFile.ends_with(".raw") || detTableFile.ends_with(".RAW")) {
391 auto startAndEndTime = getStartAndEndTimesFromRawFile(detTableFile);
392 startTime = startAndEndTime.startTime;
393 endTime = startAndEndTime.endTime;
394 } else if (detTableFile.ends_with(".nxs") || detTableFile.ends_with(".NXS")) {
395 auto startAndEndTime = getStartAndEndTimesFromNexusFile(detTableFile, startTime, endTime);
396 startTime = startAndEndTime.startTime;
397 endTime = startAndEndTime.endTime;
398 }
399 }
400
401 run.setStartAndEndTime(startTime, endTime);
402}
403
404} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
IPeaksWorkspace_sptr workspace
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
isis raw file.
Definition isisraw2.h:13
int ioRAW(FILE *file, bool from_file, bool read_data=true) override
Loads the headers of the file, leaves the file pointer at a specific position.
Definition isisraw2.cpp:43
int i_det
number of detectors NDET
Definition isisraw.h:291
int * udet
user detector number for each detector (size NDET)
Definition isisraw.h:317
int * spec
spectrum number table (size NDET)
Definition isisraw.h:297
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
A property class for workspaces.
API::MatrixWorkspace_sptr m_outputWS
Pointer to the new workspace.
void createGroupingsFromTables(const int *specTable, const int *udetTable, int ndets)
Create the grouping map from the tables.
void init() override
Initialize the algorithm's properties.
std::shared_ptr< API::Progress > m_progress
Pointer to a progress object.
std::map< specnum_t, std::set< detid_t > > m_detGroups
List of detector groupings.
void setStartDate(const API::MatrixWorkspace_sptr &workspace)
Set start date for dummy workspace.
const std::string name() const override
Algorithm's name for identification.
int version() const override
Algorithm's version for identification.
void loadMappingFromFile(const std::string &filename)
Load the detector mapping from a file.
void applyDetectorMapping()
Apply the created mapping to the workspace.
void createOneToOneMapping()
Create a one to one mapping from the spectrum numbers to detector IDs.
void loadMappingFromISISNXS(const std::string &filename)
Load the detector mapping from a NXS file.
Geometry::Instrument_const_sptr m_instrument
Pointer to the new instrument.
size_t createDetectorMapping()
Creates the detector grouping list.
HistogramData::BinEdges createBinBoundaries() const
Returns new Xbins.
const std::string category() const override
Algorithm's category for identification.
void adjustInstrument(const std::string &filename)
Apply any instrument adjustments from the file.
void loadMappingFromRAW(const std::string &filename)
Load the detector mapping from a RAW file.
static Types::Core::DateAndTime extractEndTime(ISISRAW &isisRaw)
Extract the end time from a raw file.
static Types::Core::DateAndTime extractStartTime(ISISRAW &isisRaw)
Extract the start time from a raw file.
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.
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
Validator to check that a property is not left empty.
OptionalBool : Tri-state bool.
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
Mantid::Types::Core::DateAndTime DLLExport extractEndTime(const std::string &filename)
Gets the start time from the nexus file.
Mantid::Types::Core::DateAndTime DLLExport extractStartTime(const std::string &filename)
Extracts the start and the end time from a Nexus file.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
int MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector< double > &params, std::vector< double > &xnew, const bool resize_xnew=true, const bool full_bins_only=false, const double xMinHint=std::nan(""), const double xMaxHint=std::nan(""), const bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
int32_t detid_t
Typedef for a detector ID.
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
Generate a tableworkspace to store the calibration results.
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