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#include <framework/utilities/Conversion.h>
30
31// boost
32#include <boost/algorithm/string.hpp>
33
34// C++
35#include <limits>
36#include <stdexcept>
37
38namespace 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.
370For some output trigger bits, we assign a prescale factor to reduce the number of triggered events.
371For 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).
372Prescale factor of a given output trigger bit could be different in different datasets.
373It is recommended to use prescaled trigger bits (L1PSNM) or un-prescaled trigger bits (L1FTDL) for your analysis.
374In run-independent MC, configuration of the prescales in TSIM (trigger simulation) can be different from data, so L1 FTDL is recommended.
375In run-dependent MC, configuration of the prescales in TSIM is consistent with data, so L1PSNM is recommended.
376Please 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.
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 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.
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 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.
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).
436If the trigger identifier is not found, returns NaN.
437
438For example:
439
440.. code-block::
441
442 SoftwareTriggerResult(filter 1_Estargt1_GeV_cluster_no_other_cluster_Estargt0.3_GeV)
443
444which 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: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:113
SoftwareTriggerCutResult
Enumeration with all possible results of the SoftwareTriggerCut.
Abstract base class for different kinds of events.