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

EGHTraceFitter.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: Stephan Aiche $
00032 // $Authors: Stephan Aiche $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_TRANSFORMATIONS_FEATUREFINDER_EGHTRACEFITTER_H
00036 #define OPENMS_TRANSFORMATIONS_FEATUREFINDER_EGHTRACEFITTER_H
00037 
00038 #include <sstream>
00039 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/FeatureFinderAlgorithmPickedHelperStructs.h>
00040 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/TraceFitter.h>
00041 
00042 namespace OpenMS
00043 {
00044 
00057   template <class PeakType>
00058   class EGHTraceFitter :
00059     public TraceFitter<PeakType>
00060   {
00061 public:
00062     EGHTraceFitter()
00063     {
00064       //setName("EGHTraceFitter");
00065     }
00066 
00067     EGHTraceFitter(const EGHTraceFitter & other) :
00068       TraceFitter<PeakType>(other)
00069     {
00070       this->height_ = other.height_;
00071       this->apex_rt_ = other.apex_rt_;
00072       this->sigma_square_ = other.sigma_square_;
00073       this->tau_ = other.tau_;
00074 
00075       this->sigma_5_bound_ = other.sigma_5_bound_;
00076       this->fwhm_bound_ = other.fwhm_bound_;
00077 
00078       updateMembers_();
00079     }
00080 
00081     EGHTraceFitter & operator=(const EGHTraceFitter & source)
00082     {
00083       TraceFitter<PeakType>::operator=(source);
00084 
00085       this->height_ = source.height_;
00086       this->apex_rt_ = source.apex_rt_;
00087       this->sigma_square_ = source.sigma_square_;
00088       this->tau_ = source.tau_;
00089 
00090       this->sigma_5_bound_ = source.sigma_5_bound_;
00091       this->fwhm_bound_ = source.fwhm_bound_;
00092 
00093       updateMembers_();
00094 
00095       return *this;
00096     }
00097 
00098     virtual ~EGHTraceFitter()
00099     {
00100     }
00101 
00102     // override important methods
00103     void fit(FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> & traces)
00104     {
00105       setInitialParameters_(traces);
00106 
00107       double x_init[NUM_PARAMS_] = {height_, apex_rt_, sigma_square_, tau_};
00108 
00109       Size num_params = NUM_PARAMS_;
00110 
00111       TraceFitter<PeakType>::optimize_(traces, num_params, x_init,
00112                                        &(EGHTraceFitter<PeakType>::residual_),
00113                                        &(EGHTraceFitter<PeakType>::jacobian_),
00114                                        &(EGHTraceFitter<PeakType>::evaluate_));
00115     }
00116 
00117     DoubleReal getLowerRTBound() const
00118     {
00119       return sigma_5_bound_.first;
00120     }
00121 
00122     DoubleReal getTau() const
00123     {
00124       return tau_;
00125     }
00126 
00127     DoubleReal getUpperRTBound() const
00128     {
00129       return sigma_5_bound_.second;
00130     }
00131 
00132     DoubleReal getHeight() const
00133     {
00134       return height_;
00135     }
00136 
00137     DoubleReal getSigmaSquare() const
00138     {
00139       return sigma_square_;
00140     }
00141 
00142     DoubleReal getCenter() const
00143     {
00144       return apex_rt_;
00145     }
00146 
00147     bool checkMaximalRTSpan(const DoubleReal max_rt_span)
00148     {
00149       return (sigma_5_bound_.second - sigma_5_bound_.first) > max_rt_span * region_rt_span_;
00150     }
00151 
00152     virtual bool checkMinimalRTSpan(const std::pair<DoubleReal, DoubleReal> & rt_bounds, const DoubleReal min_rt_span)
00153     {
00154       return (rt_bounds.second - rt_bounds.first) < min_rt_span * (sigma_5_bound_.second - sigma_5_bound_.first);
00155     }
00156 
00157     DoubleReal computeTheoretical(const FeatureFinderAlgorithmPickedHelperStructs::MassTrace<PeakType> & trace, Size k)
00158     {
00159       double rt = trace.peaks[k].first;
00160       double t_diff, t_diff2, denominator = 0.0;
00161       double fegh = 0.0;
00162 
00163       t_diff = rt - apex_rt_;
00164       t_diff2 = t_diff * t_diff; // -> (t - t_R)^2
00165 
00166       denominator = 2 * sigma_square_ + tau_ * t_diff; // -> 2\sigma_{g}^{2} + \tau \left(t - t_R\right)
00167 
00168       if (denominator > 0.0)
00169       {
00170         fegh =  trace.theoretical_int * height_ * exp(-t_diff2 / denominator);
00171       }
00172 
00173       return fegh;
00174     }
00175 
00176     virtual DoubleReal getFeatureIntensityContribution()
00177     {
00178       return height_ * (fwhm_bound_.second - fwhm_bound_.first);
00179     }
00180 
00181     DoubleReal getFWHM() const
00182     {
00183 
00184       std::pair<DoubleReal, DoubleReal> bounds = getAlphaBoundaries_(0.5);
00185       return bounds.second - bounds.first;
00186     }
00187 
00188     virtual String getGnuplotFormula(FeatureFinderAlgorithmPickedHelperStructs::MassTrace<PeakType> const & trace, const char function_name, const DoubleReal baseline, const DoubleReal rt_shift)
00189     {
00190       std::stringstream s;
00191       s << String(function_name)  << "(x)= " << baseline << " + ";
00192       s << "("; // the overall bracket
00193       s << "((" << 2 * sigma_square_ << " + " << tau_ << " * (x - " << (rt_shift + apex_rt_) << " )) > 0) ? "; // condition
00194       s <<  (trace.theoretical_int *  height_) << " * exp(-1 * (x - " << (rt_shift + apex_rt_) << ")**2 " <<
00195       "/" <<
00196       " ( " << 2 * sigma_square_ << " + " << tau_ << " * (x - " << (rt_shift + apex_rt_) << " )))";
00197       s << " : 0)";
00198       return String(s.str());
00199     }
00200 
00201 protected:
00202     DoubleReal apex_rt_;
00203     DoubleReal height_;
00204 
00205     DoubleReal sigma_square_;
00206     DoubleReal tau_;
00207 
00208     std::pair<DoubleReal, DoubleReal> sigma_5_bound_;
00209     std::pair<DoubleReal, DoubleReal> fwhm_bound_;
00210 
00211     DoubleReal region_rt_span_;
00212 
00213     static const Size NUM_PARAMS_ = 4;
00214 
00220     std::pair<DoubleReal, DoubleReal> getAlphaBoundaries_(const DoubleReal alpha) const
00221     {
00222       std::pair<DoubleReal, DoubleReal> bounds;
00223       DoubleReal L = log(alpha);
00224       DoubleReal s = sqrt(
00225         ((L * tau_) * (L * tau_) / 4) - 2 * L * sigma_square_
00226         );
00227 
00228       DoubleReal s1, s2;
00229       s1 = (-1 * (L * tau_) / 2) + s;
00230       s2 = (-1 * (L * tau_) / 2) - s;
00231 
00232       // the smaller one (should be < 0) = lower bound
00233       bounds.first = apex_rt_ + std::min(s1, s2);
00234       // bigger one (should be > 0) = upper bound
00235       bounds.second = apex_rt_ + std::max(s1, s2);
00236 
00237       return bounds;
00238     }
00239 
00240     void getOptimizedParameters_(gsl_multifit_fdfsolver * fdfsolver)
00241     {
00242       height_ =  gsl_vector_get(fdfsolver->x, 0);
00243       apex_rt_ =  gsl_vector_get(fdfsolver->x, 1);
00244       sigma_square_ =  gsl_vector_get(fdfsolver->x, 2);
00245       tau_ =  gsl_vector_get(fdfsolver->x, 3);
00246 
00247       // we set alpha to 0.04 which is conceptually equal to
00248       // 2.5 sigma for lower and upper bound
00249       sigma_5_bound_ = getAlphaBoundaries_(0.043937);
00250       // this is needed for the intensity contribution -> this is the 1.25 sigma region
00251       fwhm_bound_ = getAlphaBoundaries_(0.45783);
00252     }
00253 
00254     static Int residual_(const gsl_vector * param, void * data, gsl_vector * f)
00255     {
00256       FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> * traces = static_cast<FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> *>(data);
00257 
00258       double H  = gsl_vector_get(param, 0);
00259       double tR = gsl_vector_get(param, 1);
00260       double sigma_square = gsl_vector_get(param, 2);
00261       double tau = gsl_vector_get(param, 3);
00262 
00263       double t_diff, t_diff2, denominator = 0.0;
00264 
00265       double fegh = 0.0;
00266 
00267       UInt count = 0;
00268       for (Size t = 0; t < traces->size(); ++t)
00269       {
00270         FeatureFinderAlgorithmPickedHelperStructs::MassTrace<PeakType> & trace = traces->at(t);
00271         for (Size i = 0; i < trace.peaks.size(); ++i)
00272         {
00273           DoubleReal rt = trace.peaks[i].first;
00274 
00275           t_diff = rt - tR;
00276           t_diff2 = t_diff * t_diff; // -> (t - t_R)^2
00277 
00278           denominator = 2 * sigma_square + tau * t_diff; // -> 2\sigma_{g}^{2} + \tau \left(t - t_R\right)
00279 
00280           if (denominator > 0.0)
00281           {
00282             fegh =  traces->baseline + trace.theoretical_int * H * exp(-t_diff2 / denominator);
00283           }
00284           else
00285           {
00286             fegh = 0.0;
00287           }
00288 
00289           gsl_vector_set(f, count, (fegh - trace.peaks[i].second->getIntensity()));
00290           ++count;
00291         }
00292       }
00293       return GSL_SUCCESS;
00294     }
00295 
00296     static Int jacobian_(const gsl_vector * param, void * data, gsl_matrix * J)
00297     {
00298       FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> * traces = static_cast<FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> *>(data);
00299 
00300       double H  = gsl_vector_get(param, 0);
00301       double tR = gsl_vector_get(param, 1);
00302       double sigma_square = gsl_vector_get(param, 2);
00303       double tau = gsl_vector_get(param, 3);
00304 
00305       double derivative_H, derivative_tR, derivative_sigma_square, derivative_tau = 0.0;
00306       double t_diff, t_diff2, exp1, denominator = 0.0;
00307 
00308       UInt count = 0;
00309       for (Size t = 0; t < traces->size(); ++t)
00310       {
00311         FeatureFinderAlgorithmPickedHelperStructs::MassTrace<PeakType> & trace = traces->at(t);
00312         for (Size i = 0; i < trace.peaks.size(); ++i)
00313         {
00314           DoubleReal rt = trace.peaks[i].first;
00315 
00316           t_diff = rt - tR;
00317           t_diff2 = t_diff * t_diff; // -> (t - t_R)^2
00318 
00319           denominator = 2 * sigma_square + tau * t_diff; // -> 2\sigma_{g}^{2} + \tau \left(t - t_R\right)
00320 
00321           if (denominator > 0)
00322           {
00323             exp1 = exp(-t_diff2 / denominator);
00324 
00325             // \partial H f_{egh}(t) = \exp\left( \frac{-\left(t-t_R \right)}{2\sigma_{g}^{2} + \tau \left(t - t_R\right)} \right)
00326             derivative_H = trace.theoretical_int * exp1;
00327 
00328             // \partial t_R f_{egh}(t) &=& H \exp \left( \frac{-\left(t-t_R \right)}{2\sigma_{g}^{2} + \tau \left(t - t_R\right)} \right) \left( \frac{\left( 4 \sigma_{g}^{2} + \tau \left(t-t_R \right) \right) \left(t-t_R \right)}{\left( 2\sigma_{g}^{2} + \tau \left(t - t_R\right) \right)^2} \right)
00329             derivative_tR = trace.theoretical_int * H * exp1 * (((4 * sigma_square + tau * t_diff) * t_diff) / (denominator * denominator));
00330 
00331             // \partial \sigma_{g}^{2} f_{egh}(t) &=& H \exp \left( \frac{-\left(t-t_R \right)^2}{2\sigma_{g}^{2} + \tau \left(t - t_R\right)} \right) \left( \frac{ 2 \left(t - t_R\right)^2}{\left( 2\sigma_{g}^{2} + \tau \left(t - t_R\right) \right)^2} \right)
00332             derivative_sigma_square = trace.theoretical_int * H * exp1 * ((2 * t_diff2) / (denominator * denominator));
00333 
00334             // \partial \tau f_{egh}(t) &=& H \exp \left( \frac{-\left(t-t_R \right)^2}{2\sigma_{g}^{2} + \tau \left(t - t_R\right)} \right) \left( \frac{ \left(t - t_R\right)^3}{\left( 2\sigma_{g}^{2} + \tau \left(t - t_R\right) \right)^2} \right)
00335             derivative_tau = trace.theoretical_int * H * exp1 * ((t_diff * t_diff2) / (denominator * denominator));
00336           }
00337           else
00338           {
00339             derivative_H = 0.0;
00340             derivative_tR = 0.0;
00341             derivative_sigma_square = 0.0;
00342             derivative_tau = 0.0;
00343           }
00344 
00345           // set the jacobian matrix
00346           gsl_matrix_set(J, count, 0, derivative_H);
00347           gsl_matrix_set(J, count, 1, derivative_tR);
00348           gsl_matrix_set(J, count, 2, derivative_sigma_square);
00349           gsl_matrix_set(J, count, 3, derivative_tau);
00350 
00351           ++count;
00352         }
00353       }
00354       return GSL_SUCCESS;
00355     }
00356 
00357     static Int evaluate_(const gsl_vector * param, void * data, gsl_vector * f, gsl_matrix * J)
00358     {
00359       residual_(param, data, f);
00360       jacobian_(param, data, J);
00361       return GSL_SUCCESS;
00362     }
00363 
00364     void setInitialParameters_(FeatureFinderAlgorithmPickedHelperStructs::MassTraces<PeakType> & traces)
00365     {
00366       LOG_DEBUG << "EGHTraceFitter->setInitialParameters(..)" << std::endl;
00367       LOG_DEBUG << "Traces length: " << traces.size() << std::endl;
00368       LOG_DEBUG << "Max trace: " << traces.max_trace << std::endl;
00369 
00370       // initial values for externals
00371       height_ = traces[traces.max_trace].max_peak->getIntensity() - traces.baseline;
00372       LOG_DEBUG << "height: " << height_ << std::endl;
00373       apex_rt_ = traces[traces.max_trace].max_rt;
00374       LOG_DEBUG << "apex_rt: " << apex_rt_ << std::endl;
00375       region_rt_span_ = traces[traces.max_trace].peaks.back().first - traces[traces.max_trace].peaks[0].first;
00376       LOG_DEBUG << "region_rt_span_: " << region_rt_span_ << std::endl;
00377 
00378       const PeakType * max_peak = traces[traces.max_trace].peaks.begin()->second;
00379       Size max_pos = 0;
00380 
00381       for (Size i = 1; i < traces[traces.max_trace].peaks.size(); ++i)
00382       {
00383         if (traces[traces.max_trace].peaks[i].second->getIntensity() > max_peak->getIntensity())
00384         {
00385           max_peak = traces[traces.max_trace].peaks[i].second;
00386           max_pos = i;
00387         }
00388       }
00389 
00390       Size i = max_pos;
00391       LOG_DEBUG << "max_pos: " << max_pos << std::endl;
00392       if (traces[traces.max_trace].peaks.size() < 3)
00393       {
00394         // TODO: abort the whole thing here??
00395         //       because below we REQUIRE at least three peaks!!!
00396       }
00397 
00398       Size filter_max_pos = traces[traces.max_trace].peaks.size() - 2;
00399 
00400       // compute a smoothed value for the maxima
00401       // if the maximum is close to the borders, we need to think of something...
00402       DoubleReal smoothed_height;
00403       if ((max_pos < 2) || (max_pos + 2 >= traces[traces.max_trace].peaks.size()))
00404       {
00405         // ... too close to border... no smoothing
00406         smoothed_height = traces[traces.max_trace].peaks[max_pos].second->getIntensity();
00407         // TODO: does this trace even make sense?! why wasn't it extended it further? or should we have skipped it beforehand?
00408       }
00409       else
00410       {
00411         smoothed_height = (traces[traces.max_trace].peaks[max_pos - 2].second->getIntensity()
00412                            + traces[traces.max_trace].peaks[max_pos - 1].second->getIntensity()
00413                            + traces[traces.max_trace].peaks[max_pos].second->getIntensity()
00414                            + traces[traces.max_trace].peaks[max_pos + 1].second->getIntensity()
00415                            + traces[traces.max_trace].peaks[max_pos + 2].second->getIntensity()) / 5.0;
00416       }
00417 
00418       // use  moving average filter to avoid bad initial values
00419       // moving average of size 5
00420       // TODO: optimize windows size
00421       while (i > 2 && i < filter_max_pos)
00422       {
00423         // compute smoothed
00424         DoubleReal smoothed = (traces[traces.max_trace].peaks[i - 2].second->getIntensity()
00425                                + traces[traces.max_trace].peaks[i - 1].second->getIntensity()
00426                                + traces[traces.max_trace].peaks[i].second->getIntensity()
00427                                + traces[traces.max_trace].peaks[i + 1].second->getIntensity()
00428                                + traces[traces.max_trace].peaks[i + 2].second->getIntensity()) / 5.0;
00429 
00430         if (smoothed / smoothed_height < 0.5) break;
00431         else --i;
00432       }
00433       LOG_DEBUG << "Left alpha at " << i << " with " << traces[traces.max_trace].peaks[i].first << std::endl;
00434       double A = apex_rt_ - traces[traces.max_trace].peaks[i].first;
00435 
00436       i = max_pos;
00437       while (i < filter_max_pos && i > 2)
00438       {
00439         DoubleReal smoothed = (traces[traces.max_trace].peaks[i - 2].second->getIntensity()
00440                                + traces[traces.max_trace].peaks[i - 1].second->getIntensity()
00441                                + traces[traces.max_trace].peaks[i].second->getIntensity()
00442                                + traces[traces.max_trace].peaks[i + 1].second->getIntensity()
00443                                + traces[traces.max_trace].peaks[i + 2].second->getIntensity()) / 5.0;
00444 
00445         if (smoothed / smoothed_height < 0.5) break;
00446         else ++i;
00447       }
00448       LOG_DEBUG << "Right alpha at " << i << " with " << traces[traces.max_trace].peaks[i].first << std::endl;
00449       double B = traces[traces.max_trace].peaks[i].first - apex_rt_;
00450 
00451       //LOG_DEBUG << "A: " << A << std::endl;
00452       //LOG_DEBUG << "B: " << B << std::endl;
00453 
00454       // compute estimates for tau / sigma_square based on A/B
00455       double log_alpha = log(0.5);
00456 
00457       tau_ = (-1 / log_alpha) * (B - A);
00458       LOG_DEBUG << "tau: " << tau_ << std::endl;
00459       sigma_square_ = (-1 / (2 * log_alpha)) * (B * A);
00460       LOG_DEBUG << "sigma_square: " << sigma_square_ << std::endl;
00461     }
00462 
00463     virtual void updateMembers_()
00464     {
00465       TraceFitter<PeakType>::updateMembers_();
00466     }
00467 
00468     void printState_(SignedSize iter, gsl_multifit_fdfsolver * s)
00469     {
00470       LOG_DEBUG << "iter: " << iter << " "
00471                 << "height: " << gsl_vector_get(s->x, 0) << " "
00472                 << "apex_rt: " << gsl_vector_get(s->x, 1) << " "
00473                 << "sigma_square: " << gsl_vector_get(s->x, 2) << " "
00474                 << "tau: " << gsl_vector_get(s->x, 3) << " "
00475                 << "|f(x)| = " << gsl_blas_dnrm2(s->f) << std::endl;
00476     }
00477 
00478   };
00479 
00480 } // namespace OpenMS
00481 
00482 #endif // #ifndef OPENMS_TRANSFORMATIONS_FEATUREFINDER_FEATUREFINDERALGORITHMPICKEDTRACEFITTERGAUSS_H

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