Belle II Software  release-06-02-00
TriggerSkimModule.cc
1 
2 /**************************************************************************
3  * basf2 (Belle II Analysis Software Framework) *
4  * Author: The Belle II Collaboration *
5  * *
6  * See git log for contributors and copyright holders. *
7  * This file is licensed under LGPL-3.0, see LICENSE.md. *
8  **************************************************************************/
9 
10 #include <calibration/modules/TriggerSkim/TriggerSkimModule.h>
11 #include <hlt/softwaretrigger/core/utilities.h>
12 #include <framework/core/ModuleParam.templateDetails.h>
13 #include <framework/utilities/Utils.h>
14 
15 #include <algorithm>
16 #include <stdexcept>
17 
18 using namespace Belle2;
19 
20 REG_MODULE(TriggerSkim)
21 
23 {
24  // Set module properties
25  setDescription(R"DOC(Trigger Skim Module
26 
27 Module will return an overall result (True/False) based on whether or not ANY or
28 ALL (depending on ``logicMode``) of the specified triggers returned the given
29 value (``expectedResult``) from the SoftwareTriggerResult.
30 
31 Optionally it can apply prescales on each trigger line. In that case ``logicMode='and'``
32 might not be very meaningful as the return value will only be true if all trigger
33 lines were accepted after their own prescale.
34 )DOC");
35  setPropertyFlags(c_ParallelProcessingCertified);
36 
37  // Parameter definitions
38  addParam("triggerLines", m_triggerLines,
39  "Trigger lines to skim on. This can either be just a list of names or "
40  "each item can also optionally be a tuple with name and prescale factor. "
41  "So either ``['hadron', 'cosmic']`` or ``[('hadron', 1), ('cosmic', 20)]`` "
42  "or a mix of both");
43  addParam("expectedResult", m_expectedResult,
44  "The SoftwareTriggerResult value that each trigger line in the ``triggerLines`` "
45  "parameter will be tested for.", int(1));
46  addParam("logicMode", m_logicMode,
47  "Each trigger line in ``triggerLines`` will be tested against the ``expectedResult`` parameter. "
48  "The logic mode controls whether we test using 'and' or 'or' logic to get a return value. "
49  "'and' means that all trigger lines must have ``results == expectedResult``, 'or' means that only "
50  "one of the trigger lines must match the expectedResult value.", m_logicMode);
51  addParam("useRandomNumbersForPreScale", m_useRandomNumbersForPreScale, "Flag to use random numbers (True) "
52  "or a counter (False) for applying the prescale. In the latter case, the module will retain exactly "
53  "one event every N processed, where N (the counter value) is set for each line via the "
54  "``triggerLines`` option. By default, random numbers are used.", m_useRandomNumbersForPreScale);
55  addParam("resultOnMissing", m_resultOnMissing, "Value to return if hlt trigger result is not available or incomplete. "
56  "If this is set to None a FATAL error will be raised if the results are missing. Otherwise the value "
57  "given will be set as return value of the module", m_resultOnMissing);
58 }
59 
61 {
62  if(!m_resultOnMissing) {
63  m_trigResults.isRequired();
64  } else {
65  m_trigResults.isOptional();
66  }
67  if (m_logicMode != "and" and m_logicMode != "or") {
68  B2FATAL("You have entered an invalid parameter for logicMode. "
69  "Valid strings are any of ['or', 'and']");
70  }
71  if(m_expectedResult < -1 or m_expectedResult > 1) {
72  B2FATAL("Expected trigger result needs to be -1, 0 or 1");
73  }
74 
75  // check if and how many prescales we have
76  int havePrescales{0};
77  for(const auto& triggerLine: m_triggerLines){
78  boost::apply_visitor(Utils::VisitOverload{
79  [&havePrescales](const std::tuple<std::string, unsigned int>& line) {
80  const auto& [name, prescale] = line;
81  if(prescale < 1) {
82  B2ERROR("Prescale is not positive, needs to be at least 1"
83  << LogVar("trigger line", name) << LogVar("prescale", prescale));
84  }
85  ++havePrescales;
86  B2DEBUG(20, "Prescale of " << prescale << " to be applied to " << name);
87  },
88  [](const std::string& name) {
89  // nothing to do without prescales
90  B2DEBUG(20, "No prescales to be applied to " << name);
91  },
92  }, triggerLine);
93  }
94  // and reserve counters if we need them
95  if(havePrescales > 0 and not m_useRandomNumbersForPreScale) {
96  m_prescaleCounters.clear();
97  m_prescaleCounters.assign(havePrescales, 0);
98  }
99 }
100 
101 bool TriggerSkimModule::checkTrigger(const std::string& name, unsigned int prescale, uint32_t* counter) const {
102  try {
103  bool accepted = m_trigResults->getResult(name) == static_cast<SoftwareTriggerCutResult>(m_expectedResult);
104  if(accepted and prescale != 1) {
105  accepted &= SoftwareTrigger::makePreScale(prescale, counter);
106  }
107  return accepted;
108  } catch(std::out_of_range &e) {
109  // typo? change in lines? In any case we nope out of here but let's try to give a helpful message
110  std::string available_lines = "";
111  for(auto&& [line, result]: m_trigResults->getResults()) {
112  available_lines += line + "(" + std::to_string((int)result) + ") ";
113  }
114  if(m_resultOnMissing) {
115  B2WARNING("Software trigger line not found" << LogVar("requested", name)
116  << LogVar("available", available_lines)
117  << LogVar("errorFlag", m_eventMetaDataPtr->getErrorFlag())
118  << LogVar("experiment", m_eventMetaDataPtr->getExperiment())
119  << LogVar("run", m_eventMetaDataPtr->getRun())
120  << LogVar("event", m_eventMetaDataPtr->getEvent()));
121  return *m_resultOnMissing;
122  }
123  else {
124  B2FATAL("Software trigger line not found (if this is expected, please use the `resultOnMissing` parameter)"
125  << LogVar("requested", name)
126  << LogVar("available", available_lines)
127  << LogVar("errorFlag", m_eventMetaDataPtr->getErrorFlag())
128  << LogVar("experiment", m_eventMetaDataPtr->getExperiment())
129  << LogVar("run", m_eventMetaDataPtr->getRun())
130  << LogVar("event", m_eventMetaDataPtr->getEvent()));
131  return false;
132  }
133  }
134 }
135 
137 {
138  if(!m_trigResults) {
139  if(m_resultOnMissing) {
141  return;
142  }
143  B2FATAL("No HLT Trigger result available (if this is expected to be possible "
144  "please use the `resultOnMissing` parameter");
145  }
146  // count accepted triggers
147  size_t numAccepted(0);
148  // Now check all lines, index is the prescale counter if needed
149  size_t counterIndex{0};
150  for(const auto& triggerLine: m_triggerLines) {
151  const bool accept = boost::apply_visitor(Utils::VisitOverload{
152  // check in prescale case
153  [this, &counterIndex](const std::tuple<std::string, unsigned int>& line) {
154  const auto& [name, prescale] = line;
155  uint32_t* prescaleCounter = m_useRandomNumbersForPreScale ? nullptr : &m_prescaleCounters[counterIndex++];
156  return checkTrigger(name, prescale, prescaleCounter);
157  },
158  // check without prescale
159  [this](const std::string& name) {
160  return checkTrigger(name);
161  },
162  }, triggerLine);
163  if(accept)
164  ++numAccepted;
165  }
166 
167  // Apply our logic on the test results
168  if (m_logicMode == "and") {
169  setReturnValue(numAccepted == m_triggerLines.size());
170  }
171  if (m_logicMode == "or") {
172  setReturnValue(numAccepted > 0);
173  }
174 }
Base class for Modules.
Definition: Module.h:72
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition: Module.cc:220
Returns the calibration result from SoftwareTriigerResult for skimming out calibration flagged events...
boost::optional< int > m_resultOnMissing
value to return if there's no SoftwareTriggerResult
std::string m_logicMode
do we want each or any trigger line?
virtual void initialize() override
Initialize.
virtual void event() override
Event function.
int m_expectedResult
Result we want for each or any trigger line.
std::vector< boost::variant< std::string, std::tuple< std::string, unsigned int > > > m_triggerLines
List of triggerlines we're interested in.
std::vector< uint32_t > m_prescaleCounters
if we don't use random prescale we need counters
bool m_useRandomNumbersForPreScale
and do we want random prescale or counters ?
StoreObjPtr< SoftwareTriggerResult > m_trigResults
Required input for trigger results.
StoreObjPtr< EventMetaData > m_eventMetaDataPtr
EventMetaData is used to report warning/error messages.
bool checkTrigger(const std::string &name, unsigned int prescale=1, uint32_t *counter=nullptr) const
Check a single trigger line for the expected result.
Class to store variables with their name which were sent to the logging service.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
SoftwareTriggerCutResult
Enumeration with all possible results of the SoftwareTriggerCut.
Abstract base class for different kinds of events.
Helper struct for the C++17 std::visit overload pattern to allow simple use of variants.
Definition: Utils.h:26