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