Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:04:55

0001 //
0002 //
0003 
0004 #ifndef DataFormats_PatCandidates_PATObject_h
0005 #define DataFormats_PatCandidates_PATObject_h
0006 
0007 /**
0008   \class    pat::PATObject PATObject.h "DataFormats/PatCandidates/interface/PATObject.h"
0009   \brief    Templated PAT object container
0010 
0011    PATObject is the templated base PAT object that wraps around reco objects.
0012 
0013    Please post comments and questions to the Physics Tools hypernews:
0014    https://hypernews.cern.ch/HyperNews/CMS/get/physTools.html
0015 
0016   \author   Steven Lowette, Giovanni Petrucciani, Frederic Ronga, Volker Adler, Sal Rappoccio
0017 */
0018 
0019 #include "DataFormats/Common/interface/Ptr.h"
0020 #include "DataFormats/Candidate/interface/CandidateFwd.h"
0021 #include "DataFormats/Candidate/interface/Candidate.h"
0022 #include <vector>
0023 #include <string>
0024 #include <iosfwd>
0025 
0026 #include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"
0027 #include "DataFormats/PatCandidates/interface/LookupTableRecord.h"
0028 
0029 #include "DataFormats/HepMCCandidate/interface/GenParticle.h"
0030 
0031 #include "DataFormats/PatCandidates/interface/UserData.h"
0032 #include "DataFormats/Common/interface/OwnVector.h"
0033 
0034 #include "DataFormats/PatCandidates/interface/CandKinResolution.h"
0035 
0036 #include "DataFormats/PatCandidates/interface/throwMissingLabel.h"
0037 
0038 namespace pat {
0039   const reco::CandidatePtrVector &get_empty_cpv();
0040   const std::string &get_empty_str();
0041 
0042   template <class ObjectType>
0043   class PATObject : public ObjectType {
0044   public:
0045     typedef ObjectType base_type;
0046 
0047     /// default constructor
0048     PATObject();
0049     /// constructor from a base object (leaves invalid reference to original object!)
0050     PATObject(const ObjectType &obj);
0051     /// constructor from reference
0052     PATObject(const edm::RefToBase<ObjectType> &ref);
0053     /// constructor from reference
0054     PATObject(const edm::Ptr<ObjectType> &ref);
0055     /// destructor
0056     ~PATObject() override {}
0057     // returns a clone                                  // NO: ObjectType can be an abstract type like reco::Candidate
0058     // virtual PATObject<ObjectType> * clone() const ;  //     for which the clone() can't be defined
0059 
0060     /// access to the original object; returns zero for null Ref and throws for unavailable collection
0061     const reco::Candidate *originalObject() const;
0062     /// reference to original object. Returns a null reference if not available
0063     const edm::Ptr<reco::Candidate> &originalObjectRef() const;
0064 
0065     /// access to embedded trigger matches:
0066     /// duplicated functions using 'char*' instead of 'std::string' are needed in order to work properly in CINT command lines;
0067     /// duplicated functions using 'unsigned' instead of 'bool' are needed in order to work properly in the cut string parser;
0068 
0069     /// get all matched trigger objects
0070     const TriggerObjectStandAloneCollection &triggerObjectMatches() const { return triggerObjectMatchesEmbedded_; };
0071     /// get one matched trigger object by index
0072     const TriggerObjectStandAlone *triggerObjectMatch(const size_t idx = 0) const;
0073     /// get all matched trigger objects of a certain type;
0074     /// trigger object types are defined in 'enum trigger::TriggerObjectType' (DataFormats/HLTReco/interface/TriggerTypeDefs.h)
0075     const TriggerObjectStandAloneCollection triggerObjectMatchesByType(
0076         const trigger::TriggerObjectType triggerObjectType) const;
0077     const TriggerObjectStandAloneCollection triggerObjectMatchesByType(const unsigned triggerObjectType) const {
0078       return triggerObjectMatchesByType(trigger::TriggerObjectType(triggerObjectType));
0079     };
0080     // for backward compatibility
0081     const TriggerObjectStandAloneCollection triggerObjectMatchesByFilterID(const unsigned triggerObjectType) const {
0082       return triggerObjectMatchesByType(trigger::TriggerObjectType(triggerObjectType));
0083     };
0084     /// get one matched trigger object of a certain type by index
0085     const TriggerObjectStandAlone *triggerObjectMatchByType(const trigger::TriggerObjectType triggerObjectType,
0086                                                             const size_t idx = 0) const;
0087     const TriggerObjectStandAlone *triggerObjectMatchByType(const unsigned triggerObjectType,
0088                                                             const size_t idx = 0) const {
0089       return triggerObjectMatchByType(trigger::TriggerObjectType(triggerObjectType), idx);
0090     };
0091     // for backward compatibility
0092     const TriggerObjectStandAlone *triggerObjectMatchByFilterID(const unsigned triggerObjectType,
0093                                                                 const size_t idx = 0) const {
0094       return triggerObjectMatchByType(trigger::TriggerObjectType(triggerObjectType), idx);
0095     };
0096     /// get all matched trigger objects from a certain collection
0097     const TriggerObjectStandAloneCollection triggerObjectMatchesByCollection(const std::string &coll) const;
0098     // for RooT command line
0099     const TriggerObjectStandAloneCollection triggerObjectMatchesByCollection(const char *coll) const {
0100       return triggerObjectMatchesByCollection(std::string(coll));
0101     };
0102     /// get one matched trigger object from a certain collection by index
0103     const TriggerObjectStandAlone *triggerObjectMatchByCollection(const std::string &coll, const size_t idx = 0) const;
0104     // for RooT command line
0105     const TriggerObjectStandAlone *triggerObjectMatchByCollection(const char *coll, const size_t idx = 0) const {
0106       return triggerObjectMatchByCollection(std::string(coll), idx);
0107     };
0108     /// get all matched L1 objects used in a succeeding object combination of a certain L1 condition
0109     const TriggerObjectStandAloneCollection triggerObjectMatchesByCondition(const std::string &nameCondition) const;
0110     // for RooT command line
0111     const TriggerObjectStandAloneCollection triggerObjectMatchesByCondition(const char *nameCondition) const {
0112       return triggerObjectMatchesByCondition(std::string(nameCondition));
0113     };
0114     /// get one matched L1 object used in a succeeding object combination of a certain L1 condition by index
0115     const TriggerObjectStandAlone *triggerObjectMatchByCondition(const std::string &nameCondition,
0116                                                                  const size_t idx = 0) const;
0117     // for RooT command line
0118     const TriggerObjectStandAlone *triggerObjectMatchByCondition(const char *nameCondition,
0119                                                                  const size_t idx = 0) const {
0120       return triggerObjectMatchByCondition(std::string(nameCondition), idx);
0121     };
0122     /// get all matched L1 objects used in a succeeding object combination of a condition in a certain L1 (physics) algorithm;
0123     /// if 'algoCondAccepted' is set to 'true' (default), only objects used in succeeding conditions of succeeding algorithms are considered
0124     /// ("firing" objects)
0125     const TriggerObjectStandAloneCollection triggerObjectMatchesByAlgorithm(const std::string &nameAlgorithm,
0126                                                                             const bool algoCondAccepted = true) const;
0127     // for RooT command line
0128     const TriggerObjectStandAloneCollection triggerObjectMatchesByAlgorithm(const char *nameAlgorithm,
0129                                                                             const bool algoCondAccepted = true) const {
0130       return triggerObjectMatchesByAlgorithm(std::string(nameAlgorithm), algoCondAccepted);
0131     };
0132     // for the cut string parser
0133     const TriggerObjectStandAloneCollection triggerObjectMatchesByAlgorithm(const std::string &nameAlgorithm,
0134                                                                             const unsigned algoCondAccepted) const {
0135       return triggerObjectMatchesByAlgorithm(nameAlgorithm, bool(algoCondAccepted));
0136     };
0137     // for RooT command line and the cut string parser
0138     const TriggerObjectStandAloneCollection triggerObjectMatchesByAlgorithm(const char *nameAlgorithm,
0139                                                                             const unsigned algoCondAccepted) const {
0140       return triggerObjectMatchesByAlgorithm(std::string(nameAlgorithm), bool(algoCondAccepted));
0141     };
0142     /// get one matched L1 object used in a succeeding object combination of a condition in a certain L1 (physics) algorithm by index;
0143     /// if 'algoCondAccepted' is set to 'true' (default), only objects used in succeeding conditions of succeeding algorithms are considered
0144     /// ("firing" objects)
0145     const TriggerObjectStandAlone *triggerObjectMatchByAlgorithm(const std::string &nameAlgorithm,
0146                                                                  const bool algoCondAccepted = true,
0147                                                                  const size_t idx = 0) const;
0148     // for RooT command line
0149     const TriggerObjectStandAlone *triggerObjectMatchByAlgorithm(const char *nameAlgorithm,
0150                                                                  const bool algoCondAccepted = true,
0151                                                                  const size_t idx = 0) const {
0152       return triggerObjectMatchByAlgorithm(std::string(nameAlgorithm), algoCondAccepted, idx);
0153     };
0154     // for the cut string parser
0155     const TriggerObjectStandAlone *triggerObjectMatchByAlgorithm(const std::string &nameAlgorithm,
0156                                                                  const unsigned algoCondAccepted,
0157                                                                  const size_t idx = 0) const {
0158       return triggerObjectMatchByAlgorithm(nameAlgorithm, bool(algoCondAccepted), idx);
0159     };
0160     // for RooT command line and the cut string parser
0161     const TriggerObjectStandAlone *triggerObjectMatchByAlgorithm(const char *nameAlgorithm,
0162                                                                  const unsigned algoCondAccepted,
0163                                                                  const size_t idx = 0) const {
0164       return triggerObjectMatchByAlgorithm(std::string(nameAlgorithm), bool(algoCondAccepted), idx);
0165     };
0166     /// get all matched HLT objects used in a certain HLT filter
0167     const TriggerObjectStandAloneCollection triggerObjectMatchesByFilter(const std::string &labelFilter) const;
0168     // for RooT command line
0169     const TriggerObjectStandAloneCollection triggerObjectMatchesByFilter(const char *labelFilter) const {
0170       return triggerObjectMatchesByFilter(std::string(labelFilter));
0171     };
0172     /// get one matched HLT object used in a certain HLT filter by index
0173     const TriggerObjectStandAlone *triggerObjectMatchByFilter(const std::string &labelFilter,
0174                                                               const size_t idx = 0) const;
0175     // for RooT command line
0176     const TriggerObjectStandAlone *triggerObjectMatchByFilter(const char *labelFilter, const size_t idx = 0) const {
0177       return triggerObjectMatchByFilter(std::string(labelFilter), idx);
0178     };
0179     /// get all matched HLT objects used in a certain HLT path;
0180     /// if 'pathLastFilterAccepted' is set to 'true' (default), only objects used in the final filter of a succeeding path are considered
0181     /// ("firing" objects old style only valid for single object triggers);
0182     /// if 'pathL3FilterAccepted' is set to 'true' (default), only objects used in L3 filters (identified by the "saveTags" parameter being 'true')
0183     /// of a succeeding path are considered ("firing" objects old style only valid for single object triggers)
0184     const TriggerObjectStandAloneCollection triggerObjectMatchesByPath(const std::string &namePath,
0185                                                                        const bool pathLastFilterAccepted = false,
0186                                                                        const bool pathL3FilterAccepted = true) const;
0187     // for RooT command line
0188     const TriggerObjectStandAloneCollection triggerObjectMatchesByPath(const char *namePath,
0189                                                                        const bool pathLastFilterAccepted = false,
0190                                                                        const bool pathL3FilterAccepted = true) const {
0191       return triggerObjectMatchesByPath(std::string(namePath), pathLastFilterAccepted, pathL3FilterAccepted);
0192     };
0193     // for the cut string parser
0194     const TriggerObjectStandAloneCollection triggerObjectMatchesByPath(const std::string &namePath,
0195                                                                        const unsigned pathLastFilterAccepted,
0196                                                                        const unsigned pathL3FilterAccepted = 1) const {
0197       return triggerObjectMatchesByPath(namePath, bool(pathLastFilterAccepted), bool(pathL3FilterAccepted));
0198     };
0199     // for RooT command line and the cut string parser
0200     const TriggerObjectStandAloneCollection triggerObjectMatchesByPath(const char *namePath,
0201                                                                        const unsigned pathLastFilterAccepted,
0202                                                                        const unsigned pathL3FilterAccepted = 1) const {
0203       return triggerObjectMatchesByPath(
0204           std::string(namePath), bool(pathLastFilterAccepted), bool(pathL3FilterAccepted));
0205     };
0206     /// get one matched HLT object used in a certain HLT path by index;
0207     /// if 'pathLastFilterAccepted' is set to 'true' (default), only objects used in the final filter of a succeeding path are considered
0208     /// ("firing" objects, old style only valid for single object triggers);
0209     /// if 'pathL3FilterAccepted' is set to 'true' (default), only objects used in L3 filters (identified by the "saveTags" parameter being 'true')
0210     /// of a succeeding path are considered ("firing" objects also valid for x-triggers)
0211     const TriggerObjectStandAlone *triggerObjectMatchByPath(const std::string &namePath,
0212                                                             const bool pathLastFilterAccepted = false,
0213                                                             const bool pathL3FilterAccepted = true,
0214                                                             const size_t idx = 0) const;
0215     // for RooT command line
0216     const TriggerObjectStandAlone *triggerObjectMatchByPath(const char *namePath,
0217                                                             const bool pathLastFilterAccepted = false,
0218                                                             const bool pathL3FilterAccepted = true,
0219                                                             const size_t idx = 0) const {
0220       return triggerObjectMatchByPath(std::string(namePath), pathLastFilterAccepted, pathL3FilterAccepted, idx);
0221     };
0222     // for the cut string parser
0223     const TriggerObjectStandAlone *triggerObjectMatchByPath(const std::string &namePath,
0224                                                             const unsigned pathLastFilterAccepted,
0225                                                             const unsigned pathL3FilterAccepted = 1,
0226                                                             const size_t idx = 0) const {
0227       return triggerObjectMatchByPath(namePath, bool(pathLastFilterAccepted), bool(pathL3FilterAccepted), idx);
0228     };
0229     // for RooT command line and the cut string parser
0230     const TriggerObjectStandAlone *triggerObjectMatchByPath(const char *namePath,
0231                                                             const unsigned pathLastFilterAccepted,
0232                                                             const unsigned pathL3FilterAccepted = 1,
0233                                                             const size_t idx = 0) const {
0234       return triggerObjectMatchByPath(
0235           std::string(namePath), bool(pathLastFilterAccepted), bool(pathL3FilterAccepted), idx);
0236     };
0237     /// add a trigger match
0238     void addTriggerObjectMatch(const TriggerObjectStandAlone &trigObj) {
0239       triggerObjectMatchesEmbedded_.push_back(trigObj);
0240     };
0241     /// unpack path names of matched trigger objects (if they were packed before embedding, which is not normally the case)
0242     void unpackTriggerObjectPathNames(const edm::TriggerNames &names) {
0243       for (std::vector<TriggerObjectStandAlone>::iterator it = triggerObjectMatchesEmbedded_.begin(),
0244                                                           ed = triggerObjectMatchesEmbedded_.end();
0245            it != ed;
0246            ++it)
0247         it->unpackPathNames(names);
0248     }
0249 
0250     /// Returns an efficiency given its name
0251     const pat::LookupTableRecord &efficiency(const std::string &name) const;
0252     /// Returns the efficiencies as <name,value> pairs (by value)
0253     std::vector<std::pair<std::string, pat::LookupTableRecord> > efficiencies() const;
0254     /// Returns the list of the names of the stored efficiencies
0255     const std::vector<std::string> &efficiencyNames() const { return efficiencyNames_; }
0256     /// Returns the list of the values of the stored efficiencies (the ordering is the same as in efficiencyNames())
0257     const std::vector<pat::LookupTableRecord> &efficiencyValues() const { return efficiencyValues_; }
0258     /// Store one efficiency in this item, in addition to the existing ones
0259     /// If an efficiency with the same name exists, the old value is replaced by this one
0260     /// Calling this method many times with names not sorted alphabetically will be slow
0261     void setEfficiency(const std::string &name, const pat::LookupTableRecord &value);
0262 
0263     /// Get generator level particle reference (might be a transient ref if the genParticle was embedded)
0264     /// If you stored multiple GenParticles, you can specify which one you want.
0265     reco::GenParticleRef genParticleRef(size_t idx = 0) const {
0266       if (idx >= genParticlesSize())
0267         return reco::GenParticleRef();
0268       return genParticleEmbedded_.empty() ? genParticleRef_[idx] : reco::GenParticleRef(&genParticleEmbedded_, idx);
0269     }
0270     /// Get a generator level particle reference with a given pdg id and status
0271     /// If there is no MC match with that pdgId and status, it will return a null ref
0272     /// Note: this might be a transient ref if the genParticle was embedded
0273     /// If status == 0, only the pdgId will be checked; likewise, if pdgId == 0, only the status will be checked.
0274     /// When autoCharge is set to true, and a charged reco particle is matched to a charged gen particle,
0275     /// positive pdgId means 'same charge', negative pdgId means 'opposite charge';
0276     /// for example, electron.genParticleById(11,0,true) will get an e^+ matched to e^+ or e^- matched to e^-,
0277     /// while genParticleById(-15,0,true) will get e^+ matched to e^- or vice versa.
0278     /// If a neutral reco particle is matched to a charged gen particle, the sign of the pdgId passed to getParticleById must match that of the gen particle;
0279     /// for example photon.getParticleById(11) will match gamma to e^-, while genParticleById(-11) will match gamma to e^+ (pdgId=-11)
0280     // implementation note: uint8_t instead of bool, because the string parser doesn't allow bool currently
0281     reco::GenParticleRef genParticleById(int pdgId, int status, uint8_t autoCharge = 0) const;
0282 
0283     /// Get generator level particle, as C++ pointer (might be 0 if the ref was null)
0284     /// If you stored multiple GenParticles, you can specify which one you want.
0285     const reco::GenParticle *genParticle(size_t idx = 0) const {
0286       reco::GenParticleRef ref = genParticleRef(idx);
0287       return ref.isNonnull() ? ref.get() : nullptr;
0288     }
0289     /// Number of generator level particles stored as ref or embedded
0290     size_t genParticlesSize() const {
0291       return genParticleEmbedded_.empty() ? genParticleRef_.size() : genParticleEmbedded_.size();
0292     }
0293     /// Return the list of generator level particles.
0294     /// Note that the refs can be transient refs to embedded GenParticles
0295     std::vector<reco::GenParticleRef> genParticleRefs() const;
0296 
0297     /// Set the generator level particle reference
0298     void setGenParticleRef(const reco::GenParticleRef &ref, bool embed = false);
0299     /// Add a generator level particle reference
0300     /// If there is already an embedded particle, this ref will be embedded too
0301     void addGenParticleRef(const reco::GenParticleRef &ref);
0302     /// Set the generator level particle from a particle not in the Event (embedding it, of course)
0303     void setGenParticle(const reco::GenParticle &particle);
0304     /// Embed the generator level particle(s) in this PATObject
0305     /// Note that generator level particles can only be all embedded or all not embedded.
0306     void embedGenParticle();
0307 
0308     /// Returns true if there was at least one overlap for this test label
0309     bool hasOverlaps(const std::string &label) const;
0310     /// Return the list of overlaps for one label (can be empty)
0311     /// The original ordering of items is kept (usually it's by increasing deltaR from this item)
0312     const reco::CandidatePtrVector &overlaps(const std::string &label) const;
0313     /// Returns the labels of the overlap tests that found at least one overlap
0314     const std::vector<std::string> &overlapLabels() const { return overlapLabels_; }
0315     /// Sets the list of overlapping items for one label
0316     /// Note that adding an empty PtrVector has no effect at all
0317     /// Items within the list should already be sorted appropriately (this method won't sort them)
0318     void setOverlaps(const std::string &label, const reco::CandidatePtrVector &overlaps);
0319 
0320     /// Returns user-defined data. Returns NULL if the data is not present, or not of type T.
0321     template <typename T>
0322     const T *userData(const std::string &key) const {
0323       const pat::UserData *data = userDataObject_(key);
0324       return (data != nullptr ? data->template get<T>() : nullptr);
0325     }
0326     /// Check if user data with a specific type is present
0327     bool hasUserData(const std::string &key) const { return (userDataObject_(key) != nullptr); }
0328     /// Get human-readable type of user data object, for debugging
0329     const std::string &userDataObjectType(const std::string &key) const {
0330       const pat::UserData *data = userDataObject_(key);
0331       return (data != nullptr ? data->typeName() : get_empty_str());
0332     };
0333     /// Get list of user data object names
0334     const std::vector<std::string> &userDataNames() const { return userDataLabels_; }
0335 
0336     /// Get the data as a void *, for CINT usage.
0337     /// COMPLETELY UNSUPPORTED, USE ONLY FOR DEBUGGING
0338     const void *userDataBare(const std::string &key) const {
0339       const pat::UserData *data = userDataObject_(key);
0340       return (data != nullptr ? data->bareData() : nullptr);
0341     }
0342 
0343     /// Set user-defined data
0344     /// Needs dictionaries for T and for pat::UserHolder<T>,
0345     /// and it will throw exception if they're missing,
0346     /// unless transientOnly is set to true
0347     template <typename T>
0348     void addUserData(const std::string &label, const T &data, bool transientOnly = false, bool overwrite = false) {
0349       std::unique_ptr<pat::UserData> made(pat::UserData::make<T>(data, transientOnly));
0350       addUserDataObject_(label, std::move(made), overwrite);
0351     }
0352 
0353     /// Set user-defined data. To be used only to fill from ValueMap<Ptr<UserData>>
0354     /// Do not use unless you know what you are doing.
0355     void addUserDataFromPtr(const std::string &label, const edm::Ptr<pat::UserData> &data, bool overwrite = false) {
0356       std::unique_ptr<pat::UserData> cloned(data->clone());
0357       addUserDataObject_(label, std::move(cloned), overwrite);
0358     }
0359 
0360     /// Get user-defined float
0361     /// Note: throws if the key is not found; you can check if the key exists with 'hasUserFloat' method.
0362     float userFloat(const std::string &key) const;
0363     /// return a range of values corresponding to key
0364     std::vector<float> userFloatRange(const std::string &key) const;
0365     /// a CINT-friendly interface
0366     float userFloat(const char *key) const { return userFloat(std::string(key)); }
0367 
0368     /// Set user-defined float
0369     void addUserFloat(const std::string &label, float data, const bool overwrite = false);
0370     /// Get list of user-defined float names
0371     const std::vector<std::string> &userFloatNames() const { return userFloatLabels_; }
0372     /// Return true if there is a user-defined float with a given name
0373     bool hasUserFloat(const std::string &key) const {
0374       auto it = std::lower_bound(userFloatLabels_.cbegin(), userFloatLabels_.cend(), key);
0375       return (it != userFloatLabels_.cend() && *it == key);
0376     }
0377     /// a CINT-friendly interface
0378     bool hasUserFloat(const char *key) const { return hasUserFloat(std::string(key)); }
0379 
0380     /// Get user-defined int
0381     /// Note: throws if the key is not found; you can check if the key exists with 'hasUserInt' method.
0382     int32_t userInt(const std::string &key) const;
0383     /// returns a range of values corresponding to key
0384     std::vector<int> userIntRange(const std::string &key) const;
0385     /// Set user-defined int
0386     void addUserInt(const std::string &label, int32_t data, const bool overwrite = false);
0387     /// Get list of user-defined int names
0388     const std::vector<std::string> &userIntNames() const { return userIntLabels_; }
0389     /// Return true if there is a user-defined int with a given name
0390     bool hasUserInt(const std::string &key) const {
0391       auto it = std::lower_bound(userIntLabels_.cbegin(), userIntLabels_.cend(), key);
0392       return (it != userIntLabels_.cend() && *it == key);
0393     }
0394 
0395     /// Get user-defined candidate ptr
0396     /// Note: it will a null pointer if the key is not found; you can check if the key exists with 'hasUserInt' method.
0397     reco::CandidatePtr userCand(const std::string &key) const;
0398     /// Set user-defined int
0399     void addUserCand(const std::string &label, const reco::CandidatePtr &data, const bool overwrite = false);
0400     /// Get list of user-defined cand names
0401     const std::vector<std::string> &userCandNames() const { return userCandLabels_; }
0402     /// Return true if there is a user-defined int with a given name
0403     bool hasUserCand(const std::string &key) const {
0404       auto it = std::lower_bound(userCandLabels_.cbegin(), userCandLabels_.cend(), key);
0405       return (it != userCandLabels_.cend() && *it == key);
0406     }
0407 
0408     // === New Kinematic Resolutions
0409     /// Return the kinematic resolutions associated to this object, possibly specifying a label for it.
0410     /// If not present, it will throw an exception.
0411     const pat::CandKinResolution &getKinResolution(const std::string &label = "") const;
0412 
0413     /// Check if the kinematic resolutions are stored into this object (possibly specifying a label for them)
0414     bool hasKinResolution(const std::string &label = "") const;
0415 
0416     /// Add a kinematic resolution to this object (possibly with a label)
0417     void setKinResolution(const pat::CandKinResolution &resol, const std::string &label = "");
0418 
0419     /// Resolution on eta, possibly with a label to specify which resolution to use
0420     double resolEta(const std::string &label = "") const { return getKinResolution(label).resolEta(this->p4()); }
0421 
0422     /// Resolution on theta, possibly with a label to specify which resolution to use
0423     double resolTheta(const std::string &label = "") const { return getKinResolution(label).resolTheta(this->p4()); }
0424 
0425     /// Resolution on phi, possibly with a label to specify which resolution to use
0426     double resolPhi(const std::string &label = "") const { return getKinResolution(label).resolPhi(this->p4()); }
0427 
0428     /// Resolution on energy, possibly with a label to specify which resolution to use
0429     double resolE(const std::string &label = "") const { return getKinResolution(label).resolE(this->p4()); }
0430 
0431     /// Resolution on et, possibly with a label to specify which resolution to use
0432     double resolEt(const std::string &label = "") const { return getKinResolution(label).resolEt(this->p4()); }
0433 
0434     /// Resolution on p, possibly with a label to specify which resolution to use
0435     double resolP(const std::string &label = "") const { return getKinResolution(label).resolP(this->p4()); }
0436 
0437     /// Resolution on pt, possibly with a label to specify which resolution to use
0438     double resolPt(const std::string &label = "") const { return getKinResolution(label).resolPt(this->p4()); }
0439 
0440     /// Resolution on 1/p, possibly with a label to specify which resolution to use
0441     double resolPInv(const std::string &label = "") const { return getKinResolution(label).resolPInv(this->p4()); }
0442 
0443     /// Resolution on px, possibly with a label to specify which resolution to use
0444     double resolPx(const std::string &label = "") const { return getKinResolution(label).resolPx(this->p4()); }
0445 
0446     /// Resolution on py, possibly with a label to specify which resolution to use
0447     double resolPy(const std::string &label = "") const { return getKinResolution(label).resolPy(this->p4()); }
0448 
0449     /// Resolution on pz, possibly with a label to specify which resolution to use
0450     double resolPz(const std::string &label = "") const { return getKinResolution(label).resolPz(this->p4()); }
0451 
0452     /// Resolution on mass, possibly with a label to specify which resolution to use
0453     /// Note: this will be zero if a mass-constrained parametrization is used for this object
0454     double resolM(const std::string &label = "") const { return getKinResolution(label).resolM(this->p4()); }
0455 
0456   protected:
0457     // reference back to the original object
0458     edm::Ptr<reco::Candidate> refToOrig_;
0459 
0460     /// vector of trigger matches
0461     TriggerObjectStandAloneCollection triggerObjectMatchesEmbedded_;
0462 
0463     /// vector of the efficiencies (values)
0464     std::vector<pat::LookupTableRecord> efficiencyValues_;
0465     /// vector of the efficiencies (names)
0466     std::vector<std::string> efficiencyNames_;
0467 
0468     /// Reference to a generator level particle
0469     std::vector<reco::GenParticleRef> genParticleRef_;
0470     /// vector to hold an embedded generator level particle
0471     std::vector<reco::GenParticle> genParticleEmbedded_;
0472 
0473     /// Overlapping test labels (only if there are any overlaps)
0474     std::vector<std::string> overlapLabels_;
0475     /// Overlapping items (sorted by distance)
0476     std::vector<reco::CandidatePtrVector> overlapItems_;
0477 
0478     /// User data object
0479     std::vector<std::string> userDataLabels_;
0480     pat::UserDataCollection userDataObjects_;
0481     // User float values
0482     std::vector<std::string> userFloatLabels_;
0483     std::vector<float> userFloats_;
0484     // User int values
0485     std::vector<std::string> userIntLabels_;
0486     std::vector<int32_t> userInts_;
0487     // User candidate matches
0488     std::vector<std::string> userCandLabels_;
0489     std::vector<reco::CandidatePtr> userCands_;
0490 
0491     /// Kinematic resolutions.
0492     std::vector<pat::CandKinResolution> kinResolutions_;
0493     /// Labels for the kinematic resolutions.
0494     /// if (kinResolutions_.size() == kinResolutionLabels_.size()+1), then the first resolution has no label.
0495     std::vector<std::string> kinResolutionLabels_;
0496 
0497     void addUserDataObject_(const std::string &label, std::unique_ptr<pat::UserData> value, bool overwrite = false);
0498 
0499   private:
0500     const pat::UserData *userDataObject_(const std::string &key) const;
0501   };
0502 
0503   template <class ObjectType>
0504   PATObject<ObjectType>::PATObject() {}
0505 
0506   template <class ObjectType>
0507   PATObject<ObjectType>::PATObject(const ObjectType &obj) : ObjectType(obj), refToOrig_() {}
0508 
0509   template <class ObjectType>
0510   PATObject<ObjectType>::PATObject(const edm::RefToBase<ObjectType> &ref)
0511       : ObjectType(*ref),
0512         refToOrig_(ref.id(),
0513                    ref.get(),
0514                    ref.key())  // correct way to convert RefToBase=>Ptr, if ref is guaranteed to be available
0515                                // which happens to be true, otherwise the line before this throws ex. already
0516   {}
0517 
0518   template <class ObjectType>
0519   PATObject<ObjectType>::PATObject(const edm::Ptr<ObjectType> &ref) : ObjectType(*ref), refToOrig_(ref) {}
0520 
0521   template <class ObjectType>
0522   const reco::Candidate *PATObject<ObjectType>::originalObject() const {
0523     if (refToOrig_.isNull()) {
0524       // this object was not produced from a reference, so no link to the
0525       // original object exists -> return a 0-pointer
0526       return nullptr;
0527     } else if (!refToOrig_.isAvailable()) {
0528       throw edm::Exception(edm::errors::ProductNotFound)
0529           << "The original collection from which this PAT object was made is not present any more in the event, hence "
0530              "you cannot access the originating object anymore.";
0531     } else {
0532       return refToOrig_.get();
0533     }
0534   }
0535 
0536   template <class ObjectType>
0537   const edm::Ptr<reco::Candidate> &PATObject<ObjectType>::originalObjectRef() const {
0538     return refToOrig_;
0539   }
0540 
0541   template <class ObjectType>
0542   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatch(const size_t idx) const {
0543     if (idx >= triggerObjectMatches().size())
0544       return nullptr;
0545     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, idx);
0546     return ref.isNonnull() ? ref.get() : nullptr;
0547   }
0548 
0549   template <class ObjectType>
0550   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByType(
0551       const trigger::TriggerObjectType triggerObjectType) const {
0552     TriggerObjectStandAloneCollection matches;
0553     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0554       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasTriggerObjectType(triggerObjectType))
0555         matches.push_back(*(triggerObjectMatch(i)));
0556     }
0557     return matches;
0558   }
0559 
0560   template <class ObjectType>
0561   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByType(
0562       const trigger::TriggerObjectType triggerObjectType, const size_t idx) const {
0563     std::vector<size_t> refs;
0564     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0565       if (triggerObjectMatch(i) != nullptr && triggerObjectMatch(i)->hasTriggerObjectType(triggerObjectType))
0566         refs.push_back(i);
0567     }
0568     if (idx >= refs.size())
0569       return nullptr;
0570     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0571     return ref.isNonnull() ? ref.get() : nullptr;
0572   }
0573 
0574   template <class ObjectType>
0575   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByCollection(
0576       const std::string &coll) const {
0577     TriggerObjectStandAloneCollection matches;
0578     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0579       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasCollection(coll))
0580         matches.push_back(*(triggerObjectMatch(i)));
0581     }
0582     return matches;
0583   }
0584 
0585   template <class ObjectType>
0586   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByCollection(const std::string &coll,
0587                                                                                        const size_t idx) const {
0588     std::vector<size_t> refs;
0589     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0590       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasCollection(coll)) {
0591         refs.push_back(i);
0592       }
0593     }
0594     if (idx >= refs.size())
0595       return nullptr;
0596     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0597     return ref.isNonnull() ? ref.get() : nullptr;
0598   }
0599 
0600   template <class ObjectType>
0601   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByCondition(
0602       const std::string &nameCondition) const {
0603     TriggerObjectStandAloneCollection matches;
0604     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0605       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasConditionName(nameCondition))
0606         matches.push_back(*(triggerObjectMatch(i)));
0607     }
0608     return matches;
0609   }
0610 
0611   template <class ObjectType>
0612   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByCondition(const std::string &nameCondition,
0613                                                                                       const size_t idx) const {
0614     std::vector<size_t> refs;
0615     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0616       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasConditionName(nameCondition))
0617         refs.push_back(i);
0618     }
0619     if (idx >= refs.size())
0620       return nullptr;
0621     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0622     return ref.isNonnull() ? ref.get() : nullptr;
0623   }
0624 
0625   template <class ObjectType>
0626   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByAlgorithm(
0627       const std::string &nameAlgorithm, const bool algoCondAccepted) const {
0628     TriggerObjectStandAloneCollection matches;
0629     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0630       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasAlgorithmName(nameAlgorithm, algoCondAccepted))
0631         matches.push_back(*(triggerObjectMatch(i)));
0632     }
0633     return matches;
0634   }
0635 
0636   template <class ObjectType>
0637   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByAlgorithm(const std::string &nameAlgorithm,
0638                                                                                       const bool algoCondAccepted,
0639                                                                                       const size_t idx) const {
0640     std::vector<size_t> refs;
0641     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0642       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasAlgorithmName(nameAlgorithm, algoCondAccepted))
0643         refs.push_back(i);
0644     }
0645     if (idx >= refs.size())
0646       return nullptr;
0647     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0648     return ref.isNonnull() ? ref.get() : nullptr;
0649   }
0650 
0651   template <class ObjectType>
0652   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByFilter(
0653       const std::string &labelFilter) const {
0654     TriggerObjectStandAloneCollection matches;
0655     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0656       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasFilterLabel(labelFilter))
0657         matches.push_back(*(triggerObjectMatch(i)));
0658     }
0659     return matches;
0660   }
0661 
0662   template <class ObjectType>
0663   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByFilter(const std::string &labelFilter,
0664                                                                                    const size_t idx) const {
0665     std::vector<size_t> refs;
0666     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0667       if (triggerObjectMatch(i) != 0 && triggerObjectMatch(i)->hasFilterLabel(labelFilter))
0668         refs.push_back(i);
0669     }
0670     if (idx >= refs.size())
0671       return nullptr;
0672     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0673     return ref.isNonnull() ? ref.get() : nullptr;
0674   }
0675 
0676   template <class ObjectType>
0677   const TriggerObjectStandAloneCollection PATObject<ObjectType>::triggerObjectMatchesByPath(
0678       const std::string &namePath, const bool pathLastFilterAccepted, const bool pathL3FilterAccepted) const {
0679     TriggerObjectStandAloneCollection matches;
0680     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0681       if (triggerObjectMatch(i) != nullptr &&
0682           triggerObjectMatch(i)->hasPathName(namePath, pathLastFilterAccepted, pathL3FilterAccepted))
0683         matches.push_back(*(triggerObjectMatch(i)));
0684     }
0685     return matches;
0686   }
0687 
0688   template <class ObjectType>
0689   const TriggerObjectStandAlone *PATObject<ObjectType>::triggerObjectMatchByPath(const std::string &namePath,
0690                                                                                  const bool pathLastFilterAccepted,
0691                                                                                  const bool pathL3FilterAccepted,
0692                                                                                  const size_t idx) const {
0693     std::vector<size_t> refs;
0694     for (size_t i = 0; i < triggerObjectMatches().size(); ++i) {
0695       if (triggerObjectMatch(i) != nullptr &&
0696           triggerObjectMatch(i)->hasPathName(namePath, pathLastFilterAccepted, pathL3FilterAccepted))
0697         refs.push_back(i);
0698     }
0699     if (idx >= refs.size())
0700       return nullptr;
0701     TriggerObjectStandAloneRef ref(&triggerObjectMatchesEmbedded_, refs.at(idx));
0702     return ref.isNonnull() ? ref.get() : nullptr;
0703   }
0704 
0705   template <class ObjectType>
0706   const pat::LookupTableRecord &PATObject<ObjectType>::efficiency(const std::string &name) const {
0707     // find the name in the (sorted) list of names
0708     auto it = std::lower_bound(efficiencyNames_.cbegin(), efficiencyNames_.cend(), name);
0709     if ((it == efficiencyNames_.end()) || (*it != name)) {
0710       throw cms::Exception("Invalid Label") << "There is no efficiency with name '" << name << "' in this PAT Object\n";
0711     }
0712     return efficiencyValues_[std::distance(efficiencyNames_.cbegin(), it)];
0713   }
0714 
0715   template <class ObjectType>
0716   std::vector<std::pair<std::string, pat::LookupTableRecord> > PATObject<ObjectType>::efficiencies() const {
0717     std::vector<std::pair<std::string, pat::LookupTableRecord> > ret;
0718     std::vector<std::string>::const_iterator itn = efficiencyNames_.begin(), edn = efficiencyNames_.end();
0719     std::vector<pat::LookupTableRecord>::const_iterator itv = efficiencyValues_.begin();
0720     for (; itn != edn; ++itn, ++itv) {
0721       ret.emplace_back(*itn, *itv);
0722     }
0723     return ret;
0724   }
0725 
0726   template <class ObjectType>
0727   void PATObject<ObjectType>::setEfficiency(const std::string &name, const pat::LookupTableRecord &value) {
0728     // look for the name, or to the place where we can insert it without violating the alphabetic order
0729     auto it = std::lower_bound(efficiencyNames_.begin(), efficiencyNames_.end(), name);
0730     const auto dist = std::distance(efficiencyNames_.begin(), it);
0731     if (it == efficiencyNames_.end()) {  // insert at the end
0732       efficiencyNames_.push_back(name);
0733       efficiencyValues_.push_back(value);
0734     } else if (*it == name) {  // replace existing
0735       efficiencyValues_[dist] = value;
0736     } else {  // insert in the middle :-(
0737       efficiencyNames_.insert(it, name);
0738       efficiencyValues_.insert(efficiencyValues_.begin() + dist, value);
0739     }
0740   }
0741 
0742   template <class ObjectType>
0743   void PATObject<ObjectType>::setGenParticleRef(const reco::GenParticleRef &ref, bool embed) {
0744     genParticleRef_ = std::vector<reco::GenParticleRef>(1, ref);
0745     genParticleEmbedded_.clear();
0746     if (embed)
0747       embedGenParticle();
0748   }
0749 
0750   template <class ObjectType>
0751   void PATObject<ObjectType>::addGenParticleRef(const reco::GenParticleRef &ref) {
0752     if (!genParticleEmbedded_.empty()) {  // we're embedding
0753       if (ref.isNonnull())
0754         genParticleEmbedded_.push_back(*ref);
0755     } else {
0756       genParticleRef_.push_back(ref);
0757     }
0758   }
0759 
0760   template <class ObjectType>
0761   void PATObject<ObjectType>::setGenParticle(const reco::GenParticle &particle) {
0762     genParticleEmbedded_.clear();
0763     genParticleEmbedded_.push_back(particle);
0764     genParticleRef_.clear();
0765   }
0766 
0767   template <class ObjectType>
0768   void PATObject<ObjectType>::embedGenParticle() {
0769     genParticleEmbedded_.clear();
0770     for (std::vector<reco::GenParticleRef>::const_iterator it = genParticleRef_.begin(); it != genParticleRef_.end();
0771          ++it) {
0772       if (it->isNonnull())
0773         genParticleEmbedded_.push_back(**it);
0774     }
0775     genParticleRef_.clear();
0776   }
0777 
0778   template <class ObjectType>
0779   std::vector<reco::GenParticleRef> PATObject<ObjectType>::genParticleRefs() const {
0780     if (genParticleEmbedded_.empty())
0781       return genParticleRef_;
0782     std::vector<reco::GenParticleRef> ret(genParticleEmbedded_.size());
0783     for (size_t i = 0, n = ret.size(); i < n; ++i) {
0784       ret[i] = reco::GenParticleRef(&genParticleEmbedded_, i);
0785     }
0786     return ret;
0787   }
0788 
0789   template <class ObjectType>
0790   reco::GenParticleRef PATObject<ObjectType>::genParticleById(int pdgId, int status, uint8_t autoCharge) const {
0791     // get a vector, avoiding an unneeded copy if there is no embedding
0792     const std::vector<reco::GenParticleRef> &vec = (genParticleEmbedded_.empty() ? genParticleRef_ : genParticleRefs());
0793     for (std::vector<reco::GenParticleRef>::const_iterator ref = vec.begin(), end = vec.end(); ref != end; ++ref) {
0794       if (ref->isNonnull()) {
0795         const reco::GenParticle &g = **ref;
0796         if ((status != 0) && (g.status() != status))
0797           continue;
0798         if (pdgId == 0) {
0799           return *ref;
0800         } else if (!autoCharge) {
0801           if (pdgId == g.pdgId())
0802             return *ref;
0803         } else if (abs(pdgId) == abs(g.pdgId())) {
0804           // I want pdgId > 0 to match "correct charge" (for charged particles)
0805           if (g.charge() == 0)
0806             return *ref;
0807           else if ((this->charge() == 0) && (pdgId == g.pdgId()))
0808             return *ref;
0809           else if (g.charge() * this->charge() * pdgId > 0)
0810             return *ref;
0811         }
0812       }
0813     }
0814     return reco::GenParticleRef();
0815   }
0816 
0817   template <class ObjectType>
0818   bool PATObject<ObjectType>::hasOverlaps(const std::string &label) const {
0819     auto match = std::lower_bound(overlapLabels_.cbegin(), overlapLabels_.cend(), label);
0820     return (match != overlapLabels_.end() && *match == label);
0821   }
0822 
0823   template <class ObjectType>
0824   const reco::CandidatePtrVector &PATObject<ObjectType>::overlaps(const std::string &label) const {
0825     auto match = std::lower_bound(overlapLabels_.cbegin(), overlapLabels_.cend(), label);
0826     if (match == overlapLabels_.cend() || *match != label)
0827       return get_empty_cpv();
0828     return overlapItems_[std::distance(overlapLabels_.begin(), match)];
0829   }
0830 
0831   template <class ObjectType>
0832   void PATObject<ObjectType>::setOverlaps(const std::string &label, const reco::CandidatePtrVector &overlaps) {
0833     auto match = std::lower_bound(overlapLabels_.begin(), overlapLabels_.end(), label);
0834     const auto dist = std::distance(overlapLabels_.begin(), match);
0835     if (match == overlapLabels_.end() || *match != label) {
0836       overlapLabels_.insert(match, label);
0837       overlapItems_.insert(overlapItems_.begin() + dist, overlaps);
0838     } else {
0839       overlapItems_[dist] = overlaps;
0840     }
0841   }
0842 
0843   template <class ObjectType>
0844   const pat::UserData *PATObject<ObjectType>::userDataObject_(const std::string &key) const {
0845     auto it = std::lower_bound(userDataLabels_.cbegin(), userDataLabels_.cend(), key);
0846     if (it != userDataLabels_.cend() && *it == key) {
0847       return &userDataObjects_[std::distance(userDataLabels_.cbegin(), it)];
0848     }
0849     return nullptr;
0850   }
0851 
0852   template <class ObjectType>
0853   void PATObject<ObjectType>::addUserDataObject_(const std::string &label,
0854                                                  std::unique_ptr<pat::UserData> data,
0855                                                  bool overwrite) {
0856     auto it = std::lower_bound(userDataLabels_.begin(), userDataLabels_.end(), label);
0857     const auto dist = std::distance(userDataLabels_.begin(), it);
0858     if (it == userDataLabels_.end() || *it != label) {
0859       userDataLabels_.insert(it, label);
0860       userDataObjects_.insert(userDataObjects_.begin() + dist, std::move(data));
0861     } else if (overwrite) {
0862       userDataObjects_.set(dist, std::move(data));
0863     } else {
0864       //create a range by adding behind the first entry
0865       userDataLabels_.insert(it + 1, label);
0866       userDataObjects_.insert(userDataObjects_.begin() + dist + 1, std::move(data));
0867     }
0868   }
0869 
0870   template <class ObjectType>
0871   float PATObject<ObjectType>::userFloat(const std::string &key) const {
0872     auto it = std::lower_bound(userFloatLabels_.cbegin(), userFloatLabels_.cend(), key);
0873     if (it != userFloatLabels_.cend() && *it == key) {
0874       return userFloats_[std::distance(userFloatLabels_.cbegin(), it)];
0875     }
0876     throwMissingLabel("UserFloat", key, userFloatLabels_);
0877     return std::numeric_limits<float>::quiet_NaN();
0878   }
0879 
0880   template <class ObjectType>
0881   std::vector<float> PATObject<ObjectType>::userFloatRange(const std::string &key) const {
0882     auto range = std::equal_range(userFloatLabels_.cbegin(), userFloatLabels_.cend(), key);
0883     std::vector<float> result;
0884     result.reserve(std::distance(range.first, range.second));
0885     for (auto it = range.first; it != range.second; ++it) {
0886       result.push_back(userFloats_[std::distance(userFloatLabels_.cbegin(), it)]);
0887     }
0888     return result;
0889   }
0890 
0891   template <class ObjectType>
0892   void PATObject<ObjectType>::addUserFloat(const std::string &label, float data, const bool overwrite) {
0893     auto it = std::lower_bound(userFloatLabels_.begin(), userFloatLabels_.end(), label);
0894     const auto dist = std::distance(userFloatLabels_.begin(), it);
0895     if (it == userFloatLabels_.end() || *it != label) {
0896       userFloatLabels_.insert(it, label);
0897       userFloats_.insert(userFloats_.begin() + dist, data);
0898     } else if (overwrite) {
0899       userFloats_[dist] = data;
0900     } else {
0901       //create a range by adding behind the first entry
0902       userFloatLabels_.insert(it + 1, label);
0903       userFloats_.insert(userFloats_.begin() + dist + 1, data);
0904     }
0905   }
0906 
0907   template <class ObjectType>
0908   int PATObject<ObjectType>::userInt(const std::string &key) const {
0909     auto it = std::lower_bound(userIntLabels_.cbegin(), userIntLabels_.cend(), key);
0910     if (it != userIntLabels_.cend() && *it == key) {
0911       return userInts_[std::distance(userIntLabels_.cbegin(), it)];
0912     }
0913     throwMissingLabel("UserInt", key, userIntLabels_);
0914     return std::numeric_limits<int>::max();
0915   }
0916 
0917   template <class ObjectType>
0918   std::vector<int> PATObject<ObjectType>::userIntRange(const std::string &key) const {
0919     auto range = std::equal_range(userIntLabels_.cbegin(), userIntLabels_.cend(), key);
0920     std::vector<int> result;
0921     result.reserve(std::distance(range.first, range.second));
0922     for (auto it = range.first; it != range.second; ++it) {
0923       result.push_back(userInts_[std::distance(userIntLabels_.cbegin(), it)]);
0924     }
0925     return result;
0926   }
0927 
0928   template <class ObjectType>
0929   void PATObject<ObjectType>::addUserInt(const std::string &label, int data, bool overwrite) {
0930     auto it = std::lower_bound(userIntLabels_.begin(), userIntLabels_.end(), label);
0931     const auto dist = std::distance(userIntLabels_.begin(), it);
0932     if (it == userIntLabels_.end() || *it != label) {
0933       userIntLabels_.insert(it, label);
0934       userInts_.insert(userInts_.begin() + dist, data);
0935     } else if (overwrite) {
0936       userInts_[dist] = data;
0937     } else {
0938       //create a range by adding behind the first entry
0939       userIntLabels_.insert(it + 1, label);
0940       userInts_.insert(userInts_.begin() + dist + 1, data);
0941     }
0942   }
0943 
0944   template <class ObjectType>
0945   reco::CandidatePtr PATObject<ObjectType>::userCand(const std::string &key) const {
0946     auto it = std::lower_bound(userCandLabels_.cbegin(), userCandLabels_.cend(), key);
0947     if (it != userCandLabels_.cend()) {
0948       return userCands_[std::distance(userCandLabels_.begin(), it)];
0949     }
0950     return reco::CandidatePtr();
0951   }
0952 
0953   template <class ObjectType>
0954   void PATObject<ObjectType>::addUserCand(const std::string &label,
0955                                           const reco::CandidatePtr &data,
0956                                           const bool overwrite) {
0957     auto it = std::lower_bound(userCandLabels_.begin(), userCandLabels_.end(), label);
0958     const auto dist = std::distance(userCandLabels_.begin(), it);
0959     if (it == userCandLabels_.end() || *it != label) {
0960       userCandLabels_.insert(it, label);
0961       userCands_.insert(userCands_.begin() + dist, data);
0962     } else if (overwrite) {
0963       userCands_[dist] = data;
0964     } else {
0965       userCandLabels_.insert(it + 1, label);
0966       userCands_.insert(userCands_.begin() + dist + 1, data);
0967     }
0968   }
0969 
0970   template <class ObjectType>
0971   const pat::CandKinResolution &PATObject<ObjectType>::getKinResolution(const std::string &label) const {
0972     const bool has_unlabelled = (kinResolutionLabels_.size() + 1 == kinResolutions_.size());
0973     if (label.empty()) {
0974       if (has_unlabelled) {
0975         return kinResolutions_[0];
0976       } else {
0977         throw cms::Exception("Missing Data", "This object does not contain an un-labelled kinematic resolution");
0978       }
0979     } else {
0980       auto match = std::lower_bound(kinResolutionLabels_.cbegin(), kinResolutionLabels_.cend(), label);
0981       const auto dist = std::distance(kinResolutionLabels_.begin(), match);
0982       const size_t increment = (has_unlabelled ? 1 : 0);
0983       if (match == kinResolutionLabels_.end() || *match != label) {
0984         cms::Exception ex("Missing Data");
0985         ex << "This object does not contain a kinematic resolution with name '" << label << "'.\n";
0986         ex << "The known labels are: ";
0987         for (std::vector<std::string>::const_iterator it = kinResolutionLabels_.cbegin();
0988              it != kinResolutionLabels_.cend();
0989              ++it) {
0990           ex << "'" << *it << "' ";
0991         }
0992         ex << "\n";
0993         throw ex;
0994       } else {
0995         return kinResolutions_[dist + increment];
0996       }
0997     }
0998   }
0999 
1000   template <class ObjectType>
1001   bool PATObject<ObjectType>::hasKinResolution(const std::string &label) const {
1002     if (label.empty()) {
1003       return (kinResolutionLabels_.size() + 1 == kinResolutions_.size());
1004     } else {
1005       auto match = std::lower_bound(kinResolutionLabels_.cbegin(), kinResolutionLabels_.cend(), label);
1006       return (match != kinResolutionLabels_.cend() && *match == label);
1007     }
1008   }
1009 
1010   template <class ObjectType>
1011   void PATObject<ObjectType>::setKinResolution(const pat::CandKinResolution &resol, const std::string &label) {
1012     const bool has_unlabelled = (kinResolutionLabels_.size() + 1 == kinResolutions_.size());
1013     if (label.empty()) {
1014       if (has_unlabelled) {
1015         // There is already an un-labelled object. Replace it
1016         kinResolutions_[0] = resol;
1017       } else {
1018         // Insert. Note that the un-labelled is always the first, so we need to insert before begin()
1019         // (for an empty vector, this should not cost more than push_back)
1020         kinResolutions_.insert(kinResolutions_.begin(), resol);
1021       }
1022     } else {
1023       auto match = std::lower_bound(kinResolutionLabels_.begin(), kinResolutionLabels_.end(), label);
1024       const auto dist = std::distance(kinResolutionLabels_.begin(), match);
1025       const size_t increment = (has_unlabelled ? 1 : 0);
1026       if (match != kinResolutionLabels_.end() && *match == label) {
1027         // Existing object: replace
1028         kinResolutions_[dist + increment] = resol;
1029       } else {
1030         kinResolutionLabels_.insert(match, label);
1031         kinResolutions_.insert(kinResolutions_.begin() + dist + increment, resol);
1032       }
1033     }
1034   }
1035 
1036 }  // namespace pat
1037 
1038 #endif