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