/// 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 {