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