Belle II Software development
ParticleBase.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * External Contributor: Wouter Hulsbergen *
5 * *
6 * See git log for contributors and copyright holders. *
7 * This file is licensed under LGPL-3.0, see LICENSE.md. *
8 **************************************************************************/
9
10//Creates a particle. Base class for all other particle classes.
11
12#include <TDatabasePDG.h>
13
14#include <analysis/VertexFitting/TreeFitter/ParticleBase.h>
15#include <analysis/VertexFitting/TreeFitter/InternalParticle.h>
16#include <analysis/VertexFitting/TreeFitter/Composite.h>
17#include <analysis/VertexFitting/TreeFitter/RecoResonance.h>
18#include <analysis/VertexFitting/TreeFitter/RecoTrack.h>
19
20#include <analysis/VertexFitting/TreeFitter/RecoPhoton.h>
21#include <analysis/VertexFitting/TreeFitter/RecoKlong.h>
22#include <analysis/VertexFitting/TreeFitter/Resonance.h>
23#include <analysis/VertexFitting/TreeFitter/Origin.h>
24#include <analysis/VertexFitting/TreeFitter/FitParams.h>
25
26namespace TreeFitter {
27
29 m_particle(particle),
30 m_mother(mother),
31 m_isStronglyDecayingResonance(false),
32 m_config(config),
33 m_index(0),
34 m_name("Unknown")
35 {
36 if (particle) {
38 const int pdgcode = particle->getPDGCode();
39 if (pdgcode) { // PDG code != 0
41 }
42 }
43 }
44
45 ParticleBase::ParticleBase(const std::string& name) :
46 m_particle(nullptr),
47 m_mother(nullptr),
48 m_isStronglyDecayingResonance(false),
49 m_config(nullptr),
50 m_index(0),
51 m_name(name)
52 {}
53
54
56 {
57 for (auto daughter : m_daughters) {
58 delete daughter;
59 }
60 m_daughters.clear();
61 }
62
64 {
65 auto newDaughter = ParticleBase::createParticle(cand, this, config, forceFitAll);
66 m_daughters.push_back(newDaughter);
67 return m_daughters.back();
68 }
69
70
72 {
73 auto iter = std::find(m_daughters.begin(), m_daughters.end(), pb);
74 if (iter != m_daughters.end()) {
75 delete *iter;
76 m_daughters.erase(iter);
77 } else {
78 B2ERROR("Cannot remove particle, because not found ...");
79 }
80 }
81
82 void ParticleBase::updateIndex(int& offset)
83 {
84 for (auto* daughter : m_daughters) {
85 daughter->updateIndex(offset);
86 }
87 m_index = offset;
88 offset += dim();
89 }
90
92 Belle2::Particle* daughter,
93 const ConstraintConfiguration& config,
94 bool forceFitAll
95 )
96 {
97 return new Origin(daughter, config, forceFitAll);
98 }
99
101 const ConstraintConfiguration& config, bool forceFitAll)
102 {
103 ParticleBase* rc = nullptr;
104
105 if (!mother) { // If there is no mother, this is the 'head of tree' particle (is never a resonance)
106 rc = new InternalParticle(particle, nullptr, config, forceFitAll);
107 } else if (particle->hasExtraInfo("bremsCorrected") // Has Bremsstrahlungs-recovery
108 && particle->getExtraInfo("bremsCorrected") != 0) { // and gammas are attached
109 rc = new Composite(particle, mother, config, true);
110 // if no gamma is attached, it is treated as a RecoTrack
111 } else if (particle->hasExtraInfo("treeFitterTreatMeAsInvisible")
112 && particle->getExtraInfo("treeFitterTreatMeAsInvisible") == 1) { // dummy particles with invisible flag
113 rc = new RecoResonance(particle, mother, config);
114 } else if (particle->getTrack()) { // external reconstructed track
115 rc = new RecoTrack(particle, mother);
116 } else if (particle->getECLCluster()) { // external reconstructed photon
117 rc = new RecoPhoton(particle, mother);
118 } else if (particle->getKLMCluster()) { // external reconstructed klong
119 rc = new RecoKlong(particle, mother);
120 } else if (particle->getMdstArrayIndex()) { // external composite e.g. V0
121 rc = new InternalParticle(particle, mother, config, forceFitAll);
122 } else { // 'internal' particles
123 if (isAResonance(particle)) {
124 rc = new Resonance(particle, mother, config, forceFitAll);
125 } else {
126 rc = new InternalParticle(particle, mother, config, forceFitAll);
127 }
128 }
129 return rc;
130 }
131
133 {
134 bool rc = false ;
135 const int pdgcode = std::abs(particle->getPDGCode());
136
137 if (pdgcode && !(particle->getMdstArrayIndex())) {
138 switch (pdgcode) {
139 case 22: //photon conversion
140 rc = false;
141 break ;
142
143 case -11: //bremsstrahlung
144 case 11:
145 rc = true ;
146 break ;
147 default: //everything with boosted flight length less than 1 micrometer
148 rc = (pdgcode && particle->getPDGLifetime() < 1e-14);
149 }
150 }
151 return rc ;
152 }
153
154 void ParticleBase::collectVertexDaughters(std::vector<ParticleBase*>& particles, int posindex)
155 {
156 if (mother() && mother()->posIndex() == posindex) {
157 particles.push_back(this);
158 }
159
160 for (auto* daughter : m_daughters) {
161 daughter->collectVertexDaughters(particles, posindex);
162 }
163 }
164
166 {
167 // this is very sensitive and can heavily affect the efficiency of the fit
168 ErrCode status;
169
170 const int posindex = posIndex();
171 if (posindex >= 0) {
172 for (int i = 0; i < 3; ++i) {
173 fitparams.getCovariance()(posindex + i, posindex + i) = 1;
174 }
175 }
176
177 const int momindex = momIndex();
178 if (momindex >= 0) {
179 const int maxrow = hasEnergy() ? 4 : 3;
180 for (int i = 0; i < maxrow; ++i) {
181 fitparams.getCovariance()(momindex + i, momindex + i) = 10.;
182 }
183 }
184
185 const int tauindex = tauIndex();
186 if (tauindex >= 0) {
187 fitparams.getCovariance()(tauindex, tauindex) = 1.;
188 }
189 return status;
190 }
191
192 std::string ParticleBase::parname(int thisindex) const
193 {
194 std::string rc = m_name;
195 switch (thisindex) {
196 case 0: rc += "_x "; break;
197 case 1: rc += "_y "; break;
198 case 2: rc += "_z "; break;
199 case 3: rc += "_tau"; break;
200 case 4: rc += "_px "; break;
201 case 5: rc += "_py "; break;
202 case 6: rc += "_pz "; break;
203 case 7: rc += "_E "; break;
204 default:;
205 }
206 return rc;
207 }
208
210 {
211 const ParticleBase* rc = (m_particle == particle) ? this : nullptr;
212 if (!rc) {
213 for (auto* daughter : m_daughters) {
214 rc = daughter->locate(particle);
215 if (rc) {break;}
216 }
217 }
218 return rc;
219 }
220
222 {
223 map.push_back(std::pair<const ParticleBase*, int>(this, index()));
224 for (auto* daughter : m_daughters) {
225 daughter->retrieveIndexMap(map);
226 }
227 }
228
229 double ParticleBase::chiSquare(const FitParams& fitparams) const
230 {
231 double rc = 0;
232 for (auto* daughter : m_daughters) {
233 rc += daughter->chiSquare(fitparams);
234 }
235 return rc;
236 }
237
239 {
240 int rc = 0;
241 for (auto* daughter : m_daughters) {
242 rc += daughter->nFinalChargedCandidates();
243 }
244 return rc;
245 }
246
248 {
249 assert(m_config);
250 // only allow 2d for head of tree particles that are beam constrained
251 const int dim = m_config->m_originDimension == 2 && std::abs(m_particle->getPDGCode()) == m_config->m_headOfTreePDG ? 2 : 3;
252 const int posindexmother = mother()->posIndex();
253 const int posindex = posIndex();
254 const int tauindex = tauIndex();
255 const int momindex = momIndex();
256
257 const double tau = fitparams.getStateVector()(tauindex);
258 Eigen::Matrix < double, 1, -1, 1, 1, 3 > x_vec = fitparams.getStateVector().segment(posindex, dim);
259 Eigen::Matrix < double, 1, -1, 1, 1, 3 > x_m = fitparams.getStateVector().segment(posindexmother, dim);
260 Eigen::Matrix < double, 1, -1, 1, 1, 3 > p_vec = fitparams.getStateVector().segment(momindex, dim);
261 const double mom = p_vec.norm();
262 const double mom3 = mom * mom * mom;
263
264 if (3 == dim) {
265 // we can already set these
266 //diagonal momentum
267 p.getH()(0, momindex) = tau * (p_vec(1) * p_vec(1) + p_vec(2) * p_vec(2)) / mom3 ;
268 p.getH()(1, momindex + 1) = tau * (p_vec(0) * p_vec(0) + p_vec(2) * p_vec(2)) / mom3 ;
269 p.getH()(2, momindex + 2) = tau * (p_vec(0) * p_vec(0) + p_vec(1) * p_vec(1)) / mom3 ;
270
271 //offdiagonal momentum
272 p.getH()(0, momindex + 1) = - tau * p_vec(0) * p_vec(1) / mom3 ;
273 p.getH()(0, momindex + 2) = - tau * p_vec(0) * p_vec(2) / mom3 ;
274
275 p.getH()(1, momindex + 0) = - tau * p_vec(1) * p_vec(0) / mom3 ;
276 p.getH()(1, momindex + 2) = - tau * p_vec(1) * p_vec(2) / mom3 ;
277
278 p.getH()(2, momindex + 0) = - tau * p_vec(2) * p_vec(0) / mom3 ;
279 p.getH()(2, momindex + 1) = - tau * p_vec(2) * p_vec(1) / mom3 ;
280
281 } else if (2 == dim) {
282
283 // NOTE THAT THESE ARE DIFFERENT IN 2d
284 p.getH()(0, momindex) = tau * (p_vec(1) * p_vec(1)) / mom3 ;
285 p.getH()(1, momindex + 1) = tau * (p_vec(0) * p_vec(0)) / mom3 ;
286
287 //offdiagonal momentum
288 p.getH()(0, momindex + 1) = - tau * p_vec(0) * p_vec(1) / mom3 ;
289 p.getH()(1, momindex + 0) = - tau * p_vec(1) * p_vec(0) / mom3 ;
290 } else {
291 B2FATAL("Dimension of Geometric constraint is not 2 or 3. This will crash many things. You should feel bad.");
292 }
293
294 for (int row = 0; row < dim; ++row) {
295
296 double posxmother = x_m(row);
297 double posx = x_vec(row);
298 double momx = p_vec(row);
299
303 p.getResiduals()(row) = posxmother + tau * momx / mom - posx ;
304 p.getH()(row, posindexmother + row) = 1;
305 p.getH()(row, posindex + row) = -1;
306 p.getH()(row, tauindex) = momx / mom;
307 }
308
309 return ErrCode(ErrCode::Status::success);
310 }
311
313 Projection& p) const
314 {
315 double mass = 0;
316 if (particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
317 mass = particle()->getExtraInfo("treeFitterMassConstraintValue");
318 } else mass = particle()->getPDGMass();
319 const double mass2 = mass * mass;
320 double px = 0;
321 double py = 0;
322 double pz = 0;
323 double E = 0;
324
325 // the parameters of the daughters must be used otherwise the mass constraint does not have an effect on the extracted daughter momenta
326 for (const auto* daughter : m_daughters) {
327 const int momindex = daughter->momIndex();
328 // in most cases the daughters will be final states so we cache the value to use it in the energy column
329 const double px_daughter = fitparams.getStateVector()(momindex);
330 const double py_daughter = fitparams.getStateVector()(momindex + 1);
331 const double pz_daughter = fitparams.getStateVector()(momindex + 2);
332
333 px += px_daughter;
334 py += py_daughter;
335 pz += pz_daughter;
336 if (daughter->hasEnergy()) {
337 E += fitparams.getStateVector()(momindex + 3);
338 } else {
339 // final states dont have an energy index
340 double m = 0;
341 if (daughter->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
342 m = daughter->particle()->getExtraInfo("treeFitterMassConstraintValue");
343 } else m = daughter->particle()->getPDGMass();
344 E += std::sqrt(m * m + px_daughter * px_daughter + py_daughter * py_daughter + pz_daughter * pz_daughter);
345 }
346 }
347
351 p.getResiduals()(0) = mass2 - E * E + px * px + py * py + pz * pz;
352
353 for (const auto* daughter : m_daughters) {
354 //dr/dx = d/dx m2-{E1+E2+...}^2+{p1+p2+...}^2 = 2*x (x= E or p)
355 const int momindex = daughter->momIndex();
356 p.getH()(0, momindex) = 2.0 * px;
357 p.getH()(0, momindex + 1) = 2.0 * py;
358 p.getH()(0, momindex + 2) = 2.0 * pz;
359
360 if (daughter->hasEnergy()) {
361 p.getH()(0, momindex + 3) = -2.0 * E;
362 } else {
363 const double px_daughter = fitparams.getStateVector()(momindex);
364 const double py_daughter = fitparams.getStateVector()(momindex + 1);
365 const double pz_daughter = fitparams.getStateVector()(momindex + 2);
366 double m = 0;
367 if (daughter->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
368 m = daughter->particle()->getExtraInfo("treeFitterMassConstraintValue");
369 } else m = daughter->particle()->getPDGMass();
370
371 const double E_daughter = std::sqrt(m * m + px_daughter * px_daughter + py_daughter * py_daughter + pz_daughter * pz_daughter);
372 const double E_by_E_daughter = E / E_daughter;
373 p.getH()(0, momindex) -= 2.0 * E_by_E_daughter * px_daughter;
374 p.getH()(0, momindex + 1) -= 2.0 * E_by_E_daughter * py_daughter;
375 p.getH()(0, momindex + 2) -= 2.0 * E_by_E_daughter * pz_daughter;
376 }
377
378 }
379 return ErrCode(ErrCode::Status::success);
380 }
381
383 Projection& p) const
384 {
385 double mass = 0;
386 if (particle()->hasExtraInfo("treeFitterMassConstraintValue")) mass = particle()->getExtraInfo("treeFitterMassConstraintValue");
387 else mass = particle()->getPDGMass();
388 const double mass2 = mass * mass;
389 const int momindex = momIndex();
390 const double px = fitparams.getStateVector()(momindex);
391 const double py = fitparams.getStateVector()(momindex + 1);
392 const double pz = fitparams.getStateVector()(momindex + 2);
393 const double E = fitparams.getStateVector()(momindex + 3);
394
398 p.getResiduals()(0) = mass2 - E * E + px * px + py * py + pz * pz;
399
400 p.getH()(0, momindex) = 2.0 * px;
401 p.getH()(0, momindex + 1) = 2.0 * py;
402 p.getH()(0, momindex + 2) = 2.0 * pz;
403 p.getH()(0, momindex + 3) = -2.0 * E;
404
405 // TODO 0 in most cases -> needs special treatment if width=0 to not crash chi2 calculation
406 // const double width = TDatabasePDG::Instance()->GetParticle(particle()->getPDGCode())->Width();
407 // transport measurement uncertainty into residual system
408 // f' = sigma_x^2 * (df/dx)^2
409 // p.getV()(0) = width * width * 4 * mass2;
410
411 return ErrCode(ErrCode::Status::success);
412 }
413
415 Projection& p) const
416 {
417 assert(m_config);
418 if (m_config->m_massConstraintType == 0) {
419 return projectMassConstraintParticle(fitparams, p);
420 } else {
421 return projectMassConstraintDaughters(fitparams, p);
422 }
423 }
424
426 {
427 if (type == Constraint::mass) {
428 return projectMassConstraint(fitparams, p);
429 } else {
430 B2FATAL("Trying to project constraint of ParticleBase type. This is undefined.");
431 }
432 return ErrCode(ErrCode::Status::badsetup);
433 }
434
436 {
437 const int tauindex = tauIndex();
438 if (tauindex >= 0 && hasPosition()) {
439
440 const int posindex = posIndex();
441 const int mother_ps_index = mother()->posIndex();
442 const int dim = m_config->m_originDimension; // TODO can we configure this to be particle specific?
443
444 // tau has different meaning depending on the dimension of the constraint
445 // 2-> use x-y projection
446 const Eigen::Matrix < double, 1, -1, 1, 1, 3 > vertex_dist =
447 fitparams.getStateVector().segment(posindex, dim) - fitparams.getStateVector().segment(mother_ps_index, dim);
448 const Eigen::Matrix < double, 1, -1, 1, 1, 3 >
449 mom = fitparams.getStateVector().segment(posindex, dim);
450
451 // if an intermediate vertex is not well defined by a track or so it will be initialised with 0
452 // same for the momentum of for example B0, it might be initialised with 0
453 // in those cases use pdg value
454 const double mom_norm = mom.norm();
455 const double dot = std::abs(vertex_dist.dot(mom));
456 const double tau = dot / mom_norm;
457 if (0 == mom_norm || 0 == dot) {
458 const double mass = m_particle->getPDGMass();
459 if (mass > 0)
460 fitparams.getStateVector()(tauindex) = m_particle->getPDGLifetime() * 1e9 * Belle2::Const::speedOfLight / mass;
461 else
462 fitparams.getStateVector()(tauindex) = 0;
463 } else {
464 fitparams.getStateVector()(tauindex) = tau;
465 }
466 }
467
468 return ErrCode(ErrCode::Status::success);
469 }
470} //end namespace TreeFitter
471
R E
internal precision of FFTW codelets
static const double speedOfLight
[cm/ns]
Definition: Const.h:695
Class to store reconstructed particles.
Definition: Particle.h:76
const KLMCluster * getKLMCluster() const
Returns the pointer to the KLMCluster object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:1011
const Track * getTrack() const
Returns the pointer to the Track object that was used to create this Particle (ParticleType == c_Trac...
Definition: Particle.cc:916
const ECLCluster * getECLCluster() const
Returns the pointer to the ECLCluster object that was used to create this Particle (if ParticleType =...
Definition: Particle.cc:976
std::string getName() const override
Return name of this particle.
Definition: Particle.cc:1250
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1351
unsigned getMdstArrayIndex(void) const
Returns 0-based index of MDST store array object (0 for composite particles)
Definition: Particle.h:498
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:465
double getPDGMass(void) const
Returns uncertainty on the invariant mass (requires valid momentum error matrix)
Definition: Particle.cc:635
double getPDGLifetime() const
Returns particle nominal lifetime.
Definition: Particle.cc:644
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1374
A class for composite particles, where the daughters must be ignored by the fitter.
Definition: Composite.h:17
constraint configuration class
const int m_originDimension
dimension of the origin constraint and ALL geometric gcosntraints
int m_headOfTreePDG
PDG code of the head particle.
const bool m_massConstraintType
const flag for the type of the mass constraint
Type
type of constraints the order of these constraints is important: it is the order in which they are ap...
Definition: Constraint.h:27
abstract errorocode be aware that the default is success
Definition: ErrCode.h:14
Class to store and manage fitparams (statevector)
Definition: FitParams.h:20
Eigen::Matrix< double, -1, 1, 0, MAX_MATRIX_SIZE, 1 > & getStateVector()
getter for the fit parameters/statevector
Definition: FitParams.h:65
Eigen::Matrix< double, -1, -1, 0, MAX_MATRIX_SIZE, MAX_MATRIX_SIZE > & getCovariance()
getter for the states covariance
Definition: FitParams.h:53
another unnecessary layer of abstraction
representation of the beamspot as a particle
Definition: Origin.h:19
base class for all particles
Definition: ParticleBase.h:25
virtual void updateIndex(int &offset)
this sets the index for momentum, position, etc.
Definition: ParticleBase.cc:82
virtual ErrCode projectMassConstraintParticle(const FitParams &, Projection &) const
project mass constraint using the particles parameters
Belle2::Particle * particle() const
get basf2 particle
Definition: ParticleBase.h:92
ErrCode initTau(FitParams &par) const
initialises tau as a length
virtual ParticleBase * addDaughter(Belle2::Particle *, const ConstraintConfiguration &config, bool forceFitAll=false)
add daughter
Definition: ParticleBase.cc:63
static ParticleBase * createOrigin(Belle2::Particle *daughter, const ConstraintConfiguration &config, bool forceFitAll)
create a custom origin particle or a beamspot
Definition: ParticleBase.cc:91
static ParticleBase * createParticle(Belle2::Particle *particle, const ParticleBase *mother, const ConstraintConfiguration &config, bool forceFitAll=false)
create the according treeFitter particle obj for a basf2 particle type
virtual int dim() const =0
get dimension of constraint
virtual int nFinalChargedCandidates() const
number of charged candidates
virtual void retrieveIndexMap(indexmap &anindexmap) const
get index map
virtual ErrCode projectMassConstraint(const FitParams &, Projection &) const
project mass constraint abstract
const ConstraintConfiguration * m_config
has all the constraint config
Definition: ParticleBase.h:204
virtual std::string parname(int index) const
get name of parameter i
static bool isAResonance(Belle2::Particle *particle)
controls if a particle is treated as a resonance(lifetime=0) or a particle that has a finite lifetime...
virtual ErrCode projectConstraint(Constraint::Type, const FitParams &, Projection &) const
project constraint.
virtual ErrCode projectMassConstraintDaughters(const FitParams &, Projection &) const
project mass constraint using the parameters of the daughters
const ParticleBase * locate(Belle2::Particle *particle) const
get particle base from basf2 particle
virtual void removeDaughter(const ParticleBase *pb)
remove daughter
Definition: ParticleBase.cc:71
bool m_isStronglyDecayingResonance
decay length less than 1 micron
Definition: ParticleBase.h:201
virtual ErrCode initCovariance(FitParams &) const
init covariance matrix
virtual int type() const =0
get particle type
Belle2::Particle * m_particle
pointer to framework type
Definition: ParticleBase.h:192
ParticleBase(Belle2::Particle *particle, const ParticleBase *mother, const ConstraintConfiguration *config=nullptr)
default constructor
Definition: ParticleBase.cc:28
virtual ErrCode projectGeoConstraint(const FitParams &, Projection &) const
project geometrical constraint
virtual double chiSquare(const FitParams &) const
get chi2
virtual int posIndex() const
get vertex index (in statevector!)
Definition: ParticleBase.h:122
std::vector< std::pair< const ParticleBase *, int > > indexmap
alias
Definition: ParticleBase.h:55
virtual int momIndex() const
get momentum index
Definition: ParticleBase.h:128
int index() const
get index
Definition: ParticleBase.h:95
virtual bool hasEnergy() const
get momentum dimension
Definition: ParticleBase.h:132
std::vector< ParticleBase * > m_daughters
daughter container
Definition: ParticleBase.h:198
std::string m_name
name
Definition: ParticleBase.h:211
virtual ~ParticleBase()
destructor, actually does something
Definition: ParticleBase.cc:55
void collectVertexDaughters(std::vector< ParticleBase * > &particles, int posindex)
get vertex daughters
virtual int tauIndex() const
get tau index
Definition: ParticleBase.h:125
const ParticleBase * mother() const
getMother() / hasMother()
Definition: ParticleBase.h:98
virtual bool hasPosition() const
get false
Definition: ParticleBase.h:135
class to store the projected residuals and the corresponding jacobian as well as the covariance matri...
Definition: Projection.h:18
representation of the Klong constraint
Definition: RecoKlong.h:16
representation of the photon constraint
Definition: RecoPhoton.h:16
A class for resonances.
Definition: RecoResonance.h:17
representation of all charged final states FIXME rename since this name is taken in tracking
Definition: RecoTrack.h:18
class for resonances as internal particles
Definition: Resonance.h:17