Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages

SignalToNoiseEstimatorMeanIterative.h

Go to the documentation of this file.
00001 // --------------------------------------------------------------------------
00002 //                   OpenMS -- Open-Source Mass Spectrometry
00003 // --------------------------------------------------------------------------
00004 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
00005 // ETH Zurich, and Freie Universitaet Berlin 2002-2012.
00006 //
00007 // This software is released under a three-clause BSD license:
00008 //  * Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 //  * Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //  * Neither the name of any author or any participating institution
00014 //    may be used to endorse or promote products derived from this software
00015 //    without specific prior written permission.
00016 // For a full list of authors, refer to the file AUTHORS.
00017 // --------------------------------------------------------------------------
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
00022 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // --------------------------------------------------------------------------
00031 // $Maintainer: Chris Bielow $
00032 // $Authors: $
00033 // --------------------------------------------------------------------------
00034 //
00035 
00036 #ifndef OPENMS_FILTERING_NOISEESTIMATION_SIGNALTONOISEESTIMATORMEANITERATIVE_H
00037 #define OPENMS_FILTERING_NOISEESTIMATION_SIGNALTONOISEESTIMATORMEANITERATIVE_H
00038 
00039 #include <OpenMS/FILTERING/NOISEESTIMATION/SignalToNoiseEstimator.h>
00040 #include <OpenMS/CONCEPT/Exception.h>
00041 #include <vector>
00042 
00043 namespace OpenMS
00044 {
00068   template <typename Container = MSSpectrum<> >
00069   class SignalToNoiseEstimatorMeanIterative :
00070     public SignalToNoiseEstimator<Container>
00071   {
00072 
00073 public:
00074 
00076     enum IntensityThresholdCalculation {MANUAL = -1, AUTOMAXBYSTDEV = 0, AUTOMAXBYPERCENT = 1};
00077 
00078     using SignalToNoiseEstimator<Container>::stn_estimates_;
00079     using SignalToNoiseEstimator<Container>::first_;
00080     using SignalToNoiseEstimator<Container>::last_;
00081     using SignalToNoiseEstimator<Container>::is_result_valid_;
00082     using SignalToNoiseEstimator<Container>::defaults_;
00083     using SignalToNoiseEstimator<Container>::param_;
00084 
00085     typedef typename SignalToNoiseEstimator<Container>::PeakIterator PeakIterator;
00086     typedef typename SignalToNoiseEstimator<Container>::PeakType PeakType;
00087 
00088     typedef typename SignalToNoiseEstimator<Container>::GaussianEstimate GaussianEstimate;
00089 
00090 
00092     inline SignalToNoiseEstimatorMeanIterative()
00093     {
00094       //set the name for DefaultParamHandler error messages
00095       this->setName("SignalToNoiseEstimatorMeanIterative");
00096 
00097       defaults_.setValue("max_intensity", -1, "maximal intensity considered for histogram construction. By default, it will be calculated automatically (see auto_mode)." \
00098                                               " Only provide this parameter if you know what you are doing (and change 'auto_mode' to '-1')!" \
00099                                               " All intensities EQUAL/ABOVE 'max_intensity' will not be added to the histogram." \
00100                                               " If you choose 'max_intensity' too small, the noise estimate might be too small as well." \
00101                                               " If chosen too big, the bins become quite large (which you could counter by increasing 'bin_count', which increases runtime).", StringList::create("advanced"));
00102       defaults_.setMinInt("max_intensity", -1);
00103 
00104       defaults_.setValue("auto_max_stdev_factor", 3.0, "parameter for 'max_intensity' estimation (if 'auto_mode' == 0): mean + 'auto_max_stdev_factor' * stdev", StringList::create("advanced"));
00105       defaults_.setMinFloat("auto_max_stdev_factor", 0.0);
00106       defaults_.setMaxFloat("auto_max_stdev_factor", 999.0);
00107 
00108 
00109       defaults_.setValue("auto_max_percentile", 95, "parameter for 'max_intensity' estimation (if 'auto_mode' == 1): auto_max_percentile th percentile", StringList::create("advanced"));
00110       defaults_.setMinInt("auto_max_percentile", 0);
00111       defaults_.setMaxInt("auto_max_percentile", 100);
00112 
00113       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", StringList::create("advanced"));
00114       defaults_.setMinInt("auto_mode", -1);
00115       defaults_.setMaxInt("auto_mode", 1);
00116 
00117       defaults_.setValue("win_len", 200.0, "window length in Thomson");
00118       defaults_.setMinFloat("win_len", 1.0);
00119 
00120       defaults_.setValue("bin_count", 30, "number of bins for intensity values");
00121       defaults_.setMinInt("bin_count", 3);
00122 
00123       defaults_.setValue("stdev_mp", 3.0, "multiplier for stdev", StringList::create("advanced"));
00124       defaults_.setMinFloat("stdev_mp", 0.01);
00125       defaults_.setMaxFloat("stdev_mp", 999.0);
00126 
00127       defaults_.setValue("min_required_elements", 10, "minimum number of elements required in a window (otherwise it is considered sparse)");
00128       defaults_.setMinInt("min_required_elements", 1);
00129 
00130       defaults_.setValue("noise_for_empty_window", std::pow(10.0, 20), "noise value used for sparse windows", StringList::create("advanced"));
00131 
00132       SignalToNoiseEstimator<Container>::defaultsToParam_();
00133     }
00134 
00136     inline SignalToNoiseEstimatorMeanIterative(const SignalToNoiseEstimatorMeanIterative & source) :
00137       SignalToNoiseEstimator<Container>(source)
00138     {
00139       updateMembers_();
00140     }
00141 
00145 
00146     inline SignalToNoiseEstimatorMeanIterative & operator=(const SignalToNoiseEstimatorMeanIterative & source)
00147     {
00148       if (&source == this) return *this;
00149 
00150       SignalToNoiseEstimator<Container>::operator=(source);
00151       updateMembers_();
00152       return *this;
00153     }
00154 
00156 
00157 
00159     virtual ~SignalToNoiseEstimatorMeanIterative()
00160     {}
00161 
00162 
00163 protected:
00164 
00165 
00171     virtual void computeSTN_(const PeakIterator & scan_first_, const PeakIterator & scan_last_)
00172     {
00173       // reset counter for sparse windows
00174       double sparse_window_percent = 0;
00175 
00176       // reset the results
00177       stn_estimates_.clear();
00178 
00179       // maximal range of histogram needs to be calculated first
00180       if (auto_mode_ == AUTOMAXBYSTDEV)
00181       {
00182         // use MEAN+auto_max_intensity_*STDEV as threshold
00183         GaussianEstimate gauss_global = SignalToNoiseEstimator<Container>::estimate_(scan_first_, scan_last_);
00184         max_intensity_ = gauss_global.mean + std::sqrt(gauss_global.variance) * auto_max_stdev_Factor_;
00185       }
00186       else if (auto_mode_ == AUTOMAXBYPERCENT)
00187       {
00188         // get value at "auto_max_percentile_"th percentile
00189         // we use a histogram approach here as well.
00190         if ((auto_max_percentile_ < 0) || (auto_max_percentile_ > 100))
00191         {
00192           String s = auto_max_percentile_;
00193           throw Exception::InvalidValue(__FILE__,
00194                                         __LINE__,
00195                                         __PRETTY_FUNCTION__,
00196                                         "auto_mode is on AUTOMAXBYPERCENT! auto_max_percentile is not in [0,100]. Use setAutoMaxPercentile(<value>) to change it!",
00197                                         s);
00198         }
00199 
00200         std::vector<int> histogram_auto(100, 0);
00201 
00202         // find maximum of current scan
00203         int size = 0;
00204         typename PeakType::IntensityType maxInt = 0;
00205         PeakIterator run = scan_first_;
00206         while (run != scan_last_)
00207         {
00208           maxInt = std::max(maxInt, (*run).getIntensity());
00209           ++size;
00210           ++run;
00211         }
00212 
00213         double bin_size = maxInt / 100;
00214 
00215         // fill histogram
00216         run = scan_first_;
00217         while (run != scan_last_)
00218         {
00219           ++histogram_auto[(int) (((*run).getIntensity() - 1) / bin_size)];
00220           ++run;
00221         }
00222 
00223         // add up element counts in histogram until ?th percentile is reached
00224         int elements_below_percentile = (int) (auto_max_percentile_ * size / 100);
00225         int elements_seen = 0;
00226         int i = -1;
00227         run = scan_first_;
00228 
00229         while (run != scan_last_ && elements_seen < elements_below_percentile)
00230         {
00231           ++i;
00232           elements_seen += histogram_auto[i];
00233           ++run;
00234         }
00235 
00236         max_intensity_ = (((double)i) + 0.5) * bin_size;
00237       }
00238       else   //if (auto_mode_ == MANUAL)
00239       {
00240         if (max_intensity_ <= 0)
00241         {
00242           String s = max_intensity_;
00243           throw Exception::InvalidValue(__FILE__,
00244                                         __LINE__,
00245                                         __PRETTY_FUNCTION__,
00246                                         "auto_mode is on MANUAL! max_intensity is <=0. Needs to be positive! Use setMaxIntensity(<value>) or enable auto_mode!",
00247                                         s);
00248         }
00249       }
00250 
00251       if (max_intensity_ < 0)
00252       {
00253         std::cerr << "TODO SignalToNoiseEstimatorMedian: the max_intensity_ value should be positive! " << max_intensity_ << std::endl;
00254         return;
00255       }
00256 
00257       PeakIterator window_pos_center  = scan_first_;
00258       PeakIterator window_pos_borderleft = scan_first_;
00259       PeakIterator window_pos_borderright = scan_first_;
00260 
00261       double window_half_size = win_len_ / 2;
00262       double bin_size = std::max(1.0, max_intensity_ / bin_count_);   // at least size of 1 for intensity bins
00263 
00264       std::vector<int> histogram(bin_count_, 0);
00265       std::vector<double> bin_value(bin_count_, 0);
00266       // calculate average intensity that is represented by a bin
00267       for (int bin = 0; bin < bin_count_; bin++)
00268       {
00269         histogram[bin] = 0;
00270         bin_value[bin] = (bin + 0.5) * bin_size;
00271       }
00272       // index of last valid bin during iteration
00273       int hist_rightmost_bin;
00274       // bin in which a datapoint would fall
00275       int to_bin;
00276       // mean & stdev of the histogram
00277       double hist_mean;
00278       double hist_stdev;
00279 
00280       // tracks elements in current window, which may vary because of unevenly spaced data
00281       int elements_in_window = 0;
00282       int window_count = 0;
00283 
00284       double noise;      // noise value of a datapoint
00285 
00286       // determine how many elements we need to estimate (for progress estimation)
00287       int windows_overall = 0;
00288       PeakIterator run = scan_first_;
00289       while (run != scan_last_)
00290       {
00291         ++windows_overall;
00292         ++run;
00293       }
00294       SignalToNoiseEstimator<Container>::startProgress(0, windows_overall, "noise estimation of data");
00295 
00296       // MAIN LOOP
00297       while (window_pos_center != scan_last_)
00298       {
00299         // erase all elements from histogram that will leave the window on the LEFT side
00300         while ((*window_pos_borderleft).getMZ() <  (*window_pos_center).getMZ() - window_half_size)
00301         {
00302           //std::cout << "S: " << (*window_pos_borderleft).getMZ()  <<  " " << ( (*window_pos_center).getMZ() - window_half_size ) << "\n";
00303           to_bin = (int) ((std::max((*window_pos_borderleft).getIntensity(), 0.0f)) / bin_size);
00304           if (to_bin < bin_count_)
00305           {
00306             --histogram[to_bin];
00307             --elements_in_window;
00308           }
00309           ++window_pos_borderleft;
00310         }
00311 
00312         //std::printf("S1: %E %E\n", (*window_pos_borderright).getMZ(), (*window_pos_center).getMZ() + window_half_size);
00313 
00314 
00315         // add all elements to histogram that will enter the window on the RIGHT side
00316         while ((window_pos_borderright != scan_last_)
00317               && ((*window_pos_borderright).getMZ() < (*window_pos_center).getMZ() + window_half_size))
00318         {
00319           //std::printf("Sb: %E %E %E\n", (*window_pos_borderright).getMZ(), (*window_pos_center).getMZ() + window_half_size, (*window_pos_borderright).getMZ() - ((*window_pos_center).getMZ() + window_half_size));
00320 
00321           to_bin = (int) ((std::max((*window_pos_borderright).getIntensity(), 0.0f)) / bin_size);
00322           if (to_bin < bin_count_)
00323           {
00324             ++histogram[to_bin];
00325             ++elements_in_window;
00326           }
00327           ++window_pos_borderright;
00328         }
00329 
00330         if (elements_in_window < min_required_elements_)
00331         {
00332           noise = noise_for_empty_window_;
00333           ++sparse_window_percent;
00334         }
00335         else
00336         {
00337 
00338           hist_rightmost_bin = bin_count_;
00339 
00340           // do iteration on histogram and find threshold
00341           for (int i = 0; i < 3; ++i)
00342           {
00343             // mean
00344             hist_mean = 0;
00345             for (int bin = 0; bin < hist_rightmost_bin; ++bin)
00346             {
00347               //std::cout << "V: " << bin << " " << hist_mean << " " << histogram[bin] << " " << elements_in_window << " " << bin_value[bin] << "\n";
00348               // immediate division is numerically more stable
00349               hist_mean += histogram[bin] / (double) elements_in_window * bin_value[bin];
00350             }
00351             //hist_mean = hist_mean / elements_in_window;
00352 
00353             // stdev
00354             hist_stdev = 0;
00355             for (int bin = 0; bin < hist_rightmost_bin; ++bin)
00356             {
00357               DoubleReal tmp(bin_value[bin] - hist_mean);
00358               hist_stdev += histogram[bin] / (double) elements_in_window * tmp * tmp;
00359             }
00360             hist_stdev = std::sqrt(hist_stdev);
00361 
00362             //determine new threshold (i.e. the rightmost bin we consider)
00363             int estimate = (int) ((hist_mean + hist_stdev * stdev_ - 1) / bin_size + 1);
00364             //std::cout << "E: " << hist_mean << " " << hist_stdev << " " << stdev_ << " " << bin_size<< " " << estimate << "\n";
00365             hist_rightmost_bin = std::min(estimate, bin_count_);
00366           }
00367 
00368           // just avoid division by 0
00369           noise = std::max(1.0, hist_mean);
00370         }
00371 
00372         // store result
00373         stn_estimates_[*window_pos_center] = (*window_pos_center).getIntensity() / noise;
00374 
00375 
00376 
00377         // advance the window center by one datapoint
00378         ++window_pos_center;
00379         ++window_count;
00380         // update progress
00381         SignalToNoiseEstimator<Container>::setProgress(window_count);
00382 
00383       }   // end while
00384 
00385       SignalToNoiseEstimator<Container>::endProgress();
00386 
00387       sparse_window_percent = sparse_window_percent * 100 / window_count;
00388       // warn if percentage of sparse windows is above 20%
00389       if (sparse_window_percent > 20)
00390       {
00391         std::cerr << "WARNING in SignalToNoiseEstimatorMeanIterative: "
00392                   << sparse_window_percent
00393                   << "% of all windows were sparse. You should consider increasing 'win_len' or increasing 'min_required_elements'"
00394                   << " You should also check the MaximalIntensity value (or the parameters for its heuristic estimation)"
00395                   << " If it is too low, then too many high intensity peaks will be discarded, which leads to a sparse window!"
00396                   << std::endl;
00397       }
00398 
00399       return;
00400 
00401     }   // end of shiftWindow_
00402 
00404     void updateMembers_()
00405     {
00406       max_intensity_         = (double)param_.getValue("max_intensity");
00407       auto_max_stdev_Factor_ = (double)param_.getValue("auto_max_stdev_factor");
00408       auto_max_percentile_   = param_.getValue("auto_max_percentile");
00409       auto_mode_             = param_.getValue("auto_mode");
00410       win_len_               = (double)param_.getValue("win_len");
00411       bin_count_             = param_.getValue("bin_count");
00412       stdev_                 = (double)param_.getValue("stdev_mp");
00413       min_required_elements_ = param_.getValue("min_required_elements");
00414       noise_for_empty_window_ = (double)param_.getValue("noise_for_empty_window");
00415       is_result_valid_ = false;
00416     }
00417 
00419     double max_intensity_;
00421     double auto_max_stdev_Factor_;
00423     double auto_max_percentile_;
00425     int    auto_mode_;
00427     double win_len_;
00429     int    bin_count_;
00431     double stdev_;
00433     int min_required_elements_;
00436     double noise_for_empty_window_;
00437 
00438 
00439 
00440 
00441   };
00442 
00443 } // namespace OpenMS
00444 
00445 #endif //OPENMS_FILTERING_NOISEESTIMATION_SIGNALTONOISEESTIMATORMEANITERATIVE_H

OpenMS / TOPP release 1.10.0 Documentation generated on Thu Mar 7 2013 09:42:44 using doxygen 1.7.1