Belle II Software  light-2403-persian
Particle.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <analysis/dataobjects/Particle.h>
10 #include <analysis/dataobjects/ParticleExtraInfoMap.h>
11 
12 #include <analysis/ClusterUtility/ClusterUtils.h>
13 
14 #include <mdst/dataobjects/KLMCluster.h>
15 #include <mdst/dataobjects/MCParticle.h>
16 #include <mdst/dataobjects/PIDLikelihood.h>
17 #include <mdst/dataobjects/Track.h>
18 #include <mdst/dataobjects/TrackFitResult.h>
19 #include <mdst/dataobjects/V0.h>
20 #include <mdst/dbobjects/CollisionBoostVector.h>
21 #include <mdst/dbobjects/CollisionInvariantMass.h>
22 
23 #include <framework/datastore/StoreArray.h>
24 #include <framework/datastore/StoreObjPtr.h>
25 #include <framework/database/DBObjPtr.h>
26 #include <framework/logging/Logger.h>
27 #include <framework/utilities/HTML.h>
28 #include <framework/utilities/Conversion.h>
29 
30 #include <TClonesArray.h>
31 #include <TDatabasePDG.h>
32 #include <TMatrixFSym.h>
33 #include <Math/Boost.h>
34 
35 #include <iostream>
36 #include <iomanip>
37 #include <stdexcept>
38 #include <queue>
39 
40 #include <boost/algorithm/string.hpp>
41 
42 using namespace Belle2;
43 using namespace ROOT::Math;
44 
46  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
47  m_pValue(nan("")), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0),
48  m_arrayPointer(nullptr)
49 {
51 }
52 
53 
54 Particle::Particle(const ROOT::Math::PxPyPzEVector& momentum, const int pdgCode) :
55  m_pdgCode(pdgCode), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
56  m_pValue(-1), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0), m_arrayPointer(nullptr)
57 {
58  setFlavorType();
59  set4Vector(momentum);
61  // set mass of stable charged particle to its nominal value
64  }
65 }
66 
67 
68 Particle::Particle(const ROOT::Math::PxPyPzEVector& momentum,
69  const int pdgCode,
70  EFlavorType flavorType,
71  const EParticleSourceObject source,
72  const unsigned mdstIndex) :
73  m_pdgCode(pdgCode), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
74  m_pValue(-1), m_flavorType(flavorType), m_particleSource(source), m_properties(0), m_arrayPointer(nullptr)
75 {
76  if (flavorType == c_Unflavored and pdgCode < 0)
77  m_pdgCode = -pdgCode;
78 
79  setMdstArrayIndex(mdstIndex);
80  set4Vector(momentum);
82  // set mass of stable charged particle to its nominal value
85  }
86 }
87 
88 
89 Particle::Particle(const ROOT::Math::PxPyPzEVector& momentum,
90  const int pdgCode,
91  EFlavorType flavorType,
92  const std::vector<int>& daughterIndices,
93  TClonesArray* arrayPointer) :
94  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
95  m_pValue(-1),
96  m_daughterIndices(daughterIndices),
97  m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0),
98  m_properties(0), m_arrayPointer(arrayPointer)
99 {
100  m_pdgCode = pdgCode;
101  m_flavorType = flavorType;
102  if (flavorType == c_Unflavored and pdgCode < 0)
103  m_pdgCode = -pdgCode;
104  set4Vector(momentum);
106  // set mass of stable charged particle to its nominal value
109  }
110 
111  if (!daughterIndices.empty()) {
112  m_particleSource = c_Composite;
113  if (getArrayPointer() == nullptr) {
114  B2FATAL("Composite Particle (with daughters) was constructed outside StoreArray without specifying daughter array!");
115  }
116  for (unsigned int i = 0; i < m_daughterIndices.size(); i++) {
117  m_daughterProperties.push_back(Particle::PropertyFlags::c_Ordinary);
118  }
119  }
120 }
121 
122 Particle::Particle(const ROOT::Math::PxPyPzEVector& momentum,
123  const int pdgCode,
124  EFlavorType flavorType,
125  const std::vector<int>& daughterIndices,
126  const int properties,
127  TClonesArray* arrayPointer) :
128  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
129  m_pValue(-1),
130  m_daughterIndices(daughterIndices),
131  m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0),
132  m_arrayPointer(arrayPointer)
133 {
134  m_pdgCode = pdgCode;
135  m_flavorType = flavorType;
136  if (flavorType == c_Unflavored and pdgCode < 0)
137  m_pdgCode = -pdgCode;
138  set4Vector(momentum);
140  // set mass of stable charged particle to its nominal value
143  }
144  m_properties = properties;
145 
146  if (!daughterIndices.empty()) {
147  m_particleSource = c_Composite;
148  if (getArrayPointer() == nullptr) {
149  B2FATAL("Composite Particle (with daughters) was constructed outside StoreArray without specifying daughter array!");
150  }
151  for (unsigned int i = 0; i < m_daughterIndices.size(); i++) {
152  m_daughterProperties.push_back(Particle::PropertyFlags::c_Ordinary);
153  }
154  }
155 }
156 
157 
158 Particle::Particle(const ROOT::Math::PxPyPzEVector& momentum,
159  const int pdgCode,
160  EFlavorType flavorType,
161  const std::vector<int>& daughterIndices,
162  const int properties,
163  const std::vector<int>& daughterProperties,
164  TClonesArray* arrayPointer) :
165  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
166  m_pValue(-1),
167  m_daughterIndices(daughterIndices),
168  m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0),
169  m_daughterProperties(daughterProperties),
170  m_arrayPointer(arrayPointer)
171 {
172  m_pdgCode = pdgCode;
173  m_flavorType = flavorType;
174  if (flavorType == c_Unflavored and pdgCode < 0)
175  m_pdgCode = -pdgCode;
176  set4Vector(momentum);
178  // set mass of stable charged particle to its nominal value
181  }
182  m_properties = properties;
183 
184  if (!daughterIndices.empty()) {
185  m_particleSource = c_Composite;
186  if (getArrayPointer() == nullptr) {
187  B2FATAL("Composite Particle (with daughters) was constructed outside StoreArray without specifying daughter array!");
188  }
189  }
190 }
191 
192 
194  const Const::ChargedStable& chargedStable) :
195  Particle(track ? track->getArrayIndex() : 0, track ? track->getTrackFitResultWithClosestMass(chargedStable) : nullptr,
196  chargedStable)
197 {
198 }
199 
200 Particle::Particle(const int trackArrayIndex,
201  const TrackFitResult* trackFit,
202  const Const::ChargedStable& chargedStable) :
203  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
204  m_pValue(-1), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0), m_arrayPointer(nullptr)
205 {
206  if (!trackFit) return;
207 
208  m_flavorType = c_Flavored; //tracks are charged
209  m_particleSource = c_Track;
210 
211  setMdstArrayIndex(trackArrayIndex);
212 
214  m_pdgCode = generatePDGCodeFromCharge(trackFit->getChargeSign(), chargedStable);
215 
216  // set mass
217  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr)
218  B2FATAL("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
219  m_mass = TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Mass() ;
220 
221  // set momentum, position and error matrix
223 }
224 
225 Particle::Particle(const ECLCluster* eclCluster, const Const::ParticleType& type) :
226  m_pdgCode(type.getPDGCode()), m_mass(type.getMass()), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
227  m_pValue(-1), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0), m_arrayPointer(nullptr)
228 {
229  if (!eclCluster) return;
230 
231  setFlavorType();
232 
233  // returns default vertex from clusterutils (from beam parameters if available)
234  // leave it like that for the moment to make it transparent
235  ClusterUtils C;
236  const XYZVector clustervertex = C.GetIPPosition();
237  setVertex(clustervertex);
238 
239  const PxPyPzEVector clustermom = C.Get4MomentumFromCluster(eclCluster, clustervertex, getECLClusterEHypothesisBit());
240  m_px = clustermom.Px();
241  m_py = clustermom.Py();
242  m_pz = clustermom.Pz();
243 
244  m_particleSource = c_ECLCluster;
245  setMdstArrayIndex(eclCluster->getArrayIndex());
246 
247  // set Chi^2 probability:
248  //TODO: gamma quality can be written here
249  m_pValue = 1;
250 
251  // get error matrix.
253 
254 }
255 
256 
258 {
259  ClusterUtils C;
260 
261  const ECLCluster* cluster = this->getECLCluster();
262 
263  const XYZVector clustervertex = C.GetIPPosition();
264 
265  // Get Jacobi matrix.
266  TMatrixD jacobi = C.GetJacobiMatrix4x6FromCluster(cluster, clustervertex, getECLClusterEHypothesisBit());
267  storeJacobiMatrix(jacobi);
268 
269  // Propagate the photon energy scaling to jacobian elements that were calculated using energy.
270  TMatrixD scaledJacobi(4, 6);
271 
272  int element = 0;
273 
274  for (int irow = 0; irow < 4; irow++) {
275  for (int icol = 0; icol < 6; icol++) {
276  if (icol != 0 && irow != 3) {
277  scaledJacobi(irow, icol) = m_jacobiMatrix[element] * m_momentumScale;
278  } else {
279  scaledJacobi(irow, icol) = m_jacobiMatrix[element];
280  }
281  element++;
282  }
283  }
284 
285  storeJacobiMatrix(scaledJacobi);
286 
287  // Get covariance matrix of IP distribution.
288  const TMatrixDSym clustervertexcovmat = C.GetIPPositionCovarianceMatrix();
289 
290  // Set error matrix.
291  TMatrixDSym clustercovmat = C.GetCovarianceMatrix7x7FromCluster(cluster, clustervertexcovmat, scaledJacobi);
292  storeErrorMatrix(clustercovmat);
293 }
294 
295 Particle::Particle(const KLMCluster* klmCluster, const int pdgCode) :
296  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
297  m_pValue(-1), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0), m_arrayPointer(nullptr)
298 {
299  if (!klmCluster) return;
300 
301  m_pdgCode = pdgCode;
302  setFlavorType();
303 
304  set4Vector(klmCluster->getMomentum());
305  setVertex(XYZVector(0, 0, 0)); // so far KLMCluster don't provide reliable / usable position information
306  updateMass(m_pdgCode); // KLMCluster internally use Klong mass, overwrite here to allow neutrons
307 
308  m_particleSource = c_KLMCluster;
309  setMdstArrayIndex(klmCluster->getArrayIndex());
310 
311  // set Chi^2 probability:
312  //TODO: KL quality can be written here
313  m_pValue = -1;
314 
315  // TODO: set error matrix
317  //storeErrorMatrix(klmCluster->getErrorMatrix());
318 }
319 
320 
321 Particle::Particle(const MCParticle* mcParticle) :
322  m_pdgCode(0), m_mass(0), m_px(0), m_py(0), m_pz(0), m_x(0), m_y(0), m_z(0),
323  m_pValue(-1), m_flavorType(c_Unflavored), m_particleSource(c_Undefined), m_mdstIndex(0), m_properties(0), m_arrayPointer(nullptr)
324 {
325  if (!mcParticle) return;
326 
327  m_pdgCode = mcParticle->getPDG();
328  m_particleSource = c_MCParticle; // TODO: what about daughters if not FS particle?
329 
330  setMdstArrayIndex(mcParticle->getArrayIndex());
331 
332 
333  setFlavorType();
334 
335  // mass and momentum
336  m_mass = mcParticle->getMass();
337  m_px = mcParticle->getMomentum().X();
338  m_py = mcParticle->getMomentum().Y();
339  m_pz = mcParticle->getMomentum().Z();
340  // production vertex
341  // TODO: good only for FS particles, for composite we must use decay vertex
342  setVertex(mcParticle->getVertex());
343 
345 }
346 
347 
348 Particle::~Particle() = default;
349 
350 void Particle::setMdstArrayIndex(const int arrayIndex)
351 {
352  m_mdstIndex = arrayIndex;
353 
354  // set the identifier
355  if (m_particleSource == c_ECLCluster) {
356  const ECLCluster* cluster = this->getECLCluster();
357  if (cluster) {
358  m_identifier = cluster->getUniqueClusterId();
359  } else {
360  B2ERROR("Particle is of type = ECLCluster has identifier not set and no relation to ECLCluster.\n"
361  "This has happen because old microDST is analysed with newer version of software.");
362  }
363  } else {
365  }
366 }
367 
368 
370 {
371  // Is identifier already set
372  if (m_identifier > -1)
373  return m_identifier + (m_particleSource << 24);
374 
375  // Identifier is not set.
376  int identifier = 0;
377  if (m_particleSource == c_ECLCluster) {
378  const ECLCluster* cluster = this->getECLCluster();
379  if (cluster) {
380  identifier = cluster->getUniqueClusterId();
381  } else {
382  B2ERROR("Particle is of type = ECLCluster has identifier not set and no relation to ECLCluster.\n"
383  "This has happen because old microDST is analysed with newer version of software.");
384  }
385  } else {
386  identifier = m_mdstIndex;
387  }
388 
389  return identifier + (m_particleSource << 24);
390 }
391 
392 
393 void Particle::setMomentumVertexErrorMatrix(const TMatrixFSym& m)
394 {
395  // check if provided Error Matrix is of dimension 7x7
396  // if not, reset the error matrix and print warning
397  if (m.GetNrows() != c_DimMatrix || m.GetNcols() != c_DimMatrix) {
399  B2WARNING("Error Matrix is not 7x7 ");
400  return;
401  }
402  storeErrorMatrix(m);
403 
404 }
405 
406 
407 void Particle::setJacobiMatrix(const TMatrixF& m)
408 {
409  // check if provided Jacobi Matrix is of dimension 4x6
410  // if not, reset the error matrix and print warning
411  if (m.GetNrows() != 4 || m.GetNcols() != 6) {
413  B2WARNING("Jacobi Matrix is not 4x6 ");
414  return;
415  }
417 }
418 
419 
421 {
422  TMatrixFSym m(c_DimMatrix);
423 
424  int element = 0;
425  for (int irow = 0; irow < c_DimMatrix; irow++) {
426  for (int icol = irow; icol < c_DimMatrix; icol++) {
427  m(irow, icol) = m(icol, irow) = m_errMatrix[element];
428  element++;
429  }
430  }
431  return m;
432 }
433 
434 
436 {
437  TMatrixFSym mom;
438  const TMatrixFSym& full = getMomentumVertexErrorMatrix();
439 
440  // get 4x4 (momentum) submatrix from the full error matrix
441  // momentum related elements are in [0,...,3]x[0,...,3] block
442  full.GetSub(0, 3, mom, "S");
443 
444  return mom;
445 }
446 
448 {
449  TMatrixFSym pos;
450  const TMatrixFSym& full = getMomentumVertexErrorMatrix();
451 
452  // get 3x3 (position) submatrix from the full error matrix
453  // vertex related elements are in [4,5,6]x[4,5,6] block
454  full.GetSub(4, 6, pos, "S");
455 
456  return pos;
457 }
458 
459 double Particle::getCosHelicity(const Particle* mother) const
460 {
461  // boost vector to the rest frame of the particle
462  Boost boost(get4Vector().BoostToCM());
463 
464  // momentum of the mother in the particle's rest frame
465  PxPyPzEVector pMother;
466  if (mother) {
467  pMother = mother->get4Vector();
468  } else {
469  static DBObjPtr<CollisionBoostVector> cmsBoost;
470  static DBObjPtr<CollisionInvariantMass> cmsMass;
471  pMother.SetE(cmsMass->getMass());
472  pMother = Boost(cmsBoost->getBoost()) * pMother;
473  }
474  pMother = boost * pMother;
475 
476  // momentum of the daughter (or normal vector) in the particle's rest frame
477  PxPyPzEVector pDaughter;
478  if (getNDaughters() == 2) { // two body decay
479  pDaughter = boost * getDaughter(0)->get4Vector();
480  } else if (getNDaughters() == 3) {
481  if (getPDGCode() == Const::pi0.getPDGCode()) { // pi0 Dalitz decay
482  for (auto& daughter : getDaughters()) {
483  if (daughter->getPDGCode() == Const::photon.getPDGCode()) {
484  pDaughter = daughter->get4Vector();
485  }
486  }
487  pDaughter = boost * pDaughter;
488  } else { // three body decay
489  PxPyPzEVector pDaughter0 = boost * getDaughter(0)->get4Vector();
490  PxPyPzEVector pDaughter1 = boost * getDaughter(1)->get4Vector();
491 
492  XYZVector pDaughterNormal(pDaughter0.Vect().Cross(pDaughter1.Vect()));
493  pDaughter.SetPxPyPzE(pDaughterNormal.X(), pDaughterNormal.Y(), pDaughterNormal.Z(), 0); // energy doesn't matter
494  }
495  }
496 
497  double mag2 = pMother.P2() * pDaughter.P2();
498  if (mag2 <= 0) return std::numeric_limits<double>::quiet_NaN();
499  return -pMother.Vect().Dot(pDaughter.Vect()) / sqrt(mag2);
500 }
501 
502 double Particle::getCosHelicityDaughter(unsigned iDaughter, unsigned iGrandDaughter) const
503 {
504  // check existence of daughter
505  if (getNDaughters() <= iDaughter) {
506  B2ERROR("No daughter of particle 'name' with index 'iDaughter' for calculation of helicity angle"
507  << LogVar("name", getName()) << LogVar("iDaughter", iDaughter));
508  return std::numeric_limits<double>::quiet_NaN();
509  }
510 
511  // boost vector to the rest frame of the daughter particle
512  const Particle* daughter = getDaughter(iDaughter);
513  Boost boost(daughter->get4Vector().BoostToCM());
514 
515  // momentum of the this particle in the daughter's rest frame
516  PxPyPzEVector pMother = boost * get4Vector();
517 
518  // check existence of grand daughter
519  if (daughter->getNDaughters() <= iGrandDaughter) {
520  B2ERROR("No grand daughter of daughter 'iDaughter' of particle 'name' with index 'iGrandDaughter' for calculation of helicity angle"
521  << LogVar("name", getName()) << LogVar("iDaughter", iDaughter) << LogVar("iGrandDaughter", iGrandDaughter));
522  return std::numeric_limits<double>::quiet_NaN();
523  }
524 
525  // momentum of the grand daughter in the daughter's rest frame
526  PxPyPzEVector pGrandDaughter = boost * daughter->getDaughter(iGrandDaughter)->get4Vector();
527 
528  double mag2 = pMother.P2() * pGrandDaughter.P2();
529  if (mag2 <= 0) return std::numeric_limits<double>::quiet_NaN();
530  return -pMother.Vect().Dot(pGrandDaughter.Vect()) / sqrt(mag2);
531 }
532 
534 {
535  // check that we have a decay to two daughters and then two grand daughters each
536  if (getNDaughters() != 2) {
537  B2ERROR("Cannot calculate acoplanarity of particle 'name' because the number of daughters is not 2"
538  << LogVar("name", getName()) << LogVar("# of daughters", getNDaughters()));
539  return std::numeric_limits<double>::quiet_NaN();
540  }
541  const Particle* daughter0 = getDaughter(0);
542  const Particle* daughter1 = getDaughter(1);
543  if ((daughter0->getNDaughters() != 2) || (daughter1->getNDaughters() != 2)) {
544  B2ERROR("Cannot calculate acoplanarity of particle 'name' because the number of grand daughters is not 2"
545  << LogVar("name", getName()) << LogVar("# of grand daughters of first daughter", daughter0->getNDaughters())
546  << LogVar("# of grand daughters of second daughter", daughter1->getNDaughters()));
547  return std::numeric_limits<double>::quiet_NaN();
548  }
549 
550  // boost vector to the rest frame of the particle
551  Boost boost(get4Vector().BoostToCM());
552 
553  // momenta of the daughters and grand daughters in the particle's rest frame
554  PxPyPzEVector pDaughter0 = boost * daughter0->get4Vector();
555  PxPyPzEVector pGrandDaughter0 = boost * daughter0->getDaughter(0)->get4Vector();
556  PxPyPzEVector pDaughter1 = boost * daughter1->get4Vector();
557  PxPyPzEVector pGrandDaughter1 = boost * daughter1->getDaughter(0)->get4Vector();
558 
559  // calculate angle between normal vectors
560  XYZVector normal0 = pDaughter0.Vect().Cross(pGrandDaughter0.Vect());
561  XYZVector normal1 = -pDaughter1.Vect().Cross(pGrandDaughter1.Vect());
562  double result = acos(normal0.Unit().Dot(normal1.Unit()));
563  if (normal0.Cross(normal1).Dot(pDaughter0.Vect()) < 0) result = -result;
564 
565  return result;
566 }
567 
568 
569 /*
570 double Particle::getMassError(void) const
571 {
572  double result = 0.0;
573 
574  if(m_pValue<0)
575  return result;
576 
577  double invMass = getMass();
578 
579  TMatrixFSym covarianceMatrix = getMomentumErrorMatrix();
580  TVectorF jacobian(c_DimMomentum);
581  jacobian[0] = -1.0*getPx()/invMass;
582  jacobian[1] = -1.0*getPy()/invMass;
583  jacobian[2] = -1.0*getPz()/invMass;
584  jacobian[3] = 1.0*getEnergy()/invMass;
585 
586  result = jacobian * (covarianceMatrix * jacobian);
587 
588  covarianceMatrix.Print();
589 
590  if(result<0.0)
591  result = 0.0;
592 
593  return TMath::Sqrt(result);
594 }
595 */
596 
597 void Particle::updateMass(const int pdgCode)
598 {
599  if (TDatabasePDG::Instance()->GetParticle(pdgCode) == nullptr)
600  B2FATAL("PDG=" << pdgCode << " ***code unknown to TDatabasePDG");
601  m_mass = TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass() ;
602 }
603 
604 double Particle::getPDGMass() const
605 {
606  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
607  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
608  return 0.0;
609  }
610  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Mass();
611 }
612 
614 {
615  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
616  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
617  return 0.0;
618  }
619  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Lifetime();
620 }
621 
622 double Particle::getCharge() const
623 {
624  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
625  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
626  return 0.0;
627  }
628  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Charge() / 3.0;
629 }
630 
631 const Particle* Particle::getDaughter(unsigned i) const
632 {
633  if (i >= getNDaughters()) return nullptr;
634  return static_cast<Particle*>(getArrayPointer()->At(m_daughterIndices[i]));
635 }
636 
637 std::vector<Belle2::Particle*> Particle::getDaughters() const
638 {
639  const unsigned int nDaughters = getNDaughters();
640  std::vector<Particle*> daughters(nDaughters);
641 
642  const TClonesArray* array = getArrayPointer();
643  for (unsigned i = 0; i < nDaughters; i++)
644  daughters[i] = static_cast<Particle*>(array->At(m_daughterIndices[i]));
645 
646  return daughters;
647 }
648 
649 std::vector<const Belle2::Particle*> Particle::getFinalStateDaughters() const
650 {
651  std::vector<const Particle*> fspDaughters;
652  fillFSPDaughters(fspDaughters);
653 
654  return fspDaughters;
655 }
656 
657 std::vector<const Belle2::Particle*> Particle::getAllDaughters() const
658 {
659  std::vector<const Particle*> allDaughters;
660  fillAllDaughters(allDaughters);
661 
662  return allDaughters;
663 }
664 
666 {
667  std::vector<int> mdstIndices;
668  for (const Particle* fsp : getFinalStateDaughters()) {
669  // is this FSP daughter constructed from given MDST source
670  if (fsp->getParticleSource() == source)
671  mdstIndices.push_back(fsp->getMdstArrayIndex());
672  }
673  return mdstIndices;
674 }
675 
676 void Particle::appendDaughter(const Particle* daughter, const bool updateType, const int daughterProperty)
677 {
678  if (updateType) {
679  // is it a composite particle or fsr corrected?
680  m_particleSource = c_Composite;
681  }
682 
683  // add daughter index
684  m_daughterIndices.push_back(daughter->getArrayIndex());
685  m_daughterProperties.push_back(daughterProperty);
686 }
687 
688 void Particle::removeDaughter(const Particle* daughter, const bool updateType)
689 {
690  if (getNDaughters() == 0)
691  return;
692 
693  for (unsigned i = 0; i < getNDaughters(); i++) {
694  if (m_daughterIndices[i] == daughter->getArrayIndex()) {
695  m_daughterIndices.erase(m_daughterIndices.begin() + i);
696  m_daughterProperties.erase(m_daughterProperties.begin() + i);
697  i--;
698  }
699  }
700 
701  if (getNDaughters() == 0 and updateType)
702  m_particleSource = c_Undefined;
703 }
704 
705 bool Particle::replaceDaughter(const Particle* oldDaughter, Particle* newDaughter)
706 {
707  int index = oldDaughter->getArrayIndex();
708 
709  for (unsigned i = 0; i < getNDaughters(); i++) {
710  if (m_daughterIndices[i] == index) {
711  auto ite_index = m_daughterIndices.erase(m_daughterIndices.begin() + i);
712  m_daughterIndices.insert(ite_index, newDaughter->getArrayIndex());
713  auto ite_property = m_daughterProperties.erase(m_daughterProperties.begin() + i);
714  m_daughterProperties.insert(ite_property, Particle::PropertyFlags::c_Ordinary);
715 
716  newDaughter->writeExtraInfo("original_index", index);
717  return true;
718  }
719  }
720  return false;
721 }
722 
723 bool Particle::replaceDaughterRecursively(const Particle* oldDaughter, Particle* newDaughter)
724 {
725  bool isReplaced = this->replaceDaughter(oldDaughter, newDaughter);
726  if (isReplaced)
727  return true;
728  for (auto& daughter : this->getDaughters()) {
729  isReplaced = daughter->replaceDaughterRecursively(oldDaughter, newDaughter);
730  if (isReplaced)
731  return true;
732  }
733  return false;
734 }
735 
736 
737 bool Particle::overlapsWith(const Particle* oParticle) const
738 {
739  // obtain vectors of daughter final state particles
740  std::vector<const Particle*> thisFSPs = this->getFinalStateDaughters();
741  std::vector<const Particle*> otherFSPs = oParticle->getFinalStateDaughters();
742 
743  // check if they share any of the FSPs
744  for (auto& thisFSP : thisFSPs)
745  for (auto& otherFSP : otherFSPs)
746  if (thisFSP->getMdstSource() == otherFSP->getMdstSource())
747  return true;
748 
749  return false;
750 }
751 
752 bool Particle::isCopyOf(const Particle* oParticle, bool doDetailedComparison) const
753 {
754  // the name of the game is to as quickly as possible determine
755  // that the Particles are not copies
756  if (this->getPDGCode() != oParticle->getPDGCode() and !doDetailedComparison)
757  return false;
758 
759  unsigned nDaughters = this->getNDaughters();
760  if (nDaughters != oParticle->getNDaughters())
761  return false;
762 
763  if (nDaughters) {
764  // has daughters: check if the decay chain is the same and it ends with
765  // the same FSPs
766  std::vector<int> thisDecayChain(nDaughters * 2);
767  std::vector<int> othrDecayChain(nDaughters * 2);
768 
769  for (unsigned i = 0; i < nDaughters; i++) {
770  this->getDaughter(i)->fillDecayChain(thisDecayChain);
771  oParticle->getDaughter(i)->fillDecayChain(othrDecayChain);
772  }
773 
774  // Even if the daughters have been provided in a different order in the
775  // decay string the particles should be identified as copies / duplicates.
776  // Therefore, the decay chain vectors, which contain both the pdg codes and
777  // the mdst sources, are sorted here before comparing them.
778  sort(thisDecayChain.begin(), thisDecayChain.end());
779  sort(othrDecayChain.begin(), othrDecayChain.end());
780 
781  for (unsigned i = 0; i < thisDecayChain.size(); i++)
782  if (thisDecayChain[i] != othrDecayChain[i])
783  return false;
784 
785  } else if (this->getMdstSource() != oParticle->getMdstSource() and !doDetailedComparison) {
786  // has no daughters: it's a FSP, compare MDST source and index
787  return false;
788  }
789  // Stop here if we do not want a detailed comparison
790  if (!doDetailedComparison)
791  return true;
792  //If we compare here a reconstructed Particle to a generated MCParticle
793  //it means that something went horribly wrong and we must stop
794  if ((this->getParticleSource() == EParticleSourceObject::c_MCParticle
795  and oParticle->getParticleSource() != EParticleSourceObject::c_MCParticle)
796  or (this->getParticleSource() != EParticleSourceObject::c_MCParticle
797  and oParticle->getParticleSource() == EParticleSourceObject::c_MCParticle)) {
798  B2WARNING("Something went wrong: MCParticle is being compared to a non MC Particle. Please check your script!\n"
799  " If the MCParticle <-> Particle comparison happens in the RestOfEventBuilder,\n"
800  " the Rest Of Event may contain signal side particles.");
801  return false;
802  }
803  if (this->getParticleSource() == EParticleSourceObject::c_MCParticle
804  and oParticle->getParticleSource() == EParticleSourceObject::c_MCParticle) {
805  return this->getMCParticle() == oParticle->getMCParticle();
806  }
807  if (this->getParticleSource() != oParticle->getParticleSource()) {
808  return false;
809  }
810  if (this->getMdstSource() == oParticle->getMdstSource()) {
811  return true;
812  }
813  if (this->getTrack() && oParticle->getTrack() &&
814  this->getTrack()->getArrayIndex() != oParticle->getTrack()->getArrayIndex()) {
815  return false;
816  }
817  if (this->getKLMCluster() && oParticle->getKLMCluster()
818  && this->getKLMCluster()->getArrayIndex() != oParticle->getKLMCluster()->getArrayIndex()) {
819  return false;
820  }
821 
822  // It can be a bit more complicated for ECLClusters as we might also have to ensure they are connected-region unique
823  if (this->getECLCluster() && oParticle->getECLCluster()
824  && this->getECLCluster()->getArrayIndex() != oParticle->getECLCluster()->getArrayIndex()) {
825 
826  // if either is a track then they must be different
827  if (this->getECLCluster()->isTrack() or oParticle->getECLCluster()->isTrack())
828  return false;
829 
830  // we cannot combine two particles of different hypotheses from the same
831  // connected region (as their energies overlap)
832  if (this->getECLClusterEHypothesisBit() == oParticle->getECLClusterEHypothesisBit())
833  return false;
834 
835  // in the rare case that both are neutral and the hypotheses are different,
836  // we must also check that they are from different connected regions
837  // otherwise they come from the "same" underlying ECLShower
838  if (this->getECLCluster()->getConnectedRegionId() != oParticle->getECLCluster()->getConnectedRegionId())
839  return false;
840  }
841  return true;
842 
843 }
844 
845 const Track* Particle::getTrack() const
846 {
847  if (m_particleSource == c_Track) {
848  StoreArray<Track> tracks{};
849  return tracks[m_mdstIndex];
850  } else
851  return nullptr;
852 }
853 
855 {
856  // if the particle is related to a TrackFitResult then return this
857  auto* selfrelated = this->getRelatedTo<TrackFitResult>();
858  if (selfrelated && !isnan(selfrelated->getPValue()))
859  return selfrelated;
860 
861  // if not get the TFR with closest mass to this particle
862  auto* selftrack = this->getTrack();
863  if (selftrack)
864  return selftrack->getTrackFitResultWithClosestMass(
865  Belle2::Const::ChargedStable(std::abs(this->getPDGCode())));
866 
867  // otherwise we're probably not a track based particle
868  return nullptr;
869 }
870 
872 {
873  if (m_particleSource == c_Track) {
874  StoreArray<Track> tracks{};
875  return tracks[m_mdstIndex]->getRelated<PIDLikelihood>();
876  } else
877  return nullptr;
878 }
879 
880 const V0* Particle::getV0() const
881 {
882  if (m_particleSource == c_V0) {
883  StoreArray<V0> v0s{};
884  return v0s[m_mdstIndex];
885  } else {
886  return nullptr;
887  }
888 }
889 
890 
892 {
893  if (m_particleSource == c_ECLCluster) {
894  StoreArray<ECLCluster> eclClusters{};
895  return eclClusters[m_mdstIndex];
896  } else if (m_particleSource == c_Track) {
897  // a track may be matched to several clusters under different hypotheses
898  // take the most energetic of the c_nPhotons hypothesis as "the" cluster
899  StoreArray<Track> tracks{};
900  const ECLCluster* bestTrackMatchedCluster = nullptr;
901  double highestEnergy = -1.0;
902  // loop over all clusters matched to this track
903  for (const ECLCluster& cluster : tracks[m_mdstIndex]->getRelationsTo<ECLCluster>()) {
904  // ignore everything except the nPhotons hypothesis
905  if (!cluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
906  continue;
907  // check if we're most energetic thus far
908  if (cluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons) > highestEnergy) {
909  highestEnergy = cluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
910  bestTrackMatchedCluster = &cluster;
911  }
912  }
913  return bestTrackMatchedCluster;
914  } else {
915  return nullptr;
916  }
917 }
918 
920 {
921  const ECLCluster* cluster = this->getECLCluster();
922  if (!cluster) return 0;
923  return cluster->getEnergy(this->getECLClusterEHypothesisBit());
924 }
925 
927 {
928  if (m_particleSource == c_KLMCluster) {
929  StoreArray<KLMCluster> klmClusters{};
930  return klmClusters[m_mdstIndex];
931  } else if (m_particleSource == c_Track) {
932  // If there is an associated KLMCluster, it's the closest one
933  StoreArray<Track> tracks{};
934  const KLMCluster* klmCluster = tracks[m_mdstIndex]->getRelatedTo<KLMCluster>();
935  return klmCluster;
936  } else {
937  return nullptr;
938  }
939 }
940 
941 
943 {
944  if (m_particleSource == c_MCParticle) {
945  StoreArray<MCParticle> mcParticles{};
946  return mcParticles[m_mdstIndex];
947  } else {
948  const MCParticle* related = this->getRelated<MCParticle>();
949  if (related)
950  return related;
951  }
952  return nullptr;
953 }
954 
955 
956 const Particle* Particle::getParticleFromGeneralizedIndexString(const std::string& generalizedIndex) const
957 {
958  // Split the generalizedIndex string in a vector of strings.
959  std::vector<std::string> generalizedIndexes;
960  boost::split(generalizedIndexes, generalizedIndex, boost::is_any_of(":"));
961 
962  if (generalizedIndexes.empty()) {
963  B2WARNING("Generalized index of daughter particle is empty. Skipping.");
964  return nullptr;
965  }
966 
967  // To explore a decay tree of unknown depth, we need a place to store
968  // both the root particle and the daughter particle at each iteration
969  const Particle* dauPart =
970  nullptr; // This will be eventually returned
971  const Particle* currentPart = this; // This is the root particle of the next iteration
972 
973  // Loop over the generalizedIndexes until you get to the particle you want
974  for (auto& indexString : generalizedIndexes) {
975  // indexString is a string. First try to convert it into an int
976  int dauIndex = 0;
977  try {
978  dauIndex = Belle2::convertString<int>(indexString);
979  } catch (std::invalid_argument&) {
980  B2WARNING("Found the string " << indexString << "instead of a daughter index.");
981  return nullptr;
982  }
983 
984  // Check that the daughter index is smaller than the number of daughters of the current root particle
985  if (dauIndex >= int(currentPart->getNDaughters()) or dauIndex < 0) {
986  B2WARNING("Daughter index out of range" << LogVar("Daughter index", dauIndex));
987  B2WARNING("Trying to access non-existing particle.");
988  return nullptr;
989  } else {
990  dauPart = currentPart->getDaughter(dauIndex); // Pick the particle indicated by the generalizedIndex
991  currentPart = dauPart;
992  }
993  }
994  return dauPart;
995 }
996 
997 
998 
999 //--- private methods --------------------------------------------
1000 
1002 {
1003  // set momentum
1004  m_px = trackFit->getMomentum().X();
1005  m_py = trackFit->getMomentum().Y();
1006  m_pz = trackFit->getMomentum().Z();
1007 
1008  // set position at which the momentum is given (= POCA)
1009  setVertex(trackFit->getPosition());
1010 
1011  // set Chi^2 probability
1012  m_pValue = trackFit->getPValue();
1013 
1014  // set error matrix
1015  const auto cov6 = trackFit->getCovariance6();
1016  constexpr unsigned order[] = {c_X, c_Y, c_Z, c_Px, c_Py, c_Pz};
1017 
1018  TMatrixFSym errMatrix(c_DimMatrix);
1019  for (int i = 0; i < 6; i++) {
1020  for (int j = i; j < 6; j++) {
1021  // although it seems to make no sense to fill all elements of the
1022  // symmetric matrix, it has to be (do not touch this code)
1023  errMatrix(order[j], order[i]) = errMatrix(order[i], order[j]) = cov6(i, j);
1024  }
1025  }
1026 
1027  /*
1028  E = sqrt(px^2 + py^2 + pz^2 + m^2) thus:
1029  cov(x,E) = cov(px,x) *dE/dpx + cov(py,x) *dE/dpy + cov(pz,x) *dE/dpz
1030  cov(y,E) = cov(px,y) *dE/dpx + cov(py,y) *dE/dpy + cov(pz,y) *dE/dpz
1031  cov(z,E) = cov(px,z) *dE/dpx + cov(py,z) *dE/dpy + cov(pz,z) *dE/dpz
1032  cov(px,E) = cov(px,px)*dE/dpx + cov(px,py)*dE/dpy + cov(px,pz)*dE/dpz
1033  cov(py,E) = cov(py,px)*dE/dpx + cov(py,py)*dE/dpy + cov(py,pz)*dE/dpz
1034  cov(pz,E) = cov(pz,px)*dE/dpx + cov(pz,py)*dE/dpy + cov(pz,pz)*dE/dpz
1035  cov(E,E) = cov(px,px)*(dE/dpx)^2 + cov(py,py)*(dE/dpy)^2 + cov(pz,pz)*(dE/dpz)^2
1036  + 2*cov(px,py)*dE/dpx*dE/dpy
1037  + 2*cov(py,pz)*dE/dpy*dE/dpz
1038  + 2*cov(pz,px)*dE/dpz*dE/dpx
1039  dE/dpx = px/E etc.
1040  */
1041 
1042  const double E = getEnergy();
1043  const double dEdp[] = {m_px / E, m_py / E, m_pz / E};
1044  constexpr unsigned compMom[] = {c_Px, c_Py, c_Pz};
1045  constexpr unsigned compPos[] = {c_X, c_Y, c_Z};
1046 
1047  // covariances (p,E)
1048  for (unsigned int i : compMom) {
1049  double Cov = 0;
1050  for (int k = 0; k < 3; k++) {
1051  Cov += errMatrix(i, compMom[k]) * dEdp[k];
1052  }
1053  errMatrix(i, c_E) = Cov;
1054  }
1055 
1056  // covariances (x,E)
1057  for (unsigned int comp : compPos) {
1058  double Cov = 0;
1059  for (int k = 0; k < 3; k++) {
1060  Cov += errMatrix(comp, compMom[k]) * dEdp[k];
1061  }
1062  errMatrix(c_E, comp) = Cov;
1063  }
1064 
1065  // variance (E,E)
1066  double Cov = 0;
1067  for (int i = 0; i < 3; i++) {
1068  Cov += errMatrix(compMom[i], compMom[i]) * dEdp[i] * dEdp[i];
1069  }
1070  for (int i = 0; i < 3; i++) {
1071  int k = (i + 1) % 3;
1072  Cov += 2 * errMatrix(compMom[i], compMom[k]) * dEdp[i] * dEdp[k];
1073  }
1074  errMatrix(c_E, c_E) = Cov;
1075 
1076  storeErrorMatrix(errMatrix);
1077 }
1078 
1080 {
1081  for (double& i : m_errMatrix)
1082  i = 0.0;
1083 }
1084 
1086 {
1087  for (double& i : m_jacobiMatrix)
1088  i = 0.0;
1089 }
1090 
1091 void Particle::storeErrorMatrix(const TMatrixFSym& m)
1092 {
1093  int element = 0;
1094  for (int irow = 0; irow < c_DimMatrix; irow++) {
1095  for (int icol = irow; icol < c_DimMatrix; icol++) {
1096  m_errMatrix[element] = m(irow, icol);
1097  element++;
1098  }
1099  }
1100 }
1101 
1102 void Particle::storeJacobiMatrix(const TMatrixF& m)
1103 {
1104  int element = 0;
1105  for (int irow = 0; irow < 4; irow++) {
1106  for (int icol = 0; icol < 6; icol++) {
1107  m_jacobiMatrix[element] = m(irow, icol);
1108  element++;
1109  }
1110  }
1111 }
1112 
1113 
1114 void Particle::fillFSPDaughters(std::vector<const Belle2::Particle*>& fspDaughters) const
1115 {
1116  // this is FSP
1117  if (getNDaughters() == 0) {
1118  fspDaughters.push_back(this);
1119  return;
1120  }
1121 
1122  // this is not FSP (go one level down)
1123  for (unsigned i = 0; i < getNDaughters(); i++)
1124  getDaughter(i)->fillFSPDaughters(fspDaughters);
1125 }
1126 
1127 void Particle::fillAllDaughters(std::vector<const Belle2::Particle*>& allDaughters) const
1128 {
1129  // this is FSP
1130  if (getNDaughters() == 0)
1131  return;
1132 
1133  // this is not FSP (fill it and go one level down)
1134  for (unsigned i = 0; i < getNDaughters(); i++) {
1135  allDaughters.push_back(getDaughter(i));
1136  getDaughter(i)->fillAllDaughters(allDaughters);
1137  }
1138 }
1139 
1140 void Particle::fillDecayChain(std::vector<int>& decayChain) const
1141 {
1142  decayChain.push_back(m_pdgCode);
1143  decayChain.push_back(getMdstSource());
1144 
1145  for (unsigned i = 0; i < getNDaughters(); i++)
1146  getDaughter(i)->fillDecayChain(decayChain);
1147 }
1148 
1149 
1151 {
1153  if (m_pdgCode < 0) return;
1154  if (m_pdgCode == Const::photon.getPDGCode()) {m_flavorType = c_Unflavored; return;} // gamma
1155  if (m_pdgCode == Const::Kshort.getPDGCode()) {m_flavorType = c_Unflavored; return;} // K_s
1156  if (m_pdgCode == Const::Klong.getPDGCode()) {m_flavorType = c_Unflavored; return;} // K_L
1157  if (m_pdgCode == 43) {m_flavorType = c_Unflavored; return;} // Xu0
1158  int nnn = m_pdgCode / 10;
1159  int q3 = nnn % 10; nnn /= 10;
1160  int q2 = nnn % 10; nnn /= 10;
1161  int q1 = nnn % 10;
1162  if (q1 == 0 && q2 == q3) m_flavorType = c_Unflavored; // unflavored meson
1163 }
1164 
1165 std::string Particle::getName() const
1166 {
1167  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->GetName();
1168 }
1169 
1170 void Particle::print() const
1171 {
1172  B2INFO(getInfo());
1173 }
1174 
1175 std::vector<std::string> Particle::getExtraInfoNames() const
1176 {
1177  std::vector<std::string> out;
1178  if (!m_extraInfo.empty()) {
1179  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1180  if (!extraInfoMap)
1181  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1182  const ParticleExtraInfoMap::IndexMap& map = extraInfoMap->getMap(m_extraInfo[0]);
1183  for (auto const& ee : map) out.push_back(ee.first);
1184  }
1185  return out;
1186 }
1187 
1188 std::string Particle::getInfoHTML() const
1189 {
1190  std::stringstream stream;
1191  stream << std::setprecision(4);
1192  stream << "<b>collection</b>=" << getArrayName();
1193  stream << "<br>";
1194  stream << " <b>PDGCode</b>=" << m_pdgCode;
1195  stream << " <b>Charge</b>=" << getCharge();
1196  stream << " <b>PDGMass</b>=" << getPDGMass();
1197  stream << "<br>";
1198  stream << " <b>flavorType</b>=" << m_flavorType;
1199  stream << " <b>particleSource</b>=" << m_particleSource;
1200  stream << " <b>particleTypeUsedForFit</b>=" << m_pdgCodeUsedForFit;
1201  stream << "<br>";
1202 
1203  stream << " <b>mdstIndex</b>=" << m_mdstIndex;
1204  stream << " <b>arrayIndex</b>=" << getArrayIndex();
1205  stream << " <b>identifier</b>=" << m_identifier;
1206  stream << " <b>daughterIndices</b>: ";
1207  for (int daughterIndex : m_daughterIndices) {
1208  stream << daughterIndex << ", ";
1209  }
1210  if (m_daughterIndices.empty()) stream << " (none)";
1211  stream << "<br>";
1212 
1213  if (!m_daughterIndices.empty()) {
1214  stream << " <b>daughter PDGCodes</b>: ";
1215  for (unsigned i = 0; i < m_daughterIndices.size(); i++) {
1216  const Particle* p = getDaughter(i);
1217  if (p) {stream << p->getPDGCode() << ", ";}
1218  else {stream << "?, ";}
1219  }
1220  stream << "<br>";
1221  }
1222 
1223  stream << " <b>mass</b>=" << m_mass;
1224  stream << "<br>";
1225 
1226  stream << " <b>momentum</b>=" << HTML::getString(ROOT::Math::XYZVector(getPx(), getPy(), getPz()));
1227  stream << " <b>p</b>=" << getP();
1228  stream << "<br>";
1229 
1230  stream << " <b>momentum scaling factor</b>=" << m_momentumScale;
1231  stream << "<br>";
1232 
1233  stream << " <b>Energy loss correction</b>=" << m_energyLossCorrection;
1234  stream << "<br>";
1235 
1236  stream << " <b>position</b>=" << HTML::getString(ROOT::Math::XYZVector(m_x, m_y, m_z));
1237  stream << "<br>";
1238 
1239  stream << " <b>p-value of fit</b> (if done): ";
1240  stream << m_pValue;
1241  stream << "<br>";
1242 
1243  stream << " <b>error matrix</b> (px, py, pz, E, x, y ,z):<br>";
1245 
1246  stream << " <b>extra info</b>=( ";
1247  if (!m_extraInfo.empty()) {
1248  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1249  if (!extraInfoMap) {
1250  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1251  }
1252  const ParticleExtraInfoMap::IndexMap& map = extraInfoMap->getMap(m_extraInfo[0]);
1253  const unsigned int nVars = m_extraInfo.size();
1254  for (const auto& pair : map) {
1255  if (pair.second < nVars) {
1256  stream << pair.first << "=" << m_extraInfo[pair.second] << " ";
1257  }
1258  }
1259 
1260  }
1261  stream << ") " << "<br>";
1262 
1263  return stream.str();
1264 }
1265 
1266 bool Particle::hasExtraInfo(const std::string& name) const
1267 {
1268  if (m_extraInfo.empty())
1269  return false;
1270 
1271  //get index for name
1272  const auto mapID = (unsigned int)m_extraInfo[0];
1273  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1274  if (!extraInfoMap) {
1275  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1276  }
1277  unsigned int index = extraInfoMap->getIndex(mapID, name);
1278  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1279  return false;
1280 
1281  return true;
1282 }
1283 
1285 {
1286  m_extraInfo.clear();
1287 }
1288 
1289 double Particle::getExtraInfo(const std::string& name) const
1290 {
1291  if (m_extraInfo.empty())
1292  throw std::runtime_error(std::string("getExtraInfo: Value '") + name + "' not found in Particle!");
1293 
1294  //get index for name
1295  const auto mapID = (unsigned int)m_extraInfo[0];
1296  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1297  if (!extraInfoMap) {
1298  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1299  }
1300  unsigned int index = extraInfoMap->getIndex(mapID, name);
1301  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1302  throw std::runtime_error(std::string("getExtraInfo: Value '") + name + "' not found in Particle!");
1303 
1304  return m_extraInfo[index];
1305 
1306 }
1307 
1308 void Particle::writeExtraInfo(const std::string& name, const double value)
1309 {
1310  if (this->hasExtraInfo(name)) {
1311  this->setExtraInfo(name, value);
1312  } else {
1313  this->addExtraInfo(name, value);
1314  }
1315 }
1316 
1317 void Particle::setExtraInfo(const std::string& name, double value)
1318 {
1319  if (m_extraInfo.empty())
1320  throw std::runtime_error(std::string("setExtraInfo: Value '") + name + "' not found in Particle!");
1321 
1322  //get index for name
1323  const auto mapID = (unsigned int)m_extraInfo[0];
1324  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1325  if (!extraInfoMap) {
1326  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1327  }
1328  unsigned int index = extraInfoMap->getIndex(mapID, name);
1329  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1330  throw std::runtime_error(std::string("setExtraInfo: Value '") + name + "' not found in Particle!");
1331 
1332  m_extraInfo[index] = value;
1333 
1334 }
1335 
1336 void Particle::addExtraInfo(const std::string& name, double value)
1337 {
1338  if (hasExtraInfo(name))
1339  throw std::runtime_error(std::string("addExtraInfo: Value '") + name + "' already set!");
1340 
1341  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1342  if (!extraInfoMap)
1343  extraInfoMap.create();
1344  if (m_extraInfo.empty()) {
1345  unsigned int mapID = extraInfoMap->getMapForNewVar(name);
1346  m_extraInfo.push_back(mapID);
1347  m_extraInfo.push_back(value);
1348  } else {
1349  unsigned int oldMapID = m_extraInfo[0];
1350  unsigned int insertIndex = m_extraInfo.size();
1351  unsigned int mapID = extraInfoMap->getMapForNewVar(name, oldMapID, insertIndex);
1352 
1353  m_extraInfo[0] = mapID; //update map
1354  m_extraInfo.push_back(value); //add value
1355  }
1356 }
1357 
1358 bool Particle::forEachDaughter(const std::function<bool(const Particle*)>& function,
1359  bool recursive, bool includeSelf) const
1360 {
1361  std::queue<const Particle*> qq;
1362  // If we include ourselves add only this, otherwise directly all children
1363  if (includeSelf) {
1364  qq.push(this);
1365  } else {
1366  for (size_t i = 0; i < getNDaughters(); ++i) qq.push(getDaughter(i));
1367  }
1368  // Now just repeat until done: take the child, run the functor, remove the
1369  // child, add all children if needed
1370  while (!qq.empty()) {
1371  const Particle* p = qq.front();
1372  if (function(p)) return true;
1373  qq.pop();
1374  // Add children if we go through all children recursively or if we look at
1375  // the current particle: we always want the direct children.
1376  if (recursive || p == this)
1377  for (size_t i = 0; i < p->getNDaughters(); ++i) qq.push(p->getDaughter(i));
1378  }
1379  return false;
1380 }
1381 
1382 int Particle::generatePDGCodeFromCharge(const int chargeSign, const Const::ChargedStable& chargedStable)
1383 {
1384  int absPDGCode = chargedStable.getPDGCode();
1385  int PDGCode = absPDGCode * chargeSign;
1386  // flip sign of PDG code for leptons: their PDG code is positive if the lepton charge is negative and vice versa
1387  if (chargedStable == Const::muon || chargedStable == Const::electron) PDGCode = -PDGCode;
1388  return PDGCode;
1389 }
1390 
1392 {
1393  const PIDLikelihood* likelihood = Particle::getPIDLikelihood();
1394  if (likelihood) return likelihood->getMostLikely().getPDGCode() == std::abs(m_pdgCode);
1395  else return false;
1396 }
1397 
1398 std::pair<Const::ChargedStable, const TrackFitResult*> Particle::getMostLikelyTrackFitResult() const
1399 {
1400 
1401  const auto track = this->getTrack();
1402 
1403  if (!track) {
1404  return std::make_pair(Const::ChargedStable(std::abs(this->getPDGCode())), nullptr);
1405  }
1406 
1407  // Find the track fit with the highest pValue
1408  auto trackFitResults = track->getTrackFitResults();
1409  auto it_maxPValue = std::max_element(std::begin(trackFitResults), std::end(trackFitResults),
1410  [](auto tfrAndM1, auto tfrAndM2) {return tfrAndM1.second->getPValue() < tfrAndM2.second->getPValue();});
1411 
1412  return trackFitResults[std::distance(std::begin(trackFitResults), it_maxPValue)];
1413 
1414 }
1415 
1417 {
1418  const auto trackFit = this->getTrackFitResult();
1419  if (!trackFit) return false;
1420 
1421  return (trackFit == this->getMostLikelyTrackFitResult().second);
1422 }
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:36
const TMatrixDSym GetCovarianceMatrix7x7FromCluster(const ECLCluster *cluster, const TMatrixD &jacobiMatrix)
Returns 7x7 covariance matrix (px, py, pz, E, x, y, z)
const ROOT::Math::PxPyPzEVector Get4MomentumFromCluster(const ECLCluster *cluster, ECLCluster::EHypothesisBit hypo)
Returns four momentum vector.
Definition: ClusterUtils.cc:25
const TMatrixD GetJacobiMatrix4x6FromCluster(const ECLCluster *cluster, ECLCluster::EHypothesisBit hypo)
Returns 4x6 Jacobi matrix (px, py, pz, E)
Definition: ClusterUtils.cc:54
const TMatrixDSym GetIPPositionCovarianceMatrix()
Returns default IP position covariance matrix from beam parameters.
const ROOT::Math::XYZVector GetIPPosition()
Returns default IP position from beam parameters.
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:580
The ParticleType class for identifying different particle types.
Definition: Const.h:399
int getPDGCode() const
PDG code.
Definition: Const.h:464
static const ParticleType pi0
neutral pion particle
Definition: Const.h:665
static const ChargedStable muon
muon particle
Definition: Const.h:651
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:609
static const ParticleType Klong
K^0_L particle.
Definition: Const.h:669
static const ParticleType Kshort
K^0_S particle.
Definition: Const.h:668
static const ParticleType photon
photon particle
Definition: Const.h:664
static const ChargedStable electron
electron particle
Definition: Const.h:650
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
ECL cluster data.
Definition: ECLCluster.h:27
bool isTrack() const
Return true if the cluster matches with track.
Definition: ECLCluster.h:235
int getConnectedRegionId() const
Return connected region id.
Definition: ECLCluster.h:250
@ c_nPhotons
CR is split into n photons (N1)
KLM cluster data.
Definition: KLMCluster.h:28
ROOT::Math::PxPyPzEVector getMomentum() const
Get momentum.
Definition: KLMCluster.cc:51
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
float getMass() const
Return the particle mass in GeV.
Definition: MCParticle.h:135
ROOT::Math::XYZVector getVertex() const
Return production vertex position, shorthand for getProductionVertex().
Definition: MCParticle.h:183
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:244
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:112
ROOT::Math::XYZVector getMomentum() const
Return momentum.
Definition: MCParticle.h:198
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:26
Const::ChargedStable getMostLikely(const double *fractions=0, Const::PIDDetectorSet set=Const::PIDDetectorSet::set()) const
Return most likely particle among chargedStableSet; if prior fractions not given equal prior probabil...
std::map< std::string, unsigned int > IndexMap
string -> index map.
Class to store reconstructed particles.
Definition: Particle.h:75
void removeExtraInfo()
Remove all stored extra info fields.
Definition: Particle.cc:1284
double getPx() const
Returns x component of momentum.
Definition: Particle.h:587
void updateJacobiMatrix()
Propagate the photon energy scaling to jacobian elements that were calculated using energy.
Definition: Particle.cc:257
TMatrixFSym getVertexErrorMatrix() const
Returns the 3x3 position error sub-matrix.
Definition: Particle.cc:447
bool isMostLikely() const
Returns true if the (track-based) particle is created with its most likely mass hypothesis based on P...
Definition: Particle.cc:1391
const KLMCluster * getKLMCluster() const
Returns the pointer to the KLMCluster object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:926
bool replaceDaughter(const Particle *oldDaughter, Particle *newDaughter)
Replace index of given daughter with new daughter, return true if a replacement is made.
Definition: Particle.cc:705
const Track * getTrack() const
Returns the pointer to the Track object that was used to create this Particle (ParticleType == c_Trac...
Definition: Particle.cc:845
void setMomentumPositionErrorMatrix(const TrackFitResult *trackFit)
Sets the momentum, position and error matrix for this particle (created from charged Track)
Definition: Particle.cc:1001
void storeErrorMatrix(const TMatrixFSym &errMatrix)
Stores 7x7 error matrix into private member m_errMatrix.
Definition: Particle.cc:1091
bool forEachDaughter(const std::function< bool(const Particle *)> &function, bool recursive=true, bool includeSelf=true) const
Apply a function to all daughters of this particle.
Definition: Particle.cc:1358
std::vector< const Belle2::Particle * > getFinalStateDaughters() const
Returns a vector of pointers to Final State daughter particles.
Definition: Particle.cc:649
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:942
void appendDaughter(const Particle *daughter, const bool updateType=true, const int daughterProperty=c_Ordinary)
Appends index of daughter to daughters index array.
Definition: Particle.cc:676
const ECLCluster * getECLCluster() const
Returns the pointer to the ECLCluster object that was used to create this Particle (if ParticleType =...
Definition: Particle.cc:891
void setExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1317
EParticleSourceObject
particle source enumerators
Definition: Particle.h:82
double m_pValue
chi^2 probability of the fit.
Definition: Particle.h:1069
double m_pz
momentum component z
Definition: Particle.h:1059
int m_pdgCodeUsedForFit
PDG code used for the track fit.
Definition: Particle.h:1055
double m_momentumScale
effective momentum scale factor
Definition: Particle.h:1060
std::string getName() const override
Return name of this particle.
Definition: Particle.cc:1165
bool overlapsWith(const Particle *oParticle) const
Returns true if final state ancestors of oParticle overlap.
Definition: Particle.cc:737
double getCosHelicityDaughter(unsigned iDaughter, unsigned iGrandDaughter=0) const
Returns cosine of the helicity angle of the given daughter defined by given grand daughter.
Definition: Particle.cc:502
TClonesArray * getArrayPointer() const
Returns the pointer to the store array which holds the daughter particles.
Definition: Particle.h:953
double getPz() const
Returns z component of momentum.
Definition: Particle.h:605
std::vector< std::string > getExtraInfoNames() const
get a list of the extra info names
Definition: Particle.cc:1175
bool isCopyOf(const Particle *oParticle, bool doDetailedComparison=false) const
Returns true if this Particle and oParticle are copies of each other.
Definition: Particle.cc:752
void writeExtraInfo(const std::string &name, const double value)
Sets the user defined extraInfo.
Definition: Particle.cc:1308
void setVertex(const ROOT::Math::XYZVector &vertex)
Sets position (decay vertex)
Definition: Particle.h:295
std::vector< int > getMdstArrayIndices(EParticleSourceObject type) const
Returns a vector of StoreArray indices of given MDST dataobjects.
Definition: Particle.cc:665
double m_jacobiMatrix[c_SizeMatrix]
error matrix (1D representation)
Definition: Particle.h:1068
void resetJacobiMatrix()
Resets 4x6 error matrix All elements are set to 0.0.
Definition: Particle.cc:1085
void storeJacobiMatrix(const TMatrixF &jacobiMatrix)
Stores 4x6 Jacobi matrix into private member m_jacobiMatrix.
Definition: Particle.cc:1102
bool isMostLikelyTrackFitResult() const
Returns true if the (track-based) particle is created with its most likely mass hypothesis based on T...
Definition: Particle.cc:1416
std::vector< double > m_extraInfo
Stores associated user defined values.
Definition: Particle.h:1091
unsigned m_mdstIndex
0-based index of MDST store array object
Definition: Particle.h:1073
void setFlavorType()
sets m_flavorType using m_pdgCode
Definition: Particle.cc:1150
double getEnergy() const
Returns total energy.
Definition: Particle.h:535
int getMdstSource() const
Returns unique identifier of final state particle (needed in particle combiner)
Definition: Particle.cc:369
void fillAllDaughters(std::vector< const Belle2::Particle * > &allDaughters) const
Fill all generations' daughters into a vector.
Definition: Particle.cc:1127
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1266
std::string getInfoHTML() const override
Return a short summary of this object's contents in HTML format.
Definition: Particle.cc:1188
void setMdstArrayIndex(const int arrayIndex)
set mdst array index
Definition: Particle.cc:350
const Particle * getParticleFromGeneralizedIndexString(const std::string &generalizedIndex) const
Explores the decay tree of the particle and returns the (grand^n)daughter identified by a generalized...
Definition: Particle.cc:956
double m_py
momentum component y
Definition: Particle.h:1058
double m_x
position component x
Definition: Particle.h:1064
double m_px
momentum component x
Definition: Particle.h:1057
std::pair< Const::ChargedStable, const TrackFitResult * > getMostLikelyTrackFitResult() const
For a (track-based) particle, returns the charged stable mass hypothesis associated to the most proba...
Definition: Particle.cc:1398
~Particle()
Destructor.
void fillFSPDaughters(std::vector< const Belle2::Particle * > &fspDaughters) const
Fill final state particle daughters into a vector.
Definition: Particle.cc:1114
const PIDLikelihood * getPIDLikelihood() const
Returns the pointer to the PIDLikelihood object that is related to the Track, which was used to creat...
Definition: Particle.cc:871
const V0 * getV0() const
Returns the pointer to the V0 object that was used to create this Particle (if ParticleType == c_V0).
Definition: Particle.cc:880
EParticleSourceObject m_particleSource
(mdst) source of particle
Definition: Particle.h:1072
void fillDecayChain(std::vector< int > &decayChain) const
Fill vector with (PDGCode, MdstSource) pairs for the entire decay chain.
Definition: Particle.cc:1140
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:454
double getPy() const
Returns y component of momentum.
Definition: Particle.h:596
double getCosHelicity(const Particle *mother=nullptr) const
Returns cosine of the helicity angle The helicity angle is defined in the rest frame of the particle ...
Definition: Particle.cc:459
unsigned getNDaughters(void) const
Returns number of daughter particles.
Definition: Particle.h:727
std::vector< Belle2::Particle * > getDaughters() const
Returns a vector of pointers to daughter particles.
Definition: Particle.cc:637
void resetErrorMatrix()
Resets 7x7 error matrix All elements are set to 0.0.
Definition: Particle.cc:1079
double getPDGMass(void) const
Returns uncertainty on the invariant mass (requires valid momentum error matrix)
Definition: Particle.cc:604
EFlavorType m_flavorType
flavor type.
Definition: Particle.h:1071
double m_energyLossCorrection
energy loss correction.
Definition: Particle.h:1063
int generatePDGCodeFromCharge(const int chargedSign, const Const::ChargedStable &chargedStable)
Generate the PDG code with correct sign, using the charge.
Definition: Particle.cc:1382
double getCharge(void) const
Returns particle charge.
Definition: Particle.cc:622
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:547
Particle()
Default constructor.
Definition: Particle.cc:45
TMatrixFSym getMomentumErrorMatrix() const
Returns the 4x4 momentum error matrix.
Definition: Particle.cc:435
double m_mass
particle (invariant) mass
Definition: Particle.h:1056
std::vector< const Belle2::Particle * > getAllDaughters() const
Returns a vector of pointers to all generations' daughter particles.
Definition: Particle.cc:657
double getAcoplanarity() const
Returns acoplanarity angle defined as the angle between the decay planes of the grand daughters in th...
Definition: Particle.cc:533
std::vector< int > m_daughterProperties
daughter particle properties
Definition: Particle.h:1075
double m_errMatrix[c_SizeMatrix]
error matrix (1D representation)
Definition: Particle.h:1067
std::vector< int > m_daughterIndices
daughter particle indices
Definition: Particle.h:1070
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1336
void set4Vector(const ROOT::Math::PxPyPzEVector &p4)
Sets Lorentz vector.
Definition: Particle.h:271
void setJacobiMatrix(const TMatrixF &jacobiMatrix)
Sets 4x6 jacobi matrix.
Definition: Particle.cc:407
double getPDGLifetime() const
Returns particle nominal lifetime.
Definition: Particle.cc:613
void setMomentumVertexErrorMatrix(const TMatrixFSym &errMatrix)
Sets 7x7 error matrix.
Definition: Particle.cc:393
EParticleSourceObject getParticleSource() const
Returns particle source as defined with enum EParticleSourceObject.
Definition: Particle.h:478
void updateMass(const int pdgCode)
Updates particle mass with the mass of the particle corresponding to the given PDG.
Definition: Particle.cc:597
double m_z
position component z
Definition: Particle.h:1066
void print() const
Prints the contents of a Particle object to standard output.
Definition: Particle.cc:1170
EFlavorType
describes flavor type, see getFlavorType().
Definition: Particle.h:94
@ c_Unflavored
Is its own antiparticle or we don't know whether it is a particle/antiparticle.
Definition: Particle.h:95
@ c_Flavored
Is either particle or antiparticle.
Definition: Particle.h:96
int m_pdgCode
PDG code.
Definition: Particle.h:1054
TMatrixFSym getMomentumVertexErrorMatrix() const
Returns 7x7 error matrix.
Definition: Particle.cc:420
double getECLClusterEnergy() const
Returns the energy of the ECLCluster for the particle.
Definition: Particle.cc:919
const TrackFitResult * getTrackFitResult() const
Returns the pointer to the TrackFitResult that was used to create this Particle (ParticleType == c_Tr...
Definition: Particle.cc:854
void removeDaughter(const Particle *daughter, const bool updateType=true)
Removes index of daughter from daughters index array.
Definition: Particle.cc:688
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)
Definition: Particle.h:578
double m_y
position component y
Definition: Particle.h:1065
int m_identifier
Identifier that can be used to identify whether the particle is unique or is a copy or representation...
Definition: Particle.h:1084
int m_properties
particle property
Definition: Particle.h:1074
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:631
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1289
ECLCluster::EHypothesisBit getECLClusterEHypothesisBit() const
Returns the ECLCluster EHypothesisBit for this Particle.
Definition: Particle.h:1001
bool replaceDaughterRecursively(const Particle *oldDaughter, Particle *newDaughter)
Apply replaceDaughter to all Particles in the decay tree by looping recursively through it,...
Definition: Particle.cc:723
std::string getArrayName() const
Get name of array this object is stored in, or "" if not found.
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
std::string getInfo() const
Return a short summary of this object's contents in raw text format.
TO * getRelatedTo(const std::string &name="", const std::string &namedRelation="") const
Get the object to which this object has a relation.
bool create(bool replace=false)
Create a default object in the data store.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
double getPValue() const
Getter for Chi2 Probability of the track fit.
TMatrixDSym getCovariance6() const
Position and Momentum Covariance Matrix.
Const::ParticleType getParticleType() const
Getter for ParticleType of the mass hypothesis of the track fit.
ROOT::Math::XYZVector getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
ROOT::Math::XYZVector getPosition() const
Getter for vector of position at closest approach of track in r/phi projection.
Class that bundles various TrackFitResults.
Definition: Track.h:25
Object holding information for V0s.
Definition: V0.h:34
Class to store variables with their name which were sent to the logging service.
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:24