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
20#include <filesystem>
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 on which to base the GroupingWorkspace.");
44
45 const std::vector<std::string> validFilenameExtensions{".xml", ".hdf5", ".nxs", ".nxs.h5"};
46 alg->declareProperty(
47 std::make_unique<FileProperty>("InstrumentFilename", "", FileProperty::OptionalLoad, validFilenameExtensions),
48 "Optional: Path to a file (full or relative) defining the instrument on which to base the GroupingWorkspace. "
49 "The file could be an IDF or a NeXus Geometry file. Note, InstrumentFilename or InstrumentName must be "
50 "specified, but not both.");
51
52 alg->setPropertyGroup("InputWorkspace", grpName);
53 alg->setPropertyGroup("InstrumentName", grpName);
54 alg->setPropertyGroup("InstrumentFilename", grpName);
55}
56
58 MatrixWorkspace_sptr inWS = alg->getProperty("InputWorkspace");
59 if (bool(inWS))
60 return true;
61
62 std::string InstrumentName = alg->getPropertyValue("InstrumentName");
63 if (!InstrumentName.empty())
64 return true;
65
66 std::string InstrumentFilename = alg->getPropertyValue("InstrumentFilename");
67 return !InstrumentFilename.empty();
68}
69
75 MatrixWorkspace_sptr inWS = alg->getProperty("InputWorkspace");
76 std::string InstrumentName = alg->getPropertyValue("InstrumentName");
77 std::string InstrumentFilename = alg->getPropertyValue("InstrumentFilename");
78
79 // Some validation
80 int numParams = 0;
81 if (inWS)
82 numParams++;
83 if (!InstrumentName.empty())
84 numParams++;
85 if (!InstrumentFilename.empty())
86 numParams++;
87
88 if (numParams > 1)
89 throw std::invalid_argument("You must specify exactly ONE way to get an "
90 "instrument (workspace, instrument name, or "
91 "IDF file). You specified more than one.");
92 if (numParams == 0)
93 throw std::invalid_argument("You must specify exactly ONE way to get an "
94 "instrument (workspace, instrument name, or "
95 "IDF file). You specified none.");
96
97 // ---------- Get the instrument one of 3 ways ---------------------------
99 if (inWS) {
100 inst = inWS->getInstrument();
101 } else {
102 Algorithm_sptr childAlg = alg->createChildAlgorithm("LoadEmptyInstrument", 0.0, 0.2);
103 childAlg->setPropertyValue("Filename", InstrumentFilename);
104 childAlg->setPropertyValue("InstrumentName", InstrumentName);
105 childAlg->executeAsChildAlg();
106 MatrixWorkspace_sptr tempWS = childAlg->getProperty("OutputWorkspace");
107 inst = tempWS->getInstrument();
108 }
109
110 return inst;
111}
112
113//----------------------------------------------------------------------------------------------
118
119 declareProperty(std::make_unique<FileProperty>("CalFilename", "", FileProperty::Load, ".cal"),
120 "Path to the old-style .cal grouping/calibration file (multi-column "
121 "ASCII). You must also specify the instrument.");
122
123 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeGroupingWorkspace", true, Direction::Input),
124 "Set to true to create a GroupingWorkspace with called "
125 "WorkspaceName_group.");
126
127 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeOffsetsWorkspace", true, Direction::Input),
128 "Set to true to create a OffsetsWorkspace with called "
129 "WorkspaceName_offsets.");
130
131 declareProperty(std::make_unique<PropertyWithValue<bool>>("MakeMaskWorkspace", true, Direction::Input),
132 "Set to true to create a MaskWorkspace with called WorkspaceName_mask.");
133
134 declareProperty(std::make_unique<PropertyWithValue<std::string>>("WorkspaceName", "", Direction::Input),
135 "The base of the output workspace names. Names will have '_group', "
136 "'_cal', '_offsets', '_mask' appended to them.");
137}
138
139//----------------------------------------------------------------------------------------------
143 std::string CalFilename = getPropertyValue("CalFilename");
144 std::string WorkspaceName = getPropertyValue("WorkspaceName");
145 bool MakeGroupingWorkspace = getProperty("MakeGroupingWorkspace");
146 bool MakeOffsetsWorkspace = getProperty("MakeOffsetsWorkspace");
147 bool MakeMaskWorkspace = getProperty("MakeMaskWorkspace");
148
149 if (WorkspaceName.empty())
150 throw std::invalid_argument("Must specify WorkspaceName.");
151
153
155 OffsetsWorkspace_sptr offsetsWS;
156 MaskWorkspace_sptr maskWS;
157
158 // Title of all workspaces = the file without path
159 std::string title = std::filesystem::path(CalFilename).filename().string();
160
161 // Initialize all required workspaces.
162 if (MakeGroupingWorkspace) {
163 groupWS = GroupingWorkspace_sptr(new GroupingWorkspace(inst));
164 groupWS->setTitle(title);
165 declareProperty(std::make_unique<WorkspaceProperty<GroupingWorkspace>>("OutputGroupingWorkspace",
166 WorkspaceName + "_group", Direction::Output),
167 "Set the output GroupingWorkspace, if any.");
168 groupWS->mutableRun().addProperty("Filename", CalFilename);
169 setProperty("OutputGroupingWorkspace", groupWS);
170 }
171
172 if (MakeOffsetsWorkspace) {
173 offsetsWS = OffsetsWorkspace_sptr(new OffsetsWorkspace(inst));
174 offsetsWS->setTitle(title);
176 "OutputOffsetsWorkspace", WorkspaceName + "_offsets", Direction::Output),
177 "Set the output OffsetsWorkspace, if any.");
178 offsetsWS->mutableRun().addProperty("Filename", CalFilename);
179 setProperty("OutputOffsetsWorkspace", offsetsWS);
180 }
181
182 if (MakeMaskWorkspace) {
183 maskWS = MaskWorkspace_sptr(new MaskWorkspace(inst));
184 maskWS->setTitle(title);
185 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputMaskWorkspace", WorkspaceName + "_mask",
187 "Set the output MaskWorkspace, if any.");
188 maskWS->mutableRun().addProperty("Filename", CalFilename);
189 setProperty("OutputMaskWorkspace", maskWS);
190 }
191
192 LoadCalFile::readCalFile(CalFilename, groupWS, offsetsWS, maskWS);
193
194 if (MakeOffsetsWorkspace) {
195 auto alg = createChildAlgorithm("ConvertDiffCal");
196 alg->setProperty("OffsetsWorkspace", offsetsWS);
197 alg->executeAsChildAlg();
198 ITableWorkspace_sptr calWS = alg->getProperty("OutputWorkspace");
199 calWS->setTitle(title);
200 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputCalWorkspace", WorkspaceName + "_cal",
202 "Set the output Diffraction Calibration workspace, if any.");
203 setProperty("OutputCalWorkspace", calWS);
204 }
205}
206
207//-----------------------------------------------------------------------
218void LoadCalFile::readCalFile(const std::string &calFileName, const GroupingWorkspace_sptr &groupWS,
219 const OffsetsWorkspace_sptr &offsetsWS, const MaskWorkspace_sptr &maskWS) {
220 auto doGroup = bool(groupWS);
221 auto doOffsets = bool(offsetsWS);
222 auto doMask = bool(maskWS);
223
224 bool hasUnmasked(false);
225 bool hasGrouped(false);
226
227 if (!doOffsets && !doGroup && !doMask)
228 throw std::invalid_argument("You must give at least one of the grouping, "
229 "offsets or masking workspaces.");
230
231 std::ifstream grFile(calFileName.c_str());
232 if (!grFile) {
233 throw std::runtime_error("Unable to open calibration file " + calFileName);
234 }
235
236 size_t numErrors = 0;
237
238 detid2index_map detID_to_wi;
239 if (doMask) {
240 detID_to_wi = maskWS->getDetectorIDToWorkspaceIndexMap();
241 }
242
243 // not all of these should be doubles, but to make reading work read as double
244 // then recast to int
245 int n, udet, select, group;
246 double n_d, udet_d, offset, select_d, group_d;
247
248 SpectrumInfo *maskSpectrumInfo{nullptr};
249 if (maskWS)
250 maskSpectrumInfo = &maskWS->mutableSpectrumInfo();
251 std::string str;
252 while (getline(grFile, str)) {
253 if (str.empty() || str[0] == '#')
254 continue;
255 std::istringstream istr(str);
256
257 // read in everything as double then cast as appropriate
258 istr >> n_d >> udet_d >> offset >> select_d >> group_d;
259 n = static_cast<int>(n_d);
260 udet = static_cast<int>(udet_d);
261 select = static_cast<int>(select_d);
262 group = static_cast<int>(group_d);
263
264 if (doOffsets) {
265 if (offset <= -1.) // should never happen
266 {
267 std::stringstream msg;
268 msg << "Encountered offset = " << offset << " at index " << n << " for udet = " << udet
269 << ". Offsets must be greater than -1.";
270 throw std::runtime_error(msg.str());
271 }
272
273 try {
274 offsetsWS->setValue(udet, offset);
275 } catch (std::invalid_argument &) {
276 // Ignore the error if the IS is actually for a monitor
277 if (!idIsMonitor(offsetsWS->getInstrument(), udet))
278 numErrors++;
279 }
280 }
281
282 if (doGroup) {
283 try {
284 groupWS->setValue(udet, double(group));
285 if ((!hasGrouped) && (group > 0))
286 hasGrouped = true;
287 } catch (std::invalid_argument &) {
288 // Ignore the error if the IS is actually for a monitor
289 if (!idIsMonitor(groupWS->getInstrument(), udet))
290 numErrors++;
291 }
292 }
293
294 if (doMask) {
295 detid2index_map::const_iterator it = detID_to_wi.find(udet);
296 if (it != detID_to_wi.end()) {
297 size_t wi = it->second;
298
299 if (select <= 0) {
300 // Not selected, then mask this detector
301 maskWS->getSpectrum(wi).clearData();
302 maskSpectrumInfo->setMasked(wi, true);
303 maskWS->mutableY(wi)[0] = 1.0;
304 } else {
305 // Selected, set the value to be 0
306 maskWS->mutableY(wi)[0] = 0.0;
307 hasUnmasked = true;
308 }
309 } else {
310 // Ignore the error if the IS is actually for a monitor
311 if (!idIsMonitor(maskWS->getInstrument(), udet))
312 numErrors++;
313 }
314 }
315 }
316
317 // Warn about any errors
318
319 if (numErrors > 0)
320 Logger("LoadCalFile").warning() << numErrors << " errors (invalid Detector ID's) found when reading .cal file '"
321 << calFileName << "'.\n";
322 if (doGroup && (!hasGrouped))
323 Logger("LoadCalFile").warning() << "'" << calFileName << "' has no spectra grouped\n";
324 if (doMask && (!hasUnmasked))
325 Logger("LoadCalFile").warning() << "'" << calFileName << "' masks all spectra\n";
326}
327
336 auto monitorList = inst->getMonitors();
337 auto it = std::find(monitorList.begin(), monitorList.end(), detID);
338 return (it != monitorList.end());
339}
340} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
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.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
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
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 void getInstrument3WaysInit(Mantid::API::Algorithm *alg)
For use by getInstrument3Ways, initializes the properties.
void init() override
Initialise the properties.
static bool instrumentIsSpecified(API::Algorithm const *alg)
static Geometry::Instrument_const_sptr getInstrument3Ways(API::Algorithm *alg)
Get a pointer to an instrument in one of 3 ways: InputWorkspace, InstrumentName, InstrumentFilename.
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:51
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
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:52
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
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