Belle II Software  release-08-01-10
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");
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  addParam("skipFirstEvent", m_firstEvent, "Boolean to skip the first event or not. "
59  "If the module is used inside the hbasf2, like HLT storage, the first event need to be skipped.", m_firstEvent);
60 }
61 
63 {
64  if(!m_resultOnMissing) {
65  m_trigResults.isRequired();
66  } else {
67  m_trigResults.isOptional();
68  }
69  if (m_logicMode != "and" and m_logicMode != "or") {
70  B2FATAL("You have entered an invalid parameter for logicMode. "
71  "Valid strings are any of ['or', 'and']");
72  }
73  if(m_expectedResult < -1 or m_expectedResult > 1) {
74  B2FATAL("Expected trigger result needs to be -1, 0 or 1");
75  }
76 
77  // check if and how many prescales we have
78  int havePrescales{0};
79  for(const auto& triggerLine: m_triggerLines){
80  boost::apply_visitor(Utils::VisitOverload{
81  [&havePrescales](const std::tuple<std::string, unsigned int>& line) {
82  const auto& [name, prescale] = line;
83  if(prescale < 1) {
84  B2ERROR("Prescale is not positive, needs to be at least 1"
85  << LogVar("trigger line", name) << LogVar("prescale", prescale));
86  }
87  ++havePrescales;
88  B2DEBUG(20, "Prescale of " << prescale << " to be applied to " << name);
89  },
90  [](const std::string& name) {
91  // nothing to do without prescales
92  B2DEBUG(20, "No prescales to be applied to " << name);
93  },
94  }, triggerLine);
95  }
96  // and reserve counters if we need them
97  if(havePrescales > 0 and not m_useRandomNumbersForPreScale) {
98  m_prescaleCounters.clear();
99  m_prescaleCounters.assign(havePrescales, 0);
100  }
101 }
102 
103 bool TriggerSkimModule::checkTrigger(const std::string& name, unsigned int prescale, uint32_t* counter) const {
104  try {
105  bool accepted = m_trigResults->getResult(name) == static_cast<SoftwareTriggerCutResult>(m_expectedResult);
106  if(accepted and prescale != 1) {
107  accepted &= SoftwareTrigger::makePreScale(prescale, counter);
108  }
109  return accepted;
110  } catch(std::out_of_range &e) {
111  // typo? change in lines? In any case we nope out of here but let's try to give a helpful message
112  std::string available_lines = "";
113  // cppcheck-suppress unassignedVariable
114  for(auto&& [line, result]: m_trigResults->getResults()) {
115  available_lines += line + "(" + std::to_string((int)result) + ") ";
116  }
117  if(m_resultOnMissing) {
118  B2WARNING("Software trigger line not found" << LogVar("requested", name)
119  << LogVar("available", available_lines)
120  << LogVar("errorFlag", m_eventMetaDataPtr->getErrorFlag())
121  << LogVar("experiment", m_eventMetaDataPtr->getExperiment())
122  << LogVar("run", m_eventMetaDataPtr->getRun())
123  << LogVar("event", m_eventMetaDataPtr->getEvent()));
124  return *m_resultOnMissing;
125  }
126  else {
127  B2FATAL("Software trigger line not found (if this is expected, please use the `resultOnMissing` parameter)"
128  << LogVar("requested", name)
129  << LogVar("available", available_lines)
130  << LogVar("errorFlag", m_eventMetaDataPtr->getErrorFlag())
131  << LogVar("experiment", m_eventMetaDataPtr->getExperiment())
132  << LogVar("run", m_eventMetaDataPtr->getRun())
133  << LogVar("event", m_eventMetaDataPtr->getEvent()));
134  return false;
135  }
136  }
137 }
138 
140 {
141  if(m_firstEvent) {
142  m_firstEvent = false;
143  setReturnValue(true);
144  return;
145  }
146  if(!m_trigResults) {
147  if(m_resultOnMissing) {
149  return;
150  }
151  B2FATAL("No HLT Trigger result available (if this is expected to be possible "
152  "please use the `resultOnMissing` parameter");
153  }
154  // count accepted triggers
155  size_t numAccepted(0);
156  // Now check all lines, index is the prescale counter if needed
157  size_t counterIndex{0};
158  for(const auto& triggerLine: m_triggerLines) {
159  const bool accept = boost::apply_visitor(Utils::VisitOverload{
160  // check in prescale case
161  [this, &counterIndex](const std::tuple<std::string, unsigned int>& line) {
162  const auto& [name, prescale] = line;
163  uint32_t* prescaleCounter = m_useRandomNumbersForPreScale ? nullptr : &m_prescaleCounters[counterIndex++];
164  return checkTrigger(name, prescale, prescaleCounter);
165  },
166  // check without prescale
167  [this](const std::string& name) {
168  return checkTrigger(name);
169  },
170  }, triggerLine);
171  if(accept)
172  ++numAccepted;
173  }
174 
175  // Apply our logic on the test results
176  if (m_logicMode == "and") {
177  setReturnValue(numAccepted == m_triggerLines.size());
178  }
179  if (m_logicMode == "or") {
180  setReturnValue(numAccepted > 0);
181  }
182 }
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition: Module.cc:220
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
bool m_firstEvent
Check event is the first event for hbasf2 usage, especiaaly for HLT storage.
std::string m_logicMode
do we want each or any trigger line?
virtual void initialize() override
Initialize.
std::optional< int > m_resultOnMissing
value to return if there's no SoftwareTriggerResult
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.
TriggerSkimModule()
Constructor: Sets the description, the properties and the parameters of the module.
Class to store variables with their name which were sent to the logging service.
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
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