@@ -68,6 +68,8 @@ public MzMlSpectrumWriter(ParseInput parseInput) : base(parseInput)
6868 _mzMlNamespace . Add ( string . Empty , "http://psi.hupo.org/ms/mzml" ) ;
6969 _doIndexing = ParseInput . OutputFormat == OutputFormat . IndexMzML ;
7070 _osOffset = Environment . NewLine == "\n " ? 0 : 1 ;
71+ _precursorScanNumbers [ "" ] = - 1 ;
72+ _precursorTree [ - 1 ] = new PrecursorInfo ( ) ;
7173 }
7274
7375 /// <inheritdoc />
@@ -1275,7 +1277,7 @@ private SpectrumType ConstructMSSpectrum(int scanNumber)
12751277 } ) ;
12761278
12771279 // Keep track of scan number for precursor reference
1278- _precursorScanNumbers [ "" ] = scanNumber ;
1280+ _precursorScanNumbers [ "" ] = - 1 ;
12791281 _precursorTree [ scanNumber ] = new PrecursorInfo ( ) ;
12801282
12811283 }
@@ -1312,61 +1314,52 @@ private SpectrumType ConstructMSSpectrum(int scanNumber)
13121314 _precursorScanNumber = GetParentFromScanString ( result . Groups [ 1 ] . Value ) ;
13131315 }
13141316
1315- if ( _precursorScanNumber > 0 )
1317+ //finding precursor scan failed
1318+ if ( _precursorScanNumber == - 2 )
13161319 {
1320+ Log . Warn ( $ "Cannot find precursor scan for scan# { scanNumber } ") ;
1321+ _precursorTree [ - 2 ] = new PrecursorInfo ( 0 , msLevel , FindLastReaction ( scanEvent , msLevel ) , new PrecursorType [ 0 ] ) ;
1322+ }
13171323
1318- try
1324+ try
1325+ {
1326+ try //since there is no direct way to get the number of reactions available, it is necessary to try and fail
13191327 {
1320- try //since there is no direct way to get the number of reactions available, it is necessary to try and fail
1328+ scanEvent . GetReaction ( _precursorTree [ _precursorScanNumber ] . ReactionCount ) ;
1329+ }
1330+ catch ( ArgumentOutOfRangeException ex )
1331+ {
1332+ Log . Debug ( $ "Using Tribrid decision tree fix for scan# { scanNumber } ") ;
1333+ //Is it a decision tree scheduled scan on tribrid?
1334+ if ( msLevel == _precursorTree [ _precursorScanNumber ] . MSLevel )
13211335 {
1322- scanEvent . GetReaction ( _precursorTree [ _precursorScanNumber ] . ReactionCount ) ;
1336+ _precursorScanNumber = GetParentFromScanString ( result . Groups [ 1 ] . Value ) ;
13231337 }
1324- catch ( ArgumentOutOfRangeException ex )
1338+ else
13251339 {
1326- Log . Debug ( $ "Using Tribrid decision tree fix for scan# { scanNumber } ") ;
1327- //Is it a decision tree scheduled scan on tribrid?
1328- if ( msLevel == _precursorTree [ _precursorScanNumber ] . MSLevel )
1329- {
1330- _precursorScanNumber = GetParentFromScanString ( result . Groups [ 1 ] . Value ) ;
1331- }
1332- else
1333- {
1334- throw new RawFileParserException (
1335- $ "Tribrid decision tree fix failed - cannot get reaction# { _precursorTree [ _precursorScanNumber ] . ReactionCount } from { scanEvent . ToString ( ) } ",
1336- ex ) ;
1337- }
1340+ throw new RawFileParserException (
1341+ $ "Tribrid decision tree fix failed - cannot get reaction# { _precursorTree [ _precursorScanNumber ] . ReactionCount } from { scanEvent . ToString ( ) } ",
1342+ ex ) ;
13381343 }
1339-
1340- // Construct and set the precursor list element of the spectrum
1341- spectrum . precursorList =
1342- ConstructPrecursorList ( _precursorScanNumber , scanEvent , charge , monoisotopicMz , isolationWidth ,
1343- SPSMasses , out var reactionCount ) ;
1344-
1345- //save precursor information for later reference
1346- _precursorTree [ scanNumber ] = new PrecursorInfo ( _precursorScanNumber , msLevel , reactionCount , spectrum . precursorList . precursor ) ;
13471344 }
1348- catch ( Exception e )
1349- {
1350- var extra = ( e . InnerException is null ) ? "" : $ "\n { e . InnerException . StackTrace } ";
1351-
1352- Log . Warn ( $ "Failed creating precursor list for scan# { scanNumber } - precursor information for this and dependent scans will be empty\n Exception details:{ e . Message } \n { e . StackTrace } \n { extra } ") ;
1353- ParseInput . NewWarn ( ) ;
13541345
1355- _precursorTree [ scanNumber ] = new PrecursorInfo ( _precursorScanNumber , 1 , 0 , new PrecursorType [ 0 ] ) ;
1346+ // Construct and set the precursor list element of the spectrum
1347+ spectrum . precursorList =
1348+ ConstructPrecursorList ( _precursorScanNumber , scanEvent , charge , monoisotopicMz , isolationWidth ,
1349+ SPSMasses , out var reactionCount ) ;
13561350
1357- }
1358-
1351+ //save precursor information for later reference
1352+ _precursorTree [ scanNumber ] = new PrecursorInfo ( _precursorScanNumber , msLevel , reactionCount , spectrum . precursorList . precursor ) ;
13591353 }
1360- else
1354+ catch ( Exception e )
13611355 {
1362- spectrum . precursorList = new PrecursorListType
1363- {
1364- count = "0" ,
1365- precursor = new PrecursorType [ 0 ]
1366- } ;
1356+ var extra = ( e . InnerException is null ) ? "" : $ "\n { e . InnerException . StackTrace } ";
1357+
1358+ Log . Warn ( $ "Failed creating precursor list for scan# { scanNumber } - precursor information for this and dependent scans will be empty\n Exception details:{ e . Message } \n { e . StackTrace } \n { extra } ") ;
1359+ ParseInput . NewWarn ( ) ;
1360+
1361+ _precursorTree [ scanNumber ] = new PrecursorInfo ( _precursorScanNumber , 1 , 0 , new PrecursorType [ 0 ] ) ;
13671362
1368- Log . Error ( $ "Failed finding precursor for { scanNumber } ") ;
1369- ParseInput . NewError ( ) ;
13701363 }
13711364 }
13721365 else
@@ -1891,6 +1884,45 @@ private SpectrumType ConstructMSSpectrum(int scanNumber)
18911884 return spectrum ;
18921885 }
18931886
1887+ private int FindLastReaction ( IScanEvent scanEvent , int msLevel )
1888+ {
1889+ int lastReactionIndex = msLevel - 2 ;
1890+
1891+ //iteratively trying find the last available index for reaction
1892+ while ( true )
1893+ {
1894+ try
1895+ {
1896+ scanEvent . GetReaction ( lastReactionIndex + 1 ) ;
1897+ }
1898+ catch ( ArgumentOutOfRangeException )
1899+ {
1900+ //stop trying
1901+ break ;
1902+ }
1903+
1904+ lastReactionIndex ++ ;
1905+ }
1906+
1907+ //supplemental activation flag is on -> one of the levels (not necissirily the last one) used supplemental activation
1908+ //check last two activations
1909+ if ( scanEvent . SupplementalActivation == TriState . On )
1910+ {
1911+ var lastActivation = scanEvent . GetReaction ( lastReactionIndex ) . ActivationType ;
1912+ var beforeLastActivation = scanEvent . GetReaction ( lastReactionIndex - 1 ) . ActivationType ;
1913+
1914+ if ( ( beforeLastActivation == ActivationType . ElectronTransferDissociation || beforeLastActivation == ActivationType . ElectronCaptureDissociation ) &&
1915+ ( lastActivation == ActivationType . CollisionInducedDissociation || lastActivation == ActivationType . HigherEnergyCollisionalDissociation ) )
1916+ return lastReactionIndex - 1 ; //ETD or ECD followed by HCD or CID -> supplemental activation in the last level (move the last reaction one step back)
1917+ else
1918+ return lastReactionIndex ;
1919+ }
1920+ else //just use the last one
1921+ {
1922+ return lastReactionIndex ;
1923+ }
1924+ }
1925+
18941926 private SpectrumType ConstructPDASpectrum ( int scanNumber , int instrumentNumber )
18951927 {
18961928 // Get each scan from the RAW file
@@ -2153,21 +2185,25 @@ private PrecursorListType ConstructPrecursorList(int precursorScanNumber, IScanE
21532185 // Get precursors from earlier levels
21542186 var prevPrecursors = _precursorTree [ precursorScanNumber ] ;
21552187
2156- var spectrumRef = "" ;
2188+ string spectrumRef = null ;
21572189 int msLevel = ( int ) scanEvent . MSOrder ;
21582190 IReaction reaction = null ;
21592191 var precursorMz = 0.0 ;
21602192 reactionCount = prevPrecursors . ReactionCount ;
21612193
2162- spectrumRef = ConstructSpectrumTitle ( ( int ) Device . MS , 1 , precursorScanNumber ) ;
21632194 reaction = scanEvent . GetReaction ( reactionCount ) ;
2164-
2165- precursorMz = reaction . PrecursorMass ;
21662195
21672196 //if isolation width was not found in the trailer, try to get one from the reaction
21682197 if ( isolationWidth == null ) isolationWidth = reaction . IsolationWidth ;
21692198 if ( isolationWidth < 0 ) isolationWidth = null ;
2170-
2199+
2200+ precursorMz = reaction . PrecursorMass ;
2201+
2202+ if ( precursorScanNumber > 0 )
2203+ {
2204+ spectrumRef = ConstructSpectrumTitle ( ( int ) Device . MS , 1 , precursorScanNumber ) ;
2205+ }
2206+
21712207 var precursor = new PrecursorType
21722208 {
21732209 selectedIonList =
@@ -2204,7 +2240,7 @@ private PrecursorListType ConstructPrecursorList(int precursorScanNumber, IScanE
22042240 } ) ;
22052241 }
22062242
2207- if ( selectedIonMz > ZeroDelta )
2243+ if ( selectedIonMz > ZeroDelta && precursorScanNumber > 0 )
22082244 {
22092245 var selectedIonIntensity = CalculatePrecursorPeakIntensity ( _rawFile , precursorScanNumber , reaction . PrecursorMass , isolationWidth ,
22102246 ParseInput . NoPeakPicking . Contains ( msLevel - 1 ) ) ;
@@ -2472,8 +2508,7 @@ private PrecursorListType ConstructPrecursorList(int precursorScanNumber, IScanE
24722508
24732509 private int GetParentFromScanString ( string scanString )
24742510 {
2475- var result = _filterStringIsolationMzPattern . Match ( scanString ) ;
2476- var parts = Regex . Split ( result . Groups [ 1 ] . Value , " " ) ;
2511+ var parts = Regex . Split ( scanString , " " ) ;
24772512
24782513 //find the position of the first (from the end) precursor with a different mass
24792514 //to account for possible supplementary activations written in the filter
@@ -2491,7 +2526,7 @@ private int GetParentFromScanString(string scanString)
24912526 return _precursorScanNumbers [ parentFilter ] ;
24922527 }
24932528
2494- return - 1 ; //unsuccessful parsing
2529+ return - 2 ; //unsuccessful parsing
24952530 }
24962531
24972532 /// <summary>
0 commit comments