libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
timsmsrunreader.cpp
Go to the documentation of this file.
1/**
2 * \file pappsomspp/msrun/private/timsmsrunreader.h
3 * \date 05/09/2019
4 * \author Olivier Langella
5 * \brief MSrun file reader for native Bruker TimsTOF raw data
6 */
7
8/*******************************************************************************
9 * Copyright (c) 2019 Olivier Langella <Olivier.Langella@u-psud.fr>.
10 *
11 * This file is part of the PAPPSOms++ library.
12 *
13 * PAPPSOms++ 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++ 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++. If not, see <http://www.gnu.org/licenses/>.
25 *
26 ******************************************************************************/
27
28#include "timsmsrunreader.h"
29#include "../../exception/exceptionnotimplemented.h"
30#include "../../exception/exceptioninterrupted.h"
31#include <QDebug>
32
33using namespace pappso;
34
36 : MsRunReader(msrun_id_csp)
37{
38 initialize();
39}
40
45
46void
48{
49 msp_timsData = std::make_shared<TimsData>(mcsp_msRunId.get()->getFileName());
50
51 if(msp_timsData == nullptr)
52 {
53 throw PappsoException(QObject::tr("ERROR in TimsMsRunReader::initialize "
54 "msp_timsData is null for MsRunId %1")
55 .arg(mcsp_msRunId.get()->toString()));
56 }
57}
58
59
60bool
61TimsMsRunReader::accept(const QString &file_name) const
62{
63 qDebug() << file_name;
64 return true;
65}
66
67
69TimsMsRunReader::massSpectrumSPtr([[maybe_unused]] std::size_t spectrum_index)
70{
72 QObject::tr("Not yet implemented in TimsMsRunReader %1.\n").arg(__LINE__));
74}
75
76
78TimsMsRunReader::massSpectrumCstSPtr(std::size_t spectrum_index)
79{
80 return msp_timsData->getMassSpectrumCstSPtrByRawIndex(spectrum_index);
81}
82
83
85TimsMsRunReader::qualifiedMassSpectrum(std::size_t spectrum_index,
86 bool want_binary_data) const
87{
88
89 QualifiedMassSpectrum mass_spectrum;
90
91 msp_timsData->getQualifiedMassSpectrumByRawIndex(
92 getMsRunId(), mass_spectrum, spectrum_index, want_binary_data);
93 return mass_spectrum;
94}
95
96
97void
103
104void
107{
108
109 qDebug().noquote() << "Reading the spectrum collection with this "
110 "specific configuration:"
111 << config.toString();
112
113 std::vector<std::size_t> subset_of_tims_frame_ids;
114
115 bool asked_ion_mobility_scan_num_range = false;
116
117 quint32 mobility_scan_num_range_begin =
118 std::numeric_limits<quint32>::quiet_NaN();
119 quint32 mobility_scan_num_range_end =
120 std::numeric_limits<quint32>::quiet_NaN();
121 quint32 mobility_scan_num_range_width =
122 std::numeric_limits<quint32>::quiet_NaN();
123
124 double mobility_one_over_k0_range_begin =
125 std::numeric_limits<double>::quiet_NaN();
126 double mobility_one_over_k0_range_end =
127 std::numeric_limits<double>::quiet_NaN();
128
129 if(!config
130 .getParameterValue(
132 .isNull() &&
133 !config
134 .getParameterValue(
136 .isNull())
137 {
138 mobility_scan_num_range_begin =
139 config
142 .toUInt();
143 mobility_scan_num_range_end =
144 config
147 .toUInt();
148
149 // We need the range width below.
150 mobility_scan_num_range_width =
151 mobility_scan_num_range_end + 1 - mobility_scan_num_range_begin;
152
153 asked_ion_mobility_scan_num_range = true;
154
155 // Be sure to check in the frames loop below that the user might
156 // have asked for an ion mobility range but on the basis of the 1/K0 unit.
157 }
158
159 const std::vector<FrameIdDescr> &frame_id_descr_list =
160 msp_timsData->getFrameIdDescrList();
161
162 // Just for the feedback to the user.
163 std::size_t scan_count = 0;
164
165 for(auto const &frame_record : msp_timsData->getTimsFrameRecordList())
166 {
167 if(handler.shouldStop())
168 {
169 // qDebug() << "The operation was cancelled. Breaking the loop.";
171 QObject::tr("Reading timsTOF data cancelled by the user."));
172 }
173
174 if(frame_record.frame_id == 0)
175 continue;
176
177 if(!config.acceptRetentionTimeInSeconds(frame_record.frame_time))
178 continue;
179
180 std::size_t ms_level = 2;
181 if(frame_record.msms_type == 0)
182 ms_level = 1;
183
184 if(!config.acceptMsLevel(ms_level))
185 continue;
186
187 subset_of_tims_frame_ids.push_back(frame_record.frame_id);
188
189 if(mobility_scan_num_range_width)
190 {
191 scan_count += mobility_scan_num_range_width;
192 }
193 else
194 {
195 scan_count += frame_id_descr_list[frame_record.frame_id].m_size;
196 }
197 }
198
199 // At this point, we have a subset of frame records.
200 std::size_t frame_count = subset_of_tims_frame_ids.size();
201 qDebug() << "The number of retained RT range- and MS level-matching frames : "
202 << frame_count;
203
204 // Inform the handler of the spectrum list so that it can handle feedback to
205 // the user.
206 handler.spectrumListHasSize(scan_count);
207
208 // Check for m/z range selection
209 double mz_range_begin = -1;
210 double mz_range_end = -1;
211
213 .isNull() &&
215 {
216 mz_range_begin =
218 .toDouble();
219
220 mz_range_end =
222 .toDouble();
223
224 // qDebug() << "The m/z range asked is: " << mz_range_begin
225 // << "--" << mz_range_end;
226 }
227
228 // Check for m/z resolution downgrading (mz bins merge)
229 // The idea is that we merge a number of mz indices into a single index,
230 // which is essentially an increase of the m/z bin size, and therefore
231 // a reduction of the resolution/definition of the mass spectrum.
232 std::size_t mz_index_merge_window = 0;
233 if(!config
234 .getParameterValue(
236 .isNull())
237 {
238 mz_index_merge_window =
239 config
242 .toUInt();
243
244 // qDebug() << "mz_index_merge_window=" << mz_index_merge_window;
245 }
246
247 std::size_t number_of_mobility_scans_set_as_qualified_mass_spectra = 0;
248
249 for(std::size_t tims_frame_id : subset_of_tims_frame_ids)
250 {
251 if(handler.shouldStop())
252 {
253 // qDebug() << "The operation was cancelled. Breaking the loop.";
255 QObject::tr("Reading timsTOF data cancelled by the user."));
256 }
257
258 // qDebug() << "tims_frame_id=" << tims_frame_id;
259
260 const FrameIdDescr &current_frame_record =
261 frame_id_descr_list[tims_frame_id];
262
263 TimsFrameCstSPtr tims_frame_csp =
264 msp_timsData->getTimsFrameCstSPtrCached(tims_frame_id);
265
266 // If the user wants to select 1/Ko values in a given range, we need to
267 // compute the ion mobility scan value starting from that 1/Ko value in
268 // *each* frame. Note that the computed mobility_scan_num_begin and
269 // mobility_scan_num_end would override thoses possibly set with
270 // TimsFramesMsRunReader_mobility_index_begin/end above.
271
272 if(!config
273 .getParameterValue(
275 .isNull() &&
276 !config
277 .getParameterValue(
279 .isNull())
280 {
281 mobility_one_over_k0_range_begin =
282 config
285 .toDouble();
286
287 mobility_one_over_k0_range_end =
288 config
291 .toDouble();
292
293 mobility_scan_num_range_begin =
294 tims_frame_csp.get()->getScanNumFromOneOverK0(
295 mobility_one_over_k0_range_begin);
296
297 mobility_scan_num_range_end =
298 tims_frame_csp.get()->getScanNumFromOneOverK0(
299 mobility_one_over_k0_range_end);
300
301 asked_ion_mobility_scan_num_range = true;
302 }
303
304 // Now that we know if the user has asked for an ion mobility range,
305 // either using scan indices or 1/K0 values, we need to double check the
306 // range borders.
307
308 quint32 count_of_mobility_scans = tims_frame_csp->getTotalNumberOfScans();
309
310 if(asked_ion_mobility_scan_num_range)
311 {
312 if(mobility_scan_num_range_end > (count_of_mobility_scans - 1))
313 {
314 mobility_scan_num_range_end = count_of_mobility_scans - 1;
315 }
316 }
317 else
318 {
319 mobility_scan_num_range_begin = 0;
320 mobility_scan_num_range_end = count_of_mobility_scans - 1;
321 }
322
323 // Now, with or without the peak list, we have to craft a qualified mass
324 // spectrum that will hold all the data about the data in it.
325 QualifiedMassSpectrum mass_spectrum;
326
327 MassSpectrumId spectrum_id;
328
329 spectrum_id.setSpectrumIndex(tims_frame_id);
330 spectrum_id.setMsRunId(getMsRunId());
331
332 mass_spectrum.setMassSpectrumId(spectrum_id);
333
334 // We want to document the retention time!
335 mass_spectrum.setRtInSeconds(tims_frame_csp.get()->getTime());
336
337 // We do want to document the ms level of the spectrum and possibly
338 // the precursor's m/z and charge.
339 unsigned int frame_ms_level = tims_frame_csp.get()->getMsLevel();
340 mass_spectrum.setMsLevel(frame_ms_level);
341
342 // The scan index is the index of the scan in the *whole* mass data file,
343 // it is a sequential number of scans over all the frames.
344 std::size_t scan_index = current_frame_record.m_cumulSize -
345 current_frame_record.m_size +
346 mobility_scan_num_range_begin;
347
348 for(quint32 iter_scan_index = mobility_scan_num_range_begin;
349 iter_scan_index <= mobility_scan_num_range_end;
350 iter_scan_index++)
351 {
352 mass_spectrum.getMassSpectrumId().setSpectrumIndex(scan_index);
353
354 mass_spectrum.getMassSpectrumId().setNativeId(
355 QString("frame_id=%1 scan_index=%2 global_scan_index=%3")
356 .arg(tims_frame_id)
357 .arg(iter_scan_index)
358 .arg(scan_index));
359
360 // qDebug() << "iter:" << iter;
361
362 if(config.needPeakList())
363 {
364 quint32 mz_minimum_index_out = 0;
365 quint32 mz_maximum_index_out = 0;
366
367 auto raw_trace =
368 tims_frame_csp.get()->getMobilityScan(iter_scan_index,
369 mz_index_merge_window,
370 mz_range_begin,
371 mz_range_end,
372 mz_minimum_index_out,
373 mz_maximum_index_out);
374
375 // qDebug() << "Ion mobility scan's raw trace size:"
376 // << raw_trace.size();
377
378 mass_spectrum.setEmptyMassSpectrum(false);
379
380 mass_spectrum.setParameterValue(
382 mz_minimum_index_out);
383 mass_spectrum.setParameterValue(
385 mz_maximum_index_out);
386
387 // qDebug() << "Scan's mz_minimum_index:" << mz_minimum_index_out
388 // << "and mz_maximum_index:" << mz_maximum_index_out;
389
390 // Arrival time
391 mass_spectrum.setDtInMilliSeconds(
392 tims_frame_csp.get()->getDriftTime(iter_scan_index));
393 // 1/K0
394 mass_spectrum.setParameterValue(
396 tims_frame_csp.get()->getOneOverK0Transformation(
397 iter_scan_index));
398
399 qDebug();
400 mass_spectrum.setMassSpectrumSPtr(
401 std::make_shared<MassSpectrum>(raw_trace));
402
403 qDebug();
404 }
405 else
406 {
407 mass_spectrum.setEmptyMassSpectrum(true);
408 }
409
410 // qDebug() << "mz_index_merge_window=" << mz_index_merge_window;
411 handler.setQualifiedMassSpectrum(mass_spectrum);
412 ++number_of_mobility_scans_set_as_qualified_mass_spectra;
413 scan_index++;
414 }
415 }
416
417 qDebug() << "Total number of loaded mass spectra:"
418 << number_of_mobility_scans_set_as_qualified_mass_spectra;
419}
420
421void
423 SpectrumCollectionHandlerInterface &handler, unsigned int ms_level)
424{
425
426 qDebug();
427
428 try
429 {
430
431 msp_timsData.get()->rawReaderSpectrumCollectionByMsLevel(
432 getMsRunId(), handler, ms_level);
433 }
434
435 catch(ExceptionInterrupted &)
436 {
437 qDebug() << "Reading of MS data interrupted by the user.";
438 }
439
440 // Now let the loading handler know that the loading of the data has ended.
441 // The handler might need this "signal" to perform additional tasks or to
442 // cleanup cruft.
443
444 // qDebug() << "Loading ended";
445 handler.loadingEnded();
446}
447
448
449std::size_t
451{
452 return msp_timsData->getTotalNumberOfScans();
453}
454
455
456bool
458{
459 return false;
460}
461
462
463bool
465{
466 msp_timsData = nullptr;
467 return true;
468}
469
470bool
472{
473 if(msp_timsData == nullptr)
474 {
475 initialize();
476 }
477 return true;
478}
479
480
483 [[maybe_unused]],
484 pappso::PrecisionPtr precision
485 [[maybe_unused]]) const
486{
487 throw ExceptionNotImplemented(QObject::tr("Not implemented %1 %2 %3")
488 .arg(__FILE__)
489 .arg(__FUNCTION__)
490 .arg(__LINE__));
491}
492
495 const pappso::QualifiedMassSpectrum &mass_spectrum [[maybe_unused]],
496 pappso::PrecisionPtr precision [[maybe_unused]]) const
497{
498 throw ExceptionNotImplemented(QObject::tr("Not implemented %1 %2 %3")
499 .arg(__FILE__)
500 .arg(__FUNCTION__)
501 .arg(__LINE__));
502}
503
510
511
512Trace
514{
515 // Use the Sqlite database to fetch the total ion current chromatogram (TIC
516 // chromatogram).
517
519
520 // The time unit here is seconds, not minutes!!!
521 return msp_timsData->getTicChromatogram();
522}
void setNativeId(const QString &native_id)
void setMsRunId(MsRunIdCstSPtr other)
void setSpectrumIndex(std::size_t index)
const QVariant getParameterValue(MsRunReadConfigParameter parameter) const
bool acceptMsLevel(std::size_t ms_level) const
bool acceptRetentionTimeInSeconds(double retention_time_in_seconds) const
base class to read MSrun the only way to build a MsRunReader object is to use the MsRunReaderFactory
Definition msrunreader.h:63
MsRunIdCstSPtr mcsp_msRunId
const MsRunIdCstSPtr & getMsRunId() const
Class representing a fully specified mass spectrum.
void setDtInMilliSeconds(pappso_double rt)
Set the drift time in milliseconds.
const MassSpectrumId & getMassSpectrumId() const
Get the MassSpectrumId.
void setMassSpectrumId(const MassSpectrumId &iD)
Set the MassSpectrumId.
void setMsLevel(uint ms_level)
Set the mass spectrum level.
void setParameterValue(QualifiedMassSpectrumParameter parameter, const QVariant &value)
void setMassSpectrumSPtr(MassSpectrumSPtr massSpectrum)
Set the MassSpectrumSPtr.
void setRtInSeconds(pappso_double rt)
Set the retention time in seconds.
void setEmptyMassSpectrum(bool is_empty_mass_spectrum)
interface to collect spectrums from the MsRunReader class
virtual void setQualifiedMassSpectrum(const QualifiedMassSpectrum &spectrum)=0
TimsMsRunReader(MsRunIdCstSPtr &msrun_id_csp)
virtual void readSpectrumCollection2(const MsRunReadConfig &config, SpectrumCollectionHandlerInterface &handler) override
virtual void readSpectrumCollection(SpectrumCollectionHandlerInterface &handler) override
function to visit an MsRunReader and get each Spectrum in a spectrum collection handler
virtual void readSpectrumCollectionByMsLevel(SpectrumCollectionHandlerInterface &handler, unsigned int ms_level) override
function to visit an MsRunReader and get each Spectrum in a spectrum collection handler by Ms Levels
virtual MassSpectrumCstSPtr massSpectrumCstSPtr(std::size_t spectrum_index) override
virtual MassSpectrumSPtr massSpectrumSPtr(std::size_t spectrum_index) override
get a MassSpectrumSPtr class given its spectrum index
virtual bool hasScanNumbers() const override
tells if spectra can be accessed using scan numbers by default, it returns false. Only overrided func...
virtual pappso::XicCoordSPtr newXicCoordSPtrFromSpectrumIndex(std::size_t spectrum_index, pappso::PrecisionPtr precision) const override
get a xic coordinate object from a given spectrum index
virtual QualifiedMassSpectrum qualifiedMassSpectrum(std::size_t spectrum_index, bool want_binary_data=true) const override
get a QualifiedMassSpectrum class given its scan number
virtual bool releaseDevice() override
release data back end device if a the data back end is released, the developper has to use acquireDev...
virtual bool acquireDevice() override
acquire data back end device
virtual bool accept(const QString &file_name) const override
tells if the reader is able to handle this file must be implemented by private MS run reader,...
virtual TimsDataSp getTimsDataSPtr()
give an access to the underlying raw data pointer
virtual void initialize() override
virtual std::size_t spectrumListSize() const override
get the totat number of spectrum conained in the MSrun data file
virtual pappso::XicCoordSPtr newXicCoordSPtrFromQualifiedMassSpectrum(const pappso::QualifiedMassSpectrum &mass_spectrum, pappso::PrecisionPtr precision) const override
get a xic coordinate object from a given spectrum
virtual Trace getTicChromatogram() override
get a TIC chromatogram
A simple container of DataPoint instances.
Definition trace.h:148
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
std::shared_ptr< const MsRunId > MsRunIdCstSPtr
Definition msrunid.h:46
std::shared_ptr< TimsData > TimsDataSp
shared pointer on a TimsData object
Definition timsdata.h:50
std::shared_ptr< const MassSpectrum > MassSpectrumCstSPtr
@ TimsIonMobScanOneOverK0
1/kO of a simple scan
@ TimsFrameMzIndexBegin
Bruker's timsTOF mz index frame start range.
@ TimsFrameMzIndexEnd
Bruker's timsTOF mz index frame end range.
std::shared_ptr< MassSpectrum > MassSpectrumSPtr
std::shared_ptr< const TimsFrame > TimsFrameCstSPtr
Definition timsframe.h:43
std::shared_ptr< XicCoord > XicCoordSPtr
Definition xiccoord.h:43
std::size_t m_cumulSize
Definition timsdata.h:57
std::size_t m_size
Definition timsdata.h:56
MSrun file reader for native Bruker TimsTOF raw data.