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(rot[0]<1e-7 || 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 AliWarningClass(Form("Volume path %s not found!",path));
425 TGeoHMatrix align,gprime,g,ginv,l;
426 gprime = *node->GetMatrix();
427 l = *node->GetOriginalMatrix();
428 g = *node->GetMatrix(node->GetLevel()-1);
431 align = gprime * ginv;
432 alobj.SetMatrix(align);
437 void AliAlignObj::InitAlignObjFromGeometry()
439 // Loop over all alignable volumes and extract
440 // the corresponding alignment objects from
445 for (Int_t iLayer = 0; iLayer < (AliAlignObj::kLastLayer - AliAlignObj::kFirstLayer); iLayer++) {
446 fgAlignObjs[iLayer] = new AliAlignObj*[AliAlignObj::LayerSize(iLayer)];
447 for (Int_t iModule = 0; iModule < AliAlignObj::LayerSize(iLayer); iModule++) {
448 UShort_t volid = AliAlignObj::LayerToVolUID(iLayer+ AliAlignObj::kFirstLayer,iModule);
449 fgAlignObjs[iLayer][iModule] = new AliAlignObjAngles("",volid,0,0,0,0,0,0);
450 const char *path = GetVolPath(volid);
451 if (!GetFromGeometry(path, *fgAlignObjs[iLayer][iModule]))
452 AliErrorClass(Form("Failed to extract the alignment object for the volume (ID=%d and path=%s) !",volid,path));
458 //_____________________________________________________________________________
459 AliAlignObj* AliAlignObj::GetAlignObj(ELayerID layerId, Int_t modId)
461 if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
462 AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
465 return fgAlignObjs[layerId-kFirstLayer][modId];
468 //_____________________________________________________________________________
469 const char* AliAlignObj::GetVolPath(ELayerID layerId, Int_t modId)
471 if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
472 AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
475 return fgVolPath[layerId-kFirstLayer][modId].Data();
478 //_____________________________________________________________________________
479 void AliAlignObj::InitVolPaths()
481 // Initialize the LUTs which contain
482 // the TGeo volume paths for each
483 // alignable volume. The LUTs are
484 // static, so they are created during
485 // the creation of the first intance
488 if (fgVolPath[0]) return;
490 for (Int_t iLayer = 0; iLayer < (kLastLayer - kFirstLayer); iLayer++)
491 fgVolPath[iLayer] = new TString[fgLayerSize[iLayer]];
493 /********************* SPD layer1 ***********************/
496 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT12_1/I12B_"; //".../I12A_"
497 TString str1 = "/I10B_"; //"/I10A_";
498 TString str2 = "/I107_"; //"/I103_"
499 // TString str3 = "/I101_1/ITS1_1";
500 TString volpath, volpath1, volpath2;
502 for(Int_t c1 = 1; c1<=10; c1++){
506 for(Int_t c2 =1; c2<=2; c2++){
510 for(Int_t c3 =1; c3<=4; c3++){
514 fgVolPath[kSPD1-kFirstLayer][modnum] = volpath2.Data();
521 /********************* SPD layer2 ***********************/
524 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT12_1/I12B_"; //".../I12A_"
525 TString str1 = "/I20B_"; //"/I20A"
526 TString str2 = "/I1D7_"; //"/I1D3"
527 // TString str3 = "/I1D1_1/ITS2_1";
528 TString volpath, volpath1, volpath2;
530 for(Int_t c1 = 1; c1<=10; c1++){
534 for(Int_t c2 =1; c2<=4; c2++){
538 for(Int_t c3 =1; c3<=4; c3++){
542 fgVolPath[kSPD2-kFirstLayer][modnum] = volpath2.Data();
549 /********************* SDD layer1 ***********************/
552 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT34_1/I004_";
553 TString str1 = "/I302_";
554 // TString str2 = "/ITS3_1";
555 TString volpath, volpath1;
557 for(Int_t c1 = 1; c1<=14; c1++){
561 for(Int_t c2 =1; c2<=6; c2++){
565 fgVolPath[kSDD1-kFirstLayer][modnum] = volpath1.Data();
571 /********************* SDD layer2 ***********************/
574 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT34_1/I005_";
575 TString str1 = "/I402_";
576 // TString str2 = "/ITS4_1";
577 TString volpath, volpath1;
579 for(Int_t c1 = 1; c1<=22; c1++){
583 for(Int_t c2 = 1; c2<=8; c2++){
587 fgVolPath[kSDD2-kFirstLayer][modnum] = volpath1.Data();
593 /********************* SSD layer1 ***********************/
596 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT56_1/I565_";
597 TString str1 = "/I562_";
598 // TString str2 = "/ITS5_1";
599 TString volpath, volpath1;
601 for(Int_t c1 = 1; c1<=34; c1++){
605 for(Int_t c2 = 1; c2<=22; c2++){
609 fgVolPath[kSSD1-kFirstLayer][modnum] = volpath1.Data();
615 /********************* SSD layer1 ***********************/
618 TString str0 = "ALIC_1/ITSV_1/ITSD_1/IT56_1/I569_";
619 TString str1 = "/I566_";
620 // TString str2 = "/ITS6_1";
621 TString volpath, volpath1;
623 for(Int_t c1 = 1; c1<=38; c1++){
627 for(Int_t c2 = 1; c2<=25; c2++){
631 fgVolPath[kSSD2-kFirstLayer][modnum] = volpath1.Data();
637 /*************** TPC inner chambers' layer ****************/
640 TString str1 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_1/TPC_SECT_";
641 TString str2 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_2/TPC_SECT_";
642 TString str_in = "/TPC_IROC_1";
645 for(Int_t cnt=1; cnt<=18; cnt++){
649 fgVolPath[kTPC1-kFirstLayer][modnum] = volpath.Data();
652 for(Int_t cnt=1; cnt<=18; cnt++){
656 fgVolPath[kTPC1-kFirstLayer][modnum] = volpath.Data();
661 /*************** TPC outer chambers' layer ****************/
664 TString str1 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_1/TPC_SECT_";
665 TString str2 = "ALIC_1/TPC_M_1/TPC_Drift_1/TPC_ENDCAP_2/TPC_SECT_";
666 TString str_out = "/TPC_OROC_1";
669 for(Int_t cnt=1; cnt<=18; cnt++){
673 fgVolPath[kTPC2-kFirstLayer][modnum] = volpath.Data();
676 for(Int_t cnt=1; cnt<=18; cnt++){
680 fgVolPath[kTPC2-kFirstLayer][modnum] = volpath.Data();
685 /********************* TOF layer ***********************/
690 Int_t nStripSec=nstrA+2*nstrB+2*nstrC;
692 for (Int_t modnum=0; modnum < 1674; modnum++) {
694 Int_t sector = modnum/nStripSec;
702 sprintf(string1,"/ALIC_1/B077_1/B075_%i/BTO3_1",icopy);
706 sprintf(string1,"/ALIC_1/B077_1/B071_%i/BTO1_1",icopy);
708 else if(sector==11 || sector==12){
710 sprintf(string1,"/ALIC_1/B077_1/B074_%i/BTO2_1",icopy);
714 sprintf(string1,"/ALIC_1/B077_1/B071_%i/BTO1_1",icopy);
717 Int_t strInSec=modnum%nStripSec;
719 if( strInSec < nstrC){
720 icopy= nstrC - (strInSec+1) + 1;
721 sprintf(string2,"FTOC_1/FLTC_0/FSTR_%i",icopy);
723 else if(strInSec< nstrC+nstrB){
725 icopy= nstrB - (strInSec-nstrC+1) + 1;
726 sprintf(string2,"FTOB_1/FLTB_0/FSTR_%i",icopy);
729 else if(strInSec< nstrC+nstrB+nstrA){
731 icopy= strInSec-(nstrC+nstrB)+1;
732 sprintf(string2,"FTOA_0/FLTA_0/FSTR_%i",icopy);
734 else if(strInSec< nstrC+2*nstrB+nstrA){
736 icopy= strInSec-(nstrC+nstrB+nstrA)+1;
737 sprintf(string2,"FTOB_2/FLTB_0/FSTR_%i",icopy);
742 icopy= strInSec-(nstrC+2*nstrB+nstrA)+1;
743 sprintf(string2,"FTOC_2/FLTC_0/FSTR_%i",icopy);
748 sprintf(path,"%s/%s",string1,string2);
749 // printf("%d %s\n",modnum,path);
750 fgVolPath[kTOF-kFirstLayer][modnum] = path;
754 /********************* RICH layer ***********************/
756 TString str = "ALIC_1/RICH_";
759 for (Int_t modnum=0; modnum < 7; modnum++) {
761 volpath += (modnum+1);
762 fgVolPath[kRICH-kFirstLayer][modnum] = volpath.Data();