Project
Loading...
Searching...
No Matches
AlignmentTrack.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 <cstdio>
19#include "Framework/Logger.h"
23#include "Align/AlignConfig.h"
24#include "Align/utils.h"
25#include <TMatrixD.h>
26#include <TVectorD.h>
27#include <TMatrixDSymEigen.h>
29#include "MathUtils/Utils.h"
30
31#define DEBUG 4
32using namespace o2::align::utils;
33using namespace o2::base;
34using namespace TMath;
35
36namespace o2
37{
38namespace align
39{
40
41// RS: this is not good: we define constants outside the class, but it is to
42// bypass the CINT limitations on static arrays initializations
43const int kRichardsonOrd = 1; // Order of Richardson extrapolation for derivative (min=1)
44const int kRichardsonN = kRichardsonOrd + 1; // N of 2-point symmetric derivatives needed for requested order
45const int kNRDClones = kRichardsonN * 2; // number of variations for derivative of requested order
46
47//____________________________________________________________________________
48void AlignmentTrack::Clear(Option_t*)
49{
50 // reset the track
51 TObject::Clear();
52 ResetBit(0xffffffff);
53 mPoints.clear();
54 mDetPoints.clear();
56 mNDF = 0;
57 mInnerPointID = -1;
58 mNeedInv[0] = mNeedInv[1] = false;
60 //
61}
62
63//____________________________________________________________________________
65{
66 // define varied DOF's (local parameters) for the track:
67 // 1) kinematic params (5 or 4 depending on Bfield)
68 // 2) mult. scattering angles (2)
69 // 3) if requested by point: energy loss
70 //
72 int np = getNPoints();
73 //
74 // the points are sorted in order opposite to track direction -> outer points come 1st,
75 // but for the 2-leg cosmic track the innermost points are in the middle (1st lower leg, then upper one)
76 //
77 // start along track direction, i.e. last point in the ordered array
78 int minPar = mNLocPar;
79 for (int ip = getInnerPointID() + 1; ip--;) { // collision track or cosmic lower leg
80 AlignmentPoint* pnt = getPoint(ip);
81 pnt->setMinLocVarID(minPar);
82 if (pnt->containsMaterial()) {
83 mNLocPar += pnt->getNMatPar();
84 }
85 pnt->setMaxLocVarID(mNLocPar); // flag up to which parameted ID this points depends on
86 }
87 //
88 if (isCosmic()) {
89 minPar = mNLocPar;
90 for (int ip = getInnerPointID() + 1; ip < np; ip++) { // collision track or cosmic lower leg
91 AlignmentPoint* pnt = getPoint(ip);
92 pnt->setMinLocVarID(minPar);
93 if (pnt->containsMaterial()) {
94 mNLocPar += pnt->getNMatPar();
95 }
96 pnt->setMaxLocVarID(mNLocPar); // flag up to which parameted ID this points depends on
97 }
98 }
99 mLocPar.clear();
100 mLocPar.resize(mNLocPar);
101 for (int i = 0; i < 2; i++) {
102 mResid[i].clear();
103 mDResDLoc[i].clear();
104 mResid[i].resize(np);
105 mDResDLoc[i].resize(mNLocPar * np);
106 }
107}
108
109//______________________________________________________
111{
112 // Propagate for given local params and calculate residuals and their derivatives.
113 // The 1st 4 or 5 elements of params vector should be the reference trackParam_t
114 // Then parameters of material corrections for each point
115 // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed).
116 // They correspond to kink parameters
117 // (trackParam_t_after_material - trackParam_t_before_material)
118 // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t
119 // increment will be done locally in the applyMatCorr routine.
120 //
121 // If params are not provided, use internal params array
122 //
123 if (!params) {
124 params = mLocPar.data();
125 }
126 //
127 if (!getResidDone()) {
129 }
130 //
131 int np = getNPoints();
132 //
133 const auto& algConf = AlignConfig::Instance();
134 // collision track or cosmic lower leg
136 if (algConf.verbose > 2) {
137 LOG(warn) << "Failed on derivatives calculation 0";
138 }
139 return false;
140 }
141 //
142 if (isCosmic()) { // cosmic upper leg
143 if (!calcResidDeriv(params, mNeedInv[1], getInnerPointID() + 1, np - 1)) {
144 if (algConf.verbose > 2) {
145 LOG(warn) << "Failed on derivatives calculation 0";
146 }
147 }
148 }
149 //
150 setDerivDone();
151 return true;
152}
153
154//______________________________________________________
155bool AlignmentTrack::calcResidDeriv(double* extendedParams, bool invert, int pFrom, int pTo)
156{
157 // Calculate derivatives of residuals vs params for points pFrom to pT. For cosmic upper leg
158 // track parameter may require inversion.
159 // The 1st 4 or 5 elements of params vector should be the reference trackParam_t
160 // Then parameters of material corrections for each point
161 // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed).
162 // They correspond to kink parameters
163 // (trackParam_t_after_material - trackParam_t_before_material)
164 // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t
165 // increment will be done locally in the applyMatCorr routine.
166 //
167 // The derivatives are calculated using Richardson extrapolation
168 // (like http://root.cern.ch/root/html/ROOT__Math__RichardsonDerivator.html)
169 //
170 const auto& algConf = AlignConfig::Instance();
171 trackParam_t probD[kNRDClones]; // use this to vary supplied param for derivative calculation
172 double varDelta[kRichardsonN];
173 const int kInvElem[kNKinParBON] = {-1, 1, 1, -1, -1};
174 //
175 const double kDelta[kNKinParBON] = {0.02, 0.02, 0.001, 0.001, 0.01}; // variations for ExtTrackParam and material effects
176 //
177 double delta[kNKinParBON]; // variations of curvature term are relative
178 for (int i = kNKinParBOFF; i--;) {
179 delta[i] = kDelta[i];
180 }
181 if (getFieldON()) {
182 delta[kParQ2Pt] = kDelta[kParQ2Pt] * Abs(getQ2Pt());
183 }
184 //
185 int pinc, signELoss = 0; // RS Validate for cosmic. Propagation is done from inner point to outer one:
186 // energy loss is applied for collision tracks and cosmic lower leg, compensated for cosmic upper leg
187 if (pTo > pFrom) { // fit in points decreasing order: cosmics upper leg
188 pTo++;
189 pinc = 1;
190 signELoss = 1; // eloss is corrected
191 } else { // fit in points increasing order: collision track or cosmics lower leg
192 pTo--;
193 pinc = -1;
194 signELoss = -1; // eloss is applied
195 }
196
197 // 1) derivative wrt trackParam_t parameters
198 for (int ipar = mNLocExtPar; ipar--;) {
199 setParams(probD, kNRDClones, getX(), getAlpha(), extendedParams, true);
200 if (invert) {
201 for (int ic = kNRDClones; ic--;) {
202 probD[ic].invert();
203 }
204 }
205 double del = delta[ipar];
206 //
207 for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4...
208 varDelta[icl] = del;
209 modParam(probD[(icl << 1) + 0], ipar, del);
210 modParam(probD[(icl << 1) + 1], ipar, -del);
211 del *= 0.5;
212 }
213 // propagate varied tracks to each point
214 for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction
215 AlignmentPoint* pnt = getPoint(ip);
216 // we propagate w/o mat. corrections, they will be accounted in applyMatCorr
217 if (!propagateParamToPoint(probD, kNRDClones, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, signELoss)) {
218 return false;
219 }
220 if (!applyMatCorr(probD, kNRDClones, extendedParams, pnt)) {
221 return false;
222 }
223 if (pnt->containsMeasurement()) {
224 int offsDer = ip * mNLocPar + ipar;
225 richardsonDeriv(probD, varDelta, pnt, mDResDLoc[0][offsDer], mDResDLoc[1][offsDer]); // calculate derivatives
226 if (invert && kInvElem[ipar] < 0) {
227 mDResDLoc[0][offsDer] = -mDResDLoc[0][offsDer];
228 mDResDLoc[1][offsDer] = -mDResDLoc[1][offsDer];
229 }
230 }
231 } // loop over points
232 } // loop over ExtTrackParam parameters
233 // 2) now vary material effect related parameters: MS and eventually ELoss
234 for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction
235 AlignmentPoint* pnt = getPoint(ip);
236 // global derivatives at this point
237 if (pnt->containsMeasurement() && !calcResidDerivGlo(pnt)) {
238 if (algConf.verbose > 2) {
239 LOGF(warn, "Failed on global derivatives calculation at point %d", ip);
241 }
242 return false;
243 }
244 //
245 if (!pnt->containsMaterial()) {
246 continue;
247 }
248 //
249 int nParFreeI = pnt->getNMatPar();
250 //
251 // array delta gives desired variation of parameters in trackParam_t definition,
252 // while the variation should be done for parameters in the frame where the vector
253 // of material corrections has diagonal cov. matrix -> rotate the delta to this frame
254 double deltaMatD[kNKinParBON];
255 // pnt->diagMatCorr(delta, deltaMatD);
256 for (int ipar = 0; ipar < nParFreeI; ipar++) {
257 double d = pnt->getMatCorrCov()[ipar];
258 deltaMatD[ipar] = d > 0. ? Sqrt(d) * 5 : delta[ipar];
259 }
260 //
261 // printf("Vary %d [%+.3e %+.3e %+.3e %+.3e] ",ip,deltaMatD[0],deltaMatD[1],deltaMatD[2],deltaMatD[3]); pnt->print();
262
263 int offsI = pnt->getMaxLocVarID() - nParFreeI; // the parameters for this point start with this offset
264 // they are irrelevant for the points upstream
265 for (int ipar = 0; ipar < nParFreeI; ipar++) { // loop over DOFs related to MS and ELoss are point ip
266 double del = deltaMatD[ipar];
267 //
268 // We will vary the tracks starting from the original parameters propagated to given point
269 // and stored there (before applying material corrections for this point)
270 //
271 setParams(probD, kNRDClones, pnt->getXTracking(), pnt->getAlphaSens(), pnt->getTrParamWSB(), false);
272 // no need for eventual track inversion here: if needed, this is already done in ParamWSB
273 //
274 int offsIP = offsI + ipar; // parameter entry in the extendedParams array
275 // printf(" Var:%d (%d) %e\n",ipar,offsIP, del);
276
277 for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4...
278 varDelta[icl] = del;
279 double parOrig = extendedParams[offsIP];
280 extendedParams[offsIP] += del;
281 //
282 // apply varied material effects : incremented by delta
283 if (!applyMatCorr(probD[(icl << 1) + 0], extendedParams, pnt)) {
284 return false;
285 }
286 //
287 // apply varied material effects : decremented by delta
288 extendedParams[offsIP] = parOrig - del;
289 if (!applyMatCorr(probD[(icl << 1) + 1], extendedParams, pnt)) {
290 return false;
291 }
292 //
293 extendedParams[offsIP] = parOrig;
294 del *= 0.5;
295 }
296 if (pnt->containsMeasurement()) { // calculate derivatives at the scattering point itself
297 int offsDerIP = ip * mNLocPar + offsIP;
298 richardsonDeriv(probD, varDelta, pnt, mDResDLoc[0][offsDerIP], mDResDLoc[1][offsDerIP]); // calculate derivatives for ip
299 // printf("DR SELF: %e %e at %d (%d)\n",mDResDLoc[0][offsDerIP], mDResDLoc[1][offsDerIP],offsI, offsDerIP);
300 }
301 //
302 // loop over points whose residuals can be affected by the material effects on point ip
303 for (int jp = ip + pinc; jp != pTo; jp += pinc) {
304 AlignmentPoint* pntJ = getPoint(jp);
305
306 // printf(" DerFor:%d ",jp); pntJ->print();
307
308 if (!propagateParamToPoint(probD, kNRDClones, pntJ, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, signELoss)) {
309 return false;
310 }
311 //
312 if (pntJ->containsMaterial()) { // apply material corrections
313 if (!applyMatCorr(probD, kNRDClones, extendedParams, pntJ)) {
314 return false;
315 }
316 }
317 //
318 if (pntJ->containsMeasurement()) {
319 int offsDerJ = jp * mNLocPar + offsIP;
320 // calculate derivatives
321 richardsonDeriv(probD, varDelta, pntJ, mDResDLoc[0][offsDerJ], mDResDLoc[1][offsDerJ]);
322 }
323 //
324 } // << loop over points whose residuals can be affected by the material effects on point ip
325 } // << loop over DOFs related to MS and ELoss are point ip
326 } // << loop over all points of the track
327 //
328 return true;
329}
330
331//______________________________________________________
333{
334 // calculate residuals derivatives over point's sensor and its parents global params
335 double deriv[AlignableVolume::kNDOFGeom * 3];
336 //
337 const AlignableSensor* sens = pnt->getSensor();
338 const AlignableVolume* vol = sens;
339 // precalculated track parameters
340 double snp = pnt->getTrParamWSA(kParSnp), tgl = pnt->getTrParamWSA(kParTgl);
341 // precalculate track slopes to account tracking X variation
342 // these are coeffs to translate deltaX of the point to deltaY and deltaZ of track
343 double cspi = 1. / Sqrt((1 - snp) * (1 + snp)), slpY = snp * cspi, slpZ = tgl * cspi;
344 //
345 pnt->setDGloOffs(mNGloPar); // mark 1st entry of derivatives
346 do {
347 // measurement residuals
348 int nfree = vol->getNDOFsFree();
349 if (!nfree) {
350 continue;
351 } // no free parameters?
352 sens->dPosTraDParGeom(pnt, deriv, vol == sens ? nullptr : vol);
353 //
354 checkExpandDerGloBuffer(mNGloPar + nfree); // if needed, expand derivatives buffer
355 //
356 for (int ip = 0; ip < AlignableVolume::kNDOFGeom; ip++) { // we need only free parameters
357 if (!vol->isFreeDOF(ip)) {
358 continue;
359 }
360 double* dXYZ = &deriv[ip * 3]; // tracking XYZ derivatives over this parameter
361 // residual is defined as diagonalized track_estimate - measured Y,Z in tracking frame
362 // where the track is evaluated at measured X!
363 // -> take into account modified X using track parameterization at the point (paramWSA)
364 // Attention: small simplifications(to be checked if it is ok!!!):
365 // effect of changing X is accounted neglecting track curvature to preserve linearity
366 //
367 // store diagonalized residuals in track buffer
369 (dXYZ[AlignmentPoint::kX] * slpZ - dXYZ[AlignmentPoint::kZ]),
371 // and register global ID of varied parameter
372 mGloParID[mNGloPar] = vol->getParGloID(ip);
373 mNGloPar++;
374 }
375 //
376 } while ((vol = vol->getParent()));
377 //
378 // eventual detector calibration parameters
379 const AlignableDetector* det = sens->getDetector();
380 int ndof = 0;
381 if (det && (ndof = det->getNCalibDOFs())) {
382 // if needed, expand derivatives buffer
384 for (int idf = 0; idf < ndof; idf++) {
385 if (!det->isFreeDOF(idf)) {
386 continue;
387 }
388 sens->dPosTraDParCalib(pnt, deriv, idf, nullptr);
389 pnt->diagonalizeResiduals((deriv[AlignmentPoint::kX] * slpY - deriv[AlignmentPoint::kY]),
390 (deriv[AlignmentPoint::kX] * slpZ - deriv[AlignmentPoint::kZ]),
392 // and register global ID of varied parameter
393 mGloParID[mNGloPar] = det->getParGloID(idf);
394 mNGloPar++;
395 }
396 }
397 //
398 pnt->setNGloDOFs(mNGloPar - pnt->getDGloOffs()); // mark number of global derivatives filled
399 //
400 return true;
401}
402
403//______________________________________________________
404bool AlignmentTrack::calcResiduals(const double* extendedParams)
405{
406 // Propagate for given local params and calculate residuals
407 // The 1st 4 or 5 elements of extendedParams vector should be the reference trackParam_t
408 // Then parameters of material corrections for each point
409 // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed).
410 // They correspond to kink parameters
411 // (trackParam_t_after_material - trackParam_t_before_material)
412 // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t
413 // increment will be done locally in the applyMatCorr routine.
414 //
415 // If extendedParams are not provided, use internal extendedParams array
416 //
417 if (!extendedParams) {
418 extendedParams = mLocPar.data();
419 }
420 int np = getNPoints();
421 mChi2 = 0;
422 mNDF = 0;
423 //
424 const auto& algConf = AlignConfig::Instance();
425 // collision track or cosmic lower leg
426 if (!calcResiduals(extendedParams, mNeedInv[0], getInnerPointID(), 0)) {
427 if (algConf.verbose > 2) {
428 LOG(warn) << "Failed on residuals calculation 0";
429 }
430 return false;
431 }
432 //
433 if (isCosmic()) { // cosmic upper leg
434 if (!calcResiduals(extendedParams, mNeedInv[1], getInnerPointID() + 1, np - 1)) {
435 if (algConf.verbose > 2) {
436 LOG(warn) << "Failed on residuals calculation 1";
437 }
438 return false;
439 }
440 }
441 //
442 mNDF -= mNLocExtPar;
443 setResidDone();
444 return true;
445}
446
447//______________________________________________________
448bool AlignmentTrack::calcResiduals(const double* extendedParams, bool invert, int pFrom, int pTo)
449{
450 // Calculate residuals for the single leg from points pFrom to pT
451 // The 1st 4 or 5 elements of extendedParams vector should be corrections to
452 // the reference trackParam_t
453 // Then parameters of material corrections for each point
454 // marked as having materials should come (4 or 5 dependending if ELoss is varied or fixed).
455 // They correspond to kink parameters
456 // (trackParam_t_after_material - trackParam_t_before_material)
457 // rotated to frame where they error matrix is diagonal. Their conversion to trackParam_t
458 // increment will be done locally in the applyMatCorr routine.
459 //
460 trackParam_t probe;
461 setParams(probe, getX(), getAlpha(), extendedParams, true);
462 if (invert) {
463 probe.invert();
464 }
465 int pinc, signELoss = 0; // RS Validate for cosmic. Propagation is done from inner point to outer one:
466 // energy loss is applied for collision tracks and cosmic lower leg, compensated for cosmic upper leg
467 if (pTo > pFrom) { // fit in points decreasing order: cosmics upper leg
468 pTo++;
469 pinc = 1;
470 signELoss = 1; // eloss is corrected
471 } else { // fit in points increasing order: collision track or cosmics lower leg
472 pTo--;
473 pinc = -1;
474 signELoss = -1; // eloss is applied
475 }
476 //
477 const auto& algConf = AlignConfig::Instance();
478 for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction:
479 AlignmentPoint* pnt = getPoint(ip);
480 if (!propagateParamToPoint(probe, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, signELoss)) {
481 return false;
482 }
483 //
484 // store the current track kinematics at the point BEFORE applying eventual material
485 // corrections. This kinematics will be later varied around supplied parameters (in the calcResidDeriv)
486 pnt->setTrParamWSB(probe.getParams());
487 // account for materials
488 if (!applyMatCorr(probe, extendedParams, pnt)) {
489 return false;
490 }
491 pnt->setTrParamWSA(probe.getParams());
492 //
493 if (pnt->containsMeasurement()) { // need to calculate residuals in the frame where errors are orthogonal
494 pnt->getResidualsDiag(probe.getParams(), mResid[0][ip], mResid[1][ip]);
495 mChi2 += mResid[0][ip] * mResid[0][ip] / pnt->getErrDiag(0);
496 mChi2 += mResid[1][ip] * mResid[1][ip] / pnt->getErrDiag(1);
497 mNDF += 2;
498 }
499 //
500 if (pnt->containsMaterial()) {
501 // material degrees of freedom do not contribute to NDF since they are constrained by 0 expectation
502 int nCorrPar = pnt->getNMatPar();
503 const float* corCov = pnt->getMatCorrCov(); // correction diagonalized covariance
504 auto offs = pnt->getMaxLocVarID() - nCorrPar;
505 for (int i = 0; i < nCorrPar; i++) {
506 mChi2 += mLocPar[offs + i] * mLocPar[offs + i] / corCov[i];
507 }
508 }
509 }
510 return true;
511}
512
513//______________________________________________________
514bool AlignmentTrack::propagateParamToPoint(trackParam_t* tr, int nTr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr)
515{
516 // Propagate set of tracks to the point (only parameters, no error matrix)
517 // VECTORIZE this
518 //
519 const auto& algConf = AlignConfig::Instance();
520 for (int itr = nTr; itr--;) {
521 if (!propagateParamToPoint(tr[itr], pnt, maxStep, maxSnp, mt, signCorr)) {
522 if (algConf.verbose > 2) {
523 LOG(error) << "Failed on clone " << itr << " propagation ";
524 tr[itr].print();
526 }
527 return false;
528 }
529 }
530 return true;
531}
532
533//______________________________________________________
534bool AlignmentTrack::propagateParamToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, int signCorr)
535{
536 // propagate tracks to the point (only parameters, no error matrix)
537 return propagate(tr, pnt, maxStep, maxSnp, mt, nullptr, signCorr);
538}
539
540//______________________________________________________
541bool AlignmentTrack::propagateToPoint(trackParam_t& tr, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr)
542{
543 // propagate tracks to the point. If matCor is true, then material corrections will be applied.
544 // if matPar pointer is provided, it will be filled by total x2x0 and signed xrho
545 return propagate(tr, pnt, maxStep, maxSnp, mt, tLT, signCorr);
546}
547
548bool AlignmentTrack::propagate(trackParam_t& track, const AlignmentPoint* pnt, double maxStep, double maxSnp, MatCorrType mt, track::TrackLTIntegral* tLT, int signCorr)
549{
550 if (signCorr == 0) { // auto
551 // calculate the sign of the energy loss correction and ensure the upper leg of cosmics is calculated correctly.
552 double dx = pnt->getXTracking() - track.getX();
553 int dir = dx > 0.f ? 1 : -1;
554 signCorr = pnt->isInvDir() ? dir : -dir; // propagation along the track direction should have signCorr=-1
555 }
556 // do propagation in at least 2 step to reveal eventual effect of MS on the position
557 return PropagatorD::Instance()->propagateToAlphaX(track, pnt->getAlphaSens(), pnt->getXTracking(), pnt->getUseBzOnly(), maxSnp, maxStep, 2, mt, tLT, signCorr);
558}
559
560/*
561//______________________________________________________
562bool AlignmentTrack::ApplyMS(trackParam_t& trPar, double tms,double pms)
563{
564 //------------------------------------------------------------------------------
565 // Modify track par (e.g. trackParam_t) in the tracking frame
566 // (dip angle lam, az. angle phi)
567 // by multiple scattering defined by polar and azumuthal scattering angles in
568 // the track collinear frame (tms and pms resp).
569 // The updated direction vector in the tracking frame becomes
570 //
571 // | Cos[lam]*Cos[phi] Cos[phi]*Sin[lam] -Sin[phi] | | Cos[tms] |
572 // | Cos[lam]*Sin[phi] Sin[lam]*Sin[phi] Cos[phi] | x | Cos[pms]*Sin[tms]|
573 // | Sin[lam] -Cos[lam] 0 | | Sin[pms]*Sin[tms]|
574 //
575 //------------------------------------------------------------------------------
576 //
577 double *par = (double*) trPar.GetParameter();
578 //
579 if (Abs(tms)<1e-7) return true;
580 //
581 double snTms = Sin(tms), csTms = Cos(tms);
582 double snPms = Sin(pms), csPms = Cos(pms);
583 double snPhi = par[2], csPhi = Sqrt((1.-snPhi)*(1.+snPhi));
584 double csLam = 1./Sqrt(1.+par[3]*par[3]), snLam = csLam*par[3];
585 //
586 double r00 = csLam*csPhi, r01 = snLam*csPhi, &r02 = snPhi;
587 double r10 = csLam*snPhi, r11 = snLam*snPhi, &r12 = csPhi;
588 double &r20 = snLam ,&r21 = csLam;
589 //
590 double &v0 = csTms, v1 = snTms*csPms, v2 = snTms*snPms;
591 //
592 double px = r00*v0 + r01*v1 - r02*v2;
593 double py = r10*v0 + r11*v1 + r12*v2;
594 double pz = r20*v0 - r21*v1;
595 //
596 double pt = Sqrt(px*px + py*py);
597 par[2] = py/pt;
598 par[3] = pz/pt;
599 par[4]*= csLam/pt;
600 //
601 return true;
602}
603*/
604
605//______________________________________________________
606bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corrPar, const AlignmentPoint* pnt)
607{
608 // Modify track param (e.g. trackParam_t) in the tracking frame
609 // by delta accounting for material effects
610 // Note: corrPar contains delta to track parameters rotated by the matrix
611 // DIAGONALIZING ITS COVARIANCE MATRIX!
612 // transform parameters from the frame diagonalizing the errors to track frame
613 double corr[kNKinParBON] = {0};
614 if (pnt->containsMaterial()) { // are there free params from materials?
615 int nCorrPar = pnt->getNMatPar();
616 const double* corrDiag = &corrPar[pnt->getMaxLocVarID() - nCorrPar]; // material corrections for this point start here
617 pnt->unDiagMatCorr(corrDiag, corr); // this is to account for MS and RANDOM Eloss (if varied)
618 }
619 // to this we should add expected parameters modification due to the deterministic eloss
620 float* detELoss = pnt->getMatCorrExp();
621 for (int i = kNKinParBON; i--;) {
622 corr[i] += detELoss[i];
623 }
624 //corr[kParQ2Pt] += detELoss[kParQ2Pt];
625 // printf("apply corr UD %+.3e %+.3e %+.3e %+.3e %+.3e\n",corr[0],corr[1],corr[2],corr[3],corr[4]);
626 // printf(" corr D %+.3e %+.3e %+.3e %+.3e\n",corrDiag[0],corrDiag[1],corrDiag[2],corrDiag[3]);
627 // printf("at point :"); pnt->print();
628 return applyMatCorr(trPar, corr);
629 //
630}
631
632//______________________________________________________
633bool AlignmentTrack::applyMatCorr(trackParam_t& trPar, const double* corr)
634{
635 // Modify track param (e.g. trackParam_t) in the tracking frame
636 // by delta accounting for material effects
637 // Note: corr contains delta to track frame, NOT in diagonalized one
638 const double snp = trPar.getSnp() + corr[kParSnp];
639 const auto& algConf = AlignConfig::Instance();
640 if (Abs(snp) > algConf.maxSnp) {
641 if (algConf.verbose > 2) {
642 LOG(error) << "Snp is too large: " << snp;
643 printf("DeltaPar: ");
644 for (int i = 0; i < kNKinParBON; i++) {
645 printf("%+.3e ", corr[i]);
646 }
647 printf("\n");
648 trPar.print();
649 }
650 return false;
651 }
652
653 trPar.updateParams(corr);
654
655 return true;
656}
657
658//______________________________________________________
659bool AlignmentTrack::applyMatCorr(trackParam_t* trSet, int ntr, const double* corrDiag, const AlignmentPoint* pnt)
660{
661 // Modify set of track params (e.g. trackParam_t) in the tracking frame
662 // by delta accounting for material effects
663 // Note: corrDiag contain delta to track parameters rotated by the matrix DIAGONALIZING ITS
664 // COVARIANCE MATRIX
665 // transform parameters from the frame diagonalizing the errors to track frame
666 const auto& algConf = AlignConfig::Instance();
667 double corr[kNKinParBON] = {0};
668 if (pnt->containsMaterial()) { // are there free params from materials?
669 int nCorrPar = pnt->getNMatPar();
670 const double* corrDiagP = &corrDiag[pnt->getMaxLocVarID() - nCorrPar]; // material corrections for this point start here
671 pnt->unDiagMatCorr(corrDiagP, corr);
672 }
673 float* detELoss = pnt->getMatCorrExp();
674 for (int i = kNKinParBON; i--;) {
675 corr[i] += detELoss[i];
676 }
677 // if (!pnt->getELossVaried()) corr[kParQ2Pt] = pnt->getMatCorrExp()[kParQ2Pt]; // fixed eloss expected effect
678 // printf("apply corr UD %+.3e %+.3e %+.3e %+.3e\n",corr[0],corr[1],corr[2],corr[3]);
679 // printf(" corr D %+.3e %+.3e %+.3e %+.3e\n",corrDiagP[0],corrDiagP[1],corrDiagP[2],corrDiagP[3]);
680 // printf("at point :"); pnt->print();
681 //
682 for (int itr = ntr; itr--;) {
683 if (!applyMatCorr(trSet[itr], corr)) {
684 if (algConf.verbose > 2) {
685 LOGP(error, "Failed on clone {} materials", itr);
686 trSet[itr].print();
687 }
688 return false;
689 }
690 }
691 return true;
692}
693
694//______________________________________________
695double AlignmentTrack::richardsonExtrap(double* val, int ord)
696{
697 // Calculate Richardson extrapolation of order ord (starting from 1)
698 // The array val should contain estimates ord+1 of derivatives with variations
699 // d, d/2 ... d/2^ord.
700 // The array val is overwritten
701 //
702 if (ord == 1) {
703 return (4. * val[1] - val[0]) * (1. / 3);
704 }
705 do {
706 for (int i = 0; i < ord; i++) {
707 val[i] = (4. * val[i + 1] - val[i]) * (1. / 3);
708 }
709 } while (--ord);
710 return val[0];
711}
712
713//______________________________________________
714double AlignmentTrack::richardsonExtrap(const double* val, int ord)
715{
716 // Calculate Richardson extrapolation of order ord (starting from 1)
717 // The array val should contain estimates ord+1 of derivatives with variations
718 // d, d/2 ... d/2^ord.
719 // The array val is not overwritten
720 //
721 if (ord == 1) {
722 return (4. * val[1] - val[0]) * (1. / 3);
723 }
724 double* buff = new double[ord + 1];
725 memcpy(buff, val, (ord + 1) * sizeof(double));
726 do {
727 for (int i = 0; i < ord; i++) {
728 buff[i] = (4. * buff[i + 1] - buff[i]) * (1. / 3);
729 }
730 } while (--ord);
731 return buff[0];
732}
733
734//______________________________________________
735void AlignmentTrack::richardsonDeriv(const trackParam_t* trSet, const double* delta, const AlignmentPoint* pnt, double& derY, double& derZ)
736{
737 // Calculate Richardson derivatives for diagonalized Y and Z from a set of kRichardsonN pairs
738 // of tracks with same parameter of i-th pair varied by +-delta[i]
739 static double derRichY[kRichardsonN], derRichZ[kRichardsonN];
740 //
741 for (int icl = 0; icl < kRichardsonN; icl++) { // calculate kRichardsonN variations with del, del/2, del/4...
742 double resYVP = 0, resYVN = 0, resZVP = 0, resZVN = 0;
743 pnt->getResidualsDiag(trSet[(icl << 1) + 0].getParams(), resYVP, resZVP); // variation with +delta
744 pnt->getResidualsDiag(trSet[(icl << 1) + 1].getParams(), resYVN, resZVN); // variation with -delta
745 derRichY[icl] = 0.5 * (resYVP - resYVN) / delta[icl]; // 2-point symmetric derivatives
746 derRichZ[icl] = 0.5 * (resZVP - resZVN) / delta[icl];
747 }
748 derY = richardsonExtrap(derRichY, kRichardsonOrd); // dY/dPar
749 derZ = richardsonExtrap(derRichZ, kRichardsonOrd); // dZ/dPar
750 if (TMath::IsNaN(derY) || TMath::IsNaN(derZ)) {
751 LOGP(error, "NAN encounterd: DerY {} : DerZ {}", derY, derZ);
752 }
753 //
754}
755
756//______________________________________________
757void AlignmentTrack::Print(Option_t* opt) const
758{
759 // print track data
760 printf("%s ", isCosmic() ? " Cosmic " : "Collision ");
761 trackParam_t::print();
762 printf("N Free Par: %d (Kinem: %d) | Npoints: %d (Inner:%d) | Chi2Ini:%.1f Chi2: %.1f/%d",
764 if (isCosmic()) {
765 int npLow = getInnerPointID();
766 int npUp = getNPoints() - npLow - 1;
767 printf(" [Low:%.1f/%d Up:%.1f/%d]", mChi2CosmDn, npLow, mChi2CosmUp, npUp);
768 }
769 printf("\n");
770 //
771 TString optS = opt;
772 optS.ToLower();
773 bool res = optS.Contains("r") && getResidDone();
774 bool der = optS.Contains("d") && getDerivDone();
775 bool par = optS.Contains("lc"); // local param corrections
776 bool paru = optS.Contains("lcu"); // local param corrections in track param frame
777 //
778 if (par) {
779 printf("Ref.track corr: ");
780 for (int i = 0; i < mNLocExtPar; i++) {
781 printf("%+.3e ", mLocPar[i]);
782 }
783 printf("\n");
784 }
785 //
786 if (optS.Contains("p") || res || der) {
787 for (int ip = 0; ip < getNPoints(); ip++) {
788 printf("#%3d ", ip);
789 auto* pnt = getPoint(ip);
790 pnt->print(AlignmentPoint::kMeasurementBit); // RS FIXME OPT
791 //
792 if (res && pnt->containsMeasurement()) {
793 printf(" Residuals : %+.3e %+.3e -> Pulls: %+7.2f %+7.2f\n",
794 getResidual(0, ip), getResidual(1, ip),
795 getResidual(0, ip) / sqrt(pnt->getErrDiag(0)), getResidual(1, ip) / sqrt(pnt->getErrDiag(1)));
796 }
797 if (der && pnt->containsMeasurement()) {
798 for (int ipar = 0; ipar < mNLocPar; ipar++) {
799 printf(" Dres/dp%03d : %+.3e %+.3e\n", ipar, getDResDLoc(0, ip)[ipar], getDResDLoc(1, ip)[ipar]);
800 }
801 }
802 //
803 if (par && pnt->containsMaterial()) { // material corrections
804 int nCorrPar = pnt->getNMatPar();
805 printf(" Corr.Diag: ");
806 for (int i = 0; i < nCorrPar; i++) {
807 printf("%+.3e ", mLocPar[i + pnt->getMaxLocVarID() - nCorrPar]);
808 }
809 printf("\n");
810 printf(" Corr.Pull: ");
811 const float* corCov = pnt->getMatCorrCov(); // correction covariance
812 // const float *corExp = pnt->getMatCorrExp(); // correction expectation
813 for (int i = 0; i < nCorrPar; i++) {
814 printf("%+.3e ", (mLocPar[i + pnt->getMaxLocVarID() - nCorrPar] /* - corExp[i]*/) / Sqrt(corCov[i]));
815 }
816 printf("\n");
817 if (paru) { // print also mat.corrections in track frame
818 double corr[5] = {0};
819 pnt->unDiagMatCorr(&mLocPar[pnt->getMaxLocVarID() - nCorrPar], corr);
820 // if (!pnt->getELossVaried()) corr[kParQ2Pt] = pnt->getMatCorrExp()[kParQ2Pt]; // fixed eloss expected effect
821 printf(" Corr.Track: ");
822 for (int i = 0; i < kNKinParBON; i++) {
823 printf("%+.3e ", corr[i]);
824 }
825 printf("\n");
826 }
827 }
828 }
829 } // print points
830}
831
832//______________________________________________
834{
835 // print various coordinates for inspection
836 printf("gpx/D:gpy/D:gpz/D:gtxb/D:gtyb/D:gtzb/D:gtxa/D:gtya/D:gtza/D:alp/D:px/D:py/D:pz/D:tyb/D:tzb/D:tya/D:tza/D:ey/D:ez/D\n");
837 for (int ip = 0; ip < getNPoints(); ip++) {
838 auto* pnt = getPoint(ip);
839 if (!pnt->containsMeasurement()) {
840 continue;
841 }
842 pnt->dumpCoordinates();
843 }
844}
845
846//______________________________________________
848{
849 // perform initial fit of the track
850 //
851 const auto& algConf = AlignConfig::Instance();
852 if (!getFieldON()) { // for field-off data impose nominal momentum
853 setQ2Pt(isCosmic() ? 1. / algConf.defPTB0Cosm : 1. / algConf.defPTB0Coll);
854 }
855 trackParam_t trc(*(trackParam_t*)this);
857 //
858 // the points are ranged from outer to inner for collision tracks,
859 // and from outer point of lower leg to outer point of upper leg for the cosmic track
860 //
861 // the fit will always start from the outgoing track in inward direction
862 if (!fitLeg(trc, 0, getInnerPointID(), mNeedInv[0])) {
863 if (algConf.verbose > 2) {
864 LOG(warn) << "Failed fitLeg 0";
865 trc.print();
866 }
867 return false; // collision track or cosmic lower leg
868 }
869 //
870 // printf("Lower leg: %d %d\n",0,getInnerPointID()); trc.print();
871 //
872 if (isCosmic()) {
874 trackParam_t trcU = trc;
875 if (!fitLeg(trcU, getNPoints() - 1, getInnerPointID() + 1, mNeedInv[1])) { //fit upper leg of cosmic track
876 if (algConf.verbose > 2) {
877 LOG(warn) << "Failed fitLeg 1";
878 trc.print();
879 }
880 return false; // collision track or cosmic lower leg
881 }
882 //
883 // propagate to reference point, which is the inner point of lower leg
884 const AlignmentPoint* refP = getPoint(getInnerPointID());
885 if (!propagateToPoint(trcU, refP, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, -1)) { // moving along the track: energy is lost
886 return false;
887 }
888 //
890 // printf("Upper leg: %d %d\n",getInnerPointID()+1,getNPoints()-1); trcU.print();
891 //
892 if (!combineTracks(trc, trcU)) {
893 return false;
894 }
895 //printf("Combined\n"); trc.print();
896 }
897 copyFrom(&trc);
898 //
899 mChi2Ini = mChi2;
900 return true;
901}
902
903//______________________________________________
905{
906 // Assign to trcL the combined tracks (Kalman update of trcL by trcU)
907 // The trcL and trcU MUST be defined at same X,Alpha
908 //
909 // Update equations: tracks described by vectors vL and vU and coviriances CL and CU resp.
910 // then the gain matrix K = CL*(CL+CU)^-1
911 // Updated vector and its covariance:
912 // CL' = CL - K*CL
913 // vL' = vL + K(vU-vL)
914 //
915 const auto& algConf = AlignConfig::Instance();
916 if (Abs(trcL.getX() - trcU.getX()) > TinyDist || Abs(trcL.getAlpha() - trcU.getAlpha()) > TinyDist) {
917 if (algConf.verbose > 2) {
918 LOG(error) << "Tracks must be defined at same reference X and Alpha";
919 trcL.print();
920 trcU.print();
921 }
922 return false;
923 }
924 //
925 LOGP(debug, "CosmDn: {}", trcL.asString());
926 LOGP(debug, "CosmUp: {}", trcU.asString());
927 float dsnp = trcL.getSnp() - trcU.getSnp(), dTgl = trcL.getTgl() - trcU.getTgl();
928 if (std::abs(dsnp) > algConf.cosmMaxDSnp || std::abs(dTgl) > algConf.cosmMaxDTgl) {
929 if (algConf.verbose > 2) {
930 LOGP(error, "Rejecting track with dSnp={} dTgl={}", dsnp, dTgl);
931 LOGP(error, "CosmDn: {}", trcL.asString());
932 LOGP(error, "CosmUp: {}", trcU.asString());
933 }
934 return false;
935 }
936 // const covMat_t& covU = trcU.getCov();
937 // const covMat_t& covL = trcL.getCov();
938 //
939 int mtSize = getFieldON() ? kNKinParBON : kNKinParBOFF;
940 TMatrixD matCL(mtSize, mtSize), matCLplCU(mtSize, mtSize);
941 TVectorD vl(mtSize), vUmnvL(mtSize);
942 //
943 // trcL.print();
944 // trcU.print();
945 //
946 for (int i = mtSize; i--;) {
947 vUmnvL[i] = trcU.getParam(i) - trcL.getParam(i); // y = residual of 2 tracks
948 vl[i] = trcL.getParam(i);
949 for (int j = i + 1; j--;) {
950 int indIJ = ((i * (i + 1)) >> 1) + j; // position of IJ cov element in the trackParam_t covariance array
951 matCL(i, j) = matCL(j, i) = trcL.getCovarElem(i, j);
952 matCLplCU(i, j) = matCLplCU(j, i) = trcL.getCovarElem(i, j) + trcU.getCovarElem(i, j);
953 }
954 }
955 matCLplCU.Invert(); // S^-1 = (Cl + Cu)^-1
956 if (!matCLplCU.IsValid()) {
957 if (algConf.verbose > 2) {
958 LOG(error) << "Failed to invert summed cov.matrix of cosmic track";
959 matCLplCU.Print();
960 }
961 return false; // inversion failed
962 }
963 TMatrixD matK(matCL, TMatrixD::kMult, matCLplCU); // gain K = Cl*(Cl+Cu)^-1
964 TMatrixD matKdotCL(matK, TMatrixD::kMult, matCL); // K*Cl
965 TVectorD vlUp = matK * vUmnvL; // K*(vl - vu)
966 for (int i = mtSize; i--;) {
967 trcL.updateParam(vlUp[i], i); // updated param: vL' = vL + K(vU-vL)
968 for (int j = i + 1; j--;) {
969 trcL.updateCov(-matKdotCL(i, j), i, j);
970 } // updated covariance: Cl' = Cl - K*Cl
971 }
972 //
973 // update chi2
974 double chi2 = 0;
975 for (int i = mtSize; i--;) {
976 for (int j = mtSize; j--;) {
977 chi2 += matCLplCU(i, j) * vUmnvL[i] * vUmnvL[j];
978 }
979 }
980 mChi2 += chi2;
981 //
982 LOGP(debug, "CosmCB: {}", trcL.asString());
983 LOGP(debug, "Combined: Chi2Tot:{} ChiUp:{} ChiDn:{} ChiCmb:{} DSnp:{} DTgl:{} Alp:{}", mChi2, mChi2CosmUp, mChi2CosmDn, chi2, dsnp, dTgl, trcL.getAlpha());
984
985 return true;
986}
987
988//______________________________________________
989bool AlignmentTrack::fitLeg(trackParam_t& trc, int pFrom, int pTo, bool& inv)
990{
991 // perform initial fit of the track
992 // the fit will always start from the outgoing track in inward direction (i.e. if cosmics - bottom leg)
993 const int kMinNStep = 3;
994 const double kErrSpace = 50.;
995 const double kErrAng = 0.8;
996 const double kErrRelPtI = 1.;
997 const covMat_t kIniErr{// initial error
998 kErrSpace * kErrSpace,
999 0, kErrSpace * kErrSpace,
1000 0, 0, kErrAng * kErrAng,
1001 0, 0, 0, kErrAng * kErrAng,
1002 0, 0, 0, 0, kErrRelPtI * kErrRelPtI};
1003 //
1004 static int count = 0;
1005 const auto& algConf = AlignConfig::Instance();
1006 if (algConf.verbose > 2) {
1007 LOGP(info, "FIT COUNT {}", count++);
1008 }
1009 // prepare seed at outer point
1010 AlignmentPoint* p0 = getPoint(pFrom);
1011 double phi = trc.getPhi(), alp = p0->getAlphaSens();
1014 double dphi = math_utils::detail::deltaPhiSmall(phi, alp); // abs delta angle
1015 if (dphi > Pi() / 2.) { // need to invert the track to new frame
1016 inv = true;
1017 trc.invert();
1018 }
1019 // Fit is done from outward to inward: normally against the track direction (hence e.loss is compensated) unless inversion is requested (cosmic upper leg)
1020 if (!propagateParamToPoint(trc, p0, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), -1)) {
1021 if (algConf.verbose > 2) {
1022 LOGF(warn, "Failed on PropagateParamOnlyTo to %f", p0->getXTracking());
1023 trc.print();
1024 }
1025 return false;
1026 }
1027 trc.setCov(kIniErr);
1028 trc.setCov(16 * trc.getQ2Pt() * trc.getQ2Pt(), 4, 4); // lowest diagonal element (Q2Pt2)
1029 //
1030 int pinc, signELoss = 0; // RS Validate for cosmic. Propagation is done from inner point to outer one:
1031 // energy loss is applied for collision tracks and cosmic lower leg, compensated for cosmic upper leg
1032 if (pTo > pFrom) { // fit in points increasing order: collision track or cosmics lower leg
1033 pTo++;
1034 pinc = 1;
1035 signELoss = 1; // e.loss is compensated
1036 } else { // fit in points decreasing order: cosmics upper leg
1037 pTo--;
1038 pinc = -1;
1039 signELoss = -1; // e.loass is applied
1040 }
1041 //
1042 int pntCnt = 0;
1043 for (int ip = pFrom; ip != pTo; ip += pinc) { // inward fit from outer point
1044 AlignmentPoint* pnt = getPoint(ip);
1045 if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // against track direction : e.loss is compensated
1046 if (algConf.verbose > 2) {
1047 LOGF(warn, "Failed on propagateToPoint %d (%d : %d) %f", ip, pFrom, pTo, pnt->getXTracking());
1048 trc.print();
1049 }
1050 return false;
1051 }
1052 if (pnt->containsMeasurement()) {
1053 if (pnt->getNeedUpdateFromTrack()) {
1054 pnt->updatePointByTrackInfo(&trc);
1055 }
1056 const double* yz = pnt->getYZTracking();
1057 const double* errYZ = pnt->getYZErrTracking();
1058 double chi = trc.getPredictedChi2(yz, errYZ);
1059 if (!trc.update(yz, errYZ)) {
1060 if (algConf.verbose > 2) {
1061 LOGF(warn, "Failed on Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]);
1062 trc.print();
1063 }
1064 return false;
1065 }
1066 mChi2 += chi;
1067 pntCnt++;
1068 }
1069 }
1070 //
1071 if (inv) {
1072 trc.invert();
1073 }
1074 if (algConf.verbose > 2) {
1075 LOGP(info, "Fitted leg with {} points, chi2: {}", pntCnt, mChi2);
1076 }
1077 //
1078 return true;
1079}
1080
1081//______________________________________________
1083{
1084 // calculate residuals from bi-directional Kalman smoother
1085 // ATTENTION: this method modifies workspaces of the points!!!
1086 //
1087 bool inv = false;
1088 const int kMinNStep = 3;
1089 const double kErrSpace = 100.;
1090 const double kErrAng = 0.7;
1091 const double kErrRelPtI = 1.;
1092 const covMat_t kIniErr = {// initial error
1093 kErrSpace * kErrSpace,
1094 0, kErrSpace * kErrSpace,
1095 0, 0, kErrAng * kErrAng,
1096 0, 0, 0, kErrAng * kErrAng,
1097 0, 0, 0, 0, kErrRelPtI * kErrRelPtI};
1098 // const double kOverShootX = 5;
1099 //
1100 trackParam_t trc = *this;
1101 const auto& algConf = AlignConfig::Instance();
1102 int pID = 0, nPnt = getNPoints();
1103 AlignmentPoint* pnt = nullptr;
1104 // get 1st measured point
1105 while (pID < nPnt && !(pnt = getPoint(pID))->containsMeasurement()) { // points are ordered from outward to inward
1106 pID++;
1107 }
1108 if (!pnt) {
1109 return false;
1110 }
1111 double phi = trc.getPhi(), alp = pnt->getAlphaSens();
1114 double dphi = math_utils::detail::deltaPhiSmall(phi, alp);
1115 if (dphi > Pi() / 2.) { // need to invert the track to new frame
1116 inv = true;
1117 trc.invert();
1118 }
1119 // prepare track seed at 1st outermost valid point
1120 if (!propagateParamToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, 1)) {
1121 if (algConf.verbose > 2) {
1122 LOG(warn) << "Failed on propagateParamToPoint";
1123 trc.print();
1125 }
1126 return false;
1127 }
1128 //
1129 trc.setCov(kIniErr);
1130 const double inwardQ2Pt2 = 4 * trc.getCovarElem(4, 4) * trc.getQ2Pt() * trc.getQ2Pt();
1131 trc.setCov(inwardQ2Pt2, 4, 4); // lowest diagonal element (Q2Pt2)
1132 //
1133 double chifwd = 0, chibwd = 0;
1134 // inward fit
1135 int signELoss = 1; // normally inward fit goes against track direction: eloss is compensated. // RS Check for cosmic
1136 for (int ip = pID; ip < nPnt; ip++) {
1137 pnt = getPoint(ip);
1138 if (pnt->isInvDir() != inv) { // crossing point where the track should be inverted?
1139 trc.invert();
1140 inv = !inv;
1141 }
1142 if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) {
1143 return false;
1144 }
1145 if (!pnt->containsMeasurement()) {
1146 continue;
1147 }
1148 const double* yz = pnt->getYZTracking();
1149 const double* errYZ = pnt->getYZErrTracking();
1150 // store track position/errors before update in the point WorkSpace-A
1151 double* ws = (double*)pnt->getTrParamWSA();
1152 ws[0] = trc.getY();
1153 ws[1] = trc.getZ();
1154 ws[2] = trc.getSigmaY2();
1155 ws[3] = trc.getSigmaZY();
1156 ws[4] = trc.getSigmaZ2();
1157 double chi = trc.getPredictedChi2(yz, errYZ);
1158 if (!trc.update(yz, errYZ)) {
1159 if (algConf.verbose > 2) {
1160 LOGF(warn, "Failed on Inward Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]);
1161 trc.print();
1162 }
1163 return false;
1164 }
1165 // printf(">>Aft ");trc.print();
1166 chifwd += chi;
1167 // printf("KLM After update: (%f) -> %f\n",chi,chifwd); trc.print();
1168 }
1169 //
1170 // outward fit
1171 trc.setCov(kIniErr);
1172 const double outwardQ2Pt2 = 4 * trc.getCovarElem(4, 4) * trc.getQ2Pt() * trc.getQ2Pt();
1173 trc.setCov(outwardQ2Pt2, 4, 4); // lowest diagonal element (Q2Pt2)
1174 signELoss = -1; // normally outward fit goes along track direction: eloss is applied. // RS Check for cosmic
1175 for (int ip = nPnt; ip--;) {
1176 pnt = getPoint(ip);
1177 if (pnt->isInvDir() != inv) { // crossing point where the track should be inverted?
1178 trc.invert();
1179 inv = !inv;
1180 }
1181 if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), nullptr, signELoss)) { // we are going along track direction, e.loss is applied
1182 return false;
1183 }
1184 if (!pnt->containsMeasurement()) {
1185 continue;
1186 }
1187 const double* yz = pnt->getYZTracking();
1188 const double* errYZ = pnt->getYZErrTracking();
1189 // store track position/errors before update in the point WorkSpace-B
1190 double* ws = (double*)pnt->getTrParamWSB();
1191 ws[0] = trc.getY();
1192 ws[1] = trc.getZ();
1193 ws[2] = trc.getSigmaY2();
1194 ws[3] = trc.getSigmaZY();
1195 ws[4] = trc.getSigmaZ2();
1196 double chi = trc.getPredictedChi2(yz, errYZ);
1197 // printf("<< OUT%d (%9d): %+.2e %+.2e | %+.2e %+.2e %+.2e %+.2e %+.2e | %.2e %d \n",ip,pnt->getSensor()->getInternalID(),yz[0],yz[1], ws[0],ws[1],ws[2],ws[3],ws[4],chi,inv);
1198 // printf("<<Bef "); trc.print();
1199 if (!trc.update(yz, errYZ)) {
1200 if (algConf.verbose > 2) {
1201 LOGF(warn, "Failed on Outward Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]);
1202 trc.print();
1203 }
1204 return false;
1205 }
1206 chibwd += chi;
1207 // printf("<<Aft "); trc.print();
1208 }
1209 //
1210 // now compute smoothed prediction and residual
1211 for (int ip = 0; ip < nPnt; ip++) {
1212 pnt = getPoint(ip);
1213 if (!pnt->containsMeasurement()) {
1214 continue;
1215 }
1216 double* wsA = (double*)pnt->getTrParamWSA(); // inward measurement
1217 double* wsB = (double*)pnt->getTrParamWSB(); // outward measurement
1218 double &yA = wsA[0], &zA = wsA[1], &sgAYY = wsA[2], &sgAYZ = wsA[3], &sgAZZ = wsA[4];
1219 double &yB = wsB[0], &zB = wsB[1], &sgBYY = wsB[2], &sgBYZ = wsB[3], &sgBZZ = wsB[4];
1220 // compute weighted average
1221 double sgYY = sgAYY + sgBYY, sgYZ = sgAYZ + sgBYZ, sgZZ = sgAZZ + sgBZZ;
1222 double detI = sgYY * sgZZ - sgYZ * sgYZ;
1223 if (TMath::Abs(detI) < constants::math::Almost0) {
1224 return false;
1225 } else {
1226 detI = 1. / detI;
1227 }
1228 double tmp = sgYY;
1229 sgYY = sgZZ * detI;
1230 sgZZ = tmp * detI;
1231 sgYZ = -sgYZ * detI;
1232 double dy = yB - yA, dz = zB - zA;
1233 double k00 = sgAYY * sgYY + sgAYZ * sgYZ, k01 = sgAYY * sgYZ + sgAYZ * sgZZ;
1234 double k10 = sgAYZ * sgYY + sgAZZ * sgYZ, k11 = sgAYZ * sgYZ + sgAZZ * sgZZ;
1235 double sgAYZt = sgAYZ;
1236 yA += dy * k00 + dz * k01; // these are smoothed predictions, stored in WSA
1237 zA += dy * k10 + dz * k11; //
1238 sgAYY -= k00 * sgAYY + k01 * sgAYZ;
1239 sgAYZ -= k00 * sgAYZt + k01 * sgAZZ;
1240 sgAZZ -= k10 * sgAYZt + k11 * sgAZZ;
1241 // printf("|| WGH%d (%9d): | %+.2e %+.2e %+.2e %.2e %.2e\n",ip,pnt->getSensor()->getInternalID(), wsA[0],wsA[1],wsA[2],wsA[3],wsA[4]);
1242 }
1243 //
1244 mChi2 = chifwd;
1245 setKalmanDone(true);
1246 return true;
1247}
1248
1249//______________________________________________
1251{
1252 // attach material effect info to alignment points
1253 trackParam_t trc = *this;
1254 const auto& algConf = AlignConfig::Instance();
1255 // collision track or cosmic lower leg: move along track direction from last (middle for cosmic lower leg) point (inner) to 1st one (outer)
1256 if (mNeedInv[0]) {
1257 trc.invert();
1258 } // track needs to be inverted ? (should be for upper leg)
1259 if (!processMaterials(trc, getInnerPointID(), 0)) {
1260 if (algConf.verbose > 2) {
1261 LOG(error) << "Failed to process materials for leg along the track";
1262 }
1263 return false;
1264 }
1265 if (isCosmic()) {
1266 // cosmic upper leg: move againg the track direction from middle point (inner) to last one (outer)
1267 trc = *this;
1268 if (mNeedInv[1]) {
1269 trc.invert();
1270 } // track needs to be inverted ?
1271 if (!processMaterials(trc, getInnerPointID() + 1, getNPoints() - 1)) {
1272#if DEBUG > 3
1273 LOG(error) << "Failed to process materials for leg against the track";
1274#endif
1275 return false;
1276 }
1277 }
1278 return true;
1279}
1280
1281//______________________________________________
1283{
1284 // attach material effect info to alignment points
1285 const int kMinNStep = 3;
1286 const double kErrSpcT = 1e-6;
1287 const double kErrAngT = 1e-6;
1288 const double kErrPtIT = 1e-12;
1289 const covMat_t kErrTiny = {// initial tiny error
1290 kErrSpcT * kErrSpcT,
1291 0, kErrSpcT * kErrSpcT,
1292 0, 0, kErrAngT * kErrAngT,
1293 0, 0, 0, kErrAngT * kErrAngT,
1294 0, 0, 0, 0, kErrPtIT * kErrPtIT};
1295 /*
1296 const double kErrSpcH = 10.0;
1297 const double kErrAngH = 0.5;
1298 const double kErrPtIH = 0.5;
1299 const double kErrHuge[15] = { // initial tiny error
1300 kErrSpcH*kErrSpcH,
1301 0 , kErrSpcH*kErrSpcH,
1302 0 , 0, kErrAngH*kErrAngH,
1303 0 , 0, 0, kErrAngH*kErrAngH,
1304 0 , 0, 0, 0, kErrPtIH*kErrPtIH
1305 };
1306 */
1307 //
1308 // 2 copies of the track, one will be propagated accounting for materials, other - w/o
1309 trackParam_t tr0;
1311 double dpar[5] = {0};
1312 covMat_t dcov{0};
1313 matTL.setTimeNotNeeded();
1314 const auto& algConf = AlignConfig::Instance();
1315 // calculate min X/X0 to treat the point as having materials
1316 double minX2X0 = algConf.minScatteringAngleToAccount / 0.014 * trc.getPt();
1317 minX2X0 *= minX2X0;
1318
1319 //
1320 int pinc, signELoss = 0;
1321 if (pTo > pFrom) { // fit inward: cosmics upper leg
1322 pTo++;
1323 pinc = 1;
1324 signELoss = 1; // against the track direction, eloss is applied (RS Check for cosmic)
1325 } else { // fit outward collision track or cosmics lower leg: along the track direction:
1326 pTo--;
1327 pinc = -1;
1328 signELoss = -1; // eloss is applied
1329 }
1330 //
1331 for (int ip = pFrom; ip != pTo; ip += pinc) { // points are ordered against track direction
1332 AlignmentPoint* pnt = getPoint(ip);
1333 trc.setCov(kErrTiny); // assign tiny errors to both tracks
1334 tr0 = trc;
1335 //
1336 matTL.clearFast();
1337 // printf("-> ProcMat %d (%d->%d)\n",ip,pFrom,pTo);
1338 if (!propagateToPoint(trc, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType(algConf.matCorType), &matTL, signELoss)) { // with material corrections
1339 if (algConf.verbose > 2) {
1340 LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" << pTo << ") with mat.corr.";
1341 trc.print();
1343 }
1344 return false;
1345 }
1346 //
1347 // is there enough material to consider the point as a scatterer?
1348 bool hasMaterial = matTL.getX2X0() > minX2X0;
1349 if (!propagateToPoint(tr0, pnt, algConf.maxStep, algConf.maxSnp, MatCorrType::USEMatCorrNONE, nullptr, signELoss)) { // no material corrections
1350 if (algConf.verbose > 2) {
1351 LOG(error) << "Failed to take track to point" << ip << " (dir: " << pFrom << "->" << pTo << ") with mat.corr.";
1352 tr0.print();
1354 }
1355 return false;
1356 }
1357 // the difference between the params, covariance of tracks with and w/o material accounting gives
1358 // parameters and covariance of material correction. For params ONLY ELoss effect is relevant
1359 double *par0 = (double*)tr0.getParams(), *par1 = (double*)trc.getParams();
1360 const covMat_t &cov0 = tr0.getCov(), &cov1 = trc.getCov();
1361 for (int l = 15; l--;) {
1362 dcov[l] = cov1[l] - cov0[l];
1363 }
1364 for (int l = kNKinParBON; l--;) {
1365 dpar[l] = par1[l] - par0[l];
1366 } // eloss affects all parameters!
1367 pnt->setMatCorrExp(dpar);
1368 //dpar[kParQ2Pt] = par1[kParQ2Pt] - par0[kParQ2Pt]; // only e-loss expectation is non-0
1369 //
1370 if (hasMaterial) {
1371 // MP2 handles only scalar residuals hence correlated matrix of material effect need to be diagonalized
1372 bool eLossFree = pnt->getELossVaried();
1373 int nParFree = eLossFree ? kNKinParBON : kNKinParBOFF;
1374 TMatrixDSym matCov(nParFree);
1375 for (int i = nParFree; i--;) {
1376 for (int j = i + 1; j--;) {
1377 auto err2 = dcov[j + ((i * (i + 1)) >> 1)];
1378 if (i == j && err2 < 1e-20) { // meaninglessly small diagonal error
1379 LOGP(warn, "Material correction {}-th error too small: {}, declare no material despite x/X0={}", i, err2, matTL.getX2X0());
1380 hasMaterial = false;
1381 break;
1382 }
1383 matCov(i, j) = matCov(j, i) = err2;
1384 }
1385 }
1386 if (hasMaterial) {
1387 TMatrixDSymEigen matDiag(matCov); // find eigenvectors
1388 const TMatrixD& matEVec = matDiag.GetEigenVectors();
1389 if (!matEVec.IsValid()) {
1390 if (algConf.verbose > 2) {
1391 LOG(error) << "Failed to diagonalize covariance of material correction";
1392 matCov.Print();
1393 return false;
1394 }
1395 }
1396 for (int ix = 0; ix < matDiag.GetEigenValues().GetNrows(); ix++) {
1397 if (matDiag.GetEigenValues()[ix] < 1e-18) {
1398 LOG(warn) << "Too small " << ix << "-th eignevalue " << matDiag.GetEigenValues()[ix] << " for cov.matrix !!!";
1399 LOG(warn) << "Track with mat.corr: " << trc.asString();
1400 LOG(warn) << "Track w/o mat.corr: " << tr0.asString();
1401 matCov.Print();
1402 matDiag.GetEigenValues().Print();
1403 hasMaterial = false;
1404 break;
1405 }
1406 }
1407 if (hasMaterial) {
1408 pnt->setMatCovDiagonalizationMatrix(matEVec); // store diagonalization matrix
1409 pnt->setMatCovDiag(matDiag.GetEigenValues()); // store E.Values: diagonalized cov.matrix
1410 if (!eLossFree) {
1411 pnt->setMatCovDiagElem(kParQ2Pt, dcov[14]);
1412 }
1413 pnt->setX2X0(matTL.getX2X0());
1414 pnt->setXTimesRho(matTL.getXRho());
1415 }
1416 }
1417 pnt->setContainsMaterial(hasMaterial);
1418 }
1419 if (pnt->containsMeasurement()) { // update track to have best possible kinematics
1420 const double* yz = pnt->getYZTracking();
1421 const double* errYZ = pnt->getYZErrTracking();
1422 if (!trc.update(yz, errYZ)) {
1423 if (algConf.verbose > 2) {
1424 LOGF(warn, "Failed on Update %f,%f {%f,%f,%f}", yz[0], yz[1], errYZ[0], errYZ[1], errYZ[2]);
1425 trc.print();
1426 }
1427 return false;
1428 }
1429 //
1430 }
1431 //
1432 }
1433 //
1434 return true;
1435}
1436
1437//______________________________________________
1439{
1440 // sort points in order against track direction: innermost point is last
1441 // for collision tracks.
1442 // For 2-leg cosmic tracks: 1st points of outgoing (lower) leg are added from large to
1443 // small radii, then the points of incoming (upper) leg are added in increasing R direction
1444 //
1445 // The mInnerPointID will mark the id of the innermost point, i.e. the last one for collision-like
1446 // tracks and in case of cosmics - the point of lower leg with smallest R
1447 //
1448 // the mDetPoints vector will not change anymore: it is safe to work with pointers
1449 for (size_t i = 0; i < mDetPoints.size(); i++) {
1450 mPoints.push_back(&mDetPoints[i]);
1451 }
1452
1453 auto isAfter = [](const AlignmentPoint* a, const AlignmentPoint* b) {
1454 auto xa = a->getXTracking(), xb = b->getXTracking();
1455 if (!a->isInvDir()) { // lower leg: track propagates from low to large X via this point
1456 if (!b->isInvDir()) { // this one also
1457 return xa > xb;
1458 } else {
1459 return true; // any point on the lower leg has higher priority than on the upper leg
1460 }
1461 } else { // this point is from upper cosmic leg: track propagates from large to low X
1462 if (b->isInvDir()) {
1463 return xa < xb;
1464 } else {
1465 return false;
1466 }
1467 }
1468 };
1469
1470 std::sort(mPoints.begin(), mPoints.end(), isAfter);
1471 int np = getNPoints();
1472 mInnerPointID = np - 1;
1473 if (isCosmic()) {
1474 for (int ip = np; ip--;) {
1475 if (getPoint(ip)->isInvDir()) {
1476 continue;
1477 } // this is a point of upper leg
1478 mInnerPointID = ip;
1479 break;
1480 }
1481 }
1482 //
1483}
1484
1485//______________________________________________
1486void AlignmentTrack::setLocPars(const double* pars)
1487{
1488 // store loc par corrections
1489 memcpy(mLocPar.data(), pars, mNLocPar * sizeof(double));
1490}
1491
1492//______________________________________________
1493void AlignmentTrack::addLocPars(const double* pars)
1494{
1495 // store loc par corrections
1496 for (int i = 0; i < mNLocPar; i++) {
1497 mLocPar[i] += pars[i];
1498 }
1499}
1500
1501//______________________________________________
1503{
1504 // if needed, expand global derivatives buffer
1505 if (mGloParID.size() < minSize) {
1506 mGloParID.resize(minSize);
1507 mDResDGlo[0].resize(minSize);
1508 mDResDGlo[1].resize(minSize);
1509 }
1510}
1511
1512//____________________________________________
1514{
1515 // test track local solution
1516 int npnt = getNPoints();
1517 double mat[mNLocPar][mNLocPar], rhs[mNLocPar];
1518 std::memset(mat, 0, sizeof(double) * mNLocPar * mNLocPar);
1519 std::memset(rhs, 0, sizeof(double) * mNLocPar);
1520 for (int ip = npnt; ip--;) {
1521 if (mPoints[ip]->containsMeasurement()) {
1522 for (int idim = 2; idim--;) { // each point has 2 position residuals
1523 auto sg2inv = 1. / mPoints[ip]->getErrDiag(idim); // inv. error
1524 auto deriv = getDResDLoc(idim, ip); // array of Dresidual/Dparams
1525 for (int parI = 0; parI < mNLocPar; parI++) {
1526 rhs[parI] -= deriv[parI] * mResid[idim][ip] * sg2inv;
1527 for (int parJ = parI; parJ < mNLocPar; parJ++) {
1528 mat[parI][parJ] += deriv[parI] * deriv[parJ] * sg2inv;
1529 }
1530 }
1531 } // loop over 2 orthogonal measurements at the point
1532 } // derivarives at measured points
1533 // if the point contains material, consider its expected kinks, eloss as measurements
1534 if (mPoints[ip]->containsMaterial()) { // at least 4 parameters: 2 spatial + 2 angular kinks with 0 expectaction
1535 int npm = mPoints[ip]->getNMatPar();
1536 // const float* expMatCorr = mPoints[ip]->getMatCorrExp(); // expected correction (diagonalized) // RS??
1537 const auto expMatCov = mPoints[ip]->getMatCorrCov(); // its error
1538 int offs = mPoints[ip]->getMaxLocVarID() - npm;
1539 for (int ipar = 0; ipar < npm; ipar++) {
1540 int parI = offs + ipar;
1541 // expected
1542 // rhs[parI] -= expMatCorr[ipar]/expMatCov[ipar]; // consider expectation as measurement // RS??
1543 mat[parI][parI] += 1. / expMatCov[ipar]; // this measurement is orthogonal to all others
1544 }
1545 } // material effect descripotion params
1546 //
1547 }
1549 for (int i = 0; i < mNLocPar; i++) {
1550 for (int j = i; j < mNLocPar; j++) {
1551 solver.A(i, j) = mat[i][j];
1552 }
1553 solver.B(i, 0) = rhs[i];
1554 }
1555 solver.solve();
1556 // increment current params by new solution
1557 for (int i = 0; i < mNLocPar; i++) {
1558 mLocPar[i] += solver.B(i, 0);
1559 }
1560 return calcResiduals();
1561}
1562
1563//______________________________________________
1565{
1566 // remove last n points, must be called before sortPoints
1567 while (n > 0) {
1568 mDetPoints.pop_back();
1569 n--;
1570 }
1571}
1572
1573} // namespace align
1574} // namespace o2
Configuration file for global alignment.
Base class for detector: wrapper for set of volumes.
End-chain alignment volume in detector branch, where the actual measurement is done.
Base class of alignable volume.
Track model for the alignment.
size_t minSize
Definition of SymMatrixSolver class.
General auxilliary methods.
Collection of auxillary methods.
uint32_t res
Definition RawData.h:0
std::ostringstream debug
virtual void dPosTraDParCalib(const AlignmentPoint *pnt, double *deriv, int calibID, const AlignableVolume *parent=nullptr) const
AlignableDetector * getDetector() const
virtual void dPosTraDParGeom(const AlignmentPoint *pnt, double *deriv, const AlignableVolume *parent=nullptr) const
bool isFreeDOF(int dof) const
AlignableVolume * getParent() const
float * getMatCorrCov() const
virtual void dumpCoordinates() const
void updatePointByTrackInfo(const trackParam_t *t)
double getErrDiag(int i) const
void setMatCorrExp(double *p)
double * getTrParamWSB() const
void diagonalizeResiduals(double rY, double rZ, double &resU, double &resV) const
void setContainsMaterial(bool v=true)
void setTrParamWSA(const double *param)
void setMatCovDiagElem(int i, double err2)
double * getTrParamWSA() const
void print(uint16_t opt=0) const
void setMatCovDiag(const TVectorD &v)
const AlignableSensor * getSensor() const
float * getMatCorrExp() const
void getResidualsDiag(const double *pos, double &resU, double &resV) const
const double * getYZErrTracking() const
bool getNeedUpdateFromTrack() const
void setMatCovDiagonalizationMatrix(const TMatrixD &d)
const double * getYZTracking() const
void setTrParamWSB(const double *param)
void unDiagMatCorr(const double *diag, double *nodiag) const
void addLocPars(const double *pars)
bool propagateToPoint(trackParam_t &tr, const AlignmentPoint *pnt, double maxStep, double maxSnp=0.95, MatCorrType mt=MatCorrType::USEMatCorrLUT, track::TrackLTIntegral *tLT=nullptr, int signCorr=0)
void setKalmanDone(bool v=true)
void richardsonDeriv(const trackParam_t *trSet, const double *delta, const AlignmentPoint *pnt, double &derY, double &derZ)
std::vector< AlignmentPoint * > mPoints
virtual void dumpCoordinates() const
void setParams(trackParam_t &tr, double x, double alp, const double *par, bool add)
double getResidual(int dim, int pntID) const
bool applyMatCorr(trackParam_t &trPar, const double *corrDiag, const AlignmentPoint *pnt)
AlignmentPoint * getPoint(int i)
bool calcResiduals(const double *params=nullptr)
void modParam(trackParam_t &tr, int par, double delta)
std::vector< double > mDResDGlo[2]
bool calcResidDeriv(double *params=nullptr)
bool propagateParamToPoint(trackParam_t &tr, const AlignmentPoint *pnt, double maxStep=3, double maxSnp=0.95, MatCorrType mt=MatCorrType::USEMatCorrLUT, int signCorr=0)
void checkExpandDerGloBuffer(unsigned int minSize)
bool fitLeg(trackParam_t &trc, int pFrom, int pTo, bool &inv)
std::vector< double > mDResDLoc[2]
std::vector< AlignmentPoint > mDetPoints
std::vector< double > mLocPar
void setDerivDone(bool v=true)
void setLocPars(const double *pars)
bool calcResidDerivGlo(AlignmentPoint *pnt)
void Clear(Option_t *opt="") final
bool combineTracks(trackParam_t &trcL, const trackParam_t &trcU)
std::vector< int > mGloParID
void setResidDone(bool v=true)
const double * getDResDLoc(int dim, int pntID) const
void copyFrom(const o2::track::TrackParametrizationWithError< P > &trc)
void Print(Option_t *opt="") const final
std::vector< double > mResid[2]
static double richardsonExtrap(double *val, int ord=1)
int getParGloID(int par) const
Definition DOFSet.h:49
int getNCalibDOFsFree() const
Definition DOFSet.h:47
int getNCalibDOFs() const
Definition DOFSet.h:46
int getNDOFsFree() const
Definition DOFSet.h:45
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:143
double & A(int i, int j)
access to A elements
double & B(int i, int j)
access to B elements
GLdouble n
Definition glcorearb.h:1982
GLint GLsizei count
Definition glcorearb.h:399
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum const GLfloat * params
Definition glcorearb.h:272
GLuint GLfloat * val
Definition glcorearb.h:1582
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLboolean invert
Definition glcorearb.h:543
constexpr double TinyDist
Definition utils.h:42
const int kNRDClones
const int kRichardsonOrd
const int kRichardsonN
typename track::TrackParametrizationWithError< double > trackParam_t
Definition utils.h:29
constexpr float Almost0
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"