Belle II Software  release-05-01-25
TriggerVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2018 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Torben Ferber (torben.ferber@desy.de) *
7  * Sam Cunliffe (sam.cunliffe@desy.de) *
8  * *
9  * This software is provided "as is" without any warranty. *
10  **************************************************************************/
11 
12 #include <analysis/variables/TriggerVariables.h>
13 #include <analysis/dataobjects/Particle.h>
14 
15 // trigger dataobjects
16 #include <mdst/dataobjects/TRGSummary.h>
17 #include <mdst/dataobjects/SoftwareTriggerResult.h>
18 
19 // trigger dbobjects
20 #include <mdst/dbobjects/TRGGDLDBFTDLBits.h>
21 #include <mdst/dbobjects/TRGGDLDBPrescales.h>
22 
23 // HLT dbobjects
24 #include <mdst/dbobjects/DBRepresentationOfSoftwareTriggerCut.h>
25 
26 // framework
27 #include <framework/logging/Logger.h>
28 #include <framework/datastore/StoreObjPtr.h>
29 #include <framework/database/DBObjPtr.h>
30 
31 namespace Belle2 {
36  namespace {
41  double extractSoftwareTriggerResultImplementation(bool nonPrescaled, const std::string& triggerIdentifier, const Particle*)
42  {
43  // get trigger result object
44  StoreObjPtr<SoftwareTriggerResult> swtr;
45  if (!swtr) return std::numeric_limits<float>::quiet_NaN();
46 
47  // check that the trigger ID provided by the user exists in the SWTR
49  try {
50  if (nonPrescaled) {
51  swtcr = swtr->getNonPrescaledResult(triggerIdentifier);
52  } else {
53  swtcr = swtr->getResult(triggerIdentifier);
54  }
55  } catch (const std::out_of_range&) {
56  // then the trigger identifier is wrong
57  std::string err = "The trigger identifier \"" + triggerIdentifier;
58  err += "\" was not found. Maybe you misspelled it?\n";
59  err += "Here are all possible trigger identifiers: \n";
60  auto res = swtr->getResults();
61  for (auto& re : res) err += re.first + "\n";
62  B2FATAL(err);
63  }
64  return double(swtcr); // see mdst/dataobjects/include/SoftwareTriggerResult.h
65  };
66  }
67 
68  namespace Variable {
69 
70  double L1Trigger(const Particle*)
71  {
72  StoreObjPtr<TRGSummary> trg;
73  if (!trg) return std::numeric_limits<float>::quiet_NaN();
74  return trg->test();
75  }
76 
77  Manager::FunctionPtr L1PSNM(const std::vector<std::string>& arguments)
78  {
79  if (arguments.size() == 1) {
80  auto name = arguments[0];
81  auto func = [name](const Particle*) -> double {
82  StoreObjPtr<TRGSummary> trg;
83  if (!trg) return std::numeric_limits<float>::quiet_NaN();
84  return trg->testPsnm(name);
85  };
86  return func;
87  } else {
88  B2FATAL("Wrong number of arguments for L1PSNM function. The only argument must be the name of the PSNM trigger bit.");
89  }
90  }
91 
92  Manager::FunctionPtr L1FTDL(const std::vector<std::string>& arguments)
93  {
94  if (arguments.size() == 1) {
95  auto name = arguments[0];
96  auto func = [name](const Particle*) -> double {
97  StoreObjPtr<TRGSummary> trg;
98  if (!trg) return std::numeric_limits<float>::quiet_NaN();
99  return trg->testFtdl(name);
100  };
101  return func;
102  } else {
103  B2FATAL("Wrong number of arguments for L1FTDL function. The only argument must be the name of the FTDL trigger bit.");
104  }
105  }
106 
107  Manager::FunctionPtr L1Input(const std::vector<std::string>& arguments)
108  {
109  if (arguments.size() == 1) {
110  auto name = arguments[0];
111  auto func = [name](const Particle*) -> double {
112  StoreObjPtr<TRGSummary> trg;
113  if (!trg) return std::numeric_limits<float>::quiet_NaN();
114  return trg->testInput(name);
115  };
116  return func;
117  } else {
118  B2FATAL("Wrong number of arguments for L1Input function. The only argument must be the name of the input trigger bit.");
119  }
120  }
121 
122  Manager::FunctionPtr L1Prescale(const std::vector<std::string>& arguments)
123  {
124  if (arguments.size() == 1) {
125  auto name = arguments[0];
126  auto func = [name](const Particle*) -> double {
127  static DBObjPtr<TRGGDLDBFTDLBits> ftdlBits;
128  static DBObjPtr<TRGGDLDBPrescales> prescales;
129  for (unsigned int bit = 0; bit < TRGSummary::c_trgWordSize * TRGSummary::c_ntrgWords; bit++)
130  {
131  if (std::string(ftdlBits->getoutbitname((int)bit)) == name) {
132  return prescales->getprescales(bit);
133  }
134  }
135  return std::numeric_limits<float>::quiet_NaN();
136  };
137  return func;
138  } else {
139  B2FATAL("Wrong number of arguments for L1Prescale function. The only argument must be the name of the PSNM trigger bit.");
140  }
141  }
142 
143  double L1PSNMBit(const Particle*, const std::vector<double>& bit)
144  {
145  double isL1Trigger = 0.0;
146 
147  if (bit.size() != 1) return isL1Trigger;
148 
149  // The number of trigger words is hardcoded in the mdst dataobject and no getter for the full array exists
150  const unsigned int trgWordSize = 32;
151  const unsigned int ntrgWords = 10;
152  if (bit[0] >= trgWordSize * ntrgWords or bit[0] < 0) return isL1Trigger;
153 
154  // Get the trigger word that contains this bit (we could also convert the full array into a bitset or vector<bool> but that is a bit slower)
155  const unsigned int ntrgWord = (int) bit[0] / trgWordSize;
156 
157  // Get the bit by right shifting the desired bit into the least significant position and masking it with 1.
158  StoreObjPtr<TRGSummary> trg;
159  if (!trg) return std::numeric_limits<float>::quiet_NaN();
160  const unsigned int trgWord = trg->getPsnmBits(ntrgWord);
161  const unsigned int bitInWord = ((unsigned int) bit[0] - ntrgWord * trgWordSize);
162  isL1Trigger = (trgWord >> bitInWord) & 1;
163 
164  return isL1Trigger;
165  }
166 
167  double L1FTDLBit(const Particle*, const std::vector<double>& bit)
168  {
169  double isL1Trigger = 0.0;
170 
171  if (bit.size() != 1) return isL1Trigger;
172 
173  // The number of trigger words is hardcoded in the mdst dataobject and no getter for the full array exists
174 
175  const unsigned int trgWordSize = 32;
176  const unsigned int ntrgWords = 10;
177  if (bit[0] >= trgWordSize * ntrgWords or bit[0] < 0) return isL1Trigger;
178 
179  // Get the trigger word that contains this bit (we could also convert the full array into a bitset or vector<bool> but that is a bit slower)
180 
181  const unsigned int ntrgWord = (int) bit[0] / trgWordSize;
182 
183  // Get the bit by right shifting the desired bit into the least significant position and masking it with 1.
184 
185  StoreObjPtr<TRGSummary> trg;
186  if (!trg) return std::numeric_limits<float>::quiet_NaN();
187  const unsigned int trgWord = trg->getFtdlBits(ntrgWord);
188  const unsigned int bitInWord = ((unsigned int) bit[0] - ntrgWord * trgWordSize);
189  isL1Trigger = (trgWord >> bitInWord) & 1;
190 
191  return isL1Trigger;
192  }
193 
194 
195  double L1InputBit(const Particle*, const std::vector<double>& bit)
196  {
197  double isL1Trigger = 0.0;
198 
199  if (bit.size() != 1) return isL1Trigger;
200 
201  // The number of trigger words is hardcoded in the mdst dataobject and no getter for the full array exists
202  const unsigned int trgWordSize = 32;
203  const unsigned int ntrgWords = 10;
204  if (bit[0] >= trgWordSize * ntrgWords or bit[0] < 0) return isL1Trigger;
205 
206  // Get the trigger word that contains this bit (we could also convert the full array into a bitset or vector<bool> but that is a bit slower)
207  const unsigned int ntrgWord = (int) bit[0] / trgWordSize;
208 
209  // Get the bit by right shifting the desired bit into the least significant position and masking it with 1.
210  StoreObjPtr<TRGSummary> trg;
211  if (!trg) return std::numeric_limits<float>::quiet_NaN();
212  const unsigned int trgWord = trg->getInputBits(ntrgWord);
213  const unsigned int bitInWord = ((unsigned int) bit[0] - ntrgWord * trgWordSize);
214  isL1Trigger = (trgWord >> bitInWord) & 1;
215 
216  return isL1Trigger;
217  }
218 
219  double L1PSNMBitPrescale(const Particle*, const std::vector<double>& bit)
220  {
221  double prescale = 0.0;
222 
223  if (bit.size() != 1) return prescale;
224 
225  // The number of trigger words is hardcoded in the mdst dataobject
226  const unsigned int trgWordSize = 32;
227  const unsigned int ntrgWords = 10;
228  if (bit[0] >= trgWordSize * ntrgWords or bit[0] < 0) return prescale;
229 
230 
231  // Get the prescale word that contains this bit
232  const unsigned int ntrgWord = (int) bit[0] / trgWordSize;
233  const unsigned int bitInWord = ((unsigned int) bit[0] - ntrgWord * trgWordSize);
234 
235  StoreObjPtr<TRGSummary> trg;
236  if (!trg) return std::numeric_limits<float>::quiet_NaN();
237  prescale = trg->getPreScale(ntrgWord, bitInWord);
238 
239  return prescale;
240  }
241 
242  double getTimType(const Particle*)
243  {
244  StoreObjPtr<TRGSummary> trg;
245  if (!trg) return std::numeric_limits<float>::quiet_NaN();
246  return trg->getTimType();
247  }
248 
249  Manager::FunctionPtr softwareTriggerResult(const std::vector<std::string>& args)
250  {
251  /* The analyst has to know the name of the trigger she wants
252  * (after having looked this up from the trigger db payload)
253  *
254  * This workflow will probably improve later: but for now parse the args
255  * to check we have one name, then check the name does not throw an
256  * exception when we ask for it from the SWTR (std::map)
257  */
258  if (args.size() != 1)
259  B2FATAL("Wrong number of arguments for the function softwareTriggerResult");
260  std::string triggerIdentifier = args[0];
261 
262  using namespace std::placeholders;
263  return std::bind(extractSoftwareTriggerResultImplementation, false, triggerIdentifier, _1);
264  }
265 
266  Manager::FunctionPtr softwareTriggerResultNonPrescaled(const std::vector<std::string>& args)
267  {
268  /* The analyst has to know the name of the trigger she wants
269  * (after having looked this up from the trigger db payload)
270  *
271  * This workflow will probably improve later: but for now parse the args
272  * to check we have one name, then check the name does not throw an
273  * exception when we ask for it from the SWTR (std::map)
274  */
275  if (args.size() != 1)
276  B2FATAL("Wrong number of arguments for the function softwareTriggerResultNonPrescaled");
277  std::string triggerIdentifier = args[0];
278 
279  using namespace std::placeholders;
280  return std::bind(extractSoftwareTriggerResultImplementation, true, triggerIdentifier, _1);
281  }
282 
283  double passesAnyHighLevelTrigger(const Particle* p)
284  {
285  // for HLT, a c_accept is a pass and all other cases are fail
286  // see mdst/dataobjects/include/SoftwareTriggerResult.h
287  std::vector<std::string> hardcodedname
288  = { "software_trigger_cut&filter&total_result" };
289  double swtcr = softwareTriggerResult(hardcodedname)(p);
290  if (swtcr > 0.5) return 1.0; // 1
291  else return 0.0; // 0 or -1
292  }
293 
294  Manager::FunctionPtr softwareTriggerPrescaling(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 softwareTriggerPrescaling");
305  std::string triggerIdentifier = args[0];
306 
307  auto outputFunction = [triggerIdentifier](const Particle*) -> double {
308  DBObjPtr<DBRepresentationOfSoftwareTriggerCut> downloadedCut(triggerIdentifier);
309  if (not downloadedCut)
310  {
311  B2FATAL("There is no trigger with the given name " << triggerIdentifier << "!");
312  }
313 
314  return double(downloadedCut->getPreScaleFactor());
315  };
316 
317  return outputFunction;
318  }
319 
320  //-------------------------------------------------------------------------
321  VARIABLE_GROUP("L1 Trigger");
322  REGISTER_VARIABLE("L1Trigger", L1Trigger ,
323  "[Eventbased] Returns 1 if at least one PSNM L1 trigger bit is true.");
324  REGISTER_VARIABLE("L1PSNM(name)", L1PSNM ,
325  "[Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status of the trigger bit with the given name.");
326  REGISTER_VARIABLE("L1FTDL(name)", L1FTDL ,
327  "[Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status of the trigger bit with the given name.");
328  REGISTER_VARIABLE("L1Input(name)", L1Input,
329  "[Eventbased] Returns the input bit status of the trigger bit with the given name.");
330  REGISTER_VARIABLE("L1Prescale(name)", L1Prescale,
331  "[Eventbased] Returns the PSNM (prescale and mask) prescale of the trigger bit with the given name.");
332  REGISTER_VARIABLE("L1PSNMBit(i)", L1PSNMBit ,
333  "[Eventbased] Returns the PSNM (Prescale And Mask, after prescale) status of i-th trigger bit.");
334  REGISTER_VARIABLE("L1FTDLBit(i)", L1FTDLBit ,
335  "[Eventbased] Returns the FTDL (Final Trigger Decision Logic, before prescale) status of i-th trigger bit.");
336  REGISTER_VARIABLE("L1InputBit(i)", L1InputBit,
337  "[Eventbased] Returns the input bit status of the i-th input trigger bit.");
338  REGISTER_VARIABLE("L1PSNMBitPrescale(i)", L1PSNMBitPrescale,
339  "[Eventbased] Returns the PSNM (prescale and mask) prescale of i-th trigger bit.");
340  REGISTER_VARIABLE("L1TimType", getTimType ,
341  "[Eventbased] Returns ETimingType time type.");
342  //-------------------------------------------------------------------------
343  VARIABLE_GROUP("Software Trigger");
344  REGISTER_VARIABLE("SoftwareTriggerResult(triggerIdentifier)", softwareTriggerResult,
345  "[Eventbased] [Expert] returns the SoftwareTriggerCutResult, "
346  "defined as reject (-1), accept (1), or noResult (0). Note "
347  "that the meanings of these change depending if using trigger "
348  "or the skim stage, hence expert.");
349  REGISTER_VARIABLE("SoftwareTriggerResultNonPrescaled(triggerIdentifier)", softwareTriggerResultNonPrescaled,
350  "[Eventbased] [Expert] returns the SoftwareTriggerCutResult, "
351  "if this trigger would not be prescaled."
352  "Please note, this is not the final HLT decision! "
353  "It is defined as reject (-1), accept (1), or noResult (0). Note "
354  "that the meanings of these change depending if using trigger "
355  "or the skim stage, hence expert.");
356  REGISTER_VARIABLE("HighLevelTrigger", passesAnyHighLevelTrigger,
357  "[Eventbased] 1.0 if event passes the HLT trigger, 0.0 if not");
358  REGISTER_VARIABLE("SoftwareTriggerPrescaling(triggerIdentifier)", softwareTriggerPrescaling,
359  "[Eventbased] return the prescaling for the specific software trigger identifier. "
360  "Please note, this prescaling is taken from the currently setup database. It only corresponds "
361  "to the correct HLT prescale if you are using the online database!");
362  //-------------------------------------------------------------------------
363  }
365 }
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::Variable::Manager::FunctionPtr
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:118
Belle2::TRGSummary::c_trgWordSize
static const unsigned int c_trgWordSize
size of a l1 trigger word
Definition: TRGSummary.h:48
Belle2::TRGSummary::c_ntrgWords
static const unsigned int c_ntrgWords
number of l1 trigger words
Definition: TRGSummary.h:51
Belle2::SoftwareTriggerCutResult
SoftwareTriggerCutResult
Enumeration with all possible results of the SoftwareTriggerCut.
Definition: SoftwareTriggerResult.h:31