/// <summary> /// The find optimum hypothesis. /// </summary> /// <param name="observations"> /// The observations. /// </param> /// <param name="driftTubeLength"> /// The drift Tube Length. /// </param> /// <param name="massTarget"> /// The mass Target. /// </param> /// <param name="parameters"> /// The parameters. /// </param> /// <returns> /// The <see cref="AssociationHypothesis"/>. /// </returns> /// <exception cref="NotImplementedException"> /// </exception> public AssociationHypothesis FindOptimumHypothesis(IEnumerable<ObservedPeak> observations, double driftTubeLength, IImsTarget massTarget, CrossSectionSearchParameters parameters, int numberOfVoltageGroups) { observations = observations.ToList(); ObservationTransitionGraph<IonTransition> transitionGraph = new ObservationTransitionGraph<IonTransition>(observations, (a, b) => new IonTransition(a, b)); // Visualize the graph. // transitionGraph.PlotGraph(); // Find all the possible combinotorial tracks // IList<IsomerTrack> candidateTracks = this.FindAllReasonableTracks(transitionGraph, driftTubeLength, massTarget, parameters).ToList(); // Find the top N tracks using K shorestest path algorithm IEnumerable<IEnumerable<IonTransition>> kShorestPaths = transitionGraph.PeakGraph.RankedShortestPathHoffmanPavley(t => 0 - Math.Log(t.TransitionProbability), transitionGraph.SourceVertex, transitionGraph.SinkVertex, this.maxTracks); IEnumerable<IsomerTrack> candidateTracks = MinCostFlowIonTracker.ToTracks(kShorestPaths, parameters, numberOfVoltageGroups, parameters.RegressionSelection); // filter paths TrackFilter filter = new TrackFilter(); Predicate<IsomerTrack> trackPredicate = track => filter.IsTrackPossible(track, massTarget, parameters); List<IsomerTrack> filteredTracks = candidateTracks.ToList().FindAll(trackPredicate); // Select the top N tracks to proceed to next step. var hypotheses = this.FindAllHypothesis(filteredTracks, observations).ToArray(); // Find the combination of tracks that produces the highest posterior probablity. IOrderedEnumerable<AssociationHypothesis> sortedAssociationHypotheses = hypotheses.OrderByDescending(h => h.ProbabilityOfHypothesisGivenData); return sortedAssociationHypotheses.FirstOrDefault(); }
public AssociationHypothesis FindOptimumHypothesis( IEnumerable<ObservedPeak> observations, double driftTubeLength, IImsTarget target, CrossSectionSearchParameters parameters) { throw new NotImplementedException(); }
public void PlotAssociationHypothesis(AssociationHypothesis hypothesis, string plotLocation, string datasetName, IImsTarget target, IDictionary<string, IList<ObservedPeak>> preFilteredPeaks) { //int width = 450; //int height = 256; int width = 675; int height = 384; PlotModel associationHypothsisPlot = this.AssociationHypothesisPlot(hypothesis, datasetName, target); associationHypothsisPlot = this.AnnotateRemovedPeaks(associationHypothsisPlot, preFilteredPeaks); this.PlotDiagram(plotLocation, associationHypothsisPlot, width, height); }
/// <summary> /// The add result to scores table. /// </summary> /// <param name="dataset"> /// The dataset. /// </param> /// <param name="chemicalResult"> /// The chemical result. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="table"> /// The table. /// </param> /// <param name="colDef"> /// The col def. /// </param> /// <returns> /// The <see cref="int"/>. /// </returns> public static int AddResultToScoresTable(string dataset, CrossSectionWorkflowResult chemicalResult, IImsTarget target, NumericTable table, IList<string> colDef) { TableRow dict = new TableRow(dataset + target); dict.Name += "(" + chemicalResult.AnalysisStatus + ")"; dict.Add(colDef[1], chemicalResult.AverageObservedPeakStatistics.IntensityScore); dict.Add(colDef[2], chemicalResult.AverageObservedPeakStatistics.IsotopicScore); dict.Add(colDef[3], chemicalResult.AverageObservedPeakStatistics.PeakShapeScore); dict.Add(colDef[0], chemicalResult.AverageVoltageGroupStability); dict.Add(colDef[4], chemicalResult.AssociationHypothesisInfo.ProbabilityOfHypothesisGivenData); table.Add(dict); return 1; }
/// <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 score feature. /// </summary> /// <param name="peak"> /// The peak. /// </param> /// <param name="globalMaxIntensity"> /// The global max intensity. /// </param> /// <param name="uimfReader"> /// The uimf reader. /// </param> /// <param name="massToleranceInPpm"> /// The mass tolerance in ppm. /// </param> /// <param name="driftTimeToleranceInMs"> /// The drift time tolerance in ms. /// </param> /// <param name="voltageGroup"> /// The voltage group. /// </param> /// <param name="voltageGroupScans"> /// The voltage group scans. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="isotopicScoreMethod"> /// The isotopic score method. /// </param> /// <param name="theoreticalIsotopicProfile"> /// The theoretical isotopic profile. /// </param> /// <returns> /// The <see cref="PeakScores"/>. /// </returns> public static PeakScores ScoreFeature(this StandardImsPeak peak, double globalMaxIntensity, DataReader uimfReader, double massToleranceInPpm, double driftTimeToleranceInMs, VoltageGroup voltageGroup, int voltageGroupScans, IImsTarget target, IsotopicScoreMethod isotopicScoreMethod, List<Peak> theoreticalIsotopicProfile) { double intensityScore = IntensityScore(peak, globalMaxIntensity); double peakShapeScore = PeakShapeScore( peak, uimfReader, massToleranceInPpm, driftTimeToleranceInMs, voltageGroup, globalMaxIntensity, voltageGroupScans); double isotopicScore = 0; if (target.HasCompositionInfo) { isotopicScore = IsotopicProfileScore( peak, uimfReader, target, theoreticalIsotopicProfile, voltageGroup, IsotopicScoreMethod.Angle, globalMaxIntensity, voltageGroupScans); } return new PeakScores(intensityScore, isotopicScore, peakShapeScore); }
/// <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> /// The run molecule informed work flow. /// </summary> /// <param name="target"> /// The Target. /// </param> /// <param name="detailedVerbose"> /// </param> /// <returns> /// The <see cref="CrossSectionWorkflowResult"/>. /// </returns> public CrossSectionWorkflowResult RunCrossSectionWorkFlow(IImsTarget target, bool detailedVerbose = true) { // Reassign trace listener to print to console as well as the target directory. using (this.ResetTraceListenerToTarget(target, this.DatasetName)) { try { // Get the monoisotopic mass for viper, which is different from anything else. double viperFriendlyMass = target.MassWithAdduct; if (target.ChargeState < 0) { viperFriendlyMass = viperFriendlyMass + new Composition(0, target.ChargeState, 0, 0, 0).Mass; } else { viperFriendlyMass = viperFriendlyMass - new Composition(0, Math.Abs(target.ChargeState), 0, 0, 0).Mass; } // Generate Theoretical Isotopic Profile List<Peak> theoreticalIsotopicProfilePeakList = null; if (target.HasCompositionInfo) { int chargeStateAbs = Math.Abs(target.ChargeState); // Again this isotopic profile generator auto adds hydrogen for you depending on charge states. So here take it out. Composition compensatedComposition = target.CompositionWithAdduct - new Composition(0, chargeStateAbs, 0, 0, 0); string empiricalFormula = compensatedComposition.ToPlainString(); IsotopicProfile theoreticalIsotopicProfile = this.theoreticalFeatureGenerator.GenerateTheorProfile(empiricalFormula, chargeStateAbs); theoreticalIsotopicProfilePeakList = theoreticalIsotopicProfile.Peaklist.Cast<Peak>().ToList(); } Trace.WriteLine(string.Format("Dataset: {0}", this.uimfReader.UimfFilePath)); ReportTargetInfo(target, detailedVerbose); double targetMz = Math.Abs(target.MassWithAdduct / target.ChargeState); // Voltage grouping. Note that we only accumulate frames as needed. Accumulate frames globally is too costly. // Here we accumulate the XICs around target MZ. VoltageSeparatedAccumulatedXiCs accumulatedXiCs = new VoltageSeparatedAccumulatedXiCs(this.uimfReader, targetMz, this.Parameters.MzWindowHalfWidthInPpm, this.Parameters.DriftTubeLengthInCm); // Remove voltage groups that don't have sufficient frame accumulations IEnumerable<VoltageGroup> remainingVGs = accumulatedXiCs.Keys; IEnumerable<VoltageGroup> toBeRemoved = VoltageGroupFilters.RemoveVoltageGroupsWithInsufficentFrames(remainingVGs, this.Parameters.InsufficientFramesFraction); foreach (VoltageGroup voltageGroup in toBeRemoved) { accumulatedXiCs.Remove(voltageGroup); } // Perform feature detection and scoring and the given MzInDalton range on the accumulated XICs to get the base peaks. if (detailedVerbose) { Trace.WriteLine("Feature detection and scoring: "); } IList<VoltageGroup> rejectedVoltageGroups = new List<VoltageGroup>(); IList<ObservedPeak> filteredObservations = new List<ObservedPeak>(); IList<ObservedPeak> allObservations = new List<ObservedPeak>(); IDictionary<string, IList<ObservedPeak>> rejectedObservations = new Dictionary<string, IList<ObservedPeak>>(); var numberOfParticipatingVGs = accumulatedXiCs.Keys.Count; // Iterate through the features and perform filtering on isotopic affinity, intensity, drift time and peak shape. foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys) { double globalMaxIntensity = IMSUtil.MaxIntensityAfterFrameAccumulation(voltageGroup, this.uimfReader); List<StandardImsPeak> standardPeaks = this.FindPeaksBasedOnXIC(voltageGroup, accumulatedXiCs[voltageGroup], target); // Score features IDictionary<StandardImsPeak, PeakScores> scoresTable = new Dictionary<StandardImsPeak, PeakScores>(); if (detailedVerbose) { Trace.WriteLine( string.Format( " Voltage group: {0:F2} V, Frame {1}-{2}, {3:F2}K, {4:F2}Torr", voltageGroup.MeanVoltageInVolts, voltageGroup.FirstFrameNumber, voltageGroup.LastFrameNumber, voltageGroup.MeanTemperatureInKelvin, voltageGroup.MeanPressureInTorr)); } foreach (StandardImsPeak peak in standardPeaks) { PeakScores currentStatistics = FeatureScoreUtilities.ScoreFeature( peak, globalMaxIntensity, this.uimfReader, this.Parameters.MzWindowHalfWidthInPpm, this.Parameters.DriftTimeToleranceInMs, voltageGroup, this.NumberOfScans, target, IsotopicScoreMethod.Angle, theoreticalIsotopicProfilePeakList); scoresTable.Add(peak, currentStatistics); } double maxIntensity = standardPeaks.Max(x => x.SummedIntensities); Predicate<StandardImsPeak> relativeIntensityThreshold = imsPeak => FeatureFilters.FilterOnRelativeIntesity(imsPeak, maxIntensity, this.Parameters.RelativeIntensityPercentageThreshold); // filter out non Target peaks and noise. Predicate<StandardImsPeak> absoluteIntensityThreshold = imsPeak => FeatureFilters.FilterOnAbsoluteIntensity(imsPeak, scoresTable[imsPeak].IntensityScore, this.Parameters.AbsoluteIntensityThreshold); // filter out features with Ims scans at 1% left or right. Predicate<StandardImsPeak> scanPredicate = imsPeak => FeatureFilters.FilterExtremeDriftTime(imsPeak, this.NumberOfScans); // filter out features with bad peak shapes. Predicate<StandardImsPeak> shapeThreshold = imsPeak => FeatureFilters.FilterBadPeakShape(imsPeak, scoresTable[imsPeak].PeakShapeScore, this.Parameters.PeakShapeThreshold); // filter out features with distant isotopic profile. Predicate<StandardImsPeak> isotopeThreshold = imsPeak => FeatureFilters.FilterBadIsotopicProfile(imsPeak, scoresTable[imsPeak].IsotopicScore, this.Parameters.IsotopicThreshold); // Print out candidate features and how they were rejected. foreach (StandardImsPeak peak in standardPeaks) { PeakScores currentStatistics = scoresTable[peak]; string rejectionReason = ReportFeatureEvaluation( peak, currentStatistics, detailedVerbose, target, scanPredicate(peak), absoluteIntensityThreshold(peak), relativeIntensityThreshold(peak), shapeThreshold(peak), isotopeThreshold(peak)); bool pass = string.IsNullOrEmpty(rejectionReason); ObservedPeak analyzedPeak = new ObservedPeak(voltageGroup, peak, currentStatistics); if (pass) { filteredObservations.Add(analyzedPeak); } else { if (rejectedObservations.ContainsKey(rejectionReason)) { rejectedObservations[rejectionReason].Add(analyzedPeak); } else { rejectedObservations.Add(rejectionReason, new List<ObservedPeak>(){analyzedPeak}); } } allObservations.Add(analyzedPeak); } standardPeaks.RemoveAll(scanPredicate); standardPeaks.RemoveAll(absoluteIntensityThreshold); standardPeaks.RemoveAll(relativeIntensityThreshold); standardPeaks.RemoveAll(shapeThreshold); if (target.HasCompositionInfo) { standardPeaks.RemoveAll(isotopeThreshold); } if (standardPeaks.Count == 0) { if (detailedVerbose) { Trace.WriteLine(string.Format(" (All features were rejected in voltage group {0:F4} V)", voltageGroup.MeanVoltageInVolts)); Trace.WriteLine(string.Empty); Trace.WriteLine(string.Empty); } rejectedVoltageGroups.Add(voltageGroup); } // Rate the feature's VoltageGroupScoring score. VoltageGroupScoring score measures how likely the voltage group contains and detected the Target ion. voltageGroup.VoltageGroupScore = VoltageGroupScoring.ComputeVoltageGroupStabilityScore(voltageGroup); } // Remove voltage groups that were rejected foreach (VoltageGroup voltageGroup in rejectedVoltageGroups) { accumulatedXiCs.Remove(voltageGroup); } IEnumerable<ObservedPeak> rejectedPeaks = rejectedObservations.Values.SelectMany(x => x); // Report analysis as negative if (accumulatedXiCs.Keys.Count == 0) { CrossSectionWorkflowResult informedResult = CrossSectionWorkflowResult.CreateNegativeResult(rejectedPeaks, rejectedVoltageGroups, target, this.DatasetPath, this.OutputPath, this.SampleCollectionDate); ReportAnslysisResultAndMetrics(informedResult, detailedVerbose); return informedResult; } else { // Perform the data association algorithm. IIonTracker tracker = new CombinatorialIonTracker(3000); // Because for somereason we are not keeping track of drift tube length in UIMF...so we kind of have to go ask the instrument operator.. double driftTubeLength = this.Parameters.DriftTubeLengthInCm; AssociationHypothesis optimalAssociationHypothesis = tracker.FindOptimumHypothesis(filteredObservations, driftTubeLength, target, this.Parameters, numberOfParticipatingVGs); if (optimalAssociationHypothesis == null) { CrossSectionWorkflowResult negResult = CrossSectionWorkflowResult.CreateNegativeResult(rejectedPeaks, rejectedVoltageGroups, target, this.DatasetPath, this.OutputPath, this.SampleCollectionDate); ReportAnslysisResultAndMetrics(negResult, detailedVerbose); return negResult; } if (detailedVerbose) { Console.WriteLine("Writes QC plot of fitline to " + this.OutputPath); Trace.WriteLine(string.Empty); } string extension = (this.Parameters.GraphicsExtension.StartsWith(".")) ? this.Parameters.GraphicsExtension : "." + this.Parameters.GraphicsExtension; string outputPath = string.Format("{0}target_{1}_in_{2}_QA{3}", this.OutputPath, target.TargetDescriptor, this.DatasetName, extension); ImsInformedPlotter plotter = new ImsInformedPlotter(); plotter.PlotAssociationHypothesis(optimalAssociationHypothesis, outputPath, this.DatasetName, target, rejectedObservations); // Printout results if (detailedVerbose) { Trace.WriteLine("Target Data Association"); int count = 0; foreach (IsomerTrack track in optimalAssociationHypothesis.Tracks) { Trace.WriteLine(string.Format(" T{0}: ", count)); foreach (ObservedPeak peak in track.ObservedPeaks) { Trace.WriteLine(string.Format(" [td: {0:F4}ms, V: {1:F4}V, T: {2:F4}K, P: {3:F4}Torr]", peak.Peak.PeakApex.DriftTimeCenterInMs, peak.VoltageGroup.MeanVoltageInVolts, peak.VoltageGroup.MeanTemperatureInKelvin, peak.VoltageGroup.MeanPressureInTorr)); } count++; Trace.WriteLine(""); } Trace.WriteLine(""); } // Remove outliers with high influence. // FitLine.RemoveOutliersAboveThreshold(3, minFitPoints); // Remove outliers until min fit point is reached or good R2 is achieved. // while (TrackFilter.IsLowR2(FitLine.RSquared) && FitLine.FitPointCollection.Count > minFitPoints) // { // FitLine.RemoveOutlierWithHighestCookDistance(minFitPoints); // } // Remove the voltage considered outliers // foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys.Where(p => FitLine.OutlierCollection.Contains(p.FitPoint)).ToList()) // { // accumulatedXiCs.Remove(voltageGroup); // } CrossSectionWorkflowResult informedResult = CrossSectionWorkflowResult.CreateResultFromAssociationHypothesis( this.Parameters, optimalAssociationHypothesis, target, accumulatedXiCs.Keys, allObservations, this.DatasetPath, this.OutputPath, this.SampleCollectionDate, viperFriendlyMass ); ReportAnslysisResultAndMetrics(informedResult, detailedVerbose); Trace.Listeners.Clear(); return informedResult; } } catch (Exception e) { // Print result Trace.WriteLine(e.Message); Trace.WriteLine(e.StackTrace); Trace.Listeners.Clear(); Trace.Close(); Trace.Listeners.Clear(); // create the error result return CrossSectionWorkflowResult.CreateErrorResult(target, this.DatasetName, this.DatasetPath, this.OutputPath, this.SampleCollectionDate); } } }
/// <summary> /// The create error result. /// </summary> /// <param name="target"> /// The target. /// </param> /// <param name="datasetName"> /// The dataset name. /// </param> /// <param name="datasetPath"></param> /// <returns> /// The <see cref="CrossSectionWorkflowResult"/>. /// </returns> public static CrossSectionWorkflowResult CreateErrorResult(IImsTarget target, string datasetName, string datasetPath, string analysisPath, string SampleCollectionTime) { // No hypothesis can be made. return new CrossSectionWorkflowResult( datasetPath, target, AnalysisStatus.UknownError, null, null, null, 0, analysisPath, SampleCollectionTime ); }
internal static CrossSectionWorkflowResult CreateResultFromAssociationHypothesis(CrossSectionSearchParameters parameters, AssociationHypothesis optimalHypothesis, IImsTarget target, IEnumerable<VoltageGroup> allVoltageGroups, IEnumerable<ObservedPeak> allPeaks, string datasetPath, string analysisPath, string sampleCollectionDate, double viperCompatibleMass = 0) { // Initialize the result struct. AssociationHypothesisInfo associationHypothesisInfo = new AssociationHypothesisInfo(optimalHypothesis.ProbabilityOfDataGivenHypothesis, optimalHypothesis.ProbabilityOfHypothesisGivenData); double averageVoltageGroupScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(allVoltageGroups); IEnumerable<PeakScores> allFeatureStatistics = allPeaks.Select(x => x.Statistics); PeakScores averageObservedPeakStatistics = FeatureScoreUtilities.AverageFeatureStatistics(allFeatureStatistics); IEnumerable<IsomerTrack> tracks = optimalHypothesis.Tracks.ToList(); // Find the conformer with the closest m/z IsomerTrack trackWithBestMz = tracks.OrderBy(x => Math.Abs(Metrics.DaltonToPpm(x.AverageMzInDalton - target.MassWithAdduct, target.MassWithAdduct))).First(); double bestMzInPpm = Metrics.DaltonToPpm(trackWithBestMz.AverageMzInDalton - target.MassWithAdduct, target.MassWithAdduct); IList<IdentifiedIsomerInfo> isomersInfo = tracks.Select(x => x.ExportIdentifiedIsomerInfo(viperCompatibleMass, allVoltageGroups.Count() - parameters.MaxOutliers, parameters.MinR2, target, bestMzInPpm)).ToList(); AnalysisStatus finalStatus = TrackToHypothesisConclusionLogic(isomersInfo.Select(info => info.AnalysisStatus)); CrossSectionWorkflowResult informedResult = new CrossSectionWorkflowResult( datasetPath, target, finalStatus, associationHypothesisInfo, isomersInfo, averageObservedPeakStatistics, averageVoltageGroupScore, analysisPath, sampleCollectionDate ); return informedResult; }
/// <summary> /// The compute mobility info. /// </summary> /// <param name="target"> /// The inferred target. /// </param> /// <returns> /// The <see cref="double"/>. /// </returns> private MobilityInfo ComputeMobilityInfo(IImsTarget target) { // Convert the track into a Continuous XY data points. this.mobilityInfo.Mobility = this.driftTubeLengthInMeters * this.driftTubeLengthInMeters * 1000 / (this.FitLine.Slope); this.mobilityInfo.RSquared = this.FitLine.RSquared; this.mobilityInfo.T0 = this.FitLine.Intercept; Composition bufferGas = new Composition(0, 0, 2, 0, 0); double reducedMass = MoleculeUtil.ComputeReducedMass(target.MassWithAdduct, bufferGas); double meanTemperatureInKelvin = this.GetGlobalMeanTemperature(); this.mobilityInfo.CollisionCrossSectionArea = MoleculeUtil.ComputeCrossSectionalArea( meanTemperatureInKelvin, this.mobilityInfo.Mobility, target.ChargeState, reducedMass); return this.mobilityInfo; }
/// <summary> /// The equals. /// </summary> /// <param name="other"> /// The other. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public override bool Equals(IImsTarget other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (other.TargetType != TargetType.MoleculeWithKnownDriftTime) return false; return this.Equals(other as DriftTimeTarget); }
/// <summary> /// The export identified isomer info. /// </summary> /// <param name="viperCompatibleMass"> /// The viper compatible mass. /// </param> /// <param name="minFitPoints"> /// The min fit points. /// </param> /// <param name="minR2"> /// The min r 2. /// </param> /// <param name="target"></param> /// <returns> /// The <see cref="IdentifiedIsomerInfo"/>. /// </returns> public IdentifiedIsomerInfo ExportIdentifiedIsomerInfo(double viperCompatibleMass, int minFitPoints, double minR2, IImsTarget target, double bestMzInPpm) { double averageVoltageGroupStabilityScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(this.definedVoltageGroups); IList<ArrivalTimeSnapShot> snapshots = new List<ArrivalTimeSnapShot>(); foreach (var observation in this.observedPeaks) { snapshots.Add(this.ExtractArrivalTimeSnapShot(observation)); } IdentifiedIsomerInfo info = new IdentifiedIsomerInfo( this.observedPeaks.Count, this.AverageMzInDalton, this.mobilityInfo.RSquared, this.mobilityInfo.Mobility, this.mobilityInfo.CollisionCrossSectionArea, averageVoltageGroupStabilityScore, snapshots, viperCompatibleMass, this.ConcludeStatus(minFitPoints, minR2), this.TrackStatistics, target, this.mobilityInfo.T0, bestMzInPpm ); return info; }
/// <summary> /// The report target info. /// </summary> /// <param name="target"> /// The target. /// </param> /// <param name="verbose"> /// The verbose. /// </param> private static void ReportTargetInfo(IImsTarget target, bool verbose) { Trace.WriteLine(string.Empty); if (verbose) { Trace.WriteLine("Target chemical: " + target.CorrespondingChemical); Trace.WriteLine("Target description: " + target.TargetDescriptor); if (target.HasCompositionInfo) { Trace.WriteLine("Target Empirical Formula: " + target.EmpiricalFormula); } Trace.WriteLine("Targeting centerMz: " + target.MassWithAdduct); Trace.WriteLine(string.Empty); } else { Trace.WriteLine("Target: " + target.TargetDescriptor); } }
/// <summary> /// The association hypothesis plot. /// </summary> /// <param name="hypothesis"> /// The hypothesis. /// </param> /// <param name="datasetName"> /// The dataset name. /// </param> /// <param name="targetDescriptor"> /// The target descriptor. /// </param> /// <returns> /// The <see cref="PlotModel"/>. /// </returns> private PlotModel AssociationHypothesisPlot(AssociationHypothesis hypothesis, string datasetName, IImsTarget target, bool plotXAxisFromZero = false) { PlotModel model = new PlotModel(); model.LegendBorderThickness = 0; model.LegendOrientation = LegendOrientation.Vertical; model.LegendPlacement = LegendPlacement.Inside; model.LegendPosition = LegendPosition.LeftTop; model.TitlePadding = 0; model.Title = "Optimal Association Hypothesis Plot"; model.Subtitle = string.Format("Target: {0}, dataset: {1}", target.TargetDescriptor, datasetName) ; model.Axes.Add( new LinearAxis { Title = "IMS arrival time (milliseconds)", MajorGridlineStyle = LineStyle.Solid, Position = AxisPosition.Left, }); model.Axes.Add( new LinearAxis { Title = "P/(T*V) with P and T nondimensionalized (1/V)", Position = AxisPosition.Bottom, MajorGridlineStyle = LineStyle.Solid, }); // Add all the points IEnumerable<ObservedPeak> onTrackPeaks = hypothesis.OnTrackObservations; IEnumerable<ObservedPeak> offTrackPeaks = hypothesis.AllObservations.Where(x => !hypothesis.IsOnTrack(x)); Func<ObservedPeak, ScatterPoint> fitPointMap = obj => { ObservedPeak observation = obj; ContinuousXYPoint xyPoint = observation.ToContinuousXyPoint(false, 0); double size = MapToPointSize(observation); ScatterPoint sp = new ScatterPoint(xyPoint.X, xyPoint.Y, size); return sp; }; var ontrackSeries= new ScatterSeries { Title = "[Peaks On Tracks]", MarkerFill = OxyColors.BlueViolet, MarkerType = MarkerType.Circle }; var offtrackSeries= new ScatterSeries { Title = "[Peaks Off Tracks]", MarkerFill = OxyColors.Red, MarkerType = MarkerType.Circle }; ontrackSeries.Points.AddRange(onTrackPeaks.Select(x => fitPointMap(x))); offtrackSeries.Points.AddRange(offTrackPeaks.Select(x => fitPointMap(x))); model.Series.Add(ontrackSeries); model.Series.Add(offtrackSeries); var allTracks = hypothesis.Tracks; // Add the tracks as linear axes int count = 1; foreach (var track in allTracks) { FitLine fitline = track.FitLine; LineAnnotation annotation = new LineAnnotation(); annotation.Slope = fitline.Slope; annotation.Intercept = fitline.Intercept; annotation.TextPadding = 3; annotation.TextMargin = 2; annotation.Text = string.Format("Conformer {0} - mz: {1:F2}; ccs: {2:F2}, Isotopic Score: {3:F3}; Track Probability: {4:F2}; R2: {5:F5};", count, track.AverageMzInDalton, track.GetMobilityInfoForTarget(target).CollisionCrossSectionArea, track.TrackStatistics.IsotopicScore, track.TrackProbability, track.FitLine.RSquared); count++; model.Annotations.Add(annotation); //Func<object, DataPoint> lineMap = obj => //{ // ObservedPeak observation = (ObservedPeak)obj; // ContinuousXYPoint xyPoint = observation.ToContinuousXyPoint(); // double x = xyPoint.X; // double y = fitline.ModelPredictX2Y(x); // DataPoint sp = new DataPoint(x, y); // return sp; //}; //model.Series.Add(new LineSeries() //{ // Mapping = lineMap, // ItemsSource = track.ObservedPeaks, // Color = OxyColors.Purple //}); } return model; }
/// <summary> /// The reset trace listener to target. /// </summary> /// <param name="target"> /// The target. /// </param> /// <returns> /// The <see cref="FileStream"/>. /// </returns> private FileStream ResetTraceListenerToTarget(IImsTarget target, string datasetName) { Trace.Listeners.Clear(); string targetResultFileName = Path.Combine(this.OutputPath, "target_" + target.TargetDescriptor + "_in_" + datasetName + ".txt"); FileStream resultFile = new FileStream(targetResultFileName, FileMode.Create, FileAccess.Write, FileShare.None); ConsoleTraceListener consoleTraceListener = new ConsoleTraceListener(false); consoleTraceListener.TraceOutputOptions = TraceOptions.DateTime; TextWriterTraceListener targetResultTraceListener = new TextWriterTraceListener(resultFile) { TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime }; Trace.Listeners.Add(consoleTraceListener); Trace.Listeners.Add(targetResultTraceListener); Trace.AutoFlush = true; return resultFile; }
/// <summary> /// The find peaks based on xic. /// </summary> /// <param name="group"> /// The group. /// </param> /// <param name="chromatogram"> /// The chromatogram. /// </param> /// <param name="target"> /// The target. /// </param> /// <returns> /// The <see cref="IList"/>. /// </returns> /// <exception cref="NotImplementedException"> /// </exception> private List<StandardImsPeak> FindPeaksBasedOnXIC(VoltageGroup voltageGroup, ExtractedIonChromatogram chromatogram, IImsTarget target) { if (this.Parameters.PeakDetectorSelection == PeakDetectorEnum.WaterShed) { // Find peaks using multidimensional peak finder. List<IntensityPoint> intensityPoints = chromatogram.IntensityPoints; List<FeatureBlob> featureBlobs = PeakFinding.FindPeakUsingWatershed(intensityPoints, this.smoother, this.Parameters.FeatureFilterLevel); // Recapture the 2D peak using the 1D feature blob from multidimensional peak finder. return featureBlobs.Select(featureBlob => new StandardImsPeak(featureBlob, this.uimfReader, voltageGroup, target.MassWithAdduct, this.Parameters.MzWindowHalfWidthInPpm)).ToList(); } else if (this.Parameters.PeakDetectorSelection == PeakDetectorEnum.MASICPeakFinder) { // Find peaks using MASIC peak finder List<IntensityPoint> intensityPoints = chromatogram.IntensityPoints; IList<clsPeak> masicPeaks = PeakFinding.FindPeakUsingMasic(intensityPoints, this.NumberOfScans); // Recapture the 2D peak using the 1D feature blob from multidimensional peak finder. return masicPeaks.Select(peak => new StandardImsPeak(peak)).ToList(); } else { throw new NotImplementedException(string.Format("{0} not supported", this.Parameters.PeakDetectorSelection)); } }
/// <summary> /// Gets the mobility info for inferedTarget /// </summary> /// <param name="inferedTarget"> /// The inferedTarget. /// </param> public MobilityInfo GetMobilityInfoForTarget(IImsTarget inferedTarget) { return this.ComputeMobilityInfo(inferedTarget); }
public bool Equals(IImsTarget other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (other.TargetType != TargetType.Peptide) return false; return this.Equals(other as PeptideTarget); }
/// <summary> /// The equals. /// </summary> /// <param name="other"> /// The other. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public virtual bool Equals(IImsTarget other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (other.TargetType != TargetType.Molecule) return false; return this.Equals(other as MolecularTarget); }
/// <summary> /// The initiate from workflow result. /// </summary> /// <param name="result"> /// The result. /// </param> private void InitiateFromWorkflowResult(CrossSectionWorkflowResult result) { this.Target = result.Target; this.AnalysisStatus = result.AnalysisStatus; this.FusionNumber = 1; this.DetectedIsomers = result.IdentifiedIsomers; }
/// <summary> /// Initializes a new instance of the <see cref="CrossSectionWorkflowResult"/> class. /// Multiple isomer result constructor /// </summary> /// <param name="datasetName"> /// The dataset name. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="analysisStatus"> /// The analysis status. /// </param> /// <param name="associationHypothesisInfo"> /// The analysis scores holder. /// </param> /// <param name="isomerResults"> /// The isomer results. /// </param> /// <param name="averageObservedPeakStatistics"></param> /// <param name="averageVoltageGroupStability"></param> /// <param name="datasetPath"></param> /// <param name="analysisDirectory"></param> /// <param name="dateTime"></param> public CrossSectionWorkflowResult( string datasetPath, IImsTarget target, AnalysisStatus analysisStatus, AssociationHypothesisInfo associationHypothesisInfo, IList<IdentifiedIsomerInfo> isomerResults, PeakScores averageObservedPeakStatistics, double averageVoltageGroupStability, string analysisDirectory, string dateTime) { this.Target = target; this.AnalysisStatus = analysisStatus; this.AssociationHypothesisInfo = associationHypothesisInfo; this.isomerResults = isomerResults; this.AverageObservedPeakStatistics = averageObservedPeakStatistics; this.AverageVoltageGroupStability = averageVoltageGroupStability; this.AnalysisDirectory = analysisDirectory; this.DateTime = dateTime; this.DatasetPath = datasetPath; this.DatasetName = Path.GetFileNameWithoutExtension(datasetPath); this.DateTime = dateTime; }
/// <summary> /// The more likely than targeted. /// </summary> /// <param name="a"> /// The a. /// </param> /// <param name="b"> /// The b. /// </param> /// <param name="likelihoodFunc"> /// The likelihood func. /// </param> /// <param name="target"> /// The target. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> /// <exception cref="NotImplementedException"> /// </exception> public static bool MoreLikelyThanTargeted(ObservedPeak a, ObservedPeak b, LikelihoodFunc likelihoodFunc, IImsTarget target) { throw new NotImplementedException(); }
/// <summary> /// The create negative result. /// </summary> /// <param name="rejectedPeaks"> /// The rejected peaks. /// </param> /// <param name="rejectedVoltageGroups"> /// The rejected voltage groups. /// </param> /// <param name="datasetName"> /// The dataset name. /// </param> /// <param name="target"> /// The target. /// </param> /// <returns> /// The <see cref="CrossSectionWorkflowResult"/>. /// </returns> internal static CrossSectionWorkflowResult CreateNegativeResult(IEnumerable<ObservedPeak> rejectedPeaks, IEnumerable<VoltageGroup> rejectedVoltageGroups, IImsTarget target, string datasetPath, string analysisPath, string sampleCollectionTime) { // No valid feature peaks were identified. No hypothesis. double voltageGroupScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(rejectedVoltageGroups); // quantize the VG score from VGs in the removal list. IEnumerable<PeakScores> featureStats = rejectedPeaks.Select(x => x.Statistics); PeakScores averagePeakScores = FeatureScoreUtilities.AverageFeatureStatistics(featureStats); CrossSectionWorkflowResult informedResult = new CrossSectionWorkflowResult( datasetPath, target, AnalysisStatus.Negative, null, averagePeakScores, voltageGroupScore, analysisPath, sampleCollectionTime); return informedResult; }
private async Task<string> InsertChemical(SQLiteCommand cmd, IImsTarget target) { // Query if chemical is already added. string chemicalName = target.CorrespondingChemical; cmd.CommandText = string.Format("SELECT count(*) FROM chemicals WHERE name='{0}'", chemicalName); int count = Convert.ToInt32(cmd.ExecuteScalar()); if(count == 0) { // Insert chemical info to chemicals table cmd.CommandText = "INSERT INTO chemicals (name, empirical_formula, chemical_class) VALUES (@name, @empirical_formula, @chemical_class)"; cmd.Parameters.AddWithValue("@name", chemicalName); cmd.Parameters.AddWithValue("@empirical_formula", target.EmpiricalFormula); cmd.Parameters.AddWithValue("@chemical_class", ""); await Task.Run(() => cmd.ExecuteNonQuery()); return chemicalName; } return ""; }
/// Initializes a new instance of the <see cref="CrossSectionWorkflowResult"/> class. /// Constructor for no isomer result. public CrossSectionWorkflowResult( string datasetPath, IImsTarget target, AnalysisStatus analysisStatus, AssociationHypothesisInfo associationHypothesisInfo, PeakScores averageObservedPeakStatistics, double averageVoltageGroupStability, string analysisDirectory, string dateTime) : this(datasetPath, target, analysisStatus, associationHypothesisInfo, new List<IdentifiedIsomerInfo>(), averageObservedPeakStatistics, averageVoltageGroupStability, analysisDirectory, dateTime) { }
private async Task<long> InsertTarget(SQLiteCommand cmd, IImsTarget target) { cmd.CommandText = string.Format("SELECT count(*) FROM targets WHERE target_description ='{0}' AND target_chemical = '{1}'", target.TargetDescriptor, target.CorrespondingChemical); int count = Convert.ToInt32(cmd.ExecuteScalar()); if(count == 0) { // Insert target info to chemicals table cmd.CommandText = "INSERT INTO targets (target_chemical, target_type, adduct, target_description, monoisotopic_mass, composition_with_adduct, mass_with_adduct, charge_state) VALUES (@target_chemical, @target_type, @adduct, @target_description, @monoisotopic_mass, @composition_with_adduct, @mass_with_adduct, @charge_state)"; cmd.Parameters.AddWithValue("@target_chemical", target.CorrespondingChemical); cmd.Parameters.AddWithValue("@target_type", target.TargetType); cmd.Parameters.AddWithValue("@adduct", target.Adduct); cmd.Parameters.AddWithValue("@target_description", target.TargetDescriptor); cmd.Parameters.AddWithValue("@monoisotopic_mass", target.MonoisotopicMass); cmd.Parameters.AddWithValue("@composition_with_adduct", target.CompositionWithAdduct); cmd.Parameters.AddWithValue("@mass_with_adduct", target.MassWithAdduct); cmd.Parameters.AddWithValue("@charge_state", target.ChargeState); await Task.Run(() => cmd.ExecuteNonQuery()); return await this.LastID(cmd); } else { cmd.CommandText = string.Format("SELECT rowid FROM targets WHERE target_description ='{0}'", target.TargetDescriptor); int id = Convert.ToInt32(cmd.ExecuteScalar()); return id; } }
/// <summary> /// The is track possible. /// </summary> /// <param name="track"> /// The track. /// </param> /// <param name="target"></param> /// <param name="crossSectionSearchParameters"></param> /// <returns> /// The <see cref="bool"/>. /// </returns> public bool IsTrackPossible(IsomerTrack track, IImsTarget target, CrossSectionSearchParameters crossSectionSearchParameters) { int minFitPoints = track.TotalNumberOfVoltageGroups - crossSectionSearchParameters.MaxOutliers; if (this.FilterLowFitPointNumber(track.RealPeakCount, minFitPoints)) { return false; } MobilityInfo trackMobilityInfo = track.GetMobilityInfoForTarget(target); if (!this.IsConsistentWithIonDynamics(trackMobilityInfo)) { return false; } if (this.IsLowR2(trackMobilityInfo.RSquared, crossSectionSearchParameters.MinR2)) { return false; } return true; }
/// <summary> /// Initializes a new instance of the <see cref="IdentifiedIsomerInfo"/> class. /// </summary> /// <param name="numberOfFeaturePointsUsed"> /// The number of feature points used. /// </param> /// <param name="mzInDalton"></param> /// <param name="rSquared"> /// The r squred. /// </param> /// <param name="mobility"> /// The mobility. /// </param> /// <param name="crossSectionalArea"> /// The cross sectional area. /// </param> /// <param name="averageVoltageGroupStabilityScore"> /// The average voltage group stability score. /// </param> /// <param name="arrivalTimeSnapShots"> /// The arrival time snap shots. /// </param> /// <param name="viperCompatibleMass"> /// The viper Compatible Mass. /// </param> /// <param name="analysisStatus"></param> /// <param name="peakScores"></param> /// <param name="target"></param> public IdentifiedIsomerInfo( int numberOfFeaturePointsUsed, double mzInDalton, double rSquared, double mobility, double crossSectionalArea, double averageVoltageGroupStabilityScore, IEnumerable<ArrivalTimeSnapShot> arrivalTimeSnapShots, double viperCompatibleMass, AnalysisStatus analysisStatus, PeakScores peakScores, IImsTarget target, double t0, double bestMzInPpm) { this.NumberOfFeaturePointsUsed = numberOfFeaturePointsUsed; this.RSquared = rSquared; this.Mobility = mobility; this.CrossSectionalArea = crossSectionalArea; this.AverageVoltageGroupStabilityScore = averageVoltageGroupStabilityScore; this.ArrivalTimeSnapShots = arrivalTimeSnapShots; this.ViperCompatibleMass = viperCompatibleMass; this.AnalysisStatus = analysisStatus; this.PeakScores = peakScores; this.T0 = t0; this.MzInDalton = mzInDalton; this.MzInPpm = Metrics.DaltonToPpm(mzInDalton - target.MassWithAdduct, target.MassWithAdduct); this.RelativeMzInPpm = Math.Abs(MzInPpm - bestMzInPpm); }