key_hash

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 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
#include <oneapi/tbb/concurrent_unordered_map.h>
#include <boost/algorithm/string.hpp>

#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"
#include "DataFormats/Math/interface/libminifloat.h"
#include "DataFormats/Provenance/interface/ProcessConfiguration.h"
#include "DataFormats/Provenance/interface/ProcessHistory.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/Utilities/interface/path_configuration.h"
#include "FWCore/Utilities/interface/thread_safety_macros.h"

using namespace pat;

// Const data members' definitions

const char TriggerObjectStandAlone::wildcard_;

// Constructors and Destructor

// Default constructor
TriggerObjectStandAlone::TriggerObjectStandAlone() : TriggerObject() {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}

// Constructor from pat::TriggerObject
TriggerObjectStandAlone::TriggerObjectStandAlone(const TriggerObject &trigObj) : TriggerObject(trigObj) {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}

// Constructor from trigger::TriggerObject
TriggerObjectStandAlone::TriggerObjectStandAlone(const trigger::TriggerObject &trigObj) : TriggerObject(trigObj) {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}

// Constructor from reco::Candidate
TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::LeafCandidate &leafCand) : TriggerObject(leafCand) {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}

// Constructors from Lorentz-vectors and (optional) PDG ID
TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::Particle::LorentzVector &vec, int id)
    : TriggerObject(vec, id) {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}
TriggerObjectStandAlone::TriggerObjectStandAlone(const reco::Particle::PolarLorentzVector &vec, int id)
    : TriggerObject(vec, id) {
  filterLabels_.clear();
  filterLabelIndices_.clear();
  pathNames_.clear();
  pathLastFilterAccepted_.clear();
  pathL3FilterAccepted_.clear();
}

// Private methods

// Checks a string vector for occurence of a certain string, incl. wild-card mechanism
bool TriggerObjectStandAlone::hasAnyName(const std::string &name, const std::vector<std::string> &nameVec) const {
  // Special cases first
  // Always false for empty vector to check
  if (nameVec.empty())
    return false;
  // Always true for general wild-card(s)
  if (name.find_first_not_of(wildcard_) == std::string::npos)
    return true;
  // Split name to evaluate in parts, seperated by wild-cards
  std::vector<std::string> namePartsVec;
  boost::split(namePartsVec, name, boost::is_any_of(std::string(1, wildcard_)), boost::token_compress_on);
  // Iterate over vector of names to search
  for (std::vector<std::string>::const_iterator iVec = nameVec.begin(); iVec != nameVec.end(); ++iVec) {
    // Not failed yet
    bool failed(false);
    // Start searching at the first character
    size_type index(0);
    // Iterate over evaluation name parts
    for (std::vector<std::string>::const_iterator iName = namePartsVec.begin(); iName != namePartsVec.end(); ++iName) {
      // Empty parts due to
      // - wild-card at beginning/end or
      // - multiple wild-cards (should be supressed by 'boost::token_compress_on')
      if (iName->empty())
        continue;
      // Search from current index and
      // set index to found occurence
      index = iVec->find(*iName, index);
      // Failed and exit loop, if
      // - part not found
      // - part at beginning not found there
      if (index == std::string::npos || (iName == namePartsVec.begin() && index > 0)) {
        failed = true;
        break;
      }
      // Increase index by length of found part
      index += iName->length();
    }
    // Failed, if end of name not reached
    if (index < iVec->length() && !namePartsVec.back().empty())
      failed = true;
    // Match found!
    if (!failed)
      return true;
  }
  // No match found!
  return false;
}

// Adds a new HLT path or L1 algorithm name
void TriggerObjectStandAlone::addPathOrAlgorithm(const std::string &name,
                                                 bool pathLastFilterAccepted,
                                                 bool pathL3FilterAccepted) {
  checkIfPathsAreUnpacked();

  // Check, if path is already assigned
  if (!hasPathOrAlgorithm(name, false, false)) {
    // The path itself
    pathNames_.push_back(name);
    // The corresponding usage of the trigger objects
    pathLastFilterAccepted_.push_back(pathLastFilterAccepted);
    pathL3FilterAccepted_.push_back(pathL3FilterAccepted);
    // Enable status updates
  } else if (pathLastFilterAccepted || pathL3FilterAccepted) {
    // Search for path
    unsigned index(0);
    while (index < pathNames_.size()) {
      if (pathNames_.at(index) == name)
        break;
      ++index;
    }
    // Status update
    if (index < pathNames_.size()) {
      pathLastFilterAccepted_.at(index) = pathLastFilterAccepted_.at(index) || pathLastFilterAccepted;
      pathL3FilterAccepted_.at(index) = pathL3FilterAccepted_.at(index) || pathL3FilterAccepted;
    }
  }
}

