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