/// <summary> /// The run libray match workflow. /// </summary> /// <param name="target"> /// The Target. /// </param> /// <returns> /// The <see cref="LibraryMatchResult"/>. /// </returns> private LibraryMatchResult RunLibrayMatchWorkflow(DriftTimeTarget target) { Trace.WriteLine(" Target: " + target.CorrespondingChemical); Trace.WriteLine(" Target Info: " + target.TargetDescriptor); // Generate Theoretical Isotopic Profile List<Peak> theoreticalIsotopicProfilePeakList = null; string empiricalFormula = target.CompositionWithAdduct.ToPlainString(); ITheorFeatureGenerator featureGenerator = new JoshTheorFeatureGenerator(); IsotopicProfile theoreticalIsotopicProfile = featureGenerator.GenerateTheorProfile(empiricalFormula, 1); theoreticalIsotopicProfilePeakList = theoreticalIsotopicProfile.Peaklist.Cast<Peak>().ToList(); // Voltage grouping VoltageSeparatedAccumulatedXiCs accumulatedXiCs = new VoltageSeparatedAccumulatedXiCs(this.uimfReader, target.MassWithAdduct, this.Parameters.InitialSearchMassToleranceInPpm, target.NormalizedDriftTimeInMs, this.Parameters.DriftTimeToleranceInMs, this.Parameters.DriftTubeLengthInCm); foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys) { // TODO Verify the temperature, pressure and drift tube voltage of the voltage group // Because we don't record TVP info in the AMT library. we can't verify it yet, so stick with last voltage group. if (IMSUtil.IsLastVoltageGroup(voltageGroup, this.NumberOfFrames)) { double globalMaxIntensity = IMSUtil.MaxIntensityAfterFrameAccumulation(voltageGroup, this.uimfReader); Trace.WriteLine(string.Format(" Temperature/Pressure/Voltage Adjusted Drift time: {0:F4} ms", IMSUtil.DeNormalizeDriftTime(target.NormalizedDriftTimeInMs, voltageGroup))); // Find peaks using multidimensional peak finder. List<IntensityPoint> intensityPoints = accumulatedXiCs[voltageGroup].IntensityPoints; List<FeatureBlob> featureBlobs = PeakFinding.FindPeakUsingWatershed(intensityPoints, this.smoother, this.Parameters.FeatureFilterLevel); List<StandardImsPeak> standardPeaks = featureBlobs.Select(featureBlob => new StandardImsPeak(featureBlob, this.uimfReader, voltageGroup, target.MassWithAdduct, this.Parameters.InitialSearchMassToleranceInPpm)).ToList(); // Score features IDictionary<StandardImsPeak, PeakScores> scoresTable = new Dictionary<StandardImsPeak, PeakScores>(); Trace.WriteLine(string.Format(" Voltage Group: {0:F4} V, [{1}-{2}]", voltageGroup.MeanVoltageInVolts, voltageGroup.FirstFrameNumber, voltageGroup.LastFrameNumber)); foreach (StandardImsPeak peak in standardPeaks) { PeakScores currentStatistics = FeatureScoreUtilities.ScoreFeature( peak, globalMaxIntensity, this.uimfReader, this.Parameters.InitialSearchMassToleranceInPpm, this.Parameters.DriftTimeToleranceInMs, voltageGroup, this.NumberOfScans, target, IsotopicScoreMethod.Angle, theoreticalIsotopicProfilePeakList); scoresTable.Add(peak, currentStatistics); } // filter out features with Ims scans at 1% left or right. Predicate<StandardImsPeak> scanPredicate = blob => FeatureFilters.FilterExtremeDriftTime(blob, (int)this.NumberOfScans); Predicate<StandardImsPeak> shapeThreshold = blob => FeatureFilters.FilterBadPeakShape(blob, scoresTable[blob].PeakShapeScore, this.Parameters.PeakShapeThreshold); Predicate<StandardImsPeak> isotopeThreshold = blob => FeatureFilters.FilterBadIsotopicProfile(blob, scoresTable[blob].IsotopicScore, this.Parameters.IsotopicThreshold); Predicate<StandardImsPeak> massDistanceThreshold = blob => FeatureFilters.FilterHighMzDistance(blob, target, this.Parameters.MatchingMassToleranceInPpm); // Print out candidate features that pass the intensity threshold. foreach (StandardImsPeak peak in standardPeaks) { DriftTimeFeatureDistance distance = new DriftTimeFeatureDistance(target, peak, voltageGroup); bool badScanRange = scanPredicate(peak); bool badPeakShape = shapeThreshold(peak); bool lowIsotopicAffinity = isotopeThreshold(peak); bool lowMzAffinity = massDistanceThreshold(peak); PeakScores currentStatistics = scoresTable[peak]; Trace.WriteLine(string.Empty); Trace.WriteLine(string.Format(" Candidate feature found at drift time {0:F2} ms (scan number {1})", peak.PeakApex.DriftTimeCenterInMs, peak.PeakApex.DriftTimeCenterInScanNumber)); Trace.WriteLine( string.Format( " M/Z: {0:F2} Dalton", peak.PeakApex.MzCenterInDalton)); Trace.WriteLine( string.Format( " Drift time: {0:F2} ms (scan number {1})", peak.PeakApex.DriftTimeCenterInMs, peak.PeakApex.DriftTimeCenterInScanNumber)); Trace.WriteLine( string.Format(" MzInDalton difference: {0:F2} ppm", distance.MassDifferenceInPpm)); Trace.WriteLine( string.Format(" Drift time difference: {0:F4} ms", distance.DriftTimeDifferenceInMs)); Trace.WriteLine(string.Format(" Intensity Score: {0:F4}", currentStatistics.IntensityScore)); Trace.WriteLine(string.Format(" Peak Shape Score: {0:F4}", currentStatistics.PeakShapeScore)); Trace.WriteLine(string.Format(" Isotopic Score: {0:F4}", currentStatistics.IsotopicScore)); Trace.WriteLine(string.Format(" AveragedPeakIntensities: {0:F4}", peak.SummedIntensities)); string rejectionReason = badScanRange ? " [Bad scan range] " : " "; rejectionReason += badPeakShape ? "[Bad Peak Shape] " : string.Empty; rejectionReason += lowMzAffinity ? "[Inaccurate Mass] " : string.Empty; rejectionReason += lowIsotopicAffinity ? "[Different Isotopic Profile] " : string.Empty; if (badScanRange || lowIsotopicAffinity || badPeakShape) { Trace.WriteLine(rejectionReason); } else { Trace.WriteLine(" [Pass]"); } } standardPeaks.RemoveAll(scanPredicate); standardPeaks.RemoveAll(massDistanceThreshold); standardPeaks.RemoveAll(shapeThreshold); standardPeaks.RemoveAll(isotopeThreshold); if (standardPeaks.Count == 0) { Trace.WriteLine(string.Format(" [No Match]")); Trace.WriteLine(string.Empty); return new LibraryMatchResult(null, AnalysisStatus.Negative, null); } StandardImsPeak closestPeak = standardPeaks.First(); DriftTimeFeatureDistance shortestDistance = new DriftTimeFeatureDistance(target, standardPeaks.First(), voltageGroup); foreach (var peak in standardPeaks) { DriftTimeFeatureDistance distance = new DriftTimeFeatureDistance(target, peak, voltageGroup); if (distance.CompareTo(shortestDistance) < 0) { closestPeak = peak; } } Trace.WriteLine(string.Format(" [Match]")); Trace.WriteLine(string.Empty); return new LibraryMatchResult(closestPeak, AnalysisStatus.Positive, shortestDistance); } } throw new Exception("No voltage groups in the Dataset match temerature, pressure, or drift tube voltage setting from the library. Matching failed."); }
/// <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; }