Skip to content

Commit 743a127

Browse files
committed
MGF supports all MS levels
1 parent 51dfb82 commit 743a127

File tree

2 files changed

+74
-70
lines changed

2 files changed

+74
-70
lines changed

Writer/MgfSpectrumWriter.cs

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Globalization;
34
using System.Linq;
45
using System.Reflection;
@@ -21,15 +22,13 @@ public class MgfSpectrumWriter : SpectrumWriter
2122
private const string NegativePolarity = "-";
2223

2324
// Filter string
24-
private const string FilterStringIsolationMzPattern = @"ms2 (.*?)@";
25+
private readonly Regex _filterStringIsolationMzPattern = new Regex(@"ms\d+ (.+?) \[");
2526

26-
// Precursor scan number for MS2 scans
27-
private int _precursorMs1ScanNumber;
27+
// Precursor scan number for MSn scans
28+
private int _precursorScanNumber;
2829

29-
// Dictionary with isolation m/z (key) and precursor scan number (value) entries
30-
// for reference in the precursor element of an MS3 spectrum
31-
private readonly LimitedSizeDictionary<string, int> _isolationMzToPrecursorScanNumberMapping =
32-
new LimitedSizeDictionary<string, int>(40);
30+
// Precursor scan number (value) and isolation m/z (key) for reference in the precursor element of an MSn spectrum
31+
private readonly Dictionary<string, int> _precursorScanNumbers = new Dictionary<string, int>();
3332

3433
public MgfSpectrumWriter(ParseInput parseInput) : base(parseInput)
3534
{
@@ -60,6 +59,8 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
6059
}
6160
}
6261

62+
_precursorScanNumber = 0;
63+
6364
// Get the scan from the RAW file
6465
var scan = Scan.FromFile(rawFile, scanNumber);
6566

@@ -72,23 +73,81 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
7273
// Get the scan event for this scan number
7374
var scanEvent = rawFile.GetScanEventForScanNumber(scanNumber);
7475

76+
// Trailer extra data list
77+
ScanTrailer trailerData;
78+
79+
try
80+
{
81+
trailerData = new ScanTrailer(rawFile.GetTrailerExtraInformation(scanNumber));
82+
}
83+
catch (Exception ex)
84+
{
85+
Log.WarnFormat("Cannot load trailer infromation for scan {0} due to following exception\n{1}", scanNumber, ex.Message);
86+
trailerData = new ScanTrailer();
87+
}
88+
89+
// Get scan ms level
90+
var msLevel = (int)scanFilter.MSOrder;
91+
7592
// Construct the precursor reference string for the title
7693
var precursorReference = "";
94+
7795
if (ParseInput.MgfPrecursor)
7896
{
79-
if (scanFilter.MSOrder == MSOrderType.Ms)
97+
if (msLevel == 1)
8098
{
8199
// Keep track of the MS1 scan number for precursor reference
82-
_precursorMs1ScanNumber = scanNumber;
100+
_precursorScanNumbers[""] = scanNumber;
83101
}
84102
else
85103
{
86-
precursorReference = ConstructPrecursorReference(scanFilter.MSOrder, scanNumber, scanEvent);
104+
// Keep track of scan number and isolation m/z for precursor reference
105+
var result = _filterStringIsolationMzPattern.Match(scanEvent.ToString());
106+
if (result.Success)
107+
{
108+
if (_precursorScanNumbers.ContainsKey(result.Groups[1].Value))
109+
{
110+
_precursorScanNumbers.Remove(result.Groups[1].Value);
111+
}
112+
113+
_precursorScanNumbers.Add(result.Groups[1].Value, scanNumber);
114+
}
115+
116+
//update precursor scan if it is provided in trailer data
117+
var trailerMasterScan = trailerData.AsPositiveInt("Master Scan Number:");
118+
if (trailerMasterScan.HasValue)
119+
{
120+
_precursorScanNumber = trailerMasterScan.Value;
121+
}
122+
else //try getting it from the scan filter
123+
{
124+
var parts = Regex.Split(result.Groups[1].Value, " ");
125+
126+
//find the position of the first (from the end) precursor with a different mass
127+
//to account for possible supplementary activations written in the filter
128+
var lastIonMass = parts.Last().Split('@').First();
129+
int last = parts.Length;
130+
while (last > 0 &&
131+
parts[last - 1].Split('@').First() == lastIonMass)
132+
{
133+
last--;
134+
}
135+
136+
string parentFilter = String.Join(" ", parts.Take(last));
137+
if (_precursorScanNumbers.ContainsKey(parentFilter))
138+
{
139+
_precursorScanNumber = _precursorScanNumbers[parentFilter];
140+
}
141+
}
142+
143+
if (_precursorScanNumber > 0)
144+
precursorReference = ConstructSpectrumTitle((int)Device.MS, 1, _precursorScanNumber);
145+
else
146+
Log.Error($"Failed finding precursor for {scanNumber}");
87147
}
88148
}
89149

