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

ChromatogramExtractor.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: Hannes Roest $
00032 // $Authors: Hannes Roest $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_ANALYSIS_OPENSWATH_CHROMATOGRAMEXTRACTOR_H
00036 #define OPENMS_ANALYSIS_OPENSWATH_CHROMATOGRAMEXTRACTOR_H
00037 
00038 #include <OpenMS/KERNEL/MSExperiment.h>
00039 #include <OpenMS/ANALYSIS/TARGETED/TargetedExperiment.h>
00040 
00041 // move to TOPPTool
00042 #include <OpenMS/FORMAT/TransformationXMLFile.h>
00043 #include <OpenMS/FORMAT/MzMLFile.h>
00044 
00045 #ifdef _OPENMP
00046 #include <omp.h>
00047 #endif
00048 
00049 namespace OpenMS
00050 {
00051 
00061   class OPENMS_DLLAPI ChromatogramExtractor :
00062     public ProgressLogger
00063   {
00064 
00065 public:
00066 
00068     ChromatogramExtractor()
00069     {
00070     }
00071 
00073     ~ChromatogramExtractor()
00074     {
00075     }
00076 
00078     template <typename ExperimentT>
00079     void extractChromatograms(const ExperimentT& input, ExperimentT& output, OpenMS::TargetedExperiment& transition_exp, double extract_window, bool ppm,
00080                               TransformationDescription trafo, double rt_extraction_window, String filter)
00081     {
00082 
00083       // invert the trafo because we want to transform nRT values to "real" RT values
00084       trafo.invert();
00085 
00086       Size input_size = input.size();
00087       if (input_size < 1)
00088       {
00089         return;
00090       }
00091       SpectrumSettings settings = input[0];
00092       int used_filter = -1;
00093       if (filter == "tophat")
00094       {
00095         used_filter = 1;
00096       }
00097       else if (filter == "bartlett")
00098       {
00099         used_filter = 2;
00100       }
00101       else
00102       {
00103         throw Exception::IllegalArgument(__FILE__, __LINE__, __PRETTY_FUNCTION__,
00104                                          "Filter either needs to be tophat or bartlett");
00105       }
00106 
00107       // Store the peptide retention times in an intermediate map
00108       PeptideRTMap_.clear();
00109       for (Size i = 0; i < transition_exp.getPeptides().size(); i++)
00110       {
00111         const TargetedExperiment::Peptide& pep = transition_exp.getPeptides()[i];
00112         if (pep.rts.empty() || pep.rts[0].getCVTerms()["MS:1000896"].empty())
00113         {
00114           // we dont have retention times -> this is only a problem if we actually
00115           // wanted to use the RT limit feature.
00116           if (rt_extraction_window >= 0)
00117           {
00118             throw Exception::IllegalArgument(__FILE__, __LINE__, __PRETTY_FUNCTION__,
00119                                              "Error: Peptide " + pep.id + " does not have normalized retention times (term 1000896) which are necessary to perform an RT-limited extraction");
00120           }
00121           continue;
00122         }
00123         PeptideRTMap_[pep.id] = pep.rts[0].getCVTerms()["MS:1000896"][0].getValue().toString().toDouble();
00124       }
00125 
00126       // sort the transition experiment by product mass
00127       // this is essential because the algorithm assumes sorted transitions!
00128       transition_exp.sortTransitionsByProductMZ();
00129 
00130       // prepare all the spectra (but leave them empty)
00131       std::vector<typename ExperimentT::ChromatogramType> chromatograms;
00132       prepareSpectra_(settings, chromatograms, transition_exp);
00133 
00134       //go through all spectra
00135       startProgress(0, input_size, "Extracting chromatograms");
00136       for (Size scan_idx = 0; scan_idx < input_size; ++scan_idx)
00137       {
00138         setProgress(scan_idx);
00139 
00140         if (input[scan_idx].size() == 0)
00141           continue;
00142 
00143         Size peak_idx = 0;
00144 
00145         double mz;
00146         double integrated_intensity = 0;
00147 
00148         // go through all transitions / chromatograms which are sorted by
00149         // ProductMZ. We can use this to step through the spectrum and at the
00150         // same time step through the transitions. We increase the peak counter
00151         // until we hit the next transition and then extract the signal.
00152         for (Size k = 0; k < chromatograms.size(); ++k)
00153         {
00154 
00155           double current_rt = input[scan_idx].getRT();
00156           if (outsideExtractionWindow_(transition_exp.getTransitions()[k], current_rt, trafo, rt_extraction_window))
00157           {
00158             continue;
00159           }
00160 
00161           typename ExperimentT::ChromatogramType::PeakType p;
00162           mz = transition_exp.getTransitions()[k].getProductMZ();
00163 
00164           if (used_filter == 1)
00165           {
00166             extract_value_tophat(input[scan_idx], mz, peak_idx, integrated_intensity, extract_window, ppm);
00167           }
00168           else if (used_filter == 2)
00169           {
00170             extract_value_bartlett(input[scan_idx], mz, peak_idx, integrated_intensity, extract_window, ppm);
00171           }
00172 
00173           p.setRT(current_rt);
00174           p.setIntensity(integrated_intensity);
00175           chromatograms[k].push_back(p);
00176         }
00177       }
00178       endProgress();
00179 
00180       // add all the chromatograms to the output
00181       output.setChromatograms(chromatograms);
00182     }
00183 
00184 public:
00185 
00186     template <typename SpectrumT>
00187     void extract_value_tophat(const SpectrumT& input, const double& mz, Size& peak_idx, double& integrated_intensity, const double& extract_window, const bool ppm)
00188     {
00189       integrated_intensity = 0;
00190       if (input.size() == 0)
00191       {
00192         return;
00193       }
00194 
00195       // calculate extraction window
00196       double left, right;
00197       if (ppm)
00198       {
00199         left  = mz - mz * extract_window / 2.0 * 1.0e-6;
00200         right = mz + mz * extract_window / 2.0 * 1.0e-6;
00201       }
00202       else
00203       {
00204         left  = mz - extract_window / 2.0;
00205         right = mz + extract_window / 2.0;
00206       }
00207 
00208       Size walker;
00209 
00210       // advance the peak_idx until we hit the m/z value of the next transition
00211       while (peak_idx < input.size() && input[peak_idx].getMZ() < mz)
00212       {
00213         peak_idx++;
00214       }
00215 
00216       integrated_intensity = 0;
00217 
00218       // walk right and left and add to our intensity
00219       walker = peak_idx;
00220       // if we moved past the end of the spectrum, we need to try the last peak of the spectrum (it could still be within the window)
00221       if (peak_idx >= input.size())
00222       {
00223         walker = input.size() - 1;
00224       }
00225 
00226       // add the current peak if it is between right and left
00227       if (input[walker].getMZ() > left && input[walker].getMZ() < right)
00228       {
00229         integrated_intensity += input[walker].getIntensity();
00230       }
00231 
00232       // walk to the right until we go outside the window, then walk to the left until we are outside the window
00233       walker = peak_idx;
00234       if (walker > 0)
00235       {
00236         walker--;
00237       }
00238       while (walker > 0 && input[walker].getMZ() > left && input[walker].getMZ() < right)
00239       {
00240         integrated_intensity += input[walker].getIntensity(); walker--;
00241       }
00242       walker = peak_idx;
00243       if (walker < input.size() )
00244       {
00245         walker++;
00246       }
00247       while (walker<input.size() && input[walker].getMZ()> left &&  input[walker].getMZ() < right)
00248       {
00249         integrated_intensity += input[walker].getIntensity(); walker++;
00250       }
00251     }
00252 
00253     template <typename SpectrumT>
00254     void extract_value_bartlett(const SpectrumT& input, const double& mz, Size& peak_idx, double& integrated_intensity, const double& extract_window, const bool ppm)
00255     {
00256       integrated_intensity = 0;
00257       if (input.size() == 0)
00258       {
00259         return;
00260       }
00261 
00262       // calculate extraction window
00263       double left, right, half_window_size, weight;
00264       if (ppm)
00265       {
00266         half_window_size = mz * extract_window / 2.0 * 1.0e-6;
00267         left  = mz - mz * extract_window / 2.0 * 1.0e-6;
00268         right = mz + mz * extract_window / 2.0 * 1.0e-6;
00269       }
00270       else
00271       {
00272         half_window_size = extract_window / 2.0;
00273         left  = mz - extract_window / 2.0;
00274         right = mz + extract_window / 2.0;
00275       }
00276 
00277       Size walker;
00278 
00279       // advance the peak_idx until we hit the m/z value of the next transition
00280       while (peak_idx < input.size() && input[peak_idx].getMZ() < mz)
00281       {
00282         peak_idx++;
00283       }
00284 
00285 
00286       // walk right and left and add to our intensity
00287       walker = peak_idx;
00288       // if we moved past the end of the spectrum, we need to try the last peak of the spectrum (it could still be within the window)
00289       if (peak_idx >= input.size())
00290       {
00291         walker = input.size() - 1;
00292       }
00293 
00294       // add the current peak if it is between right and left
00295       if (input[walker].getMZ() > left && input[walker].getMZ() < right)
00296       {
00297         weight =  1 - fabs(input[walker].getMZ() - mz) / half_window_size;
00298         integrated_intensity += input[walker].getIntensity() * weight;
00299       }
00300 
00301       // walk to the right until we go outside the window, then walk to the left until we are outside the window
00302       walker = peak_idx;
00303       if (walker > 0 )
00304       {
00305         walker--;
00306       }
00307       while (walker > 0 && input[walker].getMZ() > left && input[walker].getMZ() < right)
00308       {
00309         weight =  1 - fabs(input[walker].getMZ() - mz) / half_window_size;
00310         integrated_intensity += input[walker].getIntensity() * weight; walker--;
00311       }
00312       walker = peak_idx;
00313       if (walker < input.size() )
00314       {
00315         walker++;
00316       }
00317       while (walker<input.size() && input[walker].getMZ()> left &&  input[walker].getMZ() < right)
00318       {
00319         weight = 1 - fabs(input[walker].getMZ() - mz) / half_window_size;
00320         integrated_intensity += input[walker].getIntensity() * weight; walker++;
00321       }
00322     }
00323 
00324     void extract_value_tophat(const std::vector<double>::const_iterator& mz_start, std::vector<double>::const_iterator& mz_it,
00325                               const std::vector<double>::const_iterator& mz_end, std::vector<double>::const_iterator& int_it,
00326                               const double& mz, double& integrated_intensity, double& extract_window, bool ppm)
00327     {
00328       integrated_intensity = 0;
00329       if (mz_start == mz_end)
00330       {
00331         return;
00332       }
00333 
00334       // calculate extraction window
00335       double left, right;
00336       if (ppm)
00337       {
00338         left  = mz - mz * extract_window / 2.0 * 1.0e-6;
00339         right = mz + mz * extract_window / 2.0 * 1.0e-6;
00340       }
00341       else
00342       {
00343         left  = mz - extract_window / 2.0;
00344         right = mz + extract_window / 2.0;
00345       }
00346 
00347       std::vector<double>::const_iterator mz_walker;
00348       std::vector<double>::const_iterator int_walker;
00349 
00350       // advance the mz / int iterator until we hit the m/z value of the next transition
00351       while (mz_it != mz_end && (*mz_it) < mz)
00352       {
00353         mz_it++; int_it++;
00354       }
00355 
00356       // walk right and left and add to our intensity
00357       mz_walker  = mz_it;
00358       int_walker = int_it;
00359 
00360       // if we moved past the end of the spectrum, we need to try the last peak of the spectrum (it could still be within the window)
00361       if (mz_it == mz_end)
00362       {
00363         mz_walker--; int_walker--;
00364       }
00365 
00366       // add the current peak if it is between right and left
00367       if ((*mz_walker) > left && (*mz_walker) < right)
00368       {
00369         integrated_intensity += (*int_walker);
00370       }
00371 
00372       // walk to the right until we go outside the window, then walk to the left until we are outside the window
00373       mz_walker  = mz_it;
00374       int_walker = int_it;
00375       if (mz_it != mz_start)
00376       {
00377         mz_walker--;
00378         int_walker--;
00379       }
00380       while (mz_walker != mz_start && (*mz_walker) > left && (*mz_walker) < right)
00381       {
00382         integrated_intensity += (*int_walker); mz_walker--; int_walker--;
00383       }
00384       mz_walker  = mz_it;
00385       int_walker = int_it;
00386       if (mz_it != mz_end)
00387       {
00388         mz_walker++;
00389         int_walker++;
00390       }
00391       while (mz_walker != mz_end && (*mz_walker) > left && (*mz_walker) < right)
00392       {
00393         integrated_intensity += (*int_walker); mz_walker++; int_walker++;
00394       }
00395     }
00396 
00397 private:
00398 
00400     template <class SpectrumSettingsT, class ChromatogramT>
00401     void prepareSpectra_(SpectrumSettingsT& settings, std::vector<ChromatogramT>& chromatograms, OpenMS::TargetedExperiment& transition_exp)
00402     {
00403 
00404       // first prepare all the spectra (but leave them empty)
00405       for (Size i = 0; i < transition_exp.getTransitions().size(); i++)
00406       {
00407         const ReactionMonitoringTransition* transition = &transition_exp.getTransitions()[i];
00408 
00409         ChromatogramT chrom;
00410         // Create precursor and set
00411         // 1) the target m/z
00412         // 2) the isolation window (upper/lower)
00413         // 3) the peptide sequence
00414         Precursor prec;
00415         prec.setMZ(transition->getPrecursorMZ());
00416         if (settings.getPrecursors().size() > 0)
00417         {
00418           prec.setIsolationWindowLowerOffset(settings.getPrecursors()[0].getIsolationWindowLowerOffset());
00419           prec.setIsolationWindowUpperOffset(settings.getPrecursors()[0].getIsolationWindowUpperOffset());
00420         }
00421 
00422         //set precursor sequence
00423         String pepref = transition->getPeptideRef();
00424         for (Size pep_idx = 0; pep_idx < transition_exp.getPeptides().size(); pep_idx++)
00425         {
00426           const OpenMS::TargetedExperiment::Peptide* pep = &transition_exp.getPeptides()[pep_idx];
00427           if (pep->id == pepref)
00428           {
00429             prec.setMetaValue("peptide_sequence", pep->sequence);
00430             break;
00431           }
00432         }
00433         // add precursor to spectrum
00434         chrom.setPrecursor(prec);
00435 
00436         // Create product and set its m/z
00437         Product prod;
00438         prod.setMZ(transition->getProductMZ());
00439         chrom.setProduct(prod);
00440 
00441         // Set the rest of the meta-data
00442         chrom.setInstrumentSettings(settings.getInstrumentSettings());
00443         chrom.setAcquisitionInfo(settings.getAcquisitionInfo());
00444         chrom.setSourceFile(settings.getSourceFile());
00445 
00446         for (Size i = 0; i < settings.getDataProcessing().size(); ++i)
00447         {
00448           DataProcessing dp = settings.getDataProcessing()[i];
00449           dp.setMetaValue("performed_on_spectra", "true");
00450           chrom.getDataProcessing().push_back(dp);
00451         }
00452 
00453         // Set the id of the chromatogram, using the id of the transition (this gives directly the mapping of the two)
00454         chrom.setNativeID(transition->getNativeID());
00455         chrom.setChromatogramType(ChromatogramSettings::SELECTED_REACTION_MONITORING_CHROMATOGRAM);
00456         chromatograms.push_back(chrom);
00457       }
00458 
00459     }
00460 
00461     bool outsideExtractionWindow_(const ReactionMonitoringTransition& transition, double current_rt,
00462                                    const TransformationDescription& trafo, double rt_extraction_window)
00463     {
00464       if (rt_extraction_window < 0)
00465       {
00466         return false;
00467       }
00468 
00469       // Get the expected retention time, apply the RT-transformation
00470       // (which describes the normalization) and then take the difference.
00471       // Note that we inverted the transformation in the beginning because
00472       // we want to transform from normalized to real RTs here and not the
00473       // other way round.
00474       double expected_rt = PeptideRTMap_[transition.getPeptideRef()];
00475       double de_normalized_experimental_rt = trafo.apply(expected_rt);
00476       if (current_rt < de_normalized_experimental_rt - rt_extraction_window || current_rt > de_normalized_experimental_rt + rt_extraction_window)
00477       {
00478         return true;
00479       }
00480       return false;
00481     }
00482 
00483     std::map<OpenMS::String, double> PeptideRTMap_;
00484 
00485   };
00486 
00487 }
00488 
00489 #endif

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