Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decoy on the fly And Searching Match Ions with All Charges for decoy library generation #2059

Merged
merged 30 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a1cef51
DecoyOnTheFly
May 11, 2021
9b66d6f
DecoyOnTheFlyAndMatchedIonsWithAllChargesNoTestsYet
May 11, 2021
711eeb8
WithTestsAdded
May 15, 2021
2c9c2e1
Merge branch 'master' into DecoyOnTheFlyForDecoyLibraryGeneration
YulingDai May 15, 2021
48550bb
DoChangesAsDecoyWasMovedTomzlib
YulingDai Jun 7, 2021
3e6892a
Merge branch 'master' into DecoyOnTheFlyForDecoyLibraryGeneration
YulingDai Jun 7, 2021
1f725b3
mzlib update
YulingDai Jun 7, 2021
d1464f1
test
YulingDai Jun 7, 2021
768394f
undo accidental changes
YulingDai Jun 7, 2021
af406c8
AddingHeadersAndFixedSomeErrors
YulingDai Jun 7, 2021
83ba306
unnecessary codes removed
YulingDai Jun 8, 2021
66ac032
AddingMoreTests
YulingDai Jun 8, 2021
98ba272
IncreasingTestCoverage
YulingDai Jun 8, 2021
2f0406b
more tests
YulingDai Jun 9, 2021
345ea98
Adding more tests
YulingDai Jun 9, 2021
fa4c840
test
YulingDai Jun 9, 2021
2187917
Add More Tests
YulingDai Jun 9, 2021
5c7adba
ImprovedCodesAndMoreTests
YulingDai Jun 17, 2021
d554fbd
Merge branch 'master' into DecoyOnTheFlyForDecoyLibraryGeneration
YulingDai Jun 17, 2021
dc7c061
MadeChangesFromRob
YulingDai Jun 22, 2021
482279a
Merge branch 'DecoyOnTheFlyForDecoyLibraryGeneration' of https://gith…
YulingDai Jun 22, 2021
6ffeb07
SmallChangesToMakeItClear
YulingDai Jun 22, 2021
a04e9f2
SmallChangesToMakeItClear
YulingDai Jun 22, 2021
92c3e51
MoreTestsAdded
YulingDai Jun 22, 2021
b3fa35f
Merge branch 'master' into DecoyOnTheFlyForDecoyLibraryGeneration
YulingDai Jun 24, 2021
7dad6fc
MoreChanges
YulingDai Jun 29, 2021
c3373ba
Merge branch 'DecoyOnTheFlyForDecoyLibraryGeneration' of https://gith…
YulingDai Jun 29, 2021
3261be2
Merge branch 'master' into DecoyOnTheFlyForDecoyLibraryGeneration
YulingDai Jun 29, 2021
0fb2d68
mzlibUpdate
YulingDai Jun 29, 2021
c032af0
Merge branch 'DecoyOnTheFlyForDecoyLibraryGeneration' of https://gith…
YulingDai Jun 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMD/CMD.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<PackageReference Include="Microsoft.ML" Version="1.3.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="1.3.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.494" />
<PackageReference Include="mzLib" Version="1.0.496" />
<PackageReference Include="Nett" Version="0.13.0" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
2 changes: 1 addition & 1 deletion Dockerfile_WindowsInstaller
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
111 changes: 78 additions & 33 deletions EngineLayer/ClassicSearch/ClassicSearchEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Modification> variableModifications, List<Modification> fixedModifications, List<SilacLabel> silacLabels, SilacLabel startLabel, SilacLabel endLabel,
List<Protein> proteinList, MassDiffAcceptor searchMode, CommonParameters commonParameters, List<(string FileName, CommonParameters Parameters)> fileSpecificParameters,
SpectralLibrary spectralLibrary, List<string> nestedIds)
SpectralLibrary spectralLibrary, List<string> nestedIds, bool writeSpectralLibrary)
: base(commonParameters, fileSpecificParameters, nestedIds)
{
PeptideSpectralMatches = globalPsms;
Expand All @@ -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 = proteinList.Where(p => !p.IsDecoy || spectralLibrary == null).ToList();
}

protected override MetaMorpheusEngineResults RunSpecific()
Expand All @@ -66,19 +74,22 @@ protected override MetaMorpheusEngineResults RunSpecific()
int[] threads = Enumerable.Range(0, maxThreadsPerFile).ToArray();
Parallel.ForEach(threads, (i) =>
{
var fragmentsForDissociationTypes = new Dictionary<DissociationType, List<Product>>();
var targetFragmentsForEachDissociationType = new Dictionary<DissociationType, List<Product>>();
var decoyFragmentsForEachDissociationType = new Dictionary<DissociationType, List<Product>>();

// 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<Product>());
targetFragmentsForEachDissociationType.Add(item.Value, new List<Product>());
decoyFragmentsForEachDissociationType.Add(item.Value, new List<Product>());
}
}
else
{
fragmentsForDissociationTypes.Add(CommonParameters.DissociationType, new List<Product>());
targetFragmentsForEachDissociationType.Add(CommonParameters.DissociationType, new List<Product>());
decoyFragmentsForEachDissociationType.Add(CommonParameters.DissociationType, new List<Product>());
}

for (; i < Proteins.Count; i += maxThreadsPerFile)
Expand All @@ -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;
Expand All @@ -116,32 +133,32 @@ protected override MetaMorpheusEngineResults RunSpecific()
peptide.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts);
}

List<MatchedFragmentIon> matchedIons = MatchFragmentIons(scan.TheScan, peptideTheorProducts, CommonParameters);
// match theoretical target ions to spectrum
List<MatchedFragmentIon> 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])
// match decoy ions for decoy-on-the-fly
var decoyTheoreticalFragments = decoyFragmentsForEachDissociationType[dissociationType];

if (decoyTheoreticalFragments.Count == 0)
{
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);
}
}
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);
}
}
}
Expand All @@ -167,6 +184,34 @@ protected override MetaMorpheusEngineResults RunSpecific()
return new MetaMorpheusEngineResults(this);
}

private void AddPeptideCandidateToPsm(ScanWithIndexAndNotchInfo scan, object[] myLocks, double thisScore, PeptideWithSetModifications peptide, List<MatchedFragmentIon> 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep this conditional outside of the method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do it but if keep it outside, then we will have to add one line to calculate the "meetsScoreCutOff" every time we call this method.

{
// 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<ScanWithIndexAndNotchInfo> GetAcceptableScans(double peptideMonoisotopicMass, MassDiffAcceptor searchMode)
{
foreach (AllowedIntervalWithNotch allowedIntervalWithNotch in searchMode.GetAllowedPrecursorMassIntervalsFromTheoreticalMass(peptideMonoisotopicMass).ToList())
Expand Down
2 changes: 1 addition & 1 deletion EngineLayer/EngineLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<PackageReference Include="Microsoft.ML" Version="1.3.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="1.3.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.494" />
<PackageReference Include="mzLib" Version="1.0.496" />
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Nett" Version="0.13.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
Expand Down
Loading