// Gets all HLT path or L1 algorithm names
std::vector<std::string> TriggerObjectStandAlone::pathsOrAlgorithms(bool pathLastFilterAccepted,
                                                                    bool pathL3FilterAccepted) const {
  checkIfPathsAreUnpacked();

  // Deal with older PAT-tuples, where trigger object usage is not available
  if (!hasLastFilter())
    pathLastFilterAccepted = false;
  if (!hasL3Filter())
    pathL3FilterAccepted = false;
  // All path names, if usage not restricted (not required or not available)
  if (!pathLastFilterAccepted && !pathL3FilterAccepted)
    return pathNames_;
  // Temp vector of path names
  std::vector<std::string> paths;
  // Loop over usage vector and fill corresponding paths into temp vector
  for (unsigned iPath = 0; iPath < pathNames_.size(); ++iPath) {
    if ((!pathLastFilterAccepted || pathLastFilterAccepted_.at(iPath)) &&
        (!pathL3FilterAccepted || pathL3FilterAccepted_.at(iPath)))
      paths.push_back(pathNames_.at(iPath));  // order matters in order to protect from empty vectors in old data
  }
  // Return temp vector
  return paths;
}

// Checks, if a certain HLT filter label or L1 condition name is assigned
bool TriggerObjectStandAlone::hasFilterOrCondition(const std::string &name) const {
  checkIfFiltersAreUnpacked();

  // Move to wild-card parser, if needed
  if (name.find(wildcard_) != std::string::npos)
    return hasAnyName(name, filterLabels_);
  // Return, if filter label is assigned
  return (std::find(filterLabels_.begin(), filterLabels_.end(), name) != filterLabels_.end());
}

// Checks, if a certain path name is assigned
bool TriggerObjectStandAlone::hasPathOrAlgorithm(const std::string &name,
                                                 bool pathLastFilterAccepted,
                                                 bool pathL3FilterAccepted) const {
  checkIfPathsAreUnpacked();

  // Move to wild-card parser, if needed
  if (name.find(wildcard_) != std::string::npos)
    return hasAnyName(name, pathsOrAlgorithms(pathLastFilterAccepted, pathL3FilterAccepted));
  // Deal with older PAT-tuples, where trigger object usage is not available
  if (!hasLastFilter())
    pathLastFilterAccepted = false;
  if (!hasL3Filter())
    pathL3FilterAccepted = false;
  // Check, if path name is assigned at all
  std::vector<std::string>::const_iterator match(std::find(pathNames_.begin(), pathNames_.end(), name));
  // False, if path name not assigned
  if (match == pathNames_.end())
    return false;
  if (!pathLastFilterAccepted && !pathL3FilterAccepted)
    return true;
  bool foundLastFilter(pathLastFilterAccepted ? pathLastFilterAccepted_.at(match - pathNames_.begin()) : true);
  bool foundL3Filter(pathL3FilterAccepted ? pathL3FilterAccepted_.at(match - pathNames_.begin()) : true);
  // Return for assigned path name, if trigger object usage meets requirement
  return (foundLastFilter && foundL3Filter);
}

// Methods

// Gets the pat::TriggerObject (parent class)
TriggerObject TriggerObjectStandAlone::triggerObject() {
  // Create a TriggerObjects
  TriggerObject theObj(p4(), pdgId());
  // Set its collection and trigger objects types (no c'tor for that)
  theObj.setCollection(collection());
  for (size_t i = 0; i < triggerObjectTypes().size(); ++i)
    theObj.addTriggerObjectType(triggerObjectTypes().at(i));
  // Return TriggerObject
  return theObj;
}

