Mantid
Loading...
Searching...
No Matches
SofQWCentre.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 +
17
18namespace Mantid::Algorithms {
19
20// Register the algorithm into the AlgorithmFactory
21DECLARE_ALGORITHM(SofQWCentre)
22
23using namespace Kernel;
24using namespace API;
25
28 useAlgorithm("SofQWNormalisedPolygon");
29 deprecatedDate("2024-11-07");
30}
31
36
37GNU_DIAG_OFF("dangling-reference")
38
39void SofQWCentre::exec() {
40 using namespace Geometry;
42
43 MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
44
45 m_EmodeProperties.initCachedValues(*inputWorkspace, this);
46 const int emode = m_EmodeProperties.m_emode;
47
48 std::vector<double> verticalAxis;
49 MatrixWorkspace_sptr outputWorkspace = SofQW::setUpOutputWorkspace<DataObjects::Workspace2D>(
50 *inputWorkspace, getProperty("QAxisBinning"), verticalAxis, getProperty("EAxisBinning"), m_EmodeProperties);
51 setProperty("OutputWorkspace", outputWorkspace);
52 const auto &xAxis = outputWorkspace->binEdges(0).rawData();
53
54 // Holds the spectrum-detector mapping
55 std::vector<specnum_t> specNumberMapping;
56 std::vector<detid_t> detIDMapping;
57
58 const auto &detectorInfo = inputWorkspace->detectorInfo();
59 const auto &spectrumInfo = inputWorkspace->spectrumInfo();
60 const V3D beamDir = normalize(detectorInfo.samplePosition() - detectorInfo.sourcePosition());
61 const double l1 = detectorInfo.l1();
62 g_log.debug() << "Source-sample distance: " << l1 << '\n';
63
64 // Loop over input workspace bins, reassigning data to correct bin in output
65 // qw workspace
66 const size_t numHists = inputWorkspace->getNumberHistograms();
67 const size_t numBins = inputWorkspace->blocksize();
68 Progress prog(this, 0.0, 1.0, numHists);
69 for (int64_t i = 0; i < int64_t(numHists); ++i) {
70 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
71 continue;
72
73 const auto &spectrumDet = spectrumInfo.detector(i);
74 const double efixed = m_EmodeProperties.getEFixed(spectrumDet);
75
76 // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda
77 // does not hold. In order to
78 // be completely general we must calculate the momentum transfer by
79 // calculating the incident and final
80 // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)]
81
82 const auto &detIDs = inputWorkspace->getSpectrum(i).getDetectorIDs();
83 auto numDets_d = static_cast<double>(detIDs.size());
84 const auto &Y = inputWorkspace->y(i);
85 const auto &E = inputWorkspace->e(i);
86 const auto &X = inputWorkspace->x(i);
87
88 // Loop over the detectors and for each bin calculate Q
89 for (const auto detID : detIDs) {
90 try {
91 size_t idet = detectorInfo.indexOf(detID);
92 // Calculate kf vector direction and then Q for each energy bin
93 const V3D scatterDir = normalize(detectorInfo.position(idet) - detectorInfo.samplePosition());
94 for (size_t j = 0; j < numBins; ++j) {
95 if (X[j] < xAxis.front() || X[j + 1] > xAxis.back())
96 continue;
97
98 const double deltaE = 0.5 * (X[j] + X[j + 1]);
99 // Compute ki and kf wave vectors and therefore q = ki - kf
100 double ei(0.0), ef(0.0);
101 if (emode == 1) {
102 ei = efixed;
103 ef = efixed - deltaE;
104 if (ef < 0) {
105 std::string mess = "Energy transfer requested in Direct mode exceeds incident "
106 "energy.\n Found for det ID: " +
107 std::to_string(idet) + " bin No " + std::to_string(j) +
108 " with Ei=" + boost::lexical_cast<std::string>(efixed) +
109 " and energy transfer: " + boost::lexical_cast<std::string>(deltaE);
110 throw std::runtime_error(mess);
111 }
112 } else {
113 ei = efixed + deltaE;
114 ef = efixed;
115 if (ef < 0) {
116 std::string mess = "Incident energy of a neutron is negative. Are you trying to "
117 "process Direct data in Indirect mode?\n Found for det ID: " +
118 std::to_string(idet) + " bin No " + std::to_string(j) +
119 " with efied=" + boost::lexical_cast<std::string>(efixed) +
120 " and energy transfer: " + boost::lexical_cast<std::string>(deltaE);
121 throw std::runtime_error(mess);
122 }
123 }
124
125 if (ei < 0)
126 throw std::runtime_error("Negative incident energy. Check binning.");
127
128 const V3D ki = beamDir * sqrt(ei / E_mev_toNeutronWavenumberSq);
129 const V3D kf = scatterDir * sqrt(ef / E_mev_toNeutronWavenumberSq);
130 const double q = (ki - kf).norm();
131
132 // Test whether it's in range of the Q axis
133 if (q < verticalAxis.front() || q > verticalAxis.back())
134 continue;
135 // Find which q bin this point lies in
136 const MantidVec::difference_type qIndex =
137 std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) - verticalAxis.begin() - 1;
138 // Find which e bin this point lies in
139 const MantidVec::difference_type eIndex =
140 std::upper_bound(xAxis.begin(), xAxis.end(), deltaE) - xAxis.begin() - 1;
141
142 // Add this spectra-detector pair to the mapping
143 specNumberMapping.emplace_back(outputWorkspace->getSpectrum(qIndex).getSpectrumNo());
144 detIDMapping.emplace_back(detID);
145
146 // And add the data and it's error to that bin, taking into account
147 // the number of detectors contributing to this bin
148 outputWorkspace->mutableY(qIndex)[eIndex] += Y[j] / numDets_d;
149 // Standard error on the average
150 outputWorkspace->mutableE(qIndex)[eIndex] =
151 sqrt((pow(outputWorkspace->e(qIndex)[eIndex], 2) + pow(E[j], 2)) / numDets_d);
152 }
153 } catch (std::out_of_range &) {
154 // Skip invalid detector IDs
155 numDets_d -= 1.0;
156 continue;
157 }
158 }
159 prog.report();
160 }
161
162 GNU_DIAG_ON("dangling-reference")
163
164 // If the input workspace was a distribution, need to divide by q bin width
165 if (inputWorkspace->isDistribution())
166 this->makeDistribution(*outputWorkspace, verticalAxis);
167
168 // Set the output spectrum-detector mapping
169 SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping);
170 outputWorkspace->updateSpectraUsing(outputDetectorMap);
171
172 // Replace any NaNs in outputWorkspace with zeroes
173 if (this->getProperty("ReplaceNaNs")) {
174 auto replaceNans = this->createChildAlgorithm("ReplaceSpecialValues");
175 replaceNans->setChild(true);
176 replaceNans->initialize();
177 replaceNans->setProperty("InputWorkspace", outputWorkspace);
178 replaceNans->setProperty("OutputWorkspace", outputWorkspace);
179 replaceNans->setProperty("NaNValue", 0.0);
180 replaceNans->setProperty("InfinityValue", 0.0);
181 replaceNans->setProperty("BigNumberThreshold", DBL_MAX);
182 replaceNans->execute();
183 }
184}
185
190void SofQWCentre::makeDistribution(API::MatrixWorkspace &outputWS, const std::vector<double> &qAxis) {
191 std::vector<double> widths(qAxis.size());
192 std::adjacent_difference(qAxis.begin(), qAxis.end(), widths.begin());
193
194 const size_t numQBins = outputWS.getNumberHistograms();
195 for (size_t i = 0; i < numQBins; ++i) {
196 auto &Y = outputWS.mutableY(i);
197 auto &E = outputWS.mutableE(i);
198 using std::placeholders::_1;
199 std::transform(Y.begin(), Y.end(), Y.begin(), std::bind(std::divides<double>(), _1, widths[i + 1]));
200 std::transform(E.begin(), E.end(), E.begin(), std::bind(std::divides<double>(), _1, widths[i + 1]));
201 }
202}
203
204} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
void deprecatedDate(const std::string &)
The date the algorithm was deprecated on.
void useAlgorithm(const std::string &, const int version=-1)
The algorithm to use instead of this one.
Base MatrixWorkspace Abstract Class.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
HistogramData::HistogramE & mutableE(const size_t index) &
HistogramData::HistogramY & mutableY(const size_t index) &
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A minimal class to hold the mapping between the spectrum number and its related detector ID numbers f...
Converts a 2D workspace that has axes of energy transfer against spectrum number to one that gives in...
Definition SofQWCentre.h:37
static void makeDistribution(API::MatrixWorkspace &outputWS, const std::vector< double > &qAxis)
Convert the workspace to a distribution.
SofQWCentre()
Default constructor.
void init() override
Initialization code.
static void createCommonInputProperties(API::Algorithm &alg)
Create the input properties on the given algorithm object.
Definition SofQW.cpp:69
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Class for 3D vectors.
Definition V3D.h:34
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
Kernel::Logger g_log("DetermineSpinStateOrder")
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:352
static constexpr double E_mev_toNeutronWavenumberSq
Transformation coefficient to transform neutron energy into neutron wavevector: K-neutron[m^-10] = sq...
std::string to_string(const wide_integer< Bits, Signed > &n)