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); }
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; }
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); }
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; }
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); }
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); }
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); }