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(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); }
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; } } }