示例#1
0
        /// <summary>
        /// Aligns an isotopic profile based on a source isotopic profile.
        /// </summary>
        /// <param name="iso1">Source isotopic profile</param>
        /// <param name="iso2">isotopic profile to be offset</param>
        public static void AlignTwoIsotopicProfiles(IsotopicProfile iso1, IsotopicProfile iso2)
        {
            double offset;

            if (iso2?.Peaklist == null || iso2.Peaklist.Count == 0)
            {
                return;
            }

            var mostIntensePeak        = iso2.getMostIntensePeak();
            var indexOfMostIntensePeak = iso2.Peaklist.IndexOf(mostIntensePeak);

            if (iso1.Peaklist == null || iso1.Peaklist.Count == 0)
            {
                return;
            }

            var enoughPeaksInTarget = (indexOfMostIntensePeak <= iso1.Peaklist.Count - 1);

            if (enoughPeaksInTarget)
            {
                var targetPeak = iso1.Peaklist[indexOfMostIntensePeak];
                offset = targetPeak.XValue - mostIntensePeak.XValue;
                //offset = observedIsotopicProfile.Peaklist[0].XValue - theorIsotopicProfile.Peaklist[0].XValue;   //want to test to see if Thrash is same as rapid
            }
            else
            {
                offset = iso1.Peaklist[0].XValue - iso2.Peaklist[0].XValue;
            }

            foreach (var peak in iso2.Peaklist)
            {
                peak.XValue = peak.XValue + offset;
            }
        }
        public static void AdjustSaturatedIsotopicProfile(IsotopicProfile iso, IsotopicProfile theorIsotopicProfile, int indexOfIsotopeToUse, bool updatePeakMasses = true, bool updatePeakIntensities = true)
        {
            //ensure targetPeak is within range
            if (indexOfIsotopeToUse >= theorIsotopicProfile.Peaklist.Count)
            {
                return;
            }

            MSPeak observedPeakOfIsotopeToUse = iso.Peaklist[indexOfIsotopeToUse];
            float intensityObsPeakForExtrapolation = observedPeakOfIsotopeToUse.Height;
            float widthObsPeakForExtrapolation = observedPeakOfIsotopeToUse.Width;
            var xValueObsPeakForExteapolation = observedPeakOfIsotopeToUse.XValue;
            float intensityTheorPeakForExtrapolation = theorIsotopicProfile.Peaklist[indexOfIsotopeToUse].Height;

            for (int i = 0; i < iso.Peaklist.Count; i++)
            {
                if (i < indexOfIsotopeToUse)
                {
                    MSPeak currentPeak = iso.Peaklist[i];

                    if (updatePeakIntensities)
                    {
                        if (i >= theorIsotopicProfile.Peaklist.Count)
                        {
                            currentPeak.Height = 0;
                        }
                        else
                        {
                            currentPeak.Height = theorIsotopicProfile.Peaklist[i].Height * intensityObsPeakForExtrapolation / intensityTheorPeakForExtrapolation;
                        }

                        currentPeak.Width = widthObsPeakForExtrapolation;    //repair the width too, because it can get huge. Width can be used in determining tolerances.
                    }

                    //correct the m/z value, to more accurately base it on the non-saturated peak.  See Chernushevich et al. 2001 http://onlinelibrary.wiley.com/doi/10.1002/jms.207/abstract
                    if (updatePeakMasses)
                    {
                        // formula is  MZ0 = MZ3 - (1.003/z)*n, where MZ0 is the m/z of the saturated peak and MZ3 the m/z of the nonSaturated peak and z is charge state and n is the difference in peak number
                        currentPeak.XValue = xValueObsPeakForExteapolation - ((Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS) / iso.ChargeState * (indexOfIsotopeToUse - i));
                    }

                }
            }

            iso.IntensityMostAbundant = iso.getMostIntensePeak().Height;

            int indexMostAbundantPeakTheor = theorIsotopicProfile.GetIndexOfMostIntensePeak();

            if (iso.Peaklist.Count > indexMostAbundantPeakTheor)
            {
                iso.IntensityMostAbundantTheor = iso.Peaklist[indexMostAbundantPeakTheor].Height;
            }
            else
            {
                iso.IntensityMostAbundantTheor = iso.IntensityMostAbundant;
            }

            UpdateMonoisotopicMassData(iso);
        }
