G4S1Light.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 "G4S1Light" physics process
33 //
34 ////////////////////////////////////////////////////////////////////////
35 // S1 Scintillation Light Class Implementation
36 ////////////////////////////////////////////////////////////////////////
37 //
38 // File: G4S1Light.cc (lives in physicslist/src)
39 // Description: (Rest)Discrete Process - Generation of S1 Photons
40 // Version: 0.98 Final
41 // Created: Thursday, January 17, 2013 12:35 PM
42 // Author: Matthew Szydagis, UC Davis
43 //
44 // mail: mmszydagis@ucdavis.edu, matthew.szydagis@gmail.com
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 "G4Version.hh" //tells you what Geant4 version you are running
51 
52 #include <G4SystemOfUnits.hh>
53 #include <G4PhysicalConstants.hh>
54 
55 #include "G4S1Light.hh"
56 
57 #define MIN_ENE -1*CLHEP::eV //lets you turn NEST off BELOW a certain energy
58 #define MAX_ENE 1.*CLHEP::TeV //lets you turn NEST off ABOVE a certain energy
59 #define HIENLIM 5*CLHEP::MeV //energy at which Doke model used exclusively
60 
61 #define R_TOL 0.2*CLHEP::mm //tolerance (for edge events)
62 #define R_MAX 1*CLHEP::km //for corraling diffusing electrons
63 G4bool diffusion = true;
64 
65 G4bool SinglePhase=false, ThomasImelTail=true, OutElectrons=true;
66 G4double GetGasElectronDriftSpeed(G4double efieldinput,G4double density);
67 G4double GetLiquidElectronDriftSpeed(double T, double F, G4bool M, G4int Z);
68 G4double CalculateElectronLET ( G4double E, G4int Z );
69 
70 G4double biExc = 0.77; //for alpha particles (bi-excitonic collisions)
71 G4double UnivScreenFunc ( G4double E, G4double Z, G4double A );
72 
73 G4int BinomFluct(G4int N0, G4double prob); //function for doing fluctuations
74 
75 void InitMatPropValues ( G4MaterialPropertiesTable* nobleElementMat );
76 
77 #define Density_LXe 2.9 //reference density for density-dep. effects
78 #define Density_LAr 1.393
79 #define Density_LNe 1.207
80 #define Density_LKr 2.413
81 
82 G4S1Light::G4S1Light(const G4String& processName,
83  G4ProcessType type)
84  : G4VRestDiscreteProcess(processName, type)
85 {
86  //luxManager = LUXSimManager::GetManager();
87  SetProcessSubType(fScintillation);
88 
89  fTrackSecondariesFirst = false;
90  //particles die first, then scintillation is generated
91 
92  if (verboseLevel>0) {
93  G4cout << GetProcessName() << " is created " << G4endl;
94  }
95 }
96 
97 G4S1Light::~G4S1Light(){} //destructor needed to avoid linker error
98 
99 G4VParticleChange*
100 G4S1Light::AtRestDoIt(const G4Track& aTrack, const G4Step& aStep)
101 
102 // This routine simply calls the equivalent PostStepDoIt since all the
103 // necessary information resides in aStep.GetTotalEnergyDeposit()
104 {
105  return G4S1Light::PostStepDoIt(aTrack, aStep);
106 }
107 
108 G4VParticleChange*
109 G4S1Light::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
110 // this is the most important function, where all light & charge yields happen!
111 {
112  aParticleChange.Initialize(aTrack);
113 
114  if ( !YieldFactor ) //set YF=0 when you want S1Light off in your sim
115  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
116 
117  if( aTrack.GetParentID() == 0 && aTrack.GetCurrentStepNumber() == 1 ) {
118  fExcitedNucleus = false; //an initialization or reset
119  fVeryHighEnergy = false; //initializes or (later) resets this
120  fAlpha = false; //ditto
121  fMultipleScattering = false;
122  }
123 
124  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
125  G4ParticleDefinition *pDef = aParticle->GetDefinition();
126  G4String particleName = pDef->GetParticleName();
127  const G4Material* aMaterial = aStep.GetPreStepPoint()->GetMaterial();
128  const G4Material* bMaterial = aStep.GetPostStepPoint()->GetMaterial();
129 
130  if((particleName == "neutron" || particleName == "antineutron") &&
131  aStep.GetTotalEnergyDeposit() <= 0)
132  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
133 
134  // code for determining whether the present/next material is noble
135  // element, or, in other words, for checking if either is a valid NEST
136  // scintillating material, and save Z for later L calculation, or
137  // return if no valid scintillators are found on this step, which is
138  // protection against G4Exception or seg. fault/violation
139  G4Element *ElementA = NULL, *ElementB = NULL;
140  if (aMaterial && aMaterial->GetMaterialPropertiesTable()) {
141  const G4ElementVector* theElementVector1 =
142  aMaterial->GetElementVector();
143  ElementA = (*theElementVector1)[0];
144  }
145  if (bMaterial && bMaterial->GetMaterialPropertiesTable()) {
146  const G4ElementVector* theElementVector2 =
147  bMaterial->GetElementVector();
148  ElementB = (*theElementVector2)[0];
149  }
150  G4int z1,z2,j=1; G4bool NobleNow=false,NobleLater=false;
151  if (ElementA) z1 = (G4int)(ElementA->GetZ()); else z1 = -1;
152  if (ElementB) z2 = (G4int)(ElementB->GetZ()); else z2 = -1;
153  if ( z1==2 || z1==10 || z1==18 || z1==36 || z1==54 ) {
154  NobleNow = true;
155  j = (G4int)aMaterial->GetMaterialPropertiesTable()->
156  GetConstProperty("TOTALNUM_INT_SITES"); //get current number
157  if ( j < 0 ) {
158  InitMatPropValues(aMaterial->GetMaterialPropertiesTable());
159  j = 0; //no sites yet
160  } //material properties initialized
161  } //end of atomic number check
162  if ( z2==2 || z2==10 || z2==18 || z2==36 || z2==54 ) {
163  NobleLater = true;
164  j = (G4int)bMaterial->GetMaterialPropertiesTable()->
165  GetConstProperty("TOTALNUM_INT_SITES");
166  if ( j < 0 ) {
167  InitMatPropValues(bMaterial->GetMaterialPropertiesTable());
168  j = 0; //no sites yet
169  } //material properties initialized
170  } //end of atomic number check
171 
172  if ( !NobleNow && !NobleLater )
173  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
174 
175  // retrieval of the particle's position, time, attributes at both the
176  // beginning and the end of the current step along its track
177  G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
178  G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
179  G4ThreeVector x1 = pPostStepPoint->GetPosition();
180  G4ThreeVector x0 = pPreStepPoint->GetPosition();
181  G4double evtStrt = pPreStepPoint->GetGlobalTime();
182  G4double t0 = pPreStepPoint->GetLocalTime();
183  G4double t1 = pPostStepPoint->GetLocalTime();
184 
185  // now check if we're entering a scintillating material (inside) or
186  // leaving one (outside), in order to determine (later on in the code,
187  // based on the booleans inside & outside) whether to add/subtract
188  // energy that can potentially be deposited from the system
189  G4bool outside = false, inside = false, InsAndOuts = false;
190  G4MaterialPropertiesTable* aMaterialPropertiesTable =
191  aMaterial->GetMaterialPropertiesTable();
192  if ( NobleNow && !NobleLater ) outside = true;
193  if ( !NobleNow && NobleLater ) {
194  aMaterial = bMaterial; inside = true; z1 = z2;
195  ElementA = ElementB;
196  aMaterialPropertiesTable = bMaterial->GetMaterialPropertiesTable();
197  }
198  if ( NobleNow && NobleLater &&
199  aMaterial->GetDensity() != bMaterial->GetDensity() )
200  InsAndOuts = true;
201 
202  // Get the LUXSimMaterials pointer
203  //LUXSimMaterials *luxMaterials = LUXSimMaterials::GetMaterials();
204 
205  // retrieve scintillation-related material properties
206  G4double Density = aMaterial->GetDensity()/(CLHEP::g/CLHEP::cm3);
207  G4double nDensity = Density*AVO; //molar mass factor applied below
208  G4int Phase = aMaterial->GetState(); //solid, liquid, or gas?
209  G4double ElectricField, FieldSign; //for field quenching of S1
210  G4bool GlobalFields = false;
211  if ( !WIN && !TOP && !ANE && !SRF && !GAT && !CTH && !BOT && !PMT ) {
212  ElectricField = aMaterialPropertiesTable->
213  GetConstProperty("ELECTRICFIELD"); GlobalFields = true; }
214  else {
215  if ( x1[2] < WIN && x1[2] > TOP && Phase == kStateGas )
216  ElectricField = aMaterialPropertiesTable->
217  GetConstProperty("ELECTRICFIELDWINDOW");
218  else if ( x1[2] < TOP && x1[2] > ANE && Phase == kStateGas )
219  ElectricField = aMaterialPropertiesTable->
220  GetConstProperty("ELECTRICFIELDTOP");
221  else if ( x1[2] < ANE && x1[2] > SRF && Phase == kStateGas )
222  ElectricField = aMaterialPropertiesTable->
223  GetConstProperty("ELECTRICFIELDANODE");
224  else if ( x1[2] < SRF && x1[2] > GAT && Phase == kStateLiquid )
225  ElectricField = aMaterialPropertiesTable->
226  GetConstProperty("ELECTRICFIELDSURFACE");
227  else if ( x1[2] < GAT && x1[2] > CTH && Phase == kStateLiquid )
228  ElectricField = aMaterialPropertiesTable->
229  GetConstProperty("ELECTRICFIELDGATE");
230  else if ( x1[2] < CTH && x1[2] > BOT && Phase == kStateLiquid )
231  ElectricField = aMaterialPropertiesTable->
232  GetConstProperty("ELECTRICFIELDCATHODE");
233  else if ( x1[2] < BOT && x1[2] > PMT && Phase == kStateLiquid )
234  ElectricField = aMaterialPropertiesTable->
235  GetConstProperty("ELECTRICFIELDBOTTOM");
236  else
237  ElectricField = aMaterialPropertiesTable->
238  GetConstProperty("ELECTRICFIELD");
239  }
240  if ( ElectricField >= 0 ) FieldSign = 1; else FieldSign = -1;
241  ElectricField = fabs((1e3*ElectricField)/(CLHEP::kilovolt/CLHEP::cm));
242  G4double Temperature = aMaterial->GetTemperature();
243  G4double ScintillationYield, ResolutionScale, R0 = 1.0*CLHEP::um,
244  DokeBirks[3], ThomasImel = 0.00, delta = 1*CLHEP::mm;
245  DokeBirks[0] = 0.00; DokeBirks[2] = 1.00;
246  G4double PhotMean = 7*CLHEP::eV, PhotWidth = 1.0*CLHEP::eV; //photon properties
247  G4double SingTripRatioR, SingTripRatioX, tau1, tau3, tauR = 0*CLHEP::ns;
248  switch ( z1 ) { //sort prop. by noble element atomic#
249  case 2: //helium
250  ScintillationYield = 1 / (41.3*CLHEP::eV); //all W's from noble gas book
251  ExcitationRatio = 0.00; //nominal (true value unknown)
252  ResolutionScale = 0.2; //Aprile, Bolotnikov, Bolozdynya, Doke
253  PhotMean = 15.9*CLHEP::eV;
254  tau1 = G4RandGauss::shoot(10.0*CLHEP::ns,0.0*CLHEP::ns);
255  tau3 = 1.6e3*CLHEP::ns;
256  tauR = G4RandGauss::shoot(13.00*CLHEP::s,2.00*CLHEP::s); //McKinsey et al. 2003
257  break;
258  case 10: //neon
259  ScintillationYield = 1 / (29.2*CLHEP::eV);
260  ExcitationRatio = 0.00; //nominal (true value unknown)
261  ResolutionScale = 0.13; //Aprile et. al book
262  PhotMean = 15.5*CLHEP::eV; PhotWidth = 0.26*CLHEP::eV;
263  tau1 = G4RandGauss::shoot(10.0*CLHEP::ns,10.*CLHEP::ns);
264  tau3 = G4RandGauss::shoot(15.4e3*CLHEP::ns,200*CLHEP::ns); //Nikkel et al. 2008
265  break;
266  case 18: //argon
267  ScintillationYield = 1 / (19.5*CLHEP::eV);
268  ExcitationRatio = 0.21; //Aprile et. al book
269  ResolutionScale = 0.107; //Doke 1976
270  R0 = 1.568*CLHEP::um; //Mozumder 1995
271  if(ElectricField) {
272  ThomasImel = 0.156977*pow(ElectricField,-0.1);
273  DokeBirks[0] = 0.07*pow((ElectricField/1.0e3),-0.85);
274  DokeBirks[2] = 0.00;
275  }
276  else {
277  ThomasImel = 0.099;
278  DokeBirks[0] = 0.0003;
279  DokeBirks[2] = 0.75;
280  } nDensity /= 39.948; //molar mass in grams per mole
281  PhotMean = 9.69*CLHEP::eV; PhotWidth = 0.22*CLHEP::eV;
282  tau1 = G4RandGauss::shoot(6.5*CLHEP::ns,0.8*CLHEP::ns); //err from wgted avg.
283  tau3 = G4RandGauss::shoot(1300*CLHEP::ns,50*CLHEP::ns); //ibid.
284  tauR = G4RandGauss::shoot(0.8*CLHEP::ns,0.2*CLHEP::ns); //Kubota 1979
285  biExc = 0.6; break;
286  case 36: //krypton
287  if ( Phase == kStateGas ) ScintillationYield = 1 / (30.0*CLHEP::eV);
288  else ScintillationYield = 1 / (15.0*CLHEP::eV);
289  ExcitationRatio = 0.08; //Aprile et. al book
290  ResolutionScale = 0.05; //Doke 1976
291  PhotMean = 8.43*CLHEP::eV;
292  tau1 = G4RandGauss::shoot(2.8*CLHEP::ns,.04*CLHEP::ns);
293  tau3 = G4RandGauss::shoot(93.*CLHEP::ns,1.1*CLHEP::ns);
294  tauR = G4RandGauss::shoot(12.*CLHEP::ns,.76*CLHEP::ns);
295  break;
296  case 54: //xenon
297  default: nDensity /= 131.293;
298  ScintillationYield = 48.814+0.80877*Density+2.6721*pow(Density,2.);
299  ScintillationYield /= CLHEP::keV; //Units: [#quanta(ph/e-) per keV]
300  //W = 13.7 eV for all recoils, Dahl thesis (that's @2.84 g/cm^3)
301  //the exciton-to-ion ratio (~0.06 for LXe at 3 g/cm^3)
302  ExcitationRatio = 0.4-0.11131*Density-0.0026651*pow(Density,2.);
303  ResolutionScale = 1.00 * //Fano factor <<1
304  (0.12724-0.032152*Density-0.0013492*pow(Density,2.));
305  //~0.1 for GXe w/ formula from Bolotnikov et al. 1995
306  if ( Phase == kStateLiquid ) {
307  ResolutionScale *= 1.5; //to get it to be ~0.03 for LXe
308  R0 = 16.6*CLHEP::um; //for zero electric field
309  //length scale above which Doke model used instead of Thomas-Imel
310  if(ElectricField) //change it with field (see NEST paper)
311  R0 = 69.492*pow(ElectricField,-0.50422)*CLHEP::um;
312  if(ElectricField) { //formulae & values all from NEST paper
313  DokeBirks[0]= 19.171*pow(ElectricField+25.552,-0.83057)+0.026772;
314  DokeBirks[2] = 0.00; //only volume recombination (above)
315  }
316  else { //zero electric field magnitude
317  DokeBirks[0] = 0.18; //volume/columnar recombination factor (A)
318  DokeBirks[2] = 0.58; //geminate/Onsager recombination (C)
319  }
320  //"ThomasImel" is alpha/(a^2*v), the recomb. coeff.
321  ThomasImel = 0.05; //aka xi/(4*N_i) from the NEST paper
322  //distance used to determine when one is at a new interaction site
323  delta = 0.4*CLHEP::mm; //distance ~30 keV x-ray travels in LXe
324  PhotMean = 6.97*CLHEP::eV; PhotWidth = 0.23*CLHEP::eV;
325  // 178+/-14nmFWHM, taken from Jortner JchPh 42 '65.
326  //these singlet and triplet times may not be the ones you're
327  //used to, but are the world average: Kubota 79, Hitachi 83 (2
328  //data sets), Teymourian 11, Morikawa 89, and Akimov '02
329  tau1 = G4RandGauss::shoot(3.1*CLHEP::ns,.7*CLHEP::ns); //err from wgted avg.
330  tau3 = G4RandGauss::shoot(24.*CLHEP::ns,1.*CLHEP::ns); //ibid.
331  } //end liquid
332  else if ( Phase == kStateGas ) {
333  if(!fAlpha) ExcitationRatio=0.07; //Nygren NIM A 603 (2009) p. 340
334  else { biExc = 1.00;
335  ScintillationYield = 1 / (12.98*CLHEP::eV); } //Saito 2003
336  R0 = 0.0*CLHEP::um; //all Doke/Birks interactions (except for alphas)
337  G4double Townsend = (ElectricField/nDensity)*1e17;
338  DokeBirks[0] = 0.0000; //all geminate (except at zero, low fields)
339  DokeBirks[2] = 0.1933*pow(Density,2.6199)+0.29754 -
340  (0.045439*pow(Density,2.4689)+0.066034)*log10(ElectricField);
341  if ( ElectricField>6990 ) DokeBirks[2]=0.0;
342  if ( ElectricField<1000 ) DokeBirks[2]=0.2;
343  if ( ElectricField<100. ) { DokeBirks[0]=0.18; DokeBirks[2]=0.58; }
344  if( Density < 0.061 ) ThomasImel = 0.041973*pow(Density,1.8105);
345  else if( Density >= 0.061 && Density <= 0.167 )
346  ThomasImel=5.9583e-5+0.0048523*Density-0.023109*pow(Density,2.);
347  else ThomasImel = 6.2552e-6*pow(Density,-1.9963);
348  if(ElectricField)ThomasImel=1.2733e-5*pow(Townsend/Density,-0.68426);
349  // field\density dependence from Kobayashi 2004 and Saito 2003
350  PhotMean = 7.1*CLHEP::eV; PhotWidth = 0.2*CLHEP::eV;
351  tau1 = G4RandGauss::shoot(5.18*CLHEP::ns,1.55*CLHEP::ns);
352  tau3 = G4RandGauss::shoot(100.1*CLHEP::ns,7.9*CLHEP::ns);
353  } //end gas information (preliminary guesses)
354  else {
355  tau1 = 3.5*CLHEP::ns; tau3 = 20.*CLHEP::ns; tauR = 40.*CLHEP::ns;
356  } //solid Xe
357  }
358 
359  // log present and running tally of energy deposition in this section
360  G4double anExcitationEnergy = ((const G4Ions*)(pDef))->
361  GetExcitationEnergy(); //grab nuclear energy level
362  G4double TotalEnergyDeposit = //total energy deposited so far
363  aMaterialPropertiesTable->GetConstProperty( "ENERGY_DEPOSIT_TOT" );
364  G4bool convert = false, annihil = false;
365  //set up special cases for pair production and positron annihilation
366  if(pPreStepPoint->GetKineticEnergy()>=(2*CLHEP::electron_mass_c2) &&
367  !pPostStepPoint->GetKineticEnergy() &&
368  !aStep.GetTotalEnergyDeposit() && aParticle->GetPDGcode()==22) {
369  convert = true; TotalEnergyDeposit = CLHEP::electron_mass_c2;
370  }
371  if(pPreStepPoint->GetKineticEnergy() &&
372  !pPostStepPoint->GetKineticEnergy() &&
373  aParticle->GetPDGcode()==-11) {
374  annihil = true; TotalEnergyDeposit += aStep.GetTotalEnergyDeposit();
375  }
376  G4bool either = false;
377  if(inside || outside || convert || annihil || InsAndOuts) either=true;
378  //conditions for returning when energy deposits too low
379  if( anExcitationEnergy<100*CLHEP::eV && aStep.GetTotalEnergyDeposit()<1*CLHEP::eV &&
380  !either && !fExcitedNucleus )
381  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
382  //add current deposit to total energy budget
383  if ( !annihil ) TotalEnergyDeposit += aStep.GetTotalEnergyDeposit();
384  if ( !convert ) aMaterialPropertiesTable->
385  AddConstProperty( "ENERGY_DEPOSIT_TOT", TotalEnergyDeposit );
386  //save current deposit for determining number of quanta produced now
387  TotalEnergyDeposit = aStep.GetTotalEnergyDeposit();
388 
389  // check what the current "goal" E is for dumping scintillation,
390  // often the initial kinetic energy of the parent particle, and deal
391  // with all other energy-related matters in this block of code
392  G4double InitialKinetEnergy = aMaterialPropertiesTable->
393  GetConstProperty( "ENERGY_DEPOSIT_GOL" );
394  //if zero, add up initial potential and kinetic energies now
395  if ( InitialKinetEnergy == 0 ) {
396  G4double tE = pPreStepPoint->GetKineticEnergy()+anExcitationEnergy;
397  if ( (fabs(tE-1.8*CLHEP::keV) < 1*CLHEP::eV
398  || fabs(tE-9.4*CLHEP::keV) < 1*CLHEP::eV) &&
399  Phase == kStateLiquid && z1 == 54 ) tE = 9.4*CLHEP::keV;
400  if ( fKr83m && ElectricField != 0 )
401  DokeBirks[2] = 0.10;
402  aMaterialPropertiesTable->
403  AddConstProperty ( "ENERGY_DEPOSIT_GOL", tE );
404  //excited nucleus is special case where accuracy reduced for total
405  //energy deposition because of G4 inaccuracies and scintillation is
406  //forced-dumped when that nucleus is fully de-excited
407  if ( anExcitationEnergy ) fExcitedNucleus = true;
408  }
409  //if a particle is leaving, remove its kinetic energy from the goal
410  //energy, as this will never get deposited (if depositable)
411  if(outside){ aMaterialPropertiesTable->
412  AddConstProperty("ENERGY_DEPOSIT_GOL",
413  InitialKinetEnergy-pPostStepPoint->GetKineticEnergy());
414  if(aMaterialPropertiesTable->
415  GetConstProperty("ENERGY_DEPOSIT_GOL")<0)
416  aMaterialPropertiesTable->AddConstProperty("ENERGY_DEPOSIT_GOL",0);
417  }
418  //if a particle is coming back into your scintillator, then add its
419  //energy to the goal energy
420  if(inside) { aMaterialPropertiesTable->
421  AddConstProperty("ENERGY_DEPOSIT_GOL",
422  InitialKinetEnergy+pPreStepPoint->GetKineticEnergy());
423  if ( TotalEnergyDeposit > 0 && InitialKinetEnergy == 0 ) {
424  aMaterialPropertiesTable->AddConstProperty("ENERGY_DEPOSIT_GOL",0);
425  TotalEnergyDeposit = .000000;
426  }
427  }
428  if ( InsAndOuts ) {
429  //G4double dribble = pPostStepPoint->GetKineticEnergy() -
430  //pPreStepPoint->GetKineticEnergy();
431  aMaterialPropertiesTable->
432  AddConstProperty("ENERGY_DEPOSIT_GOL",(-0.1*CLHEP::keV)+
433  InitialKinetEnergy-pPostStepPoint->GetKineticEnergy());
434  InitialKinetEnergy = bMaterial->GetMaterialPropertiesTable()->
435  GetConstProperty("ENERGY_DEPOSIT_GOL");
436  bMaterial->GetMaterialPropertiesTable()->
437  AddConstProperty("ENERGY_DEPOSIT_GOL",(-0.1*CLHEP::keV)+
438  InitialKinetEnergy+pPreStepPoint->GetKineticEnergy());
439  if(aMaterialPropertiesTable->
440  GetConstProperty("ENERGY_DEPOSIT_GOL")<0)
441  aMaterialPropertiesTable->AddConstProperty("ENERGY_DEPOSIT_GOL",0);
442  if ( bMaterial->GetMaterialPropertiesTable()->
443  GetConstProperty("ENERGY_DEPOSIT_GOL") < 0 )
444  bMaterial->GetMaterialPropertiesTable()->
445  AddConstProperty ( "ENERGY_DEPOSIT_GOL", 0 );
446  }
447  InitialKinetEnergy = aMaterialPropertiesTable->
448  GetConstProperty("ENERGY_DEPOSIT_GOL"); //grab current goal E
449  if ( annihil ) { //if an annihilation occurred, add energy of two gammas
450  InitialKinetEnergy += 2*CLHEP::electron_mass_c2;
451  }
452  //if pair production occurs, then subtract energy to cancel with the
453  //energy that will be added in the line above when the e+ dies
454  if ( convert ) {
455  InitialKinetEnergy -= 2*CLHEP::electron_mass_c2;
456  }
457  //update the relevant material property (goal energy)
458  aMaterialPropertiesTable->
459  AddConstProperty("ENERGY_DEPOSIT_GOL",InitialKinetEnergy);
460  if (anExcitationEnergy < 1e-100 && aStep.GetTotalEnergyDeposit()==0 &&
461  aMaterialPropertiesTable->GetConstProperty("ENERGY_DEPOSIT_GOL")==0 &&
462  aMaterialPropertiesTable->GetConstProperty("ENERGY_DEPOSIT_TOT")==0)
463  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
464 
465  G4String procName;
466  if ( aTrack.GetCreatorProcess() )
467  procName = aTrack.GetCreatorProcess()->GetProcessName();
468  else
469  procName = "NULL";
470  if ( procName == "eBrem" && outside && !OutElectrons )
471  fMultipleScattering = true;
472 
473  // next 2 codeblocks deal with position-related things
474  if ( fAlpha ) delta = 1000.*CLHEP::km;
475  G4int i, k, counter = 0; G4double pos[3];
476  if ( outside ) { //leaving
477  if ( aParticle->GetPDGcode() == 11 && !OutElectrons )
478  fMultipleScattering = true;
479  x1 = x0; //prevents generation of quanta outside active volume
480  } //no scint. for e-'s that leave
481 
482  char xCoord[80]; char yCoord[80]; char zCoord[80];
483  G4bool exists = false; //for querying whether set-up of new site needed
484  for(i=0;i<j;i++) { //loop over all saved interaction sites
485  counter = i; //save site# for later use in storing properties
486  sprintf(xCoord,"POS_X_%d",i); sprintf(yCoord,"POS_Y_%d",i);
487  sprintf(zCoord,"POS_Z_%d",i);
488  pos[0] = aMaterialPropertiesTable->GetConstProperty(xCoord);
489  pos[1] = aMaterialPropertiesTable->GetConstProperty(yCoord);
490  pos[2] = aMaterialPropertiesTable->GetConstProperty(zCoord);
491  if ( sqrt(pow(x1[0]-pos[0],2.)+pow(x1[1]-pos[1],2.)+
492  pow(x1[2]-pos[2],2.)) < delta ) {
493  exists = true; break; //we find interaction is close to an old one
494  }
495  }
496  if(!exists && TotalEnergyDeposit) { //current interaction too far away
497  counter = j;
498  sprintf(xCoord,"POS_X_%i",j); sprintf(yCoord,"POS_Y_%i",j);
499  sprintf(zCoord,"POS_Z_%i",j);
500  //save 3-space coordinates of the new interaction site
501  aMaterialPropertiesTable->AddConstProperty( xCoord, x1[0] );
502  aMaterialPropertiesTable->AddConstProperty( yCoord, x1[1] );
503  aMaterialPropertiesTable->AddConstProperty( zCoord, x1[2] );
504  j++; //increment number of sites
505  aMaterialPropertiesTable-> //save
506  AddConstProperty( "TOTALNUM_INT_SITES", j );
507  }
508 
509  // this is where nuclear recoil "L" factor is handled: total yield is
510  // reduced for nuclear recoil as per Lindhard theory
511 
512  //we assume you have a mono-elemental scintillator only
513  //now, grab A's and Z's of current particle and of material (avg)
514  G4double a1 = ElementA->GetA();
515  z2 = pDef->GetAtomicNumber();
516  G4double a2 = (G4double)(pDef->GetAtomicMass());
517  if ( particleName == "alpha" || (z2 == 2 && a2 == 4) )
518  fAlpha = true; //used later to get S1 pulse shape correct for alpha
519  if ( fAlpha || abs(aParticle->GetPDGcode()) == 2112 )
520  a2 = a1; //get average A for element at hand
521  G4double epsilon = 11.5*(TotalEnergyDeposit/CLHEP::keV)*pow(z1,(-7./3.));
522  G4double gamma = 3.*pow(epsilon,0.15)+0.7*pow(epsilon,0.6)+epsilon;
523  G4double kappa = 0.133*pow(z1,(2./3.))*pow(a2,(-1./2.))*(2./3.);
524  //check if we are dealing with nuclear recoil (Z same as material)
525  if ( (z1 == z2 && pDef->GetParticleType() == "nucleus") ||
526  particleName == "neutron" || particleName == "antineutron" ) {
527  YieldFactor=(kappa*gamma)/(1+kappa*gamma); //Lindhard factor
528  if ( z1 == 18 && Phase == kStateLiquid )
529  YieldFactor=0.23*(1+exp(-5*epsilon)); //liquid argon L_eff
530  //just a few safety checks, like for recombProb below
531  if ( YieldFactor > 1 ) YieldFactor = 1;
532  if ( YieldFactor < 0 ) YieldFactor = 0;
533  if ( ElectricField == 0 && Phase == kStateLiquid ) {
534  if ( z1 == 54 ) ThomasImel = 0.19;
535  if ( z1 == 18 ) ThomasImel = 0.25;
536  } //special TIB parameters for nuclear recoil only, in LXe and LAr
537  ExcitationRatio = 0.69337 +
538  0.3065*exp(-0.008806*pow(ElectricField,0.76313));
539  }
540  else YieldFactor = 1.000; //default
541 
542  // determine ultimate #quanta from current E-deposition (ph+e-)
543  G4double MeanNumberOfQuanta = //total mean number of exc/ions
544  ScintillationYield*TotalEnergyDeposit;
545  //the total number of either quanta produced is equal to product of the
546  //work function, the energy deposited, and yield reduction, for NR
547  G4double sigma = sqrt(ResolutionScale*MeanNumberOfQuanta); //Fano
548  G4int NumQuanta = //stochastic variation in NumQuanta
549  G4int(floor(G4RandGauss::shoot(MeanNumberOfQuanta,sigma)+0.5));
550  G4double LeffVar = G4RandGauss::shoot(YieldFactor,0.25*YieldFactor);
551  if (LeffVar > 1) LeffVar = 1.00000;
552  if (LeffVar < 0) LeffVar = 0;
553  if ( YieldFactor < 1 ) NumQuanta = BinomFluct(NumQuanta,LeffVar);
554  //if E below work function, can't make any quanta, and if NumQuanta
555  //less than zero because Gaussian fluctuated low, update to zero
556  if(TotalEnergyDeposit < 1/ScintillationYield || NumQuanta < 0)
557  NumQuanta = 0;
558 
559  // next section binomially assigns quanta to excitons and ions
560  G4int NumExcitons =
562  G4int NumIons = NumQuanta - NumExcitons;
563 
564  // this section calculates recombination following the modified Birks'
565  // Law of Doke, deposition by deposition, and may be overridden later
566  // in code if a low enough energy necessitates switching to the
567  // Thomas-Imel box model for recombination instead (determined by site)
568  G4double dE, dx=0, LET=0, recombProb;
569  dE = TotalEnergyDeposit/CLHEP::MeV;
570  if ( particleName != "e-" && particleName != "e+" && z1 != z2 &&
571  particleName != "mu-" && particleName != "mu+" ) {
572  //in other words, if it's a gamma,ion,proton,alpha,pion,et al. do not
573  //use the step length provided by Geant4 because it's not relevant,
574  //instead calculate an estimated LET and range of the electrons that
575  //would have been produced if Geant4 could track them
576  LET = CalculateElectronLET( 1000*dE, z1 );
577  if(LET) dx = dE/(Density*LET); //find the range based on the LET
578  if(abs(aParticle->GetPDGcode())==2112) dx=0;
579  }
580  else { //normal case of an e-/+ energy deposition recorded by Geant
581  dx = aStep.GetStepLength()/CLHEP::cm;
582  if(dx) LET = (dE/dx)*(1/Density); //lin. energy xfer (prop. to dE/dx)
583  if ( LET > 0 && dE > 0 && dx > 0 ) {
584  G4double ratio = CalculateElectronLET(dE*1e3,z1)/LET;
585  if ( j == 1 && ratio < 0.7 && !ThomasImelTail &&
586  particleName == "e-" ) {
587  dx /= ratio; LET *= ratio; }}
588  }
589  DokeBirks[1] = DokeBirks[0]/(1-DokeBirks[2]); //B=A/(1-C) (see paper)
590  //Doke/Birks' Law as spelled out in the NEST paper
591  recombProb = (DokeBirks[0]*LET)/(1+DokeBirks[1]*LET)+DokeBirks[2];
592  if ( Phase == kStateLiquid ) {
593  if ( z1 == 54 ) recombProb *= (Density/Density_LXe);
594  if ( z1 == 18 ) recombProb *= (Density/Density_LAr);
595  }
596  //check against unphysicality resulting from rounding errors
597  if(recombProb<0) recombProb=0;
598  if(recombProb>1) recombProb=1;
599  //use binomial distribution to assign photons, electrons, where photons
600  //are excitons plus recombined ionization electrons, while final
601  //collected electrons are the "escape" (non-recombined) electrons
602  G4int NumPhotons = NumExcitons + BinomFluct(NumIons,recombProb);
603  G4int NumElectrons = NumQuanta - NumPhotons;
604 
605 #define DETSIM
606 #ifdef DETSIM
607  // The number of photons and electrons for this step has been
608  // calculated using the Doke/Birk law version of recombination. For
609  // DETSIM we are only looking at argon, and according the Matt both
610  // Doke-Birks and Thomas-Imel fit the data. The rest of the code is
611  // short-circuited and we tally the energy that got turned into
612  // photons.
613  G4double nonIonizingEnergy = TotalEnergyDeposit;
614  nonIonizingEnergy *= 1.0*NumPhotons/NumQuanta;
615  aParticleChange.ProposeNonIonizingEnergyDeposit(nonIonizingEnergy);
616  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
617 #endif
618 
619  // next section increments the numbers of excitons, ions, photons, and
620  // electrons for the appropriate interaction site; it only appears to
621  // be redundant by saving seemingly no longer needed exciton and ion
622  // counts, these having been already used to calculate the number of ph
623  // and e- above, whereas it does need this later for Thomas-Imel model
624  char numExc[80]; char numIon[80]; char numPho[80]; char numEle[80];
625  sprintf(numExc,"N_EXC_%i",counter); sprintf(numIon,"N_ION_%i",counter);
626  NumExcitons += (G4int)aMaterialPropertiesTable->
627  GetConstProperty( numExc );
628  NumIons += (G4int)aMaterialPropertiesTable->
629  GetConstProperty( numIon );
630  aMaterialPropertiesTable->AddConstProperty( numExc, NumExcitons );
631  aMaterialPropertiesTable->AddConstProperty( numIon, NumIons );
632  sprintf(numPho,"N_PHO_%i",counter); sprintf(numEle,"N_ELE_%i",counter);
633  NumPhotons +=(G4int)aMaterialPropertiesTable->
634  GetConstProperty( numPho );
635  NumElectrons +=(G4int)aMaterialPropertiesTable->
636  GetConstProperty( numEle );
637  aMaterialPropertiesTable->AddConstProperty( numPho, NumPhotons );
638  aMaterialPropertiesTable->AddConstProperty( numEle, NumElectrons );
639 
640  // increment and save the total track length, and save interaction
641  // times for later, when generating the scintillation quanta
642  char trackL[80]; char time00[80]; char time01[80]; char energy[80];
643  sprintf(trackL,"TRACK_%i",counter); sprintf(energy,"ENRGY_%i",counter);
644  sprintf(time00,"TIME0_%i",counter); sprintf(time01,"TIME1_%i",counter);
645  delta = aMaterialPropertiesTable->GetConstProperty( trackL );
646  G4double energ = aMaterialPropertiesTable->GetConstProperty( energy );
647  delta += dx*CLHEP::cm; energ += dE*CLHEP::MeV;
648  aMaterialPropertiesTable->AddConstProperty( trackL, delta );
649  aMaterialPropertiesTable->AddConstProperty( energy, energ );
650  if ( TotalEnergyDeposit > 0 ) {
651  G4double deltaTime = aMaterialPropertiesTable->
652  GetConstProperty( time00 );
653  //for charged particles, which continuously lose energy, use initial
654  //interaction time as the minimum time, otherwise use only the final
655  if (aParticle->GetCharge() != 0) {
656  if (t0 < deltaTime)
657  aMaterialPropertiesTable->AddConstProperty( time00, t0 );
658  }
659  else {
660  if (t1 < deltaTime)
661  aMaterialPropertiesTable->AddConstProperty( time00, t1 );
662  }
663  deltaTime = aMaterialPropertiesTable->GetConstProperty( time01 );
664  //find the maximum possible scintillation "birth" time
665  if (t1 > deltaTime)
666  aMaterialPropertiesTable->AddConstProperty( time01, t1 );
667  }
668 
669  // begin the process of setting up creation of scint./ionization
670  TotalEnergyDeposit=aMaterialPropertiesTable->
671  GetConstProperty("ENERGY_DEPOSIT_TOT"); //get the total E deposited
672  InitialKinetEnergy=aMaterialPropertiesTable->
673  GetConstProperty("ENERGY_DEPOSIT_GOL"); //E that should have been
674  if(InitialKinetEnergy > HIENLIM &&
675  abs(aParticle->GetPDGcode()) != 2112) fVeryHighEnergy=true;
676  G4double safety; //margin of error for TotalE.. - InitialKinetEnergy
677  if (fVeryHighEnergy && !fExcitedNucleus) safety = 0.2*CLHEP::keV;
678  else safety = 2.*CLHEP::eV;
679 
680  //force a scintillation dump for NR and for full nuclear de-excitation
681  if( !anExcitationEnergy && pDef->GetParticleType() == "nucleus" &&
682  aTrack.GetTrackStatus() != fAlive && !fAlpha )
683  InitialKinetEnergy = TotalEnergyDeposit;
684  if ( particleName == "neutron" || particleName == "antineutron" )
685  InitialKinetEnergy = TotalEnergyDeposit;
686 
687  //force a dump of all saved scintillation under the following
688  //conditions: energy goal reached, and current particle dead, or an
689  //error has occurred and total has exceeded goal (shouldn't happen)
690  if( fabs(TotalEnergyDeposit-InitialKinetEnergy)<safety ||
691  TotalEnergyDeposit>=InitialKinetEnergy ){
692  dx = 0; dE = 0;
693  //calculate the total number of quanta from all sites and all
694  //interactions so that the number of secondaries gets set correctly
695  NumPhotons = 0; NumElectrons = 0;
696  for(i=0;i<j;i++) {
697  sprintf(numPho,"N_PHO_%d",i); sprintf(numEle,"N_ELE_%d",i);
698  NumPhotons +=(G4int)aMaterialPropertiesTable->
699  GetConstProperty( numPho );
700  NumElectrons+=(G4int)aMaterialPropertiesTable->
701  GetConstProperty( numEle );
702  sprintf(trackL,"TRACK_%d",i); sprintf(energy,"ENRGY_%d",i);
703  //add up track lengths of all sites, for a total LET calc (later)
704  dx += aMaterialPropertiesTable->GetConstProperty(trackL);
705  dE += aMaterialPropertiesTable->GetConstProperty(energy);
706  }
707  G4int buffer = 100; if ( fVeryHighEnergy ) buffer = 1;
708  aParticleChange.SetNumberOfSecondaries(
709  buffer*(NumPhotons+NumElectrons));
711  if (aTrack.GetTrackStatus() == fAlive )
712  aParticleChange.ProposeTrackStatus(fSuspend);
713  }
714 
715  // begin the loop over all sites which generates all the quanta
716  for(i=0;i<j;i++) {
717  // get the position X,Y,Z, exciton and ion numbers, total track
718  // length of the site, and interaction times
719  sprintf(xCoord,"POS_X_%d",i); sprintf(yCoord,"POS_Y_%d",i);
720  sprintf(zCoord,"POS_Z_%d",i);
721  sprintf(numExc,"N_EXC_%d",i); sprintf(numIon,"N_ION_%d",i);
722  sprintf(numPho,"N_PHO_%d",i); sprintf(numEle,"N_ELE_%d",i);
723  NumExcitons = (G4int)aMaterialPropertiesTable->
724  GetConstProperty( numExc );
725  NumIons = (G4int)aMaterialPropertiesTable->
726  GetConstProperty( numIon );
727  sprintf(trackL,"TRACK_%d",i); sprintf(energy,"ENRGY_%d",i);
728  sprintf(time00,"TIME0_%d",i); sprintf(time01,"TIME1_%d",i);
729  delta = aMaterialPropertiesTable->GetConstProperty( trackL );
730  energ = aMaterialPropertiesTable->GetConstProperty( energy );
731  t0 = aMaterialPropertiesTable->GetConstProperty( time00 );
732  t1 = aMaterialPropertiesTable->GetConstProperty( time01 );
733 
734  //if site is small enough, override the Doke/Birks' model with
735  //Thomas-Imel, but not if we're dealing with super-high energy
736  //particles, and if it's NR force Thomas-Imel (though NR should be
737  //already short enough in track even up to O(100) keV)
738  if ( (delta < R0 && !fVeryHighEnergy) || z2 == z1 || fAlpha ) {
739  if( z1 == 54 && ElectricField && //see NEST paper for ER formula
740  Phase == kStateLiquid ) {
741  if ( abs ( z1 - z2 ) && //electron recoil
742  abs ( aParticle->GetPDGcode() ) != 2112 ) {
743  ThomasImel = 0.056776*pow(ElectricField,-0.11844);
744  if ( fAlpha ) //technically ER, but special
745  ThomasImel=0.057675*pow(ElectricField,-0.49362);
746  } //end electron recoil (ER)
747  else { //nuclear recoil
748  // spline of NR data of C.E. Dahl PhD Thesis Princeton '09
749  // functions found using zunzun.com
750  ThomasImel =
751  -0.15169*pow((ElectricField+215.25),0.01811)+0.20952;
752  } //end NR information
753  // Never let LY exceed 0-field yield!
754  if (ThomasImel > 0.19) ThomasImel = 0.19;
755  if (ThomasImel < 0.00) ThomasImel = 0.00;
756  } //end non-zero E-field segment
757  if ( Phase == kStateLiquid ) {
758  if ( z1 == 54 ) ThomasImel *= pow((Density/2.84),0.3);
759  if ( z1 == 18 ) ThomasImel *= pow((Density/Density_LAr),0.3);
760  }
761  //calculate the Thomas-Imel recombination probability, which
762  //depends on energy via NumIons, but not on dE/dx, and protect
763  //against seg fault by ensuring a positive number of ions
764  if (NumIons > 0) {
765  G4double xi;
766  xi = (G4double(NumIons)/4.)*ThomasImel;
767  if ( InitialKinetEnergy == 9.4*CLHEP::keV ) {
768  G4double NumIonsEff = 1.066e7*pow(t0/CLHEP::ns,-1.303)*
769  (0.17163+162.32/(ElectricField+191.39));
770  if ( NumIonsEff > 1e6 ) NumIonsEff = 1e6;
771  xi = (G4double(NumIonsEff)/4.)*ThomasImel;
772  }
773  if ( fKr83m && ElectricField==0 )
774  xi = (G4double(1.3*NumIons)/4.)*ThomasImel;
775  recombProb = 1-log(1+xi)/xi;
776  if(recombProb<0) recombProb=0;
777  if(recombProb>1) recombProb=1;
778  }
779  //just like Doke: simple binomial distribution
780  NumPhotons = NumExcitons + BinomFluct(NumIons,recombProb);
781  NumElectrons = (NumExcitons + NumIons) - NumPhotons;
782  //override Doke NumPhotons and NumElectrons
783  aMaterialPropertiesTable->
784  AddConstProperty( numPho, NumPhotons );
785  aMaterialPropertiesTable->
786  AddConstProperty( numEle, NumElectrons );
787  }
788 
789  // grab NumPhotons/NumElectrons, which come from Birks if
790  // the Thomas-Imel block of code above was not executed
791  NumPhotons = (G4int)aMaterialPropertiesTable->
792  GetConstProperty( numPho );
793  NumElectrons =(G4int)aMaterialPropertiesTable->
794  GetConstProperty( numEle );
795 
796  // extra Fano factor caused by recomb. fluct.
797  G4double FanoFactor =0; //ionization channel
798  if(Phase == kStateLiquid && YieldFactor == 1) {
799  FanoFactor =
800  2575.9*pow((ElectricField+15.154),-0.64064)-1.4707;
801  if ( fKr83m ) TotalEnergyDeposit = 4*CLHEP::keV;
802  if ( (dE/CLHEP::keV) <= 100 && ElectricField >= 0 ) {
803  G4double keVee = (TotalEnergyDeposit/(100.*CLHEP::keV));
804  if ( keVee <= 0.06 )
805  FanoFactor *= -0.00075+0.4625*keVee+34.375*pow(keVee,2.);
806  else
807  FanoFactor *= 0.069554+1.7322*keVee-.80215*pow(keVee,2.);
808  }
809  }
810  if ( Phase == kStateGas && Density>0.5 ) FanoFactor =
811  0.42857-4.7857*Density+7.8571*pow(Density,2.);
812  if( FanoFactor <= 0 || fVeryHighEnergy ) FanoFactor = 0;
813  NumQuanta = NumPhotons + NumElectrons;
814  if(z1==54 && FanoFactor) NumElectrons = G4int(
815  floor(G4RandGauss::shoot(NumElectrons,
816  sqrt(FanoFactor*NumElectrons))+0.5));
817  NumPhotons = NumQuanta - NumElectrons;
818  if ( NumElectrons <= 0 ) NumElectrons = 0;
819  if ( NumPhotons <= 0 ) NumPhotons = 0;
820  else { //other effects
821  if ( fAlpha ) //bi-excitonic quenching due to high dE/dx
822  NumPhotons = BinomFluct(NumPhotons,biExc);
823  NumPhotons = BinomFluct(NumPhotons,QE_EFF);
824  } NumElectrons = G4int(floor(NumElectrons*phe_per_e+0.5));
825 
826  // new stuff to make Kr-83m work properly
827  if(fKr83m || InitialKinetEnergy==9.4*CLHEP::keV) fKr83m += dE/CLHEP::keV;
828  if(fKr83m > 41) fKr83m = 0;
829  if ( SinglePhase ) //for a 1-phase det. don't propagate e-'s
830  NumElectrons = 0; //saves simulation time
831 
832  // reset material properties numExc, numIon, numPho, numEle, as
833  // their values have been used or stored elsewhere already
834  aMaterialPropertiesTable->AddConstProperty( numExc, 0 );
835  aMaterialPropertiesTable->AddConstProperty( numIon, 0 );
836  aMaterialPropertiesTable->AddConstProperty( numPho, 0 );
837  aMaterialPropertiesTable->AddConstProperty( numEle, 0 );
838 
839  // start particle creation loop
840  if( InitialKinetEnergy < MAX_ENE && InitialKinetEnergy > MIN_ENE &&
842  NumQuanta = NumPhotons + NumElectrons;
843  else NumQuanta = 0;
844  for(k = 0; k < NumQuanta; k++) {
845  G4double sampledEnergy;
846  G4DynamicParticle* aQuantum;
847 
848  // Generate random direction
849  G4double cost = 1. - 2.*G4UniformRand();
850  G4double sint = std::sqrt((1.-cost)*(1.+cost));
851  G4double phi = CLHEP::twopi*G4UniformRand();
852  G4double sinp = std::sin(phi); G4double cosp = std::cos(phi);
853  G4double px = sint*cosp; G4double py = sint*sinp;
854  G4double pz = cost;
855 
856  // Create momentum direction vector
857  G4ParticleMomentum photonMomentum(px, py, pz);
858 
859  // case of photon-specific stuff
860  if (k < NumPhotons) {
861  // Determine polarization of new photon
862  G4double sx = cost*cosp;
863  G4double sy = cost*sinp;
864  G4double sz = -sint;
865  G4ThreeVector photonPolarization(sx, sy, sz);
866  G4ThreeVector perp = photonMomentum.cross(photonPolarization);
867  phi = CLHEP::twopi*G4UniformRand();
868  sinp = std::sin(phi);
869  cosp = std::cos(phi);
870  photonPolarization = cosp * photonPolarization + sinp * perp;
871  photonPolarization = photonPolarization.unit();
872 
873  // Generate a new photon or electron:
874  sampledEnergy = G4RandGauss::shoot(PhotMean,PhotWidth);
875  aQuantum =
876  new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(),
877  photonMomentum);
878  aQuantum->SetPolarization(photonPolarization.x(),
879  photonPolarization.y(),
880  photonPolarization.z());
881  }
882 
883  else { // this else statement is for ionization electrons
884  if(ElectricField) {
885  // point all electrons straight up, for drifting
886  G4ParticleMomentum electronMomentum(0, 0, -FieldSign);
887  aQuantum =
888  new G4DynamicParticle(G4ThermalElectron::ThermalElectron(),
889  electronMomentum);
890  if ( Phase == kStateGas ) {
891  sampledEnergy =
892  GetGasElectronDriftSpeed(ElectricField,nDensity);
893  }
894  else
895  sampledEnergy = GetLiquidElectronDriftSpeed(
896  Temperature,ElectricField,MillerDriftSpeed,z1);
897  }
898  else {
899  // use "photonMomentum" for the electrons in the case of zero
900  // electric field, which is just randomized vector we made
901  aQuantum =
902  new G4DynamicParticle(G4ThermalElectron::ThermalElectron(),
903  photonMomentum);
904  sampledEnergy = 1.38e-23*(CLHEP::joule/CLHEP::kelvin)*Temperature;
905  }
906  }
907 
908  //assign energy to make particle real
909  aQuantum->SetKineticEnergy(sampledEnergy);
910  if (verboseLevel>1) //verbosity stuff
911  G4cout << "sampledEnergy = " << sampledEnergy << G4endl;
912 
913  // Generate new G4Track object:
914  // emission time distribution
915 
916  // first an initial birth time is provided that is typically
917  // <<1 ns after the initial interaction in the simulation, then
918  // singlet, triplet lifetimes, and recombination time, are
919  // handled here, to create a realistic S1 pulse shape/timing
920  G4double aSecondaryTime = t0+G4UniformRand()*(t1-t0)+evtStrt;
921  if (tau1<0) tau1=0;
922  if (tau3<0) tau3=0;
923  if (tauR<0) tauR=0;
924  if ( aQuantum->GetDefinition()->
925  GetParticleName()=="opticalphoton" ) {
926  if ( abs(z2-z1) && !fAlpha && //electron recoil
927  abs(aParticle->GetPDGcode()) != 2112 ) {
928  LET = (energ/CLHEP::MeV)/(delta/CLHEP::cm)*(1/Density); //avg LET over all
929  //in future, this will be done interaction by interaction
930  // Next, find the recombination time, which is LET-dependent
931  // via ionization density (Kubota et al. Phys. Rev. B 20
932  // (1979) 3486). We find the LET-dependence by fitting to the
933  // E-dependence (Akimov et al. Phys. Lett. B 524 (2002) 245).
934  if ( Phase == kStateLiquid && z1 == 54 )
935  tauR = 3.5*((1+0.41*LET)/(0.18*LET))*CLHEP::ns
936  *exp(-0.00900*ElectricField);
937  //field dependence based on fitting Fig. 9 of Dawson et al.
938  //NIM A 545 (2005) 690
939  //singlet-triplet ratios adapted from Kubota 1979, converted
940  //into correct units to work here, and separately done for
941  //excitation and recombination processes for electron recoils
942  //and assumed same for all LET (may vary)
943  SingTripRatioX = G4RandGauss::shoot(0.17,0.05);
944  SingTripRatioR = G4RandGauss::shoot(0.8,0.2);
945  if ( z1 == 18 ) {
946  SingTripRatioR = 0.2701+0.003379*LET-4.7338e-5*pow(LET,2.)
947  +8.1449e-6*pow(LET,3.); SingTripRatioX = SingTripRatioR;
948  if( LET < 3 ) {
949  SingTripRatioX = G4RandGauss::shoot(0.36,0.06);
950  SingTripRatioR = G4RandGauss::shoot(0.5,0.2); }
951  }
952  }
953  else if ( fAlpha ) { //alpha particles
954  SingTripRatioR = G4RandGauss::shoot(2.3,0.51);
955  //currently based on Dawson 05 and Tey. 11 (arXiv:1103.3689)
956  //real ratio is likely a gentle function of LET
957  if (z1==18) SingTripRatioR = (-0.065492+1.9996
958  *exp(-dE/CLHEP::MeV))/(1+0.082154/pow(dE/CLHEP::MeV,2.)) + 2.1811;
959  SingTripRatioX = SingTripRatioR;
960  }
961  else { //nuclear recoil
962  //based loosely on Hitachi et al. Phys. Rev. B 27 (1983) 5279
963  //with an eye to reproducing Akimov 2002 Fig. 9
964  SingTripRatioR = G4RandGauss::shoot(7.8,1.5);
965  if (z1==18) SingTripRatioR = 0.22218*pow(energ/CLHEP::keV,0.48211);
966  SingTripRatioX = SingTripRatioR;
967  }
968  // now, use binomial distributions to determine singlet and
969  // triplet states (and do separately for initially excited guys
970  // and recombining)
971  if ( k > NumExcitons ) {
972  //the recombination time is non-exponential, but approximates
973  //to exp at long timescales (see Kubota '79)
974  aSecondaryTime += tauR*(1./G4UniformRand()-1);
975  if(G4UniformRand()<SingTripRatioR/(1+SingTripRatioR))
976  aSecondaryTime -= tau1*log(G4UniformRand());
977  else aSecondaryTime -= tau3*log(G4UniformRand());
978  }
979  else {
980  if(G4UniformRand()<SingTripRatioX/(1+SingTripRatioX))
981  aSecondaryTime -= tau1*log(G4UniformRand());
982  else aSecondaryTime -= tau3*log(G4UniformRand());
983  }
984  }
985  else { //electron trapping at the liquid/gas interface
986  G4double gainField = 12;
987  G4double tauTrap = 884.83-62.069*gainField;
988  if ( Phase == kStateLiquid )
989  aSecondaryTime -= tauTrap*CLHEP::ns*log(G4UniformRand());
990  }
991 
992  // emission position distribution --
993  // Generate the position of a new photon or electron, with NO
994  // stochastic variation because that could lead to particles
995  // being mistakenly generated outside of your active region by
996  // Geant4, but real-life finite detector position resolution
997  // wipes out any effects from here anyway...
998  x0[0] = aMaterialPropertiesTable->GetConstProperty( xCoord );
999  x0[1] = aMaterialPropertiesTable->GetConstProperty( yCoord );
1000  x0[2] = aMaterialPropertiesTable->GetConstProperty( zCoord );
1001  G4double radius = sqrt(pow(x0[0],2.)+pow(x0[1],2.));
1002  //re-scale radius to ensure no generation of quanta outside
1003  //the active volume of your simulation due to Geant4 rounding
1004  if ( radius >= R_TOL ) {
1005  if (x0[0] == 0) x0[0] = 1*CLHEP::nm;
1006  if (x0[1] == 0) x0[1] = 1*CLHEP::nm;
1007  radius -= R_TOL; phi = atan ( x0[1] / x0[0] );
1008  x0[0] = fabs(radius*cos(phi))*((fabs(x0[0]))/(x0[0]));
1009  x0[1] = fabs(radius*sin(phi))*((fabs(x0[1]))/(x0[1]));
1010  }
1011  //position of the new secondary particle is ready for use
1012  G4ThreeVector aSecondaryPosition = x0;
1013  if ( k >= NumPhotons && diffusion && ElectricField > 0 ) {
1014  G4double D_T = 64*pow(1e-3*ElectricField,-.17);
1015  //fit to Aprile and Doke 2009, arXiv:0910.4956 (Fig. 12)
1016  G4double D_L = 13.859*pow(1e-3*ElectricField,-0.58559);
1017  //fit to Aprile and Doke and Sorensen 2011, arXiv:1102.2865
1018  if ( Phase == kStateLiquid && z1 == 18 ) {
1019  D_T = 93.342*pow(ElectricField/nDensity,0.041322);
1020  D_L = 0.15 * D_T; }
1021  if ( Phase == kStateGas && z1 == 54 ) {
1022  D_L=4.265+19097/ElectricField-1.7397e6/pow(ElectricField,2.)+
1023  1.2477e8/pow(ElectricField,3.); D_T *= 0.01;
1024  }
1025  D_T *= CLHEP::cm2/CLHEP::s;
1026  D_L *= CLHEP::cm2/CLHEP::s;
1027  if (ElectricField<100 && Phase == kStateLiquid) {
1028  D_L = 8*CLHEP::cm2/CLHEP::s;
1029  }
1030  G4double vDrift = sqrt((2*sampledEnergy)/(EMASS));
1031  if ( BORDER == 0 ) x0[2] = 0;
1032  G4double sigmaDT = sqrt(2*D_T*fabs(BORDER-x0[2])/vDrift);
1033  G4double sigmaDL = sqrt(2*D_L*fabs(BORDER-x0[2])/vDrift);
1034  G4double dr = fabs(G4RandGauss::shoot(0.,sigmaDT));
1035  phi = CLHEP::twopi * G4UniformRand();
1036  aSecondaryPosition[0] += cos(phi) * dr;
1037  aSecondaryPosition[1] += sin(phi) * dr;
1038  aSecondaryPosition[2] += G4RandGauss::shoot(0.,sigmaDL);
1039  radius = sqrt(pow(aSecondaryPosition[0],2.)+
1040  pow(aSecondaryPosition[1],2.));
1041  if(aSecondaryPosition[2] >= BORDER && Phase == kStateLiquid) {
1042  if ( BORDER != 0 ) aSecondaryPosition[2] = BORDER - R_TOL; }
1043  if(aSecondaryPosition[2] <= PMT && !GlobalFields)
1044  aSecondaryPosition[2] = PMT + R_TOL;
1045  } //end of electron diffusion code
1046 
1047  // GEANT4 business: stuff you need to make a new track
1048  if ( aSecondaryTime < 0 ) aSecondaryTime = 0; //no neg. time
1049  G4Track * aSecondaryTrack =
1050  new G4Track(aQuantum,aSecondaryTime,aSecondaryPosition);
1051  if ( k < NumPhotons || radius < R_MAX )
1052  aParticleChange.AddSecondary(aSecondaryTrack);
1053  }
1054 
1055  //reset bunch of things when done with an interaction site
1056  aMaterialPropertiesTable->AddConstProperty( xCoord, 999*CLHEP::km );
1057  aMaterialPropertiesTable->AddConstProperty( yCoord, 999*CLHEP::km );
1058  aMaterialPropertiesTable->AddConstProperty( zCoord, 999*CLHEP::km );
1059  aMaterialPropertiesTable->AddConstProperty( trackL, 0*CLHEP::um );
1060  aMaterialPropertiesTable->AddConstProperty( energy, 0*CLHEP::eV );
1061  aMaterialPropertiesTable->AddConstProperty( time00, DBL_MAX );
1062  aMaterialPropertiesTable->AddConstProperty( time01, -1*CLHEP::ns );
1063 
1064  if (verboseLevel>0) { //more verbose stuff
1065  G4cout << "\n Exiting from G4S1Light::DoIt -- "
1066  << "NumberOfSecondaries = "
1067  << aParticleChange.GetNumberOfSecondaries() << G4endl;
1068  }
1069  } //end of interaction site loop
1070 
1071  //more things to reset...
1072  aMaterialPropertiesTable->
1073  AddConstProperty( "TOTALNUM_INT_SITES", 0 );
1074  aMaterialPropertiesTable->
1075  AddConstProperty( "ENERGY_DEPOSIT_TOT", 0*CLHEP::keV );
1076  aMaterialPropertiesTable->
1077  AddConstProperty( "ENERGY_DEPOSIT_GOL", 0*CLHEP::MeV );
1078  fExcitedNucleus = false;
1079  fAlpha = false;
1080  }
1081 
1082  //don't do anything when you're not ready to scintillate
1083  else {
1084  aParticleChange.SetNumberOfSecondaries(0);
1085  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
1086  }
1087 
1088  //the end (exiting)
1089  return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
1090 }
1091 
1092 // GetMeanFreePath
1093 // ---------------
1094 G4double G4S1Light::GetMeanFreePath(const G4Track&,
1095  G4double ,
1096  G4ForceCondition* condition)
1097 {
1098  *condition = StronglyForced;
1099  // what this does is enforce the G4S1Light physics process as always
1100  // happening, so in effect scintillation is a meta-process on top of
1101  // any and all other energy depositions which may occur, just like the
1102  // original G4Scintillation (disregard DBL_MAX, this function makes the
1103  // mean free path zero really, not infinite)
1104 
1105  return DBL_MAX; //a C-defined constant
1106 }
1107 
1108 // GetMeanLifeTime
1109 // ---------------
1110 G4double G4S1Light::GetMeanLifeTime(const G4Track&,
1111  G4ForceCondition* condition)
1112 {
1113  *condition = Forced;
1114  // this function and this condition has the same effect as the above
1115  return DBL_MAX;
1116 }
1117 
1118 G4double GetLiquidElectronDriftSpeed(G4double tempinput, G4double efieldinput,
1119  G4bool Miller, G4int Z) {
1120  if(efieldinput<0) efieldinput *= (-1);
1121  //Liquid equation one (165K) coefficients
1122  G4double onea=144623.235704015,
1123  oneb=850.812714257629,
1124  onec=1192.87056676815,
1125  oned=-395969.575204061,
1126  onef=-355.484170008875,
1127  oneg=-227.266219627672,
1128  oneh=223831.601257495,
1129  onei=6.1778950907965,
1130  onej=18.7831533426398,
1131  onek=-76132.6018884368;
1132  //Liquid equation two (200K) coefficients
1133  G4double twoa=17486639.7118995,
1134  twob=-113.174284723134,
1135  twoc=28.005913193763,
1136  twod=167994210.094027,
1137  twof=-6766.42962575088,
1138  twog=901.474643115395,
1139  twoh=-185240292.471665,
1140  twoi=-633.297790813084,
1141  twoj=87.1756135457949;
1142  //Liquid equation three (230K) coefficients
1143  G4double thra=10626463726.9833,
1144  thrb=224025158.134792,
1145  thrc=123254826.300172,
1146  thrd=-4563.5678061122,
1147  thrf=-1715.269592063,
1148  thrg=-694181.921834368,
1149  thrh=-50.9753281079838,
1150  thri=58.3785811395493,
1151  thrj=201512.080026704;
1152  G4double y1=0,y2=0,f1=0,f2=0,f3=0,edrift=0,
1153  t1=0,t2=0,frac=0,slope=0,intercept=0;
1154 
1155  //Equations defined
1156  f1=onea/(1+exp(-(efieldinput-oneb)/onec))+oned/
1157  (1+exp(-(efieldinput-onef)/oneg))+
1158  oneh/(1+exp(-(efieldinput-onei)/onej))+onek;
1159  f2=twoa/(1+exp(-(efieldinput-twob)/twoc))+twod/
1160  (1+exp(-(efieldinput-twof)/twog))+
1161  twoh/(1+exp(-(efieldinput-twoi)/twoj));
1162  f3=thra*exp(-thrb*efieldinput)+thrc*exp(-(pow(efieldinput-thrd,2))/
1163  (thrf*thrf))+
1164  thrg*exp(-(pow(efieldinput-thrh,2)/(thri*thri)))+thrj;
1165 
1166  if(efieldinput<20 && efieldinput>=0) {
1167  f1=2951*efieldinput;
1168  f2=5312*efieldinput;
1169  f3=7101*efieldinput;
1170  }
1171  //Cases for tempinput decides which 2 equations to use lin. interpolation
1172  if(tempinput<200.0 && tempinput>165.0) {
1173  y1=f1;
1174  y2=f2;
1175  t1=165.0;
1176  t2=200.0;
1177  }
1178  if(tempinput<230.0 && tempinput>200.0) {
1179  y1=f2;
1180  y2=f3;
1181  t1=200.0;
1182  t2=230.0;
1183  }
1184  if((tempinput>230.0 || tempinput<165.0) && !Miller) {
1185  G4cout << "\nWARNING: TEMPERATURE OUT OF RANGE (165-230 K)\n";
1186  return 0;
1187  }
1188  if (tempinput == 165.0) edrift = f1;
1189  else if (tempinput == 200.0) edrift = f2;
1190  else if (tempinput == 230.0) edrift = f3;
1191  else { //Linear interpolation
1192  frac=(tempinput-t1)/(t2-t1);
1193  slope = (y1-y2)/(t1-t2);
1194  intercept=y1-slope*t1;
1195  edrift=slope*tempinput+intercept;
1196  }
1197 
1198  if ( Miller ) {
1199  if ( efieldinput <= 40. )
1200  edrift = -0.13274+0.041082*efieldinput-0.0006886*pow(efieldinput,2.)+
1201  5.5503e-6*pow(efieldinput,3.);
1202  else
1203  edrift = 0.060774*efieldinput/pow(1+0.11336*pow(efieldinput,0.5218),2.);
1204  if ( efieldinput >= 1e5 ) edrift = 2.7;
1205  if ( efieldinput >= 100 )
1206  edrift -= 0.017 * ( tempinput - 163 );
1207  else
1208  edrift += 0.017 * ( tempinput - 163 );
1209  edrift *= 1e5; //put into units of cm/sec. from mm/usec.
1210  }
1211  if ( Z == 18 ) edrift = 1e5 * (
1212  .097384*pow(log10(efieldinput),3.0622)-.018614*sqrt(efieldinput) );
1213  if ( edrift < 0 ) edrift = 0.;
1214  edrift = 0.5*EMASS*pow(edrift*CLHEP::cm/CLHEP::s,2.);
1215  return edrift;
1216 }
1217 
1218 G4double CalculateElectronLET ( G4double E, G4int Z ) {
1219  G4double LET;
1220  switch ( Z ) {
1221  case 54:
1222  //use a spline fit to online ESTAR data
1223  if ( E >= 1 ) LET = 58.482-61.183*log10(E)+19.749*pow(log10(E),2)+
1224  2.3101*pow(log10(E),3)-3.3469*pow(log10(E),4)+
1225  0.96788*pow(log10(E),5)-0.12619*pow(log10(E),6)+0.0065108*pow(log10(E),7);
1226  //at energies <1 keV, use a different spline, determined manually by
1227  //generating sub-keV electrons in Geant4 and looking at their ranges, since
1228  //ESTAR does not go this low
1229  else if ( E>0 && E<1 ) LET = 6.9463+815.98*E-4828*pow(E,2)+17079*pow(E,3)-
1230  36394*pow(E,4)+44553*pow(E,5)-28659*pow(E,6)+7483.8*pow(E,7);
1231  else
1232  LET = 0;
1233  break;
1234  case 18: default:
1235  if ( E >= 1 ) LET = 116.70-162.97*log10(E)+99.361*pow(log10(E),2)-
1236  33.405*pow(log10(E),3)+6.5069*pow(log10(E),4)-
1237  0.69334*pow(log10(E),5)+.031563*pow(log10(E),6);
1238  else if ( E>0 && E<1 ) LET = 100;
1239  else
1240  LET = 0;
1241  }
1242  return LET;
1243 }
1244 
1245 G4int BinomFluct ( G4int N0, G4double prob ) {
1246  G4double mean = N0*prob;
1247  G4double sigma = sqrt(N0*prob*(1-prob));
1248  G4int N1 = 0;
1249  if ( prob == 0.00 ) return N1;
1250  if ( prob == 1.00 ) return N0;
1251 
1252  if ( N0 < 10 ) {
1253  for(G4int i = 0; i < N0; i++) {
1254  if(G4UniformRand() < prob) N1++;
1255  }
1256  }
1257  else {
1258  N1 = G4int(floor(G4RandGauss::shoot(mean,sigma)+0.5));
1259  }
1260  if ( N1 > N0 ) N1 = N0;
1261  if ( N1 < 0 ) N1 = 0;
1262  return N1;
1263 }
1264 
1265 void InitMatPropValues ( G4MaterialPropertiesTable *nobleElementMat ) {
1266  char xCoord[80]; char yCoord[80]; char zCoord[80];
1267  char numExc[80]; char numIon[80]; char numPho[80]; char numEle[80];
1268  char trackL[80]; char time00[80]; char time01[80]; char energy[80];
1269 
1270  // for loop to initialize the interaction site mat'l properties
1271  for( G4int i=0; i<10000; i++ ) {
1272  sprintf(xCoord,"POS_X_%d",i); sprintf(yCoord,"POS_Y_%d",i);
1273  sprintf(zCoord,"POS_Z_%d",i);
1274  nobleElementMat->AddConstProperty( xCoord, 999*CLHEP::km );
1275  nobleElementMat->AddConstProperty( yCoord, 999*CLHEP::km );
1276  nobleElementMat->AddConstProperty( zCoord, 999*CLHEP::km );
1277  sprintf(numExc,"N_EXC_%d",i); sprintf(numIon,"N_ION_%d",i);
1278  sprintf(numPho,"N_PHO_%d",i); sprintf(numEle,"N_ELE_%d",i);
1279  nobleElementMat->AddConstProperty( numExc, 0 );
1280  nobleElementMat->AddConstProperty( numIon, 0 );
1281  nobleElementMat->AddConstProperty( numPho, 0 );
1282  nobleElementMat->AddConstProperty( numEle, 0 );
1283  sprintf(trackL,"TRACK_%d",i); sprintf(energy,"ENRGY_%d",i);
1284  sprintf(time00,"TIME0_%d",i); sprintf(time01,"TIME1_%d",i);
1285  nobleElementMat->AddConstProperty( trackL, 0*CLHEP::um );
1286  nobleElementMat->AddConstProperty( energy, 0*CLHEP::eV );
1287  nobleElementMat->AddConstProperty( time00, DBL_MAX );
1288  nobleElementMat->AddConstProperty( time01,-1*CLHEP::ns );
1289  }
1290 
1291  // we initialize the total number of interaction sites, a variable for
1292  // updating the amount of energy deposited thus far in the medium, and a
1293  // variable for storing the amount of energy expected to be deposited
1294  nobleElementMat->AddConstProperty( "TOTALNUM_INT_SITES", 0 );
1295  nobleElementMat->AddConstProperty( "ENERGY_DEPOSIT_TOT", 0*CLHEP::keV );
1296  nobleElementMat->AddConstProperty( "ENERGY_DEPOSIT_GOL", 0*CLHEP::MeV );
1297  return;
1298 }
1299 
1300 G4double UnivScreenFunc ( G4double E, G4double Z, G4double A ) {
1301  G4double a_0 = 5.29e-11*CLHEP::m; G4double a = 0.626*a_0*pow(Z,(-1./3.));
1302  G4double epsilon_0 = 8.854e-12*(CLHEP::farad/CLHEP::m);
1303  G4double epsilon = (a*E*2.*CLHEP::twopi*epsilon_0)/(2*pow(CLHEP::eplus,2.)*pow(Z,2.));
1304  G4double zeta_0 = pow(Z,(1./6.)); G4double m_N = A*1.66e-27*CLHEP::kg;
1305  G4double hbar = 6.582e-16*CLHEP::eV*CLHEP::s;
1306  if ( Z == 54 ) {
1307  epsilon *= 1.068; //zeta_0 = 1.63;
1308  } //special case for LXe from Bezrukov et al. 2011
1309  G4double s_n = log(1+1.1383*epsilon)/(2.*(epsilon +
1310  0.01321*pow(epsilon,0.21226) +
1311  0.19593*sqrt(epsilon)));
1312  G4double s_e = (a_0*zeta_0/a)*hbar*sqrt(8*epsilon*2.*CLHEP::twopi*epsilon_0/
1313  (a*m_N*pow(CLHEP::eplus,2.)));
1314  return 1.38e5*0.5*(1+tanh(50*epsilon-0.25))*epsilon*(s_e/s_n);
1315 }
static constexpr double cm
Definition: Units.h:68
#define WIN
Definition: G4S1Light.hh:35
G4double GetGasElectronDriftSpeed(G4double efieldinput, G4double density)
Definition: G4S2Light.cc:315
code to link reconstructed objects back to the MC truth information
#define BORDER
Definition: G4S1Light.hh:29
static constexpr double keV
Definition: Units.h:128
#define EMASS
Definition: G4S1Light.hh:25
const double hbar
#define MillerDriftSpeed
Definition: G4S1Light.hh:26
G4double GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *)
Definition: G4S1Light.cc:1094
static constexpr double g
Definition: Units.h:144
G4double UnivScreenFunc(G4double E, G4double Z, G4double A)
Definition: G4S1Light.cc:1300
#define TOP
#define GAT
Definition: G4S1Light.hh:39
#define QE_EFF
Definition: G4S1Light.hh:31
static constexpr double cm3
Definition: Units.h:70
G4bool fTrackSecondariesFirst
Definition: G4S1Light.hh:109
constexpr T pow(T x)
Definition: pow.h:72
int kelvin
Definition: units.py:217
G4bool diffusion
Definition: G4S1Light.cc:63
static constexpr double kg
Definition: Units.h:143
G4double tau1[100]
Definition: G4S2Light.cc:61
static constexpr double MeV
Definition: Units.h:129
#define Density_LAr
Definition: G4S1Light.cc:78
G4double tau3[100]
Definition: G4S2Light.cc:61
static constexpr double km
Definition: Units.h:64
#define phe_per_e
Definition: G4S1Light.hh:32
#define ANE
Definition: G4S1Light.hh:37
kilovolt_as<> kilovolt
Type of potential stored in kilovolt, in double precision.
~G4S1Light()
Definition: G4S1Light.cc:97
#define HIENLIM
Definition: G4S1Light.cc:59
void InitMatPropValues(G4MaterialPropertiesTable *nobleElementMat)
Definition: G4S1Light.cc:1265
G4double YieldFactor
Definition: G4S1Light.hh:113
#define R_TOL
Definition: G4S1Light.cc:61
G4bool SinglePhase
Definition: G4S1Light.cc:65
#define AVO
Definition: G4S1Light.hh:24
#define SRF
Definition: G4S1Light.hh:38
bool exists(std::string path)
#define a2
T abs(T value)
const double e
#define BOT
Definition: G4S1Light.hh:41
static G4ThermalElectron * ThermalElectron()
static constexpr double eV
Definition: Units.h:127
static constexpr double cm2
Definition: Units.h:69
const double a
G4int BinomFluct(G4int N0, G4double prob)
Definition: G4S1Light.cc:1245
def convert(inputfile, outputfile="wire-cell-garfield-fine-response.json.bz2", average=False, shaped=False)
Definition: garfield.py:262
G4double CalculateElectronLET(G4double E, G4int Z)
Definition: G4S1Light.cc:1218
#define CTH
Definition: G4S1Light.hh:40
#define PMT
Definition: G4S1Light.hh:42
G4double GetMeanLifeTime(const G4Track &aTrack, G4ForceCondition *)
Definition: G4S1Light.cc:1110
G4bool ThomasImelTail
Definition: G4S1Light.cc:65
double gamma(double KE, const simb::MCParticle *part)
#define MIN_ENE
Definition: G4S1Light.cc:57
int twopi
Definition: units.py:12
G4VParticleChange * AtRestDoIt(const G4Track &aTrack, const G4Step &aStep)
Definition: G4S1Light.cc:100
G4bool fExcitedNucleus
Definition: G4S1Light.hh:111
G4double ExcitationRatio
Definition: G4S1Light.hh:114
#define R_MAX
Definition: G4S1Light.cc:62
#define Density_LXe
Definition: G4S1Light.cc:77
Definition: group.cpp:53
G4VParticleChange * PostStepDoIt(const G4Track &aTrack, const G4Step &aStep)
Definition: G4S1Light.cc:109
static constexpr double mm
Definition: Units.h:65
G4bool fVeryHighEnergy
Definition: G4S1Light.hh:111
G4S1Light(const G4String &processName="S1", G4ProcessType type=fElectromagnetic)
Definition: G4S1Light.cc:82
G4double fKr83m
Definition: G4S1Light.hh:112
G4bool fMultipleScattering
Definition: G4S1Light.hh:111
QAsciiDict< Entry > ns
G4double GetLiquidElectronDriftSpeed(double T, double F, G4bool M, G4int Z)
double mean(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:16
double Density(double r)
Definition: PREM.cxx:18
G4bool OutElectrons
Definition: G4S1Light.cc:65
static QCString * s
Definition: config.cpp:1042
G4double biExc
Definition: G4S1Light.cc:70
G4bool fAlpha
Definition: G4S1Light.hh:111
#define a1