Project
Loading...
Searching...
No Matches
AlignableVolume.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/*
18 Alignment formalism:
19
20 Vector l in the local frame of the volume_j (assuming hierarchy of nested volumes 0...J
21 from most coarse to the end volume) is transformed to master frame vector
22 g = G_j*l_j
23 Matrix G_j is Local2Global matrix (L2G in the code). If the volume has a parent
24 volume j-1, the global vector g can be transformed to the local volume of j-1 as
25 l_{j-1} = G^-1_{j-1}* g
26 Hence, the transormation from volume j to j-1 is
27 l_{j-1} = G^-1_{j-1}*G_j l_j = R_j*l_j
28
29 The alignment corrections in general can be defined either as a
30
31 1) local delta: l'_j = delta_j * l_j
32 hence g' = G_j * delta_j = G'_j*l_j
33 or as
34 2) global Delta: g' = Delta_j * G_j * l_j = G'_j*l_j
35
36 Hence Delta and delta are linked as
37 Delta_j = G_j delta_j G^-1_j
38 delta_j = G^-1_j Delta_j G_j
39
40 In case the whole chain of nested volumes is aligned, the corrections pile-up as:
41
42 G_0*delta_0 ... G^-1_{j-2}*G_{j-1}*delta_{j-1}*G^-1_{j-1}*G_j*delta_j =
43 Delta_0 * Delta_{1} ... Delta_{j-1}*Delta_{j}... * G_j
44
45 From this by induction one gets relation between local and global deltas:
46
47 Delta_j = Z_j * delta_j * Z^-1_j
48
49 where Z_j = [ Prod_{k=0}^{j-1} (G_k * delta_k * G^-1_k) ] * G_j
50
51 By convention, aliroot aligment framework stores global Deltas !
52
53 In case the geometry was already prealigned by PDelta_j matrices, the result
54 of the new incremental alignment Delta_j must be combined with PDelta_j to
55 resulting matrix TDelta_j before writing new alignment object.
56
57 Derivation: if G_j and IG_j are final and ideal L2G matrices for level j, then
58
59 G_j = TDelta_j * TDelta_{j-1} ... TDelta_0 * IG_j
60 = (Delta_j * Delta_{j-1} ... Delta_0) * (PDelta_j * PDelta_{j-1} ... PDelta_0) * IG_j
61
62 Hence:
63 TDelta_j = [Prod_{i=j}^0 Delta_i ] * [Prod_{k=j}^0 PDelta_k ] * [Prod_{l=0}^{j-1} TDelta_l]
64
65 By induction we get combination rule:
66
67 TDelta_j = Delta_j * X_{j-1} * PDelta_j * X^-1_{j-1}
68
69 where X_i = Delta_i * Delta_{i-1} ... Delta_0
70
71 ---------------------------------
72
73 This alignment framework internally allows to find geometry corrections either in the
74 volume LOCAL frame or in its TRACKING frame. The latter is defined for sensors as
75 lab frame, rotated by the angle alpha in such a way that the X axis is normal to the
76 sensor plane (note, that for ITS the rotated X axis origin is also moved to the sensor)
77 For the non-sensor volumes the TRACKING frame is defined by rotation of the lab frame
78 with the alpha angle = average angle of centers of its children, seen from the origin.
79
80 The TRACKING and IDEAL LOCAL (before misalignment) frames are related by the
81 tracking-to-local matrix (T2L in the code), i.e. the vectors in local and tracking frames
82 are related as
83 l = T2L * t
84
85 The alignment can be done using both frames for different volumes of the same geometry
86 branch.
87 The alignments deltas in local and tracking frames are related as:
88
89 l' = T2L * delta_t * t
90 l' = delta_l * T2L * t
91 -> delta_l = T2L * delta_t * T2L^-1
92
93 */
94
95#include "Align/Controller.h"
98#include "Align/AlignConfig.h"
101#include "Align/utils.h"
102#include "Framework/Logger.h"
103#include <TString.h>
104#include <TClonesArray.h>
105#include <TGeoManager.h>
106#include <TGeoPhysicalNode.h>
107#include <TH1.h>
108#include <TAxis.h>
109#include <cstdio>
110#include <regex>
111
113
114using namespace TMath;
115using namespace o2::align::utils;
116
117namespace o2
118{
119namespace align
120{
121
123//
125 kDOFBitTX | kDOFBitTY | kDOFBitTZ | kDOFBitPS | kDOFBitTH | kDOFBitPH;
126//
127const char* AlignableVolume::sDOFName[AlignableVolume::kNDOFGeom] = {"TX", "TY", "TZ", "PSI", "THT", "PHI"};
128
129//_________________________________________________________
130AlignableVolume::AlignableVolume(const char* symname, int iid, Controller* ctr) : DOFSet(symname, ctr), mIntID(iid)
131{
132 // def c-tor
133 if (!ctr) {
134 LOG(fatal) << "Controller has to be provided :" << symname;
135 }
136 setVolID(-1); // volumes have no VID, unless it is sensor
139}
140
141//_________________________________________________________
143{
144 // d-tor
145 delete mChildren;
146}
147
148//_________________________________________________________
149void AlignableVolume::delta2Matrix(TGeoHMatrix& deltaM, const double* delta) const
150{
151 // prepare delta matrix for the volume from its
152 // local delta vector (AliAlignObj convension): dx,dy,dz,,theta,psi,phi
153 const double *tr = &delta[0], *rt = &delta[3]; // translation(cm) and rotation(radians)
154
155 // AliAlignObjParams tempAlignObj;
156 // tempAlignObj.SetRotation(rt[0], rt[1], rt[2]);
157 // tempAlignObj.SetTranslation(tr[0], tr[1], tr[2]);
158 // tempAlignObj.GetMatrix(deltaM);
159
160 detectors::AlignParam tempAlignObj;
161 tempAlignObj.setRotation(rt[0], rt[1], rt[2]);
162 tempAlignObj.setTranslation(tr[0], tr[1], tr[2]);
163 deltaM = tempAlignObj.createMatrix();
164}
165
166//__________________________________________________________________
167void AlignableVolume::getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta) const
168{
169 // prepare the variation matrix tau in volume TRACKING frame by applying
170 // local delta of modification of LOCAL frame:
171 // tra' = tau*tra = tau*T2L^-1*loc = T2L^-1*loc' = T2L^-1*delta*loc
172 // tau = T2L^-1*delta*T2L
173 delta2Matrix(matMod, delta);
174 matMod.Multiply(&getMatrixT2L());
175 const TGeoHMatrix& t2li = getMatrixT2L().Inverse();
176 matMod.MultiplyLeft(&t2li);
177}
178
179//__________________________________________________________________
180void AlignableVolume::getDeltaT2LmodLOC(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const
181{
182 // prepare the variation matrix tau in volume TRACKING frame by applying
183 // local delta of modification of LOCAL frame of its PARENT;
184 // The relMat is matrix for transformation from child to parent frame: LOC = relMat*loc
185 //
186 // tra' = tau*tra = tau*T2L^-1*loc = T2L^-1*loc' = T2L^-1*relMat^-1*Delta*relMat*loc
187 // tau = (relMat*T2L)^-1*Delta*(relMat*T2L)
188 delta2Matrix(matMod, delta);
189 TGeoHMatrix tmp = relMat;
190 tmp *= getMatrixT2L();
191 matMod.Multiply(&tmp);
192 const TGeoHMatrix& tmpi = tmp.Inverse();
193 matMod.MultiplyLeft(&tmpi);
194}
195
196//__________________________________________________________________
197void AlignableVolume::getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta) const
198{
199 // prepare the variation matrix tau in volume TRACKING frame by applying
200 // local delta of modification of the same TRACKING frame:
201 // tra' = tau*tra
202 delta2Matrix(matMod, delta);
203}
204
205//__________________________________________________________________
206void AlignableVolume::getDeltaT2LmodTRA(TGeoHMatrix& matMod, const double* delta, const TGeoHMatrix& relMat) const
207{
208 // prepare the variation matrix tau in volume TRACKING frame by applying
209 // local delta of modification of TRACKING frame of its PARENT;
210 // The relMat is matrix for transformation from child to parent frame: TRA = relMat*tra
211 // (see DPosTraDParGeomTRA)
212 //
213 // tra' = tau*tra = tau*relMat^-1*TRA = relMat^-1*TAU*TRA = relMat^-1*TAU*relMat*tra
214 // tau = relMat^-1*TAU*relMat
215 delta2Matrix(matMod, delta); // TAU
216 matMod.Multiply(&relMat);
217 const TGeoHMatrix& reli = relMat.Inverse();
218 matMod.MultiplyLeft(&reli);
219}
220
221//_________________________________________________________
223{
224 // count parents in the chain
225 int cnt = 0;
226 const AlignableVolume* p = this;
227 while ((p = p->getParent())) {
228 cnt++;
229 }
230 return cnt;
231}
232
233//____________________________________________
234void AlignableVolume::Print(const Option_t* opt) const
235{
236 // print info
237 TString opts = opt;
238 opts.ToLower();
239 printf("Lev:%2d IntID:%7d %s | %2d nodes | Effective X:%8.4f Alp:%+.4f | Used Points: %d\n",
241 printf(" DOFs: Tot: %d (offs: %5d) Free: %d Geom: %d {", mNDOFs, mFirstParGloID, mNDOFsFree, mNDOFGeomFree);
242 for (int i = 0; i < kNDOFGeom; i++) {
243 printf("%d", isFreeDOF(i) ? 1 : 0);
244 }
245 printf("} in %s frame.", sFrameName[mVarFrame]);
246 if (getNChildren()) {
247 printf(" Child.Constr: {");
248 for (int i = 0; i < kNDOFGeom; i++) {
249 printf("%d", isChildrenDOFConstrained(i) ? 1 : 0);
250 }
251 printf("}");
252 }
254 printf(" Excl.from parent constr.");
255 }
256 printf("\n");
257 //
258 if (opts.Contains("par") && mFirstParGloID >= 0) {
259 printf(" Lb: ");
260 for (int i = 0; i < mNDOFs; i++) {
261 printf("%10d ", getParLab(i));
262 }
263 printf("\n");
264 printf(" Vl: ");
265 for (int i = 0; i < mNDOFs; i++) {
266 printf("%+9.3e ", getParVal(i));
267 }
268 printf("\n");
269 printf(" Er: ");
270 for (int i = 0; i < mNDOFs; i++) {
271 printf("%+9.3e ", getParErr(i));
272 }
273 printf("\n");
274 }
275
276 if (opts.Contains("mat")) { // print matrices
277 printf("L2G ideal : ");
278 getMatrixL2GIdeal().Print();
279 printf("L2G misalign: ");
280 getMatrixL2G().Print();
281 printf("L2G RecoTime: ");
282 getMatrixL2GReco().Print();
283 printf("T2L (fake) : ");
284 getMatrixT2L().Print();
285 }
286 //
287}
288
289//____________________________________________
291{
292 // extract from geometry L2G matrix, depending on reco flag, set it as a reco-time
293 // or current alignment matrix
294 if (isDummyEnvelope() || isDummy()) {
295 return; // unit matrix
296 }
297 const char* path = getSymName();
298 if (gGeoManager->GetAlignableEntry(path)) {
299 const TGeoHMatrix* l2g = base::GeometryManager::getMatrix(path);
300 if (!l2g) {
301 LOG(fatal) << "Failed to find L2G matrix for alignable " << path;
302 }
303 reco ? setMatrixL2GReco(*l2g) : setMatrixL2G(*l2g);
304 } else { // extract from path
305 if (!gGeoManager->CheckPath(path)) {
306 LOG(fatal) << "Volume path " << path << " is not valid!";
307 }
308 TGeoPhysicalNode* node = (TGeoPhysicalNode*)gGeoManager->GetListOfPhysicalNodes()->FindObject(path);
309 TGeoHMatrix l2g;
310 if (!node) {
311 LOG(warning) << "volume " << path << " was not misaligned, extracting original matrix";
313 LOG(fatal) << "Failed to find ideal L2G matrix for " << path;
314 }
315 } else {
316 l2g = *node->GetMatrix();
317 }
318 reco ? setMatrixL2GReco(l2g) : setMatrixL2G(l2g);
319 }
320}
321
322//____________________________________________
324{
325 // extract from geometry ideal L2G matrix
326 TGeoHMatrix mtmp;
328 LOG(fatal) << "Failed to find ideal L2G matrix for " << getSymName();
329 }
330 setMatrixL2GIdeal(mtmp);
331}
332
333//____________________________________________
335{
336 // for non-sensors we define the fake tracking frame with the alpha angle being
337 // the average angle of centers of its children
338 //
339 if (isSensor()) {
340 LOGP(fatal, "Sensor {} must provide its own prepareMatrixT2L method", getSymName());
341 }
342
343 double tot[3] = {0, 0, 0}, loc[3] = {0, 0, 0}, glo[3];
344 int nch = getNChildren();
345 for (int ich = nch; ich--;) {
346 AlignableVolume* vol = getChild(ich);
347 vol->getMatrixL2GIdeal().LocalToMaster(loc, glo);
348 for (int j = 3; j--;) {
349 tot[j] += glo[j];
350 }
351 }
352 if (nch) {
353 for (int j = 3; j--;) {
354 tot[j] /= nch;
355 }
356 }
357 //
358 mAlp = TMath::ATan2(tot[1], tot[0]);
359 math_utils::detail::bringToPMPi(mAlp);
360 //
361 mX = TMath::Sqrt(tot[0] * tot[0] + tot[1] * tot[1]);
362 //
363 // 1st create Tracking to Global matrix
364 mMatT2L.Clear();
365 mMatT2L.SetDx(mX);
366 mMatT2L.RotateZ(mAlp * RadToDeg());
367 // then convert it to Tracking to Local matrix
368 const TGeoHMatrix& l2gi = getMatrixL2GIdeal().Inverse();
369 mMatT2L.MultiplyLeft(&l2gi);
370 //
371}
372
373//__________________________________________________________________
375{
376 // Assigns offset of the DOFS of this volume in global array of DOFs, attaches arrays to volumes
377 //
379 if (mFirstParGloID == (int)mController->getGloParVal().size()) {
381 }
382 for (int i = 0; i < mNDOFs; i++) {
383 setParLab(i, getInternalID() * 100 + i);
384 }
385 int nch = getNChildren(); // go over childs
386 for (int ich = 0; ich < nch; ich++) {
387 getChild(ich)->assignDOFs();
388 }
389 //
390 return;
391}
392
393//__________________________________________________________________
395{
396 // initialize degrees of freedom
397 //
398 // Do we need this strict condition?
399 if (getInitDOFsDone()) {
400 LOG(fatal) << "DOFs are already initialized for " << GetName();
401 }
402 auto pars = getParVals();
403 auto errs = getParErrs();
404 for (int i = 0; i < mNDOFs; i++) {
405 if (errs[i] < -9999 && isZeroAbs(pars[i])) {
406 fixDOF(i);
407 }
408 }
409 calcFree(true);
411}
412
413//__________________________________________________________________
415{
416 // calculate free dofs. If condFix==true, condition parameter a la pede, i.e. error < 0
418 for (int i = 0; i < mNDOFs; i++) {
419 if (!isFreeDOF(i)) {
420 if (condFix && varsSet()) {
421 setParErr(i, -999);
422 }
423 continue;
424 }
425 mNDOFsFree++;
426 if (i < kNDOFGeom) {
428 }
429 }
430 //
431}
432
433//_________________________________________________________
434void AlignableVolume::getParValGeom(double* delta) const
435{
436 auto pars = getParVals();
437 for (int i = kNDOFGeom; i--;) {
438 delta[i] = pars[i];
439 }
440}
441
442//__________________________________________________________________
444{
445 // add child volume
446 if (!mChildren) {
447 mChildren = new TObjArray();
448 mChildren->SetOwner(false);
449 }
450 mChildren->AddLast(ch);
451}
452
453//__________________________________________________________________
455{
456 // is DOF free and conditioned?
457 return (!isZeroAbs(getParVal(i)) || !isZeroAbs(getParErr(i)));
458}
459
460//______________________________________________________
462{
463 // finalize statistics on processed points
464 mNProcPoints = 0;
465 for (int ich = getNChildren(); ich--;) {
466 AlignableVolume* child = getChild(ich);
467 mNProcPoints += child->finalizeStat();
468 }
469 return mNProcPoints;
470}
471
472//______________________________________________________
473void AlignableVolume::writePedeInfo(FILE* parOut, const Option_t* opt) const
474{
475 // contribute to params template file for PEDE
476 enum { kOff,
477 kOn,
478 kOnOn };
479 const char* comment[3] = {" ", "! ", "!!"};
480 const char* kKeyParam = "parameter";
481 const char* kKeyMeas = "measurement";
482 TString opts = opt;
483 opts.ToLower();
484 bool showDef = opts.Contains("d"); // show free DOF even if not preconditioned
485 bool showFix = opts.Contains("f"); // show DOF even if fixed
486 bool showNam = opts.Contains("n"); // show volume name even if no nothing else is printable
487 //
488 // is there something to print ?
489 int nCond(0), nFix(0), nDef(0);
490 for (int i = 0; i < mNDOFs; i++) {
491 if (!isFreeDOF(i)) {
492 nFix++;
493 }
494 if (isCondDOF(i)) {
495 nCond++;
496 }
497 if (!isCondDOF(i) && isFreeDOF(i)) {
498 nDef++;
499 }
500 }
501 //
502 int cmt = nCond > 0 || nFix > 0 ? kOff : kOn; // do we comment the "parameter" keyword for this volume
503 if (!nFix) {
504 showFix = false;
505 }
506 if (!nDef) {
507 showDef = false;
508 }
509 //
510 if (nCond || showDef || showFix || showNam) {
511 fprintf(parOut, "%s%s %s\t\tDOF/Free: %d/%d (%s) %s id : %d | Stat: %d\n", comment[cmt], kKeyParam, comment[kOnOn],
513 }
514 //
515 if (nCond || showDef || showFix) {
516 for (int i = 0; i < mNDOFs; i++) {
517 cmt = kOn;
518 if (isCondDOF(i) || !isFreeDOF(i)) {
519 cmt = kOff;
520 } // free-conditioned : MUST print
521 else if (!isFreeDOF(i)) {
522 if (!showFix) {
523 continue;
524 }
525 } // Fixed: print commented if asked
526 else if (!showDef) {
527 continue;
528 } // free-unconditioned: print commented if asked
529 //
530 fprintf(parOut, "%s %9d %+e %+e\t%s %s p%d\n", comment[cmt], getParLab(i),
531 -getParVal(i), getParErr(i), comment[kOnOn], isFreeDOF(i) ? " " : "FX", i);
532 }
533 // do we consider some DOFs of this volume as measured
534 for (int i = 0; i < mNDOFs; i++) {
535 cmt = isMeasuredDOF(i) ? kOff : kOn;
536 fprintf(parOut, "%s%s %+e %+e\n", comment[cmt], kKeyMeas, -getParVal(i), getParErr(i));
537 fprintf(parOut, "%s %d 1.0\n", comment[cmt], getParLab(i));
538 }
539 fprintf(parOut, "\n");
540 }
541 // children volume
542 int nch = getNChildren();
543 //
544 for (int ich = 0; ich < nch; ich++) {
545 getChild(ich)->writePedeInfo(parOut, opt);
546 }
547 //
548}
549
550//______________________________________________________
552{
553 // write parameters with labels
554 for (int i = 0; i < mNDOFs; i++) {
555 fprintf(parOut, "%9d %+e %+e\t! %s %d:%s vol:%d %s %s\n", getParLab(i), -getParVal(i), getParErr(i), GetName(), i, sDOFName[i], getVolID(),
556 isFreeDOF(i) ? " " : "FXU", isZeroAbs(getParVal(i)) ? "FXP" : " ");
557 }
558 // children volume
559 int nch = getNChildren();
560 //
561 for (int ich = 0; ich < nch; ich++) {
562 getChild(ich)->writeLabeledPedeResults(parOut);
563 }
564 //
565}
566
567//_________________________________________________________________
568bool AlignableVolume::createGloDeltaMatrix(TGeoHMatrix& deltaM) const
569{
570 // Create global matrix deltaM from global array containing corrections.
571 // This deltaM does not account for eventual prealignment
572 // Volume knows if its variation was done in TRA or LOC frame
573 //
574 if (createLocDeltaMatrix(deltaM)) { // do multiplications only if the matrix is non-trivial
575 const TGeoHMatrix& l2g = getMatrixL2G();
576 const TGeoHMatrix l2gi = l2g.Inverse();
577 deltaM.Multiply(&l2gi);
578 deltaM.MultiplyLeft(&l2g);
579 return true;
580 }
581 return false;
582 //
583}
584/*
585//_________________________________________________________________
586void AlignableVolume::createGloDeltaMatrix(TGeoHMatrix &deltaM) const
587{
588 // Create global matrix deltaM from global array containing corrections.
589 // This deltaM does not account for eventual prealignment
590 // Volume knows if its variation was done in TRA or LOC frame
591 //
592 // deltaM = Z * deltaL * Z^-1
593 // where deltaL is local correction matrix and Z is matrix defined as
594 // Z = [ Prod_{k=0}^{j-1} G_k * deltaL_k * G^-1_k ] * G_j
595 // with j=being the level of the volume in the hierarchy
596 //
597 createLocDeltaMatrix(deltaM);
598 TGeoHMatrix zMat = getMatrixL2G();
599 const AlignableVolume* par = this;
600 while( (par=par->getParent()) ) {
601 TGeoHMatrix locP;
602 par->createLocDeltaMatrix(locP);
603 locP.MultiplyLeft( &par->getMatrixL2G() );
604 locP.Multiply( &par->getMatrixL2G().Inverse() );
605 zMat.MultiplyLeft( &locP );
606 }
607 deltaM.MultiplyLeft( &zMat );
608 deltaM.Multiply( &zMat.Inverse() );
609 //
610}
611*/
612
613//_________________________________________________________________
614void AlignableVolume::createPreGloDeltaMatrix(TGeoHMatrix& deltaM) const
615{
616 // Create prealignment global matrix deltaM from prealigned G and
617 // original GO local-to-global matrices
618 //
619 // From G_j = Delta_j * Delta_{j-1} ... Delta_0 * GO_j
620 // where Delta_j is global prealignment matrix for volume at level j
621 // we get by induction
622 // Delta_j = G_j * GO^-1_j * GO_{j-1} * G^-1_{j-1}
623 //
624 deltaM = getMatrixL2G();
625 deltaM *= getMatrixL2GIdeal().Inverse();
626 const AlignableVolume* par = getParent();
627 if (par) {
628 deltaM *= par->getMatrixL2GIdeal();
629 deltaM *= par->getMatrixL2G().Inverse();
630 }
631 //
632}
633
634/*
635// this is an alternative lengthy way !
636//_________________________________________________________________
637void AlignableVolume::createPreGloDeltaMatrix(TGeoHMatrix &deltaM) const
638{
639 // Create prealignment global matrix deltaM from prealigned G and
640 // original GO local-to-global matrices
641 //
642 // From G_j = Delta_j * Delta_{j-1} ... Delta_0 * GO_j
643 // where Delta_j is global prealignment matrix for volume at level j
644 // we get by induction
645 // Delta_j = G_j * GO^-1_j * GO_{j-1} * G^-1_{j-1}
646 //
647 createPreLocDeltaMatrix(deltaM);
648 TGeoHMatrix zMat = getMatrixL2GIdeal();
649 const AlignableVolume* par = this;
650 while( (par=par->getParent()) ) {
651 TGeoHMatrix locP;
652 par->createPreLocDeltaMatrix(locP);
653 locP.MultiplyLeft( &par->getMatrixL2GIdeal() );
654 locP.Multiply( &par->getMatrixL2GIdeal().Inverse() );
655 zMat.MultiplyLeft( &locP );
656 }
657 deltaM.MultiplyLeft( &zMat );
658 deltaM.Multiply( &zMat.Inverse() );
659 //
660}
661*/
662
663//_________________________________________________________________
664void AlignableVolume::createPreLocDeltaMatrix(TGeoHMatrix& deltaM) const
665{
666 // Create prealignment local matrix deltaM from prealigned G and
667 // original GO local-to-global matrices
668 //
669 // From G_j = GO_0 * delta_0 * GO^-1_0 * GO_1 * delta_1 ... GO^-1_{j-1}*GO_{j}*delta_j
670 // where delta_j is local prealignment matrix for volume at level j
671 // we get by induction
672 // delta_j = GO^-1_j * GO_{j-1} * G^-1_{j-1} * G^_{j}
673 //
674 const AlignableVolume* par = getParent();
675 deltaM = getMatrixL2GIdeal().Inverse();
676 if (par) {
677 deltaM *= par->getMatrixL2GIdeal();
678 deltaM *= par->getMatrixL2G().Inverse();
679 }
680 deltaM *= getMatrixL2G();
681 //
682}
683
684//_________________________________________________________________
685bool AlignableVolume::createLocDeltaMatrix(TGeoHMatrix& deltaM) const
686{
687 // Create local matrix deltaM from global array containing corrections.
688 // This deltaM does not account for eventual prealignment
689 // Volume knows if its variation was done in TRA or LOC frame
690 auto pars = getParVals();
691 double corr[kNDOFGeom] = {0.};
692 int nonZero = 0;
693 for (int i = kNDOFGeom; i--;) {
694 if (pars[i] != 0.) {
695 nonZero++;
696 corr[i] = pars[i];
697 }
698 } // we need doubles
699 delta2Matrix(deltaM, corr);
700 if (isFrameTRA() && nonZero) { // we need corrections in local frame!
701 // l' = T2L * delta_t * t = T2L * delta_t * T2L^-1 * l = delta_l * l
702 // -> delta_l = T2L * delta_t * T2L^-1
703 const TGeoHMatrix& t2l = getMatrixT2L();
704 const TGeoHMatrix t2li = t2l.Inverse();
705 deltaM.Multiply(&t2li);
706 deltaM.MultiplyLeft(&t2l);
707 }
708 return nonZero;
709}
710
711//_________________________________________________________________
712void AlignableVolume::createAlignmenMatrix(TGeoHMatrix& alg, const TGeoHMatrix* envelopeDelta) const
713{
714 // create final alignment matrix, accounting for eventual prealignment
715 //
716 // if the correction for this volume at level j is TAU (global delta) then the combined
717 // correction (accounting for reference prealignment) is
718 // (Delta_0 * .. Delta_{j-1})^-1 * TAU ( Delta_0 * .. Delta_j)
719 // where Delta_i is prealigment global delta of volume i (0 is top)
720 // In principle, it can be obtained as:
721 // GIdeal_{j-1} * G_{j-1}^-1 * TAU * G_{j}^-1 * GIdeal_{j}^-1
722 // where G_i is pre-misaligned reference L2G and GIdeal_i is L2GIdeal,
723 // but this creates precision problem.
724 // Therefore we use explicitly cached Deltas from prealignment object.
725 //
726 // If (parent) envelopeDelta is provided, it is simply added on top of its proper global delta matrix
727
728 const AlignableVolume* par = getParent();
729 bool nonTrivial = createGloDeltaMatrix(alg);
730 if (envelopeDelta) {
731 if (nonTrivial) {
732 alg.MultiplyLeft(envelopeDelta);
733 } else {
734 alg = *envelopeDelta;
735 }
736 nonTrivial = true;
737 }
738 // Account parent matrices only if the alg matrix is non-trivial.
739 // Also, if parent is dummy envelope, it is already accounted via envelopeDelta
740 if (nonTrivial && (par && !par->isDummyEnvelope())) {
741 // if envelopeDelta is provided, then there should be
742 TGeoHMatrix dchain;
743 while (par) {
744 dchain.MultiplyLeft(&par->getGlobalDeltaRef());
745 par = par->getParent();
746 }
747 const TGeoHMatrix& dchaini = dchain.Inverse();
748 alg.Multiply(&dchain);
749 alg.MultiplyLeft(&dchaini);
750 }
751 alg *= getGlobalDeltaRef();
752
753 /* // bad precision ?
754 alg.Multiply(&getMatrixL2G());
755 alg.Multiply(&getMatrixL2GIdeal().Inverse());
756 if (par) {
757 alg.MultiplyLeft(&par->getMatrixL2G().Inverse());
758 alg.MultiplyLeft(&par->getMatrixL2GIdeal());
759 }
760 */
761}
762
763/*
764//_________________________________________________________________
765void AlignableVolume::createAlignmenMatrix(TGeoHMatrix& alg) const
766{
767 // create final alignment matrix, accounting for eventual prealignment
768 //
769 // deltaGlo_j * X_{j-1} * PdeltaGlo_j * X^-1_{j-1}
770 //
771 // where deltaGlo_j is global alignment matrix for this volume at level j
772 // of herarchy, obtained from createGloDeltaMatrix.
773 // PdeltaGlo_j is prealignment global matrix and
774 // X_i = deltaGlo_i * deltaGlo_{i-1} .. deltaGle_0
775 //
776 TGeoHMatrix delGloPre,matX;
777 createGloDeltaMatrix(alg);
778 createPreGloDeltaMatrix(delGloPre);
779 const AlignableVolume* par = this;
780 while( (par=par->getParent()) ) {
781 TGeoHMatrix parDelGlo;
782 par->createGloDeltaMatrix(parDelGlo);
783 matX *= parDelGlo;
784 }
785 alg *= matX;
786 alg *= delGloPre;
787 alg *= matX.Inverse();
788 //
789}
790*/
791
792//_________________________________________________________________
793void AlignableVolume::createAlignmentObjects(std::vector<o2::detectors::AlignParam>& arr, const TGeoHMatrix* envelopeDelta) const
794{
795 // add to supplied array alignment object for itself and children
796 if (isDummy()) {
797 LOGP(info, "Skipping alignment object creation for dummy volume {}", GetName());
798 return;
799 }
800 TGeoHMatrix algM;
801 bool nonTrivial = false;
802 if (!isDummyEnvelope()) {
803 createAlignmenMatrix(algM, envelopeDelta);
804 arr.emplace_back(getSymName(), getVolID(), algM, true).rectify(AlignConfig::Instance().alignParamZero);
805 envelopeDelta = nullptr;
806 } else {
807 nonTrivial = createGloDeltaMatrix(algM);
808 if (envelopeDelta) {
809 if (nonTrivial) {
810 algM.MultiplyLeft(envelopeDelta);
811 } else {
812 algM = *envelopeDelta;
813 }
814 nonTrivial = true;
815 }
816 envelopeDelta = &algM;
817 }
818
819 int nch = getNChildren();
820 for (int ich = 0; ich < nch; ich++) {
821 getChild(ich)->createAlignmentObjects(arr, nonTrivial ? envelopeDelta : nullptr);
822 }
823}
824
825//_________________________________________________________________
826void AlignableVolume::updateL2GRecoMatrices(const std::vector<o2::detectors::AlignParam>& algArr, const TGeoHMatrix* cumulDelta)
827{
828 // recreate mMatL2GReco matrices from ideal L2G matrix and alignment objects
829 // used during data reconstruction. For the volume at level J we have
830 // L2G' = Delta_J * Delta_{J-1} *...* Delta_0 * L2GIdeal
831 // cumulDelta is Delta_{J-1} * ... * Delta_0, supplied by the parent
832 //
834 // find alignment object for this volume;
835 const detectors::AlignParam* par = nullptr;
836 int selPar = -1;
837 for (size_t i = 0; i < algArr.size(); i++) {
838 if (algArr[i].getSymName() == getSymName()) {
839 selPar = int(i);
840 break;
841 }
842 }
843 TGeoHMatrix delta;
844 if (selPar < 0) {
845 LOG(info) << "Alignment for " << getSymName() << " is absent in Reco-Time alignment object";
846 } else {
847 delta = algArr[selPar].createMatrix();
848 }
849 if (cumulDelta) {
850 delta *= *cumulDelta;
851 }
852 //
853 mMatL2GReco.MultiplyLeft(&delta);
854 // propagate to children
855 for (int ich = getNChildren(); ich--;) {
856 getChild(ich)->updateL2GRecoMatrices(algArr, &delta);
857 }
858 //
859}
860
861//______________________________________________________
863{
864 // check if DOF ID belongs to this volume or its children
865 if (id >= mFirstParGloID && id < mFirstParGloID + mNDOFs) {
866 return true;
867 }
868 //
869 for (int iv = getNChildren(); iv--;) {
870 AlignableVolume* vol = getChild(iv);
871 if (vol->ownsDOFID(id)) {
872 return true;
873 }
874 }
875 return false;
876}
877
878//______________________________________________________
880{
881 // gets volume owning this DOF ID
882 if (id >= mFirstParGloID && id < mFirstParGloID + mNDOFs) {
883 return (AlignableVolume*)this;
884 }
885 //
886 for (int iv = getNChildren(); iv--;) {
887 AlignableVolume* vol = getChild(iv);
888 if ((vol = vol->getVolOfDOFID(id))) {
889 return vol;
890 }
891 }
892 return nullptr;
893}
894
895//______________________________________________________
896const char* AlignableVolume::getDOFName(int i) const
897{
898 // get name of DOF
899 return getGeomDOFName(i);
900}
901
902//________________________________________
904{
905 // adds automatic constraints
906 int nch = getNChildren();
907 //
908 if (hasChildrenConstraint()) {
909 auto& cstr = getController()->getConstraints().emplace_back();
910 cstr.setConstrainPattern(mConstrChild);
911 cstr.setParent(this);
912 for (int ich = nch; ich--;) {
913 auto child = getChild(ich);
914 if (child->getExcludeFromParentConstraint()) {
915 continue;
916 }
917 cstr.addChild(child);
918 }
919 if (!cstr.getNChildren()) {
920 getController()->getConstraints().pop_back(); // destroy
921 }
922 }
923 for (int ich = 0; ich < nch; ich++) {
925 }
926}
927
928//________________________________________
929bool AlignableVolume::isNameMatching(const std::string& regexStr) const
930{
931 return (!regexStr.empty() && std::regex_match(getSymName(), std::regex{regexStr}));
932}
933
934} // namespace align
935} // namespace o2
Definition of the base alignment parameters class.
Configuration file for global alignment.
ClassImp(o2::align::AlignableVolume)
Base class of alignable volume.
Steering class for the global alignment.
Collection of auxillary methods.
Definition of the GeometryManager class.
int32_t i
Descriptor of geometrical constraint.
uint32_t j
Definition RawData.h:0
void calcFree(bool condFree=true)
virtual void prepareMatrixL2G(bool reco=false)
virtual void updateL2GRecoMatrices(const std::vector< o2::detectors::AlignParam > &algArr, const TGeoHMatrix *cumulDelta)
void createPreGloDeltaMatrix(TGeoHMatrix &deltaM) const
bool isNameMatching(const std::string &regexStr) const
static const char * sFrameName[kNVarFrames]
AlignableVolume * getChild(int i) const
const TGeoHMatrix & getMatrixT2L() const
virtual void writePedeInfo(FILE *parOut, const Option_t *opt="") const
bool isChildrenDOFConstrained(int dof) const
virtual bool isSensor() const
void Print(const Option_t *opt="") const override
static const char * sDOFName[kNDOFGeom]
void getDeltaT2LmodLOC(TGeoHMatrix &matMod, const double *delta) const
bool isMeasuredDOF(int dof) const
void delta2Matrix(TGeoHMatrix &deltaM, const double *delta) const
void setMatrixL2GIdeal(const TGeoHMatrix &m)
void getParValGeom(double *delta) const
void getDeltaT2LmodTRA(TGeoHMatrix &matMod, const double *delta) const
bool getExcludeFromParentConstraint() const
bool isCondDOF(int dof) const
const TGeoHMatrix & getMatrixL2G() const
virtual void writeLabeledPedeResults(FILE *parOut) const
const TGeoHMatrix & getMatrixL2GReco() const
bool isFreeDOF(int dof) const
bool createGloDeltaMatrix(TGeoHMatrix &deltaM) const
virtual void addChild(AlignableVolume *ch)
bool createLocDeltaMatrix(TGeoHMatrix &deltaM) const
void createAlignmenMatrix(TGeoHMatrix &alg, const TGeoHMatrix *envelopeDelta=nullptr) const
void setMatrixL2GReco(const TGeoHMatrix &m)
static const char * getGeomDOFName(int i)
AlignableVolume * getVolOfDOFID(int id) const
void setMatrixL2G(const TGeoHMatrix &m)
void createAlignmentObjects(std::vector< o2::detectors::AlignParam > &arr, const TGeoHMatrix *envelopeDelta=nullptr) const
const TGeoHMatrix & getMatrixL2GIdeal() const
AlignableVolume * getParent() const
void createPreLocDeltaMatrix(TGeoHMatrix &deltaM) const
const TGeoHMatrix & getGlobalDeltaRef() const
const char * getSymName() const
virtual const char * getDOFName(int i) const
void setFreeDOFPattern(uint32_t pat)
void expandGlobalsBy(int n)
void setParLab(int par, int lab)
Definition DOFSet.h:60
const float * getParVals() const
Definition DOFSet.cxx:29
Controller * mController
Definition DOFSet.h:73
void setFirstParGloID(int id)
Definition DOFSet.h:55
float getParVal(int par) const
Definition DOFSet.h:39
const float * getParErrs() const
Definition DOFSet.cxx:35
float getParErr(int par) const
Definition DOFSet.h:40
void setNDOFs(int n)
Definition DOFSet.h:51
int getNDOFsFree() const
Definition DOFSet.h:45
int getParLab(int par) const
Definition DOFSet.h:41
bool varsSet() const
Definition DOFSet.h:71
void setParErr(int par, double e=0)
Definition DOFSet.h:59
int getNDOFs() const
Definition DOFSet.h:44
auto getController()
Definition DOFSet.h:67
static Bool_t getOriginalMatrix(o2::detectors::DetID detid, int sensid, TGeoHMatrix &m)
static TGeoHMatrix * getMatrix(const char *symname)
TGeoHMatrix createMatrix() const
extract global delta matrix
void setRotation(double psi, double theta, double phi)
set global delta rotations angles in radian
void setTranslation(double x, double y, double z)
set global delta displacements in cm
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
constexpr bool isZeroAbs(double d) noexcept
Definition utils.h:63
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"