Belle II Software development
particle.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#include <analysis/dataobjects/Particle.h>
9#include <analysis/dataobjects/RestOfEvent.h>
10#include <analysis/dataobjects/ParticleExtraInfoMap.h>
11#include <mdst/dataobjects/MCParticle.h>
12#include <mdst/dataobjects/ECLCluster.h>
13#include <mdst/dataobjects/KLMCluster.h>
14#include <mdst/dataobjects/V0.h>
15#include <framework/datastore/StoreArray.h>
16#include <framework/datastore/StoreObjPtr.h>
17#include <framework/gearbox/Const.h>
18#include <framework/utilities/TestHelpers.h>
19
20#include <analysis/utility/ParticleCopy.h>
21
22#include <TDatabasePDG.h>
23
24#include <gtest/gtest.h>
25
26using namespace std;
27using namespace Belle2;
28using namespace Belle2::ParticleCopy;
29using namespace ROOT::Math;
30
31namespace {
33 class ParticleTest : public ::testing::Test {
34 protected:
36 void SetUp() override
37 {
39 StoreObjPtr<ParticleExtraInfoMap> particleExtraInfo;
40 StoreArray<Particle> particles;
41 StoreArray<MCParticle> mcparticles;
43 StoreArray<ECLCluster> eclClusters;
44 StoreArray<KLMCluster> klmClusters;
46 particleExtraInfo.registerInDataStore();
47 particles.registerInDataStore();
48 mcparticles.registerInDataStore();
49 eclClusters.registerInDataStore();
51 klmClusters.registerInDataStore();
53 particles.registerRelationTo(mcparticles);
54 particles.registerRelationTo(roes);
56 }
57
59 void TearDown() override
60 {
62 }
63 };
64
65
66 TEST_F(ParticleTest, Constructors)
67 {
68 {
69 Particle p;
70 EXPECT_EQ(0, p.getPDGCode());
71 EXPECT_TRUE(PxPyPzEVector(0, 0, 0, 0) == p.get4Vector());
72 EXPECT_EQ(Particle::c_Undefined, p.getParticleSource());
73 }
74 {
75 PxPyPzEVector momentum(1, 2, 3, 4);
76 Particle p(momentum, 421);
77 EXPECT_EQ(421, p.getPDGCode());
78 EXPECT_FLOAT_EQ(0.0, momentum.phi() - p.get4Vector().phi());
79 EXPECT_FLOAT_EQ(0.0, momentum.Rapidity() - p.get4Vector().Rapidity());
80 EXPECT_FLOAT_EQ(momentum.energy(), p.get4Vector().energy());
81 EXPECT_FLOAT_EQ(momentum.energy(), p.getEnergy());
82 EXPECT_FLOAT_EQ(momentum.M(), p.getMass());
83 EXPECT_EQ(Particle::c_Undefined, p.getParticleSource());
84 }
85 {
86 PxPyPzEVector momentum(1, 2, 3, 4);
87 Particle p(momentum, 22, Particle::c_Unflavored, Particle::c_MCParticle, 123);
88 EXPECT_EQ(22, p.getPDGCode());
89 EXPECT_FLOAT_EQ(0.0, momentum.phi() - p.get4Vector().phi());
90 EXPECT_FLOAT_EQ(0.0, momentum.Rapidity() - p.get4Vector().Rapidity());
91 EXPECT_FLOAT_EQ(momentum.energy(), p.get4Vector().energy());
92 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
93 EXPECT_EQ(Particle::c_MCParticle, p.getParticleSource());
94 EXPECT_EQ(123u, p.getMdstArrayIndex());
95 }
96 {
97 // test constructor from ECLClusters
98 // (for now we can only create a photon this way)
100 ECLCluster* cluster = clusters.appendNew(ECLCluster());
101 cluster->setIsTrack(false);
102 cluster->addHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
103 cluster->setEnergy(1337);
104
105 Particle p(cluster);
106 EXPECT_EQ(22, p.getPDGCode());
107 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
108 EXPECT_EQ(Particle::c_ECLCluster, p.getParticleSource());
109 EXPECT_FLOAT_EQ(1337, p.getEnergy());
110 EXPECT_EQ(cluster, p.getECLCluster());
111 EXPECT_EQ(nullptr, p.getTrack());
112 }
113 {
114 // test constructor used for V0s (there is not actually a V0 constructor,
115 // the heavy-lifting is done in the particle loader), but this is V0-style
116 // construction with EParticleSourceObject::V0 and the correct getters
117 StoreArray<V0> v0s;
118 V0* v0 = v0s.appendNew(V0());
119 PxPyPzEVector momentum(1, 2, 3, 4);
120 Particle p(momentum, 310, Particle::c_Unflavored, Particle::c_V0, 0);
121 EXPECT_EQ(310, p.getPDGCode());
122 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
123 EXPECT_EQ(Particle::c_V0, p.getParticleSource());
124 EXPECT_EQ(0u, p.getMdstArrayIndex());
125 EXPECT_EQ(p.getV0(), v0); // pointers should be same
126 }
127 }
128
129 TEST_F(ParticleTest, Daughters)
130 {
131 PxPyPzEVector momentum;
132 const int nDaughters = 6;
133 StoreArray<Particle> particles;
134 std::vector<int> daughterIndices;
135 for (int i = 0; i < nDaughters; i++) {
136 Particle d(PxPyPzEVector(1, 0, 0, 3.0), (i % 2) ? 211 : -211);
137 momentum += d.get4Vector();
138 Particle* newDaughters = particles.appendNew(d);
139 daughterIndices.push_back(newDaughters->getArrayIndex());
140 }
141
142 const Particle& p = *(particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices));
143 EXPECT_EQ(411, p.getPDGCode());
144 EXPECT_FLOAT_EQ(0.0, momentum.phi() - p.get4Vector().phi());
145 EXPECT_FLOAT_EQ(0.0, momentum.Rapidity() - p.get4Vector().Rapidity());
146 EXPECT_FLOAT_EQ(momentum.energy(), p.get4Vector().energy());
147 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
148 EXPECT_EQ(Particle::c_Composite, p.getParticleSource());
149 EXPECT_EQ(0u, p.getMdstArrayIndex());
150 EXPECT_EQ((unsigned int)nDaughters, p.getNDaughters());
151 EXPECT_EQ((unsigned int)nDaughters, p.getDaughters().size());
152 EXPECT_EQ((unsigned int)nDaughters, p.getFinalStateDaughters().size());
153 EXPECT_EQ((unsigned int)nDaughters, p.getDaughterProperties().size());
154
155 const Particle pLocal(momentum, 411, Particle::c_Unflavored, daughterIndices, particles.getPtr());
156 EXPECT_DOUBLE_EQ(p.getMass(), pLocal.getMass());
157 EXPECT_EQ((unsigned int)nDaughters, pLocal.getNDaughters());
158 EXPECT_EQ((unsigned int)nDaughters, pLocal.getDaughters().size());
159 EXPECT_EQ((unsigned int)nDaughters, pLocal.getFinalStateDaughters().size());
160 EXPECT_EQ((unsigned int)nDaughters, pLocal.getDaughterProperties().size());
161
162 Particle outsideArray;
163 EXPECT_TRUE(outsideArray.getArrayPointer() == nullptr);
164 EXPECT_B2FATAL(Particle p2 = Particle(momentum, 411, Particle::c_Unflavored, daughterIndices));
165 }
166
167 TEST_F(ParticleTest, DaughterProperties)
168 {
169 PxPyPzEVector momentum;
170 const int nDaughters = 6;
171 StoreArray<Particle> particles;
172 std::vector<int> daughterIndices;
173 std::vector<int> daughterProperties;
174 for (int i = 0; i < nDaughters; i++) {
175 Particle d(PxPyPzEVector(1, 0, 0, 3.0), (i % 2) ? 211 : -211);
176 momentum += d.get4Vector();
177 Particle* newDaughters = particles.appendNew(d);
178 daughterIndices.push_back(newDaughters->getArrayIndex());
179 daughterProperties.push_back(Particle::PropertyFlags::c_Ordinary);
180 }
181
182 const Particle& p = *(particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices));
183 EXPECT_EQ(411, p.getPDGCode());
184 EXPECT_FLOAT_EQ(0.0, momentum.phi() - p.get4Vector().phi());
185 EXPECT_FLOAT_EQ(0.0, momentum.Rapidity() - p.get4Vector().Rapidity());
186 EXPECT_FLOAT_EQ(momentum.energy(), p.get4Vector().energy());
187 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
188 EXPECT_EQ(Particle::c_Composite, p.getParticleSource());
189 EXPECT_EQ(0u, p.getMdstArrayIndex());
190 EXPECT_EQ((unsigned int)nDaughters, p.getNDaughters());
191 EXPECT_EQ((unsigned int)nDaughters, p.getDaughters().size());
192 EXPECT_EQ((unsigned int)nDaughters, p.getFinalStateDaughters().size());
193 EXPECT_EQ((unsigned int)nDaughters, p.getDaughterProperties().size());
194 EXPECT_EQ(Particle::PropertyFlags::c_Ordinary, (p.getDaughterProperties())[0]);
195
196
197 const Particle pLocal(momentum, 411, Particle::c_Unflavored, daughterIndices,
198 Particle::PropertyFlags::c_Ordinary, daughterProperties,
199 particles.getPtr());
200 EXPECT_DOUBLE_EQ(p.getMass(), pLocal.getMass());
201 EXPECT_EQ((unsigned int)nDaughters, pLocal.getNDaughters());
202 EXPECT_EQ((unsigned int)nDaughters, pLocal.getDaughters().size());
203 EXPECT_EQ((unsigned int)nDaughters, pLocal.getFinalStateDaughters().size());
204 EXPECT_EQ((unsigned int)nDaughters, pLocal.getDaughterProperties().size());
205
206 Particle outsideArray;
207 EXPECT_TRUE(outsideArray.getArrayPointer() == nullptr);
208 EXPECT_B2FATAL(Particle p2 = Particle(momentum, 411, Particle::c_Unflavored, daughterIndices));
209 }
210
212 struct ParticleChildrenCounter {
213 int count{0};
215 bool operator()(const Particle*) { ++count; return false; }
216 };
217
218 TEST_F(ParticleTest, ForEachDaughters)
219 {
220 // setup a particle with some daughters and grand daughters
221 PxPyPzEVector momentum;
222 const int nDaughters = 6;
223 StoreArray<Particle> particles;
224 std::vector<int> daughterIndices;
225 int nGrandDaughters = 0;
226 for (int i = 0; i < nDaughters; i++) {
227 Particle d(PxPyPzEVector(1, 0, 0, 3.0), (i % 2) ? 211 : -211);
228 momentum += d.get4Vector();
229 Particle* newDaughters = particles.appendNew(d);
230 daughterIndices.push_back(newDaughters->getArrayIndex());
231 if (i % 2 == 0) {
232 Particle* grandDaughter = particles.appendNew(d);
233 newDaughters->appendDaughter(grandDaughter);
234 ++nGrandDaughters;
235 }
236 }
237 const Particle& p = *(particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices));
238
239 // Check if we get called the correct amount of times
240 int count{0};
241 auto counterFct = [&count](const Particle*) { ++count; return false; };
242 EXPECT_FALSE(p.forEachDaughter(counterFct, false, false));
243 EXPECT_EQ(count, nDaughters);
244 count = 0;
245 EXPECT_FALSE(p.forEachDaughter(counterFct, true, false));
246 EXPECT_EQ(count, nDaughters + nGrandDaughters);
247 count = 0;
248 EXPECT_FALSE(p.forEachDaughter(counterFct, false, true));
249 EXPECT_EQ(count, nDaughters + 1);
250 count = 0;
251 EXPECT_FALSE(p.forEachDaughter(counterFct, true, true));
252 EXPECT_EQ(count, nDaughters + nGrandDaughters + 1);
253
254 // Functors passed by value don't return the state
255 ParticleChildrenCounter counterStruct;
256 EXPECT_FALSE(p.forEachDaughter(counterStruct));
257 EXPECT_EQ(counterStruct.count, 0);
258 // But if reference_wrapped it should work fine
259 EXPECT_FALSE(p.forEachDaughter(std::reference_wrapper<ParticleChildrenCounter>(counterStruct)));
260 EXPECT_EQ(counterStruct.count, nDaughters + nGrandDaughters + 1);
261
262 // Test return value: if we return true the processing should be stopped so
263 // count should not be increased anymore
264 int maxchildren{1}, total{nDaughters + nGrandDaughters + 1};
265 auto returnFctTester = [&count, &maxchildren](const Particle*) {++count; return count >= maxchildren; };
266 for (; maxchildren < 2 * total; ++maxchildren) {
267 count = 0;
268 EXPECT_EQ(p.forEachDaughter(returnFctTester), maxchildren <= total);
269 EXPECT_EQ(count, std::min(maxchildren, total));
270 }
271 }
272
274 TEST_F(ParticleTest, ExtraInfo)
275 {
276 Particle p;
277 //doesn't exist
278 EXPECT_THROW(p.getExtraInfo("htns"), std::runtime_error);
279
280 p.addExtraInfo("htns", 32.0);
281
282 //cannot add it again
283 EXPECT_THROW(p.addExtraInfo("htns", 1234.0), std::runtime_error);
284
285 EXPECT_DOUBLE_EQ(32.0, p.getExtraInfo("htns"));
286
287 }
288
290 TEST_F(ParticleTest, Copies)
291 {
292 StoreArray<Particle> particles;
293 StoreArray<MCParticle> mcparticles;
294 StoreArray<ECLCluster> eclClusters;
295 ECLCluster* eclGamma1 = eclClusters. appendNew(ECLCluster());
296 eclGamma1->setConnectedRegionId(1);
297 eclGamma1->setClusterId(1);
298 eclGamma1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
299 ECLCluster* eclGamma2 = eclClusters. appendNew(ECLCluster());
300 eclGamma2->setConnectedRegionId(1);
301 eclGamma2->setClusterId(2);
302 eclGamma2->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
303 ECLCluster* eclGamma3 = eclClusters. appendNew(ECLCluster());
304 eclGamma3->setConnectedRegionId(2);
305 eclGamma3->setClusterId(1);
306 eclGamma3->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
307 ECLCluster* eclKL = eclClusters. appendNew(ECLCluster());
308 eclKL->setConnectedRegionId(2);
309 eclKL->setClusterId(1);
310 eclKL->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
311
312
313
314 // create some particles
315 Particle* T1Pion = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 211, Particle::c_Flavored, Particle::c_Track, 1));
316 Particle* T2Pion = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), -211, Particle::c_Flavored, Particle::c_Track, 2));
317
318 // T1PionCopy is a copy of T1Pion (both are created from the same Track and are pions)
319 Particle* T1PionCopy = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 211, Particle::c_Flavored, Particle::c_Track, 1));
320
321 // T1Kaon is not a coy of T1Pion (both are created from the same Track, but are of different hypothesis)
322 Particle* T1Kaon = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 321, Particle::c_Flavored, Particle::c_Track, 1));
323 Particle* T2Kaon = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), -321, Particle::c_Flavored, Particle::c_Track, 2));
324 Particle* T3Kaon = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 321, Particle::c_Flavored, Particle::c_Track, 3));
325 Particle* T4Kaon = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), -321, Particle::c_Flavored, Particle::c_Track, 4));
326
327 // T1Gamma
328 Particle* T1Gamma = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 22, Particle::c_Unflavored, Particle::c_ECLCluster,
329 0));
330 // T2Gamma
331 Particle* T2Gamma = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 22, Particle::c_Unflavored, Particle::c_ECLCluster,
332 1));
333
334 // T3Gamma
335 Particle* T3Gamma = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 22, Particle::c_Unflavored, Particle::c_ECLCluster,
336 2));
337 // T4KL
338 Particle* T4KL = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), Const::Klong.getPDGCode(), Particle::c_Unflavored,
339 Particle::c_ECLCluster,
340 3));
341 MCParticle* MC1Pion = mcparticles. appendNew(MCParticle());
342 MC1Pion->setPDG(Const::pion.getPDGCode());
343 MC1Pion->set4Vector(PxPyPzEVector(0, 0, 0, 0));
344 Particle* T1PionFromMC = particles.appendNew(Particle(MC1Pion));
345
346 EXPECT_TRUE(T3Gamma->overlapsWith(T4KL));
347 EXPECT_FALSE(T3Gamma->overlapsWith(T2Gamma));
348 EXPECT_FALSE(T3Gamma->overlapsWith(T1Gamma));
349 EXPECT_FALSE(T1Gamma->overlapsWith(T2Gamma));
350
351 EXPECT_TRUE(T1Pion->isCopyOf(T1PionCopy));
352 EXPECT_FALSE(T1Pion->isCopyOf(T1Kaon));
353 EXPECT_FALSE(T1Pion->isCopyOf(T1Gamma));
354 EXPECT_FALSE(T2Gamma->isCopyOf(T1Gamma));
355
356 //detailed comparison
357 EXPECT_TRUE(T1Pion->isCopyOf(T1PionCopy, true));
358 EXPECT_TRUE(T1Pion->isCopyOf(T1Kaon, true));
359 EXPECT_FALSE(T2Gamma->isCopyOf(T1Gamma, true));
360 EXPECT_TRUE(T3Gamma->isCopyOf(T4KL, true));
361 EXPECT_FALSE(T1PionFromMC->isCopyOf(T1Pion, true));
362 EXPECT_FALSE(T1Pion->isCopyOf(T1PionFromMC, true));
363 // Construct composite particles
364 Particle* D0Pi1Pi2 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
365 D0Pi1Pi2->appendDaughter(T1Pion);
366 D0Pi1Pi2->appendDaughter(T2Pion);
367
368 Particle* D0Pi1Pi2Copy = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
369 D0Pi1Pi2Copy->appendDaughter(T1Pion);
370 D0Pi1Pi2Copy->appendDaughter(T2Pion);
371
372 Particle* D0Pi1Pi2Copy2 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
373 D0Pi1Pi2Copy2->appendDaughter(T1PionCopy);
374 D0Pi1Pi2Copy2->appendDaughter(T2Pion);
375
376 Particle* D0K1K2 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
377 D0K1K2->appendDaughter(T1Kaon);
378 D0K1K2->appendDaughter(T2Kaon);
379
380 Particle* D0K1Pi2 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
381 D0K1Pi2->appendDaughter(T1Kaon);
382 D0K1Pi2->appendDaughter(T2Pion);
383
384 EXPECT_FALSE(D0Pi1Pi2->isCopyOf(D0K1K2));
385 EXPECT_FALSE(D0Pi1Pi2->isCopyOf(D0K1Pi2));
386 EXPECT_TRUE(D0Pi1Pi2->isCopyOf(D0Pi1Pi2Copy));
387 EXPECT_TRUE(D0Pi1Pi2->isCopyOf(D0Pi1Pi2Copy2));
388 EXPECT_TRUE(D0Pi1Pi2Copy->isCopyOf(D0Pi1Pi2Copy2));
389
390 // even more composite particles
391 Particle* D0K3K4 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 421));
392 D0K3K4->appendDaughter(T3Kaon);
393 D0K3K4->appendDaughter(T4Kaon);
394
395 Particle* B0_1 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 511));
396 B0_1->appendDaughter(D0Pi1Pi2);
397 B0_1->appendDaughter(D0K3K4);
398
399 Particle* B0_2 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 511));
400 B0_2->appendDaughter(D0Pi1Pi2Copy);
401 B0_2->appendDaughter(D0K3K4);
402
403 Particle* B0_3 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 511));
404 B0_3->appendDaughter(D0Pi1Pi2Copy2);
405 B0_3->appendDaughter(D0K3K4);
406
407 EXPECT_TRUE(B0_1->isCopyOf(B0_2));
408 EXPECT_TRUE(B0_1->isCopyOf(B0_3));
409 EXPECT_TRUE(B0_2->isCopyOf(B0_3));
410
411 Particle* B0_4 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 511));
412 B0_4->appendDaughter(D0Pi1Pi2);
413 B0_4->appendDaughter(D0K1K2);
414
415 Particle* B0_5 = particles.appendNew(Particle(PxPyPzEVector(0, 0, 0, 0), 511));
416 B0_5->appendDaughter(D0Pi1Pi2);
417 B0_5->appendDaughter(T1Kaon);
418 B0_5->appendDaughter(T2Kaon);
419
420 EXPECT_FALSE(B0_1->isCopyOf(B0_4));
421 EXPECT_FALSE(B0_4->isCopyOf(B0_5));
422 }
423
425 TEST_F(ParticleTest, ExtraInfoMap)
426 {
428
429 Particle p;
430 p.print();
431 p.addExtraInfo("htns", 1.0);
432 EXPECT_EQ(1u, map->getNMaps());
433
434 //adding another variable should just extend the current map
435 p.addExtraInfo("somethingelse", 2.0);
436 EXPECT_EQ(1u, map->getNMaps());
437
438 //storing same things in another particle shouldn't create a new map
439 Particle q;
440 q.addExtraInfo("htns", 11.0);
441 EXPECT_EQ(1u, map->getNMaps());
442 q.addExtraInfo("somethingelse", 12.0);
443 EXPECT_EQ(1u, map->getNMaps());
444
445 //lets store something different in p and q
446 p.addExtraInfo("thirdvar_p", 3.0);
447 EXPECT_EQ(1u, map->getNMaps());
448 //different var in 3rd place, needs new map
449 q.addExtraInfo("thirdvar_q", 13.0);
450 EXPECT_EQ(2u, map->getNMaps());
451
452
453 //set same vars as with p and q again, one of them should switch maps
454 Particle s;
455 s.addExtraInfo("htns", 1.0);
456 s.addExtraInfo("somethingelse", 2.0);
457 s.addExtraInfo("thirdvar_p", 3.0);
458 Particle t;
459 t.addExtraInfo("htns", 1.0);
460 t.addExtraInfo("somethingelse", 2.0);
461 t.addExtraInfo("thirdvar_q", 3.0);
462 //if switching works, there should still be the same number of maps
463 EXPECT_EQ(2u, map->getNMaps());
464 //verify switching worked
465 EXPECT_THROW(s.getExtraInfo("thirdvar_q"), std::runtime_error);
466 EXPECT_THROW(t.getExtraInfo("thirdvar_p"), std::runtime_error);
467
468 //reusing maps shouldn't cause it to find unset vars (e.g. when one value is set, but map has more entries)
469 Particle u;
470 EXPECT_THROW(u.getExtraInfo("htns"), std::runtime_error);
471 u.addExtraInfo("htns", 1.0);
472 EXPECT_THROW(u.getExtraInfo("somethingelse"), std::runtime_error);
473 EXPECT_THROW(u.getExtraInfo("thirdvar_p"), std::runtime_error);
474 EXPECT_THROW(u.getExtraInfo("thirdvar_q"), std::runtime_error);
475 u.addExtraInfo("somethingelse", 2.0);
476 EXPECT_THROW(u.getExtraInfo("thirdvar_p"), std::runtime_error);
477 EXPECT_THROW(u.getExtraInfo("thirdvar_q"), std::runtime_error);
478
479
480 //add something else first, followed by variables we already used
481 Particle v;
482 v.addExtraInfo("first", 0.0);
483 v.addExtraInfo("htns", 1.0);
484 v.addExtraInfo("somethingelse", 2.0);
485 v.addExtraInfo("thirdvar_q", 3.0);
486
487
488 //verify the values we set
489 EXPECT_DOUBLE_EQ(1.0, p.getExtraInfo("htns"));
490 EXPECT_DOUBLE_EQ(2.0, p.getExtraInfo("somethingelse"));
491 EXPECT_DOUBLE_EQ(3.0, p.getExtraInfo("thirdvar_p"));
492
493 EXPECT_DOUBLE_EQ(11.0, q.getExtraInfo("htns"));
494 EXPECT_DOUBLE_EQ(12.0, q.getExtraInfo("somethingelse"));
495 EXPECT_DOUBLE_EQ(13.0, q.getExtraInfo("thirdvar_q"));
496
497 EXPECT_DOUBLE_EQ(1.0, s.getExtraInfo("htns"));
498 EXPECT_DOUBLE_EQ(2.0, s.getExtraInfo("somethingelse"));
499 EXPECT_DOUBLE_EQ(3.0, s.getExtraInfo("thirdvar_p"));
500
501 EXPECT_DOUBLE_EQ(1.0, t.getExtraInfo("htns"));
502 EXPECT_DOUBLE_EQ(2.0, t.getExtraInfo("somethingelse"));
503 EXPECT_DOUBLE_EQ(3.0, t.getExtraInfo("thirdvar_q"));
504
505 EXPECT_DOUBLE_EQ(0.0, v.getExtraInfo("first"));
506 EXPECT_DOUBLE_EQ(1.0, v.getExtraInfo("htns"));
507 EXPECT_DOUBLE_EQ(2.0, v.getExtraInfo("somethingelse"));
508 EXPECT_DOUBLE_EQ(3.0, v.getExtraInfo("thirdvar_q"));
509
510 //check data is copied with Particle
511 Particle tCopy = t;
512 EXPECT_DOUBLE_EQ(1.0, tCopy.getExtraInfo("htns"));
513 EXPECT_DOUBLE_EQ(2.0, tCopy.getExtraInfo("somethingelse"));
514 EXPECT_DOUBLE_EQ(3.0, tCopy.getExtraInfo("thirdvar_q"));
515 tCopy.print();
516 }
517
518
520 TEST_F(ParticleTest, ParticleCopyUtility)
521 {
522 StoreArray<Particle> particles;
523 StoreArray<MCParticle> mcparticles;
525
526 // create some particles
527 Particle* T1Pion = particles.appendNew(Particle(PxPyPzEVector(1, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 1));
528 MCParticle* MC1 = mcparticles. appendNew(MCParticle());
529 MC1->setPDG(1);
530 T1Pion->addExtraInfo("test_var", 1.0);
531 T1Pion->addRelationTo(MC1);
532 Particle* T2Kaon = particles.appendNew(Particle(PxPyPzEVector(2, 2, 2, 2), -321, Particle::c_Flavored, Particle::c_Track, 2));
533 MCParticle* MC2 = mcparticles. appendNew(MCParticle());
534 MC1->setPDG(2);
535 T2Kaon->addExtraInfo("test_var", 2.0);
536 T2Kaon->addRelationTo(MC2);
537 Particle* T3Kaon = particles.appendNew(Particle(PxPyPzEVector(3, 3, 3, 3), 321, Particle::c_Flavored, Particle::c_Track, 3));
538 MCParticle* MC3 = mcparticles. appendNew(MCParticle());
539 MC3->setPDG(3);
540 T3Kaon->addExtraInfo("test_var", 3.0);
541 T3Kaon->addRelationTo(MC3);
542 Particle* ROEPion = particles.appendNew(Particle(PxPyPzEVector(3.5, 3.5, 3.5, 3.5), 211, Particle::c_Flavored,
543 Particle::c_Track, 4));
544
545 // Construct composite particles
546 Particle* D0KK = particles.appendNew(Particle(PxPyPzEVector(4, 4, 4, 4), 421));
547 D0KK->appendDaughter(T2Kaon);
548 D0KK->appendDaughter(T3Kaon);
549
550 Particle* B0 = particles.appendNew(Particle(PxPyPzEVector(5, 5, 5, 5), 511));
551 B0->appendDaughter(D0KK);
552 B0->appendDaughter(T1Pion);
553
554 RestOfEvent* roe = roes.appendNew(RestOfEvent());
555
556 roe->addParticles({ROEPion});
557 B0->addRelationTo(roe);
558
559 // Perform tests
560 // First sanity check
561 // at this point the size of Particle/MCParticle/ROE StoreArray should be 6/3/1
562 EXPECT_EQ(particles.getEntries(), 6);
563 EXPECT_EQ(mcparticles.getEntries(), 3);
564 EXPECT_EQ(roes.getEntries(), 1);
565
566 // now make a copy of B0
567 Particle* B0_copy = copyParticle(B0);
568 // at this point the size of Particle/MCParticle/ROE StoreArray should be 11/3/1
569 EXPECT_EQ(particles.getEntries(), 11);
570 EXPECT_EQ(mcparticles.getEntries(), 3);
571 EXPECT_EQ(roes.getEntries(), 1);
572
573 // compare copy with original
574 EXPECT_EQ(B0->getPDGCode(), B0_copy->getPDGCode());
575 EXPECT_EQ(B0->getNDaughters(), B0_copy->getNDaughters());
576 EXPECT_EQ(B0->getDaughter(0)->getPDGCode(), B0_copy->getDaughter(0)->getPDGCode());
577 EXPECT_EQ(B0->getDaughter(1)->getPDGCode(), B0_copy->getDaughter(1)->getPDGCode());
578 EXPECT_EQ(B0->getDaughter(0)->getDaughter(0)->getPDGCode(), B0_copy->getDaughter(0)->getDaughter(0)->getPDGCode());
579 EXPECT_EQ(B0->getDaughter(0)->getDaughter(1)->getPDGCode(), B0_copy->getDaughter(0)->getDaughter(1)->getPDGCode());
580
581 EXPECT_FALSE(B0->getArrayIndex() == B0_copy->getArrayIndex());
582 EXPECT_FALSE(B0->getDaughter(0)->getArrayIndex() == B0_copy->getDaughter(0)->getArrayIndex());
583 EXPECT_FALSE(B0->getDaughter(1)->getArrayIndex() == B0_copy->getDaughter(1)->getArrayIndex());
584 EXPECT_FALSE(B0->getDaughter(0)->getDaughter(0)->getArrayIndex() == B0_copy->getDaughter(0)->getDaughter(0)->getArrayIndex());
585 EXPECT_FALSE(B0->getDaughter(0)->getDaughter(1)->getArrayIndex() == B0_copy->getDaughter(0)->getDaughter(1)->getArrayIndex());
586
587 EXPECT_TRUE(B0->get4Vector() == B0_copy->get4Vector());
588 EXPECT_TRUE(B0->getDaughter(0)->get4Vector() == B0_copy->getDaughter(0)->get4Vector());
589 EXPECT_TRUE(B0->getDaughter(1)->get4Vector() == B0_copy->getDaughter(1)->get4Vector());
590 EXPECT_TRUE(B0->getDaughter(0)->getDaughter(0)->get4Vector() == B0_copy->getDaughter(0)->getDaughter(0)->get4Vector());
591 EXPECT_TRUE(B0->getDaughter(0)->getDaughter(1)->get4Vector() == B0_copy->getDaughter(0)->getDaughter(1)->get4Vector());
592
593 EXPECT_TRUE(B0->getDaughter(1)->getExtraInfo("test_var") == B0_copy->getDaughter(1)->getExtraInfo("test_var"));
594 EXPECT_TRUE(B0->getDaughter(0)->getDaughter(0)->getExtraInfo("test_var") == B0_copy->getDaughter(0)->getDaughter(
595 0)->getExtraInfo("test_var"));
596 EXPECT_TRUE(B0->getDaughter(0)->getDaughter(1)->getExtraInfo("test_var") == B0_copy->getDaughter(0)->getDaughter(
597 1)->getExtraInfo("test_var"));
598
599 // check relations
600 const MCParticle* mc1orig = B0->getDaughter(1)->getRelated<MCParticle>();
601 const MCParticle* mc2orig = B0->getDaughter(0)->getDaughter(0)->getRelated<MCParticle>();
602 const MCParticle* mc3orig = B0->getDaughter(0)->getDaughter(1)->getRelated<MCParticle>();
603
604 const MCParticle* mc1copy = B0_copy->getDaughter(1)->getRelated<MCParticle>();
605 const MCParticle* mc2copy = B0_copy->getDaughter(0)->getDaughter(0)->getRelated<MCParticle>();
606 const MCParticle* mc3copy = B0_copy->getDaughter(0)->getDaughter(1)->getRelated<MCParticle>();
607
608 const RestOfEvent* roeorig = B0->getRelated<RestOfEvent>();
609 const RestOfEvent* roecopy = B0_copy->getRelated<RestOfEvent>();
610
611 EXPECT_TRUE(mc1orig == mc1copy);
612 EXPECT_TRUE(mc2orig == mc2copy);
613 EXPECT_TRUE(mc3orig == mc3copy);
614
615 EXPECT_TRUE(mc1orig->getPDG() == mc1copy->getPDG());
616 EXPECT_TRUE(mc2orig->getPDG() == mc2copy->getPDG());
617 EXPECT_TRUE(mc3orig->getPDG() == mc3copy->getPDG());
618
619 EXPECT_TRUE(roeorig->hasParticle(ROEPion) && roecopy->hasParticle(ROEPion));
620
621 // modify original and check the copy
622 MCParticle* MC4 = mcparticles. appendNew(MCParticle());
623 MC4->setPDG(4);
624 B0->getDaughter(0)->addRelationTo(MC4);
625
626 const MCParticle* mc4orig = B0->getDaughter(0)->getRelated<MCParticle>();
627 const MCParticle* mc4copy = B0_copy->getDaughter(0)->getRelated<MCParticle>();
628
629 EXPECT_FALSE(mc4orig == nullptr);
630 EXPECT_TRUE(mc4copy == nullptr);
631
632 const_cast<Particle*>(B0->getDaughter(1))->addExtraInfo("origOnly_var", 10.0);
633
634 EXPECT_DOUBLE_EQ(10.0, B0->getDaughter(1)->getExtraInfo("origOnly_var"));
635 EXPECT_THROW(B0_copy->getDaughter(1)->getExtraInfo("origOnly_var"), std::runtime_error);
636
637 // modify copy and check the original
638 MCParticle* MC5 = mcparticles. appendNew(MCParticle());
639 MC5->setPDG(5);
640 B0_copy->addRelationTo(MC5);
641
642 const MCParticle* mc5orig = B0->getRelated<MCParticle>();
643 const MCParticle* mc5copy = B0_copy->getRelated<MCParticle>();
644
645 EXPECT_TRUE(mc5orig == nullptr);
646 EXPECT_FALSE(mc5copy == nullptr);
647
648 const_cast<Particle*>(B0_copy->getDaughter(1))->addExtraInfo("copyOnly_var", 15.0);
649
650 EXPECT_THROW(B0->getDaughter(1)->getExtraInfo("copyOnly_var"), std::runtime_error);
651 EXPECT_DOUBLE_EQ(15.0, B0_copy->getDaughter(1)->getExtraInfo("copyOnly_var"));
652
653 }
654
656 TEST_F(ParticleTest, ECLClusterBased)
657 {
658 StoreArray<ECLCluster> eclclusters;
659 {
660 ECLCluster* cluster = eclclusters.appendNew(ECLCluster());
661 cluster->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
662 cluster->setEnergy(1.);
663 cluster->setEnergyRaw(2.);
664
665 Particle p(cluster);
666 EXPECT_FLOAT_EQ(1., p.getECLClusterEnergy());
667 EXPECT_FLOAT_EQ(1., p.getEnergy());
668 EXPECT_EQ(ECLCluster::EHypothesisBit::c_nPhotons, p.getECLClusterEHypothesisBit());
669 EXPECT_FLOAT_EQ(0, p.getMass());
670 }
671
672 {
673 ECLCluster* cluster = eclclusters.appendNew(ECLCluster());
674 cluster->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
675 cluster->setEnergy(1.);
676 cluster->setEnergyRaw(2.);
677
678 Particle p(cluster, Const::Klong);
679 EXPECT_EQ(130, p.getPDGCode());
680 EXPECT_FLOAT_EQ(2., p.getECLClusterEnergy());
681 EXPECT_FLOAT_EQ(std::sqrt(4. + 0.497614 * 0.497614), p.getEnergy());
682 EXPECT_EQ(ECLCluster::EHypothesisBit::c_neutralHadron, p.getECLClusterEHypothesisBit());
683 int pdg = Const::Klong.getPDGCode();
684 double m = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
685 EXPECT_FLOAT_EQ(m, p.getMass());
686 }
687
688 {
689 ECLCluster* cluster = eclclusters.appendNew(ECLCluster());
690 cluster->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
691 cluster->setEnergy(1.);
692 cluster->setEnergyRaw(2.);
693
694 Particle p(cluster, Const::neutron);
695 EXPECT_EQ(2112, p.getPDGCode());
696 EXPECT_FLOAT_EQ(2., p.getECLClusterEnergy());
697 EXPECT_FLOAT_EQ(std::sqrt(4. + 0.93956536 * 0.93956536), p.getEnergy());
698 EXPECT_EQ(ECLCluster::EHypothesisBit::c_neutralHadron, p.getECLClusterEHypothesisBit());
699 int pdg = Const::neutron.getPDGCode();
700 double m = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
701 EXPECT_FLOAT_EQ(m, p.getMass());
702 }
703 }
704
706 TEST_F(ParticleTest, KLMClusterBased)
707 {
708 StoreArray<KLMCluster> klmClusters;
709 {
710 KLMCluster* cluster = klmClusters.appendNew(KLMCluster());
711 cluster->setTime(1.1);
712 cluster->setClusterPosition(1.1, 1.1, 1.0);
713 cluster->setLayers(1);
714 cluster->setInnermostLayer(1);
715 cluster->setMomentumMag(1.0);
716
717 Particle p(cluster);
718 int pdg = Const::Klong.getPDGCode();
719 EXPECT_EQ(pdg, p.getPDGCode());
720 double m = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
721 EXPECT_FLOAT_EQ(sqrt(1. + m * m), p.getEnergy());
722 EXPECT_EQ(Particle::c_Unflavored, p.getFlavorType());
723 EXPECT_FLOAT_EQ(m, p.getMass());
724 }
725
726 {
727 KLMCluster* cluster = klmClusters.appendNew(KLMCluster());
728 cluster->setTime(1.1);
729 cluster->setClusterPosition(1.1, 1.1, 1.0);
730 cluster->setLayers(1);
731 cluster->setInnermostLayer(1);
732 cluster->setMomentumMag(1.0);
733
734 Particle p(cluster, Const::neutron.getPDGCode());
735 int pdg = Const::neutron.getPDGCode();
736 EXPECT_EQ(pdg, p.getPDGCode());
737 double m = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
738 EXPECT_FLOAT_EQ(sqrt(1. + m * m), p.getEnergy());
739 EXPECT_EQ(Particle::c_Flavored, p.getFlavorType());
740 EXPECT_FLOAT_EQ(m, p.getMass());
741 }
742 }
743} // namespace
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleType neutron
neutron particle
Definition: Const.h:675
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
static const ParticleType Klong
K^0_L particle.
Definition: Const.h:678
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
ECL cluster data.
Definition: ECLCluster.h:27
void setConnectedRegionId(int crid)
Set connected region id.
Definition: ECLCluster.h:142
void setClusterId(int clusterid)
Set cluster id.
Definition: ECLCluster.h:145
void setHypothesis(EHypothesisBit hypothesis)
Set hypotheses.
Definition: ECLCluster.h:123
KLM cluster data.
Definition: KLMCluster.h:28
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
void setPDG(int pdg)
Set PDG code of the particle.
Definition: MCParticle.h:335
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:112
void set4Vector(const ROOT::Math::PxPyPzEVector &p4)
Sets the 4Vector of particle.
Definition: MCParticle.h:438
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
bool overlapsWith(const Particle *oParticle) const
Returns true if final state ancestors of oParticle overlap.
Definition: Particle.cc:737
bool isCopyOf(const Particle *oParticle, bool doDetailedComparison=false) const
Returns true if this Particle and oParticle are copies of each other.
Definition: Particle.cc:752
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:454
unsigned getNDaughters(void) const
Returns number of daughter particles.
Definition: Particle.h:727
TClonesArray * getArrayPointer() const
Returns the pointer to the store array which holds the daughter particles.
Definition: Particle.h:953
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:547
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1336
void print() const
Prints the contents of a Particle object to standard output.
Definition: Particle.cc:1170
@ c_Unflavored
Is its own antiparticle or we don't know whether it is a particle/antiparticle.
Definition: Particle.h:95
@ c_Flavored
Is either particle or antiparticle.
Definition: Particle.h:96
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:631
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1289
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
This is a general purpose class for collecting reconstructed MDST data objects that are not used in r...
Definition: RestOfEvent.h:57
void addParticles(const std::vector< const Particle * > &particle)
Add StoreArray indices of given Particles to the list of unused particles in the event.
Definition: RestOfEvent.cc:24
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
Object holding information for V0s.
Definition: V0.h:34
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Functions that create copies of Particles.
Definition: ParticleCopy.h:22
Particle * copyParticle(const Particle *original)
Function takes argument Particle and creates a copy of it and copies of all its (grand-)^n-daughters.
Definition: ParticleCopy.cc:18
Abstract base class for different kinds of events.
STL namespace.