Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
/** \class HLTHighLevel
 *
 * See header file for documentation
 *
 *
 *  \author Martin Grunewald
 *
 */

#include <vector>
#include <string>
#include <iostream>
#include <iomanip>

#include "DataFormats/Common/interface/Handle.h"
#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/Provenance/interface/ModuleDescription.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "FWCore/Utilities/interface/RegexMatch.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ServiceRegistry/interface/PathContext.h"
#include "FWCore/ServiceRegistry/interface/PlaceInPathContext.h"
#include "FWCore/ServiceRegistry/interface/ModuleCallingContext.h"

// needed for trigger bits from EventSetup as in ALCARECO paths
#include "CondFormats/HLTObjects/interface/AlCaRecoTriggerBits.h"
#include "CondFormats/DataRecord/interface/AlCaRecoTriggerBitsRcd.h"

#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "HLTHighLevel.h"

//
// constructors and destructor
//
HLTHighLevel::HLTHighLevel(const edm::ParameterSet& iConfig)
    : inputTag_(iConfig.getParameter<edm::InputTag>("TriggerResultsTag")),
      inputToken_(consumes<edm::TriggerResults>(inputTag_)),
      triggerNamesID_(),
      andOr_(iConfig.getParameter<bool>("andOr")),
      throw_(iConfig.getParameter<bool>("throw")),
      eventSetupPathsKey_(iConfig.getParameter<std::string>("eventSetupPathsKey")),
      eventSetupPathsLabel_(iConfig.getParameter<std::string>("eventSetupPathsLabel")),
      HLTPatterns_(iConfig.getParameter<std::vector<std::string> >("HLTPaths")),
      HLTPathsByName_(),
      HLTPathsByIndex_() {
  // names and slot numbers are computed during the event loop,
  // as they need to access the TriggerNames object via the TriggerResults

  if (!eventSetupPathsKey_.empty()) {
    // If paths come from eventsetup, we must watch for IOV changes.
    if (!HLTPatterns_.empty()) {
      // We do not want double trigger path setting, so throw!
      throw cms::Exception("Configuration")
          << " HLTHighLevel instance: " << iConfig.getParameter<std::string>("@module_label") << "\n configured with "
          << HLTPatterns_.size() << " HLTPaths and\n"
          << " eventSetupPathsKey " << eventSetupPathsKey_ << ", choose either of them.";
    }
    alcaRecotriggerBitsToken_ =
        esConsumes<AlCaRecoTriggerBits, AlCaRecoTriggerBitsRcd>(edm::ESInputTag("", eventSetupPathsLabel_));
    watchAlCaRecoTriggerBitsRcd_.emplace();
  }
}

//
// member functions
//

void HLTHighLevel::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
  edm::ParameterSetDescription desc;
  desc.add<edm::InputTag>("TriggerResultsTag", edm::InputTag("TriggerResults", "", "HLT"));
  std::vector<std::string> hltPaths(0);
  // # provide list of HLT paths (or patterns) you want
  desc.add<std::vector<std::string> >("HLTPaths", hltPaths);
  // # not empty => use read paths from AlCaRecoTriggerBitsRcd via this key
  desc.add<std::string>("eventSetupPathsKey", "");
  desc.add<std::string>("eventSetupPathsLabel", "");
  // # how to deal with multiple triggers: True (OR) accept if ANY is true, False (AND) accept if ALL are true
  desc.add<bool>("andOr", true);
  // # throw exception on unknown path names
  desc.add<bool>("throw", true);
  descriptions.add("hltHighLevel", desc);
}

// Initialize the internal trigger path representation (names and indices) from the
// patterns specified in the configuration.
// This needs to be called once at startup, whenever the trigger table has changed
// or in case of paths from eventsetup and IOV changed
void HLTHighLevel::init(const edm::TriggerResults& result,
                        const edm::Event& event,
                        const edm::EventSetup& iSetup,
                        const edm::TriggerNames& triggerNames) {
  unsigned int n;

  // clean up old data
  HLTPathsByName_.clear();
  HLTPathsByIndex_.clear();

  // Overwrite paths from EventSetup via AlCaRecoTriggerBitsRcd if configured:
  if (!eventSetupPathsKey_.empty()) {
    HLTPatterns_ = this->pathsFromSetup(eventSetupPathsKey_, event, iSetup);
  }

  if (HLTPatterns_.empty()) {
    // for empty input vector, default to all HLT trigger paths
    n = result.size();
    HLTPathsByName_.resize(n);
    HLTPathsByIndex_.resize(n);
    for (unsigned int i = 0; i < n; ++i) {
      HLTPathsByName_[i] = triggerNames.triggerName(i);
      HLTPathsByIndex_[i] = i;
    }
  } else {
    // otherwise, expand wildcards in trigger names...
    for (auto const& pattern : HLTPatterns_) {
      if (edm::is_glob(pattern)) {
        // found a glob pattern, expand it
        std::vector<std::vector<std::string>::const_iterator> matches =
            edm::regexMatch(triggerNames.triggerNames(), pattern);
        if (matches.empty()) {
          // pattern does not match any trigger paths
          if (throw_)
            throw cms::Exception("Configuration")
                << "requested pattern \"" << pattern << "\" does not match any HLT paths";
          else
            edm::LogInfo("Configuration") << "requested pattern \"" << pattern << "\" does not match any HLT paths";
        } else {
          // store the matching patterns
          for (auto const& match : matches)
            HLTPathsByName_.push_back(*match);
        }
      } else {
        // found a trigger name, just copy it
        HLTPathsByName_.push_back(pattern);
      }
    }
    n = HLTPathsByName_.size();

    // ...and get hold of trigger indices
    bool valid = false;
    HLTPathsByIndex_.resize(n);
    for (unsigned int i = 0; i < HLTPathsByName_.size(); i++) {
      HLTPathsByIndex_[i] = triggerNames.triggerIndex(HLTPathsByName_[i]);
      if (HLTPathsByIndex_[i] < result.size()) {
        valid = true;
      } else {
        // trigger path not found
        HLTPathsByIndex_[i] = (unsigned int)-1;
        if (throw_)
          throw cms::Exception("Configuration") << "requested HLT path \"" << HLTPathsByName_[i] << "\" does not exist";
        else
          edm::LogInfo("Configuration") << "requested HLT path \"" << HLTPathsByName_[i] << "\" does not exist";
      }
    }

    if (not valid) {
      // no point in throwing - if requested, it should have already happened
      edm::LogWarning("Configuration")
          << "none of the requested paths and pattern match any HLT path - no events will be selected";
    }
  }

  // report on what is finally used
  LogDebug("HLTHighLevel") << "HLT trigger paths: " + inputTag_.encode() << " - Number of paths: " << n
                           << " - andOr mode: " << andOr_ << " - throw mode: " << throw_;

  LogTrace("HLTHighLevel") << "The HLT trigger paths (# index name):";
  for (unsigned int i = 0; i < n; ++i)
    if (HLTPathsByIndex_[i] == (unsigned int)-1)
      LogTrace("HLTHighLevel") << "    n/a   " << HLTPathsByName_[i];
    else
      LogTrace("HLTHighLevel") << "    " << std::setw(4) << HLTPathsByIndex_[i] << "  " << HLTPathsByName_[i];
}

