Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:24:10

0001 #ifndef PhysicsTools_SelectorUtils_VersionedSelector_h
0002 #define PhysicsTools_SelectorUtils_VersionedSelector_h
0003 
0004 /**
0005   \class    VersionedSelector VersionedSelector.h "PhysicsTools/SelectorUtils/interface/VersionedSelector.h"
0006   \brief    cut-flow versioning info in the event provenance
0007 
0008   class template to implement versioning for IDs that's available in the 
0009   event provenance or available by hash-code in the event record
0010 
0011   \author Lindsey Gray
0012 */
0013 
0014 #if (!defined(__CINT__) && !defined(__MAKECINT__) && !defined(__REFLEX__) && !defined(__CLING__))
0015 
0016 #define REGULAR_CPLUSPLUS 1
0017 #define CINT_GUARD(CODE) CODE
0018 #include "FWCore/Framework/interface/ConsumesCollector.h"
0019 #include <memory>
0020 #define SHARED_PTR(T) std::shared_ptr<T>
0021 
0022 #else
0023 
0024 #define CINT_GUARD(CODE)
0025 
0026 #define SHARED_PTR(T) std::shared_ptr<T>
0027 
0028 #endif
0029 
0030 #include "PhysicsTools/SelectorUtils/interface/Selector.h"
0031 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0032 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0033 #include "PhysicsTools/SelectorUtils/interface/CandidateCut.h"
0034 #include "PhysicsTools/SelectorUtils/interface/CutApplicatorBase.h"
0035 #include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h"
0036 // because we need to be able to validate the ID
0037 #include "Utilities/OpenSSL/interface/openssl_init.h"
0038 
0039 namespace candf = candidate_functions;
0040 
0041 namespace vid {
0042   class CutFlowResult;
0043 }
0044 
0045 template <class T>
0046 class VersionedSelector : public Selector<T> {
0047 public:
0048   VersionedSelector() : Selector<T>(), initialized_(false) {}
0049 
0050   VersionedSelector(const edm::ParameterSet& conf) : Selector<T>(), initialized_(false) {
0051     validateParamsAreTracked(conf);
0052 
0053     name_ = conf.getParameter<std::string>("idName");
0054 
0055     // now setup the md5 and cute accessor functions
0056     cms::openssl_init();
0057     EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
0058     const EVP_MD* md = EVP_get_digestbyname("MD5");
0059     unsigned int md_len = 0;
0060     std::string tracked(conf.trackedPart().dump());
0061 
0062     EVP_DigestInit_ex(mdctx, md, nullptr);
0063     EVP_DigestUpdate(mdctx, tracked.c_str(), tracked.size());
0064     EVP_DigestFinal_ex(mdctx, id_md5_, &md_len);
0065     EVP_MD_CTX_free(mdctx);
0066     id_md5_[md_len] = 0;
0067     char tmp[EVP_MAX_MD_SIZE * 2 + 1];
0068     for (unsigned int i = 0; i < md_len; i++) {
0069       ::sprintf(&tmp[i * 2], "%02x", id_md5_[i]);
0070     }
0071     tmp[md_len * 2] = 0;
0072     md5_string_ = tmp;
0073     initialize(conf);
0074     this->retInternal_ = this->getBitTemplate();
0075   }
0076 
0077   bool operator()(const T& ref, pat::strbitset& ret) CINT_GUARD(final) {
0078     howfar_ = 0;
0079     bitmap_ = 0;
0080     values_.clear();
0081     bool failed = false;
0082     if (!initialized_) {
0083       throw cms::Exception("CutNotInitialized") << "VersionedGsfElectronSelector not initialized!" << std::endl;
0084     }
0085     for (unsigned i = 0; i < cuts_.size(); ++i) {
0086       reco::CandidatePtr temp(ref);
0087       const bool result = (*cuts_[i])(temp);
0088       values_.push_back(cuts_[i]->value(temp));
0089       if (result || this->ignoreCut(cut_indices_[i])) {
0090         this->passCut(ret, cut_indices_[i]);
0091         bitmap_ |= 1 << i;
0092         if (!failed)
0093           ++howfar_;
0094       } else {
0095         failed = true;
0096       }
0097     }
0098     this->setIgnored(ret);
0099     return (bool)ret;
0100   }
0101 
0102   bool operator()(const T& ref, edm::EventBase const& e, pat::strbitset& ret) CINT_GUARD(final) {
0103     // setup isolation needs
0104     for (size_t i = 0, cutssize = cuts_.size(); i < cutssize; ++i) {
0105       if (needs_event_content_[i]) {
0106         CutApplicatorWithEventContentBase* needsEvent = static_cast<CutApplicatorWithEventContentBase*>(cuts_[i].get());
0107         needsEvent->getEventContent(e);
0108       }
0109     }
0110     return this->operator()(ref, ret);
0111   }
0112 
0113   //repeat the other operator() we left out here
0114   //in the base class here so they are exposed to ROOT
0115 
0116   /* VID BY VALUE */
0117   bool operator()(typename T::value_type const& t) {
0118     const T temp(&t, 0);  // assuming T is edm::Ptr
0119     return this->operator()(temp);
0120   }
0121 
0122   bool operator()(typename T::value_type const& t, edm::EventBase const& e) {
0123     const T temp(&t, 0);
0124     return this->operator()(temp, e);
0125   }
0126 
0127   bool operator()(T const& t) CINT_GUARD(final) {
0128     this->retInternal_.set(false);
0129     this->operator()(t, this->retInternal_);
0130     this->setIgnored(this->retInternal_);
0131     return (bool)this->retInternal_;
0132   }
0133 
0134   bool operator()(T const& t, edm::EventBase const& e) CINT_GUARD(final) {
0135     this->retInternal_.set(false);
0136     this->operator()(t, e, this->retInternal_);
0137     this->setIgnored(this->retInternal_);
0138     return (bool)this->retInternal_;
0139   }
0140 
0141   const unsigned char* md55Raw() const { return id_md5_; }
0142   bool operator==(const VersionedSelector& other) const {
0143     constexpr unsigned length = EVP_MAX_MD_SIZE;
0144     return (0 == memcmp(id_md5_, other.id_md5_, length * sizeof(unsigned char)));
0145   }
0146   const std::string& md5String() const { return md5_string_; }
0147 
0148   const std::string& name() const { return name_; }
0149 
0150   const unsigned howFarInCutFlow() const { return howfar_; }
0151 
0152   const unsigned bitMap() const { return bitmap_; }
0153 
0154   const size_t cutFlowSize() const { return cuts_.size(); }
0155 
0156   vid::CutFlowResult cutFlowResult() const;
0157 
0158   void initialize(const edm::ParameterSet&);
0159 
0160   CINT_GUARD(void setConsumes(edm::ConsumesCollector));
0161 
0162 private:
0163   //here we check that the parameters of the VID cuts are tracked
0164   //we allow exactly one parameter to be untracked "isPOGApproved"
0165   //as if its tracked, its a pain for the md5Sums
0166   //due to the mechanics of PSets, it was demined easier just to
0167   //create a new config which doesnt have an untracked isPOGApproved
0168   //if isPOGApproved is tracked (if we decide to do that in the future), it keeps it
0169   //see https://github.com/cms-sw/cmssw/issues/19799 for the discussion
0170   static void validateParamsAreTracked(const edm::ParameterSet& conf) {
0171     edm::ParameterSet trackedPart = conf.trackedPart();
0172     edm::ParameterSet confWithoutIsPOGApproved;
0173     for (auto& paraName : conf.getParameterNames()) {
0174       if (paraName != "isPOGApproved")
0175         confWithoutIsPOGApproved.copyFrom(conf, paraName);
0176       else if (conf.existsAs<bool>(paraName, true))
0177         confWithoutIsPOGApproved.copyFrom(conf, paraName);  //adding isPOGApproved if its a tracked bool
0178     }
0179     std::string tracked(conf.trackedPart().dump()), untracked(confWithoutIsPOGApproved.dump());
0180     if (tracked != untracked) {
0181       throw cms::Exception("InvalidConfiguration") << "VersionedSelector does not allow untracked parameters"
0182                                                    << " in the cutflow ParameterSet!";
0183     }
0184   }
0185 
0186 protected:
0187   bool initialized_;
0188   std::vector<SHARED_PTR(candf::CandidateCut)> cuts_;
0189   std::vector<bool> needs_event_content_;
0190   std::vector<typename Selector<T>::index_type> cut_indices_;
0191   unsigned howfar_, bitmap_;
0192   std::vector<double> values_;
0193 
0194 private:
0195   unsigned char id_md5_[EVP_MAX_MD_SIZE];
0196   std::string md5_string_, name_;
0197 };
0198 
0199 template <class T>
0200 void VersionedSelector<T>::initialize(const edm::ParameterSet& conf) {
0201   if (initialized_) {
0202     edm::LogWarning("VersionedPatElectronSelector") << "ID was already initialized!";
0203     return;
0204   }
0205   const std::vector<edm::ParameterSet>& cutflow = conf.getParameterSetVector("cutFlow");
0206   if (cutflow.empty()) {
0207     throw cms::Exception("InvalidCutFlow") << "You have supplied a null/empty cutflow to VersionedIDSelector,"
0208                                            << " please add content to the cuflow and try again.";
0209   }
0210 
0211   // this lets us keep track of cuts without knowing what they are :D
0212   std::vector<edm::ParameterSet>::const_iterator cbegin(cutflow.begin()), cend(cutflow.end());
0213   std::vector<edm::ParameterSet>::const_iterator icut = cbegin;
0214   std::map<std::string, unsigned> cut_counter;
0215   std::vector<std::string> ignored_cuts;
0216   for (; icut != cend; ++icut) {
0217     std::stringstream realname;
0218     const std::string& name = icut->getParameter<std::string>("cutName");
0219     if (!cut_counter.count(name))
0220       cut_counter[name] = 0;
0221     realname << name << "_" << cut_counter[name];
0222     const bool needsContent = icut->getParameter<bool>("needsAdditionalProducts");
0223     const bool ignored = icut->getParameter<bool>("isIgnored");
0224     CINT_GUARD(cuts_.emplace_back(CutApplicatorFactory::get()->create(name, *icut)));
0225     needs_event_content_.push_back(needsContent);
0226     const std::string therealname = realname.str();
0227     this->push_back(therealname);
0228     this->set(therealname);
0229     if (ignored)
0230       ignored_cuts.push_back(therealname);
0231     cut_counter[name]++;
0232   }
0233   this->setIgnoredCuts(ignored_cuts);
0234 
0235   //have to loop again to set cut indices after all are filled
0236   icut = cbegin;
0237   cut_counter.clear();
0238   for (; icut != cend; ++icut) {
0239     std::stringstream realname;
0240     const std::string& name = cuts_[std::distance(cbegin, icut)]->name();
0241     if (!cut_counter.count(name))
0242       cut_counter[name] = 0;
0243     realname << name << "_" << cut_counter[name];
0244     cut_indices_.push_back(typename Selector<T>::index_type(&(this->bits_), realname.str()));
0245     cut_counter[name]++;
0246   }
0247 
0248   initialized_ = true;
0249 }
0250 
0251 #ifdef REGULAR_CPLUSPLUS
0252 #include "DataFormats/PatCandidates/interface/VIDCutFlowResult.h"
0253 template <class T>
0254 vid::CutFlowResult VersionedSelector<T>::cutFlowResult() const {
0255   std::map<std::string, unsigned> names_to_index;
0256   std::map<std::string, unsigned> cut_counter;
0257   for (unsigned idx = 0; idx < cuts_.size(); ++idx) {
0258     const std::string& name = cuts_[idx]->name();
0259     if (!cut_counter.count(name))
0260       cut_counter[name] = 0;
0261     std::stringstream realname;
0262     realname << name << "_" << cut_counter[name];
0263     names_to_index.emplace(realname.str(), idx);
0264     cut_counter[name]++;
0265   }
0266   return vid::CutFlowResult(name_, md5_string_, names_to_index, values_, bitmap_);
0267 }
0268 
0269 #include "PhysicsTools/SelectorUtils/interface/CutApplicatorWithEventContentBase.h"
0270 template <class T>
0271 void VersionedSelector<T>::setConsumes(edm::ConsumesCollector cc) {
0272   for (size_t i = 0, cutssize = cuts_.size(); i < cutssize; ++i) {
0273     if (needs_event_content_[i]) {
0274       CutApplicatorWithEventContentBase* needsEvent = dynamic_cast<CutApplicatorWithEventContentBase*>(cuts_[i].get());
0275       if (nullptr != needsEvent) {
0276         needsEvent->setConsumes(cc);
0277       } else {
0278         throw cms::Exception("InvalidCutConfiguration") << "Cut: " << ((CutApplicatorBase*)cuts_[i].get())->name()
0279                                                         << " configured to consume event products but does not "
0280                                                         << " inherit from CutApplicatorWithEventContenBase "
0281                                                         << " please correct either your python or C++!";
0282       }
0283     }
0284   }
0285 }
0286 #endif
0287 
0288 #endif