Mantid
Loading...
Searching...
No Matches
UnitsConversionHelper.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 +
11#include <cmath>
12
14
15namespace Mantid::MDAlgorithms {
16
31 const std::string &UnitsTo, bool forceViaTOF) {
32 // if units are equal, no conversion is necessary;
33 if (UnitsFrom == UnitsTo)
35
36 // get all known units:
37 std::vector<std::string> AllKnownUnits = Kernel::UnitFactory::Instance().getKeys();
38
39 // check if unit conversion is possible at all:
40 if (Kernel::Strings::isMember(AllKnownUnits, UnitsFrom) < 0)
41 throw(std::invalid_argument(" Can not initate conversion from unknown unit: " + UnitsFrom));
42
43 if (Kernel::Strings::isMember(AllKnownUnits, UnitsFrom) < 0)
44 throw(std::invalid_argument(" Can not initiate conversion to unknown unit: " + UnitsTo));
45
46 // is a quick conversion available?
48 if (m_SourceWSUnit->quickConversion(UnitsTo, m_Factor, m_Power) && !forceViaTOF) {
50 } else {
51 // are the input units TOF?
52 if (UnitsFrom == "TOF") {
54 } else { // convert using TOF
57 }
58 }
59}
78void UnitsConversionHelper::initialize(const MDWSDescription &targetWSDescr, const std::string &unitsTo,
79 bool forceViaTOF) {
80 // obtain input workspace units
81 API::MatrixWorkspace_const_sptr inWS2D = targetWSDescr.getInWS();
82 if (!inWS2D)
83 throw(std::runtime_error("UnitsConversionHelper::initialize Should not be "
84 "able to call this function when workpsace is "
85 "undefined"));
86
87 API::NumericAxis *pAxis = dynamic_cast<API::NumericAxis *>(inWS2D->getAxis(0));
88 if (!pAxis)
89 throw(std::invalid_argument("Cannot retrieve numeric X axis from the input workspace: " + inWS2D->getName()));
90
91 std::string unitsFrom = inWS2D->getAxis(0)->unit()->unitID();
92
93 // get detectors positions and other data needed for units conversion:
94 if (!(targetWSDescr.m_PreprDetTable))
95 throw std::runtime_error("MDWSDescription does not have a detector table");
96
97 auto Emode = static_cast<int>(targetWSDescr.getEMode());
98
99 this->initialize(unitsFrom, unitsTo, targetWSDescr.m_PreprDetTable, Emode, forceViaTOF);
100}
101// the helper function which used in the code below to simplify check if the
102// variable is in range
103inline bool inRange(const std::pair<double, double> &range, const double &val) {
104 return val >= range.first && val <= range.second;
105}
106// the helper function which used in the code below to simplify check if the
107// variable is in range
108inline bool inRange(const double &xMin, const double &xMax, const double &val) { return val >= xMin && val <= xMax; }
109
119std::pair<double, double> UnitsConversionHelper::getConversionRange(double x1, double x2) const {
120 std::pair<double, double> range;
121 range.first = std::min(x1, x2);
122 range.second = std::max(x1, x2);
123
124 switch (m_UnitCnvrsn) {
125 case (CnvrtToMD::ConvertNo): {
126 return range;
127 }
128 case (CnvrtToMD::ConvertFast): {
129 auto trRange = m_TargetUnit->conversionRange();
130 double u1 = this->convertUnits(x1);
131 double u2 = this->convertUnits(x2);
132
133 if (!inRange(trRange, u1) || !inRange(trRange, u2)) // hopefully it is a rare event
134 {
135 double uMin = std::min(u1, u2);
136 double uMax = std::max(u1, u2);
137 if (inRange(uMin, uMax, trRange.first)) {
138 double t1 = m_TargetUnit->singleToTOF(trRange.first);
139 range.first = m_TargetUnit->singleFromTOF(t1);
140 }
141 if (inRange(uMin, uMax, trRange.second)) {
142 double t2 = m_TargetUnit->singleToTOF(trRange.second);
143 range.second = m_SourceWSUnit->singleFromTOF(t2);
144 }
145 }
146 return range;
147 }
149 double tMin = m_TargetUnit->conversionTOFMin();
150 double tMax = m_TargetUnit->conversionTOFMax();
151
152 if (inRange(tMin, tMax, x1) && inRange(tMin, tMax, x2)) {
153 return range;
154 } else {
155 if (inRange(range, tMin))
156 range.first = tMin;
157 if (inRange(range, tMax))
158 range.second = tMax;
159 }
160 return range;
161 }
163 auto source_range = m_SourceWSUnit->conversionRange();
164 if (!inRange(source_range, range.first) || !inRange(source_range, range.second)) {
165 if (inRange(range, source_range.first))
166 range.first = source_range.first;
167 if (inRange(range, source_range.second))
168 range.second = source_range.second;
169 }
170 double tof1 = m_SourceWSUnit->singleToTOF(range.first);
171 double tof2 = m_SourceWSUnit->singleToTOF(range.second);
172 if (std::isnan(tof1) || std::isnan(tof2)) {
173 if (range.first < source_range.first)
174 range.first = source_range.first;
175 if (range.second > source_range.second)
176 range.second = source_range.second;
177 tof1 = m_SourceWSUnit->singleToTOF(range.first);
178 tof2 = m_SourceWSUnit->singleToTOF(range.second);
179 }
180
181 double tMin = m_TargetUnit->conversionTOFMin();
182 double tMax = m_TargetUnit->conversionTOFMax();
183 if (inRange(tMin, tMax, tof1) && inRange(tMin, tMax, tof2)) {
184 return range;
185 } else {
186 double u1 = range.first;
187 double u2 = range.second;
188 if (inRange(tof1, tof2, tMin))
189 u1 = m_SourceWSUnit->singleFromTOF(tMin);
190 if (inRange(tof1, tof2, tMax))
191 u2 = m_SourceWSUnit->singleFromTOF(tMax);
192 range.first = std::min(u1, u2);
193 range.second = std::max(u1, u2);
194 }
195 return range;
196 }
197 default:
198 throw std::runtime_error("updateConversion: unknown type of conversion requested");
199 }
200}
201
218void UnitsConversionHelper::initialize(const std::string &unitsFrom, const std::string &unitsTo,
219 const DataObjects::TableWorkspace_const_sptr &DetWS, int Emode,
220 bool forceViaTOF) {
221 m_Emode = Emode;
222
223 if (!DetWS)
224 throw std::runtime_error("UnitsConversionHelper::initialize called with "
225 "empty preprocessed detectors table");
226
227 // Check how the source units relate to the units requested and create source
228 // units
229 m_UnitCnvrsn = analyzeUnitsConversion(unitsFrom, unitsTo, forceViaTOF);
230
231 // create target units class
233 if (!m_TargetUnit)
234 throw(std::runtime_error(" Cannot retrieve target unit from the units factory"));
235
236 // get access to all values used by unit conversion.
237 m_pTwoThetas = &(DetWS->getColVector<double>("TwoTheta"));
238 m_pL2s = &(DetWS->getColVector<double>("L2"));
239
240 m_L1 = DetWS->getLogs()->getPropertyValueAsType<double>("L1");
241
242 // get efix
243 m_Efix = DetWS->getLogs()->getPropertyValueAsType<double>("Ei");
244 m_pEfixedArray = nullptr;
245 if (m_Emode == static_cast<int>(Kernel::DeltaEMode::Indirect))
246 m_pEfixedArray = DetWS->getColDataArray<float>("eFixed");
247
248 m_pDIFAs = &(DetWS->getColVector<double>("DIFA"));
249 m_pDIFCs = &(DetWS->getColVector<double>("DIFC"));
250 m_pTZEROs = &(DetWS->getColVector<double>("TZERO"));
251
252 // set up conversion to working state -- in some tests it can be used straight
253 // from the beginning.
254 m_TwoTheta = (*m_pTwoThetas)[0];
255 m_L2 = (*m_pL2s)[0];
256 double Efix = m_Efix;
257 if (m_pEfixedArray)
258 Efix = static_cast<double>(*(m_pEfixedArray + 0));
259 m_DIFA = (*m_pDIFAs)[0];
260 m_DIFC = (*m_pDIFCs)[0];
261 m_TZERO = (*m_pTZEROs)[0];
262
263 m_TargetUnit->initialize(m_L1, m_Emode,
264 {{UnitParams::l2, m_L2},
265 {UnitParams::twoTheta, m_TwoTheta},
266 {UnitParams::efixed, Efix},
267 {UnitParams::difa, m_DIFA},
268 {UnitParams::difc, m_DIFC},
269 {UnitParams::tzero, m_TZERO}});
270 if (m_SourceWSUnit) {
271 m_SourceWSUnit->initialize(m_L1, m_Emode,
272 {{UnitParams::l2, m_L2},
273 {UnitParams::twoTheta, m_TwoTheta},
274 {UnitParams::efixed, Efix},
275 {UnitParams::difa, m_DIFA},
276 {UnitParams::difc, m_DIFC},
277 {UnitParams::tzero, m_TZERO}});
278 }
279}
283 switch (m_UnitCnvrsn) {
285 return;
287 return;
289 m_TwoTheta = (*m_pTwoThetas)[i];
290 m_L2 = (*m_pL2s)[i];
291 double Efix = m_Efix;
292 if (m_pEfixedArray)
293 Efix = static_cast<double>(*(m_pEfixedArray + i));
294 m_DIFA = (*m_pDIFAs)[i];
295 m_DIFC = (*m_pDIFCs)[i];
296 m_TZERO = (*m_pTZEROs)[i];
297
298 m_TargetUnit->initialize(m_L1, m_Emode,
299 {{UnitParams::l2, m_L2},
300 {UnitParams::twoTheta, m_TwoTheta},
301 {UnitParams::efixed, Efix},
302 {UnitParams::difa, m_DIFA},
303 {UnitParams::difc, m_DIFC},
304 {UnitParams::tzero, m_TZERO}});
305 return;
306 }
308 m_TwoTheta = (*m_pTwoThetas)[i];
309 m_L2 = (*m_pL2s)[i];
310 double Efix = m_Efix;
311 if (m_pEfixedArray)
312 Efix = static_cast<double>(*(m_pEfixedArray + i));
313 m_DIFA = (*m_pDIFAs)[i];
314 m_DIFC = (*m_pDIFCs)[i];
315 m_TZERO = (*m_pTZEROs)[i];
316
317 Kernel::UnitParametersMap pmap = {{UnitParams::l2, m_L2}, {UnitParams::twoTheta, m_TwoTheta},
318 {UnitParams::efixed, Efix}, {UnitParams::difa, m_DIFA},
319 {UnitParams::difc, m_DIFC}, {UnitParams::tzero, m_TZERO}};
320 m_TargetUnit->initialize(m_L1, m_Emode, pmap);
321 m_SourceWSUnit->initialize(m_L1, m_Emode, pmap);
322 return;
323 }
324 default:
325 throw std::runtime_error("updateConversion: unknown type of conversion requested");
326 }
327} // namespace MDAlgorithms
332double UnitsConversionHelper::convertUnits(double val) const {
333 switch (m_UnitCnvrsn) {
334 case (CnvrtToMD::ConvertNo): {
335 return val;
336 }
337 case (CnvrtToMD::ConvertFast): {
338 return m_Factor * std::pow(val, m_Power);
339 }
341 return m_TargetUnit->singleFromTOF(val);
342 }
344 double tof = m_SourceWSUnit->singleToTOF(val);
345 return m_TargetUnit->singleFromTOF(tof);
346 }
347 default:
348 throw std::runtime_error("updateConversion: unknown type of conversion requested");
349 }
350}
351// copy constructor;
353 m_UnitCnvrsn = another.m_UnitCnvrsn;
354 m_Factor = another.m_Factor;
355 m_Power = another.m_Power;
356
357 m_Emode = another.m_Emode;
358 m_L1 = another.m_L1;
359 m_Efix = another.m_Efix;
360 m_TwoTheta = another.m_TwoTheta;
361 m_L2 = another.m_L2;
362 m_DIFA = another.m_DIFA;
363 m_DIFC = another.m_DIFC;
364 m_TZERO = another.m_TZERO;
365 m_pTwoThetas = another.m_pTwoThetas;
366 m_pL2s = another.m_pL2s;
368 m_pDIFAs = another.m_pDIFAs;
369 m_pDIFCs = another.m_pDIFCs;
370 m_pTZEROs = another.m_pTZEROs;
371
372 if (another.m_SourceWSUnit)
374 if (another.m_TargetUnit)
375 m_TargetUnit = Kernel::Unit_sptr(another.m_TargetUnit->clone());
376}
377
379 : m_UnitCnvrsn(CnvrtToMD::ConvertNo), m_Factor(1), m_Power(1), m_Emode(-1), // undefined
380 m_L1(1), m_Efix(1), m_TwoTheta(0), m_L2(1), m_DIFA(0.), m_DIFC(0.), m_TZERO(0.), m_pTwoThetas(nullptr),
381 m_pL2s(nullptr), m_pEfixedArray(nullptr), m_pDIFAs(nullptr), m_pDIFCs(nullptr), m_pTZEROs(nullptr) {}
382
383} // namespace Mantid::MDAlgorithms
const std::vector< double > & m_L2
Definition: LoadEMU.cpp:231
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
Definition: Axis.cpp:28
Class to represent a numeric axis of a workspace.
Definition: NumericAxis.h:29
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
helper class describes the properties of target MD workspace, which should be obtained as the result ...
API::MatrixWorkspace_const_sptr getInWS() const
Kernel::DeltaEMode::Type getEMode() const
DataObjects::TableWorkspace_const_sptr m_PreprDetTable
CnvrtToMD::ConvertUnits analyzeUnitsConversion(const std::string &UnitsFrom, const std::string &UnitsTo, bool forceViaTOF=false)
establish and initialize proper units conversion from input to output units;
bool isUnitConverted() const
Test and check if units conversion really occurs.
void updateConversion(size_t i)
Method updates unit conversion given the index of detector parameters in the array of detectors.
void initialize(const MDWSDescription &targetWSDescr, const std::string &unitsTo, bool forceViaTOF=false)
Initialize unit conversion helper This method is interface to internal initialize method,...
double convertUnits(double val) const
do actual unit conversion from input to oputput data
std::pair< double, double > getConversionRange(double x1, double x2) const
Method verify if the Units transformation is well defined in the range provided and if not returns th...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< const TableWorkspace > TableWorkspace_const_sptr
shared pointer to Mantid::DataObjects::TableWorkspace (const version)
MANTID_KERNEL_DLL int isMember(const std::vector< std::string > &group, const std::string &candidate)
checks if the candidate is the member of the group
Definition: Strings.cpp:1050
std::unordered_map< UnitParams, double > UnitParametersMap
Definition: Unit.h:30
std::shared_ptr< Unit > Unit_sptr
Shared pointer to the Unit base class.
Definition: Unit.h:229
bool inRange(const std::pair< double, double > &range, const double &val)
Generate a tableworkspace to store the calibration results.