libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
spectrum.cpp
Go to the documentation of this file.
1/**
2 * \file pappsomspp/core/processing/cbor/mzcbor/spectrum.h
3 * \date 24/11/2025
4 * \author Olivier Langella
5 * \brief PSI spectrum object for mzML/mzCBOR
6 */
7
8/*******************************************************************************
9 * Copyright (c) 2025 Olivier Langella <Olivier.Langella@universite-paris-saclay.fr>.
10 *
11 * This file is part of PAPPSOms-tools.
12 *
13 * PAPPSOms-tools is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * PAPPSOms-tools is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>.
25 *
26 ******************************************************************************/
27
28
29#include "spectrum.h"
34#include <qdebug.h>
35#include <qjsonarray.h>
36#include <qjsonobject.h>
37#include <qlogging.h>
38#include <qtypes.h>
39#include <unistd.h>
40
41
42void
44{
45 QString txt_value;
46 // cborBinaryDataArray.clear();
47 precursorList.clear();
49 index = 0;
50 cvParamMap.clear();
51 scanListCvParamMap.clear();
52 scanList.clear();
53 id.clear();
54 qDebug();
55
56 if(reader.isInvalid())
57 {
59 QObject::tr("ERROR in Spectrum::fromCbor :\ncbor is not valid"));
60 }
61 if(reader.enterContainer())
62 {
63 while(reader.hasNext() && (!reader.isInvalid()))
64 {
65 if(reader.isString())
66 {
67 reader.decodeString(txt_value);
68 qDebug() << txt_value;
69 if(txt_value == "id")
70 {
71 reader.decodeString(txt_value);
72 qDebug() << txt_value;
73 id = txt_value;
74 }
75 else if(txt_value == "index")
76 {
77 index = reader.toUnsignedInteger();
78 reader.next();
79 }
80 else if(txt_value == "defaultArrayLength")
81 {
82 defaultArrayLength = reader.toUnsignedInteger();
83 reader.next();
84 }
85 else if(txt_value == "cvParam")
86 {
87 cvParamMap.fromCbor(reader);
88 }
89 else if(txt_value == "scanList")
90 {
91 // mpa_cborReader->next();
92 reader.enterContainer();
93
94 while(reader.hasNext() && (!reader.isInvalid()))
95 {
96 if(reader.isString())
97 {
98 if(reader.decodeString(txt_value))
99 {
100 qDebug() << txt_value;
101 if(txt_value == "cvParam")
102 {
103 scanListCvParamMap.fromCbor(reader);
104 }
105 else if(txt_value == "scan")
106 {
107 // scan array
108 reader.enterContainer();
109
110 while(reader.hasNext() && (!reader.isInvalid()))
111 {
112 // scan array
113 Scan scan;
114 scan.fromCbor(reader);
115 scanList.emplace_back(scan);
116 }
117 reader.leaveContainer();
118 }
119 }
120 else
121 {
122 reader.next();
123 }
124 }
125 else
126 {
127 reader.next();
128 }
129 }
130 reader.leaveContainer();
131 }
132 else if(txt_value == "precursorList")
133 {
134
135 reader.enterContainer();
136
137 while(reader.hasNext() && (!reader.isInvalid()))
138 {
139 if(reader.isString())
140 {
141 if(reader.decodeString(txt_value))
142 {
143 qDebug() << txt_value;
144
145 if(txt_value == "cvParam")
146 {
147 precursorListCvParamMap.fromCbor(reader);
148 }
149 else if(txt_value == "precursor")
150 {
151
152 reader
153 .enterContainer(); // array
154
155 while(reader.hasNext() && (!reader.isInvalid()))
156 {
157 // scan array
158 Precursor precursor;
159 precursor.fromCbor(reader);
160 precursorList.emplace_back(precursor);
161 }
162 reader
163 .leaveContainer(); // array
164
165 // reader.next();
166 }
167 else
168 {
169 reader.next();
170 }
171 }
172 else
173 {
174 reader.next();
175 }
176 }
177 else
178 {
179 reader.next();
180 }
181 }
182 reader.leaveContainer();
183 }
184 else if(txt_value == "binaryDataArray")
185 {
186 if(want_binary_data)
187 {
188
189 reader.enterContainer(); // start array
190
191 while(reader.hasNext())
192 {
193
194 BinaryDataArray data_array;
195 data_array.fromCbor(reader);
196 binaryDataArrayList.emplace_back(data_array);
197 }
198
199 reader.leaveContainer(); // end array
200 }
201 else
202 {
203 reader.next();
204 }
205 }
206 else
207 {
208 reader.next();
209 }
210 }
211 // reader.next();
212 }
213
214 reader.leaveContainer();
215 }
216 else
217 {
218 throw pappso::PappsoException(QObject::tr("ERROR in Spectrum::fromCbor : no container"));
219 }
220
221
222 if(reader.lastError() != QCborError::NoError)
223 {
225 QObject::tr("ERROR in Spectrum::fromCbor :\n%1").arg(reader.lastError().toString()));
226 }
227}
228
229
230QJsonObject
232{
233 QJsonObject spectrum_json;
234 spectrum_json.insert("id", id);
235 spectrum_json.insert("index", (qint64)index);
236 spectrum_json.insert("defaultArrayLength", (qint64)defaultArrayLength);
237 spectrum_json.insert("cvParam", cvParamMap.toJsonArray());
238
239 QJsonObject scan_list;
240 // QJsonObject scan_list_cvparam;
241 scan_list.insert("cvParam", scanListCvParamMap.toJsonArray());
242 QJsonArray scan_array;
243 for(auto &scan : scanList)
244 {
245 scan_array.append(scan.toJsonObject());
246 }
247 scan_list.insert("scan", scan_array);
248 spectrum_json.insert("scanList", scan_list);
249
250 if(!precursorList.empty())
251 {
252 QJsonObject precursor_list;
253 // QJsonObject scan_list_cvparam;
254 precursor_list.insert("cvParam", precursorListCvParamMap.toJsonArray());
255 QJsonArray precursor_array;
256 for(auto &precursor : precursorList)
257 {
258 precursor_array.append(precursor.toJsonObject());
259 }
260 precursor_list.insert("precursor", precursor_array);
261 spectrum_json.insert("precursorList", precursor_list);
262 }
263
264 if(!binaryDataArrayList.empty())
265 {
266 Trace trace;
267
268 decodeTrace(trace);
269
270
271 spectrum_json.insert("spectrum", trace.toJsonObject());
272 }
273
274 return spectrum_json;
275}
276
277std::map<QString, pappso::cbor::mzcbor::CvParam>
279{
280 CvParamMap cv_params;
281 reader.enterContainer();
282 QString txt_value;
283
284 while(reader.hasNext() && (!reader.isInvalid()))
285 {
286 if(reader.isString())
287 {
288 if(reader.decodeString(txt_value))
289 {
290 qDebug() << txt_value;
291 if(txt_value == "cvParam")
292 {
293 cv_params.fromCbor(reader);
294 }
295 else
296 {
297 reader.next();
298 }
299 }
300 }
301 else
302 {
303 reader.next();
304 }
305 }
306
307 reader.leaveContainer();
308 return cv_params;
309}
310
311
312qint64
314{
315 // <cvParam cvRef="MS" accession="MS:1000285" value="17377980" name="total ion current" />
316
317 auto it = cvParamMap.find("MS:1000285");
318 if(it == cvParamMap.end())
319 {
320 throw pappso::ExceptionNotFound(QObject::tr("total ion count not found in cvParam map"));
321 }
322 qDebug() << it->first << " " << it->second.valueInt;
323 return it->second.valueInt;
324}
325
326
327uint
329{
330 // <cvParam cvRef="MS" accession="MS:1000511" value="1" name="ms level" />
331
332 auto it = cvParamMap.find("MS:1000511");
333 if(it == cvParamMap.end())
334 {
335 throw pappso::ExceptionNotFound(QObject::tr("MS level not found in cvParam map"));
336 }
337 qDebug() << it->first << " " << it->second.valueInt;
338 return it->second.valueInt;
339}
340
341double
343{
344 if(scanList.size() == 0)
345 {
346 throw pappso::ExceptionNotFound(QObject::tr("scan list is empty in spectrum"));
347 }
348 if(scanList.size() > 1)
349 {
350 throw pappso::ExceptionNotFound(QObject::tr("too many scans in spectrum"));
351 }
352 return scanList.front().getRtInSeconds();
353}
354
355void
357{
358 qDebug();
359 std::vector<pappso_double> xVector;
360 std::vector<pappso_double> yVector;
361 for(auto &binary_array : binaryDataArrayList)
362 {
363 qDebug();
364 if(binary_array.isIntensity())
365 {
366 qDebug();
367 binary_array.decodeVector(defaultArrayLength, yVector);
368 }
369 else if(binary_array.isMz())
370 {
371 qDebug();
372 binary_array.decodeVector(defaultArrayLength, xVector);
373 }
374 else
375 {
376
377 throw pappso::ExceptionNotFound(QObject::tr(
378 "error in pappso::cbor::mzcbor::Spectrum::decodeTrace: binary vector type not found"));
379 }
380 qDebug();
381 }
382
383 qDebug();
384 trace.initialize(xVector, yVector);
385 qDebug();
386}
387
388void
389pappso::cbor::mzcbor::Spectrum::toMgf(QTextStream &output, MsRunIdCstSPtr msrun_id_csptr) const
390{
391 // BEGIN IONS
392 // TITLE=20120906_balliau_extract_1_A01_urnb-1.2016.2016.3
393 // RTINSECONDS=679.467
394 // PEPMASS=417.210251631473 92010.6328125
395 // CHARGE=3+
396 // 88.03964233 1132.5438232422
397 // 91.05783844 1945.9479980469
398 // 93.03697968 6423.5581054688
399 // 93.8877182 949.33984375
400 output << "BEGIN IONS" << Qt::endl;
401 QString title;
402 if(msrun_id_csptr.get() != nullptr)
403 {
404 title = msrun_id_csptr.get()->getSampleName();
405 }
406
407 output << "TITLE=" << title << "." << index << Qt::endl;
408 output << "RTINSECONDS=" << QString::number(scanList.front().getRtInSeconds(), 'f', 4)
409 << Qt::endl;
410 bool is_ok;
411 double intensity = precursorList.front().selectedIonList.front().getIntensity(&is_ok);
412 if(is_ok)
413 {
414 output << "PEPMASS="
415 << QString::number(precursorList.front().selectedIonList.front().getMz(), 'f', 8)
416 << " " << QString::number(intensity, 'g', 10) << Qt::endl;
417 }
418 else
419 {
420 output << "PEPMASS="
421 << QString::number(precursorList.front().selectedIonList.front().getMz(), 'f', 8)
422 << Qt::endl;
423 }
424 output << "CHARGE=" << precursorList.front().selectedIonList.front().getChargeState() << "+"
425 << Qt::endl;
426
427 Trace trace;
428 decodeTrace(trace);
429
430 for(const pappso::DataPoint &one_point : trace)
431 {
432 output << QString::number(one_point.x, 'f', 8) << " " << QString::number(one_point.y, 'f', 8)
433 << Qt::endl;
434 }
435 output << "END IONS" << Qt::endl;
436}
A simple container of DataPoint instances.
Definition trace.h:152
QJsonObject toJsonObject(const QString &x_label="x", const QString &y_label="y") const
serialize a PAPPSO trace object to JSON
Definition trace.cpp:1191
size_t initialize(const std::vector< pappso_double > &xVector, const std::vector< pappso_double > &yVector)
Definition trace.cpp:597
simple override of the raw QCborStreamReader This adds convenient functions to put CBOR data into C++...
bool decodeString(QString &the_str)
decode the current cbor value as a string the point to the next value the current value is decoded as...
cvParam map
std::shared_ptr< const MsRunId > MsRunIdCstSPtr
Definition msrunid.h:46
unsigned int uint
Definition types.h:67
PSI scan object for mzML/mzCBOR.
PSI spectrum object for mzML/mzCBOR.
void fromCbor(CborStreamReader &reader)
void fromCbor(CborStreamReader &reader)
fill the structure reading data from a CBOR stream
void fromCbor(CborStreamReader &reader)
void fromCbor(CborStreamReader &reader)
Definition scan.cpp:57
static std::map< QString, pappso::cbor::mzcbor::CvParam > readScanCvParams(CborStreamReader &reader)
Definition spectrum.cpp:278
void toMgf(QTextStream &output, MsRunIdCstSPtr msrun_id_csptr) const
write spectrum in MGF text format
Definition spectrum.cpp:389
std::vector< Precursor > precursorList
Definition spectrum.h:89
std::vector< Scan > scanList
Definition spectrum.h:88
QJsonObject toJsonObject() const
write the structure to a JSON object This is a simplified representation for easy JSON data handling ...
Definition spectrum.cpp:231
void fromCbor(CborStreamReader &reader, bool want_binary_data)
fill the structure reading data from a CBOR stream
Definition spectrum.cpp:43
void decodeTrace(pappso::Trace &trace) const
Definition spectrum.cpp:356
std::vector< BinaryDataArray > binaryDataArrayList
Definition spectrum.h:90