diff --git a/CMD/CMD.csproj b/CMD/CMD.csproj index fe7829cec..eb818e068 100644 --- a/CMD/CMD.csproj +++ b/CMD/CMD.csproj @@ -23,7 +23,7 @@ - + diff --git a/Dockerfile b/Dockerfile index 408506c37..3b1eda923 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,4 +11,4 @@ RUN apk add --no-cache bash RUN apk add --no-cache procps ## Set the entrypoint of the Docker image to CMD.dll -ENTRYPOINT ["dotnet", "/metamorpheus/CMD.dll"] +ENTRYPOINT ["dotnet", "/metamorpheus/CMD.dll"] \ No newline at end of file diff --git a/Dockerfile_WindowsInstaller b/Dockerfile_WindowsInstaller index 893a68480..dcb4688d8 100644 --- a/Dockerfile_WindowsInstaller +++ b/Dockerfile_WindowsInstaller @@ -5,4 +5,4 @@ FROM mcr.microsoft.com/dotnet/runtime:5.0-nanoserver-1809 ADD /InstalledFiles/ /metamorpheus/ ## Set the entrypoint of the Docker image to CMD.exe -ENTRYPOINT ["/metamorpheus/CMD.exe"] +ENTRYPOINT ["/metamorpheus/CMD.exe"] \ No newline at end of file diff --git a/EngineLayer/ClassicSearch/ClassicSearchEngine.cs b/EngineLayer/ClassicSearch/ClassicSearchEngine.cs index 2eee0740e..2bdd0cf29 100644 --- a/EngineLayer/ClassicSearch/ClassicSearchEngine.cs +++ b/EngineLayer/ClassicSearch/ClassicSearchEngine.cs @@ -22,11 +22,12 @@ public class ClassicSearchEngine : MetaMorpheusEngine private readonly PeptideSpectralMatch[] PeptideSpectralMatches; private readonly Ms2ScanWithSpecificMass[] ArrayOfSortedMS2Scans; private readonly double[] MyScanPrecursorMasses; + private readonly bool WriteSpectralLibrary; public ClassicSearchEngine(PeptideSpectralMatch[] globalPsms, Ms2ScanWithSpecificMass[] arrayOfSortedMS2Scans, List variableModifications, List fixedModifications, List silacLabels, SilacLabel startLabel, SilacLabel endLabel, List proteinList, MassDiffAcceptor searchMode, CommonParameters commonParameters, List<(string FileName, CommonParameters Parameters)> fileSpecificParameters, - SpectralLibrary spectralLibrary, List nestedIds) + SpectralLibrary spectralLibrary, List nestedIds, bool writeSpectralLibrary) : base(commonParameters, fileSpecificParameters, nestedIds) { PeptideSpectralMatches = globalPsms; @@ -39,9 +40,16 @@ public ClassicSearchEngine(PeptideSpectralMatch[] globalPsms, Ms2ScanWithSpecifi { TurnoverLabels = (startLabel, endLabel); } - Proteins = proteinList; + SearchMode = searchMode; SpectralLibrary = spectralLibrary; + WriteSpectralLibrary = writeSpectralLibrary; + + // if we're doing a spectral library search, we can skip the reverse protein decoys generated by metamorpheus. + // we will generate reverse peptide decoys w/ in the code just below this (and calculate spectral angles for them later). + // we have to generate the reverse peptides instead of the usual reverse proteins because we generate decoy spectral + // library spectra from their corresponding paired target peptides + Proteins = spectralLibrary == null ? proteinList : proteinList.Where(p => !p.IsDecoy).ToList(); } protected override MetaMorpheusEngineResults RunSpecific() @@ -66,19 +74,22 @@ protected override MetaMorpheusEngineResults RunSpecific() int[] threads = Enumerable.Range(0, maxThreadsPerFile).ToArray(); Parallel.ForEach(threads, (i) => { - var fragmentsForDissociationTypes = new Dictionary>(); + var targetFragmentsForEachDissociationType = new Dictionary>(); + var decoyFragmentsForEachDissociationType = new Dictionary>(); // check if we're supposed to autodetect dissociation type from the scan header or not if (CommonParameters.DissociationType == DissociationType.Autodetect) { foreach (var item in GlobalVariables.AllSupportedDissociationTypes.Where(p => p.Value != DissociationType.Autodetect)) { - fragmentsForDissociationTypes.Add(item.Value, new List()); + targetFragmentsForEachDissociationType.Add(item.Value, new List()); + decoyFragmentsForEachDissociationType.Add(item.Value, new List()); } } else { - fragmentsForDissociationTypes.Add(CommonParameters.DissociationType, new List()); + targetFragmentsForEachDissociationType.Add(CommonParameters.DissociationType, new List()); + decoyFragmentsForEachDissociationType.Add(CommonParameters.DissociationType, new List()); } for (; i < Proteins.Count; i += maxThreadsPerFile) @@ -89,22 +100,28 @@ protected override MetaMorpheusEngineResults RunSpecific() // digest each protein into peptides and search for each peptide in all spectra within precursor mass tolerance foreach (PeptideWithSetModifications peptide in Proteins[i].Digest(CommonParameters.DigestionParams, FixedModifications, VariableModifications, SilacLabels, TurnoverLabels)) { - foreach (var fragmentSet in fragmentsForDissociationTypes) + PeptideWithSetModifications reversedOnTheFlyDecoy = null; + + if (SpectralLibrary != null) + { + int[] newAAlocations = new int[peptide.BaseSequence.Length]; + reversedOnTheFlyDecoy = peptide.GetReverseDecoyFromTarget(newAAlocations); + } + + // clear fragments from the last peptide + foreach (var fragmentSet in targetFragmentsForEachDissociationType) { fragmentSet.Value.Clear(); + decoyFragmentsForEachDissociationType[fragmentSet.Key].Clear(); } + // score each scan that has an acceptable precursor mass foreach (ScanWithIndexAndNotchInfo scan in GetAcceptableScans(peptide.MonoisotopicMass, SearchMode)) { - if (SpectralLibrary != null && !SpectralLibrary.ContainsSpectrum(peptide.FullSequence, scan.TheScan.PrecursorCharge)) - { - continue; - } - var dissociationType = CommonParameters.DissociationType == DissociationType.Autodetect ? scan.TheScan.TheScan.DissociationType.Value : CommonParameters.DissociationType; - if (!fragmentsForDissociationTypes.TryGetValue(dissociationType, out var peptideTheorProducts)) + if (!targetFragmentsForEachDissociationType.TryGetValue(dissociationType, out var peptideTheorProducts)) { //TODO: print some kind of warning here. the scan header dissociation type was unknown continue; @@ -116,32 +133,19 @@ protected override MetaMorpheusEngineResults RunSpecific() peptide.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); } - List matchedIons = MatchFragmentIons(scan.TheScan, peptideTheorProducts, CommonParameters); + // match theoretical target ions to spectrum + List matchedIons = MatchFragmentIons(scan.TheScan, peptideTheorProducts, CommonParameters, + matchAllCharges: WriteSpectralLibrary); - double thisScore = CalculatePeptideScore(scan.TheScan.TheScan, matchedIons); - bool meetsScoreCutoff = thisScore >= CommonParameters.ScoreCutoff; + // calculate the peptide's score + double thisScore = CalculatePeptideScore(scan.TheScan.TheScan, matchedIons, fragmentsCanHaveDifferentCharges: WriteSpectralLibrary); - // this is thread-safe because even if the score improves from another thread writing to this PSM, - // the lock combined with AddOrReplace method will ensure thread safety - if (meetsScoreCutoff) + AddPeptideCandidateToPsm(scan, myLocks, thisScore, peptide, matchedIons); + + + if (SpectralLibrary != null) { - // valid hit (met the cutoff score); lock the scan to prevent other threads from accessing it - lock (myLocks[scan.ScanIndex]) - { - bool scoreImprovement = PeptideSpectralMatches[scan.ScanIndex] == null || (thisScore - PeptideSpectralMatches[scan.ScanIndex].RunnerUpScore) > -PeptideSpectralMatch.ToleranceForScoreDifferentiation; - - if (scoreImprovement) - { - if (PeptideSpectralMatches[scan.ScanIndex] == null) - { - PeptideSpectralMatches[scan.ScanIndex] = new PeptideSpectralMatch(peptide, scan.Notch, thisScore, scan.ScanIndex, scan.TheScan, CommonParameters, matchedIons, 0); - } - else - { - PeptideSpectralMatches[scan.ScanIndex].AddOrReplace(peptide, thisScore, scan.Notch, CommonParameters.ReportAllAmbiguity, matchedIons, 0); - } - } - } + DecoyScoreForSpectralLibrarySearch(scan, reversedOnTheFlyDecoy, decoyFragmentsForEachDissociationType,dissociationType, myLocks); } } } @@ -167,6 +171,54 @@ protected override MetaMorpheusEngineResults RunSpecific() return new MetaMorpheusEngineResults(this); } + private void DecoyScoreForSpectralLibrarySearch(ScanWithIndexAndNotchInfo scan,PeptideWithSetModifications reversedOnTheFlyDecoy, Dictionary> decoyFragmentsForEachDissociationType, DissociationType dissociationType,object[] myLocks) + { + // match decoy ions for decoy-on-the-fly + var decoyTheoreticalFragments = decoyFragmentsForEachDissociationType[dissociationType]; + + if (decoyTheoreticalFragments.Count == 0) + { + reversedOnTheFlyDecoy.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, decoyTheoreticalFragments); + } + + var decoyMatchedIons = MatchFragmentIons(scan.TheScan, decoyTheoreticalFragments, CommonParameters, + matchAllCharges: WriteSpectralLibrary); + + // calculate decoy's score + var decoyScore = CalculatePeptideScore(scan.TheScan.TheScan, decoyMatchedIons, fragmentsCanHaveDifferentCharges: WriteSpectralLibrary); + + AddPeptideCandidateToPsm(scan, myLocks, decoyScore, reversedOnTheFlyDecoy, decoyMatchedIons); + } + + + private void AddPeptideCandidateToPsm(ScanWithIndexAndNotchInfo scan, object[] myLocks, double thisScore, PeptideWithSetModifications peptide, List matchedIons) + { + bool meetsScoreCutoff = thisScore >= CommonParameters.ScoreCutoff; + + // this is thread-safe because even if the score improves from another thread writing to this PSM, + // the lock combined with AddOrReplace method will ensure thread safety + if (meetsScoreCutoff) + { + // valid hit (met the cutoff score); lock the scan to prevent other threads from accessing it + lock (myLocks[scan.ScanIndex]) + { + bool scoreImprovement = PeptideSpectralMatches[scan.ScanIndex] == null || (thisScore - PeptideSpectralMatches[scan.ScanIndex].RunnerUpScore) > -PeptideSpectralMatch.ToleranceForScoreDifferentiation; + + if (scoreImprovement) + { + if (PeptideSpectralMatches[scan.ScanIndex] == null) + { + PeptideSpectralMatches[scan.ScanIndex] = new PeptideSpectralMatch(peptide, scan.Notch, thisScore, scan.ScanIndex, scan.TheScan, CommonParameters, matchedIons, 0); + } + else + { + PeptideSpectralMatches[scan.ScanIndex].AddOrReplace(peptide, thisScore, scan.Notch, CommonParameters.ReportAllAmbiguity, matchedIons, 0); + } + } + } + } + } + private IEnumerable GetAcceptableScans(double peptideMonoisotopicMass, MassDiffAcceptor searchMode) { foreach (AllowedIntervalWithNotch allowedIntervalWithNotch in searchMode.GetAllowedPrecursorMassIntervalsFromTheoreticalMass(peptideMonoisotopicMass).ToList()) diff --git a/EngineLayer/EngineLayer.csproj b/EngineLayer/EngineLayer.csproj index 763aad022..b1cc962e3 100644 --- a/EngineLayer/EngineLayer.csproj +++ b/EngineLayer/EngineLayer.csproj @@ -20,7 +20,7 @@ - + diff --git a/EngineLayer/MetaMorpheusEngine.cs b/EngineLayer/MetaMorpheusEngine.cs index 13b0e0c88..5c41141ce 100644 --- a/EngineLayer/MetaMorpheusEngine.cs +++ b/EngineLayer/MetaMorpheusEngine.cs @@ -2,10 +2,13 @@ using MassSpectrometry; using MzLibUtil; using Proteomics.Fragmentation; +using Proteomics.ProteolyticDigestion; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; namespace EngineLayer { @@ -42,8 +45,13 @@ protected MetaMorpheusEngine(CommonParameters commonParameters, List<(string Fil public static event EventHandler OutProgressHandler; - public static double CalculatePeptideScore(MsDataScan thisScan, List matchedFragmentIons) + public static double CalculatePeptideScore(MsDataScan thisScan, List matchedFragmentIons, bool fragmentsCanHaveDifferentCharges = false) { + if(fragmentsCanHaveDifferentCharges) + { + return CalculateAllChargesPeptideScore(thisScan, matchedFragmentIons); + } + double score = 0; if (thisScan.MassSpectrum.XcorrProcessed) @@ -80,8 +88,44 @@ public static double CalculatePeptideScore(MsDataScan thisScan, List MatchFragmentIons(Ms2ScanWithSpecificMass scan, List theoreticalProducts, CommonParameters commonParameters) + //Used only when user wants to generate spectral library. + //Normal search only looks for one match ion for one fragment, and if it accepts it then it doesn't try to look for different charge states of that same fragment. + //The score will be the number of matched ions and plus some fraction calculated by intensity(matchedFragmentIons[i].Intensity / thisScan.TotalIonCurrent). + //Like b1, b2, b3 will have score 3.xxx;But when generating library, we need look for match ions with all charges.So we will have b1,b2,b3, b1^2, b2^3. If using + //the normal scoring function, the score will be 5.xxxx, which is not proper. The score for b1 and b1^2 should also be 1 plus some some fraction calculated by intensity, + //because they are matching the same fragment ion just with different charges. So b1, b2, b3, b1^2, b2^3 should be also 3.xxx(but a little higher than b1, b2, b3 as + //the fraction part) rather than 5.xxx. + private static double CalculateAllChargesPeptideScore(MsDataScan thisScan, List matchedFragmentIons) + { + double score = 0; + + // Morpheus score + List ions = new List(); + for (int i = 0; i < matchedFragmentIons.Count; i++) + { + String ion = $"{ matchedFragmentIons[i].NeutralTheoreticalProduct.ProductType.ToString()}{ matchedFragmentIons[i].NeutralTheoreticalProduct.FragmentNumber}"; + if (ions.Contains(ion)) + { + score += matchedFragmentIons[i].Intensity / thisScan.TotalIonCurrent; + } + else + { + score += 1 + matchedFragmentIons[i].Intensity / thisScan.TotalIonCurrent; + ions.Add(ion); + } + } + + return score; + + } + + public static List MatchFragmentIons(Ms2ScanWithSpecificMass scan, List theoreticalProducts, CommonParameters commonParameters, bool matchAllCharges = false) { + if (matchAllCharges) + { + return MatchFragmentIonsOfAllCharges(scan, theoreticalProducts, commonParameters); + } + var matchedFragmentIons = new List(); if (scan.TheScan.MassSpectrum.XcorrProcessed && scan.TheScan.MassSpectrum.XArray.Length != 0) @@ -172,6 +216,53 @@ public static List MatchFragmentIons(Ms2ScanWithSpecificMass return matchedFragmentIons; } + //Used only when user wants to generate spectral library. + //Normal search only looks for one match ion for one fragment, and if it accepts it then it doesn't try to look for different charge states of that same fragment. + //But for library generation, we need find all the matched peaks with all the different charges. + private static List MatchFragmentIonsOfAllCharges(Ms2ScanWithSpecificMass scan, List theoreticalProducts, CommonParameters commonParameters) + { + var matchedFragmentIons = new List(); + var ions = new List(); + + // if the spectrum has no peaks + if (scan.ExperimentalFragments != null && !scan.ExperimentalFragments.Any()) + { + 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 range we can accept + var minMass = commonParameters.ProductMassTolerance.GetMinimumValue(product.NeutralMass); + var maxMass = commonParameters.ProductMassTolerance.GetMaximumValue(product.NeutralMass); + var closestExperimentalMassList = scan.GetClosestExperimentalIsotopicEnvelopeList(minMass, maxMass); + if (closestExperimentalMassList != null) + { + foreach (var x in closestExperimentalMassList) + { + String ion = $"{product.ProductType.ToString()}{ product.FragmentNumber}^{x.Charge}-{product.NeutralLoss}"; + if (x != null && !ions.Contains(ion) && commonParameters.ProductMassTolerance.Within(x.MonoisotopicMass, product.NeutralMass) && x.Charge <= scan.PrecursorCharge)//TODO apply this filter before picking the envelope + { + Product temProduct = product; + matchedFragmentIons.Add(new MatchedFragmentIon(ref temProduct, x.MonoisotopicMass.ToMz(x.Charge), + x.Peaks.First().intensity, x.Charge)); + + ions.Add(ion); + } + } + } + } + + return matchedFragmentIons; + } + public MetaMorpheusEngineResults Run() { StartingSingleEngine(); diff --git a/EngineLayer/Ms2ScanWithSpecificMass.cs b/EngineLayer/Ms2ScanWithSpecificMass.cs index 87818fd8d..4e0d8f4c4 100644 --- a/EngineLayer/Ms2ScanWithSpecificMass.cs +++ b/EngineLayer/Ms2ScanWithSpecificMass.cs @@ -114,6 +114,45 @@ public int GetClosestFragmentMass(double mass) return index - 1; } + //look for IsotopicEnvelopes which are in the range of acceptable mass + public IsotopicEnvelope[] GetClosestExperimentalIsotopicEnvelopeList(double minimumMass, double maxMass) + { + + if (DeconvolutedMonoisotopicMasses.Length == 0) + { + return null; + } + + //if no mass is in this range, then return null + if (DeconvolutedMonoisotopicMasses[0] > maxMass || DeconvolutedMonoisotopicMasses.Last() < minimumMass) + { + return null; + } + + int startIndex = GetClosestFragmentMass(minimumMass); + int endIndex = GetClosestFragmentMass(maxMass); + + //the index we get from GetClosestFragmentMass is the closest mass, while the acceptable mass we need is between minimumMass and maxMass + //so the startIndex mass is supposed to be larger than minimumMass, if not , then startIndex increases by 1; + //the endIndex mass is supposed to be smaller than maxMass, if not , then endIndex decreases by 1; + if (DeconvolutedMonoisotopicMasses[startIndex] maxMass) + { + endIndex = endIndex - 1; + } + int length = endIndex - startIndex + 1; + + if (length < 1) + { + return null; + } + IsotopicEnvelope[] isotopicEnvelopes = ExperimentalFragments.Skip(startIndex).Take(length).ToArray(); + return isotopicEnvelopes; + } + public double? GetClosestExperimentalFragmentMz(double theoreticalMz, out double? intensity) { if (TheScan.MassSpectrum.XArray.Length == 0) diff --git a/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs b/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs index a3fd04cc3..cae87de43 100644 --- a/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs +++ b/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs @@ -73,7 +73,6 @@ public static double CalculateNormalizedSpectralAngle(List t 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)); } } diff --git a/GUI/GUI.csproj b/GUI/GUI.csproj index 2ab3d4b22..b164dbbfb 100644 --- a/GUI/GUI.csproj +++ b/GUI/GUI.csproj @@ -55,7 +55,7 @@ - + diff --git a/GUI/TaskWindows/SearchTaskWindow.xaml b/GUI/TaskWindows/SearchTaskWindow.xaml index abbf59cad..169429466 100644 --- a/GUI/TaskWindows/SearchTaskWindow.xaml +++ b/GUI/TaskWindows/SearchTaskWindow.xaml @@ -449,6 +449,7 @@ + diff --git a/GUI/TaskWindows/SearchTaskWindow.xaml.cs b/GUI/TaskWindows/SearchTaskWindow.xaml.cs index 0d038676e..563d27f8e 100644 --- a/GUI/TaskWindows/SearchTaskWindow.xaml.cs +++ b/GUI/TaskWindows/SearchTaskWindow.xaml.cs @@ -303,6 +303,7 @@ private void UpdateFieldsFromTask(SearchTask task) WriteDecoyCheckBox.IsChecked = task.SearchParameters.WriteDecoys; WriteContaminantCheckBox.IsChecked = task.SearchParameters.WriteContaminants; WriteIndividualResultsCheckBox.IsChecked = task.SearchParameters.WriteIndividualFiles; + WriteSpectralLibraryCheckBox.IsChecked = task.SearchParameters.WriteSpectralLibrary; CompressIndividualResultsCheckBox.IsChecked = task.SearchParameters.CompressIndividualFiles; IncludeMotifInModNamesCheckBox.IsChecked = task.SearchParameters.IncludeModMotifInMzid; @@ -577,6 +578,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) TheTask.SearchParameters.WriteDecoys = WriteDecoyCheckBox.IsChecked.Value; TheTask.SearchParameters.WriteContaminants = WriteContaminantCheckBox.IsChecked.Value; TheTask.SearchParameters.WriteIndividualFiles = WriteIndividualResultsCheckBox.IsChecked.Value; + TheTask.SearchParameters.WriteSpectralLibrary = WriteSpectralLibraryCheckBox.IsChecked.Value; TheTask.SearchParameters.CompressIndividualFiles = CompressIndividualResultsCheckBox.IsChecked.Value; TheTask.SearchParameters.IncludeModMotifInMzid = IncludeMotifInModNamesCheckBox.IsChecked.Value; diff --git a/GuiFunctions/GuiFunctions.csproj b/GuiFunctions/GuiFunctions.csproj index a6af21514..cc4c7c2ad 100644 --- a/GuiFunctions/GuiFunctions.csproj +++ b/GuiFunctions/GuiFunctions.csproj @@ -14,7 +14,7 @@ - + diff --git a/README.md b/README.md index 976e0dea1..4e6e2a266 100644 --- a/README.md +++ b/README.md @@ -146,4 +146,4 @@ metamorpheus -t Task1-SearchTaskconfig.toml Task2-CalibrateTaskconfig.toml Task3 * [Global Identification of Protein Post-translational Modifications in a Single-Pass Database Search--J. Proteome Res., 2015, 14 (11), pp 4714–4720](http://pubs.acs.org/doi/abs/10.1021/acs.jproteome.5b00599) -* [A Proteomics Search Algorithm Specifically Designed for High-Resolution Tandem Mass Spectra--J. Proteome Res., 2013, 12 (3), pp 1377–1386](http://pubs.acs.org/doi/abs/10.1021/pr301024c) +* [A Proteomics Search Algorithm Specifically Designed for High-Resolution Tandem Mass Spectra--J. Proteome Res., 2013, 12 (3), pp 1377–1386](http://pubs.acs.org/doi/abs/10.1021/pr301024c) \ No newline at end of file diff --git a/TaskLayer/CalibrationTask/CalibrationTask.cs b/TaskLayer/CalibrationTask/CalibrationTask.cs index f7f71c67f..3f5f281d6 100644 --- a/TaskLayer/CalibrationTask/CalibrationTask.cs +++ b/TaskLayer/CalibrationTask/CalibrationTask.cs @@ -266,8 +266,9 @@ private DataPointAquisitionResults GetDataAcquisitionResults(MsDataFile myMsData Log("Searching with searchMode: " + searchMode, new List { taskId, "Individual Spectra Files", fileNameWithoutExtension }); Log("Searching with productMassTolerance: " + initProdTol, new List { taskId, "Individual Spectra Files", fileNameWithoutExtension }); + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, proteinList, searchMode, combinedParameters, - FileSpecificParameters, null, new List { taskId, "Individual Spectra Files", fileNameWithoutExtension }).Run(); + FileSpecificParameters, null, new List { taskId, "Individual Spectra Files", fileNameWithoutExtension }, writeSpectralLibrary).Run(); List allPsms = allPsmsArray.Where(b => b != null).ToList(); allPsms = allPsms.OrderByDescending(b => b.Score) diff --git a/TaskLayer/GPTMDTask/GPTMDTask.cs b/TaskLayer/GPTMDTask/GPTMDTask.cs index 7e7c90898..046e55ef4 100644 --- a/TaskLayer/GPTMDTask/GPTMDTask.cs +++ b/TaskLayer/GPTMDTask/GPTMDTask.cs @@ -98,8 +98,11 @@ protected override MyTaskResults RunSpecific(string OutputFolder, List b.PrecursorMass).ToArray(); myFileManager.DoneWithFile(origDataFile); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[arrayOfMs2ScansSortedByMass.Length]; + + //spectral Library search and library generation have't applied to GPTMD yet + bool writeSpctralLibrary = false; new ClassicSearchEngine(allPsmsArray, arrayOfMs2ScansSortedByMass, variableModifications, fixedModifications, null, null, null, - proteinList, searchMode, combinedParams, this.FileSpecificParameters, null, new List { taskId, "Individual Spectra Files", origDataFile }).Run(); + proteinList, searchMode, combinedParams, this.FileSpecificParameters, null, new List { taskId, "Individual Spectra Files", origDataFile }, writeSpctralLibrary).Run(); allPsms.AddRange(allPsmsArray.Where(p => p != null)); FinishedDataFile(origDataFile, new List { taskId, "Individual Spectra Files", origDataFile }); ReportProgress(new ProgressEventArgs(100, "Done!", new List { taskId, "Individual Spectra Files", origDataFile })); diff --git a/TaskLayer/SearchTask/MzIdentMLWriter.cs b/TaskLayer/SearchTask/MzIdentMLWriter.cs index fc2655fb4..15aee66b4 100644 --- a/TaskLayer/SearchTask/MzIdentMLWriter.cs +++ b/TaskLayer/SearchTask/MzIdentMLWriter.cs @@ -227,7 +227,7 @@ public static void WriteMzIdentMl(IEnumerable psms, Listp!=null)) { _mzid.DataCollection.Inputs.SearchDatabase[database_index] = new mzIdentML110.Generated.SearchDatabaseType() { @@ -252,7 +252,7 @@ public static void WriteMzIdentMl(IEnumerable psms, Listp.DatabaseFilePath!=null)) { _mzid.SequenceCollection.DBSequence[protein_index] = new mzIdentML110.Generated.DBSequenceType { diff --git a/TaskLayer/SearchTask/SearchParameters.cs b/TaskLayer/SearchTask/SearchParameters.cs index 057c6fc70..5e31183f3 100644 --- a/TaskLayer/SearchTask/SearchParameters.cs +++ b/TaskLayer/SearchTask/SearchParameters.cs @@ -84,6 +84,7 @@ public SearchParameters() public bool WriteDecoys { get; set; } public bool WriteContaminants { get; set; } public bool WriteIndividualFiles { get; set; } + public bool WriteSpectralLibrary { get; set; } public bool CompressIndividualFiles { get; set; } public List SilacLabels { get; set; } public SilacLabel StartTurnoverLabel { get; set; } //used for SILAC turnover experiments diff --git a/TaskLayer/SearchTask/SearchTask.cs b/TaskLayer/SearchTask/SearchTask.cs index aa1773ea4..7e90f6db6 100644 --- a/TaskLayer/SearchTask/SearchTask.cs +++ b/TaskLayer/SearchTask/SearchTask.cs @@ -333,7 +333,7 @@ protected override MyTaskResults RunSpecific(string OutputFolder, List - + diff --git a/Test/AddCompIonsTest.cs b/Test/AddCompIonsTest.cs index e6d0d076e..b59b51a42 100644 --- a/Test/AddCompIonsTest.cs +++ b/Test/AddCompIonsTest.cs @@ -47,8 +47,10 @@ public static void TestAddCompIonsClassic() var fsp = new List<(string fileName, CommonParameters fileSpecificParameters)>(); fsp.Add(("", CommonParameters)); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), writeSpectralLibrary).Run(); CommonParameters CommonParameters2 = new CommonParameters( digestionParams: new DigestionParams(protease: protease.Name, maxMissedCleavages: 0, minPeptideLength: 1), @@ -57,8 +59,9 @@ public static void TestAddCompIonsClassic() var fsp2 = new List<(string fileName, CommonParameters fileSpecificParameters)>(); fsp2.Add(("", CommonParameters2)); PeptideSpectralMatch[] allPsmsArray2 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray2, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters2, fsp2, null, new List()).Run(); + proteinList, searchModes, CommonParameters2, fsp2, null, new List(), writeSpectralLibrary).Run(); double scoreT = allPsmsArray2[0].Score; double scoreF = allPsmsArray[0].Score; diff --git a/Test/AmbiguityTest.cs b/Test/AmbiguityTest.cs index f889c5a7f..e9a4ecf29 100644 --- a/Test/AmbiguityTest.cs +++ b/Test/AmbiguityTest.cs @@ -57,10 +57,11 @@ public static void TestResolveAmbiguities() PeptideSpectralMatch[] allPsmsArray_withOutAmbiguity = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray_withAmbiguity, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters_t, fsp_t, null, new List()).Run(); //report all ambiguity TRUE + proteinList, searchModes, CommonParameters_t, fsp_t, null, new List(), writeSpectralLibrary).Run(); //report all ambiguity TRUE new ClassicSearchEngine(allPsmsArray_withOutAmbiguity, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters_f, fsp_f, null, new List()).Run(); //report all ambiguity FALSE + proteinList, searchModes, CommonParameters_f, fsp_f, null, new List(), writeSpectralLibrary).Run(); //report all ambiguity FALSE Assert.AreEqual("QQQ", allPsmsArray_withAmbiguity[0].BaseSequence); Assert.AreEqual("QQQ", allPsmsArray_withOutAmbiguity[0].BaseSequence); diff --git a/Test/CoIsolationTests.cs b/Test/CoIsolationTests.cs index d12bc4f07..caeade9bd 100644 --- a/Test/CoIsolationTests.cs +++ b/Test/CoIsolationTests.cs @@ -61,8 +61,10 @@ public static void TestCoIsolation() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters(deconvolutionIntensityRatio: 50)).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; ; + + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), writeSpectralLibrary).Run(); // Two matches for this single scan! Corresponding to two co-isolated masses Assert.AreEqual(2, allPsmsArray.Length); diff --git a/Test/FdrTest.cs b/Test/FdrTest.cs index 034d06e27..bc3b9e735 100644 --- a/Test/FdrTest.cs +++ b/Test/FdrTest.cs @@ -184,7 +184,7 @@ public static void TestDeltaValues() //check better when using delta PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), SearchParameters.WriteSpectralLibrary).Run(); var indexEngine = new IndexingEngine(proteinList, variableModifications, fixedModifications, null, null, null, 1, DecoyType.None, CommonParameters, fsp, 30000, false, new List(), TargetContaminantAmbiguity.RemoveContaminant, new List()); @@ -235,7 +235,7 @@ public static void TestDeltaValues() //check no change when using delta allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), SearchParameters.WriteSpectralLibrary).Run(); CommonParameters = new CommonParameters(useDeltaScore: true, digestionParams: new DigestionParams(minPeptideLength: 5)); @@ -268,6 +268,7 @@ public static void TestComputePEPValue() var origDataFile = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\TaGe_SA_HeLa_04_subset_longestSeq.mzML"); MyFileManager myFileManager = new MyFileManager(true); CommonParameters CommonParameters = new CommonParameters(digestionParams: new DigestionParams()); + SearchParameters SearchParameters = new SearchParameters(); var fsp = new List<(string fileName, CommonParameters fileSpecificParameters)>(); fsp.Add(("TaGe_SA_HeLa_04_subset_longestSeq.mzML", CommonParameters)); @@ -278,7 +279,7 @@ public static void TestComputePEPValue() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, @"TestData\TaGe_SA_HeLa_04_subset_longestSeq.mzML", CommonParameters).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), SearchParameters.WriteSpectralLibrary).Run(); FdrAnalysisResults fdrResultsClassicDelta = (FdrAnalysisResults)(new FdrAnalysisEngine(allPsmsArray.Where(p => p != null).ToList(), 1, CommonParameters, fsp, new List()).Run()); @@ -475,8 +476,10 @@ public static void TestComputePEPValueTopDown() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, origDataFile, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchMode, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchMode, CommonParameters, fsp, null, new List(), writeSpectralLibrary).Run(); var nonNullPsms = allPsmsArray.Where(p => p != null).ToList(); List moreNonNullPSMs = new List(); @@ -637,8 +640,9 @@ public static void ReplaceBadStdevOne() extendedArray = extendedArray.OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[extendedArray.Length]; + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, extendedArray, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), writeSpectralLibrary).Run(); List nonNullPsms = allPsmsArray.Where(p => p != null).ToList(); nonNullPsms = nonNullPsms.OrderByDescending(p => p.Score).ToList(); @@ -690,8 +694,9 @@ public static void ReplaceBadStdevTwo() extendedArray = extendedArray.OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[extendedArray.Length]; + bool writeSpectralLibrary = false; new ClassicSearchEngine(allPsmsArray, extendedArray, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), writeSpectralLibrary).Run(); List nonNullPsms = allPsmsArray.Where(p => p != null).ToList(); nonNullPsms = nonNullPsms.OrderByDescending(p => p.Score).ToList(); diff --git a/Test/MatchIonsOfAllCharges.cs b/Test/MatchIonsOfAllCharges.cs new file mode 100644 index 000000000..53c4bc1a6 --- /dev/null +++ b/Test/MatchIonsOfAllCharges.cs @@ -0,0 +1,343 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using EngineLayer; +using EngineLayer.ClassicSearch; +using IO.MzML; +using MzLibUtil; +using NUnit.Framework; +using Proteomics; +using Proteomics.Fragmentation; +using Proteomics.ProteolyticDigestion; +using TaskLayer; +using Chemistry; +using System; +using MassSpectrometry; + +namespace Test +{ + [TestFixture] + public class SearchEngineForWritingSpectralLibraryTest + { + [Test] + public static void TestMatchIonsOfAllChargesBottomUp() + { + CommonParameters CommonParameters = new CommonParameters(); + + MetaMorpheusTask.DetermineAnalyteType(CommonParameters); + + var variableModifications = new List(); + var fixedModifications = new List(); + + var proteinList = new List + { + new Protein("AAAHSSLK", ""),new Protein("RQPAQPR", ""),new Protein("EKAEAEAEK", "") + }; + var myMsDataFile = Mzml.LoadAllStaticData(Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\SmallCalibratible_Yeast.mzML")); + + + var searchMode = new SinglePpmAroundZeroSearchMode(5); + + Tolerance DeconvolutionMassTolerance = new PpmTolerance(5); + + var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); + + //search by new method of looking for all charges + PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + + new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), true).Run(); + var psm = allPsmsArray.Where(p => p != null).ToList(); + Assert.That(psm[1].MatchedFragmentIons.Count == 14); + //there are ions with same product type and same fragment number but different charges + Assert.That(psm[1].MatchedFragmentIons[8].NeutralTheoreticalProduct.ProductType == psm[1].MatchedFragmentIons[9].NeutralTheoreticalProduct.ProductType && + psm[1].MatchedFragmentIons[8].NeutralTheoreticalProduct.FragmentNumber == psm[1].MatchedFragmentIons[9].NeutralTheoreticalProduct.FragmentNumber && + psm[1].MatchedFragmentIons[8].Charge != psm[1].MatchedFragmentIons[9].Charge); + Assert.That(psm[2].MatchedFragmentIons.Count == 14); + Assert.That(psm[4].MatchedFragmentIons.Count == 16); + + //search by old method of looking for only one charge + PeptideSpectralMatch[] allPsmsArray_oneCharge = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray_oneCharge, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), false).Run(); + var psm_oneCharge = allPsmsArray_oneCharge.Where(p => p != null).ToList(); + + //compare 2 scores , they should have same integer part but new search has a little higher score than old search + Assert.That(psm[1].Score > psm_oneCharge[1].Score); + Assert.AreEqual(Math.Truncate(psm[1].Score), 12); + Assert.AreEqual(Math.Truncate(psm_oneCharge[1].Score), 12); + + //compare 2 results and evaluate the different matched ions + var peptideTheorProducts = new List(); + Assert.That(psm_oneCharge[1].MatchedFragmentIons.Count == 12); + var differences = psm[1].MatchedFragmentIons.Except(psm_oneCharge[1].MatchedFragmentIons); + psm[1].BestMatchingPeptides.First().Peptide.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); + foreach (var ion in differences) + { + foreach (var product in peptideTheorProducts) + { + if (product.Annotation.ToString().Equals(ion.NeutralTheoreticalProduct.Annotation.ToString())) + { + //to see if the different matched ions are qualified + Assert.That(CommonParameters.ProductMassTolerance.Within(ion.Mz.ToMass(ion.Charge), product.NeutralMass)); + } + } + } + + //test specific condition: unknown fragment mass; this only happens rarely for sequences with unknown amino acids + var myMsDataFile1 = new TestDataFile(); + var variableModifications1 = new List(); + var fixedModifications1 = new List(); + var proteinList1 = new List { new Protein("QXQ", null) }; + var productMassTolerance = new AbsoluteTolerance(0.01); + var searchModes = new OpenSearchMode(); + + Tolerance DeconvolutionMassTolerance1 = new PpmTolerance(5); + + var listOfSortedms2Scans1 = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); + + List motifs = new List { new DigestionMotif("K", null, 1, null) }; + Protease protease = new Protease("Custom Protease3", CleavageSpecificity.Full, null, null, motifs); + ProteaseDictionary.Dictionary.Add(protease.Name, protease); + + CommonParameters CommonParameters1 = new CommonParameters( + digestionParams: new DigestionParams(protease: protease.Name, maxMissedCleavages: 0, minPeptideLength: 1), + scoreCutoff: 1, + addCompIons: false); + var fsp = new List<(string fileName, CommonParameters fileSpecificParameters)>(); + fsp.Add(("", CommonParameters)); + PeptideSpectralMatch[] allPsmsArray1 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + + bool writeSpectralLibrary = true; + new ClassicSearchEngine(allPsmsArray1, listOfSortedms2Scans1, variableModifications1, fixedModifications1, null, null, null, + proteinList1, searchModes, CommonParameters1, fsp, null, new List(), writeSpectralLibrary).Run(); + + var psm1 = allPsmsArray1.Where(p => p != null).ToList(); + Assert.AreEqual(psm1.Count, 222); + } + + [Test] + public static void TestMatchIonsOfAllChargesTopDown() + { + CommonParameters CommonParameters = new CommonParameters( + digestionParams: new DigestionParams(protease: "top-down"), + scoreCutoff: 1, + assumeOrphanPeaksAreZ1Fragments: false); + + MetaMorpheusTask.DetermineAnalyteType(CommonParameters); + + // test output file name (should be proteoform and not peptide) + Assert.That(GlobalVariables.AnalyteType == "Proteoform"); + + var variableModifications = new List(); + var fixedModifications = new List(); + var proteinList = new List + { + new Protein("MPKVYSYQEVAEHNGPENFWIIIDDKVYDVSQFKDEHPGGDEIIMDLGGQDATESFVDIGHSDEALRLLKGLYIGDVDKTSERVSVEKVSTSENQSKGSGTLVVILAILMLGVAYYLLNE", "P40312") + }; + + var myMsDataFile = Mzml.LoadAllStaticData(Path.Combine(TestContext.CurrentContext.TestDirectory, @"TopDownTestData\slicedTDYeast.mzML")); + + var searchMode = new SinglePpmAroundZeroSearchMode(5); + + Tolerance DeconvolutionMassTolerance = new PpmTolerance(5); + + var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); + + //search by new method of looking for all charges + PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), true).Run(); + + var psm = allPsmsArray.Where(p => p != null).FirstOrDefault(); + Assert.That(psm.MatchedFragmentIons.Count == 62); + + + //search by old method of looking for only one charge + PeptideSpectralMatch[] allPsmsArray_oneCharge = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray_oneCharge, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), false).Run(); + + var psm_oneCharge = allPsmsArray_oneCharge.Where(p => p != null).FirstOrDefault(); + Assert.That(psm_oneCharge.MatchedFragmentIons.Count == 47); + + //compare 2 scores , they should have same integer but new search has a little higher score than old search + Assert.That(psm.Score > psm_oneCharge.Score); + Assert.AreEqual(Math.Truncate(psm.Score), 47); + Assert.AreEqual(Math.Truncate(psm_oneCharge.Score), 47); + + //compare 2 results and evaluate the different matched ions + var peptideTheorProducts = new List(); + var differences = psm.MatchedFragmentIons.Except(psm_oneCharge.MatchedFragmentIons); + psm.BestMatchingPeptides.First().Peptide.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); + foreach (var ion in differences) + { + foreach (var product in peptideTheorProducts) + { + if (product.Annotation.ToString().Equals(ion.NeutralTheoreticalProduct.Annotation.ToString())) + { + //to see if the different matched ions are qualified + Assert.That(CommonParameters.ProductMassTolerance.Within(ion.Mz.ToMass(ion.Charge), product.NeutralMass)); + } + } + } + } + + [Test] + public static void TestLookingForAcceptableIsotopicEnvelopes() + { + CommonParameters CommonParameters = new CommonParameters(); + + MetaMorpheusTask.DetermineAnalyteType(CommonParameters); + + var variableModifications = new List(); + var fixedModifications = new List(); + + var proteinList = new List + { + new Protein("AAAHSSLK", ""),new Protein("RQPAQPR", ""),new Protein("EKAEAEAEK", "") + }; + var myMsDataFile = Mzml.LoadAllStaticData(Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\SmallCalibratible_Yeast.mzML")); + + + var searchMode = new SinglePpmAroundZeroSearchMode(5); + + Tolerance DeconvolutionMassTolerance = new PpmTolerance(5); + + var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); + + var ms2ScanTest = listOfSortedms2Scans[0]; + + //test when all the masses are not in the given range + + //test1 when all the masses are too small + var test1 = ms2ScanTest.GetClosestExperimentalIsotopicEnvelopeList(50, 95); + Assert.AreEqual(test1, null); + //test2 when all the masses are too big + var test2 = ms2ScanTest.GetClosestExperimentalIsotopicEnvelopeList(582, 682); + Assert.AreEqual(test2, null); + //test3 when the mass which is bigger than given min mass is bigger than the mass which is smaller than the given max mass + //for example: the mass array is [1,2,3,4,5], the given min mass is 2.2, the given max mass is 2.8 + var test3 = ms2ScanTest.GetClosestExperimentalIsotopicEnvelopeList(110, 111); + Assert.AreEqual(test3, null); + + + //test normal conditions:look for IsotopicEnvelopes which are in the range of acceptable mass + var test4 = ms2ScanTest.GetClosestExperimentalIsotopicEnvelopeList(120, 130); + IsotopicEnvelope[] expected4 = ms2ScanTest.ExperimentalFragments.Skip(15).Take(9).ToArray(); + Assert.That(ms2ScanTest.ExperimentalFragments[15].MonoisotopicMass > 120 && ms2ScanTest.ExperimentalFragments[14].MonoisotopicMass < 120); + Assert.That(ms2ScanTest.ExperimentalFragments[23].MonoisotopicMass < 130 && ms2ScanTest.ExperimentalFragments[24].MonoisotopicMass > 130); + Assert.AreEqual(test4, expected4); + + var test5 = ms2ScanTest.GetClosestExperimentalIsotopicEnvelopeList(400, 500); + IsotopicEnvelope[] expected5 = ms2ScanTest.ExperimentalFragments.Skip(150).Take(7).ToArray(); + Assert.That(ms2ScanTest.ExperimentalFragments[150].MonoisotopicMass > 400 && ms2ScanTest.ExperimentalFragments[149].MonoisotopicMass < 400); + Assert.That(ms2ScanTest.ExperimentalFragments[156].MonoisotopicMass < 500 && ms2ScanTest.ExperimentalFragments[157].MonoisotopicMass > 500); + Assert.AreEqual(test5, expected5); + } + + [Test] + public static void TestReverseDecoyGenerationDuringSearch() + { + CommonParameters CommonParameters = new CommonParameters(); + + MetaMorpheusTask.DetermineAnalyteType(CommonParameters); + + var variableModifications = new List(); + var fixedModifications = new List(); + + var proteinList = new List + { + new Protein ("KKAEDGINK",""),new Protein("AVNSISLK", ""),new Protein("EKAEAEAEK", ""), new Protein("DITANLR",""), new Protein("QNAIGTAK",""), + new Protein("FHKSQLNK",""),new Protein ("KQVAQWNK",""),new Protein ("NTRIEELK",""),new Protein("RQPAQPR", ""), + }; + var myMsDataFile = Mzml.LoadAllStaticData(Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\SmallCalibratible_Yeast.mzML")); + + + var searchMode = new SinglePpmAroundZeroSearchMode(5); + + Tolerance DeconvolutionMassTolerance = new PpmTolerance(5); + + var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); + + + var path = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\myPrositLib.msp"); + + var testLibrary = new SpectralLibrary(new List { path }); + + + + //test when doing spectral library search without generating library + PeptideSpectralMatch[] allPsmsArray1 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray1, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, testLibrary, new List(), false).Run(); + var psm1 = allPsmsArray1.Where(p => p != null).ToList(); + Assert.That(psm1[0].IsDecoy == false && psm1[0].FullSequence == "DITANLR"); + Assert.That(psm1[1].IsDecoy == true && psm1[1].FullSequence == "LSISNVAK"); + Assert.That(psm1[2].IsDecoy == true&& psm1[2].FullSequence == "LSISNVAK"); + Assert.That(psm1[3].IsDecoy == false&& psm1[3].FullSequence == "RQPAQPR"); + Assert.That(psm1[4].IsDecoy == false&& psm1[4].FullSequence == "KKAEDGINK"); + Assert.That(psm1[5].IsDecoy == false&& psm1[5].FullSequence == "EKAEAEAEK"); + Assert.That(psm1[6].IsDecoy == false&& psm1[6].FullSequence == "EKAEAEAEK"); + + + proteinList.Add(new Protein("LSISNVAK", "", isDecoy: true)); + //test when doing spectral library search with generating library; non spectral search won't generate decoy by "decoy on the fly" , so proteinlist used by non spectral library search would contain decoys + PeptideSpectralMatch[] allPsmsArray2 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray2, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, testLibrary, new List(), true).Run(); + var psm2 = allPsmsArray2.Where(p => p != null).ToList(); + Assert.That(psm2[0].IsDecoy == false && psm2[0].FullSequence == "DITANLR"); + Assert.That(psm2[1].IsDecoy == true && psm2[1].FullSequence == "LSISNVAK"); + Assert.That(psm2[2].IsDecoy == true && psm2[2].FullSequence == "LSISNVAK"); + Assert.That(psm2[3].IsDecoy == false && psm2[3].FullSequence == "RQPAQPR"); + Assert.That(psm2[4].IsDecoy == false && psm2[4].FullSequence == "KKAEDGINK"); + Assert.That(psm2[5].IsDecoy == false && psm2[5].FullSequence == "EKAEAEAEK"); + Assert.That(psm2[6].IsDecoy == false && psm2[6].FullSequence == "EKAEAEAEK"); + + //test when doing non spectral library search without generating library + PeptideSpectralMatch[] allPsmsArray3 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray3, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), false).Run(); + var psm3 = allPsmsArray3.Where(p => p != null).ToList(); + Assert.That(psm3[0].IsDecoy == false && psm3[0].FullSequence == "DITANLR"); + Assert.That(psm3[1].IsDecoy == true && psm3[1].FullSequence == "LSISNVAK"); + Assert.That(psm3[2].IsDecoy == true && psm3[2].FullSequence == "LSISNVAK"); + Assert.That(psm3[3].IsDecoy == false && psm3[3].FullSequence == "RQPAQPR"); + Assert.That(psm3[4].IsDecoy == false && psm3[4].FullSequence == "KKAEDGINK"); + Assert.That(psm3[5].IsDecoy == false && psm3[5].FullSequence == "EKAEAEAEK"); + Assert.That(psm3[6].IsDecoy == false && psm3[6].FullSequence == "EKAEAEAEK"); + + + //test when doing non spectral library search with generating library + PeptideSpectralMatch[] allPsmsArray4 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + new ClassicSearchEngine(allPsmsArray4, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, + proteinList, searchMode, CommonParameters, null, null, new List(), true).Run(); + var psm4 = allPsmsArray4.Where(p => p != null).ToList(); + Assert.That(psm4[0].IsDecoy == false && psm4[0].FullSequence == "DITANLR"); + Assert.That(psm4[1].IsDecoy == true && psm4[1].FullSequence == "LSISNVAK"); + Assert.That(psm4[2].IsDecoy == true && psm4[2].FullSequence == "LSISNVAK"); + Assert.That(psm4[3].IsDecoy == false && psm4[3].FullSequence == "RQPAQPR"); + Assert.That(psm4[4].IsDecoy == false && psm4[4].FullSequence == "KKAEDGINK"); + Assert.That(psm4[5].IsDecoy == false && psm4[5].FullSequence == "EKAEAEAEK"); + Assert.That(psm4[6].IsDecoy == false && psm4[6].FullSequence == "EKAEAEAEK"); + + + //compare psm's target/decoy results in 4 conditions. they should be same as new decoy methods shouldn't change the t/d results + for (int i=0; i(), new List(), null, null, null, - new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List()); + new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List(), writeSpectralLibrary); cse.Run(); Assert.AreEqual(3, globalPsms[0].MatchedFragmentIons.Count); @@ -83,8 +84,9 @@ public static void TestLastPeaks() minPeptideLength: 1, maxModificationIsoforms: int.MaxValue, initiatorMethionineBehavior: InitiatorMethionineBehavior.Retain)); + bool writeSpectralLibrary = false; ClassicSearchEngine cse = new ClassicSearchEngine(globalPsms, arrayOfSortedMS2Scans, new List(), new List(), null, null, null, - new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List()); + new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List(), writeSpectralLibrary); cse.Run(); Assert.Less(globalPsms[0].Score, 2); @@ -119,8 +121,9 @@ public static void TestVeryCloseExperimentalsClassic() minPeptideLength: 1, maxModificationIsoforms: int.MaxValue, initiatorMethionineBehavior: InitiatorMethionineBehavior.Retain)); + bool writeSpetralLibrary = false; ClassicSearchEngine cse = new ClassicSearchEngine(globalPsms, arrayOfSortedMS2Scans, new List(), new List(), null, null, null, - new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List()); + new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List(), writeSpetralLibrary); cse.Run(); Assert.Less(globalPsms[0].Score, 2); @@ -179,9 +182,9 @@ public static void TestAllNaN() PeptideSpectralMatch[] globalPsms = new PeptideSpectralMatch[1]; Ms2ScanWithSpecificMass[] arrayOfSortedMS2Scans = { new Ms2ScanWithSpecificMass(scan, 0, 0, null, new CommonParameters()) }; CommonParameters CommonParameters = new CommonParameters(productMassTolerance: new PpmTolerance(5), scoreCutoff: 1, digestionParams: new DigestionParams(maxMissedCleavages: 0, minPeptideLength: 1, maxModificationIsoforms: int.MaxValue, initiatorMethionineBehavior: InitiatorMethionineBehavior.Retain)); - + bool writeSpetralLibrary = false; ClassicSearchEngine cse = new ClassicSearchEngine(globalPsms, arrayOfSortedMS2Scans, new List(), new List(), null, null, null, - new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List()); + new List { prot }, new OpenSearchMode(), CommonParameters, null, null, new List(), writeSpetralLibrary); cse.Run(); Assert.IsNull(globalPsms[0]); diff --git a/Test/SearchEngineTests.cs b/Test/SearchEngineTests.cs index 7447f586b..17b732896 100644 --- a/Test/SearchEngineTests.cs +++ b/Test/SearchEngineTests.cs @@ -46,8 +46,9 @@ public static void TestClassicSearchEngine() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); // Single search mode Assert.AreEqual(1, allPsmsArray.Length); @@ -276,8 +277,9 @@ public static void TestClassicSearchEngineXcorr() } PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedXcorrms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedXcorrms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); Assert.IsTrue(listOfSortedXcorrms2Scans[0].TheScan.MassSpectrum.XcorrProcessed); @@ -327,8 +329,9 @@ public static void TestClassicSearchEngineWithWeirdPeptide() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); // Single search mode Assert.AreEqual(1, allPsmsArray.Length); @@ -632,8 +635,9 @@ public static void TestClassicSearchEngineLowResSimple() var fsp = new List<(string, CommonParameters)>(); fsp.Add(("sliced_b6.mzML", CommonParameters)); + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedXcorrms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, fsp, null, new List()).Run(); + proteinList, searchModes, CommonParameters, fsp, null, new List(), writeSpetralLibrary).Run(); var nonNullPsms = allPsmsArray.Where(p => p != null).ToList(); Assert.AreEqual(131, nonNullPsms.Count); //if you run the test separately, it will be 111 because mods won't have been read in a previous test... @@ -824,8 +828,9 @@ public static void TestNonViablePSM() PeptideSpectralMatch[] allPsmsArray = allPsmsArrays[0]; //Classic + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); //Modern new ModernSearchEngine(allPsmsArray, listOfSortedms2Scans, indexResults.PeptideIndex, indexResults.FragmentIndex, 0, CommonParameters, null, massDiffAcceptor, SearchParameters.MaximumMassThatFragmentIonScoreIsDoubled, new List()).Run(); @@ -1556,8 +1561,9 @@ public static void TestClassicSemiProtease() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); ////////////////////////////// @@ -1575,7 +1581,7 @@ public static void TestClassicSemiProtease() PeptideSpectralMatch[] allPsmsArray2 = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; new ClassicSearchEngine(allPsmsArray2, listOfSortedms2Scans2, variableModifications, fixedModifications, null, null, null, - proteinList, searchModes, CommonParameters2, null, null, new List()).Run(); + proteinList, searchModes, CommonParameters2, null, null, new List(), writeSpetralLibrary).Run(); // Single search mode Assert.AreEqual(1, allPsmsArray2.Length); Assert.AreEqual(allPsmsArray.Length, allPsmsArray2.Length); @@ -1694,8 +1700,9 @@ public static void TestClassicSearchOneNterminalModifiedPeptideOneScan() //Search the scan against the protein PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[1]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, scans, new List(), new List(), null, null, null, - proteins, new SinglePpmAroundZeroSearchMode(20), new CommonParameters(dissociationType: DissociationType.CID), null, null, new List()).Run(); + proteins, new SinglePpmAroundZeroSearchMode(20), new CommonParameters(dissociationType: DissociationType.CID), null, null, new List(), writeSpetralLibrary).Run(); //Process the results List matchedFragmentIonList = allPsmsArray.SelectMany(p => p.MatchedFragmentIons).ToList(); diff --git a/Test/SpectralLibraryReaderTest.cs b/Test/SpectralLibraryReaderTest.cs index 9af8f7d3a..b45aa5387 100644 --- a/Test/SpectralLibraryReaderTest.cs +++ b/Test/SpectralLibraryReaderTest.cs @@ -3,7 +3,6 @@ using System; using System.Linq; using EngineLayer; -using MzLibUtil; using TaskLayer; using System.Collections.Generic; using Proteomics.Fragmentation; diff --git a/Test/Test.csproj b/Test/Test.csproj index beb93c0ca..cdbe6674d 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -18,7 +18,7 @@ - + diff --git a/Test/TestPsm.cs b/Test/TestPsm.cs index 8c1f9bb6e..8dcd9a6ad 100644 --- a/Test/TestPsm.cs +++ b/Test/TestPsm.cs @@ -115,8 +115,9 @@ public static void TestLongestFragmentIonSequence() string myDatabase = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\DbForPrunedDb.fasta"); var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, proteinList, searchModes, - new CommonParameters(), null, null, new List()).Run(); + new CommonParameters(), null, null, new List(), writeSpetralLibrary).Run(); List longestSeriesObserved = new List(); diff --git a/Test/TestTopDown.cs b/Test/TestTopDown.cs index a960d941e..5c768533b 100644 --- a/Test/TestTopDown.cs +++ b/Test/TestTopDown.cs @@ -47,8 +47,9 @@ public static void TestClassicSearchEngineTopDown() var listOfSortedms2Scans = MetaMorpheusTask.GetMs2Scans(myMsDataFile, null, new CommonParameters()).OrderBy(b => b.PrecursorMass).ToArray(); PeptideSpectralMatch[] allPsmsArray = new PeptideSpectralMatch[listOfSortedms2Scans.Length]; + bool writeSpetralLibrary = false; new ClassicSearchEngine(allPsmsArray, listOfSortedms2Scans, variableModifications, fixedModifications, null, null, null, - proteinList, searchMode, CommonParameters, null, null, new List()).Run(); + proteinList, searchMode, CommonParameters, null, null, new List(), writeSpetralLibrary).Run(); var psm = allPsmsArray.Where(p => p != null).FirstOrDefault(); Assert.That(psm.MatchedFragmentIons.Count == 47);