// Checks, if a certain label of original collection is assigned (method overrides)
bool TriggerObjectStandAlone::hasCollection(const std::string &collName) const {
  // Move to wild-card parser, if needed only
  if (collName.find(wildcard_) != std::string::npos) {
    // True, if collection name is simply fine
    if (hasAnyName(collName, std::vector<std::string>(1, collection())))
      return true;
    // Check, if collection name possibly fits in an edm::InputTag approach
    const edm::InputTag collectionTag(collection());
    const edm::InputTag collTag(collName);
    // If evaluated collection tag contains a process name, it must have been found already by identity check
    if (collTag.process().empty()) {
      // Check instance ...
      if ((collTag.instance().empty() && collectionTag.instance().empty()) ||
          hasAnyName(collTag.instance(), std::vector<std::string>(1, collectionTag.instance()))) {
        // ... and label
        return hasAnyName(collTag.label(), std::vector<std::string>(1, collectionTag.label()));
      }
    }
    return false;
  }
  // Use parent class's method otherwise
  return TriggerObject::hasCollection(collName);
}

bool TriggerObjectStandAlone::checkIfPathsAreUnpacked(bool throwIfPacked) const {
  bool unpacked = (!pathNames_.empty() || pathIndices_.empty());
  if (!unpacked && throwIfPacked)
    throw cms::Exception("RuntimeError",
                         "This TriggerObjectStandAlone object has packed trigger path names. Before accessing path "
                         "names you must call unpackPathNames with an edm::TriggerNames object. You can get the latter "
                         "from the edm::Event or fwlite::Event and the TriggerResults\n");
  return unpacked;
}
bool TriggerObjectStandAlone::checkIfFiltersAreUnpacked(bool throwIfPacked) const {
  bool unpacked = filterLabelIndices_.empty();
  if (!unpacked && throwIfPacked)
    throw cms::Exception("RuntimeError",
                         "This TriggerObjectStandAlone object has packed trigger filter labels. Before accessing path "
                         "names you must call unpackFilterLabels with an edm::EventBase object. Both the edm::Event or "
                         "fwlite::Event are derived from edm::EventBase and can be passed\n");
  return unpacked;
}

void TriggerObjectStandAlone::packPathNames(const edm::TriggerNames &names) {
  if (!pathIndices_.empty()) {
    if (!pathNames_.empty()) {
      throw cms::Exception("RuntimeError", "Error, trying to pack a partially packed TriggerObjectStandAlone");
    } else {
      return;
    }
  }
  bool ok = true;
  unsigned int n = pathNames_.size(), end = names.size();
  std::vector<uint16_t> indices(n);
  for (unsigned int i = 0; i < n; ++i) {
    uint16_t id = names.triggerIndex(pathNames_[i]);
    if (id >= end) {
      static std::atomic<int> _warn(0);
      if (++_warn < 5)
        edm::LogWarning("TriggerObjectStandAlone::packPathNames()")
            << "Warning: can't resolve '" << pathNames_[i] << "' to a path index" << std::endl;
      ok = false;
      break;
    } else {
      indices[i] = id;
    }
  }
  if (ok) {
    pathIndices_.swap(indices);
    pathNames_.clear();
  }
}

void TriggerObjectStandAlone::unpackPathNames(const edm::TriggerNames &names) {
  if (!pathNames_.empty()) {
    if (!pathIndices_.empty()) {
      throw cms::Exception("RuntimeError", "Error, trying to unpack a partially unpacked TriggerObjectStandAlone");
    } else {
      return;
    }
  }
  unsigned int n = pathIndices_.size(), end = names.size();
  std::vector<std::string> paths(n);
  for (unsigned int i = 0; i < n; ++i) {
    if (pathIndices_[i] >= end)
      throw cms::Exception("RuntimeError", "Error, path index out of bounds");
    paths[i] = names.triggerName(pathIndices_[i]);
  }
  pathIndices_.clear();
  pathNames_.swap(paths);
}

void TriggerObjectStandAlone::packFilterLabels(const std::vector<std::string> &names) {
  if (!filterLabelIndices_.empty()) {
    throw cms::Exception("RuntimeError",
                         "Error, trying to pack filter labels for an already packed TriggerObjectStandAlone");
  }
  std::vector<std::string> unmatched;
  std::vector<uint16_t> indices;
  indices.reserve(filterLabels_.size());

  auto nStart = names.begin(), nEnd = names.end();
  for (unsigned int i = 0, n = filterLabels_.size(); i < n; ++i) {
    auto match = std::lower_bound(nStart, nEnd, filterLabels_[i]);
    if (match != nEnd && *match == filterLabels_[i]) {
      indices.push_back(match - nStart);
    } else {
      static std::atomic<int> _warn(0);
      if (++_warn < 5)
        edm::LogWarning("TriggerObjectStandAlone::packFilterLabels()")
            << "Warning: can't resolve '" << filterLabels_[i] << "' to a label index. idx: " << i << std::endl;
      unmatched.push_back(std::move(filterLabels_[i]));
    }
  }
  std::sort(indices.begin(), indices.end());  // try reduce enthropy
  filterLabelIndices_.swap(indices);
  filterLabels_.swap(unmatched);
}