示例#3
0
        public virtual IsotopicProfile IterativelyFindMSFeature(XYData massSpecXyData, IsotopicProfile theorIso, out List <Peak> peakList)
        {
            if (massSpecXyData == null)
            {
                peakList = new List <Peak>();
                return(null);
            }


            IsotopicProfile iso = null;

            this.MSPeakDetector.MinX = theorIso.MonoPeakMZ - 10;
            this.MSPeakDetector.MaxX = theorIso.MonoPeakMZ + 20;


            //start with high PeakBR and rachet it down, so as to detect more peaks with each pass.  Stop when you find the isotopic profile.
            peakList = new List <Peak>();

            for (var d = PeakDetectorPeakBR; d >= PeakBRMin; d = d - PeakBRStep)
            {
                this.MSPeakDetector.PeakToBackgroundRatio = d;

                peakList = MSPeakDetector.FindPeaks(massSpecXyData.Xvalues, massSpecXyData.Yvalues);
                iso      = FindMSFeature(peakList, theorIso);

                bool isoIsGoodEnough;

                if (iso == null)
                {
                    isoIsGoodEnough = false;
                }
                else if (iso.Peaklist.Count < 2)
                {
                    isoIsGoodEnough = false;
                }
                else
                {
                    double maxIntensity     = iso.getMostIntensePeak().Height;
                    double minIntensityPeak = iso.Peaklist.Min(p => p.Height);

                    if (minIntensityPeak / maxIntensity < MinRelIntensityForPeakInclusion)
                    {
                        isoIsGoodEnough = true;
                    }
                    else
                    {
                        isoIsGoodEnough = false;
                    }
                }

                if (isoIsGoodEnough)
                {
                    break;
                }
            }

            return(iso);
        }
示例#4
0
 private void addInfoToResult(IsotopicProfile iso, PeptideTarget mt)
 {
     if (iso != null)
     {
         iso.ChargeState           = mt.ChargeState;
         iso.MonoIsotopicMass      = (iso.GetMZ() - Globals.PROTON_MASS) * mt.ChargeState;
         iso.IntensityMostAbundant = iso.getMostIntensePeak().Height;     // may need to change this to sum the top n peaks.
     }
 }
        /// <summary>
        /// Returns a normalized isotopic profile
        /// </summary>
        /// <param name="profile"></param>
        /// <param name="intensityForNormalization"></param>
        /// <returns></returns>
        public static void NormalizeIsotopicProfile(IsotopicProfile profile, float intensityForNormalization = 1.0f)
        {
            Check.Require(profile != null, "Isotopic profile is null");
            Check.Require(profile.Peaklist != null, "Isotopic profile peaklist is null");

            var maxIntensity = profile.getMostIntensePeak().Height;

            for (var i = 0; i < profile.Peaklist.Count; i++)
            {
                profile.Peaklist[i].Height = profile.Peaklist[i].Height / maxIntensity * intensityForNormalization;
            }
        }
示例#6
0
        /// <summary>
        /// Returns a normalized isotopic profile
        /// </summary>
        /// <param name="profile"></param>
        /// <param name="intensityForNormalization"></param>
        /// <returns></returns>
        public static void NormalizeIsotopicProfile(IsotopicProfile profile, float intensityForNormalization = 1.0f)
        {
            Check.Require(profile != null, "Isotopic profile is null");
            Check.Require(profile.Peaklist != null, "Isotopic profile peaklist is null");

            var maxIntensity = profile.getMostIntensePeak().Height;

            foreach (var dataPoint in profile.Peaklist)
            {
                dataPoint.Height = dataPoint.Height / maxIntensity * intensityForNormalization;
            }
        }
