Belle II Software development
decaydescriptor.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/DecayDescriptor/DecayDescriptor.h>
10#include <analysis/dataobjects/Particle.h>
11
12#include <framework/datastore/StoreArray.h>
13#include <framework/utilities/TestHelpers.h>
14#include <framework/gearbox/Const.h>
15
16#include <gtest/gtest.h>
17#include <string>
18#include <vector>
19
20using namespace Belle2;
21
22namespace {
23 TEST(DecayDescriptorTest, TrivialUse)
24 {
25 // trivial decay descriptor == particle name
27 bool initok = dd.init(std::string{"K+"});
28 EXPECT_EQ(initok, true);
29 ASSERT_NE(dd.getMother(), nullptr);
30 EXPECT_EQ(dd.getMother()->getName(), "K+");
31 EXPECT_EQ(dd.getMother()->getLabel(), "");
32 EXPECT_EQ(dd.getMother()->getFullName(), "K+");
33 EXPECT_EQ(dd.getMother()->getPDGCode(), Const::kaon.getPDGCode());
34 EXPECT_EQ(dd.getNDaughters(), 0);
35 }
36
37 TEST(DecayDescriptorTest, NormalBehaviour)
38 {
40 bool initok = dd.init(std::string{"B0:cand -> K+:loose pi-:loose"});
41
42 EXPECT_EQ(initok, true);
43
44 // standard arrow, not an inclusive decay
45 EXPECT_EQ(dd.isIgnoreRadiatedPhotons(), true);
46 EXPECT_EQ(dd.isIgnoreIntermediate(), true);
47
48 ASSERT_NE(dd.getMother(), nullptr);
49 EXPECT_EQ(dd.getMother()->getName(), "B0");
50 EXPECT_EQ(dd.getMother()->getLabel(), "cand");
51 EXPECT_EQ(dd.getMother()->getPDGCode(), 511);
52 EXPECT_EQ(dd.getMother()->getFullName(), "B0:cand");
53 EXPECT_EQ(dd.getNDaughters(), 2);
54
55 EXPECT_EQ(dd.getDaughter(0)->getNDaughters(), 0);
56 EXPECT_EQ(dd.getDaughter(0)->getMother()->getName(), "K+");
57 EXPECT_EQ(dd.getDaughter(0)->getMother()->getLabel(), "loose");
58 EXPECT_EQ(dd.getDaughter(0)->getMother()->getPDGCode(), Const::kaon.getPDGCode());
59 EXPECT_EQ(dd.getDaughter(0)->getMother()->getFullName(), "K+:loose");
60
61 EXPECT_EQ(dd.getDaughter(1)->getNDaughters(), 0);
62 EXPECT_EQ(dd.getDaughter(1)->getMother()->getName(), "pi-");
63 EXPECT_EQ(dd.getDaughter(1)->getMother()->getLabel(), "loose");
64 EXPECT_EQ(dd.getDaughter(1)->getMother()->getPDGCode(), -Const::pion.getPDGCode());
65 EXPECT_EQ(dd.getDaughter(1)->getMother()->getFullName(), "pi-:loose");
66
67 ASSERT_EQ(dd.getDaughter(2), nullptr);
68 }
69
70 TEST(DecayDescriptorTest, Granddaughters)
71 {
73 bool initok = dd.init(
74 std::string{"B0:cand -> [D0:dau1 -> K+:grandau pi-:grandau] [pi0:dau2 -> gamma:grandau [gamma:converted -> e+:gtgrandau e-:gtgrandau]]"}
75 );
76 EXPECT_EQ(initok, true);
77 ASSERT_NE(dd.getMother(), nullptr);
78 EXPECT_EQ(dd.getNDaughters(), 2);
79
80 // D0 -> K pi
81 EXPECT_EQ(dd.getDaughter(0)->getMother()->getName(), "D0");
82 EXPECT_EQ(dd.getDaughter(0)->getMother()->getPDGCode(), 421);
83 EXPECT_EQ(dd.getDaughter(0)->getNDaughters(), 2);
84 EXPECT_EQ(dd.getDaughter(0)->getDaughter(0)->getMother()->getName(), "K+");
85 EXPECT_EQ(dd.getDaughter(0)->getDaughter(0)->getNDaughters(), 0);
86 EXPECT_EQ(dd.getDaughter(0)->getDaughter(1)->getMother()->getName(), "pi-");
87 EXPECT_EQ(dd.getDaughter(0)->getDaughter(1)->getNDaughters(), 0);
88 ASSERT_EQ(dd.getDaughter(0)->getDaughter(2), nullptr);
89
90 // pi0 -> gamma gamma; gamma -> ee
91 EXPECT_EQ(dd.getDaughter(1)->getMother()->getName(), "pi0");
92 EXPECT_EQ(dd.getDaughter(1)->getMother()->getPDGCode(), Const::pi0.getPDGCode());
93 EXPECT_EQ(dd.getDaughter(1)->getNDaughters(), 2);
94 EXPECT_EQ(dd.getDaughter(1)->getDaughter(0)->getMother()->getName(), "gamma");
95 EXPECT_EQ(dd.getDaughter(1)->getDaughter(0)->getMother()->getLabel(), "grandau");
97 EXPECT_EQ(dd.getDaughter(1)->getDaughter(0)->getNDaughters(), 0);
98 EXPECT_EQ(dd.getDaughter(1)->getDaughter(1)->getMother()->getName(), "gamma");
99 EXPECT_EQ(dd.getDaughter(1)->getDaughter(1)->getMother()->getLabel(), "converted");
101 EXPECT_EQ(dd.getDaughter(1)->getDaughter(1)->getNDaughters(), 2);
102 EXPECT_EQ(dd.getDaughter(1)->getDaughter(1)->getDaughter(0)->getMother()->getName(), "e+");
104 EXPECT_EQ(dd.getDaughter(1)->getDaughter(1)->getDaughter(1)->getMother()->getName(), "e-");
106 ASSERT_EQ(dd.getDaughter(1)->getDaughter(1)->getDaughter(2), nullptr);
107 ASSERT_EQ(dd.getDaughter(1)->getDaughter(2), nullptr);
108
109 ASSERT_EQ(dd.getDaughter(2), nullptr);
110 }
111
112 TEST(DecayDescriptorTest, ArrowsDecaysGrammar)
113 {
114 // =direct=> means ignore intermediate resonances
115 DecayDescriptor dd1;
116 bool initok = dd1.init(std::string{"B0:candidates =direct=> K+:loose pi-:loose gamma:clean"});
117 EXPECT_EQ(initok, true);
118 EXPECT_EQ(dd1.isIgnoreRadiatedPhotons(), true);
119 EXPECT_EQ(dd1.isIgnoreIntermediate(), false);
120
121 // =norad=> means ignore photons
122 DecayDescriptor dd2;
123 initok = dd2.init(std::string{"B0:candidates =norad=> K+:loose pi-:loose gamma:clean"});
124 EXPECT_EQ(initok, true);
125 EXPECT_EQ(dd2.isIgnoreRadiatedPhotons(), false);
126 EXPECT_EQ(dd2.isIgnoreIntermediate(), true);
127
128 // =exact=> means ignore intermediate resonances *and* photons
129 DecayDescriptor dd3;
130 initok = dd3.init(std::string{"B0:candidates =exact=> K+:loose pi-:loose gamma:clean"});
131 EXPECT_EQ(initok, true);
132 EXPECT_EQ(dd3.isIgnoreRadiatedPhotons(), false);
133 EXPECT_EQ(dd3.isIgnoreIntermediate(), false);
134
135 }
136
137 TEST(DecayDescriptorTest, KeywordDecaysGrammar)
138 {
139 // ... means accept missing massive
140 DecayDescriptor dd1;
141 bool initok = dd1.init(std::string{"B0:candidates -> K+:loose gamma:clean ..."});
142 EXPECT_EQ(initok, true);
143 EXPECT_EQ(dd1.isIgnoreRadiatedPhotons(), true);
144 EXPECT_EQ(dd1.isIgnoreIntermediate(), true);
145 EXPECT_EQ(dd1.isIgnoreMassive(), true);
146 EXPECT_EQ(dd1.isIgnoreNeutrino(), false);
147 EXPECT_EQ(dd1.isIgnoreGamma(), false);
148 EXPECT_EQ(dd1.isIgnoreBrems(), false);
149
150 // ?nu means accept missing neutrino
151 DecayDescriptor dd2;
152 initok = dd2.init(std::string{"B0:candidates -> K+:loose pi-:loose ?nu"});
153 EXPECT_EQ(initok, true);
154 EXPECT_EQ(dd2.isIgnoreRadiatedPhotons(), true);
155 EXPECT_EQ(dd2.isIgnoreIntermediate(), true);
156 EXPECT_EQ(dd2.isIgnoreMassive(), false);
157 EXPECT_EQ(dd2.isIgnoreNeutrino(), true);
158 EXPECT_EQ(dd2.isIgnoreGamma(), false);
159 EXPECT_EQ(dd2.isIgnoreBrems(), false);
160
161 // !nu does not change anything. It is reserved for future updates.
162 DecayDescriptor dd3;
163 initok = dd3.init(std::string{"B0:candidates -> K+:loose pi-:loose !nu"});
164 EXPECT_EQ(initok, true);
165 EXPECT_EQ(dd3.isIgnoreRadiatedPhotons(), true);
166 EXPECT_EQ(dd3.isIgnoreIntermediate(), true);
167 EXPECT_EQ(dd3.isIgnoreMassive(), false);
168 EXPECT_EQ(dd3.isIgnoreNeutrino(), false);
169 EXPECT_EQ(dd3.isIgnoreGamma(), false);
170 EXPECT_EQ(dd3.isIgnoreBrems(), false);
171
172 // ?gamma means ignore missing gamma
173 DecayDescriptor dd4;
174 initok = dd4.init(std::string{"B0:candidates -> K+:loose pi-:loose ?gamma"});
175 EXPECT_EQ(initok, true);
176 EXPECT_EQ(dd4.isIgnoreRadiatedPhotons(), true);
177 EXPECT_EQ(dd4.isIgnoreIntermediate(), true);
178 EXPECT_EQ(dd4.isIgnoreMassive(), false);
179 EXPECT_EQ(dd4.isIgnoreNeutrino(), false);
180 EXPECT_EQ(dd4.isIgnoreGamma(), true);
181 EXPECT_EQ(dd4.isIgnoreBrems(), false);
182
183 // !gamma does not change anything. It is reserved for future updates.
184 DecayDescriptor dd5;
185 initok = dd5.init(std::string{"B0:candidates -> K+:loose pi-:loose !gamma"});
186 EXPECT_EQ(initok, true);
187 EXPECT_EQ(dd5.isIgnoreRadiatedPhotons(), true);
188 EXPECT_EQ(dd5.isIgnoreIntermediate(), true);
189 EXPECT_EQ(dd5.isIgnoreMassive(), false);
190 EXPECT_EQ(dd5.isIgnoreNeutrino(), false);
191 EXPECT_EQ(dd5.isIgnoreGamma(), false);
192 EXPECT_EQ(dd5.isIgnoreBrems(), false);
193
194 // ... ?nu ?gamma means accept missing massive
195 DecayDescriptor dd6;
196 initok = dd6.init(std::string{"B0:candidates -> e-:loose ... ?nu ?gamma"});
197 EXPECT_EQ(initok, true);
198 EXPECT_EQ(dd6.isIgnoreRadiatedPhotons(), true);
199 EXPECT_EQ(dd6.isIgnoreIntermediate(), true);
200 EXPECT_EQ(dd6.isIgnoreMassive(), true);
201 EXPECT_EQ(dd6.isIgnoreNeutrino(), true);
202 EXPECT_EQ(dd6.isIgnoreGamma(), true);
203 EXPECT_EQ(dd6.isIgnoreBrems(), false);
204
205 // ?addbrems means ignore photon added by Brems-correction tools (modularAnalysis.correctBrems / modularAnalysis.correctBremsBelle)
206 DecayDescriptor dd7;
207 initok = dd7.init(std::string{"B0:candidates -> K+:loose pi-:loose ?addbrems"});
208 EXPECT_EQ(initok, true);
209 EXPECT_EQ(dd7.isIgnoreRadiatedPhotons(), true);
210 EXPECT_EQ(dd7.isIgnoreIntermediate(), true);
211 EXPECT_EQ(dd7.isIgnoreMassive(), false);
212 EXPECT_EQ(dd7.isIgnoreNeutrino(), false);
213 EXPECT_EQ(dd7.isIgnoreGamma(), false);
214 EXPECT_EQ(dd7.isIgnoreBrems(), true);
215
216 }
217
218 TEST(DecayDescriptorTest, UnspecifiedParticleGrammar)
219 {
220 // @ means unspecified particle, for example @Xsd -> K+ pi-
221 DecayDescriptor dd1;
222 bool initok = dd1.init(std::string{"@Xsd:candidates -> K+:loose pi-:loose"});
223 EXPECT_EQ(initok, true);
224 ASSERT_NE(dd1.getMother(), nullptr);
225 EXPECT_EQ(dd1.getMother()->getName(), "Xsd");
226 EXPECT_EQ(dd1.getMother()->isUnspecified(), true);
227 EXPECT_EQ(dd1.getMother()->isSelected(), false);
228
229 // Both selectors, @ and ^, can be used at the same time
230 DecayDescriptor dd2;
231 initok = dd2.init(std::string{"^@Xsd:candidates -> K+:loose pi-:loose"});
232 EXPECT_EQ(initok, true);
233 EXPECT_EQ(dd2.getMother()->getName(), "Xsd");
234 EXPECT_EQ(dd2.getMother()->isUnspecified(), true);
235 EXPECT_EQ(dd2.getMother()->isSelected(), true);
236
237 DecayDescriptor dd3;
238 initok = dd3.init(std::string{"@^Xsd:candidates -> K+:loose pi-:loose"});
239 EXPECT_EQ(initok, true);
240 EXPECT_EQ(dd3.getMother()->getName(), "Xsd");
241 EXPECT_EQ(dd3.getMother()->isUnspecified(), true);
242 EXPECT_EQ(dd3.getMother()->isSelected(), true);
243
244 // @ can be attached to a daughter
245 DecayDescriptor dd4;
246 initok = dd4.init(std::string{"B0:Xsdee -> @Xsd e+:loose e-:loose"});
247 EXPECT_EQ(initok, true);
248 ASSERT_NE(dd4.getMother(), nullptr);
249 EXPECT_EQ(dd4.getMother()->isUnspecified(), false);
250 EXPECT_EQ(dd4.getMother()->isSelected(), false);
251 EXPECT_EQ(dd4.getDaughter(0)->getMother()->getName(), "Xsd");
252 EXPECT_EQ(dd4.getDaughter(0)->getMother()->isUnspecified(), true);
253 EXPECT_EQ(dd4.getDaughter(0)->getMother()->isSelected(), false);
254
255 // Both selectors, @ and ^, can be used at the same time
256 DecayDescriptor dd5;
257 initok = dd5.init(std::string{"B0:Xsdee -> ^@Xsd e+:loose e-:loose"});
258 EXPECT_EQ(initok, true);
259 EXPECT_EQ(dd5.getDaughter(0)->getMother()->getName(), "Xsd");
260 EXPECT_EQ(dd5.getDaughter(0)->getMother()->isUnspecified(), true);
261 EXPECT_EQ(dd5.getDaughter(0)->getMother()->isSelected(), true);
262
263 DecayDescriptor dd6;
264 initok = dd6.init(std::string{"B0:Xsdee -> @^Xsd e+:loose e-:loose"});
265 EXPECT_EQ(initok, true);
266 EXPECT_EQ(dd6.getDaughter(0)->getMother()->getName(), "Xsd");
267 EXPECT_EQ(dd6.getDaughter(0)->getMother()->isUnspecified(), true);
268 EXPECT_EQ(dd6.getDaughter(0)->getMother()->isSelected(), true);
269
270 }
271
272 TEST(DecayDescriptorTest, GrammarWithNestedDecay)
273 {
274 // ... means accept missing massive
275 DecayDescriptor dd1;
276 bool initok = dd1.init(std::string{"B0:candidates =direct=> [D-:pi =norad=> pi-:loose ... ?gamma] e+:loose ?nu ?addbrems"});
277 EXPECT_EQ(initok, true);
278 EXPECT_EQ(dd1.isIgnoreRadiatedPhotons(), true);
279 EXPECT_EQ(dd1.isIgnoreIntermediate(), false);
280 EXPECT_EQ(dd1.isIgnoreMassive(), false);
281 EXPECT_EQ(dd1.isIgnoreNeutrino(), true);
282 EXPECT_EQ(dd1.isIgnoreGamma(), false);
283 EXPECT_EQ(dd1.isIgnoreBrems(), true);
284
285 const DecayDescriptor* dd1_D = dd1.getDaughter(0);
286 EXPECT_EQ(dd1_D->getMother()->getName(), "D-");
287 EXPECT_EQ(dd1_D->isIgnoreRadiatedPhotons(), false);
288 EXPECT_EQ(dd1_D->isIgnoreIntermediate(), true);
289 EXPECT_EQ(dd1_D->isIgnoreMassive(), true);
290 EXPECT_EQ(dd1_D->isIgnoreNeutrino(), false);
291 EXPECT_EQ(dd1_D->isIgnoreGamma(), true);
292 EXPECT_EQ(dd1_D->isIgnoreBrems(), false);
293
294 }
295
296
297 TEST(DecayDescriptorTest, SelectionParticles)
298 {
299 DecayDescriptor dd1;
300 bool initok = dd1.init(std::string{"B0:B2Dzpipi -> [D0 -> ^K+:loose pi-:loose] pi+:loose pi-:loose"});
301 EXPECT_EQ(initok, true);
302 std::vector<std::string> names = dd1.getSelectionNames();
303 std::vector<int> pdgs = dd1.getSelectionPDGCodes();
304 ASSERT_EQ(names.size(), 1);
305 EXPECT_EQ(names[0], "B0_D0_K");
306 ASSERT_EQ(pdgs.size(), 1);
307 EXPECT_EQ(pdgs[0], 321);
308
309 // add another selection particle to an already existing decay descriptor
310 // not sure exactly who is using this feature, but might as well test it.
311 initok = dd1.init(std::string{"B0:B2Dzpipi -> [D0 -> K+:loose ^pi-:loose] pi+:loose pi-:loose"});
312 EXPECT_EQ(initok, true);
313 names = dd1.getSelectionNames();
314 pdgs = dd1.getSelectionPDGCodes();
315 ASSERT_EQ(names.size(), 2);
316 EXPECT_EQ(names[0], "B0_D0_K");
317 EXPECT_EQ(names[1], "B0_D0_pi");
318 ASSERT_EQ(pdgs.size(), 2);
319 EXPECT_EQ(pdgs[0], 321);
320 EXPECT_EQ(pdgs[1], -211);
321
322 // more complex decay string with multiple particles of the same type
323 DecayDescriptor dd2;
324 initok = dd2.init(std::string{"vpho:complex -> [D0 -> ^K+:loose pi-:loose] ^e+:loose ^e-:loose ^gamma:loose"});
325 EXPECT_EQ(initok, true);
326 names = dd2.getSelectionNames();
327 pdgs = dd2.getSelectionPDGCodes();
328 ASSERT_EQ(names.size(), 4);
329 EXPECT_EQ(names[0], "vpho_D0_K");
330 EXPECT_EQ(names[1], "vpho_e0");
331 EXPECT_EQ(names[2], "vpho_e1");
332 EXPECT_EQ(names[3], "vpho_gamma");
333 ASSERT_EQ(pdgs.size(), 4);
334 EXPECT_EQ(pdgs[0], 321);
335 EXPECT_EQ(pdgs[1], -11);
336 EXPECT_EQ(pdgs[2], 11);
337 EXPECT_EQ(pdgs[3], 22);
338 }
339
340 TEST(DecayDescriptorTest, MisIDandDecayInFlightGrammar)
341 {
342 // MisID is ignored for a daughter which has (misID) in the head
343 DecayDescriptor dd1;
344 bool initok = dd1.init(std::string{"B0:sig -> (misID)K+:loose pi-:loose"});
345 EXPECT_EQ(initok, true);
346 ASSERT_NE(dd1.getMother(), nullptr);
347 EXPECT_EQ(dd1.getMother()->getName(), "B0");
348 EXPECT_EQ(dd1.getMother()->isIgnoreMisID(), false);
349 EXPECT_EQ(dd1.getMother()->isIgnoreDecayInFlight(), false);
350 ASSERT_NE(dd1.getDaughter(0), nullptr);
351 EXPECT_EQ(dd1.getDaughter(0)->getMother()->getName(), "K+");
352 EXPECT_EQ(dd1.getDaughter(0)->getMother()->isIgnoreMisID(), true);
353 EXPECT_EQ(dd1.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), false);
354 ASSERT_NE(dd1.getDaughter(1), nullptr);
355 EXPECT_EQ(dd1.getDaughter(1)->getMother()->getName(), "pi-");
356 EXPECT_EQ(dd1.getDaughter(1)->getMother()->isIgnoreMisID(), false);//
357 EXPECT_EQ(dd1.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), false);
358
359 DecayDescriptor dd2;
360 initok = dd2.init(std::string{"B0:sig -> K+:loose (misID)pi-:loose"});
361 EXPECT_EQ(initok, true);
362 ASSERT_NE(dd2.getDaughter(0), nullptr);
363 EXPECT_EQ(dd2.getDaughter(0)->getMother()->getName(), "K+");
364 EXPECT_EQ(dd2.getDaughter(0)->getMother()->isIgnoreMisID(), false);//
365 EXPECT_EQ(dd2.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), false);
366 ASSERT_NE(dd2.getDaughter(1), nullptr);
367 EXPECT_EQ(dd2.getDaughter(1)->getMother()->getName(), "pi-");
368 EXPECT_EQ(dd2.getDaughter(1)->getMother()->isIgnoreMisID(), true);
369 EXPECT_EQ(dd2.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), false);
370
371 DecayDescriptor dd3;
372 initok = dd3.init(std::string{"B0:sig -> (misID)K+:loose (misID)pi-:loose"});
373 EXPECT_EQ(initok, true);
374 ASSERT_NE(dd3.getDaughter(0), nullptr);
375 EXPECT_EQ(dd3.getDaughter(0)->getMother()->getName(), "K+");
376 EXPECT_EQ(dd3.getDaughter(0)->getMother()->isIgnoreMisID(), true);
377 EXPECT_EQ(dd3.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), false);
378 ASSERT_NE(dd3.getDaughter(1), nullptr);
379 EXPECT_EQ(dd3.getDaughter(1)->getMother()->getName(), "pi-");
380 EXPECT_EQ(dd3.getDaughter(1)->getMother()->isIgnoreMisID(), true);
381 EXPECT_EQ(dd3.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), false);
382
383 // DecayInFlight is ignored for a daughter which has (decay) in the head
384 DecayDescriptor dd4;
385 initok = dd4.init(std::string{"B0:sig -> (decay)K+:loose pi-:loose"});
386 EXPECT_EQ(initok, true);
387 ASSERT_NE(dd4.getDaughter(0), nullptr);
388 EXPECT_EQ(dd4.getDaughter(0)->getMother()->getName(), "K+");
389 EXPECT_EQ(dd4.getDaughter(0)->getMother()->isIgnoreMisID(), false);
390 EXPECT_EQ(dd4.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), true);
391 ASSERT_NE(dd4.getDaughter(1), nullptr);
392 EXPECT_EQ(dd4.getDaughter(1)->getMother()->getName(), "pi-");
393 EXPECT_EQ(dd4.getDaughter(1)->getMother()->isIgnoreMisID(), false);
394 EXPECT_EQ(dd4.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), false);//
395
396 DecayDescriptor dd5;
397 initok = dd5.init(std::string{"B0:sig -> K+:loose (decay)pi-:loose"});
398 EXPECT_EQ(initok, true);
399 ASSERT_NE(dd5.getDaughter(0), nullptr);
400 EXPECT_EQ(dd5.getDaughter(0)->getMother()->getName(), "K+");
401 EXPECT_EQ(dd5.getDaughter(0)->getMother()->isIgnoreMisID(), false);
402 EXPECT_EQ(dd5.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), false);//
403 ASSERT_NE(dd5.getDaughter(1), nullptr);
404 EXPECT_EQ(dd5.getDaughter(1)->getMother()->getName(), "pi-");
405 EXPECT_EQ(dd5.getDaughter(1)->getMother()->isIgnoreMisID(), false);
406 EXPECT_EQ(dd5.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), true);
407
408 DecayDescriptor dd6;
409 initok = dd6.init(std::string{"B0:sig -> (decay)K+:loose (decay)pi-:loose"});
410 EXPECT_EQ(initok, true);
411 ASSERT_NE(dd6.getDaughter(0), nullptr);
412 EXPECT_EQ(dd6.getDaughter(0)->getMother()->getName(), "K+");
413 EXPECT_EQ(dd6.getDaughter(0)->getMother()->isIgnoreMisID(), false);
414 EXPECT_EQ(dd6.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), true);
415 ASSERT_NE(dd6.getDaughter(1), nullptr);
416 EXPECT_EQ(dd6.getDaughter(1)->getMother()->getName(), "pi-");
417 EXPECT_EQ(dd6.getDaughter(1)->getMother()->isIgnoreMisID(), false);
418 EXPECT_EQ(dd6.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), true);
419
420 // @, ^, (misID), and (decay) can be used at the same time
421 DecayDescriptor dd7;
422 initok = dd7.init(std::string{"B0:sig -> (misID)(decay)K+:loose (decay)(misID)pi-:loose"});
423 EXPECT_EQ(initok, true);
424 ASSERT_NE(dd7.getDaughter(0), nullptr);
425 EXPECT_EQ(dd7.getDaughter(0)->getMother()->getName(), "K+");
426 EXPECT_EQ(dd7.getDaughter(0)->getMother()->isSelected(), false);
427 EXPECT_EQ(dd7.getDaughter(0)->getMother()->isUnspecified(), false);
428 EXPECT_EQ(dd7.getDaughter(0)->getMother()->isIgnoreMisID(), true);
429 EXPECT_EQ(dd7.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), true);
430 ASSERT_NE(dd7.getDaughter(1), nullptr);
431 EXPECT_EQ(dd7.getDaughter(1)->getMother()->getName(), "pi-");
432 EXPECT_EQ(dd7.getDaughter(1)->getMother()->isSelected(), false);
433 EXPECT_EQ(dd7.getDaughter(1)->getMother()->isUnspecified(), false);
434 EXPECT_EQ(dd7.getDaughter(1)->getMother()->isIgnoreMisID(), true);
435 EXPECT_EQ(dd7.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), true);
436
437 DecayDescriptor dd8;
438 initok = dd8.init(std::string{"B0:sig -> ^(misID)K+:loose (decay)@pi-:loose"});
439 EXPECT_EQ(initok, true);
440 ASSERT_NE(dd8.getDaughter(0), nullptr);
441 EXPECT_EQ(dd8.getDaughter(0)->getMother()->getName(), "K+");
442 EXPECT_EQ(dd8.getDaughter(0)->getMother()->isSelected(), true);
443 EXPECT_EQ(dd8.getDaughter(0)->getMother()->isUnspecified(), false);
444 EXPECT_EQ(dd8.getDaughter(0)->getMother()->isIgnoreMisID(), true);
445 EXPECT_EQ(dd8.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), false);
446 ASSERT_NE(dd8.getDaughter(1), nullptr);
447 EXPECT_EQ(dd8.getDaughter(1)->getMother()->getName(), "pi-");
448 EXPECT_EQ(dd8.getDaughter(1)->getMother()->isSelected(), false);
449 EXPECT_EQ(dd8.getDaughter(1)->getMother()->isUnspecified(), true);
450 EXPECT_EQ(dd8.getDaughter(1)->getMother()->isIgnoreMisID(), false);
451 EXPECT_EQ(dd8.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), true);
452
453 DecayDescriptor dd9;
454 initok = dd9.init(std::string{"B0:sig -> ^@(misID)(decay)K+:loose (decay)@^(misID)pi-:loose"});
455 EXPECT_EQ(initok, true);
456 ASSERT_NE(dd9.getDaughter(0), nullptr);
457 EXPECT_EQ(dd9.getDaughter(0)->getMother()->getName(), "K+");
458 EXPECT_EQ(dd9.getDaughter(0)->getMother()->isSelected(), true);
459 EXPECT_EQ(dd9.getDaughter(0)->getMother()->isUnspecified(), true);
460 EXPECT_EQ(dd9.getDaughter(0)->getMother()->isIgnoreMisID(), true);
461 EXPECT_EQ(dd9.getDaughter(0)->getMother()->isIgnoreDecayInFlight(), true);
462 ASSERT_NE(dd9.getDaughter(1), nullptr);
463 EXPECT_EQ(dd9.getDaughter(1)->getMother()->getName(), "pi-");
464 EXPECT_EQ(dd9.getDaughter(1)->getMother()->isSelected(), true);
465 EXPECT_EQ(dd9.getDaughter(1)->getMother()->isUnspecified(), true);
466 EXPECT_EQ(dd9.getDaughter(1)->getMother()->isIgnoreMisID(), true);
467 EXPECT_EQ(dd9.getDaughter(1)->getMother()->isIgnoreDecayInFlight(), true);
468
469 }
470
471 TEST(DecayDescriptorTest, BadLabelTest)
472 {
473 // use of illegal characters in labels
474 DecayDescriptor dd1;
475 bool initok = dd1.init(std::string{"B0:lab[el -> K+:loose pi-:loose"});
476 EXPECT_EQ(initok, false);
477 EXPECT_EQ(dd1.getMother()->getName(), "");
478 EXPECT_EQ(dd1.getMother()->getLabel(), "");
479
480 DecayDescriptor dd2;
481 initok = dd2.init(std::string{"B0:lab^el -> K+:loose pi-:loose"});
482 EXPECT_EQ(initok, false);
483 EXPECT_EQ(dd2.getMother()->getName(), "");
484 EXPECT_EQ(dd2.getMother()->getLabel(), "");
485
486 DecayDescriptor dd3;
487 initok = dd3.init(std::string{"B0:lab]el -> K+:loose pi-:loose"});
488 EXPECT_EQ(initok, false);
489 EXPECT_EQ(dd3.getMother()->getName(), "");
490 EXPECT_EQ(dd3.getMother()->getLabel(), "");
491
492 DecayDescriptor dd4;
493 initok = dd4.init(std::string{"B0:lab>el -> K+:loose pi-:loose"});
494 EXPECT_EQ(initok, false);
495 EXPECT_EQ(dd4.getMother()->getName(), "");
496 EXPECT_EQ(dd4.getMother()->getLabel(), "");
497
498 DecayDescriptor dd5;
499 initok = dd5.init(std::string{"B0:lab:el -> K+:loose pi-:loose"});
500 EXPECT_EQ(initok, false);
501 EXPECT_EQ(dd5.getMother()->getName(), "");
502 EXPECT_EQ(dd5.getMother()->getLabel(), "");
503 }
504
505 TEST(DecayDescriptorTest, UnicodeTest)
506 {
507 // this is broken with boost 1.72, still need to investigate
508 return;
509 // use of unicode characters in labels
510 const std::string weird = "⨔π⁰=πŸ–ΌπŸ”°";
511 DecayDescriptor dd1;
512 bool initok = dd1.init(std::string{"B0:" + weird + " -> K+:πŸ’©πŸ˜œ pi-:πŸ’―πŸ†πŸ’¦"});
513 ASSERT_EQ(initok, true);
514 EXPECT_EQ(dd1.getMother()->getName(), "B0");
515 EXPECT_EQ(dd1.getMother()->getLabel(), weird);
516 ASSERT_EQ(dd1.getNDaughters(), 2);
517 EXPECT_EQ(dd1.getDaughter(0)->getMother()->getName(), "K+");
518 EXPECT_EQ(dd1.getDaughter(1)->getMother()->getName(), "pi-");
519 EXPECT_EQ(dd1.getDaughter(0)->getMother()->getLabel(), "πŸ’©πŸ˜œ");
520 EXPECT_EQ(dd1.getDaughter(1)->getMother()->getLabel(), "πŸ’―πŸ†πŸ’¦");
521 }
522
523 TEST(DecayDescriptorTest, BadGrammarTest)
524 {
525 DecayDescriptor dd1;
526 bool initok = dd1.init(std::string{"B0:label ---> K+:loose pi-:loose"});
527 EXPECT_EQ(initok, false);
528
529 DecayDescriptor dd2;
530 initok = dd2.init(std::string{"B0:label > K+:loose pi-:loose"});
531 EXPECT_EQ(initok, false);
532
533 DecayDescriptor dd3;
534 initok = dd3.init(std::string{"B0:label -> K+::loose pi-:loose"});
535 EXPECT_EQ(initok, false);
536
537 DecayDescriptor dd4;
538 initok = dd4.init(std::string{"B0:label K+:loose pi-:loose"});
539 EXPECT_EQ(initok, false);
540
541 DecayDescriptor dd5;
542 initok = dd5.init(std::string{"B0:label <- K+:loose pi-:loose"});
543 EXPECT_EQ(initok, false);
544
545 DecayDescriptor dd6;
546 initok = dd6.init(std::string{"B0:label => K+:loose pi-:loose"});
547 EXPECT_EQ(initok, false);
548
549 DecayDescriptor dd7;
550 initok = dd7.init(std::string{"B0:label --> K+:loose pi-:loose"});
551 EXPECT_EQ(initok, false);
552
553 DecayDescriptor dd8;
554 initok = dd8.init(std::string{"B0:label ==> K+:loose pi-:loose"});
555 EXPECT_EQ(initok, false);
556 }
557
558 TEST(DecayDescriptorTest, B2ParticleInterface)
559 {
560 // need datastore for the particles StoreArray
562 StoreArray<Particle> particles;
563 particles.registerInDataStore();
565
566 // mock up a composite Belle2::Particle
567 ROOT::Math::PxPyPzEVector zeroes(0, 0, 0, 0);
568 Particle* Kp = particles.appendNew(Particle(zeroes, 321)); // 0
569 Particle* pim1 = particles.appendNew(Particle(zeroes, -211)); // 1
570 Particle* pim2 = particles.appendNew(Particle(zeroes, -211)); // 2
571 Particle* pip = particles.appendNew(Particle(zeroes, 211)); // 3
572 Particle* D0 = particles.appendNew(Particle(zeroes, 421)); // 4
573 D0->appendDaughter(0);
574 D0->appendDaughter(1);
575 Particle* B0 = particles.appendNew(Particle(zeroes, 511)); // 5
576 B0->appendDaughter(4);
577 B0->appendDaughter(3);
578 B0->appendDaughter(2);
579
580 // ---
582 bool initok = dd.init(std::string{"B0:B2Dzpipi -> [D0 -> K+:loose ^pi-:loose] ^pi+:loose pi-:loose"});
583 ASSERT_EQ(initok, true);
584
585 std::vector<const Particle*> selectionparticles = dd.getSelectionParticles(B0);
586 EXPECT_EQ(selectionparticles.size(), 2);
587 EXPECT_EQ(selectionparticles[0], pim1);
588 EXPECT_EQ(selectionparticles[1], pip);
589
590 EXPECT_B2ERROR(dd.getSelectionParticles(D0));
591
592 EXPECT_B2WARNING(dd.getSelectionParticles(pip));
593 EXPECT_B2WARNING(dd.getSelectionParticles(Kp));
594 EXPECT_B2WARNING(dd.getSelectionParticles(pim1));
595 EXPECT_B2WARNING(dd.getSelectionParticles(pim2));
596
597 EXPECT_EQ(dd.getSelectionParticles(D0).size(), 0);
598
600 }
601
602 TEST(DecayDescriptorTest, HierarchyDefinitionTest)
603 {
605 bool initok = dd.init(std::string{"B+ -> [ D+ -> ^K+ pi0 ] ^pi0"});
606 EXPECT_EQ(initok, true);
607
608 auto selected_hierarchies = dd.getHierarchyOfSelected();
609
610 std::vector<std::vector<std::pair<int, std::string>>> expected_hierarchies;
611 std::vector<std::pair<int, std::string>> K_path;
612 std::vector<std::pair<int, std::string>> pi0_path;
613
614 K_path.emplace_back(0, std::string("B"));
615 K_path.emplace_back(0, std::string("D"));
616 K_path.emplace_back(0, std::string("K"));
617
618 pi0_path.emplace_back(0, std::string("B"));
619 pi0_path.emplace_back(1, std::string("pi0"));
620
621 EXPECT_NE(expected_hierarchies, selected_hierarchies);
622 expected_hierarchies.push_back(K_path);
623 expected_hierarchies.push_back(pi0_path);
624 EXPECT_EQ(expected_hierarchies, selected_hierarchies);
625 }
626}
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleType pi0
neutral pion particle
Definition: Const.h:674
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:662
static const ParticleType photon
photon particle
Definition: Const.h:673
static const ChargedStable electron
electron particle
Definition: Const.h:659
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:94
void reset(EDurability durability)
Frees memory occupied by data store items and removes all objects from the map.
Definition: DataStore.cc:86
int getPDGCode() const
Return PDG code.
bool isUnspecified() const
Is the particle unspecified?
std::string getFullName() const
returns the full name of the particle full_name = name:label
bool isSelected() const
Is the particle selected in the decay string?
bool isIgnoreDecayInFlight() const
Check if decayInFlight shall be ignored.
std::string getName() const
evt.pdl name of the particle.
std::string getLabel() const
The label of this particle, "default" returned, when no label set.
bool isIgnoreMisID() const
Check if misID shall be ignored.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
bool isIgnoreBrems() const
Check if added Brems gammas shall be ignored.
bool isIgnoreRadiatedPhotons() const
Check if additional radiated photons shall be ignored.
bool init(const std::string &str)
Initialise the DecayDescriptor from given string.
const DecayDescriptor * getDaughter(int i) const
return i-th daughter (0 based index).
bool isIgnoreNeutrino() const
Check if missing neutrinos shall be ignored.
std::vector< int > getSelectionPDGCodes()
Return list of PDG codes of selected particles.
int getNDaughters() const
return number of direct daughters.
bool isIgnoreMassive() const
Check if missing massive final state particles shall be ignored.
std::vector< std::vector< std::pair< int, std::string > > > getHierarchyOfSelected()
Function to get hierarchy of selected particles and their names (for python use)
bool isIgnoreGamma() const
Check if missing gammas shall be ignored.
std::vector< std::string > getSelectionNames()
Return list of human readable names of selected particles.
std::vector< const Particle * > getSelectionParticles(const Particle *particle)
Get a vector of pointers with selected daughters in the decay tree.
bool isIgnoreIntermediate() const
Check if intermediate resonances/particles shall be ignored.
const DecayDescriptorParticle * getMother() const
return mother.
Class to store reconstructed particles.
Definition: Particle.h:75
void appendDaughter(const Particle *daughter, const bool updateType=true, const int daughterProperty=c_Ordinary)
Appends index of daughter to daughters index array.
Definition: Particle.cc:676
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Abstract base class for different kinds of events.