void TriggerObjectStandAlone::unpackNamesAndLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
  unpackPathNames(event.triggerNames(res));
  unpackFilterLabels(event, res);
}

void TriggerObjectStandAlone::unpackFilterLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
  unpackFilterLabels(*allLabels(psetId_, event, res));
}

void TriggerObjectStandAlone::unpackFilterLabels(const std::vector<std::string> &labels) {
  if (filterLabelIndices_.empty())
    return;

  std::vector<std::string> mylabels(filterLabels_);
  for (unsigned int i = 0, n = filterLabelIndices_.size(), m = labels.size(); i < n; ++i) {
    if (filterLabelIndices_[i] >= m)
      throw cms::Exception("RuntimeError", "Error, filter label index out of bounds");
    mylabels.push_back(labels[filterLabelIndices_[i]]);
  }
  filterLabelIndices_.clear();
  filterLabels_.swap(mylabels);
}
void TriggerObjectStandAlone::packFilterLabels(const edm::EventBase &event, const edm::TriggerResults &res) {
  packFilterLabels(*allLabels(psetId_, event, res));
}

void TriggerObjectStandAlone::packP4() {
  setP4(reco::Particle::PolarLorentzVector(MiniFloatConverter::reduceMantissaToNbitsRounding<14>(pt()),
                                           MiniFloatConverter::reduceMantissaToNbitsRounding<11>(eta()),
                                           MiniFloatConverter::reduceMantissaToNbits<11>(phi()),
                                           MiniFloatConverter::reduceMantissaToNbitsRounding<8>(mass())));
}

namespace {
  struct key_hash {
    std::size_t operator()(edm::ParameterSetID const &iKey) const { return iKey.smallHash(); }
  };
  typedef tbb::concurrent_unordered_map<edm::ParameterSetID, std::vector<std::string>, key_hash> AllLabelsMap;
  CMS_THREAD_SAFE AllLabelsMap allLabelsMap;
}  // namespace

std::vector<std::string> const *TriggerObjectStandAlone::allLabels(edm::ParameterSetID const &psetid,
                                                                   const edm::EventBase &event,
                                                                   const edm::TriggerResults &res) const {
  // If TriggerNames was already created and cached here in the map,
  // then look it up and return that one
  AllLabelsMap::const_iterator iter = allLabelsMap.find(psetid);
  if (iter != allLabelsMap.end()) {
    return &iter->second;
  }

  const auto &triggerNames = event.triggerNames(res);
  edm::ParameterSet const *pset = nullptr;
  //getting the ParameterSet from the event ensures that the registry is filled
  if (nullptr != (pset = event.parameterSet(psetid))) {
    using namespace std;
    using namespace edm;
    using namespace trigger;

    const unsigned int n(triggerNames.size());
    std::set<std::string> saveTags;
    for (unsigned int i = 0; i != n; ++i) {
      if (pset->existsAs<vector<string>>(triggerNames.triggerName(i), true)) {
        auto const &modules = pset->getParameter<vector<string>>(triggerNames.triggerName(i));
        for (auto const &module : modules) {
          auto const moduleStrip = edm::path_configuration::removeSchedulingTokensFromModuleLabel(module);
          if (pset->exists(moduleStrip)) {
            const auto &modulePSet = pset->getParameterSet(moduleStrip);
            if (modulePSet.existsAs<bool>("saveTags", true) and modulePSet.getParameter<bool>("saveTags")) {
              saveTags.insert(moduleStrip);
            }
          }
        }
      }
    }
    std::vector<std::string> allModules(saveTags.begin(), saveTags.end());
    std::pair<AllLabelsMap::iterator, bool> ret =
        allLabelsMap.insert(std::pair<edm::ParameterSetID, std::vector<std::string>>(psetid, allModules));
    return &(ret.first->second);
  }
  return nullptr;
}