示例#7
0
        public double GetRatioBasedOnMostIntensePeak(IsotopicProfile iso1, IsotopicProfile iso2)
        {
            double returnVal = -1;

            if (iso1 == null || iso2 == null)
            {
                return(returnVal);
            }

            double iso1MaxIntensity = iso1.getMostIntensePeak().Height;
            double iso2MaxIntensity = iso2.getMostIntensePeak().Height;

            return(returnVal);
        }
        private List <double> GetTargetMzList(IsotopicProfile theorIso)
        {
            List <double> targetMZList;

            switch (ChromatogramGeneratorMode)
            {
            case Globals.ChromatogramGeneratorMode.MZ_BASED:
            {
                throw new NotSupportedException("Don't use this method if you already know your MZ target.");
            }

            case Globals.ChromatogramGeneratorMode.TOP_N_PEAKS:
            {
                targetMZList = getTargetMZListForTopNPeaks(theorIso);
            }
            break;

            case Globals.ChromatogramGeneratorMode.O16O18_THREE_MONOPEAKS:
            {
                targetMZList = getTargetMZListForO16O18ThreeMonoPeaks(theorIso);
            }
            break;

            case Globals.ChromatogramGeneratorMode.MONOISOTOPIC_PEAK:
            {
                var targetMZ = theorIso.getMonoPeak().XValue;
                targetMZList = new List <double> {
                    targetMZ
                };
                break;
            }

            case Globals.ChromatogramGeneratorMode.MOST_ABUNDANT_PEAK:
            {
                var targetMZ = theorIso.getMostIntensePeak().XValue;
                targetMZList = new List <double> {
                    targetMZ
                };
                break;
            }

            default:
            {
                throw new NotSupportedException(
                          "Chromatogram generation failed. Selected ChromatogramGeneratorMode is not supported");
            }
            }
            return(targetMZList);
        }
示例#9
0
        /// <summary>
        /// Calculates mass error based on the theoretical most intense peak.
        /// </summary>
        /// <returns> This returns the mass error between a theoretical and observed peak.  Nota bene the is MASS, not m/z
        /// If no peak is detected, we return the mass error 999999.  This should be interpreted as a null value.</returns>
        protected double TheorMostIntensePeakMassError(IsotopicProfile theoreticalIso, IsotopicProfile observedIso, int chargeState)
        {
            var theoreticalMostIntensePeak = theoreticalIso.getMostIntensePeak();

            //find peak in obs data
            var mzTolerance = WorkflowParameters.MSToleranceInPPM * theoreticalMostIntensePeak.XValue / 1e6;
            var foundPeaks  = PeakUtilities.GetPeaksWithinTolerance(new List <Peak>(observedIso.Peaklist), theoreticalMostIntensePeak.XValue, mzTolerance);

            if (foundPeaks.Count == 0)
            {
                return(999999);
            }

            var obsXValue = foundPeaks.OrderByDescending(p => p.Height).First().XValue; //order the peaks and take the first (most intense) one.

            return((theoreticalMostIntensePeak.XValue * chargeState) - (obsXValue * chargeState));
        }
示例#10
0
        private void UpdateIsoIntensitiesUsingChromCorrData(ChromCorrelationData chromCorrelationData, IsotopicProfile iso)
        {
            var totalChromCorrDataItems = chromCorrelationData.CorrelationDataItems.Count;

            double heightMaxPeak = iso.getMostIntensePeak().Height;

            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                if (i < totalChromCorrDataItems)
                {
                    var correctedRelIntensity = chromCorrelationData.CorrelationDataItems[i].CorrelationSlope;

                    if (correctedRelIntensity.HasValue)
                    {
                        iso.Peaklist[i].Height = (float)(heightMaxPeak * correctedRelIntensity);
                    }
                }
            }
        }
        private void offsetDistribution(XYData theorXYData, IsotopicProfile theorIsotopicProfile, IsotopicProfile observedIsotopicProfile)
        {
            double offset = 0;

            if (theorIsotopicProfile == null || theorIsotopicProfile.Peaklist == null || theorIsotopicProfile.Peaklist.Count == 0)
            {
                return;
            }

            var mostIntensePeak        = theorIsotopicProfile.getMostIntensePeak();
            var indexOfMostIntensePeak = theorIsotopicProfile.Peaklist.IndexOf(mostIntensePeak);

            if (observedIsotopicProfile.Peaklist == null || observedIsotopicProfile.Peaklist.Count == 0)
            {
                return;
            }

            var enoughPeaksInTarget = (indexOfMostIntensePeak <= observedIsotopicProfile.Peaklist.Count - 1);

            if (enoughPeaksInTarget)
            {
                var targetPeak = observedIsotopicProfile.Peaklist[indexOfMostIntensePeak];
                offset = targetPeak.XValue - mostIntensePeak.XValue;
                //offset = observedIsotopicProfile.Peaklist[0].XValue - theorIsotopicProfile.Peaklist[0].XValue;   //want to test to see if Thrash is same as rapid
            }
            else
            {
                offset = observedIsotopicProfile.Peaklist[0].XValue - theorIsotopicProfile.Peaklist[0].XValue;
            }

            for (var i = 0; i < theorXYData.Xvalues.Length; i++)
            {
                theorXYData.Xvalues[i] = theorXYData.Xvalues[i] + offset;
            }

            foreach (var peak in theorIsotopicProfile.Peaklist)
            {
                peak.XValue = peak.XValue + offset;
            }
        }
