Mantid
Loading...
Searching...
No Matches
AlignDetectors.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11
12#include "MantidAPI/Axis.h"
22#include "MantidKernel/V3D.h"
23
24#include <fstream>
25#include <sstream>
26#include <utility>
27
28using namespace Mantid::Kernel;
29using namespace Mantid::API;
30using namespace Mantid::Geometry;
31using namespace Mantid::DataObjects;
32using namespace Mantid::HistogramData;
34
35namespace Mantid::Algorithms {
36// Register the algorithm into the algorithm factory
37DECLARE_ALGORITHM(AlignDetectors)
38
39namespace { // anonymous namespace
40
41class ConversionFactors {
42public:
43 explicit ConversionFactors(const ITableWorkspace_const_sptr &table)
44 : m_difcCol(table->getColumn("difc")), m_difaCol(table->getColumn("difa")),
45 m_tzeroCol(table->getColumn("tzero")) {
46 this->generateDetidToRow(table);
47 }
48
49 std::tuple<double, double, double> getDiffConstants(const std::set<detid_t> &detIds) const {
50 const std::set<size_t> rows = this->getRow(detIds);
51 double difc = 0.;
52 double difa = 0.;
53 double tzero = 0.;
54 for (auto row : rows) {
55 difc += m_difcCol->toDouble(row);
56 difa += m_difaCol->toDouble(row);
57 tzero += m_tzeroCol->toDouble(row);
58 }
59 if (rows.size() > 1) {
60 double norm = 1. / static_cast<double>(rows.size());
61 difc = norm * difc;
62 difa = norm * difa;
63 tzero = norm * tzero;
64 }
65
66 return {difc, difa, tzero};
67 }
68
69private:
70 void generateDetidToRow(const ITableWorkspace_const_sptr &table) {
71 ConstColumnVector<int> detIDs = table->getVector("detid");
72 const size_t numDets = detIDs.size();
73 for (size_t i = 0; i < numDets; ++i) {
74 m_detidToRow[static_cast<detid_t>(detIDs[i])] = i;
75 }
76 }
77
78 std::set<size_t> getRow(const std::set<detid_t> &detIds) const {
79 std::set<size_t> rows;
80 for (auto detId : detIds) {
81 auto rowIter = m_detidToRow.find(detId);
82 if (rowIter != m_detidToRow.end()) { // skip if not found
83 rows.insert(rowIter->second);
84 }
85 }
86 if (rows.empty()) {
87 std::string detIdsStr = std::accumulate(std::begin(detIds), std::end(detIds), std::string{},
88 [](const std::string &a, const detid_t &b) {
89 return a.empty() ? std::to_string(b) : a + ',' + std::to_string(b);
90 });
91 throw Exception::NotFoundError("None of the detectors were found in the calibration table", detIdsStr);
92 }
93 return rows;
94 }
95
96 std::map<detid_t, size_t> m_detidToRow;
100};
101} // anonymous namespace
102
103const std::string AlignDetectors::name() const { return "AlignDetectors"; }
104
105int AlignDetectors::version() const { return 1; }
106
107const std::string AlignDetectors::category() const { return "Diffraction\\Calibration"; }
108
109const std::string AlignDetectors::summary() const {
110 return "Performs a unit change from TOF to dSpacing, correcting the X "
111 "values to account for small errors in the detector positions.";
112}
113
115AlignDetectors::AlignDetectors() : m_numberOfSpectra(0) {
116 useAlgorithm("ConvertUnits");
117 deprecatedDate("2021-01-04");
118}
119
121 auto wsValidator = std::make_shared<CompositeValidator>();
122 // Workspace unit must be TOF.
123 wsValidator->add<WorkspaceUnitValidator>("TOF");
124 wsValidator->add<RawCountValidator>();
125
127 std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
128 "A workspace with units of TOF");
129
130 declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
131 "The name to use for the output workspace");
132
133 const std::vector<std::string> exts{".h5", ".hd5", ".hdf", ".cal"};
134 declareProperty(std::make_unique<FileProperty>("CalibrationFile", "", FileProperty::OptionalLoad, exts),
135 "Optional: The .cal file containing the position correction factors. "
136 "Either this or OffsetsWorkspace needs to be specified.");
137
138 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("CalibrationWorkspace", "", Direction::Input,
140 "Optional: A Workspace containing the calibration information. Either "
141 "this or CalibrationFile needs to be specified.");
142
143 declareProperty(std::make_unique<WorkspaceProperty<OffsetsWorkspace>>("OffsetsWorkspace", "", Direction::Input,
145 "Optional: A OffsetsWorkspace containing the calibration offsets. Either "
146 "this or CalibrationFile needs to be specified.");
147
148 // make group associations.
149 std::string calibrationGroup("Calibration");
150 setPropertyGroup("CalibrationFile", calibrationGroup);
151 setPropertyGroup("CalibrationWorkspace", calibrationGroup);
152 setPropertyGroup("OffsetsWorkspace", calibrationGroup);
153}
154
155std::map<std::string, std::string> AlignDetectors::validateInputs() {
156 std::map<std::string, std::string> result;
157
158 int numWays = 0;
159
160 const std::string calFileName = getProperty("CalibrationFile");
161 if (!calFileName.empty())
162 numWays += 1;
163
164 ITableWorkspace_const_sptr calibrationWS = getProperty("CalibrationWorkspace");
165 if (bool(calibrationWS))
166 numWays += 1;
167
168 OffsetsWorkspace_const_sptr offsetsWS = getProperty("OffsetsWorkspace");
169 if (bool(offsetsWS))
170 numWays += 1;
171
172 std::string message;
173 if (numWays == 0) {
174 message = "You must specify only one of CalibrationFile, "
175 "CalibrationWorkspace, OffsetsWorkspace.";
176 }
177 if (numWays > 1) {
178 message = "You must specify one of CalibrationFile, "
179 "CalibrationWorkspace, OffsetsWorkspace.";
180 }
181
182 if (!message.empty()) {
183 result["CalibrationFile"] = message;
184 result["CalibrationWorkspace"] = message;
185 }
186
187 return result;
188}
189
190void AlignDetectors::loadCalFile(const MatrixWorkspace_sptr &inputWS, const std::string &filename) {
191 auto alg = createChildAlgorithm("LoadDiffCal");
192 alg->setProperty("InputWorkspace", inputWS);
193 alg->setPropertyValue("Filename", filename);
194 alg->setProperty<bool>("MakeCalWorkspace", true);
195 alg->setProperty<bool>("MakeGroupingWorkspace", false);
196 alg->setProperty<bool>("MakeMaskWorkspace", false);
197 alg->setPropertyValue("WorkspaceName", "temp");
198 alg->executeAsChildAlg();
199
200 m_calibrationWS = alg->getProperty("OutputCalWorkspace");
201}
202
204 m_calibrationWS = getProperty("CalibrationWorkspace");
205 if (m_calibrationWS)
206 return; // nothing more to do
207
208 OffsetsWorkspace_sptr offsetsWS = getProperty("OffsetsWorkspace");
209 if (offsetsWS) {
210 auto alg = createChildAlgorithm("ConvertDiffCal");
211 alg->setProperty("OffsetsWorkspace", offsetsWS);
212 alg->executeAsChildAlg();
213 m_calibrationWS = alg->getProperty("OutputWorkspace");
214 m_calibrationWS->setTitle(offsetsWS->getTitle());
215 return;
216 }
217
218 const std::string calFileName = getPropertyValue("CalibrationFile");
219 if (!calFileName.empty()) {
220 progress(0.0, "Reading calibration file");
221 loadCalFile(inputWS, calFileName);
222 return;
223 }
224
225 throw std::runtime_error("Failed to determine calibration information");
226}
227
229 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("dSpacing");
230}
231
239 // Get the input workspace
240 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
241
242 this->getCalibrationWS(inputWS);
243
244 // Initialise the progress reporting object
245 m_numberOfSpectra = static_cast<int64_t>(inputWS->getNumberHistograms());
246
247 API::MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
248 // If input and output workspaces are not the same, create a new workspace for
249 // the output
250 if (outputWS != inputWS) {
251 outputWS = inputWS->clone();
252 setProperty("OutputWorkspace", outputWS);
253 }
254
255 // Set the final unit that our output workspace will have
256 setXAxisUnits(outputWS);
257
258 ConversionFactors converter = ConversionFactors(m_calibrationWS);
259
260 Progress progress(this, 0.0, 1.0, m_numberOfSpectra);
261
262 align(converter, progress, outputWS);
263}
264
265void AlignDetectors::align(const ConversionFactors &converter, Progress &progress, MatrixWorkspace_sptr &outputWS) {
266 auto eventW = std::dynamic_pointer_cast<EventWorkspace>(outputWS);
268 for (int64_t i = 0; i < m_numberOfSpectra; ++i) {
270 try {
271 // Get the input spectrum number at this workspace index
272 auto &spec = outputWS->getSpectrum(size_t(i));
273 auto [difc, difa, tzero] = converter.getDiffConstants(spec.getDetectorIDs());
274
275 auto &x = outputWS->dataX(i);
276 Kernel::Units::dSpacing dSpacingUnit;
277 std::vector<double> yunused;
278 dSpacingUnit.fromTOF(x, yunused, -1., 0,
282
283 if (eventW) {
284 Kernel::Units::TOF tofUnit;
285 tofUnit.initialize(0, 0, {});
286 // EventWorkspace part, modifying the EventLists.
287 eventW->getSpectrum(i).convertUnitsViaTof(&tofUnit, &dSpacingUnit);
288 }
289 } catch (const std::runtime_error &) {
290 if (!eventW) {
291 // Zero the data in this case (detectors not found in cal table or
292 // conversion fails)
293 outputWS->setHistogram(i, BinEdges(outputWS->x(i).size()), Counts(outputWS->y(i).size()));
294 }
295 }
296 progress.report();
298 }
300 if (eventW) {
301 if (eventW->getTofMin() < 0.) {
302 std::stringstream msg;
303 msg << "Something wrong with the calibration. Negative minimum d-spacing "
304 "created. d_min = "
305 << eventW->getTofMin() << " d_max " << eventW->getTofMax();
306 g_log.warning(msg.str());
307 }
308 eventW->clearMRU();
309 }
310}
311
312Parallel::ExecutionMode
313AlignDetectors::getParallelExecutionMode(const std::map<std::string, Parallel::StorageMode> &storageModes) const {
314 using namespace Parallel;
315 const auto inputMode = storageModes.at("InputWorkspace");
316 const auto &calibrationMode = storageModes.find("CalibrationWorkspace");
317 if (calibrationMode != storageModes.end())
318 if (calibrationMode->second != StorageMode::Cloned)
319 return ExecutionMode::Invalid;
320 return getCorrespondingExecutionMode(inputMode);
321}
322
323} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
std::map< detid_t, size_t > m_detidToRow
Column_const_sptr m_tzeroCol
Column_const_sptr m_difcCol
Column_const_sptr m_difaCol
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
Definition: MultiThreaded.h:94
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
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
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
ConstColumnVector gives const access to the column elements without alowing its resizing.
size_t size()
Size of the vector.
void deprecatedDate(const std::string &)
The date the algorithm was deprecated on.
void useAlgorithm(const std::string &, const int version=-1)
The algorithm to use instead of this one.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A validator which checks that a workspace contains raw counts in its bins.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
int64_t m_numberOfSpectra
number of spectra in input workspace
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.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
void init() override
Virtual method - must be overridden by concrete algorithm.
void exec() override
Executes the algorithm.
const std::string category() const override
Algorithm's category for identification.
void align(const ConversionFactors &converter, API::Progress &progress, API::MatrixWorkspace_sptr &outputWS)
Mantid::API::ITableWorkspace_sptr m_calibrationWS
void getCalibrationWS(const API::MatrixWorkspace_sptr &inputWS)
const std::string name() const override
Algorithms name for identification.
std::map< std::string, std::string > validateInputs() override
Cross-check properties with each other.
void loadCalFile(const API::MatrixWorkspace_sptr &inputWS, const std::string &filename)
An OffsetsWorkspace is a specialized Workspace2D where the Y value at each pixel is the offset to be ...
Exception for when an item is not found in a collection.
Definition: Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
void initialize(const double &_l1, const int &_emode, const UnitParametersMap &params)
Initialize the unit to perform conversion using singleToTof() and singleFromTof()
Definition: Unit.cpp:132
void fromTOF(std::vector< double > &xdata, std::vector< double > &ydata, const double &_l1, const int &_emode, std::initializer_list< std::pair< const UnitParams, double > > params)
Convert from time-of-flight to the concrete unit.
Definition: Unit.cpp:177
Time of flight in microseconds.
Definition: Unit.h:283
d-Spacing in Angstrom
Definition: Unit.h:383
std::shared_ptr< const ITableWorkspace > ITableWorkspace_const_sptr
shared pointer to Mantid::API::ITableWorkspace (const version)
std::shared_ptr< const Column > Column_const_sptr
Definition: Column.h:229
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void setXAxisUnits(const API::MatrixWorkspace_sptr &outputWS)
std::shared_ptr< const OffsetsWorkspace > OffsetsWorkspace_const_sptr
shared pointer to a const OffsetsWorkspace
std::shared_ptr< OffsetsWorkspace > OffsetsWorkspace_sptr
shared pointer to the OffsetsWorkspace class
std::unordered_map< UnitParams, double > UnitParametersMap
Definition: Unit.h:30
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.
Definition: MultiThreaded.h:22
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
STL namespace.
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