103 const bool doGravity =
getProperty(
"AccountForGravity");
104 const bool doSolidAngle =
getProperty(
"SolidAngleWeighting");
109 g_log.
debug() <<
"All input workspaces were found to be valid\n";
118 for (
size_t i = 0; i < weights->getNumberHistograms(); ++i)
119 weights->setSharedX(i, outputWorkspace->sharedX(0));
121 const size_t numSpec = inputWorkspace->getNumberHistograms();
122 const size_t numBins = inputWorkspace->blocksize();
125 Progress prog(
this, 0.05, 1.0, numSpec);
127 const auto &spectrumInfo = inputWorkspace->spectrumInfo();
128 const auto &detectorInfo = inputWorkspace->detectorInfo();
129 const auto &componentInfo = inputWorkspace->componentInfo();
133 const V3D samplePos = spectrumInfo.samplePosition();
135 for (int64_t i = 0; i < int64_t(numSpec); ++i) {
136 if (!spectrumInfo.hasDetectors(i)) {
137 g_log.
warning() <<
"Workspace index " << i <<
" has no detector assigned to it - discarding\n";
142 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
147 const size_t wavStart =
149 if (wavStart >= inputWorkspace->y(i).size()) {
154 V3D detPos = spectrumInfo.position(i) - samplePos;
158 double phi = atan2(detPos.
Y(), detPos.
X());
161 double sinTheta = sin(spectrumInfo.twoTheta(i) * 0.5);
164 const auto &
X = inputWorkspace->x(i);
165 const auto &
Y = inputWorkspace->y(i);
166 const auto &E = inputWorkspace->e(i);
168 const auto &axis = outputWorkspace->x(0);
172 const int numberOfCylinderSlices =
getProperty(
"SolidAngleNumberOfCylinderSlices");
174 for (
const auto detID : inputWorkspace->getSpectrum(i).getDetectorIDs()) {
175 const auto index = detectorInfo.indexOf(detID);
176 if (!detectorInfo.isMasked(
index))
177 angle += componentInfo.solidAngle(
index, {samplePos, numberOfCylinderSlices});
182 std::vector<double> maskFractions;
183 if (inputWorkspace->hasMaskedBins(i)) {
186 maskFractions.resize(numBins, 1.0);
187 MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end());
188 for (it = mask.begin(); it != itEnd; ++it) {
191 maskFractions[it->first] -= it->second;
194 double maskFraction(1);
203 for (
int j =
static_cast<int>(numBins) - 1; j >=
static_cast<int>(wavStart); --j) {
207 const double binWidth =
X[j + 1] -
X[j];
209 const double wavLength =
X[j] + (binWidth) / 2.0;
218 const double Q = 4.0 * M_PI * sinTheta / wavLength;
221 const double Qx = a * Q;
223 if (Qx < axis.front() || Qx >= axis.back())
225 const double Qy = b * Q;
226 if (Qy < axis.front() || Qy >= axis.back())
230 const auto xIndex = std::upper_bound(axis.begin(), axis.end(), Qx) - axis.begin() - 1;
231 const int yIndex =
static_cast<int>(std::upper_bound(axis.begin(), axis.end(), Qy) - axis.begin() - 1);
236 double &outputBinY = outputWorkspace->mutableY(yIndex)[xIndex];
237 double &outputBinE = outputWorkspace->mutableE(yIndex)[xIndex];
239 if (std::isnan(outputBinY)) {
240 outputBinY = outputBinE = 0;
245 outputBinE = std::sqrt((outputBinE * outputBinE) + (E[j] * E[j]));
248 if (!maskFractions.empty()) {
249 maskFraction = maskFractions[j];
258 weight = maskFraction * angle;
260 weight = maskFraction;
264 auto &outWeightsY = weights->mutableY(yIndex);
265 auto &outWeightsE = weights->mutableE(yIndex);
267 if (pixelAdj && waveAdj) {
268 auto pixelY = pixelAdj->y(i)[0];
269 auto pixelE = pixelAdj->e(i)[0];
271 auto waveY = waveAdj->y(0)[j];
272 auto waveE = waveAdj->e(0)[j];
274 outWeightsY[xIndex] += weight * pixelY * waveY;
275 const double pixelYSq = pixelY * pixelY;
276 const double pixelESq = pixelE * pixelE;
277 const double waveYSq = waveY * waveY;
278 const double waveESq = waveE * waveE;
281 outWeightsE[xIndex] += weight * weight * (waveESq * pixelYSq + pixelESq * waveYSq);
282 }
else if (pixelAdj) {
283 auto pixelY = pixelAdj->y(i)[0];
284 auto pixelE = pixelAdj->e(i)[0];
286 outWeightsY[xIndex] += weight * pixelY;
287 const double pixelESq = weight * pixelE;
289 outWeightsE[xIndex] += pixelESq * pixelESq;
290 }
else if (waveAdj) {
291 auto waveY = waveAdj->y(0)[j];
292 auto waveE = waveAdj->e(0)[j];
294 outWeightsY[xIndex] += weight * waveY;
295 const double waveESq = weight * waveE;
297 outWeightsE[xIndex] += waveESq * waveESq;
299 outWeightsY[xIndex] += weight;
303 prog.
report(
"Calculating Q");
309 size_t numHist = weights->getNumberHistograms();
310 for (
size_t i = 0; i < numHist; i++) {
311 auto &weightsE = weights->mutableE(i);
312 std::transform(weightsE.cbegin(), weightsE.cend(), weightsE.begin(), [&](
double val) { return sqrt(val); });
315 bool doOutputParts = getProperty(
"OutputParts");
319 for (
size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++) {
320 ws_sumOfCounts->setHistogram(i, outputWorkspace->histogram(i));
323 helper.outputParts(
this, ws_sumOfCounts, weights);
327 outputWorkspace /= weights;
328 outputWorkspace->setDistribution(
true);
331 const size_t nhist = outputWorkspace->getNumberHistograms();
332 const size_t nbins = outputWorkspace->blocksize();
334 for (
size_t i = 0; i < nhist; ++i) {
335 const auto &yOut = outputWorkspace->y(i);
336 for (
size_t j = 0; j <
nbins; ++j) {
337 if (yOut[j] < 1.0e-12)
343 g_log.
notice() <<
"There are a total of " << emptyBins <<
" (" << (100 * emptyBins) / (outputWorkspace->size())
344 <<
"%) empty Q bins.\n";
392 const double max = getProperty(
"MaxQxy");
393 const double delta = getProperty(
"DeltaQ");
394 const bool log_binning = getProperty(
"IQxQyLogBinning");
397 auto nBins =
static_cast<int>(max /
delta);
399 HistogramData::BinEdges axis;
402 double qmin = getQminFromWs(*inputWorkspace);
403 std::vector<double> positiveBinning = logBinning(qmin, max, nBins);
404 std::reverse(std::begin(positiveBinning), std::end(positiveBinning));
405 std::vector<double> totalBinning = positiveBinning;
406 std::for_each(std::begin(totalBinning), std::end(totalBinning), [](
double &
n) {
n = -1 *
n; });
407 totalBinning.emplace_back(0.0);
408 std::reverse(std::begin(positiveBinning), std::end(positiveBinning));
409 totalBinning.insert(std::end(totalBinning), std::begin(positiveBinning), std::end(positiveBinning));
410 nBins = nBins * 2 + 1;
414 if (nBins *
delta != max)
417 double startVal = -1.0 *
delta * nBins;
422 HistogramData::BinEdges linearAxis(nBins, HistogramData::LinearGenerator(startVal,
delta));
431 auto verticalAxis = std::make_unique<BinEdgeAxis>(nBins);
432 auto verticalAxisRaw = verticalAxis.get();
433 outputWorkspace->replaceAxis(1, std::move(verticalAxis));
434 for (
int i = 0; i < nBins; ++i) {
435 const double currentVal = axis[i];
437 verticalAxisRaw->setValue(i, currentVal);
441 for (
int i = 0; i < nBins - 1; ++i) {
442 outputWorkspace->setBinEdges(i, axis);
443 auto &
y = outputWorkspace->mutableY(i);
444 auto &e = outputWorkspace->mutableE(i);
446 for (
int j = 0; j < nBins - j; ++j) {
447 y[j] = std::numeric_limits<double>::quiet_NaN();
448 e[j] = std::numeric_limits<double>::quiet_NaN();
453 outputWorkspace->getAxis(1)->unit() = outputWorkspace->getAxis(0)->unit() =
454 UnitFactory::Instance().create(
"MomentumTransfer");
457 outputWorkspace->setYUnitLabel(
"Cross Section (1/cm)");
459 setProperty(
"OutputWorkspace", outputWorkspace);
460 return outputWorkspace;