102 const bool doGravity =
getProperty(
"AccountForGravity");
103 const bool doSolidAngle =
getProperty(
"SolidAngleWeighting");
108 g_log.
debug() <<
"All input workspaces were found to be valid\n";
117 for (
size_t i = 0; i < weights->getNumberHistograms(); ++i)
118 weights->setSharedX(i, outputWorkspace->sharedX(0));
120 const size_t numSpec = inputWorkspace->getNumberHistograms();
121 const size_t numBins = inputWorkspace->blocksize();
124 Progress prog(
this, 0.05, 1.0, numSpec);
126 const auto &spectrumInfo = inputWorkspace->spectrumInfo();
127 const auto &detectorInfo = inputWorkspace->detectorInfo();
131 const V3D samplePos = spectrumInfo.samplePosition();
133 for (int64_t i = 0; i < int64_t(numSpec); ++i) {
134 if (!spectrumInfo.hasDetectors(i)) {
135 g_log.
warning() <<
"Workspace index " << i <<
" has no detector assigned to it - discarding\n";
140 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
145 const size_t wavStart =
147 if (wavStart >= inputWorkspace->y(i).size()) {
152 V3D detPos = spectrumInfo.position(i) - samplePos;
156 double phi = atan2(detPos.
Y(), detPos.
X());
159 double sinTheta = sin(spectrumInfo.twoTheta(i) * 0.5);
162 const auto &
X = inputWorkspace->x(i);
163 const auto &
Y = inputWorkspace->y(i);
164 const auto &E = inputWorkspace->e(i);
166 const auto &axis = outputWorkspace->x(0);
170 const int numberOfCylinderSlices =
getProperty(
"SolidAngleNumberOfCylinderSlices");
172 for (
const auto detID : inputWorkspace->getSpectrum(i).getDetectorIDs()) {
173 const auto index = detectorInfo.indexOf(detID);
174 if (!detectorInfo.isMasked(
index))
175 angle += detectorInfo.detector(
index).solidAngle({samplePos, numberOfCylinderSlices});
180 std::vector<double> maskFractions;
181 if (inputWorkspace->hasMaskedBins(i)) {
184 maskFractions.resize(numBins, 1.0);
185 MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end());
186 for (it = mask.begin(); it != itEnd; ++it) {
189 maskFractions[it->first] -= it->second;
192 double maskFraction(1);
201 for (
int j =
static_cast<int>(numBins) - 1; j >=
static_cast<int>(wavStart); --j) {
205 const double binWidth =
X[j + 1] -
X[j];
207 const double wavLength =
X[j] + (binWidth) / 2.0;
216 const double Q = 4.0 * M_PI * sinTheta / wavLength;
219 const double Qx = a * Q;
221 if (Qx < axis.front() || Qx >= axis.back())
223 const double Qy = b * Q;
224 if (Qy < axis.front() || Qy >= axis.back())
228 const auto xIndex = std::upper_bound(axis.begin(), axis.end(), Qx) - axis.begin() - 1;
229 const int yIndex =
static_cast<int>(std::upper_bound(axis.begin(), axis.end(), Qy) - axis.begin() - 1);
234 double &outputBinY = outputWorkspace->mutableY(yIndex)[xIndex];
235 double &outputBinE = outputWorkspace->mutableE(yIndex)[xIndex];
237 if (std::isnan(outputBinY)) {
238 outputBinY = outputBinE = 0;
243 outputBinE = std::sqrt((outputBinE * outputBinE) + (E[j] * E[j]));
246 if (!maskFractions.empty()) {
247 maskFraction = maskFractions[j];
256 weight = maskFraction * angle;
258 weight = maskFraction;
262 auto &outWeightsY = weights->mutableY(yIndex);
263 auto &outWeightsE = weights->mutableE(yIndex);
265 if (pixelAdj && waveAdj) {
266 auto pixelY = pixelAdj->y(i)[0];
267 auto pixelE = pixelAdj->e(i)[0];
269 auto waveY = waveAdj->y(0)[j];
270 auto waveE = waveAdj->e(0)[j];
272 outWeightsY[xIndex] += weight * pixelY * waveY;
273 const double pixelYSq = pixelY * pixelY;
274 const double pixelESq = pixelE * pixelE;
275 const double waveYSq = waveY * waveY;
276 const double waveESq = waveE * waveE;
279 outWeightsE[xIndex] += weight * weight * (waveESq * pixelYSq + pixelESq * waveYSq);
280 }
else if (pixelAdj) {
281 auto pixelY = pixelAdj->y(i)[0];
282 auto pixelE = pixelAdj->e(i)[0];
284 outWeightsY[xIndex] += weight * pixelY;
285 const double pixelESq = weight * pixelE;
287 outWeightsE[xIndex] += pixelESq * pixelESq;
288 }
else if (waveAdj) {
289 auto waveY = waveAdj->y(0)[j];
290 auto waveE = waveAdj->e(0)[j];
292 outWeightsY[xIndex] += weight * waveY;
293 const double waveESq = weight * waveE;
295 outWeightsE[xIndex] += waveESq * waveESq;
297 outWeightsY[xIndex] += weight;
301 prog.
report(
"Calculating Q");
307 size_t numHist = weights->getNumberHistograms();
308 for (
size_t i = 0; i < numHist; i++) {
309 auto &weightsE = weights->mutableE(i);
310 std::transform(weightsE.cbegin(), weightsE.cend(), weightsE.begin(), [&](
double val) { return sqrt(val); });
317 for (
size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++) {
318 ws_sumOfCounts->setHistogram(i, outputWorkspace->histogram(i));
325 outputWorkspace /= weights;
326 outputWorkspace->setDistribution(
true);
329 const size_t nhist = outputWorkspace->getNumberHistograms();
330 const size_t nbins = outputWorkspace->blocksize();
332 for (
size_t i = 0; i < nhist; ++i) {
333 const auto &yOut = outputWorkspace->y(i);
334 for (
size_t j = 0; j < nbins; ++j) {
335 if (yOut[j] < 1.0e-12)
341 g_log.
notice() <<
"There are a total of " << emptyBins <<
" (" << (100 * emptyBins) / (outputWorkspace->size())
342 <<
"%) empty Q bins.\n";
392 const bool log_binning =
getProperty(
"IQxQyLogBinning");
395 auto nBins =
static_cast<int>(max /
delta);
397 HistogramData::BinEdges axis;
401 std::vector<double> positiveBinning =
logBinning(qmin, max, nBins);
402 std::reverse(std::begin(positiveBinning), std::end(positiveBinning));
403 std::vector<double> totalBinning = positiveBinning;
404 std::for_each(std::begin(totalBinning), std::end(totalBinning), [](
double &
n) {
n = -1 *
n; });
405 totalBinning.emplace_back(0.0);
406 std::reverse(std::begin(positiveBinning), std::end(positiveBinning));
407 totalBinning.insert(std::end(totalBinning), std::begin(positiveBinning), std::end(positiveBinning));
408 nBins = nBins * 2 + 1;
412 if (nBins *
delta != max)
415 double startVal = -1.0 *
delta * nBins;
420 HistogramData::BinEdges linearAxis(nBins, HistogramData::LinearGenerator(startVal,
delta));
429 auto verticalAxis = std::make_unique<BinEdgeAxis>(nBins);
430 auto verticalAxisRaw = verticalAxis.get();
431 outputWorkspace->replaceAxis(1, std::move(verticalAxis));
432 for (
int i = 0; i < nBins; ++i) {
433 const double currentVal = axis[i];
435 verticalAxisRaw->setValue(i, currentVal);
439 for (
int i = 0; i < nBins - 1; ++i) {
440 outputWorkspace->setBinEdges(i, axis);
441 auto &
y = outputWorkspace->mutableY(i);
442 auto &e = outputWorkspace->mutableE(i);
444 for (
int j = 0; j < nBins - j; ++j) {
445 y[j] = std::numeric_limits<double>::quiet_NaN();
446 e[j] = std::numeric_limits<double>::quiet_NaN();
451 outputWorkspace->getAxis(1)->unit() = outputWorkspace->getAxis(0)->unit() =
452 UnitFactory::Instance().create(
"MomentumTransfer");
455 outputWorkspace->setYUnitLabel(
"Cross Section (1/cm)");
458 return outputWorkspace;