Mantid
Loading...
Searching...
No Matches
LoadCalFile.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 +
12#include "MantidAPI/Run.h"
19#include "MantidKernel/System.h"
20#include <Poco/Path.h>
21#include <fstream>
22
24using namespace Mantid::Kernel;
25using namespace Mantid::API;
26using namespace Mantid::DataObjects;
27
28namespace Mantid::DataHandling {
29// Register the algorithm into the AlgorithmFactory
31
32
35void LoadCalFile::getInstrument3WaysInit(Algorithm *alg) {
36 std::string grpName("Specify the Instrument");
37
38 alg->declareProperty(
39 std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, PropertyMode::Optional),
40 "Optional: An input workspace with the instrument we want to use.");
41
42 alg->declareProperty(std::make_unique<PropertyWithValue<std::string>>("InstrumentName", "", Direction::Input),
43 "Optional: Name of the instrument to base the "
44 "GroupingWorkspace on which to base the "
45 "GroupingWorkspace.");
46
47 alg->declareProperty(std::make_unique<FileProperty>("InstrumentFilename", "", FileProperty::OptionalLoad, ".xml"),
48 "Optional: Path to the instrument definition file on "
49 "which to base the GroupingWorkspace.");
50
51 alg->setPropertyGroup("InputWorkspace", grpName);
52 alg->setPropertyGroup("InstrumentName", grpName);
53 alg->setPropertyGroup("InstrumentFilename", grpName);
54}
55
57 MatrixWorkspace_sptr inWS = alg->getProperty("InputWorkspace");
58 if (bool(inWS))
59 return true;
60
61 std::string InstrumentName = alg->getPropertyValue("InstrumentName");
62 if (!InstrumentName.empty())
63 return true;
64
65 std::string InstrumentFilename = alg->getPropertyValue("InstrumentFilename");
66 return !InstrumentFilename.empty();
67}
68
74 MatrixWorkspace_sptr inWS = alg->getProperty("InputWorkspace");
75 std::string InstrumentName = alg->getPropertyValue("InstrumentName");
76 std::string InstrumentFilename = alg->getPropertyValue("InstrumentFilename");
77
78 // Some validation
79 int numParams = 0;
80 if (inWS)
81 numParams++;
82 if (!InstrumentName.empty())
83 numParams++;
84 if (!InstrumentFilename.empty())
85 numParams++;
86
87 if (numParams > 1)
88 throw std::invalid_argument("You must specify exactly ONE way to get an "
89 "instrument (workspace, instrument name, or "
90 "IDF file). You specified more than one.");
91 if (numParams == 0)
92 throw std::invalid_argument("You must specify exactly ONE way to get an "
93 "instrument (workspace, instrument name, or "
94 "IDF file). You specified none.");
95
96 // ---------- Get the instrument one of 3 ways ---------------------------
98 if (inWS) {
99 inst = inWS->getInstrument();
100 } else {
101 Algorithm_sptr childAlg = alg->createChildAlgorithm("LoadInstrument", 0.0, 0.2);
102 MatrixWorkspace_sptr tempWS = std::make_shared<Workspace2D>();
103 childAlg->setProperty<MatrixWorkspace_sptr>("Workspace", tempWS);
104 childAlg->setPropertyValue("Filename", InstrumentFilename);
105 childAlg->setPropertyValue("InstrumentName", InstrumentName);
106 childAlg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
107 childAlg->executeAsChildAlg();
108 inst = tempWS->getInstrument();
109 }
110
111 return inst;
112}
113
114//----------------------------------------------------------------------------------------------
119
120 declareProperty(std::make_unique<FileProperty>("CalFilename", "", FileProperty::Load, ".cal"),
121 "Path to the old-style .cal grouping/calibration file (multi-column "
122 "ASCII). You must also specify the instrument.");
123
124 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeGroupingWorkspace", true, Direction::Input),
125 "Set to true to create a GroupingWorkspace with called "
126 "WorkspaceName_group.");
127
128 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeOffsetsWorkspace", true, Direction::Input),
129 "Set to true to create a OffsetsWorkspace with called "
130 "WorkspaceName_offsets.");
131
132 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeMaskWorkspace", true, Direction::Input),
133 "Set to true to create a MaskWorkspace with called WorkspaceName_mask.");
134
135 declareProperty(std::make_unique<PropertyWithValue<std::string>>("WorkspaceName", "", Direction::Input),
136 "The base of the output workspace names. Names will have '_group', "
137 "'_cal', '_offsets', '_mask' appended to them.");
138}
139
140//----------------------------------------------------------------------------------------------
144 std::string CalFilename = getPropertyValue("CalFilename");
145 std::string WorkspaceName = getPropertyValue("WorkspaceName");
146 bool MakeGroupingWorkspace = getProperty("MakeGroupingWorkspace");
147 bool MakeOffsetsWorkspace = getProperty("MakeOffsetsWorkspace");
148 bool MakeMaskWorkspace = getProperty("MakeMaskWorkspace");
149
150 if (WorkspaceName.empty())
151 throw std::invalid_argument("Must specify WorkspaceName.");
152
154
156 OffsetsWorkspace_sptr offsetsWS;
157 MaskWorkspace_sptr maskWS;
158
159 // Title of all workspaces = the file without path
160 std::string title = Poco::Path(CalFilename).getFileName();
161
162 // Initialize all required workspaces.
163 if (MakeGroupingWorkspace) {
164 groupWS = GroupingWorkspace_sptr(new GroupingWorkspace(inst));
165 groupWS->setTitle(title);
166 declareProperty(std::make_unique<WorkspaceProperty<GroupingWorkspace>>("OutputGroupingWorkspace",
167 WorkspaceName + "_group", Direction::Output),
168 "Set the the output GroupingWorkspace, if any.");
169 groupWS->mutableRun().addProperty("Filename", CalFilename);
170 setProperty("OutputGroupingWorkspace", groupWS);
171 }
172
173 if (MakeOffsetsWorkspace) {
174 offsetsWS = OffsetsWorkspace_sptr(new OffsetsWorkspace(inst));
175 offsetsWS->setTitle(title);
177 "OutputOffsetsWorkspace", WorkspaceName + "_offsets", Direction::Output),
178 "Set the the output OffsetsWorkspace, if any.");
179 offsetsWS->mutableRun().addProperty("Filename", CalFilename);
180 setProperty("OutputOffsetsWorkspace", offsetsWS);
181 }
182
183 if (MakeMaskWorkspace) {
184 maskWS = MaskWorkspace_sptr(new MaskWorkspace(inst));
185 maskWS->setTitle(title);
186 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputMaskWorkspace", WorkspaceName + "_mask",
188 "Set the the output MaskWorkspace, if any.");
189 maskWS->mutableRun().addProperty("Filename", CalFilename);
190 setProperty("OutputMaskWorkspace", maskWS);
191 }
192
193 LoadCalFile::readCalFile(CalFilename, groupWS, offsetsWS, maskWS);
194
195 if (MakeOffsetsWorkspace) {
196 auto alg = createChildAlgorithm("ConvertDiffCal");
197 alg->setProperty("OffsetsWorkspace", offsetsWS);
198 alg->executeAsChildAlg();
199 ITableWorkspace_sptr calWS = alg->getProperty("OutputWorkspace");
200 calWS->setTitle(title);
201 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputCalWorkspace", WorkspaceName + "_cal",
203 "Set the output Diffraction Calibration workspace, if any.");
204 setProperty("OutputCalWorkspace", calWS);
205 }
206}
207
208//-----------------------------------------------------------------------
219void LoadCalFile::readCalFile(const std::string &calFileName, const GroupingWorkspace_sptr &groupWS,
220 const OffsetsWorkspace_sptr &offsetsWS, const MaskWorkspace_sptr &maskWS) {
221 auto doGroup = bool(groupWS);
222 auto doOffsets = bool(offsetsWS);
223 auto doMask = bool(maskWS);
224
225 bool hasUnmasked(false);
226 bool hasGrouped(false);
227
228 if (!doOffsets && !doGroup && !doMask)
229 throw std::invalid_argument("You must give at least one of the grouping, "
230 "offsets or masking workspaces.");
231
232 std::ifstream grFile(calFileName.c_str());
233 if (!grFile) {
234 throw std::runtime_error("Unable to open calibration file " + calFileName);
235 }
236
237 size_t numErrors = 0;
238
239 detid2index_map detID_to_wi;
240 if (doMask) {
241 detID_to_wi = maskWS->getDetectorIDToWorkspaceIndexMap();
242 }
243
244 // not all of these should be doubles, but to make reading work read as double
245 // then recast to int
246 int n, udet, select, group;
247 double n_d, udet_d, offset, select_d, group_d;
248
249 SpectrumInfo *maskSpectrumInfo{nullptr};
250 if (maskWS)
251 maskSpectrumInfo = &maskWS->mutableSpectrumInfo();
252 std::string str;
253 while (getline(grFile, str)) {
254 if (str.empty() || str[0] == '#')
255 continue;
256 std::istringstream istr(str);
257
258 // read in everything as double then cast as appropriate
259 istr >> n_d >> udet_d >> offset >> select_d >> group_d;
260 n = static_cast<int>(n_d);
261 udet = static_cast<int>(udet_d);
262 select = static_cast<int>(select_d);
263 group = static_cast<int>(group_d);
264
265 if (doOffsets) {
266 if (offset <= -1.) // should never happen
267 {
268 std::stringstream msg;
269 msg << "Encountered offset = " << offset << " at index " << n << " for udet = " << udet
270 << ". Offsets must be greater than -1.";
271 throw std::runtime_error(msg.str());
272 }
273
274 try {
275 offsetsWS->setValue(udet, offset);
276 } catch (std::invalid_argument &) {
277 // Ignore the error if the IS is actually for a monitor
278 if (!idIsMonitor(offsetsWS->getInstrument(), udet))
279 numErrors++;
280 }
281 }
282
283 if (doGroup) {
284 try {
285 groupWS->setValue(udet, double(group));
286 if ((!hasGrouped) && (group > 0))
287 hasGrouped = true;
288 } catch (std::invalid_argument &) {
289 // Ignore the error if the IS is actually for a monitor
290 if (!idIsMonitor(groupWS->getInstrument(), udet))
291 numErrors++;
292 }
293 }
294
295 if (doMask) {
296 detid2index_map::const_iterator it = detID_to_wi.find(udet);
297 if (it != detID_to_wi.end()) {
298 size_t wi = it->second;
299
300 if (select <= 0) {
301 // Not selected, then mask this detector
302 maskWS->getSpectrum(wi).clearData();
303 maskSpectrumInfo->setMasked(wi, true);
304 maskWS->mutableY(wi)[0] = 1.0;
305 } else {
306 // Selected, set the value to be 0
307 maskWS->mutableY(wi)[0] = 0.0;
308 if (!hasUnmasked)
309 hasUnmasked = true;
310 }
311 } else {
312 // Ignore the error if the IS is actually for a monitor
313 if (!idIsMonitor(maskWS->getInstrument(), udet))
314 numErrors++;
315 }
316 }
317 }
318
319 // Warn about any errors
320
321 if (numErrors > 0)
322 Logger("LoadCalFile").warning() << numErrors << " errors (invalid Detector ID's) found when reading .cal file '"
323 << calFileName << "'.\n";
324 if (doGroup && (!hasGrouped))
325 Logger("LoadCalFile").warning() << "'" << calFileName << "' has no spectra grouped\n";
326 if (doMask && (!hasUnmasked))
327 Logger("LoadCalFile").warning() << "'" << calFileName << "' masks all spectra\n";
328}
329
338 auto monitorList = inst->getMonitors();
339 auto it = std::find(monitorList.begin(), monitorList.end(), detID);
340 return (it != monitorList.end());
341}
342
343Parallel::ExecutionMode
344LoadCalFile::getParallelExecutionMode(const std::map<std::string, Parallel::StorageMode> &storageModes) const {
345 // There is an optional input workspace which may have
346 // StorageMode::Distributed but it is merely used for passing an instrument.
347 // Output should always have StorageMode::Cloned, so we run with
348 // ExecutionMode::Identical.
349 static_cast<void>(storageModes);
350 return Parallel::ExecutionMode::Identical;
351}
352
353} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:85
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
Definition: SpectrumInfo.h:53
A property class for workspaces.
Algorithm to load a 5-column ascii .cal file into up to 3 workspaces: a GroupingWorkspace,...
Definition: LoadCalFile.h:27
Parallel::ExecutionMode getParallelExecutionMode(const std::map< std::string, Parallel::StorageMode > &storageModes) const override
Get correct execution mode based on input storage modes for an MPI run.
static bool idIsMonitor(const Mantid::Geometry::Instrument_const_sptr &inst, int detID)
Checks if a detector ID is for a monitor on a given instrument.
void exec() override
Run the algorithm.
static bool instrumentIsSpecified(API::Algorithm *alg)
Definition: LoadCalFile.cpp:56
static void getInstrument3WaysInit(Mantid::API::Algorithm *alg)
For use by getInstrument3Ways, initializes the properties.
Definition: LoadCalFile.cpp:35
void init() override
Initialise the properties.
static Geometry::Instrument_const_sptr getInstrument3Ways(API::Algorithm *alg)
Get a pointer to an instrument in one of 3 ways: InputWorkspace, InstrumentName, InstrumentFilename.
Definition: LoadCalFile.cpp:73
static void readCalFile(const std::string &calFileName, const Mantid::DataObjects::GroupingWorkspace_sptr &groupWS, const Mantid::DataObjects::OffsetsWorkspace_sptr &offsetsWS, const Mantid::DataObjects::MaskWorkspace_sptr &maskWS)
Reads the calibration file.
A GroupingWorkspace is a subclass of Workspace2D where each spectrum has a single number entry,...
An OffsetsWorkspace is a specialized Workspace2D where the Y value at each pixel is the offset to be ...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
OptionalBool : Tri-state bool.
Definition: OptionalBool.h:25
The concrete, templated class for properties.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< GroupingWorkspace > GroupingWorkspace_sptr
shared pointer to the GroupingWorkspace class
std::shared_ptr< MaskWorkspace > MaskWorkspace_sptr
shared pointer to the MaskWorkspace class
Definition: MaskWorkspace.h:64
std::shared_ptr< OffsetsWorkspace > OffsetsWorkspace_sptr
shared pointer to the OffsetsWorkspace class
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54