Belle II Software  release-08-02-06
SoftwareTriggerHLTDQMModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <hlt/softwaretrigger/modules/dqm/SoftwareTriggerHLTDQMModule.h>
9 
10 #include <TDirectory.h>
11 
12 #include <hlt/softwaretrigger/core/SoftwareTriggerDBHandler.h>
13 #include <hlt/softwaretrigger/core/FinalTriggerDecisionCalculator.h>
14 #include <hlt/utilities/Units.h>
15 
16 #include <framework/core/ModuleParam.templateDetails.h>
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <stdexcept>
21 
22 using namespace Belle2;
23 using namespace SoftwareTrigger;
24 
25 REG_MODULE(SoftwareTriggerHLTDQM);
26 
28 {
29  setDescription("Monitor Physics Trigger");
31 
32  // Fill in the default values of the module parameters
34 
35  m_param_cutResultIdentifiers["filter"]["filter"] = {"total_result"};
36 
37  addParam("cutResultIdentifiers", m_param_cutResultIdentifiers,
38  "Which cuts should be reported? Please remember to include the total_result also, if wanted.",
40 
41  addParam("cutResultIdentifiersIgnored", m_param_cutResultIdentifiersIgnored,
42  "Which cuts should be ignored? This will display cleaner trigger lines, e.g. to clear them from bhabha contamination. "
43  "Vetoes on skims do not apply in filter plot and vice versa.",
45 
46  addParam("cutResultIdentifiersPerUnit", m_param_cutResultIdentifiersPerUnit,
47  "Which cuts should be reported per unit?",
49 
50  addParam("variableIdentifiers", m_param_variableIdentifiers,
51  "Which variables should be reported?",
53 
54  addParam("l1Identifiers", m_param_l1Identifiers,
55  "Which l1 identifiers to report?",
57 
58  addParam("additionalL1Identifiers", m_param_additionalL1Identifiers,
59  "Which additional l1 identifiers to be added to the l1 total result plot?",
61 
62  addParam("createTotalResultHistograms", m_param_create_total_result_histograms,
63  "Create total result histogram?",
64  true);
65 
66  addParam("createExpRunEventHistograms", m_param_create_exp_run_event_histograms,
67  "Create exp/run/event histograms?",
68  true);
69 
70  addParam("createHLTUnitHistograms", m_param_create_hlt_unit_histograms,
71  "Create HLT unit histograms?",
72  false);
73 
74  addParam("createErrorFlagHistograms", m_param_create_error_flag_histograms,
75  "Create Error Flag histograms?",
76  false);
77 
78  addParam("histogramDirectoryName", m_param_histogramDirectoryName,
79  "SoftwareTrigger DQM histograms will be put into this directory", m_param_histogramDirectoryName);
80 
81  addParam("pathLocation", m_param_pathLocation,
82  "Location of the module in the path: before filter or after filter", m_param_pathLocation);
83 }
84 
86 {
87  TDirectory* oldDirectory = nullptr;
88 
89  if (!m_param_histogramDirectoryName.empty()) {
90  oldDirectory = gDirectory;
91  TDirectory* histDir = oldDirectory->mkdir(m_param_histogramDirectoryName.c_str());
92  histDir->cd();
93  }
94 
95  for (auto const& variable : m_param_variableIdentifiers) {
96  // todo: make correct range
97  const unsigned int numberOfBins = 50;
98  const double lowerX = 0;
99  const double upperX = 50;
100  m_triggerVariablesHistograms.emplace(variable, new TH1F(variable.c_str(), variable.c_str(), numberOfBins, lowerX, upperX));
101  m_triggerVariablesHistograms[variable]->SetXTitle(("SoftwareTriggerVariable " + variable).c_str());
102  }
103 
104  for (const std::string& trigger : m_param_l1Identifiers) {
105  m_l1Histograms.emplace(trigger, new TH1F(trigger.c_str(), ("Events triggered in L1 " + trigger).c_str(), 150, 0, 150));
106  m_l1Histograms[trigger]->SetXTitle("HLT line");
107  m_l1Histograms[trigger]->SetOption("hist");
108  m_l1Histograms[trigger]->SetStats(false);
109  m_l1Histograms[trigger]->SetMinimum(0);
110 
111  float index = 0;
112  for (auto const& cutIdentifier : m_param_cutResultIdentifiers) {
113  const std::string& title = cutIdentifier.first;
114  const auto& mapVal = *(m_param_cutResultIdentifiers[title].begin());
115  const std::string& baseIdentifier = mapVal.first;
116  const auto& cuts = mapVal.second;
117 
118  if (title == baseIdentifier) {
119  for (const std::string& cutTitle : cuts) {
120  index++;
121  m_l1Histograms[trigger]->GetXaxis()->SetBinLabel(index, cutTitle.c_str());
122  }
123  }
124  }
125  index++;
126  m_l1Histograms[trigger]->GetXaxis()->SetBinLabel(index, "hlt_result");
127  m_l1Histograms[trigger]->LabelsDeflate();
128  }
129 
130  for (const auto& cutIdentifier : m_param_cutResultIdentifiers) {
131 
132  const std::string& title = cutIdentifier.first;
133  const auto& mapVal = *(m_param_cutResultIdentifiers[title].begin());
134  const std::string& baseIdentifier = mapVal.first;
135  const auto& cuts = mapVal.second;
136  const int numberOfFlags = cuts.size();
137 
138  if (m_param_histogramDirectoryName == "softwaretrigger_skim_nobhabha") {
139  if (title == baseIdentifier)
140  m_cutResultHistograms.emplace(title,
141  new TH1F((title + "_nobhabha").c_str(), ("Events triggered in HLT " + baseIdentifier).c_str(),
142  numberOfFlags, 0,
143  numberOfFlags));
144  else
145  m_cutResultHistograms.emplace(title,
146  new TH1F((baseIdentifier + "_" + title + "_nobhabha").c_str(),
147  ("Events triggered in HLT " + baseIdentifier + " : " + title).c_str(),
148  numberOfFlags, 0,
149  numberOfFlags));
150  } else {
151  if (title == baseIdentifier)
152  m_cutResultHistograms.emplace(title,
153  new TH1F(title.c_str(), ("Events triggered in HLT " + baseIdentifier).c_str(),
154  numberOfFlags, 0,
155  numberOfFlags));
156  else
157  m_cutResultHistograms.emplace(title,
158  new TH1F((baseIdentifier + "_" + title).c_str(), ("Events triggered in HLT " + baseIdentifier + " : " + title).c_str(),
159  numberOfFlags, 0,
160  numberOfFlags));
161  }
162  m_cutResultHistograms[title]->SetXTitle("");
163  m_cutResultHistograms[title]->SetOption("hist");
164  m_cutResultHistograms[title]->SetStats(false);
165  m_cutResultHistograms[title]->SetMinimum(0);
166 
167  // Set bin labels
168  int index = 0;
169  for (const std::string& cutTitle : cuts) {
170  index++;
171  m_cutResultHistograms[title]->GetXaxis()->SetBinLabel(index, cutTitle.c_str());
172  }
173  }
174 
175  // We add one for the total result
177  m_cutResultHistograms.emplace("total_result",
178  new TH1F("total_result", "Total Result of HLT (absolute numbers)", 1, 0, 0));
179  m_cutResultHistograms["total_result"]->SetXTitle("Total Cut Result");
180  m_cutResultHistograms["total_result"]->SetOption("hist");
181  m_cutResultHistograms["total_result"]->SetStats(false);
182  m_cutResultHistograms["total_result"]->SetMinimum(0);
183 
184  m_l1Histograms.emplace("l1_total_result",
185  new TH1F("l1_total_result", "Events triggered in L1 (total results)", 1, 0, 0));
186  m_l1Histograms["l1_total_result"]->SetXTitle("Total L1 Cut Result");
187  m_l1Histograms["l1_total_result"]->SetOption("hist");
188  m_l1Histograms["l1_total_result"]->SetStats(false);
189  m_l1Histograms["l1_total_result"]->SetMinimum(0);
190 
191  const int numberOfL1Flags = m_param_l1Identifiers.size() + m_param_additionalL1Identifiers.size();
192  m_l1Histograms["l1_total_result"]->SetBins(numberOfL1Flags, 0, numberOfL1Flags);
193  // Set bin labels
194  int l1Index = 0;
195  for (const std::string& l1Trigger : m_param_l1Identifiers) {
196  l1Index++;
197  m_l1Histograms["l1_total_result"]->GetXaxis()->SetBinLabel(l1Index, l1Trigger.c_str());
198  }
199  for (const std::string& l1Trigger : m_param_additionalL1Identifiers) {
200  l1Index++;
201  m_l1Histograms["l1_total_result"]->GetXaxis()->SetBinLabel(l1Index, l1Trigger.c_str());
202  }
203  }
204 
206  m_runInfoHistograms.emplace("run_number", new TH1D("run_number", "Run Number", 100, 0, 10000));
207  m_runInfoHistograms.emplace("event_number", new TH1D("event_number", "Event Number", 100, 0, 1'000'000));
208  m_runInfoHistograms.emplace("experiment_number", new TH1D("experiment_number", "Experiment Number", 50, 0, 50));
209  }
210 
212  if (m_param_histogramDirectoryName != "softwaretrigger_before_filter") {
213  m_runInfoHistograms.emplace("hlt_unit_number", new TH1D("hlt_unit_number_after_filter",
214  ("Number of events per HLT unit " + m_param_pathLocation).c_str(), HLTUnits::max_hlt_units + 1, 0,
215  HLTUnits::max_hlt_units + 1));
216  } else {
217  m_runInfoHistograms.emplace("hlt_unit_number", new TH1D("hlt_unit_number",
218  ("Number of events per HLT unit " + m_param_pathLocation).c_str(), HLTUnits::max_hlt_units + 1, 0,
219  HLTUnits::max_hlt_units + 1));
220  }
221  m_runInfoHistograms["hlt_unit_number"]->SetMinimum(0);
222 
223  for (const auto& cutIdentifierPerUnit : m_param_cutResultIdentifiersPerUnit) {
224  m_cutResultPerUnitHistograms.emplace(cutIdentifierPerUnit, new TH1F((cutIdentifierPerUnit + "_per_unit").c_str(),
225  ("Events triggered per unit in HLT : " + cutIdentifierPerUnit).c_str(), HLTUnits::max_hlt_units + 1, 0,
226  HLTUnits::max_hlt_units + 1));
227  m_cutResultPerUnitHistograms[cutIdentifierPerUnit]->SetXTitle("HLT unit number");
228  m_cutResultPerUnitHistograms[cutIdentifierPerUnit]->SetOption("histe");
229  m_cutResultPerUnitHistograms[cutIdentifierPerUnit]->SetMinimum(0);
230  }
231 
232  }
233 
235  m_runInfoHistograms.emplace("error_flag", new TH1D("error_flag", "Error Flag", 4, 0, 4));
236  m_runInfoHistograms["error_flag"]->SetStats(false);
237  m_runInfoHistograms["error_flag"]->SetOption("hist");
238  m_runInfoHistograms["error_flag"]->SetMinimum(0);
239  }
240 
241  if (oldDirectory) {
242  oldDirectory->cd();
243  }
244 }
245 
247 {
248  // Register histograms (calls back defineHisto)
249  REG_HISTOGRAM
250 
252  // Read the HLT unit's hostname straight from the HLT worker
253  FILE* pipe = popen("hostname -d", "r");
254  if (pipe) {
255  char buffer[128];
256  std::string host = "";
257 
258  while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
259  host += buffer;
260  }
261 
262  pclose(pipe);
263 
264  if (host.length() == 5) {
265  m_hlt_unit = atoi(host.substr(3, 2).c_str());
266  } else {
267  B2WARNING("HLT unit number not found");
268  }
269  } else {
270  B2WARNING("HLT unit number not found");
271  }
272  }
273 }
274 
276 {
277  // this might be pre-scaled for performance reasons in the final configuration, therefore this structure
278  // might not be filled in every event
279  if (m_variables.isValid()) {
280  for (auto& variableNameAndTH1F : m_triggerVariablesHistograms) {
281  const std::string& variable = variableNameAndTH1F.first;
282  TH1F* histogram = variableNameAndTH1F.second;
283 
284  // try to load this variable from the computed trigger variables
285  if (not m_variables->has(variable)) {
286  B2ERROR("Variable " << variable << " configured for SoftwareTriggerDQM plotting is not available");
287  } else {
288  const double value = m_variables->getVariable(variable);
289  histogram->Fill(value);
290  }
291  }
292  }
293 
294  if (m_triggerResult.isValid()) {
295  const auto results = m_triggerResult->getResults();
296 
297  for (auto const& cutIdentifier : m_param_cutResultIdentifiers) {
298  const std::string& title = cutIdentifier.first;
299  const auto& mapVal = *(m_param_cutResultIdentifiers[title].begin());
300  const std::string& baseIdentifier = mapVal.first;
301  const auto& cuts = mapVal.second;
302 
303  // check if we want to ignore it
304  bool skip = false;
305  const auto& cutsIgnored = m_param_cutResultIdentifiersIgnored[baseIdentifier];
306 
307  for (const std::string& cutTitleIgnored : cutsIgnored) {
308  const std::string& cutNameIgnored = cutTitleIgnored.substr(0, cutTitleIgnored.find("\\"));
309  const std::string& fullCutIdentifierIgnored = SoftwareTriggerDBHandler::makeFullCutName(baseIdentifier, cutNameIgnored);
310 
311  auto const cutEntryIgnored = results.find(fullCutIdentifierIgnored);
312 
313  if (cutEntryIgnored != results.end()) {
314  if (cutEntryIgnored->second > 0) skip = true;
315  }
316  }
317 
318  float index = 0;
319  for (const std::string& cutTitle : cuts) {
320  index++;
321  const std::string& cutName = cutTitle.substr(0, cutTitle.find("\\"));
322  const std::string& fullCutIdentifier = SoftwareTriggerDBHandler::makeFullCutName(baseIdentifier, cutName);
323 
324  // check if the cutResult is in the list, be graceful when not available
325  // Create results object instead of calling .find() on a temporary object. This will cause undefined behaviour
326  // when checking again the .end() pointer, when the .end() pointer is also created from a temporary object.
327  auto const cutEntry = results.find(fullCutIdentifier);
328 
329  if (cutEntry != results.end()) {
330  const int cutResult = cutEntry->second;
331  if (cutResult > 0 and not skip) {
332  m_cutResultHistograms[title]->Fill(index - 0.5);
333  }
334  }
335  }
336 
338  if (title == baseIdentifier) {
339  const std::string& totalCutIdentifier = SoftwareTriggerDBHandler::makeTotalResultName(baseIdentifier);
340  const int cutResult = static_cast<int>(m_triggerResult->getResult(totalCutIdentifier));
341 
342  m_cutResultHistograms["total_result"]->Fill(totalCutIdentifier.c_str(), cutResult > 0);
343  }
344  }
345  }
346 
349  m_cutResultHistograms["total_result"]->Fill("total_result", totalResult > 0);
350  }
351 
353  for (const std::string& cutIdentifierPerUnit : m_param_cutResultIdentifiersPerUnit) {
354  const std::string& cutName = cutIdentifierPerUnit.substr(0, cutIdentifierPerUnit.find("\\"));
355  const std::string& fullCutIdentifier = SoftwareTriggerDBHandler::makeFullCutName("filter", cutName);
356 
357  // check if the cutResult is in the list, be graceful when not available
358  auto const cutEntry = results.find(fullCutIdentifier);
359 
360  if (cutEntry != results.end()) {
361  const int cutResult = cutEntry->second;
362  if (cutResult > 0) {
363  m_cutResultPerUnitHistograms[cutIdentifierPerUnit]->Fill(m_hlt_unit);
364  }
365  }
366  }
367  }
368 
369  if (m_l1TriggerResult.isValid()) {
370  float l1Index = 0;
371  for (const std::string& l1Trigger : m_param_l1Identifiers) {
372  l1Index++;
373  bool triggerResult;
374  try {
375  triggerResult = m_l1TriggerResult->testPsnm(l1Trigger.c_str());
376  } catch (const std::exception&) {
377  try {
378  triggerResult = m_l1TriggerResult->testInput(l1Trigger.c_str());
379  } catch (const std::exception&) {
380  triggerResult = false;
381  }
382  }
384  if (triggerResult) {
385  m_l1Histograms["l1_total_result"]->Fill(l1Index - 0.5);
386  }
387  }
388 
389  if (not triggerResult) {
390  continue;
391  }
392 
393  float index = 0;
394  for (auto const& cutIdentifier : m_param_cutResultIdentifiers) {
395  const std::string& title = cutIdentifier.first;
396  const auto& mapVal = *(m_param_cutResultIdentifiers[title].begin());
397  const std::string& baseIdentifier = mapVal.first;
398  const auto& cuts = mapVal.second;
399 
400  if (title == baseIdentifier) {
401  for (const std::string& cutTitle : cuts) {
402  index++;
403  const std::string& cutName = cutTitle.substr(0, cutTitle.find("\\"));
404  const std::string& fullCutIdentifier = SoftwareTriggerDBHandler::makeFullCutName(baseIdentifier, cutName);
405 
406  // check if the cutResult is in the list, be graceful when not available
407  auto const cutEntry = results.find(fullCutIdentifier);
408 
409  if (cutEntry != results.end()) {
410  const int cutResult = cutEntry->second;
411  if (cutResult > 0) {
412  m_l1Histograms[l1Trigger]->Fill(index - 0.5);
413  }
414  }
415  }
416  }
417  }
418 
419  index++;
421  if (totalResult > 0) {
422  m_l1Histograms[l1Trigger]->Fill(index - 0.5);
423  }
424  }
426  for (const std::string& l1Trigger : m_param_additionalL1Identifiers) {
427  l1Index++;
428  bool triggerResult;
429  try {
430  triggerResult = m_l1TriggerResult->testPsnm(l1Trigger.c_str());
431  } catch (const std::exception&) {
432  try {
433  triggerResult = m_l1TriggerResult->testInput(l1Trigger.c_str());
434  } catch (const std::exception&) {
435  triggerResult = false;
436  }
437  }
438  if (triggerResult) {
439  m_l1Histograms["l1_total_result"]->Fill(l1Index - 0.5);
440  }
441  }
442  }
443  }
444  }
445 
447  m_runInfoHistograms["run_number"]->Fill(m_eventMetaData->getRun());
448  m_runInfoHistograms["event_number"]->Fill(m_eventMetaData->getEvent());
449  m_runInfoHistograms["experiment_number"]->Fill(m_eventMetaData->getExperiment());
450  }
451 
453  m_runInfoHistograms["error_flag"]->Fill("B2LinkPacketCRCError",
454  (bool)(m_eventMetaData->getErrorFlag() & EventMetaData::EventErrorFlag::c_B2LinkPacketCRCError));
455  m_runInfoHistograms["error_flag"]->Fill("B2LinkEventCRCError",
456  (bool)(m_eventMetaData->getErrorFlag() & EventMetaData::EventErrorFlag::c_B2LinkEventCRCError));
457  m_runInfoHistograms["error_flag"]->Fill("HLTCrash",
458  (bool)(m_eventMetaData->getErrorFlag() & EventMetaData::EventErrorFlag::c_HLTCrash));
459  m_runInfoHistograms["error_flag"]->Fill("ReconstructionAbort",
460  (bool)(m_eventMetaData->getErrorFlag() & EventMetaData::EventErrorFlag::c_ReconstructionAbort));
461  }
462 
464  m_runInfoHistograms["hlt_unit_number"]->Fill(m_hlt_unit);
465  }
466 }
467 
469 {
470  std::for_each(m_cutResultHistograms.begin(), m_cutResultHistograms.end(),
471  [](auto & it) { it.second->Reset(); });
472  std::for_each(m_cutResultPerUnitHistograms.begin(), m_cutResultPerUnitHistograms.end(),
473  [](auto & it) { it.second->Reset(); });
474  std::for_each(m_triggerVariablesHistograms.begin(), m_triggerVariablesHistograms.end(),
475  [](auto & it) { it.second->Reset(); });
476  std::for_each(m_l1Histograms.begin(), m_l1Histograms.end(),
477  [](auto & it) { it.second->Reset(); });
478  std::for_each(m_runInfoHistograms.begin(), m_runInfoHistograms.end(),
479  [](auto & it) { it.second->Reset(); });
480 }
481 
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
Definition: HistoModule.h:29
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
@ 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
static bool getFinalTriggerDecision(const SoftwareTriggerResult &result, bool forgetTotalResult=false)
Calculate the final cut decision using all "total_results" of all sub triggers in the software trigge...
static std::string makeFullCutName(const std::string &baseCutIdentifier, const std::string &cutIdentifier)
Helper function to compile the full identifier from the base and the specific cut name.
static std::string makeTotalResultName(const std::string &baseIdentifier="all")
Handy function to create the name related to the total result of a specific trigger stage (either fil...
std::map< std::string, TH1D * > m_runInfoHistograms
histograms with the run information
std::map< std::string, std::map< std::string, std::vector< std::string > > > m_param_cutResultIdentifiers
Which cuts should be reported? Please remember to include the total_result also, if wanted.
std::map< std::string, TH1F * > m_l1Histograms
histogram with the L1 information
void initialize() override
Module functions to be called from main process.
void event() override
Module functions to be called from event process.
StoreObjPtr< SoftwareTriggerResult > m_triggerResult
STM cut results.
std::vector< std::string > m_param_l1Identifiers
Which L1 cuts should be reported?
std::map< std::string, TH1F * > m_cutResultPerUnitHistograms
histograms for the final sw trigger decisions for each base identifier per unit
std::map< std::string, TH1F * > m_triggerVariablesHistograms
histograms for the software trigger variables in all calculators (although maybe not filled)
std::map< std::string, std::vector< std::string > > m_param_cutResultIdentifiersIgnored
Which cuts should be ignored? This can be used to clear trigger lines from e.g. bhabha contamination.
std::string m_param_pathLocation
Location of the module in the path: before filter or after filter.
void beginRun() override
Reset all histogram entries for a new run.
std::map< std::string, TH1F * > m_cutResultHistograms
histograms for the final sw trigger decisions for each base identifier
bool m_param_create_error_flag_histograms
Create error flag histograms?
std::vector< std::string > m_param_additionalL1Identifiers
Which additional L1 cuts should be added to the L1 total result plot?
bool m_param_create_hlt_unit_histograms
Create HLT unit number histograms?
StoreObjPtr< TRGSummary > m_l1TriggerResult
L1 cut results.
std::vector< std::string > m_param_cutResultIdentifiersPerUnit
Which cuts should be reported per unit?
bool m_param_create_total_result_histograms
Create total result histogram?
std::vector< std::string > m_param_variableIdentifiers
Which variables should be reported?
bool m_param_create_exp_run_event_histograms
Create exp/run/event number histograms?
std::string m_param_histogramDirectoryName
Directory to put the generated histograms.
StoreObjPtr< SoftwareTriggerVariables > m_variables
STM cut variables.
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
Abstract base class for different kinds of events.