/// <summary> /// Initializes a new instance of the <see cref="ObservedPeak"/> class with peak and its calculated statistics. /// </summary> /// <param name="group"> /// The group. /// </param> /// <param name="peak"> /// The peak. /// </param> /// <param name="statistics"> /// The Statistics. /// </param> public ObservedPeak(VoltageGroup group, StandardImsPeak peak, PeakScores statistics) { this.VoltageGroup = group; this.Peak = peak; this.Statistics = statistics; this.ObservationType = ObservationType.Peak; this.mobilityPoint = null; }
/// <summary> /// The Peak shape score. Evaluating how "good" the peak looks. A good /// peak shape score indicates that the peak is not a result of noise /// or instrument errors. Mostly the feature intensity along is sufficient /// to exclude noise but a good shape score helps evaluating the experiment /// and thus the reliability of the data analysis result. /// </summary> /// <param name="reader"> /// The reader. /// </param> /// <param name="massToleranceInPpm"> /// The mass Tolerance In Ppm. /// </param> /// <param name="driftTimeToleranceInMs"> /// The drift Time Tolerance In Scans. /// </param> /// <param name="imsPeak"> /// The imsPeak. /// </param> /// <param name="voltageGroup"> /// The voltage group. /// </param> /// <param name="targetMz"> /// The Target MZ. /// </param> /// <param name="globalMaxIntensities"> /// The global Max Intensities. /// </param> /// <param name="numberOfScans"> /// The number Of Scans. /// </param> /// <returns> /// The <see cref="double"/>. /// </returns> public static double PeakShapeScore(StandardImsPeak imsPeak, DataReader reader, double massToleranceInPpm, double driftTimeToleranceInMs, VoltageGroup voltageGroup, double globalMaxIntensities, int numberOfScans) { int scanRep = imsPeak.PeakApex.DriftTimeCenterInScanNumber; double toleranceInMz = massToleranceInPpm / 1e6 * imsPeak.PeakApex.MzCenterInDalton; int scanWidth = (int)Math.Ceiling(driftTimeToleranceInMs / 1000 / voltageGroup.AverageTofWidthInSeconds); int scanWindowSize = scanWidth * 2 + 1; int scanNumberMin = scanRep - scanWidth; int scanNumberMax = scanRep + scanWidth; if ((scanNumberMin < 0) || (scanNumberMax > numberOfScans - 1)) { return 0; } int[][] intensityWindow = reader.GetFramesAndScanIntensitiesForAGivenMz( voltageGroup.FirstFrameNumber, voltageGroup.LastFrameNumber, DataReader.FrameType.MS1, scanNumberMin, scanNumberMax, imsPeak.PeakApex.MzCenterInDalton, toleranceInMz); // Average the intensity window across frames int frames = intensityWindow.GetLength(0); double[] averagedPeak = new double[scanWindowSize]; double highestPeak = 0; for (int i = 0; i < scanWindowSize; i++) { for (int j = 0; j < frames; j++) { averagedPeak[i] += intensityWindow[j][i]; } averagedPeak[i] /= frames; highestPeak = (averagedPeak[i] > highestPeak) ? averagedPeak[i] : highestPeak; } // For peaks with peak width lower than 3, return a peak score of 0 // TODO get the intensity threshold here from the noise level instead. if (scanWindowSize >= 3) { if (averagedPeak[scanRep - scanNumberMin] < globalMaxIntensities * 0.0001 || averagedPeak[scanRep - scanNumberMin - 1] < globalMaxIntensities * 0.0001 || averagedPeak[scanRep - scanNumberMin + 1] < globalMaxIntensities * 0.0001) { return 0; } } // Perform a statistical normality test double normalityScore = NormalityTest.PeakNormalityTest(averagedPeak, NormalityTest.JaqueBeraTest, 100, globalMaxIntensities); return normalityScore; }
/// <summary> /// The score feature using isotopic profile. /// </summary> /// <param name="imsPeak"> /// The ims Peak. /// </param> /// <param name="reader"> /// The reader. /// </param> /// <param name="target"> /// The Target. /// </param> /// <param name="isotopicPeakList"> /// The isotopic peak list. /// </param> /// <param name="voltageGroup"> /// The voltage Group. /// </param> /// <param name="selectedMethod"> /// The selected Method. /// </param> /// <param name="globalMaxIntensities"> /// </param> /// <returns> /// The <see cref="double"/>. /// </returns> /// <exception cref="InvalidOperationException"> /// </exception> public static double IsotopicProfileScore(StandardImsPeak imsPeak, DataReader reader, IImsTarget target, List<Peak> isotopicPeakList, VoltageGroup voltageGroup, IsotopicScoreMethod selectedMethod, double globalMaxIntensities, double totalScans) { // No need to move on if the isotopic profile is not found // if (observedIsotopicProfile == null || observedIsotopicProfile.MonoIsotopicMass < 1) // { // result.AnalysisStatus = AnalysisStatus.IsotopicProfileNotFound; // continue; // } // Find Isotopic Profile // List<Peak> massSpectrumPeaks; // IsotopicProfile observedIsotopicProfile = _msFeatureFinder.IterativelyFindMSFeature(massSpectrum, theoreticalIsotopicProfile, out massSpectrumPeaks); if (target.CompositionWithoutAdduct == null) { throw new InvalidOperationException("Cannot score feature using isotopic profile for Ims Target without CompositionWithoutAdduct provided."); } // Bad Feature, so get out if (imsPeak == null) { return 0; } // Get the scanWindow size int scanNumberMax = imsPeak.PeakApex.DriftTimeFullWidthHalfMaxHigherBondInScanNumber; int scanNumberMin = imsPeak.PeakApex.DriftTimeFullWidthHalfMaxLowerBondInScanNumber; if ((scanNumberMin < 0) || (scanNumberMax > totalScans - 1)) { return 0; } // Get the mass error from the observed feature peak from the Target theoretical peak double mzOffset = imsPeak.PeakApex.MzCenterInDalton - target.MassWithAdduct; List<double> observedIsotopicPeakList = new List<double>(); int totalIsotopicIndex = isotopicPeakList.Count; int[] isotopicIndexMask = new int[totalIsotopicIndex]; // Find an unsaturated peak in the isotopic profile for (int i = 0; i < totalIsotopicIndex; i++) { // Isotopic centerMz double Mz = isotopicPeakList[i].XValue; var peakList = reader.GetXic(Mz + mzOffset, imsPeak.PeakApex.MzWindowToleranceInPpm, voltageGroup.FirstFrameNumber, voltageGroup.LastFrameNumber, scanNumberMin, scanNumberMax, DataReader.FrameType.MS1, DataReader.ToleranceType.PPM); // Sum the intensities double sumIntensities = 0; foreach (var point in peakList) { sumIntensities += point.Intensity; if (point.IsSaturated) { isotopicIndexMask[i] = 1; } } sumIntensities /= voltageGroup.FrameAccumulationCount; observedIsotopicPeakList.Add(sumIntensities); } // Return 0 if the intensity sum is really small if (observedIsotopicPeakList.Sum() < globalMaxIntensities * 0.0003) { return 0; } // If the unsaturated isotopes are below a certain threshold if (totalIsotopicIndex - isotopicIndexMask.Sum() <= 1) { return 0; } if (selectedMethod == IsotopicScoreMethod.Angle) { return IsotopicProfileScoreAngle(observedIsotopicPeakList, isotopicPeakList); } else if (selectedMethod == IsotopicScoreMethod.EuclideanDistance) { return IsotopicProfileScoreEuclidean(observedIsotopicPeakList, isotopicPeakList); } else if (selectedMethod == IsotopicScoreMethod.PearsonCorrelation) { return PearsonCorrelation(observedIsotopicPeakList, isotopicPeakList); } else if (selectedMethod == IsotopicScoreMethod.Bhattacharyya) { return BhattacharyyaDistance(observedIsotopicPeakList, isotopicPeakList); } else if (selectedMethod == IsotopicScoreMethod.EuclideanDistanceAlternative) { return EuclideanAlternative(observedIsotopicPeakList, isotopicPeakList); } else { throw new NotImplementedException(); } }
/// <summary> /// The intensity score. /// </summary> /// <param name="featurePeak"> /// The feature blob. /// </param> /// <param name="globalMaxIntensity"> /// The global Max Intensity. /// </param> /// <returns> /// The <see cref="double"/>. /// </returns> public static double IntensityScore(StandardImsPeak featurePeak, double globalMaxIntensity) { // Sort features by relative intensity double summedIntensities = featurePeak.SummedIntensities; // Divide intensities by accumulation (If summing instead of averaging is used) // summedIntensities /= voltageGroup.FrameAccumulationCount; // normalize the score return ScoreUtil.MapToZeroOneTrignometry(summedIntensities, false, globalMaxIntensity / 3); }
/// <summary> /// The report feature evaluation. /// </summary> /// <param name="peak"> /// The peak. /// </param> /// <param name="scores"> /// The scores. /// </param> /// <param name="verbose"> /// The verbose. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="badScanRange"> /// The bad scan range. /// </param> /// <param name="lowAbsoluteIntensity"> /// The low intensity. /// </param> /// <param name="lowRelativeIntensity"></param> /// <param name="badPeakShape"> /// The bad peak shape. /// </param> /// <param name="lowIsotopicAffinity"> /// The low isotopic affinity. /// </param> /// <returns> /// If the feature pass all the filters <see cref="bool"/>. /// </returns> private static string ReportFeatureEvaluation(StandardImsPeak peak, PeakScores scores, bool verbose, IImsTarget target, bool badScanRange, bool lowAbsoluteIntensity, bool lowRelativeIntensity, bool badPeakShape, bool lowIsotopicAffinity) { Trace.WriteLine(string.Format(" Candidate feature found at [centerMz = {0:F4}, drift time = {1:F2} ms(#{2})] ", peak.PeakApex.MzCenterInDalton, peak.PeakApex.DriftTimeCenterInMs, peak.PeakApex.DriftTimeCenterInScanNumber)); Trace.WriteLine(string.Format(" IntensityScore: {0:F4}", scores.IntensityScore)); if (!lowAbsoluteIntensity) { Trace.WriteLine(string.Format(" peakShapeScore: {0:F4}", scores.PeakShapeScore)); if (target.HasCompositionInfo) { Trace.WriteLine(string.Format(" isotopicScore: {0:F4}", scores.IsotopicScore)); } } string rejectionReason = badScanRange ? "[Bad scan range] " : lowAbsoluteIntensity ? "[Low Absolute Intensity] " : badPeakShape ? "[Bad Peak Shape] " : lowIsotopicAffinity ? "[Different Isotopic Profile] " : lowRelativeIntensity ? "[Low Relative Intensity] " : string.Empty; bool rejected = badScanRange || lowAbsoluteIntensity || lowIsotopicAffinity || badPeakShape || lowRelativeIntensity; if (verbose) { if (rejected) { Trace.WriteLine(" " + rejectionReason); } else { Trace.WriteLine(" [PASS]"); } Trace.WriteLine(string.Empty); } return rejectionReason; }
/// <summary> /// Initializes a new instance of the <see cref="LibraryMatchResult"/> class. /// </summary> /// <param name="peak"> /// The peak. /// </param> /// <param name="conlusion"> /// The conlusion. /// </param> /// <param name="distance"> /// The distance. /// </param> public LibraryMatchResult(StandardImsPeak peak, AnalysisStatus conlusion, DriftTimeFeatureDistance distance) { this.AnalysisStatus = conlusion; this.ImsFeature = peak; this.distance = distance; }