Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4DNACPA100IonisationModel.cc
Go to the documentation of this file.
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// CPA100 ionisation model class for electrons
27//
28// Based on the work of M. Terrissol and M. C. Bordage
29//
30// Users are requested to cite the following papers:
31// - M. Terrissol, A. Baudre, Radiat. Prot. Dosim. 31 (1990) 175-177
32// - M.C. Bordage, J. Bordes, S. Edel, M. Terrissol, X. Franceries,
33// M. Bardies, N. Lampe, S. Incerti, Phys. Med. 32 (2016) 1833-1840
34//
35// Authors of this class:
36// M.C. Bordage, M. Terrissol, S. Edel, J. Bordes, S. Incerti
37//
38// 15.01.2014: creation
39//
40// Based on the study by S. Zein et. al. Nucl. Inst. Meth. B 488 (2021) 70-82
41// 1/2/2023 : Hoang added modification
42
44
48#include "G4EnvironmentUtils.hh"
49#include "G4LossTableManager.hh"
51#include "G4SystemOfUnits.hh"
53
54#include <fstream>
55
56//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
57
58using namespace std;
59
60//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
61
63 const G4String& nam)
64 : G4VDNAModel(nam, "all")
65{
66 fpGuanine = G4Material::GetMaterial("G4_GUANINE", false);
67 fpG4_WATER = G4Material::GetMaterial("G4_WATER", false);
68 fpDeoxyribose = G4Material::GetMaterial("G4_DEOXYRIBOSE", false);
69 fpCytosine = G4Material::GetMaterial("G4_CYTOSINE", false);
70 fpThymine = G4Material::GetMaterial("G4_THYMINE", false);
71 fpAdenine = G4Material::GetMaterial("G4_ADENINE", false);
72 fpPhosphate = G4Material::GetMaterial("G4_PHOSPHORIC_ACID", false);
73 fpParticle = G4Electron::ElectronDefinition();
74}
75
76//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
77
79 const G4DataVector& /*cuts*/)
80{
81 if (isInitialised) {
82 return;
83 }
84 if (verboseLevel > 3) {
85 G4cout << "Calling G4DNACPA100IonisationModel::Initialise()" << G4endl;
86 }
87
89 if (p != fpParticle) {
90 std::ostringstream oss;
91 oss << " Model is not applied for this particle " << p->GetParticleName();
92 G4Exception("G4DNACPA100IonisationModel::G4DNACPA100IonisationModel", "CPA001",
93 FatalException, oss.str().c_str());
94 }
95
96 const char* path = G4FindDataDir("G4LEDATA");
97
98 if (path == nullptr) {
99 G4Exception("G4DNACPA100IonisationModel::Initialise", "em0006", FatalException,
100 "G4LEDATA environment variable not set.");
101 return;
102 }
103
104 std::size_t index;
105 if (fpG4_WATER != nullptr) {
106 index = fpG4_WATER->GetIndex();
107 G4String eFullFileName = "";
108 fasterCode ? eFullFileName = "/dna/sigmadiff_cumulated_ionisation_e_cpa100_rel"
109 : eFullFileName = "/dna/sigmadiff_ionisation_e_cpa100_rel";
110 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_form_rel", eFullFileName,
111 1.e-20 * m * m);
112 SetLowELimit(index, p, 11 * eV);
113 SetHighELimit(index, p, 255955 * eV);
114 }
115 if (fpGuanine != nullptr) {
116 index = fpGuanine->GetIndex();
117 G4String eFullFileName = "";
118 if(useDcs) {
119 fasterCode ? eFullFileName = "/dna/sigmadiff_cumulated_elastic_e_cpa100_guanine"
120 : eFullFileName = "/dna/sigmadiff_ionisation_e_cpa100_guanine";
121 }
122 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_guanine", eFullFileName,
123 1. * cm * cm);
124 SetLowELimit(index, p, 11 * eV);
125 SetHighELimit(index, p, 1 * MeV);
126 }
127 if (fpDeoxyribose != nullptr) {
128 index = fpDeoxyribose->GetIndex();
129 G4String eFullFileName = "";
130 if(useDcs) {
131 eFullFileName = "/dna/sigmadiff_cumulated_ionisation_e_cpa100_deoxyribose";
132 }
133 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_deoxyribose", eFullFileName,
134 1. * cm * cm);
135 SetLowELimit(index, p, 11 * eV);
136 SetHighELimit(index, p, 1 * MeV);
137 }
138 if (fpCytosine != nullptr) {
139 index = fpCytosine->GetIndex();
140 G4String eFullFileName = "";
141 if(useDcs) {
142 fasterCode ? eFullFileName = "/dna/sigmadiff_cumulated_ionisation_e_cpa100_cytosine"
143 : eFullFileName = "/dna/sigmadiff_ionisation_e_cpa100_cytosine";
144 }
145 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_cytosine", eFullFileName,
146 1. * cm * cm);
147 SetLowELimit(index, p, 11 * eV);
148 SetHighELimit(index, p, 1 * MeV);
149 }
150 if (fpThymine != nullptr) {
151 index = fpThymine->GetIndex();
152 G4String eFullFileName = "";
153 if(useDcs) {
154 fasterCode ? eFullFileName = "/dna/sigmadiff_cumulated_ionisation_e_cpa100_thymine"
155 : eFullFileName = "/dna/sigmadiff_ionisation_e_cpa100_thymine";
156 }
157 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_thymine", eFullFileName,
158 1. * cm * cm);
159 SetLowELimit(index, p, 11 * eV);
160 SetHighELimit(index, p, 1 * MeV);
161 }
162 if (fpAdenine != nullptr) {
163 index = fpAdenine->GetIndex();
164 G4String eFullFileName = "";
165 if(useDcs) {
166 fasterCode ? eFullFileName = "/dna/sigmadiff_cumulated_ionisation_e_cpa100_adenine"
167 : eFullFileName = "/dna/sigmadiff_ionisation_e_cpa100_adenine";
168 }
169 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_adenine", eFullFileName,
170 1. * cm * cm);
171 SetLowELimit(index, p, 11 * eV);
172 SetHighELimit(index, p, 1 * MeV);
173 }
174 if (fpPhosphate != nullptr) {
175 index = fpPhosphate->GetIndex();
176 G4String eFullFileName = "";
177 if(useDcs) {
178 eFullFileName = "dna/sigmadiff_cumulated_ionisation_e_cpa100_phosphoric_acid";
179 }
180 AddCrossSectionData(index, p, "dna/sigma_ionisation_e_cpa100_phosphoric_acid",eFullFileName,
181 1. * cm * cm);
182 SetLowELimit(index, p, 11 * eV);
183 SetHighELimit(index, p, 1 * MeV);
184 }
187 fpModelData = this;
188 }
189 else {
190 auto dataModel = dynamic_cast<G4DNACPA100IonisationModel*>(
192 if (dataModel == nullptr) {
193 G4cout << "G4DNACPA100IonisationModel::CrossSectionPerVolume:: not good modelData" << G4endl;
194 throw;
195 }
196 fpModelData = dataModel;
197 }
198
199 fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
200
202 isInitialised = true;
203}
204
206 const G4ParticleDefinition* p,
208{
209 // initialise the cross section value (output value)
210 G4double sigma(0);
211
212 // Get the current particle name
213 const G4String& particleName = p->GetParticleName();
214
215 if (p != fpParticle) {
216 G4Exception("G4DNACPA100IonisationModel::CrossSectionPerVolume", "em00223", FatalException,
217 "No model is registered for this particle");
218 }
219
220 auto matID = material->GetIndex();
221
222 // Set the low and high energy limits
223 G4double lowLim = fpModelData->GetLowELimit(matID, p);
224 G4double highLim = fpModelData->GetHighELimit(matID, p);
225
226 // Check that we are in the correct energy range
227 if (ekin >= lowLim && ekin < highLim) {
228 // Get the map with all the model data tables
229 auto tableData = fpModelData->GetData();
230
231 if ((*tableData)[matID][p] == nullptr) {
232 G4Exception("G4DNACPA100IonisationModel::CrossSectionPerVolume", "em00236", FatalException,
233 "No model is registered");
234 }
235 else {
236 sigma = (*tableData)[matID][p]->FindValue(ekin);
237 }
238
239 if (verboseLevel > 2) {
240 auto MolDensity =
242 G4cout << "__________________________________" << G4endl;
243 G4cout << "°°° G4DNACPA100IonisationModel - XS INFO START" << G4endl;
244 G4cout << "°°° Kinetic energy(eV)=" << ekin / eV << " particle : " << particleName << G4endl;
245 G4cout << "°°° lowLim (eV) = " << lowLim / eV << " highLim (eV) : " << highLim / eV << G4endl;
246 G4cout << "°°° Materials = " << (*G4Material::GetMaterialTable())[matID]->GetName() << G4endl;
247 G4cout << "°°° Cross section per " << matID << " index molecule (cm^2)=" << sigma / cm / cm
248 << G4endl;
249 G4cout << "°°° Cross section per Phosphate molecule (cm^-1)="
250 << sigma * MolDensity / (1. / cm) << G4endl;
251 G4cout << "°°° G4DNACPA100IonisationModel - XS INFO END" << G4endl;
252 }
253 }
254
255 auto MolDensity = (*G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(material))[matID];
256 return sigma * MolDensity;
257}
258
259//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
260
262 std::vector<G4DynamicParticle*>* fvect,
263 const G4MaterialCutsCouple* couple, // must be set!
264 const G4DynamicParticle* particle, G4double, G4double)
265{
266 if (verboseLevel > 3) {
267 G4cout << "Calling SampleSecondaries() of G4DNACPA100IonisationModel" << G4endl;
268 }
269 auto k = particle->GetKineticEnergy();
270
271 const G4Material* material = couple->GetMaterial();
272
273 auto MatID = material->GetIndex();
274
275 auto p = particle->GetDefinition();
276
277 auto lowLim = fpModelData->GetLowELimit(MatID, p);
278 auto highLim = fpModelData->GetHighELimit(MatID, p);
279
280 // Check if we are in the correct energy range
281 if (k >= lowLim && k < highLim) {
282 const auto& primaryDirection = particle->GetMomentumDirection();
283 auto particleMass = particle->GetDefinition()->GetPDGMass();
284 auto totalEnergy = k + particleMass;
285 auto pSquare = k * (totalEnergy + particleMass);
286 auto totalMomentum = std::sqrt(pSquare);
287 G4int shell = -1;
288 G4double bindingEnergy, secondaryKinetic;
289 shell = fpModelData->RandomSelectShell(k, p, MatID);
290 bindingEnergy = iStructure.IonisationEnergy(shell, MatID);
291
292 if (k < bindingEnergy) {
293 return;
294 }
295
296 auto info = std::make_tuple(MatID, k, shell);
297
298 secondaryKinetic = -1000 * eV;
299 if (fpG4_WATER->GetIndex() != MatID) {//for DNA material useDcs = false
300 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergyFromanalytical(info);
301 }else if(fasterCode){
302 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergyFromCumulatedDcs(info);
303 }else{
304 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergy(info);
305 }
306
307 G4double cosTheta = 0.;
308 G4double phi = 0.;
309 RandomizeEjectedElectronDirection(particle->GetDefinition(), k, secondaryKinetic, cosTheta,
310 phi);
311
312 G4double sinTheta = std::sqrt(1. - cosTheta * cosTheta);
313 G4double dirX = sinTheta * std::cos(phi);
314 G4double dirY = sinTheta * std::sin(phi);
315 G4double dirZ = cosTheta;
316 G4ThreeVector deltaDirection(dirX, dirY, dirZ);
317 deltaDirection.rotateUz(primaryDirection);
318
319 // SI - For atom. deexc. tagging - 23/05/2017
320 if (secondaryKinetic > 0) {
321 auto dp = new G4DynamicParticle(G4Electron::Electron(), deltaDirection, secondaryKinetic);
322 fvect->push_back(dp);
323 }
324
325 if (particle->GetDefinition() != fpParticle) {
327 }
328 else {
329 G4double deltaTotalMomentum =
330 std::sqrt(secondaryKinetic * (secondaryKinetic + 2. * electron_mass_c2));
331 G4double finalPx =
332 totalMomentum * primaryDirection.x() - deltaTotalMomentum * deltaDirection.x();
333 G4double finalPy =
334 totalMomentum * primaryDirection.y() - deltaTotalMomentum * deltaDirection.y();
335 G4double finalPz =
336 totalMomentum * primaryDirection.z() - deltaTotalMomentum * deltaDirection.z();
337 G4double finalMomentum = std::sqrt(finalPx * finalPx + finalPy * finalPy + finalPz * finalPz);
338 finalPx /= finalMomentum;
339 finalPy /= finalMomentum;
340 finalPz /= finalMomentum;
341
342 G4ThreeVector direction;
343 direction.set(finalPx, finalPy, finalPz);
344
346 }
347
348 // SI - For atom. deexc. tagging - 23/05/2017
349
350 // AM: sample deexcitation
351 // here we assume that H_{2}O electronic levels are the same of Oxigen.
352 // this can be considered true with a rough 10% error in energy on K-shell,
353
354 G4double scatteredEnergy = k - bindingEnergy - secondaryKinetic;
355
356 // SI: only atomic deexcitation from K shell is considered
357 // Hoang: only for water
358 if (fpG4_WATER != nullptr && material == G4Material::GetMaterial("G4_WATER")) {
359 std::size_t secNumberInit = 0; // need to know at a certain point the energy of secondaries
360 std::size_t secNumberFinal = 0; // So I'll make the diference and then sum the energies
361 if ((fAtomDeexcitation != nullptr) && shell == 4) {
362 G4int Z = 8;
363 auto Kshell = fAtomDeexcitation->GetAtomicShell(Z, G4AtomicShellEnumerator(0));
364 secNumberInit = fvect->size();
365 fAtomDeexcitation->GenerateParticles(fvect, Kshell, Z, 0, 0);
366 secNumberFinal = fvect->size();
367 if (secNumberFinal > secNumberInit) {
368 for (std::size_t i = secNumberInit; i < secNumberFinal; ++i) {
369 // Check if there is enough residual energy
370 if (bindingEnergy >= ((*fvect)[i])->GetKineticEnergy()) {
371 // Ok, this is a valid secondary: keep it
372 bindingEnergy -= ((*fvect)[i])->GetKineticEnergy();
373 }
374 else {
375 // Invalid secondary: not enough energy to create it!
376 // Keep its energy in the local deposit
377 delete (*fvect)[i];
378 (*fvect)[i] = nullptr;
379 }
380 }
381 }
382 }
383 }
384
385 // This should never happen
386 if (bindingEnergy < 0.0) {
387 G4Exception("G4DNACPA100IonisatioModel1::SampleSecondaries()", "em2050", FatalException,
388 "Negative local energy deposit");
389 }
390 if (!statCode) {
393 }
394 else {
397 }
398
399 // only water for chemistry
400 if (fpG4_WATER != nullptr && material == G4Material::GetMaterial("G4_WATER")) {
401 const G4Track* theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
403 theIncomingTrack);
404 }
405 }
406}
407
408//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
409
410G4double G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergy(PartKineticInMat info)
411{
412 auto MatID = std::get<0>(info);
413 auto k = std::get<1>(info);
414 auto shell = std::get<2>(info);
415 G4double maximumEnergyTransfer = 0.;
416 auto IonLevel = iStructure.IonisationEnergy(shell, MatID);
417 (k + IonLevel) / 2. > k ? maximumEnergyTransfer = k : maximumEnergyTransfer = (k + IonLevel) / 2.;
418
419 G4double crossSectionMaximum = 0.;
420
421 G4double minEnergy = IonLevel;
422 G4double maxEnergy = maximumEnergyTransfer;
423
424 // nEnergySteps can be optimized - 100 by default
425 G4int nEnergySteps = 50;
426
427 G4double value(minEnergy);
428 G4double stpEnergy(std::pow(maxEnergy / value, 1. / static_cast<G4double>(nEnergySteps - 1)));
429 G4int step(nEnergySteps);
430 G4double differentialCrossSection = 0.;
431 while (step > 0) {
432 step--;
433 differentialCrossSection = DifferentialCrossSection(info, value / eV);
434
435 if (differentialCrossSection > 0) {
436 crossSectionMaximum = differentialCrossSection;
437 break;
438 }
439 value *= stpEnergy;
440 }
441
442 G4double secondaryElectronKineticEnergy = 0.;
443 do {
444 secondaryElectronKineticEnergy = G4UniformRand() * (maximumEnergyTransfer - IonLevel);
445 } while (G4UniformRand() * crossSectionMaximum
446 > DifferentialCrossSection(info, (secondaryElectronKineticEnergy + IonLevel) / eV));
447
448 return secondaryElectronKineticEnergy;
449}
450
451//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
452
453void G4DNACPA100IonisationModel::RandomizeEjectedElectronDirection(G4ParticleDefinition*,
454 G4double k, G4double secKinetic,
455 G4double& cosTheta,
456 G4double& phi)
457{
458 phi = twopi * G4UniformRand();
459 G4double sin2O = (1. - secKinetic / k) / (1. + secKinetic / (2. * electron_mass_c2));
460 cosTheta = std::sqrt(1. - sin2O);
461}
462
463//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
464
466 const G4double& energyTransfer)
467{
468 auto MatID = std::get<0>(info);
469 auto k = std::get<1>(info) / eV; // in eV unit
470 auto shell = std::get<2>(info);
471 G4double sigma = 0.;
472 G4double shellEnergy = iStructure.IonisationEnergy(shell, MatID);
473 G4double kSE(energyTransfer - shellEnergy);
474
475 if (energyTransfer >= shellEnergy) {
476 G4double valueT1 = 0;
477 G4double valueT2 = 0;
478 G4double valueE21 = 0;
479 G4double valueE22 = 0;
480 G4double valueE12 = 0;
481 G4double valueE11 = 0;
482
483 G4double xs11 = 0;
484 G4double xs12 = 0;
485 G4double xs21 = 0;
486 G4double xs22 = 0;
487
488 auto t2 = std::upper_bound(fTMapWithVec[MatID][fpParticle].begin(),
489 fTMapWithVec[MatID][fpParticle].end(), k);
490 auto t1 = t2 - 1;
491
492 if (kSE <= fEMapWithVector[MatID][fpParticle][(*t1)].back()
493 && kSE <= fEMapWithVector[MatID][fpParticle][(*t2)].back())
494 {
495 auto e12 = std::upper_bound(fEMapWithVector[MatID][fpParticle][(*t1)].begin(),
496 fEMapWithVector[MatID][fpParticle][(*t1)].end(), kSE);
497 auto e11 = e12 - 1;
498
499 auto e22 = std::upper_bound(fEMapWithVector[MatID][fpParticle][(*t2)].begin(),
500 fEMapWithVector[MatID][fpParticle][(*t2)].end(), kSE);
501 auto e21 = e22 - 1;
502
503 valueT1 = *t1;
504 valueT2 = *t2;
505 valueE21 = *e21;
506 valueE22 = *e22;
507 valueE12 = *e12;
508 valueE11 = *e11;
509
510 xs11 = diffCrossSectionData[MatID][fpParticle][shell][valueT1][valueE11];
511 xs12 = diffCrossSectionData[MatID][fpParticle][shell][valueT1][valueE12];
512 xs21 = diffCrossSectionData[MatID][fpParticle][shell][valueT2][valueE21];
513 xs22 = diffCrossSectionData[MatID][fpParticle][shell][valueT2][valueE22];
514 }
515
516 G4double xsProduct = xs11 * xs12 * xs21 * xs22;
517
518 if (xsProduct != 0.) {
519 sigma = QuadInterpolator(valueE11, valueE12, valueE21, valueE22, xs11, xs12, xs21, xs22,
520 valueT1, valueT2, k, kSE);
521 }
522 }
523
524 return sigma;
525}
526
527//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
528
529G4double G4DNACPA100IonisationModel::Interpolate(G4double e1, G4double e2, G4double e, G4double xs1,
530 G4double xs2)
531{
532 G4double value = 0.;
533
534 // Log-log interpolation by default
535
536 if (e1 != 0 && e2 != 0 && (std::log10(e2) - std::log10(e1)) != 0 && !fasterCode) {
537 G4double a = (std::log10(xs2) - std::log10(xs1)) / (std::log10(e2) - std::log10(e1));
538 G4double b = std::log10(xs2) - a * std::log10(e2);
539 G4double sigma = a * std::log10(e) + b;
540 value = (std::pow(10., sigma));
541 }
542
543 // Switch to lin-lin interpolation
544 /*
545 if ((e2-e1)!=0)
546 {
547 G4double d1 = xs1;
548 G4double d2 = xs2;
549 value = (d1 + (d2 - d1)*(e - e1)/ (e2 - e1));
550 }
551 */
552
553 // Switch to log-lin interpolation for faster code
554
555 if ((e2 - e1) != 0 && xs1 != 0 && xs2 != 0 && fasterCode) {
556 G4double d1 = std::log10(xs1);
557 G4double d2 = std::log10(xs2);
558 value = std::pow(10., (d1 + (d2 - d1) * (e - e1) / (e2 - e1)));
559 }
560
561 // Switch to lin-lin interpolation for faster code
562 // in case one of xs1 or xs2 (=cum proba) value is zero
563
564 if ((e2 - e1) != 0 && (xs1 == 0 || xs2 == 0) && fasterCode) {
565 G4double d1 = xs1;
566 G4double d2 = xs2;
567 value = (d1 + (d2 - d1) * (e - e1) / (e2 - e1));
568 }
569 return value;
570}
571
572//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
573
574G4double G4DNACPA100IonisationModel::QuadInterpolator(G4double e11, G4double e12, G4double e21,
575 G4double e22, G4double xs11, G4double xs12,
576 G4double xs21, G4double xs22, G4double t1,
577 G4double t2, G4double t, G4double e)
578{
579 G4double interpolatedvalue1 = Interpolate(e11, e12, e, xs11, xs12);
580 G4double interpolatedvalue2 = Interpolate(e21, e22, e, xs21, xs22);
581 G4double value = Interpolate(t1, t2, t, interpolatedvalue1, interpolatedvalue2);
582
583 return value;
584}
585
587G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergyFromCumulatedDcs(PartKineticInMat info)
588{
589 auto MatID = std::get<0>(info);
590 auto shell = std::get<2>(info);
591 G4double secondaryElectronKineticEnergy =
592 RandomTransferedEnergy(info) * eV - iStructure.IonisationEnergy(shell, MatID);
593 if (secondaryElectronKineticEnergy < 0.) {
594 return 0.;
595 }
596 return secondaryElectronKineticEnergy;
597}
598
599G4double G4DNACPA100IonisationModel::RandomTransferedEnergy(PartKineticInMat info)
600{
601 auto materialID = std::get<0>(info);
602 auto k = std::get<1>(info) / eV; // data table in eV
603 auto shell = std::get<2>(info);
604 G4double ejectedElectronEnergy = 0.;
605 G4double valueK1 = 0;
606 G4double valueK2 = 0;
607 G4double valueCumulCS21 = 0;
608 G4double valueCumulCS22 = 0;
609 G4double valueCumulCS12 = 0;
610 G4double valueCumulCS11 = 0;
611 G4double secElecE11 = 0;
612 G4double secElecE12 = 0;
613 G4double secElecE21 = 0;
614 G4double secElecE22 = 0;
615
616 if (k == fTMapWithVec[materialID][fpParticle].back()) {
617 k = k * (1. - 1e-12);
618 }
619
620 G4double random = G4UniformRand();
621 auto k2 = std::upper_bound(fTMapWithVec[materialID][fpParticle].begin(),
622 fTMapWithVec[materialID][fpParticle].end(), k);
623 auto k1 = k2 - 1;
624
625 if (random <= fProbaShellMap[materialID][fpParticle][shell][(*k1)].back()
626 && random <= fProbaShellMap[materialID][fpParticle][shell][(*k2)].back())
627 {
628 auto cumulCS12 =
629 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k1)].begin(),
630 fProbaShellMap[materialID][fpParticle][shell][(*k1)].end(), random);
631 auto cumulCS11 = cumulCS12 - 1;
632 // Second one.
633 auto cumulCS22 =
634 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k2)].begin(),
635 fProbaShellMap[materialID][fpParticle][shell][(*k2)].end(), random);
636 auto cumulCS21 = cumulCS22 - 1;
637
638 valueK1 = *k1;
639 valueK2 = *k2;
640 valueCumulCS11 = *cumulCS11;
641 valueCumulCS12 = *cumulCS12;
642 valueCumulCS21 = *cumulCS21;
643 valueCumulCS22 = *cumulCS22;
644
645 secElecE11 = fEnergySecondaryData[materialID][fpParticle][shell][valueK1][valueCumulCS11];
646 secElecE12 = fEnergySecondaryData[materialID][fpParticle][shell][valueK1][valueCumulCS12];
647 secElecE21 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS21];
648 secElecE22 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS22];
649
650 if (valueCumulCS11 == 0. && valueCumulCS12 == 1.) {
651 auto interpolatedvalue2 =
652 Interpolate(valueCumulCS21, valueCumulCS22, random, secElecE21, secElecE22);
653 G4double valueNrjTransf = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
654 return valueNrjTransf;
655 }
656 }
657
658 if (random > fProbaShellMap[materialID][fpParticle][shell][(*k1)].back()) {
659 auto cumulCS22 =
660 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k2)].begin(),
661 fProbaShellMap[materialID][fpParticle][shell][(*k2)].end(), random);
662 auto cumulCS21 = cumulCS22 - 1;
663 valueK1 = *k1;
664 valueK2 = *k2;
665 valueCumulCS21 = *cumulCS21;
666 valueCumulCS22 = *cumulCS22;
667
668 secElecE21 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS21];
669 secElecE22 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS22];
670
671 G4double interpolatedvalue2 =
672 Interpolate(valueCumulCS21, valueCumulCS22, random, secElecE21, secElecE22);
673
674 G4double value = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
675 return value;
676 }
677 G4double nrjTransfProduct = secElecE11 * secElecE12 * secElecE21 * secElecE22;
678
679 if (nrjTransfProduct != 0.) {
680 ejectedElectronEnergy =
681 QuadInterpolator(valueCumulCS11, valueCumulCS12, valueCumulCS21, valueCumulCS22, secElecE11,
682 secElecE12, secElecE21, secElecE22, valueK1, valueK2, k, random);
683 }
684 return ejectedElectronEnergy;
685}
686
687//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
688
690G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergyFromanalytical(PartKineticInMat info)
691{
692 auto MatID = std::get<0>(info);
693 auto tt = std::get<1>(info);
694 auto shell = std::get<2>(info);
695 // ***** METHOD by M. C. Bordage ***** (optimized)
696 // Composition sampling method based on eq 7 in (Guerra et al. 2015) the RBEBV
697
698 //// Defining constants
699 G4double alfa = 1. / 137; // fine structure constant
700 G4double e_charge = 1.6e-19; // electron charge
701 G4double e_mass = 9.1e-31; // electron mass in kg
702 G4double c = 3e8; // speed of light in vacuum constant c (m/s)
703 G4double mc2 = e_mass * c * c / e_charge; //
704
705 G4double BB = iStructure.IonisationEnergy(shell, MatID); // binding energy of the shell (eV)
706
707 if (tt <= BB) return 0.;
708
709 G4double b_prime = BB / mc2; // binding energy divided by mc2
710 G4double beta_b2 = 1. - 1. / ((1 + b_prime) * (1 + b_prime)); // binding energy Beta
711
712 //// Indicent energy
713 //// tt is the incident electron energy
714
715 G4double t_prime = tt / mc2; // incident energy divided by mc2
716 G4double t = tt / BB; // reduced incident energy by binding energy
717
718 G4double D = (1 + 2 * t_prime) / ((1 + t_prime / 2) * (1 + t_prime / 2));
719 G4double F = b_prime * b_prime / ((1 + t_prime / 2) * (1 + t_prime / 2));
720
721 G4double beta_t2 = 1 - 1 / ((1 + t_prime) * (1 + t_prime)); // incident energy Beta
722
723 G4double PHI_R = std::cos(std::sqrt(alfa * alfa / (beta_t2 + beta_b2))
724 * std::log(beta_t2 / beta_b2)); // relativistic Vriens function phi
725 G4double G_R = std::log(beta_t2 / (1 - beta_t2)) - beta_t2 - std::log(2 * b_prime);
726
727 G4double tplus1 = t + 1;
728 G4double tminus1 = t - 1;
729 G4double tplus12 = tplus1 * tplus1;
730 G4double ZH1max = 1 + F - (PHI_R * D * (2 * t + 1) / (2 * t * tplus1));
731 G4double ZH2max = 1 - PHI_R * D / 4;
732
733 G4double A1_p = ZH1max * tminus1 / tplus1; // A1'
734 G4double A2_p = ZH2max * tminus1 / (t * tplus1); // A2'
735 G4double A3_p = ((tplus12 - 4) / tplus12) * G_R; // A3'
736
737 G4double AAA = A1_p + A2_p + A3_p;
738
739 G4double AA1_R = A1_p / AAA;
740 G4double AA2_R = (A1_p + A2_p) / AAA;
741
742 G4int FF = 0;
743 G4double fx = 0;
744 G4double gx = 0;
745 G4double gg = 0;
746 G4double wx = 0;
747
748 G4double r1 = 0;
749 G4double r2 = 0;
750 G4double r3 = 0;
751
752 //
753
754 do {
755 r1 = G4UniformRand();
756 r2 = G4UniformRand();
757 r3 = G4UniformRand();
758
759 if (r1 > AA2_R)
760 FF = 3;
761 else if ((r1 > AA1_R) && (r1 < AA2_R))
762 FF = 2;
763 else
764 FF = 1;
765
766 switch (FF) {
767 case 1: {
768 fx = r2 * tminus1 / tplus1;
769 wx = 1 / (1 - fx) - 1;
770 gg = PHI_R * D * (wx + 1) / tplus1;
771 gx = 1 - gg;
772 gx = gx - gg * (wx + 1) / (2 * (t - wx));
773 gx = gx + F * (wx + 1) * (wx + 1);
774 gx = gx / ZH1max;
775 break;
776 }
777
778 case 2: {
779 fx = tplus1 + r2 * tminus1;
780 wx = t * tminus1 * r2 / fx;
781 gx = 1 - (PHI_R * D * (t - wx) / (2 * tplus1));
782 gx = gx / ZH2max;
783 break;
784 }
785
786 case 3: {
787 fx = 1 - r2 * (tplus12 - 4) / tplus12;
788 wx = std::sqrt(1 / fx) - 1;
789 gg = (wx + 1) / (t - wx);
790 gx = (1 + gg * gg * gg) / 2;
791 break;
792 }
793 } // switch
794
795 } while (r3 > gx);
796
797 return wx * BB;
798}
799
800//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
801
802void G4DNACPA100IonisationModel::ReadDiffCSFile(const std::size_t& materialID,
803 const G4ParticleDefinition* p, const G4String& file,
804 const G4double& scaleFactor)
805{
806 const char* path = G4FindDataDir("G4LEDATA");
807 if (path == nullptr) {
808 G4Exception("G4DNACPA100IonisationModel::ReadAllDiffCSFiles", "em0006", FatalException,
809 "G4LEDATA environment variable was not set.");
810 return;
811 }
812
813 std::ostringstream fullFileName;
814 fullFileName << path << "/" << file << ".dat";
815
816 std::ifstream diffCrossSection(fullFileName.str().c_str());
817 std::stringstream endPath;
818 if (!diffCrossSection) {
819 endPath << "Missing data file: " << file;
820 G4Exception("G4DNACPA100IonisationModel::Initialise", "em0003", FatalException,
821 endPath.str().c_str());
822 }
823
824 // load data from the file
825 fTMapWithVec[materialID][p].push_back(0.);
826
827 G4String line;
828
829 while (!diffCrossSection.eof()) {
830 G4double T, E;
831 diffCrossSection >> T >> E;
832
833 if (T != fTMapWithVec[materialID][p].back()) {
834 fTMapWithVec[materialID][p].push_back(T);
835 }
836
837 // T is incident energy, E is the energy transferred
838 if (T != fTMapWithVec[materialID][p].back()) {
839 fTMapWithVec[materialID][p].push_back(T);
840 }
841
842 auto eshell = (G4int)iStructure.NumberOfLevels(materialID);
843 for (G4int shell = 0; shell < eshell; ++shell) {
844 diffCrossSection >> diffCrossSectionData[materialID][p][shell][T][E];
845 if (fasterCode) {
846 fEnergySecondaryData[materialID][p][shell][T]
847 [diffCrossSectionData[materialID][p][shell][T][E]] = E;
848
849 fProbaShellMap[materialID][p][shell][T].push_back(
850 diffCrossSectionData[materialID][p][shell][T][E]);
851 }
852 else {
853 diffCrossSectionData[materialID][p][shell][T][E] *= scaleFactor;
854 fEMapWithVector[materialID][p][T].push_back(E);
855 }
856 }
857 }
858}
@ eIonizedMolecule
G4double D(G4double temp)
const char * G4FindDataDir(const char *)
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
double G4double
Definition G4Types.hh:83
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
double z() const
Hep3Vector unit() const
double x() const
double y() const
void set(double x, double y, double z)
Hep3Vector & rotateUz(const Hep3Vector &)
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
Initialise Each model must implement an Initialize method.
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
SampleSecondaries Each model must implement SampleSecondaries to decide if a particle will be created...
G4DNACPA100IonisationModel(const G4ParticleDefinition *p=nullptr, const G4String &nam="DNACPA100IonisationModel")
void ReadDiffCSFile(const std::size_t &materialID, const G4ParticleDefinition *p, const G4String &file, const G4double &scaleFactor) override
G4double DifferentialCrossSection(PartKineticInMat info, const G4double &energyTransfer)
G4ParticleChangeForGamma * fParticleChangeForGamma
G4double CrossSectionPerVolume(const G4Material *material, const G4ParticleDefinition *p, G4double ekin, G4double emin, G4double emax) override
CrossSectionPerVolume Every model must implement its own CrossSectionPerVolume method....
std::size_t NumberOfLevels(const std::size_t &MatID)
G4double IonisationEnergy(const std::size_t &level, const std::size_t &MatID)
static G4DNAChemistryManager * Instance()
void CreateWaterMolecule(ElectronicModification, G4int, const G4Track *)
static G4DNAMaterialManager * Instance()
void SetMasterDataModel(const DNAModelType &t, G4VEmModel *m)
G4VEmModel * GetModel(const DNAModelType &t)
const std::vector< G4double > * GetNumMolPerVolTableFor(const G4Material *) const
Retrieve a table of molecular densities (number of molecules per unit volume) in the G4 unit system f...
static G4DNAMolecularMaterial * Instance()
const G4ThreeVector & GetMomentumDirection() const
G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
static G4Electron * ElectronDefinition()
Definition G4Electron.cc:86
static G4Electron * Electron()
Definition G4Electron.cc:91
static G4LossTableManager * Instance()
G4VAtomDeexcitation * AtomDeexcitation()
const G4Material * GetMaterial() const
std::size_t GetIndex() const
static G4MaterialTable * GetMaterialTable()
static G4Material * GetMaterial(const G4String &name, G4bool warning=true)
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
const G4String & GetParticleName() const
virtual const G4AtomicShell * GetAtomicShell(G4int Z, G4AtomicShellEnumerator shell)=0
void GenerateParticles(std::vector< G4DynamicParticle * > *secVect, const G4AtomicShell *, G4int Z, G4int coupleIndex)
The G4VDNAModel class.
G4String GetName()
GetName.
void LoadCrossSectionData(const G4ParticleDefinition *particleName)
LoadCrossSectionData Method to loop on all the registered materials in the model and load the corresp...
void SetLowELimit(const size_t &materialID, const G4ParticleDefinition *particle, G4double lim)
SetLowEnergyLimit.
void SetHighELimit(const size_t &materialID, const G4ParticleDefinition *particle, G4double lim)
SetHighEnergyLimit.
G4double GetHighELimit(const size_t &materialID, const G4ParticleDefinition *particle)
GetHighEnergyLimit.
G4int RandomSelectShell(const G4double &k, const G4ParticleDefinition *particle, const size_t &materialName)
RandomSelectShell Method to randomely select a shell from the data table uploaded....
void AddCrossSectionData(const size_t &materialName, const G4ParticleDefinition *particleName, const G4String &fileCS, const G4String &fileDiffCS, const G4double &scaleFactor)
AddCrossSectionData Method used during the initialization of the model class to add a new material....
G4double GetLowELimit(const size_t &materialID, const G4ParticleDefinition *particle)
GetLowEnergyLimit.
MaterialParticleMapData * GetData()
GetTableData.
G4ParticleChangeForGamma * GetParticleChangeForGamma()
G4bool IsLocked() const
const G4Track * GetCurrentTrack() const
void ProposeLocalEnergyDeposit(G4double anEnergyPart)