libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
msrunretentiontime.cpp
Go to the documentation of this file.
1
2/*******************************************************************************
3 * Copyright (c) 2019 Olivier Langella <Olivier.Langella@u-psud.fr>.
4 *
5 * This file is part of the PAPPSOms++ library.
6 *
7 * PAPPSOms++ is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * PAPPSOms++ is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with PAPPSOms++. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Contributors:
21 * Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
22 *implementation
23 ******************************************************************************/
24
25#include "msrunretentiontime.h"
27#include <QDebug>
28#include <QObject>
29
30// #include <odsstream/odsexception.h>
31// #include <odsstream/odsdocwriter.h>
32// #include <QFileInfo>
33
34using namespace pappso;
35
36template <class T>
37MsRunRetentionTime<T>::MsRunRetentionTime(const std::vector<double> &msrun_retention_time_line)
39{
40 m_ms1RetentionTimeVector = msrun_retention_time_line;
41
42
43 std::sort(m_ms1RetentionTimeVector.begin(),
45 [](const double &a, const double &b) { return (a < b); });
46}
47
48template <class T>
53{
56
57 m_seamarks = other.m_seamarks;
59
63}
65template <class T>
67{
70template <typename T>
74 return m_ms2MedianFilter;
75}
76
77template <class T>
78void
80{
81 m_ms2MedianFilter = ms2MedianFilter;
82}
84template <typename T>
90
91
92template <class T>
93void
95{
96 m_ms2MeanFilter = ms2MeanFilter;
97}
98
99template <typename T>
103 return m_ms1MeanFilter;
104}
105
106template <class T>
107void
110 m_ms1MeanFilter = ms1MeanFilter;
111}
112
113template <class T>
114const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &
117 qDebug();
119}
120
121template <class T>
122const std::vector<double> &
127
128template <class T>
129std::size_t
132 return m_valuesCorrected;
133}
134template <class T>
135const std::vector<double> &
141template <class T>
144 const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &other_seamarks) const
145{
146 Trace common_points;
147 getCommonDeltaRt(common_points, other_seamarks);
148 return common_points;
149}
150
151template <class T>
152void
154 double retentionTime,
155 double precursorIntensity)
156{
157 PeptideMs2Point ms2point;
158 ms2point.entityHash = peptide_id;
159 ms2point.precursorIntensity = precursorIntensity;
160 ms2point.retentionTime = retentionTime;
161 m_allMs2Points.push_back(ms2point);
162}
163
164
165template <class T>
166void
168{
169
170 qDebug();
171 if(m_allMs2Points.size() == 0)
172 {
173 // already computed
174 return;
175 }
176 m_seamarks.clear();
178 {
179
180
181 std::sort(m_allMs2Points.begin(),
182 m_allMs2Points.end(),
183 [](const PeptideMs2Point &a, const PeptideMs2Point &b) {
184 if(a.entityHash == b.entityHash)
185 {
186 return (a.precursorIntensity > b.precursorIntensity);
187 }
188 return (a.entityHash < b.entityHash);
189 });
190
191 auto itend = std::unique(m_allMs2Points.begin(),
192 m_allMs2Points.end(),
193 [](const PeptideMs2Point &a, const PeptideMs2Point &b) {
194 return (a.entityHash == b.entityHash);
195 });
196
197 auto it = m_allMs2Points.begin();
198 while(it != itend)
199 {
200 m_seamarks.push_back({it->entityHash, it->retentionTime, it->precursorIntensity});
201 it++;
202 }
203 }
204 m_allMs2Points.clear();
205
206 std::sort(
207 m_seamarks.begin(),
208 m_seamarks.end(),
210 return (a.entityHash < b.entityHash);
211 });
212 qDebug();
213}
214
215template <class T>
216void
218 Trace &delta_rt, const std::vector<MsRunRetentionTimeSeamarkPoint<T>> &other_seamarks) const
219{
220
221 qDebug();
222 auto it = other_seamarks.begin();
223
225 {
226 while((it != other_seamarks.end()) && (it->entityHash < seamark.entityHash))
227 {
228 it++;
229 }
230 if(it == other_seamarks.end())
231 break;
232 if(it->entityHash == seamark.entityHash)
233 {
234 delta_rt.push_back(
235 DataPoint(seamark.retentionTime, seamark.retentionTime - it->retentionTime));
236 }
237 }
238
239 qDebug();
240 if((m_ms2MedianFilter.getHalfWindowSize() * 2 + 1) >= delta_rt.size())
241 {
242 throw ExceptionNotPossible(QObject::tr("ERROR : MS2 alignment not possible : "
243 "\ntoo few MS2 points (%1) in common")
244 .arg(delta_rt.size()));
245 }
246
247 qDebug();
248 if((m_ms2MeanFilter.getHalfWindowSize() * 2 + 1) >= delta_rt.size())
249 {
250 throw ExceptionNotPossible(QObject::tr("ERROR : MS2 alignment not possible : "
251 "\ntoo few MS2 points (%1) in common")
252 .arg(delta_rt.size()));
253 }
254 delta_rt.sortX();
255
256 // there can be multiple entities (peptides) at one retention time
257 // in this case, avoid retention time redundancy by applying unique on trace :
258 delta_rt.unique();
259
260 qDebug();
261}
262
263
264template <class T>
265double
267{
268 if(isAligned())
269 {
270 return m_alignedRetentionTimeVector.front();
271 }
272 return m_ms1RetentionTimeVector.front();
273}
274template <class T>
275double
277{
278 if(isAligned())
279 {
280 return m_alignedRetentionTimeVector.back();
281 }
282 return m_ms1RetentionTimeVector.back();
283}
284
285
286template <class T>
287double
289{
290 if(m_alignedRetentionTimeVector.size() < 3)
291 {
292 throw ExceptionNotPossible(QObject::tr("ERROR : too few aligned points to compute aligned "
293 "retention time (%1)")
294 .arg(m_ms1RetentionTimeVector.size()));
295 }
297 {
298 throw ExceptionNotPossible(QObject::tr("ERROR : m_alignedRetentionTimeVector.size() %1 != %2 "
299 "m_ms1RetentionTimeVector.size()")
301 .arg(m_ms1RetentionTimeVector.size()));
302 }
303 auto it_plus = std::find_if(m_ms1RetentionTimeVector.begin(),
305 [original_retention_time](const double &rt_point) {
306 return original_retention_time < rt_point;
307 });
308 double rt1_a, rt2_a, rt1_b, rt2_b;
309 if(it_plus == m_ms1RetentionTimeVector.end())
310 {
311 it_plus--;
312 }
313 if(it_plus == m_ms1RetentionTimeVector.begin())
314 {
315 it_plus++;
316 }
317 auto it_minus = it_plus - 1;
318
319 rt1_a = *it_minus;
320 rt2_a = *it_plus;
321
322 double ratio = (original_retention_time - rt1_a) / (rt2_a - rt1_a);
323
324 auto itref = m_alignedRetentionTimeVector.begin() +
325 std::distance(m_ms1RetentionTimeVector.begin(), it_minus);
326
327 rt1_b = *itref;
328 itref++;
329 rt2_b = *itref;
330
331 return (((rt2_b - rt1_b) * ratio) + rt1_b);
332}
333
334template <class T>
335double
337{
338 if(m_alignedRetentionTimeVector.size() < 3)
339 {
340 throw ExceptionNotPossible(QObject::tr("ERROR : too few aligned points to compute aligned "
341 "retention time (%1)")
342 .arg(m_ms1RetentionTimeVector.size()));
343 }
345 {
346 throw ExceptionNotPossible(QObject::tr("ERROR : m_alignedRetentionTimeVector.size() %1 != %2 "
347 "m_ms1RetentionTimeVector.size()")
349 .arg(m_ms1RetentionTimeVector.size()));
350 }
351 auto it_plus = std::find_if(
354 [aligned_retention_time](const double &rt_point) { return aligned_retention_time < rt_point; });
355 double rt1_a, rt2_a, rt1_b, rt2_b;
356 if(it_plus == m_alignedRetentionTimeVector.end())
357 {
358 it_plus--;
359 }
360 if(it_plus == m_alignedRetentionTimeVector.begin())
361 {
362 it_plus++;
363 }
364 auto it_minus = it_plus - 1;
365
366 rt1_a = *it_minus;
367 rt2_a = *it_plus;
368
369 double ratio = (aligned_retention_time - rt1_a) / (rt2_a - rt1_a);
370
371 auto itref = m_ms1RetentionTimeVector.begin() +
372 std::distance(m_alignedRetentionTimeVector.begin(), it_minus);
373
374 rt1_b = *itref;
375 itref++;
376 rt2_b = *itref;
377
378 return (((rt2_b - rt1_b) * ratio) + rt1_b);
379}
380
381template <class T>
382const std::vector<MsRunRetentionTimeSeamarkPoint<T>>
384{
385 std::vector<MsRunRetentionTimeSeamarkPoint<T>> other_seamarks = m_seamarks;
386 for(auto &seamark : other_seamarks)
387 {
388 seamark.retentionTime = translateOriginal2AlignedRetentionTime(seamark.retentionTime);
389 }
390 return other_seamarks;
391}
392
393template <class T>
394bool
396{
397 return (m_alignedRetentionTimeVector.size() > 0);
398}
399
400template <class T>
401Trace
402MsRunRetentionTime<T>::align(const MsRunRetentionTime<T> &msrun_retention_time_reference)
403{
405 std::vector<MsRunRetentionTimeSeamarkPoint<T>> other_seamarks;
406 if(msrun_retention_time_reference.isAligned())
407 {
408 other_seamarks = msrun_retention_time_reference.getSeamarksReferences();
409 }
410 else
411 {
412 other_seamarks = msrun_retention_time_reference.getSeamarks();
413 }
414 qDebug();
415 if((m_ms1MeanFilter.getHalfWindowSize() * 2 + 1) >= m_ms1RetentionTimeVector.size())
416 {
417 throw ExceptionNotPossible(QObject::tr("ERROR : MS1 alignment not possible : "
418 "\ntoo few MS1 points (%1)")
419 .arg(m_ms1RetentionTimeVector.size()));
420 }
421
422 qDebug() << m_seamarks[0].entityHash << " " << m_seamarks[0].retentionTime << " "
423 << other_seamarks[0].entityHash << other_seamarks[0].retentionTime << " ";
424 // both seamarks has to be ordered
425 Trace common_points;
426 getCommonDeltaRt(common_points, other_seamarks);
427
428 // writeTrace("lib_ms2_delta_rt.ods", common_points);
429
430 qDebug() << common_points.front().x << " " << common_points.front().y;
431 m_ms2MedianFilter.filter(common_points);
432 // writeTrace("lib_ms2_delta_rt_median.ods", common_points);
433 m_ms2MeanFilter.filter(common_points);
434 // writeTrace("lib_ms2_delta_rt_mean.ods", common_points);
435 // convert common delta rt to real retention times (for convenience)
436 qDebug() << common_points.front().x << " " << common_points.front().y;
437
438
439 // add a first point to ensure coherence:
440 DataPoint first_point;
441 first_point.x = m_ms1RetentionTimeVector.front() - (double)1;
442 if(first_point.x < 0)
443 {
444 first_point.x = 0;
445 }
446 first_point.y = m_ms1RetentionTimeVector.front() -
447 msrun_retention_time_reference.getFrontRetentionTimeReference();
448
449 common_points.push_back(first_point);
450 // add a last point to ensure coherence:
451 DataPoint last_point;
452 last_point.x = m_ms1RetentionTimeVector.back() + 1;
453 last_point.y = m_ms1RetentionTimeVector.back() -
454 msrun_retention_time_reference.getBackRetentionTimeReference();
455 common_points.push_back(last_point);
456 common_points.sortX();
457
458 // now, it is possible for each time range to give a new MS1 time using a
459 // linear regression on MS2 corrected times
461
462 qDebug() << common_points.front().x << " " << common_points.front().y;
463
464 Trace ms1_aligned_points;
465
466 linearRegressionMs2toMs1(ms1_aligned_points, common_points);
467
468 // writeTrace("lib_ms1_map_rt.ods", ms1_aligned_points);
469 qDebug();
470 // smoothing on MS1 points
471 m_ms1MeanFilter.filter(ms1_aligned_points);
472
473 // writeTrace("lib_ms1_map_rt_mean.ods", ms1_aligned_points);
474 // final aligned retentionTime vector
475
476 for(DataPoint &data_point : ms1_aligned_points)
477 {
478 data_point.y = (data_point.x - data_point.y);
479 }
480
481 qDebug();
482 // Here, the correction parameter is the slope of old rt points curve
483 // (divided by 4 to get a finer correction).
484 double correction_parameter =
486 (ms1_aligned_points.size());
487 // set_correction_parameter(correction_parameter / 4);
488 correction_parameter = correction_parameter / (double)4;
489 correctNewTimeValues(ms1_aligned_points, correction_parameter);
490
491 m_alignedRetentionTimeVector = ms1_aligned_points.yValues();
492
493 qDebug();
494 return ms1_aligned_points;
495}
496
497
498template <class T>
499void
501 const Trace &common_points)
502{
503
504 // first slope :
505 std::vector<DataPoint>::const_iterator itms2 = common_points.begin();
506 std::vector<DataPoint>::const_iterator itms2next = itms2 + 1;
507 if(itms2next == common_points.end())
508 {
509 // error
510 throw ExceptionNotPossible(QObject::tr("ERROR : MS1 alignment not possible : "
511 "\ntoo few common points (%1)")
512 .arg(common_points.size()));
513 }
514 qDebug() << "() itms2->x=" << itms2->x << " itms2->y=" << itms2->y;
515
516 for(double &original_rt_point : m_ms1RetentionTimeVector)
517 {
518 DataPoint ms1_point;
519 ms1_point.x = original_rt_point;
520
521 while(ms1_point.x > itms2next->x)
522 {
523 itms2++;
524 itms2next++;
525 }
526
527 double ratio = (itms2next->x - itms2->x);
528 if(ratio != 0)
529 {
530 ratio = (ms1_point.x - itms2->x) / ratio;
531 }
532 else
533 {
534 // avoid division by zero
535 ratio = 1;
536 }
537 // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "() " <<
538 // ratio;
539
540 ms1_point.y = itms2->y + ((itms2next->y - itms2->y) * ratio);
541
542 // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << "() "
543 // << ms1_point.y;
544 ms1_aligned_points.push_back(ms1_point);
545 }
546}
547
548template <class T>
549void
550MsRunRetentionTime<T>::correctNewTimeValues(Trace &ms1_aligned_points, double correction_parameter)
551{
552
554 auto new_it(ms1_aligned_points.begin());
555 auto new_nextit(ms1_aligned_points.begin());
556 new_nextit++;
557 for(; new_nextit != ms1_aligned_points.end(); ++new_nextit, ++new_it)
558 {
559 if(new_nextit->y < new_it->y)
560 {
562 new_nextit->y = new_it->y + correction_parameter;
563 }
564 }
565}
566
567template <class T>
568void
570 const std::vector<double> &aligned_times)
571{
572
573 if(aligned_times.size() == m_ms1RetentionTimeVector.size())
574 {
575 m_alignedRetentionTimeVector = aligned_times;
576 }
577 else
578 {
579 if(aligned_times.size() == m_ms1RetentionTimeVector.size() * 2)
580 {
582 for(std::size_t i = 0; i < m_ms1RetentionTimeVector.size(); i++)
583 {
584 if(aligned_times[2 * i] != m_ms1RetentionTimeVector[i])
585 {
587 QObject::tr("ERROR : aligned_times (size=%1) vector does not have "
588 "required size (size=%2)")
589 .arg(aligned_times.size())
590 .arg(m_ms1RetentionTimeVector.size()));
591 }
592 m_alignedRetentionTimeVector[i] = aligned_times[(2 * i) + 1];
593 }
594 }
595 else
596 {
598 QObject::tr("ERROR : aligned_times (size=%1) vector does not have "
599 "required size (size=%2)")
600 .arg(aligned_times.size())
601 .arg(m_ms1RetentionTimeVector.size()));
602 }
603 }
604}
605
606
607template <class T>
608Trace
610 const MsRunRetentionTime<T> &msrun_retention_time_reference) const
611{
612 // computeSeamarks();
613 std::vector<MsRunRetentionTimeSeamarkPoint<T>> other_seamarks;
614 if(msrun_retention_time_reference.isAligned())
615 {
616 other_seamarks = msrun_retention_time_reference.getSeamarksReferences();
617 }
618 else
619 {
620 other_seamarks = msrun_retention_time_reference.getSeamarks();
621 }
622 qDebug();
623
624 qDebug() << m_seamarks[0].entityHash << " " << m_seamarks[0].retentionTime << " "
625 << other_seamarks[0].entityHash << other_seamarks[0].retentionTime << " ";
626 // both seamarks has to be ordered
627 Trace common_points;
628 getCommonDeltaRt(common_points, other_seamarks);
629 return common_points;
630}
mean filter apply mean of y values inside the window : this results in a kind of smoothing
median filter apply median of y values inside the window
void setMs2MedianFilter(const FilterMorphoMedian &ms2MedianFilter)
std::vector< double > m_alignedRetentionTimeVector
std::vector< PeptideMs2Point > m_allMs2Points
const FilterMorphoMean & getMs1MeanFilter() const
const FilterMorphoMedian & getMs2MedianFilter() const
void computeSeamarks()
convert PeptideMs2Point into Peptide seamarks this is required before computing alignment
Trace getCommonSeamarksDeltaRt(const MsRunRetentionTime< T > &msrun_retention_time_reference) const
get common seamarks between msrunretentiontime objects and their deltart
MsRunRetentionTime(const std::vector< double > &msrun_retention_time_line)
void setMs1MeanFilter(const FilterMorphoMean &ms1MeanFilter)
void linearRegressionMs2toMs1(Trace &ms1_aligned_points, const Trace &common_points)
void setMs2MeanFilter(const FilterMorphoMean &ms2MeanFilter)
double getFrontRetentionTimeReference() const
const std::vector< double > & getAlignedRetentionTimeVector() const
get aligned retention time vector
void setAlignedRetentionTimeVector(const std::vector< double > &aligned_times)
std::vector< MsRunRetentionTimeSeamarkPoint< T > > m_seamarks
Trace align(const MsRunRetentionTime< T > &msrun_retention_time_reference)
align the current msrunretentiontime object using the given reference
double translateAligned2OriginalRetentionTime(double aligned_retention_time) const
double translateOriginal2AlignedRetentionTime(double original_retention_time) const
const std::vector< double > & getMs1RetentionTimeVector() const
get orginal retention time vector (not aligned)
void correctNewTimeValues(Trace &ms1_aligned_points, double correction_parameter)
const std::vector< MsRunRetentionTimeSeamarkPoint< T > > & getSeamarks() const
Trace getCommonDeltaRt(const std::vector< MsRunRetentionTimeSeamarkPoint< T > > &other_seamarks) const
ComputeRetentionTimeReference m_retentionTimeReferenceMethod
const std::vector< MsRunRetentionTimeSeamarkPoint< T > > getSeamarksReferences() const
std::vector< double > m_ms1RetentionTimeVector
void addPeptideAsSeamark(const T &peptide_id, double retentionTime, double precursorIntensity)
collects all peptide evidences of a given MSrun seamarks has to be converted to peptide retention tim...
FilterMorphoMedian m_ms2MedianFilter
const FilterMorphoMean & getMs2MeanFilter() const
std::size_t getNumberOfCorrectedValues() const
A simple container of DataPoint instances.
Definition trace.h:148
void unique()
Definition trace.cpp:1059
std::vector< pappso_double > yValues() const
Definition trace.cpp:677
void sortX(Enums::SortOrder sort_order=Enums::SortOrder::ascending)
Definition trace.cpp:1039
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
pappso_double x
Definition datapoint.h:24
pappso_double y
Definition datapoint.h:25