/** * Rebin the input quadrilateral to the output grid * @param inputQ The input polygon * @param inputWS The input workspace containing the input intensity values * @param i The index in the vertical axis direction that inputQ references * @param j The index in the horizontal axis direction that inputQ references * @param outputWS A pointer to the output workspace that accumulates the data * @param verticalAxis A vector containing the output vertical axis bin boundaries */ void Rebin2D::rebinToFractionalOutput(const Geometry::Quadrilateral & inputQ, MatrixWorkspace_const_sptr inputWS, const size_t i, const size_t j, RebinnedOutput_sptr outputWS, const std::vector<double> & verticalAxis) { const MantidVec & X = outputWS->readX(0); size_t qstart(0), qend(verticalAxis.size()-1), en_start(0), en_end(X.size() - 1); if( !getIntersectionRegion(outputWS, verticalAxis, inputQ, qstart, qend, en_start, en_end)) return; for( size_t qi = qstart; qi < qend; ++qi ) { const double vlo = verticalAxis[qi]; const double vhi = verticalAxis[qi+1]; for( size_t ei = en_start; ei < en_end; ++ei ) { const V2D ll(X[ei], vlo); const V2D lr(X[ei+1], vlo); const V2D ur(X[ei+1], vhi); const V2D ul(X[ei], vhi); const Quadrilateral outputQ(ll, lr, ur, ul); double yValue = inputWS->readY(i)[j]; if (boost::math::isnan(yValue)) { continue; } try { ConvexPolygon overlap = intersectionByLaszlo(outputQ, inputQ); const double weight = overlap.area()/inputQ.area(); yValue *= weight; double eValue = inputWS->readE(i)[j] * weight; const double overlapWidth = overlap.largestX() - overlap.smallestX(); // Don't do the overlap removal if already RebinnedOutput. // This wreaks havoc on the data. if(inputWS->isDistribution() && inputWS->id() != "RebinnedOutput") { yValue *= overlapWidth; eValue *= overlapWidth; } eValue *= eValue; PARALLEL_CRITICAL(overlap) { outputWS->dataY(qi)[ei] += yValue; outputWS->dataE(qi)[ei] += eValue; outputWS->dataF(qi)[ei] += weight; } } catch(Geometry::NoIntersectionException &) {} } } }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors ISpectrum *outSpec = outputWorkspace->getSpectrum(0); MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec &FracSum = outWS->dataF(0); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = m_indices.begin(); it != m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); const MantidVec &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. auto localworkspace = replaceSpecialValues(in_ws); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors auto &outSpec = outputWorkspace->getSpectrum(0); auto &YSum = outSpec.mutableY(); auto &YError = outSpec.mutableE(); auto &FracSum = outWS->dataF(0); std::vector<double> Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; const auto &spectrumInfo = localworkspace->spectrumInfo(); // Loop over spectra for (const auto i : m_indices) { // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } if (spectrumInfo.hasDetectors(i)) { // Skip monitors, if the property is set to do so if (!m_keepMonitors && spectrumInfo.isMonitor(i)) continue; // Skip masked detectors if (spectrumInfo.isMasked(i)) { numMasked++; continue; } } numSpectra++; // Retrieve the spectrum into a vector const auto &YValues = localworkspace->y(i); const auto &YErrors = localworkspace->e(i); const auto &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec.addDetectorIDs(localworkspace->getSpectrum(i).getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (numSpectra > nZeros[i]) YSum[i] *= double(numSpectra - nZeros[i]) / Weight[i]; if (nZeros[i] != 0) numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }