Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:25:01

0001 #ifndef RecoEgamma_EgammaTools_EGExtraInfoModifierFromValueMaps_h
0002 #define RecoEgamma_EgammaTools_EGExtraInfoModifierFromValueMaps_h
0003 
0004 #include "CommonTools/CandAlgos/interface/ModifyObjectValueBase.h"
0005 
0006 #include "FWCore/Utilities/interface/InputTag.h"
0007 #include "FWCore/Utilities/interface/EDGetToken.h"
0008 #include "DataFormats/Common/interface/ValueMap.h"
0009 
0010 #include "DataFormats/PatCandidates/interface/Electron.h"
0011 #include "DataFormats/PatCandidates/interface/Photon.h"
0012 
0013 #include <unordered_map>
0014 
0015 namespace {
0016   const edm::InputTag empty_tag;
0017 }
0018 
0019 //class: EGExtraInfoModifierFromValueMaps
0020 //
0021 //this is a generalisation of EGExtraInfoModiferFromFloatValueMaps
0022 //orginal author of EGExtraInfoModiferFromFloatValueMaps : L. Gray (FNAL)
0023 //converter to templated version: S. Harper (RAL)
0024 //
0025 //This class allows an data of an arbitrary type in a ValueMap for pat::Electrons or pat::Photons
0026 //to be put in the pat::Electron/Photon as userData, userInt or userFloat
0027 //
0028 //IMPORTANT INFO:
0029 //by default the ValueMap is keyed to the object the pat::Electron/Photon was created from
0030 //if you want to use a ValueMap which is keyed to a different collection (ie perhaps the same
0031 //as the electrons you are aring, you must set "electronSrc" and "photonSrc" inside the ele/pho configs
0032 //so if you are running over slimmedElectrons and want to read a ValueMap keyed to slimmedElectrons
0033 //you need to set "electron_config.electronSrc = cms.InputTag("slimmedElectrons")"
0034 //
0035 //It assumes that the object can be added via pat::PATObject::userData, see pat::PATObject for the
0036 //constraints here
0037 //
0038 //The class has two template arguements:
0039 //  MapType : c++ type of the object stored in the value mape
0040 //  OutputType : c++ type of how you want to store it in the pat::PATObject
0041 //               this exists so you can specialise int and float (and future exceptions) to use
0042 //               pat::PATObject::userInt and pat::PATObject::userFloat
0043 //               The specialisations are done by EGXtraModFromVMObjFiller::addValueToObject
0044 //
0045 // MapType and OutputType do not have to be same (but are by default). This is useful as it allows
0046 // things like bools to and unsigned ints to be converted to ints to be stored as  a userInt
0047 // rather than having to go to the bother of setting up userData hooks for them
0048 
0049 namespace egmodifier {
0050   class EGID {};  //dummy class to be used as a template arguement
0051 }  // namespace egmodifier
0052 
0053 template <typename OutputType>
0054 class EGXtraModFromVMObjFiller {
0055 public:
0056   EGXtraModFromVMObjFiller() = delete;
0057   ~EGXtraModFromVMObjFiller() = delete;
0058 
0059   //will do a UserData add but specialisations exist for float and ints
0060   template <typename ObjType, typename MapType>
0061   static void addValueToObject(ObjType& obj,
0062                                const edm::Ptr<reco::Candidate>& ptr,
0063                                const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>>& vmaps,
0064                                const std::pair<const std::string, edm::EDGetTokenT<edm::ValueMap<MapType>>>& val_map,
0065                                bool overrideExistingValues);
0066 
0067   template <typename ObjType, typename MapType>
0068   static void addValuesToObject(
0069       ObjType& obj,
0070       const edm::Ptr<reco::Candidate>& ptr,
0071       const std::unordered_map<std::string, edm::EDGetTokenT<edm::ValueMap<MapType>>>& vmaps_token,
0072       const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>>& vmaps,
0073       bool overrideExistingValues) {
0074     for (auto itr = vmaps_token.begin(); itr != vmaps_token.end(); ++itr) {
0075       addValueToObject(obj, ptr, vmaps, *itr, overrideExistingValues);
0076     }
0077   }
0078 };
0079 
0080 template <typename MapType, typename OutputType = MapType>
0081 class EGExtraInfoModifierFromValueMaps : public ModifyObjectValueBase {
0082 public:
0083   using ValMapToken = edm::EDGetTokenT<edm::ValueMap<MapType>>;
0084   using ValueMaps = std::unordered_map<std::string, ValMapToken>;
0085   struct electron_config {
0086     edm::EDGetTokenT<edm::View<reco::GsfElectron>> tok_electron_src;
0087     ValueMaps tok_valuemaps;
0088   };
0089 
0090   struct photon_config {
0091     edm::EDGetTokenT<edm::View<reco::Photon>> tok_photon_src;
0092     ValueMaps tok_valuemaps;
0093   };
0094 
0095   EGExtraInfoModifierFromValueMaps(const edm::ParameterSet& conf, edm::ConsumesCollector& cc);
0096 
0097   void setEvent(const edm::Event&) final;
0098 
0099   void modifyObject(pat::Electron&) const final;
0100   void modifyObject(pat::Photon&) const final;
0101 
0102 private:
0103   electron_config e_conf;
0104   photon_config ph_conf;
0105   std::vector<edm::Ptr<reco::GsfElectron>> eles_by_oop;  // indexed by original object ptr
0106   std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>> ele_vmaps;
0107   std::vector<edm::Ptr<reco::Photon>> phos_by_oop;
0108   std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>> pho_vmaps;
0109   mutable unsigned ele_idx,
0110       pho_idx;  // hack here until we figure out why some slimmedPhotons don't have original object ptrs
0111   bool overrideExistingValues_;
0112 };
0113 
0114 template <typename MapType, typename OutputType>
0115 EGExtraInfoModifierFromValueMaps<MapType, OutputType>::EGExtraInfoModifierFromValueMaps(const edm::ParameterSet& conf,
0116                                                                                         edm::ConsumesCollector& cc)
0117     : ModifyObjectValueBase(conf) {
0118   constexpr char electronSrc[] = "electronSrc";
0119   constexpr char photonSrc[] = "photonSrc";
0120   overrideExistingValues_ =
0121       conf.exists("overrideExistingValues") ? conf.getParameter<bool>("overrideExistingValues") : false;
0122   if (conf.exists("electron_config")) {
0123     const edm::ParameterSet& electrons = conf.getParameter<edm::ParameterSet>("electron_config");
0124     if (electrons.exists(electronSrc))
0125       e_conf.tok_electron_src =
0126           cc.consumes<edm::View<reco::GsfElectron>>(electrons.getParameter<edm::InputTag>(electronSrc));
0127 
0128     const std::vector<std::string> parameters = electrons.getParameterNames();
0129     for (const std::string& name : parameters) {
0130       if (std::string(electronSrc) == name)
0131         continue;
0132       if (electrons.existsAs<edm::InputTag>(name)) {
0133         e_conf.tok_valuemaps[name] = cc.consumes<edm::ValueMap<MapType>>(electrons.getParameter<edm::InputTag>(name));
0134       }
0135     }
0136   }
0137   if (conf.exists("photon_config")) {
0138     const edm::ParameterSet& photons = conf.getParameter<edm::ParameterSet>("photon_config");
0139     if (photons.exists(photonSrc))
0140       ph_conf.tok_photon_src = cc.consumes<edm::View<reco::Photon>>(photons.getParameter<edm::InputTag>(photonSrc));
0141     const std::vector<std::string> parameters = photons.getParameterNames();
0142     for (const std::string& name : parameters) {
0143       if (std::string(photonSrc) == name)
0144         continue;
0145       if (photons.existsAs<edm::InputTag>(name)) {
0146         ph_conf.tok_valuemaps[name] = cc.consumes<edm::ValueMap<MapType>>(photons.getParameter<edm::InputTag>(name));
0147       }
0148     }
0149   }
0150   ele_idx = pho_idx = 0;
0151 }
0152 
0153 template <typename MapType, typename OutputType>
0154 void EGExtraInfoModifierFromValueMaps<MapType, OutputType>::setEvent(const edm::Event& evt) {
0155   eles_by_oop.clear();
0156   phos_by_oop.clear();
0157   ele_vmaps.clear();
0158   pho_vmaps.clear();
0159 
0160   ele_idx = pho_idx = 0;
0161 
0162   if (!e_conf.tok_electron_src.isUninitialized()) {
0163     auto eles = evt.getHandle(e_conf.tok_electron_src);
0164 
0165     eles_by_oop.resize(eles->size());
0166     std::copy(eles->ptrs().begin(), eles->ptrs().end(), eles_by_oop.begin());
0167   }
0168 
0169   for (auto const& itr : e_conf.tok_valuemaps) {
0170     ele_vmaps[itr.second.index()] = evt.getHandle(itr.second);
0171   }
0172 
0173   if (!ph_conf.tok_photon_src.isUninitialized()) {
0174     auto phos = evt.getHandle(ph_conf.tok_photon_src);
0175 
0176     phos_by_oop.resize(phos->size());
0177     std::copy(phos->ptrs().begin(), phos->ptrs().end(), phos_by_oop.begin());
0178   }
0179 
0180   for (auto const& itr : ph_conf.tok_valuemaps) {
0181     pho_vmaps[itr.second.index()] = evt.getHandle(itr.second);
0182   }
0183 }
0184 
0185 namespace {
0186   template <typename T, typename U, typename V, typename MapType>
0187   inline void assignValue(const T& ptr, const U& tok, const V& map, MapType& value) {
0188     if (!tok.isUninitialized())
0189       value = map.find(tok.index())->second->get(ptr.id(), ptr.key());
0190   }
0191 }  // namespace
0192 
0193 template <typename MapType, typename OutputType>
0194 void EGExtraInfoModifierFromValueMaps<MapType, OutputType>::modifyObject(pat::Electron& ele) const {
0195   // we encounter two cases here, either we are running AOD -> MINIAOD
0196   // and the value maps are to the reducedEG object, can use original object ptr
0197   // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference
0198   edm::Ptr<reco::Candidate> ptr(ele.originalObjectRef());
0199   if (!e_conf.tok_electron_src.isUninitialized())
0200     ptr = eles_by_oop.at(ele_idx);
0201   //now we go through and modify the objects using the valuemaps we read in
0202   EGXtraModFromVMObjFiller<OutputType>::addValuesToObject(
0203       ele, ptr, e_conf.tok_valuemaps, ele_vmaps, overrideExistingValues_);
0204   ++ele_idx;
0205 }
0206 
0207 template <typename MapType, typename OutputType>
0208 void EGExtraInfoModifierFromValueMaps<MapType, OutputType>::modifyObject(pat::Photon& pho) const {
0209   // we encounter two cases here, either we are running AOD -> MINIAOD
0210   // and the value maps are to the reducedEG object, can use original object ptr
0211   // or we are running MINIAOD->MINIAOD and we need to fetch the pat objects to reference
0212   edm::Ptr<reco::Candidate> ptr(pho.originalObjectRef());
0213   if (!ph_conf.tok_photon_src.isUninitialized())
0214     ptr = phos_by_oop.at(pho_idx);
0215   //now we go through and modify the objects using the valuemaps we read in
0216   EGXtraModFromVMObjFiller<OutputType>::addValuesToObject(
0217       pho, ptr, ph_conf.tok_valuemaps, pho_vmaps, overrideExistingValues_);
0218 
0219   ++pho_idx;
0220 }
0221 
0222 template <typename OutputType>
0223 template <typename ObjType, typename MapType>
0224 void EGXtraModFromVMObjFiller<OutputType>::addValueToObject(
0225     ObjType& obj,
0226     const edm::Ptr<reco::Candidate>& ptr,
0227     const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>>& vmaps,
0228     const std::pair<const std::string, edm::EDGetTokenT<edm::ValueMap<MapType>>>& val_map,
0229     bool overrideExistingValues) {
0230   MapType value{};
0231   assignValue(ptr, val_map.second, vmaps, value);
0232   if (overrideExistingValues || !obj.hasUserData(val_map.first)) {
0233     obj.addUserData(val_map.first, value, true);
0234   } else {
0235     throw cms::Exception("ValueNameAlreadyExists")
0236         << "Trying to add new UserData = " << val_map.first
0237         << " failed because it already exists and you didnt specify to override it (set in the config "
0238            "overrideExistingValues=cms.bool(True) )";
0239   }
0240 }
0241 
0242 template <>
0243 template <typename ObjType, typename MapType>
0244 void EGXtraModFromVMObjFiller<float>::addValueToObject(
0245     ObjType& obj,
0246     const edm::Ptr<reco::Candidate>& ptr,
0247     const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>>& vmaps,
0248     const std::pair<const std::string, edm::EDGetTokenT<edm::ValueMap<MapType>>>& val_map,
0249     bool overrideExistingValues) {
0250   float value(0.0);
0251   assignValue(ptr, val_map.second, vmaps, value);
0252   if (overrideExistingValues || !obj.hasUserFloat(val_map.first)) {
0253     obj.addUserFloat(val_map.first, value, true);
0254   } else {
0255     throw cms::Exception("ValueNameAlreadyExists")
0256         << "Trying to add new UserFloat = " << val_map.first
0257         << " failed because it already exists and you didnt specify to override it (set in the config "
0258            "overrideExistingValues=cms.bool(True) )";
0259   }
0260 }
0261 
0262 template <>
0263 template <typename ObjType, typename MapType>
0264 void EGXtraModFromVMObjFiller<int>::addValueToObject(
0265     ObjType& obj,
0266     const edm::Ptr<reco::Candidate>& ptr,
0267     const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<MapType>>>& vmaps,
0268     const std::pair<const std::string, edm::EDGetTokenT<edm::ValueMap<MapType>>>& val_map,
0269     bool overrideExistingValues) {
0270   int value(0);
0271   assignValue(ptr, val_map.second, vmaps, value);
0272   if (overrideExistingValues || !obj.hasUserInt(val_map.first)) {
0273     obj.addUserInt(val_map.first, value, true);
0274   } else {
0275     throw cms::Exception("ValueNameAlreadyExists")
0276         << "Trying to add new UserInt = " << val_map.first
0277         << " failed because it already exists and you didnt specify to override it (set in the config "
0278            "overrideExistingValues=cms.bool(True) )";
0279   }
0280 }
0281 
0282 template <>
0283 template <>
0284 inline void EGXtraModFromVMObjFiller<egmodifier::EGID>::addValuesToObject(
0285     pat::Electron& obj,
0286     const edm::Ptr<reco::Candidate>& ptr,
0287     const std::unordered_map<std::string, edm::EDGetTokenT<edm::ValueMap<float>>>& vmaps_token,
0288     const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<float>>>& vmaps,
0289     bool overrideExistingValues) {
0290   std::vector<std::pair<std::string, float>> ids;
0291   for (auto itr = vmaps_token.begin(); itr != vmaps_token.end(); ++itr) {
0292     float idVal(0);
0293     assignValue(ptr, itr->second, vmaps, idVal);
0294     ids.push_back({itr->first, idVal});
0295   }
0296   std::sort(ids.begin(), ids.end(), [](auto& lhs, auto& rhs) { return lhs.first < rhs.first; });
0297   obj.setElectronIDs(ids);
0298 }
0299 
0300 template <>
0301 template <>
0302 inline void EGXtraModFromVMObjFiller<egmodifier::EGID>::addValuesToObject(
0303     pat::Photon& obj,
0304     const edm::Ptr<reco::Candidate>& ptr,
0305     const std::unordered_map<std::string, edm::EDGetTokenT<edm::ValueMap<float>>>& vmaps_token,
0306     const std::unordered_map<unsigned, edm::Handle<edm::ValueMap<float>>>& vmaps,
0307     bool overrideExistingValues) {
0308   //we do a float->bool conversion here to make things easier to be consistent with electrons
0309   std::vector<std::pair<std::string, bool>> ids;
0310   for (auto itr = vmaps_token.begin(); itr != vmaps_token.end(); ++itr) {
0311     float idVal(0);
0312     assignValue(ptr, itr->second, vmaps, idVal);
0313     ids.push_back({itr->first, idVal});
0314   }
0315   std::sort(ids.begin(), ids.end(), [](auto& lhs, auto& rhs) { return lhs.first < rhs.first; });
0316   obj.setPhotonIDs(ids);
0317 }
0318 
0319 #endif