private void CalculateMassesForIsotopicProfile(IsotopicProfile iso)
        {
            if (iso?.Peaklist == null)
            {
                return;
            }

            //start with most abundant peak.

            var indexMostAbundantPeak = iso.GetIndexOfMostIntensePeak();

            var mzMostAbundantPeak = iso.MostAbundantIsotopeMass / iso.ChargeState + Globals.PROTON_MASS;

            //start with most abundant peak and move to the LEFT and calculate m/z values
            for (var peakIndex = indexMostAbundantPeak; peakIndex >= 0; peakIndex--)
            {
                var numPeaksToLeft = indexMostAbundantPeak - peakIndex;
                var calcMZ         = mzMostAbundantPeak - numPeaksToLeft * 1.00235 / iso.ChargeState;

                iso.Peaklist[peakIndex].XValue = calcMZ;
            }

            //move to the RIGHT and calculate m/z values
            for (var peakIndex = indexMostAbundantPeak + 1; peakIndex < iso.Peaklist.Count; peakIndex++)
            {
                var numPeaksToRight = peakIndex - indexMostAbundantPeak;
                var calcMZ          = mzMostAbundantPeak + numPeaksToRight * 1.00235 / iso.ChargeState;

                iso.Peaklist[peakIndex].XValue = calcMZ;
            }

            iso.MonoPeakMZ       = iso.getMonoPeak().XValue;
            iso.MonoIsotopicMass = (iso.MonoPeakMZ - Globals.PROTON_MASS) * iso.ChargeState;
        }
        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 void AdjustSaturatedIsotopicProfile(IsotopicProfile iso, IsotopicProfile theorIsotopicProfile, int indexOfPeakUsedInExtrapolation)
        {
            var indexOfMostAbundantTheorPeak = theorIsotopicProfile.GetIndexOfMostIntensePeak();

            //find index of peaks lower than 0.3
            var indexOfReferenceTheorPeak = -1;

            for (var i = indexOfMostAbundantTheorPeak; i < theorIsotopicProfile.Peaklist.Count; i++)
            {
                if (theorIsotopicProfile.Peaklist[i].Height < _minRelIntTheorProfile)
                {
                    indexOfReferenceTheorPeak = i;
                    break;
                }
            }

            var useProvidedPeakIndex = (indexOfPeakUsedInExtrapolation >= 0);

            double intensityObsPeakUsedForExtrapolation;
            double intensityTheorPeak;

            if (useProvidedPeakIndex)
            {
                if (indexOfPeakUsedInExtrapolation < theorIsotopicProfile.Peaklist.Count && indexOfPeakUsedInExtrapolation < iso.Peaklist.Count)
                {
                    intensityObsPeakUsedForExtrapolation = iso.Peaklist[indexOfPeakUsedInExtrapolation].Height;
                    intensityTheorPeak = theorIsotopicProfile.Peaklist[indexOfPeakUsedInExtrapolation].Height;
                }
                else
                {
                    return;
                }
            }
            else if (indexOfReferenceTheorPeak != -1 && indexOfReferenceTheorPeak < iso.Peaklist.Count)
            {
                intensityObsPeakUsedForExtrapolation = iso.Peaklist[indexOfReferenceTheorPeak].Height;
                intensityTheorPeak = theorIsotopicProfile.Peaklist[indexOfReferenceTheorPeak].Height;
            }
            else
            {
                return;
            }


            iso.IntensityAggregateAdjusted = intensityObsPeakUsedForExtrapolation / intensityTheorPeak;
        }
示例#4
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);
        }
