Belle II Software light-2607-kasei
FitManager.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#include <TMath.h>
10#include <Math/Vector4D.h>
11
12#include <analysis/dataobjects/Particle.h>
13
14#include <framework/logging/Logger.h>
15#include <framework/gearbox/Const.h>
16
17#include <analysis/VertexFitting/TreeFitter/FitManager.h>
18#include <analysis/VertexFitting/TreeFitter/FitParams.h>
19#include <analysis/VertexFitting/TreeFitter/DecayChain.h>
20#include <analysis/VertexFitting/TreeFitter/ParticleBase.h>
21
22namespace TreeFitter {
23
25 const ConstraintConfiguration& config,
26 double prec,
27 bool updateDaughters
28 ) :
30 m_decaychain(nullptr),
31 m_status(VertexStatus::UnFitted),
32 m_chiSquare(-1),
33 m_prec(prec),
34 m_updateDaugthers(updateDaughters),
35 m_ndf(0),
36 m_fitparams(nullptr),
37 m_config(config)
38 {
39 m_decaychain = new DecayChain(particle, config, false);
41 }
42
44 {
45 delete m_decaychain;
46 delete m_fitparams;
47 }
48
50 {
51 const int nitermax = 100;
52 const int maxndiverging = 3;
53 const double dChisqConv = m_prec;
54 m_chiSquare = -1;
55 m_errCode.reset();
56
57 if (m_status == VertexStatus::UnFitted) {
58 m_errCode = m_decaychain->initialize(*m_fitparams);
59 }
60
61 if (m_errCode.failure()) {
62 m_status = VertexStatus::BadInput;
63 } else {
64 m_status = VertexStatus::UnFitted;
65 int ndiverging = 0;
66 bool finished = false;
67 int niter = 0;
68 for (niter = 0; niter < nitermax && !finished; ++niter) {
69 if (niter == 0) {
71 } else {
72 auto* tempState = new FitParams(*m_fitparams);
73 m_errCode = m_decaychain->filterWithReference(*m_fitparams, *tempState);
74 delete tempState;
75 }
76 m_ndf = m_fitparams->nDof();
77 double chisq = m_fitparams->chiSquare();
78 double deltachisq = chisq - m_chiSquare;
79 if (m_errCode.failure()) {
80 finished = true ;
81 m_status = VertexStatus::Failed;
82 m_particle->writeExtraInfo("failed", 1);
83 } else {
84 if (niter > 0) {
85 if ((std::abs(deltachisq) / m_chiSquare < dChisqConv)) {
86 m_chiSquare = chisq;
87 m_status = VertexStatus::Success;
88 finished = true ;
89 m_particle->writeExtraInfo("failed", 0);
90 } else if (deltachisq > 0 && ++ndiverging >= maxndiverging) {
91 m_particle->writeExtraInfo("failed", 2);
92 m_status = VertexStatus::NonConverged;
93 m_errCode = ErrCode(ErrCode::Status::slowdivergingfit);
94 finished = true ;
95 }
96 }
97 if (deltachisq < 0) {
98 ndiverging = 0;
99 }
100 m_chiSquare = chisq;
101 }
102 }
103 if (niter == nitermax && m_status != VertexStatus::Success) {
104 m_particle->writeExtraInfo("failed", 3);
105 m_status = VertexStatus::NonConverged;
106 }
107 if (!(m_fitparams->testCovariance())) {
108 m_particle->writeExtraInfo("failed", 4);
109 m_status = VertexStatus::Failed;
110 }
111 }
112
113 if (m_status == VertexStatus::Success) {
114 // mass constraints comes after kine so we have to
115 // update the mothers with the values set by the mass constraint
116 if (m_config.m_massConstraintListPDG.size() != 0) {
117 m_decaychain->locate(m_particle)->forceP4Sum(*m_fitparams);
118 }
119 updateTree(*m_particle, true);
120 }
121
122 return (m_status == VertexStatus::Success);
123 }
124
125 // returncov is an output parameter: ROOT's const operator() overload hides the
126 // assignments below from cppcheck
127 // cppcheck-suppress constParameterReference
128 void FitManager::getCovFromPB(const ParticleBase* pb, TMatrixFSym& returncov) const
129 {
130
131 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> cov = m_fitparams->getCovariance().selfadjointView<Eigen::Lower>();
132 int posindex = pb->posIndex();
133 // hack: for tracks and photons, use the production vertex
134 if (posindex < 0 && pb->mother()) {
135 posindex = pb->mother()->posIndex();
136 }
137 int momindex = pb->momIndex();
138 if (pb->hasEnergy()) {
139 // if particle has energy, get full p4 from fitparams and put them directly in the return type
140 // very important! Belle2 uses p,E,x! Change order here!
141 for (int row = 0; row < 4; ++row) {
142 for (int col = 0; col < 4; ++col) {
143 returncov(row, col) = cov(momindex + row, momindex + col);
144 }
145 }
146
147 for (int row = 0; row < 3; ++row) {
148 for (int col = 0; col < 3; ++col) {
149 returncov(row + 4, col + 4) = cov(posindex + row, posindex + col);
150 }
151 }
152
153 } else {
154 Eigen::Matrix<double, 6, 6> cov6 =
155 Eigen::Matrix<double, 6, 6>::Zero(6, 6);
156
157 for (int row = 0; row < 3; ++row) {
158 for (int col = 0; col < 3; ++col) {
159 cov6(row, col) = cov(momindex + row, momindex + col);
160 cov6(row + 3, col + 3) = cov(posindex + row, posindex + col);
161 }
162 }
163
164 double mass = 0;
165 if (pb->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
166 mass = pb->particle()->getExtraInfo("treeFitterMassConstraintValue");
167 } else mass = pb->particle()->getPDGMass();
168 Eigen::Matrix<double, 3, 1> momVec =
169 m_fitparams->getStateVector().segment(momindex, 3);
170
171 double energy2 = momVec.transpose() * momVec;
172 energy2 += mass * mass;
173 double energy = sqrt(energy2);
174
175 Eigen::Matrix<double, 7, 6> jacobian =
176 Eigen::Matrix<double, 7, 6>::Zero(7, 6);
177
178 for (int col = 0; col < 3; ++col) {
179 jacobian(col, col) = 1;
180 jacobian(3, col) = m_fitparams->getStateVector()(momindex + col) / energy;
181 jacobian(col + 4, col + 3) = 1;
182 }
183
184 Eigen::Matrix<double, 7, 7> cov7
185 = jacobian * cov6.selfadjointView<Eigen::Lower>() * jacobian.transpose();
186
187 for (int row = 0; row < 7; ++row) {
188 for (int col = 0; col < 7; ++col) {
189 returncov(row, col) = cov7(row, col);
190 }
191 }
192 } // else
193 }
194
195 bool FitManager::updateCand(Belle2::Particle& cand, const bool isTreeHead) const
196 {
197 const ParticleBase* pb = m_decaychain->locate(&cand);
198 if (pb) {
199 updateCand(*pb, cand, isTreeHead);
200 } else {
201 B2ERROR("Can't find candidate " << cand.getName() << " in tree " << m_particle->getName());
202 }
203 return pb != nullptr;
204 }
205
207 Belle2::Particle& cand, const bool isTreeHead) const
208 {
209 int posindex = pb.posIndex();
210 if (posindex < 0 && pb.mother()) {
211 posindex = pb.mother()->posIndex();
212 }
213
214 if (m_updateDaugthers || isTreeHead) {
215 TMatrixFSym cov7b2(7);
216 if (posindex >= 0) {
217 const ROOT::Math::XYZVector pos(m_fitparams->getStateVector()(posindex),
218 m_fitparams->getStateVector()(posindex + 1),
219 m_fitparams->getStateVector()(posindex + 2));
220 cand.setVertex(pos);
221 if (&pb == m_decaychain->cand()) { // if head
222 const double fitparchi2 = m_fitparams->chiSquare();
223 cand.setPValue(TMath::Prob(fitparchi2, m_ndf));//if m_ndf<1, this is 0.
224 cand.writeExtraInfo("chiSquared", fitparchi2);
225 cand.writeExtraInfo("modifiedPValue", TMath::Prob(fitparchi2, 3));
226 cand.writeExtraInfo("ndf", m_ndf);
227 }
228 if (pb.mother()) {
229 int motherPosIndex = pb.mother()->posIndex();
230 if (motherPosIndex >= 0) {
231 cand.writeExtraInfo("prodVertexX", m_fitparams->getStateVector()(motherPosIndex));
232 cand.writeExtraInfo("prodVertexY", m_fitparams->getStateVector()(motherPosIndex + 1));
233 if (pb.mother()->dim() > 2)
234 cand.writeExtraInfo("prodVertexZ", m_fitparams->getStateVector()(motherPosIndex + 2));
235 if (not isTreeHead) {
236 getCovFromPB(pb.mother(), cov7b2);
237 cand.writeExtraInfo("prodVertSxx", cov7b2[4][4]);
238 cand.writeExtraInfo("prodVertSxy", cov7b2[4][5]);
239 cand.writeExtraInfo("prodVertSyx", cov7b2[5][4]);
240 cand.writeExtraInfo("prodVertSyy", cov7b2[5][5]);
241 if (pb.mother()->dim() > 2) {
242 cand.writeExtraInfo("prodVertexZ", m_fitparams->getStateVector()(motherPosIndex + 2));
243 cand.writeExtraInfo("prodVertSxz", cov7b2[4][6]);
244 cand.writeExtraInfo("prodVertSyz", cov7b2[5][6]);
245 cand.writeExtraInfo("prodVertSzx", cov7b2[6][4]);
246 cand.writeExtraInfo("prodVertSzy", cov7b2[6][5]);
247 cand.writeExtraInfo("prodVertSzz", cov7b2[6][6]);
248 }
249 }
250 }
251 }
252 }
253
254 const int momindex = pb.momIndex();
255 ROOT::Math::PxPyPzEVector p;
256 p.SetPx(m_fitparams->getStateVector()(momindex));
257 p.SetPy(m_fitparams->getStateVector()(momindex + 1));
258 p.SetPz(m_fitparams->getStateVector()(momindex + 2));
259 if (pb.hasEnergy()) {
260 p.SetE(m_fitparams->getStateVector()(momindex + 3));
262 } else {
263 double mass = 0;
264 if (cand.hasExtraInfo("treeFitterMassConstraintValue")) {
265 mass = cand.getExtraInfo("treeFitterMassConstraintValue");
266 } else mass = cand.getPDGMass();
267 p.SetE(std::sqrt(p.P2() + mass * mass));
269 }
270 getCovFromPB(&pb, cov7b2);
271 cand.setMomentumVertexErrorMatrix(cov7b2);
272 }
273
274 if (pb.tauIndex() > 0) {
275 const std::tuple<double, double>tau = getDecayLength(cand);
276 const std::tuple<double, double>life = getLifeTime(cand);
277 cand.writeExtraInfo("decayLength", std::get<0>(tau));
278 cand.writeExtraInfo("decayLengthErr", std::get<1>(tau));
279 cand.writeExtraInfo("lifeTime", std::get<0>(life));
280 cand.writeExtraInfo("lifeTimeErr", std::get<1>(life));
281 }
282 }
283
284 void FitManager::updateTree(Belle2::Particle& cand, const bool isTreeHead) const
285 {
286 const bool updateableMother = updateCand(cand, isTreeHead);
287
288 if (updateableMother and not cand.hasExtraInfo("bremsCorrected") and
289 not(cand.hasExtraInfo("treeFitterTreatMeAsInvisible") and cand.getExtraInfo("treeFitterTreatMeAsInvisible") == 1)) {
290 const int ndaughters = cand.getNDaughters();
291 for (int i = 0; i < ndaughters; i++) {
292 auto* daughter = const_cast<Belle2::Particle*>(cand.getDaughter(i));
293 updateTree(*daughter, false);
294 }
295 }
296 }
297
298 std::tuple<double, double> FitManager::getLifeTime(Belle2::Particle& cand) const
299 {
300 const ParticleBase* pb = m_decaychain->locate(&cand);
301
302 if (pb && pb->tauIndex() >= 0 && pb->mother()) {
303 const int momindex = pb->momIndex();
304 const int tauIndex = pb->tauIndex();
305 const Eigen::Matrix<double, 1, 3> mom_vec = m_fitparams->getStateVector().segment(momindex, 3);
306
307 const Eigen::Matrix<double, 3, 3> mom_cov = m_fitparams->getCovariance().block<3, 3>(momindex, momindex);
308 Eigen::Matrix<double, 4, 4> comb_cov = Eigen::Matrix<double, 4, 4>::Zero(4, 4);
309
310 const std::tuple<double, double> lenTuple = getDecayLength(cand);
311
312 const double lenErr = std::get<1>(lenTuple);
313 comb_cov(0, 0) = lenErr * lenErr;
314 comb_cov(1, 0) = m_fitparams->getCovariance()(momindex, tauIndex);
315 comb_cov(2, 0) = m_fitparams->getCovariance()(momindex + 1, tauIndex);
316 comb_cov(3, 0) = m_fitparams->getCovariance()(momindex + 2, tauIndex);
317
318 comb_cov.block<3, 3>(1, 1) = mom_cov;
319
320 double mass = 0;
321 if (pb->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
322 mass = pb->particle()->getExtraInfo("treeFitterMassConstraintValue");
323 } else mass = pb->particle()->getPDGMass();
324 const double mBYc = mass / Belle2::Const::speedOfLight;
325 const double mom = mom_vec.norm();
326 const double mom3 = mom * mom * mom;
327
328 const double len = std::get<0>(lenTuple);
329 const double t = len / mom * mBYc;
330
331 Eigen::Matrix<double, 1, 4> jac = Eigen::Matrix<double, 1, 4>::Zero();
332 jac(0) = 1. / mom * mBYc;
333 jac(1) = -1. * len * mom_vec(0) / mom3 * mBYc;
334 jac(2) = -1. * len * mom_vec(1) / mom3 * mBYc;
335 jac(3) = -1. * len * mom_vec(2) / mom3 * mBYc;
336
337 const double tErr2 = jac * comb_cov.selfadjointView<Eigen::Lower>() * jac.transpose();
338 // time in nanosec
339 return std::make_tuple(t, std::sqrt(tErr2));
340 }
341 return std::make_tuple(-999, -999);
342 }
343
344 std::tuple<double, double> FitManager::getDecayLength(const ParticleBase* pb) const
345 {
346 // returns the decaylength in the lab frame
347 return getDecayLength(pb, *m_fitparams);
348 }
349
350 std::tuple<double, double> FitManager::getDecayLength(const ParticleBase* pb, const FitParams& fitparams)
351 {
352 if (pb->tauIndex() >= 0 && pb->mother()) {
353 const int tauindex = pb->tauIndex();
354 const double len = fitparams.getStateVector()(tauindex);
355 const double lenErr2 = fitparams.getCovariance()(tauindex, tauindex);
356 return std::make_tuple(len, std::sqrt(lenErr2));
357 }
358 return std::make_tuple(-999, -999);
359 }
360
361 std::tuple<double, double> FitManager::getDecayLength(Belle2::Particle& cand) const
362 {
363 std::tuple<double, double> rc = std::make_tuple(-999, -999);
364 const ParticleBase* pb = m_decaychain->locate(&cand) ;
365 if (pb && pb->tauIndex() >= 0 && pb->mother()) {
366 rc = getDecayLength(pb);
367 }
368 return rc;
369 }
370
371}//end module namespace
static const double speedOfLight
[cm/ns]
Definition Const.h:696
Class to store reconstructed particles.
Definition Particle.h:76
std::string getName() const override
Return name of this particle.
Definition Particle.cc:1250
void writeExtraInfo(const std::string &name, const double value)
Sets the user defined extraInfo.
Definition Particle.cc:1393
void setVertex(const ROOT::Math::XYZVector &vertex)
Sets position (decay vertex)
Definition Particle.h:306
void set4VectorDividingByMomentumScaling(const ROOT::Math::PxPyPzEVector &p4)
Sets Lorentz vector dividing by the momentum scaling factor.
Definition Particle.h:294
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition Particle.cc:1351
unsigned getNDaughters(void) const
Returns number of daughter particles.
Definition Particle.h:747
double getPDGMass(void) const
Returns uncertainty on the invariant mass (requires valid momentum error matrix)
Definition Particle.cc:635
void setMomentumVertexErrorMatrix(const TMatrixFSym &errMatrix)
Sets 7x7 error matrix.
Definition Particle.cc:424
void setPValue(double pValue)
Sets chi^2 probability of fit.
Definition Particle.h:377
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition Particle.cc:662
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition Particle.cc:1374
this class does a lot of stuff: Build decaytree structure allowing to index particles and handle the ...
Definition DecayChain.h:21
abstract errorocode be aware that the default is success
Definition ErrCode.h:14
const ConstraintConfiguration m_config
config container
Definition FitManager.h:116
DecayChain * m_decaychain
the decay tree
Definition FitManager.h:92
FitManager()
constructor
Definition FitManager.h:36
Belle2::Particle * particle()
getter for the head of the tree
Definition FitManager.h:85
ErrCode m_errCode
errorcode
Definition FitManager.h:104
void getCovFromPB(const ParticleBase *pb, TMatrixFSym &returncov) const
extract cov from particle base
void updateTree(Belle2::Particle &particle, const bool isTreeHead) const
update the Belle2::Particles with the fit results
FitParams * m_fitparams
parameters to be fitted
Definition FitManager.h:113
const bool m_updateDaugthers
if this is set all daughters will be updated otherwise only the head of the tree
Definition FitManager.h:107
~FitManager()
destructor does stuff
Definition FitManager.cc:43
int m_ndf
number of degrees of freedom for this topology
Definition FitManager.h:110
double m_prec
precision that is needed for status:converged (delta chi2)
Definition FitManager.h:101
bool fit()
main fit function that uses the kalman filter
Definition FitManager.cc:49
int m_status
status of the current iteration
Definition FitManager.h:95
Belle2::Particle * m_particle
head of the tree
Definition FitManager.h:89
double m_chiSquare
chi2 of the current iteration
Definition FitManager.h:98
VertexStatus
status flag of the fit-itereation (the step in the newton method)
Definition FitManager.h:33
std::tuple< double, double > getLifeTime(Belle2::Particle &cand) const
get lifetime
std::tuple< double, double > getDecayLength(const ParticleBase *pb) const
get decay length
bool updateCand(Belle2::Particle &particle, const bool isTreeHead) const
update particles parameters with the fit results
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
base class for all particles
Belle2::Particle * particle() const
get basf2 particle
virtual int dim() const =0
get dimension of constraint
virtual int posIndex() const
get vertex index (in statevector!)
virtual int momIndex() const
get momentum index
virtual bool hasEnergy() const
get momentum dimension
virtual int tauIndex() const
get tau index
const ParticleBase * mother() const
getMother() / hasMother()