Belle II Software  release-08-01-10
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 header.
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 Const::doubleNaN;
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 Const::doubleNaN;
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 Const::doubleNaN;
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 Const::doubleNaN;
112  try
113  {
114  return trg->testPsnm(name);
115  } catch (const std::exception&)
116  {
117  // Something went wrong, return NaN.
118  return Const::doubleNaN;
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 Const::doubleNaN;
135  try {
136  return trg->testPsnm(testBit);
137  } catch (const std::exception&) {
138  // Something went wrong, return NaN.
139  return Const::doubleNaN;
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 Const::doubleNaN;
154  try
155  {
156  return trg->testFtdl(name);
157  } catch (const std::exception&)
158  {
159  // Something went wrong, return NaN.
160  return Const::doubleNaN;
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 Const::doubleNaN;
177  try {
178  return trg->testFtdl(testBit);
179  } catch (const std::exception&) {
180  // Something went wrong, return NaN.
181  return Const::doubleNaN;
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 Const::doubleNaN;
196  try
197  {
198  return trg->testInput(name);
199  } catch (const std::exception&)
200  {
201  // Something went wrong, return NaN.
202  return Const::doubleNaN;
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 Const::doubleNaN;
219  try {
220  return trg->testInput(testBit);
221  } catch (const std::exception&) {
222  // Something went wrong, return NaN.
223  return Const::doubleNaN;
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 Const::doubleNaN;
238  static DBObjPtr<TRGGDLDBPrescales> prescales;
239  if (!prescales.isValid())
240  return Const::doubleNaN;
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 Const::doubleNaN;
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 Const::doubleNaN;
261  static DBObjPtr<TRGGDLDBPrescales> prescales;
262  if (!prescales.isValid())
263  return Const::doubleNaN;
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 Const::doubleNaN;
275  return trg->getTimType();
276  }
277 
278  double L1TimeQuality(const Particle*)
279  {
280  StoreObjPtr<TRGSummary> trg;
281  if (!trg)
282  return Const::doubleNaN;
283  return trg->getTimQuality();
284  }
285 
286  double isPoissonInInjectionVeto(const Particle*)
287  {
288  StoreObjPtr<TRGSummary> trg;
289  if (!trg)
290  return Const::doubleNaN;
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 Const::doubleNaN;
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  R"DOC(
369 [Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status (1 or 0) of the output trigger bit with the given name.
370 For some output trigger bits, we assign a prescale factor to reduce the number of triggered events.
371 For example, we want to keep only 1% of Bhabha events. A prescale factor of 100 is then assigned to ``bha_3D`` (Bhabha selected in 3D criteria).
372 Prescale factor of a given output trigger bit could be different in different datasets.
373 It is recommended to use prescaled trigger bits (L1PSNM) or un-prescaled trigger bits (L1FTDL) for your analysis.
374 In run-independent MC, configuration of the prescales in TSIM (trigger simulation) can be different from data, so L1 FTDL is recommended.
375 In run-dependent MC, configuration of the prescales in TSIM is consistent with data, so L1PSNM is recommended.
376 Please check on `the dedicated Confluence page <https://confluence.desy.de/display/BI/TriggerBitTable>`__ or or `the dedicated Belle II notes <https://docs.belle2.org/search?ln=en&p=%22Trigger+Summary%22&f=&action_search=Search&c=Belle+II+Notes>`__ to find out the definition of trigger bits.
377 )DOC",
378  Manager::VariableDataType::c_double);
379  REGISTER_METAVARIABLE("L1FTDL(name)", L1FTDL,
380  R"DOC(
381 [Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status (1 or 0) of the output trigger bit with the given name. Output bits are the outputs of GDL, combining different input trigger bits for final decision. For example, ``ty_0/1/2/3`` is one of the input trigger bits meaning the number of neuro 3D tracks is one/two/three/more than three. While ``yyy`` is one of the output trigger bits meaning ``(ty_2 or ty_3) and !veto``. Please check on `the dedicated Confluence page <https://confluence.desy.de/display/BI/TriggerBitTable>`__ or or `the dedicated Belle II notes <https://docs.belle2.org/search?ln=en&p=%22Trigger+Summary%22&f=&action_search=Search&c=Belle+II+Notes>`__ to find out the definition of trigger bits.
382 )DOC",
383  Manager::VariableDataType::c_double);
384  REGISTER_METAVARIABLE("L1Input(name)", L1Input,
385  R"DOC(
386 [Eventbased] Returns the input bit status (1 or 0) of the trigger bit with the given name. Input trigger bits are predefined selections from each sub-detector, with adjustment of the delay and width, in order to fix latency on GDL. For example, ``ty_0/1/2/3`` is one of the input trigger bits meaning the number of neuro 3D tracks is one/two/three/more than three. Please check on `the dedicated Confluence page <https://confluence.desy.de/display/BI/TriggerBitTable>`__ or or `the dedicated Belle II notes <https://docs.belle2.org/search?ln=en&p=%22Trigger+Summary%22&f=&action_search=Search&c=Belle+II+Notes>`__ to find out the definition of trigger bits.
387 )DOC",
388  Manager::VariableDataType::c_double);
389  REGISTER_METAVARIABLE("L1Prescale(name)", L1PSNMPrescale,
390  R"DOC(
391 [Eventbased] Returns the PSNM (prescale and mask) prescale factor of the trigger bit with the given name. Definition of prescale factor is shown in a few lines before in `L1PSNM`. Prescale factors are usually dependent on different datasets.
392 )DOC",
393  Manager::VariableDataType::c_double);
394  REGISTER_VARIABLE("L1PSNMBit(i)", L1PSNMBit,
395  R"DOC(
396 [Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status (1 or 0) of i-th trigger bit.
397 
398 .. warning::
399  It is recommended to use this variable only for debugging and to use :b2:var:`L1PSNM`
400  with the explicit trigger bit name for physics analyses or performance studies.
401 )DOC");
402  REGISTER_VARIABLE("L1FTDLBit(i)", L1FTDLBit,
403  R"DOC(
404 [Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status (1 or 0) of i-th trigger bit.
405 
406 .. warning::
407  It is recommended to use this variable only for debugging and to use :b2:var:`L1FTDL`
408  with the explicit trigger bit name for physics analyses or performance studies.
409 )DOC");
410  REGISTER_VARIABLE("L1InputBit(i)", L1InputBit,
411  R"DOC(
412 [Eventbased] Returns the input bit status (1 or 0) of the i-th input trigger bit.
413 
414 .. warning::
415  It is recommended to use this variable only for debugging and to use :b2:var:`L1Input`
416  with the explicit trigger bit name for physics analyses or performance studies.
417 )DOC");
418  REGISTER_VARIABLE("L1PSNMBitPrescale(i)", L1PSNMBitPrescale,
419  R"DOC(
420 [Eventbased] Returns the PSNM (prescale and mask) prescale of i-th trigger bit.
421 
422 .. warning::
423  It is recommended to use this variable only for debugging and to use :b2:var:`L1Prescale`
424  with the explicit trigger bit name for physics analyses or performance studies.
425 )DOC");
426  REGISTER_VARIABLE("L1TimeType", L1TimeType,
427  "[Eventbased] Returns kind of detector which determines the Level1 trigger timing. 0:ECL, 1:TOP, 2:SELF(timing of PSNM bit), 3:CDC, 5:delayed bhabha, 7: random, 13:poisson.");
428  REGISTER_VARIABLE("L1TimeQuality", L1TimeQuality,
429  "[Eventbased] Returns expected Level1 timing resolution. This flag will be used for SVD 3-point sampling in future. 0:None; 1:Coarse (sigma > x ns); 2:FINE (sigma < x ns); x has been set to about 5ns before LS1 but can be changed in future");
430  REGISTER_VARIABLE("isPoissonTriggerInInjectionVeto", isPoissonInInjectionVeto,
431  "[Eventbased] Returns 1 if the poisson random trigger is within the injection veto window.");
432  //-------------------------------------------------------------------------
433  VARIABLE_GROUP("Software Trigger");
434  REGISTER_METAVARIABLE("SoftwareTriggerResult(triggerIdentifier)", softwareTriggerResult, R"DOC(
435 [Eventbased] [Expert] returns the SoftwareTriggerCutResult, defined as reject (-1), accept (1), or noResult (0).
436 If the trigger identifier is not found, returns NaN.
437 
438 For example:
439 
440 .. code-block::
441 
442  SoftwareTriggerResult(filter 1_Estargt1_GeV_cluster_no_other_cluster_Estargt0.3_GeV)
443 
444 which is equivalent to
445 
446 .. code-block::
447 
448  SoftwareTriggerResult(software_trigger_cut&filter&1_Estargt1_GeV_cluster_no_other_cluster_Estargt0.3_GeV)
449 
450 
451 .. warning:: the meanings of these change depending if using trigger or the skim stage, hence expert.
452 
453 .. seealso:: ``b2hlt_triggers`` for possible triggerIdentifiers.
454 
455  )DOC", Manager::VariableDataType::c_double);
456 
457  REGISTER_METAVARIABLE("SoftwareTriggerResultNonPrescaled(triggerIdentifier)", softwareTriggerResultNonPrescaled,
458  "[Eventbased] [Expert] returns the SoftwareTriggerCutResult, "
459  "if this trigger would not be prescaled."
460  "Please note, this is not the final HLT decision! "
461  "It is defined as reject (-1), accept (1), or noResult (0). Note "
462  "that the meanings of these change depending if using trigger "
463  "or the skim stage, hence expert."
464  "If the trigger identifier is not found, returns NaN.", Manager::VariableDataType::c_double);
465  REGISTER_VARIABLE("HighLevelTrigger", passesAnyHighLevelTrigger,
466  "[Eventbased] True if event passes the HLT trigger, false if not");
467  REGISTER_METAVARIABLE("SoftwareTriggerPrescaling(triggerIdentifier)", softwareTriggerPrescaling,
468  "[Eventbased] return the prescaling for the specific software trigger identifier. "
469  "Please note, this prescaling is taken from the currently setup database. It only corresponds "
470  "to the correct HLT prescale if you are using the online database!"
471  "If the trigger identifier is not found, returns NaN.", Manager::VariableDataType::c_double);
472  //-------------------------------------------------------------------------
473  }
475 }
static const double doubleNaN
quiet_NaN
Definition: Const.h:694
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.