1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
16 //-----------------------------------------------------------------
17 // Implementation of the alignment object class through the abstract
18 // class AliAlignObj. From it two derived concrete representation of
19 // alignment object class (AliAlignObjAngles, AliAlignObjMatrix) are
20 // derived in separate files.
21 //-----------------------------------------------------------------
22 /*****************************************************************************
23 * AliAlignObjAngles: derived alignment class storing alignment information *
24 * for a single volume in form of three doubles for the translation *
25 * and three doubles for the rotation expressed with the euler angles *
26 * in the xyz-convention (http://mathworld.wolfram.com/EulerAngles.html), *
27 * also known as roll, pitch, yaw. PLEASE NOTE THE ANGLES SIGNS ARE *
28 * INVERSE WITH RESPECT TO THIS REFERENCE!!! In this way the representation*
29 * is fully consistent with the TGeo Rotation methods. *
30 *****************************************************************************/
32 #include <TGeoManager.h>
33 #include <TGeoPhysicalNode.h>
35 #include "AliAlignObj.h"
36 #include "AliTrackPointArray.h"
38 #include "AliAlignObjAngles.h"
42 Int_t AliAlignObj::fgLayerSize[kLastLayer - kFirstLayer] = {
47 90, 90, 90, 90, 90, 90, // TRD
54 const char* AliAlignObj::fgLayerName[kLastLayer - kFirstLayer] = {
55 "ITS inner pixels layer", "ITS outer pixels layer",
56 "ITS inner drifts layer", "ITS outer drifts layer",
57 "ITS inner strips layer", "ITS outer strips layer",
58 "TPC inner chambers layer", "TPC outer chambers layer",
59 "TRD chambers layer 1", "TRD chambers layer 2", "TRD chambers layer 3",
60 "TRD chambers layer 4", "TRD chambers layer 5", "TRD chambers layer 6",
67 TString* AliAlignObj::fgVolPath[kLastLayer - kFirstLayer] = {
80 AliAlignObj** AliAlignObj::fgAlignObjs[kLastLayer - kFirstLayer] = {
93 //_____________________________________________________________________________
94 AliAlignObj::AliAlignObj():
97 // default constructor
101 //_____________________________________________________________________________
102 AliAlignObj::AliAlignObj(const AliAlignObj& theAlignObj) :
106 fVolPath = theAlignObj.GetVolPath();
107 fVolUID = theAlignObj.GetVolUID();
110 //_____________________________________________________________________________
111 AliAlignObj &AliAlignObj::operator =(const AliAlignObj& theAlignObj)
113 // assignment operator
114 if(this==&theAlignObj) return *this;
115 fVolPath = theAlignObj.GetVolPath();
116 fVolUID = theAlignObj.GetVolUID();
120 //_____________________________________________________________________________
121 AliAlignObj &AliAlignObj::operator*=(const AliAlignObj& theAlignObj)
123 // multiplication operator
124 // The operator can be used to 'combine'
125 // two alignment objects
129 theAlignObj.GetMatrix(m2);
130 m1.MultiplyLeft(&m2);
135 //_____________________________________________________________________________
136 AliAlignObj::~AliAlignObj()
141 //_____________________________________________________________________________
142 void AliAlignObj::SetVolUID(ELayerID detId, Int_t modId)
144 // From detector name and module number (according to detector numbering)
145 // build fVolUID, unique numerical identity of that volume inside ALICE
146 // fVolUID is 16 bits, first 5 reserved for detID (32 possible values),
147 // remaining 11 for module ID inside det (2048 possible values).
149 fVolUID = LayerToVolUID(detId,modId);
152 //_____________________________________________________________________________
153 void AliAlignObj::GetVolUID(ELayerID &layerId, Int_t &modId) const
155 // From detector name and module number (according to detector numbering)
156 // build fVolUID, unique numerical identity of that volume inside ALICE
157 // fVolUID is 16 bits, first 5 reserved for detID (32 possible values),
158 // remaining 11 for module ID inside det (2048 possible values).
160 layerId = VolUIDToLayer(fVolUID,modId);
163 //_____________________________________________________________________________
164 void AliAlignObj::AnglesToMatrix(const Double_t *angles, Double_t *rot) const
166 // Calculates the rotation matrix using the
167 // Euler angles in "x y z" notation
168 Double_t degrad = TMath::DegToRad();
169 Double_t sinpsi = TMath::Sin(degrad*angles[0]);
170 Double_t cospsi = TMath::Cos(degrad*angles[0]);
171 Double_t sinthe = TMath::Sin(degrad*angles[1]);
172 Double_t costhe = TMath::Cos(degrad*angles[1]);
173 Double_t sinphi = TMath::Sin(degrad*angles[2]);
174 Double_t cosphi = TMath::Cos(degrad*angles[2]);
176 rot[0] = costhe*cosphi;
177 rot[1] = -costhe*sinphi;
179 rot[3] = sinpsi*sinthe*cosphi + cospsi*sinphi;
180 rot[4] = -sinpsi*sinthe*sinphi + cospsi*cosphi;
181 rot[5] = -costhe*sinpsi;
182 rot[6] = -cospsi*sinthe*cosphi + sinpsi*sinphi;
183 rot[7] = cospsi*sinthe*sinphi + sinpsi*cosphi;
184 rot[8] = costhe*cospsi;
187 //_____________________________________________________________________________
188 Bool_t AliAlignObj::MatrixToAngles(const Double_t *rot, Double_t *angles) const
190 // Calculates the Euler angles in "x y z" notation
191 // using the rotation matrix
192 if(TMath::Abs(rot[0])<1e-7 || TMath::Abs(rot[8])<1e-7) return kFALSE;
193 Double_t raddeg = TMath::RadToDeg();
194 angles[0]=raddeg*TMath::ATan2(-rot[5],rot[8]);
195 angles[1]=raddeg*TMath::ASin(rot[2]);
196 angles[2]=raddeg*TMath::ATan2(-rot[1],rot[0]);
200 //______________________________________________________________________________
201 void AliAlignObj::Transform(AliTrackPoint &p) const
203 // The method transforms the space-point coordinates using the
204 // transformation matrix provided by the AliAlignObj
205 // The covariance matrix is not affected since we assume
206 // that the transformations are sufficiently small
208 if (fVolUID != p.GetVolumeID())
209 AliWarning(Form("Alignment object ID is not equal to the space-point ID (%d != %d)",fVolUID,p.GetVolumeID()));
213 Double_t *rot = m.GetRotationMatrix();
214 Double_t *tr = m.GetTranslation();
216 Float_t xyzin[3],xyzout[3];
218 for (Int_t i = 0; i < 3; i++)
227 //______________________________________________________________________________
228 void AliAlignObj::Transform(AliTrackPointArray &array) const
231 for (Int_t i = 0; i < array.GetNPoints(); i++) {
234 array.AddPoint(i,&p);
238 //_____________________________________________________________________________
239 void AliAlignObj::Print(Option_t *) const
241 // Print the contents of the
242 // alignment object in angles and
243 // matrix representations
250 const Double_t *rot = m.GetRotationMatrix();
251 // printf("Volume=%s ID=%u\n", GetVolPath(),GetVolUID());
254 GetVolUID(layerId,modId);
255 printf("Volume=%s LayerID=%d ModuleID=%d\n", GetVolPath(),layerId,modId);
256 printf("%12.6f%12.6f%12.6f Tx = %12.6f Psi = %12.6f\n", rot[0], rot[1], rot[2], tr[0], angles[0]);
257 printf("%12.6f%12.6f%12.6f Ty = %12.6f Theta = %12.6f\n", rot[3], rot[4], rot[5], tr[1], angles[1]);
258 printf("%12.6f%12.6f%12.6f Tz = %12.6f Phi = %12.6f\n", rot[6], rot[7], rot[8], tr[2], angles[2]);
262 //_____________________________________________________________________________
263 UShort_t AliAlignObj::LayerToVolUID(ELayerID layerId, Int_t modId)
265 // From detector (layer) name and module number (according to detector numbering)
266 // build fVolUID, unique numerical identity of that volume inside ALICE
267 // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
268 // remaining 11 for module ID inside det (2048 possible values).
270 return ((UShort_t(layerId) << 11) | UShort_t(modId));
273 //_____________________________________________________________________________
274 UShort_t AliAlignObj::LayerToVolUID(Int_t layerId, Int_t modId)
276 // From detector (layer) index and module number (according to detector numbering)
277 // build fVolUID, unique numerical identity of that volume inside ALICE
278 // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
279 // remaining 11 for module ID inside det (2048 possible values).
281 return ((UShort_t(layerId) << 11) | UShort_t(modId));
284 //_____________________________________________________________________________
285 AliAlignObj::ELayerID AliAlignObj::VolUIDToLayer(UShort_t voluid, Int_t &modId)
287 // From detector (layer) name and module number (according to detector numbering)
288 // build fVolUID, unique numerical identity of that volume inside ALICE
289 // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
290 // remaining 11 for module ID inside det (2048 possible values).
292 modId = voluid & 0x7ff;
294 return VolUIDToLayer(voluid);
297 //_____________________________________________________________________________
298 AliAlignObj::ELayerID AliAlignObj::VolUIDToLayer(UShort_t voluid)
300 // From detector (layer) name and module number (according to detector numbering)
301 // build fVolUID, unique numerical identity of that volume inside ALICE
302 // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
303 // remaining 11 for module ID inside det (2048 possible values).
305 return ELayerID((voluid >> 11) & 0x1f);
308 //_____________________________________________________________________________
309 Bool_t AliAlignObj::SetLocalPars(Double_t x, Double_t y, Double_t z,
310 Double_t psi, Double_t theta, Double_t phi)
312 // Set the translations and angles by using parameters
313 // defined in the local (in TGeo means) coordinate system
314 // of the alignable volume. In case that the TGeo was
315 // initialized, returns false and the object parameters are
317 if (!gGeoManager || !gGeoManager->IsClosed()) {
318 AliError("Can't set the alignment object parameters! gGeoManager doesn't exist or it is still opened!");
322 const char* volpath = GetVolPath();
323 TGeoPhysicalNode* node = (TGeoPhysicalNode*) gGeoManager->MakePhysicalNode(volpath);
325 AliError(Form("Volume path %s not valid!",volpath));
328 if (node->IsAligned())
329 AliWarning(Form("Volume %s has been already misaligned!",volpath));
333 tr[0]=x; tr[1]=y; tr[2]=z;
334 m.SetTranslation(tr);
335 Double_t angles[3] = {psi, theta, phi};
337 AnglesToMatrix(angles,rot);
340 TGeoHMatrix align,gprime,gprimeinv;
341 gprime = *node->GetMatrix();
342 gprimeinv = gprime.Inverse();
343 m.Multiply(&gprimeinv);
344 m.MultiplyLeft(&gprime);
351 //_____________________________________________________________________________
352 Bool_t AliAlignObj::ApplyToGeometry()
354 // Apply the current alignment object
355 // to the TGeo geometry
357 if (!gGeoManager || !gGeoManager->IsClosed()) {
358 AliError("Can't apply the alignment object! gGeoManager doesn't exist or it is still opened!");
362 const char* volpath = GetVolPath();
363 TGeoPhysicalNode* node = (TGeoPhysicalNode*) gGeoManager->MakePhysicalNode(volpath);
365 AliError(Form("Volume path %s not valid!",volpath));
368 if (node->IsAligned()) {
369 AliWarning(Form("Volume %s has been already misaligned!",volpath));
373 TGeoHMatrix align,gprime;
374 gprime = *node->GetMatrix();
376 gprime.MultiplyLeft(&align);
377 TGeoHMatrix *ginv = new TGeoHMatrix;
378 TGeoHMatrix *g = node->GetMatrix(node->GetLevel()-1);
379 *ginv = g->Inverse();
381 AliAlignObj::ELayerID layerId; // unique identity for volume in the alobj
382 Int_t modId; // unique identity for volume in the alobj
383 GetVolUID(layerId, modId);
384 AliInfo(Form("Aligning volume %s of detector layer %d with local ID %d",volpath,layerId,modId));
390 //_____________________________________________________________________________
391 Bool_t AliAlignObj::GetFromGeometry(const char *path, AliAlignObj &alobj)
393 // Get the alignment object which correspond
394 // to the TGeo volume defined by the 'path'.
395 // The method is extremely slow due to the
396 // searching by string. Therefore it should
397 // be used with great care!!
399 // Reset the alignment object
400 alobj.SetPars(0,0,0,0,0,0);
401 alobj.SetVolPath(path);
403 if (!gGeoManager || !gGeoManager->IsClosed()) {
404 AliErrorClass("Can't get the alignment object! gGeoManager doesn't exist or it is still opened!");
408 if (!gGeoManager->GetListOfPhysicalNodes()) {
409 AliErrorClass("Can't get the alignment object! gGeoManager doesn't contain any aligned nodes!");
413 TObjArray* nodesArr = gGeoManager->GetListOfPhysicalNodes();
414 TGeoPhysicalNode* node = NULL;
415 for (Int_t iNode = 0; iNode < nodesArr->GetEntriesFast(); iNode++) {
416 node = (TGeoPhysicalNode*) nodesArr->UncheckedAt(iNode);
417 const char *nodePath = node->GetName();
418 if (strcmp(path,nodePath) == 0) break;
421 if (!gGeoManager->cd(path)) {
422 AliErrorClass(Form("Volume path %s not found!",path));
426 AliWarningClass(Form("Volume (%s) has not been misaligned!",path));
431 TGeoHMatrix align,gprime,g,ginv,l;
432 gprime = *node->GetMatrix();
433 l = *node->GetOriginalMatrix();
434 g = *node->GetMatrix(node->GetLevel()-1);
437 align = gprime * ginv;
438 alobj.SetMatrix(align);
443 void AliAlignObj::InitAlignObjFromGeometry()
445 // Loop over all alignable volumes and extract
446 // the corresponding alignment objects from
449 if(fgAlignObjs[0]) return;
453 for (Int_t iLayer = 0; iLayer < (AliAlignObj::kLastLayer - AliAlignObj::kFirstLayer); iLayer++) {
454 fgAlignObjs[iLayer] = new AliAlignObj*[AliAlignObj::LayerSize(iLayer)];
455 for (Int_t iModule = 0; iModule < AliAlignObj::LayerSize(iLayer); iModule++) {
456 UShort_t volid = AliAlignObj::LayerToVolUID(iLayer+ AliAlignObj::kFirstLayer,iModule);
457 fgAlignObjs[iLayer][iModule] = new AliAlignObjAngles("",volid,0,0,0,0,0,0);
458 const char *path = GetVolPath(volid);
459 if (!GetFromGeometry(path, *fgAlignObjs[iLayer][iModule]))
460 AliErrorClass(Form("Failed to extract the alignment object for the volume (ID=%d and path=%s) !",volid,path));
466 //_____________________________________________________________________________
467 AliAlignObj* AliAlignObj::GetAlignObj(ELayerID layerId, Int_t modId)
469 if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
470 AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
473 return fgAlignObjs[layerId-kFirstLayer][modId];
476 //_____________________________________________________________________________
477 const char* AliAlignObj::GetVolPath(ELayerID layerId, Int_t modId)
479 if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
480 AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
483 return fgVolPath[layerId-kFirstLayer][modId].Data();
486 //_____________________________________________________________________________
487 void AliAlignObj::InitVolPaths()
489 // Initialize the LUTs which contain
490 // the TGeo volume paths for each
491 // alignable volume. The LUTs are
492 // static, so they are created during
493 // the creation of the first intance
496 if (fgVolPath[0]) return;
498 for (Int_t iLayer = 0; iLayer < (kLastLayer - kFirstLayer); iLayer++)
499 fgVolPath[iLayer] = new TString[fgLayerSize[iLayer]];
501 /********************* SPD layer1 ***********************/
504 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT12_1/I12B_"; //".../I12A_"
505 TString str1 = "/I10B_"; //"/I10A_";
506 TString str2 = "/I107_"; //"/I103_"
507 // TString str3 = "/I101_1/ITS1_1";
508 TString volpath, volpath1, volpath2;
510 for(Int_t c1 = 1; c1<=10; c1++){
514 for(Int_t c2 =1; c2<=2; c2++){
518 for(Int_t c3 =1; c3<=4; c3++){
522 fgVolPath[kSPD1-kFirstLayer][modnum] = volpath2.Data();
529 /********************* SPD layer2 ***********************/
532 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT12_1/I12B_"; //".../I12A_"
533 TString str1 = "/I20B_"; //"/I20A"
534 TString str2 = "/I1D7_"; //"/I1D3"
535 // TString str3 = "/I1D1_1/ITS2_1";
536 TString volpath, volpath1, volpath2;
538 for(Int_t c1 = 1; c1<=10; c1++){
542 for(Int_t c2 =1; c2<=4; c2++){
546 for(Int_t c3 =1; c3<=4; c3++){
550 fgVolPath[kSPD2-kFirstLayer][modnum] = volpath2.Data();
557 /********************* SDD layer1 ***********************/
560 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT34_1/I004_";
561 TString str1 = "/I302_";
562 // TString str2 = "/ITS3_1";
563 TString volpath, volpath1;
565 for(Int_t c1 = 1; c1<=14; c1++){
569 for(Int_t c2 =1; c2<=6; c2++){
573 fgVolPath[kSDD1-kFirstLayer][modnum] = volpath1.Data();
579 /********************* SDD layer2 ***********************/
582 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT34_1/I005_";
583 TString str1 = "/I402_";
584 // TString str2 = "/ITS4_1";
585 TString volpath, volpath1;
587 for(Int_t c1 = 1; c1<=22; c1++){
591 for(Int_t c2 = 1; c2<=8; c2++){
595 fgVolPath[kSDD2-kFirstLayer][modnum] = volpath1.Data();
601 /********************* SSD layer1 ***********************/
604 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT56_1/I565_";
605 TString str1 = "/I562_";
606 // TString str2 = "/ITS5_1";
607 TString volpath, volpath1;
609 for(Int_t c1 = 1; c1<=34; c1++){
613 for(Int_t c2 = 1; c2<=22; c2++){
617 fgVolPath[kSSD1-kFirstLayer][modnum] = volpath1.Data();
623 /********************* SSD layer1 ***********************/
626 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT56_1/I569_";
627 TString str1 = "/I566_";
628 // TString str2 = "/ITS6_1";
629 TString volpath, volpath1;
631 for(Int_t c1 = 1; c1<=38; c1++){
635 for(Int_t c2 = 1; c2<=25; c2++){
639 fgVolPath[kSSD2-kFirstLayer][modnum] = volpath1.Data();
645 /*************** TPC inner chambers' layer ****************/
648 TString str1 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_1/TPC_SECT_";
649 TString str2 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_2/TPC_SECT_";
650 TString str_in = "/TPC_IROC_1";
653 for(Int_t cnt=1; cnt<=18; cnt++){
657 fgVolPath[kTPC1-kFirstLayer][modnum] = volpath.Data();
660 for(Int_t cnt=1; cnt<=18; cnt++){
664 fgVolPath[kTPC1-kFirstLayer][modnum] = volpath.Data();
669 /*************** TPC outer chambers' layer ****************/
672 TString str1 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_1/TPC_SECT_";
673 TString str2 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_2/TPC_SECT_";
674 TString str_out = "/TPC_OROC_1";
677 for(Int_t cnt=1; cnt<=18; cnt++){
681 fgVolPath[kTPC2-kFirstLayer][modnum] = volpath.Data();
684 for(Int_t cnt=1; cnt<=18; cnt++){
688 fgVolPath[kTPC2-kFirstLayer][modnum] = volpath.Data();
693 /********************* TOF layer ***********************/
698 Int_t nStripSec=nstrA+2*nstrB+2*nstrC;
700 for (Int_t modnum=0; modnum < 1674; modnum++) {
702 Int_t sector = modnum/nStripSec;
710 sprintf(string1,"/ALIC_1/B077_1/B075_%i/BTO3_1",icopy);
714 sprintf(string1,"/ALIC_1/B077_1/B071_%i/BTO1_1",icopy);
716 else if(sector==11 || sector==12){
718 sprintf(string1,"/ALIC_1/B077_1/B074_%i/BTO2_1",icopy);
722 sprintf(string1,"/ALIC_1/B077_1/B071_%i/BTO1_1",icopy);
725 Int_t strInSec=modnum%nStripSec;
727 if( strInSec < nstrC){
728 icopy= nstrC - (strInSec+1) + 1;
729 sprintf(string2,"FTOC_1/FLTC_0/FSTR_%i",icopy);
731 else if(strInSec< nstrC+nstrB){
733 icopy= nstrB - (strInSec-nstrC+1) + 1;
734 sprintf(string2,"FTOB_1/FLTB_0/FSTR_%i",icopy);
737 else if(strInSec< nstrC+nstrB+nstrA){
739 icopy= strInSec-(nstrC+nstrB)+1;
740 sprintf(string2,"FTOA_0/FLTA_0/FSTR_%i",icopy);
742 else if(strInSec< nstrC+2*nstrB+nstrA){
744 icopy= strInSec-(nstrC+nstrB+nstrA)+1;
745 sprintf(string2,"FTOB_2/FLTB_0/FSTR_%i",icopy);
750 icopy= strInSec-(nstrC+2*nstrB+nstrA)+1;
751 sprintf(string2,"FTOC_2/FLTC_0/FSTR_%i",icopy);
756 sprintf(path,"%s/%s",string1,string2);
757 // printf("%d %s\n",modnum,path);
758 fgVolPath[kTOF-kFirstLayer][modnum] = path;
762 /********************* RICH layer ***********************/
764 TString str = "ALIC_1/RICH_";
767 for (Int_t modnum=0; modnum < 7; modnum++) {
769 volpath += (modnum+1);
770 fgVolPath[kRICH-kFirstLayer][modnum] = volpath.Data();