bb9c4c0b421a68dd0c65ed97792d90f6e1e2e4a1
[u/mrichter/AliRoot.git] / PHOS / AliPHOSGeometry.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //_________________________________________________________________________
19 // Geometry class  for PHOS : singleton  
20 // PHOS consists of the electromagnetic calorimeter (EMCA)
21 // and a charged particle veto either in the Subatech's version (PPSD)
22 // or in the IHEP's one (CPV).
23 // The EMCA/PPSD/CPV modules are parametrized so that any configuration
24 // can be easily implemented 
25 // The title is used to identify the version of CPV used.
26 //                  
27 //*-- Author: Yves Schutz (SUBATECH)
28
29 // --- ROOT system ---
30
31 #include "TVector3.h"
32 #include "TRotation.h" 
33
34 // --- Standard library ---
35
36 #include <iostream.h>
37
38 // --- AliRoot header files ---
39
40 #include "AliPHOSGeometry.h"
41 #include "AliPHOSPpsdRecPoint.h"
42 #include "AliConst.h"
43
44 ClassImp(AliPHOSGeometry) ;
45
46 AliPHOSGeometry * AliPHOSGeometry::fgGeom = 0 ;
47 Bool_t            AliPHOSGeometry::fgInit = kFALSE ;
48
49 //____________________________________________________________________________
50 AliPHOSGeometry::~AliPHOSGeometry(void)
51 {
52   // dtor
53
54   if (fRotMatrixArray) fRotMatrixArray->Delete() ; 
55   if (fRotMatrixArray) delete fRotMatrixArray ; 
56   if (fPHOSAngle     ) delete fPHOSAngle ; 
57 //    if (fGeometryEMCA  ) detete fGeometryEMCA;
58 //    if (fGeometryCPV   ) detete fGeometryCPV ;
59 }
60
61 //____________________________________________________________________________
62
63 void AliPHOSGeometry::Init(void)
64 {
65   // Initializes the PHOS parameters
66
67   if ( ((strcmp( fName, "default" )) == 0) || 
68        ((strcmp( fName, "GPS2" ))    == 0) ||
69        ((strcmp( fName, "IHEP" ))    == 0) ) {
70     fgInit     = kTRUE ; 
71                                              fGeometryEMCA = new AliPHOSEMCAGeometry();
72     if ( ((strcmp( fName, "GPS2" ))  == 0) ) fGeometryCPV  = new AliPHOSPPSDGeometry();
73     if ( ((strcmp( fName, "IHEP" ))  == 0) ) fGeometryCPV  = new AliPHOSCPVGeometry ();
74     fNModules = 5;
75     fPHOSAngle = new Float_t[fNModules] ;
76     Int_t index ;
77     for ( index = 0; index < fNModules; index++ )
78     fPHOSAngle[index] = 0.0 ; // Module position angles are set in CreateGeometry()
79
80     this->SetPHOSAngles() ; 
81     fRotMatrixArray = new TObjArray(fNModules) ; 
82   }
83  else {
84    fgInit = kFALSE ; 
85    cout << "PHOS Geometry setup: option not defined " << fName << endl ; 
86  }
87 }
88
89 //____________________________________________________________________________
90 AliPHOSGeometry *  AliPHOSGeometry::GetInstance() 
91
92   // Returns the pointer of the unique instance
93   return (AliPHOSGeometry *) fgGeom ; 
94 }
95
96 //____________________________________________________________________________
97 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title) 
98 {
99   // Returns the pointer of the unique instance
100   AliPHOSGeometry * rv = 0  ; 
101   if ( fgGeom == 0 ) {
102     if ( strcmp(name,"") == 0 ) 
103       rv = 0 ;
104     else {    
105       fgGeom = new AliPHOSGeometry(name, title) ;
106       if ( fgInit )
107         rv = (AliPHOSGeometry * ) fgGeom ;
108       else {
109         rv = 0 ; 
110         delete fgGeom ; 
111         fgGeom = 0 ; 
112       }
113     }
114   }
115   else {
116     if ( strcmp(fgGeom->GetName(), name) != 0 ) {
117       cout << "AliPHOSGeometry <E> : current geometry is " << fgGeom->GetName() << endl
118            << "                      you cannot call     " << name << endl ; 
119     }
120     else
121       rv = (AliPHOSGeometry *) fgGeom ; 
122   } 
123   return rv ; 
124 }
125
126 //____________________________________________________________________________
127 void AliPHOSGeometry::SetPHOSAngles() 
128
129   // Calculates the position in ALICE of the PHOS modules
130   
131   Double_t const kRADDEG = 180.0 / kPI ;
132   Float_t pphi =  TMath::ATan( GetOuterBoxSize(0)  / ( 2.0 * GetIPtoOuterCoverDistance() ) ) ;
133   pphi *= kRADDEG ;
134   
135   for( Int_t i = 1; i <= fNModules ; i++ ) {
136     Float_t angle = pphi * 2 * ( i - fNModules / 2.0 - 0.5 ) ;
137     fPHOSAngle[i-1] = -  angle ;
138   } 
139 }
140
141 //____________________________________________________________________________
142 Bool_t AliPHOSGeometry::AbsToRelNumbering(const Int_t AbsId, Int_t * relid)
143 {
144   // Converts the absolute numbering into the following array/
145   //  relid[0] = PHOS Module number 1:fNModules 
146   //  relid[1] = 0 if PbW04
147   //           = PPSD Module number 1:fNumberOfModulesPhi*fNumberOfModulesZ*2 (2->up and bottom level)
148   //  relid[2] = Row number inside a PHOS or PPSD module
149   //  relid[3] = Column number inside a PHOS or PPSD module
150
151   Bool_t rv  = kTRUE ; 
152   Float_t id = AbsId ;
153
154   Int_t phosmodulenumber = (Int_t)TMath:: Ceil( id / ( GetNPhi() * GetNZ() ) ) ; 
155   
156   if ( phosmodulenumber >  GetNModules() ) { // it is a PPSD or CPV pad
157
158     if      ( strcmp(fName,"GPS2") == 0 ) {
159       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
160       Float_t tempo = 2 *  GetNumberOfModulesPhi() * GetNumberOfModulesZ() *  GetNumberOfPadsPhi() * GetNumberOfPadsZ() ; 
161       relid[0] = (Int_t)TMath::Ceil( id / tempo ) ; 
162       id -= ( relid[0] - 1 ) * tempo ;
163       relid[1] = (Int_t)TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ; 
164       id -= ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ() ;
165       relid[2] = (Int_t)TMath::Ceil( id / GetNumberOfPadsPhi() ) ;
166       relid[3] = (Int_t) ( id - ( relid[2] - 1 )  * GetNumberOfPadsPhi() ) ; 
167     }
168     else if ( strcmp(fName,"IHEP") == 0 ) {
169       id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
170       relid[0] = (Int_t) TMath::Ceil( id / ( GetNumberOfPadsPhi() * GetNumberOfPadsZ() ) ) ;
171       relid[1] = 1 ;
172       id -= ( relid[0] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()  ; 
173       relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfPadsZ() ) ;
174       relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfPadsZ() ) ; 
175     }
176   } 
177   else { // its a PW04 crystal
178
179     relid[0] = phosmodulenumber ;
180     relid[1] = 0 ;
181     id -= ( phosmodulenumber - 1 ) *  GetNPhi() * GetNZ() ; 
182     relid[2] = (Int_t)TMath::Ceil( id / GetNPhi() ) ;
183     relid[3] = (Int_t)( id - ( relid[2] - 1 ) * GetNPhi() ) ; 
184   } 
185   return rv ; 
186 }
187
188 //____________________________________________________________________________  
189 void AliPHOSGeometry::EmcModuleCoverage(const Int_t mod, Double_t & tm, Double_t & tM, Double_t & pm, Double_t & pM, Option_t * opt) 
190 {
191   // calculates the angular coverage in theta and phi of a EMC module
192
193  Double_t conv ; 
194   if ( opt == Radian() ) 
195     conv = 1. ; 
196   else if ( opt == Degre() )
197     conv = 180. / TMath::Pi() ; 
198   else {
199     cout << "<I>  AliPHOSGeometry::EmcXtalCoverage : " << opt << " unknown option; result in radian " << endl ; 
200     conv = 1. ;
201       }
202
203   Float_t phi =  GetPHOSAngle(mod) *  (TMath::Pi() / 180.)  ;  
204   Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
205                   + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
206   
207   Double_t angle = TMath::ATan( GetCrystalSize(0)*GetNPhi() / (2 * y0) ) ;
208   phi = phi + 1.5 * TMath::Pi() ; // to follow the convention of the particle generator(PHOS is between 230 and 310 deg.)
209   Double_t max  = phi - angle ;
210   Double_t min   = phi + angle ;
211   pM = TMath::Max(max, min) * conv ;
212   pm = TMath::Min(max, min) * conv ; 
213   
214   angle =  TMath::ATan( GetCrystalSize(2)*GetNZ() / (2 * y0) ) ;
215   max  = TMath::Pi() / 2.  + angle ; // to follow the convention of the particle generator(PHOS is at 90 deg.)
216   min  = TMath::Pi() / 2.  - angle ;
217   tM = TMath::Max(max, min) * conv ;
218   tm = TMath::Min(max, min) * conv ; 
219  
220 }
221
222 //____________________________________________________________________________  
223 void AliPHOSGeometry::EmcXtalCoverage(Double_t & theta, Double_t & phi, Option_t * opt) 
224 {
225   // calculates the angular coverage in theta and phi of a single crystal in a EMC module
226
227   Double_t conv ; 
228   if ( opt == Radian() ) 
229     conv = 1. ; 
230   else if ( opt == Degre() )
231     conv = 180. / TMath::Pi() ; 
232   else {
233     cout << "<I>  AliPHOSGeometry::EmcXtalCoverage : " << opt << " unknown option; result in radian " << endl ; 
234     conv = 1. ;
235       }
236
237   Float_t y0   =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
238     + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;  
239   theta = 2 * TMath::ATan( GetCrystalSize(2) / (2 * y0) ) * conv ;
240   phi   = 2 * TMath::ATan( GetCrystalSize(0) / (2 * y0) ) * conv ;
241 }
242  
243
244 //____________________________________________________________________________
245 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos, TMatrix & gmat) const
246 {
247   // Calculates the ALICE global coordinates of a RecPoint and the error matrix
248  
249   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
250   TVector3 localposition ;
251
252   tmpPHOS->GetLocalPosition(gpos) ;
253
254
255   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
256     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
257                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
258
259     }
260   else
261     { // it is a PPSD pad
262       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
263       if (tmpPpsd->GetUp() ) // it is an upper module
264         {
265           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
266                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
267                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
268         } 
269       else // it is a lower module
270         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
271     }  
272
273   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
274   Double_t const kRADDEG = 180.0 / kPI ;
275   Float_t rphi          = phi / kRADDEG ; 
276   
277   TRotation rot ;
278   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
279   
280   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
281   gpos.Transform(rot) ; // rotate the baby 
282
283 }
284
285 //____________________________________________________________________________
286 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos) const 
287 {
288   // Calculates the ALICE global coordinates of a RecPoint 
289
290   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
291   TVector3 localposition ;
292   tmpPHOS->GetLocalPosition(gpos) ;
293
294
295   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
296     {  gpos.SetY( -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness() +
297                     GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()) ) ;  
298     }
299   else
300     { // it is a PPSD pad
301       AliPHOSPpsdRecPoint * tmpPpsd = (AliPHOSPpsdRecPoint *) RecPoint ;
302       if (tmpPpsd->GetUp() ) // it is an upper module
303         {
304           gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - 
305                        GetLeadToMicro2Gap() - GetLeadConverterThickness() -  
306                        GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0 )  ) ; 
307         } 
308       else // it is a lower module
309         gpos.SetY(-( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0) ) ; 
310     }  
311
312   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
313   Double_t const kRADDEG = 180.0 / kPI ;
314   Float_t rphi          = phi / kRADDEG ; 
315   
316   TRotation rot ;
317   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
318   
319   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
320   gpos.Transform(rot) ; // rotate the baby 
321 }
322
323 //____________________________________________________________________________
324 void AliPHOSGeometry::ImpactOnEmc(const Double_t theta, const Double_t phi, Int_t & ModuleNumber, Double_t & z, Double_t & x) 
325 {
326   // calculates the impact coordinates of a neutral particle  
327   // emitted in direction theta and phi in ALICE
328
329   // searches for the PHOS EMC module
330   ModuleNumber = 0 ; 
331   Double_t tm, tM, pm, pM ; 
332   Int_t index = 1 ; 
333   while ( ModuleNumber == 0 && index <= GetNModules() ) { 
334     EmcModuleCoverage(index, tm, tM, pm, pM) ; 
335     if ( (theta >= tm && theta <= tM) && (phi >= pm && phi <= pM ) ) 
336       ModuleNumber = index ; 
337     index++ ;    
338   }
339   if ( ModuleNumber != 0 ) {
340     Float_t phi0 =  GetPHOSAngle(ModuleNumber) *  (TMath::Pi() / 180.) + 1.5 * TMath::Pi()  ;  
341     Float_t y0  =  GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
342       + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness()  ;   
343     Double_t angle = phi - phi0; 
344     x = y0 * TMath::Tan(angle) ; 
345     angle = theta - TMath::Pi() / 2 ; 
346     z = y0 * TMath::Tan(angle) ; 
347   }
348 }
349
350 //____________________________________________________________________________
351 Bool_t AliPHOSGeometry::RelToAbsNumbering(const Int_t * relid, Int_t &  AbsId)
352 {
353   // Converts the relative numbering into the absolute numbering
354   //  AbsId = 1 to fNModules * fNPhi * fNZ                                                                       -> PbWO4
355   //  AbsId = N(total PHOS crystals) +
356   //          1 to fNModules * 2 * (fNumberOfModulesPhi * fNumberOfModulesZ) * fNumberOfPadsPhi * fNumberOfPadsZ -> PPSD
357   //  AbsId = N(total PHOS crystals) +
358   //          1:fNModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ                                              -> CPV
359
360   Bool_t rv = kTRUE ; 
361  
362   if      ( relid[1]  >  0 ) { // it is a PPSD pad
363     AbsId =    GetNPhi() * GetNZ() *  GetNModules()                          // the offset to separate EMCA crystals from PPSD pads
364       + ( relid[0] - 1 ) * GetNumberOfModulesPhi() * GetNumberOfModulesZ()   // the pads offset of PHOS modules 
365                          * GetNumberOfPadsPhi() * GetNumberOfPadsZ() * 2
366       + ( relid[1] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()         // the pads offset of PPSD modules 
367       + ( relid[2] - 1 ) * GetNumberOfPadsPhi()                              // the pads offset of a PPSD row
368       +   relid[3] ;                                                         // the column number
369   } 
370
371   else if ( relid[1] ==  0 ) { // it is a Phos crystal
372     AbsId =
373         ( relid[0] - 1 ) * GetNPhi() * GetNZ()                               // the offset of PHOS modules
374       + ( relid[2] - 1 ) * GetNPhi()                                         // the offset of a xtal row
375       +   relid[3] ;                                                         // the column number
376   }
377
378   else if ( relid[1] == -1 ) { // it is a CPV pad
379     AbsId =    GetNPhi() * GetNZ() *  GetNModules()                          // the offset to separate EMCA crystals from CPV pads
380       + ( relid[0] - 1 ) * GetNumberOfPadsPhi() * GetNumberOfPadsZ()         // the pads offset of PHOS modules 
381       + ( relid[2] - 1 ) * GetNumberOfPadsZ()                                // the pads offset of a CPV row
382       +   relid[3] ;                                                         // the column number
383   }
384   
385   return rv ; 
386 }
387
388 //____________________________________________________________________________
389
390 void AliPHOSGeometry::RelPosInAlice(const Int_t id, TVector3 & pos ) 
391 {
392   // Converts the absolute numbering into the global ALICE coordinates
393   
394    if (id > 0) { 
395
396   Int_t relid[4] ;
397  
398   AbsToRelNumbering(id , relid) ;
399
400   Int_t phosmodule = relid[0] ; 
401
402   Float_t y0 = 0 ; 
403
404   if ( relid[1] == 0 ) // it is a PbW04 crystal 
405   {  y0 =  -(GetIPtoOuterCoverDistance() + GetUpperPlateThickness()
406       + GetSecondUpperPlateThickness() + GetUpperCoolingPlateThickness())  ;  
407   }
408   if ( relid[1] > 0 ) { // its a PPSD pad
409     if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() ) // its an bottom module
410      {
411        y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() / 2.0)  ;
412      } 
413     else // its an upper module
414       y0 = -( GetIPtoOuterCoverDistance() - GetMicromegas2Thickness() - GetLeadToMicro2Gap()
415         -  GetLeadConverterThickness() -  GetMicro1ToLeadGap() - GetMicromegas1Thickness() / 2.0) ; 
416   }
417
418   Float_t x, z ; 
419   RelPosInModule(relid, x, z) ; 
420
421   pos.SetX(x) ;
422   pos.SetZ(z) ;
423   pos.SetY( TMath::Sqrt(x*x + z*z + y0*y0) ) ; 
424
425
426
427    Float_t phi           = GetPHOSAngle( phosmodule) ; 
428    Double_t const kRADDEG = 180.0 / kPI ;
429    Float_t rphi          = phi / kRADDEG ; 
430
431    TRotation rot ;
432    rot.RotateZ(-rphi) ; // a rotation around Z by angle  
433   
434    TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
435   
436    pos.Transform(rot) ; // rotate the baby 
437   }
438   else {
439  pos.SetX(0.);
440  pos.SetY(0.);
441  pos.SetZ(0.);
442        }
443
444
445 //____________________________________________________________________________
446 void AliPHOSGeometry::RelPosInModule(const Int_t * relid, Float_t & x, Float_t & z) 
447 {
448   // Converts the relative numbering into the local PHOS-module (x, z) coordinates
449   // Note: sign of z differs from that in the previous version (Yu.Kharlov, 12 Oct 2000)
450   
451   Int_t ppsdmodule  ; 
452   Float_t x0,z0;
453   Int_t row        = relid[2] ; //offset along x axiz
454   Int_t column     = relid[3] ; //offset along z axiz
455
456   Float_t padsizeZ = GetPadSizeZ();
457   Float_t padsizeX = GetPadSizePhi();
458
459   if ( relid[1] == 0 ) { // its a PbW04 crystal 
460     x = - ( GetNPhi()/2. - row    + 0.5 ) *  GetCrystalSize(0) ; // position ox Xtal with respect
461     z =   ( GetNZ()  /2. - column + 0.5 ) *  GetCrystalSize(2) ; // of center of PHOS module  
462   }  
463   else  {    
464     if ( relid[1] >  GetNumberOfModulesPhi() *  GetNumberOfModulesZ() )
465       ppsdmodule =  relid[1]-GetNumberOfModulesPhi() *  GetNumberOfModulesZ(); 
466     else
467       ppsdmodule =  relid[1] ;
468     Int_t modrow = 1+(Int_t)TMath::Ceil( (Float_t)ppsdmodule / GetNumberOfModulesPhi()-1. ) ; 
469     Int_t modcol = ppsdmodule -  ( modrow - 1 ) * GetNumberOfModulesPhi() ;     
470     if ( ((strcmp( fName, "GPS2" ))  == 0) ) {
471       x0 = (  GetNumberOfModulesPhi() / 2.  - modrow  + 0.5 ) * GetPPSDModuleSize(0) ;
472       z0 = (  GetNumberOfModulesZ()   / 2.  - modcol  + 0.5 ) * GetPPSDModuleSize(2)  ;     
473     } else {
474       x0 = 0;
475       z0 = 0;
476     }
477     x = - ( GetNumberOfPadsPhi()/2. - row    - 0.5 ) * padsizeX + x0 ; // position of pad  with respect
478     z =   ( GetNumberOfPadsZ()  /2. - column - 0.5 ) * padsizeZ - z0 ; // of center of PHOS module  
479   }
480 }