libpappsomspp
Library for mass spectrometry
timsframetype1.cpp
Go to the documentation of this file.
1 /**
2  * \file pappsomspp/vendors/tims/timsframetype1.cpp
3  * \date 3/10/2021
4  * \author Olivier Langella
5  * \brief handle a single Bruker's TimsTof frame type 1 compression
6  */
7 
8 /*******************************************************************************
9  * Copyright (c) 2021 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 
29 #include "timsframetype1.h"
30 #include "../../../pappsomspp/pappsoexception.h"
31 #include "../../../pappsomspp/exception/exceptionoutofrange.h"
32 #include "../../../pappsomspp/exception/exceptionnotimplemented.h"
33 #include <QDebug>
34 #include <QObject>
35 #include <liblzf/lzf.h>
36 #include <cerrno>
37 
38 
39 namespace pappso
40 {
41 TimsFrameType1::TimsFrameType1(std::size_t timsId,
42  quint32 scanNum,
43  char *p_bytes,
44  std::size_t len)
45  : TimsFrame(timsId, scanNum)
46 {
47  qDebug() << timsId;
48  m_timsDataFrame.resize(len * 2);
49 
50  if(p_bytes != nullptr)
51  {
52  qDebug() << timsId;
53  copyAndLzfDecompress(p_bytes, len);
54  qDebug() << timsId;
55  }
56  else
57  {
58  if(m_scanNumber == 0)
59  {
60 
62  QObject::tr(
63  "TimsFrameType1::TimsFrameType1(%1,%2,nullptr,%3) FAILED")
64  .arg(m_timsId)
65  .arg(m_scanNumber)
66  .arg(len));
67  }
68  }
69 }
70 
72 {
73 }
74 
76 {
77 }
78 
79 
80 void
81 TimsFrameType1::copyAndLzfDecompress(const char *src, std::size_t len)
82 {
83 
84  qDebug() << " m_scanNumber=" << m_scanNumber << " len=" << len;
85  // the start position offset for each scan and the length of the last scan
86  // copy first m_scanNumber*4 bytes in qbyte array
87  std::size_t count = (m_scanNumber + 2) * 4;
88 
89  qDebug() << " count=" << count;
90  if(m_timsDataFrame.size() < (long)(count + count))
91  {
92  qDebug() << " m_timsDataFrame.size()=" << m_timsDataFrame.size();
93  m_timsDataFrame.resize(count + count);
94  }
95 
96  /*
97  std::size_t decompressed_size =
98  lzfDecompressScan(src + 3687 - 8,
99  9,
100  m_timsDataFrame.data() + 3660,
101  m_timsDataFrame.size() - 3660);
102 
103  qDebug() << "decompressed_size=" << decompressed_size;
104  */
105  // memcpy(m_timsDataFrame.data(), src, count);
106 
107  qDebug() << "offset begin at last :" << count + 4;
108 
109  // std::vector<std::size_t> compressed_len_list;
110  std::size_t offset;
111  std::size_t previous_offset = (*(quint32 *)(src));
112  qDebug() << "first offset= " << previous_offset;
113  std::size_t cumul_decompressed_size = 0;
114 
115 
116  for(quint32 i = 1; i <= m_scanNumber; i++)
117  {
118  offset = (*(quint32 *)(src + (i * 4)));
119 
120  std::size_t compressed_size = offset - previous_offset;
121 
122  qDebug() << "scan i=" << i << " previous_offset=" << previous_offset
123  << " offset=" << offset << " length=" << compressed_size;
124  // compressed_len_list.push_back(offset - previous_offset);
125  std::size_t remaining_size = m_timsDataFrame.size();
126 
127  if(cumul_decompressed_size < remaining_size)
128  {
129  remaining_size = remaining_size - cumul_decompressed_size;
130  }
131  else
132  {
133  remaining_size = 0;
134  }
135  qDebug() << " remaining_size=" << remaining_size;
136  std::size_t decompressed_size =
137  lzfDecompressScan(src + previous_offset - 8,
138  compressed_size,
139  m_timsDataFrame.data() + cumul_decompressed_size,
140  remaining_size);
141 
142 
143  m_scanOffsetList.push_back(cumul_decompressed_size);
144  m_scanSizeList.push_back(decompressed_size / 4);
145  cumul_decompressed_size += decompressed_size;
146  qDebug() << " decompressed_size=" << decompressed_size;
147 
148 
149  previous_offset = offset;
150  }
151  /*
152  std::size_t last_offset = (*(quint32 *)(src + (m_scanNumber * 4)));
153  qDebug() << "last scan length :" << last_offset;
154 
155  qDebug() << "last scan length bonus:"
156  << (*(quint32 *)(src + (m_scanNumber + 1 * 4)));
157 
158  qDebug() << " m_scanOffsetList.size()=" << m_scanOffsetList.size()
159  << " m_scanNumber=" << m_scanNumber;
160  */
161  /*
162  throw PappsoException(
163  QObject::tr("ERROR reading TimsFrameType1 ").arg(m_timsId));
164  */
165 }
166 
167 
168 unsigned int
170  unsigned int src_len,
171  char *dest,
172  unsigned int dest_len)
173 {
174  qDebug() << "src=" << src << " src_len=" << src_len
175  << " dest_len=" << dest_len;
176  if(src_len == 0)
177  return 0;
178  unsigned int decompressed_size;
179  unsigned int more_space = src_len * 2;
180  decompressed_size = lzf_decompress(src, src_len, dest, dest_len);
181  while(decompressed_size == 0)
182  {
183  qDebug() << "dest_len=" << dest_len;
184  qDebug() << "decompressed_size=" << decompressed_size;
185 
186  if(errno == EINVAL)
187  {
188  throw PappsoException(
189  QObject::tr("ERROR reading TimsFrameType1 %1 TIMS binary file %2: "
190  "LZF decompression error EINVAL")
191  .arg(m_timsId));
192  }
193  else if(errno == E2BIG)
194  {
195  qDebug() << " m_timsDataFrame.size()=" << m_timsDataFrame.size()
196  << " more_space=" << more_space;
197  m_timsDataFrame.resize(m_timsDataFrame.size() + more_space);
198  dest_len += more_space;
199  qDebug();
200  decompressed_size = lzf_decompress(src, src_len, dest, dest_len);
201  }
202  else
203  {
204  break;
205  }
206  }
207  return decompressed_size;
208 }
209 
210 std::size_t
211 TimsFrameType1::getNbrPeaks(std::size_t scanNum) const
212 {
213  pappso::MassSpectrumSPtr mass_spectrum_sptr = getMassSpectrumSPtr(scanNum);
214  return mass_spectrum_sptr.get()->size();
215 }
216 
217 
218 void
219 TimsFrameType1::cumulateScan(std::size_t scanNum,
220  std::map<quint32, quint32> &accumulate_into) const
221 {
222  if(m_timsDataFrame.size() == 0)
223  return;
224  // checkScanNum(scanNum);
225 
226 
227  std::size_t size = m_scanSizeList[scanNum];
228 
229  std::size_t offset = m_scanOffsetList[scanNum];
230 
231  // qDebug() << "begin offset=" << offset << " size=" << size;
232  qint32 value = 0;
233  qint32 tof_index = 0;
234  for(std::size_t i = 0; i < size; i++)
235  {
236  value = (*(qint32 *)(m_timsDataFrame.constData() + offset + (i * 4)));
237  // qDebug() << " i=" << i << " value=" << value;
238 
239  if(value < 0)
240  {
241  tof_index += -1 * value;
242  }
243  else
244  {
245 
246  quint32 x = tof_index;
247  quint32 y = value;
248 
249  auto ret = accumulate_into.insert(std::pair<quint32, quint32>(x, y));
250 
251  if(ret.second == false)
252  {
253  // already existed : cumulate
254  ret.first->second += y;
255  }
256  tof_index++;
257  }
258  }
259  qDebug() << "end";
260 }
261 
262 std::vector<quint32>
263 TimsFrameType1::getScanIndexList(std::size_t scanNum) const
264 {
265  qDebug();
266  checkScanNum(scanNum);
267 
268  std::vector<quint32> mzindex_values;
269 
270  try
271  {
272  qDebug();
273 
274 
275  if(m_timsDataFrame.size() == 0)
276  return mzindex_values;
277  qDebug();
278 
279  std::size_t size = m_scanSizeList[scanNum];
280 
281  std::size_t offset = m_scanOffsetList[scanNum];
282 
283  qDebug() << " offset=" << offset << " size=" << size;
284  if(size == 0)
285  return mzindex_values;
286 
287  qint32 value = 0;
288  qint32 tof_index = 0;
289  // std::vector<quint32> index_list;
290  for(std::size_t i = 0; i < size; i++)
291  {
292  value = (*(qint32 *)(m_timsDataFrame.constData() + offset + (i * 4)));
293 
294  if(value < 0)
295  {
296  tof_index += -1 * value;
297  }
298  else
299  {
300  mzindex_values.push_back(tof_index);
301  tof_index++;
302  }
303  }
304 
305 
306  qDebug();
307  return mzindex_values;
308  }
309  catch(PappsoException &error)
310  {
311  throw pappso::PappsoException(QObject::tr("Error %1 frameId=%2 "
312  "scanNum=%3 :\n%4")
313  .arg(__FUNCTION__)
314  .arg(getId())
315  .arg(scanNum)
316  .arg(error.qwhat()));
317  }
318  qDebug();
319 }
320 
321 std::vector<quint32>
322 TimsFrameType1::getScanIntensities(std::size_t scanNum) const
323 {
324 
325 
326  qDebug() << " scanNum=" << scanNum;
327 
328  checkScanNum(scanNum);
329 
330  std::vector<quint32> int_values;
331 
332  try
333  {
334  qDebug();
335 
336 
337  if(m_timsDataFrame.size() == 0)
338  return int_values;
339  qDebug();
340 
341  std::size_t size = m_scanSizeList[scanNum];
342 
343  std::size_t offset = m_scanOffsetList[scanNum];
344 
345  qDebug() << " offset=" << offset << " size=" << size;
346  if(size == 0)
347  return int_values;
348 
349  qint32 value = 0;
350  qint32 tof_index = 0;
351  // std::vector<quint32> index_list;
352  for(std::size_t i = 0; i < size; i++)
353  {
354  value = (*(qint32 *)(m_timsDataFrame.constData() + offset + (i * 4)));
355 
356  if(value < 0)
357  {
358  tof_index += -1 * value;
359  }
360  else
361  {
362  int_values.push_back(value);
363  tof_index++;
364  }
365  }
366 
367 
368  qDebug();
369  return int_values;
370  }
371  catch(PappsoException &error)
372  {
373  throw pappso::PappsoException(QObject::tr("Error %1 frameId=%2 "
374  "scanNum=%3 :\n%4")
375  .arg(__FUNCTION__)
376  .arg(getId())
377  .arg(scanNum)
378  .arg(error.qwhat()));
379  }
380 }
381 
383 TimsFrameType1::getMassSpectrumSPtr(std::size_t scanNum) const
384 {
385 
386  qDebug() << " scanNum=" << scanNum;
387 
388  checkScanNum(scanNum);
389 
390  try
391  {
392  qDebug();
393 
394  pappso::MassSpectrumSPtr mass_spectrum_sptr =
395  std::make_shared<pappso::MassSpectrum>();
396  // std::vector<DataPoint>
397 
398  if(m_timsDataFrame.size() == 0)
399  return mass_spectrum_sptr;
400  qDebug();
401 
402  std::size_t size = m_scanSizeList[scanNum];
403 
404  std::size_t offset = m_scanOffsetList[scanNum];
405 
406  qDebug() << " offset=" << offset << " size=" << size;
407  if(size == 0)
408  return mass_spectrum_sptr;
409 
410 
411  MzCalibrationInterface *mz_calibration_p =
413 
414 
415  qint32 value = 0;
416  qint32 tof_index = 0;
417  // std::vector<quint32> index_list;
418  DataPoint data_point;
419  for(std::size_t i = 0; i < size; i++)
420  {
421  value = (*(qint32 *)(m_timsDataFrame.constData() + offset + (i * 4)));
422 
423  if(value < 0)
424  {
425  tof_index += -1 * value;
426  }
427  else
428  {
429  data_point.y = value;
430 
431  // intensity normalization
432  data_point.y *= 100.0 / m_accumulationTime;
433 
434 
435  // mz calibration
436  data_point.x = mz_calibration_p->getMzFromTofIndex(tof_index);
437  mass_spectrum_sptr.get()->push_back(data_point);
438  tof_index++;
439  }
440  }
441 
442 
443  qDebug() << mass_spectrum_sptr.get()->toString();
444  return mass_spectrum_sptr;
445  }
446  catch(PappsoException &error)
447  {
449  QObject::tr("Error TimsFrameType1::getMassSpectrumSPtr frameId=%1 "
450  "scanNum=%2 :\n%3")
451  .arg(getId())
452  .arg(scanNum)
453  .arg(error.qwhat()));
454  }
455 }
456 
457 
459 TimsFrameType1::getRawTraceSPtr(std::size_t scanNum) const
460 {
461 
462  // qDebug();
463 
464  pappso::TraceSPtr trace_sptr = std::make_shared<pappso::Trace>();
465  // std::vector<DataPoint>
466 
467  if(m_timsDataFrame.size() == 0)
468  return trace_sptr;
469  qDebug();
470 
471  std::size_t size = m_scanSizeList[scanNum];
472 
473  std::size_t offset = m_scanOffsetList[scanNum];
474 
475  qDebug() << " offset=" << offset << " size=" << size;
476  if(size == 0)
477  return trace_sptr;
478 
479  // qDebug();
480  qint32 value = 0;
481  qint32 tof_index = 0;
482 
483  // std::vector<quint32> index_list;
484  DataPoint data_point;
485  for(std::size_t i = 0; i < size; i++)
486  {
487  value = (*(qint32 *)(m_timsDataFrame.constData() + offset + (i * 4)));
488 
489  if(value < 0)
490  {
491  tof_index += -1 * value;
492  }
493  else
494  {
495  data_point.y = value;
496 
497  // intensity normalization
498  data_point.y *= 100.0 / m_accumulationTime;
499 
500 
501  // mz calibration
502  data_point.x = tof_index;
503  trace_sptr.get()->push_back(data_point);
504  tof_index++;
505  }
506  }
507 
508 
509  // qDebug();
510  return trace_sptr;
511 }
512 
513 } // namespace pappso
virtual double getMzFromTofIndex(quint32 tof_index)=0
get m/z from time of flight raw index
virtual const QString & qwhat() const
double m_accumulationTime
accumulation time in milliseconds
quint32 m_scanNumber
total number of scans contained in this frame
std::size_t m_timsId
Tims frame database id (the SQL identifier of this frame)
virtual const MzCalibrationInterfaceSPtr & getMzCalibrationInterfaceSPtr() const final
get the MzCalibration model to compute mz and TOF for this frame
bool checkScanNum(std::size_t scanNum) const
check that this scan number exists
std::size_t getId() const
virtual std::vector< quint32 > getScanIndexList(std::size_t scanNum) const override
get raw index list for one given scan index are not TOF nor m/z, just index on digitizer
std::vector< std::size_t > m_scanSizeList
TimsFrameType1(std::size_t timsId, quint32 scanNum, char *p_bytes, std::size_t len)
void copyAndLzfDecompress(const char *src, std::size_t len)
copy buffer header and lzf decompress each scan for tims compression type 1
virtual std::size_t getNbrPeaks(std::size_t scanNum) const override
get the number of peaks in this spectrum need the binary file
virtual void cumulateScan(std::size_t scanNum, std::map< quint32, quint32 > &accumulate_into) const override
cumulate a scan into a map
unsigned int lzfDecompressScan(const char *src, unsigned int src_len, char *dest, unsigned int dest_len)
decompress a single LZF compressed scan buffer
virtual pappso::MassSpectrumSPtr getMassSpectrumSPtr(std::size_t scanNum) const override
get the mass spectrum corresponding to a scan number
virtual std::vector< quint32 > getScanIntensities(std::size_t scanNum) const override
get raw intensities without transformation from one scan it needs intensity normalization
std::vector< std::size_t > m_scanOffsetList
virtual pappso::TraceSPtr getRawTraceSPtr(std::size_t scanNum) const override
get the raw index tof_index and intensities (normalized)
QByteArray m_timsDataFrame
Definition: timsframe.h:187
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39
std::shared_ptr< Trace > TraceSPtr
Definition: trace.h:135
std::shared_ptr< MassSpectrum > MassSpectrumSPtr
Definition: massspectrum.h:54
pappso_double x
Definition: datapoint.h:23
pappso_double y
Definition: datapoint.h:24
handle a single Bruker's TimsTof frame type 1 compression