示例#5
0
        public static void TrimIsotopicProfile(IsotopicProfile isotopicProfile, double cutOff, bool neverTrimLeft = false, bool neverTrimRight = false)
        {
            if (isotopicProfile == null || isotopicProfile.Peaklist == null || isotopicProfile.Peaklist.Count == 0)
            {
                return;
            }

            var indexOfMaxPeak  = isotopicProfile.GetIndexOfMostIntensePeak();
            var trimmedPeakList = new List <MSPeak>();


            //Trim left
            if (indexOfMaxPeak > 0)   // if max peak is not the first peak, then trim
            {
                for (var i = indexOfMaxPeak - 1; i >= 0; i--)
                {
                    if (isotopicProfile.Peaklist[i].Height >= cutOff || neverTrimLeft)
                    {
                        trimmedPeakList.Insert(0, isotopicProfile.Peaklist[i]);
                    }
                }
            }

            //Add max peak
            trimmedPeakList.Add(isotopicProfile.Peaklist[indexOfMaxPeak]);

            //Trim right
            if (indexOfMaxPeak < isotopicProfile.Peaklist.Count - 1)  // if max peak is not the last peak (rare condition)
            {
                for (var i = indexOfMaxPeak + 1; i < isotopicProfile.Peaklist.Count; i++)
                {
                    if (isotopicProfile.Peaklist[i].Height >= cutOff || neverTrimRight)
                    {
                        trimmedPeakList.Add(isotopicProfile.Peaklist[i]);
                    }
                }
            }

            isotopicProfile.Peaklist = trimmedPeakList;
        }
示例#6
0
        private void addMassInfoToIsotopicProfile(IsotopicProfile theorFeature, IsotopicProfile outFeature)
        {
            var indexOfMonoPeak = PeakUtilities.getIndexOfClosestValue(outFeature.Peaklist, theorFeature.MonoPeakMZ, 0, outFeature.Peaklist.Count - 1, 0.1);

            outFeature.MonoIsotopicPeakIndex = indexOfMonoPeak;


            double monopeakMZ                 = 0;
            double monoIsotopicMass           = 0;
            var    monoPeakFoundInObservedIso = (outFeature.MonoIsotopicPeakIndex != -1);

            if (monoPeakFoundInObservedIso)
            {
                var monoPeak = outFeature.Peaklist[outFeature.MonoIsotopicPeakIndex];

                monopeakMZ       = monoPeak.XValue;
                monoIsotopicMass = (monoPeak.XValue - Globals.PROTON_MASS) * outFeature.ChargeState;
            }
            else
            {
                var indexOfMostAbundantTheorPeak     = theorFeature.GetIndexOfMostIntensePeak();
                var indexOfCorrespondingObservedPeak = PeakUtilities.getIndexOfClosestValue(outFeature.Peaklist, theorFeature.Peaklist[indexOfMostAbundantTheorPeak].XValue, 0, outFeature.Peaklist.Count - 1, 0.1);

                if (indexOfCorrespondingObservedPeak != -1)
                {
                    //double mzOffset = outFeature.Peaklist[indexOfCorrespondingObservedPeak].XValue - theorFeature.Peaklist[indexOfMostAbundantTheorPeak].XValue;

                    var locationOfMonoPeakRelativeToTheorMaxPeak = theorFeature.MonoIsotopicPeakIndex - indexOfMostAbundantTheorPeak;

                    var mzOfObservedMostAbundantPeak = outFeature.Peaklist[indexOfCorrespondingObservedPeak].XValue;

                    monopeakMZ       = mzOfObservedMostAbundantPeak + (locationOfMonoPeakRelativeToTheorMaxPeak * Globals.MASS_DIFF_BETWEEN_ISOTOPICPEAKS / outFeature.ChargeState);
                    monoIsotopicMass = (monopeakMZ - Globals.PROTON_MASS) * outFeature.ChargeState;
                }
            }

            outFeature.MonoPeakMZ       = monopeakMZ;
            outFeature.MonoIsotopicMass = monoIsotopicMass;
        }
        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 (fitval == double.NaN || fitval > 1)
            {
                fitval = 1;
            }
            return(fitval);
        }
