Mantid
Loading...
Searching...
No Matches
SofQWNormalisedPolygon.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 +
25#include "MantidIndexing/IndexInfo.h"
27#include "MantidTypes/SpectrumDefinition.h"
28
29#include <boost/math/special_functions/pow.hpp>
30
31using boost::math::pow;
33
34namespace {
44double twoThetaFromLocalPoint(const Mantid::Geometry::DetectorInfo &detInfo, const size_t detInfoIndex,
45 const Mantid::Kernel::V3D &samplePos, const Mantid::Kernel::V3D &beamDir,
46 Mantid::Kernel::V3D point) {
47 const auto rotation = detInfo.rotation(detInfoIndex);
48 const auto position = detInfo.position(detInfoIndex);
49 rotation.rotate(point);
50 point += position;
51 point -= samplePos;
52 const auto twoTheta = point.angle(beamDir);
53 return twoTheta;
54}
55
66std::pair<double, double> cuboidTwoThetaRange(const Mantid::Geometry::DetectorInfo &detInfo, const size_t detInfoIndex,
67 const Mantid::Kernel::V3D &samplePos, const Mantid::Kernel::V3D &beamDir,
69 const auto back = geometry.leftBackBottom - geometry.leftFrontBottom;
70 const auto up = geometry.leftFrontTop - geometry.leftFrontBottom;
71 const auto right = geometry.rightFrontBottom - geometry.leftFrontBottom;
72 const std::array<Mantid::Kernel::V3D, 8> capRing{{geometry.leftFrontBottom, geometry.leftFrontBottom + back * 0.5,
73 geometry.leftBackBottom, geometry.leftBackBottom + up * 0.5,
74 geometry.leftBackBottom + up, geometry.leftFrontTop + back * 0.5,
75 geometry.leftFrontTop, geometry.leftFrontBottom + up * 0.5}};
76 double minTwoTheta{std::numeric_limits<double>::max()};
77 double maxTwoTheta{std::numeric_limits<double>::lowest()};
78 for (int width = 0; width < 2; ++width) {
79 const auto offset = right * static_cast<double>(width);
80 for (const auto &pointInRing : capRing) {
81 auto point = pointInRing;
82 if (width != 0) {
83 point += offset;
84 }
85 const auto current = twoThetaFromLocalPoint(detInfo, detInfoIndex, samplePos, beamDir, point);
86 minTwoTheta = std::min(minTwoTheta, current);
87 maxTwoTheta = std::max(maxTwoTheta, current);
88 }
89 }
90 const auto beltOffset = right * 0.5;
91 for (size_t beltIndex = 0; beltIndex < capRing.size(); beltIndex += 2) {
92 const auto point = capRing[beltIndex] + beltOffset;
93 const auto current = twoThetaFromLocalPoint(detInfo, detInfoIndex, samplePos, beamDir, point);
94 minTwoTheta = std::min(minTwoTheta, current);
95 maxTwoTheta = std::max(maxTwoTheta, current);
96 }
97 return std::make_pair(minTwoTheta, maxTwoTheta);
98}
99
111std::pair<double, double> cylinderTwoThetaRange(const Mantid::Geometry::DetectorInfo &detInfo,
112 const size_t detInfoIndex, const Mantid::Kernel::V3D &samplePos,
113 const Mantid::Kernel::V3D &beamDir,
115 Mantid::Kernel::V3D basis1{1., 0., 0.};
116 if (geometry.axis.X() != 0. && geometry.axis.Z() != 0) {
117 const auto inverseXZSumSq = 1. / (pow<2>(geometry.axis.X()) + pow<2>(geometry.axis.Z()));
118 basis1.setX(std::sqrt(1. - pow<2>(geometry.axis.X()) * inverseXZSumSq));
119 basis1.setY(geometry.axis.X() * std::sqrt(inverseXZSumSq));
120 }
121 const Mantid::Kernel::V3D basis2 = geometry.axis.cross_prod(basis1);
122 const std::array<double, 8> angles{
123 {0., 0.25 * M_PI, 0.5 * M_PI, 0.75 * M_PI, M_PI, 1.25 * M_PI, 1.5 * M_PI, 1.75 * M_PI}};
124 double minTwoTheta{std::numeric_limits<double>::max()};
125 double maxTwoTheta{std::numeric_limits<double>::lowest()};
126 for (const double &angle : angles) {
127 const auto basePoint =
128 geometry.centreOfBottomBase + (basis1 * std::cos(angle) + basis2 * std::sin(angle)) * geometry.radius;
129 for (int i = 0; i < 3; ++i) {
130 const auto point = basePoint + geometry.axis * (0.5 * geometry.height * static_cast<double>(i));
131 const auto current = twoThetaFromLocalPoint(detInfo, detInfoIndex, samplePos, beamDir, point);
132 minTwoTheta = std::min(minTwoTheta, current);
133 maxTwoTheta = std::max(maxTwoTheta, current);
134 }
135 }
136 return std::make_pair(minTwoTheta, maxTwoTheta);
137}
138
149double twoThetaFromBoundingBox(const Mantid::Geometry::ComponentInfo &compInfo,
150 const Mantid::Geometry::DetectorInfo &detInfo, const size_t detInfoIndex,
151 const Mantid::Kernel::V3D &samplePos, const Mantid::Kernel::V3D &beamDir,
152 const Mantid::Kernel::V3D &sideDir) {
153 const Mantid::Geometry::BoundingBox bbox = compInfo.shape(detInfoIndex).getBoundingBox();
154 const auto maxPoint = bbox.maxPoint();
155 auto side = maxPoint * sideDir;
156 return twoThetaFromLocalPoint(detInfo, detInfoIndex, samplePos, beamDir, side);
157}
158
169std::pair<double, double> generalTwoThetaRange(const Mantid::Geometry::ComponentInfo &compInfo,
170 const Mantid::Geometry::DetectorInfo &detInfo, const size_t detInfoIndex,
171 const Mantid::Kernel::V3D &samplePos,
172 const Mantid::Kernel::V3D &beamDir) {
173 double minTwoTheta{std::numeric_limits<double>::max()};
174 double maxTwoTheta{std::numeric_limits<double>::lowest()};
175 const std::array<Mantid::Kernel::V3D, 6> dirs{
176 {Mantid::Kernel::V3D{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}, {-1., 0., 0.}, {0., -1., 0.}, {0., 0., -1.}}};
177 for (const auto &dir : dirs) {
178 const auto current = twoThetaFromBoundingBox(compInfo, detInfo, detInfoIndex, samplePos, beamDir, dir);
179 minTwoTheta = std::min(minTwoTheta, current);
180 maxTwoTheta = std::max(maxTwoTheta, current);
181 }
182 return std::make_pair(minTwoTheta, maxTwoTheta);
183}
184
195std::pair<double, double> minMaxTwoTheta(const Mantid::Geometry::ComponentInfo &compInfo,
196 const Mantid::Geometry::DetectorInfo &detInfo, const size_t detInfoIndex,
197 const Mantid::Kernel::V3D &samplePos, const Mantid::Kernel::V3D &beamDir) {
198 const auto &shape = compInfo.shape(detInfoIndex);
199 const Mantid::Geometry::CSGObject *csgShape;
200 switch (shape.shape()) {
202 csgShape = dynamic_cast<const Mantid::Geometry::CSGObject *>(&shape);
203 assert(csgShape);
204 return cylinderTwoThetaRange(detInfo, detInfoIndex, samplePos, beamDir, csgShape->shapeInfo().cylinderGeometry());
206 csgShape = dynamic_cast<const Mantid::Geometry::CSGObject *>(&shape);
207 assert(csgShape);
208 return cuboidTwoThetaRange(detInfo, detInfoIndex, samplePos, beamDir, csgShape->shapeInfo().cuboidGeometry());
209 default:
210 return generalTwoThetaRange(compInfo, detInfo, detInfoIndex, samplePos, beamDir);
211 }
212}
213
221std::pair<double, double> twoThetasFromTable(const Mantid::detid_t detID, const std::vector<int> &detectorIDs,
222 const std::vector<double> &lowers, const std::vector<double> &uppers) {
223 const auto range = std::equal_range(detectorIDs.cbegin(), detectorIDs.cend(), static_cast<int>(detID));
224 if (std::distance(range.first, range.second) > 1) {
225 throw std::invalid_argument("Duplicate detector IDs in 'DetectorTwoThetaRanges'.");
226 }
227 if (range.first == detectorIDs.cend()) {
228 throw std::invalid_argument("No min/max 2thetas found for detector ID " + std::to_string(detID));
229 }
230 const auto index = std::distance(detectorIDs.cbegin(), range.first);
231 const auto minmax = std::make_pair(lowers[index], uppers[index]);
232 if (minmax.first <= 0) {
233 throw std::invalid_argument("Non-positive min 2theta for detector ID " + std::to_string(detID));
234 }
235 if (minmax.first > M_PI) {
236 throw std::invalid_argument("Min 2theta greater than pi for detector ID " + std::to_string(detID));
237 }
238 if (minmax.second > M_PI) {
239 throw std::invalid_argument("Max 2theta greater than pi for detector ID" + std::to_string(detID));
240 }
241 if (minmax.first >= minmax.second) {
242 throw std::invalid_argument("Min 2theta larger than max for detector ID " + std::to_string(detID));
243 }
244 return minmax;
245}
246} // namespace
247
248namespace Mantid::Algorithms {
249// Setup typedef for later use
250using SpectraDistanceMap = std::map<specnum_t, Mantid::Kernel::V3D>;
252
253// Register the algorithm into the AlgorithmFactory
255
256using namespace Mantid::Kernel;
257using namespace Mantid::Geometry;
258using namespace Mantid::API;
259using namespace Mantid::DataObjects;
260
261namespace {
267double getEFixedForSpectrum(const SofQCommon &emodeProperties, const SpectrumInfo &spectrumInfo,
268 const ComponentInfo &componentInfo, const size_t wsIndex) {
269 const auto &spectrumDefinition = spectrumInfo.spectrumDefinition(wsIndex);
270 if (spectrumDefinition.size() == 1 || emodeProperties.m_emode == 1 || emodeProperties.m_efixedGiven) {
271 return emodeProperties.getEFixed(componentInfo, spectrumDefinition[0].first);
272 }
273 std::string groupName;
274 for (const auto &def : spectrumDefinition) {
275 groupName += componentInfo.name(def.first) + ";";
276 }
277 throw std::runtime_error("Cannot find EFixed parameter for component \"" + groupName +
278 "\". This is required in indirect mode. Please check the IDF "
279 "contains these values.");
280}
281} // namespace
282
286const std::string SofQWNormalisedPolygon::name() const { return "SofQWNormalisedPolygon"; }
287
291int SofQWNormalisedPolygon::version() const { return 1; }
292
296const std::string SofQWNormalisedPolygon::category() const { return "Inelastic\\SofQW"; }
297
302
307std::map<std::string, std::string> SofQWNormalisedPolygon::validateInputs() {
308 std::map<std::string, std::string> result;
309 API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
310 if (!inputWS) {
311 result["InputWorkspace"] = "InputWorkspace is of Incorrect type. Please "
312 "provide a MatrixWorkspace as the "
313 "InputWorkspace";
314 }
315 TableWorkspace_sptr tableWS = getProperty("DetectorTwoThetaRanges");
316 if (tableWS) {
317 // The table should have three columns
318 if (tableWS->columnCount() != 3) {
319 result["DetectorTwoThetaRanges"] = "DetectorTwoThetaRanges requires 3 columns";
320 }
321 // The first column should be of type int
322 else if (!tableWS->getColumn(0)->isType<int>()) {
323 result["DetectorTwoThetaRanges"] = "The first column of DetectorTwoThetaRanges should be of type int";
324 }
325 // The second column should be of type double
326 else if (!tableWS->getColumn(1)->isType<double>()) {
327 result["DetectorTwoThetaRanges"] = "The second column of DetectorTwoThetaRanges should be of type "
328 "double";
329 }
330 // The third column should be of type double.
331 else if (!tableWS->getColumn(2)->isType<double>()) {
332 result["DetectorTwoThetaRanges"] = "The third column of DetectorTwoThetaRanges should be of type double";
333 }
334 // Table and workspace should have the same number of detectors.
335 else if (tableWS->rowCount() != inputWS->getNumberHistograms()) {
336 result["DetectorTwoThetaRanges"] = "The table and workspace do not have the same number of detectors";
337 }
338 }
339 return result;
340}
341
346 MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
347 // Compute input caches
348 m_EmodeProperties.initCachedValues(*inputWS, this);
349
350 RebinnedOutput_sptr outputWS = SofQW::setUpOutputWorkspace<RebinnedOutput>(
351 *inputWS, getProperty("QAxisBinning"), m_Qout, getProperty("EAxisBinning"), m_EmodeProperties);
352 g_log.debug() << "Workspace type: " << outputWS->id() << '\n';
353 setProperty("OutputWorkspace", outputWS);
354 const size_t nEnergyBins = inputWS->blocksize();
355 const size_t nHistos = inputWS->getNumberHistograms();
356
357 // Holds the spectrum-detector mapping
358 std::vector<SpectrumDefinition> detIDMapping(outputWS->getNumberHistograms());
359
360 // Progress reports & cancellation
361 const size_t nreports(nHistos * nEnergyBins);
362 m_progress = std::make_unique<API::Progress>(this, 0.0, 1.0, nreports);
363
364 // Index theta cache
365 TableWorkspace_sptr twoThetaTable = getProperty("DetectorTwoThetaRanges");
366 if (twoThetaTable) {
367 initAngularCachesTable(*inputWS, *twoThetaTable);
368 } else {
369 std::vector<double> par = inputWS->getInstrument()->getNumberParameter("detector-neighbour-offset");
370 if (par.empty()) {
371 this->initAngularCachesNonPSD(*inputWS);
372 } else {
373 g_log.debug() << "Offset: " << par[0] << '\n';
374 this->m_detNeighbourOffset = static_cast<int>(par[0]);
375 this->initAngularCachesPSD(*inputWS);
376 }
377 }
378 const auto &X = inputWS->x(0);
379
380 const auto &inputIndices = inputWS->indexInfo();
381 const auto &spectrumInfo = inputWS->spectrumInfo();
382 const auto &componentInfo = inputWS->componentInfo();
383
384 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
385 for (int64_t i = 0; i < static_cast<int64_t>(nHistos); ++i) {
387
388 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMasked(i) || spectrumInfo.isMonitor(i)) {
389 continue;
390 }
391 const double efixed = getEFixedForSpectrum(m_EmodeProperties, spectrumInfo, componentInfo, i);
392
393 const double thetaLower = m_twoThetaLowers[i];
394 const double thetaUpper = m_twoThetaUppers[i];
395
396 const auto specNo = static_cast<specnum_t>(inputIndices.spectrumNumber(i));
397 std::stringstream logStream;
398 for (size_t j = 0; j < nEnergyBins; ++j) {
399 m_progress->report("Computing polygon intersections");
400 // For each input polygon test where it intersects with
401 // the output grid and assign the appropriate weights of Y/E
402 const double dE_j = X[j];
403 const double dE_jp1 = X[j + 1];
404
405 const double lrQ = m_EmodeProperties.q(dE_jp1, thetaLower, efixed);
406
407 const V2D ll(dE_j, m_EmodeProperties.q(dE_j, thetaLower, efixed));
408 const V2D lr(dE_jp1, lrQ);
409 const V2D ur(dE_jp1, m_EmodeProperties.q(dE_jp1, thetaUpper, efixed));
410 const V2D ul(dE_j, m_EmodeProperties.q(dE_j, thetaUpper, efixed));
411 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
412 logStream << "Spectrum=" << specNo << ", lower theta=" << thetaLower * rad2deg
413 << ", upper theta=" << thetaUpper * rad2deg << ". QE polygon: ll=" << ll << ", lr=" << lr
414 << ", ur=" << ur << ", ul=" << ul << "\n";
415 }
416
418 rebinToFractionalOutput(Quadrilateral(ll, lr, ur, ul), inputWS, i, j, *outputWS, m_Qout);
419
420 // Find which q bin this point lies in
421 const MantidVec::difference_type qIndex = std::upper_bound(m_Qout.begin(), m_Qout.end(), lrQ) - m_Qout.begin();
422 if (qIndex != 0 && qIndex < static_cast<int>(m_Qout.size())) {
423 // Add this spectra-detector pair to the mapping
424 PARALLEL_CRITICAL(SofQWNormalisedPolygon_spectramap) {
425 // Could do a more complete merge of spectrum definitions here, but
426 // historically only the ID of the first detector in the spectrum is
427 // used, so I am keeping that for now.
428 detIDMapping[qIndex - 1].add(spectrumInfo.spectrumDefinition(i)[0].first);
429 }
430 }
431 }
432 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
433 g_log.debug(logStream.str());
434 }
435
437 }
439
441 outputWS->finalize();
442 FractionalRebinning::normaliseOutput(outputWS, inputWS, m_progress.get());
443
444 // Set the output spectrum-detector mapping
445 auto outputIndices = outputWS->indexInfo();
446 outputIndices.setSpectrumDefinitions(std::move(detIDMapping));
447 outputWS->setIndexInfo(outputIndices);
448
449 // Replace any NaNs in outputWorkspace with zeroes
450 if (this->getProperty("ReplaceNaNs")) {
451 auto replaceNans = this->createChildAlgorithm("ReplaceSpecialValues");
452 replaceNans->setChild(true);
453 replaceNans->initialize();
454 replaceNans->setProperty("InputWorkspace", outputWS);
455 replaceNans->setProperty("OutputWorkspace", outputWS);
456 replaceNans->setProperty("NaNValue", 0.0);
457 replaceNans->setProperty("InfinityValue", 0.0);
458 replaceNans->setProperty("BigNumberThreshold", DBL_MAX);
459 replaceNans->execute();
460 }
461}
462
472 const size_t nhist = workspace.getNumberHistograms();
473 constexpr double skipDetector{-1.};
474 m_twoThetaLowers = std::vector<double>(nhist, skipDetector);
475 m_twoThetaUppers = std::vector<double>(nhist, skipDetector);
476
477 auto inst = workspace.getInstrument();
478 const auto referenceFrame = inst->getReferenceFrame();
479 const auto beamDir = referenceFrame->vecPointingAlongBeam();
480
481 const auto &detectorInfo = workspace.detectorInfo();
482 const auto &componentInfo = workspace.componentInfo();
483 const auto &spectrumInfo = workspace.spectrumInfo();
484 const auto samplePos = spectrumInfo.samplePosition();
485 for (size_t i = 0; i < nhist; ++i) {
486 m_progress->report("Calculating detector angles");
487
488 // If no detector found, skip onto the next spectrum
489 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) {
490 continue;
491 }
492
493 // Check to see if there is an EFixed, if not skip it
494 try {
495 getEFixedForSpectrum(m_EmodeProperties, spectrumInfo, componentInfo, i);
496 } catch (std::runtime_error &) {
497 continue;
498 }
499
500 const auto &spectrumDefinition = spectrumInfo.spectrumDefinition(i);
501 double minTwoTheta{spectrumInfo.twoTheta(i)};
502 double maxTwoTheta{minTwoTheta};
503 if (spectrumInfo.hasUniqueDetector(i)) {
504 const auto detInfoIndex = spectrumDefinition[0].first;
505 std::tie(minTwoTheta, maxTwoTheta) =
506 minMaxTwoTheta(componentInfo, detectorInfo, detInfoIndex, samplePos, beamDir);
507 } else {
508 for (const auto &def : spectrumDefinition) {
509 const auto detInfoIndex = def.first;
510 const auto current = minMaxTwoTheta(componentInfo, detectorInfo, detInfoIndex, samplePos, beamDir);
511 minTwoTheta = std::min(minTwoTheta, current.first);
512 maxTwoTheta = std::max(maxTwoTheta, current.second);
513 }
514 }
515 m_twoThetaLowers[i] = minTwoTheta;
516 m_twoThetaUppers[i] = maxTwoTheta;
517 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
518 g_log.debug() << "Detector at spectrum = " << workspace.getSpectrum(i).getSpectrumNo()
519 << ", lower 2theta = " << m_twoThetaLowers[i] * rad2deg
520 << ", upper 2theta = " << m_twoThetaUppers[i] * rad2deg << " degrees\n";
521 }
522 }
523}
524
532 const size_t nHistos = workspace.getNumberHistograms();
533
534 bool ignoreMasked = true;
535 const int numNeighbours = 4;
536 WorkspaceNearestNeighbourInfo neighbourInfo(workspace, ignoreMasked, numNeighbours);
537
538 m_twoThetaLowers.resize(nHistos);
539 m_twoThetaUppers.resize(nHistos);
540
541 const auto &spectrumInfo = workspace.spectrumInfo();
542
543 for (size_t i = 0; i < nHistos; ++i) {
544 m_progress->report("Calculating detector angular widths");
545
546 // If no detector found, skip onto the next spectrum
547 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) {
548 continue;
549 }
550
551 const specnum_t inSpec = workspace.getSpectrum(i).getSpectrumNo();
552 const SpectraDistanceMap neighbours = neighbourInfo.getNeighboursExact(inSpec);
553
554 // Convert from spectrum numbers to workspace indices
555 double thetaWidth = std::numeric_limits<double>::lowest();
556
557 // Find theta and phi widths
558 const double theta = spectrumInfo.twoTheta(i);
559
560 const specnum_t deltaPlus1 = inSpec + 1;
561 const specnum_t deltaMinus1 = inSpec - 1;
562 const specnum_t deltaPlusT = inSpec + this->m_detNeighbourOffset;
563 const specnum_t deltaMinusT = inSpec - this->m_detNeighbourOffset;
564
565 for (auto const &neighbour : neighbours) {
566 specnum_t spec = neighbour.first;
567 if (spec == deltaPlus1 || spec == deltaMinus1 || spec == deltaPlusT || spec == deltaMinusT) {
568 const double theta_n = spectrumInfo.twoTheta(spec - 1) * 0.5;
569
570 const double dTheta = std::abs(theta - theta_n);
571 thetaWidth = std::max(thetaWidth, dTheta);
572 }
573 }
574 m_twoThetaLowers[i] = theta - thetaWidth / 2.;
575 m_twoThetaUppers[i] = theta + thetaWidth / 2.;
576 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
577 g_log.debug() << "Detector at spectrum = " << inSpec << ", width = " << thetaWidth * rad2deg << " degrees\n";
578 }
579 }
580}
581
583 const TableWorkspace &angleTable) {
584 constexpr double skipDetector{-1.};
585 const size_t nhist = workspace.getNumberHistograms();
586 m_twoThetaLowers = std::vector<double>(nhist, skipDetector);
587 m_twoThetaUppers = std::vector<double>(nhist, skipDetector);
588 const auto &detIDs = angleTable.getColVector<int>("Detector ID");
589 const auto &lowers = angleTable.getColVector<double>("Min two theta");
590 const auto &uppers = angleTable.getColVector<double>("Max two theta");
591 const auto &spectrumInfo = workspace.spectrumInfo();
592 const auto &detectorInfo = workspace.detectorInfo();
593 const auto &componentInfo = workspace.componentInfo();
594 for (size_t i = 0; i < nhist; ++i) {
595 m_progress->report("Reading detector angles");
596 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) {
597 continue;
598 }
599 try {
600 getEFixedForSpectrum(m_EmodeProperties, spectrumInfo, componentInfo, i);
601 } catch (std::runtime_error &) {
602 continue;
603 }
604
605 const auto &spectrumDefinition = spectrumInfo.spectrumDefinition(i);
606 if (spectrumInfo.hasUniqueDetector(i)) {
607 const auto twoThetas = twoThetasFromTable(spectrumInfo.firstDetectorID(i), detIDs, lowers, uppers);
608 m_twoThetaLowers[i] = twoThetas.first;
609 m_twoThetaUppers[i] = twoThetas.second;
610 } else {
611 double minTwoTheta{spectrumInfo.twoTheta(i)};
612 double maxTwoTheta{minTwoTheta};
613 for (const auto &def : spectrumDefinition) {
614 const auto twoThetas = twoThetasFromTable(detectorInfo.detid(def.first), detIDs, lowers, uppers);
615 minTwoTheta = std::min(minTwoTheta, twoThetas.first);
616 maxTwoTheta = std::max(maxTwoTheta, twoThetas.second);
617 }
618 m_twoThetaLowers[i] = minTwoTheta;
619 m_twoThetaUppers[i] = maxTwoTheta;
620 }
621 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
622 g_log.debug() << "Detector at spectrum = " << workspace.getSpectrum(i).getSpectrumNo()
623 << ", lower 2theta = " << m_twoThetaLowers[i] * rad2deg
624 << ", upper 2theta = " << m_twoThetaUppers[i] * rad2deg << " degrees\n";
625 }
626 }
627}
628} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
double position
Definition GetAllEi.cpp:154
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
double right
#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.
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
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.
Base MatrixWorkspace Abstract Class.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
const SpectrumDefinition & spectrumDefinition(const size_t index) const
Returns a const reference to the SpectrumDefinition of the spectrum.
WorkspaceNearestNeighbourInfo provides easy access to nearest-neighbour information for a workspace.
std::map< specnum_t, Kernel::V3D > getNeighboursExact(specnum_t spec) const
Queries the WorkspaceNearestNeighbours object for the selected spectrum number.
std::unique_ptr< API::Progress > m_progress
Progress reporter.
Definition Rebin2D.h:41
Converts a 2D workspace that has axes of energy transfer against spectrum number to one that gives in...
std::vector< double > m_twoThetaLowers
Array for the lower 2theta angles, in radians.
int m_detNeighbourOffset
Offset for finding neighbor in nearest tube.
std::map< std::string, std::string > validateInputs() override
validate the inputs
void initAngularCachesNonPSD(const API::MatrixWorkspace &workspace)
Init the theta index.
std::vector< double > m_twoThetaUppers
Array for the upper 2theta angles, in radians.
void initAngularCachesPSD(const API::MatrixWorkspace &workspace)
Get angles and calculate angular widths.
int version() const override
Algorithm's version for identification.
void init() override
Initialize the algorithm.
const std::string category() const override
Algorithm's category for identification.
const std::string name() const override
Algorithm's name for identification.
void initAngularCachesTable(const API::MatrixWorkspace &workspace, const DataObjects::TableWorkspace &widthTable)
std::vector< double > m_Qout
Output Q axis.
static void createCommonInputProperties(API::Algorithm &alg)
Create the input properties on the given algorithm object.
Definition SofQW.cpp:53
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
std::vector< T > & getColVector(size_t index)
get access to column vector for index i.
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
const Kernel::V3D & maxPoint() const
Returns the min point of the box.
Definition BoundingBox.h:91
Constructive Solid Geometry object.
Definition CSGObject.h:51
const detail::ShapeInfo & shapeInfo() const override
ComponentInfo : Provides a component centric view on to the instrument.
const std::string & name(const size_t componentIndex) const
const Geometry::IObject & shape(const size_t componentIndex) const
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
Kernel::Quat rotation(const size_t index) const
Returns the rotation of the detector with given index.
Kernel::V3D position(const size_t index) const
Returns the position of the detector with given index.
virtual const BoundingBox & getBoundingBox() const =0
Return cached value of axis-aligned bounding box.
A ConvexPolygon with only 4 vertices.
CylinderGeometry cylinderGeometry() const
Definition ShapeInfo.cpp:53
CuboidGeometry cuboidGeometry() const
Definition ShapeInfo.cpp:38
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
bool is(int level) const
Returns true if at least the given log level is set.
Definition Logger.cpp:177
void rotate(V3D &) const
Rotate a vector.
Definition Quat.cpp:397
Implements a 2-dimensional vector embedded in a 3D space, i.e.
Definition V2D.h:29
Class for 3D vectors.
Definition V3D.h:35
constexpr double X() const noexcept
Get x.
Definition V3D.h:239
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition V3D.h:285
double angle(const V3D &) const
Angle between this and another vector.
Definition V3D.cpp:162
void setX(const double xx) noexcept
Set is x position.
Definition V3D.h:225
constexpr double Z() const noexcept
Get z.
Definition V3D.h:241
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
Kernel::Logger g_log("DetermineSpinStateOrder")
Geometry::IDetector_const_sptr DetConstPtr
std::map< specnum_t, Mantid::Kernel::V3D > SpectraDistanceMap
MANTID_DATAOBJECTS_DLL void normaliseOutput(const API::MatrixWorkspace_sptr &outputWS, const API::MatrixWorkspace_const_sptr &inputWS, API::Progress *progress=nullptr)
Compute sqrt of errors and put back in bin width division if necessary.
MANTID_DATAOBJECTS_DLL void rebinToFractionalOutput(const Geometry::Quadrilateral &inputQ, const API::MatrixWorkspace_const_sptr &inputWS, const size_t i, const size_t j, DataObjects::RebinnedOutput &outputWS, std::span< double const > verticalAxis, const DataObjects::RebinnedOutput_const_sptr &inputRB=nullptr)
Rebin the input quadrilateral to to output grid.
MANTID_DATAOBJECTS_DLL void finalizeFractionalRebin(DataObjects::RebinnedOutput &outputWS)
Set finalize flag after fractional rebinning loop.
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< RebinnedOutput > RebinnedOutput_sptr
shared pointer to the RebinnedOutput class
Definition SumSpectra.h:23
constexpr double rad2deg
Radians to degrees conversion factor.
Definition AngleUnits.h:23
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:96
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.
int32_t detid_t
Typedef for a detector ID.
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
std::string to_string(const wide_integer< Bits, Signed > &n)
void initCachedValues(const API::MatrixWorkspace &workspace, API::Algorithm const *hostAlgorithm)
The procedure analyses emode and efixed properties provided to the algorithm and identify the energy ...
bool m_efixedGiven
EFixed has been provided.
Definition SofQCommon.h:26
double getEFixed(const Geometry::IDetector &det) const
Get the efixed value for the given detector.
double q(const double deltaE, const double twoTheta, const Geometry::IDetector *det) const
Calculate the Q value.