Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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