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?
47 m_SourceWSUnit = Kernel::UnitFactory::Instance().create(UnitsFrom);
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
55 m_TargetUnit = Kernel::UnitFactory::Instance().create(UnitsTo);
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
232 m_TargetUnit = Kernel::UnitFactory::Instance().create(unitsTo);
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:227
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
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:1080
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:194
bool inRange(const std::pair< double, double > &range, const double &val)
Generate a tableworkspace to store the calibration results.