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

PeakPickerHiRes.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: Erhan Kenar $
00032 // --------------------------------------------------------------------------
00033 
00034 #ifndef OPENMS_TRANSFORMATIONS_RAW2PEAK_PEAKPICKERHIRES_H
00035 #define OPENMS_TRANSFORMATIONS_RAW2PEAK_PEAKPICKERHIRES_H
00036 
00037 #include <OpenMS/KERNEL/MSExperiment.h>
00038 #include <OpenMS/DATASTRUCTURES/DefaultParamHandler.h>
00039 #include <OpenMS/CONCEPT/ProgressLogger.h>
00040 
00041 #include <OpenMS/FILTERING/NOISEESTIMATION/SignalToNoiseEstimatorMedian.h>
00042 
00043 #include <gsl/gsl_spline.h>
00044 #include <gsl/gsl_interp.h>
00045 
00046 #include <map>
00047 
00048 
00049 #define DEBUG_PEAK_PICKING
00050 #undef DEBUG_PEAK_PICKING
00051 //#undef DEBUG_DECONV
00052 namespace OpenMS
00053 {
00067   class OPENMS_DLLAPI PeakPickerHiRes :
00068     public DefaultParamHandler,
00069     public ProgressLogger
00070   {
00071 public:
00073     PeakPickerHiRes();
00074 
00076     virtual ~PeakPickerHiRes();
00077 
00081     template <typename PeakType>
00082     void pick(const MSSpectrum<PeakType> & input, MSSpectrum<PeakType> & output) const
00083     {
00084       // copy meta data of the input spectrum
00085       output.clear(true);
00086       output.SpectrumSettings::operator=(input);
00087       output.MetaInfoInterface::operator=(input);
00088       output.setRT(input.getRT());
00089       output.setMSLevel(input.getMSLevel());
00090       output.setName(input.getName());
00091       output.setType(SpectrumSettings::PEAKS);
00092 
00093       // don't pick a spectrum with less than 5 data points
00094       if (input.size() < 5) return;
00095 
00096       // signal-to-noise estimation
00097       SignalToNoiseEstimatorMedian<MSSpectrum<PeakType> > snt;
00098 
00099       if (signal_to_noise_ > 0.0)
00100       {
00101         snt.init(input);
00102       }
00103 
00104       // find local maxima in raw data
00105       for (Size i = 2; i < input.size() - 2; ++i)
00106       {
00107         double central_peak_mz = input[i].getMZ(), central_peak_int = input[i].getIntensity();
00108         double left_neighbor_mz = input[i - 1].getMZ(), left_neighbor_int = input[i - 1].getIntensity();
00109         double right_neighbor_mz = input[i + 1].getMZ(), right_neighbor_int = input[i + 1].getIntensity();
00110 
00111         // MZ spacing sanity checks
00112         double left_to_central = std::fabs(central_peak_mz - left_neighbor_mz);
00113         double central_to_right = std::fabs(right_neighbor_mz - central_peak_mz);
00114         double min_spacing = (left_to_central < central_to_right) ? left_to_central : central_to_right;
00115 
00116         double act_snt = 0.0, act_snt_l1 = 0.0, act_snt_r1 = 0.0;
00117 
00118         if (signal_to_noise_ > 0.0)
00119         {
00120           act_snt = snt.getSignalToNoise(input[i]);
00121           act_snt_l1 = snt.getSignalToNoise(input[i - 1]);
00122           act_snt_r1 = snt.getSignalToNoise(input[i + 1]);
00123         }
00124 
00125         // look for peak cores meeting MZ and intensity/SNT criteria
00126         if (act_snt >= signal_to_noise_
00127            && left_to_central < 1.5 * min_spacing
00128            && central_peak_int > left_neighbor_int
00129            && act_snt_l1 >= signal_to_noise_
00130            && central_to_right < 1.5 * min_spacing
00131            && central_peak_int > right_neighbor_int
00132            && act_snt_r1 >= signal_to_noise_)
00133         {
00134           // special case: if a peak core is surrounded by more intense
00135           // satellite peaks (indicates oscillation rather than
00136           // real peaks) -> remove
00137 
00138           double act_snt_l2 = 0.0, act_snt_r2 = 0.0;
00139 
00140           if (signal_to_noise_ > 0.0)
00141           {
00142             act_snt_l2 = snt.getSignalToNoise(input[i - 2]);
00143             act_snt_r2 = snt.getSignalToNoise(input[i + 2]);
00144           }
00145 
00146           if ((i > 1
00147               && std::fabs(left_neighbor_mz - input[i - 2].getMZ()) < 1.5 * min_spacing
00148               && left_neighbor_int < input[i - 2].getIntensity()
00149               && act_snt_l2 >= signal_to_noise_)
00150              &&
00151               ((i + 2) < input.size()
00152               && std::fabs(input[i + 2].getMZ() - right_neighbor_mz) < 1.5 * min_spacing
00153               && right_neighbor_int < input[i + 2].getIntensity()
00154               && act_snt_r2 >= signal_to_noise_)
00155               )
00156           {
00157             ++i;
00158             continue;
00159           }
00160 
00161 
00162           std::map<double, double> peak_raw_data;
00163 
00164           peak_raw_data[central_peak_mz] = central_peak_int;
00165           peak_raw_data[left_neighbor_mz] = left_neighbor_int;
00166           peak_raw_data[right_neighbor_mz] = right_neighbor_int;
00167 
00168 
00169           // peak core found, now extend it
00170           // to the left
00171           Size k = 2;
00172 
00173           Size missing_left(0);
00174           Size missing_right(0);
00175 
00176           while ((i - k + 1) > 0
00177                 && (missing_left < 2)
00178                 && input[i - k].getIntensity() <= peak_raw_data.begin()->second)
00179           {
00180 
00181             double act_snt_lk = 0.0;
00182 
00183             if (signal_to_noise_ > 0.0)
00184             {
00185               act_snt_lk = snt.getSignalToNoise(input[i - k]);
00186             }
00187 
00188 
00189             if (act_snt_lk >= signal_to_noise_ && std::fabs(input[i - k].getMZ() - peak_raw_data.begin()->first) < 1.5 * min_spacing)
00190             {
00191               peak_raw_data[input[i - k].getMZ()] = input[i - k].getIntensity();
00192             }
00193             else
00194             {
00195               peak_raw_data[input[i - k].getMZ()] = input[i - k].getIntensity();
00196               ++missing_left;
00197             }
00198 
00199             ++k;
00200 
00201           }
00202 
00203           // to the right
00204           k = 2;
00205           while ((i + k) < input.size()
00206                 && (missing_right < 2)
00207                 && input[i + k].getIntensity() <= peak_raw_data.rbegin()->second)
00208           {
00209 
00210             double act_snt_rk = 0.0;
00211 
00212             if (signal_to_noise_ > 0.0)
00213             {
00214               act_snt_rk = snt.getSignalToNoise(input[i + k]);
00215             }
00216 
00217             if (act_snt_rk >= signal_to_noise_ && std::fabs(input[i + k].getMZ() - peak_raw_data.rbegin()->first) < 1.5 * min_spacing)
00218             {
00219               peak_raw_data[input[i + k].getMZ()] = input[i + k].getIntensity();
00220             }
00221             else
00222             {
00223               peak_raw_data[input[i + k].getMZ()] = input[i + k].getIntensity();
00224               ++missing_right;
00225             }
00226 
00227             ++k;
00228           }
00229 
00230 
00231           // output all raw data points selected for one peak
00232           // TODO: #ifdef DEBUG_ ...
00233           // for (std::map<double, double>::const_iterator map_it = peak_raw_data.begin(); map_it != peak_raw_data.end(); ++map_it) {
00234           // PeakType peak;
00235           // peak.setMZ(map_it->first);
00236           // peak.setIntensity(map_it->second);
00237           // output.push_back(peak);
00238           // std::cout << map_it->first << " " << map_it->second << " snt: " << std::endl;
00239           // }
00240           // std::cout << "--------------------" << std::endl;
00241 
00242           const Size num_raw_points = peak_raw_data.size();
00243 
00244           std::vector<double> raw_mz_values;
00245           std::vector<double> raw_int_values;
00246 
00247           for (std::map<double, double>::const_iterator map_it = peak_raw_data.begin(); map_it != peak_raw_data.end(); ++map_it)
00248           {
00249             raw_mz_values.push_back(map_it->first);
00250             raw_int_values.push_back(map_it->second);
00251           }
00252 
00253           // setup gsl splines
00254           gsl_interp_accel * spline_acc = gsl_interp_accel_alloc();
00255           gsl_interp_accel * first_deriv_acc = gsl_interp_accel_alloc();
00256           gsl_spline * peak_spline = gsl_spline_alloc(gsl_interp_cspline, num_raw_points);
00257           gsl_spline_init(peak_spline, &(*raw_mz_values.begin()), &(*raw_int_values.begin()), num_raw_points);
00258 
00259 
00260           // calculate maximum by evaluating the spline's 1st derivative
00261           // (bisection method)
00262           double max_peak_mz = central_peak_mz, max_peak_int = central_peak_int;
00263           double threshold = 0.000001;
00264           double lefthand = left_neighbor_mz;
00265           double righthand = right_neighbor_mz;
00266 
00267           bool lefthand_sign = 1;
00268           double eps = std::numeric_limits<double>::epsilon();
00269 
00270 
00271           // bisection
00272           do
00273           {
00274             double mid = (lefthand + righthand) / 2;
00275 
00276             double midpoint_deriv_val = gsl_spline_eval_deriv(peak_spline, mid, first_deriv_acc);
00277 
00278             // if deriv nearly zero then maximum already found
00279             if (!(std::fabs(midpoint_deriv_val) > eps))
00280             {
00281               break;
00282             }
00283 
00284             bool midpoint_sign = (midpoint_deriv_val < 0.0) ? 0 : 1;
00285 
00286             if (lefthand_sign ^ midpoint_sign)
00287             {
00288               righthand = mid;
00289             }
00290             else
00291             {
00292               lefthand = mid;
00293             }
00294 
00295             // TODO: #ifdef DEBUG_ ...
00296             // PeakType peak;
00297             // peak.setMZ(mid);
00298             // peak.setIntensity(gsl_spline_eval(peak_spline, mid, spline_acc));
00299             // output.push_back(peak);
00300 
00301           }
00302           while (std::fabs(lefthand - righthand) > threshold);
00303 
00304           // sanity check?
00305           max_peak_mz = (lefthand + righthand) / 2;
00306           max_peak_int = gsl_spline_eval(peak_spline, max_peak_mz, spline_acc);
00307 
00308           // save picked pick into output spectrum
00309           PeakType peak;
00310           peak.setMZ(max_peak_mz);
00311           peak.setIntensity(max_peak_int);
00312           output.push_back(peak);
00313 
00314           // free allocated gsl memory
00315           gsl_spline_free(peak_spline);
00316           gsl_interp_accel_free(spline_acc);
00317           gsl_interp_accel_free(first_deriv_acc);
00318 
00319           // jump over raw data points that have been considered already
00320           i = i + k - 1;
00321         }
00322       }
00323 
00324       return;
00325     }
00326 
00330     template <typename PeakType>
00331     void pickExperiment(const MSExperiment<PeakType> & input, MSExperiment<PeakType> & output) const
00332     {
00333       // make sure that output is clear
00334       output.clear(true);
00335 
00336       // copy experimental settings
00337       static_cast<ExperimentalSettings &>(output) = input;
00338 
00339       // resize output with respect to input
00340       output.resize(input.size());
00341 
00342       bool ms1_only = param_.getValue("ms1_only").toBool();
00343       Size progress = 0;
00344 
00345       startProgress(0, input.size(), "picking peaks");
00346       for (Size scan_idx = 0; scan_idx != input.size(); ++scan_idx)
00347       {
00348         if (ms1_only && (input[scan_idx].getMSLevel() != 1))
00349         {
00350           output[scan_idx] = input[scan_idx];
00351         }
00352         else
00353         {
00354           pick(input[scan_idx], output[scan_idx]);
00355         }
00356         setProgress(++progress);
00357       }
00358       endProgress();
00359 
00360       return;
00361     }
00362 
00363 protected:
00364     // signal-to-noise parameter
00365     double signal_to_noise_;
00366 
00367     //docu in base class
00368     void updateMembers_();
00369 
00370   };   // end PeakPickerHiRes
00371 
00372 } // namespace OpenMS
00373 
00374 #endif

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