DoubleReal IsobaricChannelExtractor::sumPotentialIsotopePeaks_(const MSExperiment<Peak1D>::ConstIterator& precursor,
                                                                 const Peak1D::CoordinateType& lower_mz_bound,
                                                                 const Peak1D::CoordinateType& upper_mz_bound,
                                                                 Peak1D::CoordinateType theoretical_mz,
                                                                 const Peak1D::CoordinateType isotope_offset) const
  {
    DoubleReal intensity_contribution = 0.0;

    // move theoretical_mz to first potential isotopic peak
    theoretical_mz += isotope_offset;

    // check if we are still in the isolation window
    while (theoretical_mz > lower_mz_bound && theoretical_mz < upper_mz_bound)
    {
      Size potential_peak = precursor->findNearest(theoretical_mz);

      // is isotopic ?
      if (fabs(theoretical_mz - (*precursor)[potential_peak].getMZ()) < max_precursor_isotope_deviation_)
      {
        intensity_contribution += (*precursor)[potential_peak].getIntensity();
      }
      else
      {
        // we abort in case of missing peaks
        break;
      }

      // update mz with the defined offset
      theoretical_mz += isotope_offset;
    }

    return intensity_contribution;
  }
  DoubleReal IsobaricChannelExtractor::computePrecursorPurity_(const MSExperiment<Peak1D>::ConstIterator& ms2_spec, const MSExperiment<Peak1D>::ConstIterator& precursor) const
  {
    // we cannot analyze precursors without a charge
    if (ms2_spec->getPrecursors()[0].getCharge() == 0)
      return 1.0;

    // compute boundaries
    const MSExperiment<>::SpectrumType::ConstIterator isolation_lower_mz = precursor->MZBegin(ms2_spec->getPrecursors()[0].getMZ() - ms2_spec->getPrecursors()[0].getIsolationWindowLowerOffset());
    const MSExperiment<>::SpectrumType::ConstIterator isolation_upper_mz = precursor->MZEnd(ms2_spec->getPrecursors()[0].getMZ() + ms2_spec->getPrecursors()[0].getIsolationWindowUpperOffset());

    Peak1D::IntensityType total_intensity = 0;

    // get total intensity
    for (MSExperiment<>::SpectrumType::ConstIterator isolation_it = isolation_lower_mz;
         isolation_it != isolation_upper_mz;
         ++isolation_it)
    {
      total_intensity += isolation_it->getIntensity();
    }

    // now get the intensity of the precursor .. we assume everything in the distance of 1/c to belong to the precursor
    // for c == charge of precursor

    // precursor mz
    Size precursor_peak_idx = precursor->findNearest(ms2_spec->getPrecursors()[0].getMZ());
    Peak1D precursor_peak = (*precursor)[precursor_peak_idx];
    Peak1D::IntensityType precursor_intensity = precursor_peak.getIntensity();

    // compute the
    double charge_dist = Constants::NEUTRON_MASS_U / (double) ms2_spec->getPrecursors()[0].getCharge();

    // search left of precursor for isotopic peaks
    precursor_intensity += sumPotentialIsotopePeaks_(precursor, isolation_lower_mz->getMZ(), isolation_upper_mz->getMZ(), precursor_peak.getMZ(), -1 * charge_dist);
    // search right of precursor for isotopic peaks
    precursor_intensity += sumPotentialIsotopePeaks_(precursor, isolation_lower_mz->getMZ(), isolation_upper_mz->getMZ(), precursor_peak.getMZ(), charge_dist);

    return precursor_intensity / total_intensity;
  }