Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-03-09 23:30:28

0001 #include <oneapi/tbb/concurrent_unordered_map.h>
0002 #include <boost/algorithm/string.hpp>
0003 
0004 #include "DataFormats/Common/interface/TriggerResults.h"
0005 #include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"
0006 #include "DataFormats/Math/interface/libminifloat.h"
0007 #include "DataFormats/Provenance/interface/ProcessConfiguration.h"
0008 #include "DataFormats/Provenance/interface/ProcessHistory.h"
0009 #include "FWCore/Common/interface/TriggerNames.h"
0010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0011 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0012 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0013 
0014 using namespace pat;
0015 
0016 // Const data members' definitions
0017 
0018 const char TriggerObjectStandAlone::wildcard_;
0019 
0020 // Constructors and Destructor
0021 
0022 // Default constructor
0023 TriggerObjectStandAlone::TriggerObjectStandAlone() : TriggerObject() {
0024   filterLabels_.clear();
0025   filterLabelIndices_.clear();
0026   pathNames_.clear();
0027   pathLastFilterAccepted_.clear();
0028   pathL3FilterAccepted_.clear();
0029 }
0030 
0031 // Constructor from pat::TriggerObject
0032 TriggerObjectStandAlone::TriggerObjectStandAlone(const TriggerObject &trigObj) : TriggerObject(trigObj) {
0033   filterLabels_.clear();
0034   filterLabelIndices_.clear();
0035   pathNames_.clear();
0036   pathLastFilterAccepted_.clear();
0037   pathL3FilterAccepted_.clear();
0038 }
0039 
0040 // Constructor from trigger::TriggerObject
0041 TriggerObjectStandAlone::TriggerObjectStandAlone(const trigger::TriggerObject &trigObj) : TriggerObject(trigObj) {
0042   filterLabels_.clear();
0043   filterLabelIndices_.clear();
0044   pathNames_.clear();
0045   pathLastFilterAccepted_.clear();
0046   pathL3FilterAccepted_.clear();
0047 }
0048 
0049 // Constructor from reco::Candidate
0050 TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::LeafCandidate &leafCand) : TriggerObject(leafCand) {
0051   filterLabels_.clear();
0052   filterLabelIndices_.clear();
0053   pathNames_.clear();
0054   pathLastFilterAccepted_.clear();
0055   pathL3FilterAccepted_.clear();
0056 }
0057 
0058 // Constructors from Lorentz-vectors and (optional) PDG ID
0059 TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::Particle::LorentzVector &vec, int id)
0060     : TriggerObject(vec, id) {
0061   filterLabels_.clear();
0062   filterLabelIndices_.clear();
0063   pathNames_.clear();
0064   pathLastFilterAccepted_.clear();
0065   pathL3FilterAccepted_.clear();
0066 }
0067 TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::Particle::PolarLorentzVector &vec, int id)
0068     : TriggerObject(vec, id) {
0069   filterLabels_.clear();
0070   filterLabelIndices_.clear();
0071   pathNames_.clear();
0072   pathLastFilterAccepted_.clear();
0073   pathL3FilterAccepted_.clear();
0074 }
0075 
0076 // Private methods
0077 
0078 // Checks a string vector for occurence of a certain string, incl. wild-card mechanism
0079 bool TriggerObjectStandAlone::hasAnyName(const std::string &name, const std::vector<std::string> &nameVec) const {
0080   // Special cases first
0081   // Always false for empty vector to check
0082   if (nameVec.empty())
0083     return false;
0084   // Always true for general wild-card(s)
0085   if (name.find_first_not_of(wildcard_) == std::string::npos)
0086     return true;
0087   // Split name to evaluate in parts, seperated by wild-cards
0088   std::vector<std::string> namePartsVec;
0089   boost::split(namePartsVec, name, boost::is_any_of(std::string(1, wildcard_)), boost::token_compress_on);
0090   // Iterate over vector of names to search
0091   for (std::vector<std::string>::const_iterator iVec = nameVec.begin(); iVec != nameVec.end(); ++iVec) {
0092     // Not failed yet
0093     bool failed(false);
0094     // Start searching at the first character
0095     size_type index(0);
0096     // Iterate over evaluation name parts
0097     for (std::vector<std::string>::const_iterator iName = namePartsVec.begin(); iName != namePartsVec.end(); ++iName) {
0098       // Empty parts due to
0099       // - wild-card at beginning/end or
0100       // - multiple wild-cards (should be supressed by 'boost::token_compress_on')
0101       if (iName->length() == 0)
0102         continue;
0103       // Search from current index and
0104       // set index to found occurence
0105       index = iVec->find(*iName, index);
0106       // Failed and exit loop, if
0107       // - part not found
0108       // - part at beginning not found there
0109       if (index == std::string::npos || (iName == namePartsVec.begin() && index > 0)) {
0110         failed = true;
0111         break;
0112       }
0113       // Increase index by length of found part
0114       index += iName->length();
0115     }
0116     // Failed, if end of name not reached
0117     if (index < iVec->length() && namePartsVec.back().length() != 0)
0118       failed = true;
0119     // Match found!
0120     if (!failed)
0121       return true;
0122   }
0123   // No match found!
0124   return false;
0125 }
0126 
0127 // Adds a new HLT path or L1 algorithm name
0128 void TriggerObjectStandAlone::addPathOrAlgorithm(const std::string &name,
0129                                                  bool pathLastFilterAccepted,
0130                                                  bool pathL3FilterAccepted) {
0131   checkIfPathsAreUnpacked();
0132 
0133   // Check, if path is already assigned
0134   if (!hasPathOrAlgorithm(name, false, false)) {
0135     // The path itself
0136     pathNames_.push_back(name);
0137     // The corresponding usage of the trigger objects
0138     pathLastFilterAccepted_.push_back(pathLastFilterAccepted);
0139     pathL3FilterAccepted_.push_back(pathL3FilterAccepted);
0140     // Enable status updates
0141   } else if (pathLastFilterAccepted || pathL3FilterAccepted) {
0142     // Search for path
0143     unsigned index(0);
0144     while (index < pathNames_.size()) {
0145       if (pathNames_.at(index) == name)
0146         break;
0147       ++index;
0148     }
0149     // Status update
0150     if (index < pathNames_.size()) {
0151       pathLastFilterAccepted_.at(index) = pathLastFilterAccepted_.at(index) || pathLastFilterAccepted;
0152       pathL3FilterAccepted_.at(index) = pathL3FilterAccepted_.at(index) || pathL3FilterAccepted;
0153     }
0154   }
0155 }
0156 
0157 // Gets all HLT path or L1 algorithm names
0158 std::vector<std::string> TriggerObjectStandAlone::pathsOrAlgorithms(bool pathLastFilterAccepted,
0159                                                                     bool pathL3FilterAccepted) const {
0160   checkIfPathsAreUnpacked();
0161 
0162   // Deal with older PAT-tuples, where trigger object usage is not available
0163   if (!hasLastFilter())
0164     pathLastFilterAccepted = false;
0165   if (!hasL3Filter())
0166     pathL3FilterAccepted = false;
0167   // All path names, if usage not restricted (not required or not available)
0168   if (!pathLastFilterAccepted && !pathL3FilterAccepted)
0169     return pathNames_;
0170   // Temp vector of path names
0171   std::vector<std::string> paths;
0172   // Loop over usage vector and fill corresponding paths into temp vector
0173   for (unsigned iPath = 0; iPath < pathNames_.size(); ++iPath) {
0174     if ((!pathLastFilterAccepted || pathLastFilterAccepted_.at(iPath)) &&
0175         (!pathL3FilterAccepted || pathL3FilterAccepted_.at(iPath)))
0176       paths.push_back(pathNames_.at(iPath));  // order matters in order to protect from empty vectors in old data
0177   }
0178   // Return temp vector
0179   return paths;
0180 }
0181 
0182 // Checks, if a certain HLT filter label or L1 condition name is assigned
0183 bool TriggerObjectStandAlone::hasFilterOrCondition(const std::string &name) const {
0184   checkIfFiltersAreUnpacked();
0185 
0186   // Move to wild-card parser, if needed
0187   if (name.find(wildcard_) != std::string::npos)
0188     return hasAnyName(name, filterLabels_);
0189   // Return, if filter label is assigned
0190   return (std::find(filterLabels_.begin(), filterLabels_.end(), name) != filterLabels_.end());
0191 }
0192 
0193 // Checks, if a certain path name is assigned
0194 bool TriggerObjectStandAlone::hasPathOrAlgorithm(const std::string &name,
0195                                                  bool pathLastFilterAccepted,
0196                                                  bool pathL3FilterAccepted) const {
0197   checkIfPathsAreUnpacked();
0198 
0199   // Move to wild-card parser, if needed
0200   if (name.find(wildcard_) != std::string::npos)
0201     return hasAnyName(name, pathsOrAlgorithms(pathLastFilterAccepted, pathL3FilterAccepted));
0202   // Deal with older PAT-tuples, where trigger object usage is not available
0203   if (!hasLastFilter())
0204     pathLastFilterAccepted = false;
0205   if (!hasL3Filter())
0206     pathL3FilterAccepted = false;
0207   // Check, if path name is assigned at all
0208   std::vector<std::string>::const_iterator match(std::find(pathNames_.begin(), pathNames_.end(), name));
0209   // False, if path name not assigned
0210   if (match == pathNames_.end())
0211     return false;
0212   if (!pathLastFilterAccepted && !pathL3FilterAccepted)
0213     return true;
0214   bool foundLastFilter(pathLastFilterAccepted ? pathLastFilterAccepted_.at(match - pathNames_.begin()) : true);
0215   bool foundL3Filter(pathL3FilterAccepted ? pathL3FilterAccepted_.at(match - pathNames_.begin()) : true);
0216   // Return for assigned path name, if trigger object usage meets requirement
0217   return (foundLastFilter && foundL3Filter);
0218 }
0219 
0220 // Methods
0221 
0222 // Gets the pat::TriggerObject (parent class)
0223 TriggerObject TriggerObjectStandAlone::triggerObject() {
0224   // Create a TriggerObjects
0225   TriggerObject theObj(p4(), pdgId());
0226   // Set its collection and trigger objects types (no c'tor for that)
0227   theObj.setCollection(collection());
0228   for (size_t i = 0; i < triggerObjectTypes().size(); ++i)
0229     theObj.addTriggerObjectType(triggerObjectTypes().at(i));
0230   // Return TriggerObject
0231   return theObj;
0232 }
0233 
0234 // Checks, if a certain label of original collection is assigned (method overrides)
0235 bool TriggerObjectStandAlone::hasCollection(const std::string &collName) const {
0236   // Move to wild-card parser, if needed only
0237   if (collName.find(wildcard_) != std::string::npos) {
0238     // True, if collection name is simply fine
0239     if (hasAnyName(collName, std::vector<std::string>(1, collection())))
0240       return true;
0241     // Check, if collection name possibly fits in an edm::InputTag approach
0242     const edm::InputTag collectionTag(collection());
0243     const edm::InputTag collTag(collName);
0244     // If evaluated collection tag contains a process name, it must have been found already by identity check
0245     if (collTag.process().empty()) {
0246       // Check instance ...
0247       if ((collTag.instance().empty() && collectionTag.instance().empty()) ||
0248           hasAnyName(collTag.instance(), std::vector<std::string>(1, collectionTag.instance()))) {
0249         // ... and label
0250         return hasAnyName(collTag.label(), std::vector<std::string>(1, collectionTag.label()));
0251       }
0252     }
0253     return false;
0254   }
0255   // Use parent class's method otherwise
0256   return TriggerObject::hasCollection(collName);
0257 }
0258 
0259 bool TriggerObjectStandAlone::checkIfPathsAreUnpacked(bool throwIfPacked) const {
0260   bool unpacked = (!pathNames_.empty() || pathIndices_.empty());
0261   if (!unpacked && throwIfPacked)
0262     throw cms::Exception("RuntimeError",
0263                          "This TriggerObjectStandAlone object has packed trigger path names. Before accessing path "
0264                          "names you must call unpackPathNames with an edm::TriggerNames object. You can get the latter "
0265                          "from the edm::Event or fwlite::Event and the TriggerResults\n");
0266   return unpacked;
0267 }
0268 bool TriggerObjectStandAlone::checkIfFiltersAreUnpacked(bool throwIfPacked) const {
0269   bool unpacked = filterLabelIndices_.empty();
0270   if (!unpacked && throwIfPacked)
0271     throw cms::Exception("RuntimeError",
0272                          "This TriggerObjectStandAlone object has packed trigger filter labels. Before accessing path "
0273                          "names you must call unpackFilterLabels with an edm::EventBase object. Both the edm::Event or "
0274                          "fwlite::Event are derived from edm::EventBase and can be passed\n");
0275   return unpacked;
0276 }
0277 
0278 void TriggerObjectStandAlone::packPathNames(const edm::TriggerNames &names) {
0279   if (!pathIndices_.empty()) {
0280     if (!pathNames_.empty()) {
0281       throw cms::Exception("RuntimeError", "Error, trying to pack a partially packed TriggerObjectStandAlone");
0282     } else {
0283       return;
0284     }
0285   }
0286   bool ok = true;
0287   unsigned int n = pathNames_.size(), end = names.size();
0288   std::vector<uint16_t> indices(n);
0289   for (unsigned int i = 0; i < n; ++i) {
0290     uint16_t id = names.triggerIndex(pathNames_[i]);
0291     if (id >= end) {
0292       static std::atomic<int> _warn(0);
0293       if (++_warn < 5)
0294         edm::LogWarning("TriggerObjectStandAlone::packPathNames()")
0295             << "Warning: can't resolve '" << pathNames_[i] << "' to a path index" << std::endl;
0296       ok = false;
0297       break;
0298     } else {
0299       indices[i] = id;
0300     }
0301   }
0302   if (ok) {
0303     pathIndices_.swap(indices);
0304     pathNames_.clear();
0305   }
0306 }
0307 
0308 void TriggerObjectStandAlone::unpackPathNames(const edm::TriggerNames &names) {
0309   if (!pathNames_.empty()) {
0310     if (!pathIndices_.empty()) {
0311       throw cms::Exception("RuntimeError", "Error, trying to unpack a partially unpacked TriggerObjectStandAlone");
0312     } else {
0313       return;
0314     }
0315   }
0316   unsigned int n = pathIndices_.size(), end = names.size();
0317   std::vector<std::string> paths(n);
0318   for (unsigned int i = 0; i < n; ++i) {
0319     if (pathIndices_[i] >= end)
0320       throw cms::Exception("RuntimeError", "Error, path index out of bounds");
0321     paths[i] = names.triggerName(pathIndices_[i]);
0322   }
0323   pathIndices_.clear();
0324   pathNames_.swap(paths);
0325 }
0326 
0327 void TriggerObjectStandAlone::packFilterLabels(const std::vector<std::string> &names) {
0328   if (!filterLabelIndices_.empty()) {
0329     throw cms::Exception("RuntimeError",
0330                          "Error, trying to pack filter labels for an already packed TriggerObjectStandAlone");
0331   }
0332   std::vector<std::string> unmatched;
0333   std::vector<uint16_t> indices;
0334   indices.reserve(filterLabels_.size());
0335 
0336   auto nStart = names.begin(), nEnd = names.end();
0337   for (unsigned int i = 0, n = filterLabels_.size(); i < n; ++i) {
0338     auto match = std::lower_bound(nStart, nEnd, filterLabels_[i]);
0339     if (match != nEnd && *match == filterLabels_[i]) {
0340       indices.push_back(match - nStart);
0341     } else {
0342       static std::atomic<int> _warn(0);
0343       if (++_warn < 5)
0344         edm::LogWarning("TriggerObjectStandAlone::packFilterLabels()")
0345             << "Warning: can't resolve '" << filterLabels_[i] << "' to a label index. idx: " << i << std::endl;
0346       unmatched.push_back(std::move(filterLabels_[i]));
0347     }
0348   }
0349   std::sort(indices.begin(), indices.end());  // try reduce enthropy
0350   filterLabelIndices_.swap(indices);
0351   filterLabels_.swap(unmatched);
0352 }
0353 
0354 void TriggerObjectStandAlone::unpackNamesAndLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
0355   unpackPathNames(event.triggerNames(res));
0356   unpackFilterLabels(event, res);
0357 }
0358 
0359 void TriggerObjectStandAlone::unpackFilterLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
0360   unpackFilterLabels(*allLabels(psetId_, event, res));
0361 }
0362 
0363 void TriggerObjectStandAlone::unpackFilterLabels(const std::vector<std::string> &labels) {
0364   if (filterLabelIndices_.empty())
0365     return;
0366 
0367   std::vector<std::string> mylabels(filterLabels_);
0368   for (unsigned int i = 0, n = filterLabelIndices_.size(), m = labels.size(); i < n; ++i) {
0369     if (filterLabelIndices_[i] >= m)
0370       throw cms::Exception("RuntimeError", "Error, filter label index out of bounds");
0371     mylabels.push_back(labels[filterLabelIndices_[i]]);
0372   }
0373   filterLabelIndices_.clear();
0374   filterLabels_.swap(mylabels);
0375 }
0376 void TriggerObjectStandAlone::packFilterLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
0377   packFilterLabels(*allLabels(psetId_, event, res));
0378 }
0379 
0380 void TriggerObjectStandAlone::packP4() {
0381   setP4(reco::Particle::PolarLorentzVector(MiniFloatConverter::reduceMantissaToNbitsRounding<14>(pt()),
0382                                            MiniFloatConverter::reduceMantissaToNbitsRounding<11>(eta()),
0383                                            MiniFloatConverter::reduceMantissaToNbits<11>(phi()),
0384                                            MiniFloatConverter::reduceMantissaToNbitsRounding<8>(mass())));
0385 }
0386 
0387 namespace {
0388   struct key_hash {
0389     std::size_t operator()(edm::ParameterSetID const &iKey) const { return iKey.smallHash(); }
0390   };
0391   typedef tbb::concurrent_unordered_map<edm::ParameterSetID, std::vector<std::string>, key_hash> AllLabelsMap;
0392   CMS_THREAD_SAFE AllLabelsMap allLabelsMap;
0393 }  // namespace
0394 
0395 std::vector<std::string> const *TriggerObjectStandAlone::allLabels(edm::ParameterSetID const &psetid,
0396                                                                    const edm::EventBase &event,
0397                                                                    const edm::TriggerResults &res) const {
0398   // If TriggerNames was already created and cached here in the map,
0399   // then look it up and return that one
0400   AllLabelsMap::const_iterator iter = allLabelsMap.find(psetid);
0401   if (iter != allLabelsMap.end()) {
0402     return &iter->second;
0403   }
0404 
0405   const auto &triggerNames = event.triggerNames(res);
0406   edm::ParameterSet const *pset = nullptr;
0407   //getting the ParameterSet from the event ensures that the registry is filled
0408   if (nullptr != (pset = event.parameterSet(psetid))) {
0409     using namespace std;
0410     using namespace edm;
0411     using namespace trigger;
0412 
0413     const unsigned int n(triggerNames.size());
0414     std::set<std::string> saveTags;
0415     for (unsigned int i = 0; i != n; ++i) {
0416       if (pset->existsAs<vector<string>>(triggerNames.triggerName(i), true)) {
0417         auto const &modules = pset->getParameter<vector<string>>(triggerNames.triggerName(i));
0418         for (auto const &module : modules) {
0419           auto const moduleStrip = module.front() != '-' and module.front() != '!' ? module : module.substr(1);
0420           if (pset->exists(moduleStrip)) {
0421             const auto &modulePSet = pset->getParameterSet(moduleStrip);
0422             if (modulePSet.existsAs<bool>("saveTags", true) and modulePSet.getParameter<bool>("saveTags")) {
0423               saveTags.insert(moduleStrip);
0424             }
0425           }
0426         }
0427       }
0428     }
0429     std::vector<std::string> allModules(saveTags.begin(), saveTags.end());
0430     std::pair<AllLabelsMap::iterator, bool> ret =
0431         allLabelsMap.insert(std::pair<edm::ParameterSetID, std::vector<std::string>>(psetid, allModules));
0432     return &(ret.first->second);
0433   }
0434   return nullptr;
0435 }