]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PHOS/AliPHOSGeometry.cxx
76f907bd7de0a7dfec3050884b4a6b47823fdc7f
[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 //____________________________________________________________________________
126 Bool_t AliPHOSGeometry::IsInEMC(const Int_t id) const { 
127     Int_t relid[4] ; 
128     AbsToRelNumbering(id, relid) ; 
129     if ( relid[1] == 0 ) 
130       return kTRUE ; 
131     else 
132       return kFALSE ; 
133   }
134
135 //____________________________________________________________________________
136 Float_t AliPHOSGeometry::GetCPVBoxSize(Int_t index)  const
137 {
138   // returns the coarse dimension CPV depending on the CPV option set
139   
140     if      (strcmp(fName,"GPS2") ==0 ) 
141       return fGeometryPPSD->GetCPVBoxSize(index);
142     else if (strcmp(fName,"IHEP")==0) 
143       return fGeometryCPV ->GetCPVBoxSize(index);
144     else if (strcmp(fName,"MIXT")==0) 
145       return TMath::Max(fGeometryCPV ->GetCPVBoxSize(index), fGeometryPPSD->GetCPVBoxSize(index));
146     else                              
147       return 0;
148 }  
149
150 //____________________________________________________________________________
151 AliPHOSGeometry *  AliPHOSGeometry::GetInstance() 
152
153   // Returns the pointer of the unique instance; singleton specific
154   
155   return (AliPHOSGeometry *) fgGeom ; 
156 }
157
158 //____________________________________________________________________________
159 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title) 
160 {
161   // Returns the pointer of the unique instance
162   // Creates it with the specified options (name, title) if it does not exist yet
163
164   AliPHOSGeometry * rv = 0  ; 
165   if ( fgGeom == 0 ) {
166     if ( strcmp(name,"") == 0 ) 
167       rv = 0 ;
168     else {    
169       fgGeom = new AliPHOSGeometry(name, title) ;
170       if ( fgInit )
171         rv = (AliPHOSGeometry * ) fgGeom ;
172       else {
173         rv = 0 ; 
174         delete fgGeom ; 
175         fgGeom = 0 ; 
176       }
177     }
178   }
179   else {
180     if ( strcmp(fgGeom->GetName(), name) != 0 ) {
181       cout << "AliPHOSGeometry <E> : current geometry is " << fgGeom->GetName() << endl
182            << "                      you cannot call     " << name << endl ; 
183     }
184     else
185       rv = (AliPHOSGeometry *) fgGeom ; 
186   } 
187   return rv ; 
188 }
189
190 //____________________________________________________________________________
191 void AliPHOSGeometry::SetPHOSAngles() 
192
193   // Calculates the position of the PHOS modules in ALICE global coordinate system
194   
195   Double_t const kRADDEG = 180.0 / kPI ;
196   Float_t pphi =  2 * TMath::ATan( GetOuterBoxSize(0)  / ( 2.0 * GetIPtoOuterCoverDistance() ) ) ;
197   pphi *= kRADDEG ;
198   if (pphi > fAngle) cout << "AliPHOSGeometry: PHOS modules overlap!\n";
199   pphi = fAngle;
200   
201   for( Int_t i = 1; i <= fNModules ; i++ ) {
202     Float_t angle = pphi * ( i - fNModules / 2.0 - 0.5 ) ;
203     fPHOSAngle[i-1] = -  angle ;
204   } 
205 }
206
207 //____________________________________________________________________________
208 Bool_t AliPHOSGeometry::AbsToRelNumbering(const Int_t AbsId, Int_t * relid) const
209 {
210   // Converts the absolute numbering into the following array/
211   //  relid[0] = PHOS Module number 1:fNModules 
212   //  relid[1] = 0 if PbW04
213   //           = PPSD Module number 1:fNumberOfModulesPhi*fNumberOfModulesZ*2 (2->up and bottom level)
214   //  relid[2] = Row number inside a PHOS or PPSD module
215   //  relid[3] = Column number inside a PHOS or PPSD module
216
217   Bool_t rv  = kTRUE ; 
218   Float_t id = AbsId ;
219
220   Int_t phosmodulenumber = (Int_t)TMath:: Ceil( id / ( GetNPhi() * GetNZ() ) ) ; 
221   
222   if ( phosmodulenumber >  GetNModules() ) { // it is a PPSD or CPV pad
223
224     if      ( strcmp(fName,"GPS2") == 0 ) {
225       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
226       Float_t tempo = 2 *  GetNumberOfModulesPhi() * GetNumberOfModulesZ() *  GetNumberOfPadsPhi() * GetNumberOfPadsZ() ; 
227       relid[0] = (Int_t)TMath::Ceil( id / tempo ) ; 
228       id -= ( relid[0] - 1 ) * tempo ;
229       relid[1] = (Int_t)TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ; 
230       id -= ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ() ;
231       relid[2] = (Int_t)TMath::Ceil( id / GetNumberOfPadsPhi() ) ;
232       relid[3] = (Int_t) ( id - ( relid[2] - 1 )  * GetNumberOfPadsPhi() ) ; 
233     }
234     else if ( strcmp(fName,"IHEP") == 0 ) {
235       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
236       Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
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 if ( strcmp(fName,"MIXT") == 0 ) {
244       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
245       Float_t nPPSD = 2 * GetNumberOfModulesPhi() * GetNumberOfModulesZ() *  GetNumberOfPadsPhi() * GetNumberOfPadsZ() ; 
246       Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
247       if (id <= nCPV*GetNCPVModules()) { // this pad belons to CPV
248         relid[0] = (Int_t) TMath::Ceil( id / nCPV ) ;
249         relid[1] = 1 ;
250         id -= ( relid[0] - 1 ) * nCPV ; 
251         relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfCPVPadsZ() ) ;
252         relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfCPVPadsZ() ) ; 
253       }
254       else {                             // this pad belons to PPSD
255         id -= nCPV*GetNCPVModules();
256         relid[0] = (Int_t)TMath::Ceil( id / nPPSD ); 
257         id -= ( relid[0] - 1 ) * nPPSD ;
258         relid[0] += GetNCPVModules();
259         relid[1] = (Int_t)TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ; 
260         id -= ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ() ;
261         relid[2] = (Int_t)TMath::Ceil( id / GetNumberOfPadsPhi() ) ;
262         relid[3] = (Int_t) ( id - ( relid[2] - 1 )  * GetNumberOfPadsPhi() ) ; 
263       }
264     }
265   } 
266   else { // its a PW04 crystal
267
268     relid[0] = phosmodulenumber ;
269     relid[1] = 0 ;
270     id -= ( phosmodulenumber - 1 ) *  GetNPhi() * GetNZ() ; 
271     relid[2] = (Int_t)TMath::Ceil( id / GetNPhi() ) ;
272     relid[3] = (Int_t)( id - ( relid[2] - 1 ) * GetNPhi() ) ; 
273   } 
274   return rv ; 
275 }
276
277 //____________________________________________________________________________  
278 void AliPHOSGeometry::EmcModuleCoverage(const Int_t mod, Double_t & tm, Double_t & tM, Double_t & pm, Double_t & pM, Option_t * opt) const 
279 {
280   // calculates the angular coverage in theta and phi of one EMC (=PHOS) 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 phi =  GetPHOSAngle(mod) *  (TMath::Pi() / 180.)  ;  
293   Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
294                   + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
295   
296   Double_t angle = TMath::ATan( GetCrystalSize(0)*GetNPhi() / (2 * y0) ) ;
297   phi = phi + 1.5 * TMath::Pi() ; // to follow the convention of the particle generator(PHOS is between 230 and 310 deg.)
298   Double_t max  = phi - angle ;
299   Double_t min   = phi + angle ;
300   pM = TMath::Max(max, min) * conv ;
301   pm = TMath::Min(max, min) * conv ; 
302   
303   angle =  TMath::ATan( GetCrystalSize(2)*GetNZ() / (2 * y0) ) ;
304   max  = TMath::Pi() / 2.  + angle ; // to follow the convention of the particle generator(PHOS is at 90 deg.)
305   min  = TMath::Pi() / 2.  - angle ;
306   tM = TMath::Max(max, min) * conv ;
307   tm = TMath::Min(max, min) * conv ; 
308  
309 }
310
311 //____________________________________________________________________________  
312 void AliPHOSGeometry::EmcXtalCoverage(Double_t & theta, Double_t & phi, Option_t * opt) const
313 {
314   // calculates the angular coverage in theta and phi of a single crystal in a EMC(=PHOS) module
315
316   Double_t conv ; 
317   if ( opt == Radian() ) 
318     conv = 1. ; 
319   else if ( opt == Degre() )
320     conv = 180. / TMath::Pi() ; 
321   else {
322     cout << "<I>  AliPHOSGeometry::EmcXtalCoverage : " << opt << " unknown option; result in radian " << endl ; 
323     conv = 1. ;
324       }
325
326   Float_t y0   =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
327     + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
328   theta = 2 * TMath::ATan( GetCrystalSize(2) / (2 * y0) ) * conv ;
329   phi   = 2 * TMath::ATan( GetCrystalSize(0) / (2 * y0) ) * conv ;
330 }
331  
332
333 //____________________________________________________________________________
334 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos, TMatrix & gmat) const
335 {
336   // Calculates the coordinates of a RecPoint and the error matrix in the ALICE global coordinate system
337  
338   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
339   TVector3 localposition ;
340
341   tmpPHOS->GetLocalPosition(gpos) ;
342
343
344   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
345     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
346                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
347
348     }
349   else
350     { // it is a PPSD pad
351       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
352       if (tmpPpsd->GetUp() ) // it is an upper module
353         {
354           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
355                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
356                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
357         } 
358       else // it is a lower module
359         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
360     }  
361
362   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
363   Double_t const kRADDEG = 180.0 / kPI ;
364   Float_t rphi          = phi / kRADDEG ; 
365   
366   TRotation rot ;
367   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
368   
369   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
370   gpos.Transform(rot) ; // rotate the baby 
371
372 }
373
374 //____________________________________________________________________________
375 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos) const 
376 {
377   // Calculates the coordinates of a RecPoint in the ALICE global coordinate system 
378
379   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
380   TVector3 localposition ;
381   tmpPHOS->GetLocalPosition(gpos) ;
382
383
384   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
385     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
386                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
387     }
388   else
389     { // it is a PPSD pad
390       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
391       if (tmpPpsd->GetUp() ) // it is an upper module
392         {
393           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
394                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
395                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
396         } 
397       else // it is a lower module
398         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
399     }  
400
401   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
402   Double_t const kRADDEG = 180.0 / kPI ;
403   Float_t rphi          = phi / kRADDEG ; 
404   
405   TRotation rot ;
406   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
407   
408   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
409   gpos.Transform(rot) ; // rotate the baby 
410 }
411
412 //____________________________________________________________________________
413 void AliPHOSGeometry::ImpactOnEmc(const Double_t theta, const Double_t phi, Int_t & ModuleNumber, Double_t & z, Double_t & x) const
414 {
415   // calculates the impact coordinates on PHOS of a neutral particle  
416   // emitted in the direction theta and phi in the ALICE global coordinate system
417
418   // searches for the PHOS EMC module
419   ModuleNumber = 0 ; 
420   Double_t tm, tM, pm, pM ; 
421   Int_t index = 1 ; 
422   while ( ModuleNumber == 0 && index <= GetNModules() ) { 
423     EmcModuleCoverage(index, tm, tM, pm, pM) ; 
424     if ( (theta >= tm && theta <= tM) && (phi >= pm && phi <= pM ) ) 
425       ModuleNumber = index ; 
426     index++ ;    
427   }
428   if ( ModuleNumber != 0 ) {
429     Float_t phi0 =  GetPHOSAngle(ModuleNumber) *  (TMath::Pi() / 180.) + 1.5 * TMath::Pi()  ;  
430     Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
431       + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;   
432     Double_t angle = phi - phi0; 
433     x = y0 * TMath::Tan(angle) ; 
434     angle = theta - TMath::Pi() / 2 ; 
435     z = y0 * TMath::Tan(angle) ; 
436   }
437 }
438
439 //____________________________________________________________________________
440 Bool_t AliPHOSGeometry::RelToAbsNumbering(const Int_t * relid, Int_t &  AbsId) const
441 {
442   // Converts the relative numbering into the absolute numbering
443   // EMCA crystals:
444   //  AbsId = from 1 to fNModules * fNPhi * fNZ
445   // PPSD gas cell:
446   //  AbsId = from N(total EMCA crystals) + 1
447   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ +
448   //          fNModules * 2 * (fNumberOfModulesPhi * fNumberOfModulesZ) * fNumberOfPadsPhi * fNumberOfPadsZ
449   // CPV pad:
450   //  AbsId = from N(total PHOS crystals) + 1
451   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ
452
453   Bool_t rv = kTRUE ; 
454  
455   if      ( relid[1] > 0 && strcmp(fName,"GPS2")==0) { // it is a PPSD pad
456     AbsId =    GetNPhi() * GetNZ() * GetNModules()                         // the offset to separate EMCA crystals from PPSD pads
457       + ( relid[0] - 1 ) * 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 && strcmp(fName,"MIXT")==0) { // it is a PPSD pad
465     AbsId =    GetNPhi() * GetNZ() * GetNModules()                         // the offset to separate EMCA crystals from PPSD pads
466       + GetNCPVModules() * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() // the pads offset of CPV modules if any
467       + ( relid[0] - 1 - GetNCPVModules())
468                          * GetNumberOfModulesPhi() * GetNumberOfModulesZ() // the pads offset of PPSD modules 
469                          * GetNumberOfPadsPhi() * GetNumberOfPadsZ() * 2
470       + ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()       // the pads offset of PPSD modules 
471       + ( relid[2] - 1 ) * GetNumberOfPadsPhi()                            // the pads offset of a PPSD row
472       +   relid[3] ;                                                       // the column number
473   } 
474
475   else if ( relid[1] ==  0 ) { // it is a Phos crystal
476     AbsId =
477         ( relid[0] - 1 ) * GetNPhi() * GetNZ()                               // the offset of PHOS modules
478       + ( relid[2] - 1 ) * GetNPhi()                                         // the offset of a xtal row
479       +   relid[3] ;                                                         // the column number
480   }
481
482   else if ( relid[1] == -1 ) { // it is a CPV pad
483     AbsId =    GetNPhi() * GetNZ() *  GetNModules()                          // the offset to separate EMCA crystals from CPV pads
484       + ( relid[0] - 1 ) * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ()         // the pads offset of PHOS modules 
485       + ( relid[2] - 1 ) * GetNumberOfCPVPadsZ()                                // the pads offset of a CPV row
486       +   relid[3] ;                                                         // the column number
487   }
488   
489   return rv ; 
490 }
491
492 //____________________________________________________________________________
493
494 void AliPHOSGeometry::RelPosInAlice(const Int_t id, TVector3 & pos ) const
495 {
496   // Converts the absolute numbering into the global ALICE coordinate system
497   // It works only for the GPS2 geometry
498   
499   if (id > 0 && strcmp(fName,"GPS2")==0) { 
500     
501     Int_t relid[4] ;
502     
503     AbsToRelNumbering(id , relid) ;
504     
505     Int_t phosmodule = relid[0] ; 
506     
507     Float_t y0 = 0 ; 
508     
509     if ( relid[1] == 0 ) { // it is a PbW04 crystal 
510       y0 =  -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
511               + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness())  ;  
512     }
513     if ( relid[1] > 0 ) { // its a PPSD pad
514       if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() ) { // its an bottom module
515         y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0)  ;
516       } 
517       else // its an upper module
518         y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - GetLeadToMicro2Gap()
519                 -  GetLeadConverterThickness() -  GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0) ; 
520     }
521     
522     Float_t x, z ; 
523     RelPosInModule(relid, x, z) ; 
524     
525     pos.SetX(x) ;
526     pos.SetZ(z) ;
527     pos.SetY(- TMath::Sqrt(x*x + z*z + y0*y0) ) ; 
528     
529     
530     
531     Float_t phi           = GetPHOSAngle( phosmodule) ; 
532     Double_t const kRADDEG = 180.0 / kPI ;
533     Float_t rphi          = phi / kRADDEG ; 
534     
535     TRotation rot ;
536     rot.RotateZ(-rphi) ; // a rotation around Z by angle  
537     
538     TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
539     
540     cout << "before X,Y,Z " << pos.X() << endl << pos.Y() << endl << pos.Z() << endl;
541     pos.Transform(rot) ; // rotate the baby 
542     cout << "X,Y,Z " << pos.X() << endl << pos.Y() << endl << pos.Z() << endl;
543   }
544   else {
545     pos.SetX(0.);
546     pos.SetY(0.);
547     pos.SetZ(0.);
548   }
549
550
551 //____________________________________________________________________________
552 void AliPHOSGeometry::RelPosInModule(const Int_t * relid, Float_t & x, Float_t & z) const 
553 {
554   // Converts the relative numbering into the local PHOS-module (x, z) coordinates
555   // Note: sign of z differs from that in the previous version (Yu.Kharlov, 12 Oct 2000)
556
557   Bool_t padOfCPV  = (strcmp(fName,"IHEP")==0) ||
558                     ((strcmp(fName,"MIXT")==0) && relid[0]<=GetNCPVModules()) ;
559   Bool_t padOfPPSD = (strcmp(fName,"GPS2")==0) ||
560                     ((strcmp(fName,"MIXT")==0) && relid[0]> GetNCPVModules()) ;
561   
562   Int_t ppsdmodule  ; 
563   Float_t x0,z0;
564   Int_t row        = relid[2] ; //offset along x axiz
565   Int_t column     = relid[3] ; //offset along z axiz
566
567   Float_t padsizeZ = 0;
568   Float_t padsizeX = 0;
569   Int_t   nOfPadsPhi = 0;
570   Int_t   nOfPadsZ   = 0;
571   if      ( padOfPPSD ) {
572     padsizeZ   = GetPPSDModuleSize(2) / GetNumberOfPadsZ();
573     padsizeX   = GetPPSDModuleSize(0) / GetNumberOfPadsPhi();
574     nOfPadsPhi = GetNumberOfPadsPhi();
575     nOfPadsZ   = GetNumberOfPadsZ();
576   }
577   else if ( padOfCPV  ) {
578     padsizeZ   = GetPadSizeZ();
579     padsizeX   = GetPadSizePhi();
580     nOfPadsPhi = GetNumberOfCPVPadsPhi();
581     nOfPadsZ   = GetNumberOfCPVPadsZ();
582   }
583   
584   if ( relid[1] == 0 ) { // its a PbW04 crystal 
585     x = - ( GetNPhi()/2. - row    + 0.5 ) *  GetCrystalSize(0) ; // position ox Xtal with respect
586     z =   ( GetNZ()  /2. - column + 0.5 ) *  GetCrystalSize(2) ; // of center of PHOS module  
587   }  
588   else  {    
589     if ( padOfPPSD ) {
590       if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() )
591         ppsdmodule =  relid[1]-GetNumberOfModulesPhi() *  GetNumberOfModulesZ(); 
592       else
593         ppsdmodule =  relid[1] ;
594       Int_t modrow = 1+(Int_t)TMath::Ceil( (Float_t)ppsdmodule / GetNumberOfModulesPhi()-1. ) ; 
595       Int_t modcol = ppsdmodule -  ( modrow - 1 ) * GetNumberOfModulesPhi() ;     
596       x0 = (  GetNumberOfModulesPhi() / 2.  - modrow  + 0.5 ) * GetPPSDModuleSize(0) ;
597       z0 = (  GetNumberOfModulesZ()   / 2.  - modcol  + 0.5 ) * GetPPSDModuleSize(2)  ;     
598     } else {
599       x0 = 0;
600       z0 = 0;
601     }
602     x = - ( nOfPadsPhi/2. - row    - 0.5 ) * padsizeX + x0 ; // position of pad  with respect
603     z =   ( nOfPadsZ  /2. - column - 0.5 ) * padsizeZ - z0 ; // of center of PHOS module  
604   }
605 }