Files
geant4/source/processes/electromagnetic/dna/models/src/G4DNAQuadrupleIonisationModel.cc
T
2024-12-06 11:11:40 +01:00

367 lines
13 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4DNAQuadrupleIonisationModel.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#include "G4DNAQuadrupleIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4IonTable.hh"
#include "G4GenericIon.hh"
#include "G4DNARuddAngle.hh"
#include "G4Pow.hh"
#include <sstream>
namespace {
G4DNAWaterIonisationStructure water_structure;
G4Pow* g4pow = G4Pow::GetInstance();
} // end of anonymous namespace
//==============================================================================
// constructor
G4DNAQuadrupleIonisationModel::G4DNAQuadrupleIonisationModel(
const G4ParticleDefinition* p, const G4String& model_name)
: G4DNADoubleIonisationModel(p, model_name)
{
// Quadruple-ionisation energy
energy_threshold_ = 88.0 * eV;
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisationModel::Initialise(
const G4ParticleDefinition* particle, const G4DataVector&)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNAQuadrupleIonisationModel::Initialise()" << G4endl;
}
proton_def_ = G4Proton::ProtonDefinition();
alpha_def_ = G4DNAGenericIonsManager::Instance()->GetIon("alpha++");
carbon_def_ = G4IonTable::GetIonTable()->GetIon(6, 12);
constexpr G4double kScaleFactor = 1.0 * m * m;
mioni_manager_ = new G4DNAMultipleIonisationManager();
G4double Z{0.0}, A{0.0};
G4String alpha_param_file{"dna/multipleionisation_alphaparam_champion.dat"};
if (particle == proton_def_) {
// *************************************************************************
// for protons
const auto& proton = proton_def_->GetParticleName();
elow_tab_[proton] = model_elow_tab_[1];
eupp_tab_[proton] = 3.0 * MeV;
// load cross-section data for single ionization process
auto xs_proton = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_proton->LoadData("dna/sigma_ionisation_p_rudd");
xs_tab_[proton] = xs_proton;
// set energy limits
SetLowEnergyLimit(elow_tab_[proton]);
SetHighEnergyLimit(eupp_tab_[proton]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_p.dat";
}
Z = static_cast<G4double>(proton_def_->GetAtomicNumber());
A = static_cast<G4double>(proton_def_->GetAtomicMass());
} else if (particle == alpha_def_) {
//**************************************************************************
// for alpha particles
const auto& alpha = alpha_def_->GetParticleName();
elow_tab_[alpha] = model_elow_tab_[4];
eupp_tab_[alpha] = 23.0 * MeV;
// load cross-section data for single ionization process
auto xs_alpha = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_alpha->LoadData("dna/sigma_ionisation_alphaplusplus_rudd");
xs_tab_[alpha] = xs_alpha;
// set energy limits
SetLowEnergyLimit(elow_tab_[alpha]);
SetHighEnergyLimit(eupp_tab_[alpha]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_alphaplusplus.dat";
}
Z = static_cast<G4double>(alpha_def_->GetAtomicNumber());
A = static_cast<G4double>(alpha_def_->GetAtomicMass());
} else if (particle == G4GenericIon::GenericIonDefinition()) {
// *************************************************************************
// for carbon ions
const auto& carbon = carbon_def_->GetParticleName();
elow_tab_[carbon] = model_elow_tab_[5] * carbon_def_->GetAtomicMass();
eupp_tab_[carbon] = 120.0 * MeV;
// load cross-section data for single ionization process
auto xs_carbon = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_carbon->LoadData("dna/sigma_ionisation_c_rudd");
xs_tab_[carbon] = xs_carbon;
// set energy limits
SetLowEnergyLimit(elow_tab_[carbon]);
SetHighEnergyLimit(eupp_tab_[carbon]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_c.dat";
}
Z = static_cast<G4double>(carbon_def_->GetAtomicNumber());
A = static_cast<G4double>(carbon_def_->GetAtomicMass());
}
// load alpha parameter
mioni_manager_->LoadAlphaParam(alpha_param_file, Z, A);
if (verbose_level_ > 0) {
G4cout << "G4DNAQuadrupleIonisationModel is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV for "
<< particle->GetParticleName()
<< G4endl;
}
water_density_ = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(
G4Material::GetMaterial("G4_WATER"));
atom_deex_ = G4LossTableManager::Instance()->AtomDeexcitation();
if (is_initialized_) { return; }
particle_change_ = GetParticleChangeForGamma();
is_initialized_ = true;
}
//------------------------------------------------------------------------------
G4double G4DNAQuadrupleIonisationModel::CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNAQuadrupleIonisationModel::CrossSectionPerVolume()"
<< G4endl;
}
// Calculate total cross section for model
if (pdef != proton_def_ && pdef != alpha_def_ && pdef != carbon_def_) {
return 0.0;
}
static G4double water_dens = (*water_density_)[material->GetIndex()];
const auto& pname = pdef->GetParticleName();
const auto low_energy_lim = GetLowEnergyLimit(pname);
const auto upp_energy_lim = GetUppEnergyLimit(pname);
G4double sigma{0.0};
if (ekin <= upp_energy_lim) {
if (ekin < low_energy_lim) { ekin = low_energy_lim; }
CrossSectionDataTable::iterator pos = xs_tab_.find(pname);
if (pos == xs_tab_.end()) {
G4Exception("G4DNAQuadrupleIonisationModel::CrossSectionPerVolume",
"em0002", FatalException,
"Model not applicable to particle type.");
}
G4DNACrossSectionDataSet* table = pos->second;
if (table != nullptr) {
auto scale_param = mioni_manager_->GetAlphaParam(ekin);
scale_param = ::g4pow->powA(scale_param, 3.0);
sigma = table->FindValue(ekin) * scale_param;
}
}
if (verbose_level_ > 2) {
std::stringstream msg;
msg << "----------------------------------------------------------------\n";
msg << " G4DNAQuadrupleIonisationModel - XS INFO START\n";
msg << " - Kinetic energy(eV): " << ekin/eV << ", Particle : "
<< pdef->GetParticleName() << "\n";
msg << " - Cross section per water molecule (cm^2): "
<< sigma / cm / cm << "\n";
msg << " - Cross section per water molecule (cm^-1): "
<< sigma * water_dens / (1.0 / cm) << "\n";
msg << " G4DNAQuadrupleIonisationModel - XS INFO END\n";
msg << "----------------------------------------------------------------\n";
G4cout << msg.str() << G4endl;
}
return (sigma * water_dens);
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisationModel::SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling SampleSecondaries() of G4DNAQuadrupleIonisationModel"
<< G4endl;
}
// get the definition for this parent particle
auto pdef = particle->GetDefinition();
// get kinetic energy
auto ekin = particle->GetKineticEnergy();
// get particle name
const auto& pname = pdef->GetParticleName();
// get energy limits
const auto low_energy_lim = GetLowEnergyLimit(pname);
// ***************************************************************************
// stop the transportation process of this parent particle
// if its kinetic energy is below the lower limit
if (ekin < low_energy_lim) {
particle_change_->SetProposedKineticEnergy(0.0);
particle_change_->ProposeTrackStatus(fStopAndKill);
particle_change_->ProposeLocalEnergyDeposit(ekin);
return;
}
// ***************************************************************************
constexpr G4int kNumSecondaries = 4;
constexpr G4double kDeltaTheta = pi * 0.5;
G4int ioni_shell[kNumSecondaries] = {0, 0, 0, 0};
G4double shell_energy[kNumSecondaries];
auto scale_param = mioni_manager_->GetAlphaParam(ekin);
scale_param = ::g4pow->powA(scale_param, 3.0);
G4bool is_continue{true};
while (1) {
ioni_shell[0] = RandomSelect(ekin, scale_param, pname);
ioni_shell[1] = RandomSelect(ekin, scale_param, pname);
ioni_shell[2] = RandomSelect(ekin, scale_param, pname);
ioni_shell[3] = RandomSelect(ekin, scale_param, pname);
is_continue =
(ioni_shell[0] == ioni_shell[1] && ioni_shell[1] == ioni_shell[2]) ||
(ioni_shell[1] == ioni_shell[2] && ioni_shell[2] == ioni_shell[3]) ||
(ioni_shell[2] == ioni_shell[3] && ioni_shell[3] == ioni_shell[0]) ||
(ioni_shell[3] == ioni_shell[0] && ioni_shell[0] == ioni_shell[1]) ||
(ioni_shell[0] == ioni_shell[1] && ioni_shell[1] == ioni_shell[2] &&
ioni_shell[2] == ioni_shell[3]);
if (!is_continue) { break; }
}
G4double tot_ioni_energy{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
shell_energy[i] = ::water_structure.IonisationEnergy(ioni_shell[i]);
tot_ioni_energy += shell_energy[i];
}
if (ekin < tot_ioni_energy || tot_ioni_energy < energy_threshold_) {
return;
}
// generate secondary electrons
G4double theta{0.0}, phi{0.0}, tot_ekin2{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
tot_ekin2 += GenerateSecondaries(vsec, couple, particle, ioni_shell[i],
theta, phi, shell_energy[i]);
theta += kDeltaTheta;
}
// This should never happen
if (mioni_manager_->CheckShellEnergy(eQuadrupleIonisedMolecule,
shell_energy)) {
G4Exception("G4DNAQuadrupleIonisatioModel::SampleSecondaries()",
"em2050", FatalException, "Negative local energy deposit");
}
// ***************************************************************************
// update kinematics for this parent particle
const auto primary_dir = particle->GetMomentumDirection();
particle_change_->ProposeMomentumDirection(primary_dir);
const auto scattered_energy = ekin - tot_ioni_energy - tot_ekin2;
// update total amount of shell energy
tot_ioni_energy = shell_energy[0] + shell_energy[1] +
shell_energy[2] + shell_energy[3];
if (stat_code_) {
particle_change_->SetProposedKineticEnergy(ekin);
particle_change_->ProposeLocalEnergyDeposit(
ekin - scattered_energy);
} else {
particle_change_->SetProposedKineticEnergy(scattered_energy);
particle_change_->ProposeLocalEnergyDeposit(tot_ioni_energy);
}
// ***************************************************************************
// generate triple-ionized water molecules (H2O^4+)
const auto the_track = particle_change_->GetCurrentTrack();
mioni_manager_->CreateMultipleIonisedWaterMolecule(
eQuadrupleIonisedMolecule, ioni_shell, the_track);
// ***************************************************************************
}