40 using namespace Geometry;
45 m_EmodeProperties.initCachedValues(*inputWorkspace,
this);
46 const int emode = m_EmodeProperties.m_emode;
48 std::vector<double> verticalAxis;
50 *inputWorkspace, getProperty(
"QAxisBinning"), verticalAxis, getProperty(
"EAxisBinning"), m_EmodeProperties);
51 setProperty(
"OutputWorkspace", outputWorkspace);
52 const auto &xAxis = outputWorkspace->binEdges(0).rawData();
55 std::vector<specnum_t> specNumberMapping;
56 std::vector<detid_t> detIDMapping;
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';
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))
73 const auto &spectrumDet = spectrumInfo.detector(i);
74 const double efixed = m_EmodeProperties.getEFixed(spectrumDet);
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);
89 for (
const auto detID : detIDs) {
91 size_t idet = detectorInfo.indexOf(detID);
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())
98 const double deltaE = 0.5 * (
X[j] +
X[j + 1]);
100 double ei(0.0), ef(0.0);
105 std::string mess =
"Energy transfer requested in Direct mode exceeds incident "
106 "energy.\n Found for det ID: " +
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);
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: " +
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);
126 throw std::runtime_error(
"Negative incident energy. Check binning.");
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();
133 if (q < verticalAxis.front() || q > verticalAxis.back())
136 const MantidVec::difference_type qIndex =
137 std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) - verticalAxis.begin() - 1;
139 const MantidVec::difference_type eIndex =
140 std::upper_bound(xAxis.begin(), xAxis.end(), deltaE) - xAxis.begin() - 1;
143 specNumberMapping.emplace_back(outputWorkspace->getSpectrum(qIndex).getSpectrumNo());
144 detIDMapping.emplace_back(detID);
148 outputWorkspace->mutableY(qIndex)[eIndex] +=
Y[j] / numDets_d;
150 outputWorkspace->mutableE(qIndex)[eIndex] =
151 sqrt((pow(outputWorkspace->e(qIndex)[eIndex], 2) + pow(E[j], 2)) / numDets_d);
153 }
catch (std::out_of_range &) {
165 if (inputWorkspace->isDistribution())
166 this->makeDistribution(*outputWorkspace, verticalAxis);
170 outputWorkspace->updateSpectraUsing(outputDetectorMap);
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();
191 std::vector<double> widths(qAxis.size());
192 std::adjacent_difference(qAxis.begin(), qAxis.end(), widths.begin());
195 for (
size_t i = 0; i < numQBins; ++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]));