Import Geant4 11.0.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2021-06-25 16:12:29 +02:00
parent c968e26a39
commit 6399a014b6
4200 changed files with 207479 additions and 237366 deletions
@@ -23,104 +23,90 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointAlongStepWeightCorrection.hh"
#include "G4Step.hh"
#include "G4ParticleDefinition.hh"
#include "G4VParticleChange.hh"
#include "G4AdjointCSManager.hh"
#include "G4ParticleChange.hh"
#include "G4ParticleDefinition.hh"
#include "G4Step.hh"
#include "G4VParticleChange.hh"
///////////////////////////////////////////////////////
//
G4AdjointAlongStepWeightCorrection::G4AdjointAlongStepWeightCorrection(const G4String& name,
G4ProcessType type): G4VContinuousProcess(name, type)
{fParticleChange = new G4ParticleChange();
currentMaterialIndex=0;
preStepKinEnergy=1.;
currentCouple=0;
G4AdjointAlongStepWeightCorrection::G4AdjointAlongStepWeightCorrection(
const G4String& name, G4ProcessType type)
: G4VContinuousProcess(name, type)
{
fParticleChange = new G4ParticleChange();
fCSManager = G4AdjointCSManager::GetAdjointCSManager();
}
///////////////////////////////////////////////////////
//
G4AdjointAlongStepWeightCorrection::~G4AdjointAlongStepWeightCorrection()
{delete fParticleChange;
}
///////////////////////////////////////////////////////
//
void G4AdjointAlongStepWeightCorrection::PreparePhysicsTable(
const G4ParticleDefinition& )
{
;
delete fParticleChange;
}
///////////////////////////////////////////////////////
//
void G4AdjointAlongStepWeightCorrection::BuildPhysicsTable(const G4ParticleDefinition& )
{;
}
///////////////////////////////////////////////////////
//
G4VParticleChange* G4AdjointAlongStepWeightCorrection::AlongStepDoIt(const G4Track& track,
const G4Step& step)
void G4AdjointAlongStepWeightCorrection::ProcessDescription(
std::ostream& out) const
{
out <<
"Continuous processes act on adjoint particles to continuously correct their "
"weight during the adjoint reverse tracking. This process is needed when "
"the adjoint cross sections are not scaled such that the total adjoint cross "
"section matches the total forward cross section. By default the mode where "
"the total adjoint cross section is equal to the total forward cross section "
"is used and therefore this along step weightcorrection factor is 1. However "
"in some cases (some energy ranges) the total forward cross section or the "
"total adjoint cross section can be zero. In this case the along step weight "
"correction is needed and is given by exp(-(Sigma_tot_adj-Sigma_tot_fwd).dx)"
"\n";
}
///////////////////////////////////////////////////////
G4VParticleChange* G4AdjointAlongStepWeightCorrection::AlongStepDoIt(
const G4Track& track, const G4Step& step)
{
fParticleChange->Initialize(track);
// Get the actual (true) Step length
//----------------------------------
G4double length = step.GetStepLength();
G4double Tkin = step.GetPostStepPoint()->GetKineticEnergy();
G4ParticleDefinition* thePartDef= const_cast<G4ParticleDefinition*> (track.GetDynamicParticle()->GetDefinition());
G4double weight_correction=G4AdjointCSManager::GetAdjointCSManager()->GetContinuousWeightCorrection(thePartDef,
preStepKinEnergy,Tkin, currentCouple,length);
G4ParticleDefinition* thePartDef = const_cast<G4ParticleDefinition*>(
track.GetDynamicParticle()->GetDefinition());
G4double weight_correction = fCSManager->GetContinuousWeightCorrection(
thePartDef, fPreStepKinEnergy, Tkin, fCurrentCouple, length);
//Caution!!!
// It is important to select the weight of the post_step_point
// as the current weight and not the weight of the track, as t
// the weight of the track is changed after having applied all
// the along_step_do_it.
// Caution!!!
// It is important to select the weight of the post_step_point as the current
// weight and not the weight of the track, as the weight of the track is
// changed after having applied all the along_step_do_it.
G4double new_weight =
weight_correction * step.GetPostStepPoint()->GetWeight();
// G4double new_weight=weight_correction*track.GetWeight(); //old
G4double new_weight=weight_correction*step.GetPostStepPoint()->GetWeight();
//if (weight_correction >2.) new_weight=1.e-300;
//The following test check for zero weight.
//This happens after weight correction of gamma for photo electric effect.
//When the new weight is 0 it will be later on consider as nan by G4.
//Therefore we do put a lower limit of 1.e-300. for new_weight
//Correction by L.Desorgher on 15 July 2009
if (new_weight==0 || (new_weight<=0 && new_weight>0)){
//G4cout<<new_weight<<'\t'<<weight_correction<<'\t'<<track.GetWeight()<<G4endl;
new_weight=1.e-300;
// The following test check for zero weight.
// This happens after weight correction of gamma for photo electric effect.
// When the new weight is 0 it will be later on considered as NaN by G4.
// Therefore we put a lower limit of 1.e-300. for new_weight
if(new_weight == 0. || (new_weight <= 0. && new_weight > 0.))
{
new_weight = 1.e-300;
}
//G4cout<<new_weight<<'\t'<<weight_correction<<'\t'<<track.GetWeight()<<G4endl;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
return fParticleChange;
}
}
///////////////////////////////////////////////////////
//
G4double G4AdjointAlongStepWeightCorrection::GetContinuousStepLimit(const G4Track& track,
G4double , G4double , G4double& )
{
G4double x = DBL_MAX;
G4double G4AdjointAlongStepWeightCorrection::GetContinuousStepLimit(
const G4Track& track, G4double, G4double, G4double&)
{
DefineMaterial(track.GetMaterialCutsCouple());
preStepKinEnergy = track.GetKineticEnergy();
return x;
fPreStepKinEnergy = track.GetKineticEnergy();
return DBL_MAX;
}
@@ -23,414 +23,319 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointBremsstrahlungModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointElectron.hh"
#include "G4AdjointGamma.hh"
#include "G4Electron.hh"
#include "G4Timer.hh"
#include "G4EmModelManager.hh"
#include "G4Gamma.hh"
#include "G4ParticleChange.hh"
#include "G4PhysicalConstants.hh"
#include "G4SeltzerBergerModel.hh"
#include "G4SystemOfUnits.hh"
#include "G4TrackStatus.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointBremsstrahlungModel::G4AdjointBremsstrahlungModel(G4VEmModel* aModel):
G4VEmAdjointModel("AdjointeBremModel")
{
SetUseMatrix(false);
SetUseMatrixPerElement(false);
theDirectStdBremModel = aModel;
theDirectEMModel=theDirectStdBremModel;
theEmModelManagerForFwdModels = new G4EmModelManager();
isDirectModelInitialised = false;
G4VEmFluctuationModel* f=0;
G4Region* r=0;
theEmModelManagerForFwdModels->AddEmModel(1, theDirectStdBremModel, f, r);
SetApplyCutInRange(true);
highKinEnergy= 1.*GeV;
lowKinEnergy = 1.0*keV;
lastCZ =0.;
theAdjEquivOfDirectPrimPartDef =G4AdjointElectron::AdjointElectron();
theAdjEquivOfDirectSecondPartDef=G4AdjointGamma::AdjointGamma();
theDirectPrimaryPartDef=G4Electron::Electron();
second_part_of_same_type=false;
CS_biasing_factor =1.;
G4AdjointBremsstrahlungModel::G4AdjointBremsstrahlungModel(G4VEmModel* aModel)
: G4VEmAdjointModel("AdjointeBremModel")
{
fDirectModel = aModel;
Initialize();
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointBremsstrahlungModel::G4AdjointBremsstrahlungModel():
G4VEmAdjointModel("AdjointeBremModel")
G4AdjointBremsstrahlungModel::G4AdjointBremsstrahlungModel()
: G4VEmAdjointModel("AdjointeBremModel")
{
fDirectModel = new G4SeltzerBergerModel();
Initialize();
}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointBremsstrahlungModel::Initialize()
{
SetUseMatrix(false);
SetUseMatrixPerElement(false);
theDirectStdBremModel = new G4SeltzerBergerModel();
theDirectEMModel=theDirectStdBremModel;
theEmModelManagerForFwdModels = new G4EmModelManager();
isDirectModelInitialised = false;
G4VEmFluctuationModel* f=0;
G4Region* r=0;
theEmModelManagerForFwdModels->AddEmModel(1, theDirectStdBremModel, f, r);
// theDirectPenelopeBremModel =0;
fEmModelManagerForFwdModels = new G4EmModelManager();
fEmModelManagerForFwdModels->AddEmModel(1, fDirectModel, nullptr, nullptr);
SetApplyCutInRange(true);
highKinEnergy= 1.*GeV;
lowKinEnergy = 1.0*keV;
lastCZ =0.;
theAdjEquivOfDirectPrimPartDef =G4AdjointElectron::AdjointElectron();
theAdjEquivOfDirectSecondPartDef=G4AdjointGamma::AdjointGamma();
theDirectPrimaryPartDef=G4Electron::Electron();
second_part_of_same_type=false;
fElectron = G4Electron::Electron();
fGamma = G4Gamma::Gamma();
fAdjEquivDirectPrimPart = G4AdjointElectron::AdjointElectron();
fAdjEquivDirectSecondPart = G4AdjointGamma::AdjointGamma();
fDirectPrimaryPart = fElectron;
fSecondPartSameType = false;
fCSManager = G4AdjointCSManager::GetAdjointCSManager();
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointBremsstrahlungModel::~G4AdjointBremsstrahlungModel()
{if (theDirectStdBremModel) delete theDirectStdBremModel;
if (theEmModelManagerForFwdModels) delete theEmModelManagerForFwdModels;
{
if(fEmModelManagerForFwdModels)
delete fEmModelManagerForFwdModels;
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointBremsstrahlungModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
void G4AdjointBremsstrahlungModel::SampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
if (!UseMatrix) return RapidSampleSecondaries(aTrack,IsScatProjToProjCase,fParticleChange);
if(!fUseMatrix)
return RapidSampleSecondaries(aTrack, isScatProjToProj, fParticleChange);
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
G4double projectileKinEnergy = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy,
IsScatProjToProjCase);
//Weight correction
//-----------------------
CorrectPostStepWeight(fParticleChange,
aTrack.GetWeight(),
adjointPrimKinEnergy,
projectileKinEnergy,
IsScatProjToProjCase);
//Kinematic
//---------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
G4double projectileP = std::sqrt(projectileP2);
//Angle of the gamma direction with the projectile taken from G4eBremsstrahlungModel
//------------------------------------------------
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
G4double projectileKinEnergy =
SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, isScatProjToProj);
// Weight correction
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
adjointPrimKinEnergy, projectileKinEnergy,
isScatProjToProj);
// Kinematic
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
G4double projectileP = std::sqrt(projectileP2);
// Angle of the gamma direction with the projectile taken from
// G4eBremsstrahlungModel
G4double u;
const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
if(0.25 > G4UniformRand())
u = -std::log(G4UniformRand() * G4UniformRand()) / 0.625;
else
u = -std::log(G4UniformRand() * G4UniformRand()) / 1.875;
if (9./(9.+d) > G4UniformRand()) u = - std::log(G4UniformRand()*G4UniformRand())/a1;
else u = - std::log(G4UniformRand()*G4UniformRand())/a2;
G4double theta = u * electron_mass_c2 / projectileTotalEnergy;
G4double sint = std::sin(theta);
G4double cost = std::cos(theta);
G4double theta = u*electron_mass_c2/projectileTotalEnergy;
G4double phi = twopi * G4UniformRand();
G4double sint = std::sin(theta);
G4double cost = std::cos(theta);
G4double phi = twopi * G4UniformRand() ;
G4ThreeVector projectileMomentum;
projectileMomentum=G4ThreeVector(std::cos(phi)*sint,std::sin(phi)*sint,cost)*projectileP; //gamma frame
if (IsScatProjToProjCase) {//the adjoint primary is the scattered e-
G4ThreeVector gammaMomentum = (projectileTotalEnergy-adjointPrimTotalEnergy)*G4ThreeVector(0.,0.,1.);
G4ThreeVector dirProd=projectileMomentum-gammaMomentum;
G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
G4double sint1 = std::sqrt(1.-cost1*cost1);
projectileMomentum=G4ThreeVector(std::cos(phi)*sint1,std::sin(phi)*sint1,cost1)*projectileP;
G4ThreeVector projectileMomentum =
G4ThreeVector(std::cos(phi) * sint, std::sin(phi) * sint, cost) *
projectileP; // gamma frame
if(isScatProjToProj)
{ // the adjoint primary is the scattered e-
G4ThreeVector gammaMomentum =
(projectileTotalEnergy - adjointPrimTotalEnergy) *
G4ThreeVector(0., 0., 1.);
G4ThreeVector dirProd = projectileMomentum - gammaMomentum;
G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
G4double sint1 = std::sqrt(1. - cost1 * cost1);
projectileMomentum =
G4ThreeVector(std::cos(phi) * sint1, std::sin(phi) * sint1, cost1) *
projectileP;
}
projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointBremsstrahlungModel::RapidSampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
void G4AdjointBremsstrahlungModel::RapidSampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
G4double projectileKinEnergy =0.;
G4double gammaEnergy=0.;
G4double diffCSUsed=0.;
if (!IsScatProjToProjCase){
gammaEnergy=adjointPrimKinEnergy;
G4double Emax = GetSecondAdjEnergyMaxForProdToProjCase(adjointPrimKinEnergy);
G4double Emin= GetSecondAdjEnergyMinForProdToProjCase(adjointPrimKinEnergy);;
if (Emin>=Emax) return;
projectileKinEnergy=Emin*std::pow(Emax/Emin,G4UniformRand());
diffCSUsed=CS_biasing_factor*lastCZ/projectileKinEnergy;
}
else { G4double Emax = GetSecondAdjEnergyMaxForScatProjToProjCase(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForScatProjToProjCase(adjointPrimKinEnergy,currentTcutForDirectSecond);
if (Emin>=Emax) return;
G4double f1=(Emin-adjointPrimKinEnergy)/Emin;
G4double f2=(Emax-adjointPrimKinEnergy)/Emax/f1;
projectileKinEnergy=adjointPrimKinEnergy/(1.-f1*std::pow(f2,G4UniformRand()));
gammaEnergy=projectileKinEnergy-adjointPrimKinEnergy;
diffCSUsed=lastCZ*adjointPrimKinEnergy/projectileKinEnergy/gammaEnergy;
}
//Weight correction
//-----------------------
//First w_corr is set to the ratio between adjoint total CS and fwd total CS
//if this has to be done in the model
//For the case of forced interaction this will be done in the PostStepDoIt of the
//forced interaction
//It is important to set the weight before the vreation of the secondary
//
G4double w_corr=additional_weight_correction_factor_for_post_step_outside_model;
if (correct_weight_for_post_step_in_model) {
w_corr=G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
}
//G4cout<<"Correction factor start in brem model "<<w_corr<<std::endl;
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
//Then another correction is needed due to the fact that a biaised differential CS has been used rather than the one consistent with the direct model
//Here we consider the true diffCS as the one obtained by the numericla differentiation over Tcut of the direct CS, corrected by the Migdal term.
//Basically any other differential CS diffCS could be used here (example Penelope).
G4double projectileKinEnergy = 0.;
G4double gammaEnergy = 0.;
G4double diffCSUsed = 0.;
if(!isScatProjToProj)
{
gammaEnergy = adjointPrimKinEnergy;
G4double Emax = GetSecondAdjEnergyMaxForProdToProj(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForProdToProj(adjointPrimKinEnergy);
if(Emin >= Emax)
return;
projectileKinEnergy = Emin * std::pow(Emax / Emin, G4UniformRand());
diffCSUsed = fCsBiasingFactor * fLastCZ / projectileKinEnergy;
}
else
{
G4double Emax =
GetSecondAdjEnergyMaxForScatProjToProj(adjointPrimKinEnergy);
G4double Emin =
GetSecondAdjEnergyMinForScatProjToProj(adjointPrimKinEnergy, fTcutSecond);
if(Emin >= Emax)
return;
G4double f1 = (Emin - adjointPrimKinEnergy) / Emin;
G4double f2 = (Emax - adjointPrimKinEnergy) / Emax / f1;
projectileKinEnergy =
adjointPrimKinEnergy / (1. - f1 * std::pow(f2, G4UniformRand()));
gammaEnergy = projectileKinEnergy - adjointPrimKinEnergy;
diffCSUsed =
fLastCZ * adjointPrimKinEnergy / projectileKinEnergy / gammaEnergy;
}
G4double diffCS = DiffCrossSectionPerVolumePrimToSecond(currentMaterial, projectileKinEnergy, gammaEnergy);
/*G4cout<<"diffCS "<<diffCS <<std::endl;
G4cout<<"diffCS_Used "<<diffCSUsed <<std::endl;*/
w_corr*=diffCS/diffCSUsed;
// Weight correction:
// First w_corr is set to the ratio between adjoint total CS and fwd total CS
// if this has to be done in the model.
// For the case of forced interaction this will be done in the PostStepDoIt of
// the forced interaction. It is important to set the weight before the
// creation of the secondary
G4double w_corr = fOutsideWeightFactor;
if(fInModelWeightCorr)
{
w_corr = fCSManager->GetPostStepWeightCorrection();
}
// Then another correction is needed due to the fact that a biaised
// differential CS has been used rather than the one consistent with the
// direct model Here we consider the true diffCS as the one obtained by the
// numerical differentiation over Tcut of the direct CS, corrected by the
// Migdal term. Basically any other differential CS could be used here
// (example Penelope).
G4double diffCS = DiffCrossSectionPerVolumePrimToSecond(
fCurrentMaterial, projectileKinEnergy, gammaEnergy);
w_corr *= diffCS / diffCSUsed;
G4double new_weight = aTrack.GetWeight()*w_corr;
/*G4cout<<"New weight brem "<<new_weight<<std::endl;
G4cout<<"Weight correction brem "<<w_corr<<std::endl;*/
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
//Kinematic
//---------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
G4double projectileP = std::sqrt(projectileP2);
G4double new_weight = aTrack.GetWeight() * w_corr;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
//Use the angular model of the forward model to generate the gamma direction
//---------------------------------------------------------------------------
//Dum dynamic particle to use the model
G4DynamicParticle * aDynPart = new G4DynamicParticle(G4Electron::Electron(),G4ThreeVector(0.,0.,1.)*projectileP);
// Kinematic
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
G4double projectileP = std::sqrt(projectileP2);
//Get the element from the direct model
const G4Element* elm = theDirectEMModel->SelectRandomAtom(currentCouple,G4Electron::Electron(),
projectileKinEnergy,currentTcutForDirectSecond);
G4int Z=elm->GetZasInt();
G4double energy = aDynPart->GetTotalEnergy()-gammaEnergy;
G4ThreeVector projectileMomentum =
theDirectEMModel->GetAngularDistribution()->SampleDirection(aDynPart,energy,Z,currentMaterial)*projectileP;
// Use the angular model of the forward model to generate the gamma direction
// Dummy dynamic particle to use the model
G4DynamicParticle* aDynPart =
new G4DynamicParticle(fElectron, G4ThreeVector(0., 0., 1.) * projectileP);
// Get the element from the direct model
const G4Element* elm = fDirectModel->SelectRandomAtom(
fCurrentCouple, fElectron, projectileKinEnergy, fTcutSecond);
G4int Z = elm->GetZasInt();
G4double energy = aDynPart->GetTotalEnergy() - gammaEnergy;
G4ThreeVector projectileMomentum =
fDirectModel->GetAngularDistribution()->SampleDirection(aDynPart, energy, Z,
fCurrentMaterial) * projectileP;
G4double phi = projectileMomentum.getPhi();
/*
//Angle of the gamma direction with the projectile taken from G4eBremsstrahlungModel
//------------------------------------------------
G4double u;
const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
if (9./(9.+d) > G4UniformRand()) u = - std::log(G4UniformRand()*G4UniformRand())/a1;
else u = - std::log(G4UniformRand()*G4UniformRand())/a2;
G4double theta = u*electron_mass_c2/projectileTotalEnergy;
G4double sint = std::sin(theta);
G4double cost = std::cos(theta);
G4double phi = twopi * G4UniformRand() ;
G4ThreeVector projectileMomentum;
projectileMomentum=G4ThreeVector(std::cos(phi)*sint,std::sin(phi)*sint,cost)*projectileP; //gamma frame
*/
if (IsScatProjToProjCase) {//the adjoint primary is the scattered e-
G4ThreeVector gammaMomentum = (projectileTotalEnergy-adjointPrimTotalEnergy)*G4ThreeVector(0.,0.,1.);
G4ThreeVector dirProd=projectileMomentum-gammaMomentum;
G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
G4double sint1 = std::sqrt(1.-cost1*cost1);
projectileMomentum=G4ThreeVector(std::cos(phi)*sint1,std::sin(phi)*sint1,cost1)*projectileP;
if(isScatProjToProj)
{ // the adjoint primary is the scattered e-
G4ThreeVector gammaMomentum =
(projectileTotalEnergy - adjointPrimTotalEnergy) *
G4ThreeVector(0., 0., 1.);
G4ThreeVector dirProd = projectileMomentum - gammaMomentum;
G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
G4double sint1 = std::sqrt(1. - cost1 * cost1);
projectileMomentum =
G4ThreeVector(std::cos(phi) * sint1, std::sin(phi) * sint1, cost1) *
projectileP;
}
projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointBremsstrahlungModel::DiffCrossSectionPerVolumePrimToSecond(const G4Material* aMaterial,
G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
G4double kinEnergyProd // kinetic energy of the secondary particle
)
{if (!isDirectModelInitialised) {
theEmModelManagerForFwdModels->Initialise(G4Electron::Electron(),G4Gamma::Gamma(),1.,0);
isDirectModelInitialised =true;
}
/*
return DiffCrossSectionPerVolumePrimToSecondApproximated2(aMaterial,
kinEnergyProj,
kinEnergyProd);
*/
return G4VEmAdjointModel::DiffCrossSectionPerVolumePrimToSecond(aMaterial,
kinEnergyProj,
kinEnergyProd);
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointBremsstrahlungModel::DiffCrossSectionPerVolumePrimToSecondApproximated1(
const G4Material* aMaterial,
G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
G4double kinEnergyProd // kinetic energy of the secondary particle
)
{
G4double dCrossEprod=0.;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(kinEnergyProd);
//In this approximation we consider that the secondary gammas are sampled with 1/Egamma energy distribution
//This is what is applied in the discrete standard model before the rejection test that make a correction
//The application of the same rejection function is not possible here.
//The differentiation of the CS over Ecut does not produce neither a good differential CS. That is due to the
// fact that in the discrete model the differential CS and the integrated CS are both fitted but separatly and
// therefore do not allow a correct numerical differentiation of the integrated CS to get the differential one.
// In the future we plan to use the brem secondary spectra from the G4Penelope implementation
if (kinEnergyProj>Emin_proj && kinEnergyProj<=Emax_proj){
G4double sigma=theDirectEMModel->CrossSectionPerVolume(aMaterial,theDirectPrimaryPartDef,kinEnergyProj,1.*keV);
dCrossEprod=sigma/kinEnergyProd/std::log(kinEnergyProj/keV);
}
return dCrossEprod;
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointBremsstrahlungModel::DiffCrossSectionPerVolumePrimToSecondApproximated2(
const G4Material* material,
G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
G4double kinEnergyProd // kinetic energy of the secondary particle
)
G4double G4AdjointBremsstrahlungModel::DiffCrossSectionPerVolumePrimToSecond(
const G4Material* aMaterial,
G4double kinEnergyProj, // kin energy of primary before interaction
G4double kinEnergyProd // kinetic energy of the secondary particle
)
{
//In this approximation we derive the direct cross section over Tcut=gamma energy, en after apply the Migdla correction factor
//used in the direct model
G4double dCrossEprod=0.;
const G4ElementVector* theElementVector = material->GetElementVector();
const double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
G4double dum=0.;
G4double E1=kinEnergyProd,E2=kinEnergyProd*1.001;
G4double dE=E2-E1;
for (size_t i=0; i<material->GetNumberOfElements(); i++) {
G4double C1=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,(*theElementVector)[i]->GetZ(),dum ,E1);
G4double C2=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,(*theElementVector)[i]->GetZ(),dum,E2);
dCrossEprod += theAtomNumDensityVector[i] * (C1-C2)/dE;
}
return dCrossEprod;
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointBremsstrahlungModel::AdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double primEnergy,
G4bool IsScatProjToProjCase)
{ if (!isDirectModelInitialised) {
theEmModelManagerForFwdModels->Initialise(G4Electron::Electron(),G4Gamma::Gamma(),1.,0);
isDirectModelInitialised =true;
if(!fIsDirectModelInitialised)
{
fEmModelManagerForFwdModels->Initialise(fElectron, fGamma, 1., 0);
fIsDirectModelInitialised = true;
}
if (UseMatrix) return G4VEmAdjointModel::AdjointCrossSection(aCouple,primEnergy,IsScatProjToProjCase);
return G4VEmAdjointModel::DiffCrossSectionPerVolumePrimToSecond(
aMaterial, kinEnergyProj, kinEnergyProd);
}
////////////////////////////////////////////////////////////////////////////////
G4double G4AdjointBremsstrahlungModel::AdjointCrossSection(
const G4MaterialCutsCouple* aCouple, G4double primEnergy,
G4bool isScatProjToProj)
{
static constexpr G4double maxEnergy = 100. * MeV / 2.718281828459045;
// 2.78.. == std::exp(1.)
if(!fIsDirectModelInitialised)
{
fEmModelManagerForFwdModels->Initialise(fElectron, fGamma, 1., 0);
fIsDirectModelInitialised = true;
}
if(fUseMatrix)
return G4VEmAdjointModel::AdjointCrossSection(aCouple, primEnergy,
isScatProjToProj);
DefineCurrentMaterial(aCouple);
G4double Cross=0.;
lastCZ=theDirectEMModel->CrossSectionPerVolume(aCouple->GetMaterial(),theDirectPrimaryPartDef,100.*MeV,100.*MeV/std::exp(1.));//this give the constant above
if (!IsScatProjToProjCase ){
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(primEnergy);
if (Emax_proj>Emin_proj && primEnergy > currentTcutForDirectSecond) Cross= CS_biasing_factor*lastCZ*std::log(Emax_proj/Emin_proj);
}
else {
G4double Emax_proj = GetSecondAdjEnergyMaxForScatProjToProjCase(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForScatProjToProjCase(primEnergy,currentTcutForDirectSecond);
if (Emax_proj>Emin_proj) Cross= lastCZ*std::log((Emax_proj-primEnergy)*Emin_proj/Emax_proj/(Emin_proj-primEnergy));
}
return Cross;
}
G4double Cross = 0.;
// this gives the constant above
fLastCZ = fDirectModel->CrossSectionPerVolume(
aCouple->GetMaterial(), fDirectPrimaryPart, 100. * MeV, maxEnergy);
G4double G4AdjointBremsstrahlungModel::GetAdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double primEnergy,
G4bool IsScatProjToProjCase)
{
return AdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
lastCZ=theDirectEMModel->CrossSectionPerVolume(aCouple->GetMaterial(),theDirectPrimaryPartDef,100.*MeV,100.*MeV/std::exp(1.));//this give the constant above
return G4VEmAdjointModel::GetAdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
if(!isScatProjToProj)
{
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(primEnergy);
if(Emax_proj > Emin_proj && primEnergy > fTcutSecond)
Cross = fCsBiasingFactor * fLastCZ * std::log(Emax_proj / Emin_proj);
}
else
{
G4double Emax_proj = GetSecondAdjEnergyMaxForScatProjToProj(primEnergy);
G4double Emin_proj =
GetSecondAdjEnergyMinForScatProjToProj(primEnergy, fTcutSecond);
if(Emax_proj > Emin_proj)
Cross = fLastCZ * std::log((Emax_proj - primEnergy) * Emin_proj /
Emax_proj / (Emin_proj - primEnergy));
}
return Cross;
}
File diff suppressed because it is too large Load Diff
@@ -23,177 +23,198 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointCSMatrix.hh"
#include "G4AdjointInterpolator.hh"
#include "G4SystemOfUnits.hh"
#include <iomanip>
#include <fstream>
#include "G4AdjointCSMatrix.hh"
#include "G4SystemOfUnits.hh"
#include "G4AdjointInterpolator.hh"
///////////////////////////////////////////////////////
G4AdjointCSMatrix::G4AdjointCSMatrix(G4bool aBool) { fScatProjToProj = aBool; }
///////////////////////////////////////////////////////
//
G4AdjointCSMatrix::G4AdjointCSMatrix(G4bool aBool){
theLogPrimEnergyVector.clear();
theLogCrossSectionVector.clear();
theLogSecondEnergyMatrix.clear();
theLogProbMatrix.clear();
theLogProbMatrixIndex.clear();
log0Vector.clear();
nb_of_PrimEnergy=0;
is_scat_proj_to_proj_case =aBool;
dlog =0;
G4AdjointCSMatrix::~G4AdjointCSMatrix()
{
fLogPrimEnergyVector.clear();
fLogCrossSectionVector.clear();
for (auto p : fLogSecondEnergyMatrix) {
p->clear();
delete p;
p = nullptr;
}
fLogSecondEnergyMatrix.clear();
for (auto p : fLogProbMatrix) {
p->clear();
delete p;
p = nullptr;
}
fLogProbMatrix.clear();
for (auto p : fLogProbMatrixIndex) {
if (p) {
p->clear();
delete p;
p = nullptr;
}
}
fLogProbMatrixIndex.clear();
}
///////////////////////////////////////////////////////
//
G4AdjointCSMatrix::~G4AdjointCSMatrix(){
theLogPrimEnergyVector.clear();
theLogCrossSectionVector.clear();
theLogSecondEnergyMatrix.clear();
theLogProbMatrix.clear();
}
///////////////////////////////////////////////////////
//
void G4AdjointCSMatrix::Clear()
{
theLogPrimEnergyVector.clear();
theLogCrossSectionVector.clear();
theLogSecondEnergyMatrix.clear();
theLogProbMatrix.clear();
theLogProbMatrixIndex.clear();
log0Vector.clear();
nb_of_PrimEnergy=0;
fLogPrimEnergyVector.clear();
fLogCrossSectionVector.clear();
fLogSecondEnergyMatrix.clear();
fLogProbMatrix.clear();
fLogProbMatrixIndex.clear();
fLog0Vector.clear();
fNbPrimEnergy = 0;
}
///////////////////////////////////////////////////////
//
void G4AdjointCSMatrix::AddData(G4double aLogPrimEnergy,G4double aLogCS, std::vector< double>* aLogSecondEnergyVector,
std::vector< double>* aLogProbVector,size_t n_pro_decade){
G4AdjointInterpolator* theInterpolator=G4AdjointInterpolator::GetInstance();
//At this time we consider that the energy is increasing monotically
theLogPrimEnergyVector.push_back(aLogPrimEnergy);
theLogCrossSectionVector.push_back(aLogCS);
theLogSecondEnergyMatrix.push_back(aLogSecondEnergyVector);
theLogProbMatrix.push_back(aLogProbVector);
std::vector< size_t>* aLogProbVectorIndex = 0;
dlog =0;
if (n_pro_decade > 0 && aLogProbVector->size()>0) {
aLogProbVectorIndex = new std::vector< size_t>();
dlog=std::log(10.)/n_pro_decade;
G4double log_val = int(std::min((*aLogProbVector)[0],aLogProbVector->back())/dlog)*dlog;
log0Vector.push_back(log_val);
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
while(log_val<0.) {
aLogProbVectorIndex->push_back(theInterpolator->FindPosition(log_val,(*aLogProbVector)));
log_val+=dlog;
}
}
else {
log0Vector.push_back(0.);
}
theLogProbMatrixIndex.push_back(aLogProbVectorIndex);
nb_of_PrimEnergy++;
void G4AdjointCSMatrix::AddData(G4double aLogPrimEnergy, G4double aLogCS,
std::vector<double>* aLogSecondEnergyVector,
std::vector<double>* aLogProbVector,
size_t n_pro_decade)
{
G4AdjointInterpolator* theInterpolator = G4AdjointInterpolator::GetInstance();
// At this time we consider that the energy is increasing monotically
fLogPrimEnergyVector.push_back(aLogPrimEnergy);
fLogCrossSectionVector.push_back(aLogCS);
fLogSecondEnergyMatrix.push_back(aLogSecondEnergyVector);
fLogProbMatrix.push_back(aLogProbVector);
std::vector<size_t>* aLogProbVectorIndex = nullptr;
if(n_pro_decade > 0 && !aLogProbVector->empty())
{
aLogProbVectorIndex = new std::vector<size_t>();
G4double dlog = std::log(10.) / n_pro_decade;
G4double log_val =
int(std::min((*aLogProbVector)[0], aLogProbVector->back()) / dlog) * dlog;
fLog0Vector.push_back(log_val);
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
while(log_val < 0.)
{
aLogProbVectorIndex->push_back(
theInterpolator->FindPosition(log_val, (*aLogProbVector)));
log_val += dlog;
}
}
else
{
fLog0Vector.push_back(0.);
}
fLogProbMatrixIndex.push_back(aLogProbVectorIndex);
++fNbPrimEnergy;
}
///////////////////////////////////////////////////////
//
G4bool G4AdjointCSMatrix::GetData(unsigned int i, G4double& aLogPrimEnergy,G4double& aLogCS,G4double& log0, std::vector< double>*& aLogSecondEnergyVector,
std::vector< double>*& aLogProbVector, std::vector< size_t>*& aLogProbVectorIndex)
{ if (i>= nb_of_PrimEnergy) return false;
//G4cout<<"Test Get Data "<<G4endl;
aLogPrimEnergy = theLogPrimEnergyVector[i];
aLogCS = theLogCrossSectionVector[i];
aLogSecondEnergyVector = theLogSecondEnergyMatrix[i];
aLogProbVector = theLogProbMatrix[i];
aLogProbVectorIndex = theLogProbMatrixIndex[i];
log0=log0Vector[i];
return true;
G4bool G4AdjointCSMatrix::GetData(unsigned int i, G4double& aLogPrimEnergy,
G4double& aLogCS, G4double& log0,
std::vector<double>*& aLogSecondEnergyVector,
std::vector<double>*& aLogProbVector,
std::vector<size_t>*& aLogProbVectorIndex)
{
if(i >= fNbPrimEnergy)
return false;
aLogPrimEnergy = fLogPrimEnergyVector[i];
aLogCS = fLogCrossSectionVector[i];
aLogSecondEnergyVector = fLogSecondEnergyMatrix[i];
aLogProbVector = fLogProbMatrix[i];
aLogProbVectorIndex = fLogProbMatrixIndex[i];
log0 = fLog0Vector[i];
return true;
}
///////////////////////////////////////////////////////
//
void G4AdjointCSMatrix::Write(G4String file_name)
{ std::fstream FileOutput(file_name, std::ios::out);
FileOutput<<std::setiosflags(std::ios::scientific);
FileOutput<<std::setprecision(6);
FileOutput<<theLogPrimEnergyVector.size()<<G4endl;
for (size_t i=0;i<theLogPrimEnergyVector.size();i++){
FileOutput<<std::exp(theLogPrimEnergyVector[i])/MeV<<'\t'<<std::exp(theLogCrossSectionVector[i])<<G4endl;
size_t j1=0;
FileOutput<<theLogSecondEnergyMatrix[i]->size()<<G4endl;
for (size_t j=0;j<theLogSecondEnergyMatrix[i]->size();j++){
FileOutput<<std::exp((*theLogSecondEnergyMatrix[i])[j]);
j1++;
if (j1<10) FileOutput<<'\t';
else {
FileOutput<<G4endl;
j1=0;
}
}
if (j1>0) FileOutput<<G4endl;
j1=0;
FileOutput<<theLogProbMatrix[i]->size()<<G4endl;
for (size_t j=0;j<theLogProbMatrix[i]->size();j++){
FileOutput<<std::exp((*theLogProbMatrix[i])[j]);
j1++;
if (j1<10) FileOutput<<'\t';
else {
FileOutput<<G4endl;
j1=0;
}
}
if (j1>0) FileOutput<<G4endl;
}
{
std::fstream FileOutput(file_name, std::ios::out);
FileOutput << std::setiosflags(std::ios::scientific);
FileOutput << std::setprecision(6);
FileOutput << fLogPrimEnergyVector.size() << G4endl;
for(size_t i = 0; i < fLogPrimEnergyVector.size(); ++i)
{
FileOutput << std::exp(fLogPrimEnergyVector[i]) / MeV << '\t'
<< std::exp(fLogCrossSectionVector[i]) << G4endl;
size_t j1 = 0;
FileOutput << fLogSecondEnergyMatrix[i]->size() << G4endl;
for(size_t j = 0; j < fLogSecondEnergyMatrix[i]->size(); ++j)
{
FileOutput << std::exp((*fLogSecondEnergyMatrix[i])[j]);
++j1;
if(j1 < 10)
FileOutput << '\t';
else
{
FileOutput << G4endl;
j1 = 0;
}
}
if(j1 > 0)
FileOutput << G4endl;
j1 = 0;
FileOutput << fLogProbMatrix[i]->size() << G4endl;
for(size_t j = 0; j < fLogProbMatrix[i]->size(); ++j)
{
FileOutput << std::exp((*fLogProbMatrix[i])[j]);
++j1;
if(j1 < 10)
FileOutput << '\t';
else
{
FileOutput << G4endl;
j1 = 0;
}
}
if(j1 > 0)
FileOutput << G4endl;
}
}
///////////////////////////////////////////////////////
//
void G4AdjointCSMatrix::Read(G4String file_name)
{ std::fstream FileOutput(file_name, std::ios::in);
size_t n1,n2;
theLogPrimEnergyVector.clear();
theLogCrossSectionVector.clear();
theLogSecondEnergyMatrix.clear();
theLogProbMatrix.clear();
FileOutput>>n1;
for (size_t i=0; i<n1;i++){
G4double E,CS;
FileOutput>>E>>CS;
theLogPrimEnergyVector.push_back(E);
theLogCrossSectionVector.push_back(CS);
FileOutput>>n2;
theLogSecondEnergyMatrix.push_back(new std::vector<G4double>());
theLogProbMatrix.push_back(new std::vector<G4double>());
for (size_t j=0; j<n2;j++){
G4double E1;
FileOutput>>E1;
theLogSecondEnergyMatrix[i]->push_back(E1);
}
FileOutput>>n2;
for (size_t j=0; j<n2;j++){
G4double prob;
FileOutput>>prob;
theLogProbMatrix[i]->push_back(prob);
}
}
{
std::fstream FileOutput(file_name, std::ios::in);
size_t n1, n2;
fLogPrimEnergyVector.clear();
fLogCrossSectionVector.clear();
fLogSecondEnergyMatrix.clear();
fLogProbMatrix.clear();
FileOutput >> n1;
for(size_t i = 0; i < n1; ++i)
{
G4double E, CS;
FileOutput >> E >> CS;
fLogPrimEnergyVector.push_back(E);
fLogCrossSectionVector.push_back(CS);
FileOutput >> n2;
fLogSecondEnergyMatrix.push_back(new std::vector<G4double>());
fLogProbMatrix.push_back(new std::vector<G4double>());
for(size_t j = 0; j < n2; ++j)
{
G4double E1;
FileOutput >> E1;
fLogSecondEnergyMatrix[i]->push_back(E1);
}
FileOutput >> n2;
for(size_t j = 0; j < n2; ++j)
{
G4double prob;
FileOutput >> prob;
fLogProbMatrix[i]->push_back(prob);
}
}
}
@@ -24,395 +24,339 @@
// ********************************************************************
//
//
#include "G4AdjointComptonModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointComptonModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4AdjointElectron.hh"
#include "G4AdjointGamma.hh"
#include "G4Gamma.hh"
#include "G4KleinNishinaCompton.hh"
#include "G4ParticleChange.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4TrackStatus.hh"
#include "G4VEmProcess.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointComptonModel::G4AdjointComptonModel():
G4VEmAdjointModel("AdjointCompton")
{ SetApplyCutInRange(false);
G4AdjointComptonModel::G4AdjointComptonModel()
: G4VEmAdjointModel("AdjointCompton")
{
SetApplyCutInRange(false);
SetUseMatrix(false);
SetUseMatrixPerElement(true);
SetUseOnlyOneMatrixForAllElements(true);
theAdjEquivOfDirectPrimPartDef =G4AdjointGamma::AdjointGamma();
theAdjEquivOfDirectSecondPartDef=G4AdjointElectron::AdjointElectron();
theDirectPrimaryPartDef=G4Gamma::Gamma();
second_part_of_same_type=false;
theDirectEMModel=new G4KleinNishinaCompton(G4Gamma::Gamma(),"ComptonDirectModel");
G4direct_CS = 0.;
fAdjEquivDirectPrimPart = G4AdjointGamma::AdjointGamma();
fAdjEquivDirectSecondPart = G4AdjointElectron::AdjointElectron();
fDirectPrimaryPart = G4Gamma::Gamma();
fSecondPartSameType = false;
fDirectModel =
new G4KleinNishinaCompton(G4Gamma::Gamma(), "ComptonDirectModel");
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointComptonModel::~G4AdjointComptonModel()
{;}
G4AdjointComptonModel::~G4AdjointComptonModel() {}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointComptonModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
if (!UseMatrix) return RapidSampleSecondaries(aTrack,IsScatProjToProjCase,fParticleChange);
//A recall of the compton scattering law is
//Egamma2=Egamma1/(1+(Egamma1/E0_electron)(1.-cos_th))
//Therefore Egamma2_max= Egamma2(cos_th=1) = Egamma1
//Therefore Egamma2_min= Egamma2(cos_th=-1) = Egamma1/(1+2.(Egamma1/E0_electron))
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
if(!fUseMatrix)
return RapidSampleSecondaries(aTrack, isScatProjToProj, fParticleChange);
// A recall of the compton scattering law:
// Egamma2=Egamma1/(1+(Egamma1/E0_electron)(1.-cos_th))
// Therefore Egamma2_max= Egamma2(cos_th=1) = Egamma1
// and Egamma2_min= Egamma2(cos_th=-1) =
// Egamma1/(1+2.(Egamma1/E0_electron))
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
//Sample secondary energy
//-----------------------
G4double gammaE1;
gammaE1 = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy,
IsScatProjToProjCase);
//gammaE2
//-----------
G4double gammaE2 = adjointPrimKinEnergy;
if (!IsScatProjToProjCase) gammaE2 = gammaE1 - adjointPrimKinEnergy;
//Cos th
//-------
// G4cout<<"Compton scattering "<<gammaE1<<'\t'<<gammaE2<<G4endl;
G4double cos_th = 1.+ electron_mass_c2*(1./gammaE1 -1./gammaE2);
if (!IsScatProjToProjCase) {
G4double p_elec=theAdjointPrimary->GetTotalMomentum();
cos_th = (gammaE1 - gammaE2*cos_th)/p_elec;
}
G4double sin_th = 0.;
if (std::abs(cos_th)>1){
//G4cout<<"Problem in compton scattering with cos_th "<<cos_th<<G4endl;
if (cos_th>0) {
cos_th=1.;
}
else cos_th=-1.;
sin_th=0.;
}
else sin_th = std::sqrt(1.-cos_th*cos_th);
//gamma0 momentum
//--------------------
// Sample secondary energy
G4double gammaE1;
gammaE1 =
SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, isScatProjToProj);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector gammaMomentum1 = gammaE1*G4ThreeVector(std::cos(phi)*sin_th,std::sin(phi)*sin_th,cos_th);
gammaMomentum1.rotateUz(dir_parallel);
// G4cout<<gamma0Energy<<'\t'<<gamma0Momentum<<G4endl;
//It is important to correct the weight of particles before adding the secondary
//------------------------------------------------------------------------------
CorrectPostStepWeight(fParticleChange,
aTrack.GetWeight(),
adjointPrimKinEnergy,
gammaE1,
IsScatProjToProjCase);
if (!IsScatProjToProjCase){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,gammaMomentum1));
//G4cout<<"gamma0Momentum "<<gamma0Momentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(gammaE1);
fParticleChange->ProposeMomentumDirection(gammaMomentum1.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointComptonModel::RapidSampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
// gammaE2
G4double gammaE2 = adjointPrimKinEnergy;
if(!isScatProjToProj)
gammaE2 = gammaE1 - adjointPrimKinEnergy;
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
G4double diffCSUsed=0.1*currentMaterial->GetElectronDensity()*twopi_mc2_rcl2;
G4double gammaE1=0.;
G4double gammaE2=0.;
if (!IsScatProjToProjCase){
G4double Emax = GetSecondAdjEnergyMaxForProdToProjCase(adjointPrimKinEnergy);
G4double Emin= GetSecondAdjEnergyMinForProdToProjCase(adjointPrimKinEnergy);;
if (Emin>=Emax) return;
G4double f1=(Emin-adjointPrimKinEnergy)/Emin;
G4double f2=(Emax-adjointPrimKinEnergy)/Emax/f1;
gammaE1=adjointPrimKinEnergy/(1.-f1*std::pow(f2,G4UniformRand()));;
gammaE2=gammaE1-adjointPrimKinEnergy;
diffCSUsed= diffCSUsed*(1.+2.*std::log(1.+electron_mass_c2/adjointPrimKinEnergy))*adjointPrimKinEnergy/gammaE1/gammaE2;
}
else { G4double Emax = GetSecondAdjEnergyMaxForScatProjToProjCase(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForScatProjToProjCase(adjointPrimKinEnergy,currentTcutForDirectSecond);
if (Emin>=Emax) return;
gammaE2 =adjointPrimKinEnergy;
gammaE1=Emin*std::pow(Emax/Emin,G4UniformRand());
diffCSUsed= diffCSUsed/gammaE1;
}
//Weight correction
//-----------------------
//First w_corr is set to the ratio between adjoint total CS and fwd total CS
G4double w_corr=additional_weight_correction_factor_for_post_step_outside_model;
if (correct_weight_for_post_step_in_model) {
w_corr=G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
// Cos th
G4double cos_th = 1. + electron_mass_c2 * (1. / gammaE1 - 1. / gammaE2);
if(!isScatProjToProj)
{
cos_th =
(gammaE1 - gammaE2 * cos_th) / theAdjointPrimary->GetTotalMomentum();
}
//Then another correction is needed due to the fact that a biaised differential CS has been used rather than the
//one consistent with the direct model
G4double diffCS = DiffCrossSectionPerAtomPrimToScatPrim(gammaE1, gammaE2,1,0.);
if (diffCS >0) diffCS /=G4direct_CS; // here we have the normalised diffCS
//An we remultiply by the lambda of the forward process
diffCS*=theDirectEMProcess->GetLambda(gammaE1,currentCouple);
//diffCS*=theDirectEMModel->CrossSectionPerVolume(currentMaterial,G4Gamma::Gamma(),gammaE1,0.,2.*gammaE1);
//G4cout<<"diffCS/diffCSUsed "<<diffCS/diffCSUsed<<'\t'<<gammaE1<<'\t'<<gammaE2<<G4endl;
w_corr*=diffCS/diffCSUsed;
G4double new_weight = aTrack.GetWeight()*w_corr;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
//Cos th
//-------
G4double sin_th = 0.;
if(std::abs(cos_th) > 1.)
{
if(cos_th > 0.)
{
cos_th = 1.;
}
else
cos_th = -1.;
sin_th = 0.;
}
else
sin_th = std::sqrt(1. - cos_th * cos_th);
G4double cos_th = 1.+ electron_mass_c2*(1./gammaE1 -1./gammaE2);
if (!IsScatProjToProjCase) {
G4double p_elec=theAdjointPrimary->GetTotalMomentum();
cos_th = (gammaE1 - gammaE2*cos_th)/p_elec;
}
G4double sin_th = 0.;
if (std::abs(cos_th)>1){
//G4cout<<"Problem in compton scattering with cos_th "<<cos_th<<G4endl;
if (cos_th>0) {
cos_th=1.;
}
else cos_th=-1.;
sin_th=0.;
}
else sin_th = std::sqrt(1.-cos_th*cos_th);
// gamma0 momentum
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector gammaMomentum1 =
gammaE1 *
G4ThreeVector(std::cos(phi) * sin_th, std::sin(phi) * sin_th, cos_th);
gammaMomentum1.rotateUz(dir_parallel);
//gamma0 momentum
//--------------------
// correct the weight of particles before adding the secondary
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
adjointPrimKinEnergy, gammaE1, isScatProjToProj);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector gammaMomentum1 = gammaE1*G4ThreeVector(std::cos(phi)*sin_th,std::sin(phi)*sin_th,cos_th);
gammaMomentum1.rotateUz(dir_parallel);
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, gammaMomentum1));
}
else
{
fParticleChange->ProposeEnergy(gammaE1);
fParticleChange->ProposeMomentumDirection(gammaMomentum1.unit());
}
}
if (!IsScatProjToProjCase){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,gammaMomentum1));
//G4cout<<"gamma0Momentum "<<gamma0Momentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(gammaE1);
fParticleChange->ProposeMomentumDirection(gammaMomentum1.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
//The implementation here is correct for energy loss process, for the photoelectric and compton scattering the method should be redefine
void G4AdjointComptonModel::RapidSampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
G4double diffCSUsed =
0.1 * fCurrentMaterial->GetElectronDensity() * twopi_mc2_rcl2;
G4double gammaE1 = 0.;
G4double gammaE2 = 0.;
if(!isScatProjToProj)
{
G4double Emax = GetSecondAdjEnergyMaxForProdToProj(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForProdToProj(adjointPrimKinEnergy);
if(Emin >= Emax)
return;
G4double f1 = (Emin - adjointPrimKinEnergy) / Emin;
G4double f2 = (Emax - adjointPrimKinEnergy) / Emax / f1;
gammaE1 = adjointPrimKinEnergy / (1. - f1 * std::pow(f2, G4UniformRand()));
gammaE2 = gammaE1 - adjointPrimKinEnergy;
diffCSUsed =
diffCSUsed *
(1. + 2. * std::log(1. + electron_mass_c2 / adjointPrimKinEnergy)) *
adjointPrimKinEnergy / gammaE1 / gammaE2;
}
else
{
G4double Emax =
GetSecondAdjEnergyMaxForScatProjToProj(adjointPrimKinEnergy);
G4double Emin =
GetSecondAdjEnergyMinForScatProjToProj(adjointPrimKinEnergy, fTcutSecond);
if(Emin >= Emax)
return;
gammaE2 = adjointPrimKinEnergy;
gammaE1 = Emin * std::pow(Emax / Emin, G4UniformRand());
diffCSUsed = diffCSUsed / gammaE1;
}
// Weight correction
// First w_corr is set to the ratio between adjoint total CS and fwd total CS
G4double w_corr = fOutsideWeightFactor;
if(fInModelWeightCorr)
{
w_corr =
G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
}
// Then another correction is needed because a biased differential CS has
// been used rather than the one consistent with the direct model
G4double diffCS =
DiffCrossSectionPerAtomPrimToScatPrim(gammaE1, gammaE2, 1, 0.);
if(diffCS > 0.)
diffCS /= fDirectCS; // here we have the normalised diffCS
// And we remultiply by the lambda of the forward process
diffCS *= fDirectProcess->GetLambda(gammaE1, fCurrentCouple);
w_corr *= diffCS / diffCSUsed;
G4double new_weight = aTrack.GetWeight() * w_corr;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
G4double cos_th = 1. + electron_mass_c2 * (1. / gammaE1 - 1. / gammaE2);
if(!isScatProjToProj)
{
G4double p_elec = theAdjointPrimary->GetTotalMomentum();
cos_th = (gammaE1 - gammaE2 * cos_th) / p_elec;
}
G4double sin_th = 0.;
if(std::abs(cos_th) > 1.)
{
if(cos_th > 0.)
{
cos_th = 1.;
}
else
cos_th = -1.;
}
else
sin_th = std::sqrt(1. - cos_th * cos_th);
// gamma0 momentum
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector gammaMomentum1 =
gammaE1 *
G4ThreeVector(std::cos(phi) * sin_th, std::sin(phi) * sin_th, cos_th);
gammaMomentum1.rotateUz(dir_parallel);
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, gammaMomentum1));
}
else
{
fParticleChange->ProposeEnergy(gammaE1);
fParticleChange->ProposeMomentumDirection(gammaMomentum1.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
// The implementation here is correct for energy loss process, for the
// photoelectric and compton scattering the method should be redefined
G4double G4AdjointComptonModel::DiffCrossSectionPerAtomPrimToSecond(
G4double gamEnergy0,
G4double kinEnergyElec,
G4double Z,
G4double A)
{
G4double gamEnergy1 = gamEnergy0 - kinEnergyElec;
G4double dSigmadEprod=0.;
if (gamEnergy1>0.) dSigmadEprod=DiffCrossSectionPerAtomPrimToScatPrim(gamEnergy0,gamEnergy1,Z,A);
return dSigmadEprod;
G4double gamEnergy0, G4double kinEnergyElec, G4double Z, G4double A)
{
G4double gamEnergy1 = gamEnergy0 - kinEnergyElec;
G4double dSigmadEprod = 0.;
if(gamEnergy1 > 0.)
dSigmadEprod =
DiffCrossSectionPerAtomPrimToScatPrim(gamEnergy0, gamEnergy1, Z, A);
return dSigmadEprod;
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointComptonModel::DiffCrossSectionPerAtomPrimToScatPrim(
G4double gamEnergy0,
G4double gamEnergy1,
G4double Z,
G4double )
{ //Based on Klein Nishina formula
// In the forward case (see G4KleinNishinaCompton) the cross section is parametrised
// but the secondaries are sampled from the
// Klein Nishida differential cross section
// The used diffrential cross section here is therefore the cross section multiplied by the normalised
//differential Klein Nishida cross section
//Klein Nishida Cross Section
//-----------------------------
G4double epsilon = gamEnergy0 / electron_mass_c2 ;
G4double one_plus_two_epsi =1.+2.*epsilon;
G4double gamEnergy1_max = gamEnergy0;
G4double gamEnergy1_min = gamEnergy0/one_plus_two_epsi;
if (gamEnergy1 >gamEnergy1_max || gamEnergy1<gamEnergy1_min) {
/*G4cout<<"the differential CS is null"<<G4endl;
G4cout<<gamEnergy0<<G4endl;
G4cout<<gamEnergy1<<G4endl;
G4cout<<gamEnergy1_min<<G4endl;*/
return 0.;
}
G4double epsi2 = epsilon *epsilon ;
G4double one_plus_two_epsi_2=one_plus_two_epsi*one_plus_two_epsi;
G4double CS=std::log(one_plus_two_epsi)*(1.- 2.*(1.+epsilon)/epsi2);
CS+=4./epsilon +0.5*(1.-1./one_plus_two_epsi_2);
CS/=epsilon;
//Note that the pi*re2*Z factor is neglected because it is suppresed when computing dCS_dE1/CS;
// in the differential cross section
//Klein Nishida Differential Cross Section
//-----------------------------------------
G4double epsilon1 = gamEnergy1 / electron_mass_c2 ;
G4double v= epsilon1/epsilon;
G4double term1 =1.+ 1./epsilon -1/epsilon1;
G4double dCS_dE1= 1./v +v + term1*term1 -1.;
dCS_dE1 *=1./epsilon/gamEnergy0;
//Normalised to the CS used in G4
//-------------------------------
G4direct_CS = theDirectEMModel->ComputeCrossSectionPerAtom(G4Gamma::Gamma(),
gamEnergy0,
Z, 0., 0.,0.);
dCS_dE1 *= G4direct_CS/CS;
/* G4cout<<"the differential CS is not null"<<G4endl;
G4cout<<gamEnergy0<<G4endl;
G4cout<<gamEnergy1<<G4endl;*/
return dCS_dE1;
G4double gamEnergy0, G4double gamEnergy1, G4double Z, G4double)
{
// Based on Klein Nishina formula
// In the forward case (see G4KleinNishinaCompton) the cross section is
// parametrised but the secondaries are sampled from the Klein Nishina
// differential cross section. The differential cross section used here
// is therefore the cross section multiplied by the normalised
// differential Klein Nishina cross section
// Klein Nishina Cross Section
G4double epsilon = gamEnergy0 / electron_mass_c2;
G4double one_plus_two_epsi = 1. + 2. * epsilon;
if(gamEnergy1 > gamEnergy0 || gamEnergy1 < gamEnergy0 / one_plus_two_epsi)
{
return 0.;
}
G4double CS = std::log(one_plus_two_epsi) *
(1. - 2. * (1. + epsilon) / (epsilon * epsilon));
CS +=
4. / epsilon + 0.5 * (1. - 1. / (one_plus_two_epsi * one_plus_two_epsi));
CS /= epsilon;
// Note that the pi*re2*Z factor is neglected because it is suppressed when
// computing dCS_dE1/CS in the differential cross section
// Klein Nishina Differential Cross Section
G4double epsilon1 = gamEnergy1 / electron_mass_c2;
G4double v = epsilon1 / epsilon;
G4double term1 = 1. + 1. / epsilon - 1. / epsilon1;
G4double dCS_dE1 = 1. / v + v + term1 * term1 - 1.;
dCS_dE1 *= 1. / epsilon / gamEnergy0;
// Normalised to the CS used in G4
fDirectCS = fDirectModel->ComputeCrossSectionPerAtom(
G4Gamma::Gamma(), gamEnergy0, Z, 0., 0., 0.);
dCS_dE1 *= fDirectCS / CS;
return dCS_dE1;
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointComptonModel::GetSecondAdjEnergyMaxForScatProjToProjCase(G4double PrimAdjEnergy)
{ G4double inv_e_max = 1./PrimAdjEnergy - 2./electron_mass_c2;
G4double e_max = HighEnergyLimit;
if (inv_e_max > 0. ) e_max=std::min(1./inv_e_max,HighEnergyLimit);
return e_max;
G4double G4AdjointComptonModel::GetSecondAdjEnergyMaxForScatProjToProj(
G4double primAdjEnergy)
{
G4double inv_e_max = 1. / primAdjEnergy - 2. / electron_mass_c2;
G4double e_max = GetHighEnergyLimit();
if(inv_e_max > 0.)
e_max = std::min(1. / inv_e_max, e_max);
return e_max;
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointComptonModel::GetSecondAdjEnergyMinForProdToProjCase(G4double PrimAdjEnergy)
{ G4double half_e=PrimAdjEnergy/2.;
G4double term=std::sqrt(half_e*(electron_mass_c2+half_e));
G4double emin=half_e+term;
return emin;
G4double G4AdjointComptonModel::GetSecondAdjEnergyMinForProdToProj(
G4double primAdjEnergy)
{
G4double half_e = primAdjEnergy / 2.;
return half_e + std::sqrt(half_e * (electron_mass_c2 + half_e));
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointComptonModel::AdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double primEnergy,
G4bool IsScatProjToProjCase)
{
if (UseMatrix) return G4VEmAdjointModel::AdjointCrossSection(aCouple,primEnergy,IsScatProjToProjCase);
G4double G4AdjointComptonModel::AdjointCrossSection(
const G4MaterialCutsCouple* aCouple, G4double primEnergy,
G4bool isScatProjToProj)
{
if(fUseMatrix)
return G4VEmAdjointModel::AdjointCrossSection(aCouple, primEnergy,
isScatProjToProj);
DefineCurrentMaterial(aCouple);
float Cross=0.;
float Emax_proj =0.;
float Emin_proj =0.;
if (!IsScatProjToProjCase ){
Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(primEnergy);
Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(primEnergy);
if (Emax_proj>Emin_proj ){
Cross= 0.1*std::log((Emax_proj-float (primEnergy))*Emin_proj/Emax_proj/(Emin_proj-primEnergy))
*(1.+2.*std::log(float(1.+electron_mass_c2/primEnergy)));
}
G4float Cross = 0.;
G4float Emax_proj = 0.;
G4float Emin_proj = 0.;
if(!isScatProjToProj)
{
Emax_proj = GetSecondAdjEnergyMaxForProdToProj(primEnergy);
Emin_proj = GetSecondAdjEnergyMinForProdToProj(primEnergy);
if(Emax_proj > Emin_proj)
{
Cross = 0.1 *
std::log((Emax_proj - G4float(primEnergy)) * Emin_proj /
Emax_proj / (Emin_proj - primEnergy)) *
(1. + 2. * std::log(G4float(1. + electron_mass_c2 / primEnergy)));
}
}
else {
Emax_proj = GetSecondAdjEnergyMaxForScatProjToProjCase(primEnergy);
Emin_proj = GetSecondAdjEnergyMinForScatProjToProjCase(primEnergy,0.);
if (Emax_proj>Emin_proj) {
Cross = 0.1*std::log(Emax_proj/Emin_proj);
//+0.5*primEnergy*primEnergy(1./(Emin_proj*Emin_proj) - 1./(Emax_proj*Emax_proj)); neglected at the moment
}
else
{
Emax_proj = GetSecondAdjEnergyMaxForScatProjToProj(primEnergy);
Emin_proj = GetSecondAdjEnergyMinForScatProjToProj(primEnergy, 0.);
if(Emax_proj > Emin_proj)
{
Cross = 0.1 * std::log(Emax_proj / Emin_proj);
}
}
Cross*=currentMaterial->GetElectronDensity()*twopi_mc2_rcl2;
lastCS=Cross;
return double(Cross);
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointComptonModel::GetAdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double primEnergy,
G4bool IsScatProjToProjCase)
{ return AdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
//return G4VEmAdjointModel::GetAdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
Cross *= fCurrentMaterial->GetElectronDensity() * twopi_mc2_rcl2;
fLastCS = Cross;
return double(Cross);
}
@@ -23,264 +23,271 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointForcedInteractionForGamma.hh"
#include "G4SystemOfUnits.hh"
#include "G4AdjointCSManager.hh"
#include "G4AdjointCSMatrix.hh"
#include "G4VEmAdjointModel.hh"
#include "G4AdjointGamma.hh"
#include "G4MaterialCutsCouple.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointGamma.hh"
#include "G4SystemOfUnits.hh"
#include "G4VEmAdjointModel.hh"
G4AdjointForcedInteractionForGamma::
G4AdjointForcedInteractionForGamma(G4String process_name):
G4VContinuousDiscreteProcess(process_name),theAdjointComptonModel(0),theAdjointBremModel(0)
{ theAdjointCSManager = G4AdjointCSManager::GetAdjointCSManager();
fParticleChange=new G4ParticleChange();
lastAdjCS=0.;
trackid = nstep = 0;
is_free_flight_gamma = false;
copy_gamma_for_forced_interaction = false;
last_free_flight_trackid=1000;
theAdjointComptonModel =0;
theAdjointBremModel=0;
acc_track_length=0.;
acc_nb_adj_interaction_length=0.;
acc_nb_fwd_interaction_length=0.;
total_acc_nb_adj_interaction_length=0.;
total_acc_nb_fwd_interaction_length=0.;
continue_gamma_as_new_free_flight =false;
}
//////////////////////////////////////////////////////////////////////////////
//
G4AdjointForcedInteractionForGamma::
~G4AdjointForcedInteractionForGamma()
{ if (fParticleChange) delete fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
void G4AdjointForcedInteractionForGamma::PreparePhysicsTable(const G4ParticleDefinition&)
{;
}
//////////////////////////////////////////////////////////////////////////////
//
void G4AdjointForcedInteractionForGamma::BuildPhysicsTable(const G4ParticleDefinition&)
G4AdjointForcedInteractionForGamma::G4AdjointForcedInteractionForGamma(
G4String process_name)
: G4VContinuousDiscreteProcess(process_name)
, fAdjointComptonModel(nullptr)
, fAdjointBremModel(nullptr)
{
theAdjointCSManager->BuildCrossSectionMatrices(); //do not worry it will be done just once
theAdjointCSManager->BuildTotalSigmaTables();
fCSManager = G4AdjointCSManager::GetAdjointCSManager();
fParticleChange = new G4ParticleChange();
}
//Note on weight correction for forced interaction
//For the forced interaction applied here we do use a truncated exponential law for the probability of survival
//over a fixed total length. This is done by using a linear transformation of the non biased probability survival
//In mathematic this writes
//P'(x)=C1P(x)+C2
//With P(x)=exp(-sum(sigma_ixi)) x and L can cross different volumes with different cross section sigma.
//For forced interaction we get the following limit conditions
//P'(L)=0 P'(0)=1 (L can be used over different volumes)
//From simple solving of linear equation we get
//C1=1/(1-P(L)) et C2=-P(L)/(1-P(L))
//P'(x)=(P(x)-P(L))/(1-P(L))
//For the probability over a step x1 to x2
//P'(x1->x2)=P'(x2)/P'(x1)
//The effective cross section is defined -d(P'(x))/dx/P'(x)
//We get therefore
//sigma_eff=C1sigmaP(x)/(C1P(x)+C2)=sigmaP(x)/(P(x)+C2/C1)=sigmaP(x)/(P(x)-P(L))=sigma/(1-P(L)/P(x))
//////////////////////////////////////////////////////////////////////////////
//
G4VParticleChange* G4AdjointForcedInteractionForGamma::PostStepDoIt(const G4Track& track, const G4Step& )
{ fParticleChange->Initialize(track);
//For the free flight gamma no interaction occur but a gamma with same property is
//produces for further forced interaction
//It is done at the very beginning of the track such that the weight can be the same
if (copy_gamma_for_forced_interaction) {
G4ThreeVector theGammaMomentum = track.GetMomentum();
fParticleChange->AddSecondary(new G4DynamicParticle(G4AdjointGamma::AdjointGamma(),theGammaMomentum));
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
G4AdjointForcedInteractionForGamma::~G4AdjointForcedInteractionForGamma()
{
if(fParticleChange)
delete fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
void G4AdjointForcedInteractionForGamma::ProcessDescription(
std::ostream& out) const
{
out << "Forced interaction for gamma.\n";
}
//////////////////////////////////////////////////////////////////////////////
void G4AdjointForcedInteractionForGamma::BuildPhysicsTable(
const G4ParticleDefinition&)
{
fCSManager->BuildCrossSectionMatrices(); // it will be done just once
fCSManager->BuildTotalSigmaTables();
}
// Note on weight correction for forced interaction.
// For the forced interaction applied here we use a truncated exponential law
// for the probability of survival over a fixed total length. This is done by
// using a linear transformation of the non-biased probability survival. In
// math this is written P'(x)=C1P(x)+C2 , with P(x)=exp(-sum(sigma_ixi)) . x and
// L can cross different volumes with different cross section sigma. For forced
// interaction, we get the limit conditions:
// P'(L)=0 and P'(0)=1 (L can be used over different volumes)
// From simple solving of linear equations we
// get C1=1/(1-P(L)) and C2=-P(L)/(1-P(L))
// P'(x)=(P(x)-P(L))/(1-P(L))
// For the probability over a step x1 to x2, P'(x1->x2)=P'(x2)/P'(x1).
// The effective cross
// section is defined -d(P'(x))/dx/P'(x).
// We get therefore
// sigma_eff = C1sigmaP(x)/(C1P(x)+C2) = sigmaP(x)/(P(x)+C2/C1)
// = sigmaP(x)/(P(x)-P(L)) = sigma/(1-P(L)/P(x))
//////////////////////////////////////////////////////////////////////////////
G4VParticleChange* G4AdjointForcedInteractionForGamma::PostStepDoIt(
const G4Track& track, const G4Step&)
{
fParticleChange->Initialize(track);
// For the free flight gamma no interaction occurs but a gamma with same
// properties is produced for further forced interaction. It is done at the
// very beginning of the track so that the weight can be the same
if(fCopyGammaForForced)
{
G4ThreeVector theGammaMomentum = track.GetMomentum();
fParticleChange->AddSecondary(
new G4DynamicParticle(G4AdjointGamma::AdjointGamma(), theGammaMomentum));
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
}
else { //Occurrence of forced interaction
else
{ // Occurrence of forced interaction
// Selection of the model to be called
G4VEmAdjointModel* theSelectedModel = nullptr;
G4bool is_scat_proj_to_proj_case = false;
if(!fAdjointComptonModel && !fAdjointBremModel)
return fParticleChange;
if(!fAdjointComptonModel)
{
theSelectedModel = fAdjointBremModel;
is_scat_proj_to_proj_case = false;
// This is needed because the results of it will be used in the post step
// do it weight correction inside the model
fAdjointBremModel->AdjointCrossSection(track.GetMaterialCutsCouple(),
track.GetKineticEnergy(), false);
}
else if(!fAdjointBremModel)
{
theSelectedModel = fAdjointComptonModel;
is_scat_proj_to_proj_case = true;
}
else
{ // Choose the model according to cross sections
G4double bremAdjCS = fAdjointBremModel->AdjointCrossSection(
track.GetMaterialCutsCouple(), track.GetKineticEnergy(), false);
if(G4UniformRand() * fLastAdjCS < bremAdjCS)
{
theSelectedModel = fAdjointBremModel;
is_scat_proj_to_proj_case = false;
}
else
{
theSelectedModel = fAdjointComptonModel;
is_scat_proj_to_proj_case = true;
}
}
//Selection of the model to be called
G4VEmAdjointModel* theSelectedModel =0;
G4bool is_scat_proj_to_proj_case=false;
if (!theAdjointComptonModel && !theAdjointBremModel) return fParticleChange;
if (!theAdjointComptonModel) {
theSelectedModel = theAdjointBremModel;
is_scat_proj_to_proj_case=false;
//This is needed because the results of it will be used in the post step do it weight correction inside the model
theAdjointBremModel->AdjointCrossSection(
track.GetMaterialCutsCouple(),track.GetKineticEnergy(), false);
// Compute the weight correction factor
G4double invEffectiveAdjointCS =
(1. - std::exp(fNbAdjIntLength - fTotNbAdjIntLength)) / fLastAdjCS;
}
else if (!theAdjointBremModel) {
theSelectedModel = theAdjointComptonModel;
is_scat_proj_to_proj_case=true;
}
else { //Choose the model according to cross sections
// Call the selected model without correction of the weight in the model
theSelectedModel->SetCorrectWeightForPostStepInModel(false);
theSelectedModel
->SetAdditionalWeightCorrectionFactorForPostStepOutsideModel(
fLastAdjCS * invEffectiveAdjointCS);
theSelectedModel->SampleSecondaries(track, is_scat_proj_to_proj_case,
fParticleChange);
theSelectedModel->SetCorrectWeightForPostStepInModel(true);
G4double bremAdjCS = theAdjointBremModel->AdjointCrossSection(
track.GetMaterialCutsCouple(),track.GetKineticEnergy(), false);
if (G4UniformRand()*lastAdjCS<bremAdjCS) {
theSelectedModel = theAdjointBremModel;
is_scat_proj_to_proj_case=false;
}
else {
theSelectedModel = theAdjointComptonModel;
is_scat_proj_to_proj_case=true;
}
}
//Compute the weight correction factor
G4double one_over_effectiveAdjointCS= (1.-std::exp(acc_nb_adj_interaction_length-total_acc_nb_adj_interaction_length))/lastAdjCS;
G4double weight_correction_factor = lastAdjCS*one_over_effectiveAdjointCS;
//G4cout<<"Weight correction factor start "<<weight_correction_factor<<std::endl;
//Call the selected model without correction of the weight in the model
theSelectedModel->SetCorrectWeightForPostStepInModel(false);
theSelectedModel->SetAdditionalWeightCorrectionFactorForPostStepOutsideModel(weight_correction_factor);
theSelectedModel->SampleSecondaries(track,is_scat_proj_to_proj_case,fParticleChange);
theSelectedModel->SetCorrectWeightForPostStepInModel(true);
continue_gamma_as_new_free_flight =true;
fContinueGammaAsNewFreeFlight = true;
}
return fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
G4VParticleChange* G4AdjointForcedInteractionForGamma::AlongStepDoIt(const G4Track& track, const G4Step& )
{ fParticleChange->Initialize(track);
//Compute nb of interactions length over step length
G4VParticleChange* G4AdjointForcedInteractionForGamma::AlongStepDoIt(
const G4Track& track, const G4Step&)
{
fParticleChange->Initialize(track);
// Compute nb of interactions length over step length
G4ThreeVector position = track.GetPosition();
G4double stepLength = track.GetStep()->GetStepLength();
G4double ekin = track.GetKineticEnergy();
G4double nb_fwd_interaction_length_over_step=0.;
G4double nb_adj_interaction_length_over_step=0.;
lastAdjCS = G4AdjointCSManager::GetAdjointCSManager()->GetTotalAdjointCS(track.GetDefinition(), ekin, track.GetMaterialCutsCouple());
lastFwdCS = G4AdjointCSManager::GetAdjointCSManager()->GetTotalForwardCS(G4AdjointGamma::AdjointGamma(),
ekin,track.GetMaterialCutsCouple());
nb_fwd_interaction_length_over_step = stepLength*lastFwdCS;
nb_adj_interaction_length_over_step = stepLength*lastAdjCS;
G4double fwd_survival_probability=std::exp(-nb_fwd_interaction_length_over_step);
G4double mc_induced_survival_probability=1.;
G4double stepLength = track.GetStep()->GetStepLength();
G4double ekin = track.GetKineticEnergy();
fLastAdjCS = fCSManager->GetTotalAdjointCS(track.GetDefinition(), ekin,
track.GetMaterialCutsCouple());
G4double nb_fwd_interaction_length_over_step =
stepLength * fCSManager->GetTotalForwardCS(G4AdjointGamma::AdjointGamma(),
ekin,
track.GetMaterialCutsCouple());
if (is_free_flight_gamma) { //for free_flight survival probability stays 1
//Accumulate the number of interaction lengths during free flight of gamma
total_acc_nb_fwd_interaction_length+=nb_fwd_interaction_length_over_step;
total_acc_nb_adj_interaction_length+=nb_adj_interaction_length_over_step;
acc_track_length+=stepLength;
G4double nb_adj_interaction_length_over_step = stepLength * fLastAdjCS;
G4double fwd_survival_probability =
std::exp(-nb_fwd_interaction_length_over_step);
G4double mc_induced_survival_probability = 1.;
if(fFreeFlightGamma)
{ // for free_flight survival probability stays 1
// Accumulate the number of interaction lengths during free flight of gamma
fTotNbAdjIntLength += nb_adj_interaction_length_over_step;
fAccTrackLength += stepLength;
}
else {
G4double previous_acc_nb_adj_interaction_length =acc_nb_adj_interaction_length;
acc_nb_fwd_interaction_length+=nb_fwd_interaction_length_over_step;
acc_nb_adj_interaction_length+=nb_adj_interaction_length_over_step;
theNumberOfInteractionLengthLeft-=nb_adj_interaction_length_over_step;
else
{
G4double previous_acc_nb_adj_interaction_length = fNbAdjIntLength;
fNbAdjIntLength += nb_adj_interaction_length_over_step;
theNumberOfInteractionLengthLeft -= nb_adj_interaction_length_over_step;
//Following condition to remove very rare FPE issue
//if (total_acc_nb_adj_interaction_length <= 1.e-50 && theNumberOfInteractionLengthLeft<=1.e-50) { //condition added to avoid FPE issue
// VI 06.11.2017 - new condition
if (std::abs(total_acc_nb_adj_interaction_length - previous_acc_nb_adj_interaction_length) <= 1.e-15) {
mc_induced_survival_probability = 1.e50;
/*
G4cout << "FPE protection: " << total_acc_nb_adj_interaction_length << " "
<< previous_acc_nb_adj_interaction_length << " "
<< acc_nb_fwd_interaction_length << " "
<< acc_nb_adj_interaction_length << " "
<< theNumberOfInteractionLengthLeft
<< G4endl;
*/
}
else {
mc_induced_survival_probability= std::exp(-acc_nb_adj_interaction_length)-std::exp(-total_acc_nb_adj_interaction_length);
mc_induced_survival_probability=mc_induced_survival_probability/(std::exp(-previous_acc_nb_adj_interaction_length)-std::exp(-total_acc_nb_adj_interaction_length));
}
// protection against rare race condition
if(std::abs(fTotNbAdjIntLength - previous_acc_nb_adj_interaction_length) <=
1.e-15)
{
mc_induced_survival_probability = 1.e50;
}
else
{
mc_induced_survival_probability =
std::exp(-fNbAdjIntLength) - std::exp(-fTotNbAdjIntLength);
mc_induced_survival_probability /=
(std::exp(-previous_acc_nb_adj_interaction_length) -
std::exp(-fTotNbAdjIntLength));
}
}
G4double weight_correction = fwd_survival_probability/mc_induced_survival_probability;
G4double weight_correction =
fwd_survival_probability / mc_induced_survival_probability;
//weight_correction = 1.;
//Caution!!!
// It is important to select the weight of the post_step_point
// as the current weight and not the weight of the track, as t
// the weight of the track is changed after having applied all
// the along_step_do_it.
G4double new_weight=weight_correction*track.GetStep()->GetPostStepPoint()->GetWeight();
/*
G4cout<<"New weight "<<new_weight<<std::endl;
G4cout<<"Weight correction "<<weight_correction<<std::endl;
*/
// Caution!!!
// It is important to select the weight of the post_step_point as the
// current weight and not the weight of the track, as the weight of the track
// is changed after having applied all the along_step_do_it.
G4double new_weight =
weight_correction * track.GetStep()->GetPostStepPoint()->GetWeight();
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
return fParticleChange;
return fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointForcedInteractionForGamma::PostStepGetPhysicalInteractionLength(
const G4Track& track,
G4double ,
G4ForceCondition* condition)
{ G4int step_id = track.GetCurrentStepNumber();
*condition = NotForced;
copy_gamma_for_forced_interaction = false;
G4int track_id=track.GetTrackID();
is_free_flight_gamma = (track_id != last_free_flight_trackid+1 || continue_gamma_as_new_free_flight);
if (is_free_flight_gamma) {
if (step_id == 1 || continue_gamma_as_new_free_flight) {
*condition=Forced;
//A gamma with same conditions will be generate at next post_step do it for the forced interaction
copy_gamma_for_forced_interaction = true;
last_free_flight_trackid = track_id;
acc_track_length=0.;
total_acc_nb_adj_interaction_length=0.;
total_acc_nb_fwd_interaction_length=0.;
continue_gamma_as_new_free_flight=false;
return 1.e-90;
G4double
G4AdjointForcedInteractionForGamma::PostStepGetPhysicalInteractionLength(
const G4Track& track, G4double, G4ForceCondition* condition)
{
static G4int lastFreeFlightTrackId = 1000;
G4int step_id = track.GetCurrentStepNumber();
*condition = NotForced;
fCopyGammaForForced = false;
G4int track_id = track.GetTrackID();
fFreeFlightGamma =
(track_id != lastFreeFlightTrackId + 1 || fContinueGammaAsNewFreeFlight);
if(fFreeFlightGamma)
{
if(step_id == 1 || fContinueGammaAsNewFreeFlight)
{
*condition = Forced;
// A gamma with same conditions will be generate at next post_step do it
// for the forced interaction
fCopyGammaForForced = true;
lastFreeFlightTrackId = track_id;
fAccTrackLength = 0.;
fTotNbAdjIntLength = 0.;
fContinueGammaAsNewFreeFlight = false;
return 1.e-90;
}
else
{
return DBL_MAX;
}
}
else {
//Computation of accumulated length for
return DBL_MAX;
else
{ // compute the interaction length for forced interaction
if(step_id == 1)
{
G4double min_val = std::exp(-fTotNbAdjIntLength);
theNumberOfInteractionLengthLeft =
-std::log(min_val + G4UniformRand() * (1. - min_val));
theInitialNumberOfInteractionLength = theNumberOfInteractionLengthLeft;
fNbAdjIntLength = 0.;
}
G4VPhysicalVolume* thePostPhysVolume =
track.GetStep()->GetPreStepPoint()->GetPhysicalVolume();
G4double ekin = track.GetKineticEnergy();
G4double postCS = 0.;
if(thePostPhysVolume)
{
postCS = fCSManager->GetTotalAdjointCS(
G4AdjointGamma::AdjointGamma(), ekin,
thePostPhysVolume->GetLogicalVolume()->GetMaterialCutsCouple());
}
if(postCS > 0.)
return theNumberOfInteractionLengthLeft / postCS;
else
return DBL_MAX;
}
}
else { //compute the interaction length for forced interaction
if (step_id ==1) {
G4double min_val= std::exp(-total_acc_nb_adj_interaction_length);
theNumberOfInteractionLengthLeft = -std::log( min_val+G4UniformRand()*(1.-min_val));
theInitialNumberOfInteractionLength = theNumberOfInteractionLengthLeft;
acc_nb_adj_interaction_length=0.;
acc_nb_fwd_interaction_length=0.;
}
G4VPhysicalVolume* thePostPhysVolume = track.GetStep()->GetPreStepPoint()->GetPhysicalVolume();
G4double ekin =track.GetKineticEnergy();
G4double postCS=0.;
if (thePostPhysVolume){
postCS = G4AdjointCSManager::GetAdjointCSManager()->GetTotalAdjointCS(G4AdjointGamma::AdjointGamma(),
ekin,thePostPhysVolume->GetLogicalVolume()->GetMaterialCutsCouple());
}
if (postCS>0.) return theNumberOfInteractionLengthLeft/postCS;
else return DBL_MAX;
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointForcedInteractionForGamma::GetContinuousStepLimit(const G4Track& ,
G4double ,
G4double ,
G4double& )
{return DBL_MAX;
}
////////////////////////////////////////////////////////////////////////////////
//Not used in this process but should be implemented as virtual method
G4double G4AdjointForcedInteractionForGamma::GetMeanFreePath(const G4Track& ,
G4double ,
G4ForceCondition*)
{ return 0.;
}
////////////////////////////////////////////////////////////////////////////////
G4double G4AdjointForcedInteractionForGamma::GetContinuousStepLimit(
const G4Track&, G4double, G4double, G4double&)
{
return DBL_MAX;
}
////////////////////////////////////////////////////////////////////////////////
// Not used in this process but should be implemented as virtual method
G4double G4AdjointForcedInteractionForGamma::GetMeanFreePath(const G4Track&,
G4double,
G4ForceCondition*)
{
return 0.;
}
@@ -23,211 +23,185 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointCSMatrix.hh"
#include "G4AdjointInterpolator.hh"
G4ThreadLocal G4AdjointInterpolator* G4AdjointInterpolator::theInstance = 0;
G4ThreadLocal G4AdjointInterpolator* G4AdjointInterpolator::fInstance = nullptr;
///////////////////////////////////////////////////////
//
G4AdjointInterpolator* G4AdjointInterpolator::GetAdjointInterpolator()
{
return GetInstance();
return GetInstance();
}
///////////////////////////////////////////////////////
//
G4AdjointInterpolator* G4AdjointInterpolator::GetInstance()
{
if(!theInstance)
if(!fInstance)
{
theInstance = new G4AdjointInterpolator;
fInstance = new G4AdjointInterpolator;
}
return theInstance;
return fInstance;
}
///////////////////////////////////////////////////////
//
G4AdjointInterpolator::G4AdjointInterpolator()
{
}
G4AdjointInterpolator::G4AdjointInterpolator() {}
///////////////////////////////////////////////////////
//
G4AdjointInterpolator::~G4AdjointInterpolator()
{
}
G4AdjointInterpolator::~G4AdjointInterpolator() {}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::LinearInterpolation(G4double& x,G4double& x1,G4double& x2,G4double& y1,G4double& y2)
G4double G4AdjointInterpolator::LinearInterpolation(G4double& x, G4double& x1,
G4double& x2, G4double& y1,
G4double& y2)
{
G4double res = y1+ (x-x1)*(y2-y1)/(x2-x1);
//G4cout<<"Linear "<<res<<G4endl;
return res;
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::LogarithmicInterpolation(G4double& x,G4double& x1,G4double& x2,G4double& y1,G4double& y2)
{
if (y1<=0 || y2<=0 || x1<=0) return LinearInterpolation(x,x1,x2,y1,y2);
G4double B=std::log(y2/y1)/std::log(x2/x1);
//G4cout<<"x1,x2,y1,y2 "<<x1<<'\t'<<x2<<'\t'<<y1<<'\t'<<y2<<'\t'<<G4endl;
G4double A=y1/std::pow(x1,B);
G4double res=A*std::pow(x,B);
// G4cout<<"Log "<<res<<G4endl;
G4double res = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
return res;
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::ExponentialInterpolation(G4double& x,G4double& x1,G4double& x2,G4double& y1,G4double& y2)
G4double G4AdjointInterpolator::LogarithmicInterpolation(
G4double& x, G4double& x1, G4double& x2, G4double& y1, G4double& y2)
{
G4double B=(std::log(y2)-std::log(y1));
B=B/(x2-x1);
G4double A=y1*std::exp(-B*x1);
G4double res=A*std::exp(B*x);
if(y1 <= 0. || y2 <= 0. || x1 <= 0.)
return LinearInterpolation(x, x1, x2, y1, y2);
G4double B = std::log(y2 / y1) / std::log(x2 / x1);
G4double A = y1 / std::pow(x1, B);
G4double res = A * std::pow(x, B);
return res;
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::Interpolation(G4double& x,G4double& x1,G4double& x2,G4double& y1,G4double& y2,G4String InterPolMethod)
G4double G4AdjointInterpolator::ExponentialInterpolation(
G4double& x, G4double& x1, G4double& x2, G4double& y1, G4double& y2)
{
if (InterPolMethod == "Log" ){
return LogarithmicInterpolation(x,x1,x2,y1,y2);
G4double B = (std::log(y2) - std::log(y1)) / (x2 - x1);
G4double A = y1 * std::exp(-B * x1);
G4double res = A * std::exp(B * x);
return res;
}
///////////////////////////////////////////////////////
G4double G4AdjointInterpolator::Interpolation(G4double& x, G4double& x1,
G4double& x2, G4double& y1,
G4double& y2,
G4String InterPolMethod)
{
if(InterPolMethod == "Log")
{
return LogarithmicInterpolation(x, x1, x2, y1, y2);
}
else if (InterPolMethod == "Lin" ){
return LinearInterpolation(x,x1,x2,y1,y2);
else if(InterPolMethod == "Lin")
{
return LinearInterpolation(x, x1, x2, y1, y2);
}
else if (InterPolMethod == "Exp" ){
return ExponentialInterpolation(x,x1,x2,y1,y2);
else if(InterPolMethod == "Exp")
{
return ExponentialInterpolation(x, x1, x2, y1, y2);
}
else {
//G4cout<<"The interpolation method that you invoked does not exist!"<<G4endl;
return -1111111111.;
else
{
G4ExceptionDescription ed;
ed << "The interpolation method that you invoked does not exist!\n";
G4Exception("G4AdjointInterpolator::Interpolation", "adoint001",
FatalException, ed);
return 0.;
}
}
///////////////////////////////////////////////////////
//
size_t G4AdjointInterpolator::FindPosition(G4double& x,std::vector<G4double>& x_vec,size_t , size_t ) //only valid if x_vec is monotically increasing
// only valid if x_vec is monotically increasing
size_t G4AdjointInterpolator::FindPosition(G4double& x,
std::vector<G4double>& x_vec, size_t,
size_t)
{
//most rapid nethod could be used probably
//It is important to put std::vector<G4double>& such that the vector itself is used and not a copy
// most rapid method could be used probably
size_t ndim = x_vec.size();
size_t ind1 = 0;
size_t ind2 = ndim - 1;
/* if (ind_max >= ind_min){
ind1=ind_min;
ind2=ind_max;
if(ndim > 1)
{
if(x_vec[0] < x_vec[1])
{ // increasing
do
{
size_t midBin = (ind1 + ind2) / 2;
if(x < x_vec[midBin])
ind2 = midBin;
else
ind1 = midBin;
} while(ind2 - ind1 > 1);
}
else
{
do
{
size_t midBin = (ind1 + ind2) / 2;
if(x < x_vec[midBin])
ind1 = midBin;
else
ind2 = midBin;
} while(ind2 - ind1 > 1);
}
}
*/
if (ndim >1) {
if (x_vec[0] < x_vec[1] ) { //increasing
do {
size_t midBin = (ind1 + ind2)/2;
if (x < x_vec[midBin])
ind2 = midBin;
else
ind1 = midBin;
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
} while (ind2 - ind1 > 1);
}
else {
do {
size_t midBin = (ind1 + ind2)/2;
if (x < x_vec[midBin])
ind1 = midBin;
else
ind2 = midBin;
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
} while (ind2 - ind1 > 1);
}
}
return ind1;
}
///////////////////////////////////////////////////////
//
size_t G4AdjointInterpolator::FindPositionForLogVector(G4double& log_x,std::vector<G4double>& log_x_vec) //only valid if x_vec is monotically increasing
// only valid if x_vec is monotically increasing
size_t G4AdjointInterpolator::FindPositionForLogVector(
G4double& log_x, std::vector<G4double>& log_x_vec)
{
//most rapid nethod could be used probably
//It is important to put std::vector<G4double>& such that the vector itself is used and not a copy
// most rapid method could be used probably
return FindPosition(log_x, log_x_vec);
/*
if (log_x_vec.size()>3){
size_t ind=0;
G4double log_x1=log_x_vec[1];
G4double d_log =log_x_vec[2]-log_x1;
G4double dind=(log_x-log_x1)/d_log +1.;
if (dind <1.) ind=0;
else if (dind >= double(log_x_vec.size())-2.) ind =log_x_vec.size()-2;
else ind =size_t(dind);
return ind;
}
else return FindPosition(log_x, log_x_vec);
*/
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::Interpolate(G4double& x,std::vector<G4double>& x_vec,std::vector<G4double>& y_vec,G4String InterPolMethod)
G4double G4AdjointInterpolator::Interpolate(G4double& x,
std::vector<G4double>& x_vec,
std::vector<G4double>& y_vec,
G4String InterPolMethod)
{
size_t i=FindPosition(x,x_vec);
//G4cout<<i<<G4endl;
//G4cout<<x<<G4endl;
//G4cout<<x_vec[i]<<G4endl;
return Interpolation( x,x_vec[i],x_vec[i+1],y_vec[i],y_vec[i+1],InterPolMethod);
size_t i = FindPosition(x, x_vec);
return Interpolation(x, x_vec[i], x_vec[i + 1], y_vec[i], y_vec[i + 1],
InterPolMethod);
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::InterpolateWithIndexVector(G4double& x,std::vector<G4double>& x_vec,std::vector<G4double>& y_vec,
std::vector<size_t>& index_vec,G4double x0, G4double dx) //only linear interpolation possible
G4double G4AdjointInterpolator::InterpolateWithIndexVector(
G4double& x, std::vector<G4double>& x_vec, std::vector<G4double>& y_vec,
std::vector<size_t>& index_vec, G4double x0,
G4double dx) // only linear interpolation possible
{
size_t ind=0;
if (x>x0) ind=int((x-x0)/dx);
if (ind >= index_vec.size()-1) ind= index_vec.size()-2;
size_t ind = 0;
if(x > x0)
ind = int((x - x0) / dx);
if(ind >= index_vec.size() - 1)
ind = index_vec.size() - 2;
size_t ind1 = index_vec[ind];
size_t ind2 = index_vec[ind+1];
if (ind1 >ind2) {
size_t ind11=ind1;
ind1=ind2;
ind2=ind11;
size_t ind2 = index_vec[ind + 1];
if(ind1 > ind2)
{
size_t ind11 = ind1;
ind1 = ind2;
ind2 = ind11;
}
ind=FindPosition(x,x_vec,ind1,ind2);
return Interpolation( x,x_vec[ind],x_vec[ind+1],y_vec[ind],y_vec[ind+1],"Lin");
}
ind = FindPosition(x, x_vec, ind1, ind2);
return Interpolation(x, x_vec[ind], x_vec[ind + 1], y_vec[ind],
y_vec[ind + 1], "Lin");
}
///////////////////////////////////////////////////////
//
G4double G4AdjointInterpolator::InterpolateForLogVector(G4double& log_x,std::vector<G4double>& log_x_vec,std::vector<G4double>& log_y_vec)
G4double G4AdjointInterpolator::InterpolateForLogVector(
G4double& log_x, std::vector<G4double>& log_x_vec,
std::vector<G4double>& log_y_vec)
{
//size_t i=0;
size_t i=FindPositionForLogVector(log_x,log_x_vec);
/*G4cout<<"In interpolate "<<G4endl;
G4cout<<i<<G4endl;
G4cout<<log_x<<G4endl;
G4cout<<log_x_vec[i]<<G4endl;
G4cout<<log_x_vec[i+1]<<G4endl;
G4cout<<log_y_vec[i]<<G4endl;
G4cout<<log_y_vec[i+1]<<G4endl;*/
G4double log_y=LinearInterpolation(log_x,log_x_vec[i],log_x_vec[i+1],log_y_vec[i],log_y_vec[i+1]);
size_t i = FindPositionForLogVector(log_x, log_x_vec);
G4double log_y = LinearInterpolation(log_x, log_x_vec[i], log_x_vec[i + 1],
log_y_vec[i], log_y_vec[i + 1]);
return log_y;
}
}
@@ -23,341 +23,317 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointIonIonisationModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointIonIonisationModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4AdjointElectron.hh"
#include "G4AdjointProton.hh"
#include "G4AdjointInterpolator.hh"
#include "G4BetheBlochModel.hh"
#include "G4BraggIonModel.hh"
#include "G4Proton.hh"
#include "G4GenericIon.hh"
#include "G4NistManager.hh"
#include "G4ParticleChange.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4TrackStatus.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointIonIonisationModel::G4AdjointIonIonisationModel():
G4VEmAdjointModel("Adjoint_IonIonisation")
{
UseMatrix =true;
UseMatrixPerElement = true;
ApplyCutInRange = true;
UseOnlyOneMatrixForAllElements = true;
CS_biasing_factor =1.;
second_part_of_same_type =false;
use_only_bragg = false; // for the Ion ionisation using the parametrised table model the cross sections and the sample of secondaries is done
// as in the BraggIonModel, Therefore the use of this flag;
//The direct EM Model is taken has BetheBloch it is only used for the computation
// of the differential cross section.
//The Bragg model could be used as an alternative as it offers the same differential cross section
theBetheBlochDirectEMModel = new G4BetheBlochModel(G4GenericIon::GenericIon());
theBraggIonDirectEMModel = new G4BraggIonModel(G4GenericIon::GenericIon());
theAdjEquivOfDirectSecondPartDef=G4AdjointElectron::AdjointElectron();
theDirectPrimaryPartDef =0;
theAdjEquivOfDirectPrimPartDef =0;
/* theDirectPrimaryPartDef =fwd_ion;
theAdjEquivOfDirectPrimPartDef =adj_ion;
DefineProjectileProperty();*/
G4AdjointIonIonisationModel::G4AdjointIonIonisationModel()
: G4VEmAdjointModel("Adjoint_IonIonisation")
{
fUseMatrix = true;
fUseMatrixPerElement = true;
fApplyCutInRange = true;
fOneMatrixForAllElements = true;
fSecondPartSameType = false;
// The direct EM Model is taken as BetheBloch. It is only used for the
// computation of the differential cross section.
// The Bragg model could be used as an alternative as it offers the same
// differential cross section
fBetheBlochDirectEMModel = new G4BetheBlochModel(G4GenericIon::GenericIon());
fBraggIonDirectEMModel = new G4BraggIonModel(G4GenericIon::GenericIon());
fAdjEquivDirectSecondPart = G4AdjointElectron::AdjointElectron();
fDirectPrimaryPart = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointIonIonisationModel::~G4AdjointIonIonisationModel()
{;}
G4AdjointIonIonisationModel::~G4AdjointIonIonisationModel() {}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointIonIonisationModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
//Elastic inverse scattering
//---------------------------------------------------------
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP =theAdjointPrimary->GetTotalMomentum();
void G4AdjointIonIonisationModel::SampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
//Sample secondary energy
//-----------------------
G4double projectileKinEnergy = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, IsScatProjToProjCase);
CorrectPostStepWeight(fParticleChange,
aTrack.GetWeight(),
adjointPrimKinEnergy,
projectileKinEnergy,
IsScatProjToProjCase); //Caution !!!this weight correction should be always applied
// Elastic inverse scattering
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP = theAdjointPrimary->GetTotalMomentum();
//Kinematic:
//we consider a two body elastic scattering for the forward processes where the projectile knock on an e- at rest and gives
// him part of its energy
//----------------------------------------------------------------------------------------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
//Companion
//-----------
G4double companionM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
if (IsScatProjToProjCase) {
companionM0=theAdjEquivOfDirectSecondPartDef->GetPDGMass();
}
G4double companionTotalEnergy =companionM0+ projectileKinEnergy-adjointPrimKinEnergy;
G4double companionP2 = companionTotalEnergy*companionTotalEnergy - companionM0*companionM0;
//Projectile momentum
//--------------------
G4double P_parallel = (adjointPrimP*adjointPrimP + projectileP2 - companionP2)/(2.*adjointPrimP);
G4double P_perp = std::sqrt( projectileP2 - P_parallel*P_parallel);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector projectileMomentum = G4ThreeVector(P_perp*std::cos(phi),P_perp*std::sin(phi),P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
//G4cout<<"projectileMomentum "<<projectileMomentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointIonIonisationModel::DiffCrossSectionPerAtomPrimToSecond(
G4double kinEnergyProj,
G4double kinEnergyProd,
G4double Z,
G4double A)
{//Probably that here the Bragg Model should be also used for kinEnergyProj/nuc<2MeV
G4double dSigmadEprod=0;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(kinEnergyProd);
G4double kinEnergyProjScaled = massRatio*kinEnergyProj;
if (kinEnergyProj>Emin_proj && kinEnergyProj<=Emax_proj){ //the produced particle should have a kinetic energy smaller than the projectile
G4double Tmax=kinEnergyProj;
G4double E1=kinEnergyProd;
G4double E2=kinEnergyProd*1.000001;
G4double dE=(E2-E1);
G4double sigma1,sigma2;
theDirectEMModel =theBraggIonDirectEMModel;
if (kinEnergyProjScaled >2.*MeV && !use_only_bragg) theDirectEMModel = theBetheBlochDirectEMModel; //Bethe Bloch Model
sigma1=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E1,1.e20);
sigma2=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E2,1.e20);
dSigmadEprod=(sigma1-sigma2)/dE;
//G4double chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPrimaryPartDef,currentMaterial,E);
if (dSigmadEprod>1.) {
G4cout<<"sigma1 "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<sigma1<<G4endl;
G4cout<<"sigma2 "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<sigma2<<G4endl;
G4cout<<"dsigma "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<dSigmadEprod<<G4endl;
}
if (theDirectEMModel == theBetheBlochDirectEMModel ){
//correction of differential cross section at high energy to correct for the suppression of particle at secondary at high
//energy used in the Bethe Bloch Model. This correction consist to multiply by g the probability function used
//to test the rejection of a secondary
//-------------------------
//Source code taken from G4BetheBlochModel::SampleSecondaries
G4double deltaKinEnergy = kinEnergyProd;
//Part of the taken code
//----------------------
// projectile formfactor - suppresion of high energy
// delta-electron production at high energy
G4double x = formfact*deltaKinEnergy;
if(x > 1.e-6) {
G4double totEnergy = kinEnergyProj + mass;
G4double etot2 = totEnergy*totEnergy;
G4double beta2 = kinEnergyProj*(kinEnergyProj + 2.0*mass)/etot2;
G4double f;
G4double f1 = 0.0;
f = 1.0 - beta2*deltaKinEnergy/Tmax;
if( 0.5 == spin ) {
f1 = 0.5*deltaKinEnergy*deltaKinEnergy/etot2;
f += f1;
}
G4double x1 = 1.0 + x;
G4double gg = 1.0/(x1*x1);
if( 0.5 == spin ) {
G4double x2 = 0.5*electron_mass_c2*deltaKinEnergy/(mass*mass);
gg *= (1.0 + magMoment2*(x2 - f1/f)/(1.0 + x2));
}
if(gg > 1.0) {
G4cout << "### G4BetheBlochModel in Adjoint Sim WARNING: gg= " << gg
<< G4endl;
gg=1.;
}
//G4cout<<"gg"<<gg<<G4endl;
dSigmadEprod*=gg;
}
}
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
return dSigmadEprod;
// Sample secondary energy
G4double projectileKinEnergy =
SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, isScatProjToProj);
// Caution !!!this weight correction should be always applied
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
adjointPrimKinEnergy, projectileKinEnergy,
isScatProjToProj);
// Kinematics:
// we consider a two body elastic scattering for the forward processes where
// the projectile knock on an e- at rest and gives it part of its energy
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
// Companion
G4double companionM0 = fAdjEquivDirectPrimPart->GetPDGMass();
if(isScatProjToProj)
{
companionM0 = fAdjEquivDirectSecondPart->GetPDGMass();
}
G4double companionTotalEnergy =
companionM0 + projectileKinEnergy - adjointPrimKinEnergy;
G4double companionP2 =
companionTotalEnergy * companionTotalEnergy - companionM0 * companionM0;
// Projectile momentum
G4double P_parallel =
(adjointPrimP * adjointPrimP + projectileP2 - companionP2) /
(2. * adjointPrimP);
G4double P_perp = std::sqrt(projectileP2 - P_parallel * P_parallel);
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector projectileMomentum =
G4ThreeVector(P_perp * std::cos(phi), P_perp * std::sin(phi), P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointIonIonisationModel::SetIon(G4ParticleDefinition* adj_ion, G4ParticleDefinition* fwd_ion)
{ theDirectPrimaryPartDef =fwd_ion;
theAdjEquivOfDirectPrimPartDef =adj_ion;
////////////////////////////////////////////////////////////////////////////////
G4double G4AdjointIonIonisationModel::DiffCrossSectionPerAtomPrimToSecond(
G4double kinEnergyProj, G4double kinEnergyProd, G4double Z, G4double A)
{
// Probably that here the Bragg Model should be also used for
// kinEnergyProj/nuc<2MeV
G4double dSigmadEprod = 0.;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
G4double kinEnergyProjScaled = fMassRatio * kinEnergyProj;
// the produced particle should have a kinetic energy smaller than the
// projectile
if(kinEnergyProj > Emin_proj && kinEnergyProj <= Emax_proj)
{
G4double Tmax = kinEnergyProj;
G4double E1 = kinEnergyProd;
G4double E2 = kinEnergyProd * 1.000001;
G4double dE = (E2 - E1);
G4double sigma1, sigma2;
fDirectModel = fBraggIonDirectEMModel;
if(kinEnergyProjScaled > 2. * MeV && !fUseOnlyBragg)
fDirectModel = fBetheBlochDirectEMModel;
sigma1 = fDirectModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E1, 1.e20);
sigma2 = fDirectModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E2, 1.e20);
dSigmadEprod = (sigma1 - sigma2) / dE;
if(dSigmadEprod > 1.)
{
G4cout << "sigma1 " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << sigma1 << G4endl;
G4cout << "sigma2 " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << sigma2 << G4endl;
G4cout << "dsigma " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << dSigmadEprod << G4endl;
}
if(fDirectModel == fBetheBlochDirectEMModel)
{
// correction of differential cross section at high energy to correct for
// the suppression of particle at secondary at high energy used in the
// Bethe Bloch Model. This correction consist to multiply by g the
// probability function used to test the rejection of a secondary Source
// code taken from G4BetheBlochModel::SampleSecondaries
G4double deltaKinEnergy = kinEnergyProd;
G4double x = fFormFact * deltaKinEnergy;
if(x > 1.e-6)
{
G4double totEnergy = kinEnergyProj + fMass;
G4double etot2 = totEnergy * totEnergy;
G4double beta2 = kinEnergyProj * (kinEnergyProj + 2.0 * fMass) / etot2;
G4double f1 = 0.0;
G4double f = 1.0 - beta2 * deltaKinEnergy / Tmax;
if(0.5 == fSpin)
{
f1 = 0.5 * deltaKinEnergy * deltaKinEnergy / etot2;
f += f1;
}
G4double x1 = 1.0 + x;
G4double gg = 1.0 / (x1 * x1);
if(0.5 == fSpin)
{
G4double x2 =
0.5 * electron_mass_c2 * deltaKinEnergy / (fMass * fMass);
gg *= (1.0 + fMagMoment2 * (x2 - f1 / f) / (1.0 + x2));
}
if(gg > 1.0)
{
G4cout << "### G4BetheBlochModel in Adjoint Sim WARNING: gg= " << gg
<< G4endl;
gg = 1.;
}
dSigmadEprod *= gg;
}
}
}
return dSigmadEprod;
}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointIonIonisationModel::SetIon(G4ParticleDefinition* adj_ion,
G4ParticleDefinition* fwd_ion)
{
fDirectPrimaryPart = fwd_ion;
fAdjEquivDirectPrimPart = adj_ion;
DefineProjectileProperty();
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointIonIonisationModel::CorrectPostStepWeight(G4ParticleChange* fParticleChange, G4double old_weight,
G4double adjointPrimKinEnergy, G4double projectileKinEnergy,G4bool )
////////////////////////////////////////////////////////////////////////////////
void G4AdjointIonIonisationModel::CorrectPostStepWeight(
G4ParticleChange* fParticleChange, G4double old_weight,
G4double adjointPrimKinEnergy, G4double projectileKinEnergy, G4bool)
{
//It is needed because the direct cross section used to compute the differential cross section is not the one used in
// the direct model where the GenericIon stuff is considered with correction of effective charge. In the direct model the samnepl of secondaries does
// not reflect the integral cross section. The integral fwd cross section that we used to compute the differential CS
// match the sample of secondaries in the forward case despite the fact that its is not the same total CS than in the FWD case. For this reasion an extra
// weight correction is needed at the end.
// It is needed because the direct cross section used to compute the
// differential cross section is not the one used in
// the direct model where the GenericIon stuff is considered with correction
// of effective charge. In the direct model the samnepl of secondaries does
// not reflect the integral cross section. The integral fwd cross section that
// we used to compute the differential CS match the sample of secondaries in
// the forward case despite the fact that its is not the same total CS than in
// the FWD case. For this reason an extra weight correction is needed at the
// end.
G4double new_weight=old_weight;
//the correction of CS due to the problem explained above
G4double kinEnergyProjScaled = massRatio*projectileKinEnergy;
theDirectEMModel =theBraggIonDirectEMModel;
if (kinEnergyProjScaled >2.*MeV && !use_only_bragg) theDirectEMModel = theBetheBlochDirectEMModel; //Bethe Bloch Model
G4double UsedFwdCS=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,projectileKinEnergy,1,1 ,currentTcutForDirectSecond,1.e20);
G4double chargeSqRatio =1.;
if (chargeSquare>1.) chargeSqRatio = theDirectEMModel->GetChargeSquareRatio(theDirectPrimaryPartDef,currentMaterial,projectileKinEnergy);
G4double CorrectFwdCS = chargeSqRatio*theDirectEMModel->ComputeCrossSectionPerAtom(G4GenericIon::GenericIon(),kinEnergyProjScaled,1,1 ,currentTcutForDirectSecond,1.e20);
if (UsedFwdCS >0) new_weight*= CorrectFwdCS/UsedFwdCS;//May be some check is needed if UsedFwdCS ==0 probably that then we should avoid a secondary to be produced,
//additional CS crorrection needed for cross section biasing in general.
//May be wrong for ions!!! Most of the time not used!
G4double w_corr =1./CS_biasing_factor;
w_corr*=G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
new_weight*=w_corr;
new_weight*=projectileKinEnergy/adjointPrimKinEnergy;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
G4double new_weight = old_weight;
// the correction of CS due to the problem explained above
G4double kinEnergyProjScaled = fMassRatio * projectileKinEnergy;
fDirectModel = fBraggIonDirectEMModel;
if(kinEnergyProjScaled > 2. * MeV && !fUseOnlyBragg)
fDirectModel = fBetheBlochDirectEMModel;
G4double UsedFwdCS = fDirectModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, projectileKinEnergy, 1, 1, fTcutSecond, 1.e20);
G4double chargeSqRatio = 1.;
if(fChargeSquare > 1.)
chargeSqRatio = fDirectModel->GetChargeSquareRatio(
fDirectPrimaryPart, fCurrentMaterial, projectileKinEnergy);
G4double CorrectFwdCS =
chargeSqRatio * fDirectModel->ComputeCrossSectionPerAtom(
G4GenericIon::GenericIon(), kinEnergyProjScaled, 1, 1,
fTcutSecond, 1.e20);
// May be some check is needed if UsedFwdCS ==0 probably that then we should
// avoid a secondary to be produced,
if(UsedFwdCS > 0.)
new_weight *= CorrectFwdCS / UsedFwdCS;
// additional CS correction needed for cross section biasing in general.
// May be wrong for ions. Most of the time not used.
new_weight *=
G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection() /
fCsBiasingFactor;
new_weight *= projectileKinEnergy / adjointPrimKinEnergy;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
void G4AdjointIonIonisationModel::DefineProjectileProperty()
{
//Slightly modified code taken from G4BetheBlochModel::SetParticle
//------------------------------------------------
G4String pname = theDirectPrimaryPartDef->GetParticleName();
if (theDirectPrimaryPartDef->GetParticleType() == "nucleus" &&
pname != "deuteron" && pname != "triton") {
isIon = true;
{
// Slightly modified code taken from G4BetheBlochModel::SetParticle
G4String pname = fDirectPrimaryPart->GetParticleName();
fMass = fDirectPrimaryPart->GetPDGMass();
fMassRatio = G4GenericIon::GenericIon()->GetPDGMass() / fMass;
fSpin = fDirectPrimaryPart->GetPDGSpin();
G4double q = fDirectPrimaryPart->GetPDGCharge() / eplus;
fChargeSquare = q * q;
fRatio = electron_mass_c2 / fMass;
fOnePlusRatio2 = (1. + fRatio) * (1. + fRatio);
fOneMinusRatio2 = (1. - fRatio) * (1. - fRatio);
G4double magmom = fDirectPrimaryPart->GetPDGMagneticMoment() * fMass /
(0.5 * eplus * hbar_Planck * c_squared);
fMagMoment2 = magmom * magmom - 1.0;
if(fDirectPrimaryPart->GetLeptonNumber() == 0)
{
G4double x = 0.8426 * GeV;
if(fSpin == 0.0 && fMass < GeV)
{
x = 0.736 * GeV;
}
mass = theDirectPrimaryPartDef->GetPDGMass();
massRatio= G4GenericIon::GenericIon()->GetPDGMass()/mass;
mass_ratio_projectile = massRatio;
spin = theDirectPrimaryPartDef->GetPDGSpin();
G4double q = theDirectPrimaryPartDef->GetPDGCharge()/eplus;
chargeSquare = q*q;
ratio = electron_mass_c2/mass;
ratio2 = ratio*ratio;
one_plus_ratio_2=(1+ratio)*(1+ratio);
one_minus_ratio_2=(1-ratio)*(1-ratio);
G4double magmom = theDirectPrimaryPartDef->GetPDGMagneticMoment()
*mass/(0.5*eplus*hbar_Planck*c_squared);
magMoment2 = magmom*magmom - 1.0;
formfact = 0.0;
if(theDirectPrimaryPartDef->GetLeptonNumber() == 0) {
G4double x = 0.8426*GeV;
if(spin == 0.0 && mass < GeV) {x = 0.736*GeV;}
else if(mass > GeV) {
x /= G4NistManager::Instance()->GetZ13(mass/proton_mass_c2);
// tlimit = 51.2*GeV*A13[iz]*A13[iz];
}
formfact = 2.0*electron_mass_c2/(x*x);
tlimit = 2.0/formfact;
}
else if(fMass > GeV)
{
x /= G4NistManager::Instance()->GetZ13(fMass / proton_mass_c2);
}
fFormFact = 2.0 * electron_mass_c2 / (x * x);
}
}
//////////////////////////////////////////////////////////////////////////////
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMaxForScatProjToProj(
G4double primAdjEnergy)
{
return primAdjEnergy * fOnePlusRatio2 /
(fOneMinusRatio2 - 2. * fRatio * primAdjEnergy / fMass);
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMaxForScatProjToProjCase(G4double PrimAdjEnergy)
{
G4double Tmax=PrimAdjEnergy*one_plus_ratio_2/(one_minus_ratio_2-2.*ratio*PrimAdjEnergy/mass);
return Tmax;
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMinForScatProjToProj(
G4double primAdjEnergy, G4double tcut)
{
return primAdjEnergy + tcut;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMinForScatProjToProjCase(G4double PrimAdjEnergy,G4double Tcut)
{ return PrimAdjEnergy+Tcut;
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMaxForProdToProj(
G4double)
{
return GetHighEnergyLimit();
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMaxForProdToProjCase(G4double )
{ return HighEnergyLimit;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMinForProdToProjCase(G4double PrimAdjEnergy)
{ G4double Tmin= (2*PrimAdjEnergy-4*mass + std::sqrt(4.*PrimAdjEnergy*PrimAdjEnergy +16.*mass*mass + 8.*PrimAdjEnergy*mass*(1/ratio +ratio)))/4.;
return Tmin;
G4double G4AdjointIonIonisationModel::GetSecondAdjEnergyMinForProdToProj(
G4double primAdjEnergy)
{
return (2. * primAdjEnergy - 4. * fMass +
std::sqrt(4. * primAdjEnergy * primAdjEnergy + 16. * fMass * fMass +
8. * primAdjEnergy * fMass * (1. / fRatio + fRatio))) /
4.;
}
@@ -23,250 +23,213 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointPhotoElectricModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4PhysicalConstants.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointElectron.hh"
#include "G4Gamma.hh"
#include "G4AdjointGamma.hh"
#include "G4Gamma.hh"
#include "G4ParticleChange.hh"
#include "G4PEEffectFluoModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4TrackStatus.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointPhotoElectricModel::G4AdjointPhotoElectricModel():
G4VEmAdjointModel("AdjointPEEffect")
G4AdjointPhotoElectricModel::G4AdjointPhotoElectricModel()
: G4VEmAdjointModel("AdjointPEEffect")
{ SetUseMatrix(false);
{
SetUseMatrix(false);
SetApplyCutInRange(false);
//Initialization
current_eEnergy =0.;
totAdjointCS=0.;
factorCSBiasing =1.;
post_step_AdjointCS =0.;
pre_step_AdjointCS =0.;
totBiasedAdjointCS =0.;
index_element=0;
theAdjEquivOfDirectPrimPartDef =G4AdjointGamma::AdjointGamma();
theAdjEquivOfDirectSecondPartDef=G4AdjointElectron::AdjointElectron();
theDirectPrimaryPartDef=G4Gamma::Gamma();
second_part_of_same_type=false;
theDirectPEEffectModel = new G4PEEffectFluoModel();
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointPhotoElectricModel::~G4AdjointPhotoElectricModel()
{;}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointPhotoElectricModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{ if (IsScatProjToProjCase) return ;
//Compute the totAdjointCS vectors if not already done for the current couple and electron energy
//-----------------------------------------------------------------------------------------------
const G4MaterialCutsCouple* aCouple = aTrack.GetMaterialCutsCouple();
const G4DynamicParticle* aDynPart = aTrack.GetDynamicParticle() ;
G4double electronEnergy = aDynPart->GetKineticEnergy();
G4ThreeVector electronDirection= aDynPart->GetMomentumDirection() ;
pre_step_AdjointCS = totAdjointCS; //The last computed CS was at pre step point
post_step_AdjointCS = AdjointCrossSection(aCouple, electronEnergy,IsScatProjToProjCase);
post_step_AdjointCS = totAdjointCS;
//Sample element
//-------------
const G4ElementVector* theElementVector = currentMaterial->GetElementVector();
size_t nelm = currentMaterial->GetNumberOfElements();
G4double rand_CS= G4UniformRand()*xsec[nelm-1];
for (index_element=0; index_element<nelm-1; index_element++){
if (rand_CS<xsec[index_element]) break;
}
//Sample shell and binding energy
//-------------
G4int nShells = (*theElementVector)[index_element]->GetNbOfAtomicShells();
rand_CS= shell_prob[index_element][nShells-1]*G4UniformRand();
G4int i = 0;
for (i=0; i<nShells-1; i++){
if (rand_CS<shell_prob[index_element][i]) break;
}
G4double gammaEnergy= electronEnergy+(*theElementVector)[index_element]->GetAtomicShell(i);
//Sample cos theta
//Copy of the G4PEEfectFluoModel cos theta sampling method ElecCosThetaDistribution.
//This method cannot be used directly from G4PEEfectFluoModel because it is a friend method. I should ask Vladimir to change that
//------------------------------------------------------------------------------------------------
//G4double cos_theta = theDirectPEEffectModel->ElecCosThetaDistribution(electronEnergy);
G4double cos_theta = 1.;
G4double gamma = 1. + electronEnergy/electron_mass_c2;
if (gamma <= 5.) {
G4double beta = std::sqrt(gamma*gamma-1.)/gamma;
G4double b = 0.5*gamma*(gamma-1.)*(gamma-2);
G4double rndm,term,greject,grejsup;
if (gamma < 2.) grejsup = gamma*gamma*(1.+b-beta*b);
else grejsup = gamma*gamma*(1.+b+beta*b);
do { rndm = 1.-2*G4UniformRand();
cos_theta = (rndm+beta)/(rndm*beta+1.);
term = 1.-beta*cos_theta;
greject = (1.-cos_theta*cos_theta)*(1.+b*term)/(term*term);
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
} while(greject < G4UniformRand()*grejsup);
}
// direction of the adjoint gamma electron
//---------------------------------------
G4double sin_theta = std::sqrt(1.-cos_theta*cos_theta);
G4double Phi = twopi * G4UniformRand();
G4double dirx = sin_theta*std::cos(Phi),diry = sin_theta*std::sin(Phi),dirz = cos_theta;
G4ThreeVector adjoint_gammaDirection(dirx,diry,dirz);
adjoint_gammaDirection.rotateUz(electronDirection);
//Weight correction
//-----------------------
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(), electronEnergy,gammaEnergy,IsScatProjToProjCase);
//Create secondary and modify fParticleChange
//--------------------------------------------
G4DynamicParticle* anAdjointGamma = new G4DynamicParticle (
G4AdjointGamma::AdjointGamma(),adjoint_gammaDirection, gammaEnergy);
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(anAdjointGamma);
fAdjEquivDirectPrimPart = G4AdjointGamma::AdjointGamma();
fAdjEquivDirectSecondPart = G4AdjointElectron::AdjointElectron();
fDirectPrimaryPart = G4Gamma::Gamma();
fSecondPartSameType = false;
fDirectModel = new G4PEEffectFluoModel();
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointPhotoElectricModel::CorrectPostStepWeight(G4ParticleChange* fParticleChange,
G4double old_weight,
G4double adjointPrimKinEnergy,
G4double projectileKinEnergy ,
G4bool )
G4AdjointPhotoElectricModel::~G4AdjointPhotoElectricModel() {}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointPhotoElectricModel::SampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
G4double new_weight=old_weight;
if(isScatProjToProj)
return;
G4double w_corr =G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection()/factorCSBiasing;
w_corr*=post_step_AdjointCS/pre_step_AdjointCS;
// Compute the fTotAdjointCS vectors if not already done for the current
// couple and electron energy
const G4DynamicParticle* aDynPart = aTrack.GetDynamicParticle();
G4double electronEnergy = aDynPart->GetKineticEnergy();
G4ThreeVector electronDirection = aDynPart->GetMomentumDirection();
fPreStepAdjointCS =
fTotAdjointCS; // The last computed CS was at pre step point
AdjointCrossSection(aTrack.GetMaterialCutsCouple(), electronEnergy,
isScatProjToProj);
fPostStepAdjointCS = fTotAdjointCS;
// Sample element
const G4ElementVector* theElementVector =
fCurrentMaterial->GetElementVector();
size_t nelm = fCurrentMaterial->GetNumberOfElements();
G4double rand_CS = G4UniformRand() * fXsec[nelm - 1];
for(fIndexElement = 0; fIndexElement < nelm - 1; ++fIndexElement)
{
if(rand_CS < fXsec[fIndexElement])
break;
}
new_weight*=w_corr;
new_weight*=projectileKinEnergy/adjointPrimKinEnergy;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
}
// Sample shell and binding energy
G4int nShells = (*theElementVector)[fIndexElement]->GetNbOfAtomicShells();
rand_CS = fShellProb[fIndexElement][nShells - 1] * G4UniformRand();
G4int i;
for(i = 0; i < nShells - 1; ++i)
{
if(rand_CS < fShellProb[fIndexElement][i])
break;
}
G4double gammaEnergy =
electronEnergy + (*theElementVector)[fIndexElement]->GetAtomicShell(i);
// Sample cos theta
// Copy of the G4PEEfectFluoModel cos theta sampling method
// ElecCosThetaDistribution. This method cannot be used directly from
// G4PEEffectFluoModel because it is a friend method.
G4double cos_theta = 1.;
G4double gamma = 1. + electronEnergy / electron_mass_c2;
if(gamma <= 5.)
{
G4double beta = std::sqrt(gamma * gamma - 1.) / gamma;
G4double b = 0.5 * gamma * (gamma - 1.) * (gamma - 2.);
G4double rndm, term, greject, grejsup;
if(gamma < 2.)
grejsup = gamma * gamma * (1. + b - beta * b);
else
grejsup = gamma * gamma * (1. + b + beta * b);
do
{
rndm = 1. - 2. * G4UniformRand();
cos_theta = (rndm + beta) / (rndm * beta + 1.);
term = 1. - beta * cos_theta;
greject = (1. - cos_theta * cos_theta) * (1. + b * term) / (term * term);
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
} while(greject < G4UniformRand() * grejsup);
}
// direction of the adjoint gamma electron
G4double sin_theta = std::sqrt(1. - cos_theta * cos_theta);
G4double phi = twopi * G4UniformRand();
G4double dirx = sin_theta * std::cos(phi);
G4double diry = sin_theta * std::sin(phi);
G4double dirz = cos_theta;
G4ThreeVector adjoint_gammaDirection(dirx, diry, dirz);
adjoint_gammaDirection.rotateUz(electronDirection);
// Weight correction
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(), electronEnergy,
gammaEnergy, isScatProjToProj);
// Create secondary and modify fParticleChange
G4DynamicParticle* anAdjointGamma = new G4DynamicParticle(
G4AdjointGamma::AdjointGamma(), adjoint_gammaDirection, gammaEnergy);
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(anAdjointGamma);
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointPhotoElectricModel::CorrectPostStepWeight(
G4ParticleChange* fParticleChange, G4double old_weight,
G4double adjointPrimKinEnergy, G4double projectileKinEnergy, G4bool)
{
G4double new_weight = old_weight;
G4double G4AdjointPhotoElectricModel::AdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double electronEnergy,
G4bool IsScatProjToProjCase)
{
G4double w_corr =
G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection() /
fFactorCSBiasing;
w_corr *= fPostStepAdjointCS / fPreStepAdjointCS;
if (IsScatProjToProjCase) return 0.;
new_weight *= w_corr * projectileKinEnergy / adjointPrimKinEnergy;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
}
if (aCouple !=currentCouple || current_eEnergy !=electronEnergy) {
totAdjointCS = 0.;
DefineCurrentMaterialAndElectronEnergy(aCouple, electronEnergy);
const G4ElementVector* theElementVector = currentMaterial->GetElementVector();
const double* theAtomNumDensityVector = currentMaterial->GetVecNbOfAtomsPerVolume();
size_t nelm = currentMaterial->GetNumberOfElements();
for (index_element=0;index_element<nelm;index_element++){
totAdjointCS +=AdjointCrossSectionPerAtom((*theElementVector)[index_element],electronEnergy)*theAtomNumDensityVector[index_element];
xsec[index_element] = totAdjointCS;
}
////////////////////////////////////////////////////////////////////////////////
G4double G4AdjointPhotoElectricModel::AdjointCrossSection(
const G4MaterialCutsCouple* aCouple, G4double electronEnergy,
G4bool isScatProjToProj)
{
if(isScatProjToProj)
return 0.;
totBiasedAdjointCS=std::min(totAdjointCS,0.01);
// totBiasedAdjointCS=totAdjointCS;
factorCSBiasing = totBiasedAdjointCS/totAdjointCS;
lastCS=totBiasedAdjointCS;
G4double totBiasedAdjointCS = 0.;
if(aCouple != fCurrentCouple || fCurrenteEnergy != electronEnergy)
{
fTotAdjointCS = 0.;
DefineCurrentMaterialAndElectronEnergy(aCouple, electronEnergy);
const G4ElementVector* theElementVector =
fCurrentMaterial->GetElementVector();
const G4double* theAtomNumDensityVector =
fCurrentMaterial->GetVecNbOfAtomsPerVolume();
size_t nelm = fCurrentMaterial->GetNumberOfElements();
for(fIndexElement = 0; fIndexElement < nelm; ++fIndexElement)
{
fTotAdjointCS += AdjointCrossSectionPerAtom(
(*theElementVector)[fIndexElement], electronEnergy) *
theAtomNumDensityVector[fIndexElement];
fXsec[fIndexElement] = fTotAdjointCS;
}
totBiasedAdjointCS = std::min(fTotAdjointCS, 0.01);
fFactorCSBiasing = totBiasedAdjointCS / fTotAdjointCS;
}
return totBiasedAdjointCS;
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointPhotoElectricModel::GetAdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double electronEnergy,
G4bool IsScatProjToProjCase)
{ return AdjointCrossSection(aCouple,electronEnergy,IsScatProjToProjCase);
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointPhotoElectricModel::AdjointCrossSectionPerAtom(const G4Element* anElement,G4double electronEnergy)
{
G4int nShells = anElement->GetNbOfAtomicShells();
G4double Z= anElement->GetZ();
G4int i = 0;
G4double B0=anElement->GetAtomicShell(0);
G4double gammaEnergy = electronEnergy+B0;
G4double CS= theDirectPEEffectModel->ComputeCrossSectionPerAtom(G4Gamma::Gamma(),gammaEnergy,Z,0.,0.,0.);
G4double adjointCS =0.;
if (CS >0) adjointCS += CS/gammaEnergy;
shell_prob[index_element][0] = adjointCS;
for (i=1;i<nShells;i++){
//G4cout<<i<<G4endl;
G4double Bi_= anElement->GetAtomicShell(i-1);
G4double Bi = anElement->GetAtomicShell(i);
//G4cout<<Bi_<<'\t'<<Bi<<G4endl;
if (electronEnergy <Bi_-Bi) {
gammaEnergy = electronEnergy+Bi;
CS=theDirectPEEffectModel->ComputeCrossSectionPerAtom(G4Gamma::Gamma(),gammaEnergy,Z,0.,0.,0.);
if (CS>0) adjointCS +=CS/gammaEnergy;
}
shell_prob[index_element][i] = adjointCS;
G4double G4AdjointPhotoElectricModel::AdjointCrossSectionPerAtom(
const G4Element* anElement, G4double electronEnergy)
{
G4int nShells = anElement->GetNbOfAtomicShells();
G4double Z = anElement->GetZ();
G4double gammaEnergy = electronEnergy + anElement->GetAtomicShell(0);
G4double CS = fDirectModel->ComputeCrossSectionPerAtom(
G4Gamma::Gamma(), gammaEnergy, Z, 0., 0., 0.);
G4double adjointCS = 0.;
if(CS > 0.)
adjointCS += CS / gammaEnergy;
fShellProb[fIndexElement][0] = adjointCS;
for(G4int i = 1; i < nShells; ++i)
{
G4double Bi1 = anElement->GetAtomicShell(i - 1);
G4double Bi = anElement->GetAtomicShell(i);
if(electronEnergy < Bi1 - Bi)
{
gammaEnergy = electronEnergy + Bi;
CS = fDirectModel->ComputeCrossSectionPerAtom(G4Gamma::Gamma(),
gammaEnergy, Z, 0., 0., 0.);
if(CS > 0.)
adjointCS += CS / gammaEnergy;
}
fShellProb[fIndexElement][i] = adjointCS;
}
adjointCS*=electronEnergy;
adjointCS *= electronEnergy;
return adjointCS;
}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointPhotoElectricModel::DefineCurrentMaterialAndElectronEnergy(const G4MaterialCutsCouple* couple, G4double anEnergy)
{ currentCouple = const_cast<G4MaterialCutsCouple*> (couple);
currentMaterial = const_cast<G4Material*> (couple->GetMaterial());
currentCoupleIndex = couple->GetIndex();
currentMaterialIndex = currentMaterial->GetIndex();
current_eEnergy = anEnergy;
theDirectPEEffectModel->SetCurrentCouple(couple);
}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointPhotoElectricModel::DefineCurrentMaterialAndElectronEnergy(
const G4MaterialCutsCouple* couple, G4double anEnergy)
{
fCurrentCouple = const_cast<G4MaterialCutsCouple*>(couple);
fCurrentMaterial = const_cast<G4Material*>(couple->GetMaterial());
fCurrenteEnergy = anEnergy;
fDirectModel->SetCurrentCouple(couple);
}
@@ -23,297 +23,249 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
//
//
// ------------------------------------------------------------
// GEANT 4 class implementation file
//
// Class Description
//
// This class is for adjoint process equivalent to direct process
//
// ------------------------------------------------------------
// Created by L.Desorgher 25 Sept. 2009 Inspired from G4WrapperProcess
// Created by L.Desorgher 25 Sept. 2009
// ------------------------------------------------------------
#include "G4AdjointProcessEquivalentToDirectProcess.hh"
#include "G4DynamicParticle.hh"
G4AdjointProcessEquivalentToDirectProcess::G4AdjointProcessEquivalentToDirectProcess(const G4String& aName,
G4VProcess* aProcess,
G4ParticleDefinition* fwd_particle_def)
:G4VProcess(aName)
{
theDirectProcess =aProcess;
theProcessType = theDirectProcess->GetProcessType();
theFwdParticleDef = fwd_particle_def;
#include "G4ParticleDefinition.hh"
#include "G4VProcess.hh"
G4AdjointProcessEquivalentToDirectProcess::
G4AdjointProcessEquivalentToDirectProcess(
const G4String& aName, G4VProcess* aProcess,
G4ParticleDefinition* fwd_particle_def)
: G4VProcess(aName)
{
fDirectProcess = aProcess;
theProcessType = fDirectProcess->GetProcessType();
fFwdParticleDef = fwd_particle_def;
}
G4AdjointProcessEquivalentToDirectProcess::~G4AdjointProcessEquivalentToDirectProcess()
G4AdjointProcessEquivalentToDirectProcess::
~G4AdjointProcessEquivalentToDirectProcess()
{
if (theDirectProcess!=0) delete theDirectProcess;
if(fDirectProcess != nullptr)
delete fDirectProcess;
}
void G4AdjointProcessEquivalentToDirectProcess::ResetNumberOfInteractionLengthLeft()
void G4AdjointProcessEquivalentToDirectProcess::
ResetNumberOfInteractionLengthLeft()
{
theDirectProcess->ResetNumberOfInteractionLengthLeft();
fDirectProcess->ResetNumberOfInteractionLengthLeft();
}
G4double G4AdjointProcessEquivalentToDirectProcess::
AlongStepGetPhysicalInteractionLength( const G4Track& track,
G4double previousStepSize,
G4double currentMinimumStep,
G4double& proposedSafety,
G4GPILSelection* selection )
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
AlongStepGetPhysicalInteractionLength(const G4Track& track,
G4double previousStepSize,
G4double currentMinimumStep,
G4double& proposedSafety,
G4GPILSelection* selection)
{
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4double GPIL = theDirectProcess->
AlongStepGetPhysicalInteractionLength( track,
previousStepSize,
currentMinimumStep,
proposedSafety,
selection );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4double GPIL = fDirectProcess->AlongStepGetPhysicalInteractionLength(
track, previousStepSize, currentMinimumStep, proposedSafety, selection);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return GPIL;
}
G4double G4AdjointProcessEquivalentToDirectProcess::
AtRestGetPhysicalInteractionLength( const G4Track& track,
G4ForceCondition* condition )
{ //Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
G4double
G4AdjointProcessEquivalentToDirectProcess::AtRestGetPhysicalInteractionLength(
const G4Track& track, G4ForceCondition* condition)
{
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4double GPIL = theDirectProcess->AtRestGetPhysicalInteractionLength( track, condition );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4double GPIL =
fDirectProcess->AtRestGetPhysicalInteractionLength(track, condition);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return GPIL;
}
G4double G4AdjointProcessEquivalentToDirectProcess::
PostStepGetPhysicalInteractionLength( const G4Track& track,
G4double previousStepSize,
G4ForceCondition* condition )
G4double
G4AdjointProcessEquivalentToDirectProcess::PostStepGetPhysicalInteractionLength(
const G4Track& track, G4double previousStepSize, G4ForceCondition* condition)
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4double GPIL = theDirectProcess->PostStepGetPhysicalInteractionLength( track,
previousStepSize,
condition );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4double GPIL = fDirectProcess->PostStepGetPhysicalInteractionLength(
track, previousStepSize, condition);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return GPIL;
}
/*
void G4AdjointProcessEquivalentToDirectProcess::SetProcessManager(const G4ProcessManager* procMan)
{
theDirectProcess->SetProcessManager(procMan);
return GPIL;
}
const G4ProcessManager* G4AdjointProcessEquivalentToDirectProcess::GetProcessManager()
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::PostStepDoIt(
const G4Track& track, const G4Step& stepData)
{
return theDirectProcess->GetProcessManager();
}
*/
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::PostStepDoIt( const G4Track& track,
const G4Step& stepData )
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4VParticleChange* partChange = theDirectProcess->PostStepDoIt( track, stepData );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4VParticleChange* partChange = fDirectProcess->PostStepDoIt(track, stepData);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return partChange;
}
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::AlongStepDoIt( const G4Track& track,
const G4Step& stepData )
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::AlongStepDoIt(
const G4Track& track, const G4Step& stepData)
{
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4VParticleChange* partChange =theDirectProcess->AlongStepDoIt( track, stepData );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4VParticleChange* partChange =
fDirectProcess->AlongStepDoIt(track, stepData);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return partChange;
return partChange;
}
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::AtRestDoIt( const G4Track& track,
const G4Step& stepData )
G4VParticleChange* G4AdjointProcessEquivalentToDirectProcess::AtRestDoIt(
const G4Track& track, const G4Step& stepData)
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track.GetDynamicParticle());
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track.GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
//Call the direct process
//----------------------
G4VParticleChange* partChange =theDirectProcess->AtRestDoIt( track, stepData );
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
// Call the direct process
G4VParticleChange* partChange = fDirectProcess->AtRestDoIt(track, stepData);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return partChange;
return partChange;
}
G4bool G4AdjointProcessEquivalentToDirectProcess::IsApplicable(const G4ParticleDefinition&)
G4bool G4AdjointProcessEquivalentToDirectProcess::IsApplicable(
const G4ParticleDefinition&)
{
return theDirectProcess->IsApplicable(*theFwdParticleDef);
return fDirectProcess->IsApplicable(*fFwdParticleDef);
}
void G4AdjointProcessEquivalentToDirectProcess::BuildPhysicsTable(const G4ParticleDefinition& )
void G4AdjointProcessEquivalentToDirectProcess::BuildPhysicsTable(
const G4ParticleDefinition&)
{
return theDirectProcess->BuildPhysicsTable(*theFwdParticleDef);
return fDirectProcess->BuildPhysicsTable(*fFwdParticleDef);
}
void G4AdjointProcessEquivalentToDirectProcess::PreparePhysicsTable(const G4ParticleDefinition& )
void G4AdjointProcessEquivalentToDirectProcess::PreparePhysicsTable(
const G4ParticleDefinition&)
{
return theDirectProcess->PreparePhysicsTable(*theFwdParticleDef);
return fDirectProcess->PreparePhysicsTable(*fFwdParticleDef);
}
G4bool G4AdjointProcessEquivalentToDirectProcess::
StorePhysicsTable(const G4ParticleDefinition* ,
const G4String& directory,
G4bool ascii)
G4bool G4AdjointProcessEquivalentToDirectProcess::StorePhysicsTable(
const G4ParticleDefinition*, const G4String& directory, G4bool ascii)
{
return theDirectProcess->StorePhysicsTable(theFwdParticleDef, directory, ascii);
}
G4bool G4AdjointProcessEquivalentToDirectProcess::
RetrievePhysicsTable( const G4ParticleDefinition* ,
const G4String& directory,
G4bool ascii)
return fDirectProcess->StorePhysicsTable(fFwdParticleDef, directory, ascii);
}
G4bool G4AdjointProcessEquivalentToDirectProcess::RetrievePhysicsTable(
const G4ParticleDefinition*, const G4String& directory, G4bool ascii)
{
return theDirectProcess->RetrievePhysicsTable(theFwdParticleDef, directory, ascii);
}
return fDirectProcess->RetrievePhysicsTable(fFwdParticleDef, directory,
ascii);
}
void G4AdjointProcessEquivalentToDirectProcess::StartTracking(G4Track* track)
{
//Change the particle definition to the direct one
//------------------------------------------------
G4DynamicParticle* theDynPart = const_cast<G4DynamicParticle*> (track->GetDynamicParticle());
// Change the particle definition to the direct one
G4DynamicParticle* theDynPart =
const_cast<G4DynamicParticle*>(track->GetDynamicParticle());
G4ParticleDefinition* adjPartDef = theDynPart->GetDefinition();
G4DecayProducts* decayProducts = const_cast<G4DecayProducts*> (theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*)(0));
theDynPart->SetDefinition(theFwdParticleDef);
theDirectProcess->StartTracking(track);
//Restore the adjoint particle definition to the direct one
//------------------------------------------------
G4DecayProducts* decayProducts =
const_cast<G4DecayProducts*>(theDynPart->GetPreAssignedDecayProducts());
theDynPart->SetPreAssignedDecayProducts((G4DecayProducts*) (0));
theDynPart->SetDefinition(fFwdParticleDef);
fDirectProcess->StartTracking(track);
// Restore the adjoint particle definition to the direct one
theDynPart->SetDefinition(adjPartDef);
theDynPart->SetPreAssignedDecayProducts(decayProducts);
return;
return;
}
void G4AdjointProcessEquivalentToDirectProcess::EndTracking()
{
theDirectProcess->EndTracking();
fDirectProcess->EndTracking();
}
@@ -23,193 +23,175 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointeIonisationModel.hh"
#include "G4AdjointCSManager.hh"
#include "G4PhysicalConstants.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointElectron.hh"
#include "G4Gamma.hh"
#include "G4AdjointGamma.hh"
#include "G4Electron.hh"
#include "G4ParticleChange.hh"
#include "G4PhysicalConstants.hh"
#include "G4TrackStatus.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointeIonisationModel::G4AdjointeIonisationModel():
G4VEmAdjointModel("Inv_eIon_model")
G4AdjointeIonisationModel::G4AdjointeIonisationModel()
: G4VEmAdjointModel("Inv_eIon_model")
{
UseMatrix =true;
UseMatrixPerElement = true;
ApplyCutInRange = true;
UseOnlyOneMatrixForAllElements = true;
CS_biasing_factor =1.;
WithRapidSampling = false;
theAdjEquivOfDirectPrimPartDef =G4AdjointElectron::AdjointElectron();
theAdjEquivOfDirectSecondPartDef=G4AdjointElectron::AdjointElectron();
theDirectPrimaryPartDef=G4Electron::Electron();
second_part_of_same_type=true;
fUseMatrix = true;
fUseMatrixPerElement = true;
fApplyCutInRange = true;
fOneMatrixForAllElements = true;
fAdjEquivDirectPrimPart = G4AdjointElectron::AdjointElectron();
fAdjEquivDirectSecondPart = G4AdjointElectron::AdjointElectron();
fDirectPrimaryPart = G4Electron::Electron();
fSecondPartSameType = true;
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointeIonisationModel::~G4AdjointeIonisationModel()
{;}
G4AdjointeIonisationModel::~G4AdjointeIonisationModel() {}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointeIonisationModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
void G4AdjointeIonisationModel::SampleSecondaries(
const G4Track& aTrack, G4bool IsScatProjToProj,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
// Elastic inverse scattering
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP = theAdjointPrimary->GetTotalMomentum();
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
//Elastic inverse scattering
//---------------------------------------------------------
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP =theAdjointPrimary->GetTotalMomentum();
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
//Sample secondary energy
//-----------------------
G4double projectileKinEnergy;
if (!WithRapidSampling ) { //used by default
projectileKinEnergy = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, IsScatProjToProjCase);
CorrectPostStepWeight(fParticleChange,
aTrack.GetWeight(),
adjointPrimKinEnergy,
projectileKinEnergy,
IsScatProjToProjCase); //Caution !!!this weight correction should be always applied
}
else { //only for test at the moment
G4double Emin,Emax;
if (IsScatProjToProjCase) {
Emin=GetSecondAdjEnergyMinForScatProjToProjCase(adjointPrimKinEnergy,currentTcutForDirectSecond);
Emax=GetSecondAdjEnergyMaxForScatProjToProjCase(adjointPrimKinEnergy);
}
else {
Emin=GetSecondAdjEnergyMinForProdToProjCase(adjointPrimKinEnergy);
Emax=GetSecondAdjEnergyMaxForProdToProjCase(adjointPrimKinEnergy);
}
projectileKinEnergy = Emin*std::pow(Emax/Emin,G4UniformRand());
lastCS=lastAdjointCSForScatProjToProjCase;
if ( !IsScatProjToProjCase) lastCS=lastAdjointCSForProdToProjCase;
G4double new_weight=aTrack.GetWeight();
G4double used_diffCS=lastCS*std::log(Emax/Emin)/projectileKinEnergy;
G4double needed_diffCS=adjointPrimKinEnergy/projectileKinEnergy;
if (!IsScatProjToProjCase) needed_diffCS *=DiffCrossSectionPerVolumePrimToSecond(currentMaterial,projectileKinEnergy,adjointPrimKinEnergy);
else needed_diffCS *=DiffCrossSectionPerVolumePrimToScatPrim(currentMaterial,projectileKinEnergy,adjointPrimKinEnergy);
new_weight*=needed_diffCS/used_diffCS;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
}
//Kinematic:
//we consider a two body elastic scattering for the forward processes where the projectile knock on an e- at rest and gives
// him part of its energy
//----------------------------------------------------------------------------------------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
//Companion
//-----------
G4double companionM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
if (IsScatProjToProjCase) {
companionM0=theAdjEquivOfDirectSecondPartDef->GetPDGMass();
}
G4double companionTotalEnergy =companionM0+ projectileKinEnergy-adjointPrimKinEnergy;
G4double companionP2 = companionTotalEnergy*companionTotalEnergy - companionM0*companionM0;
//Projectile momentum
//--------------------
G4double P_parallel = (adjointPrimP*adjointPrimP + projectileP2 - companionP2)/(2.*adjointPrimP);
G4double P_perp = std::sqrt( projectileP2 - P_parallel*P_parallel);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector projectileMomentum = G4ThreeVector(P_perp*std::cos(phi),P_perp*std::sin(phi),P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
//G4cout<<"projectileMomentum "<<projectileMomentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
// Sample secondary energy
G4double projectileKinEnergy;
if(!fWithRapidSampling)
{ // used by default
projectileKinEnergy =
SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, IsScatProjToProj);
// Caution!!! this weight correction should be always applied
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
adjointPrimKinEnergy, projectileKinEnergy,
IsScatProjToProj);
}
else
{ // only for testing
G4double Emin, Emax;
if(IsScatProjToProj)
{
Emin = GetSecondAdjEnergyMinForScatProjToProj(adjointPrimKinEnergy,
fTcutSecond);
Emax = GetSecondAdjEnergyMaxForScatProjToProj(adjointPrimKinEnergy);
}
else
{
Emin = GetSecondAdjEnergyMinForProdToProj(adjointPrimKinEnergy);
Emax = GetSecondAdjEnergyMaxForProdToProj(adjointPrimKinEnergy);
}
projectileKinEnergy = Emin * std::pow(Emax / Emin, G4UniformRand());
fLastCS = fLastAdjointCSForScatProjToProj;
if(!IsScatProjToProj)
fLastCS = fLastAdjointCSForProdToProj;
G4double new_weight = aTrack.GetWeight();
G4double used_diffCS =
fLastCS * std::log(Emax / Emin) / projectileKinEnergy;
G4double needed_diffCS = adjointPrimKinEnergy / projectileKinEnergy;
if(!IsScatProjToProj)
needed_diffCS *= DiffCrossSectionPerVolumePrimToSecond(
fCurrentMaterial, projectileKinEnergy, adjointPrimKinEnergy);
else
needed_diffCS *= DiffCrossSectionPerVolumePrimToScatPrim(
fCurrentMaterial, projectileKinEnergy, adjointPrimKinEnergy);
new_weight *= needed_diffCS / used_diffCS;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
}
// Kinematic:
// we consider a two body elastic scattering for the forward processes where
// the projectile knock on an e- at rest and gives it part of its energy
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
// Companion
G4double companionM0 = fAdjEquivDirectPrimPart->GetPDGMass();
if(IsScatProjToProj)
{
companionM0 = fAdjEquivDirectSecondPart->GetPDGMass();
}
G4double companionTotalEnergy =
companionM0 + projectileKinEnergy - adjointPrimKinEnergy;
G4double companionP2 =
companionTotalEnergy * companionTotalEnergy - companionM0 * companionM0;
// Projectile momentum
G4double P_parallel =
(adjointPrimP * adjointPrimP + projectileP2 - companionP2) /
(2. * adjointPrimP);
G4double P_perp = std::sqrt(projectileP2 - P_parallel * P_parallel);
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector projectileMomentum =
G4ThreeVector(P_perp * std::cos(phi), P_perp * std::sin(phi), P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if(!IsScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
//The implementation here is correct for energy loss process, for the photoelectric and compton scattering the method should be redefine
// The implementation here is correct for energy loss process, for the
// photoelectric and compton scattering the method should be redefined
G4double G4AdjointeIonisationModel::DiffCrossSectionPerAtomPrimToSecond(
G4double kinEnergyProj,
G4double kinEnergyProd,
G4double Z,
G4double )
G4double kinEnergyProj, G4double kinEnergyProd, G4double Z, G4double)
{
G4double dSigmadEprod=0;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(kinEnergyProd);
if (kinEnergyProj>Emin_proj && kinEnergyProj<=Emax_proj){ //the produced particle should have a kinetic energy smaller than the projectile
dSigmadEprod=Z*DiffCrossSectionMoller(kinEnergyProj,kinEnergyProd);
}
return dSigmadEprod;
G4double dSigmadEprod = 0.;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
// the produced particle should have a kinetic energy smaller than the
// projectile
if(kinEnergyProj > Emin_proj && kinEnergyProj <= Emax_proj)
{
dSigmadEprod = Z * DiffCrossSectionMoller(kinEnergyProj, kinEnergyProd);
}
return dSigmadEprod;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointeIonisationModel::DiffCrossSectionMoller(G4double kinEnergyProj,G4double kinEnergyProd){
G4double energy = kinEnergyProj + electron_mass_c2;
G4double x = kinEnergyProd/kinEnergyProj;
G4double gam = energy/electron_mass_c2;
G4double gamma2 = gam*gam;
G4double beta2 = 1.0 - 1.0/gamma2;
G4double gg = (2.0*gam - 1.0)/gamma2;
G4double y = 1.0 - x;
G4double fac=twopi_mc2_rcl2/electron_mass_c2;
G4double dCS = fac*( 1.-gg + ((1.0 - gg*x)/(x*x))
+ ((1.0 - gg*y)/(y*y)))/(beta2*(gam-1));
return dCS/kinEnergyProj;
}
G4double G4AdjointeIonisationModel::DiffCrossSectionMoller(
G4double kinEnergyProj, G4double kinEnergyProd)
{
// G4double energy = kinEnergyProj + electron_mass_c2;
G4double x = kinEnergyProd / kinEnergyProj;
G4double gam = (kinEnergyProj + electron_mass_c2) / electron_mass_c2;
G4double gamma2 = gam * gam;
G4double beta2 = 1.0 - 1.0 / gamma2;
G4double gg = (2.0 * gam - 1.0) / gamma2;
G4double y = 1.0 - x;
G4double fac = twopi_mc2_rcl2 / electron_mass_c2;
G4double dCS =
fac * (1. - gg + ((1.0 - gg * x) / (x * x)) + ((1.0 - gg * y) / (y * y))) /
(beta2 * (gam - 1.));
return dCS / kinEnergyProj;
}
@@ -23,476 +23,444 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4AdjointhIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4AdjointCSManager.hh"
#include "G4Integrator.hh"
#include "G4TrackStatus.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointElectron.hh"
#include "G4AdjointProton.hh"
#include "G4AdjointInterpolator.hh"
#include "G4BetheBlochModel.hh"
#include "G4BraggModel.hh"
#include "G4Proton.hh"
#include "G4NistManager.hh"
#include "G4ParticleChange.hh"
#include "G4PhysicalConstants.hh"
#include "G4Proton.hh"
#include "G4SystemOfUnits.hh"
#include "G4TrackStatus.hh"
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointhIonisationModel::G4AdjointhIonisationModel(G4ParticleDefinition* projectileDefinition):
G4VEmAdjointModel("Adjoint_hIonisation")
{
G4AdjointhIonisationModel::G4AdjointhIonisationModel(G4ParticleDefinition* pDef)
: G4VEmAdjointModel("Adjoint_hIonisation")
{
fUseMatrix = true;
fUseMatrixPerElement = true;
fApplyCutInRange = true;
fOneMatrixForAllElements = true;
fSecondPartSameType = false;
// The direct EM Model is taken as BetheBloch. It is only used for the
// computation of the differential cross section.
// The Bragg model could be used as an alternative as it offers the same
// differential cross section
fDirectModel = new G4BetheBlochModel(pDef);
fBraggDirectEMModel = new G4BraggModel(pDef);
fAdjEquivDirectSecondPart = G4AdjointElectron::AdjointElectron();
fDirectPrimaryPart = pDef;
UseMatrix =true;
UseMatrixPerElement = true;
ApplyCutInRange = true;
UseOnlyOneMatrixForAllElements = true;
CS_biasing_factor =1.;
second_part_of_same_type =false;
//The direct EM Modfel is taken has BetheBloch it is only used for the computation
// of the differential cross section.
//The Bragg model could be used as an alternative as it offers the same differential cross section
theDirectEMModel = new G4BetheBlochModel(projectileDefinition);
theBraggDirectEMModel = new G4BraggModel(projectileDefinition);
theAdjEquivOfDirectSecondPartDef=G4AdjointElectron::AdjointElectron();
theDirectPrimaryPartDef = projectileDefinition;
theAdjEquivOfDirectPrimPartDef = 0;
if (projectileDefinition == G4Proton::Proton()) {
theAdjEquivOfDirectPrimPartDef = G4AdjointProton::AdjointProton();
if(pDef == G4Proton::Proton())
{
fAdjEquivDirectPrimPart = G4AdjointProton::AdjointProton();
}
DefineProjectileProperty();
}
////////////////////////////////////////////////////////////////////////////////
//
G4AdjointhIonisationModel::~G4AdjointhIonisationModel()
{;}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointhIonisationModel::SampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
if (!UseMatrix) return RapidSampleSecondaries(aTrack,IsScatProjToProjCase,fParticleChange);
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
//Elastic inverse scattering
//---------------------------------------------------------
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP =theAdjointPrimary->GetTotalMomentum();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
//Sample secondary energy
//-----------------------
G4double projectileKinEnergy = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, IsScatProjToProjCase);
CorrectPostStepWeight(fParticleChange,
aTrack.GetWeight(),
adjointPrimKinEnergy,
projectileKinEnergy,
IsScatProjToProjCase); //Caution !!!this weight correction should be always applied
//Kinematic:
//we consider a two body elastic scattering for the forward processes where the projectile knock on an e- at rest and gives
// him part of its energy
//----------------------------------------------------------------------------------------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
//Companion
//-----------
G4double companionM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
if (IsScatProjToProjCase) {
companionM0=theAdjEquivOfDirectSecondPartDef->GetPDGMass();
}
G4double companionTotalEnergy =companionM0+ projectileKinEnergy-adjointPrimKinEnergy;
G4double companionP2 = companionTotalEnergy*companionTotalEnergy - companionM0*companionM0;
//Projectile momentum
//--------------------
G4double P_parallel = (adjointPrimP*adjointPrimP + projectileP2 - companionP2)/(2.*adjointPrimP);
G4double P_perp = std::sqrt( projectileP2 - P_parallel*P_parallel);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector projectileMomentum = G4ThreeVector(P_perp*std::cos(phi),P_perp*std::sin(phi),P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
//G4cout<<"projectileMomentum "<<projectileMomentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
G4AdjointhIonisationModel::~G4AdjointhIonisationModel() {}
////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointhIonisationModel::RapidSampleSecondaries(const G4Track& aTrack,
G4bool IsScatProjToProjCase,
G4ParticleChange* fParticleChange)
{
void G4AdjointhIonisationModel::SampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
if(!fUseMatrix)
return RapidSampleSecondaries(aTrack, isScatProjToProj, fParticleChange);
const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP =theAdjointPrimary->GetTotalMomentum();
if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
return;
}
G4double projectileKinEnergy =0.;
G4double eEnergy=0.;
G4double newCS=currentMaterial->GetElectronDensity()*twopi_mc2_rcl2*mass;
if (!IsScatProjToProjCase){//1/E^2 distribution
eEnergy=adjointPrimKinEnergy;
G4double Emax = GetSecondAdjEnergyMaxForProdToProjCase(adjointPrimKinEnergy);
G4double Emin= GetSecondAdjEnergyMinForProdToProjCase(adjointPrimKinEnergy);
if (Emin>=Emax) return;
G4double a=1./Emax;
G4double b=1./Emin;
newCS=newCS*(b-a)/eEnergy;
projectileKinEnergy =1./(b- (b-a)*G4UniformRand());
}
else { G4double Emax = GetSecondAdjEnergyMaxForScatProjToProjCase(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForScatProjToProjCase(adjointPrimKinEnergy,currentTcutForDirectSecond);
if (Emin>=Emax) return;
G4double diff1=Emin-adjointPrimKinEnergy;
G4double diff2=Emax-adjointPrimKinEnergy;
G4double t1=adjointPrimKinEnergy*(1./diff1-1./diff2);
G4double t2=adjointPrimKinEnergy*(1./Emin-1./Emax);
/*G4double f31=diff1/Emin;
G4double f32=diff2/Emax/f31;*/
G4double t3=2.*std::log(Emax/Emin);
G4double sum_t=t1+t2+t3;
newCS=newCS*sum_t/adjointPrimKinEnergy/adjointPrimKinEnergy;
G4double t=G4UniformRand()*sum_t;
if (t <=t1 ){
G4double q= G4UniformRand()*t1/adjointPrimKinEnergy ;
projectileKinEnergy =adjointPrimKinEnergy +1./(1./diff1-q);
}
else if (t <=t2 ) {
G4double q= G4UniformRand()*t2/adjointPrimKinEnergy;
projectileKinEnergy =1./(1./Emin-q);
}
else {
projectileKinEnergy=Emin*std::pow(Emax/Emin,G4UniformRand());
}
eEnergy=projectileKinEnergy-adjointPrimKinEnergy;
}
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
// Elastic inverse scattering
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP = theAdjointPrimary->GetTotalMomentum();
G4double diffCS_perAtom_Used=twopi_mc2_rcl2*mass*adjointPrimKinEnergy/projectileKinEnergy/projectileKinEnergy/eEnergy/eEnergy;
//Weight correction
//-----------------------
//First w_corr is set to the ratio between adjoint total CS and fwd total CS
G4double w_corr=G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
//G4cout<<w_corr<<G4endl;
w_corr*=newCS/lastCS;
//G4cout<<w_corr<<G4endl;
//Then another correction is needed due to the fact that a biaised differential CS has been used rather than the one consistent with the direct model
//Here we consider the true diffCS as the one obtained by the numerical differentiation over Tcut of the direct CS
G4double diffCS = DiffCrossSectionPerAtomPrimToSecond(projectileKinEnergy, eEnergy,1,1);
w_corr*=diffCS/diffCS_perAtom_Used;
//G4cout<<w_corr<<G4endl;
G4double new_weight = aTrack.GetWeight()*w_corr;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
//Kinematic:
//we consider a two body elastic scattering for the forward processes where the projectile knock on an e- at rest and gives
// him part of its energy
//----------------------------------------------------------------------------------------
G4double projectileM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
//Companion
//-----------
G4double companionM0 = theAdjEquivOfDirectPrimPartDef->GetPDGMass();
if (IsScatProjToProjCase) {
companionM0=theAdjEquivOfDirectSecondPartDef->GetPDGMass();
}
G4double companionTotalEnergy =companionM0+ projectileKinEnergy-adjointPrimKinEnergy;
G4double companionP2 = companionTotalEnergy*companionTotalEnergy - companionM0*companionM0;
//Projectile momentum
//--------------------
G4double P_parallel = (adjointPrimP*adjointPrimP + projectileP2 - companionP2)/(2.*adjointPrimP);
G4double P_perp = std::sqrt( projectileP2 - P_parallel*P_parallel);
G4ThreeVector dir_parallel=theAdjointPrimary->GetMomentumDirection();
G4double phi =G4UniformRand()*2.*3.1415926;
G4ThreeVector projectileMomentum = G4ThreeVector(P_perp*std::cos(phi),P_perp*std::sin(phi),P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
//G4cout<<"projectileMomentum "<<projectileMomentum<<G4endl;
}
else {
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::DiffCrossSectionPerAtomPrimToSecond(
G4double kinEnergyProj,
G4double kinEnergyProd,
G4double Z,
G4double A)
{//Probably that here the Bragg Model should be also used for kinEnergyProj/nuc<2MeV
G4double dSigmadEprod=0;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(kinEnergyProd);
if (kinEnergyProj>Emin_proj && kinEnergyProj<=Emax_proj){ //the produced particle should have a kinetic energy smaller than the projectile
G4double Tmax=kinEnergyProj;
G4double E1=kinEnergyProd;
G4double E2=kinEnergyProd*1.000001;
G4double dE=(E2-E1);
G4double sigma1,sigma2;
if (kinEnergyProj >2.*MeV){
sigma1=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E1,1.e20);
sigma2=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E2,1.e20);
}
else {
sigma1=theBraggDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E1,1.e20);
sigma2=theBraggDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,Z,A ,E2,1.e20);
}
dSigmadEprod=(sigma1-sigma2)/dE;
if (dSigmadEprod>1.) {
G4cout<<"sigma1 "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<sigma1<<G4endl;
G4cout<<"sigma2 "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<sigma2<<G4endl;
G4cout<<"dsigma "<<kinEnergyProj/MeV<<'\t'<<kinEnergyProd/MeV<<'\t'<<dSigmadEprod<<G4endl;
}
//correction of differential cross section at high energy to correct for the suppression of particle at secondary at high
//energy used in the Bethe Bloch Model. This correction consist to multiply by g the probability function used
//to test the rejection of a secondary
//-------------------------
//Source code taken from G4BetheBlochModel::SampleSecondaries
G4double deltaKinEnergy = kinEnergyProd;
//Part of the taken code
//----------------------
// projectile formfactor - suppresion of high energy
// delta-electron production at high energy
G4double x = formfact*deltaKinEnergy;
if(x > 1.e-6) {
G4double totEnergy = kinEnergyProj + mass;
G4double etot2 = totEnergy*totEnergy;
G4double beta2 = kinEnergyProj*(kinEnergyProj + 2.0*mass)/etot2;
G4double f;
G4double f1 = 0.0;
f = 1.0 - beta2*deltaKinEnergy/Tmax;
if( 0.5 == spin ) {
f1 = 0.5*deltaKinEnergy*deltaKinEnergy/etot2;
f += f1;
}
G4double x1 = 1.0 + x;
G4double gg = 1.0/(x1*x1);
if( 0.5 == spin ) {
G4double x2 = 0.5*electron_mass_c2*deltaKinEnergy/(mass*mass);
gg *= (1.0 + magMoment2*(x2 - f1/f)/(1.0 + x2));
}
if(gg > 1.0) {
G4cout << "### G4BetheBlochModel in Adjoint Sim WARNING: g= " << g
<< G4endl;
gg=1.;
}
//G4cout<<"gg"<<gg<<G4endl;
dSigmadEprod*=gg;
}
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
return dSigmadEprod;
// Sample secondary energy
G4double projectileKinEnergy =
SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, isScatProjToProj);
CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
adjointPrimKinEnergy, projectileKinEnergy,
isScatProjToProj);
// Caution!!! this weight correction should be always applied
// Kinematic:
// we consider a two body elastic scattering for the forward processes where
// the projectile knock on an e- at rest and gives it part of its energy
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
// Companion
G4double companionM0 = fAdjEquivDirectPrimPart->GetPDGMass();
if(isScatProjToProj)
{
companionM0 = fAdjEquivDirectSecondPart->GetPDGMass();
}
G4double companionTotalEnergy =
companionM0 + projectileKinEnergy - adjointPrimKinEnergy;
G4double companionP2 =
companionTotalEnergy * companionTotalEnergy - companionM0 * companionM0;
// Projectile momentum
G4double P_parallel =
(adjointPrimP * adjointPrimP + projectileP2 - companionP2) /
(2. * adjointPrimP);
G4double P_perp = std::sqrt(projectileP2 - P_parallel * P_parallel);
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector projectileMomentum =
G4ThreeVector(P_perp * std::cos(phi), P_perp * std::sin(phi), P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointhIonisationModel::RapidSampleSecondaries(
const G4Track& aTrack, G4bool isScatProjToProj,
G4ParticleChange* fParticleChange)
{
const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
DefineCurrentMaterial(aTrack.GetMaterialCutsCouple());
G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
G4double adjointPrimP = theAdjointPrimary->GetTotalMomentum();
//////////////////////////////////////////////////////////////////////////////////////////////
//
void G4AdjointhIonisationModel::DefineProjectileProperty()
{
//Slightly modified code taken from G4BetheBlochModel::SetParticle
//------------------------------------------------
G4String pname = theDirectPrimaryPartDef->GetParticleName();
if (theDirectPrimaryPartDef->GetParticleType() == "nucleus" &&
pname != "deuteron" && pname != "triton") {
isIon = true;
if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
{
return;
}
G4double projectileKinEnergy = 0.;
G4double eEnergy = 0.;
G4double newCS =
fCurrentMaterial->GetElectronDensity() * twopi_mc2_rcl2 * fMass;
if(!isScatProjToProj)
{ // 1/E^2 distribution
eEnergy = adjointPrimKinEnergy;
G4double Emax = GetSecondAdjEnergyMaxForProdToProj(adjointPrimKinEnergy);
G4double Emin = GetSecondAdjEnergyMinForProdToProj(adjointPrimKinEnergy);
if(Emin >= Emax)
return;
G4double a = 1. / Emax;
G4double b = 1. / Emin;
newCS = newCS * (b - a) / eEnergy;
projectileKinEnergy = 1. / (b - (b - a) * G4UniformRand());
}
else
{
G4double Emax =
GetSecondAdjEnergyMaxForScatProjToProj(adjointPrimKinEnergy);
G4double Emin =
GetSecondAdjEnergyMinForScatProjToProj(adjointPrimKinEnergy, fTcutSecond);
if(Emin >= Emax)
return;
G4double diff1 = Emin - adjointPrimKinEnergy;
G4double diff2 = Emax - adjointPrimKinEnergy;
G4double t1 = adjointPrimKinEnergy * (1. / diff1 - 1. / diff2);
G4double t2 = adjointPrimKinEnergy * (1. / Emin - 1. / Emax);
G4double t3 = 2. * std::log(Emax / Emin);
G4double sum_t = t1 + t2 + t3;
newCS = newCS * sum_t / adjointPrimKinEnergy / adjointPrimKinEnergy;
G4double t = G4UniformRand() * sum_t;
if(t <= t1)
{
G4double q = G4UniformRand() * t1 / adjointPrimKinEnergy;
projectileKinEnergy = adjointPrimKinEnergy + 1. / (1. / diff1 - q);
}
mass = theDirectPrimaryPartDef->GetPDGMass();
mass_ratio_projectile = proton_mass_c2/theDirectPrimaryPartDef->GetPDGMass();;
spin = theDirectPrimaryPartDef->GetPDGSpin();
G4double q = theDirectPrimaryPartDef->GetPDGCharge()/eplus;
chargeSquare = q*q;
ratio = electron_mass_c2/mass;
ratio2 = ratio*ratio;
one_plus_ratio_2=(1+ratio)*(1+ratio);
one_minus_ratio_2=(1-ratio)*(1-ratio);
G4double magmom = theDirectPrimaryPartDef->GetPDGMagneticMoment()
*mass/(0.5*eplus*hbar_Planck*c_squared);
magMoment2 = magmom*magmom - 1.0;
formfact = 0.0;
if(theDirectPrimaryPartDef->GetLeptonNumber() == 0) {
G4double x = 0.8426*GeV;
if(spin == 0.0 && mass < GeV) {x = 0.736*GeV;}
else if(mass > GeV) {
x /= G4NistManager::Instance()->GetZ13(mass/proton_mass_c2);
// tlimit = 51.2*GeV*A13[iz]*A13[iz];
}
formfact = 2.0*electron_mass_c2/(x*x);
tlimit = 2.0/formfact;
}
else if(t <= t2)
{
G4double q = G4UniformRand() * t2 / adjointPrimKinEnergy;
projectileKinEnergy = 1. / (1. / Emin - q);
}
else
{
projectileKinEnergy = Emin * std::pow(Emax / Emin, G4UniformRand());
}
eEnergy = projectileKinEnergy - adjointPrimKinEnergy;
}
G4double diffCS_perAtom_Used = twopi_mc2_rcl2 * fMass * adjointPrimKinEnergy /
projectileKinEnergy / projectileKinEnergy /
eEnergy / eEnergy;
// Weight correction
// First w_corr is set to the ratio between adjoint total CS and fwd total CS
G4double w_corr =
G4AdjointCSManager::GetAdjointCSManager()->GetPostStepWeightCorrection();
w_corr *= newCS / fLastCS;
// Then another correction is needed due to the fact that a biaised
// differential CS has been used rather than the one consistent with the
// direct model. Here we consider the true diffCS as the one obtained by the
// numerical differentiation over Tcut of the direct CS
G4double diffCS =
DiffCrossSectionPerAtomPrimToSecond(projectileKinEnergy, eEnergy, 1, 1);
w_corr *= diffCS / diffCS_perAtom_Used;
G4double new_weight = aTrack.GetWeight() * w_corr;
fParticleChange->SetParentWeightByProcess(false);
fParticleChange->SetSecondaryWeightByProcess(false);
fParticleChange->ProposeParentWeight(new_weight);
// Kinematic:
// we consider a two body elastic scattering for the forward processes where
// the projectile knocks on an e- at rest and gives it part of its energy
G4double projectileM0 = fAdjEquivDirectPrimPart->GetPDGMass();
G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
G4double projectileP2 =
projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
// Companion
G4double companionM0 = fAdjEquivDirectPrimPart->GetPDGMass();
if(isScatProjToProj)
{
companionM0 = fAdjEquivDirectSecondPart->GetPDGMass();
}
G4double companionTotalEnergy =
companionM0 + projectileKinEnergy - adjointPrimKinEnergy;
G4double companionP2 =
companionTotalEnergy * companionTotalEnergy - companionM0 * companionM0;
// Projectile momentum
G4double P_parallel =
(adjointPrimP * adjointPrimP + projectileP2 - companionP2) /
(2. * adjointPrimP);
G4double P_perp = std::sqrt(projectileP2 - P_parallel * P_parallel);
G4ThreeVector dir_parallel = theAdjointPrimary->GetMomentumDirection();
G4double phi = G4UniformRand() * twopi;
G4ThreeVector projectileMomentum =
G4ThreeVector(P_perp * std::cos(phi), P_perp * std::sin(phi), P_parallel);
projectileMomentum.rotateUz(dir_parallel);
if(!isScatProjToProj)
{ // kill the primary and add a secondary
fParticleChange->ProposeTrackStatus(fStopAndKill);
fParticleChange->AddSecondary(
new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
}
else
{
fParticleChange->ProposeEnergy(projectileKinEnergy);
fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
}
}
////////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::AdjointCrossSection(const G4MaterialCutsCouple* aCouple,
G4double primEnergy,
G4bool IsScatProjToProjCase)
{
if (UseMatrix) return G4VEmAdjointModel::AdjointCrossSection(aCouple,primEnergy,IsScatProjToProjCase);
DefineCurrentMaterial(aCouple);
G4double Cross=currentMaterial->GetElectronDensity()*twopi_mc2_rcl2*mass;
if (!IsScatProjToProjCase ){
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(primEnergy);
if (Emax_proj>Emin_proj && primEnergy > currentTcutForDirectSecond) {
Cross*=(1./Emin_proj -1./Emax_proj)/primEnergy;
}
else Cross=0.;
G4double G4AdjointhIonisationModel::DiffCrossSectionPerAtomPrimToSecond(
G4double kinEnergyProj, G4double kinEnergyProd, G4double Z, G4double A)
{ // Probably here the Bragg Model should be also used for
// kinEnergyProj/nuc < 2 MeV
}
else {
G4double Emax_proj = GetSecondAdjEnergyMaxForScatProjToProjCase(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForScatProjToProjCase(primEnergy,currentTcutForDirectSecond);
G4double diff1=Emin_proj-primEnergy;
G4double diff2=Emax_proj-primEnergy;
G4double t1=(1./diff1+1./Emin_proj-1./diff2-1./Emax_proj)/primEnergy;
//G4double t2=2.*std::log(diff2*Emin_proj/Emax_proj/diff1)/primEnergy/primEnergy;
G4double t2=2.*std::log(Emax_proj/Emin_proj)/primEnergy/primEnergy;
Cross*=(t1+t2);
G4double dSigmadEprod = 0.;
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
// the produced particle should have a kinetic energy smaller than the
// projectile
if(kinEnergyProj > Emin_proj && kinEnergyProj <= Emax_proj)
{
G4double Tmax = kinEnergyProj;
G4double E1 = kinEnergyProd;
G4double E2 = kinEnergyProd * 1.000001;
G4double sigma1, sigma2;
if(kinEnergyProj > 2. * MeV)
{
sigma1 = fDirectModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E1, 1.e20);
sigma2 = fDirectModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E2, 1.e20);
}
else
{
sigma1 = fBraggDirectEMModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E1, 1.e20);
sigma2 = fBraggDirectEMModel->ComputeCrossSectionPerAtom(
fDirectPrimaryPart, kinEnergyProj, Z, A, E2, 1.e20);
}
dSigmadEprod = (sigma1 - sigma2) / (E2 - E1);
if(dSigmadEprod > 1.)
{
G4cout << "sigma1 " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << sigma1 << G4endl;
G4cout << "sigma2 " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << sigma2 << G4endl;
G4cout << "dsigma " << kinEnergyProj / MeV << '\t' << kinEnergyProd / MeV
<< '\t' << dSigmadEprod << G4endl;
}
// correction of differential cross section at high energy to correct for
// the suppression of particle at secondary at high energy used in the Bethe
// Bloch Model. This correction consists of multiplying by g the probability
// function used to test the rejection of a secondary. Source code taken
// from G4BetheBlochModel::SampleSecondaries
G4double deltaKinEnergy = kinEnergyProd;
// projectile formfactor - suppression of high energy
// delta-electron production at high energy
G4double x = fFormFact * deltaKinEnergy;
if(x > 1.e-6)
{
G4double totEnergy = kinEnergyProj + fMass;
G4double etot2 = totEnergy * totEnergy;
G4double beta2 = kinEnergyProj * (kinEnergyProj + 2.0 * fMass) / etot2;
G4double f = 1.0 - beta2 * deltaKinEnergy / Tmax;
G4double f1 = 0.0;
if(0.5 == fSpin)
{
f1 = 0.5 * deltaKinEnergy * deltaKinEnergy / etot2;
f += f1;
}
G4double x1 = 1.0 + x;
G4double gg = 1.0 / (x1 * x1);
if(0.5 == fSpin)
{
G4double x2 = 0.5 * electron_mass_c2 * deltaKinEnergy / (fMass * fMass);
gg *= (1.0 + fMagMoment2 * (x2 - f1 / f) / (1.0 + x2));
}
if(gg > 1.0)
{
G4cout << "### G4BetheBlochModel in Adjoint Sim WARNING: g= " << g
<< G4endl;
gg = 1.;
}
dSigmadEprod *= gg;
}
}
lastCS =Cross;
return Cross;
return dSigmadEprod;
}
////////////////////////////////////////////////////////////////////////////////
void G4AdjointhIonisationModel::DefineProjectileProperty()
{
// Slightly modified code taken from G4BetheBlochModel::SetParticle
G4String pname = fDirectPrimaryPart->GetParticleName();
fMass = fDirectPrimaryPart->GetPDGMass();
fSpin = fDirectPrimaryPart->GetPDGSpin();
fMassRatio = electron_mass_c2 / fMass;
fOnePlusRatio2 = (1. + fMassRatio) * (1. + fMassRatio);
fOneMinusRatio2 = (1. - fMassRatio) * (1. - fMassRatio);
G4double magmom = fDirectPrimaryPart->GetPDGMagneticMoment() * fMass /
(0.5 * eplus * hbar_Planck * c_squared);
fMagMoment2 = magmom * magmom - 1.0;
fFormFact = 0.0;
if(fDirectPrimaryPart->GetLeptonNumber() == 0)
{
G4double x = 0.8426 * GeV;
if(fSpin == 0.0 && fMass < GeV)
{
x = 0.736 * GeV;
}
else if(fMass > GeV)
{
x /= G4NistManager::Instance()->GetZ13(fMass / proton_mass_c2);
}
fFormFact = 2.0 * electron_mass_c2 / (x * x);
}
}
////////////////////////////////////////////////////////////////////////////////
G4double G4AdjointhIonisationModel::AdjointCrossSection(
const G4MaterialCutsCouple* aCouple, G4double primEnergy,
G4bool isScatProjToProj)
{
if(fUseMatrix)
return G4VEmAdjointModel::AdjointCrossSection(aCouple, primEnergy,
isScatProjToProj);
DefineCurrentMaterial(aCouple);
G4double Cross =
fCurrentMaterial->GetElectronDensity() * twopi_mc2_rcl2 * fMass;
if(!isScatProjToProj)
{
G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(primEnergy);
G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(primEnergy);
if(Emax_proj > Emin_proj && primEnergy > fTcutSecond)
{
Cross *= (1. / Emin_proj - 1. / Emax_proj) / primEnergy;
}
else
Cross = 0.;
}
else
{
G4double Emax_proj = GetSecondAdjEnergyMaxForScatProjToProj(primEnergy);
G4double Emin_proj =
GetSecondAdjEnergyMinForScatProjToProj(primEnergy, fTcutSecond);
G4double diff1 = Emin_proj - primEnergy;
G4double diff2 = Emax_proj - primEnergy;
G4double t1 =
(1. / diff1 + 1. / Emin_proj - 1. / diff2 - 1. / Emax_proj) / primEnergy;
G4double t2 =
2. * std::log(Emax_proj / Emin_proj) / primEnergy / primEnergy;
Cross *= (t1 + t2);
}
fLastCS = Cross;
return Cross;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMaxForScatProjToProjCase(G4double PrimAdjEnergy)
{
G4double Tmax=PrimAdjEnergy*one_plus_ratio_2/(one_minus_ratio_2-2.*ratio*PrimAdjEnergy/mass);
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMaxForScatProjToProj(
G4double primAdjEnergy)
{
G4double Tmax = primAdjEnergy * fOnePlusRatio2 /
(fOneMinusRatio2 - 2. * fMassRatio * primAdjEnergy / fMass);
return Tmax;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMinForScatProjToProjCase(G4double PrimAdjEnergy,G4double Tcut)
{ return PrimAdjEnergy+Tcut;
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMinForScatProjToProj(
G4double primAdjEnergy, G4double tcut)
{
return primAdjEnergy + tcut;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMaxForProdToProjCase(G4double )
{ return HighEnergyLimit;
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMaxForProdToProj(G4double)
{
return GetHighEnergyLimit();
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMinForProdToProjCase(G4double PrimAdjEnergy)
{ G4double Tmin= (2*PrimAdjEnergy-4*mass + std::sqrt(4.*PrimAdjEnergy*PrimAdjEnergy +16.*mass*mass + 8.*PrimAdjEnergy*mass*(1/ratio +ratio)))/4.;
return Tmin;
G4double G4AdjointhIonisationModel::GetSecondAdjEnergyMinForProdToProj(
G4double primAdjEnergy)
{
G4double Tmin =
(2. * primAdjEnergy - 4. * fMass +
std::sqrt(4. * primAdjEnergy * primAdjEnergy + 16. * fMass * fMass +
8. * primAdjEnergy * fMass * (1. / fMassRatio + fMassRatio))) /
4.;
return Tmin;
}
@@ -23,92 +23,61 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
//
// GEANT4 Class file
// Geant4 class file
//
// File name: G4AdjointhMultipleScattering
//
// Author: Desorgher Laurent
//
// Creation date: 03.06.2009 cloned from G4hMultipleScattering by U.Laszlo with slight modification for adjoint_ion.
// Creation date: 03.06.2009 cloned from G4hMultipleScattering by U.Laszlo with
// slight modification for adjoint_ion.
//
// -----------------------------------------------------------------------------
//
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "G4AdjointhMultipleScattering.hh"
#include "G4MscStepLimitType.hh"
#include "G4SystemOfUnits.hh"
#include "G4UrbanMscModel.hh"
#include "G4MscStepLimitType.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
using namespace std;
G4AdjointhMultipleScattering::G4AdjointhMultipleScattering(const G4String& processName)
G4AdjointhMultipleScattering::G4AdjointhMultipleScattering(
const G4String& processName)
: G4VMultipleScattering(processName)
{
isInitialized = false;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4AdjointhMultipleScattering::~G4AdjointhMultipleScattering()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4AdjointhMultipleScattering::~G4AdjointhMultipleScattering() {}
G4bool G4AdjointhMultipleScattering::IsApplicable (const G4ParticleDefinition& p)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4AdjointhMultipleScattering::ProcessDescription(std::ostream& out) const
{
out << "Inverse multiple scattering process for hadrons.\n";
StreamProcessInfo(out);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4AdjointhMultipleScattering::StreamProcessInfo(std::ostream& out) const
{
out << " RangeFactor= " << RangeFactor()
<< ", step limit type: " << StepLimitType()
<< ", lateralDisplacement: " << LateralDisplasmentFlag()
<< ", skin= " << Skin() << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool G4AdjointhMultipleScattering::IsApplicable(const G4ParticleDefinition& p)
{
return (p.GetPDGCharge() != 0.0 && !p.IsShortLived());
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4AdjointhMultipleScattering::InitialiseProcess(const G4ParticleDefinition*)
void G4AdjointhMultipleScattering::InitialiseProcess(
const G4ParticleDefinition*)
{
if(isInitialized) { return; }
if(fIsInitialized)
{
return;
}
AddEmModel(1, new G4UrbanMscModel());
isInitialized = true;
fIsInitialized = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4AdjointhMultipleScattering::PrintInfo()
{
G4cout << " RangeFactor= " << RangeFactor()
<< ", step limit type: " << StepLimitType()
<< ", lateralDisplacement: " << LateralDisplasmentFlag()
<< ", skin= " << Skin()
<< G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
/*G4double G4AdjointhMultipleScattering::AlongStepGetPhysicalInteractionLength(
const G4Track& track,
double,
G4double currentMinimalStep,
G4double& currentSafety,
G4GPILSelection* selection)
{
// get Step limit proposed by the process
valueGPILSelectionMSC = NotCandidateForSelection;
G4double escaled = track.GetKineticEnergy();
if(isIon) escaled *= track.GetDynamicParticle()->GetMass()/proton_mass_c2;
G4double steplength = GetMscContinuousStepLimit(track,
escaled,
currentMinimalStep,
currentSafety);
// G4cout << "StepLimit= " << steplength << G4endl;
// set return value for G4GPILSelection
*selection = valueGPILSelectionMSC;
return steplength;
}
*/
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -27,299 +27,232 @@
#include "G4ContinuousGainOfEnergy.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Step.hh"
#include "G4ParticleDefinition.hh"
#include "G4VEmModel.hh"
#include "G4VEmFluctuationModel.hh"
#include "G4VParticleChange.hh"
#include "G4AdjointCSManager.hh"
#include "G4EmCorrections.hh"
#include "G4LossTableManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4Material.hh"
#include "G4MaterialCutsCouple.hh"
#include "G4ParticleChange.hh"
#include "G4ParticleDefinition.hh"
#include "G4PhysicalConstants.hh"
#include "G4Step.hh"
#include "G4SystemOfUnits.hh"
#include "G4VEmFluctuationModel.hh"
#include "G4VEmModel.hh"
#include "G4VEnergyLossProcess.hh"
#include "G4VParticleChange.hh"
///////////////////////////////////////////////////////
//
G4ContinuousGainOfEnergy::G4ContinuousGainOfEnergy(const G4String& name,
G4ProcessType type): G4VContinuousProcess(name, type)
G4ContinuousGainOfEnergy::G4ContinuousGainOfEnergy(const G4String& name,
G4ProcessType type)
: G4VContinuousProcess(name, type)
{}
///////////////////////////////////////////////////////
G4ContinuousGainOfEnergy::~G4ContinuousGainOfEnergy() {}
///////////////////////////////////////////////////////
void G4ContinuousGainOfEnergy::ProcessDescription(std::ostream& out) const
{
linLossLimit=0.05;
lossFluctuationArePossible =true;
lossFluctuationFlag=true;
is_integral = false;
//Will be properly set in SetDirectParticle()
IsIon=false;
massRatio =1.;
chargeSqRatio=1.;
preStepChargeSqRatio=1.;
//Some initialization
currentCoupleIndex=9999999;
currentCutInRange=0.;
currentMaterialIndex=9999999;
currentTcut=0.;
preStepKinEnergy=0.;
preStepRange=0.;
preStepScaledKinEnergy=0.;
currentCouple=0;
out << "Continuous process acting on adjoint particles to compute the "
"continuous gain of energy of charged particles when they are "
"tracked back.\n";
}
///////////////////////////////////////////////////////
//
G4ContinuousGainOfEnergy::~G4ContinuousGainOfEnergy()
void G4ContinuousGainOfEnergy::SetDirectParticle(G4ParticleDefinition* p)
{
}
///////////////////////////////////////////////////////
//
void G4ContinuousGainOfEnergy::PreparePhysicsTable(
const G4ParticleDefinition& )
{//theDirectEnergyLossProcess->PreparePhysicsTable(part);
;
}
///////////////////////////////////////////////////////
//
void G4ContinuousGainOfEnergy::BuildPhysicsTable(const G4ParticleDefinition&)
{//theDirectEnergyLossProcess->BuildPhysicsTable(part);
;
}
///////////////////////////////////////////////////////
//
void G4ContinuousGainOfEnergy::SetDirectParticle(G4ParticleDefinition* p)
{theDirectPartDef=p;
if (theDirectPartDef->GetParticleType()== "nucleus") {
IsIon=true;
massRatio = proton_mass_c2/theDirectPartDef->GetPDGMass();
G4double q=theDirectPartDef->GetPDGCharge();
chargeSqRatio=q*q;
}
}
///////////////////////////////////////////////////////
//
//
G4VParticleChange* G4ContinuousGainOfEnergy::AlongStepDoIt(const G4Track& track,
const G4Step& step)
{
//Caution in this method the step length should be the true step length
// A problem is that this is compute by the multiple scattering that does not know the energy at the end of the adjoint step. This energy is used during the
//Forward sim. Nothing we can really do against that at this time. This is inherent to the MS method
//
aParticleChange.Initialize(track);
// Get the actual (true) Step length
//----------------------------------
G4double length = step.GetStepLength();
G4double degain = 0.0;
// Compute this for weight change after continuous energy loss
//-------------------------------------------------------------
G4double DEDX_before = theDirectEnergyLossProcess->GetDEDX(preStepKinEnergy, currentCouple);
// For the fluctuation we generate a new dynamic particle with energy =preEnergy+egain
// and then compute the fluctuation given in the direct case.
//-----------------------------------------------------------------------
G4DynamicParticle* dynParticle = new G4DynamicParticle();
*dynParticle = *(track.GetDynamicParticle());
dynParticle->SetDefinition(theDirectPartDef);
G4double Tkin = dynParticle->GetKineticEnergy();
size_t n=1;
if (is_integral ) n=10;
n=1;
G4double dlength= length/n;
for (size_t i=0;i<n;i++) {
if (Tkin != preStepKinEnergy && IsIon) {
chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,Tkin);
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,chargeSqRatio);
}
G4double r = theDirectEnergyLossProcess->GetRange(Tkin, currentCouple);
if( dlength <= linLossLimit * r ) {
degain = DEDX_before*dlength;
}
else {
G4double x = r + dlength;
//degain = theDirectEnergyLossProcess->GetKineticEnergy(x,currentCouple) - theDirectEnergyLossProcess->GetKineticEnergy(r,currentCouple);
G4double E = theDirectEnergyLossProcess->GetKineticEnergy(x,currentCouple);
if (IsIon){
chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,E);
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,chargeSqRatio);
G4double x1= theDirectEnergyLossProcess->GetRange(E, currentCouple);
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
G4int ii=0;
const G4int iimax = 100;
while (std::abs(x-x1)>0.01*x) {
E = theDirectEnergyLossProcess->GetKineticEnergy(x,currentCouple);
chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,E);
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,chargeSqRatio);
x1= theDirectEnergyLossProcess->GetRange(E, currentCouple);
++ii;
if(ii >= iimax) { break; }
}
}
degain=E-Tkin;
}
//G4cout<<degain<<G4endl;
G4double tmax = currentModel->MaxSecondaryKinEnergy(dynParticle);
tmax = std::min(tmax,currentTcut);
dynParticle->SetKineticEnergy(Tkin+degain);
// Corrections, which cannot be tabulated for ions
//----------------------------------------
G4double esecdep=0;//not used in most models
currentModel->CorrectionsAlongStep(currentCouple, dynParticle, degain,esecdep, dlength);
// Sample fluctuations
//-------------------
G4double deltaE =0.;
if (lossFluctuationFlag ) {
deltaE = currentModel->GetModelOfFluctuations()->
SampleFluctuations(currentCouple,dynParticle,tmax,dlength,degain)-degain;
}
G4double egain=degain+deltaE;
if (egain <=0) egain=degain;
Tkin+=egain;
dynParticle->SetKineticEnergy(Tkin);
}
delete dynParticle;
if (IsIon){
chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,Tkin);
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,chargeSqRatio);
fDirectPartDef = p;
if(fDirectPartDef->GetParticleType() == "nucleus")
{
fIsIon = true;
fMassRatio = proton_mass_c2 / fDirectPartDef->GetPDGMass();
}
G4double DEDX_after = theDirectEnergyLossProcess->GetDEDX(Tkin, currentCouple);
G4double weight_correction=DEDX_after/DEDX_before;
}
///////////////////////////////////////////////////////
G4VParticleChange* G4ContinuousGainOfEnergy::AlongStepDoIt(const G4Track& track,
const G4Step& step)
{
// Caution in this method the step length should be the true step length
// A problem is that this is computed by the multiple scattering that does
// not know the energy at the end of the adjoint step. This energy is used
// during the forward sim. Nothing we can really do against that at this
// time. This is inherent to the MS method
aParticleChange.Initialize(track);
// Get the actual (true) Step length
G4double length = step.GetStepLength();
G4double degain = 0.0;
// Compute this for weight change after continuous energy loss
G4double DEDX_before =
fDirectEnergyLossProcess->GetDEDX(fPreStepKinEnergy, fCurrentCouple);
// For the fluctuation we generate a new dynamic particle with energy
// = preEnergy+egain and then compute the fluctuation given in the direct
// case.
G4DynamicParticle* dynParticle = new G4DynamicParticle();
*dynParticle = *(track.GetDynamicParticle());
dynParticle->SetDefinition(fDirectPartDef);
G4double Tkin = dynParticle->GetKineticEnergy();
G4double dlength = length;
if(Tkin != fPreStepKinEnergy && fIsIon)
{
G4double chargeSqRatio = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, Tkin);
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio, chargeSqRatio);
}
G4double r = fDirectEnergyLossProcess->GetRange(Tkin, fCurrentCouple);
if(dlength <= fLinLossLimit * r)
{
degain = DEDX_before * dlength;
}
else
{
G4double x = r + dlength;
G4double E = fDirectEnergyLossProcess->GetKineticEnergy(x, fCurrentCouple);
if(fIsIon)
{
G4double chargeSqRatio = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, E);
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio, chargeSqRatio);
G4double x1 = fDirectEnergyLossProcess->GetRange(E, fCurrentCouple);
G4int ii = 0;
constexpr G4int iimax = 100;
while(std::abs(x - x1) > 0.01 * x)
{
E = fDirectEnergyLossProcess->GetKineticEnergy(x, fCurrentCouple);
chargeSqRatio = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, E);
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio,
chargeSqRatio);
x1 = fDirectEnergyLossProcess->GetRange(E, fCurrentCouple);
++ii;
if(ii >= iimax)
{
break;
}
}
}
degain = E - Tkin;
}
G4double tmax = fCurrentModel->MaxSecondaryKinEnergy(dynParticle);
tmax = std::min(tmax, fCurrentTcut);
dynParticle->SetKineticEnergy(Tkin + degain);
// Corrections, which cannot be tabulated for ions
fCurrentModel->CorrectionsAlongStep(fCurrentCouple, dynParticle, dlength, degain);
// Sample fluctuations
G4double deltaE = 0.;
if(fLossFluctuationFlag)
{
deltaE = fCurrentModel->GetModelOfFluctuations()->SampleFluctuations(
fCurrentCouple, dynParticle, tmax, dlength, degain) -
degain;
}
G4double egain = degain + deltaE;
if(egain <= 0.)
egain = degain;
Tkin += egain;
dynParticle->SetKineticEnergy(Tkin);
delete dynParticle;
if(fIsIon)
{
G4double chargeSqRatio = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, Tkin);
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio, chargeSqRatio);
}
G4double DEDX_after = fDirectEnergyLossProcess->GetDEDX(Tkin, fCurrentCouple);
G4double weight_correction = DEDX_after / DEDX_before;
aParticleChange.ProposeEnergy(Tkin);
// Caution!!! It is important to select the weight of the post_step_point
// as the current weight and not the weight of the track, as the weight of
// the track is changed after having applied all the along_step_do_it.
//Caution!!!
// It is important to select the weight of the post_step_point
// as the current weight and not the weight of the track, as t
// the weight of the track is changed after having applied all
// the along_step_do_it.
// G4double new_weight=weight_correction*track.GetWeight(); //old
G4double new_weight=weight_correction*step.GetPostStepPoint()->GetWeight();
G4double new_weight =
weight_correction * step.GetPostStepPoint()->GetWeight();
aParticleChange.SetParentWeightByProcess(false);
aParticleChange.ProposeParentWeight(new_weight);
return &aParticleChange;
}
///////////////////////////////////////////////////////
//
void G4ContinuousGainOfEnergy::SetLossFluctuations(G4bool val)
{
if(val && !lossFluctuationArePossible) return;
lossFluctuationFlag = val;
if(val && !fLossFluctuationArePossible)
return;
fLossFluctuationFlag = val;
}
///////////////////////////////////////////////////////
//
G4double G4ContinuousGainOfEnergy::GetContinuousStepLimit(const G4Track& track,
G4double , G4double , G4double& )
{
G4double x = DBL_MAX;
x=.1*mm;
G4double, G4double,
G4double&)
{
DefineMaterial(track.GetMaterialCutsCouple());
preStepKinEnergy = track.GetKineticEnergy();
preStepScaledKinEnergy = track.GetKineticEnergy()*massRatio;
currentModel = theDirectEnergyLossProcess->SelectModelForMaterial(preStepScaledKinEnergy,currentCoupleIndex);
G4double emax_model=currentModel->HighEnergyLimit();
if (IsIon) {
chargeSqRatio = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,preStepKinEnergy);
preStepChargeSqRatio = chargeSqRatio;
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,preStepChargeSqRatio);
}
G4double maxE =1.1*preStepKinEnergy;
/*if (preStepKinEnergy< 0.05*MeV) maxE =2.*preStepKinEnergy;
else if (preStepKinEnergy< 0.1*MeV) maxE =1.5*preStepKinEnergy;
else if (preStepKinEnergy< 0.5*MeV) maxE =1.25*preStepKinEnergy;*/
if (preStepKinEnergy < currentTcut) maxE = std::min(currentTcut,maxE);
maxE=std::min(emax_model*1.001,maxE);
preStepRange = theDirectEnergyLossProcess->GetRange(preStepKinEnergy, currentCouple);
if (IsIon) {
G4double chargeSqRatioAtEmax = currentModel->GetChargeSquareRatio(theDirectPartDef,currentMaterial,maxE);
theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,chargeSqRatioAtEmax);
}
G4double r1 = theDirectEnergyLossProcess->GetRange(maxE, currentCouple);
if (IsIon) theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,preStepChargeSqRatio);
x=r1-preStepRange;
x=std::max(r1-preStepRange,0.001*mm);
return x;
fPreStepKinEnergy = track.GetKineticEnergy();
fCurrentModel = fDirectEnergyLossProcess->SelectModelForMaterial(
track.GetKineticEnergy() * fMassRatio, fCurrentCoupleIndex);
G4double emax_model = fCurrentModel->HighEnergyLimit();
G4double preStepChargeSqRatio = 0.;
if(fIsIon)
{
G4double chargeSqRatio = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, fPreStepKinEnergy);
preStepChargeSqRatio = chargeSqRatio;
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio,
preStepChargeSqRatio);
}
G4double maxE = 1.1 * fPreStepKinEnergy;
if(fPreStepKinEnergy < fCurrentTcut)
maxE = std::min(fCurrentTcut, maxE);
maxE = std::min(emax_model * 1.001, maxE);
G4double preStepRange =
fDirectEnergyLossProcess->GetRange(fPreStepKinEnergy, fCurrentCouple);
if(fIsIon)
{
G4double chargeSqRatioAtEmax = fCurrentModel->GetChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, maxE);
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio,
chargeSqRatioAtEmax);
}
G4double r1 = fDirectEnergyLossProcess->GetRange(maxE, fCurrentCouple);
if(fIsIon)
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio,
preStepChargeSqRatio);
return std::max(r1 - preStepRange, 0.001 * mm);
}
#include "G4EmCorrections.hh"
///////////////////////////////////////////////////////
//
void G4ContinuousGainOfEnergy::SetDynamicMassCharge(const G4Track& ,G4double energy)
{
G4double ChargeSqRatio= G4LossTableManager::Instance()->EmCorrections()->EffectiveChargeSquareRatio(theDirectPartDef,currentMaterial,energy);
if (theDirectEnergyLossProcess) theDirectEnergyLossProcess->SetDynamicMassCharge(massRatio,ChargeSqRatio);
void G4ContinuousGainOfEnergy::SetDynamicMassCharge(const G4Track&,
G4double energy)
{
G4double ChargeSqRatio =
G4LossTableManager::Instance()->EmCorrections()->EffectiveChargeSquareRatio(
fDirectPartDef, fCurrentMaterial, energy);
if(fDirectEnergyLossProcess)
fDirectEnergyLossProcess->SetDynamicMassCharge(fMassRatio, ChargeSqRatio);
}
@@ -23,22 +23,26 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4InversePEEffect.hh"
#include "G4VEmAdjointModel.hh"
#include "G4AdjointPhotoElectricModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4InversePEEffect::G4InversePEEffect(G4String process_name,G4AdjointPhotoElectricModel* aModel):
G4VAdjointReverseReaction(process_name,false)
{theAdjointEMModel = aModel;
theAdjointEMModel->SetSecondPartOfSameType(false);
SetIntegralMode(false);
#include "G4InversePEEffect.hh"
#include "G4AdjointPhotoElectricModel.hh"
#include "G4VEmAdjointModel.hh"
////////////////////////////////////////////////////////////////////////////////
G4InversePEEffect::G4InversePEEffect(G4String process_name,
G4AdjointPhotoElectricModel* aModel)
: G4VAdjointReverseReaction(process_name, false)
{
fAdjointModel = aModel;
fAdjointModel->SetSecondPartOfSameType(false);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4InversePEEffect::~G4InversePEEffect(){
////////////////////////////////////////////////////////////////////////////////
G4InversePEEffect::~G4InversePEEffect() {}
////////////////////////////////////////////////////////////////////////////////
void G4InversePEEffect::ProcessDescription(std::ostream& out) const
{
out << "Inverse photoelectric effect process.\n";
}
@@ -23,7 +23,6 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
///////////////////////////////////////////////////////
// File name: G4IonInverseIonisation
//
@@ -32,18 +31,26 @@
// Creation date: 25.08.2009
//
///////////////////////////////////////////////////////
#include "G4IonInverseIonisation.hh"
#include "G4VEmAdjointModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4IonInverseIonisation::G4IonInverseIonisation(G4bool whichScatCase,G4String process_name,G4AdjointIonIonisationModel* aEmAdjointModel):
G4VAdjointReverseReaction(process_name,whichScatCase)
{theAdjointEMModel = aEmAdjointModel;
theAdjointEMModel->SetSecondPartOfSameType(false);
SetIntegralMode(true);
#include "G4IonInverseIonisation.hh"
#include "G4AdjointIonIonisationModel.hh"
////////////////////////////////////////////////////////////////////////////////
G4IonInverseIonisation::G4IonInverseIonisation(
G4bool whichScatCase, G4String process_name,
G4AdjointIonIonisationModel* aEmAdjointModel)
: G4VAdjointReverseReaction(process_name, whichScatCase)
{
fAdjointModel = aEmAdjointModel;
fAdjointModel->SetSecondPartOfSameType(false);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4IonInverseIonisation::~G4IonInverseIonisation(){
////////////////////////////////////////////////////////////////////////////////
G4IonInverseIonisation::~G4IonInverseIonisation() {}
////////////////////////////////////////////////////////////////////////////////
void G4IonInverseIonisation::ProcessDescription(std::ostream& out) const
{
out << "Inversion ionisation process for ions.\n";
}
File diff suppressed because it is too large Load Diff
@@ -23,145 +23,78 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4VAdjointReverseReaction.hh"
#include "G4SystemOfUnits.hh"
#include "G4AdjointCSManager.hh"
#include "G4AdjointCSMatrix.hh"
#include "G4AdjointInterpolator.hh"
#include "G4AdjointCSMatrix.hh"
#include "G4VEmAdjointModel.hh"
#include "G4ElementTable.hh"
#include "G4Element.hh"
#include "G4Material.hh"
#include "G4MaterialCutsCouple.hh"
#include "G4AdjointCSManager.hh"
#include "G4ParticleChange.hh"
#include "G4AdjointElectron.hh"
#include "G4VEmAdjointModel.hh"
G4VAdjointReverseReaction::G4VAdjointReverseReaction(G4String process_name,
G4bool whichScatCase)
: G4VDiscreteProcess(process_name)
{
fCSManager = G4AdjointCSManager::GetAdjointCSManager();
fIsScatProjToProj = whichScatCase;
fParticleChange = new G4ParticleChange();
}
G4VAdjointReverseReaction::
G4VAdjointReverseReaction(G4String process_name, G4bool whichScatCase):
G4VDiscreteProcess(process_name)
{theAdjointCSManager = G4AdjointCSManager::GetAdjointCSManager();
IsScatProjToProjCase=whichScatCase;
fParticleChange=new G4ParticleChange();
IsFwdCSUsed=false;
IsIntegralModeUsed=false;
lastCS=0.;
trackid = nstep = 0;
//////////////////////////////////////////////////////////////////////////////
G4VAdjointReverseReaction::~G4VAdjointReverseReaction()
{
if(fParticleChange)
delete fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
G4VAdjointReverseReaction::
~G4VAdjointReverseReaction()
{ if (fParticleChange) delete fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
void G4VAdjointReverseReaction::PreparePhysicsTable(const G4ParticleDefinition&)
{;
}
//////////////////////////////////////////////////////////////////////////////
//
void G4VAdjointReverseReaction::BuildPhysicsTable(const G4ParticleDefinition&)
{
theAdjointCSManager->BuildCrossSectionMatrices(); //do not worry it will be done just once
theAdjointCSManager->BuildTotalSigmaTables();
fCSManager->BuildCrossSectionMatrices(); // it will be done just once
fCSManager->BuildTotalSigmaTables();
}
//////////////////////////////////////////////////////////////////////////////
//
G4VParticleChange* G4VAdjointReverseReaction::PostStepDoIt(const G4Track& track, const G4Step& )
{
G4VParticleChange* G4VAdjointReverseReaction::PostStepDoIt(const G4Track& track,
const G4Step&)
{
fParticleChange->Initialize(track);
/* if (IsFwdCSUsed && IsIntegralModeUsed){ //INtegral mode still unstable
G4double Tkin = step.GetPostStepPoint()->GetKineticEnergy();
G4double fwdCS = theAdjointCSManager->GetTotalForwardCS(track.GetDefinition(), Tkin, track.GetMaterialCutsCouple());
//G4cout<<"lastCS "<<lastCS<<G4endl;
if (fwdCS<lastCS*G4UniformRand()) { // the reaction does not take place, same integral method as the one used for forward ionisation in G4
ClearNumberOfInteractionLengthLeft();
return fParticleChange;
}
}
*/
theAdjointEMModel->SampleSecondaries(track,
IsScatProjToProjCase,
fParticleChange);
fAdjointModel->SampleSecondaries(track, fIsScatProjToProj, fParticleChange);
ClearNumberOfInteractionLengthLeft();
return fParticleChange;
}
//////////////////////////////////////////////////////////////////////////////
//
G4double G4VAdjointReverseReaction::GetMeanFreePath(const G4Track& track,
G4double ,
G4ForceCondition* condition)
{ *condition = NotForced;
G4double,
G4ForceCondition* condition)
{
*condition = NotForced;
G4double preStepKinEnergy = track.GetKineticEnergy();
if(track.GetTrackID() != trackid) {
trackid = track.GetTrackID();
nstep = 0;
if(track.GetTrackID() != fTrackId)
{
fTrackId = track.GetTrackID();
}
++nstep;
G4double sigma = fAdjointModel->AdjointCrossSection(
track.GetMaterialCutsCouple(), preStepKinEnergy, fIsScatProjToProj);
G4double corr = fCSManager->GetCrossSectionCorrection(
track.GetDefinition(), preStepKinEnergy, track.GetMaterialCutsCouple(),
fIsFwdCSUsed);
/*G4double Sigma =
theAdjointEMModel->AdjointCrossSection(track.GetMaterialCutsCouple(),preStepKinEnergy,IsScatProjToProjCase);*/
G4double Sigma =
theAdjointEMModel->GetAdjointCrossSection(track.GetMaterialCutsCouple(),preStepKinEnergy,IsScatProjToProjCase);
//G4double sig = Sigma;
G4double fwd_TotCS;
G4double corr = theAdjointCSManager->GetCrossSectionCorrection(track.GetDefinition(),preStepKinEnergy,track.GetMaterialCutsCouple(),IsFwdCSUsed, fwd_TotCS);
if(std::fabs(corr) > 100.) { Sigma = 0.0; }
else { Sigma *= corr; }
//G4cout<<fwd_TotCS<<G4endl;
/*if (IsFwdCSUsed && IsIntegralModeUsed){ //take the maximum cross section only for charged particle
G4double e_sigma_max, sigma_max;
theAdjointCSManager->GetMaxFwdTotalCS(track.GetDefinition(),
track.GetMaterialCutsCouple(), e_sigma_max, sigma_max);
if (e_sigma_max > preStepKinEnergy){
Sigma*=sigma_max/fwd_TotCS;
}
if(std::fabs(corr) > 100.)
{
sigma = 0.0;
}
*/
G4double mean_free_path = 1.e60 *mm;
if (Sigma>0) mean_free_path = 1./Sigma;
lastCS=Sigma;
/*
if(nstep > 100) {
G4cout << "#* " << track.GetDefinition()->GetParticleName()
<< " " << GetProcessName()
<< " Nstep " << nstep
<< " E(MeV)= " << preStepKinEnergy << " Sig0= " << sig
<< " sig1= " << Sigma << " mfp= " << mean_free_path << G4endl;
}
if (nstep > 20000) {
exit(1);
else
{
sigma *= corr;
}
*/
/*G4cout<<"Sigma "<<Sigma<<G4endl;
G4cout<<"mean_free_path [mm] "<<mean_free_path/mm<<G4endl;
*/
G4double mean_free_path = 1.e60;
if(sigma > 0.)
mean_free_path = 1. / sigma;
return mean_free_path;
}
}
File diff suppressed because it is too large Load Diff
@@ -23,81 +23,81 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -----------------------------------------------------------------------------
//
// GEANT4 Class file
//
// File name: G4eAdjointMultipleScattering
//
// Author: Vladimir Ivanchenko
//
// Creation date: 10 March 2008
//
// Modifications:
//
// -----------------------------------------------------------------------------
//
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "G4eAdjointMultipleScattering.hh"
#include "G4UrbanAdjointMscModel.hh"
#include "G4MscStepLimitType.hh"
#include "G4Electron.hh"
#include "G4Positron.hh"
#include "G4DynamicParticle.hh"
#include "G4Electron.hh"
#include "G4MscStepLimitType.hh"
#include "G4UrbanAdjointMscModel.hh"
#include "G4VMultipleScattering.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
using namespace std;
G4eAdjointMultipleScattering::G4eAdjointMultipleScattering(const G4String& processName)
G4eAdjointMultipleScattering::G4eAdjointMultipleScattering(
const G4String& processName)
: G4VMultipleScattering(processName)
{
isInitialized = false;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4eAdjointMultipleScattering::~G4eAdjointMultipleScattering()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4eAdjointMultipleScattering::~G4eAdjointMultipleScattering() {}
G4bool G4eAdjointMultipleScattering::IsApplicable (const G4ParticleDefinition& p)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4eAdjointMultipleScattering::ProcessDescription(std::ostream& out) const
{
out << "Inverse multiple scattering for e-.\n";
StreamProcessInfo(out);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool G4eAdjointMultipleScattering::IsApplicable(const G4ParticleDefinition& p)
{
return (p.GetPDGCharge() != 0.0 && !p.IsShortLived());
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4eAdjointMultipleScattering::InitialiseProcess(const G4ParticleDefinition*)
void G4eAdjointMultipleScattering::InitialiseProcess(
const G4ParticleDefinition*)
{
if(isInitialized) { return; }
if(!EmModel(0)) { SetEmModel(new G4UrbanAdjointMscModel(), 0); }
if(fIsInitialized)
{
return;
}
if(EmModel(0) == nullptr)
{
SetEmModel(new G4UrbanAdjointMscModel());
}
AddEmModel(1, EmModel(0));
isInitialized = true;
fIsInitialized = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4eAdjointMultipleScattering::PrintInfo()
void G4eAdjointMultipleScattering::StreamProcessInfo(std::ostream& out) const
{
G4cout << " RangeFactor= " << RangeFactor()
<< ", stepLimitType: " << StepLimitType()
<< ", latDisplacement: " << LateralDisplasmentFlag();
if(StepLimitType() == fUseDistanceToBoundary) {
G4cout << ", skin= " << Skin() << ", geomFactor= " << GeomFactor();
}
G4cout << G4endl;
out << " RangeFactor= " << RangeFactor()
<< ", stepLimType: " << StepLimitType()
<< ", latDisp: " << LateralDisplasmentFlag();
if(StepLimitType() == fUseDistanceToBoundary)
{
out << ", skin= " << Skin() << ", geomFactor= " << GeomFactor();
}
out << "\n";
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4eAdjointMultipleScattering::StartTracking(G4Track* )
{ G4DynamicParticle* aDynPart = new G4DynamicParticle(G4Electron::Electron(), G4ThreeVector(0.,0.,1.),1.);
G4Track* tempTrack = new G4Track(aDynPart,0.,G4ThreeVector(0.,0.,0.));
G4VMultipleScattering::StartTracking( tempTrack);
delete tempTrack;
void G4eAdjointMultipleScattering::StartTracking(G4Track*)
{
G4DynamicParticle* aDynPart = new G4DynamicParticle(
G4Electron::Electron(), G4ThreeVector(0., 0., 1.), 1.);
G4Track* tempTrack = new G4Track(aDynPart, 0., G4ThreeVector(0., 0., 0.));
G4VMultipleScattering::StartTracking(tempTrack);
delete tempTrack;
}
@@ -22,23 +22,26 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4eInverseBremsstrahlung.hh"
#include "G4VEmAdjointModel.hh"
#include "G4AdjointBremsstrahlungModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseBremsstrahlung::G4eInverseBremsstrahlung(G4bool whichScatCase,G4String process_name,
G4VEmAdjointModel* aBremAdjointModel):
G4VAdjointReverseReaction(process_name,whichScatCase)
{theAdjointEMModel = aBremAdjointModel;
theAdjointEMModel->SetSecondPartOfSameType(false);
if (IsScatProjToProjCase) SetIntegralMode(true);
else SetIntegralMode(false);
#include "G4eInverseBremsstrahlung.hh"
#include "G4VEmAdjointModel.hh"
////////////////////////////////////////////////////////////////////////////////
G4eInverseBremsstrahlung::G4eInverseBremsstrahlung(
G4bool whichScatCase, G4String process_name,
G4VEmAdjointModel* aBremAdjointModel)
: G4VAdjointReverseReaction(process_name, whichScatCase)
{
fAdjointModel = aBremAdjointModel;
fAdjointModel->SetSecondPartOfSameType(false);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseBremsstrahlung::~G4eInverseBremsstrahlung(){
////////////////////////////////////////////////////////////////////////////////
G4eInverseBremsstrahlung::~G4eInverseBremsstrahlung() {}
////////////////////////////////////////////////////////////////////////////////
void G4eInverseBremsstrahlung::ProcessDescription(std::ostream& out) const
{
out << "Inverse bremsstrahlung process.\n";
}
@@ -23,30 +23,34 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
///////////////////////////////////////////////////////
// File name: G4eInverseCompton
//
// Author: Laurent Desorgher
//
// Creation date: 20.11.2006
//
///////////////////////////////////////////////////////
#include "G4eInverseCompton.hh"
#include "G4VEmAdjointModel.hh"
#include "G4AdjointComptonModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseCompton::G4eInverseCompton(G4bool whichScatCase,G4String process_name,G4AdjointComptonModel* aComptonAdjointModel):
G4VAdjointReverseReaction(process_name,whichScatCase)
{theAdjointEMModel = aComptonAdjointModel;
theAdjointEMModel->SetSecondPartOfSameType(false);
SetIntegralMode(false);
/*if (IsScatProjToProjCase) SetIntegralMode(false);
else SetIntegralMode(true); */
#include "G4eInverseCompton.hh"
#include "G4AdjointComptonModel.hh"
#include "G4VEmAdjointModel.hh"
////////////////////////////////////////////////////////////////////////////////
G4eInverseCompton::G4eInverseCompton(
G4bool whichScatCase, G4String process_name,
G4AdjointComptonModel* aComptonAdjointModel)
: G4VAdjointReverseReaction(process_name, whichScatCase)
{
fAdjointModel = aComptonAdjointModel;
fAdjointModel->SetSecondPartOfSameType(false);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseCompton::~G4eInverseCompton(){
////////////////////////////////////////////////////////////////////////////////
G4eInverseCompton::~G4eInverseCompton() {}
////////////////////////////////////////////////////////////////////////////////
void G4eInverseCompton::ProcessDescription(std::ostream& out) const
{
out << "Inverse Compton effect.\n";
}
@@ -30,21 +30,27 @@
// Author: Laurent Desorgher
//
// Creation date: 20.11.2006
//
///////////////////////////////////////////////////////
#include "G4eInverseIonisation.hh"
#include "G4VEmAdjointModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseIonisation::G4eInverseIonisation(G4bool whichScatCase,G4String process_name,G4VEmAdjointModel* aEmAdjointModel):
G4VAdjointReverseReaction(process_name,whichScatCase)
{theAdjointEMModel = aEmAdjointModel;
theAdjointEMModel->SetSecondPartOfSameType(true);
SetIntegralMode(true);
////////////////////////////////////////////////////////////////////////////////
G4eInverseIonisation::G4eInverseIonisation(G4bool whichScatCase,
G4String process_name,
G4VEmAdjointModel* aEmAdjointModel)
: G4VAdjointReverseReaction(process_name, whichScatCase)
{
fAdjointModel = aEmAdjointModel;
fAdjointModel->SetSecondPartOfSameType(true);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4eInverseIonisation::~G4eInverseIonisation(){
////////////////////////////////////////////////////////////////////////////////
G4eInverseIonisation::~G4eInverseIonisation() {}
////////////////////////////////////////////////////////////////////////////////
void G4eInverseIonisation::ProcessDescription(std::ostream& out) const
{
out << "Inverse ionisation process for electrons.\n";
}
@@ -32,18 +32,20 @@
// Creation date: 15.02.2009
//
///////////////////////////////////////////////////////
#include "G4hInverseIonisation.hh"
#include "G4VEmAdjointModel.hh"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4hInverseIonisation::G4hInverseIonisation(G4bool whichScatCase,G4String process_name,G4AdjointhIonisationModel* aEmAdjointModel):
G4VAdjointReverseReaction(process_name,whichScatCase)
{theAdjointEMModel = aEmAdjointModel;
theAdjointEMModel->SetSecondPartOfSameType(false);
SetIntegralMode(true);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
G4hInverseIonisation::~G4hInverseIonisation(){
#include "G4hInverseIonisation.hh"
#include "G4AdjointhIonisationModel.hh"
///////////////////////////////////////////////////////////////////////////////
G4hInverseIonisation::G4hInverseIonisation(
G4bool whichScatCase, G4String process_name,
G4AdjointhIonisationModel* aEmAdjointModel)
: G4VAdjointReverseReaction(process_name, whichScatCase)
{
fAdjointModel = aEmAdjointModel;
fAdjointModel->SetSecondPartOfSameType(false);
}
///////////////////////////////////////////////////////////////////////////////
G4hInverseIonisation::~G4hInverseIonisation() {}