示例#8
0
        public double CalculateFitScore(IsotopicProfile theorProfile, IsotopicProfile observedProfile, XYData massSpecXYData)
        {
            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 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();
            int ionCountUsed;

            var fitval = areafitter.GetFit(theorXYData, massSpecXYData, 0.1, out ionCountUsed);

            if (double.IsNaN(fitval) || fitval > 1)
            {
                fitval = 1;
            }
            return(fitval);
        }
示例#9
0
        public virtual IsotopicProfile FindMSFeature(List <Peak> peakList, IsotopicProfile theorFeature)
        {
            Check.Require(theorFeature != null, "Theoretical feature hasn't been defined.");
            if (theorFeature == null)
            {
                return(null);
            }

            Check.Require(theorFeature.Peaklist != null && theorFeature.Peaklist.Count > 0, "Theoretical feature hasn't been defined.");

            var outFeature = new IsotopicProfile
            {
                ChargeState = theorFeature.ChargeState
            };

            var indexOfMaxTheorPeak = theorFeature.GetIndexOfMostIntensePeak();

            var toleranceInMZ = theorFeature.getMonoPeak().XValue *ToleranceInPPM / 1e6;

            var    foundMatchingMaxPeak = false;
            double massDefect           = 0; // this is the m/z diff between the max peak of theor feature and the max peak of the experimental feature

            var failedResult = false;

            for (var i = indexOfMaxTheorPeak; i >= 0; i--)
            {
                //find experimental peak(s) within range
                var peaksWithinTol = PeakUtilities.GetPeaksWithinTolerance(peakList, theorFeature.Peaklist[i].XValue, toleranceInMZ);

                if (i == indexOfMaxTheorPeak)
                {
                    foundMatchingMaxPeak = peaksWithinTol.Count > 0;
                }

                if (!foundMatchingMaxPeak)   // can't even find the observed peak that matches the most intense theor peak.
                {
                    failedResult = true;
                    break;
                }

                if (peaksWithinTol.Count == 0)
                {
                    if (NeedMonoIsotopicPeak)
                    {
                        //here, we are looking to the left of most intense theor peak.  If we have the prerequisite of finding the monoIsotopic peak and fail here, we'll return a failed result
                        failedResult = true;
                    }
                    break;  // stop looking to the left of the most intense peak.
                }

                if (peaksWithinTol.Count == 1)
                {
                    if (outFeature.Peaklist.Count == 0)
                    {
                        outFeature.Peaklist.Add((MSPeak)peaksWithinTol[0]);
                    }
                    else
                    {
                        outFeature.Peaklist.Insert(0, (MSPeak)peaksWithinTol[0]);
                    }
                }
                else    // when we have several peaks within tolerance, we'll need to decide what to do
                {
                    MSPeak bestPeak;
                    if (i == indexOfMaxTheorPeak)   //when matching to most intense peak, we will use the most intense peak
                    {
                        bestPeak = (MSPeak)findMostIntensePeak(peaksWithinTol);
                    }
                    else
                    {
                        bestPeak = (MSPeak)findClosestToXValue(peaksWithinTol, theorFeature.Peaklist[i].XValue - massDefect);
                    }

                    if (outFeature.Peaklist.Count == 0)
                    {
                        outFeature.Peaklist.Add(bestPeak);
                    }
                    else
                    {
                        outFeature.Peaklist.Insert(0, bestPeak);
                    }
                }

                if (i == indexOfMaxTheorPeak)   //when matching to most intense peak, we will get the mass defect using the most intense peak
                {
                    massDefect = theorFeature.Peaklist[i].XValue - outFeature.Peaklist[0].XValue;
                }
            }

            //------------------------- look right -------------------------------------------
            for (var i = indexOfMaxTheorPeak + 1; i < theorFeature.Peaklist.Count; i++)     //start one peak to the right of the max intense theor peak
            {
                var peaksWithinTol = PeakUtilities.GetPeaksWithinTolerance(peakList, theorFeature.Peaklist[i].XValue, toleranceInMZ);
                if (peaksWithinTol.Count == 0)
                {
                    if (i == indexOfMaxTheorPeak + 1)  // first peak to the right of the max peak.  We need this one or we declare it to be a failure (= null)
                    {
                        failedResult = true;
                    }
                    break;    // finished.  Exit loop.
                }

                if (peaksWithinTol.Count == 1)
                {
                    outFeature.Peaklist.Add((MSPeak)peaksWithinTol[0]); //here, we tack peaks onto the profile
                }
                else                                                    //two or more peaks are within tolerance. Need to get the best one, which is based on the distance from the
                {
                    outFeature.Peaklist.Add((MSPeak)findClosestToXValue(peaksWithinTol, theorFeature.Peaklist[i].XValue - massDefect));
                }
            }

            //for higher mass peptides, we will return the profile if there is 2 or more peaks, regardless if none are found to the right of the most abundant
            if (indexOfMaxTheorPeak > 0 && outFeature.Peaklist.Count > 1)
            {
                failedResult = false;
            }

            if (failedResult)
            {
                return(null);   // return a null Isotopic profile, indicating a failed result
            }

            addMassInfoToIsotopicProfile(theorFeature, outFeature);
            return(outFeature);
        }
        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);
        }
        public ChromCorrelationData CorrelatePeaksWithinIsotopicProfile(Run run, IsotopicProfile iso, int startScan, int stopScan)
        {
            var correlationData       = new ChromCorrelationData();
            var indexMostAbundantPeak = iso.GetIndexOfMostIntensePeak();

            var  baseMZValue = iso.Peaklist[indexMostAbundantPeak].XValue;
            bool baseChromDataIsOK;
            var  basePeakChromXYData = GetBaseChromXYData(run, startScan, stopScan, baseMZValue);

            baseChromDataIsOK = basePeakChromXYData != null && basePeakChromXYData.Xvalues != null;
            //&&basePeakChromXYData.Xvalues.Length > 3;


            var minIntensity = iso.Peaklist[indexMostAbundantPeak].Height *
                               MinimumRelativeIntensityForChromCorr;


            for (var i = 0; i < iso.Peaklist.Count; i++)
            {
                if (!baseChromDataIsOK)
                {
                    var defaultChromCorrDataItem = new ChromCorrelationDataItem();
                    correlationData.AddCorrelationData(defaultChromCorrDataItem);
                    break;
                }

                if (i == indexMostAbundantPeak)
                {
                    //peak is being correlated to itself
                    correlationData.AddCorrelationData(1.0, 0, 1);
                }
                else if (iso.Peaklist[i].Height >= minIntensity)
                {
                    var  correlatedMZValue = iso.Peaklist[i].XValue;
                    bool chromDataIsOK;
                    var  chromPeakXYData = GetCorrelatedChromPeakXYData(run, startScan, stopScan, basePeakChromXYData, correlatedMZValue);

                    chromDataIsOK = chromPeakXYData != null && chromPeakXYData.Xvalues != null;
                    //&&chromPeakXYData.Xvalues.Length > 3;

                    if (chromDataIsOK)
                    {
                        double slope;
                        double intercept;
                        double rsquaredVal;

                        chromPeakXYData = FillInAnyMissingValuesInChromatogram(basePeakChromXYData, chromPeakXYData);

                        GetElutionCorrelationData(basePeakChromXYData, chromPeakXYData,
                                                  out slope, out intercept, out rsquaredVal);

                        correlationData.AddCorrelationData(slope, intercept, rsquaredVal);
                    }
                    else
                    {
                        var defaultChromCorrDataItem = new ChromCorrelationDataItem();
                        correlationData.AddCorrelationData(defaultChromCorrDataItem);
                    }
                }
                else
                {
                    var defaultChromCorrDataItem = new ChromCorrelationDataItem();
                    correlationData.AddCorrelationData(defaultChromCorrDataItem);
                }
            }

            return(correlationData);
        }
        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);
        }