]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PHOS/AliPHOSGeometry.cxx
Partial redesign of identification bits and coding rule corrections
[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 "TFolder.h" 
34 #include "TROOT.h" 
35
36 // --- Standard library ---
37
38 #include <stdlib.h>
39
40 // --- AliRoot header files ---
41
42 #include "AliPHOSGeometry.h"
43 #include "AliPHOSEMCAGeometry.h" 
44 #include "AliPHOSRecPoint.h"
45 #include "AliConst.h"
46
47 ClassImp(AliPHOSGeometry) ;
48
49 // these initialisations are needed for a singleton
50 AliPHOSGeometry * AliPHOSGeometry::fgGeom = 0 ;
51 Bool_t            AliPHOSGeometry::fgInit = kFALSE ;
52
53 //____________________________________________________________________________
54 AliPHOSGeometry::AliPHOSGeometry(void)
55 {
56   // default ctor 
57   // must be kept public for root persistency purposes,
58   // but should never be called by the outside world
59   fPHOSAngle      = 0 ;
60   fGeometryEMCA   = 0;
61   fGeometrySUPP   = 0;
62   fGeometryCPV    = 0;
63   fgGeom          = 0;
64   fRotMatrixArray = 0;
65 }
66 //____________________________________________________________________________
67 AliPHOSGeometry::~AliPHOSGeometry(void)
68 {
69   // dtor
70
71   if (fRotMatrixArray) fRotMatrixArray->Delete() ; 
72   if (fRotMatrixArray) delete fRotMatrixArray ; 
73   if (fPHOSAngle     ) delete[] fPHOSAngle ; 
74 }
75 //____________________________________________________________________________
76
77 void AliPHOSGeometry::Init(void)
78 {
79   // Initializes the PHOS parameters :
80   //  IHEP is the Protvino CPV (cathode pad chambers)
81   //  GPS2 is the Subatech Pre-Shower (two micromegas sandwiching a passive lead converter)
82   //  MIXT 4 PHOS modules withe the IHEP CPV and one PHOS module with the Subatech Pre-Shower
83   
84   TString test(GetName()) ; 
85   if (test != "IHEP" && test != "GPS2" && test != "MIXT") {
86     Fatal("Init", "%s is not a known geometry (choose among IHEP, GPS2 and MIXT)", test.Data() ) ; 
87   }
88
89   fgInit     = kTRUE ; 
90   
91   fNModules     = 5;
92   fAngle        = 20;
93   
94   fGeometryEMCA = new AliPHOSEMCAGeometry();
95   
96   fGeometryCPV  = new AliPHOSCPVGeometry ();
97   
98   fGeometrySUPP = new AliPHOSSupportGeometry();
99   
100   fPHOSAngle = new Float_t[fNModules] ;
101   
102   Float_t * emcParams = fGeometryEMCA->GetEMCParams() ;
103   
104   fPHOSParams[0] =  TMath::Max((Double_t)fGeometryCPV->GetCPVBoxSize(0)/2., 
105                                (Double_t)(emcParams[0]*(fGeometryCPV->GetCPVBoxSize(1)+emcParams[3]) - 
106                                 emcParams[1]* fGeometryCPV->GetCPVBoxSize(1))/emcParams[3] ) ;
107   fPHOSParams[1] = emcParams[1] ;
108   fPHOSParams[2] = TMath::Max((Double_t)emcParams[2], (Double_t)fGeometryCPV->GetCPVBoxSize(2)/2.);
109   fPHOSParams[3] = emcParams[3] + fGeometryCPV->GetCPVBoxSize(1)/2. ;
110   
111   fIPtoUpperCPVsurface = fGeometryEMCA->GetIPtoOuterCoverDistance() - fGeometryCPV->GetCPVBoxSize(1) ;
112   
113   Int_t index ;
114   for ( index = 0; index < fNModules; index++ )
115     fPHOSAngle[index] = 0.0 ; // Module position angles are set in CreateGeometry()
116   
117   this->SetPHOSAngles() ; 
118   fRotMatrixArray = new TObjArray(fNModules) ; 
119   
120 }
121
122 //____________________________________________________________________________
123 AliPHOSGeometry *  AliPHOSGeometry::GetInstance() 
124
125   // Returns the pointer of the unique instance; singleton specific
126   
127   return static_cast<AliPHOSGeometry *>( fgGeom ) ; 
128 }
129
130 //____________________________________________________________________________
131 AliPHOSGeometry *  AliPHOSGeometry::GetInstance(const Text_t* name, const Text_t* title) 
132 {
133   // Returns the pointer of the unique instance
134   // Creates it with the specified options (name, title) if it does not exist yet
135
136   AliPHOSGeometry * rv = 0  ; 
137   if ( fgGeom == 0 ) {
138     if ( strcmp(name,"") == 0 ) 
139       rv = 0 ;
140     else {    
141       fgGeom = new AliPHOSGeometry(name, title) ;
142       if ( fgInit )
143         rv = (AliPHOSGeometry * ) fgGeom ;
144       else {
145         rv = 0 ; 
146         delete fgGeom ; 
147         fgGeom = 0 ; 
148       }
149     }
150   }
151   else {
152     if ( strcmp(fgGeom->GetName(), name) != 0 ) 
153       ::Error("GetInstance", "Current geometry is %s. You cannot call %s", fgGeom->GetName(), name) ; 
154     else
155       rv = (AliPHOSGeometry *) fgGeom ; 
156   } 
157   return rv ; 
158 }
159
160 //____________________________________________________________________________
161 void AliPHOSGeometry::SetPHOSAngles() 
162
163   // Calculates the position of the PHOS modules in ALICE global coordinate system
164   
165   Double_t const kRADDEG = 180.0 / kPI ;
166   Float_t pphi =  2 * TMath::ATan( GetOuterBoxSize(0)  / ( 2.0 * GetIPtoUpperCPVsurface() ) ) ;
167   pphi *= kRADDEG ;
168   if (pphi > fAngle){ 
169     Error("SetPHOSAngles", "PHOS modules overlap!\n pphi = %f fAngle = %f", pphi, fAngle);
170
171   }
172   pphi = fAngle;
173   
174   for( Int_t i = 1; i <= fNModules ; i++ ) {
175     Float_t angle = pphi * ( i - fNModules / 2.0 - 0.5 ) ;
176     fPHOSAngle[i-1] = -  angle ;
177   } 
178 }
179
180 //____________________________________________________________________________
181 Bool_t AliPHOSGeometry::AbsToRelNumbering(const Int_t AbsId, Int_t * relid) const
182 {
183   // Converts the absolute numbering into the following array/
184   //  relid[0] = PHOS Module number 1:fNModules 
185   //  relid[1] = 0 if PbW04
186   //           = -1 if CPV
187   //  relid[2] = Row number inside a PHOS module
188   //  relid[3] = Column number inside a PHOS module
189
190   Bool_t rv  = kTRUE ; 
191   Float_t id = AbsId ;
192
193   Int_t phosmodulenumber = (Int_t)TMath:: Ceil( id / GetNCristalsInModule() ) ; 
194   
195   if ( phosmodulenumber >  GetNModules() ) { // it is a CPV pad
196     
197     id -=  GetNPhi() * GetNZ() *  GetNModules() ; 
198     Float_t nCPV  = GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ() ;
199     relid[0] = (Int_t) TMath::Ceil( id / nCPV ) ;
200     relid[1] = -1 ;
201     id -= ( relid[0] - 1 ) * nCPV ; 
202     relid[2] = (Int_t) TMath::Ceil( id / GetNumberOfCPVPadsZ() ) ;
203     relid[3] = (Int_t) ( id - ( relid[2] - 1 ) * GetNumberOfCPVPadsZ() ) ; 
204   } 
205   else { // it is a PW04 crystal
206
207     relid[0] = phosmodulenumber ;
208     relid[1] = 0 ;
209     id -= ( phosmodulenumber - 1 ) *  GetNPhi() * GetNZ() ; 
210     relid[2] = (Int_t)TMath::Ceil( id / GetNZ() )  ;
211     relid[3] = (Int_t)( id - ( relid[2] - 1 ) * GetNZ() ) ; 
212   } 
213   return rv ; 
214 }
215
216 //____________________________________________________________________________  
217 void AliPHOSGeometry::EmcModuleCoverage(const Int_t mod, Double_t & tm, Double_t & tM, Double_t & pm, Double_t & pM, Option_t * opt) const 
218 {
219   // calculates the angular coverage in theta and phi of one EMC (=PHOS) module
220
221  Double_t conv ; 
222   if ( opt == Radian() ) 
223     conv = 1. ; 
224   else if ( opt == Degre() )
225     conv = 180. / TMath::Pi() ; 
226   else {
227     Warning("EmcModuleCoverage", "%s unknown option; result in radian", opt) ; 
228     conv = 1. ;
229       }
230
231   Float_t phi = GetPHOSAngle(mod) *  (TMath::Pi() / 180.)  ;  
232   Float_t y0  = GetIPtoCrystalSurface() ; 
233   Float_t x0  = GetCellStep()*GetNPhi() ;
234   Float_t z0  = GetCellStep()*GetNZ();
235   Double_t angle = TMath::ATan( x0 / y0 / 2 ) ;
236   phi = phi + 1.5 * TMath::Pi() ; // to follow the convention of the particle generator(PHOS is between 220 and 320 deg.)
237   Double_t max  = phi - angle ;
238   Double_t min   = phi + angle ;
239   pM = TMath::Max(max, min) * conv ;
240   pm = TMath::Min(max, min) * conv ; 
241   
242   angle =  TMath::ATan( z0 /  y0  / 2 ) ;
243   max  = TMath::Pi() / 2.  + angle ; // to follow the convention of the particle generator(PHOS is at 90 deg.)
244   min  = TMath::Pi() / 2.  - angle ;
245   tM = TMath::Max(max, min) * conv ;
246   tm = TMath::Min(max, min) * conv ; 
247  
248 }
249
250 //____________________________________________________________________________  
251 void AliPHOSGeometry::EmcXtalCoverage(Double_t & theta, Double_t & phi, Option_t * opt) const
252 {
253   // calculates the angular coverage in theta and phi of a single crystal in a EMC(=PHOS) module
254
255   Double_t conv ; 
256   if ( opt == Radian() ) 
257     conv = 1. ; 
258   else if ( opt == Degre() )
259     conv = 180. / TMath::Pi() ; 
260   else {
261     Warning("EmcXtalCoverage", "%s unknown option; result in radian", opt) ;  
262     conv = 1. ;
263       }
264
265   Float_t y0  = GetIPtoCrystalSurface() ; 
266   theta = 2 * TMath::ATan( GetCrystalSize(2) / (2 * y0) ) * conv ;
267   phi   = 2 * TMath::ATan( GetCrystalSize(0) / (2 * y0) ) * conv ;
268 }
269  
270
271 //____________________________________________________________________________
272 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos, TMatrix & gmat) const
273 {
274   // Calculates the coordinates of a RecPoint and the error matrix in the ALICE global coordinate system
275  
276   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
277   TVector3 localposition ;
278
279   tmpPHOS->GetLocalPosition(gpos) ;
280
281
282   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
283     {  gpos.SetY( - GetIPtoCrystalSurface()) ;  
284
285     }
286   else
287     { // it is a CPV
288       gpos.SetY(- GetIPtoUpperCPVsurface()  ) ; 
289     }  
290
291   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
292   Double_t const kRADDEG = 180.0 / kPI ;
293   Float_t rphi          = phi / kRADDEG ; 
294   
295   TRotation rot ;
296   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
297   
298   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
299   gpos.Transform(rot) ; // rotate the baby 
300
301 }
302
303 //____________________________________________________________________________
304 void AliPHOSGeometry::GetGlobal(const AliRecPoint* RecPoint, TVector3 & gpos) const 
305 {
306   // Calculates the coordinates of a RecPoint in the ALICE global coordinate system 
307
308   AliPHOSRecPoint * tmpPHOS = (AliPHOSRecPoint *) RecPoint ;  
309   TVector3 localposition ;
310   tmpPHOS->GetLocalPosition(gpos) ;
311
312
313   if ( tmpPHOS->IsEmc() ) // it is a EMC crystal 
314     {  gpos.SetY( - GetIPtoCrystalSurface()  ) ;  
315     }
316   else
317     { // it is a CPV
318           gpos.SetY(- GetIPtoUpperCPVsurface()  ) ; 
319     }  
320
321   Float_t phi           = GetPHOSAngle( tmpPHOS->GetPHOSMod()) ; 
322   Double_t const kRADDEG = 180.0 / kPI ;
323   Float_t rphi          = phi / kRADDEG ; 
324   
325   TRotation rot ;
326   rot.RotateZ(-rphi) ; // a rotation around Z by angle  
327   
328   TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
329   gpos.Transform(rot) ; // rotate the baby 
330 }
331
332 //____________________________________________________________________________
333 void AliPHOSGeometry::ImpactOnEmc(const Double_t theta, const Double_t phi, Int_t & ModuleNumber, Double_t & z, Double_t & x) const
334 {
335   // calculates the impact coordinates on PHOS of a neutral particle  
336   // emitted in the direction theta and phi in the ALICE global coordinate system
337
338   // searches for the PHOS EMC module
339   ModuleNumber = 0 ; 
340   Double_t tm, tM, pm, pM ; 
341   Int_t index = 1 ; 
342   while ( ModuleNumber == 0 && index <= GetNModules() ) { 
343     EmcModuleCoverage(index, tm, tM, pm, pM) ; 
344     if ( (theta >= tm && theta <= tM) && (phi >= pm && phi <= pM ) ) 
345       ModuleNumber = index ; 
346     index++ ;    
347   }
348   if ( ModuleNumber != 0 ) {
349     Float_t phi0 =  GetPHOSAngle(ModuleNumber) *  (TMath::Pi() / 180.) + 1.5 * TMath::Pi()  ;  
350     Float_t y0  =  GetIPtoCrystalSurface()  ;   
351     Double_t angle = phi - phi0; 
352     x = y0 * TMath::Tan(angle) ; 
353     angle = theta - TMath::Pi() / 2 ; 
354     z = y0 * TMath::Tan(angle) ; 
355   }
356 }
357
358 //____________________________________________________________________________
359 Bool_t  AliPHOSGeometry::Impact(const TParticle * particle) const 
360 {
361   // Check if a particle being propagates from IP along the straight line impacts EMC
362
363   Bool_t in=kFALSE;
364   Int_t moduleNumber=0;
365   Double_t z,x;
366   ImpactOnEmc(particle->Theta(),particle->Phi(),moduleNumber,z,x);
367   if(moduleNumber) in=kTRUE;
368   else in=kFALSE;
369   return in;
370 }
371
372 //____________________________________________________________________________
373 Bool_t AliPHOSGeometry::RelToAbsNumbering(const Int_t * relid, Int_t &  AbsId) const
374 {
375   // Converts the relative numbering into the absolute numbering
376   // EMCA crystals:
377   //  AbsId = from 1 to fNModules * fNPhi * fNZ
378   // CPV pad:
379   //  AbsId = from N(total PHOS crystals) + 1
380   //          to NCPVModules * fNumberOfCPVPadsPhi * fNumberOfCPVPadsZ
381
382   Bool_t rv = kTRUE ; 
383   
384   if ( relid[1] ==  0 ) {                            // it is a Phos crystal
385     AbsId =
386       ( relid[0] - 1 ) * GetNPhi() * GetNZ()         // the offset of PHOS modules
387       + ( relid[2] - 1 ) * GetNZ()                   // the offset along phi
388       +   relid[3] ;                                 // the offset along z
389   }
390   else { // it is a CPV pad
391     AbsId =    GetNPhi() * GetNZ() *  GetNModules()         // the offset to separate EMCA crystals from CPV pads
392       + ( relid[0] - 1 ) * GetNumberOfCPVPadsPhi() * GetNumberOfCPVPadsZ()   // the pads offset of PHOS modules 
393       + ( relid[2] - 1 ) * GetNumberOfCPVPadsZ()                             // the pads offset of a CPV row
394       +   relid[3] ;                                                         // the column number
395   }
396   
397   return rv ; 
398 }
399
400 //____________________________________________________________________________
401 void AliPHOSGeometry::RelPosToAbsId(const Int_t module , const Double_t x, const Double_t z, Int_t & AbsId)const{
402   // Converts local PHOS-module (x, z) coordinates to absId 
403
404   if(!module){
405     AbsId = 0 ;
406     return ;
407   }
408   
409   Int_t relid[4] ;
410   relid[0] = module ;
411   relid[1] = 0 ;
412   relid[2] = static_cast<Int_t>(TMath::Ceil(GetNPhi()/2.+ x/GetCellStep()));
413   relid[3] = static_cast<Int_t>(TMath::Ceil(GetNZ()/2.  - z/GetCellStep())) ;
414
415   RelToAbsNumbering(relid,AbsId) ;
416
417 }
418 //____________________________________________________________________________
419 void AliPHOSGeometry::RelPosInAlice(const Int_t id, TVector3 & pos ) const
420 {
421   // Converts the absolute numbering into the global ALICE coordinate system
422   
423     
424     Int_t relid[4] ;
425     
426     AbsToRelNumbering(id , relid) ;
427     
428     Int_t phosmodule = relid[0] ; 
429     
430     Float_t y0 = 0 ; 
431     
432     if ( relid[1] == 0 )  // it is a PbW04 crystal 
433       y0 =  - GetIPtoCrystalSurface() ;  
434     else
435       y0 =  - GetIPtoUpperCPVsurface() ; 
436
437     Float_t x, z ; 
438     RelPosInModule(relid, x, z) ; 
439     
440     pos.SetX(x) ;
441     pos.SetZ(z) ;
442     pos.SetY(y0) ;
443     
444     Float_t phi           = GetPHOSAngle( phosmodule) ; 
445     Double_t const kRADDEG = 180.0 / kPI ;
446     Float_t rphi          = phi / kRADDEG ; 
447     
448     TRotation rot ;
449     rot.RotateZ(-rphi) ; // a rotation around Z by angle  
450     
451     TRotation dummy = rot.Invert() ;  // to transform from original frame to rotate frame
452     
453     pos.Transform(rot) ; // rotate the baby 
454
455
456 //____________________________________________________________________________
457 void AliPHOSGeometry::RelPosInModule(const Int_t * relid, Float_t & x, Float_t & z) const 
458 {
459   // Converts the relative numbering into the local PHOS-module (x, z) coordinates
460   // Note: sign of z differs from that in the previous version (Yu.Kharlov, 12 Oct 2000)
461   
462   Int_t row        = relid[2] ; //offset along x axis
463   Int_t column     = relid[3] ; //offset along z axis
464
465   
466   if ( relid[1] == 0 ) { // its a PbW04 crystal
467     x = - ( GetNPhi()/2. - row    + 0.5 ) *  GetCellStep() ; // position of Xtal with respect
468     z =   ( GetNZ()  /2. - column + 0.5 ) *  GetCellStep() ; // of center of PHOS module  
469   }  
470   else  {    
471     x = - ( GetNumberOfCPVPadsPhi()/2. - row    - 0.5 ) * GetPadSizePhi()  ; // position of pad  with respect
472     z =   ( GetNumberOfCPVPadsZ()  /2. - column - 0.5 ) * GetPadSizeZ()  ; // of center of PHOS module  
473   }
474 }