Belle II Software  light-2205-abys
TriggerVariables.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 
9 // Own include
10 #include <analysis/variables/TriggerVariables.h>
11 
12 #include <analysis/dataobjects/Particle.h>
13 
14 // trigger dataobjects
15 #include <mdst/dataobjects/TRGSummary.h>
16 #include <mdst/dataobjects/SoftwareTriggerResult.h>
17 
18 // trigger dbobjects
19 #include <mdst/dbobjects/TRGGDLDBFTDLBits.h>
20 #include <mdst/dbobjects/TRGGDLDBPrescales.h>
21 
22 // HLT dbobjects
23 #include <mdst/dbobjects/DBRepresentationOfSoftwareTriggerCut.h>
24 
25 // framework
26 #include <framework/logging/Logger.h>
27 #include <framework/datastore/StoreObjPtr.h>
28 #include <framework/database/DBObjPtr.h>
29 #include <framework/utilities/Conversion.h>
30 
31 // boost
32 #include <boost/algorithm/string.hpp>
33 
34 // C++
35 #include <limits>
36 #include <stdexcept>
37 
38 namespace Belle2 {
43  namespace {
58  std::string fullFormatIdentifier(const std::string& identifier)
59  {
60  std::string out = identifier;
61  boost::replace_all(out, " ", "&");
62  if (identifier.substr(0, 21) != "software_trigger_cut&")
63  out = "software_trigger_cut&" + out;
64  return out;
65  }
66 
71  double extractSoftwareTriggerResultImplementation(bool nonPrescaled, const std::string& triggerIdentifier, const Particle*)
72  {
73  // get trigger result object
74  StoreObjPtr<SoftwareTriggerResult> swtr;
75  if (!swtr)
76  return std::numeric_limits<double>::quiet_NaN();
77 
78  // check that the trigger ID provided by the user exists in the SWTR
80  try {
81  if (nonPrescaled) {
82  swtcr = swtr->getNonPrescaledResult(fullFormatIdentifier(triggerIdentifier));
83  } else {
84  swtcr = swtr->getResult(fullFormatIdentifier(triggerIdentifier));
85  }
86  } catch (const std::out_of_range&) {
87  // then the trigger identifier is wrong -- silently return nan
88  return std::numeric_limits<double>::quiet_NaN();
89  }
90  return double(swtcr); // see mdst/dataobjects/include/SoftwareTriggerResult.h
91  };
92  }
93 
94  namespace Variable {
95 
96  double L1Trigger(const Particle*)
97  {
98  StoreObjPtr<TRGSummary> trg;
99  if (!trg)
100  return std::numeric_limits<double>::quiet_NaN();
101  return trg->test();
102  }
103 
104  Manager::FunctionPtr L1PSNM(const std::vector<std::string>& arguments)
105  {
106  if (arguments.size() == 1) {
107  auto name = arguments[0];
108  auto func = [name](const Particle*) -> double {
109  StoreObjPtr<TRGSummary> trg;
110  if (!trg)
111  return std::numeric_limits<double>::quiet_NaN();
112  try
113  {
114  return trg->testPsnm(name);
115  } catch (const std::exception&)
116  {
117  // Something went wrong, return NaN.
118  return std::numeric_limits<double>::quiet_NaN();
119  }
120  };
121  return func;
122  } else {
123  B2FATAL("Wrong number of arguments for L1PSNM function. The only argument must be the name of the PSNM trigger bit.");
124  }
125  }
126 
127  double L1PSNMBit(const Particle*, const std::vector<double>& arguments)
128  {
129  if (arguments.size() == 1) {
130  int testBit = std::lround(arguments[0]);
131 
132  StoreObjPtr<TRGSummary> trg;
133  if (!trg)
134  return std::numeric_limits<double>::quiet_NaN();
135  try {
136  return trg->testPsnm(testBit);
137  } catch (const std::exception&) {
138  // Something went wrong, return NaN.
139  return std::numeric_limits<double>::quiet_NaN();
140  }
141  } else {
142  B2FATAL("Wrong number of arguments for L1PSNMBit function. The only argument must be the number of the PSNM trigger bit.");
143  }
144  }
145 
146  Manager::FunctionPtr L1FTDL(const std::vector<std::string>& arguments)
147  {
148  if (arguments.size() == 1) {
149  auto name = arguments[0];
150  auto func = [name](const Particle*) -> double {
151  StoreObjPtr<TRGSummary> trg;
152  if (!trg)
153  return std::numeric_limits<double>::quiet_NaN();
154  try
155  {
156  return trg->testFtdl(name);
157  } catch (const std::exception&)
158  {
159  // Something went wrong, return NaN.
160  return std::numeric_limits<double>::quiet_NaN();
161  }
162  };
163  return func;
164  } else {
165  B2FATAL("Wrong number of arguments for L1FTDL function. The only argument must be the name of the FTDL trigger bit.");
166  }
167  }
168 
169  double L1FTDLBit(const Particle*, const std::vector<double>& arguments)
170  {
171  if (arguments.size() == 1) {
172  int testBit = std::lround(arguments[0]);
173 
174  StoreObjPtr<TRGSummary> trg;
175  if (!trg)
176  return std::numeric_limits<double>::quiet_NaN();
177  try {
178  return trg->testFtdl(testBit);
179  } catch (const std::exception&) {
180  // Something went wrong, return NaN.
181  return std::numeric_limits<double>::quiet_NaN();
182  }
183  } else {
184  B2FATAL("Wrong number of arguments for L1FTDLBit function. The only argument must be the number of the FTDL trigger bit.");
185  }
186  }
187 
188  Manager::FunctionPtr L1Input(const std::vector<std::string>& arguments)
189  {
190  if (arguments.size() == 1) {
191  auto name = arguments[0];
192  auto func = [name](const Particle*) -> double {
193  StoreObjPtr<TRGSummary> trg;
194  if (!trg)
195  return std::numeric_limits<double>::quiet_NaN();
196  try
197  {
198  return trg->testInput(name);
199  } catch (const std::exception&)
200  {
201  // Something went wrong, return NaN.
202  return std::numeric_limits<double>::quiet_NaN();
203  }
204  };
205  return func;
206  } else {
207  B2FATAL("Wrong number of arguments for L1Input function. The only argument must be the name of the input trigger bit.");
208  }
209  }
210 
211  double L1InputBit(const Particle*, const std::vector<double>& arguments)
212  {
213  if (arguments.size() == 1) {
214  int testBit = std::lround(arguments[0]);
215 
216  StoreObjPtr<TRGSummary> trg;
217  if (!trg)
218  return std::numeric_limits<double>::quiet_NaN();
219  try {
220  return trg->testInput(testBit);
221  } catch (const std::exception&) {
222  // Something went wrong, return NaN.
223  return std::numeric_limits<double>::quiet_NaN();
224  }
225  } else {
226  B2FATAL("Wrong number of arguments for L1Input function. The only argument must be the number of the input trigger bit.");
227  }
228  }
229 
230  Manager::FunctionPtr L1PSNMPrescale(const std::vector<std::string>& arguments)
231  {
232  if (arguments.size() == 1) {
233  auto name = arguments[0];
234  auto func = [name](const Particle*) -> double {
235  static DBObjPtr<TRGGDLDBFTDLBits> ftdlBits;
236  if (!ftdlBits.isValid())
237  return std::numeric_limits<double>::quiet_NaN();
238  static DBObjPtr<TRGGDLDBPrescales> prescales;
239  if (!prescales.isValid())
240  return std::numeric_limits<double>::quiet_NaN();
241  for (unsigned int bit = 0; bit < TRGSummary::c_trgWordSize * TRGSummary::c_ntrgWords; bit++)
242  {
243  if (std::string(ftdlBits->getoutbitname((int)bit)) == name)
244  return prescales->getprescales(bit);
245  }
246  return std::numeric_limits<double>::quiet_NaN();
247  };
248  return func;
249  } else {
250  B2FATAL("Wrong number of arguments for L1Prescale function. The only argument must be the name of the PSNM trigger bit.");
251  }
252  }
253 
254  double L1PSNMBitPrescale(const Particle*, const std::vector<double>& arguments)
255  {
256  if (arguments.size() == 1) {
257  int testBit = std::lround(arguments[0]);
258 
259  if (testBit < 0 or testBit >= (int)TRGSummary::c_trgWordSize * (int)TRGSummary::c_ntrgWords)
260  return std::numeric_limits<double>::quiet_NaN();
261  static DBObjPtr<TRGGDLDBPrescales> prescales;
262  if (!prescales.isValid())
263  return std::numeric_limits<double>::quiet_NaN();
264  return prescales->getprescales(testBit);
265  } else {
266  B2FATAL("Wrong number of arguments for L1BitPrescale function. The only argument must be the number of the PSNM trigger bit.");
267  }
268  }
269 
270  double L1TimeType(const Particle*)
271  {
272  StoreObjPtr<TRGSummary> trg;
273  if (!trg)
274  return std::numeric_limits<double>::quiet_NaN();
275  return trg->getTimType();
276  }
277 
278  double L1TimeQuality(const Particle*)
279  {
280  StoreObjPtr<TRGSummary> trg;
281  if (!trg)
282  return std::numeric_limits<double>::quiet_NaN();
283  return trg->getTimQuality();
284  }
285 
286  double isPoissonInInjectionVeto(const Particle*)
287  {
288  StoreObjPtr<TRGSummary> trg;
289  if (!trg)
290  return std::numeric_limits<double>::quiet_NaN();
291  return trg->isPoissonInInjectionVeto();
292  }
293 
294  Manager::FunctionPtr softwareTriggerResult(const std::vector<std::string>& args)
295  {
296  /* The analyst has to know the name of the trigger she wants
297  * (after having looked this up from the trigger db payload)
298  *
299  * This workflow will probably improve later: but for now parse the args
300  * to check we have one name, then check the name does not throw an
301  * exception when we ask for it from the SWTR (std::map)
302  */
303  if (args.size() != 1)
304  B2FATAL("Wrong number of arguments for the function softwareTriggerResult");
305  std::string triggerIdentifier = args[0];
306 
307  using namespace std::placeholders;
308  return std::bind(extractSoftwareTriggerResultImplementation, false, triggerIdentifier, _1);
309  }
310 
311  Manager::FunctionPtr softwareTriggerResultNonPrescaled(const std::vector<std::string>& args)
312  {
313  /* The analyst has to know the name of the trigger she wants
314  * (after having looked this up from the trigger db payload)
315  *
316  * This workflow will probably improve later: but for now parse the args
317  * to check we have one name, then check the name does not throw an
318  * exception when we ask for it from the SWTR (std::map)
319  */
320  if (args.size() != 1)
321  B2FATAL("Wrong number of arguments for the function softwareTriggerResultNonPrescaled");
322  std::string triggerIdentifier = args[0];
323 
324  using namespace std::placeholders;
325  return std::bind(extractSoftwareTriggerResultImplementation, true, triggerIdentifier, _1);
326  }
327 
328  bool passesAnyHighLevelTrigger(const Particle* p)
329  {
330  // for HLT, a c_accept is a pass and all other cases are fail
331  // see mdst/dataobjects/include/SoftwareTriggerResult.h
332  std::vector<std::string> hardcodedname
333  = { "software_trigger_cut&filter&total_result" };
334  double swtcr = std::get<double>(softwareTriggerResult(hardcodedname)(p));
335  if (swtcr > 0.5) return true; // 1
336  else return false; // 0 or -1
337  }
338 
339  Manager::FunctionPtr softwareTriggerPrescaling(const std::vector<std::string>& args)
340  {
341  /* The analyst has to know the name of the trigger she wants
342  * (after having looked this up from the trigger db payload)
343  *
344  * This workflow will probably improve later: but for now parse the args
345  * to check we have one name, then check the database object is valid.
346  * If not return NAN.
347  */
348  if (args.size() != 1)
349  B2FATAL("Wrong number of arguments for the function softwareTriggerPrescaling");
350  std::string triggerIdentifier = args[0];
351 
352  auto outputFunction = [triggerIdentifier](const Particle*) -> double {
353 
354  DBObjPtr<DBRepresentationOfSoftwareTriggerCut> downloadedCut(fullFormatIdentifier(triggerIdentifier));
355  if (not downloadedCut)
356  return std::numeric_limits<double>::quiet_NaN();
357  return double(downloadedCut->getPreScaleFactor());
358  };
359 
360  return outputFunction;
361  }
362 
363  //-------------------------------------------------------------------------
364  VARIABLE_GROUP("L1 Trigger");
365  REGISTER_VARIABLE("L1Trigger", L1Trigger,
366  "[Eventbased] Returns 1 if at least one PSNM L1 trigger bit is true.");
367  REGISTER_METAVARIABLE("L1PSNM(name)", L1PSNM,
368  "[Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status of the trigger bit with the given name.",
369  Manager::VariableDataType::c_double);
370  REGISTER_METAVARIABLE("L1FTDL(name)", L1FTDL,
371  "[Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status of the trigger bit with the given name.",
372  Manager::VariableDataType::c_double);
373  REGISTER_METAVARIABLE("L1Input(name)", L1Input,
374  "[Eventbased] Returns the input bit status of the trigger bit with the given name.", Manager::VariableDataType::c_double);
375  REGISTER_METAVARIABLE("L1Prescale(name)", L1PSNMPrescale,
376  "[Eventbased] Returns the PSNM (prescale and mask) prescale of the trigger bit with the given name.",
377  Manager::VariableDataType::c_double);
378  REGISTER_VARIABLE("L1PSNMBit(i)", L1PSNMBit,
379  R"DOC(
380 [Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status of i-th trigger bit.
381 
382 .. warning::
383  It is recommended to use this variable only for debugging and to use :b2:var:`L1PSNM`
384  with the explicit trigger bit name for physics analyses or performance studies.
385 )DOC");
386  REGISTER_VARIABLE("L1FTDLBit(i)", L1FTDLBit,
387  R"DOC(
388 [Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status of i-th trigger bit.
389 
390 .. warning::
391  It is recommended to use this variable only for debugging and to use :b2:var:`L1FTDL`
392  with the explicit trigger bit name for physics analyses or performance studies.
393 )DOC");
394  REGISTER_VARIABLE("L1InputBit(i)", L1InputBit,
395  R"DOC(
396 [Eventbased] Returns the input bit status of the i-th input trigger bit.
397 
398 .. warning::
399  It is recommended to use this variable only for debugging and to use :b2:var:`L1Input`
400  with the explicit trigger bit name for physics analyses or performance studies.
401 )DOC");
402  REGISTER_VARIABLE("L1PSNMBitPrescale(i)", L1PSNMBitPrescale,
403  R"DOC(
404 [Eventbased] Returns the PSNM (prescale and mask) prescale of i-th trigger bit.
405 
406 .. warning::
407  It is recommended to use this variable only for debugging and to use :b2:var:`L1Prescale`
408  with the explicit trigger bit name for physics analyses or performance studies.
409 )DOC");
410  REGISTER_VARIABLE("L1TimeType", L1TimeType,
411  "[Eventbased] Returns ETimingType time type.");
412  REGISTER_VARIABLE("L1TimeQuality", L1TimeQuality,
413  "[Eventbased] Returns ETimingQuality time quality.");
414  REGISTER_VARIABLE("isPoissonTriggerInInjectionVeto", isPoissonInInjectionVeto,
415  "[Eventbased] Returns 1 if the poisson random trigger is within the injection veto window.");
416  //-------------------------------------------------------------------------
417  VARIABLE_GROUP("Software Trigger");
418  REGISTER_METAVARIABLE("SoftwareTriggerResult(triggerIdentifier)", softwareTriggerResult, R"DOC(
419 [Eventbased] [Expert] returns the SoftwareTriggerCutResult, defined as reject (-1), accept (1), or noResult (0).
420 If the trigger identifier is not found, returns NaN.
421 
422 For example:
423 
424 .. code-block::
425 
426  SoftwareTriggerResult(filter 1_Estargt1_GeV_cluster_no_other_cluster_Estargt0.3_GeV)
427 
428 which is equivalent to
429 
430 .. code-block::
431 
432  SoftwareTriggerResult(software_trigger_cut&filter&1_Estargt1_GeV_cluster_no_other_cluster_Estargt0.3_GeV)
433 
434 
435 .. warning:: the meanings of these change depending if using trigger or the skim stage, hence expert.
436 
437 .. seealso:: ``b2hlt_triggers`` for possible triggerIdentifiers.
438 
439  )DOC", Manager::VariableDataType::c_double);
440 
441  REGISTER_METAVARIABLE("SoftwareTriggerResultNonPrescaled(triggerIdentifier)", softwareTriggerResultNonPrescaled,
442  "[Eventbased] [Expert] returns the SoftwareTriggerCutResult, "
443  "if this trigger would not be prescaled."
444  "Please note, this is not the final HLT decision! "
445  "It is defined as reject (-1), accept (1), or noResult (0). Note "
446  "that the meanings of these change depending if using trigger "
447  "or the skim stage, hence expert."
448  "If the trigger identifier is not found, returns NaN.", Manager::VariableDataType::c_double);
449  REGISTER_VARIABLE("HighLevelTrigger", passesAnyHighLevelTrigger,
450  "[Eventbased] True if event passes the HLT trigger, false if not");
451  REGISTER_METAVARIABLE("SoftwareTriggerPrescaling(triggerIdentifier)", softwareTriggerPrescaling,
452  "[Eventbased] return the prescaling for the specific software trigger identifier. "
453  "Please note, this prescaling is taken from the currently setup database. It only corresponds "
454  "to the correct HLT prescale if you are using the online database!"
455  "If the trigger identifier is not found, returns NaN.", Manager::VariableDataType::c_double);
456  //-------------------------------------------------------------------------
457  }
459 }
static const unsigned int c_trgWordSize
size of a l1 trigger word
Definition: TRGSummary.h:37
static const unsigned int c_ntrgWords
number of l1 trigger words
Definition: TRGSummary.h:40
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition: Manager.h:113
SoftwareTriggerCutResult
Enumeration with all possible results of the SoftwareTriggerCut.
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23