示例#12
0
        private double getFitValue(XYData rawXYData, IsotopicProfile theorIso, IsotopicProfile isoN15)
        {
            var indexOfMostAbundantTheorPeak     = theorIso.GetIndexOfMostIntensePeak();
            var indexOfCorrespondingObservedPeak = PeakUtilities.getIndexOfClosestValue(isoN15.Peaklist,
                                                                                        theorIso.getMostIntensePeak().XValue, 0, isoN15.Peaklist.Count - 1, 0.1);

            var mzOffset = isoN15.Peaklist[indexOfCorrespondingObservedPeak].XValue - theorIso.Peaklist[indexOfMostAbundantTheorPeak].XValue;
            var fwhm     = isoN15.GetFWHM();

            var theorXYData = theorIso.GetTheoreticalIsotopicProfileXYData(isoN15.GetFWHM());

            theorXYData.OffSetXValues(mzOffset);     //May want to avoid this offset if the masses have been aligned using LCMS Warp

            areaFitter = new AreaFitter();
            var fitVal = areaFitter.GetFit(theorXYData, rawXYData, 0.1);

            if (double.IsNaN(fitVal) || fitVal > 1)
            {
                return(1);
            }

            return(fitVal);
        }
        private void PerformIterativeFittingAndGetAlignedProfile(XYData xyData, XYData theorXYData, int chargeState, ref IsotopicProfile theorIso, ref double bestFitVal)
        {
            if (xyData == null || xyData.Xvalues.Length == 0)
            {
                bestFitVal = 1;
                return;
            }

            double relIntensityUseForFitting = 0;

            int ionCountUsed;
            var fitval = _areafitter.GetFit(theorXYData, xyData, relIntensityUseForFitting, out ionCountUsed);

            if (fitval < bestFitVal)
            {
                bestFitVal = fitval;
            }

            double bestOffsetForTheorProfile = 0;

            // move fitting window to the left
            for (var numPeaksToTheLeft = 1; numPeaksToTheLeft < 10; numPeaksToTheLeft++)
            {
                var offsetForTheorProfile = -1 * numPeaksToTheLeft * Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS / chargeState;
                //negative offset

                fitval = _areafitter.GetFit(theorXYData, xyData, relIntensityUseForFitting, out ionCountUsed, offsetForTheorProfile);

                if (fitval > bestFitVal || fitval >= 1 || double.IsNaN(fitval))
                {
                    break;
                }

                bestFitVal = fitval;
                bestOffsetForTheorProfile = offsetForTheorProfile;
            }

            //move fitting window to the right
            for (var numPeaksToTheRight = 1; numPeaksToTheRight < 10; numPeaksToTheRight++)
            {
                var offsetForTheorProfile = numPeaksToTheRight * Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS / chargeState;

                fitval = _areafitter.GetFit(theorXYData, xyData, relIntensityUseForFitting, out ionCountUsed, offsetForTheorProfile);

                if (fitval >= bestFitVal || fitval >= 1 || double.IsNaN(fitval))
                {
                    break;
                }

                bestFitVal = fitval;
                bestOffsetForTheorProfile = offsetForTheorProfile;
            }


            foreach (var theorMSPeak in theorIso.Peaklist)
            {
                theorMSPeak.XValue = theorMSPeak.XValue + bestOffsetForTheorProfile;
            }

            theorIso.MonoPeakMZ = theorIso.getMonoPeak().XValue;

            theorIso.MonoIsotopicMass        = (theorIso.MonoPeakMZ - Globals.PROTON_MASS) * chargeState;
            theorIso.MostAbundantIsotopeMass = (theorIso.getMostIntensePeak().XValue - Globals.PROTON_MASS) * chargeState;
        }
