public static void CalibrationTestLowRes() { CalibrationTask calibrationTask = new CalibrationTask(); EngineLayer.CommonParameters CommonParameters = new EngineLayer.CommonParameters (dissociationType: MassSpectrometry.DissociationType.LowCID, scoreCutoff: 1); string outputFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestCalibrationLow"); string myFile = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\sliced_b6.mzML"); string myDatabase = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\LowResSnip_B6_mouse_11700_117500pruned.xml"); Directory.CreateDirectory(outputFolder); calibrationTask.RunTask(outputFolder, new List <DbForTask> { new DbForTask(myDatabase, false) }, new List <string> { myFile }, "test"); Assert.That(File.Exists(Path.Combine(outputFolder, @"sliced_b6-calib.mzML"))); Assert.That(File.Exists(Path.Combine(outputFolder, @"sliced_b6-calib.toml"))); var lines = File.ReadAllLines(Path.Combine(outputFolder, @"sliced_b6-calib.toml")); var tolerance = Regex.Match(lines[0], @"\d+\.\d*").Value; var tolerance1 = Regex.Match(lines[1], @"\d+\.\d*").Value; Assert.That(double.TryParse(tolerance, out double tol) == true); Assert.That(double.TryParse(tolerance1, out double tol1) == true); Assert.That(lines[0].Contains("PrecursorMassTolerance")); Assert.That(lines[1].Contains("ProductMassTolerance")); Directory.Delete(outputFolder, true); Directory.Delete(Path.Combine(TestContext.CurrentContext.TestDirectory, @"Task Settings"), true); }
public ProteinScoringAndFdrEngine(List <ProteinGroup> proteinGroups, List <PeptideSpectralMatch> newPsms, bool noOneHitWonders, bool treatModPeptidesAsDifferentPeptides, bool mergeIndistinguishableProteinGroups, CommonParameters commonParameters, List <string> nestedIds) : base(commonParameters, nestedIds) { NewPsms = newPsms; ProteinGroups = proteinGroups; NoOneHitWonders = noOneHitWonders; TreatModPeptidesAsDifferentPeptides = treatModPeptidesAsDifferentPeptides; MergeIndistinguishableProteinGroups = mergeIndistinguishableProteinGroups; }
public static IsotopicEnvelope[] GetNeutralExperimentalFragments(MsDataScan scan, CommonParameters commonParam) { int minZ = 1; int maxZ = 10; var neutralExperimentalFragmentMasses = scan.MassSpectrum.Deconvolute(scan.MassSpectrum.Range, minZ, maxZ, commonParam.DeconvolutionMassTolerance.Value, commonParam.DeconvolutionIntensityRatio).ToList(); if (commonParam.AssumeOrphanPeaksAreZ1Fragments) { HashSet <double> alreadyClaimedMzs = new HashSet <double>(neutralExperimentalFragmentMasses .SelectMany(p => p.peaks.Select(v => ClassExtensions.RoundedDouble(v.mz).Value))); for (int i = 0; i < scan.MassSpectrum.XArray.Length; i++) { double mz = scan.MassSpectrum.XArray[i]; double intensity = scan.MassSpectrum.YArray[i]; if (!alreadyClaimedMzs.Contains(ClassExtensions.RoundedDouble(mz).Value)) { neutralExperimentalFragmentMasses.Add(new IsotopicEnvelope( new List <(double mz, double intensity)> { (mz, intensity) }, mz.ToMass(1), 1, intensity, 0, 0)); } } } return(neutralExperimentalFragmentMasses.OrderBy(p => p.monoisotopicMass).ToArray()); }
public Ms2ScanWithSpecificMass(MsDataScan mzLibScan, double precursorMonoisotopicPeakMz, int precursorCharge, string fullFilePath, CommonParameters commonParam, IsotopicEnvelope[] neutralExperimentalFragments = null) { PrecursorMonoisotopicPeakMz = precursorMonoisotopicPeakMz; PrecursorCharge = precursorCharge; PrecursorMass = PrecursorMonoisotopicPeakMz.ToMass(precursorCharge); FullFilePath = fullFilePath; ChildScans = new List <Ms2ScanWithSpecificMass>(); NativeId = mzLibScan.NativeId; TheScan = mzLibScan; ExperimentalFragments = neutralExperimentalFragments ?? GetNeutralExperimentalFragments(mzLibScan, commonParam); if (ExperimentalFragments.Any()) { DeconvolutedMonoisotopicMasses = ExperimentalFragments.Select(p => p.monoisotopicMass).ToArray(); } else { DeconvolutedMonoisotopicMasses = new double[0]; } }
public ProteinParsimonyEngine(List <PeptideSpectralMatch> allPsms, bool modPeptidesAreDifferent, CommonParameters commonParameters, List <string> nestedIds) : base(commonParameters, nestedIds) { _treatModPeptidesAsDifferentPeptides = modPeptidesAreDifferent; if (!allPsms.Any()) { _fdrFilteredPsms = new List <PeptideSpectralMatch>(); } // parsimony will only use non-ambiguous, high-confidence PSMs // KEEP decoys and contaminants for use in parsimony! if (modPeptidesAreDifferent) { _fdrFilteredPsms = allPsms.Where(p => p.FullSequence != null && p.FdrInfo.QValue <= FdrCutoffForParsimony && p.FdrInfo.QValueNotch <= FdrCutoffForParsimony).ToList(); } else { _fdrFilteredPsms = allPsms.Where(p => p.BaseSequence != null && p.FdrInfo.QValue <= FdrCutoffForParsimony && p.FdrInfo.QValueNotch <= FdrCutoffForParsimony).ToList(); } // if PSM is a decoy, add only decoy sequences; same for contaminants // peptides to use in parsimony = peptides observed in high-confidence PSMs _fdrFilteredPeptides = new HashSet <PeptideWithSetModifications>(); foreach (var psm in _fdrFilteredPsms) { if (psm.IsDecoy) { foreach (var peptide in psm.BestMatchingPeptides.Select(p => p.Peptide).Where(p => p.Protein.IsDecoy)) { _fdrFilteredPeptides.Add(peptide); } } else if (psm.IsContaminant) { foreach (var peptide in psm.BestMatchingPeptides.Select(p => p.Peptide).Where(p => p.Protein.IsContaminant)) { _fdrFilteredPeptides.Add(peptide); } } else // PSM is target { foreach (var peptide in psm.BestMatchingPeptides.Select(p => p.Peptide).Where(p => !p.Protein.IsDecoy && !p.Protein.IsContaminant)) { _fdrFilteredPeptides.Add(peptide); } } } // we're storing all PSMs (not just FDR-filtered ones) here because we will remove some protein associations // from low-confidence PSMs if they can be explained by a parsimonious protein _allPsms = allPsms; }
/// <summary> /// Calculates the spectral angle, as described by Prosit ( https://www.nature.com/articles/s41592-019-0426-7 ). /// </summary> public static double CalculateNormalizedSpectralAngle(List <MatchedFragmentIon> theoreticalLibraryIons, MsDataScan scan, CommonParameters commonParameters) { double mzCutoff = 300; int fragmentNumberCutoff = 3; // if the spectrum has no peaks if (scan.MassSpectrum.XArray.Length == 0) { return(0); } Dictionary <MatchedFragmentIon, MatchedFragmentIon> matchedIons = new Dictionary <MatchedFragmentIon, MatchedFragmentIon>(); // search for each theoretical ion for (int i = 0; i < theoreticalLibraryIons.Count; i++) { var libraryIon = theoreticalLibraryIons[i]; // see https://www.nature.com/articles/s41592-019-0426-7 // "All non-zero fragment ions (m/z > 300, ion >3, no neutral loss fragment ions) were considered for spectral angle calculation" if (libraryIon.Mz <= mzCutoff || libraryIon.NeutralTheoreticalProduct.FragmentNumber <= fragmentNumberCutoff) { continue; } // get the closest peak in the spectrum to the library peak var closestPeakIndex = scan.MassSpectrum.GetClosestPeakIndex(libraryIon.Mz); double mz = scan.MassSpectrum.XArray[closestPeakIndex]; double experimentalIntensity = scan.MassSpectrum.YArray[closestPeakIndex]; // is the mass error acceptable? if (commonParameters.ProductMassTolerance.Within(mz.ToMass(libraryIon.Charge), libraryIon.Mz.ToMass(libraryIon.Charge))) { var test = new Product(libraryIon.NeutralTheoreticalProduct.ProductType, libraryIon.NeutralTheoreticalProduct.Terminus, libraryIon.NeutralTheoreticalProduct.NeutralMass, libraryIon.NeutralTheoreticalProduct.FragmentNumber, libraryIon.NeutralTheoreticalProduct.AminoAcidPosition, libraryIon.NeutralTheoreticalProduct.NeutralLoss); matchedIons.Add(libraryIon, new MatchedFragmentIon(ref test, mz, experimentalIntensity, libraryIon.Charge)); } } // L2 norm double expNormalizer = Math.Sqrt(matchedIons.Sum(p => Math.Pow(p.Value.Intensity, 2))); double theorNormalizer = Math.Sqrt(theoreticalLibraryIons.Sum(p => Math.Pow(p.Intensity, 2))); double dotProduct = 0; foreach (var libraryIon in theoreticalLibraryIons) { if (matchedIons.TryGetValue(libraryIon, out var experIon)) { dotProduct += (libraryIon.Intensity / theorNormalizer) * (experIon.Intensity / expNormalizer); } } double normalizedSpectralAngle = 1 - (2 * Math.Acos(dotProduct) / Math.PI); return(normalizedSpectralAngle); }
public SequencesToActualProteinPeptidesEngine(List <PeptideSpectralMatch> allPsms, List <Protein> proteinList, List <ModificationWithMass> fixedModifications, List <ModificationWithMass> variableModifications, List <ProductType> ionTypes, IEnumerable <DigestionParams> collectionOfDigestionParams, bool reportAllAmbiguity, CommonParameters commonParameters, List <string> nestedIds) : base(commonParameters, nestedIds) { Proteins = proteinList; AllPsms = allPsms; FixedModifications = fixedModifications; VariableModifications = variableModifications; TerminusType = ProductTypeMethods.IdentifyTerminusType(ionTypes); CollectionOfDigestionParams = collectionOfDigestionParams; ReportAllAmbiguity = reportAllAmbiguity; }
public ProteinParsimonyEngine(List <PeptideSpectralMatch> allPsms, bool modPeptidesAreDifferent, CommonParameters commonParameters, List <(string fileName, CommonParameters fileSpecificParameters)> fileSpecificParameters, List <string> nestedIds) : base(commonParameters, fileSpecificParameters, nestedIds)
public static void CalculateSpectralAngles(SpectralLibrary spectralLibrary, PeptideSpectralMatch[] peptideSpectralMatches, Ms2ScanWithSpecificMass[] arrayOfSortedMs2Scans, CommonParameters commonParameters) { foreach (PeptideSpectralMatch psm in peptideSpectralMatches.Where(p => p != null)) { Ms2ScanWithSpecificMass scan = arrayOfSortedMs2Scans[psm.ScanIndex]; //TODO: spectral angle could be used to disambiguate PSMs. right now for ambiguous PSMs, the spectral angle for only one peptide option is saved foreach (var peptide in psm.PeptidesToMatchingFragments) { if (spectralLibrary == null || !spectralLibrary.TryGetSpectrum(peptide.Key.FullSequence, scan.PrecursorCharge, out var librarySpectrum)) { continue; } double spectralAngle = CalculateNormalizedSpectralAngle(librarySpectrum.MatchedFragmentIons, scan.TheScan, commonParameters); psm.SpectralAngle = spectralAngle; } } }
public static List <MatchedFragmentIon> MatchFragmentIons(MzSpectrum spectrum, List <TheoreticalFragmentIon> theoreticalFragmentIons, CommonParameters commonParameters) { var matchedFragmentIons = new List <MatchedFragmentIon>(); var alreadyCountedMzs = new HashSet <double>(); // if the spectrum has no peaks if (spectrum.Size == 0) { return(matchedFragmentIons); } //search for ions in the spectrum foreach (var tIon in theoreticalFragmentIons) { // unknown fragment mass; this only happens rarely for sequences with unknown amino acids if (double.IsNaN(tIon.Mass)) { continue; } // get the closest peak in the spectrum to the theoretical peak int matchedPeakIndex = spectrum.GetClosestPeakIndex(tIon.Mz).Value; double mz = spectrum.XArray[matchedPeakIndex]; double intensity = spectrum.YArray[matchedPeakIndex]; // is the mass error acceptable and has it been counted already? if (commonParameters.ProductMassTolerance.Within(mz.ToMass(tIon.Charge), tIon.Mass) && !alreadyCountedMzs.Contains(mz)) { matchedFragmentIons.Add(new MatchedFragmentIon(tIon, mz, intensity)); alreadyCountedMzs.Add(mz); } } return(matchedFragmentIons); }
protected MetaMorpheusEngine(CommonParameters commonParameters, List <string> nestedIds) { this.commonParameters = commonParameters; this.nestedIds = nestedIds; }
public static void CalculateSpectralAngles(SpectralLibrary spectralLibrary, PeptideSpectralMatch[] psms, Ms2ScanWithSpecificMass[] arrayOfSortedMs2Scans, CommonParameters commonParameters) { if (spectralLibrary != null) { // one lock for each MS2 scan; a scan can only be accessed by one thread at a time var myLocks = new object[psms.Length]; for (int i = 0; i < myLocks.Length; i++) { myLocks[i] = new object(); } int maxThreadsPerFile = commonParameters.MaxThreadsToUsePerFile; int[] threads = Enumerable.Range(0, maxThreadsPerFile).ToArray(); Parallel.ForEach(threads, (i) => { // Stop loop if canceled if (GlobalVariables.StopLoops) { return; } for (; i < psms.Length; i += maxThreadsPerFile) { lock (myLocks[i]) { if (psms[i] != null) { Ms2ScanWithSpecificMass scan = arrayOfSortedMs2Scans[psms[i].ScanIndex]; List <(int, PeptideWithSetModifications)> pwsms = new(); List <double> pwsmSpectralAngles = new(); foreach (var(Notch, Peptide) in psms[i].BestMatchingPeptides) { //if peptide is target, directly look for the target's spectrum in the spectral library if (!Peptide.Protein.IsDecoy && spectralLibrary.TryGetSpectrum(Peptide.FullSequence, scan.PrecursorCharge, out var librarySpectrum)) { SpectralSimilarity s = new SpectralSimilarity(scan.TheScan.MassSpectrum, librarySpectrum.XArray, librarySpectrum.YArray, SpectralSimilarity.SpectrumNormalizationScheme.squareRootSpectrumSum, commonParameters.ProductMassTolerance.Value, false); if (s.SpectralContrastAngle().HasValue) { pwsms.Add((Notch, Peptide)); pwsmSpectralAngles.Add((double)s.SpectralContrastAngle()); } } //if peptide is decoy, look for the decoy's corresponding target's spectrum in the spectral library and generate decoy spectrum by function GetDecoyLibrarySpectrumFromTargetByRevers else if (Peptide.Protein.IsDecoy && spectralLibrary.TryGetSpectrum(Peptide.PeptideDescription, scan.PrecursorCharge, out var targetlibrarySpectrum)) { var decoyPeptideTheorProducts = new List <Product>(); Peptide.Fragment(commonParameters.DissociationType, commonParameters.DigestionParams.FragmentationTerminus, decoyPeptideTheorProducts); var decoylibrarySpectrum = GetDecoyLibrarySpectrumFromTargetByReverse(targetlibrarySpectrum, decoyPeptideTheorProducts); SpectralSimilarity s = new SpectralSimilarity(scan.TheScan.MassSpectrum, decoylibrarySpectrum.Select(x => x.Mz).ToArray(), decoylibrarySpectrum.Select(x => x.Intensity).ToArray(), SpectralSimilarity.SpectrumNormalizationScheme.squareRootSpectrumSum, commonParameters.ProductMassTolerance.Value, false); if (s.SpectralContrastAngle().HasValue) { pwsms.Add((Notch, Peptide)); pwsmSpectralAngles.Add((double)s.SpectralContrastAngle()); } } } if (pwsmSpectralAngles.Count > 0 && !pwsmSpectralAngles.Max().Equals(null)) { psms[i].SpectralAngle = pwsmSpectralAngles.Max(); } else { psms[i].SpectralAngle = -1; } } }
public ProteinParsimonyEngine(Dictionary <CompactPeptideBase, HashSet <PeptideWithSetModifications> > compactPeptideToProteinPeptideMatching, bool modPeptidesAreDifferent, CommonParameters commonParameters, List <string> nestedIds) : base(commonParameters, nestedIds) { TreatModPeptidesAsDifferentPeptides = modPeptidesAreDifferent; CompactPeptideToProteinPeptideMatching = compactPeptideToProteinPeptideMatching; ListOfDigestionParams = new HashSet <DigestionParams>(compactPeptideToProteinPeptideMatching.Values.SelectMany(p => p.Select(v => v.DigestionParams))); }
public static List <MatchedFragmentIon> MatchFragmentIons(Ms2ScanWithSpecificMass scan, List <Product> theoreticalProducts, CommonParameters commonParameters) { var matchedFragmentIons = new List <MatchedFragmentIon>(); // if the spectrum has no peaks if (!scan.ExperimentalFragments.Any()) { return(matchedFragmentIons); } if (scan.TheScan.MassSpectrum.XcorrProcessed) { foreach (Product product in theoreticalProducts) { // unknown fragment mass; this only happens rarely for sequences with unknown amino acids if (double.IsNaN(product.NeutralMass)) { continue; } double theoreticalFragmentMz = Math.Round(product.NeutralMass.ToMz(1) / 1.0005079, 0) * 1.0005079; var closestMzIndex = scan.TheScan.MassSpectrum.GetClosestPeakIndex(theoreticalFragmentMz).Value; if (commonParameters.ProductMassTolerance.Within(scan.TheScan.MassSpectrum.XArray[closestMzIndex], theoreticalFragmentMz)) { matchedFragmentIons.Add(new MatchedFragmentIon(product, theoreticalFragmentMz, scan.TheScan.MassSpectrum.YArray[closestMzIndex], 1)); } } return(matchedFragmentIons); } // search for ions in the spectrum foreach (Product product in theoreticalProducts) { // unknown fragment mass; this only happens rarely for sequences with unknown amino acids if (double.IsNaN(product.NeutralMass)) { continue; } // get the closest peak in the spectrum to the theoretical peak var closestExperimentalMass = scan.GetClosestExperimentalFragmentMass(product.NeutralMass); // is the mass error acceptable? if (commonParameters.ProductMassTolerance.Within(closestExperimentalMass.monoisotopicMass, product.NeutralMass) && closestExperimentalMass.charge <= scan.PrecursorCharge) { matchedFragmentIons.Add(new MatchedFragmentIon(product, closestExperimentalMass.monoisotopicMass.ToMz(closestExperimentalMass.charge), closestExperimentalMass.peaks.First().intensity, closestExperimentalMass.charge)); } } if (commonParameters.AddCompIons) { double protonMassShift = complementaryIonConversionDictionary[commonParameters.DissociationType].ToMass(1); foreach (Product product in theoreticalProducts) { // unknown fragment mass or diagnostic ion or precursor; skip those if (double.IsNaN(product.NeutralMass) || product.ProductType == ProductType.D || product.ProductType == ProductType.M) { continue; } double compIonMass = scan.PrecursorMass + protonMassShift - product.NeutralMass; // get the closest peak in the spectrum to the theoretical peak var closestExperimentalMass = scan.GetClosestExperimentalFragmentMass(compIonMass); // is the mass error acceptable? if (commonParameters.ProductMassTolerance.Within(closestExperimentalMass.monoisotopicMass, compIonMass) && closestExperimentalMass.charge <= scan.PrecursorCharge) { matchedFragmentIons.Add(new MatchedFragmentIon(product, closestExperimentalMass.monoisotopicMass.ToMz(closestExperimentalMass.charge), closestExperimentalMass.totalIntensity, closestExperimentalMass.charge)); } } } return(matchedFragmentIons); }