Using symbolic names instead of volume paths (Raffaele)
[u/mrichter/AliRoot.git] / STEER / AliAlignObj.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
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  **************************************************************************/
15
16 //-----------------------------------------------------------------
17 //  Implementation of the alignment object class, holding the alignment
18 //  constants for a single volume, through the abstract class AliAlignObj.
19 //  From it two derived concrete representation of alignment object class
20 //  (AliAlignObjAngles, AliAlignObjMatrix) are derived in separate files.
21 //-----------------------------------------------------------------
22 #include <TGeoManager.h>
23 #include <TGeoPhysicalNode.h>
24
25 #include "AliAlignObj.h"
26 #include "AliTrackPointArray.h"
27 #include "AliLog.h"
28 #include "AliAlignObjAngles.h"
29  
30 ClassImp(AliAlignObj)
31
32 Int_t AliAlignObj::fgLayerSize[kLastLayer - kFirstLayer] = {
33   80, 160,  // ITS SPD first and second layer
34   84, 176,  // ITS SDD first and second layer
35   748, 950, // ITS SSD first and second layer
36   36, 36,   // TPC inner and outer chambers
37   90, 90, 90, 90, 90, 90,  // 6 TRD chambers' layers
38   1638,     // TOF
39   1, 1,     // PHOS ??
40   7,        // RICH ??
41   1         // MUON ??
42 };
43
44 const char* AliAlignObj::fgLayerName[kLastLayer - kFirstLayer] = {
45   "ITS inner pixels layer", "ITS outer pixels layer",
46   "ITS inner drifts layer", "ITS outer drifts layer",
47   "ITS inner strips layer", "ITS outer strips layer",
48   "TPC inner chambers layer", "TPC outer chambers layer",
49   "TRD chambers layer 1", "TRD chambers layer 2", "TRD chambers layer 3",
50   "TRD chambers layer 4", "TRD chambers layer 5", "TRD chambers layer 6",
51   "TOF layer",
52   "?","?",
53   "RICH layer",
54   "?"
55 };
56
57 TString* AliAlignObj::fgVolPath[kLastLayer - kFirstLayer] = {
58   0x0,0x0,
59   0x0,0x0,
60   0x0,0x0,
61   0x0,0x0,
62   0x0,0x0,0x0,
63   0x0,0x0,0x0,
64   0x0,
65   0x0,0x0,
66   0x0,
67   0x0
68 };
69
70 AliAlignObj** AliAlignObj::fgAlignObjs[kLastLayer - kFirstLayer] = {
71   0x0,0x0,
72   0x0,0x0,
73   0x0,0x0,
74   0x0,0x0,
75   0x0,0x0,0x0,
76   0x0,0x0,0x0,
77   0x0,
78   0x0,0x0,
79   0x0,
80   0x0
81 };
82
83 //_____________________________________________________________________________
84 AliAlignObj::AliAlignObj():
85   fVolPath(),
86   fVolUID(0)
87 {
88   // default constructor
89   InitSymNames();
90 }
91
92 //_____________________________________________________________________________
93 AliAlignObj::AliAlignObj(const char* symname, UShort_t voluid) :
94   TObject(),
95   fVolPath(symname),
96   fVolUID(voluid)
97 {
98   // standard constructor
99   //
100 }
101
102 //_____________________________________________________________________________
103 AliAlignObj::AliAlignObj(const AliAlignObj& theAlignObj) :
104   TObject(theAlignObj),
105   fVolPath(theAlignObj.GetSymName()),
106   fVolUID(theAlignObj.GetVolUID())
107 {
108   //copy constructor
109 }
110
111 //_____________________________________________________________________________
112 AliAlignObj &AliAlignObj::operator =(const AliAlignObj& theAlignObj)
113 {
114   // assignment operator
115   if(this==&theAlignObj) return *this;
116   fVolPath = theAlignObj.GetSymName();
117   fVolUID = theAlignObj.GetVolUID();
118   return *this;
119 }
120
121 //_____________________________________________________________________________
122 AliAlignObj &AliAlignObj::operator*=(const AliAlignObj& theAlignObj)
123 {
124   // multiplication operator
125   // The operator can be used to 'combine'
126   // two alignment objects
127   TGeoHMatrix m1;
128   GetMatrix(m1);
129   TGeoHMatrix m2;
130   theAlignObj.GetMatrix(m2);
131   m1.MultiplyLeft(&m2);
132   SetMatrix(m1);
133   return *this;
134 }
135
136 //_____________________________________________________________________________
137 AliAlignObj::~AliAlignObj()
138 {
139   // dummy destructor
140 }
141
142 //_____________________________________________________________________________
143 void AliAlignObj::SetVolUID(ELayerID detId, Int_t modId)
144 {
145   // From detector name and module number (according to detector numbering)
146   // build fVolUID, unique numerical identity of that volume inside ALICE
147   // fVolUID is 16 bits, first 5 reserved for detID (32 possible values),
148   // remaining 11 for module ID inside det (2048 possible values).
149   //
150   fVolUID = LayerToVolUID(detId,modId);
151 }
152
153 //_____________________________________________________________________________
154 void AliAlignObj::GetVolUID(ELayerID &layerId, Int_t &modId) const
155 {
156   // From the fVolUID, unique numerical identity of that volume inside ALICE,
157   // (voluid is 16 bits, first 5 reserved for layerID (32 possible values),
158   // remaining 11 for module ID inside det (2048 possible values)), sets
159   // the argument layerId to the identity of the layer to which that volume
160   // belongs and sets the argument modId to the identity of that volume
161   // internally to the layer.
162   //
163   layerId = VolUIDToLayer(fVolUID,modId);
164 }
165
166 //_____________________________________________________________________________
167 Bool_t AliAlignObj::GetPars(Double_t tr[], Double_t angles[]) const
168 {
169   GetTranslation(tr);
170   return GetAngles(angles);
171 }
172
173 //_____________________________________________________________________________
174 Int_t AliAlignObj::GetLevel() const
175 {
176   // Return the geometry level of the alignable volume to which
177   // the alignment object is associated; this is the number of
178   // slashes in the corresponding volume path
179   //
180   if(!gGeoManager){
181     AliWarning("gGeoManager doesn't exist or it is still opened: unable to return meaningful level value.");
182     return (-1);
183   }
184   const char* symname = GetSymName();
185   const char* path;
186   TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
187   if(pne){
188     path = pne->GetTitle();
189   }else{
190     path = symname;
191   }
192
193   TString path_str = path;
194   if(path_str[0]!='/') path_str.Prepend('/');
195   return path_str.CountChar('/');
196 }
197
198 //_____________________________________________________________________________
199 Int_t AliAlignObj::Compare(const TObject *obj) const
200 {
201   // Compare the levels of two
202   // alignment objects
203   // Used in the sorting during
204   // the application of alignment
205   // objects to the geometry
206   //
207   Int_t level = GetLevel();
208   Int_t level2 = ((AliAlignObj *)obj)->GetLevel();
209   if (level == level2)
210     return 0;
211   else
212     return ((level > level2) ? 1 : -1);
213 }
214
215 //_____________________________________________________________________________
216 void AliAlignObj::AnglesToMatrix(const Double_t *angles, Double_t *rot) const
217 {
218   // Calculates the rotation matrix using the 
219   // Euler angles in "x y z" notation
220   //
221   Double_t degrad = TMath::DegToRad();
222   Double_t sinpsi = TMath::Sin(degrad*angles[0]);
223   Double_t cospsi = TMath::Cos(degrad*angles[0]);
224   Double_t sinthe = TMath::Sin(degrad*angles[1]);
225   Double_t costhe = TMath::Cos(degrad*angles[1]);
226   Double_t sinphi = TMath::Sin(degrad*angles[2]);
227   Double_t cosphi = TMath::Cos(degrad*angles[2]);
228
229   rot[0] =  costhe*cosphi;
230   rot[1] = -costhe*sinphi;
231   rot[2] =  sinthe;
232   rot[3] =  sinpsi*sinthe*cosphi + cospsi*sinphi;
233   rot[4] = -sinpsi*sinthe*sinphi + cospsi*cosphi;
234   rot[5] = -costhe*sinpsi;
235   rot[6] = -cospsi*sinthe*cosphi + sinpsi*sinphi;
236   rot[7] =  cospsi*sinthe*sinphi + sinpsi*cosphi;
237   rot[8] =  costhe*cospsi;
238 }
239
240 //_____________________________________________________________________________
241 Bool_t AliAlignObj::MatrixToAngles(const Double_t *rot, Double_t *angles) const
242 {
243   // Calculates the Euler angles in "x y z" notation
244   // using the rotation matrix
245   // Returns false in case the rotation angles can not be
246   // extracted from the matrix
247   //
248   if(TMath::Abs(rot[0])<1e-7 || TMath::Abs(rot[8])<1e-7) {
249     AliError("Failed to extract roll-pitch-yall angles!");
250     return kFALSE;
251   }
252   Double_t raddeg = TMath::RadToDeg();
253   angles[0]=raddeg*TMath::ATan2(-rot[5],rot[8]);
254   angles[1]=raddeg*TMath::ASin(rot[2]);
255   angles[2]=raddeg*TMath::ATan2(-rot[1],rot[0]);
256   return kTRUE;
257 }
258
259 //______________________________________________________________________________
260 void AliAlignObj::Transform(AliTrackPoint &p) const
261 {
262   // The method transforms the space-point coordinates using the
263   // transformation matrix provided by the AliAlignObj
264   // The covariance matrix is not affected since we assume
265   // that the transformations are sufficiently small
266   //
267   if (fVolUID != p.GetVolumeID())
268     AliWarning(Form("Alignment object ID is not equal to the space-point ID (%d != %d)",fVolUID,p.GetVolumeID())); 
269
270   TGeoHMatrix m;
271   GetMatrix(m);
272   Double_t *rot = m.GetRotationMatrix();
273   Double_t *tr  = m.GetTranslation();
274
275   Float_t xyzin[3],xyzout[3];
276   p.GetXYZ(xyzin);
277   for (Int_t i = 0; i < 3; i++)
278     xyzout[i] = tr[i]+
279                 xyzin[0]*rot[3*i]+
280                 xyzin[1]*rot[3*i+1]+
281                 xyzin[2]*rot[3*i+2];
282   p.SetXYZ(xyzout);
283   
284 }
285
286 //_____________________________________________________________________________
287 void AliAlignObj::Transform(AliTrackPointArray &array) const
288 {
289   // This method is used to transform all the track points
290   // from the input AliTrackPointArray
291   // 
292   AliTrackPoint p;
293   for (Int_t i = 0; i < array.GetNPoints(); i++) {
294     array.GetPoint(p,i);
295     Transform(p);
296     array.AddPoint(i,&p);
297   }
298 }
299
300 //_____________________________________________________________________________
301 void AliAlignObj::Print(Option_t *) const
302 {
303   // Print the contents of the
304   // alignment object in angles and
305   // matrix representations
306   //
307   Double_t tr[3];
308   GetTranslation(tr);
309   Double_t angles[3];
310   GetAngles(angles);
311   TGeoHMatrix m;
312   GetMatrix(m);
313   const Double_t *rot = m.GetRotationMatrix();
314
315   printf("Volume=%s\n",GetSymName());
316   if (GetVolUID() != 0) {
317     ELayerID layerId;
318     Int_t modId;
319     GetVolUID(layerId,modId);
320     printf("VolumeID=%d LayerID=%d ( %s ) ModuleID=%d\n", GetVolUID(),layerId,LayerName(layerId),modId);
321   }
322   printf("%12.8f%12.8f%12.8f    Tx = %12.8f    Psi   = %12.8f\n", rot[0], rot[1], rot[2], tr[0], angles[0]);
323   printf("%12.8f%12.8f%12.8f    Ty = %12.8f    Theta = %12.8f\n", rot[3], rot[4], rot[5], tr[1], angles[1]);
324   printf("%12.8f%12.8f%12.8f    Tz = %12.8f    Phi   = %12.8f\n", rot[6], rot[7], rot[8], tr[2], angles[2]);
325
326 }
327
328 //_____________________________________________________________________________
329 Int_t AliAlignObj::LayerSize(Int_t layerId)
330 {
331   // Get the layer size for layer corresponding to layerId.
332   // Implemented only for ITS,TPC,TRD,TOF and RICH
333   //
334   if (layerId < kFirstLayer || layerId >= kLastLayer) {
335     AliErrorClass(Form("Invalid layer index %d ! Layer range is (%d -> %d) !",layerId,kFirstLayer,kLastLayer));
336     return 0;
337   }
338   else {
339     return fgLayerSize[layerId - kFirstLayer];
340  }
341 }
342
343 //_____________________________________________________________________________
344 const char* AliAlignObj::LayerName(Int_t layerId)
345 {
346   // Get the layer name corresponding to layerId.
347   // Implemented only for ITS,TPC,TRD,TOF and RICH
348   //
349   if (layerId < kFirstLayer || layerId >= kLastLayer) {
350     AliErrorClass(Form("Invalid layer index %d ! Layer range is (%d -> %d) !",layerId,kFirstLayer,kLastLayer));
351     return "Invalid Layer!";
352   }
353   else {
354     return fgLayerName[layerId - kFirstLayer];
355  }
356 }
357
358 //_____________________________________________________________________________
359 UShort_t AliAlignObj::LayerToVolUID(ELayerID layerId, Int_t modId)
360 {
361   // From detector (layer) name and module number (according to detector
362   // internal numbering) build the unique numerical identity of that volume
363   // inside ALICE
364   // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
365   // remaining 11 for module ID inside det (2048 possible values).
366   //
367   return ((UShort_t(layerId) << 11) | UShort_t(modId));
368 }
369
370 //_____________________________________________________________________________
371 UShort_t AliAlignObj::LayerToVolUID(Int_t   layerId, Int_t modId)
372 {
373   // From detector (layer) name and module number (according to detector
374   // internal numbering) build the unique numerical identity of that volume
375   // inside ALICE
376   // fVolUID is 16 bits, first 5 reserved for layerID (32 possible values),
377   // remaining 11 for module ID inside det (2048 possible values).
378   //
379   return ((UShort_t(layerId) << 11) | UShort_t(modId));
380 }
381
382 //_____________________________________________________________________________
383 AliAlignObj::ELayerID AliAlignObj::VolUIDToLayer(UShort_t voluid, Int_t &modId)
384 {
385   // From voluid, unique numerical identity of that volume inside ALICE,
386   // (voluid is 16 bits, first 5 reserved for layerID (32 possible values),
387   // remaining 11 for module ID inside det (2048 possible values)), return
388   // the identity of the layer to which that volume belongs and sets the
389   // argument modId to the identity of that volume internally to the layer.
390   //
391   modId = voluid & 0x7ff;
392
393   return VolUIDToLayer(voluid);
394 }
395
396 //_____________________________________________________________________________
397 AliAlignObj::ELayerID AliAlignObj::VolUIDToLayer(UShort_t voluid)
398 {
399   // From voluid, unique numerical identity of that volume inside ALICE,
400   // (voluid is 16 bits, first 5 reserved for layerID (32 possible values),
401   // remaining 11 for module ID inside det (2048 possible values)), return
402   // the identity of the layer to which that volume belongs
403   //
404   return ELayerID((voluid >> 11) & 0x1f);
405 }
406
407 //_____________________________________________________________________________
408 void AliAlignObj::SetPars(Double_t x, Double_t y, Double_t z,
409                           Double_t psi, Double_t theta, Double_t phi)
410 {
411   // Set rotation matrix and translation using 3 angles and 3 translations
412   // The three angles are expressed in degrees
413   // 
414   SetTranslation(x,y,z);
415   SetRotation(psi,theta,phi);
416 }
417
418 //_____________________________________________________________________________
419 Bool_t AliAlignObj::SetLocalPars(Double_t x, Double_t y, Double_t z,
420                                  Double_t psi, Double_t theta, Double_t phi)
421 {
422   // Set the translations and angles (in degrees) by considering the
423   // parameters passed as arguments as expressed in the local reference
424   // system of the alignable volume (known by TGeo geometry).
425   // In case that the TGeo was not initialized or not closed,
426   // returns false and the object parameters are not set.
427   //
428   TGeoHMatrix m;
429   Double_t tr[3] = {x, y, z};
430   m.SetTranslation(tr);
431   Double_t angles[3] = {psi, theta, phi};
432   Double_t rot[9];
433   AnglesToMatrix(angles,rot);
434   m.SetRotation(rot);
435
436   return SetLocalMatrix(m);
437
438 }
439
440 //_____________________________________________________________________________
441 Bool_t AliAlignObj::SetLocalMatrix(const TGeoMatrix& m)
442 {
443   // Set the translations and angles by considering the TGeo matrix
444   // passed as argument as expressing the transformation in the local
445   // reference system of the alignable volume (known by TGeo geometry).
446   // In case that the TGeo was not initialized or not closed,
447   // returns false and the object parameters are not set.
448   //
449   if (!gGeoManager || !gGeoManager->IsClosed()) {
450     AliError("Can't set the alignment object parameters! gGeoManager doesn't exist or it is still opened!");
451     return kFALSE;
452   }
453
454   const char* symname = GetSymName();
455   TGeoPhysicalNode* node;
456   TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
457   if(pne){
458     node = gGeoManager->MakeAlignablePN(pne);
459   }else{
460     AliWarning(Form("The symbolic volume name %s does not correspond to a physical entry. Using it as volume path!",symname));
461     node = (TGeoPhysicalNode*) gGeoManager->MakePhysicalNode(symname);
462   }
463
464   if (!node) {
465     AliError(Form("Volume name or path %s not valid!",symname));
466     return kFALSE;
467   }
468   if (node->IsAligned())
469     AliWarning(Form("Volume %s has been already misaligned!",symname));
470
471   TGeoHMatrix m1;
472   const Double_t *tr = m.GetTranslation();
473   m1.SetTranslation(tr);
474   const Double_t* rot = m.GetRotationMatrix();
475   m1.SetRotation(rot);
476
477   TGeoHMatrix align,gprime,gprimeinv;
478   gprime = *node->GetMatrix();
479   gprimeinv = gprime.Inverse();
480   m1.Multiply(&gprimeinv);
481   m1.MultiplyLeft(&gprime);
482
483   return SetMatrix(m1);
484 }
485
486 //_____________________________________________________________________________
487 Bool_t AliAlignObj::SetMatrix(const TGeoMatrix& m)
488 {
489   // Set rotation matrix and translation using the TGeoMatrix passed
490   // as argument considering it as relative to the global reference
491   // system
492   //
493   SetTranslation(m);
494   return SetRotation(m);
495 }
496
497 //_____________________________________________________________________________
498 Bool_t AliAlignObj::ApplyToGeometry()
499 {
500   // Apply the current alignment object to the TGeo geometry
501   // This method returns FALSE if the symname of the object was not
502   // valid neither to get a TGeoPEntry nor as a volume path
503   //
504   if (!gGeoManager || !gGeoManager->IsClosed()) {
505     AliError("Can't apply the alignment object! gGeoManager doesn't exist or it is still opened!");
506     return kFALSE;
507   }
508   
509   const char* symname = GetSymName();
510   const char* path;
511   TGeoPhysicalNode* node;
512   TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
513   if(pne){
514     path = pne->GetTitle();
515     if(!gGeoManager->CheckPath(path)){
516       AliDebug(1,Form("Valid PNEntry but invalid volume path %s!",path));
517           // this should happen only for volumes in disactivated branches
518       return kTRUE;
519     }
520     node = gGeoManager->MakeAlignablePN(pne);
521   }else{
522     AliWarning(Form("The symbolic volume name %s does not correspond to a physical entry. Using it as a volume path!",symname));
523     path=symname;
524     if (!gGeoManager->CheckPath(path)) {
525       AliError(Form("Volume path %s not valid!",path));
526       return kFALSE;
527     }
528     if (gGeoManager->GetListOfPhysicalNodes()->FindObject(path)) {
529       AliError(Form("Volume %s has already been misaligned!",path));
530       return kFALSE;
531     }
532     node = (TGeoPhysicalNode*) gGeoManager->MakePhysicalNode(path);
533   }
534
535   if (!node) {
536     AliError(Form("Volume path %s not valid!",path));
537     return kFALSE;
538   }
539
540   TGeoHMatrix align,gprime;
541   gprime = *node->GetMatrix();
542   GetMatrix(align);
543   gprime.MultiplyLeft(&align);
544   TGeoHMatrix *ginv = new TGeoHMatrix;
545   TGeoHMatrix *g = node->GetMatrix(node->GetLevel()-1);
546   *ginv = g->Inverse();
547   *ginv *= gprime;
548   AliAlignObj::ELayerID layerId; // unique identity for layer in the alobj
549   Int_t modId; // unique identity for volume inside layer in the alobj
550   GetVolUID(layerId, modId);
551   AliDebug(2,Form("Aligning volume %s of detector layer %d with local ID %d",symname,layerId,modId));
552   node->Align(ginv);
553
554   return kTRUE;
555 }
556
557 //_____________________________________________________________________________
558 Bool_t AliAlignObj::GetFromGeometry(const char *symname, AliAlignObj &alobj)
559 {
560   // Get the alignment object which corresponds to the symbolic volume name
561   // symname (in case equal to the TGeo volume path)
562   // The method is extremely slow due to the searching by string.
563   // Therefore it should be used with great care!!
564   // This method returns FALSE if the symname of the object was not
565   // valid neither to get a TGeoPEntry nor as a volume path, or if the path
566   // associated to the TGeoPNEntry was not valid.
567   //
568
569   // Reset the alignment object
570   alobj.SetPars(0,0,0,0,0,0);
571   alobj.SetSymName(symname);
572
573   if (!gGeoManager || !gGeoManager->IsClosed()) {
574     AliErrorClass("Can't get the alignment object! gGeoManager doesn't exist or it is still opened!");
575     return kFALSE;
576   }
577
578   if (!gGeoManager->GetListOfPhysicalNodes()) {
579     AliErrorClass("Can't get the alignment object! gGeoManager doesn't contain any aligned nodes!");
580     return kFALSE;
581   }
582
583   const char *path;
584   TGeoPNEntry* pne = gGeoManager->GetAlignableEntry(symname);
585   if(pne){
586     path = pne->GetTitle();
587   }else{
588     AliWarningClass(Form("The symbolic volume name %s does not correspond to a physical entry. Using it as a volume path!",symname));
589     path = symname;
590   }
591   TObjArray* nodesArr = gGeoManager->GetListOfPhysicalNodes();
592   TGeoPhysicalNode* node = NULL;
593   for (Int_t iNode = 0; iNode < nodesArr->GetEntriesFast(); iNode++) {
594     TGeoPhysicalNode* tempNode = (TGeoPhysicalNode*) nodesArr->UncheckedAt(iNode);
595     const char *nodePath = tempNode->GetName();
596     if (strcmp(symname,nodePath) == 0) {
597       node = tempNode;
598       break;
599     }
600   }
601
602   if (!node) {
603     if (!gGeoManager->cd(symname)) {
604       AliErrorClass(Form("%s not valid neither as symbolic volume name nor as volume path!",symname));
605       return kFALSE;
606     }
607     else {
608       AliWarningClass(Form("Volume (%s) has not been misaligned!",symname));
609       return kTRUE;
610     }
611   }
612
613   TGeoHMatrix align,gprime,g,ginv,l;
614   gprime = *node->GetMatrix();
615   l = *node->GetOriginalMatrix();
616   g = *node->GetMatrix(node->GetLevel()-1);
617   g *= l;
618   ginv = g.Inverse();
619   align = gprime * ginv;
620
621   return alobj.SetMatrix(align);
622 }
623
624 //_____________________________________________________________________________
625 void  AliAlignObj::InitAlignObjFromGeometry()
626 {
627   // Loop over all alignable volumes and extract
628   // the corresponding alignment objects from
629   // the TGeo geometry
630
631   if(fgAlignObjs[0]) return;
632   
633   InitSymNames();
634
635   for (Int_t iLayer = kFirstLayer; iLayer < AliAlignObj::kLastLayer; iLayer++) {
636     fgAlignObjs[iLayer-kFirstLayer] = new AliAlignObj*[AliAlignObj::LayerSize(iLayer)];
637     for (Int_t iModule = 0; iModule < AliAlignObj::LayerSize(iLayer); iModule++) {
638       UShort_t volid = AliAlignObj::LayerToVolUID(iLayer,iModule);
639       fgAlignObjs[iLayer-kFirstLayer][iModule] = new AliAlignObjAngles("",volid,0,0,0,0,0,0,kTRUE);
640       const char *symname = SymName(volid);
641       if (!GetFromGeometry(symname, *fgAlignObjs[iLayer-kFirstLayer][iModule]))
642         AliErrorClass(Form("Failed to extract the alignment object for the volume (ID=%d and path=%s) !",volid,symname));
643     }
644   }
645   
646 }
647
648 //_____________________________________________________________________________
649 AliAlignObj* AliAlignObj::GetAlignObj(UShort_t voluid) {
650   // Returns the alignment object for given volume ID
651   //
652   Int_t modId;
653   ELayerID layerId = VolUIDToLayer(voluid,modId);
654   return GetAlignObj(layerId,modId);
655 }
656
657 //_____________________________________________________________________________
658 AliAlignObj* AliAlignObj::GetAlignObj(ELayerID layerId, Int_t modId)
659 {
660   // Returns pointer to alignment object given its layer and module ID
661   //
662   if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
663     AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
664     return NULL;
665   }
666   InitAlignObjFromGeometry();
667
668   return fgAlignObjs[layerId-kFirstLayer][modId];
669 }
670
671 //_____________________________________________________________________________
672 const char* AliAlignObj::SymName(UShort_t voluid) {
673   // Returns the symbolic volume name for given volume ID
674   //
675   Int_t modId;
676   ELayerID layerId = VolUIDToLayer(voluid,modId);
677   return SymName(layerId,modId);
678 }
679
680 //_____________________________________________________________________________
681 const char* AliAlignObj::SymName(ELayerID layerId, Int_t modId)
682 {
683   // Returns the symbolic volume name given for a given layer
684   // and module ID
685   //
686   if(modId<0 || modId>=fgLayerSize[layerId-kFirstLayer]){
687     AliWarningClass(Form("Module number %d not in the valid range (0->%d) !",modId,fgLayerSize[layerId-kFirstLayer]-1));
688     return NULL;
689   }
690   InitSymNames();
691
692   return fgVolPath[layerId-kFirstLayer][modId].Data();
693 }
694
695 //_____________________________________________________________________________
696 void AliAlignObj::InitSymNames()
697 {
698   // Initialize the LUTs which associate the symbolic volume names
699   // for each alignable volume with their unique numerical identity.
700   // The LUTs are static, so they are created during the instantiation
701   // of the first intance of AliAlignObj
702   //
703   if (fgVolPath[0]) return;
704
705   for (Int_t iLayer = 0; iLayer < (kLastLayer - kFirstLayer); iLayer++)
706     fgVolPath[iLayer] = new TString[fgLayerSize[iLayer]];
707
708   TString symname;
709   Int_t modnum; // in the following, set it to 0 at the start of each layer
710
711   /*********************       ITS layers  ***********************/
712   TString strSPD = "ITS/SPD";
713   TString strSDD = "ITS/SDD";
714   TString strSSD = "ITS/SSD";
715   TString strStave = "/Stave";
716   TString strLadder = "/Ladder";
717   TString strSector = "/Sector";
718   TString strSensor = "/Sensor";
719   TString strEntryName1;
720   TString strEntryName2;
721
722   /*********************       SPD layer1  ***********************/
723   {
724     modnum = 0;
725
726     for(Int_t c1 = 1; c1<=10; c1++){
727       strEntryName1 = strSPD;
728       strEntryName1 += 0;
729       strEntryName1 += strSector;
730       strEntryName1 += (c1-1);
731       for(Int_t c2 =1; c2<=2; c2++){
732         strEntryName2 = strEntryName1;
733         strEntryName2 += strStave;
734         strEntryName2 += (c2-1);
735         for(Int_t c3 =1; c3<=4; c3++){
736           symname = strEntryName2;
737           symname += strLadder;
738           symname += (c3-1);
739           fgVolPath[kSPD1-kFirstLayer][modnum] = symname.Data();
740           modnum++;
741         }
742       }
743     }
744   }
745   
746   /*********************       SPD layer2  ***********************/
747   {
748     modnum = 0;
749
750     for(Int_t c1 = 1; c1<=10; c1++){
751       strEntryName1 = strSPD;
752       strEntryName1 += 1;
753       strEntryName1 += strSector;
754       strEntryName1 += (c1-1);
755       for(Int_t c2 =1; c2<=4; c2++){
756         strEntryName2 = strEntryName1;
757         strEntryName2 += strStave;
758         strEntryName2 += (c2-1);
759         for(Int_t c3 =1; c3<=4; c3++){
760           symname = strEntryName2;
761           symname += strLadder;
762           symname += (c3-1);
763           fgVolPath[kSPD2-kFirstLayer][modnum] = symname.Data();
764           modnum++;
765         }
766       }
767     }
768   }
769
770   /*********************       SDD layer1  ***********************/
771   {
772     modnum=0;
773
774     for(Int_t c1 = 1; c1<=14; c1++){
775       strEntryName1 = strSDD;
776       strEntryName1 += 2;
777       strEntryName1 +=strLadder;
778       strEntryName1 += (c1-1);
779       for(Int_t c2 =1; c2<=6; c2++){
780         symname = strEntryName1;
781         symname += strSensor;
782         symname += (c2-1);
783         fgVolPath[kSDD1-kFirstLayer][modnum] = symname.Data();
784         modnum++;
785       }
786     }
787   }
788
789   /*********************       SDD layer2  ***********************/
790   {
791     modnum=0;
792
793     for(Int_t c1 = 1; c1<=22; c1++){
794       strEntryName1 = strSDD;
795       strEntryName1 += 3;
796       strEntryName1 +=strLadder;
797       strEntryName1 += (c1-1);
798       for(Int_t c2 = 1; c2<=8; c2++){
799         symname = strEntryName1;
800         symname += strSensor;
801         symname += (c2-1);
802         fgVolPath[kSDD2-kFirstLayer][modnum] = symname.Data();
803         modnum++;
804       }
805     }
806   }
807
808   /*********************       SSD layer1  ***********************/
809   {
810     modnum=0;
811
812     for(Int_t c1 = 1; c1<=34; c1++){
813       strEntryName1 = strSSD;
814       strEntryName1 += 4;
815       strEntryName1 +=strLadder;
816       strEntryName1 += (c1-1);
817       for(Int_t c2 = 1; c2<=22; c2++){
818         symname = strEntryName1;
819         symname += strSensor;
820         symname += (c2-1);
821         fgVolPath[kSSD1-kFirstLayer][modnum] = symname.Data();
822         modnum++;
823       }
824     }
825   }
826
827   /*********************       SSD layer2  ***********************/
828   {
829     modnum=0;
830
831     for(Int_t c1 = 1; c1<=38; c1++){
832       strEntryName1 = strSSD;
833       strEntryName1 += 5;
834       strEntryName1 +=strLadder;
835       strEntryName1 += (c1-1);
836       for(Int_t c2 = 1; c2<=25; c2++){
837         symname = strEntryName1;
838         symname += strSensor;
839         symname += (c2-1);
840         fgVolPath[kSSD2-kFirstLayer][modnum] = symname.Data();
841         modnum++;
842       }
843     }
844   }
845
846
847   /***************    TPC inner and outer layers    ****************/
848   TString sAsector="TPC/EndcapA/Sector";
849   TString sCsector="TPC/EndcapC/Sector";
850   TString sInner="/InnerChamber";
851   TString sOuter="/OuterChamber";
852   
853   /***************    TPC inner chambers' layer    ****************/
854   {
855     modnum = 0;
856     
857     for(Int_t cnt=1; cnt<=18; cnt++){
858       symname = sAsector;
859       symname += cnt;
860       symname += sInner;
861       fgVolPath[kTPC1-kFirstLayer][modnum] = symname.Data();
862       modnum++;
863     }
864     for(Int_t cnt=1; cnt<=18; cnt++){
865       symname = sCsector;
866       symname += cnt;
867       symname += sInner;
868       fgVolPath[kTPC1-kFirstLayer][modnum] = symname.Data();
869       modnum++;
870     }
871   }
872
873   /***************    TPC outer chambers' layer    ****************/
874   {
875     modnum = 0;
876     
877     for(Int_t cnt=1; cnt<=18; cnt++){
878       symname = sAsector;
879       symname += cnt;
880       symname += sOuter;
881       fgVolPath[kTPC2-kFirstLayer][modnum] = symname.Data();
882       modnum++;
883     }
884     for(Int_t cnt=1; cnt<=18; cnt++){
885       symname = sCsector;
886       symname += cnt;
887       symname += sOuter;
888       fgVolPath[kTPC2-kFirstLayer][modnum] = symname.Data();
889       modnum++;
890     }
891   }    
892
893   /*********************       TOF layer   ***********************/
894   {
895     modnum=0;
896     
897     Int_t nstrA=15;
898     Int_t nstrB=19;
899     Int_t nstrC=19;
900     Int_t nSectors=18;
901     Int_t nStrips=nstrA+2*nstrB+2*nstrC;
902     
903     TString snSM  = "TOF/sm";
904     TString snSTRIP = "/strip";
905     
906     for (Int_t isect = 0; isect < nSectors; isect++) {
907       for (Int_t istr = 1; istr <= nStrips; istr++) {   
908         symname  = snSM;
909         symname += Form("%02d",isect);
910         symname += snSTRIP;
911         symname += Form("%02d",istr);
912         fgVolPath[kTOF-kFirstLayer][modnum] = symname.Data();   
913         modnum++;
914       }
915     }
916   } 
917
918   /*********************      RICH layer   ***********************/
919   {
920     TString str = "ALIC_1/RICH_";
921     TString symname;
922
923     for (modnum=0; modnum < 7; modnum++) {
924       symname = str;
925       symname += (modnum+1);
926       fgVolPath[kRICH-kFirstLayer][modnum] = symname.Data();
927     }
928   }
929
930   /*********************      TRD layers 1-6   *******************/
931   //!! 6 layers with index increasing in outwards direction
932   {
933     Int_t arTRDlayId[6] = {kTRD1, kTRD2, kTRD3, kTRD4, kTRD5, kTRD6};
934
935     TString snStr  = "TRD/sm";
936     TString snApp1 = "/st";
937     TString snApp2 = "/pl";
938     
939     for(Int_t layer=0; layer<6; layer++){
940       modnum=0;
941       for (Int_t isect = 0; isect < 18; isect++) {
942         for (Int_t icham = 0; icham < 5; icham++) {
943           symname  = snStr;
944           symname += Form("%02d",isect);
945           symname += snApp1;
946           symname += icham;
947           symname += snApp2;
948           symname += layer;
949           fgVolPath[arTRDlayId[layer]-kFirstLayer][modnum] = symname.Data();
950           modnum++;
951         }
952       }
953     }
954   }
955 }
956