Belle II Software development
KFitV0VertexFitter.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#include <tracking/v0Finding/fitter/KFitV0VertexFitter.h>
9
10#include <framework/geometry/BFieldManager.h>
11#include <framework/logging/Logger.h>
12#include <framework/particledb/EvtGenDatabasePDG.h>
13
14#include <analysis/utility/ROOTToCLHEP.h>
15#include <analysis/utility/CLHEPToROOT.h>
16#include <analysis/VertexFitting/KFit/KFitError.h>
17#include <analysis/VertexFitting/KFit/VertexFitKFit.h>
18
19#include <genfit/Track.h>
20#include <genfit/MeasuredStateOnPlane.h>
21#include <genfit/FitStatus.h>
22#include <genfit/GFRaveVertex.h>
23#include <genfit/GFRaveTrackParameters.h>
24
25#include <TParticlePDG.h>
26
27#include <cmath>
28
29using namespace Belle2;
30
31namespace {
32
33 CLHEP::HepSymMatrix makeCov7x7(
34 const TMatrixDSym& cov6,
35 const CLHEP::HepLorentzVector& p4)
36 {
37 // ordering expected by KFit:
38 // (px,py,pz,E,x,y,z)
39 // cov6 from getPosMomCov has ordering:
40 // (x,y,z,px,py,pz)
41 // so we need to reindex: KFit 0,1,2 (px,py,pz) <- cov6 3,4,5
42 // KFit 4,5,6 (x,y,z) <- cov6 0,1,2
43 constexpr int toCov6[7] = {3, 4, 5, -1, 0, 1, 2}; // -1 = E, handled separately
44 constexpr int pIdx[3] = {3, 4, 5}; // momentum indices in cov6
45
46 CLHEP::HepSymMatrix cov7(7, 0);
47
48 // copy 6x6 block (lower triangle only), skipping E (index 3)
49 for (int i = 0; i < 7; ++i) {
50 if (i == 3) continue;
51 for (int j = i; j < 7; ++j) {
52 if (j == 3) continue;
53 cov7[j][i] = cov6(toCov6[j], toCov6[i]);
54 }
55 }
56
57 // calculate E-related derivatives
58 const double E = p4.e();
59 const double dEdp[3] = {
60 p4.px() / E,
61 p4.py() / E,
62 p4.pz() / E
63 };
64
65 // cov(E, i) for all i != E (lower triangle only)
66 for (int i = 0; i < 7; ++i) {
67 if (i == 3) continue;
68 double covEi = 0.0;
69 for (int k = 0; k < 3; ++k) {
70 covEi += cov6(toCov6[i], pIdx[k]) * dEdp[k];
71 }
72 // index 3 is E; since i != 3, we always have i < 3 or i > 3
73 if (i < 3) {
74 cov7[3][i] = covEi; // lower triangle: row > col
75 } else {
76 cov7[i][3] = covEi; // lower triangle: row > col
77 }
78 }
79
80 // cov(E,E)
81 double covEE = 0.0;
82 for (int i = 0; i < 3; ++i) {
83 for (int j = 0; j < 3; ++j) {
84 covEE += cov6(pIdx[i], pIdx[j]) * dEdp[i] * dEdp[j];
85 }
86 }
87 cov7[3][3] = covEE;
88
89 return cov7;
90 }
91
92 double getMagneticField()
93 {
94 const double bZ = BFieldManager::getFieldInTesla({0, 0, 0}).Z();
95 // KFit handles a null field analytically, as a straight-line fit (see VertexFitKFit::makeCoreMatrix),
96 // while a residual field would take the helix branch and make it ill-conditioned:
97 // snap to zero what cannot bend a track (1 uT bends a 100 MeV/c track by less than 1 um per meter of flight).
98 return std::abs(bZ) > 1e-6 ? bZ : 0.;
99 }
100
101}
102
103bool KFitV0VertexFitter::fit(genfit::Track& trackPlus, genfit::Track& trackMinus, const int pdgTrackPlus,
104 const int pdgTrackMinus, genfit::GFRaveVertex& vertex)
105{
106 analysis::VertexFitKFit vertexFit;
107 // KFit defaults to KFitConst::kDefaultMagneticField:
108 // use instead the same magnetic field used elsewhere in the V0Fitter
109 vertexFit.setMagneticField(getMagneticField());
110
112
113 auto addTrackToFit =
114 [&](const genfit::Track & track, const int pdg) {
115 const TParticlePDG* particle = pdgDB->GetParticle(pdg);
116 if (not particle) {
117 B2ERROR("Unknown PDG code of the daughter hypothesis." << LogVar("PDG code", pdg));
118 return false;
119 }
120 TVector3 pos;
121 TVector3 mom;
122 // KFit needs the 7x7 cov. matrix, not the 6x6 one:
123 // in the 6x6 one, correlations with E are missing.
124 TMatrixDSym cov6;
125 const genfit::MeasuredStateOnPlane state = track.getFittedState();
126 state.getPosMomCov(pos, mom, cov6);
127 // the mass is used only to complete the energy: the vertex fit itself drops it
128 const double mass = particle->Mass();
129 const CLHEP::HepLorentzVector clhepMom(mom.X(), mom.Y(), mom.Z(), std::sqrt(mom.Mag2() + mass * mass));
130 const HepGeom::Point3D<double> clhepPos(pos.X(), pos.Y(), pos.Z());
131 // This is now good for KFit
132 const CLHEP::HepSymMatrix clhepCov7 = makeCov7x7(cov6, clhepMom);
133 const int charge = track.getFitStatus()->getCharge();
134
135 vertexFit.addTrack(clhepMom, clhepPos, clhepCov7, charge);
136 return true;
137 };
138
139 try {
140 if (not addTrackToFit(trackPlus, pdgTrackPlus)) return false;
141 if (not addTrackToFit(trackMinus, pdgTrackMinus)) return false;
142 } catch (...) {
143 B2ERROR("Exception during vertex fit.");
144 return false;
145 }
146
147 const bool ok = (vertexFit.doFit() == analysis::KFitError::kNoError);
148 if (!ok) return false;
149
150 const HepGeom::Point3D<double> posVertex = vertexFit.getVertex();
151 const CLHEP::HepSymMatrix covVertex = vertexFit.getVertexError();
152 const TVector3 extrapolationTarget(posVertex.x(), posVertex.y(), posVertex.z());
153
154 std::vector<genfit::GFRaveTrackParameters*> trackParamsVertex;
155 trackParamsVertex.reserve(2);
156 for (int i = 0; i <= 1; ++i) {
157 const genfit::Track& daughter = i == 0 ? trackPlus : trackMinus;
158 // KFit gives back the daughter parameters at the reference point of the track:
159 // the momentum there points elsewhere than at the vertex. Transport the daughter
160 // to the vertex position with genfit instead.
161 TVector3 pos;
162 TVector3 mom;
163 TMatrixDSym cov6;
164 try {
165 genfit::MeasuredStateOnPlane daughterState = daughter.getFittedState();
166 daughterState.extrapolateToPoint(extrapolationTarget);
167 daughterState.getPosMomCov(pos, mom, cov6);
168 } catch (...) {
169 B2ERROR("Exception while extrapolating a daughter to the fitted vertex.");
170 for (auto* trackParams : trackParamsVertex) delete trackParams;
171 return false;
172 }
173 TVectorD state{6};
174 state[0] = pos.X();
175 state[1] = pos.Y();
176 state[2] = pos.Z();
177 state[3] = mom.X();
178 state[4] = mom.Y();
179 state[5] = mom.Z();
180 genfit::GFRaveTrackParameters* trackParams = new genfit::GFRaveTrackParameters(nullptr, nullptr, 1, state, cov6, true);
181 trackParamsVertex.push_back(trackParams);
182 }
183 const double ndfVertex = static_cast<double>(vertexFit.getNDF());
184 const double chisqVertex = vertexFit.getCHIsq();
185
186 vertex = genfit::GFRaveVertex{TVector3{posVertex.x(), posVertex.y(), posVertex.z()}, CLHEPToROOT::getTMatrixDSym(covVertex), trackParamsVertex, ndfVertex, chisqVertex};
187
188 return true;
189}
R E
internal precision of FFTW codelets
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
Replacement for TDatabasePDG that is filled from EvtGen's evt.pdl.
static EvtGenDatabasePDG * Instance()
Instance method that loads the EvtGen table.
bool fit(genfit::Track &trackPlus, genfit::Track &trackMinus, const int pdgTrackPlus, const int pdgTrackMinus, genfit::GFRaveVertex &vertex) override
Fit the V0 vertex. The PDG codes of the daughters are used to compute their energies.
enum KFitError::ECode addTrack(const KFitTrack &kp)
Add a track to the fitter object.
Definition KFitBase.cc:38
virtual double getCHIsq(void) const
Get a chi-square of the fit.
Definition KFitBase.cc:121
virtual int getNDF(void) const
Get an NDF of the fit.
Definition KFitBase.cc:114
enum KFitError::ECode setMagneticField(const double mf)
Change a magnetic field from the default value KFitConst::kDefaultMagneticField.
Definition KFitBase.cc:93
VertexFitKFit is a derived class from KFitBase to perform vertex-constraint kinematical fit.
const CLHEP::HepSymMatrix getVertexError(void) const
Get a fitted vertex error matrix.
enum KFitError::ECode doFit(void)
Perform a vertex-constraint fit.
const HepPoint3D getVertex(const int flag=KFitConst::kAfterFit) const
Get a vertex position.
Class to store variables with their name which were sent to the logging service.
Abstract base class for different kinds of events.