OpenMS
Loading...
Searching...
No Matches
SignalToNoiseEstimatorMedian.h
Go to the documentation of this file.
1// Copyright (c) 2002-present, OpenMS Inc. -- EKU Tuebingen, ETH Zurich, and FU Berlin
2// SPDX-License-Identifier: BSD-3-Clause
3//
4// --------------------------------------------------------------------------
5// $Maintainer: Chris Bielow $
6// $Authors: $
7// --------------------------------------------------------------------------
8//
9
10#pragma once
11
12
17#include <vector>
18#include <algorithm> //for std::max_element
19
20namespace OpenMS
21{
60 template <typename Container = MSSpectrum>
62 public SignalToNoiseEstimator<Container>
63 {
64
65public:
66
69
71 using SignalToNoiseEstimator<Container>::defaults_;
72 using SignalToNoiseEstimator<Container>::param_;
73
76
78
81 {
82 //set the name for DefaultParamHandler error messages
83 this->setName("SignalToNoiseEstimatorMedian");
84
85 defaults_.setValue("max_intensity", -1, "maximal intensity considered for histogram construction. By default, it will be calculated automatically (see auto_mode)." \
86 " Only provide this parameter if you know what you are doing (and change 'auto_mode' to '-1')!" \
87 " All intensities EQUAL/ABOVE 'max_intensity' will be added to the LAST histogram bin." \
88 " If you choose 'max_intensity' too small, the noise estimate might be too small as well. " \
89 " If chosen too big, the bins become quite large (which you could counter by increasing 'bin_count', which increases runtime)." \
90 " In general, the Median-S/N estimator is more robust to a manual max_intensity than the MeanIterative-S/N.", {"advanced"});
91 defaults_.setMinInt("max_intensity", -1);
92
93 defaults_.setValue("auto_max_stdev_factor", 3.0, "parameter for 'max_intensity' estimation (if 'auto_mode' == 0): mean + 'auto_max_stdev_factor' * stdev", {"advanced"});
94 defaults_.setMinFloat("auto_max_stdev_factor", 0.0);
95 defaults_.setMaxFloat("auto_max_stdev_factor", 999.0);
96
97 defaults_.setValue("auto_max_percentile", 95, "parameter for 'max_intensity' estimation (if 'auto_mode' == 1): auto_max_percentile th percentile", {"advanced"});
98 defaults_.setMinInt("auto_max_percentile", 0);
99 defaults_.setMaxInt("auto_max_percentile", 100);
100
101 defaults_.setValue("auto_mode", 0, "method to use to determine maximal intensity: -1 --> use 'max_intensity'; 0 --> 'auto_max_stdev_factor' method (default); 1 --> 'auto_max_percentile' method", {"advanced"});
102 defaults_.setMinInt("auto_mode", -1);
103 defaults_.setMaxInt("auto_mode", 1);
104
105 defaults_.setValue("win_len", 200.0, "window length in Thomson");
106 defaults_.setMinFloat("win_len", 1.0);
107
108 defaults_.setValue("bin_count", 30, "number of bins for intensity values");
109 defaults_.setMinInt("bin_count", 3);
110
111 defaults_.setValue("min_required_elements", 10, "minimum number of elements required in a window (otherwise it is considered sparse)");
112 defaults_.setMinInt("min_required_elements", 1);
113
114 defaults_.setValue("noise_for_empty_window", std::pow(10.0, 20), "noise value used for sparse windows", {"advanced"});
115
116 defaults_.setValue("write_log_messages", "true", "Write out log messages in case of sparse windows or median in rightmost histogram bin");
117 defaults_.setValidStrings("write_log_messages", {"true","false"});
118
120 }
121
124 SignalToNoiseEstimator<Container>(source)
125 {
127 }
128
134 {
135 if (&source == this) return *this;
136
139 return *this;
140 }
141
143
147
150 {
152 }
153
156 {
158 }
159
160protected:
161
162
168 void computeSTN_(const Container& c) override
169 {
170 //first element in the scan
171 PeakIterator scan_first_ = c.begin();
172 //last element in the scan
173 PeakIterator scan_last_ = c.end();
174
175 // reset counter for sparse windows
177 // reset counter for histogram overflow
179
180 // reset the results
181 stn_estimates_.clear();
182 stn_estimates_.resize(c.size());
183
184 // maximal range of histogram needs to be calculated first
186 {
187 // use MEAN+auto_max_intensity_*STDEV as threshold
188 GaussianEstimate gauss_global = SignalToNoiseEstimator<Container>::estimate_(scan_first_, scan_last_);
189 max_intensity_ = gauss_global.mean + std::sqrt(gauss_global.variance) * auto_max_stdev_Factor_;
190 }
191 else if (auto_mode_ == AUTOMAXBYPERCENT)
192 {
193 // get value at "auto_max_percentile_"th percentile
194 // we use a histogram approach here as well.
195 if ((auto_max_percentile_ < 0) || (auto_max_percentile_ > 100))
196 {
198 throw Exception::InvalidValue(__FILE__,
199 __LINE__,
200 OPENMS_PRETTY_FUNCTION,
201 "auto_mode is on AUTOMAXBYPERCENT! auto_max_percentile is not in [0,100]. Use setAutoMaxPercentile(<value>) to change it!",
202 s);
203 }
204
205 if (c.empty())
206 {
207 return;
208 }
209 std::vector<int> histogram_auto(100, 0);
210
211 // find maximum of current scan
212 auto maxIt = std::max_element(c.begin(), c.end() ,[](const PeakType& a, const PeakType& b){ return a.getIntensity() < b.getIntensity();});
213 typename PeakType::IntensityType maxInt = maxIt->getIntensity();
214
215 double bin_size = maxInt > 0 ? maxInt / 100 : 1.0; // no division by zero if no intensity is positive
216
217 // fill histogram
218 for(const auto& peak : c)
219 {
220 ++histogram_auto[(int) std::max(0.0, std::min((peak.getIntensity() - 1) / bin_size, 99.0))];
221 }
222
223 // add up element counts in histogram until ?th percentile is reached
224 int elements_below_percentile = (int) (auto_max_percentile_ * c.size() / 100);
225 int elements_seen = 0;
226 int i = -1;
227 PeakIterator run = scan_first_;
228
229 while (run != scan_last_ && elements_seen < elements_below_percentile)
230 {
231 ++i;
232 elements_seen += histogram_auto[i];
233 ++run;
234 }
235
236 max_intensity_ = (((double)i) + 0.5) * bin_size;
237 }
238 else //if (auto_mode_ == MANUAL)
239 {
240 if (max_intensity_ <= 0)
241 {
242 std::string s = StringUtils::toStr(max_intensity_);
243 throw Exception::InvalidValue(__FILE__,
244 __LINE__,
245 OPENMS_PRETTY_FUNCTION,
246 "auto_mode is on MANUAL! max_intensity is <=0. Needs to be positive! Use setMaxIntensity(<value>) or enable auto_mode!",
247 s);
248 }
249 }
250
251 if (max_intensity_ < 0)
252 {
253 OPENMS_LOG_WARN << "SignalToNoiseEstimatorMedian: the max_intensity_ value should be positive! " << max_intensity_ << std::endl;
254 return;
255 }
256
257 PeakIterator window_pos_center = scan_first_;
258 PeakIterator window_pos_borderleft = scan_first_;
259 PeakIterator window_pos_borderright = scan_first_;
260
261 double window_half_size = win_len_ / 2;
262 double bin_size = std::max(1.0, max_intensity_ / bin_count_); // at least size of 1 for intensity bins
263 int bin_count_minus_1 = bin_count_ - 1;
264
265 std::vector<int> histogram(bin_count_, 0);
266 std::vector<double> bin_value(bin_count_, 0);
267 // calculate average intensity that is represented by a bin
268 for (int bin = 0; bin < bin_count_; bin++)
269 {
270 histogram[bin] = 0;
271 bin_value[bin] = (bin + 0.5) * bin_size;
272 }
273 // bin in which a datapoint would fall
274 int to_bin = 0;
275
276 // index of bin where the median is located
277 int median_bin = 0;
278 // additive number of elements from left to x in histogram
279 int element_inc_count = 0;
280
281 // tracks elements in current window, which may vary because of unevenly spaced data
282 int elements_in_window = 0;
283 // number of windows
284 int window_count = 0;
285
286 // number of elements where we find the median
287 int element_in_window_half = 0;
288
289 double noise; // noise value of a datapoint
290
292 SignalToNoiseEstimator<Container>::startProgress(0, c.size(), "noise estimation of data");
293
294 // MAIN LOOP
295 while (window_pos_center != scan_last_)
296 {
297
298 // erase all elements from histogram that will leave the window on the LEFT side
299 while ((*window_pos_borderleft).getPos() < (*window_pos_center).getPos() - window_half_size)
300 {
301 to_bin = (int) std::max(std::min((*window_pos_borderleft).getIntensity() / bin_size, (double) bin_count_minus_1), 0.0); // clamp before converting to int
302 --histogram[to_bin];
303 --elements_in_window;
304 ++window_pos_borderleft;
305 }
306
307 // add all elements to histogram that will enter the window on the RIGHT side
308 while ((window_pos_borderright != scan_last_)
309 && ((*window_pos_borderright).getPos() <= (*window_pos_center).getPos() + window_half_size))
310 {
311 //std::cerr << (*window_pos_borderright).getIntensity() << " " << bin_size << " " << bin_count_minus_1 << std::endl;
312 to_bin = (int) std::max(std::min((*window_pos_borderright).getIntensity() / bin_size, (double) bin_count_minus_1), 0.0); // clamp before converting to int
313 ++histogram[to_bin];
314 ++elements_in_window;
315 ++window_pos_borderright;
316 }
317
318 if (elements_in_window < min_required_elements_)
319 {
322 }
323 else
324 {
325 // find bin i where ceil[elements_in_window/2] <= sum_c(0..i){ histogram[c] }
326 median_bin = -1;
327 element_inc_count = 0;
328 element_in_window_half = (elements_in_window + 1) / 2;
329 while (median_bin < bin_count_minus_1 && element_inc_count < element_in_window_half)
330 {
331 ++median_bin;
332 element_inc_count += histogram[median_bin];
333 }
334
335 // increase the error count
336 if (median_bin == bin_count_minus_1) {++histogram_oob_percent_; }
337
338 // Interpolate within the median bin instead of just reporting its center.
339 // Using the bin center alone means the noise estimate can only take one of
340 // 'bin_count_' discrete values; a tiny, insignificant shift in which side of
341 // a bin boundary the cumulative-median crossing falls on then causes a full
342 // bin-width jump in the reported noise, even though the underlying data barely
343 // changed. Assuming points are uniformly distributed within the bin, we can
344 // instead estimate where inside the bin the crossing actually occurs.
345 const int elements_in_median_bin = histogram[median_bin];
346 double noise_estimate;
347 if (elements_in_median_bin > 0)
348 {
349 const int elements_before_median_bin = element_inc_count - elements_in_median_bin;
350 const double median_bin_lower_edge = median_bin * bin_size;
351 noise_estimate = median_bin_lower_edge
352 + ((double)(element_in_window_half - elements_before_median_bin) / elements_in_median_bin) * bin_size;
353 }
354 else // only possible if the rightmost bin was hit while empty (already flagged above)
355 {
356 noise_estimate = bin_value[median_bin];
357 }
358
359 // just avoid division by 0
360 noise = std::max(1.0, noise_estimate);
361 }
362
363 // store result
364 stn_estimates_[window_count] = (*window_pos_center).getIntensity() / noise;
365
366
367 // advance the window center by one datapoint
368 ++window_pos_center;
369 ++window_count;
370 // update progress
372
373 } // end while
374
376
377 sparse_window_percent_ = sparse_window_percent_ * 100 / window_count;
378 histogram_oob_percent_ = histogram_oob_percent_ * 100 / window_count;
379
380 // warn if percentage of sparse windows is above 20%
382 {
383 OPENMS_LOG_WARN << "WARNING in SignalToNoiseEstimatorMedian: "
385 << "% of all windows were sparse. You should consider increasing 'win_len' or decreasing 'min_required_elements'"
386 << std::endl;
387 }
388
389 // warn if percentage of possibly wrong median estimates is above 1%
391 {
392 OPENMS_LOG_WARN << "WARNING in SignalToNoiseEstimatorMedian: "
394 << "% of all Signal-to-Noise estimates are too high, because the median was found in the rightmost histogram-bin. "
395 << "You should consider increasing 'max_intensity' (and maybe 'bin_count' with it, to keep bin width reasonable)"
396 << std::endl;
397 }
398
399 } // end of shiftWindow_
400
402 void updateMembers_() override
403 {
404 max_intensity_ = (double)param_.getValue("max_intensity");
405 auto_max_stdev_Factor_ = (double)param_.getValue("auto_max_stdev_factor");
406 auto_max_percentile_ = param_.getValue("auto_max_percentile");
407 auto_mode_ = param_.getValue("auto_mode");
408 win_len_ = (double)param_.getValue("win_len");
409 bin_count_ = param_.getValue("bin_count");
410 min_required_elements_ = param_.getValue("min_required_elements");
411 noise_for_empty_window_ = (double)param_.getValue("noise_for_empty_window");
412 write_log_messages_ = (bool)param_.getValue("write_log_messages").toBool();
413 stn_estimates_.clear();
414 }
415
425 double win_len_;
433
434 // whether to write out log messages in the case of failure
436
437 // counter for sparse windows
439 // counter for histogram overflow
441
442
443 };
444
445} // namespace OpenMS
446
#define OPENMS_LOG_WARN
Macro for warnings.
Definition LogStream.h:691
void defaultsToParam_()
Updates the parameters after the defaults have been set in the constructor.
Param param_
Container for current parameters.
Definition DefaultParamHandler.h:139
Param defaults_
Container for default parameters. This member should be filled in the constructor of derived classes!
Definition DefaultParamHandler.h:146
void setName(const std::string &name)
Mutable access to the name.
Invalid value exception.
Definition Exception.h:306
bool toBool() const
Conversion to bool.
const ParamValue & getValue(const std::string &key) const
Returns a value of a parameter.
void setValidStrings(const std::string &key, const std::vector< std::string > &strings)
Sets the valid strings for the parameter key.
void setMaxFloat(const std::string &key, double max)
Sets the maximum value for the floating point or floating point list parameter key.
void setMaxInt(const std::string &key, int max)
Sets the maximum value for the integer or integer list parameter key.
void setMinInt(const std::string &key, int min)
Sets the minimum value for the integer or integer list parameter key.
void setValue(const std::string &key, const ParamValue &value, const std::string &description="", const std::vector< std::string > &tags=std::vector< std::string >())
Sets a value.
void setMinFloat(const std::string &key, double min)
Sets the minimum value for the floating point or floating point list parameter key.
float IntensityType
Intensity type.
Definition Peak2D.h:37
void setProgress(SignedSize value) const
Sets the current progress.
void endProgress(UInt64 bytes_processed=0) const
void startProgress(SignedSize begin, SignedSize end, const std::string &label) const
Initializes the progress display.
Estimates the signal/noise (S/N) ratio of each data point in a scan by using the median (histogram ba...
Definition SignalToNoiseEstimatorMedian.h:63
SignalToNoiseEstimator< Container >::PeakIterator PeakIterator
Definition SignalToNoiseEstimatorMedian.h:74
double win_len_
range of data points which belong to a window in Thomson
Definition SignalToNoiseEstimatorMedian.h:425
SignalToNoiseEstimatorMedian & operator=(const SignalToNoiseEstimatorMedian &source)
Definition SignalToNoiseEstimatorMedian.h:133
double noise_for_empty_window_
Definition SignalToNoiseEstimatorMedian.h:432
~SignalToNoiseEstimatorMedian() override
Destructor.
Definition SignalToNoiseEstimatorMedian.h:145
SignalToNoiseEstimatorMedian()
default constructor
Definition SignalToNoiseEstimatorMedian.h:80
double max_intensity_
maximal intensity considered during binning (values above get discarded)
Definition SignalToNoiseEstimatorMedian.h:417
double auto_max_percentile_
parameter for initial automatic estimation of "max_intensity_" percentile or a stdev
Definition SignalToNoiseEstimatorMedian.h:421
double histogram_oob_percent_
Definition SignalToNoiseEstimatorMedian.h:440
void computeSTN_(const Container &c) override
Definition SignalToNoiseEstimatorMedian.h:168
bool write_log_messages_
Definition SignalToNoiseEstimatorMedian.h:435
void updateMembers_() override
overridden function from DefaultParamHandler to keep members up to date, when a parameter is changed
Definition SignalToNoiseEstimatorMedian.h:402
int min_required_elements_
minimal number of elements a window needs to cover to be used
Definition SignalToNoiseEstimatorMedian.h:429
SignalToNoiseEstimatorMedian(const SignalToNoiseEstimatorMedian &source)
Copy Constructor.
Definition SignalToNoiseEstimatorMedian.h:123
double getSparseWindowPercent() const
Returns how many percent of the windows were sparse.
Definition SignalToNoiseEstimatorMedian.h:149
double sparse_window_percent_
Definition SignalToNoiseEstimatorMedian.h:438
double getHistogramRightmostPercent() const
Returns the percentage where the median was found in the rightmost bin.
Definition SignalToNoiseEstimatorMedian.h:155
SignalToNoiseEstimator< Container >::PeakType PeakType
Definition SignalToNoiseEstimatorMedian.h:75
SignalToNoiseEstimator< Container >::GaussianEstimate GaussianEstimate
Definition SignalToNoiseEstimatorMedian.h:77
int auto_mode_
determines which method shall be used for estimating "max_intensity_". valid are MANUAL=-1,...
Definition SignalToNoiseEstimatorMedian.h:423
IntensityThresholdCalculation
method to use for estimating the maximal intensity that is used for histogram calculation
Definition SignalToNoiseEstimatorMedian.h:68
@ MANUAL
Definition SignalToNoiseEstimatorMedian.h:68
@ AUTOMAXBYSTDEV
Definition SignalToNoiseEstimatorMedian.h:68
@ AUTOMAXBYPERCENT
Definition SignalToNoiseEstimatorMedian.h:68
int bin_count_
number of bins in the histogram
Definition SignalToNoiseEstimatorMedian.h:427
double auto_max_stdev_Factor_
parameter for initial automatic estimation of "max_intensity_": a stdev multiplier
Definition SignalToNoiseEstimatorMedian.h:419
This class represents the abstract base class of a signal to noise estimator.
Definition SignalToNoiseEstimator.h:33
double variance
variance of estimated Gaussian
Definition SignalToNoiseEstimator.h:108
PeakIterator::value_type PeakType
Definition SignalToNoiseEstimator.h:40
SignalToNoiseEstimator & operator=(const SignalToNoiseEstimator &source)
Assignment operator.
Definition SignalToNoiseEstimator.h:60
GaussianEstimate estimate_(const PeakIterator &scan_first_, const PeakIterator &scan_last_) const
calculate mean & stdev of intensities of a spectrum
Definition SignalToNoiseEstimator.h:113
double mean
mean of estimated Gaussian
Definition SignalToNoiseEstimator.h:107
std::vector< double > stn_estimates_
stores the noise estimate for each peak
Definition SignalToNoiseEstimator.h:146
Container::const_iterator PeakIterator
Definition SignalToNoiseEstimator.h:39
protected struct to store parameters my, sigma for a Gaussian distribution
Definition SignalToNoiseEstimator.h:106
std::string toStr(int i)
Definition StringUtils.h:101
Main OpenMS namespace.
Definition openswathalgo/include/OpenMS/OPENSWATHALGO/DATAACCESS/ISpectrumAccess.h:19