// ------------ getting paths from EventSetup  ------------
std::vector<std::string> HLTHighLevel::pathsFromSetup(const std::string& key,
                                                      const edm::Event& event,
                                                      const edm::EventSetup& iSetup) const {
  // Get map of strings to concatenated list of names of HLT paths from EventSetup:
  const auto& triggerBits = iSetup.getData(alcaRecotriggerBitsToken_);
  typedef std::map<std::string, std::string> TriggerMap;
  const TriggerMap& triggerMap = triggerBits.m_alcarecoToTrig;

  auto listIter = triggerMap.find(key);
  if (listIter == triggerMap.end()) {
    throw cms::Exception("Configuration")
        << " HLTHighLevel [instance: " << moduleLabel() << " - path: " << pathName(event)
        << "]: No triggerList with key " << key << " in AlCaRecoTriggerBitsRcd";
  }

  // We must avoid a map<string,vector<string> > in DB for performance reason,
  // so the paths are mapped into one string that we have to decompose:
  return triggerBits.decompose(listIter->second);
}

// ------------ method called to produce the data  ------------
bool HLTHighLevel::filter(edm::Event& iEvent, const edm::EventSetup& iSetup) {
  using namespace std;
  using namespace edm;

  // get hold of TriggerResults Object
  Handle<TriggerResults> trh;
  iEvent.getByToken(inputToken_, trh);
  if (trh.isValid()) {
    LogDebug("HLTHighLevel") << "TriggerResults found, number of HLT paths: " << trh->size();
  } else {
    LogError("HLTHighLevel") << "TriggerResults product " << inputTag_.encode()
                             << " not found - returning result=false!";
    return false;
  }

  // init the TriggerNames with the TriggerResults
  const edm::TriggerNames& triggerNames = iEvent.triggerNames(*trh);
  bool config_changed = false;
  if (triggerNamesID_ != triggerNames.parameterSetID()) {
    triggerNamesID_ = triggerNames.parameterSetID();
    config_changed = true;
  }

  // (re)run the initialization stuff if
  // - this is the first event
  // - or the HLT table has changed
  // - or selected trigger bits come from AlCaRecoTriggerBitsRcd and these changed
  if (config_changed or (watchAlCaRecoTriggerBitsRcd_ and watchAlCaRecoTriggerBitsRcd_->check(iSetup))) {
    this->init(*trh, iEvent, iSetup, triggerNames);
  }
  unsigned int n = HLTPathsByName_.size();
  unsigned int nbad = 0;
  unsigned int fired = 0;

  // count invalid and fired triggers
  for (unsigned int i = 0; i < n; i++)
    if (HLTPathsByIndex_[i] == (unsigned int)-1)
      ++nbad;
    else if (trh->accept(HLTPathsByIndex_[i]))
      ++fired;

  if ((nbad > 0) and (config_changed or throw_)) {
    // only generate the error message if it's actually going to be used
    std::string message;

    for (unsigned int i = 0; i < n; i++)
      if (HLTPathsByIndex_[i] == (unsigned int)-1)
        message += HLTPathsByName_[i] + " ";

    if (config_changed) {
      LogTrace("HLTHighLevel") << " HLTHighLevel [instance: " << moduleLabel() << " - path: " << pathName(iEvent)
                               << "] configured with " << nbad << "/" << n << " unknown HLT path names: " << message;
    }

    if (throw_) {
      throw cms::Exception("Configuration")
          << " HLTHighLevel [instance: " << moduleLabel() << " - path: " << pathName(iEvent) << "] configured with "
          << nbad << "/" << n << " unknown HLT path names: " << message;
    }
  }

  // Boolean filter result (always at least one trigger)
  const bool accept((fired > 0) and (andOr_ or (fired == n - nbad)));
  LogDebug("HLTHighLevel") << "Accept = " << std::boolalpha << accept;

  return accept;
}

std::string const& HLTHighLevel::pathName(const edm::Event& event) const {
  return event.moduleCallingContext()->placeInPathContext()->pathContext()->pathName();
}

std::string const& HLTHighLevel::moduleLabel() const { return moduleDescription().moduleLabel(); }