Mantid
Loading...
Searching...
No Matches
ConvertDiffCal.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 +
10#include "MantidAPI/TableRow.h"
18
19namespace Mantid {
20
21namespace {
22
23const std::vector<std::string> DIFC_TABLE_COLUMN_NAMES{"detid", "difc", "difa", "tzero"};
24const std::vector<std::string> DIFC_TABLE_COLUMN_TYPES{"int", "double", "double", "double"};
25
26enum class OffsetMode { RELATIVE_OFFSET, ABSOLUTE_OFFSET, SIGNED_OFFSET, enum_count };
27const std::vector<std::string> offsetModeNames{"Relative", "Absolute", "Signed"};
29
30namespace PropertyNames {
31const std::string OFFSTS_WKSP("OffsetsWorkspace");
32const std::string CALIB_WKSP("PreviousCalibration");
33const std::string OUTPUT_WKSP("OutputWorkspace");
34const std::string OFFSET_MODE("OffsetMode");
35const std::string BINWIDTH("BinWidth");
36} // namespace PropertyNames
37} // namespace
38
39namespace Algorithms {
40
52
53// Register the algorithm into the AlgorithmFactory
54DECLARE_ALGORITHM(ConvertDiffCal)
55
56//----------------------------------------------------------------------------------------------
57
58
59const std::string ConvertDiffCal::name() const { return "ConvertDiffCal"; }
60
62int ConvertDiffCal::version() const { return 1; }
63
65const std::string ConvertDiffCal::category() const { return "Diffraction\\Utility"; }
66
68const std::string ConvertDiffCal::summary() const { return "Convert diffraction calibration from old to new style"; }
69
70//----------------------------------------------------------------------------------------------
76 "OffsetsWorkspace containing the calibration offsets.");
77
80 "A calibration table used as a cache for creating the OutputWorkspace. "
81 "Effectively, this algorithm applies partial updates to this table and "
82 "returns it as the OutputWorkspace");
83
84 declareProperty(PropertyNames::OFFSET_MODE, offsetModeNames[size_t(OffsetMode::RELATIVE_OFFSET)],
85 std::make_shared<Mantid::Kernel::StringListValidator>(offsetModeNames),
86 "Optional: Whether to calculate a relative, absolute, or signed offset");
87
89 "Optional: The bin width of the X axis. If using 'Signed' OffsetMode, this value is mandatory");
90
93 "An output workspace.");
94}
95
96std::map<std::string, std::string> ConvertDiffCal::validateInputs() {
97 std::map<std::string, std::string> result;
98
99 OFFSETMODE offsetMode = std::string(getProperty(PropertyNames::OFFSET_MODE));
100 if (isDefault(PropertyNames::BINWIDTH) && (offsetMode == OffsetMode::SIGNED_OFFSET)) {
101 std::string msg = "Signed offset mode requires bin width to be specified.";
102 result[PropertyNames::BINWIDTH] = msg;
103 result[PropertyNames::OFFSET_MODE] = msg;
104 }
105
107 if (previous_calibration) {
108 /* validate previous calibration has correct columns */
109 std::vector<std::string> column_names = previous_calibration->getColumnNames();
110 if (column_names != DIFC_TABLE_COLUMN_NAMES) {
111 result[PropertyNames::CALIB_WKSP] = "PreviousCalibration table's column names do not match expected format";
112 }
113 // TODO validate PreviousCalibration table's column types with DIFC_TABLE_COLUMN_TYPES
114 }
115
116 return result;
117}
118
119namespace { // anonymous namespace to enscope the below functions
120
128detid_t getDetID(const OffsetsWorkspace_const_sptr &offsetsWS, const size_t index) {
129 auto detIDs = offsetsWS->getSpectrum(index).getDetectorIDs();
130 if (detIDs.size() != 1) {
131 std::stringstream msg;
132 msg << "Encountered spectrum with multiple detector ids (size=" << detIDs.size() << ")";
133 throw std::logic_error(msg.str());
134 }
135 return (*(detIDs.begin()));
136}
137
147double calculateDIFC(const OffsetsWorkspace_const_sptr &offsetsWS, const size_t index,
148 const Mantid::API::SpectrumInfo &spectrumInfo, const double binWidth, OFFSETMODE offsetMode) {
149 const detid_t detid = getDetID(offsetsWS, index);
150 const double offset = offsetsWS->getValue(detid, 0.0);
151 double twotheta;
152 try {
153 twotheta = spectrumInfo.twoTheta(index);
154 } catch (std::runtime_error &) {
155 // Choose an arbitrary angle if detector 2theta determination fails.
156 twotheta = 0.;
157 }
158 // the factor returned is what is needed to convert TOF->d-spacing
159 // the table is supposed to be filled with DIFC which goes the other way
160 double newDIFC = 0.0;
161 if (offsetMode == OffsetMode::SIGNED_OFFSET)
162 newDIFC = Mantid::Geometry::Conversion::calculateDIFCCorrection(spectrumInfo.l1(), spectrumInfo.l2(index), twotheta,
163 offset, binWidth);
164 else {
165 const double factor =
166 Mantid::Geometry::Conversion::tofToDSpacingFactor(spectrumInfo.l1(), spectrumInfo.l2(index), twotheta, offset);
167 newDIFC = 1. / factor;
168 }
169 return newDIFC;
170}
171
179double updateAbsoluteDIFC(const double offset, const double oldDIFC, const double unused) {
180 UNUSED_ARG(unused);
181 if (offset <= -1.) { // non-physical
182 std::stringstream msg;
183 msg << "Encountered offset of " << offset << " which converts data to negative d-spacing from old DIFC " << oldDIFC
184 << "\n";
185 throw std::logic_error(msg.str());
186 }
187 return oldDIFC / (1.0 + offset);
188}
189
196double updateSignedDIFC(const double offset, const double oldDIFC, const double binWidth) {
197 return oldDIFC * pow(1.0 + fabs(binWidth), -1.0 * offset);
198}
199
200} // end anonymous namespace
201
202//----------------------------------------------------------------------------------------------
207
208 /* If a previous calibration is provided, initialize the output calibration table
209 * with it */
210 ITableWorkspace_sptr configWksp;
211
213
214 OFFSETMODE offsetMode = std::string(getProperty(PropertyNames::OFFSET_MODE));
215 const double binWidth = getProperty(PropertyNames::BINWIDTH);
216
217 if (previous_calibration) {
218 configWksp = previous_calibration->clone();
219 } else {
220 // initial setup of new style config
221 configWksp = std::make_shared<TableWorkspace>();
222 for (size_t i = 0; i < DIFC_TABLE_COLUMN_NAMES.size(); i++)
223 configWksp->addColumn(DIFC_TABLE_COLUMN_TYPES[i], DIFC_TABLE_COLUMN_NAMES[i]);
224 }
225
226 /* obtain detector ids from the previous calibration workspace */
227 std::unordered_map<int, int> id_to_row;
228 if (previous_calibration) {
229 std::vector<int> previous_calibration_ids = previous_calibration->getColumn(0)->numeric_fill<int>();
230
231 int row = 0;
232
233 for (auto id : previous_calibration_ids) {
234 id_to_row[id] = row++;
235 }
236 }
237
238 // create values in the table
239 const size_t numberOfSpectra = offsetsWS->getNumberHistograms();
240 Progress progress(this, 0.0, 1.0, numberOfSpectra);
241
242 const Mantid::API::SpectrumInfo &spectrumInfo = offsetsWS->spectrumInfo();
243 Mantid::Geometry::DetectorInfo const &d_info = offsetsWS->detectorInfo();
244
245 // set the function to use for updating the DIFC value
246 // setting here avoids branching inside the for loop
247 std::function<double(const double, const double, const double)> newDIFC;
248 if (offsetMode == OffsetMode::SIGNED_OFFSET) {
249 newDIFC = updateSignedDIFC;
250 } else {
251 newDIFC = updateAbsoluteDIFC;
252 }
253
254 for (size_t i = 0; i < numberOfSpectra; ++i) {
255
256 /* obtain detector id for this spectra */
257 detid_t detector_id = getDetID(offsetsWS, i);
258 size_t internal_index = d_info.indexOf(detector_id);
259 /* obtain the mask */
260 if (!d_info.isMasked(internal_index)) {
261 /* find the detector id's offset value in the offset workspace */
262 double new_offset_value = offsetsWS->getValue(detector_id, 0.0);
263
264 /* search for it in the table */
265 auto iter = id_to_row.find(detector_id);
266
267 /* if it is found, update the correct row in the output table */
268 if (iter != id_to_row.end()) {
269 /* Get the row and update the difc value in the first column */
270 int row_to_update = iter->second;
271
272 double &difc_value_to_update = configWksp->cell<double>(row_to_update, 1);
273 difc_value_to_update = newDIFC(new_offset_value, difc_value_to_update, binWidth);
274 }
275
276 /* value was not found in PreviousCalibration - calculate from experiment's geometry */
277 else {
278 API::TableRow newrow = configWksp->appendRow();
279 newrow << static_cast<int>(detector_id);
280 newrow << calculateDIFC(offsetsWS, i, spectrumInfo, binWidth, offsetMode);
281 newrow << 0.; // difa
282 newrow << 0.; // tzero
283 }
284 }
285
286 progress.report();
287 }
288
289 // sort the results
290 auto sortTable = createChildAlgorithm("SortTableWorkspace");
291 sortTable->setProperty("InputWorkspace", configWksp);
292 sortTable->setProperty("OutputWorkspace", configWksp);
293 sortTable->setPropertyValue("Columns", "detid");
294 sortTable->executeAsChildAlg();
295
296 // copy over the results
297 configWksp = sortTable->getProperty("OutputWorkspace");
299}
300
301} // namespace Algorithms
302} // namespace Mantid
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
#define fabs(x)
Definition Matrix.cpp:22
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
Helper class for reporting progress from algorithms.
Definition Progress.h:25
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
double twoTheta(const size_t index) const
Returns the scattering angle 2 theta in radians (angle w.r.t.
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
double l1() const
Returns L1 (distance from source to sample).
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
ConvertDiffCal : TODO: DESCRIPTION.
const std::string category() const override
Algorithm's category for identification.
int version() const override
Algorithm's version for identification.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
void exec() override
Execute the algorithm.
void init() override
Initialize the algorithm's properties.
An OffsetsWorkspace is a specialized Workspace2D where the Y value at each pixel is the offset to be ...
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
bool isMasked(const size_t index) const
Returns true if the detector is masked.
size_t indexOf(const detid_t id) const
Returns the index of the detector with the given detector ID.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const OffsetsWorkspace > OffsetsWorkspace_const_sptr
shared pointer to a const OffsetsWorkspace
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
MANTID_GEOMETRY_DLL double calculateDIFCCorrection(const double l1, const double l2, const double twoTheta, const double offset, const double binWidth)
MANTID_GEOMETRY_DLL double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset)
Calculate and return conversion factor from tof to d-spacing.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
const std::string BINWIDTH("BinWidth")
const std::string OFFSET_MODE("OffsetMode")
const std::string OFFSTS_WKSP("OffsetsWorkspace")
const std::string CALIB_WKSP("CalibrationWorkspace")
const std::string OUTPUT_WKSP("OutputWorkspace")
Helper class which provides the Collimation Length for SANS instruments.
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54