libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
timsdiaslices.cpp
Go to the documentation of this file.
1/**
2 * \file pappsomspp/vendors/tims/timsdiaslices.cpp
3 * \date 02/07/2024
4 * \brief handle specific data for DIA MS runs
5 */
6
7/*******************************************************************************
8 * Copyright (c) 2024 Olivier Langella <Olivier.Langella@u-psud.fr>.
9 *
10 * This file is part of the PAPPSOms++ library.
11 *
12 * PAPPSOms++ is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * PAPPSOms++ is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with PAPPSOms++. If not, see <http://www.gnu.org/licenses/>.
24 *
25 ******************************************************************************/
26
27#include "timsdiaslices.h"
29
30#include <iterator>
31#include <QSqlError>
32
33namespace pappso
34{
35
36bool
38{
39 double half_window = IsolationWidth / 2;
40 if(mz < (IsolationMz - half_window))
41 return false;
42 if(mz > (IsolationMz + half_window))
43 return false;
44 return true;
45}
46
48{
49 for(MsMsWindowGroup *p_group : *this)
50 {
51 delete p_group;
52 }
53}
54
55void
57{
58 std::size_t group_id = window.WindowGroup;
59 auto it_in_list = std::find_if(begin(), end(), [group_id](const MsMsWindowGroup *group) {
60 if(group->WindowGroup == group_id)
61 return true;
62 return false;
63 });
64 if(it_in_list == end())
65 {
66
67 qDebug();
68 MsMsWindowGroup *new_group = new MsMsWindowGroup();
69 new_group->WindowGroup = group_id;
70 new_group->push_back(window);
71 push_back(new_group);
72 }
73 else
74 {
75 qDebug();
76 (*it_in_list)->push_back(window);
77
78 std::sort(
79 (*it_in_list)->begin(), (*it_in_list)->end(), [](const MsMsWindow &a, const MsMsWindow &b) {
80 return (a.ScanNumBegin < b.ScanNumBegin);
81 });
82 std::size_t i = 0;
83 for(MsMsWindow &window : *(*it_in_list))
84 {
85 window.SliceIndex = i;
86 i++;
87 }
88 }
89 qDebug();
90}
91
94{
95
96 auto it_in_list = std::find_if(begin(), end(), [window_group_id](const MsMsWindowGroup *group) {
97 if(group->WindowGroup == window_group_id)
98 return true;
99 return false;
100 });
101
102 if(it_in_list == end())
103 {
105 QObject::tr("MsMsWindowGroup %1 not found").arg(window_group_id));
106 }
107 return *it_in_list;
108}
109
110TimsDiaSlices::TimsDiaSlices(QSqlQuery &query, TimsData *tims_data_origin)
111 : mp_timsDataOrigin(tims_data_origin)
112{
113
114 /*
115CREATE TABLE IF NOT EXISTS "DiaFrameMsMsWindows" (
116"WindowGroup" INTEGER NOT NULL,
117"ScanNumBegin" INTEGER NOT NULL,
118"ScanNumEnd" INTEGER NOT NULL,
119"IsolationMz" REAL NOT NULL,
120"IsolationWidth" REAL NOT NULL,
121"CollisionEnergy" REAL NOT NULL,
122FOREIGN KEY("WindowGroup") REFERENCES "FrameMsMsWindowGroups"("Id"),
123PRIMARY KEY("WindowGroup","ScanNumBegin")
124) WITHOUT ROWID;
125*/
126
127 if(!query.exec("SELECT WindowGroup, ScanNumBegin, ScanNumEnd, IsolationMz, "
128 "IsolationWidth, CollisionEnergy FROM DiaFrameMsMsWindows;"))
129 {
130 qDebug();
131 throw ExceptionNotFound(QObject::tr("ERROR : executing %1 :\n%2")
132 .arg(query.lastQuery())
133 .arg(query.lastError().text()));
134 }
135 else
136 {
137
138 qDebug() << query.size();
139 if(query.size() == 0)
140 {
141 qDebug();
142 // FIXME: this exception is thrown, but my file is DDA.
143 // That's not a nice info...
144 throw ExceptionNotFound(
145 QObject::tr("ERROR : DiaFrameMsMsWindows table is empty in SqlLite database"));
146 }
147 MsMsWindow msms_window;
148 while(query.next())
149 {
150 qDebug();
151 msms_window.WindowGroup = query.value(0).toLongLong();
152 msms_window.ScanNumBegin = query.value(1).toLongLong();
153 msms_window.ScanNumEnd = query.value(2).toLongLong();
154 msms_window.IsolationMz = query.value(3).toDouble();
155 msms_window.IsolationWidth = query.value(4).toDouble();
156 msms_window.CollisionEnergy = query.value(5).toDouble();
157
158 qDebug();
159 m_msMsWindowGroupList.addInGroup(msms_window);
160 }
161
162 if(m_msMsWindowGroupList.size() == 0)
163 {
164 qDebug();
165 // FIXME: this exception is thrown, but my file is DDA.
166 // That's not a nice info...
167 throw ExceptionNotFound(
168 QObject::tr("ERROR : no DiaFrameMsMsWindows in SqlLite database"));
169 }
170 }
171
172 qDebug();
173 std::size_t max_frame_id = 0;
174 if(!query.exec("SELECT Frame, WindowGroup FROM DiaFrameMsMsInfo;"))
175 {
176 qDebug();
178 QObject::tr("ERROR : no DiaFrameMsMsInfo in SqlLite database"));
179 }
180 else
181 {
182 qDebug() << query.size();
183 if(query.size() == 0)
184 {
185 qDebug();
187 QObject::tr("ERROR : no DiaFrameMsMsInfo in SqlLite database"));
188 }
189 while(query.next())
190 {
191 qDebug();
192 max_frame_id = query.value(0).toLongLong();
193 m_mapFrame2WindowGroupPtr[query.value(0).toLongLong()] =
194 m_msMsWindowGroupList.getWindowGroupPtrByGroupId(query.value(1).toLongLong());
195 }
196
197 if(m_mapFrame2WindowGroupPtr.size() == 0)
198 {
199 qDebug();
200 throw ExceptionNotFound(QObject::tr("ERROR : no DiaFrameMsMsInfo in SqlLite database"));
201 }
202 }
203 qDebug();
204
205 m_frameId2GlobalSliceIndexBegin.resize(max_frame_id + 1);
206
207 m_ms2frameId2Ms1FrameId.resize(max_frame_id + 1);
208 std::size_t last_ms1 = 0;
209 std::size_t previous_frame = 0;
210
211 std::size_t cumul_global_slice = 0;
212 m_ms1frameIdList.clear();
213 for(const std::pair<std::size_t, MsMsWindowGroup *> pair_frame_pgroup : m_mapFrame2WindowGroupPtr)
214 {
215 if(previous_frame != pair_frame_pgroup.first - 1)
216 {
217 last_ms1 = previous_frame + 1;
218 m_ms1frameIdList.push_back(last_ms1);
219 }
220 previous_frame = pair_frame_pgroup.first;
221 qDebug() << pair_frame_pgroup.first << " " << m_frameId2GlobalSliceIndexBegin.size();
222 FrameSliceRange slice_range;
223 qDebug() << pair_frame_pgroup.first;
224 slice_range.frame_id = pair_frame_pgroup.first;
225 slice_range.begin_global_slice_index = cumul_global_slice;
226 m_frameId2GlobalSliceIndexBegin[pair_frame_pgroup.first] = cumul_global_slice;
227 m_ms2frameId2Ms1FrameId[pair_frame_pgroup.first] = last_ms1;
228
229 cumul_global_slice += pair_frame_pgroup.second->size();
230
231 if(cumul_global_slice > 0)
232 slice_range.end_global_slice_index = cumul_global_slice - 1;
233 m_frameSliceRangeList.push_back(slice_range);
234 }
235
236 qDebug();
237 m_totalSlicesCount = cumul_global_slice;
238}
239
243
244const std::map<std::size_t, TimsDiaSlices::MsMsWindowGroup *> &
254
255std::size_t
257{
258 return (m_frameId2GlobalSliceIndexBegin[frame_id]);
259}
260std::size_t
261TimsDiaSlices::getFrameIdByGlobalSliceIndex(std::size_t global_slice_id) const
262{
263 return (getFrameSliceRangeByGlobalSliceIndex(global_slice_id).frame_id);
264}
265
267TimsDiaSlices::getFrameSliceRangeByGlobalSliceIndex(std::size_t global_slice_index) const
268{
269
270 qDebug();
271 auto it = std::find_if(m_frameSliceRangeList.cbegin(),
273 [global_slice_index](const FrameSliceRange &x) {
274 if(global_slice_index < x.begin_global_slice_index)
275 return false;
276 if(global_slice_index > x.end_global_slice_index)
277 return false;
278 return true;
279 });
280
281 if(it != m_frameSliceRangeList.cend())
282 {
283 return *it;
284 }
285 qDebug();
286 throw ExceptionNotFound(
287 QObject::tr("ERROR : GlobalSliceIndex %1 not found").arg(global_slice_index));
288}
289
290std::size_t
295
297TimsDiaSlices::getMsMsWindowByGlobalSliceIndex(std::size_t global_slice_index) const
298{
299 qDebug() << global_slice_index;
300 const TimsDiaSlices::FrameSliceRange &range =
301 getFrameSliceRangeByGlobalSliceIndex(global_slice_index);
302
303 qDebug() << "range.frame_id=" << range.frame_id
304 << " range.begin_global_slice_index=" << range.begin_global_slice_index;
305 return m_mapFrame2WindowGroupPtr.at(range.frame_id)
306 ->at(global_slice_index - range.begin_global_slice_index);
307}
308
309std::size_t
311{
312
313 return m_ms2frameId2Ms1FrameId.at(frame_id);
314}
315
316
318TimsDiaSlices::getCombinedMs2ScansByGlobalSliceIndex(std::size_t global_slice_index) const
319{
320
321 qDebug();
323 raw_spectrum.clear();
324 try
325 {
326 FrameSliceRange range = getFrameSliceRangeByGlobalSliceIndex(global_slice_index);
327
329 ->at(global_slice_index - range.begin_global_slice_index);
330 qDebug();
331 TimsFrameCstSPtr tims_frame;
332 tims_frame = mp_timsDataOrigin->getTimsFrameCstSPtrCached(range.frame_id);
333 qDebug();
334 /*combiner.combine(combiner_result,
335 tims_frame.get()->cumulateScanToTrace(
336 scan_mobility_start, scan_mobility_end));*/
337 tims_frame.get()->combineScansInTofIndexIntensityMap(
338 raw_spectrum, window.ScanNumBegin, window.ScanNumEnd);
339 qDebug();
340 }
341
342 catch(PappsoException &error)
343 {
344 throw PappsoException(QObject::tr("ERROR in %1 (global_slice_index=%2):\n%3")
345 .arg(__FUNCTION__)
346 .arg(global_slice_index)
347 .arg(error.qwhat()));
348 }
349 catch(std::exception &error)
350 {
351 qDebug() << QString("Failure %1 ").arg(error.what());
352 }
353 return raw_spectrum;
354 qDebug();
355}
356void
358 QualifiedMassSpectrum &mass_spectrum,
359 std::size_t global_slice_index,
360 bool want_binary_data) const
361{
362
363 qDebug();
364 try
365 {
366 FrameSliceRange range = getFrameSliceRangeByGlobalSliceIndex(global_slice_index);
367
369 ->at(global_slice_index - range.begin_global_slice_index);
370
371 MassSpectrumId spectrum_id;
372
373 spectrum_id.setSpectrumIndex(global_slice_index);
374 spectrum_id.setNativeId(
375 QString("global_slice_index=%1 frame=%2 begin=%3 end=%4 group=%5 slice=%6")
376 .arg(global_slice_index)
377 .arg(range.frame_id)
378 .arg(window.ScanNumBegin)
379 .arg(window.ScanNumEnd)
380 .arg(window.WindowGroup)
381 .arg(window.SliceIndex));
382
383 spectrum_id.setMsRunId(msrun_id);
384
385 mass_spectrum.setMassSpectrumId(spectrum_id);
386
387 mass_spectrum.setMsLevel(2);
388 // mass_spectrum.setPrecursorSpectrumIndex(spectrum_descr.ms1_index);
389
390 mass_spectrum.setEmptyMassSpectrum(true);
391
392 qDebug();
393
394 // get precursor ion data
395
396 // mass_spectrum.appendPrecursorIonData(spectrum_descr.precursor_ion_data);
397
398 mass_spectrum.setPrecursorNativeId(QString("frame_id=%1 begin=%2 end=%3 group=%4 slice=%5")
399 .arg(m_ms2frameId2Ms1FrameId.at(range.frame_id))
400 .arg(window.ScanNumBegin)
401 .arg(window.ScanNumEnd)
402 .arg(window.WindowGroup)
403 .arg(window.SliceIndex));
404
406 window.IsolationMz);
408 window.IsolationWidth);
410 window.IsolationWidth);
411
413 window.CollisionEnergy);
414
415
416 qDebug() << window.ScanNumBegin;
418 (qulonglong)window.ScanNumBegin);
419
420
421 qDebug() << window.ScanNumEnd;
423 (qulonglong)window.ScanNumEnd);
424 qDebug();
425 TimsFrameBaseCstSPtr tims_frame;
426
427
428 if(want_binary_data)
429 {
430 qDebug() << "bindec";
431 tims_frame = mp_timsDataOrigin->getTimsFrameCstSPtrCached(range.frame_id);
432 }
433 else
434 {
435 tims_frame = mp_timsDataOrigin->getTimsFrameBaseCstSPtrCached(range.frame_id);
436 }
437
438 mass_spectrum.setRtInSeconds(tims_frame.get()->getRtInSeconds());
439
440
441 mass_spectrum.setParameterValue(
443 tims_frame.get()->getOneOverK0Transformation(window.ScanNumBegin));
444
445 mass_spectrum.setParameterValue(
447 tims_frame.get()->getOneOverK0Transformation(window.ScanNumEnd));
448
449 qDebug();
450 /*combiner.combine(combiner_result,
451 tims_frame.get()->cumulateScanToTrace(
452 scan_mobility_start, scan_mobility_end));*/
453 if(want_binary_data)
454 {
455
457 raw_spectrum.clear();
458 tims_frame.get()->combineScansInTofIndexIntensityMap(
459 raw_spectrum, window.ScanNumBegin, window.ScanNumEnd);
460
461
462 Trace trace;
464 {
465 // raw_spectrum.removeArtefactualSpike();
466 raw_spectrum.builtInCentroid();
467 }
468
469 trace = tims_frame.get()->getTraceFromTofIndexIntensityMap(raw_spectrum);
470
471 if(trace.size() > 0)
472 {
473 mass_spectrum.setMassSpectrumSPtr(MassSpectrum(trace).makeMassSpectrumSPtr());
474 mass_spectrum.setEmptyMassSpectrum(false);
475 }
476 else
477 {
478 mass_spectrum.setMassSpectrumSPtr(nullptr);
479 mass_spectrum.setEmptyMassSpectrum(true);
480 }
481 }
482 qDebug();
483 }
484
485 catch(PappsoException &error)
486 {
487 throw PappsoException(QObject::tr("ERROR in %1 (global_slice_index=%2):\n%3")
488 .arg(__FUNCTION__)
489 .arg(global_slice_index)
490 .arg(error.qwhat()));
491 }
492 catch(std::exception &error)
493 {
494 qDebug() << QString("Failure %1 ").arg(error.what());
495 }
496 qDebug();
497}
498
499void
501 QualifiedMassSpectrum &mass_spectrum,
502 std::size_t global_slice_index,
503 bool want_binary_data,
504 int rt_position) const
505{
506
507 qDebug();
508 try
509 {
510 FrameSliceRange range = getFrameSliceRangeByGlobalSliceIndex(global_slice_index);
511
513 ->at(global_slice_index - range.begin_global_slice_index);
514
515 std::size_t ms1_frame_id = getLastMs1FrameIdByMs2FrameId(range.frame_id);
516 if(rt_position != 0)
517 {
518 std::size_t i = 0;
519 for(i = 0; i < m_ms1frameIdList.size(); i++)
520 {
521 if(m_ms1frameIdList.at(i) == ms1_frame_id)
522 break;
523 }
524 long index = (long)i + rt_position;
525 if((index > -1) && (index < (long)m_ms1frameIdList.size()))
526 ms1_frame_id = m_ms1frameIdList.at(index);
527 }
528
529 MassSpectrumId spectrum_id;
530
531 spectrum_id.setSpectrumIndex(global_slice_index);
532 spectrum_id.setNativeId(
533 QString("global_slice_index=%1 frame=%2 begin=%3 end=%4 group=%5 slice=%6")
534 .arg(global_slice_index)
535 .arg(ms1_frame_id)
536 .arg(window.ScanNumBegin)
537 .arg(window.ScanNumEnd)
538 .arg(window.WindowGroup)
539 .arg(window.SliceIndex));
540
541 spectrum_id.setMsRunId(msrun_id);
542
543 mass_spectrum.setMassSpectrumId(spectrum_id);
544
545 mass_spectrum.setMsLevel(1);
546 // mass_spectrum.setPrecursorSpectrumIndex(spectrum_descr.ms1_index);
547
548 mass_spectrum.setEmptyMassSpectrum(true);
549
550 qDebug();
551
552 // get precursor ion data
553
554 // mass_spectrum.appendPrecursorIonData(spectrum_descr.precursor_ion_data);
555
556
557 qDebug() << window.ScanNumBegin;
559 (qulonglong)window.ScanNumBegin);
560
561
562 qDebug() << window.ScanNumEnd;
564 (qulonglong)window.ScanNumEnd);
565 qDebug();
566 TimsFrameBaseCstSPtr tims_frame;
567
568
569 if(want_binary_data)
570 {
571 qDebug() << "bindec";
572 tims_frame = mp_timsDataOrigin->getTimsFrameCstSPtrCached(ms1_frame_id);
573 }
574 else
575 {
576 tims_frame = mp_timsDataOrigin->getTimsFrameBaseCstSPtrCached(ms1_frame_id);
577 }
578 mass_spectrum.setRtInSeconds(tims_frame.get()->getRtInSeconds());
579
580
581 mass_spectrum.setParameterValue(
583 tims_frame.get()->getOneOverK0Transformation(window.ScanNumBegin));
584
585 mass_spectrum.setParameterValue(
587 tims_frame.get()->getOneOverK0Transformation(window.ScanNumEnd));
588
589 qDebug();
590 /*combiner.combine(combiner_result,
591 tims_frame.get()->cumulateScanToTrace(
592 scan_mobility_start, scan_mobility_end));*/
593 if(want_binary_data)
594 {
595
596 double mz = (window.IsolationMz - (window.IsolationWidth / 2));
597 qDebug() << mz;
598
599 quint32 tof_index_begin =
600 tims_frame.get()->getMzCalibrationInterfaceSPtr().get()->getTofIndexFromMz(mz);
601
602 mz = (window.IsolationMz + (window.IsolationWidth / 2));
603 qDebug() << mz;
604 quint32 tof_index_end =
605 tims_frame.get()->getMzCalibrationInterfaceSPtr().get()->getTofIndexFromMz(mz);
606
607 qDebug() << "tof_index_begin=" << tof_index_begin << " tof_index_end=" << tof_index_end;
608
610 raw_spectrum.clear();
611 tims_frame.get()->combineScansInTofIndexIntensityMap(
612 raw_spectrum, window.ScanNumBegin, window.ScanNumEnd, tof_index_begin, tof_index_end);
613
614
615 Trace trace;
617 {
618 // raw_spectrum.removeArtefactualSpike();
619 raw_spectrum.builtInCentroid();
620 }
621
622 trace = tims_frame.get()->getTraceFromTofIndexIntensityMap(raw_spectrum);
623
624 if(trace.size() > 0)
625 {
626 mass_spectrum.setMassSpectrumSPtr(MassSpectrum(trace).makeMassSpectrumSPtr());
627 mass_spectrum.setEmptyMassSpectrum(false);
628 }
629 else
630 {
631 mass_spectrum.setMassSpectrumSPtr(nullptr);
632 mass_spectrum.setEmptyMassSpectrum(true);
633 }
634 }
635 qDebug();
636 }
637
638 catch(PappsoException &error)
639 {
640 throw PappsoException(QObject::tr("ERROR in %1 (global_slice_index=%2):\n%3")
641 .arg(__FUNCTION__)
642 .arg(global_slice_index)
643 .arg(error.qwhat()));
644 }
645 catch(std::exception &error)
646 {
647 qDebug() << QString("Failure %1 ").arg(error.what());
648 }
649 qDebug();
650}
651
652} // namespace pappso
void setNativeId(const QString &native_id)
void setMsRunId(MsRunIdCstSPtr other)
void setSpectrumIndex(std::size_t index)
Class to represent a mass spectrum.
const char * what() const noexcept override
virtual const QString & qwhat() const
Class representing a fully specified mass spectrum.
void setPrecursorNativeId(const QString &native_id)
Set the scan native id of the precursor ion.
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)
replacement for std::map
void builtInCentroid()
simple filter to agregate counts on neigbhor mobility slots (+1)
static TimsDataFastMap & getTimsDataFastMapInstance()
std::vector< std::size_t > m_ms2frameId2Ms1FrameId
TimsDataFastMap & getCombinedMs2ScansByGlobalSliceIndex(std::size_t global_slice_index) const
std::size_t getGlobalSliceIndexBeginByFrameId(std::size_t frame_id) const
std::size_t getLastMs1FrameIdByMs2FrameId(std::size_t frame_id) const
const FrameSliceRange & getFrameSliceRangeByGlobalSliceIndex(std::size_t global_slice_index) const
MsMsWindowGroupList m_msMsWindowGroupList
const MsMsWindow & getMsMsWindowByGlobalSliceIndex(std::size_t global_slice_index) const
bool m_builtinMs2Centroid
enable builtin centroid on raw tims integers by default
std::vector< std::size_t > m_ms1frameIdList
std::map< std::size_t, MsMsWindowGroup * > m_mapFrame2WindowGroupPtr
std::size_t m_totalSlicesCount
std::size_t getFrameIdByGlobalSliceIndex(std::size_t global_slice_id) const
std::vector< std::size_t > m_frameId2GlobalSliceIndexBegin
void getMs2QualifiedSpectrumByGlobalSliceIndex(const MsRunIdCstSPtr &msrun_id, QualifiedMassSpectrum &mass_spectrum, std::size_t global_slice_index, bool want_binary_data) const
const std::map< std::size_t, MsMsWindowGroup * > & getMapFrame2WindowGroupPtr() const
void getMs1QualifiedSpectrumByGlobalSliceIndex(const MsRunIdCstSPtr &msrun_id, QualifiedMassSpectrum &mass_spectrum, std::size_t global_slice_index, bool want_binary_data, int rt_position=0) const
get MS1 spectrum corresponding to the given slice extract MS1 mz range and mobility range correspondi...
TimsDiaSlices(QSqlQuery &query, TimsData *tims_data_origin)
std::vector< FrameSliceRange > m_frameSliceRangeList
std::size_t getTotalSlicesCount() const
get the number of DIA MS2 slices analyzed by PASEF
const MsMsWindowGroupList & getMsMsWindowGroupList() const
A simple container of DataPoint instances.
Definition trace.h:152
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
std::shared_ptr< const TimsFrameBase > TimsFrameBaseCstSPtr
std::shared_ptr< const MsRunId > MsRunIdCstSPtr
Definition msrunid.h:46
@ IsolationWindowTargetMz
Isolation m/z value isolation window target m/z (thomson).
@ IsolationWindowUpperOffset
isolation window upper offset (thomson)
@ CollisionEnergy
Bruker's timsTOF collision energy.
@ IsolationWindowLowerOffset
isolation window lower offset (thomson)
std::shared_ptr< const TimsFrame > TimsFrameCstSPtr
Definition timsframe.h:44
MsMsWindowGroup * getWindowGroupPtrByGroupId(std::size_t window_group_id) const
void addInGroup(const MsMsWindow &window)
bool isMzInRange(double mz) const
tell if given mz is in range for this window