G4S2Light.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The NEST program is intended for use with the Geant4 software, *
6 // * which is copyright of the Copyright Holders of the Geant4 *
7 // * Collaboration. This additional software is copyright of the NEST *
8 // * development team. As such, it is subject to the terms and *
9 // * conditions of both the Geant4 License, included with your copy *
10 // * of Geant4 and available at http://cern.ch/geant4/license, as *
11 // * well as the NEST License included with the download of NEST and *
12 // * available at http://nest.physics.ucdavis.edu/ *
13 // * *
14 // * Neither the authors of this software system, nor their employing *
15 // * institutions, nor the agencies providing financial support for *
16 // * this work make any representation or warranty, express or *
17 // * implied, regarding this software system, or assume any liability *
18 // * for its use. Please read the pdf license or view it online *
19 // * before download for the full disclaimer and lack of liability. *
20 // * *
21 // * This code implementation is based on work by Peter Gumplinger *
22 // * and his fellow collaborators on Geant4 and is distributed with *
23 // * the express written consent of the Geant4 collaboration. By *
24 // * using, copying, modifying, or sharing the software (or any work *
25 // * based on the software) you agree to acknowledge use of both NEST *
26 // * and Geant4 in resulting scientific publications, and you *
27 // * indicate your acceptance of all the terms and conditions of the *
28 // * licenses, which must always be included with this code. *
29 // ********************************************************************
30 //
31 //
32 // Noble Element Simulation Technique "G4S2Light" physics process
33 //
34 ////////////////////////////////////////////////////////////////////////
35 // S2 Scintillation Light Class Implementation
36 ////////////////////////////////////////////////////////////////////////
37 //
38 // File: G4S2Light.cc (companion of G4S1Light.cc)
39 // Description: RestDiscrete Process - Generation of S2 Photons in GXe
40 // Version: 0.98 final
41 // Created: Thursday, January 17, 2013
42 // Authors: Matthew Szydagis, Dustin Stolp, and Michael Woods
43 //
44 // mail: mmszydagis@ucdavis.edu
45 //
46 ////////////////////////////////////////////////////////////////////////
47 
48 #include "G4ParticleTypes.hh" //lets you refer to G4OpticalPhoton, etc.
49 #include "G4EmProcessSubType.hh" //lets you call this process Scintillation
50 #include "G4S2Light.hh"
51 #include "G4S1Light.hh"
52 
53 #include "G4SystemOfUnits.hh"
54 #include "G4PhysicalConstants.hh"
55 
56 #define E_PURITY 2*CLHEP::m //the electron absorption z-length
57 #define GRID_DENSITY 8.03*(CLHEP::g/CLHEP::cm3) //density of your grid material
58 
59 G4double thr[100]; //offset in linear light yield formula for S2 ph/e-
60 G4double E_eV[100]; //energy of single photon in gas, eV
61 G4double tau1[100], tau3[100], MolarMass[100], ConvertEff[100];
62 
63 G4double GetGasElectronDriftSpeed(G4double efieldinput,G4double density);
64 G4double GetLiquidElectronDriftSpeed(double T, double F, G4bool M, G4int Z);
65 
66 G4S2Light::G4S2Light(const G4String& processName,
67  G4ProcessType type)
68  : G4VRestDiscreteProcess(processName, type)
69 {
70  thr[18] = 0.190; E_eV[18] = 9.7; MolarMass[18] = 39.948;
71  tau1[18] = 6*CLHEP::ns; tau3[18] = 1600*CLHEP::ns; ConvertEff[18]=0.7857;
72  thr[54] = 0.474; E_eV[54] = 7.143; MolarMass[54] = 131.293;
73  ConvertEff[54] = 1.01; //50% when LXe TPC is dirty
74  //luxManager = LUXSimManager::GetManager();
75  SetProcessSubType(fScintillation);
76  fTrackSecondariesFirst = false;
77  if (verboseLevel>0) {
78  G4cout << GetProcessName() << " is created " << G4endl;
79  }
80 }
81 
82 G4S2Light::~G4S2Light(){} //destructor
83 
84 G4VParticleChange*
85 G4S2Light::AtRestDoIt(const G4Track& aTrack, const G4Step& aStep)
86 {
87  return G4S2Light::PostStepDoIt(aTrack, aStep);
88 }
89 
90 G4VParticleChange*
91 G4S2Light::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
92 {
93 // The function where all the action happens! Not yet well commented, as this
94 // is but an alpha version of the electroluminescence code
95  YieldFactor = 1.000;
96  aParticleChange.Initialize(aTrack);
97  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
98  const G4Material* aMaterial = aTrack.GetMaterial();
99  if ( !aMaterial ) {
100  aParticleChange.ProposeTrackStatus(fStopAndKill);
101  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
102  }
103  G4MaterialPropertiesTable* aMaterialPropertiesTable =
104  aMaterial->GetMaterialPropertiesTable();
105  if ( !aMaterialPropertiesTable ) {
106  aParticleChange.ProposeTrackStatus(fStopAndKill);
107  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
108  }
109  const G4ElementVector* theElementVector =
110  aMaterial->GetElementVector();
111  G4Element* Element = (*theElementVector)[0]; G4int z1;
112  if ( Element ) z1 = (G4int)(Element->GetZ()); else z1 = -1;
113  G4double z_anode = BORDER + GASGAP;
114  G4double z_start = BORDER;
115  //if(luxManager->GetGasRun()) z_start=GAT;
116  tau1[54] = G4RandGauss::shoot(5.18*CLHEP::ns,1.55*CLHEP::ns);
117  tau3[54] = G4RandGauss::shoot(100.1*CLHEP::ns,7.9*CLHEP::ns);
118 
119  G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
120  G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
121  G4ThreeVector x0 = pPreStepPoint->GetPosition();
122  G4ThreeVector x1 = pPostStepPoint->GetPosition();
123  G4double t1 = pPostStepPoint->GetGlobalTime();
124  G4double Density = aMaterial->GetDensity()/(CLHEP::g/CLHEP::cm3);
125  G4double nDensity = (Density/MolarMass[z1])*AVO;
126  G4int Phase = aMaterial->GetState();
127 
128  if ( Phase == kStateLiquid && x0[2] > (GAT-5*CLHEP::mm) && GAT != 0 ) {
129  aParticleChange.ProposeEnergy(GetLiquidElectronDriftSpeed(
130  aMaterial->GetTemperature(),fabs(aMaterialPropertiesTable->
131  GetConstProperty("ELECTRICFIELDSURFACE")/(CLHEP::volt/CLHEP::cm)),MillerDriftSpeed,z1));
132  aParticleChange.ProposeWeight(2.0);
133  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
134  }
135 
136  // absorb the electron if you are in liquid and there is non-perfect
137  // purity, you turned S2 off with YieldFactor, the e- is above the
138  // anode in the gas already, or it's not present in a noble element
139  if ( Phase == kStateLiquid || !YieldFactor || x0[2] > z_anode ||
140  x1[2] > z_anode || fabs(x1[2]-x0[2]) < 1e-7*CLHEP::nm ||
141  (z1!=2 && z1!=10 && z1!=18 && z1!=36 && z1!=54) ) {
142  G4double KE = aParticle->GetKineticEnergy();
143  aParticleChange.ProposeTrackStatus(fStopAndKill);
144  aParticleChange.ProposeEnergy(0.);
145  aParticleChange.ProposeLocalEnergyDeposit(KE);
146  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
147  }
148  if ( x0[2] <= z_start && x1[2] <= z_start )
149  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
150 
151  G4double ElectricField;
152  if(!WIN && !TOP && !ANE && !SRF && !GAT && !CTH && !BOT && !PMT)
153  ElectricField = aMaterialPropertiesTable->
154  GetConstProperty("ELECTRICFIELD");
155  else
156  ElectricField = aMaterialPropertiesTable->
157  GetConstProperty("ELECTRICFIELDANODE");
158  ElectricField =
159  fabs(ElectricField/(CLHEP::kilovolt/CLHEP::cm));
160 
161  if ( Density > 0. && Phase == kStateGas && (x0[2] > z_start ||
162  x1[2] > z_start) && aParticleChange.GetWeight() >= 1.0 ) {
163  aParticleChange.ProposeWeight(0);
164  G4double ExtractEff = -0.0012052 + //Aprile 2004 IEEE No.5
165  0.1638*ElectricField-0.0063782*pow(ElectricField,2.);
166  if ( ElectricField > 10.0 ) ExtractEff = 1.00;
167  if ( ElectricField <= 0.0 ) ExtractEff = 0.00;
168  if ( ExtractEff < 0 ) ExtractEff = 0;
169  if ( ExtractEff > 1 ) ExtractEff = 1;
170  //if ( luxManager->GetGasRun() ) ExtractEff = 1;
171  if (G4UniformRand() > ExtractEff || !ElectricField ||
172  (1/E_eV[z1])*1e17*((ElectricField*1e3)/nDensity)<=thr[z1]) {
173  aParticleChange.ProposeTrackStatus(fStopAndKill);
174  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
175  }
176  else {
177  G4double eDrift =
178  GetGasElectronDriftSpeed(1000.*ElectricField,nDensity);
179  aParticleChange.ProposeEnergy(eDrift);
180  }
181  }
182 
183  if ( G4UniformRand () >= QE_EFF )
184  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
185  aParticleChange.SetNumberOfSecondaries(G4int(floor(YieldFactor)));
186  if ( verboseLevel > 0 ) {
187  G4cout << "\n Exiting from G4S2Light::DoIt -- "
188  << "NumberOfSecondaries = "
189  << aParticleChange.GetNumberOfSecondaries() << G4endl;
190  }
191 
192  // start particle creation
193  G4double sampledEnergy;
194  G4DynamicParticle* aQuantum;
195 
196  // Generate random direction
197  G4double cost = 1. - 2.*G4UniformRand();
198  G4double sint = std::sqrt((1.-cost)*(1.+cost));
199  G4double phi = CLHEP::twopi*G4UniformRand();
200  G4double sinp = std::sin(phi);
201  G4double cosp = std::cos(phi);
202  G4double px = sint*cosp; G4double py = sint*sinp;
203  G4double pz = cost;
204 
205  // Create momentum direction vector
206  G4ParticleMomentum photonMomentum(px, py, pz);
207 
208  // Determine polarization of new photon
209  G4double sx = cost*cosp; G4double sy = cost*sinp;
210  G4double sz = -sint;
211  G4ThreeVector photonPolarization(sx, sy, sz);
212  G4ThreeVector perp = photonMomentum.cross(photonPolarization);
213  phi = CLHEP::twopi*G4UniformRand();
214  sinp = std::sin(phi); cosp = std::cos(phi);
215  photonPolarization = cosp * photonPolarization + sinp * perp;
216  photonPolarization = photonPolarization.unit();
217 
218  // Generate a new photon:
219  sampledEnergy = G4RandGauss::shoot(E_eV[z1]*CLHEP::eV,0.2*CLHEP::eV);
220  if ( z1==54 && sampledEnergy>8.5*CLHEP::eV ) sampledEnergy = 8.5*CLHEP::eV;
221  aQuantum =
222  new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(),
223  photonMomentum);
224  aQuantum->SetPolarization(photonPolarization.x(),
225  photonPolarization.y(),
226  photonPolarization.z());
227 
228  //assign energy to make particle real
229  aQuantum->SetKineticEnergy(sampledEnergy);
230  if (verboseLevel>1)
231  G4cout << "sampledEnergy = " << sampledEnergy << G4endl;
232 
233  // electroluminesence emission time distribution
234  G4double aSecondaryTime = t1,
235  SingTripRatio=.1; //guess: revisit
236  if(G4UniformRand()<SingTripRatio/(1+SingTripRatio))
237  aSecondaryTime -= tau1[z1]*log(G4UniformRand());
238  else aSecondaryTime -=
239  tau3[z1]*log(G4UniformRand());
240 
241  //the position of the new secondary particle
242  if ( x1[2] < BORDER + GASGAP / 2. )
243  x1[2] += 0.001*CLHEP::mm;
244  if ( x1[2] > BORDER + GASGAP / 2. )
245  x1[2] -= 0.001*CLHEP::mm;
246  G4ThreeVector aSecondaryPosition = x1;
247 
248  // GEANT4 business: stuff you need to make a new track
249  G4Track* aSecondaryTrack =
250  new G4Track(aQuantum,aSecondaryTime,aSecondaryPosition);
251  aParticleChange.AddSecondary(aSecondaryTrack);
252 
253  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
254 }
255 
256 // GetMeanFreePath
257 // ---------------
258 G4double G4S2Light::GetMeanFreePath(const G4Track& aTrack,
259  G4double ,
260  G4ForceCondition* condition)
261 {
262  const G4Material* aMaterial = aTrack.GetMaterial();
263  if ( !aMaterial ) return DBL_MIN;
264  const G4ElementVector* theElementVector = aMaterial->GetElementVector();
265  G4Element* Element = (*theElementVector)[0]; G4int z1;
266  if ( Element ) z1 = (G4int)(Element->GetZ()); else z1 = -1;
267  if ( (z1==2 || z1==10 || z1==18 || z1==36 || z1==54) &&
268  aMaterial->GetState() == kStateLiquid ) {
269  if ( aTrack.GetPosition()[2] < (GAT-5*CLHEP::mm) || aTrack.GetWeight() == 2 )
270  return E_PURITY;
271  else return 0.000*CLHEP::mm;
272  }
273  else if ((z1==2 || z1==10 || z1==18 || z1==36 || z1==54) &&
274  aMaterial->GetState()== kStateGas && aMaterial->GetDensity()>0.0*(CLHEP::g/CLHEP::cm3)) {
275  G4MaterialPropertiesTable* aMaterialPropertiesTable =
276  aMaterial->GetMaterialPropertiesTable();
277  if(!aMaterialPropertiesTable) return DBL_MIN;
278  if ( aTrack.GetPosition()[2] < (GAT-5*CLHEP::mm) ) return DBL_MAX;
279  G4double ElectricField = fabs(aMaterialPropertiesTable->
280  GetConstProperty("ELECTRICFIELDANODE"));
281  ElectricField = ElectricField/(CLHEP::volt/CLHEP::cm);
282  G4double mfp, nDensity =
283  (aMaterial->GetDensity()/(CLHEP::g/CLHEP::cm3))/(MolarMass[z1])*AVO;
284  if ( (1/E_eV[z1])*(ElectricField/nDensity)*1e17 == thr[z1] ) {
285  mfp = 0*CLHEP::cm;
286  }
287  else { //denominator of formula OK
288  mfp = 1 /
289  (nDensity*1e-17*((1/E_eV[z1])*(ElectricField/nDensity)*1e17-thr[z1]));
290  }
291  //equation 8 within Monteiro's paper JINST 2007 (where 140=1/7.14.. eV)
292  mfp*=CLHEP::cm/ConvertEff[z1];
293  if(mfp<0)mfp=0;
294  if(mfp>GASGAP/2.7)mfp=GASGAP/exp(1);
295  return mfp; //mean free path for 1 photon
296  }
297  else {
298  *condition = NotForced;
299  const G4Material* aMaterial = aTrack.GetMaterial();
300  if ( aMaterial->GetDensity() == GRID_DENSITY )
301  return DBL_MAX; //pass electrons through grid wires
302  return 0*CLHEP::nm; //kill elsewhere
303  }
304 }
305 
306 // GetMeanLifeTime
307 // ---------------
308 G4double G4S2Light::GetMeanLifeTime(const G4Track&,
309  G4ForceCondition* condition)
310 {
311  *condition = InActivated;
312  return DBL_MAX;
313 }
314 
315 G4double GetGasElectronDriftSpeed(G4double efieldinput, G4double density)
316 {
317  //Gas equation one coefficients(E/N of 1.2E-19 to 3.5E-19)
318  double gas1a=395.50266631436,gas1b=-357384143.004642,gas1c=0.518110447340587;
319  //Gas equation two coefficients(E/N of 3.5E-19 to 3.8E-17)
320  double gas2a=-592981.611357632,gas2b=-90261.9643716643,
321  gas2c=-4911.83213989609,gas2d=-115.157545835228, gas2f=-0.990440443390298,
322  gas2g=1008.30998933704,gas2h=223.711221224885;
323 
324  G4double edrift=0, gasdep=efieldinput/density, gas1fix=0, gas2fix=0;
325 
326  if ( gasdep < 1.2e-19 && gasdep >= 0 ) edrift = 4e22*gasdep;
327  if ( gasdep < 3.5e-19 && gasdep >= 1.2e-19 ) {
328  gas1fix = gas1b*pow(gasdep,gas1c); edrift = gas1a*pow(gasdep,gas1fix);
329  }
330  if ( gasdep < 3.8e-17 && gasdep >= 3.5e-19 ) {
331  gas2fix = log(gas2g*gasdep);
332  edrift = (gas2a+gas2b*gas2fix+gas2c*pow(gas2fix,2)+gas2d*pow(gas2fix,3)+
333  gas2f*pow(gas2fix,4))*(gas2h*exp(gasdep));
334  }
335  if ( gasdep >= 3.8e-17 ) edrift = 6e21*gasdep-32279;
336 
337  return 0.5*EMASS*pow(edrift*(CLHEP::cm/CLHEP::s),2.);
338 }
static constexpr double cm
Definition: Units.h:68
#define WIN
Definition: G4S1Light.hh:35
#define BORDER
Definition: G4S1Light.hh:29
#define EMASS
Definition: G4S1Light.hh:25
#define MillerDriftSpeed
Definition: G4S1Light.hh:26
static constexpr double g
Definition: Units.h:144
G4double thr[100]
Definition: G4S2Light.cc:59
#define TOP
#define GAT
Definition: G4S1Light.hh:39
#define QE_EFF
Definition: G4S1Light.hh:31
static constexpr double cm3
Definition: Units.h:70
constexpr T pow(T x)
Definition: pow.h:72
G4double MolarMass[100]
Definition: G4S2Light.cc:61
G4double YieldFactor
Definition: G4S2Light.hh:77
G4double tau1[100]
Definition: G4S2Light.cc:61
G4double tau3[100]
Definition: G4S2Light.cc:61
#define ANE
Definition: G4S1Light.hh:37
kilovolt_as<> kilovolt
Type of potential stored in kilovolt, in double precision.
~G4S2Light()
Definition: G4S2Light.cc:82
#define AVO
Definition: G4S1Light.hh:24
#define SRF
Definition: G4S1Light.hh:38
G4VParticleChange * PostStepDoIt(const G4Track &aTrack, const G4Step &aStep)
Definition: G4S2Light.cc:91
#define E_PURITY
Definition: G4S2Light.cc:56
const double e
#define BOT
Definition: G4S1Light.hh:41
static constexpr double eV
Definition: Units.h:127
G4double GetLiquidElectronDriftSpeed(double T, double F, G4bool M, G4int Z)
G4S2Light(const G4String &processName="S2", G4ProcessType type=fElectromagnetic)
Definition: G4S2Light.cc:66
G4bool fTrackSecondariesFirst
Definition: G4S2Light.hh:76
#define CTH
Definition: G4S1Light.hh:40
#define PMT
Definition: G4S1Light.hh:42
volt_as<> volt
Type of potential stored in volts, in double precision.
G4double GetGasElectronDriftSpeed(G4double efieldinput, G4double density)
Definition: G4S2Light.cc:315
G4double ConvertEff[100]
Definition: G4S2Light.cc:61
G4double GetMeanLifeTime(const G4Track &aTrack, G4ForceCondition *)
Definition: G4S2Light.cc:308
int twopi
Definition: units.py:12
#define GASGAP
Definition: G4S1Light.hh:28
G4VParticleChange * AtRestDoIt(const G4Track &aTrack, const G4Step &aStep)
Definition: G4S2Light.cc:85
static constexpr double mm
Definition: Units.h:65
#define GRID_DENSITY
Definition: G4S2Light.cc:57
G4double E_eV[100]
Definition: G4S2Light.cc:60
G4double GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *)
Definition: G4S2Light.cc:258
QAsciiDict< Entry > ns
double Density(double r)
Definition: PREM.cxx:18
static QCString * s
Definition: config.cpp:1042