Changed to Copy(TObject &A) to appease the HP-compiler
[u/mrichter/AliRoot.git] / TRD / AliTRDv1.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 /*
17 $Log$
18 Revision 1.21  2000/06/09 11:10:07  cblume
19 Compiler warnings and coding conventions, next round
20
21 Revision 1.20  2000/06/08 18:32:58  cblume
22 Make code compliant to coding conventions
23
24 Revision 1.19  2000/06/07 16:27:32  cblume
25 Try to remove compiler warnings on Sun and HP
26
27 Revision 1.18  2000/05/08 16:17:27  cblume
28 Merge TRD-develop
29
30 Revision 1.17.2.1  2000/05/08 14:59:16  cblume
31 Made inline function non-virtual. Bug fix in setting sensitive chamber
32
33 Revision 1.17  2000/02/28 19:10:26  cblume
34 Include the new TRD classes
35
36 Revision 1.16.4.1  2000/02/28 18:04:35  cblume
37 Change to new hit version, introduce geometry class, and move digitization and clustering to AliTRDdigitizer/AliTRDclusterizerV1
38
39 Revision 1.16  1999/11/05 22:50:28  fca
40 Do not use Atan, removed from ROOT too
41
42 Revision 1.15  1999/11/02 17:20:19  fca
43 initialise nbytes before using it
44
45 Revision 1.14  1999/11/02 17:15:54  fca
46 Correct ansi scoping not accepted by HP compilers
47
48 Revision 1.13  1999/11/02 17:14:51  fca
49 Correct ansi scoping not accepted by HP compilers
50
51 Revision 1.12  1999/11/02 16:35:56  fca
52 New version of TRD introduced
53
54 Revision 1.11  1999/11/01 20:41:51  fca
55 Added protections against using the wrong version of FRAME
56
57 Revision 1.10  1999/09/29 09:24:35  fca
58 Introduction of the Copyright and cvs Log
59
60 */
61
62 ///////////////////////////////////////////////////////////////////////////////
63 //                                                                           //
64 //  Transition Radiation Detector version 2 -- slow simulator                //
65 //                                                                           //
66 //Begin_Html
67 /*
68 <img src="picts/AliTRDfullClass.gif">
69 */
70 //End_Html
71 //                                                                           //
72 //                                                                           //
73 ///////////////////////////////////////////////////////////////////////////////
74
75 #include <TMath.h>
76 #include <TVector.h>
77 #include <TRandom.h>
78
79 #include "AliRun.h"
80 #include "AliMC.h"
81 #include "AliConst.h"
82
83 #include "AliTRDv1.h"
84 #include "AliTRDmatrix.h"
85 #include "AliTRDgeometry.h"
86
87 ClassImp(AliTRDv1)
88
89  
90 //_____________________________________________________________________________
91 AliTRDv1::AliTRDv1():AliTRD()
92 {
93   //
94   // Default constructor
95   //
96
97   fIdSens          =  0;
98
99   fIdChamber1      =  0;
100   fIdChamber2      =  0;
101   fIdChamber3      =  0;
102
103   fSensSelect      =  0;
104   fSensPlane       = -1;
105   fSensChamber     = -1;
106   fSensSector      = -1;
107   fSensSectorRange =  0;
108
109   fDeltaE          = NULL;
110
111 }
112
113 //_____________________________________________________________________________
114 AliTRDv1::AliTRDv1(const char *name, const char *title) 
115          :AliTRD(name, title) 
116 {
117   //
118   // Standard constructor for Transition Radiation Detector version 1
119   //
120
121   fIdSens          =  0;
122
123   fIdChamber1      =  0;
124   fIdChamber2      =  0;
125   fIdChamber3      =  0;
126
127   fSensSelect      =  0;
128   fSensPlane       = -1;
129   fSensChamber     = -1;
130   fSensSector      = -1;
131   fSensSectorRange =  0;
132
133   fDeltaE          = NULL;
134
135   SetBufferSize(128000);
136
137 }
138
139 //_____________________________________________________________________________
140 AliTRDv1::AliTRDv1(const AliTRDv1 &trd)
141 {
142   //
143   // Copy constructor
144   //
145
146   ((AliTRDv1 &) trd).Copy(*this);
147
148 }
149
150 //_____________________________________________________________________________
151 AliTRDv1::~AliTRDv1()
152 {
153   //
154   // AliTRDv1 destructor
155   //
156
157   if (fDeltaE) delete fDeltaE;
158
159 }
160  
161 //_____________________________________________________________________________
162 AliTRDv1 &AliTRDv1::operator=(const AliTRDv1 &trd)
163 {
164   //
165   // Assignment operator
166   //
167
168   if (this != &trd) ((AliTRDv1 &) trd).Copy(*this);
169   return *this;
170
171 }
172  
173 //_____________________________________________________________________________
174 void AliTRDv1::Copy(TObject &trd)
175 {
176   //
177   // Copy function
178   //
179
180   ((AliTRDv1 &) trd).fIdSens          = fIdSens;
181
182   ((AliTRDv1 &) trd).fIdChamber1      = fIdChamber1;
183   ((AliTRDv1 &) trd).fIdChamber2      = fIdChamber2;
184   ((AliTRDv1 &) trd).fIdChamber3      = fIdChamber3;
185
186   ((AliTRDv1 &) trd).fSensSelect      = fSensSelect;
187   ((AliTRDv1 &) trd).fSensPlane       = fSensPlane;
188   ((AliTRDv1 &) trd).fSensChamber     = fSensChamber;
189   ((AliTRDv1 &) trd).fSensSector      = fSensSector;
190   ((AliTRDv1 &) trd).fSensSectorRange = fSensSectorRange;
191
192   ((AliTRDv1 &) trd).fDeltaE          = NULL;
193
194 }
195
196 //_____________________________________________________________________________
197 void AliTRDv1::CreateGeometry()
198 {
199   //
200   // Create the GEANT geometry for the Transition Radiation Detector - Version 1
201   // This version covers the full azimuth. 
202   //
203
204   // Check that FRAME is there otherwise we have no place where to put the TRD
205   AliModule* frame = gAlice->GetModule("FRAME");
206   if (!frame) return;
207
208   // Define the chambers
209   AliTRD::CreateGeometry();
210
211 }
212
213 //_____________________________________________________________________________
214 void AliTRDv1::CreateMaterials()
215 {
216   //
217   // Create materials for the Transition Radiation Detector version 1
218   //
219
220   AliTRD::CreateMaterials();
221
222 }
223
224 //_____________________________________________________________________________
225 void AliTRDv1::Init() 
226 {
227   //
228   // Initialise Transition Radiation Detector after geometry has been built.
229   //
230
231   AliTRD::Init();
232
233   printf("          Slow simulator\n\n");
234   if (fSensSelect) {
235     if (fSensPlane   >= 0)
236       printf("          Only plane %d is sensitive\n",fSensPlane);
237     if (fSensChamber >= 0)   
238       printf("          Only chamber %d is sensitive\n",fSensChamber);
239     if (fSensSector  >= 0) {
240       Int_t sens1  = fSensSector;
241       Int_t sens2  = fSensSector + fSensSectorRange;
242             sens2 -= ((Int_t) (sens2 / kNsect)) * kNsect;
243       printf("          Only sectors %d - %d are sensitive\n",sens1,sens2-1);
244     }
245   }
246   printf("\n");
247
248   // First ionization potential (eV) for the gas mixture (90% Xe + 10% CO2)
249   const Float_t kPoti = 12.1;
250   // Maximum energy (50 keV);
251   const Float_t kEend = 50000.0;
252   // Ermilova distribution for the delta-ray spectrum
253   Float_t poti = TMath::Log(kPoti);
254   Float_t eEnd = TMath::Log(kEend);
255   fDeltaE  = new TF1("deltae",Ermilova,poti,eEnd,0);
256
257   // Identifier of the sensitive volume (drift region)
258   fIdSens     = gMC->VolId("UL05");
259
260   // Identifier of the TRD-driftchambers
261   fIdChamber1 = gMC->VolId("UCIO");
262   fIdChamber2 = gMC->VolId("UCIM");
263   fIdChamber3 = gMC->VolId("UCII");
264
265   for (Int_t i = 0; i < 80; i++) printf("*");
266   printf("\n");
267
268 }
269
270 //_____________________________________________________________________________
271 void AliTRDv1::SetSensPlane(Int_t iplane)
272 {
273   //
274   // Defines the hit-sensitive plane (0-5)
275   //
276
277   if ((iplane < 0) || (iplane > 5)) {
278     printf("Wrong input value: %d\n",iplane);
279     printf("Use standard setting\n");
280     fSensPlane  = -1;
281     fSensSelect =  0;
282     return;
283   }
284
285   fSensSelect = 1;
286   fSensPlane  = iplane;
287
288 }
289
290 //_____________________________________________________________________________
291 void AliTRDv1::SetSensChamber(Int_t ichamber)
292 {
293   //
294   // Defines the hit-sensitive chamber (0-4)
295   //
296
297   if ((ichamber < 0) || (ichamber > 4)) {
298     printf("Wrong input value: %d\n",ichamber);
299     printf("Use standard setting\n");
300     fSensChamber = -1;
301     fSensSelect  =  0;
302     return;
303   }
304
305   fSensSelect  = 1;
306   fSensChamber = ichamber;
307
308 }
309
310 //_____________________________________________________________________________
311 void AliTRDv1::SetSensSector(Int_t isector)
312 {
313   //
314   // Defines the hit-sensitive sector (0-17)
315   //
316
317   SetSensSector(isector,1);
318
319 }
320
321 //_____________________________________________________________________________
322 void AliTRDv1::SetSensSector(Int_t isector, Int_t nsector)
323 {
324   //
325   // Defines a range of hit-sensitive sectors. The range is defined by
326   // <isector> (0-17) as the starting point and <nsector> as the number 
327   // of sectors to be included.
328   //
329
330   if ((isector < 0) || (isector > 17)) {
331     printf("Wrong input value <isector>: %d\n",isector);
332     printf("Use standard setting\n");
333     fSensSector      = -1;
334     fSensSectorRange =  0;
335     fSensSelect      =  0;
336     return;
337   }
338
339   if ((nsector < 1) || (nsector > 18)) {
340     printf("Wrong input value <nsector>: %d\n",nsector);
341     printf("Use standard setting\n");
342     fSensSector      = -1;
343     fSensSectorRange =  0;
344     fSensSelect      =  0;
345     return;
346   }
347
348   fSensSelect      = 1;
349   fSensSector      = isector;
350   fSensSectorRange = nsector;
351
352 }
353
354 //_____________________________________________________________________________
355 void AliTRDv1::StepManager()
356 {
357   //
358   // Slow simulator. Every charged track produces electron cluster as hits 
359   // along its path across the drift volume. The step size is set acording
360   // to Bethe-Bloch. The energy distribution of the delta electrons follows
361   // a spectrum taken from Ermilova et al.
362   //
363
364   Int_t    iIdSens, icSens;
365   Int_t    iIdSpace, icSpace;
366   Int_t    iIdChamber, icChamber;
367   Int_t    pla = 0;
368   Int_t    cha = 0;
369   Int_t    sec = 0;
370   Int_t    iPdg;
371
372   Int_t    det[1];
373
374   Float_t  hits[4];
375   Float_t  random[1];
376   Float_t  charge;
377   Float_t  aMass;
378
379   Double_t pTot;
380   Double_t qTot;
381   Double_t eDelta;
382   Double_t betaGamma, pp;
383
384   TLorentzVector pos, mom;
385   TClonesArray  &lhits = *fHits;
386
387   const Double_t kBig     = 1.0E+12;
388
389   // Ionization energy
390   const Float_t  kWion    = 22.04;
391   // Maximum energy for e+ e- g for the step-size calculation
392   const Float_t  kPTotMax = 0.002;
393   // Plateau value of the energy-loss for electron in xenon
394   // taken from: Allison + Comb, Ann. Rev. Nucl. Sci. (1980), 30, 253
395   //const Double_t kPlateau = 1.70;
396   // the averaged value (26/3/99)
397   const Float_t  kPlateau = 1.55;
398   // dN1/dx|min for the gas mixture (90% Xe + 10% CO2)
399   const Float_t  kPrim    = 48.0;
400   // First ionization potential (eV) for the gas mixture (90% Xe + 10% CO2)
401   const Float_t  kPoti    = 12.1;
402
403   // PDG code electron
404   const Int_t    kPdgElectron = 11;
405
406   // Set the maximum step size to a very large number for all 
407   // neutral particles and those outside the driftvolume
408   gMC->SetMaxStep(kBig); 
409
410   // Use only charged tracks 
411   if (( gMC->TrackCharge()       ) &&
412       (!gMC->IsTrackStop()       ) && 
413       (!gMC->IsTrackDisappeared())) {
414
415     // Inside a sensitive volume?
416     iIdSens = gMC->CurrentVolID(icSens);
417     if (iIdSens == fIdSens) { 
418
419       iIdSpace   = gMC->CurrentVolOffID(4,icSpace  );
420       iIdChamber = gMC->CurrentVolOffID(1,icChamber);
421
422       // Calculate the energy of the delta-electrons
423       eDelta = TMath::Exp(fDeltaE->GetRandom()) - kPoti;
424       eDelta = TMath::Max(eDelta,0.0);
425
426       // The number of secondary electrons created
427       qTot = (Double_t) ((Int_t) (eDelta / kWion) + 1);
428
429       // The hit coordinates and charge
430       gMC->TrackPosition(pos);
431       hits[0] = pos[0];
432       hits[1] = pos[1];
433       hits[2] = pos[2];
434       hits[3] = qTot;
435
436       // The sector number (0 - 17)
437       // The numbering goes clockwise and starts at y = 0
438       Float_t phi = kRaddeg*TMath::ATan2(pos[0],pos[1]);
439       if (phi < 90.) 
440         phi = phi + 270.;
441       else
442         phi = phi -  90.;
443       sec = ((Int_t) (phi / 20));
444
445       // The chamber number 
446       //   0: outer left
447       //   1: middle left
448       //   2: inner
449       //   3: middle right
450       //   4: outer right
451       if      (iIdChamber == fIdChamber1)
452         cha = (hits[2] < 0 ? 0 : 4);
453       else if (iIdChamber == fIdChamber2)       
454         cha = (hits[2] < 0 ? 1 : 3);
455       else if (iIdChamber == fIdChamber3)       
456         cha = 2;
457
458       // The plane number
459       // The numbering starts at the innermost plane
460       pla = icChamber - TMath::Nint((Float_t) (icChamber / 7)) * 6 - 1;
461
462       // Check on selected volumes
463       Int_t addthishit = 1;
464       if (fSensSelect) {
465         if ((fSensPlane   >= 0) && (pla != fSensPlane  )) addthishit = 0;
466         if ((fSensChamber >= 0) && (cha != fSensChamber)) addthishit = 0;
467         if (fSensSector  >= 0) {
468           Int_t sens1  = fSensSector;
469           Int_t sens2  = fSensSector + fSensSectorRange;
470                 sens2 -= ((Int_t) (sens2 / kNsect)) * kNsect;
471           if (sens1 < sens2) {
472             if ((sec < sens1) || (sec >= sens2)) addthishit = 0;
473           }
474           else {
475             if ((sec < sens1) && (sec >= sens2)) addthishit = 0;
476           }
477         }
478       }
479
480       // Add this hit
481       if (addthishit) {
482
483         det[0] = fGeometry->GetDetector(pla,cha,sec);
484         new(lhits[fNhits++]) AliTRDhit(fIshunt
485                                       ,gAlice->CurrentTrack()
486                                       ,det
487                                       ,hits);
488
489         // The energy loss according to Bethe Bloch
490         gMC->TrackMomentum(mom);
491         pTot = mom.Rho();
492         iPdg = TMath::Abs(gMC->TrackPid());
493         if ( (iPdg != kPdgElectron) ||
494             ((iPdg == kPdgElectron) && (pTot < kPTotMax))) {
495           aMass     = gMC->TrackMass();
496           betaGamma = pTot / aMass;
497           pp        = kPrim * BetheBloch(betaGamma);
498           // Take charge > 1 into account
499           charge = gMC->TrackCharge();
500           if (TMath::Abs(charge) > 1) pp = pp * charge*charge;
501         }
502         // Electrons above 20 Mev/c are at the plateau
503         else {
504           pp = kPrim * kPlateau;
505         }
506       
507         // Calculate the maximum step size for the next tracking step
508         if (pp > 0) {
509           do 
510             gMC->Rndm(random,1);
511           while ((random[0] == 1.) || (random[0] == 0.));
512           gMC->SetMaxStep( - TMath::Log(random[0]) / pp);
513         }
514
515       }
516       else {
517         // set step size to maximal value
518         gMC->SetMaxStep(kBig); 
519       }
520
521     }
522
523   }
524
525 }
526
527 //_____________________________________________________________________________
528 Double_t AliTRDv1::BetheBloch(Double_t bg) 
529 {
530   //
531   // Parametrization of the Bethe-Bloch-curve
532   // The parametrization is the same as for the TPC and is taken from Lehrhaus.
533   //
534
535   // This parameters have been adjusted to averaged values from GEANT
536   const Double_t kP1 = 7.17960e-02;
537   const Double_t kP2 = 8.54196;
538   const Double_t kP3 = 1.38065e-06;
539   const Double_t kP4 = 5.30972;
540   const Double_t kP5 = 2.83798;
541
542   // This parameters have been adjusted to Xe-data found in:
543   // Allison & Cobb, Ann. Rev. Nucl. Sci. (1980), 30, 253
544   //const Double_t kP1 = 0.76176E-1;
545   //const Double_t kP2 = 10.632;
546   //const Double_t kP3 = 3.17983E-6;
547   //const Double_t kP4 = 1.8631;
548   //const Double_t kP5 = 1.9479;
549
550   if (bg > 0) {
551     Double_t yy = bg / TMath::Sqrt(1. + bg*bg);
552     Double_t aa = TMath::Power(yy,kP4);
553     Double_t bb = TMath::Power((1./bg),kP5);
554              bb = TMath::Log(kP3 + bb);
555     return ((kP2 - aa - bb)*kP1 / aa);
556   }
557   else
558     return 0;
559
560 }
561
562 //_____________________________________________________________________________
563 Double_t Ermilova(Double_t *x, Double_t *)
564 {
565   //
566   // Calculates the delta-ray energy distribution according to Ermilova.
567   // Logarithmic scale !
568   //
569
570   Double_t energy;
571   Double_t dpos;
572   Double_t dnde;
573
574   Int_t    pos1, pos2;
575
576   const Int_t kNv = 31;
577
578   Float_t vxe[kNv] = { 2.3026, 2.9957, 3.4012, 3.6889, 3.9120  
579                      , 4.0943, 4.2485, 4.3820, 4.4998, 4.6052
580                      , 4.7005, 5.0752, 5.2983, 5.7038, 5.9915
581                      , 6.2146, 6.5221, 6.9078, 7.3132, 7.6009
582                      , 8.0064, 8.5172, 8.6995, 8.9872, 9.2103
583                      , 9.4727, 9.9035,10.3735,10.5966,10.8198
584                      ,11.5129 };
585
586   Float_t vye[kNv] = { 80.0  , 31.0  , 23.3  , 21.1  , 21.0
587                      , 20.9  , 20.8  , 20.0  , 16.0  , 11.0
588                      ,  8.0  ,  6.0  ,  5.2  ,  4.6  ,  4.0
589                      ,  3.5  ,  3.0  ,  1.4  ,  0.67 ,  0.44
590                      ,  0.3  ,  0.18 ,  0.12 ,  0.08 ,  0.056
591                      ,  0.04 ,  0.023,  0.015,  0.011,  0.01
592                      ,  0.004 };
593
594   energy = x[0];
595
596   // Find the position 
597   pos1 = pos2 = 0;
598   dpos = 0;
599   do {
600     dpos = energy - vxe[pos2++];
601   } 
602   while (dpos > 0);
603   pos2--; 
604   if (pos2 > kNv) pos2 = kNv;
605   pos1 = pos2 - 1;
606
607   // Differentiate between the sampling points
608   dnde = (vye[pos1] - vye[pos2]) / (vxe[pos2] - vxe[pos1]);
609
610   return dnde;
611
612 }