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

IDMapper.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: Chris Bielow $
00032 // $Authors: Marc Sturm, Hendrik Weisser $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_ANALYSIS_ID_IDMAPPER_H
00036 #define OPENMS_ANALYSIS_ID_IDMAPPER_H
00037 
00038 #include <OpenMS/KERNEL/MSExperiment.h>
00039 #include <OpenMS/KERNEL/FeatureMap.h>
00040 #include <OpenMS/KERNEL/ConsensusMap.h>
00041 #include <OpenMS/CONCEPT/LogStream.h>
00042 
00043 #include <algorithm>
00044 #include <limits>
00045 
00046 namespace OpenMS
00047 {
00062   class OPENMS_DLLAPI IDMapper :
00063     public DefaultParamHandler
00064   {
00065 public:
00066     enum Measure {MEASURE_PPM = 0, MEASURE_DA};
00067 
00069     IDMapper();
00070 
00072     IDMapper(const IDMapper & cp);
00073 
00075     IDMapper & operator=(const IDMapper & rhs);
00076 
00089     template <typename PeakType>
00090     void annotate(MSExperiment<PeakType> & map, const std::vector<PeptideIdentification> & ids, const std::vector<ProteinIdentification> & protein_ids)
00091     {
00092       checkHits_(ids);
00093 
00094       //append protein identifications
00095       map.getProteinIdentifications().insert(map.getProteinIdentifications().end(), protein_ids.begin(), protein_ids.end());
00096 
00097       //store mapping of scan RT to index
00098       std::multimap<DoubleReal, Size> experiment_precursors;
00099       for (Size i = 0; i < map.size(); i++)
00100       {
00101         experiment_precursors.insert(std::make_pair(map[i].getRT(), i));
00102       }
00103 
00104       //store mapping of identification RT to index
00105       std::multimap<DoubleReal, Size> identifications_precursors;
00106       for (Size i = 0; i < ids.size(); i++)
00107       {
00108         identifications_precursors.insert(std::make_pair(ids[i].getMetaValue("RT"), i));
00109       }
00110 
00111       //calculate the actual mapping
00112       std::multimap<DoubleReal, Size>::iterator experiment_iterator = experiment_precursors.begin();
00113       std::multimap<DoubleReal, Size>::iterator identifications_iterator = identifications_precursors.begin();
00114       Size matches(0);
00115       while (experiment_iterator != experiment_precursors.end() && identifications_iterator != identifications_precursors.end())
00116       {
00117         while (identifications_iterator != identifications_precursors.end())
00118         {
00119           // testing whether the retention times are within the precision threshold
00120           if (fabs(experiment_iterator->first - identifications_iterator->first) < rt_tolerance_)
00121           {
00122             // testing whether the m/z fits
00123             if (!map[experiment_iterator->second].getPrecursors().empty())
00124             {
00125               if (fabs((DoubleReal)(ids[identifications_iterator->second].getMetaValue("MZ")) - map[experiment_iterator->second].getPrecursors()[0].getMZ()) < mz_tolerance_)
00126               {
00127                 if (!(ids[identifications_iterator->second].empty()))
00128                 {
00129                   map[experiment_iterator->second].getPeptideIdentifications().push_back(ids[identifications_iterator->second]);
00130                   ++matches;
00131                 }
00132               }
00133             }
00134           }
00135           ++identifications_iterator;
00136         }
00137         identifications_iterator = identifications_precursors.begin();
00138         ++experiment_iterator;
00139       }
00140 
00141       // some statistics output
00142       LOG_INFO << "Unassigned peptides: " << ids.size() - matches << "\n"
00143                << "Peptides assigned to a precursor: " << matches << std::endl;
00144 
00145     }
00146 
00164     template <typename FeatureType>
00165     void annotate(FeatureMap<FeatureType> & map, const std::vector<PeptideIdentification> & ids, const std::vector<ProteinIdentification> & protein_ids, bool use_centroid_rt = false, bool use_centroid_mz = false)
00166     {
00167       // std::cout << "Starting annotation..." << std::endl;
00168       checkHits_(ids);
00169 
00170       // append protein identifications
00171       map.getProteinIdentifications().insert(map.getProteinIdentifications().end(), protein_ids.begin(), protein_ids.end());
00172 
00173       // check if all features have at least one convex hull
00174       // if not, use the centroid and the given tolerances
00175       if (!(use_centroid_rt && use_centroid_mz))
00176       {
00177         for (typename FeatureMap<FeatureType>::Iterator f_it = map.begin(); f_it != map.end(); ++f_it)
00178         {
00179           if (f_it->getConvexHulls().empty())
00180           {
00181             use_centroid_rt = true;
00182             use_centroid_mz = true;
00183             LOG_WARN << "IDMapper warning: at least one feature has no convex hull - using centroid coordinates for matching" << std::endl;
00184             break;
00185           }
00186         }
00187       }
00188 
00189       bool use_avg_mass = false;           // use avg. peptide masses for matching?
00190       if (use_centroid_mz && (param_.getValue("mz_reference") == "peptide"))
00191       {
00192         // if possible, check which m/z value is reported for features,
00193         // so the appropriate peptide mass can be used for matching
00194         use_avg_mass = checkMassType_(map.getDataProcessing());
00195       }
00196 
00197       // calculate feature bounding boxes only once:
00198       std::vector<DBoundingBox<2> > boxes;
00199       DoubleReal min_rt = std::numeric_limits<DoubleReal>::max(),
00200                  max_rt = -std::numeric_limits<DoubleReal>::max();
00201       // std::cout << "Precomputing bounding boxes..." << std::endl;
00202       boxes.reserve(map.size());
00203       for (typename FeatureMap<FeatureType>::Iterator f_it = map.begin();
00204            f_it != map.end(); ++f_it)
00205       {
00206         DBoundingBox<2> box;
00207         if (!(use_centroid_rt && use_centroid_mz))
00208         {
00209           box = f_it->getConvexHull().getBoundingBox();
00210         }
00211         if (use_centroid_rt)
00212         {
00213           box.setMinX(f_it->getRT());
00214           box.setMaxX(f_it->getRT());
00215         }
00216         if (use_centroid_mz)
00217         {
00218           box.setMinY(f_it->getMZ());
00219           box.setMaxY(f_it->getMZ());
00220         }
00221         increaseBoundingBox_(box);
00222         boxes.push_back(box);
00223 
00224         min_rt = std::min(min_rt, box.minPosition().getX());
00225         max_rt = std::max(max_rt, box.maxPosition().getX());
00226       }
00227 
00228       // hash bounding boxes of features by RT:
00229       // RT range is partitioned into slices (bins) of 1 second; every feature
00230       // that overlaps a certain slice is hashed into the corresponding bin
00231       std::vector<std::vector<SignedSize> > hash_table;
00232       // make sure the RT hash table has indices >= 0 and doesn't waste space
00233       // in the beginning:
00234       SignedSize offset(0);
00235 
00236       if (map.size() > 0)
00237       {
00238         // std::cout << "Setting up hash table..." << std::endl;
00239         offset = SignedSize(floor(min_rt));
00240         // this only works if features were found
00241         hash_table.resize(SignedSize(floor(max_rt)) - offset + 1);
00242         for (Size index = 0; index < boxes.size(); ++index)
00243         {
00244           const DBoundingBox<2> & box = boxes[index];
00245           for (SignedSize i = SignedSize(floor(box.minPosition().getX()));
00246                i <= SignedSize(floor(box.maxPosition().getX())); ++i)
00247           {
00248             hash_table[i - offset].push_back(index);
00249           }
00250         }
00251       }
00252       else
00253       {
00254         LOG_WARN << "IDMapper received an empty FeatureMap! All peptides are mapped as 'unassigned'!" << std::endl;
00255       }
00256 
00257       // for statistics:
00258       Size matches_none = 0, matches_single = 0, matches_multi = 0;
00259 
00260       // std::cout << "Finding matches..." << std::endl;
00261       // iterate over peptide IDs:
00262       for (std::vector<PeptideIdentification>::const_iterator id_it =
00263              ids.begin(); id_it != ids.end(); ++id_it)
00264       {
00265         // std::cout << "Peptide ID: " << id_it - ids.begin() << std::endl;
00266 
00267         if (id_it->getHits().empty()) continue;
00268 
00269         DoubleList mz_values;
00270         DoubleReal rt_value;
00271         IntList charges;
00272         getIDDetails_(*id_it, rt_value, mz_values, charges, use_avg_mass);
00273 
00274         if ((rt_value < min_rt) || (rt_value > max_rt))             // RT out of bounds
00275         {
00276           map.getUnassignedPeptideIdentifications().push_back(*id_it);
00277           ++matches_none;
00278           continue;
00279         }
00280 
00281         // iterate over candidate features:
00282         Size index = SignedSize(floor(rt_value)) - offset;
00283         Size matching_features = 0;
00284         for (std::vector<SignedSize>::iterator hash_it =
00285                hash_table[index].begin(); hash_it != hash_table[index].end();
00286              ++hash_it)
00287         {
00288           Feature & feat = map[*hash_it];
00289 
00290           // need to check the charge state?
00291           bool check_charge = !ignore_charge_;
00292           if (check_charge && (mz_values.size() == 1))               // check now
00293           {
00294             if (!charges.contains(feat.getCharge())) continue;
00295             check_charge = false;                 // don't need to check later
00296           }
00297 
00298           // iterate over m/z values (only one if "mz_ref." is "precursor"):
00299           Size index = 0;
00300           for (DoubleList::iterator mz_it = mz_values.begin();
00301                mz_it != mz_values.end(); ++mz_it, ++index)
00302           {
00303             if (check_charge && (charges[index] != feat.getCharge()))
00304             {
00305               continue;                   // charge states need to match
00306             }
00307 
00308             DPosition<2> id_pos(rt_value, *mz_it);
00309             if (boxes[*hash_it].encloses(id_pos))                 // potential match
00310             {
00311               if (use_centroid_mz)
00312               {
00313                 // only one m/z value to check, which was alredy incorporated
00314                 // into the overall bounding box -> success!
00315                 feat.getPeptideIdentifications().push_back(*id_it);
00316                 ++matching_features;
00317                 break;                     // "mz_it" loop
00318               }
00319               // else: check all the mass traces
00320               bool found_match = false;
00321               for (std::vector<ConvexHull2D>::iterator ch_it =
00322                      feat.getConvexHulls().begin(); ch_it !=
00323                    feat.getConvexHulls().end(); ++ch_it)
00324               {
00325                 DBoundingBox<2> box = ch_it->getBoundingBox();
00326                 if (use_centroid_rt)
00327                 {
00328                   box.setMinX(feat.getRT());
00329                   box.setMaxX(feat.getRT());
00330                 }
00331                 increaseBoundingBox_(box);
00332                 if (box.encloses(id_pos))                     // success!
00333                 {
00334                   feat.getPeptideIdentifications().push_back(*id_it);
00335                   ++matching_features;
00336                   found_match = true;
00337                   break;                       // "ch_it" loop
00338                 }
00339               }
00340               if (found_match) break;                   // "mz_it" loop
00341             }
00342           }
00343         }
00344         if (matching_features == 0)
00345         {
00346           map.getUnassignedPeptideIdentifications().push_back(*id_it);
00347           ++matches_none;
00348         }
00349         else if (matching_features == 1) ++matches_single;
00350         else ++matches_multi;
00351       }
00352 
00353       // some statistics output
00354       LOG_INFO << "Unassigned peptides: " << matches_none << "\n"
00355                << "Peptides assigned to exactly one feature: "
00356                << matches_single << "\n"
00357                << "Peptides assigned to multiple features: "
00358                << matches_multi << std::endl;
00359 
00360     }
00361 
00375     void annotate(ConsensusMap & map, const std::vector<PeptideIdentification> & ids, const std::vector<ProteinIdentification> & protein_ids, bool measure_from_subelements = false);
00376 
00377 protected:
00378     void updateMembers_();
00379 
00381     DoubleReal rt_tolerance_;
00383     DoubleReal mz_tolerance_;
00385     Measure measure_;
00387     bool ignore_charge_;
00388 
00392     DoubleReal getAbsoluteMZTolerance_(const DoubleReal mz) const;
00393 
00395     bool isMatch_(const DoubleReal rt_distance, const DoubleReal mz_theoretical, const DoubleReal mz_observed) const;
00396 
00398     void checkHits_(const std::vector<PeptideIdentification> & ids) const;
00399 
00403     void getIDDetails_(const PeptideIdentification & id, DoubleReal & rt_pep, DoubleList & mz_values, IntList & charges, bool use_avg_mass = false) const;
00404 
00406     void increaseBoundingBox_(DBoundingBox<2> & box);
00407 
00410     bool checkMassType_(const std::vector<DataProcessing> & processing) const;
00411 
00412   };
00413 
00414 } // namespace OpenMS
00415 
00416 #endif // OPENMS_ANALYSIS_ID_IDMAPPER_H

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