Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/dna/models/src/G4DNAEmfietzoglouIonisationModel.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 // Based on the work described in
 27 // Rad Res 163, 98-111 (2005)
 28 // D. Emfietzoglou, H. Nikjoo
 29 //
 30 // Authors of the class (2014):
 31 // I. Kyriakou (kyriak@cc.uoi.gr)
 32 // D. Emfietzoglou (demfietz@cc.uoi.gr)
 33 // S. Incerti (incerti@cenbg.in2p3.fr)
 34 //
 35 
 36 #include "G4DNAEmfietzoglouIonisationModel.hh"
 37 #include "G4PhysicalConstants.hh"
 38 #include "G4SystemOfUnits.hh"
 39 #include "G4UAtomicDeexcitation.hh"
 40 #include "G4LossTableManager.hh"
 41 #include "G4DNAChemistryManager.hh"
 42 #include "G4DNAMolecularMaterial.hh"
 43 #include "G4DNABornAngle.hh"
 44 #include "G4DeltaAngle.hh"
 45 
 46 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 47 
 48 using namespace std;
 49 
 50 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 51 
 52 G4DNAEmfietzoglouIonisationModel::G4DNAEmfietzoglouIonisationModel(const G4ParticleDefinition*,
 53                                                                    const G4String& nam) :
 54 G4VEmModel(nam) 
 55 {
 56   verboseLevel = 0;
 57   // Verbosity scale:
 58   // 0 = nothing
 59   // 1 = warning for energy non-conservation
 60   // 2 = details of energy budget
 61   // 3 = calculation of cross sections, file openings, sampling of atoms
 62   // 4 = entering in methods
 63 
 64   if(verboseLevel > 0)
 65   {
 66     G4cout << "Emfietzoglou ionisation model is constructed " << G4endl;
 67   }
 68 
 69   // Mark this model as "applicable" for atomic deexcitation
 70   SetDeexcitationFlag(true);
 71   fAtomDeexcitation = nullptr;
 72   fParticleChangeForGamma = nullptr;
 73   fpMolWaterDensity = nullptr;
 74 
 75   // Define default angular generator
 76   SetAngularDistribution(new G4DNABornAngle());
 77 
 78   SetLowEnergyLimit(10. * eV);
 79   SetHighEnergyLimit(10. * keV);
 80 
 81   // Selection of computation method
 82 
 83   fasterCode = false;
 84 
 85   // Selection of stationary mode
 86 
 87   statCode = false;
 88 }
 89 
 90 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 91 
 92 G4DNAEmfietzoglouIonisationModel::~G4DNAEmfietzoglouIonisationModel()
 93 {
 94   // Cross section
 95 
 96   std::map<G4String, G4DNACrossSectionDataSet*, std::less<G4String> >::iterator pos;
 97   for(pos = tableData.begin(); pos != tableData.end(); ++pos)
 98   {
 99     G4DNACrossSectionDataSet* table = pos->second;
100     delete table;
101   }
102 
103   // Final state
104 
105   eVecm.clear();
106 
107 }
108 
109 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
110 
111 void G4DNAEmfietzoglouIonisationModel::Initialise(const G4ParticleDefinition* particle,
112                                                   const G4DataVector& /*cuts*/)
113 {
114 
115   if(verboseLevel > 3)
116   {
117     G4cout << "Calling G4DNAEmfietzoglouIonisationModel::Initialise()" << G4endl;
118   }
119 
120   // Energy limits
121 
122   G4String fileElectron("dna/sigma_ionisation_e_emfietzoglou");
123 
124   G4ParticleDefinition* electronDef = G4Electron::ElectronDefinition();
125 
126   G4String electron;
127 
128   G4double scaleFactor = (1.e-22 / 3.343) * m*m;
129 
130   const char *path = G4FindDataDir("G4LEDATA");
131 
132   // *** ELECTRON
133 
134   electron = electronDef->GetParticleName();
135 
136   tableFile[electron] = fileElectron;
137 
138   // Cross section
139 
140   auto  tableE = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, eV,scaleFactor );
141   tableE->LoadData(fileElectron);
142 
143   tableData[electron] = tableE;
144 
145   // Final state
146 
147   std::ostringstream eFullFileName;
148 
149   if (fasterCode) eFullFileName << path << "/dna/sigmadiff_cumulated_ionisation_e_emfietzoglou.dat";
150   if (!fasterCode) eFullFileName << path << "/dna/sigmadiff_ionisation_e_emfietzoglou.dat";
151 
152   std::ifstream eDiffCrossSection(eFullFileName.str().c_str());
153 
154   if (!eDiffCrossSection)
155   {
156     if (fasterCode) G4Exception("G4DNAEmfietzoglouIonisationModel::Initialise","em0003",
157         FatalException,"Missing data file:/dna/sigmadiff_cumulated_ionisation_e_emfietzoglou.dat");
158 
159     if (!fasterCode) G4Exception("G4DNAEmfietzoglouIonisationModel::Initialise","em0003",
160         FatalException,"Missing data file:/dna/sigmadiff_ionisation_e_emfietzoglou.dat");
161   }
162 
163   //
164 
165   // Clear the arrays for re-initialization case (MT mode)
166   // March 25th, 2014 - Vaclav Stepan, Sebastien Incerti
167 
168   eTdummyVec.clear();
169 
170   eVecm.clear();
171 
172   eProbaShellMap->clear();
173 
174   eDiffCrossSectionData->clear();
175 
176   eNrjTransfData->clear();
177 
178   //
179 
180   eTdummyVec.push_back(0.);
181   while(!eDiffCrossSection.eof())
182   {
183     G4double tDummy;
184     G4double eDummy;
185     eDiffCrossSection>>tDummy>>eDummy;
186     if (tDummy != eTdummyVec.back()) eTdummyVec.push_back(tDummy);
187     for (G4int j=0; j<5; j++)
188     {
189       eDiffCrossSection>>eDiffCrossSectionData[j][tDummy][eDummy];
190 
191       if (fasterCode)
192       {
193         eNrjTransfData[j][tDummy][eDiffCrossSectionData[j][tDummy][eDummy]]=eDummy;
194         eProbaShellMap[j][tDummy].push_back(eDiffCrossSectionData[j][tDummy][eDummy]);
195       }
196 
197       // SI - only if eof is not reached
198       if (!eDiffCrossSection.eof() && !fasterCode)
199       {
200         eDiffCrossSectionData[j][tDummy][eDummy]*=scaleFactor;
201       }
202 
203       if (!fasterCode) eVecm[tDummy].push_back(eDummy);
204 
205     }
206   }
207 
208   //
209 
210   if( verboseLevel>0 )
211   {
212     G4cout << "Emfietzoglou ionisation model is initialized " << G4endl
213     << "Energy range: "
214     << LowEnergyLimit() / eV << " eV - "
215     << HighEnergyLimit() / keV << " keV for "
216     << particle->GetParticleName()
217     << G4endl;
218   }
219 
220   // Initialize water density pointer
221 
222   fpMolWaterDensity =
223       G4DNAMolecularMaterial::Instance()->
224         GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
225 
226   // AD
227 
228   fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
229 
230   if (isInitialised)
231   { return;}
232   fParticleChangeForGamma = GetParticleChangeForGamma();
233   isInitialised = true;
234 }
235 
236 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
237 
238 G4double G4DNAEmfietzoglouIonisationModel::
239 CrossSectionPerVolume(const G4Material* material,
240                       const G4ParticleDefinition* particleDefinition,
241                       G4double ekin,
242                       G4double,
243                       G4double)
244 {
245   if(verboseLevel > 3)
246   {
247     G4cout
248         << "Calling CrossSectionPerVolume() of G4DNAEmfietzoglouIonisationModel"
249         << G4endl;
250   }
251 
252   if (particleDefinition != G4Electron::ElectronDefinition()) return 0; // necessary ??
253 
254   // Calculate total cross section for model
255 
256   G4double sigma=0;
257 
258   G4double waterDensity = (*fpMolWaterDensity)[material->GetIndex()];
259 
260   const G4String& particleName = particleDefinition->GetParticleName();
261 
262   if (ekin >= LowEnergyLimit() && ekin <= HighEnergyLimit())
263   {
264     std::map< G4String,G4DNACrossSectionDataSet*,std::less<G4String> >::iterator pos;
265     pos = tableData.find(particleName);
266 
267     if (pos != tableData.end())
268     {
269       G4DNACrossSectionDataSet* table = pos->second;
270       if (table != nullptr)
271       {
272         sigma = table->FindValue(ekin);
273       }
274     }
275     else
276     {
277       G4Exception("G4DNAEmfietzoglouIonisationModel::CrossSectionPerVolume","em0002",
278           FatalException,"Model not applicable to particle type.");
279     }
280   }
281 
282   if (verboseLevel > 2)
283   {
284     G4cout << "__________________________________" << G4endl;
285     G4cout << "G4DNAEmfietzoglouIonisationModel - XS INFO START" << G4endl;
286     G4cout << "Kinetic energy(eV)=" << ekin/eV << " particle : " << particleName << G4endl;
287     G4cout << "Cross section per water molecule (cm^2)=" << sigma/cm/cm << G4endl;
288     G4cout << "Cross section per water molecule (cm^-1)=" << sigma*waterDensity/(1./cm) << G4endl;
289     G4cout << "G4DNAEmfietzoglouIonisationModel - XS INFO END" << G4endl;
290   }
291 
292   return sigma*waterDensity;
293 }
294 
295 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
296 
297 void G4DNAEmfietzoglouIonisationModel::
298 SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
299                   const G4MaterialCutsCouple* couple,
300                   const G4DynamicParticle* particle,
301                   G4double,
302                   G4double)
303 {
304 
305   if(verboseLevel > 3)
306   {
307     G4cout << "Calling SampleSecondaries() of G4DNAEmfietzoglouIonisationModel"
308            << G4endl;
309   }
310 
311   G4double k = particle->GetKineticEnergy();
312 
313   const G4String& particleName = particle->GetDefinition()->GetParticleName();
314 
315   if (k >= LowEnergyLimit() && k <= HighEnergyLimit())
316   {
317     G4ParticleMomentum primaryDirection = particle->GetMomentumDirection();
318     G4double particleMass = particle->GetDefinition()->GetPDGMass();
319     G4double totalEnergy = k + particleMass;
320     G4double pSquare = k * (totalEnergy + particleMass);
321     G4double totalMomentum = std::sqrt(pSquare);
322 
323     G4int ionizationShell = 0;
324 
325     ionizationShell = RandomSelect(k,particleName);
326 
327     G4double bindingEnergy = 0;
328     bindingEnergy = waterStructure.IonisationEnergy(ionizationShell);
329 
330     // SI : additional protection if tcs interpolation method is modified
331     if (k<bindingEnergy) return;
332     //
333 
334     G4double secondaryKinetic=-1000*eV;
335 
336     if (!fasterCode) secondaryKinetic = RandomizeEjectedElectronEnergy(particle->GetDefinition(),k,ionizationShell);
337 
338     if (fasterCode)
339     secondaryKinetic = RandomizeEjectedElectronEnergyFromCumulatedDcs(particle->GetDefinition(),k,ionizationShell);
340 
341     // SI - For atom. deexc. tagging - 23/05/2017
342 
343     G4int Z = 8;
344 
345     G4ThreeVector deltaDirection =
346     GetAngularDistribution()->SampleDirectionForShell(particle, secondaryKinetic,
347         Z, ionizationShell,
348         couple->GetMaterial());
349 
350     if (secondaryKinetic>0)
351     {
352       auto  dp = new G4DynamicParticle (G4Electron::Electron(),deltaDirection,secondaryKinetic);
353       fvect->push_back(dp);
354     }
355 
356     G4double deltaTotalMomentum = std::sqrt(secondaryKinetic*(secondaryKinetic + 2.*electron_mass_c2 ));
357 
358     G4double finalPx = totalMomentum*primaryDirection.x() - deltaTotalMomentum*deltaDirection.x();
359     G4double finalPy = totalMomentum*primaryDirection.y() - deltaTotalMomentum*deltaDirection.y();
360     G4double finalPz = totalMomentum*primaryDirection.z() - deltaTotalMomentum*deltaDirection.z();
361     G4double finalMomentum = std::sqrt(finalPx*finalPx + finalPy*finalPy + finalPz*finalPz);
362     finalPx /= finalMomentum;
363     finalPy /= finalMomentum;
364     finalPz /= finalMomentum;
365 
366     G4ThreeVector direction;
367     direction.set(finalPx,finalPy,finalPz);
368 
369     fParticleChangeForGamma->ProposeMomentumDirection(direction.unit());
370 
371     // AM: sample deexcitation
372     // here we assume that H_{2}O electronic levels are the same as Oxygen.
373     // this can be considered true with a rough 10% error in energy on K-shell,
374 
375     size_t secNumberInit = 0;// need to know at a certain point the energy of secondaries
376     size_t secNumberFinal = 0;// So I'll make the diference and then sum the energies
377 
378     G4double scatteredEnergy = k-bindingEnergy-secondaryKinetic;
379 
380     // SI: only atomic deexcitation from K shell is considered
381     if((fAtomDeexcitation != nullptr) && ionizationShell == 4)
382     {
383       const G4AtomicShell* shell
384         = fAtomDeexcitation->GetAtomicShell(Z, G4AtomicShellEnumerator(0));
385       secNumberInit = fvect->size();
386       fAtomDeexcitation->GenerateParticles(fvect, shell, Z, 0, 0);
387       secNumberFinal = fvect->size();
388 
389       if(secNumberFinal > secNumberInit) {
390   for (size_t i=secNumberInit; i<secNumberFinal; ++i) {
391           //Check if there is enough residual energy
392           if (bindingEnergy >= ((*fvect)[i])->GetKineticEnergy())
393            {
394              //Ok, this is a valid secondary: keep it
395        bindingEnergy -= ((*fvect)[i])->GetKineticEnergy();
396            }
397           else
398            {
399        //Invalid secondary: not enough energy to create it!
400        //Keep its energy in the local deposit
401              delete (*fvect)[i];
402              (*fvect)[i]=nullptr;
403            }
404   }
405       }
406 
407     }
408 
409     //This should never happen
410     if(bindingEnergy < 0.0)
411      G4Exception("G4DNAEmfietzoglouIonisatioModel1::SampleSecondaries()",
412                  "em2050",FatalException,"Negative local energy deposit");
413 
414     //bindingEnergy has been decreased
415     //by the amount of energy taken away by deexc. products
416     if (!statCode)
417     {
418       fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
419       fParticleChangeForGamma->ProposeLocalEnergyDeposit(bindingEnergy);
420     }
421     else
422     {
423       fParticleChangeForGamma->SetProposedKineticEnergy(k);
424       fParticleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy);
425     }
426     // TEST //////////////////////////
427     // if (secondaryKinetic<0) abort();
428     // if (scatteredEnergy<0) abort();
429     // if (k-scatteredEnergy-secondaryKinetic-deexSecEnergy<0) abort();
430     // if (k-scatteredEnergy<0) abort();
431     /////////////////////////////////
432 
433     const G4Track * theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
434     G4DNAChemistryManager::Instance()->CreateWaterMolecule(eIonizedMolecule,
435         ionizationShell,
436         theIncomingTrack);
437   }
438 
439 }
440 
441 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
442 
443 G4double
444 G4DNAEmfietzoglouIonisationModel::
445 RandomizeEjectedElectronEnergy(G4ParticleDefinition* particleDefinition,
446                                G4double k,
447                                G4int shell)
448 {
449   // G4cout << "*** SLOW computation for "
450   //        << " " << particleDefinition->GetParticleName() << G4endl;
451 
452   if(particleDefinition == G4Electron::ElectronDefinition())
453   {
454     G4double maximumEnergyTransfer = 0.;
455     if((k + waterStructure.IonisationEnergy(shell)) / 2. > k)
456       maximumEnergyTransfer =  k;
457     else
458       maximumEnergyTransfer = (k + waterStructure.IonisationEnergy(shell))/ 2.;
459 
460     // SI : original method
461     /*
462      G4double crossSectionMaximum = 0.;
463      for(G4double value=waterStructure.IonisationEnergy(shell); value<=maximumEnergyTransfer; value+=0.1*eV)
464      {
465      G4double differentialCrossSection = DifferentialCrossSection(particleDefinition, k/eV, value/eV, shell);
466      if(differentialCrossSection >= crossSectionMaximum) crossSectionMaximum = differentialCrossSection;
467      }
468     */
469 
470     // SI : alternative method
471     G4double crossSectionMaximum = 0.;
472 
473     G4double minEnergy = waterStructure.IonisationEnergy(shell);
474     G4double maxEnergy = maximumEnergyTransfer;
475     G4int nEnergySteps = 50;
476 
477     G4double value(minEnergy);
478     G4double stpEnergy(std::pow(maxEnergy / value,
479                                 1. / static_cast<G4double>(nEnergySteps - 1)));
480     G4int step(nEnergySteps);
481     while(step > 0)
482     {
483       step--;
484       G4double differentialCrossSection =
485           DifferentialCrossSection(particleDefinition,
486                                    k / eV,
487                                    value / eV,
488                                    shell);
489       if(differentialCrossSection >= crossSectionMaximum) crossSectionMaximum =
490           differentialCrossSection;
491       value *= stpEnergy;
492     }
493     //
494 
495     G4double secondaryElectronKineticEnergy = 0.;
496     do
497     {
498       secondaryElectronKineticEnergy = G4UniformRand()* (maximumEnergyTransfer-waterStructure.IonisationEnergy(shell));
499     }while(G4UniformRand()*crossSectionMaximum >
500         DifferentialCrossSection(particleDefinition, k/eV,
501             (secondaryElectronKineticEnergy+waterStructure.IonisationEnergy(shell))/eV,shell));
502 
503     return secondaryElectronKineticEnergy;
504 
505   }
506 
507   return 0;
508 }
509 
510 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
511 
512 // The following section is not used anymore but is kept for memory
513 // GetAngularDistribution()->SampleDirectionForShell is used instead
514 
515 /*
516  void G4DNAEmfietzoglouIonisationModel::RandomizeEjectedElectronDirection(G4ParticleDefinition* particleDefinition,
517  G4double k,
518  G4double secKinetic,
519  G4double & cosTheta,
520  G4double & phi )
521  {
522  if (particleDefinition == G4Electron::ElectronDefinition())
523  {
524  phi = twopi * G4UniformRand();
525  if (secKinetic < 50.*eV) cosTheta = (2.*G4UniformRand())-1.;
526  else if (secKinetic <= 200.*eV)
527  {
528  if (G4UniformRand() <= 0.1) cosTheta = (2.*G4UniformRand())-1.;
529  else cosTheta = G4UniformRand()*(std::sqrt(2.)/2);
530  }
531  else
532  {
533  G4double sin2O = (1.-secKinetic/k) / (1.+secKinetic/(2.*electron_mass_c2));
534  cosTheta = std::sqrt(1.-sin2O);
535  }
536  }
537 
538  else if (particleDefinition == G4Proton::ProtonDefinition())
539  {
540  G4double maxSecKinetic = 4.* (electron_mass_c2 / proton_mass_c2) * k;
541  phi = twopi * G4UniformRand();
542 
543  // cosTheta = std::sqrt(secKinetic / maxSecKinetic);
544 
545  // Restriction below 100 eV from Emfietzoglou (2000)
546 
547  if (secKinetic>100*eV) cosTheta = std::sqrt(secKinetic / maxSecKinetic);
548  else cosTheta = (2.*G4UniformRand())-1.;
549 
550  }
551  }
552  */
553 
554 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
555 G4double G4DNAEmfietzoglouIonisationModel::DifferentialCrossSection(G4ParticleDefinition * particleDefinition,
556                                                                   G4double k,
557                                                                   G4double energyTransfer,
558                                                                   G4int ionizationLevelIndex)
559 {
560   G4double sigma = 0.;
561 
562   if(energyTransfer >= waterStructure.IonisationEnergy(ionizationLevelIndex)/eV)
563   {
564     G4double valueT1 = 0;
565     G4double valueT2 = 0;
566     G4double valueE21 = 0;
567     G4double valueE22 = 0;
568     G4double valueE12 = 0;
569     G4double valueE11 = 0;
570 
571     G4double xs11 = 0;
572     G4double xs12 = 0;
573     G4double xs21 = 0;
574     G4double xs22 = 0;
575 
576     if(particleDefinition == G4Electron::ElectronDefinition())
577     {
578       // Protection against out of boundary access
579       if (k==eTdummyVec.back()) k=k*(1.-1e-12);
580       //
581 
582       // k should be in eV and energy transfer eV also
583 
584       auto t2 = std::upper_bound(eTdummyVec.begin(),
585                                                           eTdummyVec.end(),
586                                                           k);
587 
588       auto t1 = t2 - 1;
589 
590       // SI : the following condition avoids situations where energyTransfer >last vector element
591       // added strict limitations (09/08/2017)
592       if(energyTransfer < eVecm[(*t1)].back() &&
593          energyTransfer < eVecm[(*t2)].back())
594       {
595         auto e12 =
596             std::upper_bound(eVecm[(*t1)].begin(),
597                              eVecm[(*t1)].end(),
598                              energyTransfer);
599         auto e11 = e12 - 1;
600 
601         auto e22 =
602             std::upper_bound(eVecm[(*t2)].begin(),
603                              eVecm[(*t2)].end(),
604                              energyTransfer);
605         auto e21 = e22 - 1;
606 
607         valueT1 = *t1;
608         valueT2 = *t2;
609         valueE21 = *e21;
610         valueE22 = *e22;
611         valueE12 = *e12;
612         valueE11 = *e11;
613 
614         xs11 = eDiffCrossSectionData[ionizationLevelIndex][valueT1][valueE11];
615         xs12 = eDiffCrossSectionData[ionizationLevelIndex][valueT1][valueE12];
616         xs21 = eDiffCrossSectionData[ionizationLevelIndex][valueT2][valueE21];
617         xs22 = eDiffCrossSectionData[ionizationLevelIndex][valueT2][valueE22];
618 
619         //G4cout << "-------------------" << G4endl;
620         //G4cout << "ionizationLevelIndex=" << ionizationLevelIndex << G4endl;
621         //G4cout << "valueT1/eV=" << valueT1 << " valueT2/eV=" << valueT2 << G4endl;
622         //G4cout << "valueE11/eV=" << valueE11 << " valueE12/eV=" << valueE12
623         //       << " valueE21/eV=" << valueE21 << " valueE22/eV=" << valueE22 << G4endl;
624         //G4cout << "xs11=" << xs11 / ((1.e-22 / 3.343) * m*m) << G4endl;
625         //G4cout << "xs12=" << xs12 / ((1.e-22 / 3.343) * m*m) << G4endl;
626         //G4cout << "xs21=" << xs21 / ((1.e-22 / 3.343) * m*m) << G4endl;
627         //G4cout << "xs22=" << xs22 / ((1.e-22 / 3.343) * m*m) << G4endl;
628         //G4cout << "###################" << G4endl;
629 
630       }
631 
632     }
633 
634     G4double xsProduct = xs11 * xs12 * xs21 * xs22;
635     if(xsProduct != 0.)
636     {
637       sigma = QuadInterpolator(valueE11,
638                                valueE12,
639                                valueE21,
640                                valueE22,
641                                xs11,
642                                xs12,
643                                xs21,
644                                xs22,
645                                valueT1,
646                                valueT2,
647                                k,
648                                energyTransfer);
649     }
650 
651   }
652 
653   return sigma;
654 }
655 
656 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
657 
658 G4double G4DNAEmfietzoglouIonisationModel::Interpolate(G4double e1,
659                                                        G4double e2,
660                                                        G4double e,
661                                                        G4double xs1,
662                                                        G4double xs2)
663 {
664 
665   G4double value = 0.;
666 
667   // Log-log interpolation by default
668 
669   if(e1 != 0 && e2 != 0 && (std::log10(e2) - std::log10(e1)) != 0
670      && !fasterCode)
671   {
672     G4double a = (std::log10(xs2) - std::log10(xs1))
673         / (std::log10(e2) - std::log10(e1));
674     G4double b = std::log10(xs2) - a * std::log10(e2);
675     G4double sigma = a * std::log10(e) + b;
676     value = (std::pow(10., sigma));
677   }
678 
679   // Switch to lin-lin interpolation
680   /*
681    if ((e2-e1)!=0)
682    {
683    G4double d1 = xs1;
684    G4double d2 = xs2;
685    value = (d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
686    }
687   */
688 
689   // Switch to log-lin interpolation for faster code
690   if((e2 - e1) != 0 && xs1 != 0 && xs2 != 0 && fasterCode)
691   {
692     G4double d1 = std::log10(xs1);
693     G4double d2 = std::log10(xs2);
694     value = std::pow(10., (d1 + (d2 - d1) * (e - e1) / (e2 - e1)));
695   }
696 
697   // Switch to lin-lin interpolation for faster code
698   // in case one of xs1 or xs2 (=cum proba) value is zero
699 
700   if((e2 - e1) != 0 && (xs1 == 0 || xs2 == 0) && fasterCode)
701   {
702     G4double d1 = xs1;
703     G4double d2 = xs2;
704     value = (d1 + (d2 - d1) * (e - e1) / (e2 - e1));
705   }
706 
707   /*
708    G4cout
709    << e1 << " "
710    << e2 << " "
711    << e  << " "
712    << xs1 << " "
713    << xs2 << " "
714    << value
715    << G4endl;
716   */
717 
718   return value;
719 }
720 
721 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
722 
723 G4double G4DNAEmfietzoglouIonisationModel::QuadInterpolator(G4double e11,
724                                                             G4double e12,
725                                                             G4double e21,
726                                                             G4double e22,
727                                                             G4double xs11,
728                                                             G4double xs12,
729                                                             G4double xs21,
730                                                             G4double xs22,
731                                                             G4double t1,
732                                                             G4double t2,
733                                                             G4double t,
734                                                             G4double e)
735 {
736   G4double interpolatedvalue1 = Interpolate(e11, e12, e, xs11, xs12);
737   G4double interpolatedvalue2 = Interpolate(e21, e22, e, xs21, xs22);
738   G4double value = Interpolate(t1,
739                                t2,
740                                t,
741                                interpolatedvalue1,
742                                interpolatedvalue2);
743 
744   return value;
745 }
746 
747 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
748 
749 G4int G4DNAEmfietzoglouIonisationModel::RandomSelect(G4double k,
750                                                      const G4String& particle)
751 {
752   G4int level = 0;
753 
754   auto pos = tableData.find(particle);
755 
756   if(pos != tableData.cend())
757   {
758     G4DNACrossSectionDataSet* table = pos->second;
759 
760     if(table != nullptr)
761     {
762       auto  valuesBuffer = new G4double[table->NumberOfComponents()];
763       const auto  n = (G4int)table->NumberOfComponents();
764       G4int i(n);
765       G4double value = 0.;
766 
767       while(i > 0)
768       {
769         i--;
770         valuesBuffer[i] = table->GetComponent(i)->FindValue(k);
771         value += valuesBuffer[i];
772       }
773 
774       value *= G4UniformRand();
775 
776       i = n;
777 
778       while(i > 0)
779       {
780         i--;
781 
782         if(valuesBuffer[i] > value)
783         {
784           delete[] valuesBuffer;
785           return i;
786         }
787         value -= valuesBuffer[i];
788       }
789 
790       delete[] valuesBuffer;
791 
792     }
793   }
794   else
795   {
796     G4Exception("G4DNAEmfietzoglouIonisationModel::RandomSelect",
797                 "em0002",
798                 FatalException,
799                 "Model not applicable to particle type.");
800   }
801 
802   return level;
803 }
804 
805 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
806 
807 G4double G4DNAEmfietzoglouIonisationModel::RandomizeEjectedElectronEnergyFromCumulatedDcs(G4ParticleDefinition* particleDefinition,
808                                                                                           G4double k,
809                                                                                           G4int shell)
810 {
811   //G4cout << "*** FAST computation for " << " " << particleDefinition->GetParticleName() << G4endl;
812 
813   G4double secondaryElectronKineticEnergy = 0.;
814 
815   secondaryElectronKineticEnergy = RandomTransferedEnergy(particleDefinition,
816                                                           k / eV,
817                                                           shell)
818                                    * eV
819                                    - waterStructure.IonisationEnergy(shell);
820 
821   //G4cout << RandomTransferedEnergy(particleDefinition, k/eV, shell) << G4endl;
822   if(secondaryElectronKineticEnergy < 0.) return 0.;
823 
824   return secondaryElectronKineticEnergy;
825 }
826 
827 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
828 
829 G4double G4DNAEmfietzoglouIonisationModel::RandomTransferedEnergy(G4ParticleDefinition* particleDefinition,
830                                                                   G4double k,
831                                                                   G4int ionizationLevelIndex)
832 {
833 
834   G4double random = G4UniformRand();
835 
836   G4double nrj = 0.;
837 
838   G4double valueK1 = 0;
839   G4double valueK2 = 0;
840   G4double valuePROB21 = 0;
841   G4double valuePROB22 = 0;
842   G4double valuePROB12 = 0;
843   G4double valuePROB11 = 0;
844 
845   G4double nrjTransf11 = 0;
846   G4double nrjTransf12 = 0;
847   G4double nrjTransf21 = 0;
848   G4double nrjTransf22 = 0;
849 
850   if (particleDefinition == G4Electron::ElectronDefinition())
851   {
852     // Protection against out of boundary access
853     if (k==eTdummyVec.back()) k=k*(1.-1e-12);
854     //
855 
856     // k should be in eV
857     auto k2 = std::upper_bound(eTdummyVec.begin(),eTdummyVec.end(), k);
858 
859     auto k1 = k2-1;
860 
861     /*
862      G4cout << "----> k=" << k
863      << " " << *k1
864      << " " << *k2
865      << " " << random
866      << " " << ionizationLevelIndex
867      << " " << eProbaShellMap[ionizationLevelIndex][(*k1)].back()
868      << " " << eProbaShellMap[ionizationLevelIndex][(*k2)].back()
869      << G4endl;
870      */
871 
872     // SI : the following condition avoids situations where random >last vector element
873     if ( random <= eProbaShellMap[ionizationLevelIndex][(*k1)].back()
874         && random <= eProbaShellMap[ionizationLevelIndex][(*k2)].back() )
875 
876     {
877       auto prob12 = std::upper_bound(eProbaShellMap[ionizationLevelIndex][(*k1)].begin(),
878           eProbaShellMap[ionizationLevelIndex][(*k1)].end(), random);
879 
880       auto prob11 = prob12-1;
881 
882       auto prob22 = std::upper_bound(eProbaShellMap[ionizationLevelIndex][(*k2)].begin(),
883           eProbaShellMap[ionizationLevelIndex][(*k2)].end(), random);
884 
885       auto prob21 = prob22-1;
886 
887       valueK1 =*k1;
888       valueK2 =*k2;
889       valuePROB21 =*prob21;
890       valuePROB22 =*prob22;
891       valuePROB12 =*prob12;
892       valuePROB11 =*prob11;
893 
894       /*
895        G4cout << "        " << random << " " << valuePROB11 << " "
896        << valuePROB12 << " " << valuePROB21 << " " << valuePROB22 << G4endl;
897        */
898 
899       nrjTransf11 = eNrjTransfData[ionizationLevelIndex][valueK1][valuePROB11];
900       nrjTransf12 = eNrjTransfData[ionizationLevelIndex][valueK1][valuePROB12];
901       nrjTransf21 = eNrjTransfData[ionizationLevelIndex][valueK2][valuePROB21];
902       nrjTransf22 = eNrjTransfData[ionizationLevelIndex][valueK2][valuePROB22];
903 
904       /*
905        G4cout << "        " << ionizationLevelIndex << " "
906        << random << " " <<valueK1 << " " << valueK2 << G4endl;
907 
908        G4cout << "        " << random << " " << nrjTransf11 << " "
909        << nrjTransf12 << " " << nrjTransf21 << " " <<nrjTransf22 << G4endl;
910        */
911 
912     }
913 
914     // Avoids cases where cum xs is zero for k1 and is not for k2 (with always k1<k2)
915 
916     if ( random > eProbaShellMap[ionizationLevelIndex][(*k1)].back() )
917 
918     {
919       auto prob22 = std::upper_bound(eProbaShellMap[ionizationLevelIndex][(*k2)].begin(),
920           eProbaShellMap[ionizationLevelIndex][(*k2)].end(), random);
921 
922       auto prob21 = prob22-1;
923 
924       valueK1 =*k1;
925       valueK2 =*k2;
926       valuePROB21 =*prob21;
927       valuePROB22 =*prob22;
928 
929       //G4cout << "        " << random << " " << valuePROB21 << " " << valuePROB22 << G4endl;
930 
931       nrjTransf21 = eNrjTransfData[ionizationLevelIndex][valueK2][valuePROB21];
932       nrjTransf22 = eNrjTransfData[ionizationLevelIndex][valueK2][valuePROB22];
933 
934       G4double interpolatedvalue2 = Interpolate(valuePROB21, valuePROB22, random, nrjTransf21, nrjTransf22);
935 
936       // zeros are explicitly set
937 
938       G4double value = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
939 
940       /*
941        G4cout << "        " << ionizationLevelIndex << " "
942        << random << " " <<valueK1 << " " << valueK2 << G4endl;
943 
944        G4cout << "        " << random << " " << nrjTransf11 << " "
945        << nrjTransf12 << " " << nrjTransf21 << " " <<nrjTransf22 << G4endl;
946 
947        G4cout << "ici" << " " << value << G4endl;
948        */
949 
950       return value;
951     }
952 
953   }
954 
955   // End electron
956 
957   G4double nrjTransfProduct = nrjTransf11 * nrjTransf12 * nrjTransf21 * nrjTransf22;
958 
959   //G4cout << "nrjTransfProduct=" << nrjTransfProduct << G4endl;
960 
961   if (nrjTransfProduct != 0.)
962   {
963     nrj = QuadInterpolator( valuePROB11, valuePROB12,
964         valuePROB21, valuePROB22,
965         nrjTransf11, nrjTransf12,
966         nrjTransf21, nrjTransf22,
967         valueK1, valueK2,
968         k, random);
969   }
970 
971   //G4cout << nrj << endl;
972 
973   return nrj;
974 }
975