112 template <
typename SpectrumT,
typename TransitionT>
118 std::vector<MSChromatogram > picked_chroms;
119 std::vector<MSChromatogram > smoothed_chroms;
130 !transition_group.
getTransition(native_id).isDetectingTransition() )
136 picker_.pickChromatogram(chromatogram, picked_chrom, smoothed_chrom);
138 picked_chroms.push_back(std::move(picked_chrom));
139 smoothed_chroms.push_back(std::move(smoothed_chrom));
147 SpectrumT picked_chrom, smoothed_chrom;
150 picker_.pickChromatogram(chromatogram, picked_chrom, smoothed_chrom);
151 picked_chrom.sortByIntensity();
152 picked_chroms.push_back(picked_chrom);
153 smoothed_chroms.push_back(smoothed_chrom);
161 int chr_idx, peak_idx, cnt = 0;
162 std::vector<MRMFeature> features;
165 chr_idx = -1; peak_idx = -1;
167 if (boundary_selection_method_ ==
"largest")
169 findLargestPeak(picked_chroms, chr_idx, peak_idx);
171 else if (boundary_selection_method_ ==
"widest")
173 findWidestPeakIndices(picked_chroms, chr_idx, peak_idx);
176 if (chr_idx == -1 && peak_idx == -1)
break;
179 MRMFeature mrm_feature = createMRMFeature(transition_group, picked_chroms, smoothed_chroms, chr_idx, peak_idx);
180 double total_xic = 0;
185 features.push_back(std::move(mrm_feature));
189 if (stop_after_feature_ > 0 && cnt > stop_after_feature_) {
break;}
190 if (intensity > 0 && intensity / total_xic < stop_after_intensity_ratio_)
197 for (
Size i = 0; i < features.size(); i++)
201 for (
Size j = 0; j < i; j++)
203 if ((
double)mrm_feature.
getMetaValue(
"leftWidth") >= (
double)features[j].getMetaValue(
"leftWidth") &&
216 template <
typename SpectrumT,
typename TransitionT>
218 std::vector<SpectrumT>& picked_chroms,
219 const std::vector<SpectrumT>& smoothed_chroms,
230 double peak_apex = picked_chroms[chr_idx][peak_idx].getRT();
231 OPENMS_LOG_DEBUG <<
"**** Creating MRMFeature for peak " << chr_idx <<
" " << peak_idx <<
" " <<
232 picked_chroms[chr_idx][peak_idx] <<
" with borders " << best_left <<
" " <<
233 best_right <<
" (" << best_right - best_left <<
")" << std::endl;
235 if (use_consensus_ && recalculate_peaks_)
238 recalculatePeakBorders_(picked_chroms, best_left, best_right, recalculate_peaks_max_z_);
239 if (peak_apex < best_left || peak_apex > best_right)
242 peak_apex = (best_left + best_right) / 2.0;
246 std::vector< double > left_edges;
247 std::vector< double > right_edges;
248 double min_left = best_left;
249 double max_right = best_right;
255 remove_overlapping_features(picked_chroms, best_left, best_right);
259 pickApex(picked_chroms, best_left, best_right, peak_apex,
260 min_left, max_right, left_edges, right_edges);
263 picked_chroms[chr_idx][peak_idx].setIntensity(0.0);
268 if (min_peak_width_ > 0.0 && std::fabs(best_right - best_left) < min_peak_width_)
273 if (compute_peak_quality_)
276 double qual = computeQuality_(transition_group, picked_chroms, chr_idx, best_left, best_right, outlier);
277 if (qual < min_qual_)
281 mrmFeature.setMetaValue(
"potentialOutlier", outlier);
282 mrmFeature.setMetaValue(
"initialPeakQuality", qual);
283 mrmFeature.setOverallQuality(qual);
291 SpectrumT master_peak_container;
292 const SpectrumT& ref_chromatogram = selectChromHelper_(transition_group, picked_chroms[chr_idx].getNativeID());
293 prepareMasterContainer_(ref_chromatogram, master_peak_container, min_left, max_right);
298 double total_intensity = 0;
double total_peak_apices = 0;
double total_xic = 0;
double total_mi = 0;
299 pickFragmentChromatograms(transition_group, picked_chroms, mrmFeature, smoothed_chroms,
300 best_left, best_right, use_consensus_,
301 total_intensity, total_xic, total_mi, total_peak_apices,
302 master_peak_container, left_edges, right_edges,
307 pickPrecursorChromatograms(transition_group,
308 picked_chroms, mrmFeature, smoothed_chroms,
309 best_left, best_right, use_consensus_,
310 total_intensity, master_peak_container, left_edges, right_edges,
313 mrmFeature.setRT(peak_apex);
314 mrmFeature.setIntensity(total_intensity);
316 mrmFeature.setMetaValue(
"leftWidth", best_left);
317 mrmFeature.setMetaValue(
"rightWidth", best_right);
318 mrmFeature.setMetaValue(
"total_xic", total_xic);
319 if (compute_total_mi_)
321 mrmFeature.setMetaValue(
"total_mi", total_mi);
323 mrmFeature.setMetaValue(
"peak_apices_sum", total_peak_apices);
325 mrmFeature.ensureUniqueId();
341 template <
typename SpectrumT>
342 void pickApex(std::vector<SpectrumT>& picked_chroms,
343 const double best_left,
const double best_right,
const double peak_apex,
344 double &min_left,
double &max_right,
345 std::vector< double > & left_edges, std::vector< double > & right_edges)
347 for (
Size k = 0;
k < picked_chroms.size();
k++)
349 double peak_apex_dist_min = std::numeric_limits<double>::max();
351 for (
Size i = 0; i < picked_chroms[
k].size(); i++)
357 if (pa_tmp.
apex_pos > 0.0 && std::fabs(pa_tmp.
apex_pos - peak_apex) < peak_apex_dist_min)
359 peak_apex_dist_min = std::fabs(pa_tmp.
apex_pos - peak_apex);
365 double l = best_left;
366 double r = best_right;
371 picked_chroms[
k][min_dist].setIntensity(0.0);
374 left_edges.push_back(l);
375 right_edges.push_back(r);
377 if (l < min_left) {min_left = l;}
378 if (r > max_right) {max_right = r;}
382 template <
typename SpectrumT,
typename TransitionT>
384 const std::vector<SpectrumT>& picked_chroms,
386 const std::vector<SpectrumT>& smoothed_chroms,
387 const double best_left,
const double best_right,
388 const bool use_consensus_,
389 double & total_intensity,
392 double & total_peak_apices,
393 const SpectrumT & master_peak_container,
394 const std::vector< double > & left_edges,
395 const std::vector< double > & right_edges,
402 double local_left = best_left;
403 double local_right = best_right;
412 "When using non-censensus peak picker, all transitions need to be detecting transitions.");
414 local_left = left_edges[
k];
415 local_right = right_edges[
k];
418 const SpectrumT& chromatogram = selectChromHelper_(transition_group, transition_group.
getTransitions()[
k].getNativeID());
421 for (
typename SpectrumT::const_iterator it = chromatogram.begin(); it != chromatogram.end(); it++)
423 total_xic += it->getIntensity();
428 double transition_total_xic = 0;
430 for (
typename SpectrumT::const_iterator it = chromatogram.begin(); it != chromatogram.end(); it++)
432 transition_total_xic += it->getIntensity();
436 double transition_total_mi = 0;
437 if (compute_total_mi_)
439 std::vector<double> chrom_vect_id, chrom_vect_det;
440 for (
typename SpectrumT::const_iterator it = chromatogram.begin(); it != chromatogram.end(); it++)
442 chrom_vect_id.push_back(it->getIntensity());
446 int transition_total_mi_norm = 0;
451 const SpectrumT& chromatogram_det = selectChromHelper_(transition_group, transition_group.
getTransitions()[m].getNativeID());
452 chrom_vect_det.clear();
453 for (
typename SpectrumT::const_iterator it = chromatogram_det.begin(); it != chromatogram_det.end(); it++)
455 chrom_vect_det.push_back(it->getIntensity());
458 transition_total_mi_norm++;
461 if (transition_total_mi_norm > 0) { transition_total_mi /= transition_total_mi_norm; }
466 total_mi += transition_total_mi / transition_total_mi_norm;
470 SpectrumT used_chromatogram;
472 if (peak_integration_ ==
"original")
474 used_chromatogram = resampleChromatogram_(chromatogram, master_peak_container, local_left, local_right);
476 else if (peak_integration_ ==
"smoothed")
478 if (smoothed_chroms.size() <=
k)
481 "Tried to calculate peak area and height without any smoothed chromatograms");
483 used_chromatogram = resampleChromatogram_(smoothed_chroms[
k], master_peak_container, local_left, local_right);
488 String(
"Peak integration chromatogram ") + peak_integration_ +
" is not a valid method for MRMTransitionGroupPicker");
497 double peak_integral = pa.
area;
498 double peak_apex_int = pa.
height;
500 if (background_subtraction_ !=
"none")
502 double background{0};
503 double avg_noise_level{0};
504 if (background_subtraction_ ==
"original")
506 const double intensity_left = chromatogram.PosBegin(local_left)->getIntensity();
507 const double intensity_right = (chromatogram.PosEnd(local_right) - 1)->getIntensity();
508 const UInt n_points = std::distance(chromatogram.PosBegin(local_left), chromatogram.PosEnd(local_right));
509 avg_noise_level = (intensity_right + intensity_left) / 2;
510 background = avg_noise_level * n_points;
512 else if (background_subtraction_ ==
"exact")
515 background = pb.
area;
516 avg_noise_level = pb.
height;
518 peak_integral -= background;
519 peak_apex_int -= avg_noise_level;
520 if (peak_integral < 0) {peak_integral = 0;}
521 if (peak_apex_int < 0) {peak_apex_int = 0;}
524 f.
setMetaValue(
"noise_background_level", avg_noise_level);
527 f.
setRT(picked_chroms[chr_idx][peak_idx].getMZ());
533 f.
setMZ(chromatogram.getProduct().getMZ());
534 mrmFeature.
setMZ(chromatogram.getPrecursor().getMZ());
536 if (chromatogram.metaValueExists(
"product_mz"))
538 f.
setMetaValue(
"MZ", chromatogram.getMetaValue(
"product_mz"));
539 f.
setMZ(chromatogram.getMetaValue(
"product_mz"));
542 f.
setMetaValue(
"native_id", chromatogram.getNativeID());
545 if (compute_total_mi_)
552 total_intensity += peak_integral;
553 total_peak_apices += peak_apex_int;
560 if (compute_peak_shape_metrics_)
579 mrmFeature.
addFeature(f, chromatogram.getNativeID());
583 template <
typename SpectrumT,
typename TransitionT>
585 const std::vector<SpectrumT>& picked_chroms,
587 const std::vector<SpectrumT>& smoothed_chroms,
588 const double best_left,
const double best_right,
589 const bool use_consensus_,
590 double & total_intensity,
591 const SpectrumT & master_peak_container,
592 const std::vector< double > & left_edges,
593 const std::vector< double > & right_edges,
605 double local_left = best_left;
606 double local_right = best_right;
607 if (!use_consensus_ && right_edges.size() > prec_idx && left_edges.size() > prec_idx)
609 local_left = left_edges[prec_idx];
610 local_right = right_edges[prec_idx];
613 SpectrumT used_chromatogram;
615 if (peak_integration_ ==
"original")
617 used_chromatogram = resampleChromatogram_(chromatogram, master_peak_container, local_left, local_right);
620 else if (peak_integration_ ==
"smoothed" && smoothed_chroms.size() <= prec_idx)
623 "Tried to calculate peak area and height without any smoothed chromatograms for precursors");
625 else if (peak_integration_ ==
"smoothed")
627 used_chromatogram = resampleChromatogram_(smoothed_chroms[prec_idx], master_peak_container, local_left, local_right);
632 String(
"Peak integration chromatogram ") + peak_integration_ +
" is not a valid method for MRMTransitionGroupPicker");
641 double peak_integral = pa.
area;
642 double peak_apex_int = pa.
height;
644 if (background_subtraction_ !=
"none")
646 double background{0};
647 double avg_noise_level{0};
648 if ((peak_integration_ ==
"smoothed") && smoothed_chroms.size() <= prec_idx)
651 "Tried to calculate background estimation without any smoothed chromatograms");
653 else if (background_subtraction_ ==
"original")
655 const double intensity_left = chromatogram.PosBegin(local_left)->getIntensity();
656 const double intensity_right = (chromatogram.PosEnd(local_right) - 1)->getIntensity();
657 const UInt n_points = std::distance(chromatogram.PosBegin(local_left), chromatogram.PosEnd(local_right));
658 avg_noise_level = (intensity_right + intensity_left) / 2;
659 background = avg_noise_level * n_points;
661 else if (background_subtraction_ ==
"exact")
664 background = pb.
area;
665 avg_noise_level = pb.
height;
667 peak_integral -= background;
668 peak_apex_int -= avg_noise_level;
669 if (peak_integral < 0) {peak_integral = 0;}
670 if (peak_apex_int < 0) {peak_apex_int = 0;}
673 f.
setMetaValue(
"noise_background_level", avg_noise_level);
676 f.
setMZ(chromatogram.getPrecursor().getMZ());
677 if (
k == 0) {mrmFeature.
setMZ(chromatogram.getPrecursor().getMZ());}
679 if (chromatogram.metaValueExists(
"precursor_mz"))
681 f.
setMZ(chromatogram.getMetaValue(
"precursor_mz"));
682 if (
k == 0) {mrmFeature.
setMZ(chromatogram.getMetaValue(
"precursor_mz"));}
685 f.
setRT(picked_chroms[chr_idx][peak_idx].getMZ());
690 f.
setMetaValue(
"native_id", chromatogram.getNativeID());
695 total_intensity += peak_integral;
715 template <
typename SpectrumT>
719 for (
Size k = 0;
k < picked_chroms.size();
k++)
721 for (
Size i = 0; i < picked_chroms[
k].size(); i++)
723 if (picked_chroms[
k][i].getMZ() >= best_left && picked_chroms[
k][i].getMZ() <= best_right)
725 picked_chroms[
k][i].setIntensity(0.0);
731 for (
Size k = 0;
k < picked_chroms.size();
k++)
733 for (
Size i = 0; i < picked_chroms[
k].size(); i++)
735 if (picked_chroms[
k][i].getIntensity() <= 0.0) {
continue; }
739 if ((left > best_left && left < best_right)
740 || (right > best_left && right < best_right))
742 picked_chroms[
k][i].setIntensity(0.0);
749 void findLargestPeak(
const std::vector<MSChromatogram >& picked_chroms,
int& chr_idx,
int& peak_idx);
759 void findWidestPeakIndices(
const std::vector<MSChromatogram>& picked_chroms,
Int& chrom_idx,
Int& point_idx)
const;
764 void updateMembers_()
override;
772 template <
typename SpectrumT,
typename TransitionT>
785 throw Exception::IllegalArgument(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
"Did not find chromatogram for id '" + native_id +
"'.");
805 template <
typename SpectrumT,
typename TransitionT>
807 const std::vector<SpectrumT>& picked_chroms,
809 const double best_left,
810 const double best_right,
816 double resample_boundary = resample_boundary_;
817 SpectrumT master_peak_container;
818 const SpectrumT& ref_chromatogram = selectChromHelper_(transition_group, picked_chroms[chr_idx].getNativeID());
819 prepareMasterContainer_(ref_chromatogram, master_peak_container, best_left - resample_boundary, best_right + resample_boundary);
820 std::vector<std::vector<double> > all_ints;
821 for (
Size k = 0;
k < picked_chroms.size();
k++)
823 const SpectrumT& chromatogram = selectChromHelper_(transition_group, picked_chroms[
k].getNativeID());
824 const SpectrumT used_chromatogram = resampleChromatogram_(chromatogram,
825 master_peak_container, best_left - resample_boundary, best_right + resample_boundary);
827 std::vector<double> int_here;
828 for (
const auto& peak : used_chromatogram) int_here.push_back(peak.getIntensity());
830 double tic = std::accumulate(int_here.begin(), int_here.end(), 0.0);
831 if (tic > 0.0) all_ints.push_back(int_here);
835 std::vector<double> mean_shapes;
836 std::vector<double> mean_coel;
837 for (
Size k = 0;
k < all_ints.size();
k++)
839 std::vector<double> shapes;
840 std::vector<double> coel;
841 for (
Size i = 0; i < all_ints.size(); i++)
843 if (i ==
k) {
continue;}
845 all_ints[
k], all_ints[i], boost::numeric_cast<int>(all_ints[i].size()), 1);
851 shapes.push_back(res_shape);
852 coel.push_back(res_coelution);
858 msc = std::for_each(shapes.begin(), shapes.end(), msc);
859 double shapes_mean = msc.
mean();
860 msc = std::for_each(coel.begin(), coel.end(), msc);
861 double coel_mean = msc.
mean();
865 mean_shapes.push_back(shapes_mean);
866 mean_coel.push_back(coel_mean);
872 int min_index_shape = std::distance(mean_shapes.begin(), std::min_element(mean_shapes.begin(), mean_shapes.end()));
873 int max_index_coel = std::distance(mean_coel.begin(), std::max_element(mean_coel.begin(), mean_coel.end()));
876 int missing_peaks = 0;
877 int multiple_peaks = 0;
880 std::vector<double> left_borders;
881 std::vector<double> right_borders;
882 for (
Size k = 0;
k < picked_chroms.size();
k++)
891 for (
Size i = 0; i < picked_chroms[
k].size(); i++)
893 if (picked_chroms[
k][i].getMZ() >= best_left && picked_chroms[
k][i].getMZ() <= best_right)
896 if (picked_chroms[
k][i].getIntensity() > max_int)
898 max_int = picked_chroms[
k][i].getIntensity() > max_int;
905 if (l_tmp > 0.0) left_borders.push_back(l_tmp);
906 if (r_tmp > 0.0) right_borders.push_back(r_tmp);
908 if (pfound == 0) missing_peaks++;
909 if (pfound > 1) multiple_peaks++;
914 OPENMS_LOG_DEBUG <<
" Overall found missing : " << missing_peaks <<
" and multiple : " << multiple_peaks << std::endl;
920 if (min_index_shape == max_index_coel)
922 OPENMS_LOG_DEBUG <<
" element " << min_index_shape <<
" is a candidate for removal ... " << std::endl;
923 outlier =
String(picked_chroms[min_index_shape].getNativeID());
935 double shape_score = std::accumulate(mean_shapes.begin(), mean_shapes.end(), 0.0) / mean_shapes.size();
936 double coel_score = std::accumulate(mean_coel.begin(), mean_coel.end(), 0.0) / mean_coel.size();
937 coel_score = (coel_score - 1.0) / 2.0;
939 double score = shape_score - coel_score - 1.0 * missing_peaks / picked_chroms.size();
941 OPENMS_LOG_DEBUG <<
" computed score " << score <<
" (from " << shape_score <<
942 " - " << coel_score <<
" - " << 1.0 * missing_peaks / picked_chroms.size() <<
")" << std::endl;
956 template <
typename SpectrumT>
957 void recalculatePeakBorders_(
const std::vector<SpectrumT>& picked_chroms,
double& best_left,
double& best_right,
double max_z)
963 std::vector<double> left_borders;
964 std::vector<double> right_borders;
965 for (
Size k = 0;
k < picked_chroms.size();
k++)
970 for (
Size i = 0; i < picked_chroms[
k].size(); i++)
972 if (picked_chroms[
k][i].getMZ() >= best_left && picked_chroms[
k][i].getMZ() <= best_right)
984 left_borders.push_back(left);
985 right_borders.push_back(right);
986 OPENMS_LOG_DEBUG <<
" * " <<
k <<
" left boundary " << left_borders.back() <<
" with int " << max_int << std::endl;
987 OPENMS_LOG_DEBUG <<
" * " <<
k <<
" right boundary " << right_borders.back() <<
" with int " << max_int << std::endl;
992 if (right_borders.empty())
1010 mean = std::accumulate(right_borders.begin(), right_borders.end(), 0.0) / (
double) right_borders.size();
1011 stdev = std::sqrt(std::inner_product(right_borders.begin(), right_borders.end(), right_borders.begin(), 0.0)
1012 / right_borders.size() -
mean *
mean);
1013 std::sort(right_borders.begin(), right_borders.end());
1016 << best_right <<
" std " << stdev <<
" : " << std::fabs(best_right -
mean) / stdev
1017 <<
" coefficient of variation" << std::endl;
1020 if (std::fabs(best_right -
mean) / stdev > max_z)
1022 best_right = right_borders[right_borders.size() / 2];
1023 OPENMS_LOG_DEBUG <<
" - Setting right boundary to " << best_right << std::endl;
1027 mean = std::accumulate(left_borders.begin(), left_borders.end(), 0.0) / (
double) left_borders.size();
1028 stdev = std::sqrt(std::inner_product(left_borders.begin(), left_borders.end(), left_borders.begin(), 0.0)
1029 / left_borders.size() -
mean *
mean);
1030 std::sort(left_borders.begin(), left_borders.end());
1033 << best_left <<
" std " << stdev <<
" : " << std::fabs(best_left -
mean) / stdev
1034 <<
" coefficient of variation" << std::endl;
1037 if (std::fabs(best_left -
mean) / stdev > max_z)
1039 best_left = left_borders[left_borders.size() / 2];
1040 OPENMS_LOG_DEBUG <<
" - Setting left boundary to " << best_left << std::endl;
1062 template <
typename SpectrumT>
1064 SpectrumT& master_peak_container,
double left_boundary,
double right_boundary)
1071 typename SpectrumT::const_iterator begin = ref_chromatogram.begin();
1072 while (begin != ref_chromatogram.end() && begin->getMZ() < left_boundary) {begin++; }
1073 if (begin != ref_chromatogram.begin()) {begin--; }
1075 typename SpectrumT::const_iterator end = begin;
1076 while (end != ref_chromatogram.end() && end->getMZ() < right_boundary) {end++; }
1077 if (end != ref_chromatogram.end()) {end++; }
1080 master_peak_container.resize(distance(begin, end));
1081 typename SpectrumT::iterator it = master_peak_container.begin();
1082 for (
typename SpectrumT::const_iterator chrom_it = begin; chrom_it != end; chrom_it++, it++)
1084 it->setMZ(chrom_it->getMZ());
1098 template <
typename SpectrumT>
1100 const SpectrumT& master_peak_container,
double left_boundary,
double right_boundary)
1105 typename SpectrumT::const_iterator begin = chromatogram.begin();
1106 while (begin != chromatogram.end() && begin->getMZ() < left_boundary) {begin++;}
1107 if (begin != chromatogram.begin()) {begin--;}
1109 typename SpectrumT::const_iterator end = begin;
1110 while (end != chromatogram.end() && end->getMZ() < right_boundary) {end++;}
1111 if (end != chromatogram.end()) {end++;}
1113 SpectrumT resampled_peak_container = master_peak_container;
1115 lresampler.
raster(begin, end, resampled_peak_container.begin(), resampled_peak_container.end());
1117 return resampled_peak_container;