@@ -22,11 +22,12 @@ public class ClassicSearchEngine : MetaMorpheusEngine
22
22
private readonly PeptideSpectralMatch [ ] PeptideSpectralMatches ;
23
23
private readonly Ms2ScanWithSpecificMass [ ] ArrayOfSortedMS2Scans ;
24
24
private readonly double [ ] MyScanPrecursorMasses ;
25
+ private readonly bool WriteSpectralLibrary ;
25
26
26
27
public ClassicSearchEngine ( PeptideSpectralMatch [ ] globalPsms , Ms2ScanWithSpecificMass [ ] arrayOfSortedMS2Scans ,
27
28
List < Modification > variableModifications , List < Modification > fixedModifications , List < SilacLabel > silacLabels , SilacLabel startLabel , SilacLabel endLabel ,
28
29
List < Protein > proteinList , MassDiffAcceptor searchMode , CommonParameters commonParameters , List < ( string FileName , CommonParameters Parameters ) > fileSpecificParameters ,
29
- SpectralLibrary spectralLibrary , List < string > nestedIds )
30
+ SpectralLibrary spectralLibrary , List < string > nestedIds , bool writeSpectralLibrary )
30
31
: base ( commonParameters , fileSpecificParameters , nestedIds )
31
32
{
32
33
PeptideSpectralMatches = globalPsms ;
@@ -39,9 +40,16 @@ public ClassicSearchEngine(PeptideSpectralMatch[] globalPsms, Ms2ScanWithSpecifi
39
40
{
40
41
TurnoverLabels = ( startLabel , endLabel ) ;
41
42
}
42
- Proteins = proteinList ;
43
+
43
44
SearchMode = searchMode ;
44
45
SpectralLibrary = spectralLibrary ;
46
+ WriteSpectralLibrary = writeSpectralLibrary ;
47
+
48
+ // if we're doing a spectral library search, we can skip the reverse protein decoys generated by metamorpheus.
49
+ // we will generate reverse peptide decoys w/ in the code just below this (and calculate spectral angles for them later).
50
+ // we have to generate the reverse peptides instead of the usual reverse proteins because we generate decoy spectral
51
+ // library spectra from their corresponding paired target peptides
52
+ Proteins = spectralLibrary == null ? proteinList : proteinList . Where ( p => ! p . IsDecoy ) . ToList ( ) ;
45
53
}
46
54
47
55
protected override MetaMorpheusEngineResults RunSpecific ( )
@@ -66,19 +74,22 @@ protected override MetaMorpheusEngineResults RunSpecific()
66
74
int [ ] threads = Enumerable . Range ( 0 , maxThreadsPerFile ) . ToArray ( ) ;
67
75
Parallel . ForEach ( threads , ( i ) =>
68
76
{
69
- var fragmentsForDissociationTypes = new Dictionary < DissociationType , List < Product > > ( ) ;
77
+ var targetFragmentsForEachDissociationType = new Dictionary < DissociationType , List < Product > > ( ) ;
78
+ var decoyFragmentsForEachDissociationType = new Dictionary < DissociationType , List < Product > > ( ) ;
70
79
71
80
// check if we're supposed to autodetect dissociation type from the scan header or not
72
81
if ( CommonParameters . DissociationType == DissociationType . Autodetect )
73
82
{
74
83
foreach ( var item in GlobalVariables . AllSupportedDissociationTypes . Where ( p => p . Value != DissociationType . Autodetect ) )
75
84
{
76
- fragmentsForDissociationTypes . Add ( item . Value , new List < Product > ( ) ) ;
85
+ targetFragmentsForEachDissociationType . Add ( item . Value , new List < Product > ( ) ) ;
86
+ decoyFragmentsForEachDissociationType . Add ( item . Value , new List < Product > ( ) ) ;
77
87
}
78
88
}
79
89
else
80
90
{
81
- fragmentsForDissociationTypes . Add ( CommonParameters . DissociationType , new List < Product > ( ) ) ;
91
+ targetFragmentsForEachDissociationType . Add ( CommonParameters . DissociationType , new List < Product > ( ) ) ;
92
+ decoyFragmentsForEachDissociationType . Add ( CommonParameters . DissociationType , new List < Product > ( ) ) ;
82
93
}
83
94
84
95
for ( ; i < Proteins . Count ; i += maxThreadsPerFile )
@@ -89,22 +100,28 @@ protected override MetaMorpheusEngineResults RunSpecific()
89
100
// digest each protein into peptides and search for each peptide in all spectra within precursor mass tolerance
90
101
foreach ( PeptideWithSetModifications peptide in Proteins [ i ] . Digest ( CommonParameters . DigestionParams , FixedModifications , VariableModifications , SilacLabels , TurnoverLabels ) )
91
102
{
92
- foreach ( var fragmentSet in fragmentsForDissociationTypes )
103
+ PeptideWithSetModifications reversedOnTheFlyDecoy = null ;
104
+
105
+ if ( SpectralLibrary != null )
106
+ {
107
+ int [ ] newAAlocations = new int [ peptide . BaseSequence . Length ] ;
108
+ reversedOnTheFlyDecoy = peptide . GetReverseDecoyFromTarget ( newAAlocations ) ;
109
+ }
110
+
111
+ // clear fragments from the last peptide
112
+ foreach ( var fragmentSet in targetFragmentsForEachDissociationType )
93
113
{
94
114
fragmentSet . Value . Clear ( ) ;
115
+ decoyFragmentsForEachDissociationType [ fragmentSet . Key ] . Clear ( ) ;
95
116
}
96
117
118
+ // score each scan that has an acceptable precursor mass
97
119
foreach ( ScanWithIndexAndNotchInfo scan in GetAcceptableScans ( peptide . MonoisotopicMass , SearchMode ) )
98
120
{
99
- if ( SpectralLibrary != null && ! SpectralLibrary . ContainsSpectrum ( peptide . FullSequence , scan . TheScan . PrecursorCharge ) )
100
- {
101
- continue ;
102
- }
103
-
104
121
var dissociationType = CommonParameters . DissociationType == DissociationType . Autodetect ?
105
122
scan . TheScan . TheScan . DissociationType . Value : CommonParameters . DissociationType ;
106
123
107
- if ( ! fragmentsForDissociationTypes . TryGetValue ( dissociationType , out var peptideTheorProducts ) )
124
+ if ( ! targetFragmentsForEachDissociationType . TryGetValue ( dissociationType , out var peptideTheorProducts ) )
108
125
{
109
126
//TODO: print some kind of warning here. the scan header dissociation type was unknown
110
127
continue ;
@@ -116,32 +133,19 @@ protected override MetaMorpheusEngineResults RunSpecific()
116
133
peptide . Fragment ( dissociationType , CommonParameters . DigestionParams . FragmentationTerminus , peptideTheorProducts ) ;
117
134
}
118
135
119
- List < MatchedFragmentIon > matchedIons = MatchFragmentIons ( scan . TheScan , peptideTheorProducts , CommonParameters ) ;
136
+ // match theoretical target ions to spectrum
137
+ List < MatchedFragmentIon > matchedIons = MatchFragmentIons ( scan . TheScan , peptideTheorProducts , CommonParameters ,
138
+ matchAllCharges : WriteSpectralLibrary ) ;
120
139
121
- double thisScore = CalculatePeptideScore ( scan . TheScan . TheScan , matchedIons ) ;
122
- bool meetsScoreCutoff = thisScore >= CommonParameters . ScoreCutoff ;
140
+ // calculate the peptide's score
141
+ double thisScore = CalculatePeptideScore ( scan . TheScan . TheScan , matchedIons , fragmentsCanHaveDifferentCharges : WriteSpectralLibrary ) ;
123
142
124
- // this is thread-safe because even if the score improves from another thread writing to this PSM,
125
- // the lock combined with AddOrReplace method will ensure thread safety
126
- if ( meetsScoreCutoff )
143
+ AddPeptideCandidateToPsm ( scan , myLocks , thisScore , peptide , matchedIons ) ;
144
+
145
+
146
+ if ( SpectralLibrary != null )
127
147
{
128
- // valid hit (met the cutoff score); lock the scan to prevent other threads from accessing it
129
- lock ( myLocks [ scan . ScanIndex ] )
130
- {
131
- bool scoreImprovement = PeptideSpectralMatches [ scan . ScanIndex ] == null || ( thisScore - PeptideSpectralMatches [ scan . ScanIndex ] . RunnerUpScore ) > - PeptideSpectralMatch . ToleranceForScoreDifferentiation ;
132
-
133
- if ( scoreImprovement )
134
- {
135
- if ( PeptideSpectralMatches [ scan . ScanIndex ] == null )
136
- {
137
- PeptideSpectralMatches [ scan . ScanIndex ] = new PeptideSpectralMatch ( peptide , scan . Notch , thisScore , scan . ScanIndex , scan . TheScan , CommonParameters , matchedIons , 0 ) ;
138
- }
139
- else
140
- {
141
- PeptideSpectralMatches [ scan . ScanIndex ] . AddOrReplace ( peptide , thisScore , scan . Notch , CommonParameters . ReportAllAmbiguity , matchedIons , 0 ) ;
142
- }
143
- }
144
- }
148
+ DecoyScoreForSpectralLibrarySearch ( scan , reversedOnTheFlyDecoy , decoyFragmentsForEachDissociationType , dissociationType , myLocks ) ;
145
149
}
146
150
}
147
151
}
@@ -167,6 +171,54 @@ protected override MetaMorpheusEngineResults RunSpecific()
167
171
return new MetaMorpheusEngineResults ( this ) ;
168
172
}
169
173
174
+ private void DecoyScoreForSpectralLibrarySearch ( ScanWithIndexAndNotchInfo scan , PeptideWithSetModifications reversedOnTheFlyDecoy , Dictionary < DissociationType , List < Product > > decoyFragmentsForEachDissociationType , DissociationType dissociationType , object [ ] myLocks )
175
+ {
176
+ // match decoy ions for decoy-on-the-fly
177
+ var decoyTheoreticalFragments = decoyFragmentsForEachDissociationType [ dissociationType ] ;
178
+
179
+ if ( decoyTheoreticalFragments . Count == 0 )
180
+ {
181
+ reversedOnTheFlyDecoy . Fragment ( dissociationType , CommonParameters . DigestionParams . FragmentationTerminus , decoyTheoreticalFragments ) ;
182
+ }
183
+
184
+ var decoyMatchedIons = MatchFragmentIons ( scan . TheScan , decoyTheoreticalFragments , CommonParameters ,
185
+ matchAllCharges : WriteSpectralLibrary ) ;
186
+
187
+ // calculate decoy's score
188
+ var decoyScore = CalculatePeptideScore ( scan . TheScan . TheScan , decoyMatchedIons , fragmentsCanHaveDifferentCharges : WriteSpectralLibrary ) ;
189
+
190
+ AddPeptideCandidateToPsm ( scan , myLocks , decoyScore , reversedOnTheFlyDecoy , decoyMatchedIons ) ;
191
+ }
192
+
193
+
194
+ private void AddPeptideCandidateToPsm ( ScanWithIndexAndNotchInfo scan , object [ ] myLocks , double thisScore , PeptideWithSetModifications peptide , List < MatchedFragmentIon > matchedIons )
195
+ {
196
+ bool meetsScoreCutoff = thisScore >= CommonParameters . ScoreCutoff ;
197
+
198
+ // this is thread-safe because even if the score improves from another thread writing to this PSM,
199
+ // the lock combined with AddOrReplace method will ensure thread safety
200
+ if ( meetsScoreCutoff )
201
+ {
202
+ // valid hit (met the cutoff score); lock the scan to prevent other threads from accessing it
203
+ lock ( myLocks [ scan . ScanIndex ] )
204
+ {
205
+ bool scoreImprovement = PeptideSpectralMatches [ scan . ScanIndex ] == null || ( thisScore - PeptideSpectralMatches [ scan . ScanIndex ] . RunnerUpScore ) > - PeptideSpectralMatch . ToleranceForScoreDifferentiation ;
206
+
207
+ if ( scoreImprovement )
208
+ {
209
+ if ( PeptideSpectralMatches [ scan . ScanIndex ] == null )
210
+ {
211
+ PeptideSpectralMatches [ scan . ScanIndex ] = new PeptideSpectralMatch ( peptide , scan . Notch , thisScore , scan . ScanIndex , scan . TheScan , CommonParameters , matchedIons , 0 ) ;
212
+ }
213
+ else
214
+ {
215
+ PeptideSpectralMatches [ scan . ScanIndex ] . AddOrReplace ( peptide , thisScore , scan . Notch , CommonParameters . ReportAllAmbiguity , matchedIons , 0 ) ;
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+
170
222
private IEnumerable < ScanWithIndexAndNotchInfo > GetAcceptableScans ( double peptideMonoisotopicMass , MassDiffAcceptor searchMode )
171
223
{
172
224
foreach ( AllowedIntervalWithNotch allowedIntervalWithNotch in searchMode . GetAllowedPrecursorMassIntervalsFromTheoreticalMass ( peptideMonoisotopicMass ) . ToList ( ) )
0 commit comments