Mantid
Loading...
Searching...
No Matches
CalculateCoverageDGS.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 +
9#include "MantidAPI/Run.h"
10#include "MantidAPI/Sample.h"
24
25#include <boost/lexical_cast.hpp>
26
27namespace Mantid::MDAlgorithms {
28using namespace Mantid::Kernel;
30using namespace Mantid::API;
31using namespace Mantid::DataObjects;
32using namespace Mantid::Geometry;
33
34namespace {
35// function to compare two intersections (h,k,l,Momentum) by scattered momentum
36bool compareMomentum(const Mantid::Kernel::VMD &v1, const Mantid::Kernel::VMD &v2) { return (v1[3] < v2[3]); }
37} // namespace
38// Register the algorithm into the AlgorithmFactory
39DECLARE_ALGORITHM(CalculateCoverageDGS)
40
41
44 : m_hmin(0.f), m_hmax(0.f), m_kmin(0.f), m_kmax(0.f), m_lmin(0.f), m_lmax(0.f), m_dEmin(0.f), m_dEmax(0.f),
45 m_Ei(0.), m_ki(0.), m_kfmin(0.), m_kfmax(0.), m_hIntegrated(false), m_kIntegrated(false), m_lIntegrated(false),
46 m_dEIntegrated(false), m_hX(), m_kX(), m_lX(), m_eX(), m_hIdx(-1), m_kIdx(-1), m_lIdx(-1), m_eIdx(-1),
47 m_rubw(3, 3), m_normWS() {}
48
50const std::string CalculateCoverageDGS::name() const { return "CalculateCoverageDGS"; }
51
53int CalculateCoverageDGS::version() const { return 1; }
54
56const std::string CalculateCoverageDGS::category() const { return "Inelastic\\Planning;MDAlgorithms\\Planning"; }
57
59const std::string CalculateCoverageDGS::summary() const {
60 return "Calculate the reciprocal space coverage for direct geometry "
61 "spectrometers";
62}
63
68 const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 /
70
71 auto &hDim = *m_normWS->getDimension(m_hIdx);
72 m_hX.resize(hDim.getNBins());
73 for (size_t i = 0; i < m_hX.size(); ++i) {
74 m_hX[i] = hDim.getX(i);
75 }
76 auto &kDim = *m_normWS->getDimension(m_kIdx);
77 m_kX.resize(kDim.getNBins());
78 for (size_t i = 0; i < m_kX.size(); ++i) {
79 m_kX[i] = kDim.getX(i);
80 }
81 auto &lDim = *m_normWS->getDimension(m_lIdx);
82 m_lX.resize(lDim.getNBins());
83 for (size_t i = 0; i < m_lX.size(); ++i) {
84 m_lX[i] = lDim.getX(i);
85 }
86 // NOTE: store k final instead
87 auto &eDim = *m_normWS->getDimension(m_eIdx);
88 m_eX.resize(eDim.getNBins());
89 for (size_t i = 0; i < m_eX.size(); ++i) {
90 m_eX[i] = std::sqrt(energyToK * (m_Ei - eDim.getX(i)));
91 }
92}
93
97 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Mantid::Kernel::Direction::Input,
98 std::make_shared<InstrumentValidator>()),
99 "An input workspace.");
100
101 auto mustBe3D = std::make_shared<ArrayLengthValidator<double>>(3);
102 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
103 mustBePositive->setLower(0.0);
104
105 std::vector<double> Q1(3, 0.), Q2(3, 0), Q3(3, 0);
106 Q1[0] = 1.;
107 Q2[1] = 1.;
108 Q3[2] = 1.;
109 declareProperty(std::make_unique<ArrayProperty<double>>("Q1Basis", std::move(Q1), mustBe3D->clone()),
110 "Q1 projection direction in the x,y,z format. Q1, Q2, Q3 "
111 "must not be coplanar");
112 declareProperty(std::make_unique<ArrayProperty<double>>("Q2Basis", std::move(Q2), mustBe3D->clone()),
113 "Q2 projection direction in the x,y,z format. Q1, Q2, Q3 "
114 "must not be coplanar");
115 declareProperty(std::make_unique<ArrayProperty<double>>("Q3Basis", std::move(Q3), std::move(mustBe3D)),
116 "Q3 projection direction in the x,y,z format. Q1, Q2, Q3 "
117 "must not be coplanar");
118 declareProperty(std::make_unique<PropertyWithValue<double>>("IncidentEnergy", EMPTY_DBL(), std::move(mustBePositive),
120 "Incident energy. If set, will override Ei in the input workspace");
121
122 std::vector<std::string> options{"Q1", "Q2", "Q3", "DeltaE"};
123
124 for (int i = 1; i <= 4; i++) {
125 std::string dim("Dimension");
126 dim += boost::lexical_cast<std::string>(i);
127 declareProperty(dim, options[i - 1], std::make_shared<StringListValidator>(options),
128 "Dimension to bin or integrate");
129 declareProperty(dim + "Min", EMPTY_DBL(), dim + " minimum value. If empty will take minimum possible value.");
130 declareProperty(dim + "Max", EMPTY_DBL(), dim + " maximum value. If empty will take maximum possible value.");
131 declareProperty(dim + "Step", EMPTY_DBL(),
132 dim + " step size. If empty the dimension will be "
133 "integrated between minimum and maximum values");
134 }
136 std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Mantid::Kernel::Direction::Output),
137 "A name for the output data MDHistoWorkspace.");
138}
139
143 const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 /
145 // get the limits
146 Mantid::API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
147 convention = Kernel::ConfigService::Instance().getString("Q.convention");
148 // cache two theta and phi
149 const auto &detectorInfo = inputWS->detectorInfo();
150 std::vector<double> tt, phi;
151 for (size_t i = 0; i < detectorInfo.size(); ++i) {
152 if (!detectorInfo.isMasked(i) && !detectorInfo.isMonitor(i)) {
153 tt.emplace_back(detectorInfo.twoTheta(i, V3D(0, 0, 0), V3D(0, 0, 1)));
154 phi.emplace_back(detectorInfo.phi(i));
155 }
156 }
157
158 double ttmax = *(std::max_element(tt.begin(), tt.end()));
159
160 m_Ei = getProperty("IncidentEnergy");
161
162 if (m_Ei == EMPTY_DBL()) {
163 if (inputWS->run().hasProperty("Ei")) {
164 Kernel::Property const *eiprop = inputWS->run().getProperty("Ei");
165 m_Ei = boost::lexical_cast<double>(eiprop->value());
166 if (m_Ei <= 0) {
167 throw std::invalid_argument("Ei stored in the workspace is not positive");
168 }
169 } else {
170 throw std::invalid_argument("Could not find Ei in the workspace. Please enter a positive value");
171 }
172 }
173
174 // Check if there is duplicate elements in dimension selection, and calculate
175 // the affine matrix
176 Kernel::Matrix<coord_t> affineMat(4, 4);
177 double q1min(0.), q1max(0.), q2min(0.), q2max(0.), q3min(0.), q3max(0.);
178 double q1step(0.), q2step(0.), q3step(0.), dEstep(0.);
179 size_t q1NumBins = 1, q2NumBins = 1, q3NumBins = 1, dENumBins = 1;
180 for (int i = 1; i <= 4; i++) {
181 std::string dim("Dimension");
182 dim += boost::lexical_cast<std::string>(i);
183 std::string dimensioni = getProperty(dim);
184 if (dimensioni == "Q1") {
185 affineMat[i - 1][0] = 1.;
186 q1min = getProperty(dim + "Min");
187 q1max = getProperty(dim + "Max");
188 q1step = getProperty(dim + "Step");
189 m_hIdx = i - 1;
190 }
191 if (dimensioni == "Q2") {
192 affineMat[i - 1][1] = 1.;
193 q2min = getProperty(dim + "Min");
194 q2max = getProperty(dim + "Max");
195 q2step = getProperty(dim + "Step");
196 m_kIdx = i - 1;
197 }
198 if (dimensioni == "Q3") {
199 affineMat[i - 1][2] = 1.;
200 q3min = getProperty(dim + "Min");
201 q3max = getProperty(dim + "Max");
202 q3step = getProperty(dim + "Step");
203 m_lIdx = i - 1;
204 }
205 if (dimensioni == "DeltaE") {
206 affineMat[i - 1][3] = 1.;
207 m_eIdx = i - 1;
208 double dmin = getProperty(dim + "Min");
209 if (dmin == EMPTY_DBL()) {
210 m_dEmin = -static_cast<coord_t>(m_Ei);
211 } else {
212 m_dEmin = static_cast<coord_t>(dmin);
213 }
214 double dmax = getProperty(dim + "Max");
215 if (dmax == EMPTY_DBL()) {
216 m_dEmax = static_cast<coord_t>(m_Ei);
217 } else {
218 m_dEmax = static_cast<coord_t>(dmax);
219 }
220 dEstep = getProperty(dim + "Step");
221 if (dEstep == EMPTY_DBL()) {
222 dENumBins = 1;
223 } else {
224 dENumBins = static_cast<size_t>((m_dEmax - m_dEmin) / dEstep);
225 if (dEstep * static_cast<double>(dENumBins) + m_dEmin < m_dEmax) {
226 dENumBins += 1;
227 m_dEmax = static_cast<coord_t>(dEstep * static_cast<double>(dENumBins)) + m_dEmin;
228 }
229 }
230 }
231 }
232
233 if (affineMat.determinant() == 0.) {
234 g_log.debug() << affineMat;
235 throw std::invalid_argument("Please make sure each dimension is selected only once.");
236 }
237
238 // Qmax is at kf=kfmin or kf=kfmax
239 m_ki = std::sqrt(energyToK * m_Ei);
240 if (m_Ei > m_dEmin) {
241 m_kfmin = std::sqrt(energyToK * (m_Ei - m_dEmin));
242 } else {
243 m_kfmin = 0.;
244 }
245 if (m_Ei > m_dEmax) {
246 m_kfmax = std::sqrt(energyToK * (m_Ei - m_dEmax));
247 } else {
248 m_kfmax = 0;
249 }
250
251 double QmaxTemp = sqrt(m_ki * m_ki + m_kfmin * m_kfmin - 2 * m_ki * m_kfmin * cos(ttmax));
252 double Qmax = QmaxTemp;
253 QmaxTemp = sqrt(m_ki * m_ki + m_kfmax * m_kfmax - 2 * m_ki * m_kfmax * cos(ttmax));
254 if (QmaxTemp > Qmax)
255 Qmax = QmaxTemp;
256
257 // get goniometer
258 DblMatrix gon = DblMatrix(3, 3, true);
259 if (inputWS->run().getGoniometer().isDefined()) {
260 gon = inputWS->run().getGoniometerMatrix();
261 }
262
263 // get the UB
264 DblMatrix UB = DblMatrix(3, 3, true) * (0.5 / M_PI);
265 if (inputWS->sample().hasOrientedLattice()) {
266 UB = inputWS->sample().getOrientedLattice().getUB();
267 }
268
269 // get the W matrix
270 DblMatrix W = DblMatrix(3, 3);
271 std::vector<double> Q1Basis = getProperty("Q1Basis");
272 std::vector<double> Q2Basis = getProperty("Q2Basis");
273 std::vector<double> Q3Basis = getProperty("Q3Basis");
274 W.setColumn(0, Q1Basis);
275 W.setColumn(1, Q2Basis);
276 W.setColumn(2, Q3Basis);
277
278 m_rubw = gon * UB * W * (2.0 * M_PI);
279
280 // calculate maximum original limits
282 ol.setUB(m_rubw);
283 m_hmin = static_cast<coord_t>(-Qmax * ol.a());
284 m_hmax = static_cast<coord_t>(Qmax * ol.a());
285 m_kmin = static_cast<coord_t>(-Qmax * ol.b());
286 m_kmax = static_cast<coord_t>(Qmax * ol.b());
287 m_lmin = static_cast<coord_t>(-Qmax * ol.c());
288 m_lmax = static_cast<coord_t>(Qmax * ol.c());
289 m_rubw.Invert();
290 // adjust Q steps/dimensions
291 if (q1min == EMPTY_DBL()) {
292 q1min = m_hmin;
293 }
294 if (q1max == EMPTY_DBL()) {
295 q1max = m_hmax;
296 }
297 if (q1min >= q1max) {
298 throw std::invalid_argument("Q1max has to be greater than Q1min");
299 }
300 if (q1step == EMPTY_DBL()) {
301 q1NumBins = 1;
302 } else {
303 q1NumBins = static_cast<size_t>((q1max - q1min) / q1step);
304 if (q1step * static_cast<double>(q1NumBins) + q1min < q1max) {
305 q1NumBins += 1;
306 q1max = q1step * static_cast<double>(q1NumBins) + q1min;
307 }
308 }
309
310 if (q2min == EMPTY_DBL()) {
311 q2min = m_kmin;
312 }
313 if (q2max == EMPTY_DBL()) {
314 q2max = m_kmax;
315 }
316 if (q2min >= q2max) {
317 throw std::invalid_argument("Q2max has to be greater than Q2min");
318 }
319 if (q2step == EMPTY_DBL()) {
320 q2NumBins = 1;
321 } else {
322 q2NumBins = static_cast<size_t>((q2max - q2min) / q2step);
323 if (q2step * static_cast<double>(q2NumBins) + q2min < q2max) {
324 q2NumBins += 1;
325 q2max = q2step * static_cast<double>(q2NumBins) + q2min;
326 }
327 }
328
329 if (q3min == EMPTY_DBL()) {
330 q3min = m_lmin;
331 }
332 if (q3max == EMPTY_DBL()) {
333 q3max = m_lmax;
334 }
335 if (q3min >= q3max) {
336 throw std::invalid_argument("Q3max has to be greater than Q3min");
337 }
338 if (q3step == EMPTY_DBL()) {
339 q3NumBins = 1;
340 } else {
341 q3NumBins = static_cast<size_t>((q3max - q3min) / q3step);
342 if (q3step * static_cast<double>(q3NumBins) + q3min < q3max) {
343 q3NumBins += 1;
344 q3max = q3step * static_cast<double>(q3NumBins) + q3min;
345 }
346 }
347
348 // create the output workspace
349 std::vector<Mantid::Geometry::MDHistoDimension_sptr> binDimensions;
350
351 // Define frames
352 Mantid::Geometry::GeneralFrame frame1("Q1", "");
353 Mantid::Geometry::GeneralFrame frame2("Q2", "");
354 Mantid::Geometry::GeneralFrame frame3("Q3", "");
355 Mantid::Geometry::GeneralFrame frame4("meV", "");
356 auto out1 = std::make_shared<MDHistoDimension>("Q1", "Q1", frame1, static_cast<coord_t>(q1min),
357 static_cast<coord_t>(q1max), q1NumBins);
358 auto out2 = std::make_shared<MDHistoDimension>("Q2", "Q2", frame2, static_cast<coord_t>(q2min),
359 static_cast<coord_t>(q2max), q2NumBins);
360 auto out3 = std::make_shared<MDHistoDimension>("Q3", "Q3", frame3, static_cast<coord_t>(q3min),
361 static_cast<coord_t>(q3max), q3NumBins);
362 auto out4 = std::make_shared<MDHistoDimension>("DeltaE", "DeltaE", frame4, static_cast<coord_t>(m_dEmin),
363 static_cast<coord_t>(m_dEmax), dENumBins);
364
365 for (size_t row = 0; row <= 3; row++) {
366 if (affineMat[row][0] == 1.) {
367 binDimensions.emplace_back(out1);
368 }
369 if (affineMat[row][1] == 1.) {
370 binDimensions.emplace_back(out2);
371 }
372 if (affineMat[row][2] == 1.) {
373 binDimensions.emplace_back(out3);
374 }
375 if (affineMat[row][3] == 1.) {
376 binDimensions.emplace_back(out4);
377 }
378 }
379
380 m_normWS = std::make_shared<MDHistoWorkspace>(binDimensions);
381 m_normWS->setTo(0., 0., 0.);
382 setProperty("OutputWorkspace", std::dynamic_pointer_cast<Workspace>(m_normWS));
383
385
386 const auto ndets = static_cast<int64_t>(tt.size());
387
389 for (int64_t i = 0; i < ndets; i++) {
391 auto intersections = calculateIntersections(tt[i], phi[i]);
392 if (intersections.empty())
393 continue;
394 auto intersectionsBegin = intersections.begin();
395 for (auto it = intersectionsBegin + 1; it != intersections.end(); ++it) {
396 const auto &curIntSec = *it;
397 const auto &prevIntSec = *(it - 1);
398 // the full vector isn't used so compute only what is necessary
399 double delta = curIntSec[3] - prevIntSec[3];
400 if (delta < 1e-10)
401 continue; // Assume zero contribution if difference is small
402 // Average between two intersections for final position
403 std::vector<coord_t> pos(4);
404 std::transform(curIntSec.getBareArray(), curIntSec.getBareArray() + 4, prevIntSec.getBareArray(), pos.begin(),
405 [](const double lhs, const double rhs) { return static_cast<coord_t>(0.5 * (lhs + rhs)); });
406 // transform kf to energy transfer
407 pos[3] = static_cast<coord_t>(m_Ei - pos[3] * pos[3] / energyToK);
408
409 std::vector<coord_t> posNew = affineMat * pos;
410 size_t linIndex = m_normWS->getLinearIndexAtCoord(posNew.data());
411 if (linIndex == size_t(-1))
412 continue;
413 PARALLEL_CRITICAL(updateMD) { m_normWS->setSignalAt(linIndex, 1.); }
414 }
416 }
418}
419
428std::vector<Kernel::VMD> CalculateCoverageDGS::calculateIntersections(const double theta, const double phi) {
429 V3D qout(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)), qin(0., 0., m_ki);
430 qout = m_rubw * qout;
431 qin = m_rubw * qin;
432 if (convention == "Crystallography") {
433 qout *= -1;
434 qin *= -1;
435 }
436 double hStart = qin.X() - qout.X() * m_kfmin, hEnd = qin.X() - qout.X() * m_kfmax;
437 double kStart = qin.Y() - qout.Y() * m_kfmin, kEnd = qin.Y() - qout.Y() * m_kfmax;
438 double lStart = qin.Z() - qout.Z() * m_kfmin, lEnd = qin.Z() - qout.Z() * m_kfmax;
439 double eps = 1e-10;
440 auto hNBins = m_hX.size();
441 auto kNBins = m_kX.size();
442 auto lNBins = m_lX.size();
443 auto eNBins = m_eX.size();
444 std::vector<Kernel::VMD> intersections;
445 intersections.reserve(hNBins + kNBins + lNBins + eNBins + 8); // 8 is 3*(min,max for each Q component)+kfmin+kfmax
446
447 // calculate intersections with planes perpendicular to h
448 if (fabs(hStart - hEnd) > eps) {
449 double fmom = (m_kfmax - m_kfmin) / (hEnd - hStart);
450 double fk = (kEnd - kStart) / (hEnd - hStart);
451 double fl = (lEnd - lStart) / (hEnd - hStart);
452 if (!m_hIntegrated) {
453 for (size_t i = 0; i < hNBins; i++) {
454 double hi = m_hX[i];
455 if ((hi >= m_hmin) && (hi <= m_hmax) && ((hStart - hi) * (hEnd - hi) < 0)) {
456 // if hi is between hStart and hEnd, then ki and li will be between
457 // kStart, kEnd and lStart, lEnd and momi will be between m_kfmin and
458 // m_kfmax
459 double ki = fk * (hi - hStart) + kStart;
460 double li = fl * (hi - hStart) + lStart;
461 if ((ki >= m_kmin) && (ki <= m_kmax) && (li >= m_lmin) && (li <= m_lmax)) {
462 double momi = fmom * (hi - hStart) + m_kfmin;
463 intersections.emplace_back(hi, ki, li, momi);
464 }
465 }
466 }
467 }
468 double momhMin = fmom * (m_hmin - hStart) + m_kfmin;
469 if ((momhMin - m_kfmin) * (momhMin - m_kfmax) < 0) // m_kfmin>m_kfmax
470 {
471 // khmin and lhmin
472 double khmin = fk * (m_hmin - hStart) + kStart;
473 double lhmin = fl * (m_hmin - hStart) + lStart;
474 if ((khmin >= m_kmin) && (khmin <= m_kmax) && (lhmin >= m_lmin) && (lhmin <= m_lmax)) {
475 intersections.emplace_back(m_hmin, khmin, lhmin, momhMin);
476 }
477 }
478 double momhMax = fmom * (m_hmax - hStart) + m_kfmin;
479 if ((momhMax - m_kfmin) * (momhMax - m_kfmax) <= 0) {
480 // khmax and lhmax
481 double khmax = fk * (m_hmax - hStart) + kStart;
482 double lhmax = fl * (m_hmax - hStart) + lStart;
483 if ((khmax >= m_kmin) && (khmax <= m_kmax) && (lhmax >= m_lmin) && (lhmax <= m_lmax)) {
484 intersections.emplace_back(m_hmax, khmax, lhmax, momhMax);
485 }
486 }
487 }
488
489 // calculate intersections with planes perpendicular to k
490 if (fabs(kStart - kEnd) > eps) {
491 double fmom = (m_kfmax - m_kfmin) / (kEnd - kStart);
492 double fh = (hEnd - hStart) / (kEnd - kStart);
493 double fl = (lEnd - lStart) / (kEnd - kStart);
494 if (!m_kIntegrated) {
495 for (size_t i = 0; i < kNBins; i++) {
496 double ki = m_kX[i];
497 if ((ki >= m_kmin) && (ki <= m_kmax) && ((kStart - ki) * (kEnd - ki) < 0)) {
498 // if ki is between kStart and kEnd, then hi and li will be between
499 // hStart, hEnd and lStart, lEnd and momi will be between m_kfmin and
500 // m_kfmax
501 double hi = fh * (ki - kStart) + hStart;
502 double li = fl * (ki - kStart) + lStart;
503 if ((hi >= m_hmin) && (hi <= m_hmax) && (li >= m_lmin) && (li <= m_lmax)) {
504 double momi = fmom * (ki - kStart) + m_kfmin;
505 intersections.emplace_back(hi, ki, li, momi);
506 }
507 }
508 }
509 }
510 double momkMin = fmom * (m_kmin - kStart) + m_kfmin;
511 if ((momkMin - m_kfmin) * (momkMin - m_kfmax) < 0) {
512 // hkmin and lkmin
513 double hkmin = fh * (m_kmin - kStart) + hStart;
514 double lkmin = fl * (m_kmin - kStart) + lStart;
515 if ((hkmin >= m_hmin) && (hkmin <= m_hmax) && (lkmin >= m_lmin) && (lkmin <= m_lmax)) {
516 intersections.emplace_back(hkmin, m_kmin, lkmin, momkMin);
517 }
518 }
519 double momkMax = fmom * (m_kmax - kStart) + m_kfmin;
520 if ((momkMax - m_kfmin) * (momkMax - m_kfmax) <= 0) {
521 // hkmax and lkmax
522 double hkmax = fh * (m_kmax - kStart) + hStart;
523 double lkmax = fl * (m_kmax - kStart) + lStart;
524 if ((hkmax >= m_hmin) && (hkmax <= m_hmax) && (lkmax >= m_lmin) && (lkmax <= m_lmax)) {
525 intersections.emplace_back(hkmax, m_kmax, lkmax, momkMax);
526 }
527 }
528 }
529
530 // calculate intersections with planes perpendicular to l
531 if (fabs(lStart - lEnd) > eps) {
532 double fmom = (m_kfmax - m_kfmin) / (lEnd - lStart);
533 double fh = (hEnd - hStart) / (lEnd - lStart);
534 double fk = (kEnd - kStart) / (lEnd - lStart);
535 if (!m_lIntegrated) {
536 for (size_t i = 0; i < lNBins; i++) {
537 double li = m_lX[i];
538 if ((li >= m_lmin) && (li <= m_lmax) && ((lStart - li) * (lEnd - li) < 0)) {
539 double hi = fh * (li - lStart) + hStart;
540 double ki = fk * (li - lStart) + kStart;
541 if ((hi >= m_hmin) && (hi <= m_hmax) && (ki >= m_kmin) && (ki <= m_kmax)) {
542 double momi = fmom * (li - lStart) + m_kfmin;
543 intersections.emplace_back(hi, ki, li, momi);
544 }
545 }
546 }
547 }
548 double momlMin = fmom * (m_lmin - lStart) + m_kfmin;
549 if ((momlMin - m_kfmin) * (momlMin - m_kfmax) <= 0) {
550 // hlmin and klmin
551 double hlmin = fh * (m_lmin - lStart) + hStart;
552 double klmin = fk * (m_lmin - lStart) + kStart;
553 if ((hlmin >= m_hmin) && (hlmin <= m_hmax) && (klmin >= m_kmin) && (klmin <= m_kmax)) {
554 intersections.emplace_back(hlmin, klmin, m_lmin, momlMin);
555 }
556 }
557 double momlMax = fmom * (m_lmax - lStart) + m_kfmin;
558 if ((momlMax - m_kfmin) * (momlMax - m_kfmax) < 0) {
559 // hlmax and klmax
560 double hlmax = fh * (m_lmax - lStart) + hStart;
561 double klmax = fk * (m_lmax - lStart) + kStart;
562 if ((hlmax >= m_hmin) && (hlmax <= m_hmax) && (klmax >= m_kmin) && (klmax <= m_kmax)) {
563 intersections.emplace_back(hlmax, klmax, m_lmax, momlMax);
564 }
565 }
566 }
567
568 // intersections with dE
569 if (!m_dEIntegrated) {
570 for (size_t i = 0; i < eNBins; i++) {
571 double kfi = m_eX[i];
572 if ((kfi - m_kfmin) * (kfi - m_kfmax) <= 0) {
573 double h = qin.X() - qout.X() * kfi;
574 double k = qin.Y() - qout.Y() * kfi;
575 double l = qin.Z() - qout.Z() * kfi;
576 if ((h >= m_hmin) && (h <= m_hmax) && (k >= m_kmin) && (k <= m_kmax) && (l >= m_lmin) && (l <= m_lmax)) {
577 intersections.emplace_back(h, k, l, kfi);
578 }
579 }
580 }
581 }
582
583 // endpoints
584 if ((hStart >= m_hmin) && (hStart <= m_hmax) && (kStart >= m_kmin) && (kStart <= m_kmax) && (lStart >= m_lmin) &&
585 (lStart <= m_lmax)) {
586 intersections.emplace_back(hStart, kStart, lStart, m_kfmin);
587 }
588 if ((hEnd >= m_hmin) && (hEnd <= m_hmax) && (kEnd >= m_kmin) && (kEnd <= m_kmax) && (lEnd >= m_lmin) &&
589 (lEnd <= m_lmax)) {
590 intersections.emplace_back(hEnd, kEnd, lEnd, m_kfmax);
591 }
592
593 // sort intersections by final momentum
594 using IterType = std::vector<Mantid::Kernel::VMD>::iterator;
595 std::stable_sort<IterType, bool (*)(const Mantid::Kernel::VMD &, const Mantid::Kernel::VMD &)>(
596 intersections.begin(), intersections.end(), compareMomentum);
597
598 return intersections;
599}
600
601} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
const std::vector< double > & rhs
#define fabs(x)
Definition Matrix.cpp:22
#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...
#define PARALLEL_CRITICAL(name)
#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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:426
A property class for workspaces.
GeneralFrame : Any MDFrame that isn't related to momemtum transfer.
Class to implement UB matrix.
void setUB(const Kernel::DblMatrix &newUB)
Sets the UB matrix and recalculates lattice parameters.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
Numerical Matrix class.
Definition Matrix.h:41
T determinant() const
Calculate the determinant.
Definition Matrix.cpp:1048
T Invert()
LU inversion routine.
Definition Matrix.cpp:924
void setColumn(const size_t nCol, const std::vector< T > &newCol)
Definition Matrix.cpp:675
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:95
virtual std::string value() const =0
Returns the value of the property as a string.
Class for 3D vectors.
Definition V3D.h:35
constexpr double X() const noexcept
Get x.
Definition V3D.h:239
constexpr double Y() const noexcept
Get y.
Definition V3D.h:240
constexpr double Z() const noexcept
Get z.
Definition V3D.h:241
CalculateCoverageDGS : Calculate coverage for single crystal direct geometry scattering.
bool m_hIntegrated
flag for integrated h,k,l,dE dimensions
const std::string category() const override
Algorithm's category for identification.
Mantid::DataObjects::MDHistoWorkspace_sptr m_normWS
Normalization workspace (this is the coverage workspace)
const std::string name() const override
Algorithms name for identification.
coord_t m_hmin
limits for h,k,l,dE dimensions
void cacheDimensionXValues()
Stores the X values from each H,K,L dimension as member variables.
double m_Ei
cached values for incident energy and momentum, final momentum min/max
Mantid::Kernel::DblMatrix m_rubw
(2*PiRUBW)^-1
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.
std::vector< double > m_hX
cached X values along dimensions h,k,l, dE
size_t m_hIdx
index of h,k,l,dE dimensions in the output workspaces
void exec() override
Execute the algorithm.
void init() override
Initialize the algorithm's properties.
std::vector< Kernel::VMD > calculateIntersections(const double theta, const double phi)
Calculate the points of intersection for the given detector with cuboid surrounding the detector posi...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
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.
Mantid::Kernel::Matrix< double > DblMatrix
Definition Matrix.h:205
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition MDTypes.h:27
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55