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

ModelFitter.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: Clemens Groepl $
00032 // $Authors: $
00033 // --------------------------------------------------------------------------
00034 
00035 
00036 #ifndef OPENMS_TRANSFORMATIONS_FEATUREFINDER_MODELFITTER_H
00037 #define OPENMS_TRANSFORMATIONS_FEATUREFINDER_MODELFITTER_H
00038 
00039 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/FeaFiModule.h>
00040 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/ProductModel.h>
00041 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/IsotopeModel.h>
00042 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/ExtendedIsotopeModel.h>
00043 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/LmaIsotopeModel.h>
00044 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/Fitter1D.h>
00045 #include <OpenMS/MATH/STATISTICS/AsymmetricStatistics.h>
00046 #include <OpenMS/MATH/STATISTICS/StatisticFunctions.h>
00047 #include <OpenMS/CONCEPT/Factory.h>
00048 
00049 #include <boost/math/special_functions/fpclassify.hpp>
00050 
00051 #include <iostream>
00052 #include <fstream>
00053 #include <numeric>
00054 #include <cmath>
00055 #include <vector>
00056 #include <set>
00057 
00058 namespace OpenMS
00059 {
00060 
00076   template <class PeakType, class FeatureType>
00077   class ModelFitter :
00078     public FeaFiModule<PeakType, FeatureType>,
00079     public FeatureFinderDefs
00080   {
00081 public:
00082 
00084     typedef IndexSet::const_iterator IndexSetIter;
00086     typedef Feature::QualityType QualityType;
00088     typedef Feature::CoordinateType CoordinateType;
00090     typedef Feature::IntensityType IntensityType;
00092     typedef Feature::ChargeType ChargeType;
00094     typedef FeaFiModule<PeakType, FeatureType> Base;
00096     typedef std::vector<PeakType> RawDataArrayType;
00097 
00098     enum
00099     {
00100       RT = Peak2D::RT,
00101       MZ = Peak2D::MZ
00102     };
00103 
00105     ModelFitter(const MSExperiment<PeakType> * map, FeatureMap<FeatureType> * features, FeatureFinder * ff) :
00106       Base(map, features, ff),
00107       model2D_(),
00108       mz_stat_(),
00109       rt_stat_(),
00110       monoisotopic_mz_(0),
00111 #ifdef DEBUG_FEATUREFINDER
00112       counter_(1),
00113 #endif
00114       iso_stdev_first_(0),
00115       iso_stdev_last_(0),
00116       iso_stdev_stepsize_(0),
00117       first_mz_model_(0),
00118       last_mz_model_(0),
00119       quality_rt_(0),
00120       quality_mz_(0)
00121     {
00122       this->setName("ModelFitter");
00123 
00124       this->defaults_.setValue("fit_algorithm", "simple", "Fitting algorithm type (internal parameter).", StringList::create("advanced"));
00125       std::vector<String> fit_opts;
00126       fit_opts.push_back("simple");
00127       fit_opts.push_back("simplest");
00128       fit_opts.push_back("wavelet");
00129       this->defaults_.setValidStrings("fit_algorithm", fit_opts);
00130 
00131       this->defaults_.setValue("max_iteration", 500, "Maximum number of iterations for fitting with Levenberg-Marquardt algorithm.", StringList::create("advanced"));
00132       this->defaults_.setMinInt("max_iteration", 1);
00133       this->defaults_.setValue("deltaAbsError", 0.0001, "Absolute error used by the Levenberg-Marquardt algorithm.", StringList::create("advanced"));
00134       this->defaults_.setMinFloat("deltaAbsError", 0.0);
00135       this->defaults_.setValue("deltaRelError", 0.0001, "Relative error used by the Levenberg-Marquardt algorithm.", StringList::create("advanced"));
00136       this->defaults_.setMinFloat("deltaRelError", 0.0);
00137 
00138       this->defaults_.setValue("tolerance_stdev_bounding_box", 3.0f, "Bounding box has range [minimim of data, maximum of data] enlarged by tolerance_stdev_bounding_box times the standard deviation of the data", StringList::create("advanced"));
00139       this->defaults_.setMinFloat("tolerance_stdev_bounding_box", 0.0);
00140 
00141       this->defaults_.setValue("intensity_cutoff_factor", 0.05f, "Cutoff peaks with a predicted intensity below intensity_cutoff_factor times the maximal intensity of the model");
00142       this->defaults_.setMinFloat("intensity_cutoff_factor", 0.0);
00143       this->defaults_.setMaxFloat("intensity_cutoff_factor", 1.0);
00144 
00145       this->defaults_.setValue("feature_intensity_sum", 1, "Determines what is reported as feature intensity.\n1: the sum of peak intensities;\n0: the maximum intensity of all peaks", StringList::create("advanced"));
00146       this->defaults_.setMinInt("feature_intensity_sum", 0);
00147       this->defaults_.setMaxInt("feature_intensity_sum", 1);
00148 
00149       this->defaults_.setValue("min_num_peaks:final", 5, "Minimum number of peaks left after cutoff. If smaller, feature will be discarded.");
00150       this->defaults_.setMinInt("min_num_peaks:final", 1);
00151       this->defaults_.setValue("min_num_peaks:extended", 10, "Minimum number of peaks after extension. If smaller, feature will be discarded.");
00152       this->defaults_.setMinInt("min_num_peaks:extended", 1);
00153       this->defaults_.setSectionDescription("min_num_peaks", "Required number of peaks for a feature.");
00154 
00155       this->defaults_.setValue("rt:interpolation_step", 0.2f, "Step size in seconds used to interpolate model for RT.");
00156       this->defaults_.setMinFloat("rt:interpolation_step", 0.0);
00157       this->defaults_.setSectionDescription("rt", "Model settings in RT dimension.");
00158 
00159       this->defaults_.setValue("mz:interpolation_step", 0.03f, "Interpolation step size for m/z.");
00160       this->defaults_.setMinFloat("mz:interpolation_step", 0.001);
00161       this->defaults_.setValue("mz:model_type:first", 1, "Numeric id of first m/z model fitted (usually indicating the charge state), 0 = no isotope pattern (fit a single gaussian).");
00162       this->defaults_.setMinInt("mz:model_type:first", 0);
00163       this->defaults_.setValue("mz:model_type:last", 4, "Numeric id of last m/z model fitted (usually indicating the charge state), 0 = no isotope pattern (fit a single gaussian).");
00164       this->defaults_.setMinInt("mz:model_type:last", 0);
00165       this->defaults_.setSectionDescription("mz", "Model settings in m/z dimension.");
00166 
00167       this->defaults_.setValue("quality:type", "Correlation", "Type of the quality measure used to assess the fit of model vs data.", StringList::create("advanced"));
00168       std::vector<String> quality_opts;
00169       quality_opts.push_back("Correlation");
00170       quality_opts.push_back("RankCorrelation");
00171       this->defaults_.setValidStrings("quality:type", quality_opts);
00172       this->defaults_.setValue("quality:minimum", 0.65f, "Minimum quality of fit, features below this threshold are discarded.");
00173       this->defaults_.setMinFloat("quality:minimum", 0.0);
00174       this->defaults_.setMaxFloat("quality:minimum", 1.0);
00175       this->defaults_.setSectionDescription("quality", "Fitting quality settings.");
00176 
00177       this->defaults_.setValue("isotope_model:stdev:first", 0.04f, "First standard deviation to be considered for isotope model.");
00178       this->defaults_.setMinFloat("isotope_model:stdev:first", 0.0);
00179       this->defaults_.setValue("isotope_model:stdev:last", 0.12f, "Last standard deviation to be considered for isotope model.");
00180       this->defaults_.setMinFloat("isotope_model:stdev:last", 0.0);
00181       this->defaults_.setValue("isotope_model:stdev:step", 0.04f, "Step size for standard deviations considered for isotope model.");
00182       this->defaults_.setMinFloat("isotope_model:stdev:step", 0.0);
00183       this->defaults_.setSectionDescription("isotope_model:stdev", "Instrument resolution settings for m/z dimension.");
00184 
00185       this->defaults_.setValue("isotope_model:averagines:C", 0.04443989f, "Number of C atoms per Dalton of the mass.", StringList::create("advanced"));
00186       this->defaults_.setMinFloat("isotope_model:averagines:C", 0.0);
00187       this->defaults_.setValue("isotope_model:averagines:H", 0.06981572f, "Number of H atoms per Dalton of the mass.", StringList::create("advanced"));
00188       this->defaults_.setMinFloat("isotope_model:averagines:H", 0.0);
00189       this->defaults_.setValue("isotope_model:averagines:N", 0.01221773f, "Number of N atoms per Dalton of the mass.", StringList::create("advanced"));
00190       this->defaults_.setMinFloat("isotope_model:averagines:N", 0.0);
00191       this->defaults_.setValue("isotope_model:averagines:O", 0.01329399f, "Number of O atoms per Dalton of the mass.", StringList::create("advanced"));
00192       this->defaults_.setMinFloat("isotope_model:averagines:O", 0.0);
00193       this->defaults_.setValue("isotope_model:averagines:S", 0.00037525f, "Number of S atoms per Dalton of the mass.", StringList::create("advanced"));
00194       this->defaults_.setMinFloat("isotope_model:averagines:S", 0.0);
00195       this->defaults_.setSectionDescription("isotope_model:averagines", "Averagines are used to approximate the number of atoms (C,H,N,O,S) which a peptide of a given mass contains.");
00196 
00197       this->defaults_.setValue("isotope_model:isotope:trim_right_cutoff", 0.001f, "Cutoff for averagine distribution, trailing isotopes below this relative intensity are not considered.", StringList::create("advanced"));
00198       this->defaults_.setMinFloat("isotope_model:isotope:trim_right_cutoff", 0.0);
00199       this->defaults_.setValue("isotope_model:isotope:maximum", 100, "Maximum number of isotopes being used for the IsotopeModel.", StringList::create("advanced"));
00200       this->defaults_.setMinInt("isotope_model:isotope:maximum", 1);
00201       this->defaults_.setValue("isotope_model:isotope:distance", 1.000495f, "Distance between consecutive isotopic peaks.", StringList::create("advanced"));
00202       this->defaults_.setMinFloat("isotope_model:isotope:distance", 0.0);
00203       this->defaults_.setSectionDescription("isotope_model", "Settings of the isotope model (m/z).");
00204 
00205       this->defaultsToParam_();
00206     }
00207 
00209     virtual ~ModelFitter()
00210     {
00211     }
00212 
00215     void setMonoIsotopicMass(CoordinateType mz)
00216     {
00217       monoisotopic_mz_ = mz;
00218     }
00219 
00226     Feature fit(const ChargedIndexSet & index_set)
00227     {
00228       // Test the number of peaks (not enough peaks to fit)
00229       if (index_set.size() < UInt(this->param_.getValue("min_num_peaks:extended")))
00230       {
00231         String mess = String("Skipping feature, IndexSet size too small: ") + index_set.size();
00232         throw Exception::UnableToFit(__FILE__, __LINE__, __PRETTY_FUNCTION__, "UnableToFit-IndexSet", mess.c_str());
00233       }
00234 
00235       // Calculate statistics for mz and rt
00236       mz_stat_.update
00237       (
00238         Internal::IntensityIterator<ModelFitter>(index_set.begin(), this),
00239         Internal::IntensityIterator<ModelFitter>(index_set.end(), this),
00240         Internal::MzIterator<ModelFitter>(index_set.begin(), this)
00241       );
00242       rt_stat_.update
00243       (
00244         Internal::IntensityIterator<ModelFitter>(index_set.begin(), this),
00245         Internal::IntensityIterator<ModelFitter>(index_set.end(), this),
00246         Internal::RtIterator<ModelFitter>(index_set.begin(), this)
00247       );
00248 
00249       // set charge
00250       if (index_set.charge != 0)
00251       {
00252         first_mz_model_ = index_set.charge;
00253         last_mz_model_ = index_set.charge;
00254       }
00255 
00256       if (first_mz_model_ > last_mz_model_) throw Exception::InvalidParameter(__FILE__, __LINE__, __PRETTY_FUNCTION__, "ModelFitter::fit(): charge range tested is not valid; check \"model_type:first\" and \"model_type:last\" ");
00257 
00258       // Check charge estimate if charge is not specified by user
00259 #ifdef DEBUG_FEATUREFINDER
00260       std::cout << "Checking charge state from " << first_mz_model_ << " to " << last_mz_model_ << std::endl;
00261 #endif
00262 
00263       // ** Projection
00264       doProjectionDim_(RT, index_set, rt_input_data_);
00265       doProjectionDim_(MZ, index_set, mz_input_data_);
00266       // Fit rt model
00267       InterpolationModel * model_rt = 0;
00268       quality_rt_ = fitRT_(model_rt);
00269       model2D_.setModel(RT, model_rt);          // Set model in 2D-model
00270 
00271       FeatureMap<Feature> feature_collection;
00272 
00273       for (ChargeType charge = first_mz_model_; charge <= last_mz_model_; ++charge)
00274       {
00275         Feature f;
00276         try
00277         {
00278           // "reset" model2D!!
00279           model2D_.setScale(1.);
00280 
00281           // TODO: intensity scaling should use a more robust estimator (rather than comparing max of data vs. model)
00282 
00283           // Compute model with the best correlation
00284           // result is in model2D_
00285           QualityType max_quality = fitMZLoop_(index_set, charge);
00286 
00287           // find peak with highest predicted intensity to use as cutoff
00288           IntensityType model_max = 0;
00289 
00290           for (IndexSetIter it = index_set.begin(); it != index_set.end(); ++it)
00291           {
00292             IntensityType model_int = model2D_.getIntensity(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it)));
00293             if (model_int > model_max) model_max = model_int;
00294           }
00295           model2D_.setCutOff(model_max * Real(this->param_.getValue("intensity_cutoff_factor")));
00296 
00297           // Cutoff low intensities wrt to model maximum -> cutoff independent of scaling
00298           IndexSet model_set;
00299           for (IndexSetIter it = index_set.begin(); it != index_set.end(); ++it)
00300           {
00301             if (model2D_.isContained(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it))))
00302             {
00303               model_set.insert(*it);
00304             }
00305           }
00306 
00307           // Print number of selected peaks after cutoff
00308 #ifdef DEBUG_FEATUREFINDER
00309           std::cout << " Selected " << model_set.size() << " from " << index_set.size() << " peaks.\n";
00310 #endif
00311 
00312           // Calculate intensity scaling
00313           IntensityType model_sum = 0;
00314           //IntensityType data_sum = 0;
00315           IntensityType data_max = 0;
00316           for (IndexSetIter it = model_set.begin(); it != model_set.end(); ++it)
00317           {
00318             IntensityType model_int = model2D_.getIntensity(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it)));
00319             model_sum += model_int;
00320             //data_sum += this->getPeakIntensity( *it );
00321             if (this->getPeakIntensity(*it) > data_max) data_max = this->getPeakIntensity(*it);
00322           }
00323 
00324           if (model_sum == 0)
00325           {
00326             throw Exception::UnableToFit(__FILE__, __LINE__, __PRETTY_FUNCTION__, "UnableToFit-ZeroSum", "Skipping feature, model_sum zero.");
00327           }
00328 
00329           //std::cout << "data_max: " << data_max << " model_max: " <<  model_max << " model2dscale: " << (data_max / model_max) << std::endl;
00330           model2D_.setScale(data_max / model_max);              // use max quotient instead of sum quotient
00331 
00332           //std::cout << model2D_.getParameters() << std::endl;
00333 
00334           // Build Feature
00335           // The feature coordinate in rt dimension is given
00336           // by the centroid of the rt model whereas the coordinate
00337           // in mz dimension is equal to the monoisotopic peak.
00338           f.setModelDescription(ModelDescription<2>(&model2D_));
00339           f.setOverallQuality(max_quality);
00340           f.setRT(static_cast<InterpolationModel *>(model2D_.getModel(RT))->getCenter());
00341           f.setMZ(static_cast<InterpolationModel *>(model2D_.getModel(MZ))->getCenter());
00342 
00343           // set and check convex hull whether m/z is contained or not
00344           this->addConvexHull(model_set, f);
00345           if (!f.encloses(f.getRT(), f.getMZ())) f.setMZ(f.getConvexHull().getBoundingBox().minY());
00346 
00347           // feature charge ...
00348           // if we used a simple Gaussian model to fit the feature, we can't say anything about
00349           // its charge state. The value 0 indicates that charge state is undetermined.
00350           if (model2D_.getModel(MZ)->getName() == "LmaIsotopeModel")
00351           {
00352             f.setCharge(static_cast<LmaIsotopeModel *>(model2D_.getModel(MZ))->getCharge());
00353           }
00354           else if (model2D_.getModel(MZ)->getName() == "IsotopeModel")
00355           {
00356             f.setCharge(static_cast<IsotopeModel *>(model2D_.getModel(MZ))->getCharge());
00357           }
00358           else if (model2D_.getModel(MZ)->getName() == "ExtendedIsotopeModel")
00359           {
00360             f.setCharge(static_cast<ExtendedIsotopeModel *>(model2D_.getModel(MZ))->getCharge());
00361           }
00362           else
00363           {
00364             f.setCharge(0);
00365           }
00366 
00367           // feature intensity
00368           Int const intensity_choice = this->param_.getValue("feature_intensity_sum");
00369           IntensityType feature_intensity = 0.0;
00370           if (intensity_choice == 1)
00371           {
00372             // intensity of the feature is the sum of all included data points
00373             for (IndexSetIter it = model_set.begin(); it != model_set.end(); ++it)
00374             {
00375               feature_intensity += this->getPeakIntensity(*it);
00376             }
00377           }
00378           else
00379           {
00380             // feature intensity is the maximum intensity of all peaks
00381             for (IndexSetIter it = model_set.begin(); it != model_set.end(); ++it)
00382             {
00383               if (this->getPeakIntensity(*it) > feature_intensity)
00384               {
00385                 feature_intensity = this->getPeakIntensity(*it);
00386               }
00387             }
00388           }
00389 
00390           // set intensity
00391           f.setIntensity(feature_intensity);
00392 
00393           // set quality (1D)
00394           f.setQuality(RT, quality_rt_);
00395           f.setQuality(MZ, quality_mz_);
00396 
00397           //std::cout << "QA: " << f.getOverallQuality() << "  qMZ: " << f.getQuality(1) << " charge: " << f.getCharge() << " stdev: " <<  f.getModelDescription().getParam().getValue("MZ:isotope:stdev")<< std::endl;
00398 
00399 #ifdef DEBUG_FEATUREFINDER
00400           // debug output
00401           if (this->param_.getValue("fit_algorithm") != "wavelet")
00402           {
00403             std::cout << "Feature " << counter_ << ": (" << f.getRT()   << "," << f.getMZ() << ") Qual.: "  << max_quality << std::endl;
00404           }
00405           // Save meta data in feature for TOPPView
00406           f.setMetaValue(3, String(counter_));
00407 
00408           std::cout << "Feature charge: " << f.getCharge() << std::endl;
00409           std::cout << "Feature quality in mz: " << f.getQuality(MZ) << std::endl;
00410 
00411           // write debug output
00412           CoordinateType rt = f.getRT();
00413           CoordinateType mz = f.getMZ();
00414 
00415           // write feature model
00416           String fname = String("model") + counter_ + "_" + rt + "_" + mz;
00417           std::ofstream file(fname.c_str());
00418           for (IndexSetIter it = model_set.begin(); it != model_set.end(); ++it)
00419           {
00420             DPosition<2> pos = DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it));
00421             if (model2D_.isContained(pos))
00422             {
00423               file << pos[RT] << " " << pos[MZ] << " " << model2D_.getIntensity(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it))) << "\n";
00424             }
00425           }
00426           file.close();
00427 
00428           // wrote peaks remaining after model fit
00429           fname = String("feature") + counter_ + "_" + rt + "_" + mz;
00430           std::ofstream file2(fname.c_str());
00431           for (IndexSetIter it = model_set.begin(); it != model_set.end(); ++it)
00432           {
00433             DPosition<2> pos = DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it));
00434             if (model2D_.isContained(pos))
00435             {
00436               file2 << pos[RT] << " " << pos[MZ] << " " << this->getPeakIntensity(*it) << "\n";
00437             }
00438           }
00439           file2.close();
00440 
00441           // Count features
00442           ++counter_;
00443 
00444 #endif
00445 
00446           feature_collection.push_back(f);
00447         }         // ! try
00448         catch (Exception::UnableToFit & /*e*/)
00449         {
00450           //std::cout << "CAUGHT!! " << e.getName() << "  " << e.getMessage() << std::endl;
00451         }
00452       }
00453 
00454       if (feature_collection.empty())
00455       {
00456         String mess = String("Skipping feature, nothing in the feature collection.");
00457         throw Exception::UnableToFit(__FILE__, __LINE__, __PRETTY_FUNCTION__, "UnableToFit-EmptyFeatureCollection", mess.c_str());
00458       }
00459 
00460       QualityType best_quality = -std::numeric_limits<QualityType>::max();
00461       // find best feature
00462       std::size_t best_idx = 0;
00463       for (std::size_t idx = 0; idx < feature_collection.size(); ++idx)
00464       {
00465         if (best_quality < feature_collection[idx].getOverallQuality())
00466         {
00467           best_quality = feature_collection[idx].getOverallQuality();
00468           best_idx = idx;
00469         }
00470       }
00471 
00472       Feature best_feature = feature_collection[best_idx];
00473       // check some more conditions
00474       // not enough peaks left for feature
00475 
00476       // fit has too low quality or fit was not possible i.e. because of zero stdev
00477       if (best_feature.getOverallQuality() < (Real) (this->param_.getValue("quality:minimum")))
00478       {
00479         String mess = String("Skipping feature, correlation too small: ") + best_feature.getOverallQuality();
00480         throw Exception::UnableToFit(__FILE__, __LINE__, __PRETTY_FUNCTION__, "UnableToFit-Correlation", mess.c_str());
00481       }
00482 
00483       // free unused peaks for best feature
00484       IndexSet model_set;
00485       ProductModel<2> * best_model = static_cast<ProductModel<2> *>(best_feature.getModelDescription().createModel());
00486       for (IndexSetIter it = index_set.begin(); it != index_set.end(); ++it)
00487       {
00488         if (best_model->isContained(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it))))
00489         {
00490           model_set.insert(*it);
00491         }
00492         else
00493         {
00494           this->ff_->getPeakFlag(*it) = UNUSED;
00495         }
00496       }
00497       delete best_model;
00498       if (model_set.size() < (UInt) (this->param_.getValue("min_num_peaks:final")))
00499       {
00500         throw Exception::UnableToFit(__FILE__, __LINE__, __PRETTY_FUNCTION__, "UnableToFit-FinalSet", String("Skipping feature, IndexSet size after cutoff too small: ") + model_set.size());
00501       }
00502 
00503       // add all but the best feature to the suboptimal ones
00504       for (std::size_t idx = 0; idx < feature_collection.size(); ++idx)
00505       {
00506         if (idx == best_idx) continue;
00507         best_feature.getSubordinates().push_back(feature_collection[idx]);
00508       }
00509 
00510       // return "best" feature
00511       return best_feature;
00512 
00513     }
00514 
00515 protected:
00516 
00517     virtual void updateMembers_()
00518     {
00519       algorithm_ = this->param_.getValue("fit_algorithm");
00520 
00521       max_iteration_ = this->param_.getValue("max_iteration");
00522       deltaAbsError_ = this->param_.getValue("deltaAbsError");
00523       deltaRelError_ = this->param_.getValue("deltaRelError");
00524 
00525       tolerance_stdev_box_ = this->param_.getValue("tolerance_stdev_bounding_box");
00526       max_isotope_ = this->param_.getValue("isotope_model:isotope:maximum");
00527 
00528       interpolation_step_mz_ = this->param_.getValue("mz:interpolation_step");
00529       interpolation_step_rt_ = this->param_.getValue("rt:interpolation_step");
00530 
00531       iso_stdev_first_ = this->param_.getValue("isotope_model:stdev:first");
00532       iso_stdev_last_ = this->param_.getValue("isotope_model:stdev:last");
00533       iso_stdev_stepsize_ = this->param_.getValue("isotope_model:stdev:step");
00534 
00535       first_mz_model_ = (Int) this->param_.getValue("mz:model_type:first");
00536       last_mz_model_ = (Int) this->param_.getValue("mz:model_type:last");
00537     }
00538 
00540     QualityType fitMZLoop_(const ChargedIndexSet & set, const ChargeType & charge)
00541     {
00542 
00543       // Fit mz model ... test different charge states and stdevs
00544       QualityType max_quality_mz = -std::numeric_limits<QualityType>::max();
00545 
00546       InterpolationModel * best_model_mz = 0;
00547       for (Real stdev = iso_stdev_first_; stdev <= iso_stdev_last_; stdev += iso_stdev_stepsize_)
00548       {
00549         isotope_stdev_ = stdev;
00550 
00551         InterpolationModel * model_mz = 0;
00552         quality_mz_ = fitMZ_(model_mz, charge);
00553 
00554 
00555         if (quality_mz_ > max_quality_mz)
00556         {
00557           max_quality_mz = quality_mz_;
00558           if (best_model_mz) delete best_model_mz;
00559           best_model_mz = model_mz;
00560         }
00561         else
00562         {
00563           delete model_mz;
00564         }
00565       }
00566 
00567       model2D_.setModel(MZ, best_model_mz);                 // Set model in 2D-model
00568 
00569       quality_mz_ = max_quality_mz;
00570 
00571       // return overall quality
00572       return evaluate_(set);
00573     }
00574 
00576     QualityType evaluate_(const IndexSet & set) const
00577     {
00578       QualityType quality = 0.0;
00579 
00580       // Calculate the pearson correlation coefficient for the values in [begin_a, end_a) and [begin_b, end_b)
00581       if (algorithm_ != "")
00582       {
00583         std::vector<Real> real_data;
00584         real_data.reserve(set.size());
00585         std::vector<Real> model_data;
00586         model_data.reserve(set.size());
00587 
00588         for (IndexSet::const_iterator it = set.begin(); it != set.end(); ++it)
00589         {
00590           real_data.push_back(this->getPeakIntensity(*it));
00591           model_data.push_back(model2D_.getIntensity(DPosition<2>(this->getPeakRt(*it), this->getPeakMz(*it))));
00592         }
00593 
00594         if (this->param_.getValue("quality:type") == "RankCorrelation")
00595         {
00596           quality = Math::rankCorrelationCoefficient(real_data.begin(), real_data.end(), model_data.begin(), model_data.end());
00597         }
00598         else quality = Math::pearsonCorrelationCoefficient(real_data.begin(), real_data.end(), model_data.begin(), model_data.end());
00599       }
00600 
00601       if (boost::math::isnan(quality)) quality = -1.0;
00602 
00603       return quality;
00604     }
00605 
00607     QualityType fitRT_(InterpolationModel * & model) const
00608     {
00609       QualityType quality;
00610       Param param;
00611       Fitter1D * fitter;
00612 
00613       if (algorithm_ == "simplest")     // Fit with BiGauss
00614       {
00615         param.setValue("tolerance_stdev_bounding_box", tolerance_stdev_box_);
00616         param.setValue("statistics:mean", rt_stat_.mean());
00617         param.setValue("statistics:variance", rt_stat_.variance());
00618         param.setValue("statistics:variance1", rt_stat_.variance1());
00619         param.setValue("statistics:variance2", rt_stat_.variance2());
00620         param.setValue("interpolation_step", interpolation_step_rt_);
00621 
00622         fitter = Factory<Fitter1D>::create("BiGaussFitter1D");
00623       }
00624       else       // Fit with EMG (LM optimization)
00625       {
00626         param.setValue("tolerance_stdev_bounding_box", tolerance_stdev_box_);
00627         param.setValue("statistics:mean", rt_stat_.mean());
00628         param.setValue("statistics:variance", rt_stat_.variance());
00629         param.setValue("interpolation_step", interpolation_step_rt_);
00630         param.setValue("max_iteration", max_iteration_);
00631         param.setValue("deltaAbsError", deltaAbsError_);
00632         param.setValue("deltaRelError", deltaRelError_);
00633 
00634         fitter = Factory<Fitter1D>::create("EmgFitter1D");
00635       }
00636 
00637       // Set parameter for fitter
00638       fitter->setParameters(param);
00639 
00640       // Construct model for rt
00641       quality = fitter->fit1d(rt_input_data_, model);
00642       // Check quality
00643       if (boost::math::isnan(quality)) quality = -1.0;
00644 
00645       delete(fitter);
00646 
00647       return quality;
00648     }
00649 
00651     QualityType fitMZ_(InterpolationModel * & model, const ChargeType & charge) const
00652     {
00653       QualityType quality;
00654       Param param;
00655       Fitter1D * fitter;
00656 
00657       param.setValue("tolerance_stdev_bounding_box", tolerance_stdev_box_);
00658       param.setValue("statistics:mean", mz_stat_.mean());
00659       param.setValue("statistics:variance", mz_stat_.variance());
00660       param.setValue("interpolation_step", interpolation_step_mz_);
00661 
00662       if (monoisotopic_mz_ != 0)         // monoisotopic mz is known
00663       {
00664         param.setValue("statistics:mean", monoisotopic_mz_);
00665       }
00666 
00667       if (charge != 0)       // charge is not zero
00668       {
00669         param.setValue("charge", charge);
00670         param.setValue("isotope:stdev", isotope_stdev_);
00671         param.setValue("isotope:maximum", max_isotope_);
00672         fitter = Factory<Fitter1D>::create("IsotopeFitter1D");
00673       }
00674       else       // charge is zero
00675       {
00676         if (algorithm_ == "simplest")       // Fit with GaussModel
00677         {
00678           param.setValue("charge", charge);
00679           param.setValue("isotope:stdev", isotope_stdev_);
00680           param.setValue("isotope:maximum", max_isotope_);
00681           fitter = Factory<Fitter1D>::create("IsotopeFitter1D");
00682         }
00683         else         // Fit with LmaGaussModel
00684         {
00685           param.setValue("max_iteration", max_iteration_);
00686           param.setValue("deltaAbsError", deltaAbsError_);
00687           param.setValue("deltaRelError", deltaRelError_);
00688           fitter = Factory<Fitter1D>::create("LmaGaussFitter1D");
00689         }
00690       }
00691 
00692       // Set parameter for fitter
00693       fitter->setParameters(param);
00694 
00695       // Construct model for mz
00696       quality = fitter->fit1d(mz_input_data_, model);
00697 
00698       //std::cout << "model after fitting: " << model->getParameters() << std::endl << std::endl;
00699 
00700       // Check quality
00701       if (boost::math::isnan(quality)) quality = -1.0;
00702 
00703       delete(fitter);
00704 
00705       return quality;
00706     }
00707 
00709     void doProjectionDim_(const Int dim, const ChargedIndexSet & index_set, RawDataArrayType & set) const
00710     {
00711 
00712       if (algorithm_ != "")
00713       {
00714         std::map<CoordinateType, CoordinateType> data_map;
00715 
00716         if (dim == MZ)
00717         {
00718           for (IndexSet::const_iterator it = index_set.begin(); it != index_set.end(); ++it)
00719           {
00720             data_map[this->getPeakMz(*it)] += this->getPeakIntensity(*it);
00721           }
00722         }
00723         else
00724         {
00725           for (IndexSet::const_iterator it = index_set.begin(); it != index_set.end(); ++it)
00726           {
00727             data_map[this->getPeakRt(*it)] += this->getPeakIntensity(*it);
00728           }
00729         }
00730 
00731         // Copy the raw data into set
00732         set.resize(data_map.size());
00733         std::map<CoordinateType, CoordinateType>::iterator it;
00734         UInt i = 0;
00735         for (it = data_map.begin(); it != data_map.end(); ++it, ++i)
00736         {
00737           set[i].setPosition((*it).first);
00738           set[i].setIntensity((*it).second);
00739         }
00740 
00741       }
00742 
00743     }
00744 
00746     ProductModel<2> model2D_;
00748     Math::BasicStatistics<> mz_stat_;
00750     Math::AsymmetricStatistics<> rt_stat_;
00752     RawDataArrayType mz_input_data_;
00754     RawDataArrayType rt_input_data_;
00756     CoordinateType tolerance_stdev_box_;
00758     CoordinateType monoisotopic_mz_;
00759 #ifdef DEBUG_FEATUREFINDER
00760 
00761     UInt counter_;
00762 #endif
00763 
00764     CoordinateType interpolation_step_mz_;
00766     CoordinateType interpolation_step_rt_;
00768     Int max_isotope_;
00770     CoordinateType iso_stdev_first_;
00772     CoordinateType iso_stdev_last_;
00774     CoordinateType iso_stdev_stepsize_;
00776     Int first_mz_model_;
00778     Int last_mz_model_;
00780     CoordinateType isotope_stdev_;
00782     String algorithm_;
00784     Int max_iteration_;
00786 
00787     CoordinateType deltaAbsError_;
00789     CoordinateType deltaRelError_;
00791     Math::BasicStatistics<> basic_stat_;
00793     QualityType quality_rt_;
00795     QualityType quality_mz_;
00796 
00797 private:
00798 
00800     ModelFitter();
00802     ModelFitter & operator=(const ModelFitter &);
00804     ModelFitter(const ModelFitter &);
00805 
00806   };
00807 
00808 }
00809 
00810 #endif // OPENMS_TRANSFORMATIONS_FEATUREFINDER_MODELFITTER_H

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