Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/dna/models/src/G4DNARuddIonisationModel.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 
 28 #include "G4DNARuddIonisationModel.hh"
 29 #include "G4PhysicalConstants.hh"
 30 #include "G4SystemOfUnits.hh"
 31 #include "G4UAtomicDeexcitation.hh"
 32 #include "G4LossTableManager.hh"
 33 #include "G4DNAChemistryManager.hh"
 34 #include "G4DNAMolecularMaterial.hh"
 35 #include "G4DNARuddAngle.hh"
 36 #include "G4DeltaAngle.hh"
 37 #include "G4Exp.hh"
 38 #include "G4Pow.hh"
 39 #include "G4Log.hh"
 40 #include "G4Alpha.hh"
 41 
 42 static G4Pow * gpow = G4Pow::GetInstance();
 43 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 44 
 45 using namespace std;
 46 
 47 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 48 
 49 G4DNARuddIonisationModel::G4DNARuddIonisationModel(const G4ParticleDefinition*,
 50                                                    const G4String& nam) :
 51 G4VEmModel(nam) 
 52 {
 53   slaterEffectiveCharge[0] = 0.;
 54   slaterEffectiveCharge[1] = 0.;
 55   slaterEffectiveCharge[2] = 0.;
 56   sCoefficient[0] = 0.;
 57   sCoefficient[1] = 0.;
 58   sCoefficient[2] = 0.;
 59 
 60   lowEnergyLimitForZ1 = 0 * eV;
 61   lowEnergyLimitForZ2 = 0 * eV;
 62   lowEnergyLimitOfModelForZ1 = 100 * eV;
 63   lowEnergyLimitOfModelForZ2 = 1 * keV;
 64   killBelowEnergyForZ1 = lowEnergyLimitOfModelForZ1;
 65   killBelowEnergyForZ2 = lowEnergyLimitOfModelForZ2;
 66 
 67   verboseLevel = 0;
 68   // Verbosity scale:
 69   // 0 = nothing
 70   // 1 = warning for energy non-conservation
 71   // 2 = details of energy budget
 72   // 3 = calculation of cross sections, file openings, sampling of atoms
 73   // 4 = entering in methods
 74 
 75   if (verboseLevel > 0)
 76   {
 77     G4cout << "Rudd ionisation model is constructed " << G4endl;
 78   }
 79 
 80   // Define default angular generator
 81   SetAngularDistribution(new G4DNARuddAngle());
 82 
 83   // Mark this model as "applicable" for atomic deexcitation
 84   SetDeexcitationFlag(true);
 85 
 86  // Selection of stationary mode
 87 
 88   statCode = false;
 89 }
 90 
 91 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 92 
 93 G4DNARuddIonisationModel::~G4DNARuddIonisationModel()
 94 {
 95   // Cross section
 96 
 97   std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
 98   for (pos = tableData.begin(); pos != tableData.end(); ++pos)
 99   {
100     G4DNACrossSectionDataSet* table = pos->second;
101     delete table;
102   }
103 
104   // The following removal is forbidden since G4VEnergyLossmodel takes care of deletion
105   // Coverity however will signal this as an error
106   // if (fAtomDeexcitation) {delete  fAtomDeexcitation;}
107 
108 }
109 
110 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
111 
112 void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
113                                           const G4DataVector& /*cuts*/)
114 {
115 
116   if (verboseLevel > 3)
117   {
118     G4cout << "Calling G4DNARuddIonisationModel::Initialise()" << G4endl;
119   }
120 
121   // Energy limits
122 
123   G4String fileProton("dna/sigma_ionisation_p_rudd");
124   G4String fileHydrogen("dna/sigma_ionisation_h_rudd");
125   G4String fileAlphaPlusPlus("dna/sigma_ionisation_alphaplusplus_rudd");
126   G4String fileAlphaPlus("dna/sigma_ionisation_alphaplus_rudd");
127   G4String fileHelium("dna/sigma_ionisation_he_rudd");
128 
129   G4DNAGenericIonsManager *instance;
130   instance = G4DNAGenericIonsManager::Instance();
131   protonDef = G4Proton::ProtonDefinition();
132   hydrogenDef = instance->GetIon("hydrogen");
133   alphaPlusPlusDef = G4Alpha::Alpha();
134   alphaPlusDef = instance->GetIon("alpha+");
135   heliumDef = instance->GetIon("helium");
136 
137   G4String proton;
138   G4String hydrogen;
139   G4String alphaPlusPlus;
140   G4String alphaPlus;
141   G4String helium;
142 
143   G4double scaleFactor = 1 * m*m;
144 
145   // LIMITS AND DATA
146 
147   // ********************************************************
148 
149   proton = protonDef->GetParticleName();
150   tableFile[proton] = fileProton;
151 
152   lowEnergyLimit[proton] = lowEnergyLimitForZ1;
153   highEnergyLimit[proton] = 500. * keV;
154 
155   // Cross section
156 
157   auto  tableProton = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
158       eV,
159       scaleFactor );
160   tableProton->LoadData(fileProton);
161   tableData[proton] = tableProton;
162 
163   // ********************************************************
164 
165   hydrogen = hydrogenDef->GetParticleName();
166   tableFile[hydrogen] = fileHydrogen;
167 
168   lowEnergyLimit[hydrogen] = lowEnergyLimitForZ1;
169   highEnergyLimit[hydrogen] = 100. * MeV;
170 
171   // Cross section
172 
173   auto  tableHydrogen = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
174       eV,
175       scaleFactor );
176   tableHydrogen->LoadData(fileHydrogen);
177 
178   tableData[hydrogen] = tableHydrogen;
179 
180   // ********************************************************
181 
182   alphaPlusPlus = alphaPlusPlusDef->GetParticleName();
183   tableFile[alphaPlusPlus] = fileAlphaPlusPlus;
184 
185   lowEnergyLimit[alphaPlusPlus] = lowEnergyLimitForZ2;
186   highEnergyLimit[alphaPlusPlus] = 400. * MeV;
187 
188   // Cross section
189 
190   auto  tableAlphaPlusPlus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
191       eV,
192       scaleFactor );
193   tableAlphaPlusPlus->LoadData(fileAlphaPlusPlus);
194 
195   tableData[alphaPlusPlus] = tableAlphaPlusPlus;
196 
197   // ********************************************************
198 
199   alphaPlus = alphaPlusDef->GetParticleName();
200   tableFile[alphaPlus] = fileAlphaPlus;
201 
202   lowEnergyLimit[alphaPlus] = lowEnergyLimitForZ2;
203   highEnergyLimit[alphaPlus] = 400. * MeV;
204 
205   // Cross section
206 
207   auto  tableAlphaPlus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
208       eV,
209       scaleFactor );
210   tableAlphaPlus->LoadData(fileAlphaPlus);
211   tableData[alphaPlus] = tableAlphaPlus;
212 
213   // ********************************************************
214 
215   helium = heliumDef->GetParticleName();
216   tableFile[helium] = fileHelium;
217 
218   lowEnergyLimit[helium] = lowEnergyLimitForZ2;
219   highEnergyLimit[helium] = 400. * MeV;
220 
221   // Cross section
222 
223   auto  tableHelium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
224       eV,
225       scaleFactor );
226   tableHelium->LoadData(fileHelium);
227   tableData[helium] = tableHelium;
228 
229   //
230 
231   if (particle==protonDef)
232   {
233     SetLowEnergyLimit(lowEnergyLimit[proton]);
234     SetHighEnergyLimit(highEnergyLimit[proton]);
235   }
236 
237   if (particle==hydrogenDef)
238   {
239     SetLowEnergyLimit(lowEnergyLimit[hydrogen]);
240     SetHighEnergyLimit(highEnergyLimit[hydrogen]);
241   }
242 
243   if (particle==heliumDef)
244   {
245     SetLowEnergyLimit(lowEnergyLimit[helium]);
246     SetHighEnergyLimit(highEnergyLimit[helium]);
247   }
248 
249   if (particle==alphaPlusDef)
250   {
251     SetLowEnergyLimit(lowEnergyLimit[alphaPlus]);
252     SetHighEnergyLimit(highEnergyLimit[alphaPlus]);
253   }
254 
255   if (particle==alphaPlusPlusDef)
256   {
257     SetLowEnergyLimit(lowEnergyLimit[alphaPlusPlus]);
258     SetHighEnergyLimit(highEnergyLimit[alphaPlusPlus]);
259   }
260 
261   if( verboseLevel>0 )
262   {
263     G4cout << "Rudd ionisation model is initialized " << G4endl
264     << "Energy range: "
265     << LowEnergyLimit() / eV << " eV - "
266     << HighEnergyLimit() / keV << " keV for "
267     << particle->GetParticleName()
268     << G4endl;
269   }
270 
271   // Initialize water density pointer
272   fpWaterDensity = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
273 
274   //
275 
276   fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
277 
278   if (isInitialised)
279   { return;}
280   fParticleChangeForGamma = GetParticleChangeForGamma();
281   isInitialised = true;
282 
283 }
284 
285 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
286 
287 G4double G4DNARuddIonisationModel::CrossSectionPerVolume(const G4Material* material,
288                                                          const G4ParticleDefinition* particleDefinition,
289                                                          G4double k,
290                                                          G4double,
291                                                          G4double)
292 {
293   if (verboseLevel > 3)
294   {
295     G4cout << "Calling CrossSectionPerVolume() of G4DNARuddIonisationModel"
296         << G4endl;
297   }
298 
299   // Calculate total cross section for model
300 
301   if (
302       particleDefinition != protonDef
303       &&
304       particleDefinition != hydrogenDef
305       &&
306       particleDefinition != alphaPlusPlusDef
307       &&
308       particleDefinition != alphaPlusDef
309       &&
310       particleDefinition != heliumDef
311   )
312 
313   return 0;
314 
315   G4double lowLim = 0;
316 
317   if ( particleDefinition == protonDef
318       || particleDefinition == hydrogenDef
319   )
320 
321   lowLim = lowEnergyLimitOfModelForZ1;
322 
323   if ( particleDefinition == alphaPlusPlusDef
324       || particleDefinition == alphaPlusDef
325       || particleDefinition == heliumDef
326   )
327 
328   lowLim = lowEnergyLimitOfModelForZ2;
329 
330   G4double highLim = 0;
331   G4double sigma=0;
332 
333   G4double waterDensity = (*fpWaterDensity)[material->GetIndex()];
334 
335   const G4String& particleName = particleDefinition->GetParticleName();
336 
337   // SI - the following is useless since lowLim is already defined
338   /*
339   std::map< G4String,G4double,std::less<G4String> >::iterator pos1;
340   pos1 = lowEnergyLimit.find(particleName);
341 
342   if (pos1 != lowEnergyLimit.end())
343   {
344     lowLim = pos1->second;
345   }
346   */
347 
348   std::map< G4String,G4double,std::less<G4String> >::iterator pos2;
349   pos2 = highEnergyLimit.find(particleName);
350 
351   if (pos2 != highEnergyLimit.end())
352   {
353     highLim = pos2->second;
354   }
355 
356   if (k <= highLim)
357   {
358     //SI : XS must not be zero otherwise sampling of secondaries method ignored
359 
360     if (k < lowLim) k = lowLim;
361 
362     //
363 
364     std::map< G4String,G4DNACrossSectionDataSet*,std::less<G4String> >::iterator pos;
365     pos = tableData.find(particleName);
366 
367     if (pos != tableData.end())
368     {
369       G4DNACrossSectionDataSet* table = pos->second;
370       if (table != nullptr)
371       {
372         sigma = table->FindValue(k);
373       }
374     }
375     else
376     {
377       G4Exception("G4DNARuddIonisationModel::CrossSectionPerVolume","em0002",
378           FatalException,"Model not applicable to particle type.");
379     }
380 
381   } 
382 
383   if (verboseLevel > 2)
384   {
385     G4cout << "__________________________________" << G4endl;
386     G4cout << "G4DNARuddIonisationModel - XS INFO START" << G4endl;
387     G4cout << "Kinetic energy(eV)=" << k/eV << " particle : " << particleDefinition->GetParticleName() << G4endl;
388     G4cout << "Cross section per water molecule (cm^2)=" << sigma/cm/cm << G4endl;
389     G4cout << "Cross section per water molecule (cm^-1)=" << sigma*waterDensity/(1./cm) << G4endl;
390     //G4cout << " - Cross section per water molecule (cm^-1)=" 
391     //<< sigma*material->GetAtomicNumDensityVector()[1]/(1./cm) << G4endl;
392     G4cout << "G4DNARuddIonisationModel - XS INFO END" << G4endl;
393   }
394 
395   return sigma*waterDensity;
396 
397 }
398 
399 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
400 
401 void G4DNARuddIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
402                                                  const G4MaterialCutsCouple* couple,
403                                                  const G4DynamicParticle* particle,
404                                                  G4double,
405                                                  G4double)
406 {
407   if (verboseLevel > 3)
408   {
409     G4cout << "Calling SampleSecondaries() of G4DNARuddIonisationModel"
410         << G4endl;
411   }
412 
413   G4double lowLim = 0;
414   G4double highLim = 0;
415 
416   if ( particle->GetDefinition() == protonDef
417       || particle->GetDefinition() == hydrogenDef
418   )
419 
420   lowLim = killBelowEnergyForZ1;
421 
422   if ( particle->GetDefinition() == alphaPlusPlusDef
423       || particle->GetDefinition() == alphaPlusDef
424       || particle->GetDefinition() == heliumDef
425   )
426 
427   lowLim = killBelowEnergyForZ2;
428 
429   G4double k = particle->GetKineticEnergy();
430 
431   const G4String& particleName = particle->GetDefinition()->GetParticleName();
432 
433   // SI - the following is useless since lowLim is already defined
434   /*
435    std::map< G4String,G4double,std::less<G4String> >::iterator pos1;
436    pos1 = lowEnergyLimit.find(particleName);
437 
438    if (pos1 != lowEnergyLimit.end())
439    {
440    lowLim = pos1->second;
441    }
442   */
443 
444   std::map< G4String,G4double,std::less<G4String> >::iterator pos2;
445   pos2 = highEnergyLimit.find(particleName);
446 
447   if (pos2 != highEnergyLimit.end())
448   {
449     highLim = pos2->second;
450   }
451 
452   if (k >= lowLim && k <= highLim)
453   {
454     G4ParticleDefinition* definition = particle->GetDefinition();
455     G4ParticleMomentum primaryDirection = particle->GetMomentumDirection();
456     /*
457      G4double particleMass = definition->GetPDGMass();
458      G4double totalEnergy = k + particleMass;
459      G4double pSquare = k*(totalEnergy+particleMass);
460      G4double totalMomentum = std::sqrt(pSquare);
461     */
462 
463     G4int ionizationShell = RandomSelect(k,particleName);
464 
465     G4double bindingEnergy = 0;
466     bindingEnergy = waterStructure.IonisationEnergy(ionizationShell);
467 
468     //SI: additional protection if tcs interpolation method is modified
469     if (k<bindingEnergy) return;
470     //
471 
472     // SI - For atom. deexc. tagging - 23/05/2017
473     G4int Z = 8;
474     //
475     
476     G4double secondaryKinetic = RandomizeEjectedElectronEnergy(definition,k,ionizationShell);
477 
478     G4ThreeVector deltaDirection =
479     GetAngularDistribution()->SampleDirectionForShell(particle, secondaryKinetic,
480         Z, ionizationShell,
481         couple->GetMaterial());
482 
483     auto  dp = new G4DynamicParticle (G4Electron::Electron(),deltaDirection,secondaryKinetic);
484     fvect->push_back(dp);
485 
486     // Ignored for ions on electrons
487     /*
488      G4double deltaTotalMomentum = std::sqrt(secondaryKinetic*(secondaryKinetic + 2.*electron_mass_c2 ));
489 
490      G4double finalPx = totalMomentum*primaryDirection.x() - deltaTotalMomentum*deltaDirection.x();
491      G4double finalPy = totalMomentum*primaryDirection.y() - deltaTotalMomentum*deltaDirection.y();
492      G4double finalPz = totalMomentum*primaryDirection.z() - deltaTotalMomentum*deltaDirection.z();
493      G4double finalMomentum = std::sqrt(finalPx*finalPx+finalPy*finalPy+finalPz*finalPz);
494      finalPx /= finalMomentum;
495      finalPy /= finalMomentum;
496      finalPz /= finalMomentum;
497 
498      G4ThreeVector direction;
499      direction.set(finalPx,finalPy,finalPz);
500 
501      fParticleChangeForGamma->ProposeMomentumDirection(direction.unit()) ;
502     */
503      
504     fParticleChangeForGamma->ProposeMomentumDirection(primaryDirection);
505 
506     // sample deexcitation
507     // here we assume that H_{2}O electronic levels are the same of Oxigen.
508     // this can be considered true with a rough 10% error in energy on K-shell,
509 
510     size_t secNumberInit = 0;// need to know at a certain point the energy of secondaries
511     size_t secNumberFinal = 0;// So I'll make the diference and then sum the energies
512 
513     G4double scatteredEnergy = k-bindingEnergy-secondaryKinetic;
514 
515     // SI: only atomic deexcitation from K shell is considered
516     if((fAtomDeexcitation != nullptr) && ionizationShell == 4)
517     {
518       const G4AtomicShell* shell 
519         = fAtomDeexcitation->GetAtomicShell(Z, G4AtomicShellEnumerator(0));
520       secNumberInit = fvect->size();
521       fAtomDeexcitation->GenerateParticles(fvect, shell, Z, 0, 0);
522       secNumberFinal = fvect->size();
523 
524       if(secNumberFinal > secNumberInit) 
525       {
526   for (size_t i=secNumberInit; i<secNumberFinal; ++i) 
527         {
528           //Check if there is enough residual energy 
529           if (bindingEnergy >= ((*fvect)[i])->GetKineticEnergy())
530           {
531              //Ok, this is a valid secondary: keep it
532        bindingEnergy -= ((*fvect)[i])->GetKineticEnergy();
533           }
534           else
535           {
536        //Invalid secondary: not enough energy to create it!
537        //Keep its energy in the local deposit
538              delete (*fvect)[i]; 
539              (*fvect)[i]=nullptr;
540           }
541   } 
542       }
543 
544     }
545 
546     //This should never happen
547     if(bindingEnergy < 0.0) 
548      G4Exception("G4DNAEmfietzoglouIonisatioModel1::SampleSecondaries()",
549                  "em2050",FatalException,"Negative local energy deposit");   
550  
551     //bindingEnergy has been decreased 
552     //by the amount of energy taken away by deexc. products
553     if (!statCode)
554     {
555       fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
556       fParticleChangeForGamma->ProposeLocalEnergyDeposit(bindingEnergy);
557     }
558     else
559     {
560       fParticleChangeForGamma->SetProposedKineticEnergy(k);
561       fParticleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy);
562     }
563 
564     // debug
565     // k-scatteredEnergy-secondaryKinetic-deexSecEnergy = k-(k-bindingEnergy-secondaryKinetic)-secondaryKinetic-deexSecEnergy =
566     // = k-k+bindingEnergy+secondaryKinetic-secondaryKinetic-deexSecEnergy=
567     // = bindingEnergy-deexSecEnergy
568     // SO deexSecEnergy=0 => LocalEnergyDeposit =  bindingEnergy
569 
570     // TEST //////////////////////////
571     // if (secondaryKinetic<0) abort();
572     // if (scatteredEnergy<0) abort();
573     // if (k-scatteredEnergy-secondaryKinetic-deexSecEnergy<0) abort();
574     // if (k-scatteredEnergy<0) abort();     
575     /////////////////////////////////
576 
577     const G4Track * theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
578     G4DNAChemistryManager::Instance()->CreateWaterMolecule(eIonizedMolecule,
579         ionizationShell,
580         theIncomingTrack);
581   }
582 
583   // SI - not useful since low energy of model is 0 eV
584 
585   if (k < lowLim)
586   {
587     fParticleChangeForGamma->SetProposedKineticEnergy(0.);
588     fParticleChangeForGamma->ProposeTrackStatus(fStopAndKill);
589     fParticleChangeForGamma->ProposeLocalEnergyDeposit(k);
590   }
591 
592 }
593 
594 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
595 
596 G4double G4DNARuddIonisationModel::RandomizeEjectedElectronEnergy(G4ParticleDefinition* particleDefinition,
597                                                                   G4double k,
598                                                                   G4int shell)
599 {
600   G4double maximumKineticEnergyTransfer = 0.;
601 
602   if (particleDefinition == protonDef
603       || particleDefinition == hydrogenDef)
604   {
605     maximumKineticEnergyTransfer = 4. * (electron_mass_c2 / proton_mass_c2) * k;
606   }
607 
608   else if (particleDefinition == heliumDef
609       || particleDefinition == alphaPlusDef
610       || particleDefinition == alphaPlusPlusDef)
611   {
612     maximumKineticEnergyTransfer = 4. * (0.511 / 3728) * k;
613   }
614 
615   G4double crossSectionMaximum = 0.;
616 
617   for (G4double value = waterStructure.IonisationEnergy(shell);
618       value <= 5. * waterStructure.IonisationEnergy(shell) && k >= value;
619       value += 0.1 * eV)
620   {
621     G4double differentialCrossSection =
622         DifferentialCrossSection(particleDefinition, k, value, shell);
623     if (differentialCrossSection >= crossSectionMaximum)
624       crossSectionMaximum = differentialCrossSection;
625   }
626 
627   G4double secElecKinetic = 0.;
628 
629   do
630   {
631     secElecKinetic = G4UniformRand()* maximumKineticEnergyTransfer;
632   }while(G4UniformRand()*crossSectionMaximum > DifferentialCrossSection(particleDefinition,
633           k,
634           secElecKinetic+waterStructure.IonisationEnergy(shell),
635           shell));
636 
637   return (secElecKinetic);
638 }
639 
640 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
641 
642 // The following section is not used anymore but is kept for memory
643 // GetAngularDistribution()->SampleDirectionForShell is used instead
644 
645 /*
646  void G4DNARuddIonisationModel::RandomizeEjectedElectronDirection(G4ParticleDefinition* particleDefinition,
647  G4double k,
648  G4double secKinetic,
649  G4double & cosTheta,
650  G4double & phi )
651  {
652  G4DNAGenericIonsManager *instance;
653  instance = G4DNAGenericIonsManager::Instance();
654 
655  G4double maxSecKinetic = 0.;
656 
657  if (particleDefinition == protonDef
658  || particleDefinition == hydrogenDef)
659  {
660  maxSecKinetic = 4.* (electron_mass_c2 / proton_mass_c2) * k;
661  }
662 
663  else if (particleDefinition == heliumDef
664  || particleDefinition == alphaPlusDef
665  || particleDefinition == alphaPlusPlusDef)
666  {
667  maxSecKinetic = 4.* (0.511 / 3728) * k;
668  }
669 
670  phi = twopi * G4UniformRand();
671 
672  // cosTheta = std::sqrt(secKinetic / maxSecKinetic);
673 
674  // Restriction below 100 eV from Emfietzoglou (2000)
675 
676  if (secKinetic>100*eV) cosTheta = std::sqrt(secKinetic / maxSecKinetic);
677  else cosTheta = (2.*G4UniformRand())-1.;
678 
679  }
680  */
681 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
682 G4double G4DNARuddIonisationModel::DifferentialCrossSection(G4ParticleDefinition* particleDefinition,
683                                                             G4double k,
684                                                             G4double energyTransfer,
685                                                             G4int ionizationLevelIndex)
686 {
687   // Shells ids are 0 1 2 3 4 (4 is k shell)
688   // !!Attention, "energyTransfer" here is the energy transfered to the electron which means
689   //             that the secondary kinetic energy is w = energyTransfer - bindingEnergy
690   //
691   //   ds            S                F1(nu) + w * F2(nu)
692   //  ---- = G(k) * ----     -------------------------------------------
693   //   dw            Bj       (1+w)^3 * [1 + exp{alpha * (w - wc) / nu}]
694   //
695   // w is the secondary electron kinetic Energy in eV
696   //
697   // All the other parameters can be found in Rudd's Papers
698   //
699   // M.Eugene Rudd, 1988, User-Friendly model for the energy distribution of
700   // electrons from protons or electron collisions. Nucl. Tracks Rad. Meas.Vol 16 N0 2/3 pp 219-218
701   //
702 
703   const G4int j = ionizationLevelIndex;
704 
705   G4double A1;
706   G4double B1;
707   G4double C1;
708   G4double D1;
709   G4double E1;
710   G4double A2;
711   G4double B2;
712   G4double C2;
713   G4double D2;
714   G4double alphaConst;
715 
716   //  const G4double Bj[5] = {12.61*eV, 14.73*eV, 18.55*eV, 32.20*eV, 539.7*eV};
717   // The following values are provided by M. dingfelder (priv. comm)
718   const G4double Bj[5] = { 12.60 * eV, 14.70 * eV, 18.40 * eV, 32.20 * eV, 540
719       * eV };
720 
721   if (j == 4)
722   {
723     //Data For Liquid Water K SHELL from Dingfelder (Protons in Water)
724     A1 = 1.25;
725     B1 = 0.5;
726     C1 = 1.00;
727     D1 = 1.00;
728     E1 = 3.00;
729     A2 = 1.10;
730     B2 = 1.30;
731     C2 = 1.00;
732     D2 = 0.00;
733     alphaConst = 0.66;
734   } else
735   {
736     //Data For Liquid Water from Dingfelder (Protons in Water)
737     A1 = 1.02;
738     B1 = 82.0;
739     C1 = 0.45;
740     D1 = -0.80;
741     E1 = 0.38;
742     A2 = 1.07;
743     // Value provided by M. Dingfelder (priv. comm)
744     B2 = 11.6;
745     //
746     C2 = 0.60;
747     D2 = 0.04;
748     alphaConst = 0.64;
749   }
750 
751   const G4double n = 2.;
752   const G4double Gj[5] = { 0.99, 1.11, 1.11, 0.52, 1. };
753 
754   G4double wBig = (energyTransfer
755       - waterStructure.IonisationEnergy(ionizationLevelIndex));
756   if (wBig < 0)
757     return 0.;
758 
759   G4double w = wBig / Bj[ionizationLevelIndex];
760   // Note that the following (j==4) cases are provided by   M. Dingfelder (priv. comm)
761   if (j == 4)
762     w = wBig / waterStructure.IonisationEnergy(ionizationLevelIndex);
763 
764   G4double Ry = 13.6 * eV;
765 
766   G4double tau = 0.;
767 
768   G4bool isProtonOrHydrogen = false;
769   G4bool isHelium = false;
770 
771   if (particleDefinition == protonDef
772       || particleDefinition == hydrogenDef)
773   {
774     isProtonOrHydrogen = true;
775     tau = (electron_mass_c2 / proton_mass_c2) * k;
776   }
777 
778   else if (particleDefinition == heliumDef
779       || particleDefinition == alphaPlusDef
780       || particleDefinition == alphaPlusPlusDef)
781   {
782     isHelium = true;
783     tau = (0.511 / 3728.) * k;
784   }
785 
786   G4double S = 4. * pi * Bohr_radius * Bohr_radius * n
787       * gpow->powN((Ry / Bj[ionizationLevelIndex]), 2);
788   if (j == 4)
789     S = 4. * pi * Bohr_radius * Bohr_radius * n
790         * gpow->powN((Ry / waterStructure.IonisationEnergy(ionizationLevelIndex)),
791                    2);
792 
793   G4double v2 = tau / Bj[ionizationLevelIndex];
794   if (j == 4)
795     v2 = tau / waterStructure.IonisationEnergy(ionizationLevelIndex);
796 
797   G4double v = std::sqrt(v2);
798   G4double wc = 4. * v2 - 2. * v - (Ry / (4. * Bj[ionizationLevelIndex]));
799   if (j == 4)
800     wc = 4. * v2 - 2. * v
801         - (Ry / (4. * waterStructure.IonisationEnergy(ionizationLevelIndex)));
802 
803   G4double L1 = (C1 * gpow->powA(v, (D1))) / (1. + E1 * gpow->powA(v, (D1 + 4.)));
804   G4double L2 = C2 * gpow->powA(v, (D2));
805   G4double H1 = (A1 * G4Log(1. + v2)) / (v2 + (B1 / v2));
806   G4double H2 = (A2 / v2) + (B2 / (v2 * v2));
807 
808   G4double F1 = L1 + H1;
809   G4double F2 = (L2 * H2) / (L2 + H2);
810 
811   G4double sigma =
812       CorrectionFactor(particleDefinition, k) * Gj[j]
813           * (S / Bj[ionizationLevelIndex])
814           * ((F1 + w * F2)
815               / (gpow->powN((1. + w), 3)
816                   * (1. + G4Exp(alphaConst * (w - wc) / v))));
817 
818   if (j == 4)
819     sigma = CorrectionFactor(particleDefinition, k) * Gj[j]
820         * (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
821         * ((F1 + w * F2)
822             / (gpow->powN((1. + w), 3)
823                 * (1. + G4Exp(alphaConst * (w - wc) / v))));
824 
825   if ((particleDefinition == hydrogenDef)
826       && (ionizationLevelIndex == 4))
827   {
828     //    sigma = Gj[j] * (S/Bj[ionizationLevelIndex])
829     sigma = Gj[j] * (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
830         * ((F1 + w * F2)
831             / (gpow->powN((1. + w), 3)
832                 * (1. + G4Exp(alphaConst * (w - wc) / v))));
833   }
834   
835   //    if (    particleDefinition == protonDef
836   //            || particleDefinition == hydrogenDef
837   //            )
838   
839   if (isProtonOrHydrogen)
840   {
841     return (sigma);
842   }
843 
844   if (particleDefinition == alphaPlusPlusDef)
845   {
846     slaterEffectiveCharge[0] = 0.;
847     slaterEffectiveCharge[1] = 0.;
848     slaterEffectiveCharge[2] = 0.;
849     sCoefficient[0] = 0.;
850     sCoefficient[1] = 0.;
851     sCoefficient[2] = 0.;
852   }
853 
854   else if (particleDefinition == alphaPlusDef)
855   {
856     slaterEffectiveCharge[0] = 2.0;
857     // The following values are provided by M. Dingfelder (priv. comm)
858     slaterEffectiveCharge[1] = 2.0;
859     slaterEffectiveCharge[2] = 2.0;
860     //
861     sCoefficient[0] = 0.7;
862     sCoefficient[1] = 0.15;
863     sCoefficient[2] = 0.15;
864   }
865 
866   else if (particleDefinition == heliumDef)
867   {
868     slaterEffectiveCharge[0] = 1.7;
869     slaterEffectiveCharge[1] = 1.15;
870     slaterEffectiveCharge[2] = 1.15;
871     sCoefficient[0] = 0.5;
872     sCoefficient[1] = 0.25;
873     sCoefficient[2] = 0.25;
874   }
875 
876   //    if (    particleDefinition == heliumDef
877   //            || particleDefinition == alphaPlusDef
878   //            || particleDefinition == alphaPlusPlusDef
879   //            )
880   if (isHelium)
881   {
882     sigma = Gj[j] * (S / Bj[ionizationLevelIndex])
883         * ((F1 + w * F2)
884             / (gpow->powN((1. + w), 3)
885                 * (1. + G4Exp(alphaConst * (w - wc) / v))));
886 
887     if (j == 4)
888       sigma = Gj[j]
889           * (S / waterStructure.IonisationEnergy(ionizationLevelIndex))
890           * ((F1 + w * F2)
891               / (gpow->powN((1. + w), 3)
892                   * (1. + G4Exp(alphaConst * (w - wc) / v))));
893 
894     G4double zEff = particleDefinition->GetPDGCharge() / eplus
895         + particleDefinition->GetLeptonNumber();
896 
897     zEff -= (sCoefficient[0]
898         * S_1s(k, energyTransfer, slaterEffectiveCharge[0], 1.)
899         + sCoefficient[1]
900             * S_2s(k, energyTransfer, slaterEffectiveCharge[1], 2.)
901         + sCoefficient[2]
902             * S_2p(k, energyTransfer, slaterEffectiveCharge[2], 2.));
903 
904     return zEff * zEff * sigma;
905   }
906 
907   return 0;
908 }
909 
910 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
911 
912 G4double G4DNARuddIonisationModel::S_1s(G4double t,
913                                         G4double energyTransferred,
914                                         G4double slaterEffectiveChg,
915                                         G4double shellNumber)
916 {
917   // 1 - e^(-2r) * ( 1 + 2 r + 2 r^2)
918   // Dingfelder, in Chattanooga 2005 proceedings, formula (7)
919 
920   G4double r = R(t, energyTransferred, slaterEffectiveChg, shellNumber);
921   G4double value = 1. - G4Exp(-2 * r) * ((2. * r + 2.) * r + 1.);
922 
923   return value;
924 }
925 
926 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
927 
928 G4double G4DNARuddIonisationModel::S_2s(G4double t,
929                                         G4double energyTransferred,
930                                         G4double slaterEffectiveChg,
931                                         G4double shellNumber)
932 {
933   // 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 2 r^4)
934   // Dingfelder, in Chattanooga 2005 proceedings, formula (8)
935 
936   G4double r = R(t, energyTransferred, slaterEffectiveChg, shellNumber);
937   G4double value = 1.
938       - G4Exp(-2 * r) * (((2. * r * r + 2.) * r + 2.) * r + 1.);
939 
940   return value;
941 
942 }
943 
944 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
945 
946 G4double G4DNARuddIonisationModel::S_2p(G4double t,
947                                         G4double energyTransferred,
948                                         G4double slaterEffectiveChg,
949                                         G4double shellNumber)
950 {
951   // 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 4/3 r^3 + 2/3 r^4)
952   // Dingfelder, in Chattanooga 2005 proceedings, formula (9)
953 
954   G4double r = R(t, energyTransferred, slaterEffectiveChg, shellNumber);
955   G4double value = 1.
956       - G4Exp(-2 * r)
957           * ((((2. / 3. * r + 4. / 3.) * r + 2.) * r + 2.) * r + 1.);
958 
959   return value;
960 }
961 
962 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
963 
964 G4double G4DNARuddIonisationModel::R(G4double t,
965                                      G4double energyTransferred,
966                                      G4double slaterEffectiveChg,
967                                      G4double shellNumber)
968 {
969   // tElectron = m_electron / m_alpha * t
970   // Dingfelder, in Chattanooga 2005 proceedings, p 4
971 
972   G4double tElectron = 0.511 / 3728. * t;
973   // The following values are provided by M. Dingfelder (priv. comm)
974   G4double H = 2. * 13.60569172 * eV;
975   G4double value = std::sqrt(2. * tElectron / H) / (energyTransferred / H)
976       * (slaterEffectiveChg / shellNumber);
977 
978   return value;
979 }
980 
981 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
982 
983 G4double G4DNARuddIonisationModel::CorrectionFactor(G4ParticleDefinition* particleDefinition,
984                                                     G4double k)
985 {
986 
987   if (particleDefinition == G4Proton::Proton())
988   {
989     return (1.);
990   }
991   if (particleDefinition == hydrogenDef)
992   {
993     G4double value = (G4Log(k / eV)/gpow->logZ(10) - 4.2) / 0.5;
994     // The following values are provided by M. Dingfelder (priv. comm)
995     return ((0.6 / (1 + G4Exp(value))) + 0.9);
996   } 
997   return (1.);
998 }
999 
1000 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
1001 
1002 G4int G4DNARuddIonisationModel::RandomSelect(G4double k,
1003                                              const G4String& particle)
1004 {
1005 
1006   // BEGIN PART 1/2 OF ELECTRON CORRECTION
1007 
1008   // add ONE or TWO electron-water ionisation for alpha+ and helium
1009 
1010   G4int level = 0;
1011 
1012   // Retrieve data table corresponding to the current particle type
1013 
1014   std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
1015   pos = tableData.find(particle);
1016 
1017   if (pos != tableData.end())
1018   {
1019     G4DNACrossSectionDataSet* table = pos->second;
1020 
1021     if (table != nullptr)
1022     {
1023       auto  valuesBuffer = new G4double[table->NumberOfComponents()];
1024 
1025       const auto  n = (G4int)table->NumberOfComponents();
1026       G4int i(n);
1027       G4double value = 0.;
1028 
1029       while (i > 0)
1030       {
1031         --i;
1032         valuesBuffer[i] = table->GetComponent(i)->FindValue(k);
1033         value += valuesBuffer[i];
1034       }
1035 
1036       value *= G4UniformRand();
1037 
1038       i = n;
1039 
1040       while (i > 0)
1041       {
1042         --i;
1043 
1044         if (valuesBuffer[i] > value)
1045         {
1046           delete[] valuesBuffer;
1047           return i;
1048         }
1049         value -= valuesBuffer[i];
1050       }
1051 
1052       
1053         delete[] valuesBuffer;
1054 
1055     }
1056   } else
1057   {
1058     G4Exception("G4DNARuddIonisationModel::RandomSelect",
1059                 "em0002",
1060                 FatalException,
1061                 "Model not applicable to particle type.");
1062   }
1063 
1064   return level;
1065 }
1066 
1067 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
1068 
1069 G4double G4DNARuddIonisationModel::PartialCrossSection(const G4Track& track)
1070 {
1071   G4double sigma = 0.;
1072 
1073   const G4DynamicParticle* particle = track.GetDynamicParticle();
1074   G4double k = particle->GetKineticEnergy();
1075 
1076   G4double lowLim = 0;
1077   G4double highLim = 0;
1078 
1079   const G4String& particleName = particle->GetDefinition()->GetParticleName();
1080 
1081   std::map<G4String, G4double, std::less<G4String> >::iterator pos1;
1082   pos1 = lowEnergyLimit.find(particleName);
1083 
1084   if (pos1 != lowEnergyLimit.end())
1085   {
1086     lowLim = pos1->second;
1087   }
1088 
1089   std::map<G4String, G4double, std::less<G4String> >::iterator pos2;
1090   pos2 = highEnergyLimit.find(particleName);
1091 
1092   if (pos2 != highEnergyLimit.end())
1093   {
1094     highLim = pos2->second;
1095   }
1096 
1097   if (k >= lowLim && k <= highLim)
1098   {
1099     std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
1100     pos = tableData.find(particleName);
1101 
1102     if (pos != tableData.end())
1103     {
1104       G4DNACrossSectionDataSet* table = pos->second;
1105       if (table != nullptr)
1106       {
1107         sigma = table->FindValue(k);
1108       }
1109     } else
1110     {
1111       G4Exception("G4DNARuddIonisationModel::PartialCrossSection",
1112                   "em0002",
1113                   FatalException,
1114                   "Model not applicable to particle type.");
1115     }
1116   }
1117 
1118   return sigma;
1119 }
1120 
1121 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
1122 
1123 G4double G4DNARuddIonisationModel::Sum(G4double /* energy */,
1124                                        const G4String& /* particle */)
1125 {
1126   return 0;
1127 }
1128 
1129