Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/dna/models/src/G4DNADoubleIonisationModel.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 ]

Diff markup

Differences between /processes/electromagnetic/dna/models/src/G4DNADoubleIonisationModel.cc (Version 11.3.0) and /processes/electromagnetic/dna/models/src/G4DNADoubleIonisationModel.cc (Version 6.2.p2)


  1 //                                                  1 
  2 // *******************************************    
  3 // * License and Disclaimer                       
  4 // *                                              
  5 // * The  Geant4 software  is  copyright of th    
  6 // * the Geant4 Collaboration.  It is provided    
  7 // * conditions of the Geant4 Software License    
  8 // * LICENSE and available at  http://cern.ch/    
  9 // * include a list of copyright holders.         
 10 // *                                              
 11 // * Neither the authors of this software syst    
 12 // * institutes,nor the agencies providing fin    
 13 // * work  make  any representation or  warran    
 14 // * regarding  this  software system or assum    
 15 // * use.  Please see the license in the file     
 16 // * for the full disclaimer and the limitatio    
 17 // *                                              
 18 // * This  code  implementation is the result     
 19 // * technical work of the GEANT4 collaboratio    
 20 // * By using,  copying,  modifying or  distri    
 21 // * any work based  on the software)  you  ag    
 22 // * use  in  resulting  scientific  publicati    
 23 // * acceptance of all terms of the Geant4 Sof    
 24 // *******************************************    
 25 //                                                
 26 // G4DNADoubleIonisationModel.cc                  
 27 //                                                
 28 //  Created at 2024/04/03 (Thu.)                  
 29 //  Author: Shogo OKADA @KEK-CRC (shogo.okada@    
 30 //                                                
 31 //  Reference: J.Meesungnoen et. al, DOI: 10.1    
 32 //                                                
 33                                                   
 34 #include "G4DNADoubleIonisationModel.hh"          
 35                                                   
 36 #include "G4PhysicalConstants.hh"                 
 37 #include "G4SystemOfUnits.hh"                     
 38 #include "G4UAtomicDeexcitation.hh"               
 39 #include "G4LossTableManager.hh"                  
 40 #include "G4DNAChemistryManager.hh"               
 41 #include "G4DNAMolecularMaterial.hh"              
 42                                                   
 43 #include "G4IonTable.hh"                          
 44 #include "G4GenericIon.hh"                        
 45 #include "G4DNARuddAngle.hh"                      
 46 #include "G4DeltaAngle.hh"                        
 47 #include "G4Exp.hh"                               
 48                                                   
 49 #include <sstream>                                
 50                                                   
 51 namespace {                                       
 52                                                   
 53 G4DNAWaterIonisationStructure water_structure;    
 54                                                   
 55 // parameters for rejection function              
 56 struct FuncParams {                               
 57   G4double Bj_energy;                             
 58   G4double alpha_const;                           
 59   G4double beta_squared;                          
 60   G4double velocity;                              
 61   G4double correction_factor;                     
 62   G4double wc;                                    
 63   G4double F1;                                    
 64   G4double F2;                                    
 65   G4double c;                                     
 66 };                                                
 67                                                   
 68 //--------------------------------------------    
 69 void setup_rejection_function(G4ParticleDefini    
 70                               const G4int shel    
 71 {                                                 
 72                                                   
 73   // Following values provided by M. Dingfelde    
 74   const G4double Bj[5]                            
 75     = { 12.60 * eV, 14.70 * eV, 18.40 * eV, 32    
 76                                                   
 77   // Data For Liquid Water from Dingfelder (Pr    
 78   G4double A1{1.02}, B1{82.0}, C1{0.45}, D1{-0    
 79            B2{11.6}, // Value provided by M. D    
 80            C2{0.60}, D2{0.04}, alpha_const{0.6    
 81                                                   
 82   auto Bj_energy = Bj[shell];                     
 83                                                   
 84   if (shell == 4) {                               
 85     alpha_const = 0.66;                           
 86     //Data For Liquid Water K SHELL from Dingf    
 87     A1 = 1.25; B1 = 0.5;  C1 = 1.00; D1 = 1.00    
 88     A2 = 1.10; B2 = 1.30; C2 = 1.00; D2 = 0.00    
 89     // The following cases are provided by M.     
 90     Bj_energy = water_structure.IonisationEner    
 91   }                                               
 92                                                   
 93   const auto mass  = pdef->GetPDGMass();          
 94   const auto tau   = ekin * electron_mass_c2 /    
 95   const auto A_ion = pdef->GetAtomicMass();       
 96                                                   
 97   G4double v2;                                    
 98   G4double beta2;                                 
 99                                                   
100   constexpr G4double Ry  = 13.6 * eV;             
101   constexpr G4double xxx = 5.447761194E-02 * M    
102                                                   
103   if (tau < xxx) {                                
104     v2 = tau / Bj_energy;                         
105     beta2 = 2.0 * tau / electron_mass_c2;         
106   } else {                                        
107     // Relativistic                               
108     v2 = (0.5 * electron_mass_c2 / Bj_energy)     
109             * (1.0 - (1.0 / std::pow((1.0 + (t    
110     beta2 = 1.0 - 1.0 / std::pow((1.0 + (tau /    
111   }                                               
112                                                   
113   const auto v = std::sqrt(v2);                   
114   const auto wc = 4.0 * v2 - 2.0 * v - (Ry / (    
115                                                   
116   const auto L1 = (C1 * std::pow(v, D1)) / (1.    
117   const auto L2 = C2 * std::pow(v, D2);           
118   const auto H1 = (A1 * G4Log(1.0 + v2)) / (v2    
119   const auto H2 = (A2 / v2) + (B2 /(v2 * v2));    
120   const auto F1 = L1 + H1;                        
121   const auto F2 = (L2 * H2) / (L2 + H2);          
122                                                   
123   // ZF. generalized & relativistic version       
124   G4double max_energy;                            
125                                                   
126   if (ekin <= 0.1 * mass) {                       
127     // maximum kinetic energy , non relativist    
128     max_energy = 4.0 * (electron_mass_c2 / mas    
129   } else {                                        
130     // relativistic                               
131     auto gamma = 1.0 / std::sqrt(1.0 - beta2);    
132     max_energy = 2.0 * electron_mass_c2 * (gam    
133         / (1.0 + 2.0 * gamma * (electron_mass_    
134             + std::pow(electron_mass_c2 / mass    
135   }                                               
136                                                   
137   const auto wmax = max_energy / Bj_energy;       
138   auto c = wmax * (F2 * wmax+ F1 * (2.0 + wmax    
139               / (2.0 * (1.0 + wmax) * (1.0 + w    
140   c = 1.0 / c; // manual calculus leads to c =    
141                                                   
142   par.Bj_energy = Bj_energy;                      
143   par.alpha_const = alpha_const;                  
144   par.beta_squared = beta2;                       
145   par.velocity = v;                               
146   par.correction_factor = 1.0;                    
147   par.wc = wc;                                    
148   par.F1 = F1;                                    
149   par.F2 = F2;                                    
150   par.c = c;                                      
151                                                   
152 }                                                 
153                                                   
154 //--------------------------------------------    
155 G4double rejection_function(G4ParticleDefiniti    
156                             const FuncParams&     
157 {                                                 
158                                                   
159   const G4double Gj[5] = { 0.99, 1.11, 1.11, 0    
160                                                   
161   proposed_ws /= par.Bj_energy;                   
162                                                   
163   auto rejection_term = 1.0 + G4Exp(par.alpha_    
164                                       / par.ve    
165   rejection_term = (1.0 / rejection_term) * pa    
166                                                   
167   if (pdef == G4Proton::ProtonDefinition()) {     
168                                                   
169     // for protons                                
170     return rejection_term;                        
171                                                   
172   } else if (pdef->GetAtomicMass() > 4) {         
173                                                   
174     // for carbon ions                            
175     auto Z = pdef->GetAtomicNumber();             
176     auto x = 100.0 * std::sqrt(par.beta_square    
177     auto zeff = Z * (1.0 - G4Exp(x * (-1.316 +    
178                                                   
179     rejection_term *= (zeff * zeff);              
180                                                   
181     return rejection_term;                        
182                                                   
183   }                                               
184                                                   
185   // for alpha particles                          
186   auto zeff = pdef->GetPDGCharge() / eplus + p    
187   rejection_term *= (zeff * zeff);                
188                                                   
189   return rejection_term;                          
190                                                   
191 }                                                 
192                                                   
193 //--------------------------------------------    
194 G4double proposed_sampled_energy(const FuncPar    
195 {                                                 
196   const auto rval = G4UniformRand();              
197                                                   
198   auto proposed_ws = par.c * (par.F1 * par.F1     
199                       + 2.0 * rval * (par.F2 -    
200                                                   
201   proposed_ws = -par.F1 * par.c + 2.0 * rval +    
202                                                   
203   proposed_ws /= (par.c * (par.F1 + par.F2) -     
204                                                   
205   proposed_ws *= par.Bj_energy;                   
206                                                   
207   return proposed_ws;                             
208 }                                                 
209                                                   
210 } // end of anonymous namespace                   
211                                                   
212 //============================================    
213                                                   
214 // constructor                                    
215 G4DNADoubleIonisationModel::G4DNADoubleIonisat    
216   const G4ParticleDefinition*, const G4String&    
217     : G4VEmModel(model_name),                     
218       is_initialized_(false)                      
219 {                                                 
220   water_density_ = nullptr;                       
221                                                   
222   model_elow_tab_[1] = 100 * eV;                  
223   model_elow_tab_[4] = 1.0 * keV;                 
224   model_elow_tab_[5] = 0.5 * MeV; // For A = 3    
225                                                   
226   verbose_level_ = 0;                             
227                                                   
228   // Define default angular generator             
229   SetAngularDistribution(new G4DNARuddAngle())    
230                                                   
231   // Mark this model as "applicable" for atomi    
232   SetDeexcitationFlag(true);                      
233   atom_deex_ = nullptr;                           
234   particle_change_ = nullptr;                     
235                                                   
236   // Selection of stationary mode                 
237   stat_code_ = false;                             
238                                                   
239   // True if use champion alpha parameter         
240   use_champion_param_ = false;                    
241                                                   
242   // Double-ionization energy                     
243   energy_threshold_ = 40.0 * eV;                  
244 }                                                 
245                                                   
246 //--------------------------------------------    
247 G4DNADoubleIonisationModel::~G4DNADoubleIonisa    
248 {                                                 
249   for (const auto& x : xs_tab_) {                 
250     G4DNACrossSectionDataSet* table = x.second    
251     if (table) { delete table; }                  
252   }                                               
253 }                                                 
254                                                   
255 //--------------------------------------------    
256 void G4DNADoubleIonisationModel::Initialise(      
257   const G4ParticleDefinition* particle, const     
258 {                                                 
259   if (verbose_level_ > 3) {                       
260     G4cout << "Calling G4DNADoubleIonisationMo    
261   }                                               
262                                                   
263   proton_def_  = G4Proton::ProtonDefinition();    
264   alpha_def_   = G4DNAGenericIonsManager::Inst    
265   carbon_def_  = G4IonTable::GetIonTable()->Ge    
266                                                   
267   constexpr G4double kScaleFactor = 1.0 * m *     
268                                                   
269   mioni_manager_ = new G4DNAMultipleIonisation    
270                                                   
271   G4double Z{0.0}, A{0.0};                        
272   G4String alpha_param_file{"dna/multipleionis    
273                                                   
274   if (particle == proton_def_) {                  
275                                                   
276     // ***************************************    
277     // for protons                                
278     const auto& proton = proton_def_->GetParti    
279     elow_tab_[proton] = model_elow_tab_[1];       
280     eupp_tab_[proton] = 3.0 * MeV;                
281                                                   
282     // load cross-section data for single ioni    
283     auto xs_proton = new G4DNACrossSectionData    
284                           new G4LogLogInterpol    
285     xs_proton->LoadData("dna/sigma_ionisation_    
286     xs_tab_[proton] = xs_proton;                  
287                                                   
288     // set energy limits                          
289     SetLowEnergyLimit(elow_tab_[proton]);         
290     SetHighEnergyLimit(eupp_tab_[proton]);        
291                                                   
292     if (!use_champion_param_) {                   
293       alpha_param_file = "dna/multipleionisati    
294     }                                             
295                                                   
296     Z = static_cast<G4double>(proton_def_->Get    
297     A = static_cast<G4double>(proton_def_->Get    
298                                                   
299   } else if (particle == alpha_def_) {            
300                                                   
301     //****************************************    
302     // for alpha particles                        
303     const auto& alpha = alpha_def_->GetParticl    
304     elow_tab_[alpha] = model_elow_tab_[4];        
305     eupp_tab_[alpha] = 23.0 * MeV;                
306                                                   
307     // load cross-section data for single ioni    
308     auto xs_alpha = new G4DNACrossSectionDataS    
309                         new G4LogLogInterpolat    
310     xs_alpha->LoadData("dna/sigma_ionisation_a    
311     xs_tab_[alpha] = xs_alpha;                    
312                                                   
313     // set energy limits                          
314     SetLowEnergyLimit(elow_tab_[alpha]);          
315     SetHighEnergyLimit(eupp_tab_[alpha]);         
316                                                   
317     if (!use_champion_param_) {                   
318       alpha_param_file = "dna/multipleionisati    
319     }                                             
320                                                   
321     Z = static_cast<G4double>(alpha_def_->GetA    
322     A = static_cast<G4double>(alpha_def_->GetA    
323                                                   
324   } else if (particle == G4GenericIon::Generic    
325                                                   
326     // ***************************************    
327     // for carbon ions                            
328     const auto& carbon = carbon_def_->GetParti    
329     elow_tab_[carbon] = model_elow_tab_[5] * c    
330     eupp_tab_[carbon] = 120.0 * MeV;              
331                                                   
332     // load cross-section data for single ioni    
333     auto xs_carbon = new G4DNACrossSectionData    
334                         new G4LogLogInterpolat    
335     xs_carbon->LoadData("dna/sigma_ionisation_    
336     xs_tab_[carbon] = xs_carbon;                  
337                                                   
338     // set energy limits                          
339     SetLowEnergyLimit(elow_tab_[carbon]);         
340     SetHighEnergyLimit(eupp_tab_[carbon]);        
341                                                   
342     if (!use_champion_param_) {                   
343       alpha_param_file = "dna/multipleionisati    
344     }                                             
345                                                   
346     Z = static_cast<G4double>(carbon_def_->Get    
347     A = static_cast<G4double>(carbon_def_->Get    
348                                                   
349   }                                               
350                                                   
351   // load alpha parameter                         
352   mioni_manager_->LoadAlphaParam(alpha_param_f    
353                                                   
354   if (verbose_level_ > 0) {                       
355     G4cout << "G4DNADoubleIonisationModel is i    
356            << "Energy range: "                    
357            << LowEnergyLimit() / eV << " eV -     
358            << HighEnergyLimit() / keV << " keV    
359            << particle->GetParticleName()         
360            << G4endl;                             
361   }                                               
362                                                   
363   water_density_ = G4DNAMolecularMaterial::Ins    
364                       G4Material::GetMaterial(    
365                                                   
366   atom_deex_ = G4LossTableManager::Instance()-    
367                                                   
368   if (is_initialized_) { return; }                
369                                                   
370   particle_change_ = GetParticleChangeForGamma    
371   is_initialized_ = true;                         
372 }                                                 
373                                                   
374 //--------------------------------------------    
375 G4double G4DNADoubleIonisationModel::GetLowEne    
376 {                                                 
377   G4double elim{0.0};                             
378                                                   
379   EnergyLimitTable::iterator itr = elow_tab_.f    
380   if (itr != elow_tab_.end()) { elim = itr->se    
381                                                   
382   return elim;                                    
383 }                                                 
384                                                   
385 //--------------------------------------------    
386 G4double G4DNADoubleIonisationModel::GetUppEne    
387 {                                                 
388   G4double elim{0.0};                             
389                                                   
390   EnergyLimitTable::iterator itr = eupp_tab_.f    
391   if (itr != eupp_tab_.end()) { elim = itr->se    
392                                                   
393   return elim;                                    
394 }                                                 
395                                                   
396 //--------------------------------------------    
397 G4double G4DNADoubleIonisationModel::CrossSect    
398   const G4Material* material, const G4Particle    
399   G4double ekin, G4double, G4double)              
400 {                                                 
401                                                   
402   if (verbose_level_ > 3) {                       
403     G4cout << "Calling G4DNADoubleIonisationMo    
404            << G4endl;                             
405   }                                               
406                                                   
407   // Calculate total cross section for model      
408                                                   
409   if (pdef != proton_def_ && pdef != alpha_def    
410     return 0.0;                                   
411   }                                               
412                                                   
413   static G4double water_dens = (*water_density    
414                                                   
415   const auto& pname = pdef->GetParticleName();    
416                                                   
417   const auto low_energy_lim = GetLowEnergyLimi    
418   const auto upp_energy_lim = GetUppEnergyLimi    
419                                                   
420   G4double sigma{0.0};                            
421   if (ekin <= upp_energy_lim) {                   
422                                                   
423     if (ekin < low_energy_lim) { ekin = low_en    
424                                                   
425     CrossSectionDataTable::iterator pos = xs_t    
426     if (pos == xs_tab_.end()) {                   
427       G4Exception("G4DNADoubleIonisationModel:    
428                   "em0002", FatalException,       
429                   "Model not applicable to par    
430     }                                             
431                                                   
432     G4DNACrossSectionDataSet* table = pos->sec    
433     if (table != nullptr) {                       
434       const auto a = mioni_manager_->GetAlphaP    
435       sigma = table->FindValue(ekin) * a;         
436     }                                             
437                                                   
438   }                                               
439                                                   
440   if (verbose_level_ > 2) {                       
441                                                   
442     std::stringstream msg;                        
443                                                   
444     msg << "----------------------------------    
445     msg << " G4DNADoubleIonisationModel - XS I    
446     msg << "  - Kinetic energy(eV): " << ekin/    
447         << pdef->GetParticleName() << "\n";       
448     msg << "  - Cross section per water molecu    
449         << sigma / cm / cm << "\n";               
450     msg << "  - Cross section per water molecu    
451         << sigma * water_dens / (1.0 / cm) <<     
452     msg << " G4DNADoubleIonisationModel - XS I    
453     msg << "----------------------------------    
454                                                   
455     G4cout << msg.str() << G4endl;                
456                                                   
457   }                                               
458                                                   
459   return (sigma * water_dens);                    
460                                                   
461 }                                                 
462                                                   
463 //--------------------------------------------    
464 G4double G4DNADoubleIonisationModel::GenerateS    
465   std::vector<G4DynamicParticle*>* vsec, const    
466   const G4DynamicParticle* particle, G4int ion    
467   G4double& theta, G4double& phi, G4double& sh    
468 {                                                 
469   auto pdef = particle->GetDefinition();          
470                                                   
471   // get kinetic energy for a parent particle     
472   auto ekin1 = particle->GetKineticEnergy();      
473                                                   
474   // sample kinetic energy for a secondary ele    
475   auto ekin2 = RandomizeEjectedElectronEnergy(    
476                                                   
477   // sample momentum direction for a secondary    
478   auto sample_electron_direction = [this](        
479       const G4DynamicParticle* dp, G4double _e    
480       const G4MaterialCutsCouple* mcc, G4doubl    
481                                                   
482     G4ThreeVector locdir;                         
483                                                   
484     if (_theta > 0.0) {                           
485                                                   
486       auto costh = std::cos(_theta);              
487       auto sinth = std::sqrt((1.0 - costh) * (    
488       locdir.set(sinth * std::cos(_phi), sinth    
489       locdir.rotateUz(dp->GetMomentumDirection    
490                                                   
491     } else {                                      
492                                                   
493       locdir = GetAngularDistribution()->Sampl    
494                   dp, _ekin2, _Z, _ioni_shell,    
495       _theta = locdir.theta();                    
496       _phi   = locdir.phi();                      
497                                                   
498     }                                             
499                                                   
500     return locdir;                                
501   };                                              
502                                                   
503   constexpr G4int Z = 8;                          
504   auto delta_dir = sample_electron_direction(     
505                      particle, ekin2, Z, ioni_    
506                                                   
507   // generate a secondary electron and put it     
508   auto dp = new G4DynamicParticle(G4Electron::    
509   vsec->push_back(dp);                            
510                                                   
511   if (!atom_deex_ || ioni_shell != 4) { return    
512                                                   
513   // *****************************************    
514   // Only atomic deexcitation from K shell is     
515                                                   
516   constexpr auto k_shell = G4AtomicShellEnumer    
517   const auto shell = atom_deex_->GetAtomicShel    
518                                                   
519   // get number of secondary electrons in the     
520   // before processing atomic deescitation        
521   const auto num_sec_init = vsec->size();         
522                                                   
523   // perform atomic deexcitation process          
524   atom_deex_->GenerateParticles(vsec, shell, Z    
525                                                   
526   // get number of secondary electrons in the     
527   // after processing atomic deescitation         
528   const auto num_sec_final = vsec->size();        
529                                                   
530   if (num_sec_final == num_sec_init) { return     
531                                                   
532   for (auto i = num_sec_init; i < num_sec_fina    
533                                                   
534     auto e = ((*vsec)[i])->GetKineticEnergy();    
535                                                   
536     // Check if there is enough residual energ    
537     if (shell_energy < e) {                       
538                                                   
539       // Invalid secondary: not enough energy     
540       // Keep its energy in the local deposit     
541       delete (*vsec)[i];                          
542       (*vsec)[i] = 0;                             
543                                                   
544       continue;                                   
545                                                   
546     }                                             
547                                                   
548     // Ok, this is a valid secondary: keep it     
549     shell_energy -= e;                            
550   }                                               
551                                                   
552   // *****************************************    
553                                                   
554   return ekin2;                                   
555 }                                                 
556                                                   
557 //--------------------------------------------    
558 void G4DNADoubleIonisationModel::SampleSeconda    
559   std::vector<G4DynamicParticle*>* vsec, const    
560   const G4DynamicParticle* particle, G4double,    
561 {                                                 
562                                                   
563   if (verbose_level_ > 3) {                       
564     G4cout << "Calling SampleSecondaries() of     
565            << G4endl;                             
566   }                                               
567                                                   
568   // get the definition for this parent partic    
569   auto pdef = particle->GetDefinition();          
570                                                   
571   // get kinetic energy                           
572   auto ekin = particle->GetKineticEnergy();       
573                                                   
574   // get particle name                            
575   const auto& pname = pdef->GetParticleName();    
576                                                   
577   // get energy limits                            
578   const auto low_energy_lim = GetLowEnergyLimi    
579                                                   
580   // *****************************************    
581   // stop the transportation process of this p    
582   // if its kinetic energy  is below the lower    
583   if (ekin < low_energy_lim) {                    
584     particle_change_->SetProposedKineticEnergy    
585     particle_change_->ProposeTrackStatus(fStop    
586     particle_change_->ProposeLocalEnergyDeposi    
587     return;                                       
588   }                                               
589   // *****************************************    
590                                                   
591   constexpr G4int kNumSecondaries = 2;            
592   constexpr G4double kDeltaTheta  = pi;           
593                                                   
594   G4int ioni_shell[kNumSecondaries];              
595   G4double shell_energy[kNumSecondaries];         
596                                                   
597   const auto scale_param = mioni_manager_->Get    
598   G4double tot_ioni_energy{0.0};                  
599   for (G4int i = 0; i < kNumSecondaries; i++)     
600     ioni_shell[i]   = RandomSelect(ekin, scale    
601     shell_energy[i] = ::water_structure.Ionisa    
602     tot_ioni_energy += shell_energy[i];           
603   }                                               
604                                                   
605   if (ekin < tot_ioni_energy || tot_ioni_energ    
606     return;                                       
607   }                                               
608                                                   
609   // generate secondary electrons                 
610   G4double theta{0.0}, phi{0.0}, tot_ekin2{0.0    
611   for (G4int i = 0; i < kNumSecondaries; i++)     
612     tot_ekin2 += GenerateSecondaries(vsec, cou    
613                                      theta, ph    
614     theta += kDeltaTheta;                         
615   }                                               
616                                                   
617   // This should never happen                     
618   if (mioni_manager_->CheckShellEnergy(eDouble    
619     G4Exception("G4DNADoubleIonisatioModel::Sa    
620         "em2050", FatalException, "Negative lo    
621   }                                               
622                                                   
623   // *****************************************    
624   // update kinematics for this parent particl    
625   const auto primary_dir = particle->GetMoment    
626   particle_change_->ProposeMomentumDirection(p    
627                                                   
628   const auto scattered_energy = ekin - tot_ion    
629                                                   
630   // update total amount of shell energy          
631   tot_ioni_energy = shell_energy[0] + shell_en    
632                                                   
633   if (stat_code_) {                               
634     particle_change_->SetProposedKineticEnergy    
635     particle_change_->ProposeLocalEnergyDeposi    
636   } else {                                        
637     particle_change_->SetProposedKineticEnergy    
638     particle_change_->ProposeLocalEnergyDeposi    
639   }                                               
640                                                   
641   // *****************************************    
642   // generate double-ionized water molecules (    
643   const auto the_track = particle_change_->Get    
644   mioni_manager_->CreateMultipleIonisedWaterMo    
645                     eDoubleIonisedMolecule, io    
646   // *****************************************    
647                                                   
648 }                                                 
649                                                   
650 //--------------------------------------------    
651 G4double G4DNADoubleIonisationModel::Randomize    
652   G4ParticleDefinition* pdef, G4double ekin, G    
653 {                                                 
654                                                   
655   //                                              
656   // based on RandomizeEjectedElectronEnergy()    
657   //     of G4DNARuddIonisationExtendedModel      
658   //                                              
659                                                   
660   ::FuncParams par;                               
661   ::setup_rejection_function(pdef, ekin, shell    
662                                                   
663   // calculate maximum value                      
664   G4double emax{0.0}, val;                        
665   for (G4double en = 0.0; en < 20.0; en += 1.0    
666     val = ::rejection_function(pdef, shell, pa    
667     if (val <= emax) { continue; }                
668     emax = val;                                   
669   }                                               
670                                                   
671   G4double proposed_energy, rand;                 
672   do {                                            
673     // Proposed energy by inverse function sam    
674     proposed_energy = ::proposed_sampled_energ    
675     rand = G4UniformRand() * emax;                
676     val = ::rejection_function(pdef, shell, pa    
677   } while (rand > val);                           
678                                                   
679   return proposed_energy;                         
680 }                                                 
681                                                   
682 //--------------------------------------------    
683 G4int G4DNADoubleIonisationModel::RandomSelect    
684   G4double ekin, G4double scale_param, const G    
685 {                                                 
686                                                   
687   //                                              
688   // based on RandomSelect() of G4DNARuddIonis    
689   //                                              
690                                                   
691   // Retrieve data table corresponding to the     
692   CrossSectionDataTable::iterator pos = xs_tab    
693                                                   
694   if (pos == xs_tab_.end()) {                     
695     G4Exception("G4DNADoubleIonisationModel::R    
696         FatalException, "Model not applicable     
697   }                                               
698                                                   
699   G4DNACrossSectionDataSet* table = pos->secon    
700                                                   
701   if (table != nullptr) {                         
702                                                   
703     // get total number of energy level           
704     const auto num_component = table->NumberOf    
705                                                   
706     auto* valuesBuffer = new G4double[num_comp    
707                                                   
708     auto shell = num_component;                   
709     G4double value = 0.0;                         
710                                                   
711     while (shell > 0) {                           
712       shell--;                                    
713       valuesBuffer[shell] = table->GetComponen    
714                               * scale_param;      
715       value += valuesBuffer[shell];               
716     }                                             
717                                                   
718     value *= G4UniformRand();                     
719                                                   
720     shell = num_component;                        
721                                                   
722     while (shell > 0) {                           
723       shell--;                                    
724       if (valuesBuffer[shell] > value) {          
725         delete [] valuesBuffer;                   
726         return (G4int)shell;                      
727       }                                           
728       value -= valuesBuffer[shell];               
729     }                                             
730                                                   
731     delete [] valuesBuffer;                       
732   }                                               
733                                                   
734   return 0;                                       
735 }                                                 
736