84 if (verboseLevel > 3) {
85 G4cout <<
"Calling G4DNACPA100IonisationModel::Initialise()" <<
G4endl;
89 if (p != fpParticle) {
90 std::ostringstream oss;
91 oss <<
" Model is not applied for this particle " << p->
GetParticleName();
92 G4Exception(
"G4DNACPA100IonisationModel::G4DNACPA100IonisationModel",
"CPA001",
98 if (path ==
nullptr) {
100 "G4LEDATA environment variable not set.");
105 if (fpG4_WATER !=
nullptr) {
108 fasterCode ? eFullFileName =
"/dna/sigmadiff_cumulated_ionisation_e_cpa100_rel"
109 : eFullFileName =
"/dna/sigmadiff_ionisation_e_cpa100_rel";
115 if (fpGuanine !=
nullptr) {
119 fasterCode ? eFullFileName =
"/dna/sigmadiff_cumulated_elastic_e_cpa100_guanine"
120 : eFullFileName =
"/dna/sigmadiff_ionisation_e_cpa100_guanine";
127 if (fpDeoxyribose !=
nullptr) {
131 eFullFileName =
"/dna/sigmadiff_cumulated_ionisation_e_cpa100_deoxyribose";
138 if (fpCytosine !=
nullptr) {
142 fasterCode ? eFullFileName =
"/dna/sigmadiff_cumulated_ionisation_e_cpa100_cytosine"
143 : eFullFileName =
"/dna/sigmadiff_ionisation_e_cpa100_cytosine";
150 if (fpThymine !=
nullptr) {
154 fasterCode ? eFullFileName =
"/dna/sigmadiff_cumulated_ionisation_e_cpa100_thymine"
155 : eFullFileName =
"/dna/sigmadiff_ionisation_e_cpa100_thymine";
162 if (fpAdenine !=
nullptr) {
166 fasterCode ? eFullFileName =
"/dna/sigmadiff_cumulated_ionisation_e_cpa100_adenine"
167 : eFullFileName =
"/dna/sigmadiff_ionisation_e_cpa100_adenine";
174 if (fpPhosphate !=
nullptr) {
178 eFullFileName =
"dna/sigmadiff_cumulated_ionisation_e_cpa100_phosphoric_acid";
180 AddCrossSectionData(index, p,
"dna/sigma_ionisation_e_cpa100_phosphoric_acid",eFullFileName,
192 if (dataModel ==
nullptr) {
193 G4cout <<
"G4DNACPA100IonisationModel::CrossSectionPerVolume:: not good modelData" <<
G4endl;
196 fpModelData = dataModel;
202 isInitialised =
true;
215 if (p != fpParticle) {
217 "No model is registered for this particle");
227 if (ekin >= lowLim && ekin < highLim) {
229 auto tableData = fpModelData->
GetData();
231 if ((*tableData)[matID][p] ==
nullptr) {
233 "No model is registered");
236 sigma = (*tableData)[matID][p]->FindValue(ekin);
239 if (verboseLevel > 2) {
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;
247 G4cout <<
"°°° Cross section per " << matID <<
" index molecule (cm^2)=" << sigma / cm / cm
249 G4cout <<
"°°° Cross section per Phosphate molecule (cm^-1)="
250 << sigma * MolDensity / (1. / cm) <<
G4endl;
251 G4cout <<
"°°° G4DNACPA100IonisationModel - XS INFO END" <<
G4endl;
256 return sigma * MolDensity;
262 std::vector<G4DynamicParticle*>* fvect,
266 if (verboseLevel > 3) {
267 G4cout <<
"Calling SampleSecondaries() of G4DNACPA100IonisationModel" <<
G4endl;
281 if (k >= lowLim && k < highLim) {
284 auto totalEnergy = k + particleMass;
285 auto pSquare = k * (totalEnergy + particleMass);
286 auto totalMomentum = std::sqrt(pSquare);
288 G4double bindingEnergy, secondaryKinetic;
292 if (k < bindingEnergy) {
296 auto info = std::make_tuple(MatID, k, shell);
298 secondaryKinetic = -1000 * eV;
299 if (fpG4_WATER->
GetIndex() != MatID) {
300 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergyFromanalytical(info);
301 }
else if(fasterCode){
302 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergyFromCumulatedDcs(info);
304 secondaryKinetic = fpModelData->RandomizeEjectedElectronEnergy(info);
309 RandomizeEjectedElectronDirection(particle->
GetDefinition(), k, secondaryKinetic, cosTheta,
312 G4double sinTheta = std::sqrt(1. - cosTheta * cosTheta);
313 G4double dirX = sinTheta * std::cos(phi);
314 G4double dirY = sinTheta * std::sin(phi);
317 deltaDirection.
rotateUz(primaryDirection);
320 if (secondaryKinetic > 0) {
322 fvect->push_back(dp);
330 std::sqrt(secondaryKinetic * (secondaryKinetic + 2. * electron_mass_c2));
332 totalMomentum * primaryDirection.x() - deltaTotalMomentum * deltaDirection.
x();
334 totalMomentum * primaryDirection.y() - deltaTotalMomentum * deltaDirection.
y();
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;
343 direction.
set(finalPx, finalPy, finalPz);
354 G4double scatteredEnergy = k - bindingEnergy - secondaryKinetic;
359 std::size_t secNumberInit = 0;
360 std::size_t secNumberFinal = 0;
361 if ((fAtomDeexcitation !=
nullptr) && shell == 4) {
364 secNumberInit = fvect->size();
366 secNumberFinal = fvect->size();
367 if (secNumberFinal > secNumberInit) {
368 for (std::size_t i = secNumberInit; i < secNumberFinal; ++i) {
370 if (bindingEnergy >= ((*fvect)[i])->GetKineticEnergy()) {
372 bindingEnergy -= ((*fvect)[i])->GetKineticEnergy();
378 (*fvect)[i] =
nullptr;
386 if (bindingEnergy < 0.0) {
388 "Negative local energy deposit");
410G4double G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergy(PartKineticInMat info)
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.;
417 (k + IonLevel) / 2. > k ? maximumEnergyTransfer = k : maximumEnergyTransfer = (k + IonLevel) / 2.;
422 G4double maxEnergy = maximumEnergyTransfer;
425 G4int nEnergySteps = 50;
428 G4double stpEnergy(std::pow(maxEnergy / value, 1. /
static_cast<G4double>(nEnergySteps - 1)));
429 G4int step(nEnergySteps);
430 G4double differentialCrossSection = 0.;
435 if (differentialCrossSection > 0) {
436 crossSectionMaximum = differentialCrossSection;
442 G4double secondaryElectronKineticEnergy = 0.;
444 secondaryElectronKineticEnergy =
G4UniformRand() * (maximumEnergyTransfer - IonLevel);
448 return secondaryElectronKineticEnergy;
459 G4double sin2O = (1. - secKinetic / k) / (1. + secKinetic / (2. * electron_mass_c2));
460 cosTheta = std::sqrt(1. - sin2O);
468 auto MatID = std::get<0>(info);
469 auto k = std::get<1>(info) / eV;
470 auto shell = std::get<2>(info);
473 G4double kSE(energyTransfer - shellEnergy);
475 if (energyTransfer >= shellEnergy) {
488 auto t2 = std::upper_bound(fTMapWithVec[MatID][fpParticle].begin(),
489 fTMapWithVec[MatID][fpParticle].end(), k);
492 if (kSE <= fEMapWithVector[MatID][fpParticle][(*t1)].back()
493 && kSE <= fEMapWithVector[MatID][fpParticle][(*t2)].back())
495 auto e12 = std::upper_bound(fEMapWithVector[MatID][fpParticle][(*t1)].begin(),
496 fEMapWithVector[MatID][fpParticle][(*t1)].end(), kSE);
499 auto e22 = std::upper_bound(fEMapWithVector[MatID][fpParticle][(*t2)].begin(),
500 fEMapWithVector[MatID][fpParticle][(*t2)].end(), kSE);
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];
516 G4double xsProduct = xs11 * xs12 * xs21 * xs22;
518 if (xsProduct != 0.) {
519 sigma = QuadInterpolator(valueE11, valueE12, valueE21, valueE22, xs11, xs12, xs21, xs22,
520 valueT1, valueT2, k, kSE);
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));
555 if ((e2 - e1) != 0 && xs1 != 0 && xs2 != 0 && fasterCode) {
558 value = std::pow(10., (d1 + (d2 - d1) * (e - e1) / (e2 - e1)));
564 if ((e2 - e1) != 0 && (xs1 == 0 || xs2 == 0) && fasterCode) {
567 value = (d1 + (d2 - d1) * (e - e1) / (e2 - e1));
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);
587G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergyFromCumulatedDcs(PartKineticInMat info)
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.) {
596 return secondaryElectronKineticEnergy;
599G4double G4DNACPA100IonisationModel::RandomTransferedEnergy(PartKineticInMat info)
601 auto materialID = std::get<0>(info);
602 auto k = std::get<1>(info) / eV;
603 auto shell = std::get<2>(info);
604 G4double ejectedElectronEnergy = 0.;
616 if (k == fTMapWithVec[materialID][fpParticle].back()) {
617 k = k * (1. - 1e-12);
621 auto k2 = std::upper_bound(fTMapWithVec[materialID][fpParticle].begin(),
622 fTMapWithVec[materialID][fpParticle].end(), k);
625 if (random <= fProbaShellMap[materialID][fpParticle][shell][(*k1)].back()
626 && random <= fProbaShellMap[materialID][fpParticle][shell][(*k2)].back())
629 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k1)].begin(),
630 fProbaShellMap[materialID][fpParticle][shell][(*k1)].end(), random);
631 auto cumulCS11 = cumulCS12 - 1;
634 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k2)].begin(),
635 fProbaShellMap[materialID][fpParticle][shell][(*k2)].end(), random);
636 auto cumulCS21 = cumulCS22 - 1;
640 valueCumulCS11 = *cumulCS11;
641 valueCumulCS12 = *cumulCS12;
642 valueCumulCS21 = *cumulCS21;
643 valueCumulCS22 = *cumulCS22;
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];
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;
658 if (random > fProbaShellMap[materialID][fpParticle][shell][(*k1)].back()) {
660 std::upper_bound(fProbaShellMap[materialID][fpParticle][shell][(*k2)].begin(),
661 fProbaShellMap[materialID][fpParticle][shell][(*k2)].end(), random);
662 auto cumulCS21 = cumulCS22 - 1;
665 valueCumulCS21 = *cumulCS21;
666 valueCumulCS22 = *cumulCS22;
668 secElecE21 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS21];
669 secElecE22 = fEnergySecondaryData[materialID][fpParticle][shell][valueK2][valueCumulCS22];
672 Interpolate(valueCumulCS21, valueCumulCS22, random, secElecE21, secElecE22);
674 G4double value = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
677 G4double nrjTransfProduct = secElecE11 * secElecE12 * secElecE21 * secElecE22;
679 if (nrjTransfProduct != 0.) {
680 ejectedElectronEnergy =
681 QuadInterpolator(valueCumulCS11, valueCumulCS12, valueCumulCS21, valueCumulCS22, secElecE11,
682 secElecE12, secElecE21, secElecE22, valueK1, valueK2, k, random);
684 return ejectedElectronEnergy;
690G4DNACPA100IonisationModel::RandomizeEjectedElectronEnergyFromanalytical(PartKineticInMat info)
692 auto MatID = std::get<0>(info);
693 auto tt = std::get<1>(info);
694 auto shell = std::get<2>(info);
703 G4double mc2 = e_mass * c * c / e_charge;
707 if (tt <= BB)
return 0.;
710 G4double beta_b2 = 1. - 1. / ((1 + b_prime) * (1 + b_prime));
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));
721 G4double beta_t2 = 1 - 1 / ((1 + t_prime) * (1 + t_prime));
723 G4double PHI_R = std::cos(std::sqrt(alfa * alfa / (beta_t2 + beta_b2))
724 * std::log(beta_t2 / beta_b2));
725 G4double G_R = std::log(beta_t2 / (1 - beta_t2)) - beta_t2 - std::log(2 * b_prime);
730 G4double ZH1max = 1 + F - (PHI_R *
D * (2 * t + 1) / (2 * t * tplus1));
733 G4double A1_p = ZH1max * tminus1 / tplus1;
734 G4double A2_p = ZH2max * tminus1 / (t * tplus1);
735 G4double A3_p = ((tplus12 - 4) / tplus12) * G_R;
740 G4double AA2_R = (A1_p + A2_p) / AAA;
761 else if ((r1 > AA1_R) && (r1 < AA2_R))
768 fx = r2 * tminus1 / tplus1;
769 wx = 1 / (1 - fx) - 1;
770 gg = PHI_R *
D * (wx + 1) / tplus1;
772 gx = gx - gg * (wx + 1) / (2 * (t - wx));
773 gx = gx + F * (wx + 1) * (wx + 1);
779 fx = tplus1 + r2 * tminus1;
780 wx = t * tminus1 * r2 / fx;
781 gx = 1 - (PHI_R *
D * (t - wx) / (2 * tplus1));
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;
807 if (path ==
nullptr) {
809 "G4LEDATA environment variable was not set.");
813 std::ostringstream fullFileName;
814 fullFileName << path <<
"/" << file <<
".dat";
816 std::ifstream diffCrossSection(fullFileName.str().c_str());
817 std::stringstream endPath;
818 if (!diffCrossSection) {
819 endPath <<
"Missing data file: " << file;
821 endPath.str().c_str());
825 fTMapWithVec[materialID][p].push_back(0.);
829 while (!diffCrossSection.eof()) {
831 diffCrossSection >> T >> E;
833 if (T != fTMapWithVec[materialID][p].back()) {
834 fTMapWithVec[materialID][p].push_back(T);
838 if (T != fTMapWithVec[materialID][p].back()) {
839 fTMapWithVec[materialID][p].push_back(T);
843 for (
G4int shell = 0; shell < eshell; ++shell) {
844 diffCrossSection >> diffCrossSectionData[materialID][p][shell][T][E];
846 fEnergySecondaryData[materialID][p][shell][T]
847 [diffCrossSectionData[materialID][p][shell][T][E]] = E;
849 fProbaShellMap[materialID][p][shell][T].push_back(
850 diffCrossSectionData[materialID][p][shell][T][E]);
853 diffCrossSectionData[materialID][p][shell][T][E] *= scaleFactor;
854 fEMapWithVector[materialID][p][T].push_back(E);
G4double D(G4double temp)
const char * G4FindDataDir(const char *)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4GLOB_DLL std::ostream G4cout
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()
static G4Electron * Electron()
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)
G4double GetPDGMass() const
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)
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()
const G4Track * GetCurrentTrack() const
void ProposeLocalEnergyDeposit(G4double anEnergyPart)