Belle II Software development
KLMTrackFitter.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/* Own header. */
10#include <klm/modules/KLMTracking/KLMTrackFitter.h>
11
12/* KLM headers. */
13#include <klm/bklm/geometry/Module.h>
14#include <klm/bklm/geometry/GeometryPar.h>
15#include <klm/eklm/geometry/GeometryData.h>
16
17
18/* Basf2 headers. */
19#include <framework/logging/Logger.h>
20#include <framework/utilities/MathHelpers.h>
21
22/* CLHEP headers. */
23#include <CLHEP/Matrix/DiagMatrix.h>
24#include <CLHEP/Matrix/Matrix.h>
25
26/* C++ headers. */
27#include <cfloat>
28
29using namespace CLHEP;
30using namespace Belle2;
31using namespace Belle2::KLM;
32
34enum { VX = 0, VY = 1, VZ = 2 };
35
37enum { AY = 0, BY = 1, AZ = 2, BZ = 3 };
38
40enum { MY = 0, MZ = 1 };
41
44// Description: "For the use of standalone KLM tracking, this module is the fitter component.";
45 m_Valid(false),
46 m_Good(false),
47 m_Chi2(0.0),
48 m_NumHit(0),
49 m_GlobalPar(4, 0),
50 m_GlobalErr(4, 0),
51 m_GeoPar(nullptr)
52{
53}
54
59
60double KLMTrackFitter::fit(std::list<KLMHit2d* >& listHitSector)
61{
62
63 // We can only do fit if there are at least two hits
64 if (listHitSector.size() < 2) {
65 m_Valid = false;
66 m_Good = false;
67 return (false);
68 }
69
70 HepVector eta(2, 0); // ( a, b ) in y = a + bx, used as inbetween
71 HepSymMatrix error(2, 0);
72 HepVector gloEta(2, 0); // ( a, b ) in y = a + bx in global system
73 HepSymMatrix gloError(2, 0);
74 m_Chi2 = 0;
75
76 // Create temporary vector and matrix... so size can be set.
77 HepVector globalPar(4, 0);
78 HepSymMatrix globalErr(4, 0);
79
80 m_Chi2 = fit1dTrack(listHitSector, eta, error, VY, VX);
81 globalPar.sub(1, eta);
82 globalErr.sub(1, error);
83
84 //m_Chi2 += fit1dTrack(listHitSector, eta, error, VY, VZ);
85 m_Chi2 += fit1dTrack(listHitSector, eta, error, VZ, VX);
86 globalPar.sub(3, eta);
87 globalErr.sub(3, error);
88
89
90 m_Chi2 /= 2.0;
91
92 m_GlobalPar = globalPar;
93 m_GlobalErr = globalErr;
94
95 m_Valid = true;
96 m_Good = false;
97 m_NumHit = listHitSector.size();
98 if (m_Chi2 <= 20.0) {
99 m_Good = true;
100 }
101
102 return (m_Chi2);
103
104}
105
106
107
110 double& error,
111 double& sigma)
112{
113
114 if (!m_Valid) {
115 error = DBL_MAX;
116 sigma = DBL_MAX;
117 return DBL_MAX;
118 }
119
120 //in global fit, we have two functions y = a + b*x and y = c + d*z
121 double x_mea = hit->getPositionX();
122 double y_mea = hit->getPositionY();
123 double z_mea = hit->getPositionZ();
124
125 //there is some subdetector dependence so let's define this first.
126 double x_pre, y_pre, z_pre, dx, dy, dz;
127
128 // Error is composed of four parts: error due to tracking;
129 // and error in hit, y(x) or z(x).
130 HepMatrix errors(2, 2, 0); // Matrix for errors
131 HepMatrix A(2, 4, 0); // Matrix for derivatives
132
133
134 //defining quanitites for hit errors
135 double hit_xErr; double hit_yErr; double hit_zErr;
136 HepMatrix globalHitErr(3, 3, 0);
137
138 // Derivatives of y (z) = a + bx with respect to a and b.
139 A[ MY ][ AY ] = 1. ;
140 A[ MY ][ BY ] = x_mea;
141 A[ MZ ][ AZ ] = 1;
142 A[ MZ ][ BZ ] = x_mea;
143
144
145 //error from trackPar is inclueded, error from y_mea is not included
146 errors = A * m_GlobalErr * A.T();
147
149
150 // defining terms relating to distance
151 x_pre = x_mea; //by definition
152 y_pre = m_GlobalPar[ AY ] + m_GlobalPar[ BY ] * x_mea;
153 z_pre = m_GlobalPar[ AZ ] + m_GlobalPar[ BZ ] * x_mea;
154
155 const bklm::GeometryPar* bklmGeo = m_GeoPar->BarrelInstance();
156 //here get the resolustion of a hit, repeated several times, ugly. should we store this in KLMHit2d object ?
157 const bklm::Module* corMod = bklmGeo->findModule(hit->getSection(), hit->getSector(), hit->getLayer());
158 double hit_localPhiErr = corMod->getPhiStripWidth() / sqrt(12);
159 double hit_localZErr = corMod->getZStripWidth() / sqrt(12);
160
161 if (hit->inRPC()) {
162 //+++ scale localErr based on measured-in-Belle resolution
163 int nStrips = hit->getPhiStripMax() - hit->getPhiStripMin() + 1;
164 double dn = nStrips - 1.5;
165 double factor = std::pow((0.9 + 0.4 * dn * dn), 1.5) * 0.60;//measured-in-Belle resolution
166 hit_localPhiErr = hit_localPhiErr * sqrt(factor);
167
168 nStrips = hit->getZStripMax() - hit->getZStripMin() + 1;
169 dn = nStrips - 1.5;
170 factor = std::pow((0.9 + 0.4 * dn * dn), 1.5) * 0.55;//measured-in-Belle resolution
171 hit_localZErr = hit_localZErr * sqrt(factor);
172 }
173
174 Hep3Vector globalOrigin = corMod->getGlobalOrigin();
175 double sinphi = globalOrigin[1] / globalOrigin.mag();
176 double cosphi = globalOrigin[0] / globalOrigin.mag();
177
178 hit_xErr = hit_localPhiErr * sinphi;
179 hit_yErr = hit_localPhiErr * cosphi;
180 hit_zErr = hit_localZErr;
181
182
183 globalHitErr[0][0] = square(hit_xErr); //x
184 globalHitErr[0][1] = (hit_xErr) * (hit_yErr);
185 globalHitErr[0][2] = 0;
186 globalHitErr[1][1] = square(hit_yErr);;
187 globalHitErr[1][0] = (hit_xErr) * (hit_yErr);
188 globalHitErr[1][2] = 0;
189 globalHitErr[2][2] = square(hit_zErr);
190 globalHitErr[2][0] = 0;
191 globalHitErr[2][1] = 0;
192
193
194 } // end of BKLM portion
195
196 else if (hit->getSubdetector() == KLMElementNumbers::c_EKLM) {
197 // distance related (choose z variable)
198 // z coordinate should correspond to where track passes through EKLM-plane
199 z_pre = z_mea; //by design, due to EKLM geometry
200 x_pre = (z_mea - m_GlobalPar[ AZ ]) / m_GlobalPar[ BZ ];
201 y_pre = m_GlobalPar[ AY ] + m_GlobalPar[ BY ] * x_pre;
202
203 const EKLM::GeometryData* eklmGeo = m_GeoPar->EndcapInstance();
204
205 //EKLM GeometryData is needed for strip widths
206 //here get the resolustion of a hit, repeated several times, ugly. should we store this in KLMHit2d object ?
207 hit_xErr = (eklmGeo->getStripGeometry()->getWidth()) * (Unit::cm / CLHEP::cm) *
208 (hit->getXStripMax() - hit->getXStripMin() + 1) / sqrt(12);
209 hit_yErr = (eklmGeo->getStripGeometry()->getWidth()) * (Unit::cm / CLHEP::cm) *
210 (hit->getYStripMax() - hit->getYStripMin() + 1) / sqrt(12);
211 hit_zErr = 0.; //KLMHit2d is always centred on the boundary between the x/y planes with ~0 uncertainty
212
213 globalHitErr[0][0] = square(hit_xErr); //x
214 globalHitErr[0][1] = 0.;
215 globalHitErr[0][2] = 0.;
216 globalHitErr[1][1] = square(hit_yErr); //y
217 globalHitErr[1][0] = 0.;
218 globalHitErr[1][2] = 0.;
219 globalHitErr[2][2] = square(hit_zErr);; //z
220 globalHitErr[2][0] = 0.;
221 globalHitErr[2][1] = 0.;
222
223
224 } // end of EKLM section
225
226 else
227 B2FATAL("In KLMTrackFitter globalDistanceToHit, hit is neither from E/B-KLM.");
228
229 dx = x_pre - x_mea;
230 dy = y_pre - y_mea;
231 dz = z_pre - z_mea;
232 double distance = sqrt(dx * dx + dy * dy + dz * dz);
233
234 // now that we have globalHitErr, compute error
235 error = sqrt(errors[ MY ][ MY ] +
236 errors[ MZ ][ MZ ] +
237 //errors_b[0] + errors_b[1] + //error of prediced point due to error of inPos (y_mea)
238 globalHitErr[0][0] +
239 globalHitErr[1][1] + //y_mea error is correlated to the error of predicted point, but we didn't consider that part in errors
240 globalHitErr[2][2]); //we ignore y_mea error?
241
242
243 if (error != 0.0) {
244 sigma = distance / error;
245 } else {
246 sigma = DBL_MAX;
247 }
248
249 return (distance);
250}
251
252
254double KLMTrackFitter::fit1dTrack(std::list< KLMHit2d* > hitList,
255 HepVector& eta,
256 HepSymMatrix& error,
257 int depDir, int indDir)
258{
259// Fit d = a + bi, where d is dependent direction and i is independent
260// in global system we assume y = a + b*x and z = c + dx different from local fit
261// Check KLMTrackFitter::fit to see what modes are being used
262 HepMatrix globalHitErr(3, 3, 0);
263
264 double indPos = 0;
265 double depPos = 0;
266
267 // Matrix based solution
268 int noPoints = hitList.size();
269
270 // Derivative of y = a + bx, with respect to a and b evaluated at x.
271 HepMatrix A(noPoints, 2, 0);
272
273 // Measured data points.
274 HepVector y(noPoints, 0);
275
276 // Inverse of covariance (error) matrix, also known as the weight matrix.
277 // In plain English: V_y_inverse_nn = 1 / (error of nth measurement)^2
278 HepDiagMatrix V_y_inverse(noPoints, 0);
279
280 // Error or correlation matrix for coefficients (2x2 matrices)
281 HepSymMatrix V_A, V_A_inverse;
282
283
284 int n = 0;
285 for (std::list< KLMHit2d* >::iterator iHit = hitList.begin(); iHit != hitList.end(); ++iHit) {
286
287 KLMHit2d* hit = *iHit;
288
289 CLHEP::Hep3Vector globalPos(hit->getPositionX(), hit->getPositionY(), hit->getPositionZ());
290
291
293 const bklm::GeometryPar* bklmGeo = m_GeoPar->BarrelInstance();
294 const bklm::Module* corMod = bklmGeo->findModule(hit->getSection(), hit->getSector(), hit->getLayer());
295
296 double hit_localPhiErr = corMod->getPhiStripWidth() / sqrt(12);
297 double hit_localZErr = corMod->getZStripWidth() / sqrt(12);
298
299 if (hit->inRPC()) {
300 //+++ scale localErr based on measured-in-Belle resolution
301 int nStrips = hit->getPhiStripMax() - hit->getPhiStripMin() + 1;
302 double dn = nStrips - 1.5;
303 double factor = std::pow((0.9 + 0.4 * dn * dn), 1.5) * 0.60;//measured-in-Belle resolution
304 hit_localPhiErr = hit_localPhiErr * sqrt(factor);
305
306 nStrips = hit->getZStripMax() - hit->getZStripMin() + 1;
307 dn = nStrips - 1.5;
308 factor = std::pow((0.9 + 0.4 * dn * dn), 1.5) * 0.55;//measured-in-Belle resolution
309 hit_localZErr = hit_localZErr * sqrt(factor);
310 }
311
312 Hep3Vector globalOrigin = corMod->getGlobalOrigin();
313 double sinphi = globalOrigin[1] / globalOrigin.mag();
314 double cosphi = globalOrigin[0] / globalOrigin.mag();
315
316 globalHitErr[0][0] = square(hit_localPhiErr * sinphi); // x
317 globalHitErr[0][1] = (hit_localPhiErr * sinphi) * (hit_localPhiErr * cosphi);
318 globalHitErr[0][2] = 0.;
319 globalHitErr[1][1] = square(hit_localPhiErr * cosphi); // y
320 globalHitErr[1][0] = (hit_localPhiErr * sinphi) * (hit_localPhiErr * cosphi);
321 globalHitErr[1][2] = 0.;
322 globalHitErr[2][2] = square(hit_localZErr); // z
323 globalHitErr[2][0] = 0.;
324 globalHitErr[2][1] = 0.;
325
326 switch (indDir) {
327
328 case VX:
329 indPos = globalPos.x();
330 break;
331
332 case VY:
333 indPos = globalPos.y();
334 break;
335
336 case VZ:
337 indPos = globalPos.z();
338 break;
339
340 default:
341 B2DEBUG(20, "error in bklm in-TrackFit: illegal direction");
342
343 }
344
345 switch (depDir) {
346
347 case VX:
348 depPos = globalPos.x();
349 break;
350
351 case VY:
352 depPos = globalPos.y();
353 break;
354
355 case VZ:
356 depPos = globalPos.z();
357 break;
358
359 default:
360 B2DEBUG(20, "error in bklm dep-TrackFit: illegal direction");
361
362 }
363 } //end of BKLM section
364
365 else if (hit->getSubdetector() == KLMElementNumbers::c_EKLM) {
366 const EKLM::GeometryData* eklmGeo = m_GeoPar->EndcapInstance();
367
368 //here get the resolustion of a hit, repeated several times, ugly. should we store this in KLMHit2d object ?
369 double hit_xErr = (eklmGeo->getStripGeometry()->getWidth()) * (Unit::cm / CLHEP::cm) *
370 (hit->getXStripMax() - hit->getXStripMin() + 1) / sqrt(12);
371 double hit_yErr = (eklmGeo->getStripGeometry()->getWidth()) * (Unit::cm / CLHEP::cm) *
372 (hit->getYStripMax() - hit->getYStripMin() + 1) / sqrt(12);
373 double hit_zErr = 0; //KLMHit2d is always centred on the boundary between the x/y planes with ~0 uncertainty
374
375 B2DEBUG(28, "KLMTrackFitter" << " Width: " << eklmGeo->getStripGeometry()->getWidth() << " Vec_x: " << hit_xErr * sqrt(
376 12) << " Vec_y: " << hit_yErr * sqrt(12));
377
378 globalHitErr[0][0] = square(hit_xErr); //x
379 globalHitErr[0][1] = 0.;
380 globalHitErr[0][2] = 0.;
381 globalHitErr[1][1] = square(hit_yErr); //y
382 globalHitErr[1][0] = 0.;
383 globalHitErr[1][2] = 0.;
384 globalHitErr[2][2] = square(hit_zErr); //z
385 globalHitErr[2][0] = 0.;
386 globalHitErr[2][1] = 0.;
387
388
389
390 switch (indDir) {
391
392 case VX:
393 indPos = globalPos.x();
394 break;
395
396 case VY:
397 indPos = globalPos.y();
398 break;
399
400 case VZ:
401 indPos = globalPos.z();
402 break;
403
404 default:
405 B2DEBUG(20, "error in EKLM in-TrackFit: illegal direction");
406
407 }
408
409 switch (depDir) {
410
411 case VX:
412 depPos = globalPos.x();
413 break;
414
415 case VY:
416 depPos = globalPos.y();
417 break;
418
419 case VZ:
420 depPos = globalPos.z();
421 break;
422
423 default:
424 B2DEBUG(20, "error in EKLM dep-TrackFit: illegal direction");
425
426 }
427 } //end of EKLM section
428
429 A[ n ][ 0 ] = 1;
430 A[ n ][ 1 ] = indPos;
431
432 y[ n ] = depPos;
433
434 double error_raw = globalHitErr[indDir][indDir] + globalHitErr[depDir][depDir];
435 double weight = error_raw;
436 if (weight > 0) {
437 V_y_inverse[ n ][ n ] = 1.0 / weight;
438 } else {
439 V_y_inverse[ n ][ n ] = DBL_MAX;
440 }
441 ++n;//n is the index of measured points/hits
442 } // end of loop
443
444
445 V_A_inverse = V_y_inverse.similarityT(A);
446
447 int ierr = 0;
448 V_A = V_A_inverse.inverse(ierr);
449
450 eta = V_A * A.T() * V_y_inverse * y;
451 error = V_A;
452
453// Calculate residuals:
454 HepMatrix residual = y - A * eta;
455 HepMatrix chisqr = residual.T() * V_y_inverse * residual;
456
457 return (chisqr.trace());
458
459}
double getWidth() const
Get width.
const StripGeometry * getStripGeometry() const
Get strip geometry data.
EKLM geometry data.
KLM 2d hit.
Definition KLMHit2d.h:33
bool inRPC() const
Determine whether this 2D hit is in RPC or scintillator.
Definition KLMHit2d.h:185
int getSubdetector() const
Get subdetector number.
Definition KLMHit2d.h:78
int getYStripMin() const
Get first strip number for EKLM hit in the y-measuring plane.
Definition KLMHit2d.h:258
int getLayer() const
Get layer number.
Definition KLMHit2d.h:132
int getZStripMax() const
Get last strip number for z plane.
Definition KLMHit2d.h:202
int getSection() const
Get section number.
Definition KLMHit2d.h:96
float getPositionZ() const
Get hit global position z coordinate.
Definition KLMHit2d.h:306
int getSector() const
Get sector number.
Definition KLMHit2d.h:114
float getPositionX() const
Get hit global position x coordinate.
Definition KLMHit2d.h:288
int getPhiStripMin() const
Get strip number for phi plane.
Definition KLMHit2d.h:218
int getZStripMin() const
Get strip number for z plane.
Definition KLMHit2d.h:194
int getXStripMax() const
Get last strip number for EKLM hit in the x-measuring plane.
Definition KLMHit2d.h:250
int getPhiStripMax() const
Get last strip number for phi plane.
Definition KLMHit2d.h:226
float getPositionY() const
Get hit global position y coordinate.
Definition KLMHit2d.h:297
int getYStripMax() const
Get last strip number for EKLM hit in the y-measuring plane.
Definition KLMHit2d.h:266
int getXStripMin() const
Get first strip number for EKLM hit in the x-measuring plane.
Definition KLMHit2d.h:242
double fit(std::list< KLMHit2d * > &listTrackPoint)
do fit and returns chi square of the fit.
float m_Chi2
Chi square of fit.
double fit1dTrack(std::list< KLMHit2d * > hitList, CLHEP::HepVector &eta, CLHEP::HepSymMatrix &error, int depDir, int indDir)
do fit in the global system
int m_NumHit
the number of hits on this track
double globalDistanceToHit(KLMHit2d *hit, double &error, double &sigma)
Distance from track to a hit in the global system.
Belle2::KLM::KLMGeometryPar * m_GeoPar
pointer to GeometryPar singleton
CLHEP::HepSymMatrix m_GlobalErr
track params errors in global system
CLHEP::HepVector m_GlobalPar
track params in global system
bool m_Valid
Is fit valid.
KLMTrackFitter()
Default constructor.
bool m_Good
Is fit good.
static const double cm
Standard units with the value = 1.
Definition Unit.h:47
Provides BKLM geometry parameters for simulation, reconstruction etc (from Gearbox or DataBase)
Definition GeometryPar.h:37
const Module * findModule(int section, int sector, int layer) const
Get the pointer to the definition of a module.
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition Module.h:76
double getPhiStripWidth() const
Get phi-strip width.
Definition Module.h:137
const CLHEP::Hep3Vector getGlobalOrigin() const
Return the position (in global coordinates) of this module's sensitive-volume origin.
Definition Module.h:285
double getZStripWidth() const
Get z-strip width.
Definition Module.h:155
constexpr T square(const T &x)
Calculate the square of the input.
Definition MathHelpers.h:21
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.