Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/dna/models/src/G4DNARuddIonisationExtendedModel.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 //
 27 // Modified by Z. Francis, S. Incerti to handle HZE 
 28 // && inverse rudd function sampling 26-10-2010
 29 //
 30 // Rewitten by V.Ivanchenko 21.05.2023
 31 //
 32 
 33 #include "G4EmCorrections.hh"
 34 #include "G4DNARuddIonisationExtendedModel.hh"
 35 #include "G4PhysicalConstants.hh"
 36 #include "G4SystemOfUnits.hh"
 37 #include "G4UAtomicDeexcitation.hh"
 38 #include "G4LossTableManager.hh"
 39 #include "G4NistManager.hh"
 40 #include "G4DNAChemistryManager.hh"
 41 #include "G4DNAMolecularMaterial.hh"
 42 
 43 #include "G4IonTable.hh"
 44 #include "G4DNARuddAngle.hh"
 45 #include "G4DeltaAngle.hh"
 46 #include "G4Exp.hh"
 47 #include "G4Log.hh"
 48 #include "G4Pow.hh"
 49 #include "G4Alpha.hh"
 50 #include "G4Proton.hh"
 51 
 52 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 53 
 54 G4DNACrossSectionDataSet* G4DNARuddIonisationExtendedModel::xsdata[] = {nullptr};
 55 G4DNACrossSectionDataSet* G4DNARuddIonisationExtendedModel::xshelium = nullptr;
 56 G4DNACrossSectionDataSet* G4DNARuddIonisationExtendedModel::xsalphaplus = nullptr;
 57 const std::vector<G4double>* G4DNARuddIonisationExtendedModel::fpWaterDensity = nullptr;
 58 
 59 namespace
 60 {
 61   const G4double scaleFactor = CLHEP::m*CLHEP::m;
 62   const G4double tolerance = 1*CLHEP::eV;
 63   const G4double Ry = 13.6*CLHEP::eV;
 64 
 65   // Following values provided by M. Dingfelder (priv. comm)
 66   const G4double Bj[5] = {12.60*CLHEP::eV, 14.70*CLHEP::eV, 18.40*CLHEP::eV,
 67                           32.20*CLHEP::eV, 539*CLHEP::eV};
 68 }
 69 
 70 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 71 
 72 G4DNARuddIonisationExtendedModel::G4DNARuddIonisationExtendedModel(const G4ParticleDefinition*,
 73                                                                    const G4String& nam)
 74   : G4VEmModel(nam)
 75 {
 76   fEmCorrections = G4LossTableManager::Instance()->EmCorrections();
 77   fGpow = G4Pow::GetInstance();
 78   fLowestEnergy = 100*CLHEP::eV;
 79   fLimitEnergy = 1*CLHEP::keV;
 80 
 81   // Mark this model as "applicable" for atomic deexcitation
 82   SetDeexcitationFlag(true);
 83 
 84   // Define default angular generator
 85   SetAngularDistribution(new G4DNARuddAngle());
 86 
 87   if (nullptr == xshelium) { LoadData(); }
 88 }
 89 
 90 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 91 
 92 G4DNARuddIonisationExtendedModel::~G4DNARuddIonisationExtendedModel()
 93 {  
 94   if(isFirst) {
 95     for(auto & i : xsdata) { delete i; }
 96   }
 97 }
 98 
 99 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
