CMS 3D CMS Logo

L1GTAlgoBlockProducer.cc
Go to the documentation of this file.
6 
9 
12 
16 
27 
28 #include <boost/spirit/include/qi.hpp>
29 
32 
33 #include <string>
34 #include <memory>
35 #include <utility>
36 #include <map>
37 #include <vector>
38 #include <set>
39 #include <tuple>
40 
43 namespace qi = boost::spirit::qi;
44 namespace ascii = boost::spirit::ascii;
45 
47  class Evaluator {
48  public:
49  virtual ~Evaluator() {}
50 
52  virtual EvaluatorType type() const = 0;
53 
54  virtual const char* pathName() const { return ""; }
55 
56  virtual void setLeft(std::unique_ptr<Evaluator>&&) {}
57  virtual void setRight(std::unique_ptr<Evaluator>&&) {}
58 
59  virtual void print(std::ostream& out, unsigned int indentation) const {}
60  virtual void init(edm::ConsumesCollector&) {}
61  virtual bool evaluate(edm::Event const& event) const { return true; };
62  };
63 
64  class Operand : public Evaluator {
65  public:
66  Operand(std::vector<char> const& pathName) : pathName_(pathName.begin(), pathName.end()) {}
67 
68  EvaluatorType type() const override { return Name; }
69 
70  void print(std::ostream& out, unsigned int indentation) const override {
71  out << std::string(indentation, ' ') << pathName_ << "\n";
72  }
73 
75 
76  bool evaluate(edm::Event const& event) const override { return event.get(token_).accept(); }
77 
78  private:
81  };
82 
83  class NotOperator : public Evaluator {
84  public:
85  EvaluatorType type() const override { return Not; }
86 
87  void setLeft(std::unique_ptr<Evaluator>&& v) override { operand_ = std::move(v); }
88 
89  void print(std::ostream& out, unsigned int indentation) const override {
90  out << std::string(indentation, ' ') << "not\n";
91  operand_->print(out, indentation + 4);
92  }
93 
94  void init(edm::ConsumesCollector& iC) override { operand_->init(iC); }
95 
96  bool evaluate(edm::Event const& event) const override { return !operand_->evaluate(event); }
97 
98  private:
100  };
101 
102  template <typename T>
103  class BinaryOperator : public Evaluator {
104  public:
105  EvaluatorType type() const override;
106 
107  void setLeft(std::unique_ptr<Evaluator>&& v) override { left_ = std::move(v); }
108  void setRight(std::unique_ptr<Evaluator>&& v) override { right_ = std::move(v); }
109 
110  void print(std::ostream& out, unsigned int indentation) const override;
111 
112  void init(edm::ConsumesCollector& iC) override {
113  left_->init(iC);
114  right_->init(iC);
115  }
116 
117  bool evaluate(edm::Event const& event) const override {
118  T op;
119  return op(left_->evaluate(event), right_->evaluate(event));
120  }
121 
122  private:
125  };
126 
127  template <>
129  return And;
130  }
131 
132  template <>
134  return Or;
135  }
136 
137  template <>
138  void BinaryOperator<std::logical_and<bool>>::print(std::ostream& out, unsigned int indentation) const {
139  out << std::string(indentation, ' ') << "and\n";
140  left_->print(out, indentation + 4);
141  right_->print(out, indentation + 4);
142  }
143  template <>
144  void BinaryOperator<std::logical_or<bool>>::print(std::ostream& out, unsigned int indentation) const {
145  out << std::string(indentation, ' ') << "or\n";
146  left_->print(out, indentation + 4);
147  right_->print(out, indentation + 4);
148  }
149 
152 
153  class BeginParenthesis : public Evaluator {
154  public:
155  EvaluatorType type() const override { return BeginParen; }
156  };
157 
158  // This class exists to properly handle the precedence of the
159  // operators and also handle the order of operations specified
160  // by parentheses. (search for shunting yard algorithm on the
161  // internet for a description of this algorithm)
163  public:
164  void addPathName(std::vector<char> const& s) {
165  operandStack.push_back(std::make_unique<Operand>(s));
166  pathNames_.emplace_back(s.begin(), s.end());
167  }
168 
169  void addOperatorNot() {
170  if (operatorStack.empty() || operatorStack.back()->type() != Evaluator::Not) {
171  operatorStack.push_back(std::make_unique<NotOperator>());
172  } else {
173  // Two Not operations in a row cancel and are the same as no operation at all.
174  operatorStack.pop_back();
175  }
176  }
177 
179  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
180  backEvaluator->setRight(std::move(operandStack.back()));
181  operandStack.pop_back();
182  backEvaluator->setLeft(std::move(operandStack.back()));
183  operandStack.pop_back();
184  operandStack.push_back(std::move(backEvaluator));
185  operatorStack.pop_back();
186  }
187 
189  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
190  backEvaluator->setLeft(std::move(operandStack.back()));
191  operandStack.pop_back();
192  operandStack.push_back(std::move(backEvaluator));
193  operatorStack.pop_back();
194  }
195 
196  void addOperatorAnd() {
197  while (!operatorStack.empty()) {
198  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
199  if (backEvaluator->type() == Evaluator::And) {
201  } else if (backEvaluator->type() == Evaluator::Not) {
202  moveNotOperator();
203  } else {
204  break;
205  }
206  }
207  operatorStack.push_back(std::make_unique<AndOperator>());
208  }
209 
210  void addOperatorOr() {
211  while (!operatorStack.empty()) {
212  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
213  if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
215  } else if (backEvaluator->type() == Evaluator::Not) {
216  moveNotOperator();
217  } else {
218  break;
219  }
220  }
221  operatorStack.push_back(std::make_unique<OrOperator>());
222  }
223 
224  void addBeginParenthesis() { operatorStack.push_back(std::make_unique<BeginParenthesis>()); }
225 
227  while (!operatorStack.empty()) {
228  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
229  if (backEvaluator->type() == Evaluator::BeginParen) {
230  operatorStack.pop_back();
231  break;
232  }
233  if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
235  } else if (backEvaluator->type() == Evaluator::Not) {
236  moveNotOperator();
237  }
238  }
239  }
240 
241  std::unique_ptr<Evaluator> finish() {
242  while (!operatorStack.empty()) {
243  std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
244  // Just a sanity check. The grammar defined for the boost Spirit parser
245  // should catch any errors of this type before we get here.
246  if (backEvaluator->type() == Evaluator::BeginParen) {
247  throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
248  }
249  if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
251  } else if (backEvaluator->type() == Evaluator::Not) {
252  moveNotOperator();
253  }
254  }
255  // Just a sanity check. The grammar defined for the boost Spirit parser
256  // should catch any errors of this type before we get here.
257  if (!operatorStack.empty() || operandStack.size() != 1U) {
258  throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
259  }
260  std::unique_ptr<Evaluator> temp = std::move(operandStack.back());
261  operandStack.pop_back();
262  return temp;
263  }
264 
265  const std::vector<std::string>& pathNames() { return pathNames_; }
266 
267  private:
268  std::vector<std::string> pathNames_;
269  std::vector<std::unique_ptr<Evaluator>> operandStack;
270  std::vector<std::unique_ptr<Evaluator>> operatorStack;
271  };
272 
273  // Use boost Spirit to parse the logical expression character string
274  template <typename Iterator>
275  class Grammar : public qi::grammar<Iterator, ascii::space_type> {
276  public:
278  // setup functors that call into shunting algorithm while parsing the logical expression
279  auto addPathName = std::bind(&ShuntingYardAlgorithm::addPathName, algorithm_, std::placeholders::_1);
280  auto addOperatorNot = std::bind(&ShuntingYardAlgorithm::addOperatorNot, algorithm_);
281  auto addOperatorAnd = std::bind(&ShuntingYardAlgorithm::addOperatorAnd, algorithm_);
282  auto addOperatorOr = std::bind(&ShuntingYardAlgorithm::addOperatorOr, algorithm_);
283  auto addBeginParenthesis = std::bind(&ShuntingYardAlgorithm::addBeginParenthesis, algorithm_);
284  auto addEndParenthesis = std::bind(&ShuntingYardAlgorithm::addEndParenthesis, algorithm_);
285 
286  // Define the syntax allowed in the logical expressions
287  pathName = !unaryOperator >> !binaryOperatorTest >> (+qi::char_("a-zA-Z0-9_"))[addPathName];
288  binaryOperand = (qi::lit('(')[addBeginParenthesis] >> expression >> qi::lit(')')[addEndParenthesis]) |
289  (unaryOperator[addOperatorNot] >> binaryOperand) | pathName;
290  afterOperator = ascii::space | &qi::lit('(') | &qi::eoi;
291  unaryOperator = qi::lit("not") >> afterOperator;
292  // The only difference in the next two is that one calls a functor and the other does not
293  binaryOperatorTest = (qi::lit("and") >> afterOperator) | (qi::lit("or") >> afterOperator);
295  (qi::lit("and") >> afterOperator)[addOperatorAnd] | (qi::lit("or") >> afterOperator)[addOperatorOr];
297  }
298 
299  private:
300  qi::rule<Iterator> pathName;
301  qi::rule<Iterator, ascii::space_type> binaryOperand;
302  qi::rule<Iterator> afterOperator;
303  qi::rule<Iterator> unaryOperator;
304  qi::rule<Iterator> binaryOperatorTest;
305  qi::rule<Iterator> binaryOperator;
306  qi::rule<Iterator, ascii::space_type> expression;
307 
309  };
310 } // namespace pathStatusExpression
311 
312 using namespace l1t;
313 
315 public:
316  explicit L1GTAlgoBlockProducer(const edm::ParameterSet&);
317  ~L1GTAlgoBlockProducer() override = default;
318 
320 
321  void beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) override;
322 
323 private:
324  struct AlgoDefinition {
326  std::vector<std::string> pathNames_;
327  std::set<std::tuple<std::string, std::string>> filtModules_;
328  };
329 
330  void produce(edm::Event&, const edm::EventSetup&) override;
331 
333  std::map<std::string, AlgoDefinition> algoDefinitions_;
334 };
335 
338  algoDesc.add<std::string>("name", "");
339  algoDesc.add<std::string>("expression");
340 
342  desc.addVPSet("algorithms", algoDesc);
343 
344  description.addWithDefaultLabel(desc);
345 }
346 
348  : getterOfPassedReferences_(edm::TypeMatch(), this) {
349  edm::ConsumesCollector iC(consumesCollector());
350 
351  for (const auto& algoConfig : config.getParameterSetVector("algorithms")) {
352  const std::string logicalExpression = algoConfig.getParameter<std::string>("expression");
353  std::string name = algoConfig.getParameter<std::string>("name");
354  if (name.empty()) {
356  }
357 
358  pathStatusExpression::ShuntingYardAlgorithm shuntingYardAlgorithm;
359  pathStatusExpression::Grammar<std::string::const_iterator> grammar(&shuntingYardAlgorithm);
360 
361  auto it = logicalExpression.cbegin();
362  if (!qi::phrase_parse(it, logicalExpression.cend(), grammar, ascii::space) || (it != logicalExpression.cend())) {
363  throw cms::Exception("Configuration") << "Syntax error in logical expression. Here is an example of how\n"
364  << "the syntax should look:\n"
365  << " \"path1 and not (path2 or not path3)\"\n"
366  << "The expression must contain alternating appearances of operands\n"
367  << "which are path names and binary operators which can be \'and\'\n"
368  << "or \'or\', with a path name at the beginning and end. There\n"
369  << "must be at least one path name. In addition to the alternating\n"
370  << "path names and binary operators, the unary operator \'not\' can\n"
371  << "be inserted before a path name or a begin parenthesis.\n"
372  << "Parentheses are allowed. Parentheses must come in matching pairs.\n"
373  << "Matching begin and end parentheses must contain a complete and\n"
374  << "syntactically correct logical expression. There must be at least\n"
375  << "one space or parenthesis between operators and path names. Extra\n"
376  << "space is ignored and OK. Path names can only contain upper and\n"
377  << "lower case letters, numbers, and underscores. A path name cannot\n"
378  << "be the same as an operator name.\n";
379  }
380 
381  AlgoDefinition definition;
382 
383  for (const std::string& pathName : shuntingYardAlgorithm.pathNames()) {
384  definition.pathNames_.push_back(pathName);
385  }
386 
387  definition.evaluator_ = shuntingYardAlgorithm.finish();
388 
389  definition.evaluator_->init(iC);
390  algoDefinitions_.emplace(std::move(name), std::move(definition));
391  }
392 
393  callWhenNewProductsRegistered(getterOfPassedReferences_);
394  produces<P2GTAlgoBlockCollection>();
395 }
396 
397 void L1GTAlgoBlockProducer::beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) {
399 
401 
403 
404  const edm::ParameterSet* pset = edm::pset::Registry::instance()->getMapped(cfg.parameterSetID());
405 
406  for (auto& [name, algoDef] : algoDefinitions_) {
407  for (const std::string& pathName : algoDef.pathNames_) {
408  if (pset->existsAs<std::vector<std::string>>(pathName)) {
409  const auto& modules = pset->getParameter<std::vector<std::string>>(pathName);
410  for (const auto& mod : modules) {
411  if (mod.front() != std::string("-") && pset->exists(mod)) {
412  const auto& modPSet = pset->getParameterSet(mod);
413  if (modPSet.getParameter<std::string>("@module_edm_type") == "EDFilter") {
414  if (modPSet.getParameter<std::string>("@module_type") == "L1GTSingleObjectCond") {
415  algoDef.filtModules_.insert({mod, modPSet.getParameter<edm::InputTag>("tag").instance()});
416  } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTDoubleObjectCond") {
417  algoDef.filtModules_.insert(
418  {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
419  algoDef.filtModules_.insert(
420  {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
421  } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTTripleObjectCond") {
422  algoDef.filtModules_.insert(
423  {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
424  algoDef.filtModules_.insert(
425  {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
426  algoDef.filtModules_.insert(
427  {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
428  } else if (modPSet.getParameter<std::string>("@module_type") == "L1GTQuadObjectCond") {
429  algoDef.filtModules_.insert(
430  {mod, modPSet.getParameterSet("collection1").getParameter<edm::InputTag>("tag").instance()});
431  algoDef.filtModules_.insert(
432  {mod, modPSet.getParameterSet("collection2").getParameter<edm::InputTag>("tag").instance()});
433  algoDef.filtModules_.insert(
434  {mod, modPSet.getParameterSet("collection3").getParameter<edm::InputTag>("tag").instance()});
435  algoDef.filtModules_.insert(
436  {mod, modPSet.getParameterSet("collection4").getParameter<edm::InputTag>("tag").instance()});
437  }
438  }
439  }
440  }
441  }
442  }
443  }
444 }
445 
447  std::vector<edm::Handle<P2GTCandidateVectorRef>> handles;
449 
450  std::unique_ptr<P2GTAlgoBlockCollection> algoCollection = std::make_unique<P2GTAlgoBlockCollection>();
451  algoCollection->reserve(algoDefinitions_.size());
452 
453  for (const auto& [name, algoDef] : algoDefinitions_) {
454  bool initial = algoDef.evaluator_->evaluate(event);
455  // TODO apply prescale and bunch mask
456 
457  P2GTCandidateVectorRef trigObjects;
458 
459  if (initial) {
460  for (const auto& handle : handles) {
461  const std::string& module = handle.provenance()->moduleLabel();
462  const std::string& instance = handle.provenance()->productInstanceName();
463 
464  if (algoDef.filtModules_.count({module, instance}) > 0) {
465  trigObjects.insert(trigObjects.end(), handle->begin(), handle->end());
466  }
467  }
468  }
469 
470  algoCollection->emplace_back(name, initial, initial, initial, std::move(trigObjects));
471  }
472 
473  event.put(std::move(algoCollection));
474 }
475 
virtual bool evaluate(edm::Event const &event) const
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
qi::rule< Iterator, ascii::space_type > expression
static void fillDescriptions(edm::ConfigurationDescriptions &)
bool getMapped(key_type const &k, value_type &result) const
Definition: Registry.cc:17
void setRight(std::unique_ptr< Evaluator > &&v) override
std::set< std::tuple< std::string, std::string > > filtModules_
void addPathName(std::vector< char > const &s)
static PFTauRenderPlugin instance
virtual void setRight(std::unique_ptr< Evaluator > &&)
edm::propagate_const< std::unique_ptr< pathStatusExpression::Evaluator > > evaluator_
void init(edm::ConsumesCollector &iC) override
virtual void init(edm::ConsumesCollector &)
delete x;
Definition: CaloConfig.h:22
Definition: config.py:1
std::vector< std::unique_ptr< Evaluator > > operandStack
void produce(edm::Event &, const edm::EventSetup &) override
bool getConfigurationForProcess(std::string const &name, ProcessConfiguration &config) const
void print(std::ostream &out, unsigned int indentation) const override
std::map< std::string, AlgoDefinition > algoDefinitions_
void setLeft(std::unique_ptr< Evaluator > &&v) override
edm::EDGetTokenT< edm::PathStatus > token_
edm::propagate_const< std::unique_ptr< Evaluator > > left_
bool evaluate(edm::Event const &event) const override
edm::propagate_const< std::unique_ptr< Evaluator > > right_
void init(edm::ConsumesCollector &iC) override
L1GTAlgoBlockProducer(const edm::ParameterSet &)
std::vector< BaseVolumeHandle * > handles
void print(std::ostream &out, unsigned int indentation) const override
EvaluatorType type() const override
edm::propagate_const< std::unique_ptr< Evaluator > > operand_
virtual EvaluatorType type() const =0
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
EvaluatorType type() const override
Operand(std::vector< char > const &pathName)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
edm::GetterOfProducts< P2GTCandidateVectorRef > getterOfPassedReferences_
ProcessHistory const & processHistory() const
Definition: Run.cc:115
ParameterDescriptionBase * add(U const &iLabel, T const &value)
virtual const char * pathName() const
def getProcessName(pdgGen, requiredNumberOfGeneratedObjects)
void fillHandles(ProductContainer const &productContainer, std::vector< edm::Handle< T >> &handles) const
void print(std::ostream &out, unsigned int indentation) const override
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
virtual void print(std::ostream &out, unsigned int indentation) const
bool evaluate(edm::Event const &event) const override
void init(edm::ConsumesCollector &iC) override
qi::rule< Iterator, ascii::space_type > binaryOperand
virtual void setLeft(std::unique_ptr< Evaluator > &&)
EvaluatorType type() const override
std::vector< P2GTCandidateRef > P2GTCandidateVectorRef
Definition: P2GTCandidate.h:20
std::vector< std::unique_ptr< Evaluator > > operatorStack
bool evaluate(edm::Event const &event) const override
HLT enums.
void setLeft(std::unique_ptr< Evaluator > &&v) override
HLTPathStatus PathStatus
Definition: PathStatus.h:7
const std::vector< std::string > & pathNames()
long double T
T mod(const T &a, const T &b)
Definition: ecalDccMap.h:4
Grammar(ShuntingYardAlgorithm *algorithm)
ShuntingYardAlgorithm * algorithm_
def move(src, dest)
Definition: eostools.py:511
static Registry * instance()
Definition: Registry.cc:12
Definition: event.py:1
Definition: Run.h:45
void beginRun(const edm::Run &iRun, const edm::EventSetup &iSetup) override