OpenMS
Loading...
Searching...
No Matches
MascotGenericFile.h
Go to the documentation of this file.
1// Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin
2// SPDX-License-Identifier: BSD-3-Clause
3//
4// --------------------------------------------------------------------------
5// $Maintainer: Chris Bielow $
6// $Authors: Andreas Bertsch, Chris Bielow $
7// --------------------------------------------------------------------------
8
9#pragma once
10
16#include <OpenMS/SYSTEM/File.h>
18
19#include <vector>
20#include <fstream>
21
22#ifdef _OPENMP
23#include <omp.h>
24#endif
25
26namespace OpenMS
27{
51 class OPENMS_DLLAPI MascotGenericFile :
52 public ProgressLogger,
54 {
55public:
56
59
62
64 void updateMembers_() override;
65
67 void store(const std::string& filename, const PeakMap& experiment,
68 bool compact = false);
69
71 void store(std::ostream& os, const std::string& filename,
72 const PeakMap& experiment, bool compact = false);
73
81 template <typename MapType>
82 void load(const std::string& filename, MapType& exp)
83 {
84 if (!File::exists(filename))
85 {
86 throw Exception::FileNotFound(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, filename);
87 }
88
89 exp.reset();
90
91 std::ifstream is(filename.c_str());
92 // get size of file
93 is.seekg(0, std::ios::end);
94 startProgress(0, is.tellg(), "loading MGF");
95 is.seekg(0, std::ios::beg);
96
97 UInt spectrum_number(0);
98 Size line_number(0); // carry line number for error messages within getNextSpectrum()
99
100 typename MapType::SpectrumType spectrum; // (re-)initialized for every block by getNextSpectrum_()
101 while (getNextSpectrum_(is, spectrum, line_number, spectrum_number))
102 {
103 exp.addSpectrum(spectrum);
104 setProgress(is.tellg());
105 ++spectrum_number;
106 } // next spectrum
107 exp.updateRanges();
108 endProgress();
109 }
110
118 std::pair<std::string, std::string> getHTTPPeakListEnclosure(const std::string& filename) const;
119
121 void writeSpectrum(std::ostream& os, const PeakSpectrum& spec, const std::string& filename, const std::string& native_id_type_accession);
122
123protected:
124
127
129 std::map<std::string, std::string> mod_group_map_;
130
132 void writeParameterHeader_(const std::string& name, std::ostream& os);
133
135 void writeModifications_(const std::vector<std::string>& mods, std::ostream& os,
136 bool variable_mods = false);
137
139 void writeHeader_(std::ostream& os);
140
142 void writeMSExperiment_(std::ostream& os, const std::string& filename, const PeakMap& experiment);
143
152 template <typename SpectrumType>
153 bool getNextSpectrum_(std::ifstream& is, SpectrumType& spectrum, Size& line_number, const Size& spectrum_number)
154 {
155 // Start every block from a pristine spectrum: clear(true) removes the peaks and data arrays,
156 // all SpectrumSettings (precursors, native ID, meta values such as TITLE/SEQ/NAME, ...) and
157 // resets RT, drift time and MS level. Every field below is only set when its line is present
158 // (e.g. CHARGE is commonly omitted), so nothing from the previous block may survive here.
159 spectrum.clear(true);
160 spectrum.setMSLevel(2);
161 spectrum.getPrecursors().resize(1);
162 spectrum.setType(SpectrumSettings::SpectrumType::CENTROID); // MGF is always centroided, by definition
163 spectrum.setNativeID(std::string("index=") + (spectrum_number));
164
165 typename SpectrumType::PeakType p;
166
167 std::string line;
168 // seek to next peak list block
169 while (getline(is, line, '\n'))
170 {
171 ++line_number;
172
173 StringUtils::trim(line); // remove whitespaces, line-endings etc
174
175 // found peak list block?
176 if (line == "BEGIN IONS")
177 {
178 while (getline(is, line, '\n'))
179 {
180 ++line_number;
181 StringUtils::trim(line); // remove whitespaces, line-endings etc
182
183 if (line.empty()) continue;
184
185 if (line == "END IONS")
186 {
187 // block without peak lines: return it as an empty spectrum instead of silently
188 // merging it with the next block (or dropping it if it is the last one in the file)
189 return true;
190 }
191
192 if (isdigit(line[0])) // actual data .. this comes first, since its the most common case
193 {
194 std::vector<std::string> split;
195 do
196 {
197 if (line.empty())
198 {
199 continue;
200 }
201
202 StringUtils::simplify(line); // merge double spaces (explicitly allowed by MGF), to prevent empty split() chunks and subsequent parse error
203 StringUtils::substitute(line, '\t', ' '); // also accept Tab (strictly, only space(s) are allowed)
204 if (StringUtils::split(line, ' ', split, false))
205 {
206 try
207 {
208 p.setPosition(StringUtils::toDouble(split[0]));
209 p.setIntensity(StringUtils::toDouble(split[1]));
210 }
211 catch (Exception::ConversionError& /*e*/)
212 {
213 throw Exception::ParseError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "The content '" + line + "' at line #" + StringUtils::toStr(line_number) + " could not be converted to a number! Expected two (m/z int) or three (m/z int charge) numbers separated by whitespace (space or tab).", "");
214 }
215 spectrum.push_back(p);
216 }
217 else
218 {
219 throw Exception::ParseError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "The content '" + line + "' at line #" + StringUtils::toStr(line_number) + " does not contain m/z and intensity values separated by whitespace (space or tab)!", "");
220 }
221 }
222 while (getline(is, line, '\n') && ++line_number && StringUtils::trim(line) != "END IONS"); // StringUtils::trim(line) is important here!
223
224 if (line == "END IONS")
225 {
226 return true; // found end of spectrum
227 }
228 else
229 {
230 throw Exception::ParseError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, R"(Reached end of file. Found "BEGIN IONS" but not the corresponding "END IONS"!)", "");
231 }
232 }
233 else if (StringUtils::hasPrefix(line, "PEPMASS")) // parse precursor position
234 {
235 std::string tmp = StringUtils::substr(line, 8); // copy since we might need the original line for error reporting later
236 StringUtils::substitute(tmp, '\t', ' ');
237 std::vector<std::string> split;
238 StringUtils::split(tmp, ' ', split);
239 if (split.size() == 1)
240 {
241 spectrum.getPrecursors()[0].setMZ(StringUtils::toDouble(StringUtils::trim(split[0])));
242 }
243 else if (split.size() == 2)
244 {
245 spectrum.getPrecursors()[0].setMZ(StringUtils::toDouble(StringUtils::trim(split[0])));
246 spectrum.getPrecursors()[0].setIntensity(StringUtils::toDouble(StringUtils::trim(split[1])));
247 }
248 else
249 {
250 throw Exception::ParseError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Cannot parse PEPMASS in '" + line + "' at line #" + StringUtils::toStr(line_number) + " (expected 1 or 2 entries, but " + StringUtils::toStr(split.size()) + " were present)!", "");
251 }
252 }
253 else if (StringUtils::hasPrefix(line, "CHARGE"))
254 {
255 std::string tmp = StringUtils::substr(line, 7);
256 StringUtils::remove(tmp, '+');
257 spectrum.getPrecursors()[0].setCharge(StringUtils::toInt32(tmp));
258 }
259 else if (StringUtils::hasPrefix(line, "RTINSECONDS"))
260 {
261 std::string tmp = StringUtils::substr(line, 12);
262 spectrum.setRT(StringUtils::toDouble(tmp));
263 }
264 else if (StringUtils::hasPrefix(line, "TITLE"))
265 {
266 // test if we have a line like "TITLE= Cmpd 1, +MSn(595.3), 10.9 min"
267 if (StringUtils::hasSubstring(line, "min"))
268 {
269 try
270 {
271 std::vector<std::string> split;
272 StringUtils::split(line, ',', split);
273 if (!split.empty())
274 {
275 for (Size i = 0; i != split.size(); ++i)
276 {
277 if (StringUtils::hasSubstring(split[i], "min"))
278 {
279 std::vector<std::string> split2;
280 StringUtils::trim(split[i]);
281 StringUtils::split(split[i], ' ', split2);
282 if (!split2.empty())
283 {
284 StringUtils::trim(split2[0]);
285 spectrum.setRT(StringUtils::toDouble(split2[0]) * 60.0);
286 }
287 }
288 }
289 }
290 }
291 catch (Exception::BaseException& /*e*/)
292 {
293 // just do nothing and write the whole title to spec
294 std::vector<std::string> split;
295 if (StringUtils::split(line, '=', split))
296 {
297 if (!split[1].empty()) spectrum.setMetaValue("TITLE", split[1]);
298 }
299 }
300 }
301 else // just write the title as metainfo to the spectrum and add native ID to make the titles unique
302 {
303 Size firstEqual = line.find('=', 4);
304 if (firstEqual != std::string::npos)
305 {
306 if (StringUtils::hasSubstring(StringUtils::toStr(spectrum.getMetaValue("TITLE")), spectrum.getNativeID()))
307 {
308 spectrum.setMetaValue("TITLE", StringUtils::substr(line, firstEqual + 1));
309 }
310 else
311 {
312 spectrum.setMetaValue("TITLE", StringUtils::substr(line, firstEqual + 1) + "_" + spectrum.getNativeID());
313 }
314 }
315 }
316 }
317 else if (StringUtils::hasPrefix(line, "NAME"))
318 {
319 std::string tmp = StringUtils::substr(line, 5);
320 spectrum.setMetaValue(Constants::UserParam::MSM_METABOLITE_NAME, tmp);
321 }
322 else if (StringUtils::hasPrefix(line, "COMPOUND_NAME"))
323 {
324 std::string tmp = StringUtils::substr(line, 14);
325 spectrum.setMetaValue(Constants::UserParam::MSM_METABOLITE_NAME, tmp);
326 }
327 else if (StringUtils::hasPrefix(line, "INCHI="))
328 {
329 std::string tmp = StringUtils::substr(line, 6);
330 spectrum.setMetaValue(Constants::UserParam::MSM_INCHI_STRING, tmp);
331 }
332 else if (StringUtils::hasPrefix(line, "SMILES"))
333 {
334 std::string tmp = StringUtils::substr(line, 7);
335 spectrum.setMetaValue(Constants::UserParam::MSM_SMILES_STRING, tmp);
336 }
337 else if (StringUtils::hasPrefix(line, "IONMODE"))
338 {
339 std::string tmp = StringUtils::substr(line, 8);
340 spectrum.setMetaValue("IONMODE", tmp);
341 }
342 else if (StringUtils::hasPrefix(line, "MSLEVEL"))
343 {
344 std::string tmp = StringUtils::substr(line, 8);
345 try
346 {
347 int ms_level = std::stoi(tmp);
348 spectrum.setMSLevel(ms_level);
349 }
350 catch (const std::invalid_argument& /*e*/)
351 {
352 // Default to MS2 if parsing fails
353 spectrum.setMSLevel(2);
354 spectrum.setMetaValue("MSLEVEL", "2");
355 }
356 catch (const std::out_of_range& /*e*/)
357 {
358 spectrum.setMSLevel(2);
359 }
360 }
361 else if (StringUtils::hasPrefix(line, "SOURCE_INSTRUMENT"))
362 {
363 std::string tmp = StringUtils::substr(line, 18);
364 spectrum.setMetaValue("SOURCE_INSTRUMENT", tmp);
365 }
366 else if (StringUtils::hasPrefix(line, "ORGANISM"))
367 {
368 std::string tmp = StringUtils::substr(line, 9);
369 spectrum.setMetaValue("ORGANISM", tmp);
370 }
371 else if (StringUtils::hasPrefix(line, "PI"))
372 {
373 std::string tmp = StringUtils::substr(line, 3);
374 spectrum.setMetaValue("PI", tmp);
375 }
376 else if (StringUtils::hasPrefix(line, "DATACOLLECTOR"))
377 {
378 std::string tmp = StringUtils::substr(line, 14);
379 spectrum.setMetaValue("DATACOLLECTOR", tmp);
380 }
381 else if (StringUtils::hasPrefix(line, "LIBRARYQUALITY"))
382 {
383 std::string tmp = StringUtils::substr(line, 15);
384 spectrum.setMetaValue("LIBRARYQUALITY", tmp);
385 }
386 else if (StringUtils::hasPrefix(line, "SPECTRUMID"))
387 {
388 std::string tmp = StringUtils::substr(line, 11);
389 spectrum.setMetaValue("GNPS_Spectrum_ID", tmp);
390 }
391 else if (StringUtils::hasPrefix(line, "SCANS="))
392 {
393 std::string tmp = StringUtils::substr(line, 6);
394 spectrum.setMetaValue("Scan_ID", tmp);
395 }
396 else if (StringUtils::hasPrefix(line, "SEQ="))
397 {
398 // Mascot sequence-query field: peptide sequence in one-letter code.
399 // Per spec, SEQ may appear multiple times per query (each entry is
400 // an independent sequence filter). Always stored as a StringList
401 // under the "SEQ" key for a stable interface regardless of how
402 // many SEQ lines were present.
403 std::string sequence = StringUtils::substr(line, 4);
404 StringList sequences;
405 if (spectrum.metaValueExists("SEQ"))
406 {
407 sequences = spectrum.getMetaValue("SEQ").toStringList();
408 }
409 sequences.push_back(sequence);
410 spectrum.setMetaValue("SEQ", sequences);
411 }
412 }
413 }
414 }
415
416 return false; // found end of file
417 }
418
419 };
420} // namespace OpenMS
StringList toStringList() const
Explicitly convert DataValue to StringList.
A base class for all classes handling default parameters.
Definition DefaultParamHandler.h:66
Exception base class.
Definition Exception.h:63
Invalid conversion exception.
Definition Exception.h:331
File not found exception.
Definition Exception.h:475
Parse Error exception.
Definition Exception.h:596
In-Memory representation of a mass spectrometry run.
Definition MSExperiment.h:49
void addSpectrum(const MSSpectrum &spectrum)
adds a spectrum to the list
void reset()
Clear all internal data (spectra, chromatograms, ranges, metadata)
void updateRanges()
Updates the m/z, intensity, mobility, and retention time ranges of all spectra and chromatograms.
The representation of a 1D spectrum.
Definition MSSpectrum.h:44
void setMSLevel(UInt ms_level)
Sets the MS level.
void clear(bool clear_meta_data)
Clears all data and meta data.
void setRT(double rt)
Sets the absolute retention time (in seconds)
Read/write Mascot generic files (MGF).
Definition MascotGenericFile.h:54
bool store_compact_
use a compact format for storing (no zero-intensity peaks, limited number of decimal places)?
Definition MascotGenericFile.h:126
void writeMSExperiment_(std::ostream &os, const std::string &filename, const PeakMap &experiment)
writes the MSExperiment
void writeHeader_(std::ostream &os)
writes the full header
void store(std::ostream &os, const std::string &filename, const PeakMap &experiment, bool compact=false)
store the experiment data in a MascotGenericFile; the output is written to the given stream,...
void writeModifications_(const std::vector< std::string > &mods, std::ostream &os, bool variable_mods=false)
write a list of (fixed or variable) modifications
void store(const std::string &filename, const PeakMap &experiment, bool compact=false)
stores the experiment data in a MascotGenericFile that can be used as input for MASCOT shell executio...
void writeParameterHeader_(const std::string &name, std::ostream &os)
writes a parameter header
~MascotGenericFile() override
destructor
void writeSpectrum(std::ostream &os, const PeakSpectrum &spec, const std::string &filename, const std::string &native_id_type_accession)
writes a spectrum in MGF format to an ostream
bool getNextSpectrum_(std::ifstream &is, SpectrumType &spectrum, Size &line_number, const Size &spectrum_number)
reads the next spectrum block (the section between 'BEGIN IONS' and 'END IONS') of a MGF file into sp...
Definition MascotGenericFile.h:153
void updateMembers_() override
docu in base class
void load(const std::string &filename, MapType &exp)
loads a Mascot Generic File into a PeakMap
Definition MascotGenericFile.h:82
MascotGenericFile()
constructor
std::pair< std::string, std::string > getHTTPPeakListEnclosure(const std::string &filename) const
enclosing Strings of the peak list body for HTTP submission
std::map< std::string, std::string > mod_group_map_
mapping of modifications with specificity groups, that have to be treated specially (e....
Definition MascotGenericFile.h:129
const DataValue & getMetaValue(const std::string &name) const
Returns the value corresponding to a string, or DataValue::EMPTY if not found.
void setMetaValue(const std::string &name, const DataValue &value)
Sets the DataValue corresponding to a name.
bool metaValueExists(const std::string &name) const
Returns whether an entry with the given name exists.
A 1-dimensional raw data point or peak.
Definition Peak1D.h:30
void setIntensity(IntensityType intensity)
Mutable access to the data point intensity (height)
Definition Peak1D.h:86
void setPosition(PositionType const &position)
Mutable access to the position.
Definition Peak1D.h:125
Base class for all classes that want to report their progress.
Definition ProgressLogger.h:27
const std::vector< Precursor > & getPrecursors() const
returns a const reference to the precursors
void setType(SpectrumType type)
sets the spectrum type
const std::string & getNativeID() const
returns the native identifier for the spectrum, used by the acquisition software.
void setNativeID(const std::string &native_id)
sets the native identifier for the spectrum, used by the acquisition software.
unsigned int UInt
Unsigned integer type.
Definition Types.h:64
size_t Size
Size type e.g. used as variable which can hold result of size()
Definition Types.h:97
std::vector< std::string > StringList
Vector of String.
Definition TypeAliases.h:39
Main OpenMS namespace.
Definition openswathalgo/include/OpenMS/OPENSWATHALGO/DATAACCESS/ISpectrumAccess.h:19