示例#14
0
        public double CalculateFitScore(IsotopicProfile theorProfile, IsotopicProfile observedProfile, XYData massSpecXYData, int numberOfPeaksToLeftForPenalty = 0, double massErrorPPMBetweenPeaks = 15)
        {
            if (observedProfile == null || observedProfile.Peaklist == null || observedProfile.Peaklist.Count == 0)
            {
                return(1.0);   // this is the worst possible fit score. ( 0.000 is the best possible fit score);  Maybe we want to return a '-1' to indicate a failure...
            }

            var indexOfMostAbundantTheorPeak     = theorProfile.GetIndexOfMostIntensePeak();
            var indexOfCorrespondingObservedPeak = PeakUtilities.getIndexOfClosestValue(observedProfile.Peaklist, theorProfile.getMostIntensePeak().XValue, 0, observedProfile.Peaklist.Count - 1, 0.1);

            if (indexOfCorrespondingObservedPeak < 0)      // most abundant peak isn't present in the actual theoretical profile... problem!
            {
                return(1.0);
            }

            var mzOffset = observedProfile.Peaklist[indexOfCorrespondingObservedPeak].XValue - theorProfile.Peaklist[indexOfMostAbundantTheorPeak].XValue;

            var observedPeakList = observedProfile.Peaklist.Cast <Peak>().ToList();
            var theorPeakList    = theorProfile.Peaklist.Cast <Peak>().ToList();

            foreach (var peak in theorPeakList)//May want to avoid this offset if the masses have been aligned using LCMS Warp
            {
                peak.XValue += mzOffset;
            }

            var minCuttoffTheorPeakIntensityFraction = 0.1f;

            var peakFitter = new PeakLeastSquaresFitter();
            int ionCountUsed;

            var fitval = peakFitter.GetFit(
                theorPeakList,
                observedPeakList,
                minCuttoffTheorPeakIntensityFraction,
                massErrorPPMBetweenPeaks,
                numberOfPeaksToLeftForPenalty,
                out ionCountUsed);

            if (double.IsNaN(fitval) || fitval > 1)
            {
                fitval = 1;
            }
            return(fitval);
        }
 private void UpdateMonoisotopicMassData(IsotopicProfile iso)
 {
     iso.MonoIsotopicMass        = (iso.getMonoPeak().XValue - Globals.PROTON_MASS) * iso.ChargeState;
     iso.MonoPeakMZ              = iso.getMonoPeak().XValue;
     iso.MostAbundantIsotopeMass = (iso.getMostIntensePeak().XValue - Globals.PROTON_MASS) * iso.ChargeState;
 }
        public void AdjustSaturatedIsotopicProfile(IsotopicProfile iso, IsotopicProfile theorIsotopicProfile, bool updatePeakMasses = true, bool updatePeakIntensities = true)
        {
            //get index of suitable peak on which to base the intensity adjustment
            var indexOfPeakUsedInExtrapolation = 0;


            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                var currentPeak = iso.Peaklist[i];

                //double idealRatioMin = 0.2;
                //double idealRatioMax = 0.8;

                //double peakRatio = currentPeak.Height / mostAbundantPeak.Height;

                if (currentPeak.Height < NewDeconToolsParameters.MiscMSProcessingParameters.SaturationThreshold)
                {
                    indexOfPeakUsedInExtrapolation = i;
                    break;
                }

                //if none are below the saturation threshold, use the last peak
                indexOfPeakUsedInExtrapolation = iso.Peaklist.Count - 1;
            }

            //ensure targetPeak is within range
            if (indexOfPeakUsedInExtrapolation >= theorIsotopicProfile.Peaklist.Count)
            {
                return;
            }

            var intensityObsPeakForExtrapolation   = iso.Peaklist[indexOfPeakUsedInExtrapolation].Height;
            var intensityTheorPeakForExtrapolation =
                theorIsotopicProfile.Peaklist[indexOfPeakUsedInExtrapolation].Height;

            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                if (iso.Peaklist[i].Height > NewDeconToolsParameters.MiscMSProcessingParameters.SaturationThreshold)
                {
                    if (updatePeakIntensities)
                    {
                        if (i >= theorIsotopicProfile.Peaklist.Count)
                        {
                            iso.Peaklist[i].Height = 0;
                        }
                        else
                        {
                            iso.Peaklist[i].Height = theorIsotopicProfile.Peaklist[i].Height *
                                                     intensityObsPeakForExtrapolation /
                                                     intensityTheorPeakForExtrapolation;
                        }


                        iso.Peaklist[i].Width = iso.Peaklist[indexOfPeakUsedInExtrapolation].Width;    //repair the width too, because it can get huge. Width can be used in determining tolerances.
                    }


                    //correct the m/z value, to more accurately base it on the non-saturated peak.  See Chernushevich et al. 2001 http://onlinelibrary.wiley.com/doi/10.1002/jms.207/abstract
                    if (updatePeakMasses)
                    {
                        iso.Peaklist[i].XValue = iso.Peaklist[indexOfPeakUsedInExtrapolation].XValue -               // formula is  MZ0 = MZ3 - (1.003/z)*n
                                                 ((Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS) / iso.ChargeState *      // where MZ0 is the m/z of the saturated peak and MZ3 the m/z of the nonSaturated peak
                                                  (indexOfPeakUsedInExtrapolation - i));                             // and z is charge state and n is the difference in peak number
                    }
                }
            }

            iso.IntensityMostAbundant = iso.getMostIntensePeak().Height;

            var indexMostAbundantPeakTheor = theorIsotopicProfile.GetIndexOfMostIntensePeak();

            if (iso.Peaklist.Count > indexMostAbundantPeakTheor)
            {
                iso.IntensityMostAbundantTheor = iso.Peaklist[indexMostAbundantPeakTheor].Height;
            }
            else
            {
                iso.IntensityMostAbundantTheor = iso.IntensityMostAbundant;
            }


            UpdateMonoisotopicMassData(iso);
        }
