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