]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PHOS/AliPHOSGeometry.cxx
corrected a bug in the root geometry: several TNode were created with the same name
[u/mrichter/AliRoot.git] / PHOS / AliPHOSGeometry.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 // Geometry class  for PHOS : singleton  
20 // PHOS consists of the electromagnetic calorimeter (EMCA)
21 // and a charged particle veto either in the Subatech's version (PPSD)
22 // or in the IHEP's one (CPV).
23 // The EMCA/PPSD/CPV modules are parametrized so that any configuration
24 // can be easily implemented 
25 // The title is used to identify the version of CPV used.
26 //                  
27 //*-- Author: Yves Schutz (SUBATECH)
28
29 // --- ROOT system ---
30
31 #include "TVector3.h"
32 #include "TRotation.h" 
33 #include "TFolder.h" 
34 #include "TROOT.h" 
35
36 // --- Standard library ---
37
38 #include <iostream.h>
39
40 // --- AliRoot header files ---
41
42 #include "AliPHOSGeometry.h"
43 #include "AliPHOSEMCAGeometry.h" 
44 #include "AliPHOSPpsdRecPoint.h"
45 #include "AliConst.h"
46
47 ClassImp(AliPHOSGeometry) ;
48
49 // these initialisations are needed for a singleton
50 AliPHOSGeometry * AliPHOSGeometry::fgGeom = 0 ;
51 Bool_t            AliPHOSGeometry::fgInit = kFALSE ;
52
53 //____________________________________________________________________________
54 AliPHOSGeometry::~AliPHOSGeometry(void)
55 {
56   // dtor
57
58   if (fRotMatrixArray) fRotMatrixArray->Delete() ; 
59   if (fRotMatrixArray) delete fRotMatrixArray ; 
60   if (fPHOSAngle     ) delete fPHOSAngle ; 
61 }
62
63 //____________________________________________________________________________
64
65 void AliPHOSGeometry::Init(void)
66 {
67   // Initializes the PHOS parameters :
68   //  IHEP is the Protvino CPV (cathode pad chambers)
69   //  GPS2 is the Subatech Pre-Shower (two micromegas sandwiching a passive lead converter)
70   //  MIXT 4 PHOS modules withe the IHEP CPV qnd one PHOS module with the Subatche Pre-Shower
71
72   if ( ((strcmp( fName, "GPS2" ))    == 0) ||
73        ((strcmp( fName, "IHEP" ))    == 0) ||
74        ((strcmp( fName, "MIXT" ))    == 0) ) {
75     fgInit     = kTRUE ; 
76
77     fNModules     = 5;
78     fNPPSDModules = 0;
79     fAngle        = 20;
80
81       fGeometryEMCA = new AliPHOSEMCAGeometry();
82     if      ( ((strcmp( fName, "GPS2" ))  == 0) ) {
83       fGeometryPPSD = new AliPHOSPPSDGeometry();
84       fGeometryCPV  = 0;
85       fNPPSDModules = fNModules;
86     }
87     else if ( ((strcmp( fName, "IHEP" ))  == 0) ) {
88       fGeometryCPV  = new AliPHOSCPVGeometry ();
89       fGeometryPPSD = 0;
90       fNPPSDModules = 0;
91     }
92     else if ( ((strcmp( fName, "MIXT" ))  == 0) ) {
93       fGeometryCPV  = new AliPHOSCPVGeometry ();
94       fGeometryPPSD = new AliPHOSPPSDGeometry();
95       fNPPSDModules = 1;
96     }
97       fGeometrySUPP = new AliPHOSSupportGeometry();
98
99     fPHOSAngle = new Float_t[fNModules] ;
100     Int_t index ;
101     for ( index = 0; index < fNModules; index++ )
102     fPHOSAngle[index] = 0.0 ; // Module position angles are set in CreateGeometry()
103
104     this->SetPHOSAngles() ; 
105     fRotMatrixArray = new TObjArray(fNModules) ; 
106
107     // post the geometry into the appropriate folder
108     //  get the alice folder
109     TFolder * alice = (TFolder*)gROOT->GetListOfBrowsables()->FindObject("YSAlice") ;
110     //  the folder that contains the alarms for PHOS   
111     TFolder * folder = (TFolder*)alice->FindObject("folders/Geometry/PHOS");   
112     folder->SetOwner() ;
113     folder->Add(this) ; 
114   }
115   else {
116     fgInit = kFALSE ; 
117     cout << "PHOS Geometry setup: option not defined " << fName << endl ; 
118   }
119 }
120
121 //____________________________________________________________________________
122 Float_t AliPHOSGeometry::GetCPVBoxSize(Int_t index)  const
123 {
124   // returns the coarse dimension CPV depending on the CPV option set
125   
126     if      (strcmp(fName,"GPS2") ==0 ) 
127       return fGeometryPPSD->GetCPVBoxSize(index);
128     else if (strcmp(fName,"IHEP")==0) 
129       return fGeometryCPV ->GetCPVBoxSize(index);
130     else if (strcmp(fName,"MIXT")==0) 
131       return TMath::Max(fGeometryCPV ->GetCPVBoxSize(index), fGeometryPPSD->GetCPVBoxSize(index));
132     else                              
133       return 0;
134 }  
135
136 //____________________________________________________________________________
137 AliPHOSGeometry *  AliPHOSGeometry::GetInstance() 
138
139   // Returns the pointer of the unique instance; singleton specific
140   
141   return (AliPHOSGeometry *) fgGeom ; 
142 }
143
144 //____________________________________________________________________________
145 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title) 
146 {
147   // Returns the pointer of the unique instance
148   // Creates it with the specified options (name, title) if it does not exist yet
149
150   AliPHOSGeometry * rv = 0  ; 
151   if ( fgGeom == 0 ) {
152     if ( strcmp(name,"") == 0 ) 
153       rv = 0 ;
154     else {    
155       fgGeom = new AliPHOSGeometry(name, title) ;
156       if ( fgInit )
157         rv = (AliPHOSGeometry * ) fgGeom ;
158       else {
159         rv = 0 ; 
160         delete fgGeom ; 
161         fgGeom = 0 ; 
162       }
163     }
164   }
165   else {
166     if ( strcmp(fgGeom->GetName(), name) != 0 ) {
167       cout << "AliPHOSGeometry <E> : current geometry is " << fgGeom->GetName() << endl
168            << "                      you cannot call     " << name << endl ; 
169     }
170     else
171       rv = (AliPHOSGeometry *) fgGeom ; 
172   } 
173   return rv ; 
174 }
175
176 //____________________________________________________________________________
177 void AliPHOSGeometry::SetPHOSAngles() 
178
179   // Calculates the position of the PHOS modules in ALICE global coordinate system
180   
181   Double_t const kRADDEG = 180.0 / kPI ;
182   Float_t pphi =  2 * TMath::ATan( GetOuterBoxSize(0)  / ( 2.0 * GetIPtoOuterCoverDistance() ) ) ;
183   pphi *= kRADDEG ;
184   if (pphi > fAngle) cout << "AliPHOSGeometry: PHOS modules overlap!\n";
185   pphi = fAngle;
186   
187   for( Int_t i = 1; i <= fNModules ; i++ ) {
188     Float_t angle = pphi * ( i - fNModules / 2.0 - 0.5 ) ;
189     fPHOSAngle[i-1] = -  angle ;
190   } 
191 }
192
193 //____________________________________________________________________________
194 Bool_t AliPHOSGeometry::AbsToRelNumbering(const Int_t AbsId, Int_t * relid)
195 {
196   // Converts the absolute numbering into the following array/
197   //  relid[0] = PHOS Module number 1:fNModules 
198   //  relid[1] = 0 if PbW04
199   //           = PPSD Module number 1:fNumberOfModulesPhi*fNumberOfModulesZ*2 (2->up and bottom level)
200   //  relid[2] = Row number inside a PHOS or PPSD module
201   //  relid[3] = Column number inside a PHOS or PPSD module
202
203   Bool_t rv  = kTRUE ; 
204   Float_t id = AbsId ;
205
206   Int_t phosmodulenumber = (Int_t)TMath:: Ceil( id / ( GetNPhi() * GetNZ() ) ) ; 
207   
208   if ( phosmodulenumber >  GetNModules() ) { // it is a PPSD or CPV pad
209
210     if      ( strcmp(fName,"GPS2") == 0 ) {
211       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
212       Float_t tempo = 2 *  GetNumberOfModulesPhi() * GetNumberOfModulesZ() *  GetNumberOfPadsPhi() * GetNumberOfPadsZ() ; 
213       relid[0] = (Int_t)TMath::Ceil( id / tempo ) ; 
214       id -= ( relid[0] - 1 ) * tempo ;
215       relid[1] = (Int_t)TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ; 
216       id -= ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ() ;
217       relid[2] = (Int_t)TMath::Ceil( id / GetNumberOfPadsPhi() ) ;
218       relid[3] = (Int_t) ( id - ( relid[2] - 1 )  * GetNumberOfPadsPhi() ) ; 
219     }
220     else if ( strcmp(fName,"IHEP") == 0 ) {
221       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
222       Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
223       relid[0] = (Int_t) TMath::Ceil( id / nCPV ) ;
224       relid[1] = 1 ;
225       id -= ( relid[0] - 1 ) * nCPV ; 
226       relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfCPVPadsZ() ) ;
227       relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfCPVPadsZ() ) ; 
228     }
229     else if ( strcmp(fName,"MIXT") == 0 ) {
230       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
231       Float_t nPPSD = 2 * GetNumberOfModulesPhi() * GetNumberOfModulesZ() *  GetNumberOfPadsPhi() * GetNumberOfPadsZ() ; 
232       Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
233       if (id <= nCPV*GetNCPVModules()) { // this pad belons to CPV
234         relid[0] = (Int_t) TMath::Ceil( id / nCPV ) ;
235         relid[1] = 1 ;
236         id -= ( relid[0] - 1 ) * nCPV ; 
237         relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfCPVPadsZ() ) ;
238         relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfCPVPadsZ() ) ; 
239       }
240       else {                             // this pad belons to PPSD
241         id -= nCPV*GetNCPVModules();
242         relid[0] = (Int_t)TMath::Ceil( id / nPPSD ); 
243         id -= ( relid[0] - 1 ) * nPPSD ;
244         relid[0] += GetNCPVModules();
245         relid[1] = (Int_t)TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ; 
246         id -= ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ() ;
247         relid[2] = (Int_t)TMath::Ceil( id / GetNumberOfPadsPhi() ) ;
248         relid[3] = (Int_t) ( id - ( relid[2] - 1 )  * GetNumberOfPadsPhi() ) ; 
249       }
250     }
251   } 
252   else { // its a PW04 crystal
253
254     relid[0] = phosmodulenumber ;
255     relid[1] = 0 ;
256     id -= ( phosmodulenumber - 1 ) *  GetNPhi() * GetNZ() ; 
257     relid[2] = (Int_t)TMath::Ceil( id / GetNPhi() ) ;
258     relid[3] = (Int_t)( id - ( relid[2] - 1 ) * GetNPhi() ) ; 
259   } 
260   return rv ; 
261 }
262
263 //____________________________________________________________________________  
264 void AliPHOSGeometry::EmcModuleCoverage(const Int_t mod, Double_t & tm, Double_t & tM, Double_t & pm, Double_t & pM, Option_t * opt) 
265 {
266   // calculates the angular coverage in theta and phi of one EMC (=PHOS) module
267
268  Double_t conv ; 
269   if ( opt == Radian() ) 
270     conv = 1. ; 
271   else if ( opt == Degre() )
272     conv = 180. / TMath::Pi() ; 
273   else {
274     cout << "<I>  AliPHOSGeometry::EmcXtalCoverage : " << opt << " unknown option; result in radian " << endl ; 
275     conv = 1. ;
276       }
277
278   Float_t phi =  GetPHOSAngle(mod) *  (TMath::Pi() / 180.)  ;  
279   Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
280                   + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
281   
282   Double_t angle = TMath::ATan( GetCrystalSize(0)*GetNPhi() / (2 * y0) ) ;
283   phi = phi + 1.5 * TMath::Pi() ; // to follow the convention of the particle generator(PHOS is between 230 and 310 deg.)
284   Double_t max  = phi - angle ;
285   Double_t min   = phi + angle ;
286   pM = TMath::Max(max, min) * conv ;
287   pm = TMath::Min(max, min) * conv ; 
288   
289   angle =  TMath::ATan( GetCrystalSize(2)*GetNZ() / (2 * y0) ) ;
290   max  = TMath::Pi() / 2.  + angle ; // to follow the convention of the particle generator(PHOS is at 90 deg.)
291   min  = TMath::Pi() / 2.  - angle ;
292   tM = TMath::Max(max, min) * conv ;
293   tm = TMath::Min(max, min) * conv ; 
294  
295 }
296
297 //____________________________________________________________________________  
298 void AliPHOSGeometry::EmcXtalCoverage(Double_t & theta, Double_t & phi, Option_t * opt) 
299 {
300   // calculates the angular coverage in theta and phi of a single crystal in a EMC(=PHOS) module
301
302   Double_t conv ; 
303   if ( opt == Radian() ) 
304     conv = 1. ; 
305   else if ( opt == Degre() )
306     conv = 180. / TMath::Pi() ; 
307   else {
308     cout << "<I>  AliPHOSGeometry::EmcXtalCoverage : " << opt << " unknown option; result in radian " << endl ; 
309     conv = 1. ;
310       }
311
312   Float_t y0   =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
313     + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
314   theta = 2 * TMath::ATan( GetCrystalSize(2) / (2 * y0) ) * conv ;
315   phi   = 2 * TMath::ATan( GetCrystalSize(0) / (2 * y0) ) * conv ;
316 }
317  
318
319 //____________________________________________________________________________
320 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos, TMatrix & gmat) const
321 {
322   // Calculates the coordinates of a RecPoint and the error matrix in the ALICE global coordinate system
323  
324   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
325   TVector3 localposition ;
326
327   tmpPHOS->GetLocalPosition(gpos) ;
328
329
330   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
331     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
332                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
333
334     }
335   else
336     { // it is a PPSD pad
337       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
338       if (tmpPpsd->GetUp() ) // it is an upper module
339         {
340           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
341                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
342                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
343         } 
344       else // it is a lower module
345         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
346     }  
347
348   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
349   Double_t const kRADDEG = 180.0 / kPI ;
350   Float_t rphi          = phi / kRADDEG ; 
351   
352   TRotation rot ;
353   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
354   
355   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
356   gpos.Transform(rot) ; // rotate the baby 
357
358 }
359
360 //____________________________________________________________________________
361 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos) const 
362 {
363   // Calculates the coordinates of a RecPoint in the ALICE global coordinate system 
364
365   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
366   TVector3 localposition ;
367   tmpPHOS->GetLocalPosition(gpos) ;
368
369
370   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
371     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
372                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
373     }
374   else
375     { // it is a PPSD pad
376       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
377       if (tmpPpsd->GetUp() ) // it is an upper module
378         {
379           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
380                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
381                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
382         } 
383       else // it is a lower module
384         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
385     }  
386
387   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
388   Double_t const kRADDEG = 180.0 / kPI ;
389   Float_t rphi          = phi / kRADDEG ; 
390   
391   TRotation rot ;
392   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
393   
394   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
395   gpos.Transform(rot) ; // rotate the baby 
396 }
397
398 //____________________________________________________________________________
399 void AliPHOSGeometry::ImpactOnEmc(const Double_t theta, const Double_t phi, Int_t & ModuleNumber, Double_t & z, Double_t & x) 
400 {
401   // calculates the impact coordinates on PHOS of a neutral particle  
402   // emitted in the direction theta and phi in the ALICE global coordinate system
403
404   // searches for the PHOS EMC module
405   ModuleNumber = 0 ; 
406   Double_t tm, tM, pm, pM ; 
407   Int_t index = 1 ; 
408   while ( ModuleNumber == 0 && index <= GetNModules() ) { 
409     EmcModuleCoverage(index, tm, tM, pm, pM) ; 
410     if ( (theta >= tm && theta <= tM) && (phi >= pm && phi <= pM ) ) 
411       ModuleNumber = index ; 
412     index++ ;    
413   }
414   if ( ModuleNumber != 0 ) {
415     Float_t phi0 =  GetPHOSAngle(ModuleNumber) *  (TMath::Pi() / 180.) + 1.5 * TMath::Pi()  ;  
416     Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
417       + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;   
418     Double_t angle = phi - phi0; 
419     x = y0 * TMath::Tan(angle) ; 
420     angle = theta - TMath::Pi() / 2 ; 
421     z = y0 * TMath::Tan(angle) ; 
422   }
423 }
424
425 //____________________________________________________________________________
426 Bool_t AliPHOSGeometry::RelToAbsNumbering(const Int_t * relid, Int_t &  AbsId)
427 {
428   // Converts the relative numbering into the absolute numbering
429   // EMCA crystals:
430   //  AbsId = from 1 to fNModules * fNPhi * fNZ
431   // PPSD gas cell:
432   //  AbsId = from N(total EMCA crystals) + 1
433   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ +
434   //          fNModules * 2 * (fNumberOfModulesPhi * fNumberOfModulesZ) * fNumberOfPadsPhi * fNumberOfPadsZ
435   // CPV pad:
436   //  AbsId = from N(total PHOS crystals) + 1
437   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ
438
439   Bool_t rv = kTRUE ; 
440  
441   if      ( relid[1] > 0 && strcmp(fName,"GPS2")==0) { // it is a PPSD pad
442     AbsId =    GetNPhi() * GetNZ() * GetNModules()                         // the offset to separate EMCA crystals from PPSD pads
443       + ( relid[0] - 1 ) * GetNumberOfModulesPhi() * GetNumberOfModulesZ() // the pads offset of PPSD modules 
444                          * GetNumberOfPadsPhi() * GetNumberOfPadsZ() * 2
445       + ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()       // the pads offset of PPSD modules 
446       + ( relid[2] - 1 ) * GetNumberOfPadsPhi()                            // the pads offset of a PPSD row
447       +   relid[3] ;                                                       // the column number
448   } 
449
450   else if ( relid[1] > 0 && strcmp(fName,"MIXT")==0) { // it is a PPSD pad
451     AbsId =    GetNPhi() * GetNZ() * GetNModules()                         // the offset to separate EMCA crystals from PPSD pads
452       + GetNCPVModules() * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() // the pads offset of CPV modules if any
453       + ( relid[0] - 1 - GetNCPVModules())
454                          * GetNumberOfModulesPhi() * GetNumberOfModulesZ() // the pads offset of PPSD modules 
455                          * GetNumberOfPadsPhi() * GetNumberOfPadsZ() * 2
456       + ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()       // the pads offset of PPSD modules 
457       + ( relid[2] - 1 ) * GetNumberOfPadsPhi()                            // the pads offset of a PPSD row
458       +   relid[3] ;                                                       // the column number
459   } 
460
461   else if ( relid[1] ==  0 ) { // it is a Phos crystal
462     AbsId =
463         ( relid[0] - 1 ) * GetNPhi() * GetNZ()                               // the offset of PHOS modules
464       + ( relid[2] - 1 ) * GetNPhi()                                         // the offset of a xtal row
465       +   relid[3] ;                                                         // the column number
466   }
467
468   else if ( relid[1] == -1 ) { // it is a CPV pad
469     AbsId =    GetNPhi() * GetNZ() *  GetNModules()                          // the offset to separate EMCA crystals from CPV pads
470       + ( relid[0] - 1 ) * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ()         // the pads offset of PHOS modules 
471       + ( relid[2] - 1 ) * GetNumberOfCPVPadsZ()                                // the pads offset of a CPV row
472       +   relid[3] ;                                                         // the column number
473   }
474   
475   return rv ; 
476 }
477
478 //____________________________________________________________________________
479
480 void AliPHOSGeometry::RelPosInAlice(const Int_t id, TVector3 & pos ) 
481 {
482   // Converts the absolute numbering into the global ALICE coordinate system
483   // It works only for the GPS2 geometry
484   
485   if (id > 0 && strcmp(fName,"GPS2")==0) { 
486     
487     Int_t relid[4] ;
488     
489     AbsToRelNumbering(id , relid) ;
490     
491     Int_t phosmodule = relid[0] ; 
492     
493     Float_t y0 = 0 ; 
494     
495     if ( relid[1] == 0 ) { // it is a PbW04 crystal 
496       y0 =  -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
497               + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness())  ;  
498     }
499     if ( relid[1] > 0 ) { // its a PPSD pad
500       if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() ) { // its an bottom module
501         y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0)  ;
502       } 
503       else // its an upper module
504         y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - GetLeadToMicro2Gap()
505                 -  GetLeadConverterThickness() -  GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0) ; 
506     }
507     
508     Float_t x, z ; 
509     RelPosInModule(relid, x, z) ; 
510     
511     pos.SetX(x) ;
512     pos.SetZ(z) ;
513     pos.SetY( TMath::Sqrt(x*x + z*z + y0*y0) ) ; 
514     
515     
516     
517     Float_t phi           = GetPHOSAngle( phosmodule) ; 
518     Double_t const kRADDEG = 180.0 / kPI ;
519     Float_t rphi          = phi / kRADDEG ; 
520     
521     TRotation rot ;
522     rot.RotateZ(-rphi) ; // a rotation around Z by angle  
523     
524     TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
525     
526     pos.Transform(rot) ; // rotate the baby 
527   }
528   else {
529     pos.SetX(0.);
530     pos.SetY(0.);
531     pos.SetZ(0.);
532   }
533
534
535 //____________________________________________________________________________
536 void AliPHOSGeometry::RelPosInModule(const Int_t * relid, Float_t & x, Float_t & z) 
537 {
538   // Converts the relative numbering into the local PHOS-module (x, z) coordinates
539   // Note: sign of z differs from that in the previous version (Yu.Kharlov, 12 Oct 2000)
540
541   Bool_t padOfCPV  = (strcmp(fName,"IHEP")==0) ||
542                     ((strcmp(fName,"MIXT")==0) && relid[0]<=GetNCPVModules()) ;
543   Bool_t padOfPPSD = (strcmp(fName,"GPS2")==0) ||
544                     ((strcmp(fName,"MIXT")==0) && relid[0]> GetNCPVModules()) ;
545   
546   Int_t ppsdmodule  ; 
547   Float_t x0,z0;
548   Int_t row        = relid[2] ; //offset along x axiz
549   Int_t column     = relid[3] ; //offset along z axiz
550
551   Float_t padsizeZ = 0;
552   Float_t padsizeX = 0;
553   Int_t   nOfPadsPhi = 0;
554   Int_t   nOfPadsZ   = 0;
555   if      ( padOfPPSD ) {
556     padsizeZ   = GetPPSDModuleSize(2) / GetNumberOfPadsZ();
557     padsizeX   = GetPPSDModuleSize(0) / GetNumberOfPadsPhi();
558     nOfPadsPhi = GetNumberOfPadsPhi();
559     nOfPadsZ   = GetNumberOfPadsZ();
560   }
561   else if ( padOfCPV  ) {
562     padsizeZ   = GetPadSizeZ();
563     padsizeX   = GetPadSizePhi();
564     nOfPadsPhi = GetNumberOfCPVPadsPhi();
565     nOfPadsZ   = GetNumberOfCPVPadsZ();
566   }
567   
568   if ( relid[1] == 0 ) { // its a PbW04 crystal 
569     x = - ( GetNPhi()/2. - row    + 0.5 ) *  GetCrystalSize(0) ; // position ox Xtal with respect
570     z =   ( GetNZ()  /2. - column + 0.5 ) *  GetCrystalSize(2) ; // of center of PHOS module  
571   }  
572   else  {    
573     if ( padOfPPSD ) {
574       if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() )
575         ppsdmodule =  relid[1]-GetNumberOfModulesPhi() *  GetNumberOfModulesZ(); 
576       else
577         ppsdmodule =  relid[1] ;
578       Int_t modrow = 1+(Int_t)TMath::Ceil( (Float_t)ppsdmodule / GetNumberOfModulesPhi()-1. ) ; 
579       Int_t modcol = ppsdmodule -  ( modrow - 1 ) * GetNumberOfModulesPhi() ;     
580       x0 = (  GetNumberOfModulesPhi() / 2.  - modrow  + 0.5 ) * GetPPSDModuleSize(0) ;
581       z0 = (  GetNumberOfModulesZ()   / 2.  - modcol  + 0.5 ) * GetPPSDModuleSize(2)  ;     
582     } else {
583       x0 = 0;
584       z0 = 0;
585     }
586     x = - ( nOfPadsPhi/2. - row    - 0.5 ) * padsizeX + x0 ; // position of pad  with respect
587     z =   ( nOfPadsZ  /2. - column - 0.5 ) * padsizeZ - z0 ; // of center of PHOS module  
588   }
589 }