Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:23:40

0001 #include "TriggerOutputFields.h"
0002 
0003 #include "RNTupleFieldPtr.h"
0004 
0005 #include "DataFormats/Common/interface/TriggerResults.h"
0006 #include "FWCore/Common/interface/TriggerNames.h"
0007 #include "FWCore/Framework/interface/EventForOutput.h"
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0010 #include "FWCore/ParameterSet/interface/Registry.h"
0011 #include "FWCore/Utilities/interface/EDGetToken.h"
0012 #include "FWCore/Utilities/interface/Exception.h"
0013 
0014 #include <algorithm>
0015 
0016 namespace {
0017 
0018   void trimVersionSuffix(std::string& trigger_name) {
0019     // HLT and L1 triggers have version suffixes we trim before filling the RNTuple
0020     if (trigger_name.compare(0, 3, "HLT") != 0 && trigger_name.compare(0, 2, "L1") != 0) {
0021       return;
0022     }
0023     auto vfound = trigger_name.rfind("_v");
0024     if (vfound == std::string::npos) {
0025       return;
0026     }
0027     trigger_name.replace(vfound, trigger_name.size() - vfound, "");
0028   }
0029 
0030   bool isNanoaodTrigger(const std::string& name) {
0031     return name.compare(0, 3, "HLT") == 0 || name.compare(0, 4, "Flag") == 0 || name.compare(0, 2, "L1") == 0;
0032   }
0033 
0034 }  // anonymous namespace
0035 
0036 TriggerFieldPtr::TriggerFieldPtr(
0037     std::string name, int index, std::string fieldName, std::string fieldDesc, RNTupleModel& model)
0038     : m_triggerName(name), m_triggerIndex(index) {
0039   m_field = RNTupleFieldPtr<bool>(fieldName, fieldDesc, model);
0040 }
0041 
0042 void TriggerFieldPtr::fill(const edm::TriggerResults& triggers) {
0043   if (m_triggerIndex == -1) {
0044     m_field.fill(false);
0045   }
0046   m_field.fill(triggers.accept(m_triggerIndex));
0047 }
0048 
0049 std::vector<std::string> TriggerOutputFields::getTriggerNames(const edm::TriggerResults& triggerResults) {
0050   // Trigger names are either stored in the TriggerResults object (e.g. L1) or
0051   // need to be looked up in the registry (e.g. HLT)
0052   auto triggerNames = triggerResults.getTriggerNames();
0053   if (!triggerNames.empty()) {
0054     return triggerNames;
0055   }
0056   edm::pset::Registry* psetRegistry = edm::pset::Registry::instance();
0057   edm::ParameterSet const* pset = psetRegistry->getMapped(triggerResults.parameterSetID());
0058   if (nullptr == pset || !pset->existsAs<std::vector<std::string>>("@trigger_paths", true)) {
0059     return {};
0060   }
0061   edm::TriggerNames names(*pset);
0062   if (names.size() != triggerResults.size()) {
0063     throw cms::Exception("LogicError") << "TriggerOutputFields::getTriggerNames "
0064                                           "Encountered vector\n of trigger names and a TriggerResults object with\n"
0065                                           "different sizes.  This should be impossible.\n"
0066                                           "Please send information to reproduce this problem to\nthe edm developers.\n";
0067   }
0068   return names.triggerNames();
0069 }
0070 
0071 void TriggerOutputFields::createFields(const edm::EventForOutput& event, RNTupleModel& model) {
0072   m_lastRun = event.id().run();
0073   edm::Handle<edm::TriggerResults> handle;
0074   event.getByToken(m_token, handle);
0075   const edm::TriggerResults& triggerResults = *handle;
0076   std::vector<std::string> triggerNames(TriggerOutputFields::getTriggerNames(triggerResults));
0077   m_triggerFields.reserve(triggerNames.size());
0078   for (std::size_t i = 0; i < triggerNames.size(); i++) {
0079     auto& name = triggerNames[i];
0080     if (!isNanoaodTrigger(name)) {
0081       continue;
0082     }
0083     trimVersionSuffix(name);
0084     std::string modelName = name;
0085     makeUniqueFieldName(model, modelName);
0086     std::string desc = std::string("Trigger/flag bit (process: ") + m_processName + ")";
0087     m_triggerFields.emplace_back(TriggerFieldPtr(name, i, modelName, desc, model));
0088   }
0089 }
0090 
0091 // Worst case O(n^2) to adjust the triggers
0092 void TriggerOutputFields::updateTriggerFields(const edm::TriggerResults& triggers) {
0093   std::vector<std::string> newNames(TriggerOutputFields::getTriggerNames(triggers));
0094   // adjust existing trigger indices
0095   for (auto& t : m_triggerFields) {
0096     t.setIndex(-1);
0097     for (std::size_t j = 0; j < newNames.size(); j++) {
0098       auto& name = newNames[j];
0099       if (!isNanoaodTrigger(name)) {
0100         continue;
0101       }
0102       trimVersionSuffix(name);
0103       if (name == t.getTriggerName()) {
0104         t.setIndex(j);
0105       }
0106     }
0107   }
0108   // find new triggers
0109   for (std::size_t j = 0; j < newNames.size(); j++) {
0110     auto& name = newNames[j];
0111     if (!isNanoaodTrigger(name)) {
0112       continue;
0113     }
0114     trimVersionSuffix(name);
0115     if (std::none_of(m_triggerFields.cbegin(), m_triggerFields.cend(), [&](const TriggerFieldPtr& t) {
0116           return t.getTriggerName() == name;
0117         })) {
0118       // TODO backfill / friend ntuples
0119       edm::LogWarning("TriggerOutputFields") << "Skipping output of TriggerField " << name << "\n";
0120     }
0121   }
0122 }
0123 
0124 void TriggerOutputFields::makeUniqueFieldName(RNTupleModel& model, std::string& name) {
0125   // Could also use a cache of names in a higher-level object, don't ask the RNTupleModel each time
0126 #if ROOT_VERSION_CODE < ROOT_VERSION(6, 31, 0)
0127   auto existing_field = model.Get<bool>(name);
0128 #else
0129   auto existing_field = model.GetDefaultEntry().GetPtr<bool>(name);
0130 #endif
0131   if (!existing_field) {
0132     return;
0133   }
0134   edm::LogWarning("TriggerOutputFields") << "Found a branch with name " << name
0135                                          << " already present. Will add suffix _p" << m_processName
0136                                          << " to the new branch.\n";
0137   name += std::string("_p") + m_processName;
0138 }
0139 
0140 void TriggerOutputFields::fill(const edm::EventForOutput& event) {
0141   edm::Handle<edm::TriggerResults> handle;
0142   event.getByToken(m_token, handle);
0143   const edm::TriggerResults& triggers = *handle;
0144   if (m_lastRun != event.id().run()) {
0145     m_lastRun = event.id().run();
0146     updateTriggerFields(triggers);
0147   }
0148   for (auto& t : m_triggerFields) {
0149     t.fill(triggers);
0150   }
0151 }