Belle II Software  release-08-01-10
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 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 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 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 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 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  const int crid = cluster->getConnectedRegionId();
359  const int clusterid = cluster->getClusterId();
360  m_identifier = 1000 * crid + clusterid;
361  } else {
362  B2ERROR("Particle is of type = ECLCluster has identifier not set and no relation to ECLCluster.\n"
363  "This has happen because old microDST is analysed with newer version of software.");
364  }
365  } else {
367  }
368 }
369 
370 
372 {
373  // Is identifier already set
374  if (m_identifier > -1)
375  return m_identifier + (m_particleSource << 24);
376 
377  // Identifier is not set.
378  int identifier = 0;
379  if (m_particleSource == c_ECLCluster) {
380  const ECLCluster* cluster = this->getECLCluster();
381  if (cluster) {
382  const int crid = cluster->getConnectedRegionId();
383  const int clusterid = cluster->getClusterId();
384  identifier = 1000 * crid + clusterid;
385  } else {
386  B2ERROR("Particle is of type = ECLCluster has identifier not set and no relation to ECLCluster.\n"
387  "This has happen because old microDST is analysed with newer version of software.");
388  }
389  } else {
390  identifier = m_mdstIndex;
391  }
392 
393  return identifier + (m_particleSource << 24);
394 }
395 
396 
397 void Particle::setMomentumVertexErrorMatrix(const TMatrixFSym& m)
398 {
399  // check if provided Error Matrix is of dimension 7x7
400  // if not, reset the error matrix and print warning
401  if (m.GetNrows() != c_DimMatrix || m.GetNcols() != c_DimMatrix) {
403  B2WARNING("Error Matrix is not 7x7 ");
404  return;
405  }
406  storeErrorMatrix(m);
407 
408 }
409 
410 
411 void Particle::setJacobiMatrix(const TMatrixF& m)
412 {
413  // check if provided Jacobi Matrix is of dimension 4x6
414  // if not, reset the error matrix and print warning
415  if (m.GetNrows() != 4 || m.GetNcols() != 6) {
417  B2WARNING("Jacobi Matrix is not 4x6 ");
418  return;
419  }
421 }
422 
423 
425 {
426  TMatrixFSym m(c_DimMatrix);
427 
428  int element = 0;
429  for (int irow = 0; irow < c_DimMatrix; irow++) {
430  for (int icol = irow; icol < c_DimMatrix; icol++) {
431  m(irow, icol) = m(icol, irow) = m_errMatrix[element];
432  element++;
433  }
434  }
435  return m;
436 }
437 
438 
440 {
441  TMatrixFSym mom;
442  const TMatrixFSym& full = getMomentumVertexErrorMatrix();
443 
444  // get 4x4 (momentum) submatrix from the full error matrix
445  // momentum related elements are in [0,...,3]x[0,...,3] block
446  full.GetSub(0, 3, mom, "S");
447 
448  return mom;
449 }
450 
452 {
453  TMatrixFSym pos;
454  const TMatrixFSym& full = getMomentumVertexErrorMatrix();
455 
456  // get 3x3 (position) submatrix from the full error matrix
457  // vertex related elements are in [4,5,6]x[4,5,6] block
458  full.GetSub(4, 6, pos, "S");
459 
460  return pos;
461 }
462 
463 double Particle::getCosHelicity(const Particle* mother) const
464 {
465  // boost vector to the rest frame of the particle
466  Boost boost(get4Vector().BoostToCM());
467 
468  // momentum of the mother in the particle's rest frame
469  PxPyPzEVector pMother;
470  if (mother) {
471  pMother = mother->get4Vector();
472  } else {
473  static DBObjPtr<CollisionBoostVector> cmsBoost;
474  static DBObjPtr<CollisionInvariantMass> cmsMass;
475  pMother.SetE(cmsMass->getMass());
476  pMother = Boost(cmsBoost->getBoost()) * pMother;
477  }
478  pMother = boost * pMother;
479 
480  // momentum of the daughter (or normal vector) in the particle's rest frame
481  PxPyPzEVector pDaughter;
482  if (getNDaughters() == 2) { // two body decay
483  pDaughter = boost * getDaughter(0)->get4Vector();
484  } else if (getNDaughters() == 3) {
485  if (getPDGCode() == Const::pi0.getPDGCode()) { // pi0 Dalitz decay
486  for (auto& daughter : getDaughters()) {
487  if (daughter->getPDGCode() == Const::photon.getPDGCode()) {
488  pDaughter = daughter->get4Vector();
489  }
490  }
491  pDaughter = boost * pDaughter;
492  } else { // three body decay
493  PxPyPzEVector pDaughter0 = boost * getDaughter(0)->get4Vector();
494  PxPyPzEVector pDaughter1 = boost * getDaughter(1)->get4Vector();
495 
496  XYZVector pDaughterNormal(pDaughter0.Vect().Cross(pDaughter1.Vect()));
497  pDaughter.SetPxPyPzE(pDaughterNormal.X(), pDaughterNormal.Y(), pDaughterNormal.Z(), 0); // energy doesn't matter
498  }
499  }
500 
501  double mag2 = pMother.P2() * pDaughter.P2();
502  if (mag2 <= 0) return std::numeric_limits<double>::quiet_NaN();
503  return -pMother.Vect().Dot(pDaughter.Vect()) / sqrt(mag2);
504 }
505 
506 double Particle::getCosHelicityDaughter(unsigned iDaughter, unsigned iGrandDaughter) const
507 {
508  // check existence of daughter
509  if (getNDaughters() <= iDaughter) {
510  B2ERROR("No daughter of particle 'name' with index 'iDaughter' for calculation of helicity angle"
511  << LogVar("name", getName()) << LogVar("iDaughter", iDaughter));
512  return std::numeric_limits<double>::quiet_NaN();
513  }
514 
515  // boost vector to the rest frame of the daughter particle
516  const Particle* daughter = getDaughter(iDaughter);
517  Boost boost(daughter->get4Vector().BoostToCM());
518 
519  // momentum of the this particle in the daughter's rest frame
520  PxPyPzEVector pMother = boost * get4Vector();
521 
522  // check existence of grand daughter
523  if (daughter->getNDaughters() <= iGrandDaughter) {
524  B2ERROR("No grand daughter of daughter 'iDaughter' of particle 'name' with index 'iGrandDaughter' for calculation of helicity angle"
525  << LogVar("name", getName()) << LogVar("iDaughter", iDaughter) << LogVar("iGrandDaughter", iGrandDaughter));
526  return std::numeric_limits<double>::quiet_NaN();
527  }
528 
529  // momentum of the grand daughter in the daughter's rest frame
530  PxPyPzEVector pGrandDaughter = boost * daughter->getDaughter(iGrandDaughter)->get4Vector();
531 
532  double mag2 = pMother.P2() * pGrandDaughter.P2();
533  if (mag2 <= 0) return std::numeric_limits<double>::quiet_NaN();
534  return -pMother.Vect().Dot(pGrandDaughter.Vect()) / sqrt(mag2);
535 }
536 
538 {
539  // check that we have a decay to two daughters and then two grand daughters each
540  if (getNDaughters() != 2) {
541  B2ERROR("Cannot calculate acoplanarity of particle 'name' because the number of daughters is not 2"
542  << LogVar("name", getName()) << LogVar("# of daughters", getNDaughters()));
543  return std::numeric_limits<double>::quiet_NaN();
544  }
545  const Particle* daughter0 = getDaughter(0);
546  const Particle* daughter1 = getDaughter(1);
547  if ((daughter0->getNDaughters() != 2) || (daughter1->getNDaughters() != 2)) {
548  B2ERROR("Cannot calculate acoplanarity of particle 'name' because the number of grand daughters is not 2"
549  << LogVar("name", getName()) << LogVar("# of grand daughters of first daughter", daughter0->getNDaughters())
550  << LogVar("# of grand daughters of second daughter", daughter1->getNDaughters()));
551  return std::numeric_limits<double>::quiet_NaN();
552  }
553 
554  // boost vector to the rest frame of the particle
555  Boost boost(get4Vector().BoostToCM());
556 
557  // momenta of the daughters and grand daughters in the particle's rest frame
558  PxPyPzEVector pDaughter0 = boost * daughter0->get4Vector();
559  PxPyPzEVector pGrandDaughter0 = boost * daughter0->getDaughter(0)->get4Vector();
560  PxPyPzEVector pDaughter1 = boost * daughter1->get4Vector();
561  PxPyPzEVector pGrandDaughter1 = boost * daughter1->getDaughter(0)->get4Vector();
562 
563  // calculate angle between normal vectors
564  XYZVector normal0 = pDaughter0.Vect().Cross(pGrandDaughter0.Vect());
565  XYZVector normal1 = -pDaughter1.Vect().Cross(pGrandDaughter1.Vect());
566  double result = acos(normal0.Unit().Dot(normal1.Unit()));
567  if (normal0.Cross(normal1).Dot(pDaughter0.Vect()) < 0) result = -result;
568 
569  return result;
570 }
571 
572 
573 /*
574 double Particle::getMassError(void) const
575 {
576  double result = 0.0;
577 
578  if(m_pValue<0)
579  return result;
580 
581  double invMass = getMass();
582 
583  TMatrixFSym covarianceMatrix = getMomentumErrorMatrix();
584  TVectorF jacobian(c_DimMomentum);
585  jacobian[0] = -1.0*getPx()/invMass;
586  jacobian[1] = -1.0*getPy()/invMass;
587  jacobian[2] = -1.0*getPz()/invMass;
588  jacobian[3] = 1.0*getEnergy()/invMass;
589 
590  result = jacobian * (covarianceMatrix * jacobian);
591 
592  covarianceMatrix.Print();
593 
594  if(result<0.0)
595  result = 0.0;
596 
597  return TMath::Sqrt(result);
598 }
599 */
600 
601 void Particle::updateMass(const int pdgCode)
602 {
603  if (TDatabasePDG::Instance()->GetParticle(pdgCode) == nullptr)
604  B2FATAL("PDG=" << pdgCode << " ***code unknown to TDatabasePDG");
605  m_mass = TDatabasePDG::Instance()->GetParticle(pdgCode)->Mass() ;
606 }
607 
608 double Particle::getPDGMass() const
609 {
610  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
611  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
612  return 0.0;
613  }
614  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Mass();
615 }
616 
618 {
619  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
620  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
621  return 0.0;
622  }
623  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Lifetime();
624 }
625 
626 double Particle::getCharge() const
627 {
628  if (TDatabasePDG::Instance()->GetParticle(m_pdgCode) == nullptr) {
629  B2ERROR("PDG=" << m_pdgCode << " ***code unknown to TDatabasePDG");
630  return 0.0;
631  }
632  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->Charge() / 3.0;
633 }
634 
635 const Particle* Particle::getDaughter(unsigned i) const
636 {
637  if (i >= getNDaughters()) return nullptr;
638  return static_cast<Particle*>(getArrayPointer()->At(m_daughterIndices[i]));
639 }
640 
641 std::vector<Belle2::Particle*> Particle::getDaughters() const
642 {
643  const unsigned int nDaughters = getNDaughters();
644  std::vector<Particle*> daughters(nDaughters);
645 
646  const TClonesArray* array = getArrayPointer();
647  for (unsigned i = 0; i < nDaughters; i++)
648  daughters[i] = static_cast<Particle*>(array->At(m_daughterIndices[i]));
649 
650  return daughters;
651 }
652 
653 std::vector<const Belle2::Particle*> Particle::getFinalStateDaughters() const
654 {
655  std::vector<const Particle*> fspDaughters;
656  fillFSPDaughters(fspDaughters);
657 
658  return fspDaughters;
659 }
660 
661 std::vector<const Belle2::Particle*> Particle::getAllDaughters() const
662 {
663  std::vector<const Particle*> allDaughters;
664  fillAllDaughters(allDaughters);
665 
666  return allDaughters;
667 }
668 
670 {
671  std::vector<int> mdstIndices;
672  for (const Particle* fsp : getFinalStateDaughters()) {
673  // is this FSP daughter constructed from given MDST source
674  if (fsp->getParticleSource() == source)
675  mdstIndices.push_back(fsp->getMdstArrayIndex());
676  }
677  return mdstIndices;
678 }
679 
680 void Particle::appendDaughter(const Particle* daughter, const bool updateType, const int daughterProperty)
681 {
682  if (updateType) {
683  // is it a composite particle or fsr corrected?
684  m_particleSource = c_Composite;
685  }
686 
687  // add daughter index
688  m_daughterIndices.push_back(daughter->getArrayIndex());
689  m_daughterProperties.push_back(daughterProperty);
690 }
691 
692 void Particle::removeDaughter(const Particle* daughter, const bool updateType)
693 {
694  if (getNDaughters() == 0)
695  return;
696 
697  for (unsigned i = 0; i < getNDaughters(); i++) {
698  if (m_daughterIndices[i] == daughter->getArrayIndex()) {
699  m_daughterIndices.erase(m_daughterIndices.begin() + i);
700  m_daughterProperties.erase(m_daughterProperties.begin() + i);
701  i--;
702  }
703  }
704 
705  if (getNDaughters() == 0 and updateType)
706  m_particleSource = c_Undefined;
707 }
708 
709 bool Particle::replaceDaughter(const Particle* oldDaughter, Particle* newDaughter)
710 {
711  int index = oldDaughter->getArrayIndex();
712 
713  for (unsigned i = 0; i < getNDaughters(); i++) {
714  if (m_daughterIndices[i] == index) {
715  auto ite_index = m_daughterIndices.erase(m_daughterIndices.begin() + i);
716  m_daughterIndices.insert(ite_index, newDaughter->getArrayIndex());
717  auto ite_property = m_daughterProperties.erase(m_daughterProperties.begin() + i);
718  m_daughterProperties.insert(ite_property, Particle::PropertyFlags::c_Ordinary);
719 
720  newDaughter->writeExtraInfo("original_index", index);
721  return true;
722  }
723  }
724  return false;
725 }
726 
727 bool Particle::replaceDaughterRecursively(const Particle* oldDaughter, Particle* newDaughter)
728 {
729  bool isReplaced = this->replaceDaughter(oldDaughter, newDaughter);
730  if (isReplaced)
731  return true;
732  for (auto& daughter : this->getDaughters()) {
733  isReplaced = daughter->replaceDaughterRecursively(oldDaughter, newDaughter);
734  if (isReplaced)
735  return true;
736  }
737  return false;
738 }
739 
740 
741 bool Particle::overlapsWith(const Particle* oParticle) const
742 {
743  // obtain vectors of daughter final state particles
744  std::vector<const Particle*> thisFSPs = this->getFinalStateDaughters();
745  std::vector<const Particle*> otherFSPs = oParticle->getFinalStateDaughters();
746 
747  // check if they share any of the FSPs
748  for (auto& thisFSP : thisFSPs)
749  for (auto& otherFSP : otherFSPs)
750  if (thisFSP->getMdstSource() == otherFSP->getMdstSource())
751  return true;
752 
753  return false;
754 }
755 
756 bool Particle::isCopyOf(const Particle* oParticle, bool doDetailedComparison) const
757 {
758  // the name of the game is to as quickly as possible determine
759  // that the Particles are not copies
760  if (this->getPDGCode() != oParticle->getPDGCode() and !doDetailedComparison)
761  return false;
762 
763  unsigned nDaughters = this->getNDaughters();
764  if (nDaughters != oParticle->getNDaughters())
765  return false;
766 
767  if (nDaughters) {
768  // has daughters: check if the decay chain is the same and it ends with
769  // the same FSPs
770  std::vector<int> thisDecayChain(nDaughters * 2);
771  std::vector<int> othrDecayChain(nDaughters * 2);
772 
773  for (unsigned i = 0; i < nDaughters; i++) {
774  this->getDaughter(i)->fillDecayChain(thisDecayChain);
775  oParticle->getDaughter(i)->fillDecayChain(othrDecayChain);
776  }
777 
778  // Even if the daughters have been provided in a different order in the
779  // decay string the particles should be identified as copies / duplicates.
780  // Therefore, the decay chain vectors, which contain both the pdg codes and
781  // the mdst sources, are sorted here before comparing them.
782  sort(thisDecayChain.begin(), thisDecayChain.end());
783  sort(othrDecayChain.begin(), othrDecayChain.end());
784 
785  for (unsigned i = 0; i < thisDecayChain.size(); i++)
786  if (thisDecayChain[i] != othrDecayChain[i])
787  return false;
788 
789  } else if (this->getMdstSource() != oParticle->getMdstSource() and !doDetailedComparison) {
790  // has no daughters: it's a FSP, compare MDST source and index
791  return false;
792  }
793  // Stop here if we do not want a detailed comparison
794  if (!doDetailedComparison)
795  return true;
796  //If we compare here a reconstructed Particle to a generated MCParticle
797  //it means that something went horribly wrong and we must stop
798  if ((this->getParticleSource() == EParticleSourceObject::c_MCParticle
799  and oParticle->getParticleSource() != EParticleSourceObject::c_MCParticle)
800  or (this->getParticleSource() != EParticleSourceObject::c_MCParticle
801  and oParticle->getParticleSource() == EParticleSourceObject::c_MCParticle)) {
802  B2WARNING("Something went wrong: MCParticle is being compared to a non MC Particle. Please check your script!\n"
803  " If the MCParticle <-> Particle comparison happens in the RestOfEventBuilder,\n"
804  " the Rest Of Event may contain signal side particles.");
805  return false;
806  }
807  if (this->getParticleSource() == EParticleSourceObject::c_MCParticle
808  and oParticle->getParticleSource() == EParticleSourceObject::c_MCParticle) {
809  return this->getMCParticle() == oParticle->getMCParticle();
810  }
811  if (this->getParticleSource() != oParticle->getParticleSource()) {
812  return false;
813  }
814  if (this->getMdstSource() == oParticle->getMdstSource()) {
815  return true;
816  }
817  if (this->getTrack() && oParticle->getTrack() &&
818  this->getTrack()->getArrayIndex() != oParticle->getTrack()->getArrayIndex()) {
819  return false;
820  }
821  if (this->getKLMCluster() && oParticle->getKLMCluster()
822  && this->getKLMCluster()->getArrayIndex() != oParticle->getKLMCluster()->getArrayIndex()) {
823  return false;
824  }
825 
826  // It can be a bit more complicated for ECLClusters as we might also have to ensure they are connected-region unique
827  if (this->getECLCluster() && oParticle->getECLCluster()
828  && this->getECLCluster()->getArrayIndex() != oParticle->getECLCluster()->getArrayIndex()) {
829 
830  // if either is a track then they must be different
831  if (this->getECLCluster()->isTrack() or oParticle->getECLCluster()->isTrack())
832  return false;
833 
834  // we cannot combine two particles of different hypotheses from the same
835  // connected region (as their energies overlap)
836  if (this->getECLClusterEHypothesisBit() == oParticle->getECLClusterEHypothesisBit())
837  return false;
838 
839  // in the rare case that both are neutral and the hypotheses are different,
840  // we must also check that they are from different connected regions
841  // otherwise they come from the "same" underlying ECLShower
842  if (this->getECLCluster()->getConnectedRegionId() != oParticle->getECLCluster()->getConnectedRegionId())
843  return false;
844  }
845  return true;
846 
847 }
848 
849 const Track* Particle::getTrack() const
850 {
851  if (m_particleSource == c_Track) {
852  StoreArray<Track> tracks{};
853  return tracks[m_mdstIndex];
854  } else
855  return nullptr;
856 }
857 
859 {
860  // if the particle is related to a TrackFitResult then return this
861  auto* selfrelated = this->getRelatedTo<TrackFitResult>();
862  if (selfrelated && !isnan(selfrelated->getPValue()))
863  return selfrelated;
864 
865  // if not get the TFR with closest mass to this particle
866  auto* selftrack = this->getTrack();
867  if (selftrack)
868  return selftrack->getTrackFitResultWithClosestMass(
869  Belle2::Const::ChargedStable(std::abs(this->getPDGCode())));
870 
871  // otherwise we're probably not a track based particle
872  return nullptr;
873 }
874 
876 {
877  if (m_particleSource == c_Track) {
878  StoreArray<Track> tracks{};
879  return tracks[m_mdstIndex]->getRelated<PIDLikelihood>();
880  } else
881  return nullptr;
882 }
883 
884 const V0* Particle::getV0() const
885 {
886  if (m_particleSource == c_V0) {
887  StoreArray<V0> v0s{};
888  return v0s[m_mdstIndex];
889  } else {
890  return nullptr;
891  }
892 }
893 
894 
896 {
897  if (m_particleSource == c_ECLCluster) {
898  StoreArray<ECLCluster> eclClusters{};
899  return eclClusters[m_mdstIndex];
900  } else if (m_particleSource == c_Track) {
901  // a track may be matched to several clusters under different hypotheses
902  // take the most energetic of the c_nPhotons hypothesis as "the" cluster
903  StoreArray<Track> tracks{};
904  const ECLCluster* bestTrackMatchedCluster = nullptr;
905  double highestEnergy = -1.0;
906  // loop over all clusters matched to this track
907  for (const ECLCluster& cluster : tracks[m_mdstIndex]->getRelationsTo<ECLCluster>()) {
908  // ignore everything except the nPhotons hypothesis
909  if (!cluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
910  continue;
911  // check if we're most energetic thus far
912  if (cluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons) > highestEnergy) {
913  highestEnergy = cluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
914  bestTrackMatchedCluster = &cluster;
915  }
916  }
917  return bestTrackMatchedCluster;
918  } else {
919  return nullptr;
920  }
921 }
922 
924 {
925  const ECLCluster* cluster = this->getECLCluster();
926  if (!cluster) return 0;
927  return cluster->getEnergy(this->getECLClusterEHypothesisBit());
928 }
929 
931 {
932  if (m_particleSource == c_KLMCluster) {
933  StoreArray<KLMCluster> klmClusters{};
934  return klmClusters[m_mdstIndex];
935  } else if (m_particleSource == c_Track) {
936  // If there is an associated KLMCluster, it's the closest one
937  StoreArray<Track> tracks{};
938  const KLMCluster* klmCluster = tracks[m_mdstIndex]->getRelatedTo<KLMCluster>();
939  return klmCluster;
940  } else {
941  return nullptr;
942  }
943 }
944 
945 
947 {
948  if (m_particleSource == c_MCParticle) {
949  StoreArray<MCParticle> mcParticles{};
950  return mcParticles[m_mdstIndex];
951  } else {
952  const MCParticle* related = this->getRelated<MCParticle>();
953  if (related)
954  return related;
955  }
956  return nullptr;
957 }
958 
959 
960 const Particle* Particle::getParticleFromGeneralizedIndexString(const std::string& generalizedIndex) const
961 {
962  // Split the generalizedIndex string in a vector of strings.
963  std::vector<std::string> generalizedIndexes;
964  boost::split(generalizedIndexes, generalizedIndex, boost::is_any_of(":"));
965 
966  if (generalizedIndexes.empty()) {
967  B2WARNING("Generalized index of daughter particle is empty. Skipping.");
968  return nullptr;
969  }
970 
971  // To explore a decay tree of unknown depth, we need a place to store
972  // both the root particle and the daughter particle at each iteration
973  const Particle* dauPart =
974  nullptr; // This will be eventually returned
975  const Particle* currentPart = this; // This is the root particle of the next iteration
976 
977  // Loop over the generalizedIndexes until you get to the particle you want
978  for (auto& indexString : generalizedIndexes) {
979  // indexString is a string. First try to convert it into an int
980  int dauIndex = 0;
981  try {
982  dauIndex = Belle2::convertString<int>(indexString);
983  } catch (std::invalid_argument&) {
984  B2WARNING("Found the string " << indexString << "instead of a daughter index.");
985  return nullptr;
986  }
987 
988  // Check that the daughter index is smaller than the number of daughters of the current root particle
989  if (dauIndex >= int(currentPart->getNDaughters()) or dauIndex < 0) {
990  B2WARNING("Daughter index out of range" << LogVar("Daughter index", dauIndex));
991  B2WARNING("Trying to access non-existing particle.");
992  return nullptr;
993  } else {
994  dauPart = currentPart->getDaughter(dauIndex); // Pick the particle indicated by the generalizedIndex
995  currentPart = dauPart;
996  }
997  }
998  return dauPart;
999 }
1000 
1001 
1002 
1003 //--- private methods --------------------------------------------
1004 
1006 {
1007  // set momentum
1008  m_px = trackFit->getMomentum().X();
1009  m_py = trackFit->getMomentum().Y();
1010  m_pz = trackFit->getMomentum().Z();
1011 
1012  // set position at which the momentum is given (= POCA)
1013  setVertex(trackFit->getPosition());
1014 
1015  // set Chi^2 probability
1016  m_pValue = trackFit->getPValue();
1017 
1018  // set error matrix
1019  const auto cov6 = trackFit->getCovariance6();
1020  constexpr unsigned order[] = {c_X, c_Y, c_Z, c_Px, c_Py, c_Pz};
1021 
1022  TMatrixFSym errMatrix(c_DimMatrix);
1023  for (int i = 0; i < 6; i++) {
1024  for (int j = i; j < 6; j++) {
1025  // although it seems to make no sense to fill all elements of the
1026  // symmetric matrix, it has to be (do not touch this code)
1027  errMatrix(order[j], order[i]) = errMatrix(order[i], order[j]) = cov6(i, j);
1028  }
1029  }
1030 
1031  /*
1032  E = sqrt(px^2 + py^2 + pz^2 + m^2) thus:
1033  cov(x,E) = cov(px,x) *dE/dpx + cov(py,x) *dE/dpy + cov(pz,x) *dE/dpz
1034  cov(y,E) = cov(px,y) *dE/dpx + cov(py,y) *dE/dpy + cov(pz,y) *dE/dpz
1035  cov(z,E) = cov(px,z) *dE/dpx + cov(py,z) *dE/dpy + cov(pz,z) *dE/dpz
1036  cov(px,E) = cov(px,px)*dE/dpx + cov(px,py)*dE/dpy + cov(px,pz)*dE/dpz
1037  cov(py,E) = cov(py,px)*dE/dpx + cov(py,py)*dE/dpy + cov(py,pz)*dE/dpz
1038  cov(pz,E) = cov(pz,px)*dE/dpx + cov(pz,py)*dE/dpy + cov(pz,pz)*dE/dpz
1039  cov(E,E) = cov(px,px)*(dE/dpx)^2 + cov(py,py)*(dE/dpy)^2 + cov(pz,pz)*(dE/dpz)^2
1040  + 2*cov(px,py)*dE/dpx*dE/dpy
1041  + 2*cov(py,pz)*dE/dpy*dE/dpz
1042  + 2*cov(pz,px)*dE/dpz*dE/dpx
1043  dE/dpx = px/E etc.
1044  */
1045 
1046  const double E = getEnergy();
1047  const double dEdp[] = {m_px / E, m_py / E, m_pz / E};
1048  constexpr unsigned compMom[] = {c_Px, c_Py, c_Pz};
1049  constexpr unsigned compPos[] = {c_X, c_Y, c_Z};
1050 
1051  // covariances (p,E)
1052  for (unsigned int i : compMom) {
1053  double Cov = 0;
1054  for (int k = 0; k < 3; k++) {
1055  Cov += errMatrix(i, compMom[k]) * dEdp[k];
1056  }
1057  errMatrix(i, c_E) = Cov;
1058  }
1059 
1060  // covariances (x,E)
1061  for (unsigned int comp : compPos) {
1062  double Cov = 0;
1063  for (int k = 0; k < 3; k++) {
1064  Cov += errMatrix(comp, compMom[k]) * dEdp[k];
1065  }
1066  errMatrix(c_E, comp) = Cov;
1067  }
1068 
1069  // variance (E,E)
1070  double Cov = 0;
1071  for (int i = 0; i < 3; i++) {
1072  Cov += errMatrix(compMom[i], compMom[i]) * dEdp[i] * dEdp[i];
1073  }
1074  for (int i = 0; i < 3; i++) {
1075  int k = (i + 1) % 3;
1076  Cov += 2 * errMatrix(compMom[i], compMom[k]) * dEdp[i] * dEdp[k];
1077  }
1078  errMatrix(c_E, c_E) = Cov;
1079 
1080  storeErrorMatrix(errMatrix);
1081 }
1082 
1084 {
1085  for (double& i : m_errMatrix)
1086  i = 0.0;
1087 }
1088 
1090 {
1091  for (double& i : m_jacobiMatrix)
1092  i = 0.0;
1093 }
1094 
1095 void Particle::storeErrorMatrix(const TMatrixFSym& m)
1096 {
1097  int element = 0;
1098  for (int irow = 0; irow < c_DimMatrix; irow++) {
1099  for (int icol = irow; icol < c_DimMatrix; icol++) {
1100  m_errMatrix[element] = m(irow, icol);
1101  element++;
1102  }
1103  }
1104 }
1105 
1106 void Particle::storeJacobiMatrix(const TMatrixF& m)
1107 {
1108  int element = 0;
1109  for (int irow = 0; irow < 4; irow++) {
1110  for (int icol = 0; icol < 6; icol++) {
1111  m_jacobiMatrix[element] = m(irow, icol);
1112  element++;
1113  }
1114  }
1115 }
1116 
1117 
1118 void Particle::fillFSPDaughters(std::vector<const Belle2::Particle*>& fspDaughters) const
1119 {
1120  // this is FSP
1121  if (getNDaughters() == 0) {
1122  fspDaughters.push_back(this);
1123  return;
1124  }
1125 
1126  // this is not FSP (go one level down)
1127  for (unsigned i = 0; i < getNDaughters(); i++)
1128  getDaughter(i)->fillFSPDaughters(fspDaughters);
1129 }
1130 
1131 void Particle::fillAllDaughters(std::vector<const Belle2::Particle*>& allDaughters) const
1132 {
1133  // this is FSP
1134  if (getNDaughters() == 0)
1135  return;
1136 
1137  // this is not FSP (fill it and go one level down)
1138  for (unsigned i = 0; i < getNDaughters(); i++) {
1139  allDaughters.push_back(getDaughter(i));
1140  getDaughter(i)->fillAllDaughters(allDaughters);
1141  }
1142 }
1143 
1144 void Particle::fillDecayChain(std::vector<int>& decayChain) const
1145 {
1146  decayChain.push_back(m_pdgCode);
1147  decayChain.push_back(getMdstSource());
1148 
1149  for (unsigned i = 0; i < getNDaughters(); i++)
1150  getDaughter(i)->fillDecayChain(decayChain);
1151 }
1152 
1153 
1155 {
1157  if (m_pdgCode < 0) return;
1158  if (m_pdgCode == Const::photon.getPDGCode()) {m_flavorType = c_Unflavored; return;} // gamma
1159  if (m_pdgCode == Const::Kshort.getPDGCode()) {m_flavorType = c_Unflavored; return;} // K_s
1160  if (m_pdgCode == Const::Klong.getPDGCode()) {m_flavorType = c_Unflavored; return;} // K_L
1161  if (m_pdgCode == 43) {m_flavorType = c_Unflavored; return;} // Xu0
1162  int nnn = m_pdgCode / 10;
1163  int q3 = nnn % 10; nnn /= 10;
1164  int q2 = nnn % 10; nnn /= 10;
1165  int q1 = nnn % 10;
1166  if (q1 == 0 && q2 == q3) m_flavorType = c_Unflavored; // unflavored meson
1167 }
1168 
1169 std::string Particle::getName() const
1170 {
1171  return TDatabasePDG::Instance()->GetParticle(m_pdgCode)->GetName();
1172 }
1173 
1174 void Particle::print() const
1175 {
1176  B2INFO(getInfo());
1177 }
1178 
1179 std::vector<std::string> Particle::getExtraInfoNames() const
1180 {
1181  std::vector<std::string> out;
1182  if (!m_extraInfo.empty()) {
1183  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1184  if (!extraInfoMap)
1185  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1186  const ParticleExtraInfoMap::IndexMap& map = extraInfoMap->getMap(m_extraInfo[0]);
1187  for (auto const& ee : map) out.push_back(ee.first);
1188  }
1189  return out;
1190 }
1191 
1192 std::string Particle::getInfoHTML() const
1193 {
1194  std::stringstream stream;
1195  stream << std::setprecision(4);
1196  stream << "<b>collection</b>=" << getArrayName();
1197  stream << "<br>";
1198  stream << " <b>PDGCode</b>=" << m_pdgCode;
1199  stream << " <b>Charge</b>=" << getCharge();
1200  stream << " <b>PDGMass</b>=" << getPDGMass();
1201  stream << "<br>";
1202  stream << " <b>flavorType</b>=" << m_flavorType;
1203  stream << " <b>particleSource</b>=" << m_particleSource;
1204  stream << " <b>particleTypeUsedForFit</b>=" << m_pdgCodeUsedForFit;
1205  stream << "<br>";
1206 
1207  stream << " <b>mdstIndex</b>=" << m_mdstIndex;
1208  stream << " <b>arrayIndex</b>=" << getArrayIndex();
1209  stream << " <b>identifier</b>=" << m_identifier;
1210  stream << " <b>daughterIndices</b>: ";
1211  for (int daughterIndex : m_daughterIndices) {
1212  stream << daughterIndex << ", ";
1213  }
1214  if (m_daughterIndices.empty()) stream << " (none)";
1215  stream << "<br>";
1216 
1217  if (!m_daughterIndices.empty()) {
1218  stream << " <b>daughter PDGCodes</b>: ";
1219  for (unsigned i = 0; i < m_daughterIndices.size(); i++) {
1220  const Particle* p = getDaughter(i);
1221  if (p) {stream << p->getPDGCode() << ", ";}
1222  else {stream << "?, ";}
1223  }
1224  stream << "<br>";
1225  }
1226 
1227  stream << " <b>mass</b>=" << m_mass;
1228  stream << "<br>";
1229 
1230  stream << " <b>momentum</b>=" << HTML::getString(ROOT::Math::XYZVector(getPx(), getPy(), getPz()));
1231  stream << " <b>p</b>=" << getP();
1232  stream << "<br>";
1233 
1234  stream << " <b>momentum scaling factor</b>=" << m_momentumScale;
1235  stream << "<br>";
1236 
1237  stream << " <b>position</b>=" << HTML::getString(ROOT::Math::XYZVector(m_x, m_y, m_z));
1238  stream << "<br>";
1239 
1240  stream << " <b>p-value of fit</b> (if done): ";
1241  stream << m_pValue;
1242  stream << "<br>";
1243 
1244  stream << " <b>error matrix</b> (px, py, pz, E, x, y ,z):<br>";
1246 
1247  stream << " <b>extra info</b>=( ";
1248  if (!m_extraInfo.empty()) {
1249  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1250  if (!extraInfoMap) {
1251  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1252  }
1253  const ParticleExtraInfoMap::IndexMap& map = extraInfoMap->getMap(m_extraInfo[0]);
1254  const unsigned int nVars = m_extraInfo.size();
1255  for (const auto& pair : map) {
1256  if (pair.second < nVars) {
1257  stream << pair.first << "=" << m_extraInfo[pair.second] << " ";
1258  }
1259  }
1260 
1261  }
1262  stream << ") " << "<br>";
1263 
1264  return stream.str();
1265 }
1266 
1267 bool Particle::hasExtraInfo(const std::string& name) const
1268 {
1269  if (m_extraInfo.empty())
1270  return false;
1271 
1272  //get index for name
1273  const auto mapID = (unsigned int)m_extraInfo[0];
1274  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1275  if (!extraInfoMap) {
1276  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1277  }
1278  unsigned int index = extraInfoMap->getIndex(mapID, name);
1279  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1280  return false;
1281 
1282  return true;
1283 }
1284 
1286 {
1287  m_extraInfo.clear();
1288 }
1289 
1290 double Particle::getExtraInfo(const std::string& name) const
1291 {
1292  if (m_extraInfo.empty())
1293  throw std::runtime_error(std::string("getExtraInfo: Value '") + name + "' not found in Particle!");
1294 
1295  //get index for name
1296  const auto mapID = (unsigned int)m_extraInfo[0];
1297  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1298  if (!extraInfoMap) {
1299  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1300  }
1301  unsigned int index = extraInfoMap->getIndex(mapID, name);
1302  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1303  throw std::runtime_error(std::string("getExtraInfo: Value '") + name + "' not found in Particle!");
1304 
1305  return m_extraInfo[index];
1306 
1307 }
1308 
1309 void Particle::writeExtraInfo(const std::string& name, const double value)
1310 {
1311  if (this->hasExtraInfo(name)) {
1312  this->setExtraInfo(name, value);
1313  } else {
1314  this->addExtraInfo(name, value);
1315  }
1316 }
1317 
1318 void Particle::setExtraInfo(const std::string& name, double value)
1319 {
1320  if (m_extraInfo.empty())
1321  throw std::runtime_error(std::string("setExtraInfo: Value '") + name + "' not found in Particle!");
1322 
1323  //get index for name
1324  const auto mapID = (unsigned int)m_extraInfo[0];
1325  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1326  if (!extraInfoMap) {
1327  B2FATAL("ParticleExtraInfoMap not available, but needed for storing extra info in Particle!");
1328  }
1329  unsigned int index = extraInfoMap->getIndex(mapID, name);
1330  if (index == 0 or index >= m_extraInfo.size()) //actually indices start at 1
1331  throw std::runtime_error(std::string("setExtraInfo: Value '") + name + "' not found in Particle!");
1332 
1333  m_extraInfo[index] = value;
1334 
1335 }
1336 
1337 void Particle::addExtraInfo(const std::string& name, double value)
1338 {
1339  if (hasExtraInfo(name))
1340  throw std::runtime_error(std::string("addExtraInfo: Value '") + name + "' already set!");
1341 
1342  StoreObjPtr<ParticleExtraInfoMap> extraInfoMap;
1343  if (!extraInfoMap)
1344  extraInfoMap.create();
1345  if (m_extraInfo.empty()) {
1346  unsigned int mapID = extraInfoMap->getMapForNewVar(name);
1347  m_extraInfo.push_back(mapID);
1348  m_extraInfo.push_back(value);
1349  } else {
1350  unsigned int oldMapID = m_extraInfo[0];
1351  unsigned int insertIndex = m_extraInfo.size();
1352  unsigned int mapID = extraInfoMap->getMapForNewVar(name, oldMapID, insertIndex);
1353 
1354  m_extraInfo[0] = mapID; //update map
1355  m_extraInfo.push_back(value); //add value
1356  }
1357 }
1358 
1359 bool Particle::forEachDaughter(const std::function<bool(const Particle*)>& function,
1360  bool recursive, bool includeSelf) const
1361 {
1362  std::queue<const Particle*> qq;
1363  // If we include ourselves add only this, otherwise directly all children
1364  if (includeSelf) {
1365  qq.push(this);
1366  } else {
1367  for (size_t i = 0; i < getNDaughters(); ++i) qq.push(getDaughter(i));
1368  }
1369  // Now just repeat until done: take the child, run the functor, remove the
1370  // child, add all children if needed
1371  while (!qq.empty()) {
1372  const Particle* p = qq.front();
1373  if (function(p)) return true;
1374  qq.pop();
1375  // Add children if we go through all children recursively or if we look at
1376  // the current particle: we always want the direct children.
1377  if (recursive || p == this)
1378  for (size_t i = 0; i < p->getNDaughters(); ++i) qq.push(p->getDaughter(i));
1379  }
1380  return false;
1381 }
1382 
1383 int Particle::generatePDGCodeFromCharge(const int chargeSign, const Const::ChargedStable& chargedStable)
1384 {
1385  int absPDGCode = chargedStable.getPDGCode();
1386  int PDGCode = absPDGCode * chargeSign;
1387  // flip sign of PDG code for leptons: their PDG code is positive if the lepton charge is negative and vice versa
1388  if (chargedStable == Const::muon || chargedStable == Const::electron) PDGCode = -PDGCode;
1389  return PDGCode;
1390 }
1391 
1393 {
1394  const PIDLikelihood* likelihood = Particle::getPIDLikelihood();
1395  if (likelihood) return likelihood->getMostLikely().getPDGCode() == std::abs(m_pdgCode);
1396  else return false;
1397 }
1398 
1399 std::pair<Const::ChargedStable, const TrackFitResult*> Particle::getMostLikelyTrackFitResult() const
1400 {
1401 
1402  const auto track = this->getTrack();
1403 
1404  if (!track) {
1405  return std::make_pair(Const::ChargedStable(std::abs(this->getPDGCode())), nullptr);
1406  }
1407 
1408  // Find the track fit with the highest pValue
1409  auto trackFitResults = track->getTrackFitResults();
1410  auto it_maxPValue = std::max_element(std::begin(trackFitResults), std::end(trackFitResults),
1411  [](auto tfrAndM1, auto tfrAndM2) {return tfrAndM1.second->getPValue() < tfrAndM2.second->getPValue();});
1412 
1413  return trackFitResults[std::distance(std::begin(trackFitResults), it_maxPValue)];
1414 
1415 }
1416 
1418 {
1419  const auto trackFit = this->getTrackFitResult();
1420  if (!trackFit) return false;
1421 
1422  return (trackFit == this->getMostLikelyTrackFitResult().second);
1423 }
R E
internal precision of FFTW codelets
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:35
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:1285
double getPx() const
Returns x component of momentum.
Definition: Particle.h:553
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:451
bool isMostLikely() const
Returns true if the (track-based) particle is created with its most likely mass hypothesis based on P...
Definition: Particle.cc:1392
const KLMCluster * getKLMCluster() const
Returns the pointer to the KLMCluster object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:930
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:709
const Track * getTrack() const
Returns the pointer to the Track object that was used to create this Particle (ParticleType == c_Trac...
Definition: Particle.cc:849
void setMomentumPositionErrorMatrix(const TrackFitResult *trackFit)
Sets the momentum, position and error matrix for this particle (created from charged Track)
Definition: Particle.cc:1005
void storeErrorMatrix(const TMatrixFSym &errMatrix)
Stores 7x7 error matrix into private member m_errMatrix.
Definition: Particle.cc:1095
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:1359
std::vector< const Belle2::Particle * > getFinalStateDaughters() const
Returns a vector of pointers to Final State daughter particles.
Definition: Particle.cc:653
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:946
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:680
const ECLCluster * getECLCluster() const
Returns the pointer to the ECLCluster object that was used to create this Particle (if ParticleType =...
Definition: Particle.cc:895
void setExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1318
EParticleSourceObject
particle source enumerators
Definition: Particle.h:82
double m_pValue
chi^2 probability of the fit.
Definition: Particle.h:1026
double m_pz
momentum component z
Definition: Particle.h:1017
int m_pdgCodeUsedForFit
PDG code used for the track fit.
Definition: Particle.h:1013
double m_momentumScale
effective momentum scale factor
Definition: Particle.h:1018
std::string getName() const override
Return name of this particle.
Definition: Particle.cc:1169
bool overlapsWith(const Particle *oParticle) const
Returns true if final state ancestors of oParticle overlap.
Definition: Particle.cc:741
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:506
TClonesArray * getArrayPointer() const
Returns the pointer to the store array which holds the daughter particles.
Definition: Particle.h:911
double getPz() const
Returns z component of momentum.
Definition: Particle.h:571
std::vector< std::string > getExtraInfoNames() const
get a list of the extra info names
Definition: Particle.cc:1179
bool isCopyOf(const Particle *oParticle, bool doDetailedComparison=false) const
Returns true if this Particle and oParticle are copies of each other.
Definition: Particle.cc:756
void writeExtraInfo(const std::string &name, const double value)
Sets the user defined extraInfo.
Definition: Particle.cc:1309
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:669
double m_jacobiMatrix[c_SizeMatrix]
error matrix (1D representation)
Definition: Particle.h:1025
void resetJacobiMatrix()
Resets 4x6 error matrix All elements are set to 0.0.
Definition: Particle.cc:1089
void storeJacobiMatrix(const TMatrixF &jacobiMatrix)
Stores 4x6 Jacobi matrix into private member m_jacobiMatrix.
Definition: Particle.cc:1106
bool isMostLikelyTrackFitResult() const
Returns true if the (track-based) particle is created with its most likely mass hypothesis based on T...
Definition: Particle.cc:1417
std::vector< double > m_extraInfo
Stores associated user defined values.
Definition: Particle.h:1048
unsigned m_mdstIndex
0-based index of MDST store array object
Definition: Particle.h:1030
void setFlavorType()
sets m_flavorType using m_pdgCode
Definition: Particle.cc:1154
double getEnergy() const
Returns total energy.
Definition: Particle.h:507
int getMdstSource() const
Returns unique identifier of final state particle (needed in particle combiner)
Definition: Particle.cc:371
void fillAllDaughters(std::vector< const Belle2::Particle * > &allDaughters) const
Fill all generations' daughters into a vector.
Definition: Particle.cc:1131
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1267
std::string getInfoHTML() const override
Return a short summary of this object's contents in HTML format.
Definition: Particle.cc:1192
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:960
double m_py
momentum component y
Definition: Particle.h:1016
double m_x
position component x
Definition: Particle.h:1021
double m_px
momentum component x
Definition: Particle.h:1015
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:1399
~Particle()
Destructor.
void fillFSPDaughters(std::vector< const Belle2::Particle * > &fspDaughters) const
Fill final state particle daughters into a vector.
Definition: Particle.cc:1118
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:875
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:884
EParticleSourceObject m_particleSource
(mdst) source of particle
Definition: Particle.h:1029
void fillDecayChain(std::vector< int > &decayChain) const
Fill vector with (PDGCode, MdstSource) pairs for the entire decay chain.
Definition: Particle.cc:1144
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:426
double getPy() const
Returns y component of momentum.
Definition: Particle.h:562
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:463
unsigned getNDaughters(void) const
Returns number of daughter particles.
Definition: Particle.h:685
std::vector< Belle2::Particle * > getDaughters() const
Returns a vector of pointers to daughter particles.
Definition: Particle.cc:641
void resetErrorMatrix()
Resets 7x7 error matrix All elements are set to 0.0.
Definition: Particle.cc:1083
double getPDGMass(void) const
Returns uncertainty on the invariant mass (requires valid momentum error matrix)
Definition: Particle.cc:608
EFlavorType m_flavorType
flavor type.
Definition: Particle.h:1028
int generatePDGCodeFromCharge(const int chargedSign, const Const::ChargedStable &chargedStable)
Generate the PDG code with correct sign, using the charge.
Definition: Particle.cc:1383
double getCharge(void) const
Returns particle charge.
Definition: Particle.cc:626
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:517
Particle()
Default constructor.
Definition: Particle.cc:45
TMatrixFSym getMomentumErrorMatrix() const
Returns the 4x4 momentum error matrix.
Definition: Particle.cc:439
double m_mass
particle (invariant) mass
Definition: Particle.h:1014
std::vector< const Belle2::Particle * > getAllDaughters() const
Returns a vector of pointers to all generations' daughter particles.
Definition: Particle.cc:661
double getAcoplanarity() const
Returns acoplanarity angle defined as the angle between the decay planes of the grand daughters in th...
Definition: Particle.cc:537
std::vector< int > m_daughterProperties
daughter particle properties
Definition: Particle.h:1032
double m_errMatrix[c_SizeMatrix]
error matrix (1D representation)
Definition: Particle.h:1024
std::vector< int > m_daughterIndices
daughter particle indices
Definition: Particle.h:1027
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1337
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:411
double getPDGLifetime() const
Returns particle nominal lifetime.
Definition: Particle.cc:617
void setMomentumVertexErrorMatrix(const TMatrixFSym &errMatrix)
Sets 7x7 error matrix.
Definition: Particle.cc:397
EParticleSourceObject getParticleSource() const
Returns particle source as defined with enum EParticleSourceObject.
Definition: Particle.h:450
void updateMass(const int pdgCode)
Updates particle mass with the mass of the particle corresponding to the given PDG.
Definition: Particle.cc:601
double m_z
position component z
Definition: Particle.h:1023
void print() const
Prints the contents of a Particle object to standard output.
Definition: Particle.cc:1174
@ 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:1012
TMatrixFSym getMomentumVertexErrorMatrix() const
Returns 7x7 error matrix.
Definition: Particle.cc:424
double getECLClusterEnergy() const
Returns the energy of the ECLCluster for the particle.
Definition: Particle.cc:923
const TrackFitResult * getTrackFitResult() const
Returns the pointer to the TrackFitResult that was used to create this Particle (ParticleType == c_Tr...
Definition: Particle.cc:858
void removeDaughter(const Particle *daughter, const bool updateType=true)
Removes index of daughter from daughters index array.
Definition: Particle.cc:692
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)
Definition: Particle.h:544
double m_y
position component y
Definition: Particle.h:1022
int m_identifier
Identifier that can be used to identify whether the particle is unique or is a copy or representation...
Definition: Particle.h:1041
int m_properties
particle property
Definition: Particle.h:1031
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:635
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1290
ECLCluster::EHypothesisBit getECLClusterEHypothesisBit() const
Returns the ECLCluster EHypothesisBit for this Particle.
Definition: Particle.h:959
bool replaceDaughterRecursively(const Particle *oldDaughter, Particle *newDaughter)
Apply replaceDaughter to all Particles in the decay tree by looping recursively through it,...
Definition: Particle.cc:727
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.
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.
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
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.