]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PHOS/AliPHOSGeometry.cxx
Additional protection. The call to RecWithStack has to be removed in case of raw...
[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) & Dmitri Peressounko (RRC "KI" & SUBATECH)
28
29 // --- ROOT system ---
30
31 #include "TVector3.h"
32 #include "TRotation.h" 
33 #include "TParticle.h"
34
35 // --- Standard library ---
36
37 // --- AliRoot header files ---
38 #include "AliLog.h"
39 #include "AliPHOSGeometry.h"
40 #include "AliPHOSEMCAGeometry.h" 
41 #include "AliPHOSRecPoint.h"
42
43 ClassImp(AliPHOSGeometry)
44
45 // these initialisations are needed for a singleton
46 AliPHOSGeometry  * AliPHOSGeometry::fgGeom = 0 ;
47 Bool_t             AliPHOSGeometry::fgInit = kFALSE ;
48 AliPHOSAlignData * AliPHOSGeometry::fgAlignData = 0 ;
49
50 //____________________________________________________________________________
51 AliPHOSGeometry::AliPHOSGeometry() {
52     // default ctor 
53     // must be kept public for root persistency purposes, but should never be called by the outside world
54     fPHOSAngle      = 0 ;
55     fGeometryEMCA   = 0 ;
56     fGeometrySUPP   = 0 ;
57     fGeometryCPV    = 0 ;
58     fgGeom          = 0 ;
59     fRotMatrixArray = 0 ;  
60 }  
61
62 //____________________________________________________________________________
63 AliPHOSGeometry::~AliPHOSGeometry(void)
64 {
65   // dtor
66
67   if (fRotMatrixArray) fRotMatrixArray->Delete() ; 
68   if (fRotMatrixArray) delete fRotMatrixArray ; 
69   if (fPHOSAngle     ) delete[] fPHOSAngle ; 
70 }
71 //____________________________________________________________________________
72
73 void AliPHOSGeometry::Init(void)
74 {
75   // Initializes the PHOS parameters :
76   //  IHEP is the Protvino CPV (cathode pad chambers)
77   
78   TString test(GetName()) ; 
79   if (test != "IHEP" ) {
80     AliFatal(Form("%s is not a known geometry (choose among IHEP)", 
81                   test.Data() )) ; 
82   }
83
84   fgInit     = kTRUE ; 
85
86   // YK 23.02.2006
87   if(fgAlignData != NULL) {
88     // Number of modules is read from Alignment DB if exists
89     fNModules = fgAlignData->GetNModules();
90   }
91   else {
92     // Number of modules is fixed if Alignment DB does not exist
93     fNModules     = 5;
94     fAngle        = 20;
95   }
96
97   fGeometryEMCA = new AliPHOSEMCAGeometry();
98   
99   fGeometryCPV  = new AliPHOSCPVGeometry ();
100   
101   fGeometrySUPP = new AliPHOSSupportGeometry();
102   
103   fPHOSAngle = new Float_t[fNModules] ;
104   
105   Float_t * emcParams = fGeometryEMCA->GetEMCParams() ;
106   
107   fPHOSParams[0] =  TMath::Max((Double_t)fGeometryCPV->GetCPVBoxSize(0)/2., 
108                                (Double_t)(emcParams[0] - (emcParams[1]-emcParams[0])*
109                                           fGeometryCPV->GetCPVBoxSize(1)/2/emcParams[3]));
110   fPHOSParams[1] = emcParams[1] ;
111   fPHOSParams[2] = TMath::Max((Double_t)emcParams[2], (Double_t)fGeometryCPV->GetCPVBoxSize(2)/2.);
112   fPHOSParams[3] = emcParams[3] + fGeometryCPV->GetCPVBoxSize(1)/2. ;
113   
114   fIPtoUpperCPVsurface = fGeometryEMCA->GetIPtoOuterCoverDistance() - fGeometryCPV->GetCPVBoxSize(1) ;
115   
116   Int_t index ;
117   for ( index = 0; index < fNModules; index++ )
118     fPHOSAngle[index] = 0.0 ; // Module position angles are set in CreateGeometry()
119   
120   fRotMatrixArray = new TObjArray(fNModules) ; 
121
122   // YK 23.02.2006
123   if(fgAlignData) {
124     // Geometry parameters are read from Alignment DB if exists
125
126     for (Int_t iModule=0; iModule<fNModules; iModule++) {
127       for (Int_t iXYZ=0; iXYZ<3; iXYZ++) {
128         fModuleCenter[iModule][iXYZ]   =
129           fgAlignData->GetModuleCenter(iModule,iXYZ);
130         fModuleAngle[iModule][iXYZ][0] = 
131           fgAlignData->GetModuleAngle(iModule,iXYZ,0);
132         fModuleAngle[iModule][iXYZ][1] = 
133           fgAlignData->GetModuleAngle(iModule,iXYZ,1);
134       }
135     }
136   }
137   else {
138     // Geometry parameters are calculated if Alignment DB does not exist
139
140     SetPHOSAngles();
141     Double_t const kRADDEG = 180.0 / TMath::Pi() ;
142     Float_t r = GetIPtoOuterCoverDistance() + fPHOSParams[3] - GetCPVBoxSize(1) ;
143     for (Int_t iModule=0; iModule<fNModules; iModule++) {
144       fModuleCenter[iModule][0] = r * TMath::Sin(fPHOSAngle[iModule] / kRADDEG );
145       fModuleCenter[iModule][1] =-r * TMath::Cos(fPHOSAngle[iModule] / kRADDEG );
146       fModuleCenter[iModule][2] = 0.;
147
148       fModuleAngle[iModule][0][0] =  90;
149       fModuleAngle[iModule][0][1] =   fPHOSAngle[iModule];
150       fModuleAngle[iModule][1][0] =   0;
151       fModuleAngle[iModule][1][1] =   0;
152       fModuleAngle[iModule][2][0] =  90;
153       fModuleAngle[iModule][2][1] = 270 + fPHOSAngle[iModule];
154     }
155   }
156
157 }
158
159 //____________________________________________________________________________
160 AliPHOSGeometry *  AliPHOSGeometry::GetInstance() 
161
162   // Returns the pointer of the unique instance; singleton specific
163   
164   return static_cast<AliPHOSGeometry *>( fgGeom ) ; 
165 }
166
167 //____________________________________________________________________________
168 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title) 
169 {
170   // Returns the pointer of the unique instance
171   // Creates it with the specified options (name, title) if it does not exist yet
172
173   AliPHOSGeometry * rv = 0  ; 
174   if ( fgGeom == 0 ) {
175     if ( strcmp(name,"") == 0 ) 
176       rv = 0 ;
177     else {    
178       fgGeom = new AliPHOSGeometry(name, title) ;
179       if ( fgInit )
180         rv = (AliPHOSGeometry * ) fgGeom ;
181       else {
182         rv = 0 ; 
183         delete fgGeom ; 
184         fgGeom = 0 ; 
185       }
186     }
187   }
188   else {
189     if ( strcmp(fgGeom->GetName(), name) != 0 ) 
190       ::Error("GetInstance", "Current geometry is %s. You cannot call %s", 
191                       fgGeom->GetName(), name) ; 
192     else
193       rv = (AliPHOSGeometry *) fgGeom ; 
194   } 
195   return rv ; 
196 }
197
198 //____________________________________________________________________________
199 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title,
200                                                 AliPHOSAlignData *alignda) 
201 {
202   // Returns the pointer of the unique instance
203   // Creates it with the specified options (name, title) if it does not exist yet
204
205   fgAlignData = alignda;
206   return GetInstance(name,title);
207 }
208
209 //____________________________________________________________________________
210 void AliPHOSGeometry::SetPHOSAngles() 
211
212   // Calculates the position of the PHOS modules in ALICE global coordinate system
213   
214   Double_t const kRADDEG = 180.0 / TMath::Pi() ;
215   Float_t pphi =  2 * TMath::ATan( GetOuterBoxSize(0)  / ( 2.0 * GetIPtoUpperCPVsurface() ) ) ;
216   pphi *= kRADDEG ;
217   if (pphi > fAngle){ 
218     AliError(Form("PHOS modules overlap!\n pphi = %f fAngle = %f", 
219                   pphi, fAngle));
220
221   }
222   pphi = fAngle;
223   
224   for( Int_t i = 1; i <= fNModules ; i++ ) {
225     Float_t angle = pphi * ( i - fNModules / 2.0 - 0.5 ) ;
226     fPHOSAngle[i-1] = -  angle ;
227   } 
228 }
229
230 //____________________________________________________________________________
231 Bool_t AliPHOSGeometry::AbsToRelNumbering(Int_t AbsId, Int_t * relid) const
232 {
233   // Converts the absolute numbering into the following array/
234   //  relid[0] = PHOS Module number 1:fNModules 
235   //  relid[1] = 0 if PbW04
236   //           = -1 if CPV
237   //  relid[2] = Row number inside a PHOS module
238   //  relid[3] = Column number inside a PHOS module
239
240   Bool_t rv  = kTRUE ; 
241   Float_t id = AbsId ;
242
243   Int_t phosmodulenumber = (Int_t)TMath:: Ceil( id / GetNCristalsInModule() ) ; 
244   
245   if ( phosmodulenumber >  GetNModules() ) { // it is a CPV pad
246     
247     id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
248     Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
249     relid[0] = (Int_t) TMath::Ceil( id / nCPV ) ;
250     relid[1] = -1 ;
251     id -= ( relid[0] - 1 ) * nCPV ; 
252     relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfCPVPadsZ() ) ;
253     relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfCPVPadsZ() ) ; 
254   } 
255   else { // it is 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 / GetNZ() )  ;
261     relid[3] = (Int_t)( id - ( relid[2] - 1 ) * GetNZ() ) ; 
262   } 
263   return rv ; 
264 }
265
266 //____________________________________________________________________________  
267 void AliPHOSGeometry::EmcModuleCoverage(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     AliWarning(Form("%s unknown option; result in radian", opt)) ; 
278     conv = 1. ;
279       }
280
281   Float_t phi = GetPHOSAngle(mod) *  (TMath::Pi() / 180.)  ;  
282   Float_t y0  = GetIPtoCrystalSurface() ; 
283   Float_t * strip = fGeometryEMCA->GetStripHalfSize() ;
284   Float_t x0  = fGeometryEMCA->GetNStripX()*strip[0] ;
285   Float_t z0  = fGeometryEMCA->GetNStripZ()*strip[2] ;
286   Double_t angle = TMath::ATan( x0 / y0 ) ;
287   phi = phi + 1.5 * TMath::Pi() ; // to follow the convention of the particle generator(PHOS is between 220 and 320 deg.)
288   Double_t max  = phi - angle ;
289   Double_t min   = phi + angle ;
290   pM = TMath::Max(max, min) * conv ;
291   pm = TMath::Min(max, min) * conv ; 
292   
293   angle =  TMath::ATan( z0 /  y0 ) ;
294   max  = TMath::Pi() / 2.  + angle ; // to follow the convention of the particle generator(PHOS is at 90 deg.)
295   min  = TMath::Pi() / 2.  - angle ;
296   tM = TMath::Max(max, min) * conv ;
297   tm = TMath::Min(max, min) * conv ; 
298  
299 }
300
301 //____________________________________________________________________________  
302 void AliPHOSGeometry::EmcXtalCoverage(Double_t & theta, Double_t & phi, Option_t * opt) const
303 {
304   // calculates the angular coverage in theta and phi of a single crystal in a EMC(=PHOS) module
305
306   Double_t conv ; 
307   if ( opt == Radian() ) 
308     conv = 1. ; 
309   else if ( opt == Degre() )
310     conv = 180. / TMath::Pi() ; 
311   else {
312     AliWarning(Form("%s unknown option; result in radian", opt)) ;  
313     conv = 1. ;
314       }
315
316   Float_t y0  = GetIPtoCrystalSurface() ; 
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, TMatrixF & /*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( - GetIPtoCrystalSurface()) ;  
335
336     }
337   else
338     { // it is a CPV
339       gpos.SetY(- GetIPtoUpperCPVsurface()  ) ; 
340     }  
341
342   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
343   Double_t const kRADDEG = 180.0 / TMath::Pi() ;
344   Float_t rphi          = phi / kRADDEG ; 
345   
346   TRotation rot ;
347   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
348   
349   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
350   gpos.Transform(rot) ; // rotate the baby 
351
352 }
353
354 //____________________________________________________________________________
355 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos) const 
356 {
357   // Calculates the coordinates of a RecPoint in the ALICE global coordinate system 
358
359   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
360   TVector3 localposition ;
361   tmpPHOS->GetLocalPosition(gpos) ;
362
363
364   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
365     {  gpos.SetY( - GetIPtoCrystalSurface()  ) ;  
366     }
367   else
368     { // it is a CPV
369           gpos.SetY(- GetIPtoUpperCPVsurface()  ) ; 
370     }  
371
372   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
373   Double_t const kRADDEG = 180.0 / TMath::Pi() ;
374   Float_t rphi          = phi / kRADDEG ; 
375   
376   TRotation rot ;
377   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
378   
379   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
380   gpos.Transform(rot) ; // rotate the baby 
381 }
382
383 //____________________________________________________________________________
384 void AliPHOSGeometry::ImpactOnEmc(Double_t theta, Double_t phi, Int_t & moduleNumber, Double_t & z, Double_t & x) const
385 {
386   // calculates the impact coordinates on PHOS of a neutral particle  
387   // emitted in the direction theta and phi in the ALICE global coordinate system
388
389   // searches for the PHOS EMC module
390
391   moduleNumber = 0 ; 
392   Double_t tm, tM, pm, pM ; 
393   Int_t index = 1 ; 
394   while ( moduleNumber == 0 && index <= GetNModules() ) { 
395     EmcModuleCoverage(index, tm, tM, pm, pM) ; 
396     if ( (theta >= tm && theta <= tM) && (phi >= pm && phi <= pM ) ) 
397       moduleNumber = index ; 
398     index++ ;    
399   }
400   if ( moduleNumber != 0 ) {
401     Float_t phi0 =  GetPHOSAngle(moduleNumber) *  (TMath::Pi() / 180.) + 1.5 * TMath::Pi()  ;  
402     Float_t y0  =  GetIPtoCrystalSurface()  ;   
403     Double_t angle = phi - phi0; 
404     x = y0 * TMath::Tan(angle) ; 
405     angle = theta - TMath::Pi() / 2 ; 
406     z = y0 * TMath::Tan(angle) ; 
407   }
408 }
409
410 //____________________________________________________________________________
411 void AliPHOSGeometry::ImpactOnEmc(const TVector3& vec, Int_t & moduleNumber, Double_t & z, Double_t & x) const
412 {
413   // calculates the impact coordinates on PHOS of a neutral particle  
414   // emitted in the direction theta and phi in the ALICE global coordinate system
415   // searches for the PHOS EMC module
416
417   Double_t theta = vec.Theta() ; 
418   Double_t phi   = vec.Phi() ; 
419
420   ImpactOnEmc(theta, phi, moduleNumber, z, x) ;
421 }
422
423 //____________________________________________________________________________
424 void AliPHOSGeometry::ImpactOnEmc(const TParticle& p, Int_t & moduleNumber, Double_t & z, Double_t & x) const
425 {
426   // calculates the impact coordinates on PHOS of a neutral particle  
427   // emitted in the direction theta and phi in the ALICE global coordinate system
428
429   // searches for the PHOS EMC module
430   Double_t theta = p.Theta() ; 
431   Double_t phi   = p.Phi() ; 
432
433   ImpactOnEmc(theta, phi, moduleNumber, z, x) ;
434 }
435
436 //____________________________________________________________________________
437 Bool_t  AliPHOSGeometry::Impact(const TParticle * particle) const 
438 {
439   // Tells if a particle enters PHOS
440   Bool_t in=kFALSE;
441   Int_t moduleNumber=0;
442   Double_t z,x;
443   ImpactOnEmc(particle->Theta(),particle->Phi(),moduleNumber,z,x);
444   if(moduleNumber) 
445     in=kTRUE;
446   else 
447     in=kFALSE;
448   return in;
449 }
450
451 //____________________________________________________________________________
452 Bool_t AliPHOSGeometry::RelToAbsNumbering(const Int_t * relid, Int_t &  AbsId) const
453 {
454   // Converts the relative numbering into the absolute numbering
455   // EMCA crystals:
456   //  AbsId = from 1 to fNModules * fNPhi * fNZ
457   // CPV pad:
458   //  AbsId = from N(total PHOS crystals) + 1
459   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ
460
461   Bool_t rv = kTRUE ; 
462   
463   if ( relid[1] ==  0 ) {                            // it is a Phos crystal
464     AbsId =
465       ( relid[0] - 1 ) * GetNPhi() * GetNZ()         // the offset of PHOS modules
466       + ( relid[2] - 1 ) * GetNZ()                   // the offset along phi
467       +   relid[3] ;                                 // the offset along z
468   }
469   else { // it is a CPV pad
470     AbsId =    GetNPhi() * GetNZ() *  GetNModules()         // the offset to separate EMCA crystals from CPV pads
471       + ( relid[0] - 1 ) * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ()   // the pads offset of PHOS modules 
472       + ( relid[2] - 1 ) * GetNumberOfCPVPadsZ()                             // the pads offset of a CPV row
473       +   relid[3] ;                                                         // the column number
474   }
475   
476   return rv ; 
477 }
478
479 //____________________________________________________________________________
480
481 void AliPHOSGeometry::RelPosInAlice(Int_t id, TVector3 & pos ) const
482 {
483   // Converts the absolute numbering into the global ALICE coordinate system
484   
485     
486     Int_t relid[4] ;
487     
488     AbsToRelNumbering(id , relid) ;
489     
490     Int_t phosmodule = relid[0] ; 
491     
492     Float_t y0 = 0 ; 
493     
494     if ( relid[1] == 0 )  // it is a PbW04 crystal 
495       y0 =  - GetIPtoCrystalSurface() ;  
496     else
497       y0 =  - GetIPtoUpperCPVsurface() ; 
498
499     Float_t x, z ; 
500     RelPosInModule(relid, x, z) ; 
501     
502     pos.SetX(x) ;
503     pos.SetZ(z) ;
504     pos.SetY(y0) ;
505     
506     Float_t phi           = GetPHOSAngle( phosmodule) ; 
507     Double_t const kRADDEG = 180.0 / TMath::Pi() ;
508     Float_t rphi          = phi / kRADDEG ; 
509     
510     TRotation rot ;
511     rot.RotateZ(-rphi) ; // a rotation around Z by angle  
512     
513     TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
514     
515     pos.Transform(rot) ; // rotate the baby 
516
517
518 //____________________________________________________________________________
519 void AliPHOSGeometry::RelPosToAbsId(Int_t module, Double_t x, Double_t z, Int_t & AbsId) const
520 {
521   // converts local PHOS-module (x, z) coordinates to absId 
522   Int_t relid[4] ;
523   relid[0] = module ;
524   relid[1] = 0 ;
525   relid[2] = static_cast<Int_t>(TMath::Ceil( x/ GetCellStep() + GetNPhi() / 2.) );
526   relid[3] = static_cast<Int_t>(TMath::Ceil(-z/ GetCellStep() + GetNZ()   / 2.) ) ;
527   
528   RelToAbsNumbering(relid,AbsId) ;
529 }
530
531 //____________________________________________________________________________
532 void AliPHOSGeometry::RelPosInModule(const Int_t * relid, Float_t & x, Float_t & z) const 
533 {
534   // Converts the relative numbering into the local PHOS-module (x, z) coordinates
535   // Note: sign of z differs from that in the previous version (Yu.Kharlov, 12 Oct 2000)
536   
537   Int_t row        = relid[2] ; //offset along x axis
538   Int_t column     = relid[3] ; //offset along z axis
539
540   
541   if ( relid[1] == 0 ) { // its a PbW04 crystal
542     x = - ( GetNPhi()/2. - row    + 0.5 ) *  GetCellStep() ; // position of Xtal with respect
543     z = - ( GetNZ()  /2. - column + 0.5 ) *  GetCellStep() ; // of center of PHOS module  
544   }  
545   else  {    
546     x = - ( GetNumberOfCPVPadsPhi()/2. - row    - 0.5 ) * GetPadSizePhi()  ; // position of pad  with respect
547     z = - ( GetNumberOfCPVPadsZ()  /2. - column - 0.5 ) * GetPadSizeZ()  ; // of center of PHOS module  
548   }
549 }
550
551 //____________________________________________________________________________
552
553 void AliPHOSGeometry::GetModuleCenter(TVector3& center, 
554                                       const char *det,
555                                       Int_t module) const
556 {
557   // Returns a position of the center of the CPV or EMC module
558   Float_t rDet = 0.;
559   if      (strcmp(det,"CPV") == 0) rDet  = GetIPtoCPVDistance   ();
560   else if (strcmp(det,"EMC") == 0) rDet  = GetIPtoCrystalSurface();
561   else 
562     AliFatal(Form("Wrong detector name %s",det));
563
564   Float_t angle = GetPHOSAngle(module); // (40,20,0,-20,-40) degrees
565   angle *= TMath::Pi()/180;
566   angle += 3*TMath::Pi()/2.;
567   center.SetXYZ(rDet*TMath::Cos(angle), rDet*TMath::Sin(angle), 0.);
568 }
569
570 //____________________________________________________________________________
571
572 void AliPHOSGeometry::Global2Local(TVector3& localPosition,
573                                    const TVector3& globalPosition,
574                                    Int_t module) const
575 {
576   // Transforms a global position of the rec.point to the local coordinate system
577   Float_t angle = GetPHOSAngle(module); // (40,20,0,-20,-40) degrees
578   angle *= TMath::Pi()/180;
579   angle += 3*TMath::Pi()/2.;
580   localPosition = globalPosition;
581   localPosition.RotateZ(-angle);
582 }