Belle II Software  release-08-01-10
mcmatching.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/utility/MCMatching.h>
9 #include <analysis/dataobjects/Particle.h>
10 #include <analysis/dataobjects/ParticleExtraInfoMap.h>
11 #include <analysis/variables/BasicParticleInformation.h>
12 #include <analysis/variables/MCTruthVariables.h>
13 
14 #include <mdst/dataobjects/MCParticle.h>
15 #include <mdst/dataobjects/MCParticleGraph.h>
16 #include <framework/datastore/StoreArray.h>
17 #include <framework/datastore/StoreObjPtr.h>
18 #include <framework/gearbox/Const.h>
19 
20 #include <gtest/gtest.h>
21 
22 using namespace std;
23 using namespace Belle2;
24 
25 
26 namespace {
27  MCParticleGraph gParticleGraph;
28 
30  bool isFSP(int pdg)
31  {
32  switch (abs(pdg)) {
33  case 211:
34  case 321:
35  case 11:
36  case 13:
37  case 2212:
38  case 22:
39  case 130:
40  return true;
41  default:
42  return false;
43  }
44  }
45 
47  struct Decay {
48  public:
50  enum EBehavior {
51  c_Default,
52  c_CreateNewMCParticle,
53  c_RelateWith,
54  c_ReconstructFrom,
55  };
57  // cppcheck-suppress noExplicitConstructor; yes, there is no explicit constructor for this class, and this isn't one
58  Decay(int pdg, const std::vector<Decay>& daughters = std::vector<Decay>()):
59  m_pdg(pdg), m_daughterDecays(daughters), m_mcparticle(nullptr), m_particle(nullptr)
60  {
61  m_graphParticle = &gParticleGraph.addParticle();
62  m_graphParticle->setPDG(m_pdg);
63  m_graphParticle->setStatus(MCParticle::c_PrimaryParticle);
64  for (const Decay& d : daughters) {
65  gParticleGraph.addDecay(*m_graphParticle, *d.m_graphParticle);
66  }
67  }
69  void finalize()
70  {
71  gParticleGraph.generateList();
72  gParticleGraph.clear(); //don't add them again in the next call..
73 
74  StoreArray<MCParticle> mcparticles{};
75  m_mcparticle = mcparticles[m_graphParticle->getIndex() - 1];
76 
77  for (Decay& d : m_daughterDecays)
78  d.finalize();
79  }
80 
82  [[nodiscard]] Particle* getParticle(int pdg) const
83  {
84  if (m_pdg == pdg and m_particle)
85  return m_particle;
86 
87  for (auto& d : m_daughterDecays) {
88  Particle* res = d.getParticle(pdg);
89  if (res)
90  return res;
91  }
92  return nullptr;
93  }
95  [[nodiscard]] MCParticle* getMCParticle(int pdg) const
96  {
97  if (m_pdg == pdg and m_mcparticle)
98  return m_mcparticle;
99 
100  for (auto& d : m_daughterDecays) {
101  MCParticle* res = d.getMCParticle(pdg);
102  if (res)
103  return res;
104  }
105  return nullptr;
106  }
108  Decay* getDecay(int pdg)
109  {
110  if (m_pdg == pdg)
111  return this;
112 
113  for (auto& d : m_daughterDecays) {
114  Decay* res = d.getDecay(pdg);
115  if (res)
116  return res;
117  }
118  return nullptr;
119  }
120 
121  Decay& operator[](int i) { return m_daughterDecays[i]; }
122 
124  struct ReconstructedDecay {
125  // cppcheck-suppress noExplicitConstructor; yes, there is no explicit constructor for this class, and this isn't one
126  ReconstructedDecay(int pdg, const std::vector<ReconstructedDecay>& daughters = std::vector<ReconstructedDecay>(),
127  EBehavior behavior = c_Default):
128  m_pdg(pdg), m_daughterDecays(daughters), m_behavior(behavior), m_optMcPart(nullptr), m_optDecay(nullptr) { }
129  ReconstructedDecay(int pdg, const std::vector<ReconstructedDecay>& daughters, EBehavior behavior, MCParticle* optMcPart):
130  m_pdg(pdg), m_daughterDecays(daughters), m_behavior(behavior), m_optMcPart(optMcPart), m_optDecay(nullptr) { }
131  ReconstructedDecay(int pdg, const std::vector<ReconstructedDecay>& daughters, EBehavior behavior, Decay* optDecay):
132  m_pdg(pdg), m_daughterDecays(daughters), m_behavior(behavior), m_optMcPart(nullptr), m_optDecay(optDecay) { }
133  int m_pdg;
134  vector<ReconstructedDecay> m_daughterDecays;
135  EBehavior m_behavior;
136  MCParticle* m_optMcPart;
137  Decay* m_optDecay;
138  };
139 
146  void reconstruct(ReconstructedDecay decay)
147  {
148  if (!m_mcparticle) {
149  finalize();
150  }
151  if (decay.m_behavior == c_CreateNewMCParticle) {
152  m_graphParticle = &gParticleGraph.addParticle();
153  m_graphParticle->setPDG(decay.m_pdg);
154  finalize(); //overwrites m_mcparticle with the new particle
155  } else if (decay.m_behavior == c_RelateWith) {
156  m_mcparticle = decay.m_optMcPart;
157  } else if (decay.m_behavior == c_ReconstructFrom) {
158  ASSERT_TRUE(decay.m_optDecay != nullptr);
159  Decay* mcDecay = decay.m_optDecay;
160  decay.m_optDecay = nullptr;
161  decay.m_behavior = Decay::c_Default;
162  mcDecay->reconstruct(decay);
163  return;
164  }
165 
166  StoreArray<Particle> particles;
167  if (isFSP(decay.m_pdg)) {
168  //is a final state particle, link with MCParticle
169  m_particle = particles.appendNew(m_graphParticle->get4Vector(), decay.m_pdg);
170  m_particle->addRelationTo(m_mcparticle);
171  }
172 
173  if (!decay.m_daughterDecays.empty()) {
174  Decay* mcDecay = this;
175  if (decay.m_behavior == c_ReconstructFrom) {
176  //use given decay to reconstruct daughters instead
177  mcDecay = decay.m_optDecay;
178  }
179  std::vector<int> daughterIndices;
180  for (unsigned int i = 0; i < decay.m_daughterDecays.size(); i++) {
181  Decay* d = nullptr;
182  ReconstructedDecay rd = decay.m_daughterDecays[i];
183  //we must make sure that m_graphParticle always corresponds to the same thing in the reconstructed thing.
184  if (rd.m_behavior == c_ReconstructFrom) {
185  ASSERT_NE(rd.m_optDecay, nullptr);
186  d = rd.m_optDecay;
187  rd.m_optDecay = nullptr;
188  rd.m_behavior = Decay::c_Default;
189  } else {
190  ASSERT_TRUE(decay.m_daughterDecays.size() > i);
191  d = &(mcDecay->m_daughterDecays[i]);
192  }
193  d->reconstruct({rd});
194  if (d->m_particle)
195  daughterIndices.push_back(d->m_particle->getArrayIndex());
196 
197  }
198  if (decay.m_pdg != 0) {
199  //is decay self conjugated?
200  std::vector<int> decaylist, decaybarlist;
201  for (int idx : daughterIndices) {
202  const Particle* daughterPart = particles[idx];
203  int daughterPDG = daughterPart->getPDGCode();
204  decaylist.push_back(daughterPDG);
205  decaybarlist.push_back((daughterPart->getFlavorType() == Particle::c_Flavored) ? (-daughterPDG) : daughterPDG);
206  }
207  std::sort(decaylist.begin(), decaylist.end());
208  std::sort(decaybarlist.begin(), decaybarlist.end());
209  bool isUnflavored = (decaylist == decaybarlist);
210 
211  m_particle = particles.appendNew(ROOT::Math::PxPyPzEVector(), decay.m_pdg,
212  isUnflavored ? (Particle::c_Unflavored) : (Particle::c_Flavored),
213  daughterIndices);
214  }
215  }
216  }
217 
218  [[nodiscard]] string getString() const { return "Particles(MCParticles,MCMatch,Flags):\n" + getStringInternal(); }
219 
220  int m_pdg;
221  vector<Decay> m_daughterDecays;
223  m_graphParticle;
224  MCParticle* m_mcparticle;
225  Particle* m_particle;
227  private:
229  [[nodiscard]] string getStringInternal(int depth = 0) const
230  {
231  stringstream s;
232  string spaces;
233  for (int i = 0; i < depth; i++)
234  spaces += " ";
235  s << spaces;
236 
237  if (m_particle)
238  s << m_particle->getPDGCode();
239  else
240  s << "?";
241 
242  s << " (";
243  if (m_mcparticle)
244  s << m_mcparticle->getPDG();
245  else
246  s << "?";
247  const MCParticle* mcMatch = nullptr;
248  if (m_particle)
249  mcMatch = m_particle->getRelated<MCParticle>();
250  if (mcMatch) {
251  s << ", " << mcMatch->getPDG() << ", ";
252  if (m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors))
253  s << MCMatching::explainFlags(m_particle->getExtraInfo(MCMatching::c_extraInfoMCErrors));
254  else
255  s << "-not set-";
256  } else {
257  s << ", ?";
258  s << ", ?";
259  }
260  s << ") ";
261 
262  if (!m_daughterDecays.empty()) {
263  s << " [";
264  for (const Decay& d : m_daughterDecays) {
265  s << "\n" << d.getStringInternal(depth + 1);
266  }
267 
268  s << "\n" << spaces << "]";
269  }
270 
271  return s.str();
272  }
273  };
274 
276  class MCMatchingTest : public ::testing::Test {
277  protected:
279  void SetUp() override
280  {
281  StoreObjPtr<ParticleExtraInfoMap> particleExtraInfo;
282  StoreArray<Particle> particles;
283  StoreArray<MCParticle> mcparticles;
284  particleExtraInfo.registerInDataStore();
285  particles.registerInDataStore();
286  mcparticles.registerInDataStore();
287  particles.registerRelationTo(mcparticles);
288  }
289 
291  void TearDown() override
292  {
293  DataStore::Instance().reset();
294  }
295  };
296 
297 
299  TEST_F(MCMatchingTest, MCParticleGraph)
300  {
301  Decay d(111, {22, 22});
302  StoreArray<MCParticle> mcparticles;
303  //actually push things into StoreArray
304  d.finalize();
305  EXPECT_EQ(mcparticles.getEntries(), 3);
306  EXPECT_EQ(mcparticles[0]->getPDG(), Const::pi0.getPDGCode());
307  EXPECT_EQ(mcparticles[1]->getPDG(), Const::photon.getPDGCode());
308  EXPECT_EQ(mcparticles[2]->getPDG(), Const::photon.getPDGCode());
309  EXPECT_EQ(mcparticles[0]->getMother(), nullptr);
310  EXPECT_EQ(mcparticles[1]->getMother(), mcparticles[0]);
311  EXPECT_EQ(mcparticles[2]->getMother(), mcparticles[0]);
312 
313  Decay e(111, {22, 22});
314  e.finalize();
315  EXPECT_EQ(mcparticles.getEntries(), 6);
316  EXPECT_EQ(mcparticles[3]->getPDG(), Const::pi0.getPDGCode());
317  EXPECT_EQ(mcparticles[3]->getNDaughters(), 2);
318  EXPECT_EQ(mcparticles[4]->getPDG(), Const::photon.getPDGCode());
319  EXPECT_EQ(mcparticles[5]->getPDG(), Const::photon.getPDGCode());
320  EXPECT_EQ(mcparticles[4]->getNDaughters(), 0);
321  EXPECT_EQ(mcparticles[5]->getNDaughters(), 0);
322  EXPECT_EQ(mcparticles[3]->getMother(), nullptr);
323  EXPECT_EQ(mcparticles[4]->getMother(), mcparticles[3]);
324  EXPECT_EQ(mcparticles[5]->getMother(), mcparticles[3]);
325 
326  Decay f(211);
327  f.finalize();
328  EXPECT_EQ(mcparticles.getEntries(), 7);
329  EXPECT_EQ(mcparticles[6]->getPDG(), Const::pion.getPDGCode());
330 
331  Decay g(421, {321, -211, {111, {22, 22}}});
332  g.finalize();
333  EXPECT_EQ(3, g.m_mcparticle->getNDaughters());
334  EXPECT_EQ(mcparticles.getEntries(), 13);
335  }
336 
338  TEST_F(MCMatchingTest, CorrectReconstruction)
339  {
340  StoreArray<MCParticle> mcparticles;
341  StoreArray<Particle> particles;
342 
343  Decay d(421, {321, -211, {111, {22, 22}}});
344  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
345  //reconstruct() calls finalize(), so MCParticles are filled now
346  EXPECT_EQ(mcparticles.getEntries(), 6);
347  EXPECT_EQ(mcparticles[0]->getPDG(), 421);
348  EXPECT_EQ(mcparticles[5]->getPDG(), Const::photon.getPDGCode());
349  EXPECT_EQ(particles.getEntries(), 6);
350 
351  ASSERT_NE(d.m_particle, nullptr);
352  const auto& fspParticles = d.m_particle->getFinalStateDaughters();
353  EXPECT_EQ(fspParticles.size(), 4u);
354  //all final state particles should have relations...
355  for (const Particle* p : fspParticles) {
356  EXPECT_EQ(p->getRelated<MCParticle>()->getDaughters().size(), 0u);
357  }
358  //composite particles don't have them
359  EXPECT_TRUE(mcparticles[0] == d.m_mcparticle);
360  EXPECT_TRUE(mcparticles[0]->getRelated<Particle>() == nullptr);
361  EXPECT_TRUE(mcparticles[3]->getRelated<Particle>() == nullptr);
362 
363  //run MC matching (should be able to set a relation)
364  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
365 
366  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
367 
368  }
370  TEST_F(MCMatchingTest, SetMCTruthNeverRun)
371  {
372  Decay d(421, {321, -211, {111, {22, 22}}});
373  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
374 
375  EXPECT_EQ(nullptr, d.m_particle->getRelated<MCParticle>());
376  ASSERT_FALSE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
377  EXPECT_EQ(MCMatching::c_InternalError, MCMatching::getMCErrors(d.m_particle)) << d.getString();
378  }
379 
380  TEST_F(MCMatchingTest, SettingTruths)
381  {
382  Decay d(421, {321, -211, {111, {22, 22}}});
383  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
384 
385  //setMCTruth should set relation
386  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
387  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
388 
389  //but no extra-info flags
390  ASSERT_FALSE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
391  ASSERT_FALSE(d.getParticle(111)->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
392 
393  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
394 
395  //now it's set
396  ASSERT_TRUE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
397  ASSERT_TRUE(d.getParticle(111)->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
398  }
399 
401  TEST_F(MCMatchingTest, MisID)
402  {
403  {
404  Decay d(421, {321, -211, {111, {22, 22}}});
405  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
406  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
407  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
408  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
409  }
410  {
411  //+ wrong non-FSP
412  Decay d(421, {321, -211, {111, {22, 22}}});
413  d.reconstruct({413, {321, -13, {111, {22, 22}}}});
414  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
415  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
416  }
417  {
418  Decay d(421, {321, -211, {111, {22, 22}}});
419  d.reconstruct({421, {321, 13, {111, {22, 22}}}});
420  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
421  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
422  }
423  {
424  Decay d(421, {321, -211, {111, {22, 22}}});
425  d.reconstruct({421, {211, 13, {111, {22, 22}}}});
426  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
427  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
428  }
429  {
430  //pion and kaon switched
431  Decay d(421, {321, -211, {111, {22, 22}}});
432  d.reconstruct({421, { -211, 321, {111, {22, 22}}}});
433  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
434  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
435  }
436  }
437 
439  TEST_F(MCMatchingTest, MissingParticles)
440  {
441  {
442  //pi0 is not FSP, so doesn't get MCMatching::c_MissMassiveParticle (but MCMatching::c_MissingResonance)
443  Decay d(421, {321, -211, {111, {22, 22}}});
444  d.reconstruct({421, {321, -211, {0}}});
445  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
446  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
447  }
448  {
449  Decay d(421, {321, -211, {111, {22, 22}}});
450  d.reconstruct({421, {321, 0, {111, {22, 22}}}});
451  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
452  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
453  }
454  {
455  Decay d(421, {321, -211, {111, {22, 22}}});
456  d.reconstruct({421, {0, -211, {111, {22, 22}}}});
457  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
458  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
459  }
460  {
461  Decay d(421, {321, -211, {111, {22, 22}}});
462  d.reconstruct({421, {0, -13, {111, {22, 22}}}});
463  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
464  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle | MCMatching::c_MisID) << d.getString();
465  }
466  }
467  TEST_F(MCMatchingTest, KLongCorrect)
468  {
469  //correct (we miss the 'K0' resonance, but that's fine)
470  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
471  d.finalize();
472  //K0L and daughters are secondary
473  MCParticle* k0l = d.getMCParticle(130);
474  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
475 
476  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, {130, {}, Decay::c_ReconstructFrom, d.getDecay(130)}}});
477  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
478  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
479  }
480  TEST_F(MCMatchingTest, KLongMissed)
481  {
482  //K0L not reconstructed
483  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
484  d.finalize();
485  //K0L and daughters are secondary
486  MCParticle* k0l = d.getMCParticle(130);
487  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
488 
489  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
490  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
491  EXPECT_EQ(MCMatching::c_MissKlong | MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
492  MCMatching::getMCErrors(d.m_particle)) << d.getString();
493  }
494  TEST_F(MCMatchingTest, KShortCorrect)
495  {
496  //correct (we miss the 'K0' resonance, but that's fine)
497  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
498  d.finalize();
499  //K0S and daughters are secondary
500  MCParticle* k0s = d.getMCParticle(310);
501  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
502  MCParticle* pi1 = d.getMCParticle(211);
503  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
504  MCParticle* pi2 = d.getMCParticle(-211);
505  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
506 
507  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, {310, {{211, {}, Decay::c_ReconstructFrom, d.getDecay(211)}, { -211, {}, Decay::c_ReconstructFrom, d.getDecay(-211)}}}}});
508  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
509  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
510  }
511  TEST_F(MCMatchingTest, KShortMissed)
512  {
513  //K0S not reconstructed
514  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
515  d.finalize();
516  //K0S and daughters are secondary
517  MCParticle* k0s = d.getMCParticle(310);
518  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
519  MCParticle* pi1 = d.getMCParticle(211);
520  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
521  MCParticle* pi2 = d.getMCParticle(-211);
522  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
523 
524  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
525  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
526  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
527  MCMatching::getMCErrors(d.m_particle)) << d.getString();
528  }
530  TEST_F(MCMatchingTest, PionWithOneGamma)
531  {
532  {
533  StoreArray<Particle> particles;
534  StoreArray<MCParticle> mcparticles;
535  Decay d(421, {321, -211, {111, {22, 22}}});
536  d.reconstruct({421, {321, -211, {111, {0, 22}}}});
537  EXPECT_EQ(mcparticles.getEntries(), 6);
538  EXPECT_EQ(particles.getEntries(), 5); //we added only 5 Particles
539  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
540  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
541  }
542  {
543  Decay d(421, {321, -211, {111, {22, 22}}});
544  d.reconstruct({421, {321, 0, {111, {0, 22}}}});
545  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
546  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
547  }
548  }
549  TEST_F(MCMatchingTest, TauWithResonance)
550  {
551  // Correct tau
552  {
553  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
554  d.reconstruct({15, {0, { -213, { -211, {111, {22, 22}}}}}});
555  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
556  EXPECT_EQ(MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
557  }
558  // Miss Resoanace
559  {
560  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
561  d.reconstruct({15, {{ -211, {}, Decay::c_ReconstructFrom, &d[1][0]}, {111, {22, 22}, Decay::c_ReconstructFrom, &d[1][1]}}});
562  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
563  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
564  }
565  // Miss Gamma
566  {
567  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
568  d.reconstruct({15, {{ -211, {}, Decay::c_ReconstructFrom, &d[1][0]}, {111, {0, {22, {}, Decay::c_ReconstructFrom, &d[1][1][1]}}, Decay::c_ReconstructFrom, &d[1][1]}}});
569  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
570  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
571  }
572  // Added Wrong Pion
573  {
574  Decay g(-512, {211, -211, -16, {15, {16, { -213, { -211, {111, {22, 22}}}}}}});
575  Decay& d = g[3];
576  d.reconstruct({15, {{ -211, {}, Decay::c_ReconstructFrom, &g[1]}, {111, {22, 22}, Decay::c_ReconstructFrom, &d[1][1]}}});
577  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
578  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance | MCMatching::c_MissNeutrino |
579  MCMatching::c_AddedWrongParticle,
580  MCMatching::getMCErrors(d.m_particle)) << d.getString();
581  }
582 
583 
584  }
585  TEST_F(MCMatchingTest, MissGamma)
586  {
587  {
588  //D*+ -> D+ pi0
589  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}});
590  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}}});
591  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
592  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
593  }
594  {
595  //D*+ -> D+ pi0 reconstructed as D*+ -> D+ gamma
596  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}});
597  Decay& gamma = d[1][0]; //first gamma from second pi0
598  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
599  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
600  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
601  }
602 
603  {
604  //D*+ -> D+ gamma
605  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, 22});
606  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, 22}});
607  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
608  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
609  }
610  {
611  //pi0 -> e+ e- gamma
612  Decay d(111, {11, -11, 22});
613  d.reconstruct({111, {11, -11, 22}});
614  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
615  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
616  }
617  {
618  //pi0 -> e+ e- gamma reconstructed without gamma
619  Decay d(111, {11, -11, 22});
620  d.reconstruct({111, {11, -11, 0}});
621  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
622  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
623  }
624  {
625  //pi0 -> 2 gamma, with both clusters coming from same photon
626  Decay d(111, {22, 22});
627  Decay& gamma = d[0];
628  d.reconstruct({111, {22, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
629  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
630  //MCMatch of pi0 is first gamma
631  EXPECT_EQ(MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
632  }
633  {
634  //pi0 -> 4 gamma
635  Decay d(111, {22, 22, 22, 22});
636  d.reconstruct({111, {22, 22, 22, 22}});
637  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
638  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
639  }
640  {
641  //pi0 -> 4 gamma as 2 gamma
642  Decay d(111, {22, 22, 22, 22});
643  d.reconstruct({111, {22, 22, 0, 0}});
644  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
645  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
646  }
647  {
648  //pi0 -> 4 gamma, with two clusters coming from same photon
649  Decay d(111, {22, 22, 22, 22});
650  Decay& gamma = d[0];
651  d.reconstruct({111, {22, 22, 22, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
652  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
653  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
654  }
655  }
657  TEST_F(MCMatchingTest, WrongPhotonForPi0)
658  {
659  {
660  Decay d(521, {211, Decay(421, {321, -211, Decay(111, {22, 22})}), 22});
661  d.finalize();
662  d.reconstruct({521, {211, {421, {321, -211, {111, {{22}, {22, {}, Decay::c_RelateWith, d.getMCParticle(211)}}}}}}});
663  //result: pi0 gets MC match 521.
664  //Gets misID & c_AddedWrongParticle because of 'wrong' photon,
665  //plus c_MissMassiveParticle since the B's daughters are missing,
666  //plus c_MissGamma because one photon was not reconstructed,
667  //plus c_MissingResonance because non-FSPs were missed (MC matched particle (521) has lots of daughters)
668 
669  Particle* pi0 = d.getParticle(111);
670  Decay* pi0decay = d.getDecay(111);
671  ASSERT_TRUE(MCMatching::setMCTruth(pi0)) << pi0decay->getString();
672  EXPECT_EQ(521, pi0->getRelated<MCParticle>()->getPDG());
673  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissMassiveParticle | MCMatching::c_MissGamma |
674  MCMatching::c_MissingResonance,
675  MCMatching::getMCErrors(pi0)) << pi0decay->getString();
676 
677  //flags migrate upstream
678  Particle* p = d.getParticle(421);
679  Decay* d0decay = d.getDecay(421);
680  ASSERT_TRUE(MCMatching::setMCTruth(p)) << d0decay->getString();
681  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissGamma | MCMatching::c_MissingResonance,
682  MCMatching::getMCErrors(p)) << d0decay->getString();
683 
684  //even with addedWrongParticle (inherited from daughter), missFSR should be detected.
685  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
686  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissGamma | MCMatching::c_MissingResonance,
687  MCMatching::getMCErrors(d.m_particle)) << d.getString();
688  }
689  }
690 
692  TEST_F(MCMatchingTest, DecayInFlightCorrect)
693  {
694  {
695  Decay d(421, {321, { -211, {13}}, {111, {22, 22}}});
696  d.finalize();
697  MCParticle* muon = d.getMCParticle(13);
698  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
699  ASSERT_FALSE(muon->hasStatus(MCParticle::c_PrimaryParticle));
700  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
701 
702  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
703  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
704  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
705  }
706  {
707  Decay d(421, {{321, {11, -12, {111, {22, 22}}}}, -211, {111, {22, 22}}});
708  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
709 
710  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
711  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
712  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
713  }
714  }
716  TEST_F(MCMatchingTest, DecayInFlight)
717  {
718  {
719  Decay d(-211, {13});
720  d.finalize();
721  MCParticle* muon = d.getMCParticle(13);
722  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
723  d.reconstruct({ -211, {}, Decay::c_RelateWith, muon});
724 
725  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
726  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
727  EXPECT_EQ(MCMatching::c_DecayInFlight, MCMatching::getMCErrors(d.m_particle)) << d.getString();
728  }
729  {
730  Decay d(421, {321, { -211, {13}}, {111, {22, 22}}});
731  d.finalize();
732  MCParticle* muon = d.getMCParticle(13);
733  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
734  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, muon}, {111, {22, 22}}}});
735 
736 
737  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
738  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
739  EXPECT_EQ(MCMatching::c_DecayInFlight, MCMatching::getMCErrors(d.m_particle)) << d.getString();
740  }
741  }
743  TEST_F(MCMatchingTest, CorrectFSPsWrongDecay)
744  {
745  {
746  Decay d(-413, {{ -411, {321, -211, -211}}, {111, {22, 22}}});
747 
748  Decay& pi0 = d[1];
749  Decay& pi2 = d[0][2];
750 
751  ASSERT_TRUE(d.getDecay(111) == &pi0);
752 
753  d.reconstruct({ -413, {{ -421, {321, -211, {111, {22, 22}, Decay::c_ReconstructFrom, &pi0}}}, { -211, {}, Decay::c_ReconstructFrom, &pi2}}});
754 
755 
756  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
757  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
758  //inherits c_AddedWrongParticle from D0, gets c_MissingResonance since D+ is missing
759  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
760  MCMatching::getMCErrors(d.m_particle)) << d.getString();
761  }
762  }
764  TEST_F(MCMatchingTest, WrongCombination)
765  {
767  {
768  Decay d(-413, {{ -421, {321, -211, {111, {22, 22}}}}, -211});
769 
770  Decay* pi1 = &(d[0][1]);
771  Decay* pi2 = &(d[1]);
772  ASSERT_TRUE(pi1->m_pdg == pi2->m_pdg);
773 
774  d.reconstruct({ -413, {{ -421, {321, { -211, {}, Decay::c_ReconstructFrom, pi2}, {111, {22, 22}}}}, { -211, {}, Decay::c_ReconstructFrom, pi1}}});
775 
776 
777  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
778  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
779  //gets c_MissingResonance since none of the Particles got the D0 MCParticle as MC match
780  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
781  MCMatching::getMCErrors(d.m_particle)) << d.getString();
782  }
783 
785  {
786  Decay d(511, {{333, {321, -321}}, {333, {321, -321}}});
787 
788  Decay* k1 = &(d[0][1]);
789  Decay* k2 = &(d[1][1]);
790  ASSERT_TRUE(k1->m_pdg == k2->m_pdg);
791 
792  d.reconstruct({511, {
793  {333, {321, { -321, {}, Decay::c_ReconstructFrom, k2}}},
794  {333, {321, { -321, {}, Decay::c_ReconstructFrom, k1}}}
795  }
796  });
797 
798 
799  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
800  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
801  //gets c_MissingResonance since none of the Particles got the phi MCParticle as MC match
802  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
803  MCMatching::getMCErrors(d.m_particle)) << d.getString();
804  }
805  }
807  TEST_F(MCMatchingTest, SelfCrossFeed)
808  {
809  {
810  Decay d(300533, {{511, {321, -211, {111, {22, 22}}}}, { -511, { -321, 211, {111, {22, 22}}}}});
811 
812  Decay* pi1 = &(d[0][2]);
813  Decay* pi2 = &(d[1][2]);
814  ASSERT_TRUE(pi1->m_pdg == pi2->m_pdg);
815 
816  d.reconstruct({300533, {
817  {511, {321, -211, {111, {22, 22}, Decay::c_ReconstructFrom, pi2}}},
818  { -511, { -321, 211, {111, {22, 22}, Decay::c_ReconstructFrom, pi1}}}
819  }
820  });
821 
822 
823  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
824  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
825  //gets c_MissingResonance since none of the Particles got the B0/anti-B0 MCParticle as MC match
826  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
827  MCMatching::getMCErrors(d.m_particle)) << d.getString();
828  }
829  }
830 
831  TEST_F(MCMatchingTest, FlavouredD0Decay)
832  {
833  {
834  //ok
835  Decay d(421, { -321, 211});
836  d.reconstruct({421, { -321, 211}});
837  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
838 
839  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
840  EXPECT_EQ(d.m_particle->getPDGCode(), d.m_particle->getRelated<MCParticle>()->getPDG());
841  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
842  }
843  {
844  //also exists, but suppressed
845  Decay d(-421, { -321, 211});
846  d.reconstruct({ -421, { -321, 211}});
847  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
848 
849  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
850  EXPECT_EQ(d.m_particle->getPDGCode(), d.m_particle->getRelated<MCParticle>()->getPDG());
851  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
852  }
853  {
854  //however, reconstructing the wrong D0 is not okay
855  Decay d(421, { -321, 211});
856  d.reconstruct({ -421, { -321, 211}});
857  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
858 
859  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
860  EXPECT_EQ(MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
861  }
862  {
863  //however, reconstructing the wrong D0 is not okay
864  Decay d(-421, { -321, 211});
865  d.reconstruct({421, { -321, 211}});
866  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
867 
868  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
869  EXPECT_EQ(MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
870  }
871  }
872 
873  TEST_F(MCMatchingTest, UnflavouredD0Decay)
874  {
875  {
876  //ok
877  Decay d(421, { -321, 321});
878  d.reconstruct({421, { -321, 321}});
879  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
880 
881  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
882  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
883  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
884  }
885  {
886  //ok
887  Decay d(-421, { -321, 321});
888  d.reconstruct({ -421, { -321, 321}});
889  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
890 
891  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
892  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
893  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
894  }
895  {
896  //we don't know the flavour, so this is also fine
897  Decay d(421, { -321, 321});
898  d.reconstruct({ -421, { -321, 321}});
899  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
900 
901  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
902  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
903  }
904  {
905  //we don't know the flavour, so this is also fine
906  Decay d(-421, { -321, 321});
907  d.reconstruct({421, { -321, 321}});
908  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
909 
910  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
911  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
912  }
913  }
914 
915  //B0 -> rho+ D-
916  TEST_F(MCMatchingTest, MissingResonance)
917  {
918  //explicitly reconstruct the rho
919  {
920  Decay d(511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}});
921  d.reconstruct({511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}}});
922 
923  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
924  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
925  }
926  //missing rho
927  {
928  Decay d(511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}});
929  //d.reconstruct({511, {{-411, {-321, 321, 211}}, {0, {211, {111, {22, 22}}}}}});
930  Decay* piplus = &(d[1][0]);
931  Decay* pi0 = &(d[1][1]);
932 
933  d.reconstruct({511, {{ -411, { -321, 321, 211}}, {211, {}, Decay::c_ReconstructFrom, piplus}, {111, {22, 22}, Decay::c_ReconstructFrom, pi0}}});
934 
935  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
936  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
937  }
938  }
939 
940  TEST_F(MCMatchingTest, MissingFSPReplacedBySecondary)
941  {
942  Decay d(521, {{ -421, {321, { -211, {22, -211}}}}, 211, 211, -211});
943  Decay* pi = &(d[0][1][1]);
944  d.reconstruct({521, {{ -421, {321, -211}}, 211, 211, {
945  -211, {},
946  Decay::c_ReconstructFrom, pi
947  }
948  }
949  });
950  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
951  EXPECT_EQ(MCMatching::c_MissMassiveParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
952  }
953  TEST_F(MCMatchingTest, BeamBackground)
954  {
955  Decay d(421, {321, -211, {111, {22, 22}}});
956  d.finalize();
957  MCParticle* noParticle = nullptr;
958  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, noParticle}, {111, {22, 22}}}});
959 
960  //no common mother
961  ASSERT_FALSE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
962  EXPECT_EQ(MCMatching::c_InternalError, MCMatching::getMCErrors(d.m_particle)) << d.getString();
963  EXPECT_EQ(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
964  }
965 
966  TEST_F(MCMatchingTest, DuplicateTrack)
967  {
968  {
969  Decay d(421, {321, -211, {111, {22, 22}}});
970  d.finalize();
971  MCParticle* kaon = d.getMCParticle(321);
972  ASSERT_TRUE(kaon != nullptr);
973  //tracks for the same MCParticle used twice:
974  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, kaon}, {111, {22, 22}}}});
975 
976  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
977  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
978  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
979  }
980  }
981 
983  TEST_F(MCMatchingTest, MissingFSRMissingPHOTOS)
984  {
985  {
986  Decay d(521, { -11, 12, 22});
987  d.finalize();
988  MCParticle* photon = d.getMCParticle(22);
989  EXPECT_FALSE(MCMatching::isFSR(photon));
990 
991  d.reconstruct({521, { -11}});
992  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
993  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
994  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
995 
996  }
997  {
998  //ISR flag should not trigger anything special
999  Decay d(521, { -11, 12, 22});
1000  d.finalize();
1001  MCParticle* photon = d.getMCParticle(22);
1002  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsISRPhoton);
1003  EXPECT_FALSE(MCMatching::isFSR(photon));
1004 
1005  d.reconstruct({521, { -11}});
1006  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1007  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1008  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1009  }
1010 
1011  {
1012  //now try the same with FSR flag
1013  Decay d(521, { -11, 12, 22});
1014  d.finalize();
1015  MCParticle* photon = d.getMCParticle(22);
1016  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsFSRPhoton);
1017  EXPECT_TRUE(MCMatching::isFSR(photon));
1018 
1019  d.reconstruct({521, { -11}});
1020  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1021  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1022  EXPECT_EQ(MCMatching::c_MissFSR | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1023  }
1024 
1025  {
1026  //now try PHOTOS photon
1027  Decay d(521, { -11, 12, 22});
1028  d.finalize();
1029  MCParticle* photon = d.getMCParticle(22);
1030  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsPHOTOSPhoton);
1031  EXPECT_FALSE(MCMatching::isFSR(photon));
1032 
1033  d.reconstruct({521, { -11}});
1034  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1035  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1036  EXPECT_EQ(MCMatching::c_MissPHOTOS | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1037  }
1038  }
1039 
1041  TEST_F(MCMatchingTest, UnspecifiedParticleReconstruction)
1042  {
1043  {
1045  Decay d(511, {{30343, {321, -211}}, -13, 13});
1046  d.reconstruct({511, {{30343, {321, -211}}, -13, 13}});
1047 
1048  Particle* Xsd = d.m_particle->getDaughters()[0];
1049  ASSERT_TRUE(Xsd != nullptr);
1050  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1051  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1052  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1053 
1054  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1055  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1056  }
1057  {
1059  Decay d(511, {{313, {321, -211}}, -13, 13});
1060  d.reconstruct({511, {{30343, {321, -211}}, -13, 13}});
1061 
1062  Particle* Xsd = d.m_particle->getDaughters()[0];
1063  ASSERT_TRUE(Xsd != nullptr);
1064  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1065  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1066  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1067 
1068  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1069  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1070  }
1071  {
1073  Decay d(511, { {313, {321, -211}}, {443, { -13, 13}}});
1074  Decay* mup = &(d[1][0]);
1075  Decay* mum = &(d[1][1]);
1076  d.reconstruct({511, {{30343, {321, -211}}, { -13, {}, Decay::c_ReconstructFrom, mup}, {13, {}, Decay::c_ReconstructFrom, mum}}});
1077 
1078  Particle* Xsd = d.m_particle->getDaughters()[0];
1079  ASSERT_TRUE(Xsd != nullptr);
1080  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1081  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1082  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1083 
1084  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1085  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1086  }
1087  }
1088 
1090  TEST_F(MCMatchingTest, CountMissingParticle)
1091  {
1092  {
1093  // pi0 not reconstructed
1094  Decay d(421, {321, -211, {111, {22, 22}}});
1095  d.reconstruct({421, {321, -211, {0}}});
1096  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1097  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1098  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1099  vector<int> daughterPDG{Const::pi0.getPDGCode()};
1100  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1101  }
1102  {
1103  // pi not reconstructed
1104  Decay d(421, {321, -211, {111, {22, 22}}});
1105  d.reconstruct({421, {321, 0, {111, {22, 22}}}});
1106  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1107  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1108  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1109  vector<int> daughterPDG{Const::pion.getPDGCode()};
1110  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1111  }
1112  {
1113  // K not reconstructed
1114  Decay d(421, {321, -211, {111, {22, 22}}});
1115  d.reconstruct({421, {0, -211, {111, {22, 22}}}});
1116  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1117  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1118  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1119  vector<int> daughterPDG{Const::kaon.getPDGCode()};
1120  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1121  }
1122  {
1123  // 2K not reconstructed
1124  Decay d(-521, { -321, {421, {321, -211, {111, {22, 22}}}}});
1125  d.reconstruct({ -521, {0, {421, {0, -211, {111, {22, 22}}}}}});
1126  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1127  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1128  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1129  vector<int> daughterPDG{Const::kaon.getPDGCode()};
1130  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 2);
1131  }
1132  {
1133  //K0S not reconstructed
1134  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
1135  d.finalize();
1136  //K0S and daughters are secondary
1137  MCParticle* k0s = d.getMCParticle(310);
1138  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
1139  MCParticle* pi1 = d.getMCParticle(211);
1140  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
1141  MCParticle* pi2 = d.getMCParticle(-211);
1142  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
1143 
1144  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
1145  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1146  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
1147  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1148  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1149  vector<int> daughterPDG{Const::Kshort.getPDGCode()};
1150  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1151  }
1152  {
1153  //K0L not reconstructed
1154  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
1155  d.finalize();
1156  //K0L and daughters are secondary
1157  MCParticle* k0l = d.getMCParticle(130);
1158  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
1159 
1160  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
1161  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1162  EXPECT_EQ(MCMatching::c_MissKlong | MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
1163  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1164  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1165  vector<int> daughterPDG{Const::Klong.getPDGCode()};
1166  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1167  }
1168  {
1169  // e and nutrino not reconstructed
1170  Decay d(521, { -11, 12, 22});
1171  d.reconstruct({521, {0, 0, 22}});
1172  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1173  EXPECT_EQ(MCMatching::c_MissNeutrino | MCMatching::c_MissMassiveParticle,
1174  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1175  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1176  vector<int> daughterPDG_E{Const::electron.getPDGCode()};
1177  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_E), 1);
1178  vector<int> daughterPDG_NuE{12};
1179  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_NuE), 1);
1180  vector<int> daughterPDG_Nu{12, 14, 16};
1181  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Nu), 1);
1182  }
1183  {
1184  // e and nutrino not reconstructed
1185  Decay d(521, { -13, 14, 22});
1186  d.reconstruct({521, {0, 0, 22}});
1187  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1188  EXPECT_EQ(MCMatching::c_MissNeutrino | MCMatching::c_MissMassiveParticle,
1189  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1190  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1191  vector<int> daughterPDG_Mu{Const::muon.getPDGCode()};
1192  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Mu), 1);
1193  vector<int> daughterPDG_NuMu{14};
1194  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_NuMu), 1);
1195  vector<int> daughterPDG_Nu{12, 14, 16};
1196  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Nu), 1);
1197  }
1198 
1199  }
1200 
1202  TEST_F(MCMatchingTest, IsSignalBehavior)
1203  {
1204  {
1206  Decay d(511, { {313, {321, -211}}, {443, { -11, 11, 22}}});
1207  Decay* ep = &(d[1][0]);
1208  Decay* em = &(d[1][1]);
1209 
1211  d.reconstruct({511, {{313, {321, -211}}, { -11, {}, Decay::c_ReconstructFrom, ep}, {11, {}, Decay::c_ReconstructFrom, em}}});
1212 
1213  MCParticle* photon = d.getMCParticle(22);
1214  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsPHOTOSPhoton);
1215 
1216  Particle* B = d.m_particle;
1217 
1218  // '=exact=>' c_Ordinary
1219  B->setProperty(Particle::PropertyFlags::c_Ordinary);
1220  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1221  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissPHOTOS, MCMatching::getMCErrors(B)) << d.getString();
1222  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1223 
1224  B->removeExtraInfo();
1225 
1226  // '=norad=>' c_IsIgnoreIntermediate
1227  B->setProperty(Particle::PropertyFlags::c_IsIgnoreIntermediate);
1228  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1229  EXPECT_EQ(MCMatching::c_MissPHOTOS, MCMatching::getMCErrors(B)) << d.getString();
1230  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1231 
1232  B->removeExtraInfo();
1233 
1234  // '=direct=>' c_IsIgnoreRadiatedPhotons
1235  B->setProperty(Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons);
1236  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1237  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(B)) << d.getString();
1238  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1239 
1240  B->removeExtraInfo();
1241 
1242  // '->' c_IsIgnoreRadiatedPhotons and c_IsIgnoreIntermediate
1243  B->setProperty(Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons | Particle::PropertyFlags::c_IsIgnoreIntermediate);
1244  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1245  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B)) << d.getString();
1246  EXPECT_EQ(Variable::isSignal(B), 1.0) << d.getString();
1247  }
1248  }
1249 
1250 
1251  TEST_F(MCMatchingTest, MissingFlagsOfDaughters)
1252  {
1253  {
1255  Decay d(300553, { {511, { -13, 13, 321, -211, {111, {22, 22}}}}, {511, {{ -411, {321, -211, -211}}, 211}} });
1256 
1258  d.reconstruct({300553, { {511, { -13, 13, 0, 0, {0, {0, 0}}}}, {511, {{ -411, {321, -211, -211}}, 211}} } });
1259 
1260  Particle* Y4S = d.m_particle;
1261  Particle* B1 = d.m_particle->getDaughters()[0];
1262  Particle* B2 = d.m_particle->getDaughters()[1];
1263 
1264  // don't set any properties
1265  ASSERT_TRUE(MCMatching::setMCTruth(B1)) << d.getString();
1266  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissGamma | MCMatching::c_MissMassiveParticle,
1267  MCMatching::getMCErrors(B1)) << d.getString();
1268  EXPECT_EQ(Variable::isSignal(B1), 0.0) << d.getString();
1269 
1270  ASSERT_TRUE(MCMatching::setMCTruth(B2)) << d.getString();
1271  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B2)) << d.getString();
1272  EXPECT_EQ(Variable::isSignal(B2), 1.0) << d.getString();
1273 
1274  ASSERT_TRUE(MCMatching::setMCTruth(Y4S)) << d.getString();
1275  EXPECT_EQ(Y4S->getProperty(), Particle::PropertyFlags::c_Ordinary) << d.getString();
1276  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissGamma | MCMatching::c_MissMassiveParticle,
1277  MCMatching::getMCErrors(Y4S)) << d.getString();
1278  EXPECT_EQ(Variable::isSignal(Y4S), 0.0) << d.getString();
1279 
1280  }
1281  {
1283  Decay d(300553, { {511, { -13, 13, 321, -211, {111, {22, 22}}}}, {511, {{ -411, {321, -211, -211}}, 211}} });
1284 
1286  d.reconstruct({300553, { {511, { -13, 13, 0, 0, {0, {0, 0}}}}, {511, {{ -411, {321, -211, -211}}, 211}} } });
1287 
1288  Particle* Y4S = d.m_particle;
1289  Particle* B1 = d.m_particle->getDaughters()[0];
1290  Particle* B2 = d.m_particle->getDaughters()[1];
1291 
1292  int isIgnoreMissing = Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons |
1293  Particle::PropertyFlags::c_IsIgnoreIntermediate |
1294  Particle::PropertyFlags::c_IsIgnoreMassive |
1295  Particle::PropertyFlags::c_IsIgnoreNeutrino |
1296  Particle::PropertyFlags::c_IsIgnoreGamma;
1297 
1298  // set missing particle properties on B1
1299  B1->setProperty(isIgnoreMissing);
1300  ASSERT_TRUE(MCMatching::setMCTruth(B1)) << d.getString();
1301  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B1)) << d.getString();
1302  EXPECT_EQ(Variable::isSignal(B1), 1.0) << d.getString();
1303 
1304 
1305  ASSERT_TRUE(MCMatching::setMCTruth(B2)) << d.getString();
1306  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B2)) << d.getString();
1307  EXPECT_EQ(Variable::isSignal(B2), 1.0) << d.getString();
1308 
1309  ASSERT_TRUE(MCMatching::setMCTruth(Y4S)) << d.getString();
1310  EXPECT_EQ(Y4S->getProperty(), Particle::PropertyFlags::c_Ordinary) << d.getString();
1311  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(Y4S)) << d.getString();
1312  EXPECT_EQ(Variable::isSignal(Y4S), 1.0) << d.getString();
1313 
1314  }
1315 
1316  {
1318  Decay d(511, {{ -411, { -211, 211, -211, {111, {22, 22}}}}, 211, {113, {211, -211}}});
1319 
1321  d.reconstruct({511, {{ -411, { -211, 0, 0, {111, {22, 22}}}}, 211, {0, {0, 0}}}});
1322 
1323  Particle* B = d.m_particle;
1324  Particle* D = d.m_particle->getDaughters()[0];
1325 
1326  // don't set any properties
1327 
1328  // D missed pi+ pi- -> c_MissMassiveParticle
1329  ASSERT_TRUE(MCMatching::setMCTruth(D)) << d.getString();
1330  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1331  MCMatching::getMCErrors(D)) << d.getString();
1332  EXPECT_EQ(Variable::isSignal(D), 0.0) << d.getString();
1333 
1334  // B missed [rho0 -> pi+ pi-] and D's daughters -> c_MissMassiveParticle and c_MissingResonance
1335  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1336  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissMassiveParticle,
1337  MCMatching::getMCErrors(B)) << d.getString();
1338  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1339  }
1340  {
1342  Decay d(511, {{ -411, { -211, 211, -211, {111, {22, 22}}}}, 211, {113, {211, -211}}});
1343 
1345  d.reconstruct({511, {{ -411, { -211, 0, 0, {111, {22, 22}}}}, 211, {0, {0, 0}}}});
1346 
1347  Particle* B = d.m_particle;
1348  Particle* D = d.m_particle->getDaughters()[0];
1349 
1350  int isIgnoreMissing = Particle::PropertyFlags::c_IsIgnoreIntermediate |
1351  Particle::PropertyFlags::c_IsIgnoreMassive;
1352  // set missing particle properties on B1
1353  B->setProperty(isIgnoreMissing);
1354 
1355  // D missed pi+ pi- -> c_MissMassiveParticle
1356  ASSERT_TRUE(MCMatching::setMCTruth(D)) << d.getString();
1357  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1358  MCMatching::getMCErrors(D)) << d.getString();
1359  EXPECT_EQ(Variable::isSignal(D), 0.0) << d.getString();
1360 
1361  // B missed [rho0 -> pi+ pi-] and D's daughters.
1362  // B should accept missing [rho0 -> pi+ pi-]. But the D's daughters are supposed to still fire the missing massive flag.
1363  // -> c_MissMassiveParticle
1364  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1365  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1366  MCMatching::getMCErrors(B)) << d.getString();
1367  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1368  }
1369 
1370  }
1371 
1372 
1373 } // namespace
Class to represent Particle data in graph.
Class to build, validate and sort a particle decay chain.
void generateList(const std::string &name="", int options=c_setNothing)
Generates the MCParticle list and stores it in the StoreArray with the given name.
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
Definition: MCParticle.cc:52
unsigned int getStatus(unsigned short int bitmask=USHRT_MAX) const
Return status code of particle.
Definition: MCParticle.h:122
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 setStatus(unsigned short int status)
Set Status code for the particle.
Definition: MCParticle.h:346
Class to store reconstructed particles.
Definition: Particle.h:75
void setProperty(const int properties)
sets m_properties
Definition: Particle.h:346
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1267
EFlavorType getFlavorType() const
Returns flavor type of the decay (for FS particles: flavor type of particle)
Definition: Particle.h:441
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:426
int getProperty() const
Returns particle property as a bit pattern The values are defined in the PropertyFlags enum and descr...
Definition: Particle.h:470
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1290
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
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
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
void addDecay(GraphParticle &mother, GraphParticle &daughter)
Add decay information between two particles.
void clear()
Reset particles and decay information to make the class reusable.
GraphParticle & addParticle()
Add new particle to the graph.
std::string getString(const TMatrixFBase &matrix, int precision=2, bool color=true)
get HTML table representing a matrix.
Definition: HTML.cc:24
Abstract base class for different kinds of events.