Belle II Software  release-05-02-19
clusteringVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Sam Cunliffe, Torben Ferber, Giacomo De Pietro *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Unit tests for all variables related to clustering and clustering
12 // subdetectors (KLM and ECL variables, track <--> cluster matching etc)
13 
14 #include <gtest/gtest.h>
15 #include <TRandom3.h>
16 
17 #include <analysis/ParticleCombiner/ParticleCombiner.h>
18 
19 // VariableManager and particle(list)
20 #include <analysis/VariableManager/Manager.h>
21 #include <analysis/dataobjects/Particle.h>
22 #include <analysis/dataobjects/ParticleList.h>
23 
24 // mdst dataobjects
25 #include <mdst/dataobjects/ECLCluster.h>
26 #include <mdst/dataobjects/KLMCluster.h>
27 #include <mdst/dataobjects/Track.h>
28 
29 // framework - set up mock events
30 #include <framework/datastore/StoreArray.h>
31 #include <framework/datastore/StoreObjPtr.h>
32 #include <framework/utilities/TestHelpers.h>
33 #include <framework/gearbox/Const.h>
34 #include <framework/gearbox/Gearbox.h>
35 
36 using namespace Belle2;
37 using namespace Belle2::Variable;
38 
39 namespace {
40 
42  class ECLVariableTest : public ::testing::Test {
43  protected:
45  void SetUp() override
46  {
47  // setup the DataStore
49 
50  // particles (to be filled)
51  StoreArray<Particle> particles;
52  particles.registerInDataStore();
53 
54  // mock up mdst objects
55  StoreArray<Track> tracks;
56  tracks.registerInDataStore();
58  trackFits.registerInDataStore();
59  StoreArray<ECLCluster> eclclusters;
60  eclclusters.registerInDataStore();
61 
62  // tracks can be matched to clusters
63  tracks.registerRelationTo(eclclusters);
64 
65  // we're done setting up the datastore
67 
68  // add some tracks the zeroth one is not going to be matched
69  tracks.appendNew(Track());
70  const Track* t1 = tracks.appendNew(Track());
71  const Track* t2 = tracks.appendNew(Track());
72  const Track* t3 = tracks.appendNew(Track());
73  const Track* t4 = tracks.appendNew(Track());
74  tracks.appendNew(Track());
75  tracks.appendNew(Track());
76 
77  // mock up some TrackFits for them (all pions)
78  TRandom3 generator;
79  TMatrixDSym cov6(6);
80  auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
81 
82  for (int i = 0; i < tracks.getEntries(); ++i) {
83  int charge = (i % 2 == 0) ? +1 : -1;
84  TVector2 d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
85  TVector2 pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
86  d.Set(d.X(), -(d.X()*pt.Px()) / pt.Py());
87  TVector3 position(d.X(), d.Y(), generator.Uniform(-1, 1));
88  TVector3 momentum(pt.Px(), pt.Py(), generator.Uniform(-1, 1));
89  trackFits.appendNew(position, momentum, cov6, charge, Const::pion, 0.5, 1.5, CDCValue, 16777215, 0);
90  tracks[i]->setTrackFitResultIndex(Const::pion, i);
91  }
92 
93  // add some ECL clusters
94  ECLCluster* e1 = eclclusters.appendNew(ECLCluster());
95  e1->setEnergy(0.3);
97  e1->setClusterId(1);
98  e1->setTime(1);
99  e1->setDeltaTime99(0.1);
100  // leave this guy with default theta and phi
101  ECLCluster* e2 = eclclusters.appendNew(ECLCluster());
102  e2->setEnergy(0.6);
103  e2->setTheta(1.0); // somewhere in the barrel
104  e2->setPhi(2.0);
105  e2->setR(148.5);
107  e2->setClusterId(2);
108  e2->setTime(2);
109  e2->setDeltaTime99(0.2);
110  ECLCluster* e3 = eclclusters.appendNew(ECLCluster());
111  e3->setEnergy(0.15);
112  e3->setTheta(0.2); // somewhere in the fwd endcap
113  e3->setPhi(1.5);
114  e3->setR(200.0);
117  // let's suppose this cluster could also be due to a neutral hadron. In
118  // this case, the c_neutralHadron hypothesis bit would hopefully also have
119  // been set by the reconstruction... arbitrarily choose cluster 3
120  e3->setClusterId(3);
121  e3->setTime(3);
122  e3->setDeltaTime99(0.3);
123 
124  // aaand add clusters related to the tracks
125  ECLCluster* e4 = eclclusters.appendNew(ECLCluster());
126  e4->setEnergy(0.2);
128  e4->setClusterId(4);
129  t1->addRelationTo(e4);
130  e4->setIsTrack(true);
131 
132  ECLCluster* e5 = eclclusters.appendNew(ECLCluster());
133  e5->setEnergy(0.3);
135  e5->setClusterId(5);
136  t2->addRelationTo(e5);
137  e5->setIsTrack(true);
138 
139  ECLCluster* e6 = eclclusters.appendNew(ECLCluster());
140  e6->setEnergy(0.2);
142  e6->setClusterId(6);
143  t3->addRelationTo(e6);
144  t4->addRelationTo(e6);
145  // two tracks are related to this cluster this can happen due to real
146  // physics and we should be able to cope
147  e6->setIsTrack(true);
148 
149  }
150 
152  void TearDown() override
153  {
155  }
156  };
157 
158  TEST_F(ECLVariableTest, b2bKinematicsTest)
159  {
160  // we need the particles and ECLClusters arrays
161  StoreArray<Particle> particles;
162  StoreArray<ECLCluster> eclclusters;
163  StoreArray<Track> tracks;
164 
165  // connect gearbox for CMS boosting etc
166  Gearbox& gearbox = Gearbox::getInstance();
167  gearbox.setBackends({std::string("file:")});
168  gearbox.close();
169  gearbox.open("geometry/Belle2.xml", false);
170 
171  // register in the datastore
172  StoreObjPtr<ParticleList> gammalist("gamma:testGammaAllList");
174  gammalist.registerInDataStore(DataStore::c_DontWriteOut);
176 
177  // initialise the lists
178  gammalist.create();
179  gammalist->initialize(22, gammalist.getName());
180 
181  // make the photons from clusters
182  for (int i = 0; i < eclclusters.getEntries(); ++i) {
183  if (!eclclusters[i]->isTrack()) {
184  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
185  gammalist->addParticle(p);
186  }
187  }
188 
189  // get the zeroth track in the array (is not associated to a cluster)
190  const Particle* noclustertrack = particles.appendNew(Particle(tracks[0], Const::pion));
191 
192  // grab variables for testing
193  const Manager::Var* b2bClusterTheta = Manager::Instance().getVariable("b2bClusterTheta");
194  const Manager::Var* b2bClusterPhi = Manager::Instance().getVariable("b2bClusterPhi");
195 
196  EXPECT_EQ(gammalist->getListSize(), 3);
197 
198  EXPECT_FLOAT_EQ(b2bClusterTheta->function(gammalist->getParticle(0)), 3.0276606);
199  EXPECT_FLOAT_EQ(b2bClusterPhi->function(gammalist->getParticle(0)), 0.0);
200  EXPECT_FLOAT_EQ(b2bClusterTheta->function(gammalist->getParticle(1)), 1.6036042);
201  EXPECT_FLOAT_EQ(b2bClusterPhi->function(gammalist->getParticle(1)), -1.0607308);
202  EXPECT_FLOAT_EQ(b2bClusterTheta->function(gammalist->getParticle(2)), 2.7840068);
203  EXPECT_FLOAT_EQ(b2bClusterPhi->function(gammalist->getParticle(2)), -1.3155469);
204 
205  // track (or anything without a cluster) should be nan
206  ASSERT_TRUE(std::isnan(b2bClusterTheta->function(noclustertrack)));
207  ASSERT_TRUE(std::isnan(b2bClusterPhi->function(noclustertrack)));
208 
209  // the "normal" (not cluster based) variables should be the same for photons
210  // (who have no track information)
211  const Manager::Var* b2bTheta = Manager::Instance().getVariable("b2bTheta");
212  const Manager::Var* b2bPhi = Manager::Instance().getVariable("b2bPhi");
213 
214  EXPECT_FLOAT_EQ(b2bClusterTheta->function(gammalist->getParticle(0)),
215  b2bTheta->function(gammalist->getParticle(0)));
216  EXPECT_FLOAT_EQ(b2bClusterPhi->function(gammalist->getParticle(0)),
217  b2bPhi->function(gammalist->getParticle(0)));
218  }
219 
220  TEST_F(ECLVariableTest, clusterKinematicsTest)
221  {
222  // we need the particles and ECLClusters arrays
223  StoreArray<Particle> particles;
224  StoreArray<ECLCluster> eclclusters;
225  StoreArray<Track> tracks;
226 
227  // connect gearbox for CMS boosting etc
228  Gearbox& gearbox = Gearbox::getInstance();
229  gearbox.setBackends({std::string("file:")});
230  gearbox.close();
231  gearbox.open("geometry/Belle2.xml", false);
232 
233  // register in the datastore
234  StoreObjPtr<ParticleList> gammalist("gamma:testGammaAllList");
236  gammalist.registerInDataStore(DataStore::c_DontWriteOut);
238 
239  // initialise the lists
240  gammalist.create();
241  gammalist->initialize(22, gammalist.getName());
242 
243  // make the photons from clusters
244  for (int i = 0; i < eclclusters.getEntries(); ++i) {
245  if (!eclclusters[i]->isTrack()) {
246  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
247  gammalist->addParticle(p);
248  }
249  }
250 
251  // grab variables for testing
252  const Manager::Var* clusterPhi = Manager::Instance().getVariable("clusterPhi");
253  const Manager::Var* clusterPhiCMS = Manager::Instance().getVariable("useCMSFrame(clusterPhi)");
254  const Manager::Var* clusterTheta = Manager::Instance().getVariable("clusterTheta");
255  const Manager::Var* clusterThetaCMS = Manager::Instance().getVariable("useCMSFrame(clusterTheta)");
256 
257  EXPECT_FLOAT_EQ(clusterPhi->function(gammalist->getParticle(1)), 2.0);
258  EXPECT_FLOAT_EQ(clusterPhiCMS->function(gammalist->getParticle(1)), 2.042609);
259  EXPECT_FLOAT_EQ(clusterTheta->function(gammalist->getParticle(1)), 1.0);
260  EXPECT_FLOAT_EQ(clusterThetaCMS->function(gammalist->getParticle(1)), 1.2599005);
261 
262  // test cluster quantities directly (lab system only)
263  EXPECT_FLOAT_EQ(clusterPhi->function(gammalist->getParticle(0)), eclclusters[0]->getPhi());
264  EXPECT_FLOAT_EQ(clusterTheta->function(gammalist->getParticle(0)), eclclusters[0]->getTheta());
265  }
266 
267  TEST_F(ECLVariableTest, HypothesisVariables)
268  {
269  // we need the particles and ECLClusters arrays
270  StoreArray<Particle> particles;
271  StoreArray<ECLCluster> eclclusters;
272 
273  // register in the datastore
274  StoreObjPtr<ParticleList> gammalist("gamma");
276  gammalist.registerInDataStore(DataStore::c_DontWriteOut);
278 
279  // initialise the lists
280  gammalist.create();
281  gammalist->initialize(22, gammalist.getName());
282 
283  // make the photons from clusters
284  for (int i = 0; i < eclclusters.getEntries(); ++i)
285  if (!eclclusters[i]->isTrack()) {
286  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
287  gammalist->addParticle(p);
288  }
289 
290  // grab variables for testing
291  const Manager::Var* vHasNPhotons = Manager::Instance().getVariable("clusterHasNPhotons");
292  const Manager::Var* vHasNeutHadr = Manager::Instance().getVariable("clusterHasNeutralHadron");
293 
294  // check that the hypotheses are correctly propagated to the VM.
295  for (size_t i = 0; i < gammalist->getListSize(); ++i) {
296  EXPECT_FLOAT_EQ(vHasNPhotons->function(gammalist->getParticle(i)), 1.0);
297  if (i == 2) { // third cluster arbitrarily chosen to test the behaviour of dual hypothesis clusters
298  EXPECT_FLOAT_EQ(vHasNeutHadr->function(gammalist->getParticle(i)), 1.0);
299  } else {
300  EXPECT_FLOAT_EQ(vHasNeutHadr->function(gammalist->getParticle(i)), 0.0);
301  }
302  } // end loop over test list
303  }
304 
305  TEST_F(ECLVariableTest, IsFromECL)
306  {
307  StoreArray<Particle> particles;
308  StoreArray<ECLCluster> eclclusters;
309 
310  const Manager::Var* vIsFromECL = Manager::Instance().getVariable("isFromECL");
311  const Manager::Var* vIsFromKLM = Manager::Instance().getVariable("isFromKLM");
312  const Manager::Var* vIsFromTrack = Manager::Instance().getVariable("isFromTrack");
313  const Manager::Var* vIsFromV0 = Manager::Instance().getVariable("isFromV0");
314 
315  for (int i = 0; i < eclclusters.getEntries(); ++i)
316  if (!eclclusters[i]->isTrack()) {
317  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
318  EXPECT_TRUE(vIsFromECL->function(p));
319  EXPECT_FALSE(vIsFromKLM->function(p));
320  EXPECT_FALSE(vIsFromTrack->function(p));
321  EXPECT_FALSE(vIsFromV0->function(p));
322  }
323  }
324 
325  TEST_F(ECLVariableTest, WholeEventClosure)
326  {
327  // we need the particles, tracks, and ECLClusters StoreArrays
328  StoreArray<Particle> particles;
329  StoreArray<Track> tracks;
330  StoreArray<ECLCluster> eclclusters;
331 
332  // create a photon (clusters) and pion (tracks) lists
333  StoreObjPtr<ParticleList> gammalist("gamma:testGammaAllList");
334  StoreObjPtr<ParticleList> pionslist("pi+:testPionAllList");
335  StoreObjPtr<ParticleList> apionslist("pi-:testPionAllList");
336 
337  // register the lists in the datastore
339  gammalist.registerInDataStore(DataStore::c_DontWriteOut);
340  pionslist.registerInDataStore(DataStore::c_DontWriteOut);
341  apionslist.registerInDataStore(DataStore::c_DontWriteOut);
343 
344  // initialise the lists
345  gammalist.create();
346  gammalist->initialize(22, gammalist.getName());
347  pionslist.create();
348  pionslist->initialize(211, pionslist.getName());
349  apionslist.create();
350  apionslist->initialize(-211, apionslist.getName());
351  apionslist->bindAntiParticleList(*(pionslist));
352 
353  // make the photons from clusters (and sum up the total ecl energy)
354  double eclEnergy = 0.0;
355  for (int i = 0; i < eclclusters.getEntries(); ++i) {
356  eclEnergy += eclclusters[i]->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
357  if (!eclclusters[i]->isTrack()) {
358  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
359  gammalist->addParticle(p);
360  }
361  }
362 
363 
364  // make the pions from tracks
365  for (int i = 0; i < tracks.getEntries(); ++i) {
366  const Particle* p = particles.appendNew(Particle(tracks[i], Const::pion));
367  pionslist->addParticle(p);
368  }
369 
370  // grab variables
371  const Manager::Var* vClusterE = Manager::Instance().getVariable("clusterE");
372  const Manager::Var* vClNTrack = Manager::Instance().getVariable("nECLClusterTrackMatches");
373 
374  // calculate the total neutral energy from the particle list --> VM
375  double totalNeutralClusterE = 0.0;
376  for (size_t i = 0; i < gammalist->getListSize(); ++i)
377  totalNeutralClusterE += vClusterE->function(gammalist->getParticle(i));
378 
379  // calculate the total track-matched cluster energy from the particle list --> VM
380  double totalTrackClusterE = 0.0;
381  for (size_t i = 0; i < pionslist->getListSize(); ++i) { // includes antiparticles
382  double clusterE = vClusterE->function(pionslist->getParticle(i));
383  double nOtherCl = vClNTrack->function(pionslist->getParticle(i));
384  if (nOtherCl > 0)
385  totalTrackClusterE += clusterE / nOtherCl;
386  }
387 
388  EXPECT_FLOAT_EQ(totalNeutralClusterE + totalTrackClusterE, eclEnergy);
389  }
390 
391  TEST_F(ECLVariableTest, eclClusterOnlyInvariantMass)
392  {
393  // declare all the array we need
394  StoreArray<Particle> particles, particles_noclst;
395  std::vector<int> daughterIndices, daughterIndices_noclst;
396 
397  //proxy initialize where to declare the needed array
399  StoreArray<ECLCluster> eclclusters_new;
400  eclclusters_new.registerInDataStore();
401  particles.registerRelationTo(eclclusters_new);
403 
404  // create two Lorentz vectors
405  const float px_0 = 2.;
406  const float py_0 = 1.;
407  const float pz_0 = 3.;
408  const float px_1 = 1.5;
409  const float py_1 = 1.5;
410  const float pz_1 = 2.5;
411  float E_0, E_1;
412  E_0 = sqrt(pow(px_0, 2) + pow(py_0, 2) + pow(pz_0, 2));
413  E_1 = sqrt(pow(px_1, 2) + pow(py_1, 2) + pow(pz_1, 2));
414  TLorentzVector momentum;
415  TLorentzVector dau0_4vec(px_0, py_0, pz_0, E_0), dau1_4vec(px_1, py_1, pz_1, E_1);
416 
417  // add the two photons as the two daughters of some particle and create the latter
418  Particle dau0_noclst(dau0_4vec, 22);
419  momentum += dau0_noclst.get4Vector();
420  Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
421  daughterIndices_noclst.push_back(newDaughter0_noclst->getArrayIndex());
422  Particle dau1_noclst(dau1_4vec, 22);
423  momentum += dau1_noclst.get4Vector();
424  Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
425  daughterIndices_noclst.push_back(newDaughter1_noclst->getArrayIndex());
426  const Particle* par_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices_noclst);
427 
428  // grab variables
429  const Manager::Var* var = Manager::Instance().getVariable("eclClusterOnlyInvariantMass");
430 
431  // when no relations are set between the particles and the eclClusters, nan is expected to be returned
432  ASSERT_NE(var, nullptr);
433  EXPECT_TRUE(std::isnan(var->function(par_noclst)));
434 
435  // set relations between particles and eclClusters
436  ECLCluster* eclst0 = eclclusters_new.appendNew(ECLCluster());
437  eclst0->setEnergy(dau0_4vec.E());
439  eclst0->setClusterId(1);
440  eclst0->setTheta(dau0_4vec.Theta());
441  eclst0->setPhi(dau0_4vec.Phi());
442  eclst0->setR(148.4);
443  ECLCluster* eclst1 = eclclusters_new.appendNew(ECLCluster());
444  eclst1->setEnergy(dau1_4vec.E());
446  eclst1->setClusterId(2);
447  eclst1->setTheta(dau1_4vec.Theta());
448  eclst1->setPhi(dau1_4vec.Phi());
449  eclst1->setR(148.5);
450 
451  // use these new-created clusters rather than the 6 default ones
452  const Particle* newDaughter0 = particles.appendNew(Particle(eclclusters_new[6]));
453  daughterIndices.push_back(newDaughter0->getArrayIndex());
454  const Particle* newDaughter1 = particles.appendNew(Particle(eclclusters_new[7]));
455  daughterIndices.push_back(newDaughter1->getArrayIndex());
456 
457  const Particle* par = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices);
458 
459  //now we expect non-nan results
460  EXPECT_FLOAT_EQ(var->function(par), 0.73190731);
461  }
462 
463  TEST_F(ECLVariableTest, averageECLTimeQuantities)
464  {
465  // we need the particles, and ECLClusters StoreArrays
466  StoreArray<Particle> particles;
467  StoreArray<ECLCluster> eclclusters;
468 
469  // create a photon (clusters) and a pi0 list
470  StoreObjPtr<ParticleList> gammalist("gamma:testGammaAllList");
471  StoreObjPtr<ParticleList> pionslist("pi0:testPizAllList");
472 
473  // register the lists in the datastore
475  gammalist.registerInDataStore(DataStore::c_DontWriteOut);
476  pionslist.registerInDataStore(DataStore::c_DontWriteOut);
478 
479  // initialise the lists
480  gammalist.create();
481  gammalist->initialize(22, gammalist.getName());
482  pionslist.create();
483  pionslist->initialize(111, pionslist.getName());
484 
485  // make the photons from clusters
486  for (int i = 0; i < eclclusters.getEntries(); ++i) {
487  if (!eclclusters[i]->isTrack()) {
488  const Particle* p = particles.appendNew(Particle(eclclusters[i]));
489  gammalist->addParticle(p);
490  }
491  }
492 
493  // make the pi0s as combinations of photons
494  ParticleGenerator combiner_pi0("pi0:testPizAllList -> gamma:testGammaAllList gamma:testGammaAllList");
495  combiner_pi0.init();
496  while (combiner_pi0.loadNext()) {
497  const Particle& particle = combiner_pi0.getCurrentParticle();
498 
499  particles.appendNew(particle);
500  int iparticle = particles.getEntries() - 1;
501 
502  pionslist->addParticle(iparticle, particle.getPDGCode(), particle.getFlavorType());
503  }
504 
505  // grab variables
506  const Manager::Var* weightedAverageECLTime = Manager::Instance().getVariable("weightedAverageECLTime");
507  const Manager::Var* maxDist = Manager::Instance().getVariable("maxWeightedDistanceFromAverageECLTime");
508 
509  // particles without daughters should have NaN as weighted average
510  EXPECT_TRUE(std::isnan(weightedAverageECLTime->function(gammalist->getParticle(0))));
511 
512  // check that weighted average of first pi0 is correct
513  EXPECT_FLOAT_EQ(weightedAverageECLTime->function(pionslist->getParticle(0)), 1.2);
514 
515  // check that maximal difference to weighted average in units of uncertainty is calculated correctly
516  EXPECT_FLOAT_EQ(maxDist->function(pionslist->getParticle(0)), 4.0);
517  }
518 
519  class KLMVariableTest : public ::testing::Test {
520  protected:
522  void SetUp() override
523  {
524  // setup the DataStore
526 
527  // particles (to be filled)
528  StoreArray<Particle> particles;
529  particles.registerInDataStore();
530 
531  // mock up mdst objects
532  StoreArray<Track> tracks;
533  tracks.registerInDataStore();
534  StoreArray<TrackFitResult> trackFits;
535  trackFits.registerInDataStore();
536  StoreArray<KLMCluster> klmClusters;
537  klmClusters.registerInDataStore();
538 
539  // tracks can be matched to clusters
540  tracks.registerRelationTo(klmClusters);
541 
542  // we're done setting up the datastore
544  }
545 
547  void TearDown() override
548  {
550  }
551  };
552 
553  TEST_F(KLMVariableTest, WholeEventClosure)
554  {
555  // we need the Particles, Tracks, TrackFitResults and KLMClusters StoreArrays
556  StoreArray<Particle> particles;
557  StoreArray<Track> tracks;
558  StoreArray<TrackFitResult> trackFits;
559  StoreArray<KLMCluster> klmClusters;
560 
561  // create a KLong (clusters) and muon (tracks) lists
562  StoreObjPtr<ParticleList> kLongList("K0_L:testKLong");
563  StoreObjPtr<ParticleList> muonsList("mu-:testMuons");
564  StoreObjPtr<ParticleList> amuonsList("mu+:testMuons");
565 
566  // register the lists in the datastore
568  kLongList.registerInDataStore(DataStore::c_DontWriteOut);
569  muonsList.registerInDataStore(DataStore::c_DontWriteOut);
570  amuonsList.registerInDataStore(DataStore::c_DontWriteOut);
572 
573  // initialise the lists
574  kLongList.create();
575  kLongList->initialize(130, kLongList.getName());
576  muonsList.create();
577  muonsList->initialize(13, muonsList.getName());
578  amuonsList.create();
579  amuonsList->initialize(-13, amuonsList.getName());
580  amuonsList->bindAntiParticleList(*(muonsList));
581 
582  // add some tracks
583  const Track* t1 = tracks.appendNew(Track());
584  const Track* t2 = tracks.appendNew(Track());
585  const Track* t3 = tracks.appendNew(Track());
586  tracks.appendNew(Track());
587  tracks.appendNew(Track());
588 
589  // mock up some TrackFits for them (all muons)
590  TRandom3 generator;
591  TMatrixDSym cov6(6);
592  auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
593 
594  for (int i = 0; i < tracks.getEntries(); ++i) {
595  int charge = (i % 2 == 0) ? +1 : -1;
596  TVector2 d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
597  TVector2 pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
598  d.Set(d.X(), -(d.X()*pt.Px()) / pt.Py());
599  TVector3 position(d.X(), d.Y(), generator.Uniform(-1, 1));
600  TVector3 momentum(pt.Px(), pt.Py(), generator.Uniform(-1, 1));
601  trackFits.appendNew(position, momentum, cov6, charge, Const::muon, 0.5, 1.5, CDCValue, 16777215, 0);
602  tracks[i]->setTrackFitResultIndex(Const::muon, i);
603  }
604 
605  // add some clusters
606  KLMCluster* klm1 = klmClusters.appendNew(KLMCluster());
607  klm1->setTime(1.1);
608  klm1->setClusterPosition(1.1, 1.1, 1.0);
609  klm1->setLayers(1);
610  klm1->setInnermostLayer(1);
611  klm1->setMomentumMag(1.0);
612  KLMCluster* klm2 = klmClusters.appendNew(KLMCluster());
613  klm2->setTime(1.2);
614  klm2->setClusterPosition(1.2, 1.2, 2.0);
615  klm2->setLayers(2);
616  klm2->setInnermostLayer(2);
617  klm2->setMomentumMag(1.0);
618  KLMCluster* klm3 = klmClusters.appendNew(KLMCluster());
619  klm3->setTime(1.3);
620  klm3->setClusterPosition(1.3, 1.3, 3.0);
621  klm3->setLayers(3);
622  klm3->setInnermostLayer(3);
623  klm3->setMomentumMag(1.0);
624 
625  // and add clusters related to the tracks
626  // case 1: 1 track --> 1 cluster
627  KLMCluster* klm4 = klmClusters.appendNew(KLMCluster());
628  klm4->setTime(1.4);
629  klm4->setClusterPosition(-1.4, -1.4, 1.0);
630  klm4->setLayers(4);
631  klm4->setInnermostLayer(4);
632  klm4->setMomentumMag(1.0);
633  t1->addRelationTo(klm4);
634 
635  // case 2: 2 tracks --> 1 cluster
636  KLMCluster* klm5 = klmClusters.appendNew(KLMCluster());
637  klm5->setTime(1.5);
638  klm5->setClusterPosition(-1.5, -1.5, 1.0);
639  klm5->setLayers(5);
640  klm5->setInnermostLayer(5);
641  klm5->setMomentumMag(1.0);
642  t2->addRelationTo(klm5);
643  t3->addRelationTo(klm5);
644 
645  // case 3: 1 track --> 2 clusters
646  // not possible
647 
648  // make the KLong from clusters (and sum up the total KLM momentum magnitude)
649  double klmMomentum = 0.0;
650  for (int i = 0; i < klmClusters.getEntries(); ++i) {
651  klmMomentum += klmClusters[i]->getMomentumMag();
652  if (!klmClusters[i]->getAssociatedTrackFlag()) {
653  const Particle* p = particles.appendNew(Particle(klmClusters[i]));
654  kLongList->addParticle(p);
655  }
656  }
657 
658  // make the muons from tracks
659  for (int i = 0; i < tracks.getEntries(); ++i) {
660  const Particle* p = particles.appendNew(Particle(tracks[i], Const::muon));
661  muonsList->addParticle(p);
662  }
663 
664  // grab variables
665  const Manager::Var* vClusterP = Manager::Instance().getVariable("klmClusterMomentum");
666  const Manager::Var* vClNTrack = Manager::Instance().getVariable("nKLMClusterTrackMatches");
667 
668  // calculate the total KLM momentum from the KLong list --> VM
669  double totalKLongMomentum = 0.0;
670  for (size_t i = 0; i < kLongList->getListSize(); ++i)
671  totalKLongMomentum += vClusterP->function(kLongList->getParticle(i));
672 
673  // calculate the total KLM momentum from muon-matched list --> VM
674  double totalMuonMomentum = 0.0;
675  for (size_t i = 0; i < muonsList->getListSize(); ++i) { // includes antiparticles
676  double muonMomentum = vClusterP->function(muonsList->getParticle(i));
677  double nOtherCl = vClNTrack->function(muonsList->getParticle(i));
678  if (nOtherCl > 0)
679  totalMuonMomentum += muonMomentum / nOtherCl;
680  }
681 
682  EXPECT_FLOAT_EQ(5.0, klmMomentum);
683  EXPECT_FLOAT_EQ(totalKLongMomentum + totalMuonMomentum, klmMomentum);
684  }
685 
686  TEST_F(KLMVariableTest, TrackToKLMClusterMatchingTest)
687  {
688  StoreArray<Particle> particles;
689  StoreArray<Track> tracks;
690  StoreArray<TrackFitResult> trackFits;
691  StoreArray<KLMCluster> klmClusters;
692 
693  // add a TrackFitResult
694  TVector3 position(1.0, 0, 0);
695  TVector3 momentum(0, 1.0, 0);
696  TMatrixDSym cov6(6);
697  const int charge = 1;
698  const float pValue = 0.5;
699  const float bField = 1.5;
700  auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
701  trackFits.appendNew(position, momentum, cov6, charge, Const::muon, pValue, bField, CDCValue, 16777215, 0);
702 
703  // add one Track
704  Track myTrack;
706  Track* muonTrack = tracks.appendNew(myTrack);
707 
708  // add two KLMClusters
709  KLMCluster* klm1 = klmClusters.appendNew(KLMCluster());
710  klm1->setTime(1.1);
711  klm1->setClusterPosition(1.1, 1.1, 1.0);
712  klm1->setLayers(1);
713  klm1->setInnermostLayer(1);
714  klm1->setMomentumMag(1.0);
715  KLMCluster* klm2 = klmClusters.appendNew(KLMCluster());
716  klm2->setTime(1.2);
717  klm2->setClusterPosition(1.2, 1.2, 2.0);
718  klm2->setLayers(2);
719  klm2->setInnermostLayer(2);
720  klm2->setMomentumMag(1.0);
721 
722  // and add a weighted relationship between the track and both clusters
723  // only the relation with klm1 must be returned
724  // in reconstruction we set a relation to only one cluster (if any),
725  // so here we test that getKLMCluster() returns the first cluster
726  // stored in the RelationVector
727  float distance1 = 11.1;
728  muonTrack->addRelationTo(klm1, 1. / distance1);
729  float distance2 = 2.2;
730  muonTrack->addRelationTo(klm2, 1. / distance2);
731 
732  // add a Particle
733  const Particle* muon = particles.appendNew(Particle(muonTrack, Const::muon));
734 
735  // grab variables
736  const Manager::Var* vTrNClusters = Manager::Instance().getVariable("nMatchedKLMClusters");
737  const Manager::Var* vClusterInnermostLayer = Manager::Instance().getVariable("klmClusterInnermostLayer");
738  const Manager::Var* vClusterTrackDistance = Manager::Instance().getVariable("klmClusterTrackDistance");
739 
740  EXPECT_POSITIVE(vTrNClusters->function(muon));
741  EXPECT_FLOAT_EQ(1.0, vClusterInnermostLayer->function(muon));
742  EXPECT_FLOAT_EQ(distance1, vClusterTrackDistance->function(muon));
743 
744  // add a Pion - no clusters matched here
745  trackFits.appendNew(position, momentum, cov6, charge, Const::pion, pValue, bField, CDCValue, 16777215, 0);
746  Track mySecondTrack;
747  mySecondTrack.setTrackFitResultIndex(Const::pion, 0);
748  Track* pionTrack = tracks.appendNew(mySecondTrack);
749  const Particle* pion = particles.appendNew(Particle(pionTrack, Const::pion));
750 
751  EXPECT_FLOAT_EQ(0.0, vTrNClusters->function(pion));
752  }
753 }
Belle2::EvtPDLUtil::charge
double charge(int pdgCode)
Returns electric charge of a particle with given pdg code.
Definition: EvtPDLUtil.cc:46
Belle2::StoreArray::appendNew
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:256
Belle2::ECLCluster::setTime
void setTime(double time)
Set time information.
Definition: ECLCluster.h:223
Belle2::ECLCluster::setIsTrack
void setIsTrack(bool istrack)
Set m_isTrack true if the cluster matches with a track.
Definition: ECLCluster.h:115
Belle2::Variable::Manager::Var
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:137
Belle2::Variable::Manager::getVariable
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:33
Belle2::DataStore::Instance
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
Belle2::ECLCluster
ECL cluster data.
Definition: ECLCluster.h:39
Belle2::Gearbox::getInstance
static Gearbox & getInstance()
Return reference to the Gearbox instance.
Definition: Gearbox.cc:74
Belle2::DataStore::setInitializeActive
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:94
Belle2::ECLCluster::EHypothesisBit::c_nPhotons
@ c_nPhotons
CR is split into n photons (N1)
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::DataStore::c_DontWriteOut
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition: DataStore.h:73
Belle2::KLMCluster::setTime
void setTime(float time)
Set time.
Definition: KLMCluster.h:148
Belle2::ECLCluster::setEnergy
void setEnergy(double energy)
Set Corrected Energy (GeV).
Definition: ECLCluster.h:238
Belle2::Variable::Manager::Var::function
FunctionPtr function
Pointer to function.
Definition: Manager.h:138
Belle2::DataStore::reset
void reset(EDurability durability)
Frees memory occupied by data store items and removes all objects from the map.
Definition: DataStore.cc:86
Belle2::Const::pion
static const ChargedStable pion
charged pion particle
Definition: Const.h:535
Belle2::ECLCluster::setPhi
void setPhi(double phi)
Set Phi of Shower (radian).
Definition: ECLCluster.h:232
Belle2::Track::setTrackFitResultIndex
void setTrackFitResultIndex(const Const::ChargedStable &chargedStable, short index)
Set an index (for positive values) or unavailability-code (with negative values) for a specific mass ...
Definition: Track.h:104
Belle2::KLMCluster::setClusterPosition
void setClusterPosition(float globalX, float globalY, float globalZ)
Set global position.
Definition: KLMCluster.h:171
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
Belle2::Gearbox
Singleton class responsible for loading detector parameters from an XML file.
Definition: Gearbox.h:44
Belle2::ECLCluster::addHypothesis
void addHypothesis(EHypothesisBit bitmask)
Add bitmask to current hypothesis.
Definition: ECLCluster.h:140
Belle2::Particle::c_Unflavored
@ c_Unflavored
Is its own antiparticle or we don't know whether it is a particle/antiparticle.
Definition: Particle.h:96
Belle2::TEST_F
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:65
Belle2::ECLCluster::setClusterId
void setClusterId(int clusterid)
Set cluster id.
Definition: ECLCluster.h:156
Belle2::ECLCluster::setDeltaTime99
void setDeltaTime99(double dtime99)
Set 99% time containment range.
Definition: ECLCluster.h:226
Belle2::ECLCluster::EHypothesisBit::c_neutralHadron
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
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
Belle2::ECLCluster::setR
void setR(double r)
Set R (in cm).
Definition: ECLCluster.h:235
Belle2::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::KLMCluster::setLayers
void setLayers(int layers)
Set number of layers with hits.
Definition: KLMCluster.h:155
Belle2::Const::muon
static const ChargedStable muon
muon particle
Definition: Const.h:534
Belle2::Track
Class that bundles various TrackFitResults.
Definition: Track.h:35
Belle2::StoreArray< Particle >
Belle2::KLMCluster::setInnermostLayer
void setInnermostLayer(int innermostLayer)
Set number of the innermost layer with hits.
Definition: KLMCluster.h:162
Belle2::StoreArray::getEntries
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:226
Belle2::KLMCluster::setMomentumMag
void setMomentumMag(float momentumMag)
Set momentum magnitude.
Definition: KLMCluster.h:182
Belle2::ECLCluster::setTheta
void setTheta(double theta)
Set Theta of Shower (radian).
Definition: ECLCluster.h:229
Belle2::ParticleGenerator
ParticleGenerator is a generator for all the particles combined from the given ParticleLists.
Definition: ParticleCombiner.h:129
Belle2::Variable::Manager::Instance
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:27