/// Modifies count data so that the sum is zero. void PoldiResidualCorrelationCore::correctCountData() const { double sumOfResiduals = getSumOfCounts(m_timeBinCount, m_detectorElements); double numberOfCells = static_cast<double>(m_timeBinCount * m_detectorElements.size()); double ratio = sumOfResiduals / numberOfCells; PARALLEL_FOR_NO_WSP_CHECK() for (int i = 0; i < static_cast<int>(m_detectorElements.size()); // NOLINT ++i) { int element = m_detectorElements[i]; for (int j = 0; j < m_timeBinCount; ++j) { addToCountData(element, j, -ratio); } } }
/** * Distributes correlation counts into count data and corrects correlation *spectrum * * This method does three things: First it distributes the intensity of the *correlation spectrum * for a given d-value over all places in the detector where it may belong. *After that it sums * the new residuals and distributes them equally over all points of the 2D *data. * * After a new summation of those corrected residuals, the correlation spectrum *is corrected * accordingly. * * Please note that this method modifies the stored count data. * * @param correctedCorrelatedIntensities :: Corrected correlation spectrum of *the residuals. * @param dValues :: d-values in reverse order. * @return Final corrected correlation spectrum of residuals. */ DataObjects::Workspace2D_sptr PoldiResidualCorrelationCore::finalizeCalculation( const std::vector<double> &correctedCorrelatedIntensities, const std::vector<double> &dValues) const { distributeCorrelationCounts(correctedCorrelatedIntensities, dValues); correctCountData(); double sumOfResiduals = getSumOfCounts(m_timeBinCount, m_detectorElements); std::vector<double> newCorrected(correctedCorrelatedIntensities.size()); for (size_t i = 0; i < correctedCorrelatedIntensities.size(); ++i) { newCorrected[i] = correctedCorrelatedIntensities[i] - (sumOfResiduals * m_weightsForD[i] / m_sumOfWeights); } return PoldiAutoCorrelationCore::finalizeCalculation(newCorrected, dValues); }
/** Performs auto-correlation algorithm on the POLDI data in the supplied *workspace. * * @param countData :: Instance of Workspace2D with POLDI data. * @return A workspace containing the correlation spectrum. */ DataObjects::Workspace2D_sptr PoldiAutoCorrelationCore::calculate( DataObjects::Workspace2D_sptr &countData, const DataObjects::Workspace2D_sptr &normCountData) { m_logger.information() << "Starting Autocorrelation method..." << std::endl; if (m_detector && m_chopper) { m_logger.information() << " Assigning count data..." << std::endl; setCountData(countData); if (normCountData) { setNormCountData(normCountData); } else { setNormCountData(countData); } /* Calculations related to experiment timings * - width of time bins (deltaT) * - d-resolution deltaD, which results directly from deltaT * - number of time bins for each copper cycle */ std::vector<double> timeData = m_countData->readX(0); m_logger.information() << " Setting time data..." << std::endl; m_deltaT = timeData[1] - timeData[0]; m_timeBinCount = static_cast<int>(m_chopper->cycleTime() / m_deltaT); PoldiDGrid dGrid(m_detector, m_chopper, m_deltaT, m_wavelengthRange); m_deltaD = dGrid.deltaD(); /* Data related to detector geometry * - vector with available detector element-indices (wires, cells, ...) * - vector that contains the TOF/Angstrom for each detector element * - vector with indices on interval [0, number of detector elements) for * help with access in algorithm */ m_detectorElements = m_detector->availableElements(); m_tofsFor1Angstrom = getTofsFor1Angstrom(m_detectorElements); m_indices.resize(m_detectorElements.size()); for (int i = 0; i < static_cast<int>(m_indices.size()); ++i) { m_indices[i] = i; } /* The auto-correlation algorithm works by probing a list of d-Values, which * is created at this point. The spacing used is the maximum resolution of * the instrument, * which was calculated before. */ m_logger.information() << " Generating d-grid..." << std::endl; std::vector<double> dValues = dGrid.grid(); /* When the correlation background is subtracted from the correlation * spectrum, it is done for each d-Value * according to a certain weight. The calculation method corresponds closely * to the original fortran program, * although it simply leads to unit weights. */ m_logger.information() << " Calculating weights (" << dValues.size() << ")..." << std::endl; m_weightsForD = calculateDWeights(m_tofsFor1Angstrom, m_deltaT, m_deltaD, dValues.size()); m_sumOfWeights = getNormalizedTOFSum(m_weightsForD); /* Calculation of the raw correlation spectrum. Each d-Value is mapped to an * intensity value through, * taking into account the d-Value and the weight. Since the calculations * for different d-Values do not * depend on eachother, the for-loop is marked as a candidate for * parallelization. Since the calculation * of the intensity is rather complex and typical d-grids consist of ~5000 * elements, the parallelization * pays off quite well. */ m_logger.information() << " Calculating intensities..." << std::endl; std::vector<double> rawCorrelatedIntensities(dValues.size()); PARALLEL_FOR_NO_WSP_CHECK() for (int i = 0; i < static_cast<int>(dValues.size()); ++i) { rawCorrelatedIntensities[i] = getRawCorrelatedIntensity(dValues[i], m_weightsForD[i]); } /* As detailed in the original POLDI-paper, the sum of all correlation *intensities is much higher than the * sum of counts in the recorded spectrum. The difference is called *"correlation background" and is subtracted * from the raw intensities, using the weights calculated before. * * After this procedure, the sum of correlated intensities should be equal *to the sum of counts in the spectrum. * In the fortran program there seems to be a small difference, possibly due *to numerical inaccuracies connected * to floating point precision. */ double sumOfCorrelatedIntensities = std::accumulate( rawCorrelatedIntensities.begin(), rawCorrelatedIntensities.end(), 0.0); double sumOfCounts = getSumOfCounts(m_timeBinCount, m_detectorElements); m_logger.information() << " Summing intensities (" << sumOfCounts << ")..." << std::endl; m_correlationBackground = calculateCorrelationBackground(sumOfCorrelatedIntensities, sumOfCounts); m_logger.information() << " Correcting intensities..." << std::endl; std::vector<double> correctedCorrelatedIntensities(dValues.size()); std::transform(rawCorrelatedIntensities.begin(), rawCorrelatedIntensities.end(), m_weightsForD.begin(), correctedCorrelatedIntensities.rbegin(), boost::bind(&PoldiAutoCorrelationCore::correctedIntensity, this, _1, _2)); /* The algorithm performs some finalization. In the default case the * spectrum is * simply converted to Q and stored in a workspace. The reason to make this * step variable * is that for calculation of residuals, everything is the same except this * next step. */ return finalizeCalculation(correctedCorrelatedIntensities, dValues); } else {