/// <summary> /// The append correlation result to csv. /// </summary> /// <param name="correlationResult"> /// The correlation result. /// </param> public void AppendCorrelationResultToCsv(ChargeStateCorrelationResult correlationResult) { PeptideTarget target = correlationResult.ImsTarget; string modificationString = ""; foreach (var modification in target.ModificationList) { modificationString += modification.Name + ":" + modification.AccessionNum + ";"; } StringBuilder peptideInfo = new StringBuilder(); peptideInfo.Append(target.ID + ","); peptideInfo.Append(target.PeptideSequence + ","); peptideInfo.Append(modificationString + ","); // TODO: Mods peptideInfo.Append(target.EmpiricalFormula + ","); peptideInfo.Append(target.MonoisotopicMass + ","); double targetElutionTime = target.NormalizedElutionTime; foreach (var result in correlationResult.CorrelatedResults) { int chargeState = result.ChargeState; IEnumerable<DriftTimeTarget> possibleDriftTimeTargets = target.DriftTimeTargetList.Where(x => x.ChargeState == chargeState).OrderBy(x => Math.Abs(x.NormalizedDriftTimeInMs - result.DriftTime)); double targetDriftTime = 0; double driftTimeError = 0; if(possibleDriftTimeTargets.Any()) { DriftTimeTarget driftTimeTarget = possibleDriftTimeTargets.First(); targetDriftTime = driftTimeTarget.NormalizedDriftTimeInMs; driftTimeError = result.DriftTime - targetDriftTime; } double elutionTimeError = result.NormalizedElutionTime - targetElutionTime; double correlationAverage = correlationResult.CorrelationSum / (correlationResult.CorrelatedResults.Count - 1); StringBuilder resultInfo = new StringBuilder(); resultInfo.Append(result.ChargeState + ","); resultInfo.Append(result.IsotopicProfile.MonoPeakMZ + ","); resultInfo.Append(result.PpmError + ","); resultInfo.Append(result.ScanLcRep + ","); resultInfo.Append(result.IsotopicFitScore + ","); resultInfo.Append(result.IsotopicProfile.GetAbundance() + ","); resultInfo.Append(targetElutionTime + ","); resultInfo.Append(result.NormalizedElutionTime + ","); resultInfo.Append(elutionTimeError + ","); resultInfo.Append(targetDriftTime + ","); resultInfo.Append(result.DriftTime + ","); resultInfo.Append(driftTimeError + ","); resultInfo.Append(correlationAverage + ","); resultInfo.Append(result.AnalysisStatus.ToString()); this.TextWriter.WriteLine(peptideInfo.ToString() + resultInfo.ToString()); } }
/// <summary> /// The run informed workflow. /// </summary> /// <param name="target"> /// The Target. /// </param> /// <returns> /// The <see cref="ChargeStateCorrelationResult"/>. /// </returns> public ChargeStateCorrelationResult RunInformedWorkflow(PeptideTarget target) { Composition targetComposition = target.CompositionWithoutAdduct; double targetMass = targetComposition.Mass; string empiricalFormula = targetComposition.ToPlainString(); double targetNet = target.NormalizedElutionTime; double targetNetMin = targetNet - this._parameters.NetTolerance; double targetNetMax = targetNet + this._parameters.NetTolerance; double reverseAlignedNetMin = targetNetMin; double reverseAlignedNetMax = targetNetMax; if (this._netAlignment != null) { double reverseAlignedNet = this.GetReverseAlignedNet(targetNet); reverseAlignedNetMin = reverseAlignedNet - this._parameters.NetTolerance; reverseAlignedNetMax = reverseAlignedNet + this._parameters.NetTolerance; } int scanLcSearchMin = (int)Math.Floor(reverseAlignedNetMin * this.NumberOfFrames); int scanLcSearchMax = (int)Math.Ceiling(reverseAlignedNetMax * this.NumberOfFrames); int iteration = (targetComposition == null) ? 1 : this._parameters.ChargeStateMax; for (int chargeState = 1; chargeState <= iteration; chargeState++) { if (targetComposition != null) { Ion targetIon = new Ion(targetComposition, chargeState); target.MassWithAdduct = targetIon.GetMonoIsotopicMz(); } double minMzForSpectrum = target.MassWithAdduct - (1.6 / chargeState); double maxMzForSpectrum = target.MassWithAdduct + (4.6 / chargeState); // Generate Theoretical Isotopic Profile IsotopicProfile theoreticalIsotopicProfile = this._theoreticalFeatureGenerator.GenerateTheorProfile(empiricalFormula, chargeState); List<Peak> theoreticalIsotopicProfilePeakList = theoreticalIsotopicProfile.Peaklist.Cast<Peak>().ToList(); // Find XIC Features IEnumerable<FeatureBlob> featureBlobs = this.FindFeatures(target.MassWithAdduct, scanLcSearchMin, scanLcSearchMax); // Filter away small XIC peaks featureBlobs = FeatureDetection.FilterFeatureList(featureBlobs, 0.25); if(!featureBlobs.Any()) { LcImsTargetResult result = new LcImsTargetResult { ChargeState = chargeState, AnalysisStatus = AnalysisStatus.XicNotFound }; target.ResultList.Add(result); } // Check each XIC Peak found foreach (var featureBlob in featureBlobs) { // Setup result object LcImsTargetResult result = new LcImsTargetResult { ChargeState = chargeState, AnalysisStatus = AnalysisStatus.Positive }; target.ResultList.Add(result); FeatureBlobStatistics statistics = featureBlob.CalculateStatistics(); int unsaturatedIsotope = 0; FeatureBlob isotopeFeature = null; int scanLcMin = statistics.ScanLcMin; int scanLcMax = statistics.ScanLcMax; int scanImsMin = statistics.ScanImsMin; int scanImsMax = statistics.ScanImsMax; // TODO: Verify that there are no peaks at isotope #s 0.5 and 1.5?? (If we filter on drift time, this shouldn't actually be necessary) // Find an unsaturated peak in the isotopic profile for (int i = 1; i < 10; i++) { if (!statistics.IsSaturated) break; // Target isotope m/z double isotopeTargetMz = (target.CompositionWithoutAdduct != null) ? new Ion(targetComposition, chargeState).GetIsotopeMz(i) : target.MassWithAdduct; // Find XIC Features IEnumerable<FeatureBlob> newFeatureBlobs = this.FindFeatures(isotopeTargetMz, scanLcMin - 20, scanLcMax + 20); // If no feature, then get out if (!newFeatureBlobs.Any()) { statistics = null; break; } bool foundFeature = false; foreach (var newFeatureBlob in newFeatureBlobs.OrderByDescending(x => x.PointList.Count)) { var newStatistics = newFeatureBlob.CalculateStatistics(); if(newStatistics.ScanImsRep <= scanImsMax && newStatistics.ScanImsRep >= scanImsMin && newStatistics.ScanLcRep <= scanLcMax && newStatistics.ScanLcRep >= scanLcMin) { isotopeFeature = newFeatureBlob; foundFeature = true; break; } } if(!foundFeature) { statistics = null; break; } statistics = isotopeFeature.CalculateStatistics(); unsaturatedIsotope = i; } // Bad Feature, so get out if (statistics == null) { result.AnalysisStatus = AnalysisStatus.IsotopicProfileNotFound; continue; } // TODO: Calculate accurate NET and drift time using quadratic equation int scanLcRep = statistics.ScanLcRep + 1; int scanImsRep = statistics.ScanImsRep; // Calculate NET using aligned data if applicable double net = scanLcRep / this.NumberOfFrames; if (this._netAlignment != null) { net = this._netAlignment.Interpolate(net); } FeatureBlob featureToUseForResult = unsaturatedIsotope > 0 ? isotopeFeature : featureBlob; // Set data to result result.FeatureBlobStatistics = statistics; result.IsSaturated = unsaturatedIsotope > 0; result.ScanLcRep = statistics.ScanLcRep; result.NormalizedElutionTime = net; result.DriftTime = this._uimfReader.GetDriftTime(statistics.ScanLcRep, statistics.ScanImsRep, true); result.XicFeature = featureToUseForResult; // Don't consider bogus results if (scanImsRep < 5 || scanImsRep > this.NumberOfScans - 5) { result.AnalysisStatus = AnalysisStatus.DriftTimeError; continue; } // Don't consider bogus results if (scanLcRep < 3 || scanLcRep > this.NumberOfFrames - 4) { result.AnalysisStatus = AnalysisStatus.ElutionTimeError; continue; } // TODO: ViperCompatibleMass Alignment??? if (target.TargetType == TargetType.Peptide) { // Filter by NET if (net > targetNetMax || net < targetNetMin) { result.AnalysisStatus = AnalysisStatus.ElutionTimeError; continue; } } //Console.WriteLine(Target.PeptideSequence + "\t" + targetMass + "\t" + targetMz + "\t" + scanLcRep); // Get ViperCompatibleMass Spectrum Data XYData massSpectrum = this.GetMassSpectrum(scanLcRep, scanImsRep, minMzForSpectrum, maxMzForSpectrum); List<Peak> massSpectrumPeakList = this._peakDetector.FindPeaks(massSpectrum); //WriteXYDataToFile(massSpectrum, targetMz); // Find Isotopic Profile List<Peak> massSpectrumPeaks; IsotopicProfile observedIsotopicProfile = this._msFeatureFinder.IterativelyFindMSFeature(massSpectrum, theoreticalIsotopicProfile, out massSpectrumPeaks); // Add data to result result.MassSpectrum = massSpectrum; // No need to move on if the isotopic profile is not found if (observedIsotopicProfile == null || observedIsotopicProfile.MonoIsotopicMass < 1) { result.AnalysisStatus = AnalysisStatus.IsotopicProfileNotFound; continue; } // Add data to result result.IsotopicProfile = observedIsotopicProfile; result.MonoisotopicMass = observedIsotopicProfile.MonoIsotopicMass; result.PpmError = Math.Abs(PeptideUtil.PpmError(targetMass, observedIsotopicProfile.MonoIsotopicMass)); // If not enough peaks to reach unsaturated isotope, no need to move on if (observedIsotopicProfile.Peaklist.Count <= unsaturatedIsotope) { result.AnalysisStatus = AnalysisStatus.IsotopicProfileNotFound; continue; } // If the mass error is too high, then ignore if (result.PpmError > this._parameters.MassToleranceInPpm) { result.AnalysisStatus = AnalysisStatus.MassError; continue; } // Correct for Saturation if needed if (unsaturatedIsotope > 0) { IsotopicProfileUtil.AdjustSaturatedIsotopicProfile(observedIsotopicProfile, theoreticalIsotopicProfile, unsaturatedIsotope); } //WriteMSPeakListToFile(observedIsotopicProfile.Peaklist, targetMz); // TODO: This is a hack to fix an issue where the peak width is being calculated way too large which causes the leftOfMonoPeakLooker to use too wide of a tolerance MSPeak monoPeak = observedIsotopicProfile.getMonoPeak(); if (monoPeak.Width > 0.15) monoPeak.Width = 0.15f; // Filter out flagged results MSPeak peakToLeft = this._leftOfMonoPeakLooker.LookforPeakToTheLeftOfMonoPeak(monoPeak, observedIsotopicProfile.ChargeState, massSpectrumPeaks); if (peakToLeft != null) { result.AnalysisStatus = AnalysisStatus.PeakToLeft; continue; } double isotopicFitScore; // Calculate isotopic fit score if(unsaturatedIsotope > 0) { int unsaturatedScanLc = this.FindFrameNumberUseForIsotopicProfile(target.MassWithAdduct, scanLcRep, scanImsRep); if (unsaturatedScanLc > 0) { // Use the unsaturated profile if we were able to get one XYData unsaturatedMassSpectrum = this.GetMassSpectrum(unsaturatedScanLc, scanImsRep, minMzForSpectrum, maxMzForSpectrum); //WriteXYDataToFile(unsaturatedMassSpectrum, targetMz); List<Peak> unsaturatedMassSpectrumPeakList = this._peakDetector.FindPeaks(unsaturatedMassSpectrum); isotopicFitScore = this._isotopicPeakFitScoreCalculator.GetFit(theoreticalIsotopicProfilePeakList, unsaturatedMassSpectrumPeakList, 0.15, this._parameters.MassToleranceInPpm); } else { // Use the saturated profile isotopicFitScore = this._isotopicPeakFitScoreCalculator.GetFit(theoreticalIsotopicProfilePeakList, massSpectrumPeakList, 0.15, this._parameters.MassToleranceInPpm); } } else { isotopicFitScore = this._isotopicPeakFitScoreCalculator.GetFit(theoreticalIsotopicProfilePeakList, massSpectrumPeakList, 0.15, this._parameters.MassToleranceInPpm); } // Add data to result result.IsotopicFitScore = isotopicFitScore; // Filter out bad isotopic fit scores if (isotopicFitScore > this._parameters.IsotopicFitScoreThreshold && unsaturatedIsotope == 0) { result.AnalysisStatus = AnalysisStatus.IsotopicFitScoreError; continue; } Console.WriteLine(chargeState + "\t" + unsaturatedIsotope + "\t" + statistics.ScanLcMin + "\t" + statistics.ScanLcMax + "\t" + statistics.ScanLcRep + "\t" + statistics.ScanImsMin + "\t" + statistics.ScanImsMax + "\t" + statistics.ScanImsRep + "\t" + isotopicFitScore.ToString("0.0000") + "\t" + result.NormalizedElutionTime.ToString("0.0000") + "\t" + result.DriftTime.ToString("0.0000")); } // TODO: Isotope Correlation (probably not going to do because of saturation issues) } // Charge State Correlation (use first unsaturated XIC feature) List<ChargeStateCorrelationResult> chargeStateCorrelationResultList = new List<ChargeStateCorrelationResult>(); ChargeStateCorrelationResult bestCorrelationResult = null; double bestCorrelationSum = -1; List<LcImsTargetResult> resultList = target.ResultList.Where(x => x.AnalysisStatus == AnalysisStatus.Positive).OrderBy(x => x.IsotopicFitScore).ToList(); int numResults = resultList.Count; for (int i = 0; i < numResults; i++) { LcImsTargetResult referenceResult = resultList[i]; ChargeStateCorrelationResult chargeStateCorrelationResult = new ChargeStateCorrelationResult(target, referenceResult); chargeStateCorrelationResultList.Add(chargeStateCorrelationResult); for (int j = i + 1; j < numResults; j++) { LcImsTargetResult testResult = resultList[j]; double correlation = FeatureCorrelator.CorrelateFeaturesUsingLc(referenceResult.XicFeature, testResult.XicFeature); chargeStateCorrelationResult.CorrelationMap.Add(testResult, correlation); Console.WriteLine(referenceResult.FeatureBlobStatistics.ScanLcRep + "\t" + referenceResult.FeatureBlobStatistics.ScanImsRep + "\t" + testResult.FeatureBlobStatistics.ScanLcRep + "\t" + testResult.FeatureBlobStatistics.ScanImsRep + "\t" + correlation); } List<LcImsTargetResult> possibleBestResultList; double correlationSum = chargeStateCorrelationResult.GetBestCorrelation(out possibleBestResultList); if(correlationSum > bestCorrelationSum) { bestCorrelationSum = correlationSum; bestCorrelationResult = chargeStateCorrelationResult; } } // TODO: Score Target // TODO: Quantify Target (return isotopic profile abundance) return bestCorrelationResult; }