Mantid
Loading...
Searching...
No Matches
MDTransfModQ.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 +
8#include "Eigen/Core"
9#include "Eigen/Dense"
12
13namespace Mantid::MDAlgorithms {
14// register the class, whith conversion factory under ModQ name
15// clang-format off
16DECLARE_MD_TRANSFID(MDTransfModQ, |Q|)
17// clang-format on
18
19
26const std::string MDTransfModQ::inputUnitID(Kernel::DeltaEMode::Type dEmode,
27 API::MatrixWorkspace_const_sptr inWS) const {
28 UNUSED_ARG(inWS);
29 switch (dEmode) {
31 return "Momentum";
33 return "DeltaE";
35 return "DeltaE";
36 default:
37 throw(std::invalid_argument(" MDTransfModQ::inputUnitID: this class "
38 "supports only conversion in Elastic and "
39 "Inelastic energy transfer modes"));
40 }
41}
42
51 UNUSED_ARG(inWS);
52 switch (mode) {
54 return 2;
56 return 2;
58 return 1;
59 default:
60 throw(std::invalid_argument("Unknown or unsupported energy conversion mode"));
61 }
62}
63
79bool MDTransfModQ::calcMatrixCoord(const double &deltaEOrK0, std::vector<coord_t> &Coord, double &signal,
80 double &ErrSq) const {
81 UNUSED_ARG(signal);
82 UNUSED_ARG(ErrSq);
84 return calcMatrixCoordElastic(deltaEOrK0, Coord);
85 } else {
86 return calcMatrixCoordInelastic(deltaEOrK0, Coord);
87 }
88}
89
100bool MDTransfModQ::calcGenericVariables(std::vector<coord_t> &Coord, size_t nd) {
101 // sanity check. If fails, something went fundamentally wrong
102 if (m_NMatrixDim + m_AddDimCoordinates.size() != nd) {
103 std::string ERR = "Number of matrix dimensions: " + std::to_string(m_NMatrixDim) +
104 " plus number of additional dimensions: " + std::to_string(m_AddDimCoordinates.size()) +
105 " not equal to number of workspace dimensions: " + std::to_string(nd);
106 throw(std::invalid_argument(ERR));
107 }
108
109 // in Elastic case, 1 coordinate (|Q|) came from workspace
110 // in inelastic 2 coordinates (|Q| dE) came from workspace. All other are
111 // defined by properties.
112 // m_NMatrixDim is either 1 in elastic case or 2 in inelastic
113 size_t ic(0);
114 for (size_t i = m_NMatrixDim; i < nd; i++) {
116 return false;
117 Coord[i] = m_AddDimCoordinates[ic];
118 ic++;
119 }
120 return true;
121}
122
131bool MDTransfModQ::calcYDepCoordinates(std::vector<coord_t> &Coord, size_t i) {
132 UNUSED_ARG(Coord);
133 m_ex = (m_DetDirecton + i)->X();
134 m_ey = (m_DetDirecton + i)->Y();
135 m_ez = (m_DetDirecton + i)->Z();
136 // if input energy changes on each detector (efixed, indirect mode only), then
137 // set up its value
138 if (m_pEfixedArray) {
139 m_eFixed = double(*(m_pEfixedArray + i));
141 }
142 // if spectra masked, this spectra should be excluded
143 if (m_pDetMasks) {
144 if (*(m_pDetMasks + i) > 0)
145 return false;
146 }
147 return true;
148}
149
164bool MDTransfModQ::calcMatrixCoordInelastic(const double deltaE, std::vector<coord_t> &Coord) const {
165 if (deltaE < m_DimMin[1] || deltaE >= m_DimMax[1])
166 return false;
167 Coord[1] = static_cast<coord_t>(deltaE);
168
169 // x,y,z refer to internal coordinate system where Z is the beam direction
170 double qx{0.0}, qy{0.0}, qz{0.0};
171 if (this->m_Emode == Kernel::DeltaEMode::Direct) {
172 const double kFinal = sqrt((m_eFixed - deltaE) / PhysicalConstants::E_mev_toNeutronWavenumberSq);
173 qx = -m_ex * kFinal;
174 qy = -m_ey * kFinal;
175 qz = m_kFixed - m_ez * kFinal;
176 } else {
177 const double kInitial = sqrt((m_eFixed + deltaE) / PhysicalConstants::E_mev_toNeutronWavenumberSq);
178 qx = -m_ex * m_kFixed;
179 qy = -m_ey * m_kFixed;
180 qz = kInitial - m_ez * m_kFixed;
181 }
182 return applyCoordTransf(qx, qy, qz, Coord);
183}
198bool MDTransfModQ::calcMatrixCoordElastic(const double k0, std::vector<coord_t> &Coord) const {
199 double qx = -m_ex * k0;
200 double qy = -m_ey * k0;
201 double qz = (1 - m_ez) * k0;
202 return applyCoordTransf(qx, qy, qz, Coord);
203}
204
215std::vector<double> MDTransfModQ::getExtremumPoints(const double eMin, const double eMax, size_t det_num) const {
216 std::vector<double> rez(2);
217 switch (m_Emode) {
219 rez[0] = eMin;
220 rez[1] = eMax;
221 return rez;
222 }
225 double ei = m_eFixed;
226 if (m_pEfixedArray)
227 ei = double(*(m_pEfixedArray + det_num));
228
229 double ez = (m_DetDirecton + det_num)->Z();
230 double eps_extr = ei * (1 - ez * ez);
231 if (eps_extr > eMin && eps_extr < eMax) {
232 rez.resize(3);
233 rez[0] = eMin;
234 rez[1] = eps_extr;
235 rez[2] = eMax;
236 } else {
237 rez[0] = eMin;
238 rez[1] = eMax;
239 }
240 return rez;
241 }
242 default: {
243 throw std::invalid_argument("Undefined or unsupported energy conversion mode ");
244 }
245 }
246 return rez;
247}
248
252 //********** Generic part of initialization, common for elastic and inelastic
253 // modes:
254 // get transformation matrix (needed for CrystalAsPoder mode)
255 m_RotMat = ConvParams.getTransfMatrix();
256 m_pEfixedArray = nullptr;
257 m_invertRot = false;
258 if (!ConvParams.m_PreprDetTable)
259 throw(std::runtime_error("The detectors have not been preprocessed but "
260 "they have to before running initialize"));
261
262 // get pointer to the positions of the detectors
263 std::vector<Kernel::V3D> const &DetDir = ConvParams.m_PreprDetTable->getColVector<Kernel::V3D>("DetDirections");
264 m_DetDirecton = &DetDir[0]; //
265
266 // get min and max values defined by the algorithm.
267 ConvParams.getMinMax(m_DimMin, m_DimMax);
268 // m_DimMin/max here are momentums and they are verified on momentum squared
269 // base
270 if (m_DimMin[0] < 0)
271 m_DimMin[0] = 0;
272 if (m_DimMax[0] < 0)
273 m_DimMax[0] = 0;
274
275 // m_DimMin here is a momentum and it is verified on momentum squared base
276 m_DimMin[0] *= m_DimMin[0];
277 m_DimMax[0] *= m_DimMax[0];
278 if (std::fabs(m_DimMin[0] - m_DimMax[0]) < FLT_EPSILON || m_DimMax[0] < m_DimMin[0]) {
279 std::string ERR =
280 "ModQ coordinate transformation: Min Q^2 value: " + boost::lexical_cast<std::string>(m_DimMin[0]) +
281 " is more or equal then Max Q^2 value: " + boost::lexical_cast<std::string>(m_DimMax[0]);
282 throw(std::invalid_argument(ERR));
283 }
284 m_AddDimCoordinates = ConvParams.getAddCoord();
285
286 //************ specific part of the initialization, dependent on emode:
287 m_Emode = ConvParams.getEMode();
290 // energy needed in inelastic case
291 volatile auto Ei = ConvParams.m_PreprDetTable->getLogs()->getPropertyValueAsType<double>("Ei");
292 m_eFixed = Ei;
293 if (Ei != m_eFixed) // Ei is NaN, try Efixed, but the value should be
294 // overridden later
295 {
296 try {
297 m_eFixed = ConvParams.m_PreprDetTable->getLogs()->getPropertyValueAsType<double>("eFixed");
298 } catch (...) {
299 }
300 }
301
302 // the wave vector of incident neutrons;
304 m_pEfixedArray = nullptr;
305 if (m_Emode == static_cast<int>(Kernel::DeltaEMode::Indirect))
306 m_pEfixedArray = ConvParams.m_PreprDetTable->getColDataArray<float>("eFixed");
308 throw(std::invalid_argument("MDTransfModQ::initialize::Unknown energy conversion mode"));
309
310 m_pDetMasks = ConvParams.m_PreprDetTable->getColDataArray<int>("detMask");
311}
325 UNUSED_ARG(inWS);
326 std::vector<std::string> default_dim_ID;
327 switch (dEmode) {
329 default_dim_ID.resize(1);
330 break;
331 }
334 default_dim_ID.resize(2);
335 default_dim_ID[1] = "DeltaE";
336 break;
337 }
338 default:
339 throw(std::invalid_argument("MDTransfModQ::getDefaultDimID::Unknown energy conversion mode"));
340 }
341 default_dim_ID[0] = "|Q|";
342
343 return default_dim_ID;
344}
345
353 UNUSED_ARG(inWS);
354 std::vector<std::string> UnitID = this->getDefaultDimID(dEmode, inWS);
355 // TODO: is it really momentum transfer, as MomentumTransfer units are seems
356 // bound to elastic mode only (at least accorting to Units description on
357 // Wiki)?
358 if (dEmode == Kernel::DeltaEMode::Elastic) {
359 UnitID[0] = "Momentum";
360 } else {
361 UnitID[0] = "MomentumTransfer";
362 }
363 return UnitID;
364}
365
368 : m_ex(0), m_ey(0), m_ez(1), m_DetDirecton(nullptr), //,m_NMatrixDim(-1)
369 m_NMatrixDim(0), // uninitialized
370 m_Emode(Kernel::DeltaEMode::Undefined), // uninitialized
371 m_kFixed(1.), m_eFixed(1.), m_pEfixedArray(nullptr), m_pDetMasks(nullptr), m_invertRot(false) {}
372
377std::pair<coord_t, coord_t> MDTransfModQ::getDimBounds(size_t dim) const {
378 return std::make_pair(m_DimMin[dim], m_DimMax[dim]);
379}
380
381std::vector<std::string> MDTransfModQ::getEmodes() const { return Kernel::DeltaEMode::availableTypes(); }
382
389 Mantid::API::MatrixWorkspace_sptr underlyingWorkspace) const {
391 auto isQ = true;
392 setter(mdWorkspace, underlyingWorkspace, isQ, m_Emode);
393}
394
395bool MDTransfModQ::applyCoordTransf(double qx, double qy, double qz, std::vector<coord_t> &Coord) const {
396 std::array<coord_t, 3> Q{};
397 if (m_invertRot) {
398 calcMatrixCoordLinSys(qx, qy, qz, Q);
399 } else {
400 // transformation matrix has to be here for "Crystal AS Powder conversion
401 // mode, further specialization possible if "powder" mode defined"
402 Q[0] = static_cast<coord_t>(m_RotMat[0] * qx + m_RotMat[1] * qy + m_RotMat[2] * qz);
403 Q[1] = static_cast<coord_t>(m_RotMat[3] * qx + m_RotMat[4] * qy + m_RotMat[5] * qz);
404 Q[2] = static_cast<coord_t>(m_RotMat[6] * qx + m_RotMat[7] * qy + m_RotMat[8] * qz);
405 }
406
407 const auto Qsq = Q[0] * Q[0] + Q[1] * Q[1] + Q[2] * Q[2];
408 if (Qsq < static_cast<coord_t>(m_DimMin[0]) || Qsq >= static_cast<coord_t>(m_DimMax[0])) {
409 return false;
410 }
411 Coord[0] = static_cast<coord_t>(std::sqrt(Qsq));
412
413 return true;
414}
415
416void MDTransfModQ::calcMatrixCoordLinSys(double qx, double qy, double qz, std::array<coord_t, 3> &Coord) const {
417 // For some computations, e.g. continuous rotation in ConvToMDEventsWS, the rotation matrix
418 // has to be recomputed multiple times, so it is not inverted prior to calculating the coordinates.
419 // Deferring to a linear system solution here makes it slightly more efficient and stable.
420 Eigen::Map<const Eigen::Matrix<double, 3, 3, Eigen::RowMajor>> map_rm(m_RotMat.data());
421 const Eigen::Vector3d qs(qx, qy, qz);
422 const Eigen::PartialPivLU<Eigen::Matrix<double, 3, 3, Eigen::RowMajor>> lu(map_rm);
423 Eigen::Vector3d coords = lu.solve(qs);
424
425 Coord[0] = static_cast<coord_t>(coords[0]);
426 Coord[1] = static_cast<coord_t>(coords[1]);
427 Coord[2] = static_cast<coord_t>(coords[2]);
428}
429
430} // namespace Mantid::MDAlgorithms
#define DECLARE_MD_TRANSFID(classname, regID)
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
Class for 3D vectors.
Definition V3D.h:34
DisplayNormalizationSetter: Sets the displaynormalization on a workspace based on several parameters ...
Class responsible for conversion of input workspace data into proper number of output dimensions for ...
void setDisplayNormalization(Mantid::API::IMDWorkspace_sptr mdWorkspace, Mantid::API::MatrixWorkspace_sptr underlyingWorkspace) const override
Set the display normalization for Q.
bool calcGenericVariables(std::vector< coord_t > &Coord, size_t nd) override
Method fills-in all additional properties requested by user and not defined by matrix workspace itsel...
bool calcMatrixCoordInelastic(const double deltaE, std::vector< coord_t > &Coord) const
how to transform workspace data in inelastic case
std::vector< double > m_RotMat
Kernel::V3D const * m_DetDirecton
bool applyCoordTransf(double qx, double qy, double qz, std::vector< coord_t > &Coord) const
bool calcMatrixCoordElastic(const double k0, std::vector< coord_t > &Coord) const
how to transform workspace data in elastic case
bool calcMatrixCoord(const double &deltaEOrK0, std::vector< coord_t > &Coord, double &signal, double &ErrSq) const override
Convert single point of matrix workspace into reciprocal space and (optionally) modify signal and err...
void calcMatrixCoordLinSys(double qx, double qy, double qz, std::array< coord_t, 3 > &Coord) const
std::vector< double > m_DimMin
unsigned int getNMatrixDimensions(Kernel::DeltaEMode::Type mode, API::MatrixWorkspace_const_sptr inWS=API::MatrixWorkspace_const_sptr()) const override
return the number of dimensions, calculated by the transformation from the workspace.
std::vector< double > m_DimMax
Kernel::DeltaEMode::Type m_Emode
std::vector< std::string > getEmodes() const override
energy conversion modes supported by this class; The class supports three standard energy conversion ...
std::vector< std::string > outputUnitID(Kernel::DeltaEMode::Type dEmode, API::MatrixWorkspace_const_sptr inWS=API::MatrixWorkspace_const_sptr()) const override
function returns units ID-s which this transformation prodiuces its ouptut.
std::vector< coord_t > m_AddDimCoordinates
the vector of the additional coordinates which define additional MD dimensions.
std::vector< std::string > getDefaultDimID(Kernel::DeltaEMode::Type dEmode, API::MatrixWorkspace_const_sptr inWS=API::MatrixWorkspace_const_sptr()) const override
the default dimID-s in ModQ mode are |Q| and dE if necessary
void initialize(const MDWSDescription &ConvParams) override
function initializes all variables necessary for converting workspace variables into MD variables in ...
std::vector< double > getExtremumPoints(const double eMin, const double eMax, size_t det_num) const override
method returns the vector of input coordinates values where the transformed coordinates reach its ext...
bool calcYDepCoordinates(std::vector< coord_t > &Coord, size_t i) override
Method updates the value of pre-processed detector coordinates in Q-space, used by other functions.
std::pair< coord_t, coord_t > getDimBounds(size_t dim) const override
helper class describes the properties of target MD workspace, which should be obtained as the result ...
Kernel::DeltaEMode::Type getEMode() const
std::vector< coord_t > getAddCoord() const
void getMinMax(std::vector< double > &min, std::vector< double > &max) const
get vector of minimal and maximal values from the class
DataObjects::TableWorkspace_const_sptr m_PreprDetTable
std::vector< double > getTransfMatrix() const
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static constexpr double E_mev_toNeutronWavenumberSq
Transformation coefficient to transform neutron energy into neutron wavevector: K-neutron[m^-10] = sq...
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition MDTypes.h:27
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
Defines the possible energy transfer modes:
Definition DeltaEMode.h:23
static const std::vector< std::string > availableTypes()
Returns the string list of available modes.
Type
Define the available energy transfer modes It is important to assign enums proper numbers,...
Definition DeltaEMode.h:29