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