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