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