Belle II Software development
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 void FitManager::getCovFromPB(const ParticleBase* pb, TMatrixFSym& returncov) const
126 {
127
128 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> cov = m_fitparams->getCovariance().selfadjointView<Eigen::Lower>();
129 int posindex = pb->posIndex();
130 // hack: for tracks and photons, use the production vertex
131 if (posindex < 0 && pb->mother()) {
132 posindex = pb->mother()->posIndex();
133 }
134 int momindex = pb->momIndex();
135 if (pb->hasEnergy()) {
136 // if particle has energy, get full p4 from fitparams and put them directly in the return type
137 // very important! Belle2 uses p,E,x! Change order here!
138 for (int row = 0; row < 4; ++row) {
139 for (int col = 0; col < 4; ++col) {
140 returncov(row, col) = cov(momindex + row, momindex + col);
141 }
142 }
143
144 for (int row = 0; row < 3; ++row) {
145 for (int col = 0; col < 3; ++col) {
146 returncov(row + 4, col + 4) = cov(posindex + row, posindex + col);
147 }
148 }
149
150 } else {
151 Eigen::Matrix<double, 6, 6> cov6 =
152 Eigen::Matrix<double, 6, 6>::Zero(6, 6);
153
154 for (int row = 0; row < 3; ++row) {
155 for (int col = 0; col < 3; ++col) {
156 cov6(row, col) = cov(momindex + row, momindex + col);
157 cov6(row + 3, col + 3) = cov(posindex + row, posindex + col);
158 }
159 }
160
161 double mass = 0;
162 if (pb->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
163 mass = pb->particle()->getExtraInfo("treeFitterMassConstraintValue");
164 } else mass = pb->particle()->getPDGMass();
165 Eigen::Matrix<double, 3, 1> momVec =
166 m_fitparams->getStateVector().segment(momindex, 3);
167
168 double energy2 = momVec.transpose() * momVec;
169 energy2 += mass * mass;
170 double energy = sqrt(energy2);
171
172 Eigen::Matrix<double, 7, 6> jacobian =
173 Eigen::Matrix<double, 7, 6>::Zero(7, 6);
174
175 for (int col = 0; col < 3; ++col) {
176 jacobian(col, col) = 1;
177 jacobian(3, col) = m_fitparams->getStateVector()(momindex + col) / energy;
178 jacobian(col + 4, col + 3) = 1;
179 }
180
181 Eigen::Matrix<double, 7, 7> cov7
182 = jacobian * cov6.selfadjointView<Eigen::Lower>() * jacobian.transpose();
183
184 for (int row = 0; row < 7; ++row) {
185 for (int col = 0; col < 7; ++col) {
186 returncov(row, col) = cov7(row, col);
187 }
188 }
189 } // else
190 }
191
192 bool FitManager::updateCand(Belle2::Particle& cand, const bool isTreeHead) const
193 {
194 const ParticleBase* pb = m_decaychain->locate(&cand);
195 if (pb) {
196 updateCand(*pb, cand, isTreeHead);
197 } else {
198 B2ERROR("Can't find candidate " << cand.getName() << " in tree " << m_particle->getName());
199 }
200 return pb != nullptr;
201 }
202
204 Belle2::Particle& cand, const bool isTreeHead) const
205 {
206 int posindex = pb.posIndex();
207 if (posindex < 0 && pb.mother()) {
208 posindex = pb.mother()->posIndex();
209 }
210
211 if (m_updateDaugthers || isTreeHead) {
212 TMatrixFSym cov7b2(7);
213 if (posindex >= 0) {
214 const ROOT::Math::XYZVector pos(m_fitparams->getStateVector()(posindex),
215 m_fitparams->getStateVector()(posindex + 1),
216 m_fitparams->getStateVector()(posindex + 2));
217 cand.setVertex(pos);
218 if (&pb == m_decaychain->cand()) { // if head
219 const double fitparchi2 = m_fitparams->chiSquare();
220 cand.setPValue(TMath::Prob(fitparchi2, m_ndf));//if m_ndf<1, this is 0.
221 cand.writeExtraInfo("chiSquared", fitparchi2);
222 cand.writeExtraInfo("modifiedPValue", TMath::Prob(fitparchi2, 3));
223 cand.writeExtraInfo("ndf", m_ndf);
224 }
225 if (pb.mother()) {
226 int motherPosIndex = pb.mother()->posIndex();
227 if (motherPosIndex >= 0) {
228 cand.writeExtraInfo("prodVertexX", m_fitparams->getStateVector()(motherPosIndex));
229 cand.writeExtraInfo("prodVertexY", m_fitparams->getStateVector()(motherPosIndex + 1));
230 if (pb.mother()->dim() > 2)
231 cand.writeExtraInfo("prodVertexZ", m_fitparams->getStateVector()(motherPosIndex + 2));
232 if (not isTreeHead) {
233 getCovFromPB(pb.mother(), cov7b2);
234 cand.writeExtraInfo("prodVertSxx", cov7b2[4][4]);
235 cand.writeExtraInfo("prodVertSxy", cov7b2[4][5]);
236 cand.writeExtraInfo("prodVertSyx", cov7b2[5][4]);
237 cand.writeExtraInfo("prodVertSyy", cov7b2[5][5]);
238 if (pb.mother()->dim() > 2) {
239 cand.writeExtraInfo("prodVertexZ", m_fitparams->getStateVector()(motherPosIndex + 2));
240 cand.writeExtraInfo("prodVertSxz", cov7b2[4][6]);
241 cand.writeExtraInfo("prodVertSyz", cov7b2[5][6]);
242 cand.writeExtraInfo("prodVertSzx", cov7b2[6][4]);
243 cand.writeExtraInfo("prodVertSzy", cov7b2[6][5]);
244 cand.writeExtraInfo("prodVertSzz", cov7b2[6][6]);
245 }
246 }
247 }
248 }
249 }
250
251 const int momindex = pb.momIndex();
252 ROOT::Math::PxPyPzEVector p;
253 p.SetPx(m_fitparams->getStateVector()(momindex));
254 p.SetPy(m_fitparams->getStateVector()(momindex + 1));
255 p.SetPz(m_fitparams->getStateVector()(momindex + 2));
256 if (pb.hasEnergy()) {
257 p.SetE(m_fitparams->getStateVector()(momindex + 3));
259 } else {
260 double mass = 0;
261 if (cand.hasExtraInfo("treeFitterMassConstraintValue")) {
262 mass = cand.getExtraInfo("treeFitterMassConstraintValue");
263 } else mass = cand.getPDGMass();
264 p.SetE(std::sqrt(p.P2() + mass * mass));
266 }
267 getCovFromPB(&pb, cov7b2);
268 cand.setMomentumVertexErrorMatrix(cov7b2);
269 }
270
271 if (pb.tauIndex() > 0) {
272 const std::tuple<double, double>tau = getDecayLength(cand);
273 const std::tuple<double, double>life = getLifeTime(cand);
274 cand.writeExtraInfo("decayLength", std::get<0>(tau));
275 cand.writeExtraInfo("decayLengthErr", std::get<1>(tau));
276 cand.writeExtraInfo("lifeTime", std::get<0>(life));
277 cand.writeExtraInfo("lifeTimeErr", std::get<1>(life));
278 }
279 }
280
281 void FitManager::updateTree(Belle2::Particle& cand, const bool isTreeHead) const
282 {
283 const bool updateableMother = updateCand(cand, isTreeHead);
284
285 if (updateableMother and not cand.hasExtraInfo("bremsCorrected") and
286 not(cand.hasExtraInfo("treeFitterTreatMeAsInvisible") and cand.getExtraInfo("treeFitterTreatMeAsInvisible") == 1)) {
287 const int ndaughters = cand.getNDaughters();
288 for (int i = 0; i < ndaughters; i++) {
289 auto* daughter = const_cast<Belle2::Particle*>(cand.getDaughter(i));
290 updateTree(*daughter, false);
291 }
292 }
293 }
294
295 std::tuple<double, double> FitManager::getLifeTime(Belle2::Particle& cand) const
296 {
297 const ParticleBase* pb = m_decaychain->locate(&cand);
298
299 if (pb && pb->tauIndex() >= 0 && pb->mother()) {
300 const int momindex = pb->momIndex();
301 const int tauIndex = pb->tauIndex();
302 const Eigen::Matrix<double, 1, 3> mom_vec = m_fitparams->getStateVector().segment(momindex, 3);
303
304 const Eigen::Matrix<double, 3, 3> mom_cov = m_fitparams->getCovariance().block<3, 3>(momindex, momindex);
305 Eigen::Matrix<double, 4, 4> comb_cov = Eigen::Matrix<double, 4, 4>::Zero(4, 4);
306
307 const std::tuple<double, double> lenTuple = getDecayLength(cand);
308
309 const double lenErr = std::get<1>(lenTuple);
310 comb_cov(0, 0) = lenErr * lenErr;
311 comb_cov(1, 0) = m_fitparams->getCovariance()(momindex, tauIndex);
312 comb_cov(2, 0) = m_fitparams->getCovariance()(momindex + 1, tauIndex);
313 comb_cov(3, 0) = m_fitparams->getCovariance()(momindex + 2, tauIndex);
314
315 comb_cov.block<3, 3>(1, 1) = mom_cov;
316
317 double mass = 0;
318 if (pb->particle()->hasExtraInfo("treeFitterMassConstraintValue")) {
319 mass = pb->particle()->getExtraInfo("treeFitterMassConstraintValue");
320 } else mass = pb->particle()->getPDGMass();
321 const double mBYc = mass / Belle2::Const::speedOfLight;
322 const double mom = mom_vec.norm();
323 const double mom3 = mom * mom * mom;
324
325 const double len = std::get<0>(lenTuple);
326 const double t = len / mom * mBYc;
327
328 Eigen::Matrix<double, 1, 4> jac = Eigen::Matrix<double, 1, 4>::Zero();
329 jac(0) = 1. / mom * mBYc;
330 jac(1) = -1. * len * mom_vec(0) / mom3 * mBYc;
331 jac(2) = -1. * len * mom_vec(1) / mom3 * mBYc;
332 jac(3) = -1. * len * mom_vec(2) / mom3 * mBYc;
333
334 const double tErr2 = jac * comb_cov.selfadjointView<Eigen::Lower>() * jac.transpose();
335 // time in nanosec
336 return std::make_tuple(t, std::sqrt(tErr2));
337 }
338 return std::make_tuple(-999, -999);
339 }
340
341 std::tuple<double, double> FitManager::getDecayLength(const ParticleBase* pb) const
342 {
343 // returns the decaylength in the lab frame
344 return getDecayLength(pb, *m_fitparams);
345 }
346
347 std::tuple<double, double> FitManager::getDecayLength(const ParticleBase* pb, const FitParams& fitparams) const
348 {
349 if (pb->tauIndex() >= 0 && pb->mother()) {
350 const int tauindex = pb->tauIndex();
351 const double len = fitparams.getStateVector()(tauindex);
352 const double lenErr2 = fitparams.getCovariance()(tauindex, tauindex);
353 return std::make_tuple(len, std::sqrt(lenErr2));
354 }
355 return std::make_tuple(-999, -999);
356 }
357
358 std::tuple<double, double> FitManager::getDecayLength(Belle2::Particle& cand) const
359 {
360 std::tuple<double, double> rc = std::make_tuple(-999, -999);
361 const ParticleBase* pb = m_decaychain->locate(&cand) ;
362 if (pb && pb->tauIndex() >= 0 && pb->mother()) {
363 rc = getDecayLength(pb);
364 }
365 return rc;
366 }
367
368}//end module namespace
static const double speedOfLight
[cm/ns]
Definition Const.h:695
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()