示例#17
0
        public double CalculateFitScore(IsotopicProfile theorProfile, IsotopicProfile observedProfile, XYData massSpecXYData)
        {
            if (observedProfile?.Peaklist == null || observedProfile.Peaklist.Count == 0)
            {
                return(1.0);   // this is the worst possible fit score. ( 0.000 is the best possible fit score);  Maybe we want to return a '-1' to indicate a failure...
            }

            var indexOfMostAbundantTheorPeak     = theorProfile.GetIndexOfMostIntensePeak();
            var indexOfCorrespondingObservedPeak = PeakUtilities.getIndexOfClosestValue(observedProfile.Peaklist,
                                                                                        theorProfile.getMostIntensePeak().XValue, 0, observedProfile.Peaklist.Count - 1, 0.1);

            if (indexOfCorrespondingObservedPeak < 0)      // most abundant peak isn't present in the actual theoretical profile... problem!
            {
                return(1.0);
            }

            var mzOffset = observedProfile.Peaklist[indexOfCorrespondingObservedPeak].XValue - theorProfile.Peaklist[indexOfMostAbundantTheorPeak].XValue;

            var theorXYData = theorProfile.GetTheoreticalIsotopicProfileXYData(observedProfile.GetFWHM());

            //theorXYData.Display();

            theorXYData.OffSetXValues(mzOffset);     // May want to avoid this offset if the masses have been aligned using LCMS Warp

            //theorXYData.Display();

            var areaFitter = new AreaFitter();

            var fitVal = areaFitter.GetFit(theorXYData, massSpecXYData, 0.1, out _);

            if (double.IsNaN(fitVal) || fitVal > 1)
            {
                fitVal = 1;
            }
            return(fitVal);
        }
 private static void UpdateMonoisotopicMassData(IsotopicProfile iso)
 {
     iso.MonoIsotopicMass = (iso.getMonoPeak().XValue - Globals.PROTON_MASS) * iso.ChargeState;
     iso.MonoPeakMZ = iso.getMonoPeak().XValue;
     iso.MostAbundantIsotopeMass = (iso.getMostIntensePeak().XValue - Globals.PROTON_MASS) * iso.ChargeState;
 }
        public void AdjustSaturatedIsotopicProfile(IsotopicProfile iso, IsotopicProfile theorIsotopicProfile, bool updatePeakMasses = true, bool updatePeakIntensities = true)
        {
            //get index of suitable peak on which to base the intensity adjustment
            var indexOfPeakUsedInExtrapolation = 0;

            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                var currentPeak = iso.Peaklist[i];

                //double idealRatioMin = 0.2;
                //double idealRatioMax = 0.8;

                //double peakRatio = currentPeak.Height / mostAbundantPeak.Height;

                if (currentPeak.Height < NewDeconToolsParameters.MiscMSProcessingParameters.SaturationThreshold)
                {
                    indexOfPeakUsedInExtrapolation = i;
                    break;
                }

                //if none are below the saturation threshold, use the last peak
                indexOfPeakUsedInExtrapolation = iso.Peaklist.Count - 1;
            }

            //ensure targetPeak is within range
            if (indexOfPeakUsedInExtrapolation >= theorIsotopicProfile.Peaklist.Count)
            {
                return;
            }

            var intensityObsPeakForExtrapolation   = iso.Peaklist[indexOfPeakUsedInExtrapolation].Height;
            var intensityTheorPeakForExtrapolation =
                theorIsotopicProfile.Peaklist[indexOfPeakUsedInExtrapolation].Height;

            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                if (iso.Peaklist[i].Height > NewDeconToolsParameters.MiscMSProcessingParameters.SaturationThreshold)
                {
                    if (updatePeakIntensities)
                    {
                        if (i >= theorIsotopicProfile.Peaklist.Count)
                        {
                            iso.Peaklist[i].Height = 0;
                        }
                        else
                        {
                            iso.Peaklist[i].Height = theorIsotopicProfile.Peaklist[i].Height *
                                                     intensityObsPeakForExtrapolation /
                                                     intensityTheorPeakForExtrapolation;
                        }

                        iso.Peaklist[i].Width = iso.Peaklist[indexOfPeakUsedInExtrapolation].Width;    //repair the width too, because it can get huge. Width can be used in determining tolerances.
                    }

                    // ReSharper disable CommentTypo

                    // Correct the m/z value, to more accurately base it on the non-saturated peak.
                    // See Chernushevich et al. 2001 https://onlinelibrary.wiley.com/doi/full/10.1002/jms.207
                    // "An introduction to quadrupole–time‐of‐flight mass spectrometry"
                    // Journal of Mass Spectrometry, Volume 36, Issue 8, (2001), pages 849-865

                    // ReSharper restore CommentTypo

                    if (updatePeakMasses)
                    {
                        // Formula is MZ0 = MZ3 - (1.00235/z)*n
                        // where MZ0 is the m/z of the saturated peak and MZ3 the m/z of the nonSaturated peak,
                        // z is charge state, and n is the difference in peak number

                        iso.Peaklist[i].XValue = iso.Peaklist[indexOfPeakUsedInExtrapolation].XValue -
                                                 Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS / iso.ChargeState *
                                                 (indexOfPeakUsedInExtrapolation - i);
                    }
                }
            }

            iso.IntensityMostAbundant = iso.getMostIntensePeak().Height;

            var indexMostAbundantPeakTheor = theorIsotopicProfile.GetIndexOfMostIntensePeak();

            if (iso.Peaklist.Count > indexMostAbundantPeakTheor)
            {
                iso.IntensityMostAbundantTheor = iso.Peaklist[indexMostAbundantPeakTheor].Height;
            }
            else
            {
                iso.IntensityMostAbundantTheor = iso.IntensityMostAbundant;
            }

            UpdateMonoisotopicMassData(iso);
        }