Belle II Software  release-08-01-10
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 
26 using namespace std;
27 using namespace Belle2;
28 using namespace Belle2::ParticleCopy;
29 using namespace ROOT::Math;
30 
31 namespace {
33  class ParticleTest : public ::testing::Test {
34  protected:
36  void SetUp() override
37  {
38  DataStore::Instance().setInitializeActive(true);
39  StoreObjPtr<ParticleExtraInfoMap> particleExtraInfo;
40  StoreArray<Particle> particles;
41  StoreArray<MCParticle> mcparticles;
43  StoreArray<ECLCluster> eclClusters;
44  StoreArray<KLMCluster> klmClusters;
45  StoreArray<V0> v0s;
46  particleExtraInfo.registerInDataStore();
47  particles.registerInDataStore();
48  mcparticles.registerInDataStore();
49  eclClusters.registerInDataStore();
50  roes.registerInDataStore();
51  klmClusters.registerInDataStore();
52  v0s.registerInDataStore();
53  particles.registerRelationTo(mcparticles);
54  particles.registerRelationTo(roes);
55  DataStore::Instance().setInitializeActive(false);
56  }
57 
59  void TearDown() override
60  {
61  DataStore::Instance().reset();
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)
99  StoreArray<ECLCluster> clusters;
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
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:680
bool overlapsWith(const Particle *oParticle) const
Returns true if final state ancestors of oParticle overlap.
Definition: Particle.cc:741
TClonesArray * getArrayPointer() const
Returns the pointer to the store array which holds the daughter particles.
Definition: Particle.h:911
bool isCopyOf(const Particle *oParticle, bool doDetailedComparison=false) const
Returns true if this Particle and oParticle are copies of each other.
Definition: Particle.cc:756
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:426
unsigned getNDaughters(void) const
Returns number of daughter particles.
Definition: Particle.h:685
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:517
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1337
void print() const
Prints the contents of a Particle object to standard output.
Definition: Particle.cc:1174
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:635
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1290
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
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
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.