diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionConstant.h b/HLTrigger/HLTcore/interface/TriggerExpressionConstant.h index 7636b96a1c17e..64d710aeffb3f 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionConstant.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionConstant.h @@ -1,5 +1,5 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionConstant_h -#define HLTrigger_HLTfilters_TriggerExpressionConstant_h +#ifndef HLTrigger_HLTcore_TriggerExpressionConstant_h +#define HLTrigger_HLTcore_TriggerExpressionConstant_h #include "HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h" @@ -13,7 +13,7 @@ namespace triggerExpression { bool operator()(const Data& data) const override { return m_value; } - void dump(std::ostream& out) const override { out << (m_value ? "TRUE" : "FALSE"); } + void dump(std::ostream& out, bool const ignoreMasks = false) const override { out << (m_value ? "TRUE" : "FALSE"); } private: bool m_value; @@ -21,4 +21,4 @@ namespace triggerExpression { } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionConstant_h +#endif // HLTrigger_HLTcore_TriggerExpressionConstant_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionData.h b/HLTrigger/HLTcore/interface/TriggerExpressionData.h index 918d4dc99a8d0..b4181e5bbcdd7 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionData.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionData.h @@ -1,5 +1,5 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionData_h -#define HLTrigger_HLTfilters_TriggerExpressionData_h +#ifndef HLTrigger_HLTcore_TriggerExpressionData_h +#define HLTrigger_HLTcore_TriggerExpressionData_h #include "FWCore/Framework/interface/ConsumesCollector.h" #include "FWCore/Utilities/interface/InputTag.h" @@ -220,4 +220,4 @@ namespace triggerExpression { } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionData_h +#endif // HLTrigger_HLTcore_TriggerExpressionData_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h b/HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h index 81e8e54d8e728..09ff7e3d2f2ad 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h @@ -1,9 +1,10 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionEvaluator_h -#define HLTrigger_HLTfilters_TriggerExpressionEvaluator_h +#ifndef HLTrigger_HLTcore_TriggerExpressionEvaluator_h +#define HLTrigger_HLTcore_TriggerExpressionEvaluator_h #include #include #include +#include namespace triggerExpression { @@ -13,6 +14,9 @@ namespace triggerExpression { public: Evaluator() = default; + // virtual destructor + virtual ~Evaluator() = default; + // check if the data satisfies the logical expression virtual bool operator()(const Data& data) const = 0; @@ -22,11 +26,22 @@ namespace triggerExpression { // list CMSSW path patterns associated to the logical expression virtual std::vector patterns() const { return {}; } + // list of triggers associated to the Evaluator (filled only for certain derived classes) + virtual std::vector> triggers() const { return {}; } + // dump the logical expression to the output stream - virtual void dump(std::ostream& out) const = 0; + virtual void dump(std::ostream& out, bool const ignoreMasks = false) const = 0; - // virtual destructor - virtual ~Evaluator() = default; + // apply masks based on another Evaluator + virtual void mask(Evaluator const&) {} + + // methods to control m_masksEnabled boolean + virtual bool masksEnabled() const { return m_masksEnabled; } + virtual void enableMasks() { m_masksEnabled = true; } + virtual void disableMasks() { m_masksEnabled = false; } + + private: + bool m_masksEnabled = false; }; inline std::ostream& operator<<(std::ostream& out, const Evaluator& eval) { @@ -36,4 +51,4 @@ namespace triggerExpression { } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionEvaluator_h +#endif // HLTrigger_HLTcore_TriggerExpressionEvaluator_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionL1uGTReader.h b/HLTrigger/HLTcore/interface/TriggerExpressionL1uGTReader.h index dcfadcf7199b1..2f98e7424c5c2 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionL1uGTReader.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionL1uGTReader.h @@ -1,8 +1,5 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionL1uGTReader_h -#define HLTrigger_HLTfilters_TriggerExpressionL1uGTReader_h - -#include -#include +#ifndef HLTrigger_HLTcore_TriggerExpressionL1uGTReader_h +#define HLTrigger_HLTcore_TriggerExpressionL1uGTReader_h #include "HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h" @@ -10,20 +7,27 @@ namespace triggerExpression { class L1uGTReader : public Evaluator { public: - L1uGTReader(const std::string& pattern) : m_pattern{pattern}, m_triggers{}, m_initialised{false} {} + L1uGTReader(const std::string& pattern) + : m_pattern{pattern}, m_triggers{}, m_triggersAfterMasking{}, m_initialised{false} {} bool operator()(const Data& data) const override; void init(const Data& data) override; - void dump(std::ostream& out) const override; + void dump(std::ostream& out, bool const ignoreMasks = false) const override; + + void mask(Evaluator const& eval) override; + + std::vector> triggers() const override { return m_triggers; } + std::vector> triggersAfterMasking() const { return m_triggersAfterMasking; } private: std::string m_pattern; std::vector> m_triggers; + std::vector> m_triggersAfterMasking; bool m_initialised; }; } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionL1uGTReader_h +#endif // HLTrigger_HLTcore_TriggerExpressionL1uGTReader_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionOperators.h b/HLTrigger/HLTcore/interface/TriggerExpressionOperators.h index de3a18abd3e33..7971625432b2c 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionOperators.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionOperators.h @@ -1,7 +1,8 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionOperators_h -#define HLTrigger_HLTfilters_TriggerExpressionOperators_h +#ifndef HLTrigger_HLTcore_TriggerExpressionOperators_h +#define HLTrigger_HLTcore_TriggerExpressionOperators_h #include + #include "HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h" namespace triggerExpression { @@ -14,6 +15,9 @@ namespace triggerExpression { // initialize the depending modules void init(const Data& data) override { m_arg->init(data); } + // apply mask(s) to the Evaluator + void mask(Evaluator const& arg) override { m_arg->mask(arg); } + // return the patterns from the depending modules std::vector patterns() const override { return m_arg->patterns(); } @@ -32,6 +36,12 @@ namespace triggerExpression { m_arg2->init(data); } + // apply mask(s) to the Evaluators + void mask(Evaluator const& arg) override { + m_arg1->mask(arg); + m_arg2->mask(arg); + } + // return the patterns from the depending modules std::vector patterns() const override { std::vector patterns = m_arg1->patterns(); @@ -54,10 +64,10 @@ namespace triggerExpression { bool operator()(const Data& data) const override { return not(*m_arg)(data); } - void dump(std::ostream& out) const override { + void dump(std::ostream& out, bool const ignoreMasks = false) const override { out << '('; out << "NOT "; - m_arg->dump(out); + m_arg->dump(out, ignoreMasks); out << ')'; } }; @@ -67,17 +77,17 @@ namespace triggerExpression { OperatorAnd(Evaluator* arg1, Evaluator* arg2) : BinaryOperator(arg1, arg2) {} bool operator()(const Data& data) const override { - // force the execution af both arguments, otherwise precalers won't work properly + // force the execution of both arguments, otherwise prescalers won't work properly bool r1 = (*m_arg1)(data); bool r2 = (*m_arg2)(data); return r1 and r2; } - void dump(std::ostream& out) const override { + void dump(std::ostream& out, bool const ignoreMasks = false) const override { out << '('; - m_arg1->dump(out); + m_arg1->dump(out, ignoreMasks); out << " AND "; - m_arg2->dump(out); + m_arg2->dump(out, ignoreMasks); out << ')'; } }; @@ -87,17 +97,17 @@ namespace triggerExpression { OperatorOr(Evaluator* arg1, Evaluator* arg2) : BinaryOperator(arg1, arg2) {} bool operator()(const Data& data) const override { - // force the execution af both arguments, otherwise precalers won't work properly + // force the execution of both arguments, otherwise prescalers won't work properly bool r1 = (*m_arg1)(data); bool r2 = (*m_arg2)(data); return r1 or r2; } - void dump(std::ostream& out) const override { + void dump(std::ostream& out, bool const ignoreMasks = false) const override { out << '('; - m_arg1->dump(out); + m_arg1->dump(out, ignoreMasks); out << " OR "; - m_arg2->dump(out); + m_arg2->dump(out, ignoreMasks); out << ')'; } }; @@ -107,19 +117,47 @@ namespace triggerExpression { OperatorXor(Evaluator* arg1, Evaluator* arg2) : BinaryOperator(arg1, arg2) {} bool operator()(const Data& data) const override { - // force the execution af both arguments, otherwise precalers won't work properly + // force the execution of both arguments, otherwise prescalers won't work properly bool r1 = (*m_arg1)(data); bool r2 = (*m_arg2)(data); return r1 xor r2; } - void dump(std::ostream& out) const override { - m_arg1->dump(out); + void dump(std::ostream& out, bool const ignoreMasks = false) const override { + out << '('; + m_arg1->dump(out, ignoreMasks); out << " XOR "; - m_arg2->dump(out); + m_arg2->dump(out, ignoreMasks); + out << ')'; + } + }; + + class OperatorMasking : public BinaryOperator { + public: + OperatorMasking(Evaluator* arg1, Evaluator* arg2) : BinaryOperator(arg1, arg2) {} + + bool operator()(const Data& data) const override { return (*m_arg1)(data); } + + void init(const Data& data) override { + m_arg1->init(data); + m_arg2->init(data); + m_arg1->mask(*m_arg2); + } + + // apply mask(s) only to the first Evaluator + // (the second Evaluator is not used in the decision of OperatorMasking) + void mask(Evaluator const& arg) override { m_arg1->mask(arg); } + + void dump(std::ostream& out, bool const ignoreMasks = false) const override { + out << '('; + // ignore masks on the first Evaluator to dump the full logical expression + m_arg1->dump(out, true); + out << " MASKING "; + m_arg2->dump(out, ignoreMasks); + out << ')'; } }; } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionOperators_h +#endif // HLTrigger_HLTcore_TriggerExpressionOperators_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionParser.h b/HLTrigger/HLTcore/interface/TriggerExpressionParser.h index 5c107d16c0933..ac81d2d21d7ad 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionParser.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionParser.h @@ -1,5 +1,5 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionParser_h -#define HLTrigger_HLTfilters_TriggerExpressionParser_h +#ifndef HLTrigger_HLTcore_TriggerExpressionParser_h +#define HLTrigger_HLTcore_TriggerExpressionParser_h // Note: this requires Boost 1.41 or higher, for Spirit 2.1 or higher #include @@ -25,20 +25,27 @@ namespace triggerExpression { Parser() : Parser::base_type(expression) { auto delimiter = qi::copy(qi::eoi | !qi::char_("a-zA-Z0-9_*?")); - token_true = qi::lexeme[qi::lit("TRUE") >> delimiter]; - token_false = qi::lexeme[qi::lit("FALSE") >> delimiter]; - operand_not = qi::lexeme[qi::lit("NOT") >> delimiter]; operand_and = qi::lexeme[qi::lit("AND") >> delimiter]; operand_or = qi::lexeme[qi::lit("OR") >> delimiter]; + operand_masking = qi::lexeme[qi::lit("MASKING") >> delimiter]; + + // "TRUE": keyword to accept all events + token_true = qi::lexeme[qi::lit("TRUE") >> delimiter]; + // "FALSE": keyword to reject all events + token_false = qi::lexeme[qi::lit("FALSE") >> delimiter]; + + // Level-1 Global Trigger decisions: must begin with characters "L1_" token_l1algo %= qi::raw[qi::lexeme["L1_" >> +(qi::char_("a-zA-Z0-9_*?"))]]; - token_path %= qi::raw[qi::lexeme[+(qi::char_("a-zA-Z0-9_*?"))] - operand_not - operand_and - operand_or]; - token = (token_true[qi::_val = new_(true)] | // TRUE - token_false[qi::_val = new_(false)] | // FALSE - token_l1algo[qi::_val = new_(qi::_1)] | // L1_* - token_path[qi::_val = new_(qi::_1)]); // * (except "NOT", "AND" and "OR") + // Decisions of Paths in the CMSSW configuration (e.g. high-level triggers): + // any alphanumeric pattern except for "TRUE", "FALSE", "NOT", "AND", "OR", and "MASKING" + token_path %= qi::raw[qi::lexeme[+(qi::char_("a-zA-Z0-9_*?"))] - token_true - token_false - operand_not - + operand_and - operand_or - operand_masking]; + + token = (token_true[qi::_val = new_(true)] | token_false[qi::_val = new_(false)] | + token_l1algo[qi::_val = new_(qi::_1)] | token_path[qi::_val = new_(qi::_1)]); parenthesis %= ('(' >> expression >> ')'); @@ -50,9 +57,18 @@ namespace triggerExpression { unary = ((operand_not >> unary)[qi::_val = new_(qi::_1)] | operand[qi::_val = qi::_1]); - expression = - unary[qi::_val = qi::_1] >> *((operand_and >> unary)[qi::_val = new_(qi::_val, qi::_1)] | - (operand_or >> unary)[qi::_val = new_(qi::_val, qi::_1)]); + // token_masking is used to restrict the argument (rhs) of the "MASKING" + // operation to Constant[FALSE], L1uGTReader and PathReader evaluators + token_masking = + (token_false[qi::_val = new_(false)] | token_l1algo[qi::_val = new_(qi::_1)] | + token_path[qi::_val = new_(qi::_1)]); + + argument_masking %= (token_masking | ('(' >> argument_masking >> ')')); + + expression = unary[qi::_val = qi::_1] >> + *((operand_and >> unary)[qi::_val = new_(qi::_val, qi::_1)] | + (operand_or >> unary)[qi::_val = new_(qi::_val, qi::_1)] | + (operand_masking >> argument_masking)[qi::_val = new_(qi::_val, qi::_1)]); } private: @@ -66,6 +82,7 @@ namespace triggerExpression { terminal_rule operand_not; terminal_rule operand_and; terminal_rule operand_or; + terminal_rule operand_masking; name_rule token_l1algo; name_rule token_path; @@ -76,6 +93,8 @@ namespace triggerExpression { rule prescale; rule operand; rule unary; + rule token_masking; + rule argument_masking; rule expression; }; @@ -121,4 +140,4 @@ namespace triggerExpression { } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionParser_h +#endif // HLTrigger_HLTcore_TriggerExpressionParser_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h b/HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h index decba2a243aa7..9ea681307a41e 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h @@ -1,8 +1,5 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionPathReader_h -#define HLTrigger_HLTfilters_TriggerExpressionPathReader_h - -#include -#include +#ifndef HLTrigger_HLTcore_TriggerExpressionPathReader_h +#define HLTrigger_HLTcore_TriggerExpressionPathReader_h #include "HLTrigger/HLTcore/interface/TriggerExpressionEvaluator.h" @@ -10,22 +7,29 @@ namespace triggerExpression { class PathReader : public Evaluator { public: - PathReader(const std::string& pattern) : m_pattern{pattern}, m_triggers{}, m_initialised{false} {} + PathReader(const std::string& pattern) + : m_pattern{pattern}, m_triggers{}, m_triggersAfterMasking{}, m_initialised{false} {} bool operator()(const Data& data) const override; void init(const Data& data) override; - std::vector patterns() const override { return std::vector{m_pattern}; } + std::vector patterns() const override { return {m_pattern}; } + + void dump(std::ostream& out, bool const ignoreMasks = false) const override; + + void mask(Evaluator const& eval) override; - void dump(std::ostream& out) const override; + std::vector> triggers() const override { return m_triggers; } + std::vector> triggersAfterMasking() const { return m_triggersAfterMasking; } private: std::string m_pattern; std::vector> m_triggers; + std::vector> m_triggersAfterMasking; bool m_initialised; }; } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionPathReader_h +#endif // HLTrigger_HLTcore_TriggerExpressionPathReader_h diff --git a/HLTrigger/HLTcore/interface/TriggerExpressionPrescaler.h b/HLTrigger/HLTcore/interface/TriggerExpressionPrescaler.h index cc8e6d8294c2d..c7d65e86f3c06 100644 --- a/HLTrigger/HLTcore/interface/TriggerExpressionPrescaler.h +++ b/HLTrigger/HLTcore/interface/TriggerExpressionPrescaler.h @@ -1,8 +1,7 @@ -#ifndef HLTrigger_HLTfilters_TriggerExpressionPrescaler_h -#define HLTrigger_HLTfilters_TriggerExpressionPrescaler_h +#ifndef HLTrigger_HLTcore_TriggerExpressionPrescaler_h +#define HLTrigger_HLTcore_TriggerExpressionPrescaler_h #include "HLTrigger/HLTcore/interface/TriggerExpressionOperators.h" -#include "HLTrigger/HLTcore/interface/TriggerExpressionData.h" namespace triggerExpression { @@ -14,7 +13,11 @@ namespace triggerExpression { void init(const Data& data) override; - void dump(std::ostream& out) const override { out << "(" << (*m_arg) << " / " << m_prescale << ")"; } + void dump(std::ostream& out, bool const ignoreMasks = false) const override { + out << '('; + m_arg->dump(out, ignoreMasks); + out << " / " << m_prescale << ')'; + } private: unsigned int m_prescale; @@ -23,4 +26,4 @@ namespace triggerExpression { } // namespace triggerExpression -#endif // HLTrigger_HLTfilters_TriggerExpressionPrescaler_h +#endif // HLTrigger_HLTcore_TriggerExpressionPrescaler_h diff --git a/HLTrigger/HLTcore/src/TriggerExpressionL1uGTReader.cc b/HLTrigger/HLTcore/src/TriggerExpressionL1uGTReader.cc index 38826ba674500..1a6a0d468d5b3 100644 --- a/HLTrigger/HLTcore/src/TriggerExpressionL1uGTReader.cc +++ b/HLTrigger/HLTcore/src/TriggerExpressionL1uGTReader.cc @@ -3,9 +3,7 @@ #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "FWCore/Utilities/interface/RegexMatch.h" -#include "CondFormats/L1TObjects/interface/L1GtTriggerMask.h" #include "CondFormats/L1TObjects/interface/L1TUtmTriggerMenu.h" -#include "DataFormats/L1GlobalTrigger/interface/L1GlobalTriggerReadoutRecord.h" #include "HLTrigger/HLTcore/interface/TriggerExpressionData.h" #include "HLTrigger/HLTcore/interface/TriggerExpressionL1uGTReader.h" @@ -20,26 +18,31 @@ namespace triggerExpression { if (word.empty()) return false; - for (auto const& trigger : m_triggers) + auto const& triggers = masksEnabled() ? m_triggersAfterMasking : m_triggers; + + for (auto const& trigger : triggers) if (trigger.second < word.size() and word[trigger.second]) return true; return false; } - void L1uGTReader::dump(std::ostream& out) const { + void L1uGTReader::dump(std::ostream& out, bool const ignoreMasks) const { if (not m_initialised) { out << "Uninitialised_L1_Expression"; return; } - if (m_triggers.empty()) { + + auto const& triggers = ignoreMasks or not masksEnabled() ? m_triggers : m_triggersAfterMasking; + + if (triggers.empty()) { out << "FALSE"; - } else if (m_triggers.size() == 1) { - out << m_triggers[0].first; + } else if (triggers.size() == 1) { + out << triggers[0].first; } else { - out << "(" << m_triggers[0].first; - for (unsigned int i = 1; i < m_triggers.size(); ++i) - out << " OR " << m_triggers[i].first; + out << "(" << triggers[0].first; + for (unsigned int i = 1; i < triggers.size(); ++i) + out << " OR " << triggers[i].first; out << ")"; } } @@ -61,14 +64,15 @@ namespace triggerExpression { if (entry != triggerMap.end()) { // single L1 bit m_triggers.push_back(std::make_pair(m_pattern, entry->second.getIndex())); - } else - // trigger not found in the current menu - if (data.shouldThrow()) - throw cms::Exception("Configuration") - << "requested L1 trigger \"" << m_pattern << "\" does not exist in the current L1 menu"; - else - edm::LogWarning("Configuration") << "requested L1 trigger \"" << m_pattern - << "\" does not exist in the current L1 menu"; + } else { + // trigger not found in the current menu + if (data.shouldThrow()) + throw cms::Exception("Configuration") + << "requested L1 trigger \"" << m_pattern << "\" does not exist in the current L1 menu"; + else + edm::LogWarning("Configuration") + << "requested L1 trigger \"" << m_pattern << "\" does not exist in the current L1 menu"; + } } else { // expand wildcards in the pattern bool match = false; @@ -90,7 +94,42 @@ namespace triggerExpression { } } + m_triggersAfterMasking = m_triggers; m_initialised = true; } + void L1uGTReader::mask(Evaluator const& eval) { + auto const& triggersToMask = eval.triggers(); + + if (triggersToMask.empty()) { + edm::LogInfo("NoTriggersToMask") << "\tL1uGTReader[\"" << *this << "\"]::mask(arg = \"" << eval << "\")" + << " failed: arg.triggers() is empty"; + return; + } + + // patterns() is always empty for a L1uGTReader, and not empty for PathReader; + // here, PathReader evaluators are skipped as they shouldn't be used to mask a L1uGTReader + if (not eval.patterns().empty()) { + edm::LogWarning("InvalidArgumentForMasking") + << "\tL1uGTReader[\"" << *this << "\"]::mask(arg = \"" << eval << "\")" + << " failed: arg.patterns() is not empty (arg is not a L1uGTReader)"; + return; + } + + enableMasks(); + + // clang-format off + m_triggersAfterMasking.erase( + std::remove_if( + m_triggersAfterMasking.begin(), + m_triggersAfterMasking.end(), + [&triggersToMask](auto const& foo) { + return std::find(triggersToMask.begin(), triggersToMask.end(), foo) != triggersToMask.end(); + } + ), + m_triggersAfterMasking.end() + ); + // clang-format on + } + } // namespace triggerExpression diff --git a/HLTrigger/HLTcore/src/TriggerExpressionPathReader.cc b/HLTrigger/HLTcore/src/TriggerExpressionPathReader.cc index 0fda7507e34bd..71254f9f514d6 100644 --- a/HLTrigger/HLTcore/src/TriggerExpressionPathReader.cc +++ b/HLTrigger/HLTcore/src/TriggerExpressionPathReader.cc @@ -3,9 +3,8 @@ #include "FWCore/Utilities/interface/RegexMatch.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" -#include "DataFormats/Common/interface/TriggerResults.h" -#include "HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h" #include "HLTrigger/HLTcore/interface/TriggerExpressionData.h" +#include "HLTrigger/HLTcore/interface/TriggerExpressionPathReader.h" namespace triggerExpression { @@ -14,26 +13,31 @@ namespace triggerExpression { if (not data.hasHLT() && not data.usePathStatus()) return false; - for (auto const& trigger : m_triggers) + auto const& triggers = masksEnabled() ? m_triggersAfterMasking : m_triggers; + + for (auto const& trigger : triggers) if (data.passHLT(trigger.second)) return true; return false; } - void PathReader::dump(std::ostream& out) const { + void PathReader::dump(std::ostream& out, bool const ignoreMasks) const { if (not m_initialised) { out << "Uninitialised_Path_Expression"; return; } - if (m_triggers.empty()) { + + auto const& triggers = ignoreMasks or not masksEnabled() ? m_triggers : m_triggersAfterMasking; + + if (triggers.empty()) { out << "FALSE"; - } else if (m_triggers.size() == 1) { - out << m_triggers[0].first; + } else if (triggers.size() == 1) { + out << triggers[0].first; } else { - out << "(" << m_triggers[0].first; - for (unsigned int i = 1; i < m_triggers.size(); ++i) - out << " OR " << m_triggers[i].first; + out << "(" << triggers[0].first; + for (unsigned int i = 1; i < triggers.size(); ++i) + out << " OR " << triggers[i].first; out << ")"; } } @@ -89,7 +93,42 @@ namespace triggerExpression { } } + m_triggersAfterMasking = m_triggers; m_initialised = true; } + void PathReader::mask(Evaluator const& eval) { + auto const& triggersToMask = eval.triggers(); + + if (triggersToMask.empty()) { + edm::LogInfo("NoTriggersToMask") << "\tPathReader[\"" << *this << "\"]::mask(arg = \"" << eval << "\")" + << " failed: arg.triggers() is empty"; + return; + } + + // patterns() is always empty for a L1uGTReader, and not empty for PathReader; + // here, L1uGTReader evaluators are skipped as they shouldn't be used to mask a PathReader + if (eval.patterns().empty()) { + edm::LogWarning("InvalidArgumentForMasking") + << "\tPathReader[\"" << *this << "\"]::mask(arg = \"" << eval << "\")" + << " failed: arg.patterns() is empty (arg is not a PathReader)"; + return; + } + + enableMasks(); + + // clang-format off + m_triggersAfterMasking.erase( + std::remove_if( + m_triggersAfterMasking.begin(), + m_triggersAfterMasking.end(), + [&triggersToMask](auto const& foo) { + return std::find(triggersToMask.begin(), triggersToMask.end(), foo) != triggersToMask.end(); + } + ), + m_triggersAfterMasking.end() + ); + // clang-format on + } + } // namespace triggerExpression diff --git a/HLTrigger/HLTcore/src/TriggerExpressionPrescaler.cc b/HLTrigger/HLTcore/src/TriggerExpressionPrescaler.cc index 6eed7dc05e173..dd4bdb3e9a7fb 100644 --- a/HLTrigger/HLTcore/src/TriggerExpressionPrescaler.cc +++ b/HLTrigger/HLTcore/src/TriggerExpressionPrescaler.cc @@ -1,4 +1,5 @@ #include "HLTrigger/HLTcore/interface/TriggerExpressionPrescaler.h" +#include "HLTrigger/HLTcore/interface/TriggerExpressionData.h" namespace triggerExpression { @@ -24,7 +25,7 @@ namespace triggerExpression { UnaryOperator::init(data); // initialize the counter to the first event number seen, - // in order to avoid all prescalers on different FUs to be syncronous + // in order to avoid all prescalers on different FUs to be synchronous m_counter = data.eventNumber(); } diff --git a/HLTrigger/HLTcore/test/test_catch2_TriggerExpressionParser.cc b/HLTrigger/HLTcore/test/test_catch2_TriggerExpressionParser.cc index 93c64886b6d96..0b7d5c5d666b9 100644 --- a/HLTrigger/HLTcore/test/test_catch2_TriggerExpressionParser.cc +++ b/HLTrigger/HLTcore/test/test_catch2_TriggerExpressionParser.cc @@ -80,6 +80,16 @@ TEST_CASE("Test TriggerExpressionParser", "[TriggerExpressionParser]") { REQUIRE(testExpression("NOT(THIS OR THAT)AND(L1_THEOTHER)OR(NOTFALSE)", // "(((NOT (Uninitialised_Path_Expression OR Uninitialised_Path_Expression))" " AND Uninitialised_L1_Expression) OR Uninitialised_Path_Expression)")); + REQUIRE(testExpression("EXPR_A MASKING L1_?", // + "(Uninitialised_Path_Expression MASKING Uninitialised_L1_Expression)")); + REQUIRE(testExpression( + "L1_*copy* MASKING L1_*copy MASKING ((L1_*copy2))", // + "((Uninitialised_L1_Expression MASKING Uninitialised_L1_Expression) MASKING Uninitialised_L1_Expression)")); + REQUIRE(testExpression( + "(A AND B OR C) MASKING D OR E", // + "((((Uninitialised_Path_Expression AND Uninitialised_Path_Expression) OR Uninitialised_Path_Expression)" + " MASKING Uninitialised_Path_Expression) OR Uninitialised_Path_Expression)")); + REQUIRE(testExpression("EXPR_A MASKING FALSE", "(Uninitialised_Path_Expression MASKING FALSE)")); } // examples of expressions not supported by the triggerExpression parser @@ -92,5 +102,14 @@ TEST_CASE("Test TriggerExpressionParser", "[TriggerExpressionParser]") { REQUIRE(not testExpression("ThisPath ANDThatPath")); REQUIRE(not testExpression("ThisPath AND ThatPath AND OR")); REQUIRE(not testExpression("ThisPath AND ThatPath OR NOT")); + REQUIRE(not testExpression("ThisPath AND ThatPath MASKING MASKING")); + REQUIRE(not testExpression("Path_? AND MASKING Path_2")); + REQUIRE(not testExpression("MASKING Path_1 AND Path_?")); + REQUIRE(not testExpression("EXPR_1 MASKING (Path_1 OR Path_2)")); + REQUIRE(not testExpression("EXPR_1 MASKING TRUE")); + REQUIRE(not testExpression("EXPR_1 MASKING (NOT Path_1)")); + REQUIRE(not testExpression("EXPR_1 MASKING (Path_1 / 15)")); + REQUIRE(not testExpression("EXPR_1 MASKING (Path*_* MASKING Path1_*)")); + REQUIRE(not testExpression("EXPR_1 MASKINGPath2")); } } diff --git a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.py b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.py index 2085db39d2bc9..569b1ba7b317d 100644 --- a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.py +++ b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.py @@ -86,6 +86,18 @@ triggerConditions = ( '(Path_1) / 15', ) ) +# accept if 'Path_1' succeeds, prescaled by 15 +# masking Path_2 (equivalent to filter_1_pre) +process.filter_1_pre_with_masks1 = _triggerResultsFilter.clone( + triggerConditions = ( '(Path_1 / 15 OR Path_2) MASKING Path_2', ) +) + +# accept if 'Path_1' succeeds, prescaled by 15 +# masking Path_2 and Path_3 (equivalent to filter_1_pre) +process.filter_1_pre_with_masks2 = _triggerResultsFilter.clone( + triggerConditions = ( '(Path_? / 15) MASKING Path_2 MASKING Path_3', ) +) + # accept if 'Path_1' prescaled by 15 does not succeed process.filter_not_1_pre = _triggerResultsFilter.clone( triggerConditions = ( 'NOT (Path_1 / 15)', ) @@ -193,6 +205,8 @@ process.Check_Any_Star = cms.Path( process.filter_any_star ) process.Check_1_Pre = cms.Path( process.filter_1_pre ) +process.Check_1_Pre_With_Masks1 = cms.Path( process.filter_1_pre_with_masks1 ) +process.Check_1_Pre_With_Masks2 = cms.Path( process.filter_1_pre_with_masks2 ) process.Check_NOT_1_Pre = cms.Path( process.filter_not_1_pre ) process.Check_2_Pre = cms.Path( process.filter_2_pre ) process.Check_Any_Pre = cms.Path( process.filter_any_pre ) diff --git a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.sh b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.sh index 74bfacaffb8fd..52ca6e8d947ab 100755 --- a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.sh +++ b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_PathStatus.sh @@ -34,23 +34,25 @@ TrigReport 1 9 1000 33 967 0 Check_All_Expl TrigReport 1 10 1000 733 267 0 Check_Any_Or TrigReport 1 11 1000 733 267 0 Check_Any_Star TrigReport 1 12 1000 33 967 0 Check_1_Pre -TrigReport 1 13 1000 967 33 0 Check_NOT_1_Pre -TrigReport 1 14 1000 33 967 0 Check_2_Pre -TrigReport 1 15 1000 99 901 0 Check_Any_Pre -TrigReport 1 16 1000 99 901 0 Check_Any_Pre_DoubleNOT -TrigReport 1 17 1000 901 99 0 Check_Not_Any_Pre -TrigReport 1 18 1000 733 267 0 Check_Any_Question -TrigReport 1 19 1000 733 267 0 Check_Any_StarQuestion -TrigReport 1 20 1000 0 1000 0 Check_Wrong_Name -TrigReport 1 21 1000 0 1000 0 Check_Wrong_Pattern -TrigReport 1 22 1000 1000 0 0 Check_Not_Wrong_Pattern -TrigReport 1 23 1000 0 1000 0 Check_Empty_Pattern -TrigReport 1 24 1000 0 1000 0 Check_L1Path_Pattern -TrigReport 1 25 1000 0 1000 0 Check_L1Singlemuopen_Pattern -TrigReport 1 26 1000 1000 0 0 Check_True_Pattern -TrigReport 1 27 1000 0 1000 0 Check_False_Pattern -TrigReport 1 28 1000 1000 0 0 Check_AlwaysNOTFalse_Pattern -TrigReport 1 29 1000 1000 0 0 Check_NOTAlwaysFALSE_Pattern +TrigReport 1 13 1000 33 967 0 Check_1_Pre_With_Masks1 +TrigReport 1 14 1000 33 967 0 Check_1_Pre_With_Masks2 +TrigReport 1 15 1000 967 33 0 Check_NOT_1_Pre +TrigReport 1 16 1000 33 967 0 Check_2_Pre +TrigReport 1 17 1000 99 901 0 Check_Any_Pre +TrigReport 1 18 1000 99 901 0 Check_Any_Pre_DoubleNOT +TrigReport 1 19 1000 901 99 0 Check_Not_Any_Pre +TrigReport 1 20 1000 733 267 0 Check_Any_Question +TrigReport 1 21 1000 733 267 0 Check_Any_StarQuestion +TrigReport 1 22 1000 0 1000 0 Check_Wrong_Name +TrigReport 1 23 1000 0 1000 0 Check_Wrong_Pattern +TrigReport 1 24 1000 1000 0 0 Check_Not_Wrong_Pattern +TrigReport 1 25 1000 0 1000 0 Check_Empty_Pattern +TrigReport 1 26 1000 0 1000 0 Check_L1Path_Pattern +TrigReport 1 27 1000 0 1000 0 Check_L1Singlemuopen_Pattern +TrigReport 1 28 1000 1000 0 0 Check_True_Pattern +TrigReport 1 29 1000 0 1000 0 Check_False_Pattern +TrigReport 1 30 1000 1000 0 0 Check_AlwaysNOTFalse_Pattern +TrigReport 1 31 1000 1000 0 0 Check_NOTAlwaysFALSE_Pattern @EOF # compare to expected output of test job diff --git a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.py b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.py index de019f1825cac..e89ad7d74f7fb 100644 --- a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.py +++ b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.py @@ -47,6 +47,18 @@ triggerConditions = ( '(Path_1) / 15', ) ) +# accept if 'Path_1' succeeds, prescaled by 15 +# masking Path_2 (equivalent to filter_1_pre) +process.filter_1_pre_with_masks1 = _triggerResultsFilter.clone( + triggerConditions = ( '(Path_1 / 15 OR Path_2) MASKING Path_2', ) +) + +# accept if 'Path_1' succeeds, prescaled by 15 +# masking Path_2 and Path_3 (equivalent to filter_1_pre) +process.filter_1_pre_with_masks2 = _triggerResultsFilter.clone( + triggerConditions = ( '(Path_? / 15) MASKING Path_2 MASKING Path_3', ) +) + # accept if 'Path_1' prescaled by 15 does not succeed process.filter_not_1_pre = _triggerResultsFilter.clone( triggerConditions = ( 'NOT (Path_1 / 15)', ) @@ -146,6 +158,8 @@ process.path_any_star = cms.Path( process.filter_any_star ) process.path_1_pre = cms.Path( process.filter_1_pre ) +process.path_1_pre_with_masks1 = cms.Path( process.filter_1_pre_with_masks1 ) +process.path_1_pre_with_masks2 = cms.Path( process.filter_1_pre_with_masks2 ) process.path_not_1_pre = cms.Path( process.filter_not_1_pre ) process.path_2_pre = cms.Path( process.filter_2_pre ) process.path_any_pre = cms.Path( process.filter_any_pre ) diff --git a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.sh b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.sh index b036db4b6f64c..968a2d5e6cf16 100755 --- a/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.sh +++ b/HLTrigger/HLTfilters/test/triggerResultsFilter_by_TriggerResults.sh @@ -31,21 +31,23 @@ TrigReport 1 3 1000 33 967 0 path_all_expli TrigReport 1 4 1000 733 267 0 path_any_or TrigReport 1 5 1000 1000 0 0 path_any_star TrigReport 1 6 1000 33 967 0 path_1_pre -TrigReport 1 7 1000 967 33 0 path_not_1_pre -TrigReport 1 8 1000 33 967 0 path_2_pre -TrigReport 1 9 1000 99 901 0 path_any_pre -TrigReport 1 10 1000 99 901 0 path_any_pre_doubleNOT -TrigReport 1 11 1000 901 99 0 path_not_any_pre -TrigReport 1 12 1000 1000 0 0 path_any_doublestar -TrigReport 1 13 1000 733 267 0 path_any_question -TrigReport 1 14 1000 0 1000 0 path_wrong_name -TrigReport 1 15 1000 0 1000 0 path_wrong_pattern -TrigReport 1 16 1000 1000 0 0 path_not_wrong_pattern -TrigReport 1 17 1000 0 1000 0 path_empty_pattern -TrigReport 1 18 1000 0 1000 0 path_l1path_pattern -TrigReport 1 19 1000 0 1000 0 path_l1singlemuopen_pattern -TrigReport 1 20 1000 1000 0 0 path_true_pattern -TrigReport 1 21 1000 0 1000 0 path_false_pattern +TrigReport 1 7 1000 33 967 0 path_1_pre_with_masks1 +TrigReport 1 8 1000 33 967 0 path_1_pre_with_masks2 +TrigReport 1 9 1000 967 33 0 path_not_1_pre +TrigReport 1 10 1000 33 967 0 path_2_pre +TrigReport 1 11 1000 99 901 0 path_any_pre +TrigReport 1 12 1000 99 901 0 path_any_pre_doubleNOT +TrigReport 1 13 1000 901 99 0 path_not_any_pre +TrigReport 1 14 1000 1000 0 0 path_any_doublestar +TrigReport 1 15 1000 733 267 0 path_any_question +TrigReport 1 16 1000 0 1000 0 path_wrong_name +TrigReport 1 17 1000 0 1000 0 path_wrong_pattern +TrigReport 1 18 1000 1000 0 0 path_not_wrong_pattern +TrigReport 1 19 1000 0 1000 0 path_empty_pattern +TrigReport 1 20 1000 0 1000 0 path_l1path_pattern +TrigReport 1 21 1000 0 1000 0 path_l1singlemuopen_pattern +TrigReport 1 22 1000 1000 0 0 path_true_pattern +TrigReport 1 23 1000 0 1000 0 path_false_pattern @EOF # compare to expected output of test job