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

FeatureFinderAlgorithmMRM.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: Andreas Bertsch $
00032 // $Authors: Andreas Bertsch $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_TRANSFORMATIONS_FEATUREFINDER_FEATUREFINDERALGORITHMMRM_H
00036 #define OPENMS_TRANSFORMATIONS_FEATUREFINDER_FEATUREFINDERALGORITHMMRM_H
00037 
00038 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/FeatureFinderAlgorithm.h>
00039 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/ProductModel.h>
00040 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/EmgFitter1D.h>
00041 #include <OpenMS/TRANSFORMATIONS/FEATUREFINDER/EmgModel.h>
00042 #include <OpenMS/FILTERING/SMOOTHING/SavitzkyGolayFilter.h>
00043 #include <OpenMS/FILTERING/SMOOTHING/GaussFilter.h>
00044 #include <OpenMS/DATASTRUCTURES/Map.h>
00045 #include <OpenMS/FILTERING/NOISEESTIMATION/SignalToNoiseEstimatorMeanIterative.h>
00046 #include <OpenMS/FILTERING/TRANSFORMERS/LinearResampler.h>
00047 #include <OpenMS/KERNEL/StandardTypes.h>
00048 
00049 #include <boost/math/special_functions/fpclassify.hpp>
00050 
00051 #include <fstream>
00052 #include <limits>
00053 
00054 namespace OpenMS
00055 {
00072   template <class PeakType, class FeatureType>
00073   class FeatureFinderAlgorithmMRM :
00074     public FeatureFinderAlgorithm<PeakType, FeatureType>,
00075     public FeatureFinderDefs
00076   {
00077 public:
00079 
00080     typedef typename FeatureFinderAlgorithm<PeakType, FeatureType>::MapType MapType;
00081     typedef typename MapType::SpectrumType SpectrumType;
00082     typedef typename SpectrumType::FloatDataArrays FloatDataArrays;
00084 
00085     using FeatureFinderAlgorithm<PeakType, FeatureType>::param_;
00086     using FeatureFinderAlgorithm<PeakType, FeatureType>::features_;
00087     using FeatureFinderAlgorithm<PeakType, FeatureType>::ff_;
00088     using FeatureFinderAlgorithm<PeakType, FeatureType>::defaults_;
00089     using FeatureFinderAlgorithm<PeakType, FeatureType>::map_;
00090 
00091 public:
00092 
00093     enum
00094     {
00095       RT = Peak2D::RT,
00096       MZ = Peak2D::MZ
00097     };
00098 
00099 
00101     FeatureFinderAlgorithmMRM() :
00102       FeatureFinderAlgorithm<PeakType, FeatureType>()
00103     {
00104       defaults_.setValue("min_rt_distance", 10.0, "Minimal distance of MRM features in seconds.");
00105       defaults_.setMinFloat("min_rt_distance", 0.0);
00106       defaults_.setValue("min_num_peaks_per_feature", 5, "Minimal number of peaks which are needed for a single feature", StringList::create("advanced"));
00107       defaults_.setMinInt("min_num_peaks_per_feature", 1);
00108       defaults_.setValue("min_signal_to_noise_ratio", 2.0, "Minimal S/N ratio a peak must have to be taken into account. Set to zero if the MRM-traces contains mostly signals, and no noise.");
00109       defaults_.setMinFloat("min_signal_to_noise_ratio", 0);
00110       defaults_.setValue("write_debug_files", "false", "If set to true, for each feature a plot will be created, in the subdirectory 'debug'", StringList::create("advanced"));
00111       defaults_.setValidStrings("write_debug_files", StringList::create("true,false"));
00112 
00113       defaults_.setValue("resample_traces", "false", "If set to true, each trace, which is in this case a part of the MRM monitoring trace with signal is resampled, using the minimal distance of two data points in RT dimension", StringList::create("advanced"));
00114       defaults_.setValidStrings("resample_traces", StringList::create("true,false"));
00115 
00116       defaults_.setValue("write_debuginfo", "false", "If set to true, debug messages are written, the output can be somewhat lengthy.", StringList::create("advanced"));
00117       defaults_.setValidStrings("write_debuginfo", StringList::create("true,false"));
00118 
00119       this->defaultsToParam_();
00120     }
00121 
00123     virtual void run()
00124     {
00125       //-------------------------------------------------------------------------
00126       //General initialization
00127       //-------------------------------------------------------------------------
00128 
00129       Map<Size, Map<Size, std::vector<std::pair<DoubleReal, PeakType> > > > traces;
00130 
00131       SignalToNoiseEstimatorMeanIterative<RichPeakSpectrum> sne;
00132       LinearResampler resampler;
00133 
00134       // Split the whole map into traces (== MRM transitions)
00135       ff_->startProgress(0, traces.size(), "Finding features in traces.");
00136       Size counter(0);
00137       //typename Map<Size, Map<Size, std::vector<std::pair<DoubleReal, PeakType> > > >::const_iterator it1 = traces.begin();
00138       //typename Map<Size, std::vector<std::pair<DoubleReal, PeakType> > >::const_iterator it2;
00139       DoubleReal min_rt_distance(param_.getValue("min_rt_distance"));
00140       DoubleReal min_signal_to_noise_ratio(param_.getValue("min_signal_to_noise_ratio"));
00141       Size min_num_peaks_per_feature(param_.getValue("min_num_peaks_per_feature"));
00142       Size feature_id(0);
00143       bool write_debuginfo(param_.getValue("write_debuginfo").toBool());
00144       bool write_debug_files(param_.getValue("write_debug_files").toBool());
00145       bool resample_traces(param_.getValue("resample_traces").toBool());
00146 
00147       if (write_debuginfo)
00148       {
00149         std::cerr << "Starting feature finding #chromatograms=" << map_->getChromatograms().size() << ", #spectra=" << map_->size() << std::endl;
00150       }
00151 
00152       typename std::vector<MSChromatogram<ChromatogramPeak> >::const_iterator first_it = map_->getChromatograms().begin();
00153       for (; first_it != map_->getChromatograms().end(); ++first_it)
00154       {
00155         // throw the peaks into a "spectrum" where the m/z values are RTs in reality (more a chromatogram)
00156         RichPeakSpectrum chromatogram;
00157         //typename std::vector<std::pair<DoubleReal, PeakType> >::const_iterator it3 = it2->second.begin();
00158         for (MSChromatogram<ChromatogramPeak>::const_iterator it = first_it->begin(); it != first_it->end(); ++it)
00159         {
00160           RichPeak1D peak;
00161           peak.setMZ(it->getRT());
00162           peak.setIntensity(it->getIntensity());
00163           chromatogram.push_back(peak);
00164         }
00165 
00166         // TODO
00167         // find presection of separated RTs of peaks;
00168         // resampling to min distance?
00169         // for each of the section, try to estimate S/N
00170         // find core regions and fit them
00171         //
00172 
00173         if (resample_traces)
00174         {
00175           // resample the chromatogram, first find minimal distance and use this as resampling distance
00176           DoubleReal min_distance(std::numeric_limits<DoubleReal>::max()), old_rt(0);
00177           for (RichPeakSpectrum::ConstIterator it = chromatogram.begin(); it != chromatogram.end(); ++it)
00178           {
00179             if (write_debuginfo)
00180             {
00181               std::cerr << "CHROMATOGRAM: " << it->getMZ() << " " << it->getIntensity() << std::endl;
00182             }
00183             DoubleReal rt_diff = it->getMZ() - old_rt;
00184             if (rt_diff < min_distance && rt_diff > 0)
00185             {
00186               min_distance = rt_diff;
00187             }
00188             old_rt = it->getMZ();
00189           }
00190 
00191           if (write_debuginfo)
00192           {
00193             std::cerr << "Min_distance=" << min_distance << std::endl;
00194           }
00195           if (min_distance > 50 || chromatogram.size() < min_num_peaks_per_feature)
00196           {
00197             continue;
00198           }
00199           Param resampler_param(resampler.getParameters());
00200           resampler_param.setValue("spacing", min_distance);
00201           resampler.setParameters(resampler_param);
00202           resampler.raster(chromatogram);
00203         }
00204 
00205         // now smooth the data
00206         GaussFilter filter;
00207         Param filter_param(filter.getParameters());
00208         filter.setParameters(filter_param);
00209 
00210         // calculate signal to noise levels
00211         RichPeakSpectrum sn_chrom;
00212         Param sne_param(sne.getParameters());
00213         // set window length to whole range, we expect only at most one signal
00214         if (write_debuginfo)
00215         {
00216           std::cerr << "win_len m/z: " <<  (chromatogram.end() - 1)->getMZ() << " " << chromatogram.begin()->getMZ() << std::endl;
00217         }
00218         sne_param.setValue("win_len", (chromatogram.end() - 1)->getMZ() - chromatogram.begin()->getMZ());
00219 
00220         if ((DoubleReal)sne_param.getValue("win_len") < 10e-4)
00221         {
00222           continue;
00223         }
00224         sne.setParameters(sne_param);
00225         sne.init(chromatogram.begin(), chromatogram.end());
00226 
00227         if (write_debuginfo)
00228         {
00229           std::cerr << first_it->getPrecursor().getMZ() << " " << first_it->getProduct().getMZ() << " ";
00230         }
00231         for (RichPeakSpectrum::Iterator sit = chromatogram.begin(); sit != chromatogram.end(); ++sit)
00232         {
00233           DoubleReal sn(sne.getSignalToNoise(sit));
00234           sit->setMetaValue("SN", sn);
00235           if (write_debuginfo)
00236           {
00237             std::cerr << sit->getMZ() << " " << sit->getIntensity() << " " << sn << std::endl;
00238           }
00239           if (min_signal_to_noise_ratio == 0 || sn > min_signal_to_noise_ratio)
00240           {
00241             sn_chrom.push_back(*sit);
00242           }
00243         }
00244 
00245         // now find sections in the chromatogram which have high s/n value
00246         DoubleReal last_rt(0), this_rt(0);
00247         std::vector<std::vector<DPosition<2> > > sections;
00248         for (RichPeakSpectrum::Iterator sit = sn_chrom.begin(); sit != sn_chrom.end(); ++sit)
00249         {
00250           if (write_debuginfo)
00251           {
00252             std::cerr << "SECTIONS: " << sit->getMZ() << " " << sit->getIntensity() << std::endl;
00253           }
00254           this_rt = sit->getMZ();
00255           if (sections.empty() || (this_rt - last_rt) > min_rt_distance)
00256           {
00257             if (write_debuginfo)
00258             {
00259               std::cerr << "Starting new section, sections.size()=" << sections.size() << ", rt_diff=" << this_rt - last_rt << std::endl;
00260             }
00261             // new section
00262             std::vector<DPosition<2> > section;
00263             section.push_back(DPosition<2>(this_rt, sit->getIntensity()));
00264             sections.push_back(section);
00265           }
00266           else
00267           {
00268             sections.back().push_back(DPosition<2>(this_rt, sit->getIntensity()));
00269           }
00270           last_rt = this_rt;
00271         }
00272 
00273         // for each of the sections identify local maxima which can be used for extension
00274         // if needed split the sections into smaller sections
00275         for (Size i = 0; i != sections.size(); ++i)
00276         {
00277           if (sections[i].size() < min_num_peaks_per_feature)
00278           {
00279             continue;
00280           }
00281 
00282           std::vector<DoubleReal> deltas(2, 0.0);
00283           DoubleReal last_int(sections[i][0].getY());
00284           for (Size j = 1; j < sections[i].size(); ++j)
00285           {
00286             deltas.push_back((sections[i][j].getY() - last_int) / last_int);
00287             last_int = sections[i][j].getY();
00288             if (write_debuginfo)
00289             {
00290               DoubleReal average_delta = std::accumulate(deltas.begin(), deltas.end(), 0.0) / (DoubleReal)3.0;
00291               std::cerr << "AverageDelta: " << average_delta << " (" << sections[i][j].getX() << ", " << sections[i][j].getY() << ")" << std::endl;
00292             }
00293           }
00294         }
00295 
00296 
00297         // for each section estimate the rt min/max and add up the intensities
00298         for (Size i = 0; i != sections.size(); ++i)
00299         {
00300           if (sections[i].size() > min_num_peaks_per_feature)
00301           {
00302             // first smooth the data to prevent outliers from destroying the fit
00303             PeakSpectrum filter_spec;
00304             for (Size j = 0; j != sections[i].size(); ++j)
00305             {
00306               Peak1D p;
00307               p.setMZ(sections[i][j].getX());
00308               p.setIntensity(sections[i][j].getY());
00309               filter_spec.push_back(p);
00310             }
00311 
00312             // add two peaks at the beginning and at the end for better fit
00313             // therefore calculate average distance first
00314             std::vector<DoubleReal> distances;
00315             for (Size j = 1; j < filter_spec.size(); ++j)
00316             {
00317               distances.push_back(filter_spec[j].getMZ() - filter_spec[j - 1].getMZ());
00318             }
00319             DoubleReal dist_average = std::accumulate(distances.begin(), distances.end(), 0.0) / (DoubleReal)distances.size();
00320 
00321             // append peaks
00322             Peak1D new_peak;
00323             new_peak.setIntensity(0);
00324             new_peak.setMZ(filter_spec.back().getMZ() + dist_average);
00325             filter_spec.push_back(new_peak);
00326             new_peak.setMZ(filter_spec.back().getMZ() + dist_average);
00327             filter_spec.push_back(new_peak);
00328             new_peak.setMZ(filter_spec.back().getMZ() + dist_average);
00329             filter_spec.push_back(new_peak);
00330 
00331             // prepend peaks
00332             new_peak.setMZ(filter_spec.front().getMZ() - dist_average);
00333             filter_spec.insert(filter_spec.begin(), new_peak);
00334             new_peak.setMZ(filter_spec.front().getMZ() - dist_average);
00335             filter_spec.insert(filter_spec.begin(), new_peak);
00336             new_peak.setMZ(filter_spec.front().getMZ() - dist_average);
00337             filter_spec.insert(filter_spec.begin(), new_peak);
00338 
00339             filter_param.setValue("gaussian_width", 4 * dist_average);
00340             filter.setParameters(filter_param);
00341 
00342             // smooth the data
00343             filter.filter(filter_spec);
00344 
00345             // transform the data for fitting and fit RT profile
00346             std::vector<PeakType> data_to_fit;
00347             for (Size j = 0; j != filter_spec.size(); ++j)
00348             {
00349               PeakType p;
00350               p.setPosition(filter_spec[j].getMZ());
00351               p.setIntensity(filter_spec[j].getIntensity());
00352               data_to_fit.push_back(p);
00353             }
00354             InterpolationModel * model_rt = 0;
00355             DoubleReal quality = fitRT_(data_to_fit, model_rt);
00356 
00357             Feature f;
00358             f.setQuality(0, quality);
00359             f.setOverallQuality(quality);
00360 
00361             ConvexHull2D::PointArrayType hull_points(sections[i].size());
00362             DoubleReal intensity_sum(0.0), rt_sum(0.0);
00363             for (Size j = 0; j < sections[i].size(); ++j)
00364             {
00365               hull_points[j][0] = sections[i][j].getX();
00366               hull_points[j][1] = first_it->getProduct().getMZ();
00367 
00368               rt_sum += sections[i][j].getX();
00369               intensity_sum += sections[i][j].getY();
00370             }
00371 
00372             // create the feature according to fit
00373             f.setRT((DoubleReal)model_rt->getParameters().getValue("emg:retention"));
00374             f.setMZ((DoubleReal)first_it->getProduct().getMZ());
00375             f.setIntensity(intensity_sum);
00376             ConvexHull2D hull;
00377             hull.addPoints(hull_points);
00378             f.getConvexHulls().push_back(hull);
00379             f.setMetaValue("MZ", (DoubleReal)first_it->getPrecursor().getMZ());
00380 
00381 
00382             // add the model to the feature
00383             ProductModel<2> prod_model;
00384             prod_model.setModel(RT, model_rt);
00385             f.setModelDescription(ModelDescription<2>(&prod_model));
00386 
00387 
00388             feature_id++;
00389 
00390             // writes a feature plot using gnuplot (should be installed on computer)
00391             if (write_debug_files)
00392             {
00393               String base_name = "debug/" + String((DoubleReal)f.getMetaValue("MZ")) + "_id" + String(feature_id) + "_RT" + String(f.getRT()) + "_Q3" + String(f.getMZ());
00394               std::ofstream data_out(String(base_name + "_data.dat").c_str());
00395               for (Size j = 0; j < sections[i].size(); ++j)
00396               {
00397                 // RT intensity
00398                 DoubleReal rt = sections[i][j].getX();
00399                 DoubleReal intensity = sections[i][j].getY();
00400                 data_out << rt << " " << intensity << std::endl;
00401               }
00402               data_out.close();
00403 
00404               std::ofstream smoothed_data_out(String(base_name + "_smoothed_data.dat").c_str());
00405               for (Size j = 0; j < filter_spec.size(); ++j)
00406               {
00407                 smoothed_data_out << filter_spec[j].getMZ() + 0.5 << " " << filter_spec[j].getIntensity() << std::endl;
00408               }
00409               smoothed_data_out.close();
00410 
00411               std::ofstream fit_out(String(base_name + "_rt_fit.dat").c_str());
00412               EmgModel emg_model;
00413               emg_model.setParameters(model_rt->getParameters());
00414               emg_model.setSamples();
00415               DoubleReal bb_min((DoubleReal)emg_model.getParameters().getValue("bounding_box:min"));
00416               DoubleReal bb_max((DoubleReal)emg_model.getParameters().getValue("bounding_box:max"));
00417               DoubleReal int_step((DoubleReal)emg_model.getParameters().getValue("interpolation_step"));
00418               for (DoubleReal pos = bb_min; pos < bb_max; pos += int_step)
00419               {
00420                 // RT intensity
00421                 fit_out << pos << " " << emg_model.getIntensity(pos) << std::endl;
00422               }
00423               fit_out.close();
00424 
00425               std::ofstream gnuplot_out(String(base_name + "_gnuplot.gpl").c_str());
00426               gnuplot_out << "set terminal png" << std::endl;
00427               gnuplot_out << "set output \"" << base_name << ".png\"" << std::endl;
00428               gnuplot_out << "plot '" << base_name << "_data.dat' w i, '" << base_name << "_smoothed_data.dat'  w i, '" << base_name << "_rt_fit.dat' w lp title 'quality=" << f.getOverallQuality() << "'" << std::endl;
00429               gnuplot_out.close();
00430               String gnuplot_call = "gnuplot " + base_name + "_gnuplot.gpl";
00431               int error = system(gnuplot_call.c_str());
00432               if (error != 0)
00433               {
00434                 std::cerr << "An error occurred during the gnuplot execution" << std::endl;
00435               }
00436             }
00437 
00438             features_->push_back(f);
00439           }
00440         }
00441 
00442         ff_->setProgress(++counter);
00443       }
00444     }
00445 
00446     static FeatureFinderAlgorithm<PeakType, FeatureType> * create()
00447     {
00448       return new FeatureFinderAlgorithmMRM();
00449     }
00450 
00451     static const String getProductName()
00452     {
00453       return "mrm";
00454     }
00455 
00456 protected:
00457 
00458     DoubleReal fitRT_(std::vector<PeakType> & rt_input_data, InterpolationModel * & model) const
00459     {
00460       DoubleReal quality;
00461       Param param;
00462       EmgFitter1D fitter;
00463 
00464       /*
00465 param.setValue( "tolerance_stdev_bounding_box", tolerance_stdev_box_);
00466 param.setValue( "statistics:mean", rt_stat_.mean() );
00467 param.setValue( "statistics:variance", rt_stat_.variance() );
00468 param.setValue( "interpolation_step", interpolation_step_rt_ );
00469 param.setValue( "max_iteration", max_iteration_);
00470 param.setValue( "deltaAbsError", deltaAbsError_);
00471 param.setValue( "deltaRelError", deltaRelError_);
00472       */
00473 
00474       // Set parameter for fitter
00475       fitter.setParameters(param);
00476 
00477       // Construct model for rt
00478       quality = fitter.fit1d(rt_input_data, model);
00479 
00480       // Check quality
00481       if (boost::math::isnan(quality)) quality = -1.0;
00482 
00483       return quality;
00484     }
00485 
00486     //Docu in base class
00487     virtual void updateMembers_()
00488     {
00489     }
00490 
00491   };
00492 
00493 } // namespace OpenMS
00494 
00495 #endif // OPENMS_TRANSFORMATIONS_FEATUREFINDER_FEATUREFINDERALGORITHMMRM_H

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