90-
// Don't include MS1 spectra
91-
if (ParseInput.MsLevel.Contains((int) scanFilter.MSOrder))
150+
if (ParseInput.MsLevel.Contains(msLevel))
92151
{
93152
var reaction = GetReaction(scanEvent, scanNumber);
94153

@@ -107,23 +166,10 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
107166
Writer.WriteLine(
108167
$"RTINSECONDS={(retentionTime * 60).ToString(CultureInfo.InvariantCulture)}");
109168

110-
// Trailer extra data list
111-
ScanTrailer trailerData;
112-
113-
try
114-
{
115-
trailerData = new ScanTrailer(rawFile.GetTrailerExtraInformation(scanNumber));
116-
}
117-
catch (Exception ex)
118-
{
119-
Log.WarnFormat("Cannot load trailer infromation for scan {0} due to following exception\n{1}", scanNumber, ex.Message);
120-
trailerData = new ScanTrailer();
121-
}
122-
123169
int? charge = trailerData.AsPositiveInt("Charge State:");
124170
double? monoisotopicMz = trailerData.AsDouble("Monoisotopic M/Z:");
125171
double? isolationWidth =
126-
trailerData.AsDouble("MS" + (int) scanFilter.MSOrder + " Isolation Width:");
172+
trailerData.AsDouble("MS" + msLevel + " Isolation Width:");
127173

128174
if (reaction != null)
129175
{
@@ -153,7 +199,7 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
153199
double[] masses;
154200
double[] intensities;
155201

156-
if (!ParseInput.NoPeakPicking.Contains((int) scanFilter.MSOrder))
202+
if (!ParseInput.NoPeakPicking.Contains(msLevel))
157203
{
158204
// Check if the scan has a centroid stream
159205
if (scan.HasCentroidStream)
@@ -200,48 +246,5 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
200246
}
201247
}
202248
}
203-
204-
private string ConstructPrecursorReference(MSOrderType msOrder, int scanNumber, IScanEvent scanEvent)
205-
{
206-
// Precursor reference
207-
var precursorReference = "";
208-
209-
switch (msOrder)
210-
{
211-
case MSOrderType.Ms2:
212-
// Keep track of the MS2 scan number and isolation m/z for precursor reference
213-
var result = Regex.Match(scanEvent.ToString(), FilterStringIsolationMzPattern);
214-
if (result.Success)
215-
{
216-
if (_isolationMzToPrecursorScanNumberMapping.ContainsKey(result.Groups[1].Value))
217-
{
218-
_isolationMzToPrecursorScanNumberMapping.Remove(result.Groups[1].Value);
219-
}
220-
221-
_isolationMzToPrecursorScanNumberMapping.Add(result.Groups[1].Value, scanNumber);
222-
}
223-
224-
precursorReference = ConstructSpectrumTitle((int) Device.MS, 1, _precursorMs1ScanNumber);
225-
break;
226-
227-
case MSOrderType.Ms3:
228-
var precursorScanNumber = _isolationMzToPrecursorScanNumberMapping.Keys.FirstOrDefault(
229-
isolationMz => scanEvent.ToString().Contains(isolationMz));
230-
if (!precursorScanNumber.IsNullOrEmpty())
231-
{
232-
precursorReference = ConstructSpectrumTitle((int) Device.MS, 1,
233-
_isolationMzToPrecursorScanNumberMapping[precursorScanNumber]);
234-
}
235-
else
236-
{
237-
throw new InvalidOperationException("Couldn't find a MS2 precursor scan for MS3 scan " +
238-
scanEvent);
239-
}
240-
241-
break;
242-
}
243-
244-
return precursorReference;
245-
}
246249
}
247250
}

Writer/MzMlSpectrumWriter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ public override void Write(IRawDataPlus rawFile, int firstScanNumber, int lastSc
307307

308308
// Run
309309
_writer.WriteStartElement("run");
310+
//TODO: validate id against NCName
310311
_writer.WriteAttributeString("id", ParseInput.RawFileNameWithoutExtension);
311312
_writer.WriteAttributeString("defaultInstrumentConfigurationRef", "IC1");
312313
_writer.WriteAttributeString("startTimeStamp",

0 commit comments

Comments
 (0)