Project
Loading...
Searching...
No Matches
TrackFitter.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
17#include "MFTBase/Constants.h"
19#include "MFTTracking/TrackCA.h"
20#include "MFTTracking/Cluster.h"
24#include <stdexcept>
25#include <TMath.h>
26#include <TMatrixD.h>
27#include <TF1.h>
28#include <TF2.h>
30#include "MathUtils/fit.h"
31#include "MathUtils/Utils.h"
32
34
35namespace o2
36{
37namespace mft
38{
39
40//_________________________________________________________________________________________________
41template <typename T>
42bool TrackFitter<T>::fit(T& track, bool outward)
43{
46
47 auto nClusters = track.getNumberOfPoints();
48 auto lastLayer = track.getLayers()[(outward ? 0 : nClusters - 1)];
49
50 if (mVerbose) {
51 std::cout << "Seed covariances: \n"
52 << track.getCovariances() << std::endl
53 << std::endl;
54 }
55
56 // recursively compute clusters, updating the track parameters
57 if (!outward) { // Inward for vertexing
58 while (nClusters-- > 0) {
59 if (!computeCluster(track, nClusters, lastLayer)) {
60 return false;
61 }
62 }
63 } else { // Outward for MCH matching
64 int ncl = 0;
65 while (ncl < nClusters) {
66 if (!computeCluster(track, ncl, lastLayer)) {
67 return false;
68 }
69 ncl++;
70 }
71 }
72 if (mVerbose) {
73 std::cout << "Track Chi2 = " << track.getTrackChi2() << std::endl;
74 std::cout << " ***************************** Done fitting *****************************\n";
75 }
76
77 return true;
78}
79
80//_________________________________________________________________________________________________
81template <typename T>
82bool TrackFitter<T>::initTrack(T& track, bool outward)
83{
84
85 if constexpr (std::is_same<T, o2::mft::TrackLTF>::value) { // Magnet on
86 // initialize the starting track parameters
87 double sigmainvQPtsq;
88 double chi2invqptquad;
89 auto invQPt0 = invQPtFromFCF(track, mBZField, sigmainvQPtsq);
90 auto nPoints = track.getNumberOfPoints();
91 auto k = TMath::Abs(o2::constants::math::B2C * mBZField);
92 auto Hz = std::copysign(1, mBZField);
93
94 if (mVerbose) {
95 std::cout << "\n ***************************** Start Fitting new track ***************************** \n";
96 std::cout << "N Clusters = " << nPoints << std::endl;
97 }
98
99 track.setInvQPtSeed(invQPt0);
100 track.setChi2QPtSeed(chi2invqptquad);
101 track.setInvQPt(invQPt0);
102
104 int first_cls, next_cls;
105 if (outward) { // MCH matching
106 first_cls = 0;
107 next_cls = nPoints - 1;
108 } else { // Vertexing
109 first_cls = nPoints - 1;
110 next_cls = 0;
111 }
112
113 auto x0 = track.getXCoordinates()[first_cls];
114 auto y0 = track.getYCoordinates()[first_cls];
115 auto z0 = track.getZCoordinates()[first_cls];
116
117 // Compute tanl using first two clusters
118 auto deltaX = track.getXCoordinates()[1] - track.getXCoordinates()[0];
119 auto deltaY = track.getYCoordinates()[1] - track.getYCoordinates()[0];
120 auto deltaZ = track.getZCoordinates()[1] - track.getZCoordinates()[0];
121 auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
122 auto tanl0 = -std::abs(deltaZ / deltaR);
123
124 // Compute phi at the last cluster using two last clusters
125 deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[next_cls];
126 deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[next_cls];
127 deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[next_cls];
128 deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
129 double phi0;
130 if (outward) {
131 phi0 = TMath::ATan2(-deltaY, -deltaX) - 0.5 * Hz * invQPt0 * deltaZ * k / tanl0;
132 } else {
133 phi0 = TMath::ATan2(deltaY, deltaX) - 0.5 * Hz * invQPt0 * deltaZ * k / tanl0;
134 }
135 // The low momentum phi0 correction may be irrelevant and may require a call to o2::math_utils::bringToPMPiGend(phi0);
136
137 track.setX(x0);
138 track.setY(y0);
139 track.setZ(z0);
140 track.setPhi(phi0);
141 track.setTanl(tanl0);
142
143 if (mVerbose) {
144 std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << (outward ? " (outward)" : " (inward)") << std::endl;
145 auto model = (mTrackModel == Helix) ? "Helix" : (mTrackModel == Quadratic) ? "Quadratic"
146 : (mTrackModel == Optimized) ? "Optimized"
147 : "Linear";
148 std::cout << "Track Model: " << model << std::endl;
149 std::cout << " initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << " Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
150 }
151
152 SMatrix55Sym lastParamCov;
153 double qptsigma = TMath::Range(1., 10., std::abs(track.getInvQPt()));
154
155 lastParamCov(0, 0) = 1.; // <X,X>
156 lastParamCov(1, 1) = 1.; // <Y,Y>
157 lastParamCov(2, 2) = 1.; // <PHI,PHI>
158 lastParamCov(3, 3) = 1.; // <TANL,TANL>
159 lastParamCov(4, 4) = qptsigma; // <INVQPT,INVQPT>
160
161 track.setCovariances(lastParamCov);
162 track.setTrackChi2(0.);
163
164 } else { // Magnet off: linear tracks
165
166 // initialize the starting track parameters
167 double chi2invqptquad;
168 auto invQPt0 = 0.;
169
170 auto nPoints = track.getNumberOfPoints();
171
172 if (mVerbose) {
173 std::cout << "\n ***************************** Start Fitting new track ***************************** \n";
174 std::cout << "N Clusters = " << nPoints << std::endl;
175 }
176
177 track.setInvQPtSeed(0);
178 track.setChi2QPtSeed(0);
179 track.setInvQPt(invQPt0);
180
182 int first_cls, next_cls;
183 if (outward) { // MCH matching
184 first_cls = 0;
185 next_cls = nPoints - 1;
186 } else { // Vertexing
187 first_cls = nPoints - 1;
188 next_cls = 0;
189 }
190
191 auto x0 = track.getXCoordinates()[first_cls];
192 auto y0 = track.getYCoordinates()[first_cls];
193 auto z0 = track.getZCoordinates()[first_cls];
194
195 auto deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[next_cls];
196 auto deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[next_cls];
197 auto deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[next_cls];
198 auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
199 auto tanl0 = -std::abs(deltaZ) / deltaR;
200 double phi0;
201 if (outward) {
202 phi0 = TMath::ATan2(-deltaY, -deltaX);
203 } else {
204 phi0 = TMath::ATan2(deltaY, deltaX);
205 }
206
207 track.setX(x0);
208 track.setY(y0);
209 track.setZ(z0);
210 track.setPhi(phi0);
211 track.setTanl(tanl0);
212
213 if (mVerbose) {
214 std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << (outward ? " (outward)" : " (inward)") << std::endl;
215 auto model = "Linear";
216 std::cout << "Track Model: " << model << std::endl;
217 std::cout << " initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << " Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
218 }
219
220 SMatrix55Sym lastParamCov;
221 double qptsigma = TMath::Range(1., 10., std::abs(track.getInvQPt()));
222
223 lastParamCov(0, 0) = 1.; // <X,X>
224 lastParamCov(1, 1) = 1.; // <Y,Y>
225 lastParamCov(2, 2) = 1.; // <PHI,PHI>
226 lastParamCov(3, 3) = 1.; // <TANL,TANL>
227 lastParamCov(4, 4) = 0.; // <INVQPT,INVQPT>
228
229 track.setCovariances(lastParamCov);
230 track.setTrackChi2(0.);
231 }
232
233 return true;
234}
235
236//_________________________________________________________________________________________________
237template <typename T>
238bool TrackFitter<T>::propagateToZ(T& track, double z)
239{
240 // Propagate track to the z position of the new cluster
241 if constexpr (std::is_same<T, o2::mft::TrackLTF>::value) { // Magnet on
242
243 switch (mTrackModel) {
244 case Linear:
245 track.propagateToZlinear(z);
246 break;
247 case Quadratic:
248 track.propagateToZquadratic(z, mBZField);
249 break;
250 case Helix:
251 track.propagateToZhelix(z, mBZField);
252 break;
253 case Optimized:
254 track.propagateToZ(z, mBZField);
255 break;
256 default:
257 std::cout << " Invalid track model.\n";
258 return false;
259 break;
260 }
261 } else {
262 track.propagateToZlinear(z);
263 }
264 return true;
265}
266
267//_________________________________________________________________________________________________
268template <typename T>
269bool TrackFitter<T>::propagateToNextClusterWithMCS(T& track, double z, int& startingLayerID, const int& newLayerID)
270{
271
272 // Propagate track to the next cluster z position, adding angular MCS effects at the center of
273 // each disk crossed by the track. This method is valid only for track propagation between
274 // clusters at MFT layers positions.
275
276 if (startingLayerID == newLayerID) { // Same layer, nothing to do.
277 if (mVerbose) {
278 std::cout << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > "
279 << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID);
280 std::cout << ") ; track.getZ() = " << track.getZ() << " => ";
281 std::cout << "destination cluster z = " << z << " ; => Same layer: no MCS effects." << std::endl;
282 }
283 if (z != track.getZ()) {
284 propagateToZ(track, z);
285 }
286 return true;
287 }
288
290 auto startingZ = track.getZ();
291
292 // https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
293 auto signum = [](auto a) {
294 return (0 < a) - (a < 0);
295 };
296 int direction = signum(newLayerID - startingLayerID); // takes values +1, 0, -1
297 auto currentLayer = startingLayerID;
298
299 if (mVerbose) {
300 std::cout << " => Propagate to next cluster with MCS : startingLayerID = " << startingLayerID << " = > "
301 << " newLayerID = " << newLayerID << " (NLayers = " << std::abs(newLayerID - startingLayerID);
302 std::cout << ") ; track.getZ() = " << track.getZ() << " => ";
303 std::cout << "destination cluster z = " << z << " ; " << std::endl;
304 }
305
306 // Number of disks crossed by this track segment
307 while (currentLayer != newLayerID) {
308 auto nextlayer = currentLayer + direction;
309 auto nextZ = LayerZPosition[nextlayer];
310
311 int NDisksMS;
312 if (nextZ - track.getZ() > 0) {
313 NDisksMS = (currentLayer % 2 == 0) ? (currentLayer - nextlayer) / 2 : (currentLayer - nextlayer + 1) / 2;
314 } else {
315 NDisksMS = (currentLayer % 2 == 0) ? (nextlayer - currentLayer + 1) / 2 : (nextlayer - currentLayer) / 2;
316 }
317
318 if (mVerbose) {
319 std::cout << "currentLayer = " << currentLayer << " ; "
320 << "nextlayer = " << nextlayer << " ; ";
321 std::cout << "track.getZ() = " << track.getZ() << " ; ";
322 std::cout << "nextZ = " << nextZ << " ; ";
323 std::cout << "NDisksMS = " << NDisksMS << std::endl;
324 }
325
326 if ((NDisksMS * mMFTDiskThicknessInX0) != 0) {
327 track.addMCSEffect(NDisksMS * mMFTDiskThicknessInX0);
328 if (mVerbose) {
329 std::cout << "Track covariances after MCS effects: \n"
330 << track.getCovariances() << std::endl
331 << std::endl;
332 }
333 }
334
335 if (mVerbose) {
336 std::cout << " BeforeExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
337 }
338
339 propagateToZ(track, nextZ);
340
341 currentLayer = nextlayer;
342 }
343 if (z != track.getZ()) {
344 propagateToZ(track, z);
345 }
346 startingLayerID = newLayerID;
347 return true;
348}
349
350//_________________________________________________________________________________________________
351template <typename T>
352bool TrackFitter<T>::computeCluster(T& track, int cluster, int& startingLayerID)
353{
358
359 const auto& clx = track.getXCoordinates()[cluster];
360 const auto& cly = track.getYCoordinates()[cluster];
361 const auto& clz = track.getZCoordinates()[cluster];
362 const auto& sigmaX2 = track.getSigmasX2()[cluster] + mAlignResidual;
363 const auto& sigmaY2 = track.getSigmasY2()[cluster] + mAlignResidual;
364 const auto& newLayerID = track.getLayers()[cluster];
365
366 if (mVerbose) {
367 std::cout << "computeCluster: X = " << clx << " Y = " << cly << " Z = " << clz << " nCluster = " << cluster << " Layer = " << newLayerID << std::endl;
368 }
369
370 if (!propagateToNextClusterWithMCS(track, clz, startingLayerID, newLayerID)) {
371 return false;
372 }
373
374 if (mVerbose) {
375 std::cout << " AfterExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
376 std::cout << "Track covariances after extrap: \n"
377 << track.getCovariances() << std::endl
378 << std::endl;
379 }
380
381 // recompute parameters
382 const std::array<float, 2>& pos = {clx, cly};
383 const std::array<float, 2>& cov = {sigmaX2, sigmaY2};
384
385 if (track.update(pos, cov)) {
386 if (mVerbose) {
387 std::cout << " New Cluster: X = " << clx << " Y = " << cly << " Z = " << clz << " sigmaX2 = " << sigmaX2 << " sigmaY2 = " << sigmaY2 << std::endl;
388 std::cout << " AfterKalman: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
389 std::cout << std::endl;
390 std::cout << "Track covariances after Kalman update: \n"
391 << track.getCovariances() << std::endl
392 << std::endl;
393 }
394 return true;
395 }
396 return false;
397}
398
399//_________________________________________________________________________________________________
400template <typename T>
401Double_t invQPtFromFCF(const T& track, Double_t bFieldZ, Double_t& sigmainvqptsq)
402{
403
404 const std::array<Float_t, constants::mft::LayersNumber>& xPositions = track.getXCoordinates();
405 const std::array<Float_t, constants::mft::LayersNumber>& yPositions = track.getYCoordinates();
406 const std::array<Float_t, constants::mft::LayersNumber>& zPositions = track.getZCoordinates();
407 const std::array<Float_t, constants::mft::LayersNumber>& SigmasX2 = track.getSigmasX2();
408 const std::array<Float_t, constants::mft::LayersNumber>& SigmasY2 = track.getSigmasY2();
409
410 // Fast Circle Fit (Hansroul, Jeremie, Savard, 1987)
411 auto nPoints = track.getNumberOfPoints();
412 std::vector<double> xVal(nPoints);
413 std::vector<double> yVal(nPoints);
414 std::vector<double> zVal(nPoints);
415 std::vector<double> xErr(nPoints);
416 std::vector<double> yErr(nPoints);
417 std::vector<double> uVal(nPoints);
418 std::vector<double> vVal(nPoints);
419 std::vector<double> vErr(nPoints);
420 std::vector<double> fweight(nPoints);
421 std::vector<double> Rn(nPoints);
422 std::vector<double> Pn(nPoints);
423 Double_t A, Aerr, B, Berr, x2, y2, invx2y2, a, b, r, sigmaRsq, u2, sigma;
424 Double_t F0, F1, F2, F3, F4, SumSRn, SumSPn, SumRn, SumUPn, SumRP;
425
426 SumSRn = SumSPn = SumRn = SumUPn = SumRP = 0.0;
427 F0 = F1 = F2 = F3 = F4 = 0.0;
428
429 for (auto np = 0; np < nPoints; np++) {
430 xErr[np] = SigmasX2[np];
431 yErr[np] = SigmasY2[np];
432 if (np > 0) {
433 xVal[np] = xPositions[np] - xPositions[0] + xVal[0];
434 yVal[np] = yPositions[np] - yPositions[0] + yVal[0];
435 } else {
436 xVal[np] = .00001;
437 yVal[np] = 0.;
438 }
439 zVal[np] = zPositions[np];
440 }
441 for (int i = 0; i < nPoints; i++) {
442 x2 = xVal[i] * xVal[i];
443 y2 = yVal[i] * yVal[i];
444 invx2y2 = 1. / (x2 + y2);
445 uVal[i] = xVal[i] * invx2y2;
446 vVal[i] = yVal[i] * invx2y2;
447 vErr[i] = std::sqrt(8. * xErr[i] * xErr[i] * x2 * y2 + 2. * yErr[i] * yErr[i] * (x2 - y2) * (x2 - y2)) * invx2y2 * invx2y2;
448 }
449
450 Double_t invqpt_fcf;
451 Int_t qfcf;
452 // chi2 = 0.;
453 if (LinearRegression(nPoints, uVal, vVal, vErr, B, Berr, A, Aerr)) {
454 // v = a * u + b
455 // circle passing through (0,0):
456 // (x - rx)^2 + (y - ry)^2 = r^2
457 // ---> a = - rx / ry;
458 // ---> b = 1 / (2 * ry)
459 b = 1. / (2. * A);
460 a = -B * b;
461 r = std::sqrt(a * a + b * b);
462 double_t invR = 1. / r;
463
464 // pt --->
465 Double_t invpt = 1. / (o2::constants::math::B2C * bFieldZ * r);
466
467 // sign(q) --->
468 // rotate around the first point (0,0) to bring the last point
469 // on the x axis (y = 0) and check the y sign of the rotated
470 // center of the circle
471 Double_t x = xVal[nPoints - 1], y = yVal[nPoints - 1], z = zVal[nPoints - 1];
472 Double_t slope = TMath::ATan2(y, x);
473 Double_t cosSlope = TMath::Cos(slope);
474 Double_t sinSlope = TMath::Sin(slope);
475 Double_t rxRot = a * cosSlope + b * sinSlope;
476 Double_t ryRot = a * sinSlope - b * cosSlope;
477 qfcf = (ryRot > 0.) ? -1 : +1;
478
479 invqpt_fcf = qfcf * invpt;
480 } else { // the linear regression failed...
481 LOG(warn) << "LinearRegression failed!";
482 invqpt_fcf = 1. / 100.;
483 }
484
485 return invqpt_fcf;
486}
487
489Bool_t LinearRegression(Int_t nVal, std::vector<double>& xVal, std::vector<double>& yVal, std::vector<double>& yErr, Double_t& B, Double_t& Berr, Double_t& A, Double_t& Aerr)
490{
491 // linear regression y = B * x + A
492
493 Double_t S1, SXY, SX, SY, SXX, SsXY, SsXX, SsYY, Xm, Ym, s, delta, difx;
494 Double_t invYErr2;
495
496 S1 = SXY = SX = SY = SXX = 0.0;
497 SsXX = SsYY = SsXY = Xm = Ym = 0.;
498 difx = 0.;
499 for (Int_t i = 0; i < nVal; i++) {
500 invYErr2 = 1. / (yErr[i] * yErr[i]);
501 S1 += invYErr2;
502 SXY += xVal[i] * yVal[i] * invYErr2;
503 SX += xVal[i] * invYErr2;
504 SY += yVal[i] * invYErr2;
505 SXX += xVal[i] * xVal[i] * invYErr2;
506 if (i > 0) {
507 difx += TMath::Abs(xVal[i] - xVal[i - 1]);
508 }
509 Xm += xVal[i];
510 Ym += yVal[i];
511 SsXX += xVal[i] * xVal[i];
512 SsYY += yVal[i] * yVal[i];
513 SsXY += xVal[i] * yVal[i];
514 }
515 delta = SXX * S1 - SX * SX;
516 if (delta == 0.) {
517 return kFALSE;
518 }
519 B = (SXY * S1 - SX * SY) / delta;
520 A = (SY * SXX - SX * SXY) / delta;
521
522 Ym /= (Double_t)nVal;
523 Xm /= (Double_t)nVal;
524 SsYY -= (Double_t)nVal * (Ym * Ym);
525 SsXX -= (Double_t)nVal * (Xm * Xm);
526 SsXY -= (Double_t)nVal * (Ym * Xm);
527 Double_t eps = 1.E-24;
528 if ((nVal > 2) && (TMath::Abs(difx) > eps) && ((SsYY - (SsXY * SsXY) / SsXX) > 0.)) {
529 s = TMath::Sqrt((SsYY - (SsXY * SsXY) / SsXX) / (nVal - 2));
530 Aerr = s * TMath::Sqrt(1. / (Double_t)nVal + (Xm * Xm) / SsXX);
531 Berr = s / TMath::Sqrt(SsXX);
532 } else {
533 Aerr = 0.;
534 Berr = 0.;
535 }
536 return kTRUE;
537}
538
539template class TrackFitter<o2::mft::TrackLTF>;
540template class TrackFitter<o2::mft::TrackLTFL>;
541
542} // namespace mft
543} // namespace o2
General auxilliary methods.
Constants for the MFT; distance unit is cm.
A simple structure for the MFT cluster, used by the standalone track finder.
int32_t i
Definition of a class to fit a track to a set of clusters.
useful math constants
uint16_t pos
Definition RawData.h:3
uint16_t slope
Definition RawData.h:1
Standalone classes for the track found by the Linear-Track-Finder (LTF) and by the Cellular-Automaton...
int nClusters
Definition A.h:16
Definition B.h:16
Class to fit a forward track to a set of clusters.
Definition TrackFitter.h:35
bool initTrack(T &track, bool outward=false)
bool fit(T &track, bool outward=false)
GLint GLenum GLint x
Definition glcorearb.h:403
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLfloat x0
Definition glcorearb.h:5034
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr float B2C
Double_t fitGaus(const size_t nBins, const T *arr, const T xMin, const T xMax, std::vector< T > &param)
Definition fit.h:231
constexpr Double_t LayerZPosition[]
layer Z position to the middle of the CMOS sensor
Definition Constants.h:32
Bool_t LinearRegression(Int_t nVal, std::vector< double > &xVal, std::vector< double > &yVal, std::vector< double > &yErr, Double_t &a, Double_t &ae, Double_t &b, Double_t &be)
Double_t invQPtFromFCF(const T &track, Double_t bFieldZ, Double_t &chi2)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"