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