1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////////
20 // Transition Radiation Detector version 1 -- slow simulator //
24 <img src="picts/AliTRDfullClass.gif">
29 ///////////////////////////////////////////////////////////////////////////////
34 #include <TLorentzVector.h>
38 #include <TVirtualMC.h>
44 #include "AliTRDgeometry.h"
45 #include "AliTRDhit.h"
46 #include "AliTRDsim.h"
51 //_____________________________________________________________________________
52 AliTRDv1::AliTRDv1():AliTRD()
55 // Default constructor
69 fTypeOfStepManager = 1;
73 //_____________________________________________________________________________
74 AliTRDv1::AliTRDv1(const char *name, const char *title)
78 // Standard constructor for Transition Radiation Detector version 1
91 fTypeOfStepManager = 1;
93 SetBufferSize(128000);
97 //_____________________________________________________________________________
98 AliTRDv1::AliTRDv1(const AliTRDv1 &trd):AliTRD(trd)
104 ((AliTRDv1 &) trd).Copy(*this);
108 //_____________________________________________________________________________
109 AliTRDv1::~AliTRDv1()
112 // AliTRDv1 destructor
115 if (fDeltaE) delete fDeltaE;
116 if (fDeltaG) delete fDeltaG;
121 //_____________________________________________________________________________
122 AliTRDv1 &AliTRDv1::operator=(const AliTRDv1 &trd)
125 // Assignment operator
128 if (this != &trd) ((AliTRDv1 &) trd).Copy(*this);
133 //_____________________________________________________________________________
134 void AliTRDv1::Copy(TObject &trd) const
136 printf("void AliTRDv1::Copy(TObject &trd) const\n");
141 ((AliTRDv1 &) trd).fSensSelect = fSensSelect;
142 ((AliTRDv1 &) trd).fSensPlane = fSensPlane;
143 ((AliTRDv1 &) trd).fSensChamber = fSensChamber;
144 ((AliTRDv1 &) trd).fSensSector = fSensSector;
145 ((AliTRDv1 &) trd).fSensSectorRange = fSensSectorRange;
147 ((AliTRDv1 &) trd).fTypeOfStepManager = fTypeOfStepManager;
148 ((AliTRDv1 &) trd).fStepSize = fStepSize;
150 fDeltaE->Copy(*((AliTRDv1 &) trd).fDeltaE);
151 fDeltaG->Copy(*((AliTRDv1 &) trd).fDeltaG);
152 fTR->Copy(*((AliTRDv1 &) trd).fTR);
156 //_____________________________________________________________________________
157 void AliTRDv1::CreateGeometry()
160 // Create the GEANT geometry for the Transition Radiation Detector - Version 1
161 // This version covers the full azimuth.
164 // Check that FRAME is there otherwise we have no place where to put the TRD
165 AliModule* frame = gAlice->GetModule("FRAME");
168 // Define the chambers
169 AliTRD::CreateGeometry();
173 //_____________________________________________________________________________
174 void AliTRDv1::CreateMaterials()
177 // Create materials for the Transition Radiation Detector version 1
180 AliTRD::CreateMaterials();
184 //_____________________________________________________________________________
185 void AliTRDv1::CreateTRhit(Int_t det)
188 // Creates an electron cluster from a TR photon.
189 // The photon is assumed to be created a the end of the radiator. The
190 // distance after which it deposits its energy takes into account the
191 // absorbtion of the entrance window and of the gas mixture in drift
196 const Int_t kPdgElectron = 11;
199 const Float_t kWion = 22.57;
201 // Maximum number of TR photons per track
202 const Int_t kNTR = 50;
204 TLorentzVector mom, pos;
206 // Create TR at the entrance of the chamber
207 if (gMC->IsTrackEntering()) {
209 // Create TR only for electrons
210 Int_t iPdg = gMC->TrackPid();
211 if (TMath::Abs(iPdg) != kPdgElectron) return;
217 gMC->TrackMomentum(mom);
218 Float_t pTot = mom.Rho();
219 fTR->CreatePhotons(iPdg,pTot,nTR,eTR);
221 AliFatal(Form("Boundary error: nTR = %d, kNTR = %d",nTR,kNTR));
224 // Loop through the TR photons
225 for (Int_t iTR = 0; iTR < nTR; iTR++) {
227 Float_t energyMeV = eTR[iTR] * 0.001;
228 Float_t energyeV = eTR[iTR] * 1000.0;
229 Float_t absLength = 0;
232 // Take the absorbtion in the entrance window into account
233 Double_t muMy = fTR->GetMuMy(energyMeV);
234 sigma = muMy * fFoilDensity;
236 absLength = gRandom->Exp(1.0/sigma);
237 if (absLength < AliTRDgeometry::MyThick()) continue;
243 // The absorbtion cross sections in the drift gas
244 // Gas-mixture (Xe/CO2)
245 Double_t muXe = fTR->GetMuXe(energyMeV);
246 Double_t muCO = fTR->GetMuCO(energyMeV);
247 sigma = (0.85 * muXe + 0.15 * muCO) * fGasDensity * fTR->GetTemp();
249 // The distance after which the energy of the TR photon
252 absLength = gRandom->Exp(1.0/sigma);
253 if (absLength > (AliTRDgeometry::DrThick()
254 + AliTRDgeometry::AmThick())) {
262 // The position of the absorbtion
264 gMC->TrackPosition(pos);
265 posHit[0] = pos[0] + mom[0] / pTot * absLength;
266 posHit[1] = pos[1] + mom[1] / pTot * absLength;
267 posHit[2] = pos[2] + mom[2] / pTot * absLength;
270 Int_t q = ((Int_t) (energyeV / kWion));
272 // Add the hit to the array. TR photon hits are marked
273 // by negative charge
274 AddHit(gAlice->GetMCApp()->GetCurrentTrackNumber(),det,posHit,-q,kTRUE);
282 //_____________________________________________________________________________
283 void AliTRDv1::Init()
286 // Initialise Transition Radiation Detector after geometry has been built.
291 AliDebug(1,"Slow simulator\n");
294 AliInfo(Form("Only plane %d is sensitive"));
295 if (fSensChamber >= 0)
296 AliInfo(Form("Only chamber %d is sensitive",fSensChamber));
297 if (fSensSector >= 0) {
298 Int_t sens1 = fSensSector;
299 Int_t sens2 = fSensSector + fSensSectorRange;
300 sens2 -= ((Int_t) (sens2 / AliTRDgeometry::Nsect()))
301 * AliTRDgeometry::Nsect();
302 AliInfo(Form("Only sectors %d - %d are sensitive\n",sens1,sens2-1));
306 AliInfo("TR simulation on")
308 AliInfo("TR simulation off");
310 // First ionization potential (eV) for the gas mixture (90% Xe + 10% CO2)
311 const Float_t kPoti = 12.1;
312 // Maximum energy (50 keV);
313 const Float_t kEend = 50000.0;
314 // Ermilova distribution for the delta-ray spectrum
315 Float_t poti = TMath::Log(kPoti);
316 Float_t eEnd = TMath::Log(kEend);
318 // Ermilova distribution for the delta-ray spectrum
319 fDeltaE = new TF1("deltae" ,Ermilova ,poti,eEnd,0);
321 // Geant3 distribution for the delta-ray spectrum
322 fDeltaG = new TF1("deltag",IntSpecGeant,2.421257,28.536469,0);
324 AliDebug(1,"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
328 //_____________________________________________________________________________
329 AliTRDsim *AliTRDv1::CreateTR()
332 // Enables the simulation of TR
335 fTR = new AliTRDsim();
340 //_____________________________________________________________________________
341 void AliTRDv1::SetSensPlane(Int_t iplane)
344 // Defines the hit-sensitive plane (0-5)
347 if ((iplane < 0) || (iplane > 5)) {
348 AliWarning(Form("Wrong input value:%d",iplane));
349 AliWarning("Use standard setting");
360 //_____________________________________________________________________________
361 void AliTRDv1::SetSensChamber(Int_t ichamber)
364 // Defines the hit-sensitive chamber (0-4)
367 if ((ichamber < 0) || (ichamber > 4)) {
368 AliWarning(Form("Wrong input value: %d",ichamber));
369 AliWarning("Use standard setting");
376 fSensChamber = ichamber;
380 //_____________________________________________________________________________
381 void AliTRDv1::SetSensSector(Int_t isector)
384 // Defines the hit-sensitive sector (0-17)
387 SetSensSector(isector,1);
391 //_____________________________________________________________________________
392 void AliTRDv1::SetSensSector(Int_t isector, Int_t nsector)
395 // Defines a range of hit-sensitive sectors. The range is defined by
396 // <isector> (0-17) as the starting point and <nsector> as the number
397 // of sectors to be included.
400 if ((isector < 0) || (isector > 17)) {
401 AliWarning(Form("Wrong input value <isector>: %d",isector));
402 AliWarning("Use standard setting");
404 fSensSectorRange = 0;
409 if ((nsector < 1) || (nsector > 18)) {
410 AliWarning(Form("Wrong input value <nsector>: %d",nsector));
411 AliWarning("Use standard setting");
413 fSensSectorRange = 0;
419 fSensSector = isector;
420 fSensSectorRange = nsector;
424 //_____________________________________________________________________________
425 void AliTRDv1::StepManager()
428 // Slow simulator. Every charged track produces electron cluster as hits
429 // along its path across the drift volume.
432 switch (fTypeOfStepManager) {
433 case 0 : StepManagerErmilova(); break; // 0 is Ermilova
434 case 1 : StepManagerGeant(); break; // 1 is Geant
435 case 2 : StepManagerFixedStep(); break; // 2 is fixed step
436 default : AliWarning("Not a valid Step Manager.");
441 //_____________________________________________________________________________
442 void AliTRDv1::SelectStepManager(Int_t t)
445 // Selects a step manager type:
448 // 2 - Fixed step size
452 AliWarning("Sorry, Geant parametrization step manager is not implemented yet. Please ask K.Oyama for detail.");
455 fTypeOfStepManager = t;
456 AliInfo(Form("Step Manager type %d was selected",fTypeOfStepManager));
460 //_____________________________________________________________________________
461 void AliTRDv1::StepManagerGeant()
464 // Slow simulator. Every charged track produces electron cluster as hits
465 // along its path across the drift volume. The step size is set acording
466 // to Bethe-Bloch. The energy distribution of the delta electrons follows
467 // a spectrum taken from Geant3.
482 Double_t betaGamma, pp;
485 Bool_t drRegion = kFALSE;
486 Bool_t amRegion = kFALSE;
489 TString cIdSensDr = "J";
490 TString cIdSensAm = "K";
491 Char_t cIdChamber[3];
494 TLorentzVector pos, mom;
496 const Int_t kNplan = AliTRDgeometry::Nplan();
497 const Int_t kNcham = AliTRDgeometry::Ncham();
498 const Int_t kNdetsec = kNplan * kNcham;
500 const Double_t kBig = 1.0E+12; // Infinitely big
501 const Float_t kWion = 22.57; // Ionization energy
502 const Float_t kPTotMaxEl = 0.002; // Maximum momentum for e+ e- g
504 // Minimum energy for the step size adjustment
505 const Float_t kEkinMinStep = 1.0e-5;
506 // energy threshold for production of delta electrons
507 const Float_t kECut = 1.0e4;
508 // Parameters entering the parametrized range for delta electrons
509 const float ra=5.37E-4, rb=0.9815, rc=3.123E-3;
510 // Gas density -> To be made user adjustable !
511 const float rho=0.004945 ; //[0.85*0.00549+0.15*0.00186 (Xe-CO2 85-15)]
513 // Plateau value of the energy-loss for electron in xenon
514 // taken from: Allison + Comb, Ann. Rev. Nucl. Sci. (1980), 30, 253
515 //const Double_t kPlateau = 1.70;
516 // the averaged value (26/3/99)
517 const Float_t kPlateau = 1.55;
519 const Float_t kPrim = 19.34; // dN1/dx|min for the gas mixture (90% Xe + 10% CO2)
520 // First ionization potential (eV) for the gas mixture (90% Xe + 10% CO2)
521 const Float_t kPoti = 12.1;
523 const Int_t kPdgElectron = 11; // PDG code electron
525 // Set the maximum step size to a very large number for all
526 // neutral particles and those outside the driftvolume
527 gMC->SetMaxStep(kBig);
529 // Use only charged tracks
530 if (( gMC->TrackCharge() ) &&
531 (!gMC->IsTrackStop() ) &&
532 (!gMC->IsTrackDisappeared())) {
534 // Inside a sensitive volume?
537 cIdCurrent = gMC->CurrentVolName();
538 if (cIdSensDr == cIdCurrent[1]) {
541 if (cIdSensAm == cIdCurrent[1]) {
544 if (drRegion || amRegion) {
546 // The hit coordinates and charge
547 gMC->TrackPosition(pos);
552 // The sector number (0 - 17)
553 // The numbering goes clockwise and starts at y = 0
554 Float_t phi = kRaddeg*TMath::ATan2(pos[0],pos[1]);
559 sec = ((Int_t) (phi / 20));
561 // The plane and chamber number
562 cIdChamber[0] = cIdCurrent[2];
563 cIdChamber[1] = cIdCurrent[3];
564 Int_t idChamber = (atoi(cIdChamber) % kNdetsec);
565 cha = kNcham - ((Int_t) idChamber / kNplan) - 1;
566 pla = ((Int_t) idChamber % kNplan);
568 // Check on selected volumes
569 Int_t addthishit = 1;
571 if ((fSensPlane >= 0) && (pla != fSensPlane )) addthishit = 0;
572 if ((fSensChamber >= 0) && (cha != fSensChamber)) addthishit = 0;
573 if (fSensSector >= 0) {
574 Int_t sens1 = fSensSector;
575 Int_t sens2 = fSensSector + fSensSectorRange;
576 sens2 -= ((Int_t) (sens2 / AliTRDgeometry::Nsect()))
577 * AliTRDgeometry::Nsect();
579 if ((sec < sens1) || (sec >= sens2)) addthishit = 0;
582 if ((sec < sens1) && (sec >= sens2)) addthishit = 0;
590 // The detector number
591 det = fGeometry->GetDetector(pla,cha,sec);
593 // Special hits only in the drift region
595 // Create a track reference at the entrance and
596 // exit of each chamber that contain the
597 // momentum components of the particle
598 if (gMC->IsTrackEntering() || gMC->IsTrackExiting()) {
599 gMC->TrackMomentum(mom);
600 AddTrackReference(gAlice->GetMCApp()->GetCurrentTrackNumber());
603 if (gMC->IsTrackEntering() && !gMC->IsNewTrack()) {
604 // determine if hit belong to primary track
605 fPrimaryTrackPid=gAlice->GetMCApp()->GetCurrentTrackNumber();
606 //determine track length when entering the detector
607 fTrackLength0=gMC->TrackLength();
610 // Create the hits from TR photons
611 if (fTR) CreateTRhit(det);
614 // Calculate the energy of the delta-electrons
615 // modified by Alex Bercuci (A.Bercuci@gsi.de) on 26.01.06
616 // take into account correlation with the underlying GEANT tracking
618 // http://www-linux.gsi.de/~abercuci/Contributions/TRD/index.html
620 // determine the most significant process (last on the processes list)
621 // which caused this hit
623 gMC->StepProcesses(processes);
624 int nofprocesses=processes.GetSize(), pid;
625 if(!nofprocesses) pid=0;
626 else pid= processes[nofprocesses-1];
628 // generate Edep according to GEANT parametrisation
629 eDelta =TMath::Exp(fDeltaG->GetRandom()) - kPoti;
630 eDelta=TMath::Max(eDelta,0.0);
632 float range=gMC->TrackLength()-fTrackLength0;
633 // merge GEANT tracker information with localy cooked one
634 if(gAlice->GetMCApp()->GetCurrentTrackNumber()==fPrimaryTrackPid) {
635 // printf("primary pid=%d eDelta=%f\n",pid,eDelta);
638 pr_range=ra*eDelta*.001*(1.-rb/(1.+rc*eDelta*0.001))/rho;
639 if(pr_range>=(3.7-range)) eDelta*=.1;
642 if(eDelta<kECut) eDelta*=.5;
644 pr_range=ra*eDelta*.001*(1.-rb/(1.+rc*eDelta*0.001))/rho;
645 if(pr_range>=((AliTRDgeometry::DrThick()
646 + AliTRDgeometry::AmThick())-range)) eDelta*=.05;
652 // Generate the electron cluster size
653 if(eDelta==0.) qTot=0;
654 else qTot = ((Int_t) (eDelta / kWion) + 1);
655 // Create a new dEdx hit
656 AddHit(gAlice->GetMCApp()->GetCurrentTrackNumber(),det,hits,qTot, drRegion);
658 // Calculate the maximum step size for the next tracking step
659 // Produce only one hit if Ekin is below cutoff
660 aMass = gMC->TrackMass();
661 if ((gMC->Etot() - aMass) > kEkinMinStep) {
663 // The energy loss according to Bethe Bloch
664 iPdg = TMath::Abs(gMC->TrackPid());
665 if ( (iPdg != kPdgElectron) ||
666 ((iPdg == kPdgElectron) && (pTot < kPTotMaxEl))) {
667 gMC->TrackMomentum(mom);
669 betaGamma = pTot / aMass;
670 pp = BetheBlochGeant(betaGamma);
671 // Take charge > 1 into account
672 charge = gMC->TrackCharge();
673 if (TMath::Abs(charge) > 1) pp = pp * charge*charge;
674 } else { // Electrons above 20 Mev/c are at the plateau
675 pp = kPrim * kPlateau;
678 stepSize = 1./gRandom->Poisson(pp);
679 gMC->SetMaxStep(stepSize);
686 //_____________________________________________________________________________
687 void AliTRDv1::StepManagerErmilova()
690 // Slow simulator. Every charged track produces electron cluster as hits
691 // along its path across the drift volume. The step size is set acording
692 // to Bethe-Bloch. The energy distribution of the delta electrons follows
693 // a spectrum taken from Ermilova et al.
710 Double_t betaGamma, pp;
713 Bool_t drRegion = kFALSE;
714 Bool_t amRegion = kFALSE;
717 TString cIdSensDr = "J";
718 TString cIdSensAm = "K";
719 Char_t cIdChamber[3];
722 TLorentzVector pos, mom;
724 const Int_t kNplan = AliTRDgeometry::Nplan();
725 const Int_t kNcham = AliTRDgeometry::Ncham();
726 const Int_t kNdetsec = kNplan * kNcham;
728 const Double_t kBig = 1.0E+12; // Infinitely big
729 const Float_t kWion = 22.57; // Ionization energy
730 const Float_t kPTotMaxEl = 0.002; // Maximum momentum for e+ e- g
732 // energy threshold for production of delta electrons
733 //const Float_t kECut = 1.0e4;
734 // Parameters entering the parametrized range for delta electrons
735 //const float ra=5.37E-4, rb=0.9815, rc=3.123E-3;
736 // Gas density -> To be made user adjustable !
737 //const float rho=0.004945 ; //[0.85*0.00549+0.15*0.00186 (Xe-CO2 85-15)]
739 // Minimum energy for the step size adjustment
740 const Float_t kEkinMinStep = 1.0e-5;
742 // Plateau value of the energy-loss for electron in xenon
743 // taken from: Allison + Comb, Ann. Rev. Nucl. Sci. (1980), 30, 253
744 //const Double_t kPlateau = 1.70;
745 // the averaged value (26/3/99)
746 const Float_t kPlateau = 1.55;
748 const Float_t kPrim = 48.0; // dN1/dx|min for the gas mixture (90% Xe + 10% CO2)
749 // First ionization potential (eV) for the gas mixture (90% Xe + 10% CO2)
750 const Float_t kPoti = 12.1;
752 const Int_t kPdgElectron = 11; // PDG code electron
754 // Set the maximum step size to a very large number for all
755 // neutral particles and those outside the driftvolume
756 gMC->SetMaxStep(kBig);
758 // Use only charged tracks
759 if (( gMC->TrackCharge() ) &&
760 (!gMC->IsTrackStop() ) &&
761 (!gMC->IsTrackDisappeared())) {
763 // Inside a sensitive volume?
766 cIdCurrent = gMC->CurrentVolName();
767 if (cIdSensDr == cIdCurrent[1]) {
770 if (cIdSensAm == cIdCurrent[1]) {
773 if (drRegion || amRegion) {
775 // The hit coordinates and charge
776 gMC->TrackPosition(pos);
781 // The sector number (0 - 17)
782 // The numbering goes clockwise and starts at y = 0
783 Float_t phi = kRaddeg*TMath::ATan2(pos[0],pos[1]);
788 sec = ((Int_t) (phi / 20));
790 // The plane and chamber number
791 cIdChamber[0] = cIdCurrent[2];
792 cIdChamber[1] = cIdCurrent[3];
793 Int_t idChamber = (atoi(cIdChamber) % kNdetsec);
794 cha = kNcham - ((Int_t) idChamber / kNplan) - 1;
795 pla = ((Int_t) idChamber % kNplan);
797 // Check on selected volumes
798 Int_t addthishit = 1;
800 if ((fSensPlane >= 0) && (pla != fSensPlane )) addthishit = 0;
801 if ((fSensChamber >= 0) && (cha != fSensChamber)) addthishit = 0;
802 if (fSensSector >= 0) {
803 Int_t sens1 = fSensSector;
804 Int_t sens2 = fSensSector + fSensSectorRange;
805 sens2 -= ((Int_t) (sens2 / AliTRDgeometry::Nsect()))
806 * AliTRDgeometry::Nsect();
808 if ((sec < sens1) || (sec >= sens2)) addthishit = 0;
811 if ((sec < sens1) && (sec >= sens2)) addthishit = 0;
819 // The detector number
820 det = fGeometry->GetDetector(pla,cha,sec);
822 // Special hits only in the drift region
825 // Create a track reference at the entrance and
826 // exit of each chamber that contain the
827 // momentum components of the particle
828 if (gMC->IsTrackEntering() || gMC->IsTrackExiting()) {
829 gMC->TrackMomentum(mom);
830 AddTrackReference(gAlice->GetMCApp()->GetCurrentTrackNumber());
832 // Create the hits from TR photons
833 if (fTR) CreateTRhit(det);
837 // Calculate the energy of the delta-electrons
838 eDelta = TMath::Exp(fDeltaE->GetRandom()) - kPoti;
839 eDelta = TMath::Max(eDelta,0.0);
840 // Generate the electron cluster size
841 if(eDelta==0.) qTot=0;
842 else qTot = ((Int_t) (eDelta / kWion) + 1);
844 // Create a new dEdx hit
846 AddHit(gAlice->GetMCApp()->GetCurrentTrackNumber()
847 ,det,hits,qTot, kTRUE);
850 AddHit(gAlice->GetMCApp()->GetCurrentTrackNumber()
851 ,det,hits,qTot,kFALSE);
854 // Calculate the maximum step size for the next tracking step
855 // Produce only one hit if Ekin is below cutoff
856 aMass = gMC->TrackMass();
857 if ((gMC->Etot() - aMass) > kEkinMinStep) {
859 // The energy loss according to Bethe Bloch
860 iPdg = TMath::Abs(gMC->TrackPid());
861 if ( (iPdg != kPdgElectron) ||
862 ((iPdg == kPdgElectron) && (pTot < kPTotMaxEl))) {
863 gMC->TrackMomentum(mom);
865 betaGamma = pTot / aMass;
866 pp = kPrim * BetheBloch(betaGamma);
867 // Take charge > 1 into account
868 charge = gMC->TrackCharge();
869 if (TMath::Abs(charge) > 1) pp = pp * charge*charge;
870 } else { // Electrons above 20 Mev/c are at the plateau
871 pp = kPrim * kPlateau;
876 gMC->GetRandom()->RndmArray(1, random);
877 while ((random[0] == 1.) || (random[0] == 0.));
878 stepSize = - TMath::Log(random[0]) / pp;
879 gMC->SetMaxStep(stepSize);
887 //_____________________________________________________________________________
888 void AliTRDv1::StepManagerFixedStep()
891 // Slow simulator. Every charged track produces electron cluster as hits
892 // along its path across the drift volume. The step size is fixed in
893 // this version of the step manager.
905 Bool_t drRegion = kFALSE;
906 Bool_t amRegion = kFALSE;
909 TString cIdSensDr = "J";
910 TString cIdSensAm = "K";
911 Char_t cIdChamber[3];
914 TLorentzVector pos, mom;
916 const Int_t kNplan = AliTRDgeometry::Nplan();
917 const Int_t kNcham = AliTRDgeometry::Ncham();
918 const Int_t kNdetsec = kNplan * kNcham;
920 const Double_t kBig = 1.0E+12;
922 const Float_t kWion = 22.57; // Ionization energy
923 const Float_t kEkinMinStep = 1.0e-5; // Minimum energy for the step size adjustment
925 // Set the maximum step size to a very large number for all
926 // neutral particles and those outside the driftvolume
927 gMC->SetMaxStep(kBig);
929 // If not charged track or already stopped or disappeared, just return.
930 if ((!gMC->TrackCharge()) ||
931 gMC->IsTrackStop() ||
932 gMC->IsTrackDisappeared()) return;
934 // Inside a sensitive volume?
935 cIdCurrent = gMC->CurrentVolName();
937 if (cIdSensDr == cIdCurrent[1]) drRegion = kTRUE;
938 if (cIdSensAm == cIdCurrent[1]) amRegion = kTRUE;
940 if ((!drRegion) && (!amRegion)) return;
942 // The hit coordinates and charge
943 gMC->TrackPosition(pos);
948 // The sector number (0 - 17)
949 // The numbering goes clockwise and starts at y = 0
950 Float_t phi = kRaddeg*TMath::ATan2(pos[0],pos[1]);
951 if (phi < 90.) phi += 270.;
953 sec = ((Int_t) (phi / 20.));
955 // The plane and chamber number
956 cIdChamber[0] = cIdCurrent[2];
957 cIdChamber[1] = cIdCurrent[3];
958 Int_t idChamber = (atoi(cIdChamber) % kNdetsec);
959 cha = kNcham - ((Int_t) idChamber / kNplan) - 1;
960 pla = ((Int_t) idChamber % kNplan);
962 // Check on selected volumes
963 Int_t addthishit = 1;
965 if ((fSensPlane >= 0) && (pla != fSensPlane )) addthishit = 0;
966 if ((fSensChamber >= 0) && (cha != fSensChamber)) addthishit = 0;
967 if (fSensSector >= 0) {
968 Int_t sens1 = fSensSector;
969 Int_t sens2 = fSensSector + fSensSectorRange;
970 sens2 -= ((Int_t) (sens2 / AliTRDgeometry::Nsect())) * AliTRDgeometry::Nsect();
972 if ((sec < sens1) || (sec >= sens2)) addthishit = 0;
975 if ((sec < sens1) && (sec >= sens2)) addthishit = 0;
980 if (!addthishit) return;
982 det = fGeometry->GetDetector(pla,cha,sec); // The detector number
984 Int_t trkStat = 0; // 0: InFlight 1:Entering 2:Exiting
986 // Special hits only in the drift region
989 // Create a track reference at the entrance and exit of each
990 // chamber that contain the momentum components of the particle
992 if (gMC->IsTrackEntering()) {
993 gMC->TrackMomentum(mom);
994 AddTrackReference(gAlice->GetMCApp()->GetCurrentTrackNumber());
997 if (gMC->IsTrackExiting()) {
998 gMC->TrackMomentum(mom);
999 AddTrackReference(gAlice->GetMCApp()->GetCurrentTrackNumber());
1003 // Create the hits from TR photons
1004 if (fTR) CreateTRhit(det);
1008 // Calculate the charge according to GEANT Edep
1009 // Create a new dEdx hit
1010 eDep = TMath::Max(gMC->Edep(),0.0) * 1.0e+09;
1011 qTot = (Int_t) (eDep / kWion);
1012 AddHit(gAlice->GetMCApp()->GetCurrentTrackNumber()
1013 ,det,hits,qTot,drRegion);
1015 // Set Maximum Step Size
1016 // Produce only one hit if Ekin is below cutoff
1017 if ((gMC->Etot() - gMC->TrackMass()) < kEkinMinStep) return;
1018 gMC->SetMaxStep(fStepSize);
1022 //_____________________________________________________________________________
1023 Double_t AliTRDv1::BetheBloch(Double_t bg)
1026 // Parametrization of the Bethe-Bloch-curve
1027 // The parametrization is the same as for the TPC and is taken from Lehrhaus.
1030 // This parameters have been adjusted to averaged values from GEANT
1031 const Double_t kP1 = 7.17960e-02;
1032 const Double_t kP2 = 8.54196;
1033 const Double_t kP3 = 1.38065e-06;
1034 const Double_t kP4 = 5.30972;
1035 const Double_t kP5 = 2.83798;
1037 // This parameters have been adjusted to Xe-data found in:
1038 // Allison & Cobb, Ann. Rev. Nucl. Sci. (1980), 30, 253
1039 //const Double_t kP1 = 0.76176E-1;
1040 //const Double_t kP2 = 10.632;
1041 //const Double_t kP3 = 3.17983E-6;
1042 //const Double_t kP4 = 1.8631;
1043 //const Double_t kP5 = 1.9479;
1045 // Lower cutoff of the Bethe-Bloch-curve to limit step sizes
1046 const Double_t kBgMin = 0.8;
1047 const Double_t kBBMax = 6.83298;
1048 //const Double_t kBgMin = 0.6;
1049 //const Double_t kBBMax = 17.2809;
1050 //const Double_t kBgMin = 0.4;
1051 //const Double_t kBBMax = 82.0;
1054 Double_t yy = bg / TMath::Sqrt(1. + bg*bg);
1055 Double_t aa = TMath::Power(yy,kP4);
1056 Double_t bb = TMath::Power((1./bg),kP5);
1057 bb = TMath::Log(kP3 + bb);
1058 return ((kP2 - aa - bb)*kP1 / aa);
1066 //_____________________________________________________________________________
1067 Double_t AliTRDv1::BetheBlochGeant(Double_t bg)
1070 // Return dN/dx (number of primary collisions per centimeter)
1071 // for given beta*gamma factor.
1073 // Implemented by K.Oyama according to GEANT 3 parametrization shown in
1074 // A.Andronic's webpage: http://www-alice.gsi.de/trd/papers/dedx/dedx.html
1075 // This must be used as a set with IntSpecGeant.
1078 Double_t arr_g[20] = {
1079 1.100000, 1.200000, 1.300000, 1.500000,
1080 1.800000, 2.000000, 2.500000, 3.000000,
1081 4.000000, 7.000000, 10.000000, 20.000000,
1082 40.000000, 70.000000, 100.000000, 300.000000,
1083 600.000000, 1000.000000, 3000.000000, 10000.000000 };
1085 Double_t arr_nc[20] = {
1086 75.009056, 45.508083, 35.299252, 27.116327,
1087 22.734999, 21.411915, 19.934095, 19.449375,
1088 19.344431, 20.185553, 21.027925, 22.912676,
1089 24.933352, 26.504053, 27.387468, 29.566597,
1090 30.353779, 30.787134, 31.129285, 31.157350 };
1092 // betagamma to gamma
1093 Double_t g = TMath::Sqrt( 1. + bg*bg );
1095 // Find the index just before the point we need.
1097 for( i = 0 ; i < 18 ; i++ )
1098 if( arr_g[i] < g && arr_g[i+1] > g )
1101 // Simple interpolation.
1102 Double_t pp = ((arr_nc[i+1] - arr_nc[i]) /
1103 (arr_g[i+1]-arr_g[i])) * (g-arr_g[i]) + arr_nc[i];
1105 return pp; //arr_nc[8];
1109 //_____________________________________________________________________________
1110 void AliTRDv1::Stepping()
1129 gMC->TrackPosition(x, y, z);
1130 cout << setw(8) << setprecision(3) << x << " "
1131 << setw(8) << setprecision(3) << y << " "
1132 << setw(8) << setprecision(3) << z << " ";
1136 Double_t px, py, pz, etot;
1137 gMC->TrackMomentum(px, py, pz, etot);
1138 Double_t ekin = etot - gMC->TrackMass();
1139 cout << setw(9) << setprecision(4) << ekin*1e03 << " ";
1143 cout << setw(9) << setprecision(4) << gMC->Edep()*1e03 << " ";
1147 cout << setw(8) << setprecision(3) << gMC->TrackStep() << " ";
1151 cout << setw(8) << setprecision(3) << gMC->TrackLength() << " ";
1155 if (gMC->CurrentVolName() != 0)
1156 cout << setw(4) << gMC->CurrentVolName() << " ";
1158 cout << setw(4) << "None" << " ";
1163 Int_t nofProcesses = gMC->StepProcesses(processes);
1164 for(int ip=0;ip<nofProcesses; ip++)
1165 cout << TMCProcessName[processes[ip]]<<" / ";
1171 //_____________________________________________________________________________
1172 Double_t Ermilova(Double_t *x, Double_t *)
1175 // Calculates the delta-ray energy distribution according to Ermilova.
1176 // Logarithmic scale !
1185 const Int_t kNv = 31;
1187 Float_t vxe[kNv] = { 2.3026, 2.9957, 3.4012, 3.6889, 3.9120
1188 , 4.0943, 4.2485, 4.3820, 4.4998, 4.6052
1189 , 4.7005, 5.0752, 5.2983, 5.7038, 5.9915
1190 , 6.2146, 6.5221, 6.9078, 7.3132, 7.6009
1191 , 8.0064, 8.5172, 8.6995, 8.9872, 9.2103
1192 , 9.4727, 9.9035,10.3735,10.5966,10.8198
1195 Float_t vye[kNv] = { 80.0 , 31.0 , 23.3 , 21.1 , 21.0
1196 , 20.9 , 20.8 , 20.0 , 16.0 , 11.0
1197 , 8.0 , 6.0 , 5.2 , 4.6 , 4.0
1198 , 3.5 , 3.0 , 1.4 , 0.67 , 0.44
1199 , 0.3 , 0.18 , 0.12 , 0.08 , 0.056
1200 , 0.04 , 0.023, 0.015, 0.011, 0.01
1205 // Find the position
1209 dpos = energy - vxe[pos2++];
1213 if (pos2 > kNv) pos2 = kNv - 1;
1216 // Differentiate between the sampling points
1217 dnde = (vye[pos1] - vye[pos2]) / (vxe[pos2] - vxe[pos1]);
1223 //_____________________________________________________________________________
1224 Double_t IntSpecGeant(Double_t *x, Double_t *)
1227 // Integrated spectrum from Geant3
1230 const Int_t n_pts = 83;
1231 Double_t arr_e[n_pts] = {
1232 2.421257, 2.483278, 2.534301, 2.592230,
1233 2.672067, 2.813299, 3.015059, 3.216819,
1234 3.418579, 3.620338, 3.868209, 3.920198,
1235 3.978284, 4.063923, 4.186264, 4.308605,
1236 4.430946, 4.553288, 4.724261, 4.837736,
1237 4.999842, 5.161949, 5.324056, 5.486163,
1238 5.679688, 5.752998, 5.857728, 5.962457,
1239 6.067185, 6.171914, 6.315653, 6.393674,
1240 6.471694, 6.539689, 6.597658, 6.655627,
1241 6.710957, 6.763648, 6.816338, 6.876198,
1242 6.943227, 7.010257, 7.106285, 7.252151,
1243 7.460531, 7.668911, 7.877290, 8.085670,
1244 8.302979, 8.353585, 8.413120, 8.483500,
1245 8.541030, 8.592857, 8.668865, 8.820485,
1246 9.037086, 9.253686, 9.470286, 9.686887,
1247 9.930838, 9.994655, 10.085822, 10.176990,
1248 10.268158, 10.359325, 10.503614, 10.627565,
1249 10.804637, 10.981709, 11.158781, 11.335854,
1250 11.593397, 11.781165, 12.049404, 12.317644,
1251 12.585884, 12.854123, 14.278421, 16.975889,
1252 20.829416, 24.682943, 28.536469
1254 Double_t arr_dndx[n_pts] = {
1255 19.344431, 18.664679, 18.136106, 17.567745,
1256 16.836426, 15.677382, 14.281277, 13.140237,
1257 12.207677, 11.445510, 10.697049, 10.562296,
1258 10.414673, 10.182341, 9.775256, 9.172330,
1259 8.240271, 6.898587, 4.808303, 3.889751,
1260 3.345288, 3.093431, 2.897347, 2.692470,
1261 2.436222, 2.340029, 2.208579, 2.086489,
1262 1.975535, 1.876519, 1.759626, 1.705024,
1263 1.656374, 1.502638, 1.330566, 1.200697,
1264 1.101168, 1.019323, 0.943867, 0.851951,
1265 0.755229, 0.671576, 0.570675, 0.449672,
1266 0.326722, 0.244225, 0.188225, 0.149608,
1267 0.121529, 0.116289, 0.110636, 0.103490,
1268 0.096147, 0.089191, 0.079780, 0.063927,
1269 0.047642, 0.036341, 0.028250, 0.022285,
1270 0.017291, 0.016211, 0.014802, 0.013533,
1271 0.012388, 0.011352, 0.009803, 0.008537,
1272 0.007039, 0.005829, 0.004843, 0.004034,
1273 0.003101, 0.002564, 0.001956, 0.001494,
1274 0.001142, 0.000873, 0.000210, 0.000014,
1275 0.000000, 0.000000, 0.000000
1279 Double_t energy = x[0];
1282 for( i = 0 ; i < n_pts ; i++ )
1283 if( energy < arr_e[i] ) break;
1286 AliErrorGeneral("AliTRDv1","Given energy value is too small or zero");
1289 dnde = (arr_dndx[i-1] - arr_dndx[i]) / (arr_e[i] - arr_e[i-1]);