/** Carries out the bin-by-bin normalization * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin( const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace) { if (inputEvent) { outputWorkspace = inputWorkspace->clone(); } else outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); } auto outputEvent = boost::dynamic_pointer_cast<EventWorkspace>(outputWorkspace); // Get hold of the monitor spectrum const MantidVec &monX = m_monitor->readX(0); MantidVec &monY = m_monitor->dataY(0); MantidVec &monE = m_monitor->dataE(0); // Calculate the overall normalization just the once if bins are all matching if (m_commonBins) this->normalisationFactor(m_monitor->readX(0), &monY, &monE); const size_t numHists = inputWorkspace->getNumberHistograms(); MantidVec::size_type specLength = inputWorkspace->blocksize(); // Flag set when a division by 0 is found bool hasZeroDivision = false; Progress prog(this, 0.0, 1.0, numHists); // Loop over spectra PARALLEL_FOR3(inputWorkspace, outputWorkspace, m_monitor) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const MantidVec &X = inputWorkspace->readX(i); // If not rebinning, just point to our monitor spectra, otherwise create new // vectors MantidVec *Y = (m_commonBins ? &monY : new MantidVec(specLength)); MantidVec *E = (m_commonBins ? &monE : new MantidVec(specLength)); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeros - skip these, they cause // problems if (X.back() == 0.0 && X.front() == 0.0) continue; // Rebin the monitor spectrum to match the binning of the current data // spectrum VectorHelper::rebinHistogram(monX, monY, monE, X, *Y, *E, false); // Recalculate the overall normalization factor this->normalisationFactor(X, Y, E); } if (inputEvent) { // ----------------------------------- EventWorkspace // --------------------------------------- EventList &outEL = outputEvent->getEventList(i); outEL.divide(X, *Y, *E); } else { // ----------------------------------- Workspace2D // --------------------------------------- MantidVec &YOut = outputWorkspace->dataY(i); MantidVec &EOut = outputWorkspace->dataE(i); const MantidVec &inY = inputWorkspace->readY(i); const MantidVec &inE = inputWorkspace->readE(i); outputWorkspace->dataX(i) = inputWorkspace->readX(i); // The code below comes more or less straight out of Divide.cpp for (MantidVec::size_type k = 0; k < specLength; ++k) { // Get references to the input Y's const double &leftY = inY[k]; const double &rightY = (*Y)[k]; if (rightY == 0.0) { hasZeroDivision = true; } // Calculate result and store in local variable to avoid overwriting // original data if // output workspace is same as one of the input ones const double newY = leftY / rightY; if (fabs(rightY) > 1.0e-12 && fabs(newY) > 1.0e-12) { const double lhsFactor = (inE[k] < 1.0e-12 || fabs(leftY) < 1.0e-12) ? 0.0 : pow((inE[k] / leftY), 2); const double rhsFactor = (*E)[k] < 1.0e-12 ? 0.0 : pow(((*E)[k] / rightY), 2); EOut[k] = std::abs(newY) * sqrt(lhsFactor + rhsFactor); } // Now store the result YOut[k] = newY; } // end Workspace2D case } // end loop over current spectrum if (!m_commonBins) { delete Y; delete E; } PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION if (hasZeroDivision) { g_log.warning() << "Division by zero in some of the bins." << std::endl; } }
/** Carries out the bin-by-bin normalization * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin( const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace) { if (inputEvent) { outputWorkspace = inputWorkspace->clone(); } else outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); } auto outputEvent = boost::dynamic_pointer_cast<EventWorkspace>(outputWorkspace); // Get hold of the monitor spectrum const auto &monX = m_monitor->binEdges(0); auto monY = m_monitor->counts(0); auto monE = m_monitor->countStandardDeviations(0); // Calculate the overall normalization just the once if bins are all matching if (m_commonBins) this->normalisationFactor(monX, monY, monE); const size_t numHists = inputWorkspace->getNumberHistograms(); auto specLength = inputWorkspace->blocksize(); // Flag set when a division by 0 is found bool hasZeroDivision = false; Progress prog(this, 0.0, 1.0, numHists); // Loop over spectra PARALLEL_FOR_IF( Kernel::threadSafe(*inputWorkspace, *outputWorkspace, *m_monitor)) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const auto &X = inputWorkspace->binEdges(i); // If not rebinning, just point to our monitor spectra, otherwise create new // vectors auto Y = (m_commonBins ? monY : Counts(specLength)); auto E = (m_commonBins ? monE : CountStandardDeviations(specLength)); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeros - skip these, they cause // problems if (X.back() == 0.0 && X.front() == 0.0) continue; // Rebin the monitor spectrum to match the binning of the current data // spectrum VectorHelper::rebinHistogram( monX.rawData(), monY.mutableRawData(), monE.mutableRawData(), X.rawData(), Y.mutableRawData(), E.mutableRawData(), false); // Recalculate the overall normalization factor this->normalisationFactor(X, Y, E); } if (inputEvent) { // ----------------------------------- EventWorkspace // --------------------------------------- EventList &outEL = outputEvent->getSpectrum(i); outEL.divide(X.rawData(), Y.mutableRawData(), E.mutableRawData()); } else { // ----------------------------------- Workspace2D // --------------------------------------- auto &YOut = outputWorkspace->mutableY(i); auto &EOut = outputWorkspace->mutableE(i); const auto &inY = inputWorkspace->y(i); const auto &inE = inputWorkspace->e(i); outputWorkspace->mutableX(i) = inputWorkspace->x(i); // The code below comes more or less straight out of Divide.cpp for (size_t k = 0; k < specLength; ++k) { // Get the input Y's const double leftY = inY[k]; const double rightY = Y[k]; if (rightY == 0.0) { hasZeroDivision = true; } // Calculate result and store in local variable to avoid overwriting // original data if // output workspace is same as one of the input ones const double newY = leftY / rightY; if (fabs(rightY) > 1.0e-12 && fabs(newY) > 1.0e-12) { const double lhsFactor = (inE[k] < 1.0e-12 || fabs(leftY) < 1.0e-12) ? 0.0 : pow((inE[k] / leftY), 2); const double rhsFactor = E[k] < 1.0e-12 ? 0.0 : pow((E[k] / rightY), 2); EOut[k] = std::abs(newY) * sqrt(lhsFactor + rhsFactor); } // Now store the result YOut[k] = newY; } // end Workspace2D case } // end loop over current spectrum PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION if (hasZeroDivision) { g_log.warning() << "Division by zero in some of the bins.\n"; } }