Belle II Software  release-06-02-00
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(TLorentzVector(), decay.m_pdg, isUnflavored ? (Particle::c_Unflavored) : (Particle::c_Flavored),
222  daughterIndices);
223  }
224  }
225  }
226 
227  [[nodiscard]] string getString() const { return "Particles(MCParticles,MCMatch,Flags):\n" + getStringInternal(); }
228 
229  int m_pdg;
230  vector<Decay> m_daughterDecays;
232  m_graphParticle;
233  MCParticle* m_mcparticle;
234  Particle* m_particle;
236  private:
238  [[nodiscard]] string getStringInternal(int depth = 0) const
239  {
240  stringstream s;
241  string spaces;
242  for (int i = 0; i < depth; i++)
243  spaces += " ";
244  s << spaces;
245 
246  if (m_particle)
247  s << m_particle->getPDGCode();
248  else
249  s << "?";
250 
251  s << " (";
252  if (m_mcparticle)
253  s << m_mcparticle->getPDG();
254  else
255  s << "?";
256  const MCParticle* mcMatch = nullptr;
257  if (m_particle)
258  mcMatch = m_particle->getRelated<MCParticle>();
259  if (mcMatch) {
260  s << ", " << mcMatch->getPDG() << ", ";
261  if (m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors))
262  s << MCMatching::explainFlags(m_particle->getExtraInfo(MCMatching::c_extraInfoMCErrors));
263  else
264  s << "-not set-";
265  } else {
266  s << ", ?";
267  s << ", ?";
268  }
269  s << ") ";
270 
271  if (!m_daughterDecays.empty()) {
272  s << " [";
273  for (const Decay& d : m_daughterDecays) {
274  s << "\n" << d.getStringInternal(depth + 1);
275  }
276 
277  s << "\n" << spaces << "]";
278  }
279 
280  return s.str();
281  }
282  };
283 
285  class MCMatchingTest : public ::testing::Test {
286  protected:
288  void SetUp() override
289  {
290  StoreObjPtr<ParticleExtraInfoMap> particleExtraInfo;
291  StoreArray<Particle> particles;
292  StoreArray<MCParticle> mcparticles;
293  particleExtraInfo.registerInDataStore();
294  particles.registerInDataStore();
295  mcparticles.registerInDataStore();
296  particles.registerRelationTo(mcparticles);
297  }
298 
300  void TearDown() override
301  {
302  DataStore::Instance().reset();
303  }
304  };
305 
306 
308  TEST_F(MCMatchingTest, MCParticleGraph)
309  {
310  Decay d(111, {22, 22});
311  StoreArray<MCParticle> mcparticles;
312  //actually push things into StoreArray
313  d.finalize();
314  EXPECT_EQ(mcparticles.getEntries(), 3);
315  EXPECT_EQ(mcparticles[0]->getPDG(), Const::pi0.getPDGCode());
316  EXPECT_EQ(mcparticles[1]->getPDG(), Const::photon.getPDGCode());
317  EXPECT_EQ(mcparticles[2]->getPDG(), Const::photon.getPDGCode());
318  EXPECT_EQ(mcparticles[0]->getMother(), nullptr);
319  EXPECT_EQ(mcparticles[1]->getMother(), mcparticles[0]);
320  EXPECT_EQ(mcparticles[2]->getMother(), mcparticles[0]);
321 
322  Decay e(111, {22, 22});
323  e.finalize();
324  EXPECT_EQ(mcparticles.getEntries(), 6);
325  EXPECT_EQ(mcparticles[3]->getPDG(), Const::pi0.getPDGCode());
326  EXPECT_EQ(mcparticles[3]->getNDaughters(), 2);
327  EXPECT_EQ(mcparticles[4]->getPDG(), Const::photon.getPDGCode());
328  EXPECT_EQ(mcparticles[5]->getPDG(), Const::photon.getPDGCode());
329  EXPECT_EQ(mcparticles[4]->getNDaughters(), 0);
330  EXPECT_EQ(mcparticles[5]->getNDaughters(), 0);
331  EXPECT_EQ(mcparticles[3]->getMother(), nullptr);
332  EXPECT_EQ(mcparticles[4]->getMother(), mcparticles[3]);
333  EXPECT_EQ(mcparticles[5]->getMother(), mcparticles[3]);
334 
335  Decay f(211);
336  f.finalize();
337  EXPECT_EQ(mcparticles.getEntries(), 7);
338  EXPECT_EQ(mcparticles[6]->getPDG(), Const::pion.getPDGCode());
339 
340  Decay g(421, {321, -211, {111, {22, 22}}});
341  g.finalize();
342  EXPECT_EQ(3, g.m_mcparticle->getNDaughters());
343  EXPECT_EQ(mcparticles.getEntries(), 13);
344  }
345 
347  TEST_F(MCMatchingTest, CorrectReconstruction)
348  {
349  StoreArray<MCParticle> mcparticles;
350  StoreArray<Particle> particles;
351 
352  Decay d(421, {321, -211, {111, {22, 22}}});
353  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
354  //reconstruct() calls finalize(), so MCParticles are filled now
355  EXPECT_EQ(mcparticles.getEntries(), 6);
356  EXPECT_EQ(mcparticles[0]->getPDG(), 421);
357  EXPECT_EQ(mcparticles[5]->getPDG(), Const::photon.getPDGCode());
358  EXPECT_EQ(particles.getEntries(), 6);
359 
360  ASSERT_NE(d.m_particle, nullptr);
361  const auto& fspParticles = d.m_particle->getFinalStateDaughters();
362  EXPECT_EQ(fspParticles.size(), 4u);
363  //all final state particles should have relations...
364  for (const Particle* p : fspParticles) {
365  EXPECT_EQ(p->getRelated<MCParticle>()->getDaughters().size(), 0u);
366  }
367  //composite particles don't have them
368  EXPECT_TRUE(mcparticles[0] == d.m_mcparticle);
369  EXPECT_TRUE(mcparticles[0]->getRelated<Particle>() == nullptr);
370  EXPECT_TRUE(mcparticles[3]->getRelated<Particle>() == nullptr);
371 
372  //run MC matching (should be able to set a relation)
373  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
374 
375  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
376 
377  }
379  TEST_F(MCMatchingTest, SetMCTruthNeverRun)
380  {
381  Decay d(421, {321, -211, {111, {22, 22}}});
382  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
383 
384  EXPECT_EQ(nullptr, d.m_particle->getRelated<MCParticle>());
385  ASSERT_FALSE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
386  EXPECT_EQ(MCMatching::c_InternalError, MCMatching::getMCErrors(d.m_particle)) << d.getString();
387  }
388 
389  TEST_F(MCMatchingTest, SettingTruths)
390  {
391  Decay d(421, {321, -211, {111, {22, 22}}});
392  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
393 
394  //setMCTruth should set relation
395  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
396  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
397 
398  //but no extra-info flags
399  ASSERT_FALSE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
400  ASSERT_FALSE(d.getParticle(111)->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
401 
402  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
403 
404  //now it's set
405  ASSERT_TRUE(d.m_particle->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
406  ASSERT_TRUE(d.getParticle(111)->hasExtraInfo(MCMatching::c_extraInfoMCErrors));
407  }
408 
410  TEST_F(MCMatchingTest, MisID)
411  {
412  {
413  Decay d(421, {321, -211, {111, {22, 22}}});
414  d.reconstruct({421, {211, -211, {111, {22, 22}}}});
415  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
416  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
417  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
418  }
419  {
420  //+ wrong non-FSP
421  Decay d(421, {321, -211, {111, {22, 22}}});
422  d.reconstruct({413, {321, -13, {111, {22, 22}}}});
423  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
424  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
425  }
426  {
427  Decay d(421, {321, -211, {111, {22, 22}}});
428  d.reconstruct({421, {321, 13, {111, {22, 22}}}});
429  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
430  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
431  }
432  {
433  Decay d(421, {321, -211, {111, {22, 22}}});
434  d.reconstruct({421, {211, 13, {111, {22, 22}}}});
435  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
436  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
437  }
438  {
439  //pion and kaon switched
440  Decay d(421, {321, -211, {111, {22, 22}}});
441  d.reconstruct({421, { -211, 321, {111, {22, 22}}}});
442  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
443  EXPECT_EQ(MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
444  }
445  }
446 
448  TEST_F(MCMatchingTest, MissingParticles)
449  {
450  {
451  //pi0 is not FSP, so doesn't get MCMatching::c_MissMassiveParticle (but MCMatching::c_MissingResonance)
452  Decay d(421, {321, -211, {111, {22, 22}}});
453  d.reconstruct({421, {321, -211, {0}}});
454  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
455  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
456  }
457  {
458  Decay d(421, {321, -211, {111, {22, 22}}});
459  d.reconstruct({421, {321, 0, {111, {22, 22}}}});
460  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
461  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
462  }
463  {
464  Decay d(421, {321, -211, {111, {22, 22}}});
465  d.reconstruct({421, {0, -211, {111, {22, 22}}}});
466  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
467  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
468  }
469  {
470  Decay d(421, {321, -211, {111, {22, 22}}});
471  d.reconstruct({421, {0, -13, {111, {22, 22}}}});
472  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
473  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle | MCMatching::c_MisID) << d.getString();
474  }
475  }
476  TEST_F(MCMatchingTest, KLongCorrect)
477  {
478  //correct (we miss the 'K0' resonance, but that's fine)
479  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
480  d.finalize();
481  //K0L and daughters are secondary
482  MCParticle* k0l = d.getMCParticle(130);
483  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
484 
485  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, {130, {}, Decay::c_ReconstructFrom, d.getDecay(130)}}});
486  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
487  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
488  }
489  TEST_F(MCMatchingTest, KLongMissed)
490  {
491  //K0L not reconstructed
492  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
493  d.finalize();
494  //K0L and daughters are secondary
495  MCParticle* k0l = d.getMCParticle(130);
496  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
497 
498  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
499  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
500  EXPECT_EQ(MCMatching::c_MissKlong | MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
501  MCMatching::getMCErrors(d.m_particle)) << d.getString();
502  }
503  TEST_F(MCMatchingTest, KShortCorrect)
504  {
505  //correct (we miss the 'K0' resonance, but that's fine)
506  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
507  d.finalize();
508  //K0S and daughters are secondary
509  MCParticle* k0s = d.getMCParticle(310);
510  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
511  MCParticle* pi1 = d.getMCParticle(211);
512  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
513  MCParticle* pi2 = d.getMCParticle(-211);
514  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
515 
516  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, {310, {{211, {}, Decay::c_ReconstructFrom, d.getDecay(211)}, { -211, {}, Decay::c_ReconstructFrom, d.getDecay(-211)}}}}});
517  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
518  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
519  }
520  TEST_F(MCMatchingTest, KShortMissed)
521  {
522  //K0S not reconstructed
523  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
524  d.finalize();
525  //K0S and daughters are secondary
526  MCParticle* k0s = d.getMCParticle(310);
527  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
528  MCParticle* pi1 = d.getMCParticle(211);
529  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
530  MCParticle* pi2 = d.getMCParticle(-211);
531  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
532 
533  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
534  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
535  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
536  MCMatching::getMCErrors(d.m_particle)) << d.getString();
537  }
539  TEST_F(MCMatchingTest, PionWithOneGamma)
540  {
541  {
542  StoreArray<Particle> particles;
543  StoreArray<MCParticle> mcparticles;
544  Decay d(421, {321, -211, {111, {22, 22}}});
545  d.reconstruct({421, {321, -211, {111, {0, 22}}}});
546  EXPECT_EQ(mcparticles.getEntries(), 6);
547  EXPECT_EQ(particles.getEntries(), 5); //we added only 5 Particles
548  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
549  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
550  }
551  {
552  Decay d(421, {321, -211, {111, {22, 22}}});
553  d.reconstruct({421, {321, 0, {111, {0, 22}}}});
554  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
555  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
556  }
557  }
558  TEST_F(MCMatchingTest, TauWithResonance)
559  {
560  // Correct tau
561  {
562  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
563  d.reconstruct({15, {0, { -213, { -211, {111, {22, 22}}}}}});
564  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
565  EXPECT_EQ(MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
566  }
567  // Miss Resoanace
568  {
569  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
570  d.reconstruct({15, {{ -211, {}, Decay::c_ReconstructFrom, &d[1][0]}, {111, {22, 22}, Decay::c_ReconstructFrom, &d[1][1]}}});
571  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
572  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
573  }
574  // Miss Gamma
575  {
576  Decay d(15, {16, { -213, { -211, {111, {22, 22}}}}});
577  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]}}});
578  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
579  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
580  }
581  // Added Wrong Pion
582  {
583  Decay g(-512, {211, -211, -16, {15, {16, { -213, { -211, {111, {22, 22}}}}}}});
584  Decay& d = g[3];
585  d.reconstruct({15, {{ -211, {}, Decay::c_ReconstructFrom, &g[1]}, {111, {22, 22}, Decay::c_ReconstructFrom, &d[1][1]}}});
586  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
587  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance | MCMatching::c_MissNeutrino |
588  MCMatching::c_AddedWrongParticle,
589  MCMatching::getMCErrors(d.m_particle)) << d.getString();
590  }
591 
592 
593  }
594  TEST_F(MCMatchingTest, MissGamma)
595  {
596  {
597  //D*+ -> D+ pi0
598  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}});
599  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}}});
600  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
601  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
602  }
603  {
604  //D*+ -> D+ pi0 reconstructed as D*+ -> D+ gamma
605  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, {111, {22, 22}}});
606  Decay& gamma = d[1][0]; //first gamma from second pi0
607  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
608  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
609  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
610  }
611 
612  {
613  //D*+ -> D+ gamma
614  Decay d(431, {{421, {321, -211, {111, {22, 22}}}}, 22});
615  d.reconstruct({431, {{421, {321, -211, {111, {22, 22}}}}, 22}});
616  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
617  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
618  }
619  {
620  //pi0 -> e+ e- gamma
621  Decay d(111, {11, -11, 22});
622  d.reconstruct({111, {11, -11, 22}});
623  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
624  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
625  }
626  {
627  //pi0 -> e+ e- gamma reconstructed without gamma
628  Decay d(111, {11, -11, 22});
629  d.reconstruct({111, {11, -11, 0}});
630  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
631  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
632  }
633  {
634  //pi0 -> 2 gamma, with both clusters coming from same photon
635  Decay d(111, {22, 22});
636  Decay& gamma = d[0];
637  d.reconstruct({111, {22, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
638  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
639  //MCMatch of pi0 is first gamma
640  EXPECT_EQ(MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
641  }
642  {
643  //pi0 -> 4 gamma
644  Decay d(111, {22, 22, 22, 22});
645  d.reconstruct({111, {22, 22, 22, 22}});
646  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
647  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
648  }
649  {
650  //pi0 -> 4 gamma as 2 gamma
651  Decay d(111, {22, 22, 22, 22});
652  d.reconstruct({111, {22, 22, 0, 0}});
653  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
654  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
655  }
656  {
657  //pi0 -> 4 gamma, with two clusters coming from same photon
658  Decay d(111, {22, 22, 22, 22});
659  Decay& gamma = d[0];
660  d.reconstruct({111, {22, 22, 22, {22, {}, Decay::c_ReconstructFrom, &gamma}}});
661  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
662  EXPECT_EQ(MCMatching::c_MissGamma, MCMatching::getMCErrors(d.m_particle)) << d.getString();
663  }
664  }
666  TEST_F(MCMatchingTest, WrongPhotonForPi0)
667  {
668  {
669  Decay d(521, {211, Decay(421, {321, -211, Decay(111, {22, 22})}), 22});
670  d.finalize();
671  d.reconstruct({521, {211, {421, {321, -211, {111, {{22}, {22, {}, Decay::c_RelateWith, d.getMCParticle(211)}}}}}}});
672  //result: pi0 gets MC match 521.
673  //Gets misID & c_AddedWrongParticle because of 'wrong' photon,
674  //plus c_MissMassiveParticle since the B's daughters are missing,
675  //plus c_MissGamma because one photon was not reconstructed,
676  //plus c_MissingResonance because non-FSPs were missed (MC matched particle (521) has lots of daughters)
677 
678  Particle* pi0 = d.getParticle(111);
679  Decay* pi0decay = d.getDecay(111);
680  ASSERT_TRUE(MCMatching::setMCTruth(pi0)) << pi0decay->getString();
681  EXPECT_EQ(521, pi0->getRelated<MCParticle>()->getPDG());
682  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissMassiveParticle | MCMatching::c_MissGamma |
683  MCMatching::c_MissingResonance,
684  MCMatching::getMCErrors(pi0)) << pi0decay->getString();
685 
686  //flags migrate upstream
687  Particle* p = d.getParticle(421);
688  Decay* d0decay = d.getDecay(421);
689  ASSERT_TRUE(MCMatching::setMCTruth(p)) << d0decay->getString();
690  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissGamma | MCMatching::c_MissingResonance,
691  MCMatching::getMCErrors(p)) << d0decay->getString();
692 
693  //even with addedWrongParticle (inherited from daughter), missFSR should be detected.
694  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
695  EXPECT_EQ(MCMatching::c_MisID | MCMatching::c_AddedWrongParticle | MCMatching::c_MissGamma | MCMatching::c_MissingResonance,
696  MCMatching::getMCErrors(d.m_particle)) << d.getString();
697  }
698  }
699 
701  TEST_F(MCMatchingTest, DecayInFlightCorrect)
702  {
703  {
704  Decay d(421, {321, { -211, {13}}, {111, {22, 22}}});
705  d.finalize();
706  MCParticle* muon = d.getMCParticle(13);
707  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
708  ASSERT_FALSE(muon->hasStatus(MCParticle::c_PrimaryParticle));
709  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
710 
711  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
712  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
713  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
714  }
715  {
716  Decay d(421, {{321, {11, -12, {111, {22, 22}}}}, -211, {111, {22, 22}}});
717  d.reconstruct({421, {321, -211, {111, {22, 22}}}});
718 
719  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
720  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
721  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
722  }
723  }
725  TEST_F(MCMatchingTest, DecayInFlight)
726  {
727  {
728  Decay d(-211, {13});
729  d.finalize();
730  MCParticle* muon = d.getMCParticle(13);
731  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
732  d.reconstruct({ -211, {}, Decay::c_RelateWith, muon});
733 
734  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
735  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
736  EXPECT_EQ(MCMatching::c_DecayInFlight, MCMatching::getMCErrors(d.m_particle)) << d.getString();
737  }
738  {
739  Decay d(421, {321, { -211, {13}}, {111, {22, 22}}});
740  d.finalize();
741  MCParticle* muon = d.getMCParticle(13);
742  muon->setStatus(muon->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
743  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, muon}, {111, {22, 22}}}});
744 
745 
746  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
747  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
748  EXPECT_EQ(MCMatching::c_DecayInFlight, MCMatching::getMCErrors(d.m_particle)) << d.getString();
749  }
750  }
752  TEST_F(MCMatchingTest, CorrectFSPsWrongDecay)
753  {
754  {
755  Decay d(-413, {{ -411, {321, -211, -211}}, {111, {22, 22}}});
756 
757  Decay& pi0 = d[1];
758  Decay& pi2 = d[0][2];
759 
760  ASSERT_TRUE(d.getDecay(111) == &pi0);
761 
762  d.reconstruct({ -413, {{ -421, {321, -211, {111, {22, 22}, Decay::c_ReconstructFrom, &pi0}}}, { -211, {}, Decay::c_ReconstructFrom, &pi2}}});
763 
764 
765  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
766  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
767  //inherits c_AddedWrongParticle from D0, gets c_MissingResonance since D+ is missing
768  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
769  MCMatching::getMCErrors(d.m_particle)) << d.getString();
770  }
771  }
773  TEST_F(MCMatchingTest, WrongCombination)
774  {
776  {
777  Decay d(-413, {{ -421, {321, -211, {111, {22, 22}}}}, -211});
778 
779  Decay* pi1 = &(d[0][1]);
780  Decay* pi2 = &(d[1]);
781  ASSERT_TRUE(pi1->m_pdg == pi2->m_pdg);
782 
783  d.reconstruct({ -413, {{ -421, {321, { -211, {}, Decay::c_ReconstructFrom, pi2}, {111, {22, 22}}}}, { -211, {}, Decay::c_ReconstructFrom, pi1}}});
784 
785 
786  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
787  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
788  //gets c_MissingResonance since none of the Particles got the D0 MCParticle as MC match
789  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
790  MCMatching::getMCErrors(d.m_particle)) << d.getString();
791  }
792 
794  {
795  Decay d(511, {{333, {321, -321}}, {333, {321, -321}}});
796 
797  Decay* k1 = &(d[0][1]);
798  Decay* k2 = &(d[1][1]);
799  ASSERT_TRUE(k1->m_pdg == k2->m_pdg);
800 
801  d.reconstruct({511, {
802  {333, {321, { -321, {}, Decay::c_ReconstructFrom, k2}}},
803  {333, {321, { -321, {}, Decay::c_ReconstructFrom, k1}}}
804  }
805  });
806 
807 
808  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
809  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
810  //gets c_MissingResonance since none of the Particles got the phi MCParticle as MC match
811  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
812  MCMatching::getMCErrors(d.m_particle)) << d.getString();
813  }
814  }
816  TEST_F(MCMatchingTest, SelfCrossFeed)
817  {
818  {
819  Decay d(300533, {{511, {321, -211, {111, {22, 22}}}}, { -511, { -321, 211, {111, {22, 22}}}}});
820 
821  Decay* pi1 = &(d[0][2]);
822  Decay* pi2 = &(d[1][2]);
823  ASSERT_TRUE(pi1->m_pdg == pi2->m_pdg);
824 
825  d.reconstruct({300533, {
826  {511, {321, -211, {111, {22, 22}, Decay::c_ReconstructFrom, pi2}}},
827  { -511, { -321, 211, {111, {22, 22}, Decay::c_ReconstructFrom, pi1}}}
828  }
829  });
830 
831 
832  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
833  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
834  //gets c_MissingResonance since none of the Particles got the B0/anti-B0 MCParticle as MC match
835  EXPECT_EQ(MCMatching::c_AddedWrongParticle | MCMatching::c_MissingResonance,
836  MCMatching::getMCErrors(d.m_particle)) << d.getString();
837  }
838  }
839 
840  TEST_F(MCMatchingTest, FlavouredD0Decay)
841  {
842  {
843  //ok
844  Decay d(421, { -321, 211});
845  d.reconstruct({421, { -321, 211}});
846  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
847 
848  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
849  EXPECT_EQ(d.m_particle->getPDGCode(), d.m_particle->getRelated<MCParticle>()->getPDG());
850  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
851  }
852  {
853  //also exists, but suppressed
854  Decay d(-421, { -321, 211});
855  d.reconstruct({ -421, { -321, 211}});
856  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
857 
858  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
859  EXPECT_EQ(d.m_particle->getPDGCode(), d.m_particle->getRelated<MCParticle>()->getPDG());
860  EXPECT_EQ(MCMatching::c_Correct, 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  //however, reconstructing the wrong D0 is not okay
873  Decay d(-421, { -321, 211});
874  d.reconstruct({421, { -321, 211}});
875  ASSERT_EQ(Particle::c_Flavored, d.m_particle->getFlavorType());
876 
877  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
878  EXPECT_EQ(MCMatching::c_AddedWrongParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
879  }
880  }
881 
882  TEST_F(MCMatchingTest, UnflavouredD0Decay)
883  {
884  {
885  //ok
886  Decay d(421, { -321, 321});
887  d.reconstruct({421, { -321, 321}});
888  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
889 
890  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
891  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
892  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
893  }
894  {
895  //ok
896  Decay d(-421, { -321, 321});
897  d.reconstruct({ -421, { -321, 321}});
898  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
899 
900  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
901  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
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  //we don't know the flavour, so this is also fine
915  Decay d(-421, { -321, 321});
916  d.reconstruct({421, { -321, 321}});
917  ASSERT_EQ(Particle::c_Unflavored, d.m_particle->getFlavorType());
918 
919  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
920  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
921  }
922  }
923 
924  //B0 -> rho+ D-
925  TEST_F(MCMatchingTest, MissingResonance)
926  {
927  //explicitly reconstruct the rho
928  {
929  Decay d(511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}});
930  d.reconstruct({511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}}});
931 
932  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
933  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
934  }
935  //missing rho
936  {
937  Decay d(511, {{ -411, { -321, 321, 211}}, {213, {211, {111, {22, 22}}}}});
938  //d.reconstruct({511, {{-411, {-321, 321, 211}}, {0, {211, {111, {22, 22}}}}}});
939  Decay* piplus = &(d[1][0]);
940  Decay* pi0 = &(d[1][1]);
941 
942  d.reconstruct({511, {{ -411, { -321, 321, 211}}, {211, {}, Decay::c_ReconstructFrom, piplus}, {111, {22, 22}, Decay::c_ReconstructFrom, pi0}}});
943 
944  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
945  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
946  }
947  }
948 
949  TEST_F(MCMatchingTest, MissingFSPReplacedBySecondary)
950  {
951  Decay d(521, {{ -421, {321, { -211, {22, -211}}}}, 211, 211, -211});
952  Decay* pi = &(d[0][1][1]);
953  d.reconstruct({521, {{ -421, {321, -211}}, 211, 211, {
954  -211, {},
955  Decay::c_ReconstructFrom, pi
956  }
957  }
958  });
959  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
960  EXPECT_EQ(MCMatching::c_MissMassiveParticle, MCMatching::getMCErrors(d.m_particle)) << d.getString();
961  }
962  TEST_F(MCMatchingTest, BeamBackground)
963  {
964  Decay d(421, {321, -211, {111, {22, 22}}});
965  d.finalize();
966  MCParticle* noParticle = nullptr;
967  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, noParticle}, {111, {22, 22}}}});
968 
969  //no common mother
970  ASSERT_FALSE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
971  EXPECT_EQ(MCMatching::c_InternalError, MCMatching::getMCErrors(d.m_particle)) << d.getString();
972  EXPECT_EQ(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
973  }
974 
975  TEST_F(MCMatchingTest, DuplicateTrack)
976  {
977  {
978  Decay d(421, {321, -211, {111, {22, 22}}});
979  d.finalize();
980  MCParticle* kaon = d.getMCParticle(321);
981  ASSERT_TRUE(kaon != nullptr);
982  //tracks for the same MCParticle used twice:
983  d.reconstruct({421, {321, { -211, {}, Decay::c_RelateWith, kaon}, {111, {22, 22}}}});
984 
985  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
986  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
987  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MisID, MCMatching::getMCErrors(d.m_particle)) << d.getString();
988  }
989  }
990 
992  TEST_F(MCMatchingTest, MissingFSRMissingPHOTOS)
993  {
994  {
995  Decay d(521, { -11, 12, 22});
996  d.finalize();
997  MCParticle* photon = d.getMCParticle(22);
998  EXPECT_FALSE(MCMatching::isFSR(photon));
999 
1000  d.reconstruct({521, { -11}});
1001  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1002  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1003  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1004 
1005  }
1006  {
1007  //ISR flag should not trigger anything special
1008  Decay d(521, { -11, 12, 22});
1009  d.finalize();
1010  MCParticle* photon = d.getMCParticle(22);
1011  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsISRPhoton);
1012  EXPECT_FALSE(MCMatching::isFSR(photon));
1013 
1014  d.reconstruct({521, { -11}});
1015  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1016  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1017  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1018  }
1019 
1020  {
1021  //now try the same with FSR flag
1022  Decay d(521, { -11, 12, 22});
1023  d.finalize();
1024  MCParticle* photon = d.getMCParticle(22);
1025  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsFSRPhoton);
1026  EXPECT_TRUE(MCMatching::isFSR(photon));
1027 
1028  d.reconstruct({521, { -11}});
1029  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1030  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1031  EXPECT_EQ(MCMatching::c_MissFSR | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1032  }
1033 
1034  {
1035  //now try PHOTOS photon
1036  Decay d(521, { -11, 12, 22});
1037  d.finalize();
1038  MCParticle* photon = d.getMCParticle(22);
1039  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsPHOTOSPhoton);
1040  EXPECT_FALSE(MCMatching::isFSR(photon));
1041 
1042  d.reconstruct({521, { -11}});
1043  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1044  EXPECT_EQ(d.m_mcparticle->getPDG(), d.m_particle->getRelated<MCParticle>()->getPDG());
1045  EXPECT_EQ(MCMatching::c_MissPHOTOS | MCMatching::c_MissNeutrino, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1046  }
1047  }
1048 
1050  TEST_F(MCMatchingTest, UnspecifiedParticleReconstruction)
1051  {
1052  {
1054  Decay d(511, {{30343, {321, -211}}, -13, 13});
1055  d.reconstruct({511, {{30343, {321, -211}}, -13, 13}});
1056 
1057  Particle* Xsd = d.m_particle->getDaughters()[0];
1058  ASSERT_TRUE(Xsd != nullptr);
1059  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1060  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1061  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1062 
1063  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1064  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1065  }
1066  {
1068  Decay d(511, {{313, {321, -211}}, -13, 13});
1069  d.reconstruct({511, {{30343, {321, -211}}, -13, 13}});
1070 
1071  Particle* Xsd = d.m_particle->getDaughters()[0];
1072  ASSERT_TRUE(Xsd != nullptr);
1073  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1074  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1075  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1076 
1077  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1078  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1079  }
1080  {
1082  Decay d(511, { {313, {321, -211}}, {443, { -13, 13}}});
1083  Decay* mup = &(d[1][0]);
1084  Decay* mum = &(d[1][1]);
1085  d.reconstruct({511, {{30343, {321, -211}}, { -13, {}, Decay::c_ReconstructFrom, mup}, {13, {}, Decay::c_ReconstructFrom, mum}}});
1086 
1087  Particle* Xsd = d.m_particle->getDaughters()[0];
1088  ASSERT_TRUE(Xsd != nullptr);
1089  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), false);
1090  Xsd->setProperty(Particle::PropertyFlags::c_IsUnspecified);
1091  EXPECT_EQ(Variable::particleIsUnspecified(Xsd), true);
1092 
1093  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1094  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1095  }
1096  }
1097 
1099  TEST_F(MCMatchingTest, CountMissingParticle)
1100  {
1101  {
1102  // pi0 not reconstructed
1103  Decay d(421, {321, -211, {111, {22, 22}}});
1104  d.reconstruct({421, {321, -211, {0}}});
1105  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1106  EXPECT_EQ(MCMatching::c_MissGamma | MCMatching::c_MissingResonance, MCMatching::getMCErrors(d.m_particle)) << d.getString();
1107  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1108  vector<int> daughterPDG{Const::pi0.getPDGCode()};
1109  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1110  }
1111  {
1112  // pi not reconstructed
1113  Decay d(421, {321, -211, {111, {22, 22}}});
1114  d.reconstruct({421, {321, 0, {111, {22, 22}}}});
1115  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1116  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1117  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1118  vector<int> daughterPDG{Const::pion.getPDGCode()};
1119  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1120  }
1121  {
1122  // K not reconstructed
1123  Decay d(421, {321, -211, {111, {22, 22}}});
1124  d.reconstruct({421, {0, -211, {111, {22, 22}}}});
1125  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1126  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1127  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1128  vector<int> daughterPDG{Const::kaon.getPDGCode()};
1129  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1130  }
1131  {
1132  // 2K not reconstructed
1133  Decay d(-521, { -321, {421, {321, -211, {111, {22, 22}}}}});
1134  d.reconstruct({ -521, {0, {421, {0, -211, {111, {22, 22}}}}}});
1135  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1136  EXPECT_EQ(MCMatching::getMCErrors(d.m_particle), MCMatching::c_MissMassiveParticle) << d.getString();
1137  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1138  vector<int> daughterPDG{Const::kaon.getPDGCode()};
1139  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 2);
1140  }
1141  {
1142  //K0S not reconstructed
1143  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {{310, {211, -211}}}}});
1144  d.finalize();
1145  //K0S and daughters are secondary
1146  MCParticle* k0s = d.getMCParticle(310);
1147  k0s->setStatus(k0s->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
1148  MCParticle* pi1 = d.getMCParticle(211);
1149  pi1->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
1150  MCParticle* pi2 = d.getMCParticle(-211);
1151  pi2->setStatus(pi1->getStatus() & (~MCParticle::c_PrimaryParticle));
1152 
1153  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
1154  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1155  EXPECT_EQ(MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
1156  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1157  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1158  vector<int> daughterPDG{Const::Kshort.getPDGCode()};
1159  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1160  }
1161  {
1162  //K0L not reconstructed
1163  Decay d(431, { {323, {321, {111, {22, 22}} }}, { -311, {130}}});
1164  d.finalize();
1165  //K0L and daughters are secondary
1166  MCParticle* k0l = d.getMCParticle(130);
1167  k0l->setStatus(k0l->getStatus() & (~MCParticle::c_PrimaryParticle)); //remove c_PrimaryParticle
1168 
1169  d.reconstruct({431, { {323, {321, {111, {22, 22}} }}, 0}});
1170  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1171  EXPECT_EQ(MCMatching::c_MissKlong | MCMatching::c_MissMassiveParticle | MCMatching::c_MissingResonance,
1172  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1173  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1174  vector<int> daughterPDG{Const::Klong.getPDGCode()};
1175  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG), 1);
1176  }
1177  {
1178  // e and nutrino not reconstructed
1179  Decay d(521, { -11, 12, 22});
1180  d.reconstruct({521, {0, 0, 22}});
1181  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1182  EXPECT_EQ(MCMatching::c_MissNeutrino | MCMatching::c_MissMassiveParticle,
1183  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1184  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1185  vector<int> daughterPDG_E{Const::electron.getPDGCode()};
1186  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_E), 1);
1187  vector<int> daughterPDG_NuE{12};
1188  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_NuE), 1);
1189  vector<int> daughterPDG_Nu{12, 14, 16};
1190  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Nu), 1);
1191  }
1192  {
1193  // e and nutrino not reconstructed
1194  Decay d(521, { -13, 14, 22});
1195  d.reconstruct({521, {0, 0, 22}});
1196  ASSERT_TRUE(MCMatching::setMCTruth(d.m_particle)) << d.getString();
1197  EXPECT_EQ(MCMatching::c_MissNeutrino | MCMatching::c_MissMassiveParticle,
1198  MCMatching::getMCErrors(d.m_particle)) << d.getString();
1199  ASSERT_NE(nullptr, d.m_particle->getRelated<MCParticle>()) << d.getString();
1200  vector<int> daughterPDG_Mu{Const::muon.getPDGCode()};
1201  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Mu), 1);
1202  vector<int> daughterPDG_NuMu{14};
1203  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_NuMu), 1);
1204  vector<int> daughterPDG_Nu{12, 14, 16};
1205  EXPECT_EQ(MCMatching::countMissingParticle(d.m_particle, d.m_particle->getRelated<MCParticle>(), daughterPDG_Nu), 1);
1206  }
1207 
1208  }
1209 
1211  TEST_F(MCMatchingTest, IsSignalBehavior)
1212  {
1213  {
1215  Decay d(511, { {313, {321, -211}}, {443, { -11, 11, 22}}});
1216  Decay* ep = &(d[1][0]);
1217  Decay* em = &(d[1][1]);
1218 
1220  d.reconstruct({511, {{313, {321, -211}}, { -11, {}, Decay::c_ReconstructFrom, ep}, {11, {}, Decay::c_ReconstructFrom, em}}});
1221 
1222  MCParticle* photon = d.getMCParticle(22);
1223  photon->setStatus(MCParticle::c_PrimaryParticle | MCParticle::c_IsPHOTOSPhoton);
1224 
1225  Particle* B = d.m_particle;
1226 
1227  // '=exact=>' c_Ordinary
1228  B->setProperty(Particle::PropertyFlags::c_Ordinary);
1229  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1230  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissPHOTOS, MCMatching::getMCErrors(B)) << d.getString();
1231  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1232 
1233  B->removeExtraInfo();
1234 
1235  // '=norad=>' c_IsIgnoreIntermediate
1236  B->setProperty(Particle::PropertyFlags::c_IsIgnoreIntermediate);
1237  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1238  EXPECT_EQ(MCMatching::c_MissPHOTOS, MCMatching::getMCErrors(B)) << d.getString();
1239  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1240 
1241  B->removeExtraInfo();
1242 
1243  // '=direct=>' c_IsIgnoreRadiatedPhotons
1244  B->setProperty(Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons);
1245  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1246  EXPECT_EQ(MCMatching::c_MissingResonance, MCMatching::getMCErrors(B)) << d.getString();
1247  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1248 
1249  B->removeExtraInfo();
1250 
1251  // '->' c_IsIgnoreRadiatedPhotons and c_IsIgnoreIntermediate
1252  B->setProperty(Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons | Particle::PropertyFlags::c_IsIgnoreIntermediate);
1253  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1254  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B)) << d.getString();
1255  EXPECT_EQ(Variable::isSignal(B), 1.0) << d.getString();
1256  }
1257  }
1258 
1259 
1260  TEST_F(MCMatchingTest, MissingFlagsOfDaughters)
1261  {
1262  {
1264  Decay d(300553, { {511, { -13, 13, 321, -211, {111, {22, 22}}}}, {511, {{ -411, {321, -211, -211}}, 211}} });
1265 
1267  d.reconstruct({300553, { {511, { -13, 13, 0, 0, {0, {0, 0}}}}, {511, {{ -411, {321, -211, -211}}, 211}} } });
1268 
1269  Particle* Y4S = d.m_particle;
1270  Particle* B1 = d.m_particle->getDaughters()[0];
1271  Particle* B2 = d.m_particle->getDaughters()[1];
1272 
1273  // don't set any properties
1274  ASSERT_TRUE(MCMatching::setMCTruth(B1)) << d.getString();
1275  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissGamma | MCMatching::c_MissMassiveParticle,
1276  MCMatching::getMCErrors(B1)) << d.getString();
1277  EXPECT_EQ(Variable::isSignal(B1), 0.0) << d.getString();
1278 
1279  ASSERT_TRUE(MCMatching::setMCTruth(B2)) << d.getString();
1280  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B2)) << d.getString();
1281  EXPECT_EQ(Variable::isSignal(B2), 1.0) << d.getString();
1282 
1283  ASSERT_TRUE(MCMatching::setMCTruth(Y4S)) << d.getString();
1284  EXPECT_EQ(Y4S->getProperty(), Particle::PropertyFlags::c_Ordinary) << d.getString();
1285  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissGamma | MCMatching::c_MissMassiveParticle,
1286  MCMatching::getMCErrors(Y4S)) << d.getString();
1287  EXPECT_EQ(Variable::isSignal(Y4S), 0.0) << d.getString();
1288 
1289  }
1290  {
1292  Decay d(300553, { {511, { -13, 13, 321, -211, {111, {22, 22}}}}, {511, {{ -411, {321, -211, -211}}, 211}} });
1293 
1295  d.reconstruct({300553, { {511, { -13, 13, 0, 0, {0, {0, 0}}}}, {511, {{ -411, {321, -211, -211}}, 211}} } });
1296 
1297  Particle* Y4S = d.m_particle;
1298  Particle* B1 = d.m_particle->getDaughters()[0];
1299  Particle* B2 = d.m_particle->getDaughters()[1];
1300 
1301  int isIgnoreMissing = Particle::PropertyFlags::c_IsIgnoreRadiatedPhotons |
1302  Particle::PropertyFlags::c_IsIgnoreIntermediate |
1303  Particle::PropertyFlags::c_IsIgnoreMassive |
1304  Particle::PropertyFlags::c_IsIgnoreNeutrino |
1305  Particle::PropertyFlags::c_IsIgnoreGamma;
1306 
1307  // set missing particle properties on B1
1308  B1->setProperty(isIgnoreMissing);
1309  ASSERT_TRUE(MCMatching::setMCTruth(B1)) << d.getString();
1310  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B1)) << d.getString();
1311  EXPECT_EQ(Variable::isSignal(B1), 1.0) << d.getString();
1312 
1313 
1314  ASSERT_TRUE(MCMatching::setMCTruth(B2)) << d.getString();
1315  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(B2)) << d.getString();
1316  EXPECT_EQ(Variable::isSignal(B2), 1.0) << d.getString();
1317 
1318  ASSERT_TRUE(MCMatching::setMCTruth(Y4S)) << d.getString();
1319  EXPECT_EQ(Y4S->getProperty(), Particle::PropertyFlags::c_Ordinary) << d.getString();
1320  EXPECT_EQ(MCMatching::c_Correct, MCMatching::getMCErrors(Y4S)) << d.getString();
1321  EXPECT_EQ(Variable::isSignal(Y4S), 1.0) << d.getString();
1322 
1323  }
1324 
1325  {
1327  Decay d(511, {{ -411, { -211, 211, -211, {111, {22, 22}}}}, 211, {113, {211, -211}}});
1328 
1330  d.reconstruct({511, {{ -411, { -211, 0, 0, {111, {22, 22}}}}, 211, {0, {0, 0}}}});
1331 
1332  Particle* B = d.m_particle;
1333  Particle* D = d.m_particle->getDaughters()[0];
1334 
1335  // don't set any properties
1336 
1337  // D missed pi+ pi- -> c_MissMassiveParticle
1338  ASSERT_TRUE(MCMatching::setMCTruth(D)) << d.getString();
1339  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1340  MCMatching::getMCErrors(D)) << d.getString();
1341  EXPECT_EQ(Variable::isSignal(D), 0.0) << d.getString();
1342 
1343  // B missed [rho0 -> pi+ pi-] and D's daughters -> c_MissMassiveParticle and c_MissingResonance
1344  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1345  EXPECT_EQ(MCMatching::c_MissingResonance | MCMatching::c_MissMassiveParticle,
1346  MCMatching::getMCErrors(B)) << d.getString();
1347  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1348  }
1349  {
1351  Decay d(511, {{ -411, { -211, 211, -211, {111, {22, 22}}}}, 211, {113, {211, -211}}});
1352 
1354  d.reconstruct({511, {{ -411, { -211, 0, 0, {111, {22, 22}}}}, 211, {0, {0, 0}}}});
1355 
1356  Particle* B = d.m_particle;
1357  Particle* D = d.m_particle->getDaughters()[0];
1358 
1359  int isIgnoreMissing = Particle::PropertyFlags::c_IsIgnoreIntermediate |
1360  Particle::PropertyFlags::c_IsIgnoreMassive;
1361  // set missing particle properties on B1
1362  B->setProperty(isIgnoreMissing);
1363 
1364  // D missed pi+ pi- -> c_MissMassiveParticle
1365  ASSERT_TRUE(MCMatching::setMCTruth(D)) << d.getString();
1366  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1367  MCMatching::getMCErrors(D)) << d.getString();
1368  EXPECT_EQ(Variable::isSignal(D), 0.0) << d.getString();
1369 
1370  // B missed [rho0 -> pi+ pi-] and D's daughters.
1371  // B should accept missing [rho0 -> pi+ pi-]. But the D's daughters are supposed to still fire the missing massive flag.
1372  // -> c_MissMassiveParticle
1373  ASSERT_TRUE(MCMatching::setMCTruth(B)) << d.getString();
1374  EXPECT_EQ(MCMatching::c_MissMassiveParticle,
1375  MCMatching::getMCErrors(B)) << d.getString();
1376  EXPECT_EQ(Variable::isSignal(B), 0.0) << d.getString();
1377  }
1378 
1379  }
1380 
1381 
1382 } // namespace
1383 #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:50
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:332
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:343
Class to store reconstructed particles.
Definition: Particle.h:74
void setProperty(const int properties)
sets m_properties
Definition: Particle.h:328
float getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1242
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1219
EFlavorType getFlavorType() const
Returns flavor type of the decay (for FS particles: flavor type of particle)
Definition: Particle.h:407
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:392
int getProperty() const
Returns particle property as a bit pattern The values are defined in the PropertyFlags enum and descr...
Definition: Particle.h:436
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:95
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
bool isFSP(int pdg)
defines what is a final state particle for this purpose.
TEST(TestgetDetectorRegion, TestgetDetectorRegion)
Test Constructors.
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:25
Abstract base class for different kinds of events.