File indexing completed on 2023-10-25 09:55:50
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/stream/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 <vector>
0038 #include <set>
0039 #include <tuple>
0040
0041
0042
0043 namespace qi = boost::spirit::qi;
0044 namespace ascii = boost::spirit::ascii;
0045
0046 namespace pathStatusExpression {
0047 class Evaluator {
0048 public:
0049 virtual ~Evaluator() {}
0050
0051 enum EvaluatorType { Name, Not, And, Or, BeginParen };
0052 virtual EvaluatorType type() const = 0;
0053
0054 virtual const char* pathName() const { return ""; }
0055
0056 virtual void setLeft(std::unique_ptr<Evaluator>&&) {}
0057 virtual void setRight(std::unique_ptr<Evaluator>&&) {}
0058
0059 virtual void print(std::ostream& out, unsigned int indentation) const {}
0060 virtual void init(edm::ConsumesCollector&) {}
0061 virtual bool evaluate(edm::Event const& event) const { return true; };
0062 };
0063
0064 class Operand : public Evaluator {
0065 public:
0066 Operand(std::vector<char> const& pathName) : pathName_(pathName.begin(), pathName.end()) {}
0067
0068 EvaluatorType type() const override { return Name; }
0069
0070 void print(std::ostream& out, unsigned int indentation) const override {
0071 out << std::string(indentation, ' ') << pathName_ << "\n";
0072 }
0073
0074 void init(edm::ConsumesCollector& iC) override { token_ = iC.consumes<edm::PathStatus>(edm::InputTag(pathName_)); }
0075
0076 bool evaluate(edm::Event const& event) const override { return event.get(token_).accept(); }
0077
0078 private:
0079 std::string pathName_;
0080 edm::EDGetTokenT<edm::PathStatus> token_;
0081 };
0082
0083 class NotOperator : public Evaluator {
0084 public:
0085 EvaluatorType type() const override { return Not; }
0086
0087 void setLeft(std::unique_ptr<Evaluator>&& v) override { operand_ = std::move(v); }
0088
0089 void print(std::ostream& out, unsigned int indentation) const override {
0090 out << std::string(indentation, ' ') << "not\n";
0091 operand_->print(out, indentation + 4);
0092 }
0093
0094 void init(edm::ConsumesCollector& iC) override { operand_->init(iC); }
0095
0096 bool evaluate(edm::Event const& event) const override { return !operand_->evaluate(event); }
0097
0098 private:
0099 edm::propagate_const<std::unique_ptr<Evaluator>> operand_;
0100 };
0101
0102 template <typename T>
0103 class BinaryOperator : public Evaluator {
0104 public:
0105 EvaluatorType type() const override;
0106
0107 void setLeft(std::unique_ptr<Evaluator>&& v) override { left_ = std::move(v); }
0108 void setRight(std::unique_ptr<Evaluator>&& v) override { right_ = std::move(v); }
0109
0110 void print(std::ostream& out, unsigned int indentation) const override;
0111
0112 void init(edm::ConsumesCollector& iC) override {
0113 left_->init(iC);
0114 right_->init(iC);
0115 }
0116
0117 bool evaluate(edm::Event const& event) const override {
0118 T op;
0119 return op(left_->evaluate(event), right_->evaluate(event));
0120 }
0121
0122 private:
0123 edm::propagate_const<std::unique_ptr<Evaluator>> left_;
0124 edm::propagate_const<std::unique_ptr<Evaluator>> right_;
0125 };
0126
0127 template <>
0128 inline Evaluator::EvaluatorType BinaryOperator<std::logical_and<bool>>::type() const {
0129 return And;
0130 }
0131
0132 template <>
0133 inline Evaluator::EvaluatorType BinaryOperator<std::logical_or<bool>>::type() const {
0134 return Or;
0135 }
0136
0137 template <>
0138 void BinaryOperator<std::logical_and<bool>>::print(std::ostream& out, unsigned int indentation) const {
0139 out << std::string(indentation, ' ') << "and\n";
0140 left_->print(out, indentation + 4);
0141 right_->print(out, indentation + 4);
0142 }
0143 template <>
0144 void BinaryOperator<std::logical_or<bool>>::print(std::ostream& out, unsigned int indentation) const {
0145 out << std::string(indentation, ' ') << "or\n";
0146 left_->print(out, indentation + 4);
0147 right_->print(out, indentation + 4);
0148 }
0149
0150 using AndOperator = BinaryOperator<std::logical_and<bool>>;
0151 using OrOperator = BinaryOperator<std::logical_or<bool>>;
0152
0153 class BeginParenthesis : public Evaluator {
0154 public:
0155 EvaluatorType type() const override { return BeginParen; }
0156 };
0157
0158
0159
0160
0161
0162 class ShuntingYardAlgorithm {
0163 public:
0164 void addPathName(std::vector<char> const& s) {
0165 operandStack.push_back(std::make_unique<Operand>(s));
0166 pathNames_.emplace_back(s.begin(), s.end());
0167 }
0168
0169 void addOperatorNot() {
0170 if (operatorStack.empty() || operatorStack.back()->type() != Evaluator::Not) {
0171 operatorStack.push_back(std::make_unique<NotOperator>());
0172 } else {
0173
0174 operatorStack.pop_back();
0175 }
0176 }
0177
0178 void moveBinaryOperator() {
0179 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0180 backEvaluator->setRight(std::move(operandStack.back()));
0181 operandStack.pop_back();
0182 backEvaluator->setLeft(std::move(operandStack.back()));
0183 operandStack.pop_back();
0184 operandStack.push_back(std::move(backEvaluator));
0185 operatorStack.pop_back();
0186 }
0187
0188 void moveNotOperator() {
0189 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0190 backEvaluator->setLeft(std::move(operandStack.back()));
0191 operandStack.pop_back();
0192 operandStack.push_back(std::move(backEvaluator));
0193 operatorStack.pop_back();
0194 }
0195
0196 void addOperatorAnd() {
0197 while (!operatorStack.empty()) {
0198 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0199 if (backEvaluator->type() == Evaluator::And) {
0200 moveBinaryOperator();
0201 } else if (backEvaluator->type() == Evaluator::Not) {
0202 moveNotOperator();
0203 } else {
0204 break;
0205 }
0206 }
0207 operatorStack.push_back(std::make_unique<AndOperator>());
0208 }
0209
0210 void addOperatorOr() {
0211 while (!operatorStack.empty()) {
0212 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0213 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0214 moveBinaryOperator();
0215 } else if (backEvaluator->type() == Evaluator::Not) {
0216 moveNotOperator();
0217 } else {
0218 break;
0219 }
0220 }
0221 operatorStack.push_back(std::make_unique<OrOperator>());
0222 }
0223
0224 void addBeginParenthesis() { operatorStack.push_back(std::make_unique<BeginParenthesis>()); }
0225
0226 void addEndParenthesis() {
0227 while (!operatorStack.empty()) {
0228 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0229 if (backEvaluator->type() == Evaluator::BeginParen) {
0230 operatorStack.pop_back();
0231 break;
0232 }
0233 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0234 moveBinaryOperator();
0235 } else if (backEvaluator->type() == Evaluator::Not) {
0236 moveNotOperator();
0237 }
0238 }
0239 }
0240
0241 std::unique_ptr<Evaluator> finish() {
0242 while (!operatorStack.empty()) {
0243 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0244
0245
0246 if (backEvaluator->type() == Evaluator::BeginParen) {
0247 throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
0248 }
0249 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0250 moveBinaryOperator();
0251 } else if (backEvaluator->type() == Evaluator::Not) {
0252 moveNotOperator();
0253 }
0254 }
0255
0256
0257 if (!operatorStack.empty() || operandStack.size() != 1U) {
0258 throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
0259 }
0260 std::unique_ptr<Evaluator> temp = std::move(operandStack.back());
0261 operandStack.pop_back();
0262 return temp;
0263 }
0264
0265 const std::vector<std::string>& pathNames() { return pathNames_; }
0266
0267 private:
0268 std::vector<std::string> pathNames_;
0269 std::vector<std::unique_ptr<Evaluator>> operandStack;
0270 std::vector<std::unique_ptr<Evaluator>> operatorStack;
0271 };
0272
0273
0274 template <typename Iterator>
0275 class Grammar : public qi::grammar<Iterator, ascii::space_type> {
0276 public:
0277 Grammar(ShuntingYardAlgorithm* algorithm) : Grammar::base_type(expression), algorithm_(algorithm) {
0278
0279 auto addPathName = std::bind(&ShuntingYardAlgorithm::addPathName, algorithm_, std::placeholders::_1);
0280 auto addOperatorNot = std::bind(&ShuntingYardAlgorithm::addOperatorNot, algorithm_);
0281 auto addOperatorAnd = std::bind(&ShuntingYardAlgorithm::addOperatorAnd, algorithm_);
0282 auto addOperatorOr = std::bind(&ShuntingYardAlgorithm::addOperatorOr, algorithm_);
0283 auto addBeginParenthesis = std::bind(&ShuntingYardAlgorithm::addBeginParenthesis, algorithm_);
0284 auto addEndParenthesis = std::bind(&ShuntingYardAlgorithm::addEndParenthesis, algorithm_);
0285
0286
0287 pathName = !unaryOperator >> !binaryOperatorTest >> (+qi::char_("a-zA-Z0-9_"))[addPathName];
0288 binaryOperand = (qi::lit('(')[addBeginParenthesis] >> expression >> qi::lit(')')[addEndParenthesis]) |
0289 (unaryOperator[addOperatorNot] >> binaryOperand) | pathName;
0290 afterOperator = ascii::space | &qi::lit('(') | &qi::eoi;
0291 unaryOperator = qi::lit("not") >> afterOperator;
0292
0293 binaryOperatorTest = (qi::lit("and") >> afterOperator) | (qi::lit("or") >> afterOperator);
0294 binaryOperator =
0295 (qi::lit("and") >> afterOperator)[addOperatorAnd] | (qi::lit("or") >> afterOperator)[addOperatorOr];
0296 expression = binaryOperand % binaryOperator;
0297 }
0298
0299 private:
0300 qi::rule<Iterator> pathName;
0301 qi::rule<Iterator, ascii::space_type> binaryOperand;
0302 qi::rule<Iterator> afterOperator;
0303 qi::rule<Iterator> unaryOperator;
0304 qi::rule<Iterator> binaryOperatorTest;
0305 qi::rule<Iterator> binaryOperator;
0306 qi::rule<Iterator, ascii::space_type> expression;
0307
0308 ShuntingYardAlgorithm* algorithm_;
0309 };
0310 }
0311
0312 using namespace l1t;
0313
0314 class L1GTAlgoBlockProducer : public edm::stream::EDProducer<> {
0315 public:
0316 explicit L1GTAlgoBlockProducer(const edm::ParameterSet&);
0317 ~L1GTAlgoBlockProducer() override = default;
0318
0319 static void fillDescriptions(edm::ConfigurationDescriptions&);
0320
0321 void beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) override;
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 };
0329
0330 void produce(edm::Event&, const edm::EventSetup&) override;
0331
0332 edm::GetterOfProducts<P2GTCandidateVectorRef> getterOfPassedReferences_;
0333 std::map<std::string, AlgoDefinition> algoDefinitions_;
0334 };
0335
0336 void L1GTAlgoBlockProducer::fillDescriptions(edm::ConfigurationDescriptions& description) {
0337 edm::ParameterSetDescription algoDesc;
0338 algoDesc.add<std::string>("name", "");
0339 algoDesc.add<std::string>("expression");
0340
0341 edm::ParameterSetDescription desc;
0342 desc.addVPSet("algorithms", algoDesc);
0343
0344 description.addWithDefaultLabel(desc);
0345 }
0346
0347 L1GTAlgoBlockProducer::L1GTAlgoBlockProducer(const edm::ParameterSet& config)
0348 : getterOfPassedReferences_(edm::TypeMatch(), this) {
0349 edm::ConsumesCollector iC(consumesCollector());
0350
0351 for (const auto& algoConfig : config.getParameterSetVector("algorithms")) {
0352 const std::string logicalExpression = algoConfig.getParameter<std::string>("expression");
0353 std::string name = algoConfig.getParameter<std::string>("name");
0354 if (name.empty()) {
0355 name = logicalExpression;
0356 }
0357
0358 pathStatusExpression::ShuntingYardAlgorithm shuntingYardAlgorithm;
0359 pathStatusExpression::Grammar<std::string::const_iterator> grammar(&shuntingYardAlgorithm);
0360
0361 auto it = logicalExpression.cbegin();
0362 if (!qi::phrase_parse(it, logicalExpression.cend(), grammar, ascii::space) || (it != logicalExpression.cend())) {
0363 throw cms::Exception("Configuration") << "Syntax error in logical expression. Here is an example of how\n"
0364 << "the syntax should look:\n"
0365 << " \"path1 and not (path2 or not path3)\"\n"
0366 << "The expression must contain alternating appearances of operands\n"
0367 << "which are path names and binary operators which can be \'and\'\n"
0368 << "or \'or\', with a path name at the beginning and end. There\n"
0369 << "must be at least one path name. In addition to the alternating\n"
0370 << "path names and binary operators, the unary operator \'not\' can\n"
0371 << "be inserted before a path name or a begin parenthesis.\n"
0372 << "Parentheses are allowed. Parentheses must come in matching pairs.\n"
0373 << "Matching begin and end parentheses must contain a complete and\n"
0374 << "syntactically correct logical expression. There must be at least\n"
0375 << "one space or parenthesis between operators and path names. Extra\n"
0376 << "space is ignored and OK. Path names can only contain upper and\n"
0377 << "lower case letters, numbers, and underscores. A path name cannot\n"
0378 << "be the same as an operator name.\n";
0379 }
0380
0381 AlgoDefinition definition;
0382
0383 for (const std::string& pathName : shuntingYardAlgorithm.pathNames()) {
0384 definition.pathNames_.push_back(pathName);
0385 }
0386
0387 definition.evaluator_ = shuntingYardAlgorithm.finish();
0388
0389 definition.evaluator_->init(iC);
0390 algoDefinitions_.emplace(std::move(name), std::move(definition));
0391 }
0392
0393 callWhenNewProductsRegistered(getterOfPassedReferences_);
0394 produces<P2GTAlgoBlockCollection>();
0395 }
0396
0397 void L1GTAlgoBlockProducer::beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) {
0398 const std::string& pName = edm::Service<edm::service::TriggerNamesService>()->getProcessName();
0399
0400 edm::ProcessConfiguration cfg;
0401
0402 iRun.processHistory().getConfigurationForProcess(pName, cfg);
0403
0404 const edm::ParameterSet* pset = edm::pset::Registry::instance()->getMapped(cfg.parameterSetID());
0405
0406 for (auto& [name, algoDef] : algoDefinitions_) {
0407 for (const std::string& pathName : algoDef.pathNames_) {
0408 if (pset->existsAs<std::vector<std::string>>(pathName)) {
0409 const auto& modules = pset->getParameter<std::vector<std::string>>(pathName);
0410 for (const auto& mod : modules) {
0411 if (mod.front() != std::string("-") && pset->exists(mod)) {
0412 const auto& modPSet = pset->getParameterSet(mod);
0413 if (modPSet.getParameter<std::string>("@module_edm_type") == "EDFilter") {
0414 if (modPSet.getParameter<std::string>("@module_type") == "L1GTSingleObjectCond") {
0415 algoDef.filtModules_.insert({mod, modPSet.getParameter<edm::InputTag>("tag").instance()});
0416 } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTDoubleObjectCond") {
0417 algoDef.filtModules_.insert(
0418 {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0419 algoDef.filtModules_.insert(
0420 {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0421 } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTTripleObjectCond") {
0422 algoDef.filtModules_.insert(
0423 {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0424 algoDef.filtModules_.insert(
0425 {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0426 algoDef.filtModules_.insert(
0427 {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
0428 } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTQuadObjectCond") {
0429 algoDef.filtModules_.insert(
0430 {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
0431 algoDef.filtModules_.insert(
0432 {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
0433 algoDef.filtModules_.insert(
0434 {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
0435 algoDef.filtModules_.insert(
0436 {mod, modPSet.getParameterSet("collection4").getParameter<edm::InputTag>("tag").instance()});
0437 }
0438 }
0439 }
0440 }
0441 }
0442 }
0443 }
0444 }
0445
0446 void L1GTAlgoBlockProducer::produce(edm::Event& event, const edm::EventSetup& eventSetup) {
0447 std::vector<edm::Handle<P2GTCandidateVectorRef>> handles;
0448 getterOfPassedReferences_.fillHandles(event, handles);
0449
0450 std::unique_ptr<P2GTAlgoBlockCollection> algoCollection = std::make_unique<P2GTAlgoBlockCollection>();
0451 algoCollection->reserve(algoDefinitions_.size());
0452
0453 for (const auto& [name, algoDef] : algoDefinitions_) {
0454 bool initial = algoDef.evaluator_->evaluate(event);
0455
0456
0457 P2GTCandidateVectorRef trigObjects;
0458
0459 if (initial) {
0460 for (const auto& handle : handles) {
0461 const std::string& module = handle.provenance()->moduleLabel();
0462 const std::string& instance = handle.provenance()->productInstanceName();
0463
0464 if (algoDef.filtModules_.count({module, instance}) > 0) {
0465 trigObjects.insert(trigObjects.end(), handle->begin(), handle->end());
0466 }
0467 }
0468 }
0469
0470 algoCollection->emplace_back(name, initial, initial, initial, std::move(trigObjects));
0471 }
0472
0473 event.put(std::move(algoCollection));
0474 }
0475
0476 DEFINE_FWK_MODULE(L1GTAlgoBlockProducer);