100 
101 void G4DNARuddIonisationExtendedModel::LoadData()
102 {
103   // initialisation of static data once
104   isFirst = true;
105   G4String filename("dna/sigma_ionisation_h_rudd");
106   xsdata[0] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
107   xsdata[0]->LoadData(filename);
108 
109   filename = "dna/sigma_ionisation_p_rudd";
110   xsdata[1] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
111   xsdata[1]->LoadData(filename);
112 
113   filename = "dna/sigma_ionisation_alphaplusplus_rudd";
114   xsdata[2] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
115   xsdata[2]->LoadData(filename);
116 
117   filename = "dna/sigma_ionisation_li_rudd";
118   xsdata[3] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
119   xsdata[3]->LoadData(filename);
120 
121   filename = "dna/sigma_ionisation_be_rudd";
122   xsdata[4] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
123   xsdata[4]->LoadData(filename);
124 
125   filename = "dna/sigma_ionisation_b_rudd";
126   xsdata[5] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
127   xsdata[5]->LoadData(filename);
128 
129   filename = "dna/sigma_ionisation_c_rudd";
130   xsdata[6] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
131   xsdata[6]->LoadData(filename);
132 
133   filename = "dna/sigma_ionisation_n_rudd";
134   xsdata[7] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
135   xsdata[7]->LoadData(filename);
136 
137   filename = "dna/sigma_ionisation_o_rudd";
138   xsdata[8] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
139   xsdata[8]->LoadData(filename);
140 
141   filename = "dna/sigma_ionisation_si_rudd";
142   xsdata[14] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
143   xsdata[14]->LoadData(filename);
144 
145   filename = "dna/sigma_ionisation_fe_rudd";
146   xsdata[26] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
147   xsdata[26]->LoadData(filename);
148 
149   filename = "dna/sigma_ionisation_alphaplus_rudd";
150   xsalphaplus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
151   xsalphaplus->LoadData(filename);
152 
153   filename = "dna/sigma_ionisation_he_rudd";
154   xshelium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
155   xshelium->LoadData(filename);
156 
157   // to avoid possible threading problem fill this vector only once
158   auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
159   fpWaterDensity =
160     G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
161 }
162 
163 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
164 
165 void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
166                                                   const G4DataVector&)
167 {
168   if (p != fParticle) { SetParticle(p); }
169 
170   // particle change object may be externally set
171   if (nullptr == fParticleChangeForGamma) {
172     fParticleChangeForGamma = GetParticleChangeForGamma();
173   }
174 
175   // initialisation once in each thread
176   if (!isInitialised) {
177     isInitialised = true;
178     const G4String& pname = fParticle->GetParticleName();
179     if (pname == "proton") {
180       idx = 1;
181       xscurrent = xsdata[1];
182       fElow = fLowestEnergy;
183     } else if (pname == "hydrogen") {
184       idx = 0; 
185       xscurrent = xsdata[0];
186       fElow = fLowestEnergy;
187     } else if (pname == "alpha") {
188       idx = 1;
189       xscurrent = xsdata[2];
190       isHelium = true;
191       fElow = fLimitEnergy;
192     } else if (pname == "alpha+") {
193       idx = 1;
194       isHelium = true;
195       xscurrent = xsalphaplus;
196       fElow = fLimitEnergy;
197       // The following values are provided by M. Dingfelder (priv. comm)
198       slaterEffectiveCharge[0]=2.0;
199       slaterEffectiveCharge[1]=2.0;
200       slaterEffectiveCharge[2]=2.0;
201       sCoefficient[0]=0.7;
202       sCoefficient[1]=0.15;
203       sCoefficient[2]=0.15;
204     } else if (pname == "helium") {
205       idx = 0; 
206       isHelium = true;
207       fElow = fLimitEnergy;
208       xscurrent = xshelium;
209       slaterEffectiveCharge[0]=1.7;
210       slaterEffectiveCharge[1]=1.15;
211       slaterEffectiveCharge[2]=1.15;
212       sCoefficient[0]=0.5;
213       sCoefficient[1]=0.25;
214       sCoefficient[2]=0.25;
215     } else {
216       isIon = true;
217       idx = -1;
218       xscurrent = xsdata[1];
219       fElow = fLowestEnergy;
220     }
221     // defined stationary mode
222     statCode = G4EmParameters::Instance()->DNAStationary();
223 
224     // initialise atomic de-excitation
225     fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
226 
227     if (verbose > 0) {
228       G4cout << "### G4DNARuddIonisationExtendedModel::Initialise(..) " << pname 
229        << "/n    idx=" << idx << " isIon=" << isIon
230        << " isHelium=" << isHelium << G4endl;
231     }
232   }
233 }
234 
235 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
236 
237 void G4DNARuddIonisationExtendedModel::SetParticle(const G4ParticleDefinition* p)
238 {
239   fParticle = p;
240   fMass = p->GetPDGMass();
241   fMassRate = (isIon) ? CLHEP::proton_mass_c2/fMass : 1.0; 
242 }
243 
244 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
245 
246 G4double 
247 G4DNARuddIonisationExtendedModel::CrossSectionPerVolume(const G4Material* material,
248                                                         const G4ParticleDefinition* part,
249                                                         G4double kinE,
250                                                         G4double, G4double)
251 {
252   // check if model is applicable for given material
253   G4double density = (material->GetIndex() < fpWaterDensity->size())
254     ? (*fpWaterDensity)[material->GetIndex()] : 0.0;
255   if (0.0 == density) { return 0.0; }
256 
257   // ion may be different
258   if (fParticle != part) { SetParticle(part); }
259 
260   // ion shoud be stopped - check on kinetic energy and not scaled energy
261   if (kinE < fLowestEnergy) { return DBL_MAX; }
262 
263   G4double e = kinE*fMassRate;
264 
265   G4double sigma = (e > fElow) ? xscurrent->FindValue(e)
266     : xscurrent->FindValue(fElow) * e / fElow;
267 
268   if (idx == -1) {
269     sigma *= fEmCorrections->EffectiveChargeSquareRatio(part, material, kinE);
270   }
271 
272   sigma *= density;
273 
274   if (verbose > 1) {
275     G4cout << "G4DNARuddIonisationExtendedModel for " << part->GetParticleName() 
276            << " Ekin(keV)=" << kinE/CLHEP::keV 
277            << " sigma(cm^2)=" << sigma/CLHEP::cm2 << G4endl;
278   }
279   return sigma;
280 }
281 
282 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
283 
284 void
285 G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
286                                                     const G4MaterialCutsCouple* couple,
287                                                     const G4DynamicParticle* dpart,
288                                                     G4double, G4double)
289 {
290   const G4ParticleDefinition* pd = dpart->GetDefinition();
291   if (fParticle != pd) { SetParticle(pd); }
292 
293   // stop ion with energy below low energy limit
294   G4double kinE = dpart->GetKineticEnergy();
295   // ion shoud be stopped - check on kinetic energy and not scaled energy
296   if (kinE <= fLowestEnergy) {
297     fParticleChangeForGamma->SetProposedKineticEnergy(0.);
298     fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
299     fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE);
300     return;
301   }
302 
303   G4int shell = SelectShell(kinE*fMassRate);
304   G4double bindingEnergy = (useDNAWaterStructure)
305     ? waterStructure.IonisationEnergy(shell) : Bj[shell];
306 
307   //Si: additional protection if tcs interpolation method is modified
308   if (kinE < bindingEnergy) { return; }
309   
310   G4double esec = SampleElectronEnergy(kinE, shell);
311   G4double esum = 0.0;
312 
313   // sample deexcitation
314   // here we assume that H2O electronic levels are the same as Oxygen.
315   // this can be considered true with a rough 10% error in energy on K-shell,
316   G4int Z = 8;  
317   G4ThreeVector deltaDir = 
318     GetAngularDistribution()->SampleDirectionForShell(dpart, esec, Z, shell, couple->GetMaterial());
319 
320   // SI: only atomic deexcitation from K shell is considered
321   if(fAtomDeexcitation != nullptr && shell == 4) {
322     auto as = G4AtomicShellEnumerator(0);
323     auto ashell = fAtomDeexcitation->GetAtomicShell(Z, as);
324     fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
325 
326     // compute energy sum from de-excitation
327     for (auto const & ptr : *fvect) {
328       esum += ptr->GetKineticEnergy();
329     }
330   }
331   // check energy balance
332   // remaining excitation energy of water molecule
333   G4double exc = bindingEnergy - esum;
334 
335   // remaining projectile energy
336   G4double scatteredEnergy = kinE - bindingEnergy - esec;
337   if(scatteredEnergy < -tolerance || exc < -tolerance) {
338     G4cout << "G4DNARuddIonisationExtendedModel::SampleSecondaries: "
339            << "negative final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
340            << kinE/CLHEP::keV << "  " << pd->GetParticleName()
341            << " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
342      << G4endl;
343   }
344 
345   // projectile
346   if (!statCode) {
347     fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
348     fParticleChangeForGamma->ProposeLocalEnergyDeposit(exc);
349   } else {
350     fParticleChangeForGamma->SetProposedKineticEnergy(kinE);
351     fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE - scatteredEnergy);
352   }
353 
354   // delta-electron
355   auto  dp = new G4DynamicParticle(G4Electron::Electron(), deltaDir, esec);
356   fvect->push_back(dp);
357 
358   // create radical
359   const G4Track* theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
360   G4DNAChemistryManager::Instance()->CreateWaterMolecule(eIonizedMolecule, shell,
361                theIncomingTrack);
362 }
363 
364 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
365 
366 G4int G4DNARuddIonisationExtendedModel::SelectShell(G4double e)
367 {
368   G4double sum = 0.0;
369   G4double xs;
370   for (G4int i=0; i<5; ++i) {
371     auto ptr = xscurrent->GetComponent(i);
372     xs = (e > fElow) ? ptr->FindValue(e) : ptr->FindValue(fElow)*e/fElow;
373     sum += xs;
374     fTemp[i] = sum;
375   }
376   sum *= G4UniformRand();
377   for (G4int i=0; i<5; ++i) {
378     if (sum <= fTemp[i]) { return i; }
379   }
380   return 0;
381 }
382 
383 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
384 
385 G4double G4DNARuddIonisationExtendedModel::MaxEnergy(G4double kine, G4int shell)
386 {
387   // kinematic limit
388   G4double tau = kine/fMass;
389   G4double gam = 1.0 + tau;
390   G4double emax = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
391 
392   // Initialisation of sampling
393   G4double A1, B1, C1, D1, E1, A2, B2, C2, D2;
394   if (shell == 4) {
395     //Data For Liquid Water K SHELL from Dingfelder (Protons in Water)
396     A1 = 1.25;
397     B1 = 0.5;
398     C1 = 1.00;
399     D1 = 1.00;
400     E1 = 3.00;
401     A2 = 1.10;
402     B2 = 1.30;
403     C2 = 1.00;
404     D2 = 0.00;
405     alphaConst = 0.66;
406   } else {
407     //Data For Liquid Water from Dingfelder (Protons in Water)
408     A1 = 1.02;
409     B1 = 82.0;
410     C1 = 0.45;
411     D1 = -0.80;
412     E1 = 0.38;
413     A2 = 1.07;
414     // Value provided by M. Dingfelder (priv. comm)
415     B2 = 11.6;
416     C2 = 0.60;
417     D2 = 0.04;
418     alphaConst = 0.64;
419   }
420   bEnergy = Bj[shell];
421   G4double v2 = 0.25*emax/(bEnergy*gam*gam);
422   v = std::sqrt(v2);
423   u = Ry/bEnergy;
424   wc = 4.*v2 - 2.*v - 0.25*u;
425 
426   G4double L1 = (C1 * fGpow->powA(v, D1)) / (1. + E1 * fGpow->powA(v, (D1 + 4.)));
427   G4double L2 = C2 * fGpow->powA(v, D2);
428   G4double H1 = (A1 * G4Log(1. + v2)) / (v2 + (B1 / v2));
429   G4double H2 = (A2 / v2) + (B2 / (v2 * v2));
430 
431   F1 = L1 + H1;
432   F2 = (L2 * H2) / (L2 + H2);
433   return emax;
434 }
435 
436 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
437 
438 G4double G4DNARuddIonisationExtendedModel::SampleElectronEnergy(G4double kine,
439                                                                 G4int shell)
440 {
441   G4double emax = MaxEnergy(kine, shell);
442   // compute cumulative probability function
443   G4double step = 1*CLHEP::eV;
444   auto nn = (G4int)(emax/step);
445   nn = std::min(std::max(nn, 10), 100);
446   step = emax/(G4double)nn;
447 
448   // find max probability
449   G4double pmax = ProbabilityFunction(kine, 0.0, shell);
450   //G4cout << "## E(keV)=" << kine/keV << " emax=" << emax/keV
451   //       << " pmax(0)=" << pmax << " shell=" << shell << " nn=" << nn << G4endl;
452 
453   G4double e0 = 0.0; // energy with max probability
454   // 2 areas after point with max probability
455   G4double e1 = emax;
456   G4double e2 = emax;
457   G4double p1 = 0.0;
458   G4double p2 = 0.0;
459   const G4double f = 0.25;
460 
461   // find max probability
462   G4double e = 0.0;
463   G4double p = 0.0;
464   for (G4int i=0; i<nn; ++i) {
465     e += step;
466     p = ProbabilityFunction(kine, e, shell);
467     if (p > pmax) {
468       pmax = p;
469       e0 = e;
470     } else {
471       break;
472     }
473   }
474   // increase step to be more effective
475   step *= 2.0;
476   // 2-nd area
477   for (G4int i=0; i<nn; ++i) {
478     e += step;
479     if (std::abs(e - emax) < step) {
480       e1 = emax;
481       break;
482     }
483     p = ProbabilityFunction(kine, e, shell);
484     if (p < f*pmax) {
485       p1 = p;
486       e1 = e;
487       break;
488     }
489   }
490   // 3-d area
491   if (e < emax) {
492     for (G4int i=0; i<nn; ++i) {
493       e += step;
494       if (std::abs(e - emax) < step) {
495         e2 = emax;
496   break;
497       }
498       p = ProbabilityFunction(kine, e, shell);
499       if (p < f*p1) {
500   p2 = p;
501   e2 = e;
502         break;
503       }
504     }
505   }
506   pmax *= 1.05;
507   // regression method with 3 regions
508   G4double s0 = pmax*e1;
509   G4double s1 = s0 + p1 * (e2 - e1);
510   G4double s2 = s1 + p2 * (emax - e2);
511   s0 = (s0 == s1) ? 1.0 : s0 / s2;
512   s1 = (s1 == s2) ? 1.0 : s1 / s2;
513 
514   //G4cout << "pmax=" << pmax << " e1(keV)=" << e1/keV << " p1=" << p1 << " e2(keV)=" << e2/keV
515   //   << " p2=" << p2 << " s0=" << s0 << " s1=" << s1 << " s2=" << s2 << G4endl;
516 
517   // sampling
518   G4int count = 0;
519   G4double ymax, y, deltae;
520   for (G4int i = 0; i<100000; ++i) {
521     G4double q = G4UniformRand();
522     if (q <= s0) {
523       ymax = pmax;
524       deltae = e1 * q / s0;
525     } else if (q <= s1) {
526       ymax = p1;
527       deltae = e1 + (e2 - e1) * (q - s0) / (s1 - s0);
528     } else {
529       ymax = p2;
530       deltae = e2 + (emax - e2) * (q - s1) / (1.0 - s1);
531     }
532     y = ProbabilityFunction(kine, deltae, shell);
533     //G4cout << "    " << i << ".  deltae=" << deltae/CLHEP::keV 
534     //       << " y=" << y << " ymax=" << ymax << G4endl; 
535     if (y > ymax && count < 10) {
536       ++count;
537       G4cout << "G4DNARuddIonisationExtendedModel::SampleElectronEnergy warning: "
538        << fParticle->GetParticleName() << " E(keV)=" << kine/CLHEP::keV
539        << " Edelta(keV)=" << deltae/CLHEP::keV 
540        << " y=" << y << " ymax=" << ymax << " n=" << i << G4endl; 
541     }
542     if (ymax * G4UniformRand() <= y) {
543       return deltae;
544     }
545   }
546   deltae = std::min(e0 + step, 0.5*emax);
547   return deltae;
548 }
549 
550 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
551 
552 G4double G4DNARuddIonisationExtendedModel::ProbabilityFunction(G4double kine,
553                                                                G4double deltae,
554                                                                G4int shell)
555 {
556   // Shells ids are 0 1 2 3 4 (4 is k shell)
557   // !!Attention, "energyTransfer" here is the energy transfered to the electron which means
558   //             that the secondary kinetic energy is w = energyTransfer - bindingEnergy
559   //
560   //   ds            S                F1(nu) + w * F2(nu)
561   //  ---- = G(k) * ----     -------------------------------------------
562   //   dw            Bj       (1+w)^3 * [1 + exp{alpha * (w - wc) / nu}]
563   //
564   // w is the secondary electron kinetic Energy in eV
565   //
566   // All the other parameters can be found in Rudd's Papers
567   //
568   // M.Eugene Rudd, 1988, User-Friendly model for the energy distribution of
569   // electrons from protons or electron collisions. Nucl. Tracks Rad. Meas.Vol 16 N0 2/3 pp 219-218
570   //
571   G4double w = deltae/bEnergy;
572   G4double x = alphaConst*(w - wc)/v;
573   G4double y = (x > -15.) ? 1.0 + G4Exp(x) : 1.0;
574 
575   G4double res = CorrectionFactor(kine, shell) * (F1 + w*F2) /
576     (fGpow->powN((1. + w)/u, 3) * y);
577 
578   if (isHelium) {
579     G4double energyTransfer = deltae + bEnergy;
580     G4double Zeff = 2.0 -
581       (sCoefficient[0] * S_1s(kine, energyTransfer, slaterEffectiveCharge[0], 1.) +
582        sCoefficient[1] * S_2s(kine, energyTransfer, slaterEffectiveCharge[1], 2.) +
583        sCoefficient[2] * S_2p(kine, energyTransfer, slaterEffectiveCharge[2], 2.) );
584 
585     res *= Zeff * Zeff;
586   }
587   return std::max(res, 0.0);
588 }
589 
590 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
591 
592 G4double G4DNARuddIonisationExtendedModel::ComputeProbabilityFunction(
593          const G4ParticleDefinition* p, G4double e, G4double deltae, G4int shell)
594 {
595   if (fParticle != p) { SetParticle(p); }
596   MaxEnergy(e, shell);
597   return ProbabilityFunction(e, deltae, shell);
598 }
599 
600 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
601 
602 G4double G4DNARuddIonisationExtendedModel::S_1s(G4double kine,
603                                                 G4double energyTransfer,
604                                                 G4double slaterEffCharge,
605                                                 G4double shellNumber)
606 {
607   // 1 - e^(-2r) * ( 1 + 2 r + 2 r^2)
608   // Dingfelder, in Chattanooga 2005 proceedings, formula (7)
609 
610   G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
611   G4double value = 1. - G4Exp(-2 * r) * ( ( 2. * r + 2. ) * r + 1. );
612   return value;
613 }
614 
615 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
616 
617 G4double G4DNARuddIonisationExtendedModel::S_2s(G4double kine,
618                                                 G4double energyTransfer,
619                                                 G4double slaterEffCharge,
620                                                 G4double shellNumber)
621 {
622   // 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 2 r^4)
623   // Dingfelder, in Chattanooga 2005 proceedings, formula (8)
624 
625   G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
626   G4double value =
627     1. - G4Exp(-2 * r) * (((2. * r * r + 2.) * r + 2.) * r + 1.);
628 
629   return value;
630 }
631 
632 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
633 
634 G4double G4DNARuddIonisationExtendedModel::S_2p(G4double kine, 
635                                                 G4double energyTransfer,
636                                                 G4double slaterEffCharge,
637                                                 G4double shellNumber)
638 {
639   // 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 4/3 r^3 + 2/3 r^4)
640   // Dingfelder, in Chattanooga 2005 proceedings, formula (9)
641 
642   G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
643   G4double value =
644     1. - G4Exp(-2 * r) * (((( 2./3. * r + 4./3.) * r + 2.) * r + 2.) * r  + 1.);
645 
646   return value;
647 }
648 
649 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
650 
651 G4double G4DNARuddIonisationExtendedModel::Rh(G4double ekin, G4double etrans,
652                                               G4double q, G4double shell)
653 {
654   // The following values are provided by M. Dingfelder (priv. comm)
655   // Dingfelder, in Chattanooga 2005 proceedings, p 4
656 
657   G4double escaled = CLHEP::electron_mass_c2/fMass * ekin;
658   const G4double H = 13.60569172 * CLHEP::eV;
659   G4double value = 2.0*std::sqrt(escaled / H)*q*H /(etrans*shell);
660 
661   return value;
662 }
663 
664 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
665 
666 G4double 
667 G4DNARuddIonisationExtendedModel::CorrectionFactor(G4double kine, G4int shell) 
668 {
669   // ZF Shortened
670   G4double res = 1.0;
671   if (shell < 4 && 0 != idx) {
672     const G4double ln10 = fGpow->logZ(10);
673     G4double x = 2.0*((G4Log(kine/CLHEP::eV)/ln10) - 4.2);
674     // The following values are provided by M. Dingfelder (priv. comm)
675     res = 0.6/(1.0 + G4Exp(x)) + 0.9;
676   }
677   return res;
678 }
679 
680 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
681