Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-07-22 23:31:17

0001 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0002 #include "DataFormats/Common/interface/Handle.h"
0003 #include "FWCore/Utilities/interface/EDGetToken.h"
0004 #include "FWCore/Framework/interface/GetterOfProducts.h"
0005 #include "FWCore/Framework/interface/TypeMatch.h"
0006 
0007 #include "FWCore/Framework/interface/MakerMacros.h"
0008 #include "DataFormats/Common/interface/View.h"
0009 
0010 #include "FWCore/Framework/interface/Frameworkfwd.h"
0011 #include "FWCore/Framework/interface/one/EDProducer.h"
0012 
0013 #include "FWCore/ServiceRegistry/interface/Service.h"
0014 #include "FWCore/Framework/interface/TriggerNamesService.h"
0015 #include "FWCore/ParameterSet/interface/Registry.h"
0016 
0017 #include "DataFormats/Common/interface/PathStatus.h"
0018 #include "FWCore/Framework/interface/ConsumesCollector.h"
0019 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0020 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0021 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0022 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0023 #include "FWCore/Utilities/interface/EDGetToken.h"
0024 #include "FWCore/Utilities/interface/Exception.h"
0025 #include "FWCore/Utilities/interface/InputTag.h"
0026 #include "FWCore/Utilities/interface/propagate_const.h"
0027 
0028 #include <boost/spirit/include/qi.hpp>
0029 
0030 #include "DataFormats/L1Trigger/interface/P2GTCandidate.h"
0031 #include "DataFormats/L1Trigger/interface/P2GTAlgoBlock.h"
0032 
0033 #include <string>
0034 #include <memory>
0035 #include <utility>
0036 #include <map>
0037 #include <unordered_map>
0038 #include <vector>
0039 #include <set>
0040 #include <tuple>
0041 
0042 /** pathStatusExpression is borrowed from \class edm::PathStatusFilter by W. David Dagenhart */
0043 
0044 namespace qi = boost::spirit::qi;
0045 namespace ascii = boost::spirit::ascii;
0046 
0047 namespace pathStatusExpression {
0048   class Evaluator {
0049   public:
0050     virtual ~Evaluator() {}
0051 
0052     enum EvaluatorType { Name, Not, And, Or, BeginParen };
0053     virtual EvaluatorType type() const = 0;
0054 
0055     virtual const char* pathName() const { return ""; }
0056 
0057     virtual void setLeft(std::unique_ptr<Evaluator>&&) {}
0058     virtual void setRight(std::unique_ptr<Evaluator>&&) {}
0059 
0060     virtual void print(std::ostream& out, unsigned int indentation) const {}
0061     virtual void init(edm::ConsumesCollector&) {}
0062     virtual bool evaluate(edm::Event const& event) const { return true; };
0063   };
0064 
0065   class Operand : public Evaluator {
0066   public:
0067     Operand(std::vector<char> const& pathName) : pathName_(pathName.begin(), pathName.end()) {}
0068 
0069     EvaluatorType type() const override { return Name; }
0070 
0071     void print(std::ostream& out, unsigned int indentation) const override {
0072       out << std::string(indentation, ' ') << pathName_ << "\n";
0073     }
0074 
0075     void init(edm::ConsumesCollector& iC) override { token_ = iC.consumes<edm::PathStatus>(edm::InputTag(pathName_)); }
0076 
0077     bool evaluate(edm::Event const& event) const override { return event.get(token_).accept(); }
0078 
0079   private:
0080     std::string pathName_;
0081     edm::EDGetTokenT<edm::PathStatus> token_;
0082   };
0083 
0084   class NotOperator : public Evaluator {
0085   public:
0086     EvaluatorType type() const override { return Not; }
0087 
0088     void setLeft(std::unique_ptr<Evaluator>&& v) override { operand_ = std::move(v); }
0089 
0090     void print(std::ostream& out, unsigned int indentation) const override {
0091       out << std::string(indentation, ' ') << "not\n";
0092       operand_->print(out, indentation + 4);
0093     }
0094 
0095     void init(edm::ConsumesCollector& iC) override { operand_->init(iC); }
0096 
0097     bool evaluate(edm::Event const& event) const override { return !operand_->evaluate(event); }
0098 
0099   private:
0100     edm::propagate_const<std::unique_ptr<Evaluator>> operand_;
0101   };
0102 
0103   template <typename T>
0104   class BinaryOperator : public Evaluator {
0105   public:
0106     EvaluatorType type() const override;
0107 
0108     void setLeft(std::unique_ptr<Evaluator>&& v) override { left_ = std::move(v); }
0109     void setRight(std::unique_ptr<Evaluator>&& v) override { right_ = std::move(v); }
0110 
0111     void print(std::ostream& out, unsigned int indentation) const override;
0112 
0113     void init(edm::ConsumesCollector& iC) override {
0114       left_->init(iC);
0115       right_->init(iC);
0116     }
0117 
0118     bool evaluate(edm::Event const& event) const override {
0119       T op;
0120       return op(left_->evaluate(event), right_->evaluate(event));
0121     }
0122 
0123   private:
0124     edm::propagate_const<std::unique_ptr<Evaluator>> left_;
0125     edm::propagate_const<std::unique_ptr<Evaluator>> right_;
0126   };
0127 
0128   template <>
0129   inline Evaluator::EvaluatorType BinaryOperator<std::logical_and<bool>>::type() const {
0130     return And;
0131   }
0132 
0133   template <>
0134   inline Evaluator::EvaluatorType BinaryOperator<std::logical_or<bool>>::type() const {
0135     return Or;
0136   }
0137 
0138   template <>
0139   void BinaryOperator<std::logical_and<bool>>::print(std::ostream& out, unsigned int indentation) const {
0140     out << std::string(indentation, ' ') << "and\n";
0141     left_->print(out, indentation + 4);
0142     right_->print(out, indentation + 4);
0143   }
0144   template <>
0145   void BinaryOperator<std::logical_or<bool>>::print(std::ostream& out, unsigned int indentation) const {
0146     out << std::string(indentation, ' ') << "or\n";
0147     left_->print(out, indentation + 4);
0148     right_->print(out, indentation + 4);
0149   }
0150 
0151   using AndOperator = BinaryOperator<std::logical_and<bool>>;
0152   using OrOperator = BinaryOperator<std::logical_or<bool>>;
0153 
0154   class BeginParenthesis : public Evaluator {
0155   public:
0156     EvaluatorType type() const override { return BeginParen; }
0157   };
0158 
0159   // This class exists to properly handle the precedence of the
0160   // operators and also handle the order of operations specified
0161   // by parentheses. (search for shunting yard algorithm on the
0162   // internet for a description of this algorithm)
0163   class ShuntingYardAlgorithm {
0164   public:
0165     void addPathName(std::vector<char> const& s) {
0166       operandStack.push_back(std::make_unique<Operand>(s));
0167       pathNames_.emplace_back(s.begin(), s.end());
0168     }
0169 
0170     void addOperatorNot() {
0171       if (operatorStack.empty() || operatorStack.back()->type() != Evaluator::Not) {
0172         operatorStack.push_back(std::make_unique<NotOperator>());
0173       } else {
0174         // Two Not operations in a row cancel and are the same as no operation at all.
0175         operatorStack.pop_back();
0176       }
0177     }
0178 
0179     void moveBinaryOperator() {
0180       std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0181       backEvaluator->setRight(std::move(operandStack.back()));
0182       operandStack.pop_back();
0183       backEvaluator->setLeft(std::move(operandStack.back()));
0184       operandStack.pop_back();
0185       operandStack.push_back(std::move(backEvaluator));
0186       operatorStack.pop_back();
0187     }
0188 
0189     void moveNotOperator() {
0190       std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0191       backEvaluator->setLeft(std::move(operandStack.back()));
0192       operandStack.pop_back();
0193       operandStack.push_back(std::move(backEvaluator));
0194       operatorStack.pop_back();
0195     }
0196 
0197     void addOperatorAnd() {
0198       while (!operatorStack.empty()) {
0199         std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0200         if (backEvaluator->type() == Evaluator::And) {
0201           moveBinaryOperator();
0202         } else if (backEvaluator->type() == Evaluator::Not) {
0203           moveNotOperator();
0204         } else {
0205           break;
0206         }
0207       }
0208       operatorStack.push_back(std::make_unique<AndOperator>());
0209     }
0210 
0211     void addOperatorOr() {
0212       while (!operatorStack.empty()) {
0213         std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0214         if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0215           moveBinaryOperator();
0216         } else if (backEvaluator->type() == Evaluator::Not) {
0217           moveNotOperator();
0218         } else {
0219           break;
0220         }
0221       }
0222       operatorStack.push_back(std::make_unique<OrOperator>());
0223     }
0224 
0225     void addBeginParenthesis() { operatorStack.push_back(std::make_unique<BeginParenthesis>()); }
0226 
0227     void addEndParenthesis() {
0228       while (!operatorStack.empty()) {
0229         std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0230         if (backEvaluator->type() == Evaluator::BeginParen) {
0231           operatorStack.pop_back();
0232           break;
0233         }
0234         if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0235           moveBinaryOperator();
0236         } else if (backEvaluator->type() == Evaluator::Not) {
0237           moveNotOperator();
0238         }
0239       }
0240     }
0241 
0242     std::unique_ptr<Evaluator> finish() {
0243       while (!operatorStack.empty()) {
0244         std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0245         // Just a sanity check. The grammar defined for the boost Spirit parser
0246         // should catch any errors of this type before we get here.
0247         if (backEvaluator->type() == Evaluator::BeginParen) {
0248           throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
0249         }
0250         if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0251           moveBinaryOperator();
0252         } else if (backEvaluator->type() == Evaluator::Not) {
0253           moveNotOperator();
0254         }
0255       }
0256       // Just a sanity check. The grammar defined for the boost Spirit parser
0257       // should catch any errors of this type before we get here.
0258       if (!operatorStack.empty() || operandStack.size() != 1U) {
0259         throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
0260       }
0261       std::unique_ptr<Evaluator> temp = std::move(operandStack.back());
0262       operandStack.pop_back();
0263       return temp;
0264     }
0265 
0266     const std::vector<std::string>& pathNames() { return pathNames_; }
0267 
0268   private:
0269     std::vector<std::string> pathNames_;
0270     std::vector<std::unique_ptr<Evaluator>> operandStack;
0271     std::vector<std::unique_ptr<Evaluator>> operatorStack;
0272   };
0273 
0274   // Use boost Spirit to parse the logical expression character string
0275   template <typename Iterator>
0276   class Grammar : public qi::grammar<Iterator, ascii::space_type> {
0277   public:
0278     Grammar(ShuntingYardAlgorithm* algorithm) : Grammar::base_type(expression), algorithm_(algorithm) {
0279       // setup functors that call into shunting algorithm while parsing the logical expression
0280       auto addPathName = std::bind(&ShuntingYardAlgorithm::addPathName, algorithm_, std::placeholders::_1);
0281       auto addOperatorNot = std::bind(&ShuntingYardAlgorithm::addOperatorNot, algorithm_);
0282       auto addOperatorAnd = std::bind(&ShuntingYardAlgorithm::addOperatorAnd, algorithm_);
0283       auto addOperatorOr = std::bind(&ShuntingYardAlgorithm::addOperatorOr, algorithm_);
0284       auto addBeginParenthesis = std::bind(&ShuntingYardAlgorithm::addBeginParenthesis, algorithm_);
0285       auto addEndParenthesis = std::bind(&ShuntingYardAlgorithm::addEndParenthesis, algorithm_);
0286 
0287       // Define the syntax allowed in the logical expressions
0288       pathName = !unaryOperator >> !binaryOperatorTest >> (+qi::char_("a-zA-Z0-9_"))[addPathName];
0289       binaryOperand = (qi::lit('(')[addBeginParenthesis] >> expression >> qi::lit(')')[addEndParenthesis]) |
0290                       (unaryOperator[addOperatorNot] >> binaryOperand) | pathName;
0291       afterOperator = ascii::space | &qi::lit('(') | &qi::eoi;
0292       unaryOperator = qi::lit("not") >> afterOperator;
0293       // The only difference in the next two is that one calls a functor and the other does not
0294       binaryOperatorTest = (qi::lit("and") >> afterOperator) | (qi::lit("or") >> afterOperator);
0295       binaryOperator =
0296           (qi::lit("and") >> afterOperator)[addOperatorAnd] | (qi::lit("or") >> afterOperator)[addOperatorOr];
0297       expression = binaryOperand % binaryOperator;
0298     }
0299 
0300   private:
0301     qi::rule<Iterator> pathName;
0302     qi::rule<Iterator, ascii::space_type> binaryOperand;
0303     qi::rule<Iterator> afterOperator;
0304     qi::rule<Iterator> unaryOperator;
0305     qi::rule<Iterator> binaryOperatorTest;
0306     qi::rule<Iterator> binaryOperator;
0307     qi::rule<Iterator, ascii::space_type> expression;
0308 
0309     ShuntingYardAlgorithm* algorithm_;
0310   };
0311 }  // namespace pathStatusExpression
0312 
0313 using namespace l1t;
0314 
0315 class L1GTAlgoBlockProducer
0316     : public edm::one::EDProducer<edm::RunCache<std::unordered_map<std::string, unsigned int>>> {
0317 public:
0318   explicit L1GTAlgoBlockProducer(const edm::ParameterSet&);
0319   ~L1GTAlgoBlockProducer() override = default;
0320 
0321   static void fillDescriptions(edm::ConfigurationDescriptions&);
0322 
0323 private:
0324   struct AlgoDefinition {
0325     edm::propagate_const<std::unique_ptr<pathStatusExpression::Evaluator>> evaluator_;
0326     std::vector<std::string> pathNames_;
0327     std::set<std::tuple<std::string, std::string>> filtModules_;
0328     unsigned int prescale_;
0329     unsigned int prescalePreview_;
0330     std::set<unsigned int> bunchMask_;
0331     bool isVeto_;
0332     int triggerTypes_;
0333   };
0334 
0335   void init(const edm::ProcessHistory&);
0336   void produce(edm::Event&, const edm::EventSetup&) override;
0337   std::shared_ptr<std::unordered_map<std::string, unsigned int>> globalBeginRun(edm::Run const&,
0338                                                                                 edm::EventSetup const&) const override;
0339 
0340   void globalEndRun(edm::Run const&, edm::EventSetup const&) override {}
0341 
0342   edm::GetterOfProducts<P2GTCandidateVectorRef> getterOfPassedReferences_;
0343   std::map<std::string, AlgoDefinition> algoDefinitions_;
0344   bool initialized_ = false;
0345   int bunchCrossingEmu_ = 0;
0346 };
0347 
0348 void L1GTAlgoBlockProducer::fillDescriptions(edm::ConfigurationDescriptions& description) {
0349   edm::ParameterSetDescription algoDesc;
0350   algoDesc.add<std::string>("name", "");
0351   algoDesc.add<std::string>("expression");
0352   algoDesc.add<double>("prescale", 1);
0353   algoDesc.add<double>("prescalePreview", 1);
0354   algoDesc.add<std::vector<unsigned int>>("bunchMask", {});
0355 
0356   algoDesc.add<std::vector<int>>("triggerTypes", {1});
0357   algoDesc.add<bool>("veto", false);
0358 
0359   edm::ParameterSetDescription desc;
0360   desc.addVPSet("algorithms", algoDesc);
0361 
0362   description.addWithDefaultLabel(desc);
0363 }
0364 
0365 L1GTAlgoBlockProducer::L1GTAlgoBlockProducer(const edm::ParameterSet& config)
0366     : getterOfPassedReferences_(edm::TypeMatch(), this) {
0367   edm::ConsumesCollector iC(consumesCollector());
0368 
0369   for (const auto& algoConfig : config.getParameterSetVector("algorithms")) {
0370     const std::string logicalExpression = algoConfig.getParameter<std::string>("expression");
0371     std::string name = algoConfig.getParameter<std::string>("name");
0372     if (name.empty()) {
0373       name = logicalExpression;
0374     }
0375 
0376     pathStatusExpression::ShuntingYardAlgorithm shuntingYardAlgorithm;
0377     pathStatusExpression::Grammar<std::string::const_iterator> grammar(&shuntingYardAlgorithm);
0378 
0379     auto it = logicalExpression.cbegin();
0380     if (!qi::phrase_parse(it, logicalExpression.cend(), grammar, ascii::space) || (it != logicalExpression.cend())) {
0381       throw cms::Exception("Configuration") << "Syntax error in logical expression. Here is an example of how\n"
0382                                             << "the syntax should look:\n"
0383                                             << "    \"path1 and not (path2 or not path3)\"\n"
0384                                             << "The expression must contain alternating appearances of operands\n"
0385                                             << "which are path names and binary operators which can be \'and\'\n"
0386                                             << "or \'or\', with a path name at the beginning and end. There\n"
0387                                             << "must be at least one path name. In addition to the alternating\n"
0388                                             << "path names and binary operators, the unary operator \'not\' can\n"
0389                                             << "be inserted before a path name or a begin parenthesis.\n"
0390                                             << "Parentheses are allowed. Parentheses must come in matching pairs.\n"
0391                                             << "Matching begin and end parentheses must contain a complete and\n"
0392                                             << "syntactically correct logical expression. There must be at least\n"
0393                                             << "one space or parenthesis between operators and path names. Extra\n"
0394                                             << "space is ignored and OK. Path names can only contain upper and\n"
0395                                             << "lower case letters, numbers, and underscores. A path name cannot\n"
0396                                             << "be the same as an operator name.\n";
0397     }
0398 
0399     AlgoDefinition definition;
0400 
0401     for (const std::string& pathName : shuntingYardAlgorithm.pathNames()) {
0402       definition.pathNames_.push_back(pathName);
0403     }
0404 
0405     definition.evaluator_ = shuntingYardAlgorithm.finish();
0406     double dPrescale = algoConfig.getParameter<double>("prescale");
0407     if ((dPrescale < 1. || dPrescale >= std::pow(2, 24) / 100 - 1) && dPrescale != 0) {
0408       throw cms::Exception("Configuration")
0409           << "Prescale value error. Expected prescale value between 1 and 2^24/100 - 1 or 0 got " << dPrescale << "."
0410           << std::endl;
0411     }
0412 
0413     definition.prescale_ = std::round(dPrescale * 100);
0414 
0415     double dPrescalePreview = algoConfig.getParameter<double>("prescalePreview");
0416     if ((dPrescalePreview < 1. || dPrescalePreview >= std::pow(2, 24) / 100 - 1) && dPrescalePreview != 0) {
0417       throw cms::Exception("Configuration")
0418           << "PrescalePreview value error. Expected prescale value between 1 and 2^24/100 - 1 or 0 got "
0419           << dPrescalePreview << "." << std::endl;
0420     }
0421 
0422     definition.prescalePreview_ = std::round(dPrescalePreview * 100);
0423 
0424     std::vector<unsigned int> vBunchMask = algoConfig.getParameter<std::vector<unsigned int>>("bunchMask");
0425     definition.bunchMask_ =
0426         std::set<unsigned int>(std::make_move_iterator(vBunchMask.begin()), std::make_move_iterator(vBunchMask.end()));
0427 
0428     definition.isVeto_ = algoConfig.getParameter<bool>("veto");
0429     definition.triggerTypes_ = 0;
0430     const std::vector<int> triggerTypes = algoConfig.getParameter<std::vector<int>>("triggerTypes");
0431     for (int type : triggerTypes) {
0432       definition.triggerTypes_ |= type;
0433     }
0434 
0435     definition.evaluator_->init(iC);
0436     auto [iter, wasInserted] = algoDefinitions_.emplace(std::move(name), std::move(definition));
0437     if (!wasInserted) {
0438       throw cms::Exception("Configuration")
0439           << "Algorithm " << iter->first << " already exists. Algorithm names must be unique." << std::endl;
0440     }
0441   }
0442 
0443   callWhenNewProductsRegistered(getterOfPassedReferences_);
0444   produces<P2GTAlgoBlockMap>();
0445 }
0446 
0447 void L1GTAlgoBlockProducer::init(const edm::ProcessHistory& pHistory) {
0448   const std::string& pName = edm::Service<edm::service::TriggerNamesService>()->getProcessName();
0449 
0450   edm::ProcessConfiguration cfg;
0451 
0452   pHistory.getConfigurationForProcess(pName, cfg);
0453 
0454   const edm::ParameterSet* pset = edm::pset::Registry::instance()->getMapped(cfg.parameterSetID());
0455 
0456   for (auto& [name, algoDef] : algoDefinitions_) {
0457     for (const std::string& pathName : algoDef.pathNames_) {
0458       if (pset->existsAs<std::vector<std::string>>(pathName)) {
0459         const auto& modules = pset->getParameter<std::vector<std::string>>(pathName);
0460         for (const auto& mod : modules) {
0461           if (mod.front() != std::string("-") && pset->exists(mod)) {
0462             const auto& modPSet = pset->getParameterSet(mod);
0463             if (modPSet.getParameter<std::string>("@module_edm_type") == "EDFilter") {
0464               if (modPSet.getParameter<std::string>("@module_type") == "L1GTSingleObjectCond") {
0465                 algoDef.filtModules_.insert({mod, modPSet.getParameter<edm::InputTag>("tag").instance()});
0466               } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTDoubleObjectCond") {
0467                 algoDef.filtModules_.insert(
0468                     {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0469                 algoDef.filtModules_.insert(
0470                     {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0471               } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTTripleObjectCond") {
0472                 algoDef.filtModules_.insert(
0473                     {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0474                 algoDef.filtModules_.insert(
0475                     {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0476                 algoDef.filtModules_.insert(
0477                     {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
0478               } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTQuadObjectCond") {
0479                 algoDef.filtModules_.insert(
0480                     {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0481                 algoDef.filtModules_.insert(
0482                     {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0483                 algoDef.filtModules_.insert(
0484                     {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
0485                 algoDef.filtModules_.insert(
0486                     {mod, modPSet.getParameterSet("collection4").getParameter<edm::InputTag>("tag").instance()});
0487               }
0488             }
0489           }
0490         }
0491       }
0492     }
0493   }
0494 }
0495 
0496 std::shared_ptr<std::unordered_map<std::string, unsigned int>> L1GTAlgoBlockProducer::globalBeginRun(
0497     edm::Run const&, edm::EventSetup const&) const {
0498   // Reset prescale counters at the beginning of a new run
0499   return std::make_shared<std::unordered_map<std::string, unsigned int>>();
0500 }
0501 
0502 void L1GTAlgoBlockProducer::produce(edm::Event& event, const edm::EventSetup& eventSetup) {
0503   if (!initialized_) {
0504     init(event.processHistory());
0505     initialized_ = true;
0506   }
0507 
0508   std::vector<edm::Handle<P2GTCandidateVectorRef>> handles;
0509   getterOfPassedReferences_.fillHandles(event, handles);
0510 
0511   std::unique_ptr<P2GTAlgoBlockMap> algoCollection = std::make_unique<P2GTAlgoBlockMap>();
0512 
0513   std::unordered_map<std::string, unsigned int>& prescaleCounters = *runCache(event.getRun().index());
0514 
0515   int bunchCrossing = event.isRealData() ? event.bunchCrossing() : bunchCrossingEmu_ + 1;
0516 
0517   for (const auto& [name, algoDef] : algoDefinitions_) {
0518     bool decisionBeforeBxAndPrescale = algoDef.evaluator_->evaluate(event);
0519     bool decisionBeforePrescale = decisionBeforeBxAndPrescale && algoDef.bunchMask_.count(bunchCrossing) == 0;
0520     bool decisionFinal = false;
0521     bool decisionFinalPreview = false;
0522 
0523     if (algoDef.prescale_ != 0 && decisionBeforePrescale) {
0524       if (prescaleCounters.count(name) > 0) {
0525         prescaleCounters[name] += 100;
0526       } else {
0527         prescaleCounters[name] = 100;
0528       }
0529 
0530       if (prescaleCounters[name] >= algoDef.prescale_) {
0531         decisionFinal = true;
0532         prescaleCounters[name] -= algoDef.prescale_;
0533       } else {
0534         decisionFinal = false;
0535       }
0536     }
0537 
0538     if (algoDef.prescalePreview_ != 0 && decisionBeforePrescale) {
0539       std::string previewName = name + "_preview";
0540       if (prescaleCounters.count(previewName) > 0) {
0541         prescaleCounters[previewName] += 100;
0542       } else {
0543         prescaleCounters[previewName] = 100;
0544       }
0545 
0546       if (prescaleCounters[previewName] >= algoDef.prescalePreview_) {
0547         decisionFinalPreview = true;
0548         prescaleCounters[previewName] -= algoDef.prescalePreview_;
0549       } else {
0550         decisionFinalPreview = false;
0551       }
0552     }
0553 
0554     P2GTCandidateVectorRef trigObjects;
0555 
0556     if (decisionFinal) {
0557       for (const auto& handle : handles) {
0558         const std::string& module = handle.provenance()->moduleLabel();
0559         const std::string& instance = handle.provenance()->productInstanceName();
0560 
0561         if (algoDef.filtModules_.count({module, instance}) > 0) {
0562           trigObjects.insert(trigObjects.end(), handle->begin(), handle->end());
0563         }
0564       }
0565     }
0566 
0567     algoCollection->emplace(name,
0568                             P2GTAlgoBlock(decisionBeforeBxAndPrescale,
0569                                           decisionBeforePrescale,
0570                                           decisionFinal,
0571                                           decisionFinalPreview,
0572                                           algoDef.isVeto_,
0573                                           algoDef.triggerTypes_,
0574                                           std::move(trigObjects)));
0575   }
0576 
0577   event.put(std::move(algoCollection));
0578 
0579   bunchCrossingEmu_ = (bunchCrossingEmu_ + 1) % 3564;
0580 }
0581 
0582 DEFINE_FWK_MODULE(L1GTAlgoBlockProducer);