Import Geant4 11.2.0 source tree
This commit is contained in:
@@ -72,6 +72,7 @@
|
||||
namespace { G4Mutex LivermoreBremsstrahlungModelMutex = G4MUTEX_INITIALIZER; }
|
||||
using namespace std;
|
||||
|
||||
|
||||
G4Physics2DVector* G4LivermoreBremsstrahlungModel::dataSB[] = {nullptr};
|
||||
G4double G4LivermoreBremsstrahlungModel::ylimit[] = {0.0};
|
||||
G4double G4LivermoreBremsstrahlungModel::expnumlim = -12.;
|
||||
@@ -86,7 +87,6 @@ G4LivermoreBremsstrahlungModel::G4LivermoreBremsstrahlungModel(
|
||||
: G4eBremsstrahlungRelModel(p,nam),useBicubicInterpolation(false)
|
||||
{
|
||||
SetLowEnergyLimit(10.0*eV);
|
||||
SetLPMFlag(false);
|
||||
SetAngularDistribution(new G4Generator2BS());
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ void G4LivermoreBremsstrahlungModel::ReadData(G4int Z, const char* path)
|
||||
if(dataSB[Z]) { return; }
|
||||
const char* datadir = path;
|
||||
|
||||
if(!datadir) {
|
||||
if(nullptr == datadir) {
|
||||
datadir = G4FindDataDir("G4LEDATA");
|
||||
if(!datadir) {
|
||||
G4Exception("G4LivermoreBremsstrahlungModel::ReadData()","em0006",
|
||||
|
||||
@@ -45,22 +45,26 @@
|
||||
#include "G4SauterGavrilaAngularDistribution.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4VAtomDeexcitation.hh"
|
||||
#include "G4EmParameters.hh"
|
||||
#include <thread>
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
G4PhysicsFreeVector* G4LivermorePhotoElectricModel::fCrossSection[] = {nullptr};
|
||||
G4PhysicsFreeVector* G4LivermorePhotoElectricModel::fCrossSectionLE[] = {nullptr};
|
||||
|
||||
G4ElementData* G4LivermorePhotoElectricModel::fCrossSection = nullptr;
|
||||
G4ElementData* G4LivermorePhotoElectricModel::fCrossSectionLE = nullptr;
|
||||
std::vector<G4double>* G4LivermorePhotoElectricModel::fParamHigh[] = {nullptr};
|
||||
std::vector<G4double>* G4LivermorePhotoElectricModel::fParamLow[] = {nullptr};
|
||||
G4int G4LivermorePhotoElectricModel::fNShells[] = {0};
|
||||
G4int G4LivermorePhotoElectricModel::fNShellsUsed[] = {0};
|
||||
G4ElementData* G4LivermorePhotoElectricModel::fShellCrossSection = nullptr;
|
||||
G4Material* G4LivermorePhotoElectricModel::fWater = nullptr;
|
||||
G4double G4LivermorePhotoElectricModel::fWaterEnergyLimit = 0.0;
|
||||
G4String G4LivermorePhotoElectricModel::fDataDirectory = "";
|
||||
|
||||
static std::once_flag applyOnce;
|
||||
|
||||
namespace
|
||||
{
|
||||
G4Mutex livPhotoeffMutex = G4MUTEX_INITIALIZER;
|
||||
G4Mutex livPhotoeffMutex = G4MUTEX_INITIALIZER;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -97,10 +101,8 @@ G4LivermorePhotoElectricModel::G4LivermorePhotoElectricModel(const G4String& nam
|
||||
|
||||
G4LivermorePhotoElectricModel::~G4LivermorePhotoElectricModel()
|
||||
{
|
||||
if (IsMaster()) {
|
||||
delete fShellCrossSection;
|
||||
fShellCrossSection = nullptr;
|
||||
for (G4int i = 0; i <= maxZ; ++i) {
|
||||
if (isInitializer) {
|
||||
for (G4int i = 0; i < ZMAXPE; ++i) {
|
||||
if (fParamHigh[i]) {
|
||||
delete fParamHigh[i];
|
||||
fParamHigh[i] = nullptr;
|
||||
@@ -109,57 +111,60 @@ G4LivermorePhotoElectricModel::~G4LivermorePhotoElectricModel()
|
||||
delete fParamLow[i];
|
||||
fParamLow[i] = nullptr;
|
||||
}
|
||||
if (fCrossSection[i]) {
|
||||
delete fCrossSection[i];
|
||||
fCrossSection[i] = nullptr;
|
||||
}
|
||||
if (fCrossSectionLE[i]) {
|
||||
delete fCrossSectionLE[i];
|
||||
fCrossSectionLE[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*, const G4DataVector&)
|
||||
void G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*,
|
||||
const G4DataVector&)
|
||||
{
|
||||
if (verboseLevel > 2) {
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "Calling G4LivermorePhotoElectricModel::Initialise() " << G4endl;
|
||||
}
|
||||
|
||||
if (IsMaster()) {
|
||||
// initialise static tables only once
|
||||
std::call_once(applyOnce, [this]() { isInitializer = true; });
|
||||
|
||||
if (isInitializer) {
|
||||
G4AutoLock l(&livPhotoeffMutex);
|
||||
FindDirectoryPath();
|
||||
if (fWater == nullptr) {
|
||||
fWater = G4Material::GetMaterial("G4_WATER", false);
|
||||
if (fWater == nullptr) {
|
||||
fWater = G4Material::GetMaterial("Water", false);
|
||||
}
|
||||
if (fWater != nullptr) {
|
||||
fWaterEnergyLimit = 13.6 * eV;
|
||||
fWaterEnergyLimit = 13.6 * CLHEP::eV;
|
||||
}
|
||||
}
|
||||
|
||||
if (fShellCrossSection == nullptr) {
|
||||
fShellCrossSection = new G4ElementData();
|
||||
if (fCrossSection == nullptr) {
|
||||
fCrossSection = new G4ElementData(ZMAXPE);
|
||||
fCrossSection->SetName("PhotoEffXS");
|
||||
fCrossSectionLE = new G4ElementData(ZMAXPE);
|
||||
fCrossSectionLE->SetName("PhotoEffLowXS");
|
||||
}
|
||||
|
||||
const G4ElementTable* elemTable = G4Element::GetElementTable();
|
||||
std::size_t numElems = (*elemTable).size();
|
||||
for (std::size_t ie = 0; ie < numElems; ++ie) {
|
||||
const G4Element* elem = (*elemTable)[ie];
|
||||
const G4int Z = std::min(maxZ, elem->GetZasInt());
|
||||
if (fCrossSection[Z] == nullptr) {
|
||||
ReadData(Z);
|
||||
G4int Z = elem->GetZasInt();
|
||||
if (Z < ZMAXPE) {
|
||||
if (fCrossSection->GetElementData(Z) == nullptr) {
|
||||
ReadData(Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
l.unlock();
|
||||
}
|
||||
|
||||
if (verboseLevel > 2) {
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "Loaded cross section files for new LivermorePhotoElectric model" << G4endl;
|
||||
}
|
||||
if (!isInitialised) {
|
||||
isInitialised = true;
|
||||
if (nullptr == fParticleChange) {
|
||||
fParticleChange = GetParticleChangeForGamma();
|
||||
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
|
||||
}
|
||||
@@ -169,16 +174,18 @@ void G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*, cons
|
||||
fDeexcitationActive = fAtomDeexcitation->IsFluoActive();
|
||||
}
|
||||
|
||||
if (verboseLevel > 0) {
|
||||
G4cout << "LivermorePhotoElectric model is initialized " << G4endl << G4endl;
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "LivermorePhotoElectric model is initialized " << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4double G4LivermorePhotoElectricModel::CrossSectionPerVolume(const G4Material* material,
|
||||
const G4ParticleDefinition* p,
|
||||
G4double energy, G4double, G4double)
|
||||
G4double
|
||||
G4LivermorePhotoElectricModel::CrossSectionPerVolume(const G4Material* material,
|
||||
const G4ParticleDefinition* p,
|
||||
G4double energy,
|
||||
G4double, G4double)
|
||||
{
|
||||
fCurrSection = 0.0;
|
||||
if (fWater && (material == fWater || material->GetBaseMaterial() == fWater)) {
|
||||
@@ -190,8 +197,8 @@ G4double G4LivermorePhotoElectricModel::CrossSectionPerVolume(const G4Material*
|
||||
G4double energy4 = energy2 * energy2;
|
||||
|
||||
fCurrSection = material->GetDensity()
|
||||
* (fSandiaCof[0] / energy + fSandiaCof[1] / energy2 + fSandiaCof[2] / energy3
|
||||
+ fSandiaCof[3] / energy4);
|
||||
* (fSandiaCof[0] / energy + fSandiaCof[1] / energy2 +
|
||||
fSandiaCof[2] / energy3 + fSandiaCof[3] / energy4);
|
||||
}
|
||||
}
|
||||
if (0.0 == fCurrSection) {
|
||||
@@ -202,9 +209,11 @@ G4double G4LivermorePhotoElectricModel::CrossSectionPerVolume(const G4Material*
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4double G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
|
||||
G4double energy, G4double ZZ,
|
||||
G4double, G4double, G4double)
|
||||
G4double
|
||||
G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom(const G4ParticleDefinition*,
|
||||
G4double energy,
|
||||
G4double ZZ, G4double,
|
||||
G4double, G4double)
|
||||
{
|
||||
if (verboseLevel > 3) {
|
||||
G4cout << "\n G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom():"
|
||||
@@ -212,14 +221,15 @@ G4double G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom(const G4Parti
|
||||
}
|
||||
G4double cs = 0.0;
|
||||
G4int Z = G4lrint(ZZ);
|
||||
if (Z > maxZ) {
|
||||
if (Z >= ZMAXPE || Z <= 0) {
|
||||
return cs;
|
||||
}
|
||||
// if element was not initialised
|
||||
|
||||
// do initialisation safely for MT mode
|
||||
if (fCrossSection[Z] == nullptr) {
|
||||
InitialiseForElement(theGamma, Z);
|
||||
if (fCrossSection->GetElementData(Z) == nullptr) {
|
||||
InitialiseOnFly(Z);
|
||||
if (fCrossSection->GetElementData(Z) == nullptr) { return cs; }
|
||||
}
|
||||
|
||||
// 7: rows in the parameterization file; 5: number of parameters
|
||||
@@ -236,27 +246,27 @@ G4double G4LivermorePhotoElectricModel::ComputeCrossSectionPerAtom(const G4Parti
|
||||
G4double x4 = x2 * x2;
|
||||
G4double x5 = x4 * x1;
|
||||
|
||||
cs = x1
|
||||
* ((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
|
||||
cs = x1 *
|
||||
((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
|
||||
}
|
||||
// low energy parameterisation
|
||||
else if (energy >= (*(fParamLow[Z]))[0]) {
|
||||
G4double x4 = x2 * x2;
|
||||
G4double x5 = x4 * x1; // this variable usage can probably be optimized
|
||||
cs = x1
|
||||
* ((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
|
||||
cs = x1 *
|
||||
((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
|
||||
}
|
||||
// Tabulated values above k-shell ionization energy
|
||||
else if (energy >= (*(fParamHigh[Z]))[1]) {
|
||||
cs = x3 * (fCrossSection[Z])->Value(energy);
|
||||
cs = x3 * (fCrossSection->GetElementData(Z))->Value(energy);
|
||||
}
|
||||
// Tabulated values below k-shell ionization energy
|
||||
else {
|
||||
cs = x3 * (fCrossSectionLE[Z])->Value(energy);
|
||||
cs = x3 * (fCrossSectionLE->GetElementData(Z))->Value(energy);
|
||||
}
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "G4LivermorePhotoElectricModel: E(keV)= " << energy / keV << " Z= " << Z
|
||||
@@ -296,13 +306,13 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
|
||||
|
||||
// Select randomly one element in the current material
|
||||
const G4Element* elm = SelectRandomAtom(material, theGamma, gammaEnergy);
|
||||
G4int Z = std::min(elm->GetZasInt(), maxZ);
|
||||
G4int Z = elm->GetZasInt();
|
||||
|
||||
// Select the ionised shell in the current atom according to shell
|
||||
// cross sections
|
||||
|
||||
// If element was not initialised gamma should be absorbed
|
||||
if (fCrossSection[Z] == nullptr) {
|
||||
if (Z >= ZMAXPE || fCrossSection->GetElementData(Z) == nullptr) {
|
||||
fParticleChange->ProposeLocalEnergyDeposit(gammaEnergy);
|
||||
return;
|
||||
}
|
||||
@@ -322,17 +332,17 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
|
||||
// so cross section is not real
|
||||
|
||||
G4double rand = G4UniformRand();
|
||||
G4double cs0 = rand
|
||||
* ((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
|
||||
G4double cs0 = rand *
|
||||
((*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5]);
|
||||
|
||||
for (shellIdx = 0; shellIdx < nn; ++shellIdx) {
|
||||
idx = shellIdx * 7 + 2;
|
||||
if (gammaEnergy > (*(fParamHigh[Z]))[idx - 1]) {
|
||||
G4double cs = (*(fParamHigh[Z]))[idx] + x1 * (*(fParamHigh[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5];
|
||||
+ x2 * (*(fParamHigh[Z]))[idx + 2] + x3 * (*(fParamHigh[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamHigh[Z]))[idx + 4] + x5 * (*(fParamHigh[Z]))[idx + 5];
|
||||
|
||||
if (cs >= cs0) {
|
||||
break;
|
||||
@@ -352,16 +362,16 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
|
||||
std::size_t idx = nn * 7 - 5;
|
||||
// when do sampling common factors are not taken into account
|
||||
// so cross section is not real
|
||||
G4double cs0 = G4UniformRand()
|
||||
* ((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
|
||||
G4double cs0 = G4UniformRand() *
|
||||
((*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5]);
|
||||
for (shellIdx = 0; shellIdx < nn; ++shellIdx) {
|
||||
idx = shellIdx * 7 + 2;
|
||||
if (gammaEnergy > (*(fParamLow[Z]))[idx - 1]) {
|
||||
G4double cs = (*(fParamLow[Z]))[idx] + x1 * (*(fParamLow[Z]))[idx + 1]
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5];
|
||||
+ x2 * (*(fParamLow[Z]))[idx + 2] + x3 * (*(fParamLow[Z]))[idx + 3]
|
||||
+ x4 * (*(fParamLow[Z]))[idx + 4] + x5 * (*(fParamLow[Z]))[idx + 5];
|
||||
if (cs >= cs0) {
|
||||
break;
|
||||
}
|
||||
@@ -378,17 +388,17 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
|
||||
|
||||
if (gammaEnergy >= (*(fParamHigh[Z]))[1]) {
|
||||
// above K-shell binding energy
|
||||
cs *= (fCrossSection[Z])->Value(gammaEnergy);
|
||||
cs *= fCrossSection->GetElementData(Z)->Value(gammaEnergy);
|
||||
}
|
||||
else {
|
||||
// below K-shell binding energy
|
||||
cs *= (fCrossSectionLE[Z])->Value(gammaEnergy);
|
||||
cs *= fCrossSectionLE->GetElementData(Z)->Value(gammaEnergy);
|
||||
}
|
||||
|
||||
for (G4int j = 0; j < (G4int)nn; ++j) {
|
||||
shellIdx = (std::size_t)fShellCrossSection->GetComponentID(Z, j);
|
||||
shellIdx = (std::size_t)fCrossSection->GetComponentID(Z, j);
|
||||
if (gammaEnergy > (*(fParamLow[Z]))[7 * shellIdx + 1]) {
|
||||
cs -= fShellCrossSection->GetValueForComponent(Z, j, gammaEnergy);
|
||||
cs -= fCrossSection->GetValueForComponent(Z, j, gammaEnergy);
|
||||
}
|
||||
if (cs <= 0.0 || j + 1 == (G4int)nn) {
|
||||
break;
|
||||
@@ -423,11 +433,12 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
|
||||
aDynamicGamma, eKineticEnergy, (G4int)shellIdx, couple->GetMaterial());
|
||||
|
||||
// The electron is created
|
||||
auto electron = new G4DynamicParticle(theElectron, electronDirection, eKineticEnergy);
|
||||
auto electron =
|
||||
new G4DynamicParticle(theElectron, electronDirection, eKineticEnergy);
|
||||
fvect->push_back(electron);
|
||||
|
||||
// Sample deexcitation
|
||||
if (shell) {
|
||||
if (nullptr != shell) {
|
||||
G4int index = couple->GetIndex();
|
||||
if (fAtomDeexcitation->CheckDeexcitationActiveRegion(index)) {
|
||||
std::size_t nbefore = fvect->size();
|
||||
@@ -483,26 +494,27 @@ const G4String& G4LivermorePhotoElectricModel::FindDirectoryPath()
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
void G4LivermorePhotoElectricModel::ReadData(G4int Z)
|
||||
{
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "Calling ReadData() of G4LivermorePhotoElectricModel for Z=" << ZZ << G4endl;
|
||||
if (Z <= 0 || Z >= ZMAXPE) {
|
||||
G4cout << "G4LivermorePhotoElectricModel::ReadData() Warning: Z="
|
||||
<< Z << " is out of range - request ignored" << G4endl;
|
||||
return;
|
||||
}
|
||||
if (verboseLevel > 1) {
|
||||
G4cout << "G4LivermorePhotoElectricModel::ReadData() for Z=" << Z << G4endl;
|
||||
}
|
||||
G4int Z = std::min(ZZ, maxZ);
|
||||
|
||||
if (fCrossSection[Z] != nullptr) {
|
||||
if (fCrossSection->GetElementData(Z) != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// spline for photoeffect total x-section above K-shell when using EPDL97
|
||||
// but below the parameterized ones
|
||||
|
||||
if (G4EmParameters::Instance()->LivermoreDataDir() == "livermore") {
|
||||
fCrossSection[Z] = new G4PhysicsFreeVector(true);
|
||||
}
|
||||
else {
|
||||
fCrossSection[Z] = new G4PhysicsFreeVector();
|
||||
}
|
||||
G4bool spline = (G4EmParameters::Instance()->LivermoreDataDir() == "livermore");
|
||||
G4int number = G4EmParameters::Instance()->NumberForFreeVector();
|
||||
auto pv = new G4PhysicsFreeVector(spline);
|
||||
|
||||
// fDataDirectory will be defined after these lines
|
||||
std::ostringstream ost;
|
||||
@@ -510,8 +522,8 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
std::ifstream fin(ost.str().c_str());
|
||||
if (!fin.is_open()) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << "G4LivermorePhotoElectricModel data file <" << ost.str().c_str() << "> is not opened!"
|
||||
<< G4endl;
|
||||
ed << "G4LivermorePhotoElectricModel data file <"
|
||||
<< ost.str().c_str() << "> is not opened!" << G4endl;
|
||||
G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
|
||||
"G4LEDATA version should be G4EMLOW8.0 or later.");
|
||||
return;
|
||||
@@ -520,9 +532,11 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
G4cout << "File " << ost.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
|
||||
<< G4endl;
|
||||
}
|
||||
fCrossSection[Z]->Retrieve(fin, true);
|
||||
fCrossSection[Z]->ScaleVector(MeV, barn);
|
||||
fCrossSection[Z]->FillSecondDerivatives();
|
||||
pv->Retrieve(fin, true);
|
||||
pv->ScaleVector(MeV, barn);
|
||||
pv->FillSecondDerivatives();
|
||||
pv->EnableLogBinSearch(number);
|
||||
fCrossSection->InitialiseForElement(Z, pv);
|
||||
fin.close();
|
||||
|
||||
// read high-energy fit parameters
|
||||
@@ -535,8 +549,8 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
std::ifstream fin1(ost1.str().c_str());
|
||||
if (!fin1.is_open()) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << "G4LivermorePhotoElectricModel data file <" << ost1.str().c_str() << "> is not opened!"
|
||||
<< G4endl;
|
||||
ed << "G4LivermorePhotoElectricModel data file <"
|
||||
<< ost1.str().c_str() << "> is not opened!" << G4endl;
|
||||
G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
|
||||
"G4LEDATA version should be G4EMLOW7.2 or later.");
|
||||
return;
|
||||
@@ -645,7 +659,7 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
if (nShellLimit < n2) {
|
||||
n2 = nShellLimit;
|
||||
}
|
||||
fShellCrossSection->InitialiseForComponent(Z, n2); // number of shells
|
||||
fCrossSection->InitialiseForComponent(Z, n2); // number of shells
|
||||
fNShellsUsed[Z] = n2;
|
||||
|
||||
if (1 < n2) {
|
||||
@@ -672,16 +686,17 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
auto v = new G4PhysicsFreeVector(n3, x, y);
|
||||
for (G4int j = 0; j < n3; ++j) {
|
||||
fin2 >> x >> y;
|
||||
v->PutValues(j, x * MeV, y * barn);
|
||||
v->PutValues(j, x * CLHEP::MeV, y * CLHEP::barn);
|
||||
}
|
||||
fShellCrossSection->AddComponent(Z, n4, v);
|
||||
v->EnableLogBinSearch(number);
|
||||
fCrossSection->AddComponent(Z, n4, v);
|
||||
}
|
||||
fin2.close();
|
||||
}
|
||||
|
||||
// no spline for photoeffect total x-section below K-shell
|
||||
if (1 < fNShells[Z]) {
|
||||
fCrossSectionLE[Z] = new G4PhysicsFreeVector();
|
||||
auto pv1 = new G4PhysicsFreeVector(false);
|
||||
std::ostringstream ost3;
|
||||
ost3 << fDataDirectory << "pe-le-cs-" << Z << ".dat";
|
||||
std::ifstream fin3(ost3.str().c_str());
|
||||
@@ -697,8 +712,10 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
G4cout << "File " << ost3.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
|
||||
<< G4endl;
|
||||
}
|
||||
fCrossSectionLE[Z]->Retrieve(fin3, true);
|
||||
fCrossSectionLE[Z]->ScaleVector(MeV, barn);
|
||||
pv1->Retrieve(fin3, true);
|
||||
pv1->ScaleVector(CLHEP::MeV, CLHEP::barn);
|
||||
pv1->EnableLogBinSearch(number);
|
||||
fCrossSectionLE->InitialiseForElement(Z, pv1);
|
||||
fin3.close();
|
||||
}
|
||||
}
|
||||
@@ -707,30 +724,45 @@ void G4LivermorePhotoElectricModel::ReadData(G4int ZZ)
|
||||
|
||||
G4double G4LivermorePhotoElectricModel::GetBindingEnergy(G4int Z, G4int shell)
|
||||
{
|
||||
if (Z < 1 || Z > maxZ) {
|
||||
if (Z < 1 || Z >= ZMAXPE) {
|
||||
return -1;
|
||||
} // If Z is out of the supported return 0
|
||||
// If necessary load data for Z
|
||||
InitialiseForElement(theGamma, Z);
|
||||
if (fCrossSection[Z] == nullptr || shell < 0 || shell >= fNShellsUsed[Z]) {
|
||||
|
||||
InitialiseOnFly(Z);
|
||||
if (fCrossSection->GetElementData(Z) == nullptr ||
|
||||
shell < 0 || shell >= fNShellsUsed[Z]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Z > 2) {
|
||||
return fShellCrossSection->GetComponentDataByIndex(Z, shell)->Energy(0);
|
||||
return fCrossSection->GetComponentDataByIndex(Z, shell)->Energy(0);
|
||||
}
|
||||
else {
|
||||
return fCrossSection[Z]->Energy(0);
|
||||
return fCrossSection->GetElementData(Z)->Energy(0);
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4LivermorePhotoElectricModel::InitialiseForElement(const G4ParticleDefinition*, G4int Z)
|
||||
void
|
||||
G4LivermorePhotoElectricModel::InitialiseForElement(const G4ParticleDefinition*, G4int Z)
|
||||
{
|
||||
if (fCrossSection[Z] == nullptr) {
|
||||
if (fCrossSection == nullptr) {
|
||||
fCrossSection = new G4ElementData(ZMAXPE);
|
||||
fCrossSection->SetName("PhotoEffXS");
|
||||
fCrossSectionLE = new G4ElementData(ZMAXPE);
|
||||
fCrossSectionLE->SetName("PhotoEffLowXS");
|
||||
}
|
||||
ReadData(Z);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4LivermorePhotoElectricModel::InitialiseOnFly(G4int Z)
|
||||
{
|
||||
if (fCrossSection->GetElementData(Z) == nullptr && Z > 0 && Z < ZMAXPE) {
|
||||
G4AutoLock l(&livPhotoeffMutex);
|
||||
if (fCrossSection[Z] == nullptr) {
|
||||
if (fCrossSection->GetElementData(Z) == nullptr) {
|
||||
ReadData(Z);
|
||||
}
|
||||
l.unlock();
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// G4MicroElecCapture.cc,
|
||||
// 2011/08/29 A.Valentin, M. Raine are with CEA [a]
|
||||
// 2020/05/20 P. Caron, C. Inguimbert are with ONERA [b]
|
||||
// Q. Gibaru is with CEA [a], ONERA [b] and CNES [c]
|
||||
// M. Raine and D. Lambert are with CEA [a]
|
||||
//
|
||||
// A part of this work has been funded by the French space agency(CNES[c])
|
||||
// [a] CEA, DAM, DIF - 91297 ARPAJON, France
|
||||
// [b] ONERA - DPHY, 2 avenue E.Belin, 31055 Toulouse, France
|
||||
// [c] CNES, 18 av.E.Belin, 31401 Toulouse CEDEX, France
|
||||
//
|
||||
// Based on the following publications
|
||||
// - A.Valentin, M. Raine,
|
||||
// Inelastic cross-sections of low energy electrons in silicon
|
||||
// for the simulation of heavy ion tracks with the Geant4-DNA toolkit,
|
||||
// NSS Conf. Record 2010, pp. 80-85
|
||||
// https://doi.org/10.1109/NSSMIC.2010.5873720
|
||||
//
|
||||
// - A.Valentin, M. Raine, M.Gaillardin, P.Paillet
|
||||
// Geant4 physics processes for microdosimetry simulation:
|
||||
// very low energy electromagnetic models for electrons in Silicon,
|
||||
// https://doi.org/10.1016/j.nimb.2012.06.007
|
||||
// NIM B, vol. 288, pp. 66-73, 2012, part A
|
||||
// heavy ions in Si, NIM B, vol. 287, pp. 124-129, 2012, part B
|
||||
// https://doi.org/10.1016/j.nimb.2012.07.028
|
||||
//
|
||||
// - M. Raine, M. Gaillardin, P. Paillet
|
||||
// Geant4 physics processes for silicon microdosimetry simulation:
|
||||
// Improvements and extension of the energy-range validity up to 10 GeV/nucleon
|
||||
// NIM B, vol. 325, pp. 97-100, 2014
|
||||
// https://doi.org/10.1016/j.nimb.2014.01.014
|
||||
//
|
||||
// - J. Pierron, C. Inguimbert, M. Belhaj, T. Gineste, J. Puech, M. Raine
|
||||
// Electron emission yield for low energy electrons:
|
||||
// Monte Carlo simulation and experimental comparison for Al, Ag, and Si
|
||||
// Journal of Applied Physics 121 (2017) 215107.
|
||||
// https://doi.org/10.1063/1.4984761
|
||||
//
|
||||
// - P. Caron,
|
||||
// Study of Electron-Induced Single-Event Upset in Integrated Memory Devices
|
||||
// PHD, 16th October 2019
|
||||
//
|
||||
// - Q.Gibaru, C.Inguimbert, P.Caron, M.Raine, D.Lambert, J.Puech,
|
||||
// Geant4 physics processes for microdosimetry and secondary electron emission simulation :
|
||||
// Extension of MicroElec to very low energies and new materials
|
||||
// NIM B, 2020, in review.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// ClassName: G4MicroElecCapture derivated from G4ElectronCapture (V Ivanchenko)
|
||||
//
|
||||
// Description: The process to kill particles to save CPU
|
||||
//
|
||||
// Author: C. Inguimbert 31 january 2022 derivated from G4ElectronCapture (V.Ivanchenko 31 August 2010)
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
#include "G4MicroElecCapture.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4Step.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4Track.hh"
|
||||
#include "G4Region.hh"
|
||||
#include "G4RegionStore.hh"
|
||||
#include "G4Electron.hh"
|
||||
#include "G4Pow.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4MicroElecCapture::G4MicroElecCapture(const G4String& regName, G4double ekinlim)
|
||||
: G4VDiscreteProcess("MicroElecCapture", fElectromagnetic), kinEnergyThreshold(ekinlim),
|
||||
regionName(regName), region(0)
|
||||
{
|
||||
if(regName == "" || regName == "world")
|
||||
{
|
||||
regionName = "DefaultRegionForTheWorld";
|
||||
}
|
||||
isInitialised = false;
|
||||
pParticleChange = &fParticleChange;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4MicroElecCapture::~G4MicroElecCapture()
|
||||
{
|
||||
for (auto pos = tableWF.cbegin(); pos != tableWF.cend(); ++pos)
|
||||
{
|
||||
G4MicroElecMaterialStructure* table = pos->second;
|
||||
delete table;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4MicroElecCapture::SetKinEnergyLimit(G4double val)
|
||||
{
|
||||
kinEnergyThreshold = val;
|
||||
}
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4MicroElecCapture::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
region = (G4RegionStore::GetInstance())->GetRegion(regionName);
|
||||
// if(region && verboseLevel > 0) {
|
||||
G4cout << "### G4MicroElecCapture: Tracking cut E(MeV) = "
|
||||
<< kinEnergyThreshold/MeV << " is assigned to " << regionName
|
||||
<< G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4bool G4MicroElecCapture::IsApplicable(const G4ParticleDefinition&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void G4MicroElecCapture::Initialise()
|
||||
{
|
||||
if (isInitialised) { return; }
|
||||
|
||||
G4ProductionCutsTable* theCoupleTable = G4ProductionCutsTable::GetProductionCutsTable();
|
||||
G4int numOfCouples = (G4int)theCoupleTable->GetTableSize();
|
||||
G4cout << numOfCouples << G4endl;
|
||||
|
||||
for (G4int i = 0; i < numOfCouples; ++i)
|
||||
{
|
||||
const G4Material* material = theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
|
||||
|
||||
G4cout << "G4Capture, Material " << i + 1 << " / "
|
||||
<< numOfCouples << " : " << material->GetName() << G4endl;
|
||||
if (material->GetName() == "Vacuum")
|
||||
{
|
||||
tableWF[material->GetName()] = 0;
|
||||
continue;
|
||||
}
|
||||
G4String mat = material->GetName();
|
||||
G4MicroElecMaterialStructure* str = new G4MicroElecMaterialStructure(mat);
|
||||
tableWF[mat] = str;
|
||||
}
|
||||
isInitialised = true;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4VParticleChange* G4MicroElecCapture::PostStepDoIt(const G4Track& aTrack,
|
||||
const G4Step&)
|
||||
{
|
||||
if (!isInitialised) { Initialise(); }
|
||||
|
||||
G4String mat = aTrack.GetMaterial()->GetName();
|
||||
G4int Ztarget = ((*(aTrack.GetMaterial()->GetElementVector()))[0])->GetZasInt();
|
||||
G4int Atarget = ((*(aTrack.GetMaterial()->GetElementVector()))[0])->GetAtomicMassAmu();
|
||||
G4double Nbelements = aTrack.GetMaterial()->GetNumberOfElements();
|
||||
G4double moleculeMass = aTrack.GetMaterial()->GetMassOfMolecule() / amu;
|
||||
auto FractionMass = aTrack.GetMaterial()->GetFractionVector();
|
||||
G4int Zinc = aTrack.GetParticleDefinition()->GetAtomicNumber();
|
||||
G4int Ainc = aTrack.GetParticleDefinition()->GetAtomicMass();
|
||||
G4String IncPartName = aTrack.GetParticleDefinition()->GetParticleName();
|
||||
G4double NIEdep = 0.0;
|
||||
|
||||
for (G4int i = 0; i < Nbelements; ++i)
|
||||
{
|
||||
Ztarget = ((*(aTrack.GetMaterial()->GetElementVector()))[i])->GetZasInt();
|
||||
Atarget = ((*(aTrack.GetMaterial()->GetElementVector()))[i])->GetAtomicMassAmu();
|
||||
NIEdep = NIEdep + moleculeMass*FractionMass[i] / Atarget*G_Lindhard_Rob(aTrack.GetKineticEnergy(), Zinc, Ainc, Ztarget, Atarget);
|
||||
}
|
||||
|
||||
WorkFunctionTable::iterator matWF;
|
||||
matWF = tableWF.find(mat);
|
||||
|
||||
if (matWF == tableWF.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += mat + " not found!";
|
||||
G4Exception("G4MicroElecCapture::PostStepGPIL", "em0002",
|
||||
FatalException, str);
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4MicroElecMaterialStructure* str = matWF->second;
|
||||
pParticleChange->Initialize(aTrack);
|
||||
pParticleChange->ProposeTrackStatus(fStopAndKill);
|
||||
|
||||
G4double InitE = str->GetEnergyGap() + str->GetInitialEnergy();
|
||||
|
||||
if (IncPartName == "e-")
|
||||
{
|
||||
// metals = Non ionizing deposited energy = 0.0
|
||||
if (((str->GetEnergyGap()) / eV)<(0.001))
|
||||
{
|
||||
pParticleChange->ProposeNonIonizingEnergyDeposit(0.0);
|
||||
pParticleChange->ProposeLocalEnergyDeposit(aTrack.GetKineticEnergy());
|
||||
}
|
||||
else // MicroElec materials Non ionizing deposited energy different from zero
|
||||
{
|
||||
G4int c = (G4int)((aTrack.GetKineticEnergy()) / (InitE));
|
||||
pParticleChange->ProposeNonIonizingEnergyDeposit(aTrack.GetKineticEnergy() - InitE*c);
|
||||
pParticleChange->ProposeLocalEnergyDeposit(aTrack.GetKineticEnergy());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((IncPartName == "Genericion") || (IncPartName == "alpha")
|
||||
|| (IncPartName == "He3") || (IncPartName == "deuteron")
|
||||
|| (IncPartName == "triton") || (IncPartName == "proton"))
|
||||
{
|
||||
pParticleChange->ProposeNonIonizingEnergyDeposit(NIEdep);
|
||||
pParticleChange->ProposeLocalEnergyDeposit(aTrack.GetKineticEnergy());
|
||||
}
|
||||
else
|
||||
{
|
||||
pParticleChange->ProposeNonIonizingEnergyDeposit(0.0);
|
||||
pParticleChange->ProposeLocalEnergyDeposit(aTrack.GetKineticEnergy());
|
||||
}
|
||||
}
|
||||
} // matWF == tableWF.end())
|
||||
|
||||
fParticleChange.SetProposedKineticEnergy(0.0);
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4double G4MicroElecCapture::GetMeanFreePath(const G4Track& aTrack, G4double,
|
||||
G4ForceCondition*)
|
||||
{
|
||||
G4String material = aTrack.GetMaterial()->GetName();
|
||||
// test particle type in order to applied the capture to both electrons, protons and heavy ions
|
||||
|
||||
if ((aTrack.GetParticleDefinition()->GetParticleName()) == "e-")
|
||||
{
|
||||
if (material != "G4_ALUMINUM_OXIDE" && material != "G4_SILICON_DIOXIDE"
|
||||
&& material != "G4_BORON_NITRIDE")
|
||||
{
|
||||
return DBL_MAX;
|
||||
}
|
||||
G4double S = 0;
|
||||
G4double y = 0;
|
||||
if (material == "G4_ALUMINUM_OXIDE")
|
||||
{
|
||||
S = 1 * (1 / nm);
|
||||
y = 0.25 * (1 / eV);
|
||||
}
|
||||
if (material == "G4_SILICON_DIOXIDE")
|
||||
{
|
||||
S = 0.3 * (1 / nm);
|
||||
y = 0.2 * (1 / eV);
|
||||
}
|
||||
if (material == "G4_BORON_NITRIDE")
|
||||
{
|
||||
S = 0 * (1 / nm);
|
||||
y = 1 * (1 / eV);
|
||||
}
|
||||
|
||||
G4double P = S * G4Exp(-y * aTrack.GetKineticEnergy());
|
||||
if (P <= 0) { return DBL_MAX; }
|
||||
else { return 1 / P; }
|
||||
}
|
||||
else return DBL_MAX;
|
||||
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4double G4MicroElecCapture::G_Lindhard_Rob(G4double Trecoil, G4int Zrecoil, G4int Arecoil, G4int Zcible, G4int Acible)
|
||||
{
|
||||
G4double Lind =0.0;
|
||||
|
||||
if (Arecoil <= 0 || Zrecoil == 0)
|
||||
{
|
||||
Lind = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4double El = 30.724 * Zcible * Zrecoil
|
||||
* std::pow((G4Pow::GetInstance()->Z23(Zcible) + G4Pow::GetInstance()->Z23(Zrecoil)), 0.5)
|
||||
* (Arecoil + Acible) / Acible;
|
||||
|
||||
// multiplication by 1e6 to change El from eV to MeV
|
||||
G4double e = Trecoil / (El * CLHEP::eV);
|
||||
G4double Fl = (0.0793 * G4Pow::GetInstance()->Z23(Zrecoil) * std::pow(Zcible, 0.5) * std::pow((Arecoil + Acible), 1.5))
|
||||
/ (std::pow((G4Pow::GetInstance()->Z23(Zcible) + G4Pow::GetInstance()->Z23(Zrecoil)), 3. / 4.) * std::pow(Arecoil, 3. / 2.) * std::pow(Acible, 1. / 2.));
|
||||
|
||||
Lind = 1. / (1 + Fl * (3.4008 * std::pow(e, 1. / 6.) + 0.40244 * std::pow(e, 3. / 4.) + e));
|
||||
|
||||
// to get the energie that go into displacement
|
||||
Lind = Lind * Trecoil;
|
||||
}
|
||||
return Lind;
|
||||
}
|
||||
@@ -78,6 +78,7 @@
|
||||
#include "G4Exp.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "G4String.hh"
|
||||
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
@@ -348,6 +349,18 @@ G4double G4MicroElecElasticModel_new::CrossSectionPerVolume(const G4Material* ma
|
||||
return AcousticCrossSectionPerVolume(ekin, kbz, rho, cs, Aac, Eac, prefactor);
|
||||
}
|
||||
|
||||
else if (currentMaterialName == "ALUMINUM_OXIDE" && ekin < 20 * eV) {
|
||||
acousticModelEnabled = true;
|
||||
|
||||
//Values for Al2O3
|
||||
G4double kbz = 8871930614.247564,
|
||||
rho = 3.97 * 1000, // [g/cm3] * 1000
|
||||
cs = 233329.07733059773, //Sound speed
|
||||
Aac = 2.9912494342262614e-19, //A screening parameter
|
||||
Eac = 2.1622471654789847e-18, //C deformation potential
|
||||
prefactor = 1;
|
||||
return AcousticCrossSectionPerVolume(ekin, kbz, rho, cs, Aac, Eac, prefactor);
|
||||
}
|
||||
//Elastic
|
||||
else {
|
||||
acousticModelEnabled = false;
|
||||
@@ -395,6 +408,11 @@ G4double G4MicroElecElasticModel_new::CrossSectionPerVolume(const G4Material* ma
|
||||
G4cout << " - Cross section per Si atom (cm^2)=" << sigma / cm / cm << G4endl;
|
||||
G4cout << " - Cross section per Si atom (cm^-1)=" << sigma*density / (1. / cm) << G4endl;
|
||||
}
|
||||
|
||||
// Hsing-YinChangaAndrewAlvaradoaTreyWeberaJaimeMarianab Monte Carlo modeling of low-energy electron-induced secondary electron emission yields in micro-architected boron nitride surfaces - ScienceDirect, (n.d.). https://www.sciencedirect.com/science/article/pii/S0168583X19304069 (accessed April 1, 2022).
|
||||
if (currentMaterialName == "BORON_NITRIDE") {
|
||||
sigma = sigma * tanh(0.5 * pow(ekin / 5.2e-6, 2));
|
||||
}
|
||||
return sigma*density;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
|
||||
#include "globals.hh"
|
||||
#include "G4MicroElecInelasticModel_new.hh"
|
||||
#include "G4MicroElecInelasticModel_new.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ios.hh"
|
||||
@@ -143,37 +143,22 @@ G4MicroElecInelasticModel_new::~G4MicroElecInelasticModel_new()
|
||||
}
|
||||
tableTCS.clear();
|
||||
|
||||
dataDiffCSMap::iterator iterator_proba;
|
||||
// (1)
|
||||
for (iterator_proba = eNrjTransStorage.begin(); iterator_proba != eNrjTransStorage.end(); ++iterator_proba) {
|
||||
vector<TriDimensionMap>* eNrjTransfData = iterator_proba->second;
|
||||
eNrjTransfData->clear();
|
||||
delete eNrjTransfData;
|
||||
for (auto const & obj : eNrjTransStorage) {
|
||||
delete obj.second;
|
||||
}
|
||||
eNrjTransStorage.clear();
|
||||
|
||||
for (iterator_proba = pNrjTransStorage.begin(); iterator_proba != pNrjTransStorage.end(); ++iterator_proba) {
|
||||
vector<TriDimensionMap>* pNrjTransfData = iterator_proba->second;
|
||||
pNrjTransfData->clear();
|
||||
delete pNrjTransfData;
|
||||
for (auto const & obj : pNrjTransStorage) {
|
||||
delete obj.second;
|
||||
}
|
||||
pNrjTransStorage.clear();
|
||||
|
||||
// (2)
|
||||
for (iterator_proba = eDiffDatatable.begin(); iterator_proba != eDiffDatatable.end(); ++iterator_proba) {
|
||||
vector<TriDimensionMap>* eDiffCrossSectionData = iterator_proba->second;
|
||||
eDiffCrossSectionData->clear();
|
||||
delete eDiffCrossSectionData;
|
||||
}
|
||||
eDiffDatatable.clear();
|
||||
|
||||
for (iterator_proba = pDiffDatatable.begin(); iterator_proba != pDiffDatatable.end(); ++iterator_proba) {
|
||||
vector<TriDimensionMap>* pDiffCrossSectionData = iterator_proba->second;
|
||||
pDiffCrossSectionData->clear();
|
||||
delete pDiffCrossSectionData;
|
||||
// (2)
|
||||
for (auto const & obj : eDiffDatatable) {
|
||||
delete obj.second;
|
||||
}
|
||||
pDiffDatatable.clear();
|
||||
|
||||
for (auto const & obj : pDiffDatatable) {
|
||||
delete obj.second;
|
||||
}
|
||||
|
||||
// (3)
|
||||
dataProbaShellMap::iterator iterator_probaShell;
|
||||
|
||||
@@ -309,7 +294,6 @@ void G4MicroElecInelasticModel_new::Initialise(const G4ParticleDefinition* parti
|
||||
|
||||
if (fasterCode) G4Exception("G4MicroElecInelasticModel_new::Initialise", "em0003",
|
||||
FatalException, sortieString.c_str());
|
||||
|
||||
else {
|
||||
G4Exception("G4MicroElecInelasticModel_new::Initialise", "em0003",
|
||||
FatalException, "Missing data file:/microelec/sigmadiff_inelastic_e_Si.dat");
|
||||
@@ -478,13 +462,13 @@ void G4MicroElecInelasticModel_new::Initialise(const G4ParticleDefinition* parti
|
||||
pIncidentEnergyStorage[mat] = pTdummyVec;
|
||||
|
||||
//Cleanup support vectors
|
||||
// delete pNrjTransfData;
|
||||
// delete eVecm;
|
||||
// delete pDiffCrossSectionData;
|
||||
// delete pProbaShellMap;
|
||||
//delete pNrjTransfData;
|
||||
//delete eVecm;
|
||||
//delete pDiffCrossSectionData;
|
||||
//delete pProbaShellMap;
|
||||
}
|
||||
tableTCS[mat] = tableData;
|
||||
}
|
||||
}
|
||||
if (particle==electronDef)
|
||||
{
|
||||
SetLowEnergyLimit(lowEnergyLimit[electron]);
|
||||
@@ -669,6 +653,8 @@ void G4MicroElecInelasticModel_new::SampleSecondaries(std::vector<G4DynamicParti
|
||||
|
||||
G4double bindingEnergy = currentMaterialStructure->Energy(Shell);
|
||||
G4double limitEnergy = currentMaterialStructure->GetLimitEnergy(Shell);
|
||||
|
||||
G4bool weaklyBound = currentMaterialStructure->IsShellWeaklyBound(Shell);
|
||||
|
||||
if (verboseLevel > 3)
|
||||
{
|
||||
@@ -676,14 +662,18 @@ void G4MicroElecInelasticModel_new::SampleSecondaries(std::vector<G4DynamicParti
|
||||
G4cout << "Shell: " << Shell << ", energy: " << bindingEnergy/eV << G4endl;
|
||||
}
|
||||
|
||||
|
||||
if (k<limitEnergy) {
|
||||
if (weaklyBound && k > currentMaterialStructure->GetEnergyGap()) {
|
||||
limitEnergy = currentMaterialStructure->GetEnergyGap();
|
||||
}
|
||||
else return; }
|
||||
|
||||
// sample deexcitation
|
||||
|
||||
std::size_t secNumberInit = 0; // need to know at a certain point the energy of secondaries
|
||||
std::size_t secNumberFinal = 0; // So I'll make the difference and then sum the energies
|
||||
|
||||
//SI: additional protection if tcs interpolation method is modified
|
||||
//if (k<bindingEnergy) return;
|
||||
if (k<limitEnergy) return;
|
||||
|
||||
// G4cout << currentMaterial << G4endl;
|
||||
G4int Z = currentMaterialStructure->GetZ(Shell);
|
||||
G4int shellEnum = currentMaterialStructure->GetEADL_Enumerator(Shell);
|
||||
@@ -745,10 +735,20 @@ void G4MicroElecInelasticModel_new::SampleSecondaries(std::vector<G4DynamicParti
|
||||
for (std::size_t j=secNumberInit; j < secNumberFinal; ++j) {
|
||||
deexSecEnergy = deexSecEnergy + (*fvect)[j]->GetKineticEnergy();
|
||||
}
|
||||
if (SEFromFermiLevel) limitEnergy = currentMaterialStructure->GetEnergyGap();
|
||||
fParticleChangeForGamma->SetProposedKineticEnergy(ekin - secondaryKinetic - limitEnergy); //Ef = Ei-(Q-El)-El = Ei-Q
|
||||
fParticleChangeForGamma->ProposeLocalEnergyDeposit(limitEnergy - deexSecEnergy);
|
||||
|
||||
// correction CI 12/01/2023 limit energy = gap
|
||||
//if (SEFromFermiLevel) limitEnergy = currentMaterialStructure->GetEnergyGap();
|
||||
//fParticleChangeForGamma->SetProposedKineticEnergy(ekin - secondaryKinetic - limitEnergy); //Ef = Ei-(Q-El)-El = Ei-Q
|
||||
//fParticleChangeForGamma->ProposeLocalEnergyDeposit(limitEnergy - deexSecEnergy);
|
||||
|
||||
// correction CI 09/03/2022 limit energy = gap
|
||||
//if (!SEFromFermiLevel && weaklyBound) limitEnergy += currentMaterialStructure->GetInitialEnergy();
|
||||
//if (!SEFromFermiLevel && weaklyBound) limitEnergy += currentMaterialStructure->GetEnergyGap();
|
||||
fParticleChangeForGamma->SetProposedKineticEnergy(ekin - secondaryKinetic-limitEnergy); //Ef = Ei-(Q-El)-El = Ei-Q
|
||||
fParticleChangeForGamma->ProposeLocalEnergyDeposit(limitEnergy-deexSecEnergy);
|
||||
|
||||
|
||||
|
||||
|
||||
if (secondaryKinetic>0)
|
||||
{
|
||||
G4DynamicParticle* dp = new G4DynamicParticle(G4Electron::Electron(), deltaDirection, secondaryKinetic); //Esec = Q-El
|
||||
@@ -791,7 +791,9 @@ G4double G4MicroElecInelasticModel_new::RandomizeEjectedElectronEnergy(
|
||||
} while(G4UniformRand()*crossSectionMaximum >
|
||||
DifferentialCrossSection(particleDefinition, k,
|
||||
(secondaryElectronKineticEnergy+currentMaterialStructure->GetLimitEnergy(shell)),shell));
|
||||
}
|
||||
// added 12/01/2023
|
||||
return secondaryElectronKineticEnergy;
|
||||
}
|
||||
else if (particleDefinition == G4Proton::ProtonDefinition())
|
||||
{
|
||||
G4double maximumEnergyTransfer =
|
||||
@@ -839,17 +841,24 @@ G4double G4MicroElecInelasticModel_new::RandomizeEjectedElectronEnergyFromCumula
|
||||
{
|
||||
G4double secondaryElectronKineticEnergy = 0.;
|
||||
G4double random = G4UniformRand();
|
||||
|
||||
secondaryElectronKineticEnergy = TransferedEnergy(particleDefinition, k, shell, random)
|
||||
- currentMaterialStructure->GetLimitEnergy(shell) ;
|
||||
|
||||
if (isnan(secondaryElectronKineticEnergy)) { secondaryElectronKineticEnergy = k - currentMaterialStructure->GetLimitEnergy(shell); }
|
||||
|
||||
if (secondaryElectronKineticEnergy < 0.) {
|
||||
secondaryElectronKineticEnergy = k - currentMaterialStructure->GetEnergyGap();
|
||||
SEFromFermiLevel = true;
|
||||
}
|
||||
return secondaryElectronKineticEnergy;
|
||||
G4bool weaklyBound = currentMaterialStructure->IsShellWeaklyBound(shell);
|
||||
G4double transf = TransferedEnergy(particleDefinition, k, shell, random);
|
||||
if (!weaklyBound) {
|
||||
secondaryElectronKineticEnergy = transf - currentMaterialStructure->GetLimitEnergy(shell); //shell energy for core electrons,
|
||||
if(secondaryElectronKineticEnergy <= 0.) {
|
||||
secondaryElectronKineticEnergy = 0.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
secondaryElectronKineticEnergy = transf - currentMaterialStructure->GetLimitEnergy(shell);
|
||||
// for weaklybound electrons = gap + average energy in the energy band
|
||||
if (secondaryElectronKineticEnergy <= 0.) {
|
||||
secondaryElectronKineticEnergy = 0.0;
|
||||
SEFromFermiLevel = true;
|
||||
}
|
||||
}
|
||||
//corrections CI 07/02/2022 - added
|
||||
return secondaryElectronKineticEnergy;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -901,7 +910,7 @@ G4double G4MicroElecInelasticModel_new::TransferedEnergy(
|
||||
vector<VecMap>* eProbaShellMap = iterator_Proba->second; //Storage of probabilities for energy transfer
|
||||
vector<G4double>* eTdummyVec = iterator_Tdummy->second; //Incident energies for interpolation
|
||||
|
||||
// k should be in eV
|
||||
// k should be in eV auto, :std::vector<double>::iterator
|
||||
auto k2 = std::upper_bound(eTdummyVec->begin(),
|
||||
eTdummyVec->end(),
|
||||
k);
|
||||
@@ -1001,14 +1010,14 @@ G4double G4MicroElecInelasticModel_new::TransferedEnergy(
|
||||
incidentEnergyMap::iterator iterator_Tdummy;
|
||||
iterator_Tdummy = pIncidentEnergyStorage.find(currentMaterial);
|
||||
|
||||
if (iterator_Nrj == pNrjTransStorage.end() || iterator_Proba == pProbaShellStorage.end() ||
|
||||
iterator_Tdummy == pIncidentEnergyStorage.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += currentMaterial + " not found!";
|
||||
G4Exception("G4MicroElecInelasticModel_new::TransferedEnergy", "em0002",
|
||||
FatalException, str);
|
||||
}
|
||||
if (iterator_Nrj == pNrjTransStorage.end() || iterator_Proba == pProbaShellStorage.end() ||
|
||||
iterator_Tdummy == pIncidentEnergyStorage.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += currentMaterial + " not found!";
|
||||
G4Exception("G4MicroElecInelasticModel_new::TransferedEnergy", "em0002",
|
||||
FatalException, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<TriDimensionMap>* pNrjTransfData = iterator_Nrj->second; //Storage of possible transfer energies
|
||||
@@ -1085,7 +1094,7 @@ G4double G4MicroElecInelasticModel_new::TransferedEnergy(
|
||||
nrjTransf22);
|
||||
|
||||
// zeros are explicitly set
|
||||
G4double value = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
|
||||
G4double value = Interpolate(valueK1, valueK2, k, 0., interpolatedvalue2);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1262,9 +1271,11 @@ G4double G4MicroElecInelasticModel_new::Interpolate(G4double e1,
|
||||
G4double xs2)
|
||||
{
|
||||
G4double value = 0.;
|
||||
if (e == e1 || e1 == e2 ) { return xs1; }
|
||||
if (e == e2) { return xs2; }
|
||||
|
||||
// Log-log interpolation by default
|
||||
if (e1 != 0 && e2 != 0 && (e2-e1) != 0 && !fasterCode)
|
||||
if (e1 > 0. && e2 > 0. && xs1 > 0. && xs2 > 0. && !fasterCode)
|
||||
{
|
||||
G4double a = std::log(xs2/xs1)/ std::log(e2/e1);
|
||||
G4double b = std::log(xs2) - a * std::log(e2);
|
||||
@@ -1273,7 +1284,7 @@ G4double G4MicroElecInelasticModel_new::Interpolate(G4double e1,
|
||||
}
|
||||
|
||||
// Switch to log-lin interpolation for faster code
|
||||
if ((e2 - e1) != 0 && xs1 != 0 && xs2 != 0 && fasterCode)
|
||||
else if (xs1 > 0. && xs2 > 0. && fasterCode)
|
||||
{
|
||||
G4double d1 = std::log(xs1);
|
||||
G4double d2 = std::log(xs2);
|
||||
@@ -1282,7 +1293,7 @@ G4double G4MicroElecInelasticModel_new::Interpolate(G4double e1,
|
||||
|
||||
// Switch to lin-lin interpolation for faster code
|
||||
// in case one of xs1 or xs2 (=cum proba) value is zero
|
||||
if ((e2 - e1) != 0 && (xs1 == 0 || xs2 == 0) && fasterCode)
|
||||
else
|
||||
{
|
||||
G4double d1 = xs1;
|
||||
G4double d2 = xs2;
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
//
|
||||
//
|
||||
// G4MicroElecLOPhononModel.cc,
|
||||
// 2020/05/20 P. Caron, C. Inguimbert are with ONERA [b]
|
||||
// Q. Gibaru is with CEA [a], ONERA [b] and CNES [c]
|
||||
// M. Raine and D. Lambert are with CEA [a]
|
||||
// 2020/05/20 P. Caron, C. Inguimbert are with ONERA [b]
|
||||
// Q. Gibaru is with CEA [a], ONERA [b] and CNES [c]
|
||||
// M. Raine and D. Lambert are with CEA [a]
|
||||
//
|
||||
// A part of this work has been funded by the French space agency(CNES[c])
|
||||
// [a] CEA, DAM, DIF - 91297 ARPAJON, France
|
||||
@@ -36,45 +36,41 @@
|
||||
//
|
||||
// Based on the following publications
|
||||
//
|
||||
// - J. Pierron, C. Inguimbert, M. Belhaj, T. Gineste, J. Puech, M. Raine
|
||||
// Electron emission yield for low energy electrons:
|
||||
// Monte Carlo simulation and experimental comparison for Al, Ag, and Si
|
||||
// Journal of Applied Physics 121 (2017) 215107.
|
||||
// https://doi.org/10.1063/1.4984761
|
||||
// - J. Pierron, C. Inguimbert, M. Belhaj, T. Gineste, J. Puech, M. Raine
|
||||
// Electron emission yield for low energy electrons:
|
||||
// Monte Carlo simulation and experimental comparison for Al, Ag, and Si
|
||||
// Journal of Applied Physics 121 (2017) 215107.
|
||||
// https://doi.org/10.1063/1.4984761
|
||||
//
|
||||
// - P. Caron,
|
||||
// Study of Electron-Induced Single-Event Upset in Integrated Memory Devices
|
||||
// PHD, 16th October 2019
|
||||
// - P. Caron,
|
||||
// Study of Electron-Induced Single-Event Upset in Integrated Memory Devices
|
||||
// PHD, 16th October 2019
|
||||
//
|
||||
// - Q.Gibaru, C.Inguimbert, P.Caron, M.Raine, D.Lambert, J.Puech,
|
||||
// Geant4 physics processes for microdosimetry and secondary electron emission simulation :
|
||||
// Extension of MicroElec to very low energies and new materials
|
||||
// NIM B, 2020, in review.
|
||||
// - Q.Gibaru, C.Inguimbert, P.Caron, M.Raine, D.Lambert, J.Puech,
|
||||
// Geant4 physics processes for microdosimetry and secondary electron emission simulation :
|
||||
// Extension of MicroElec to very low energies and new materials
|
||||
// NIM B, 2020, in review.
|
||||
//
|
||||
//
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "G4MicroElecLOPhononModel.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
|
||||
G4MicroElecLOPhononModel::G4MicroElecLOPhononModel(const G4ParticleDefinition*,
|
||||
const G4String& nam)
|
||||
: G4VEmModel(nam)
|
||||
const G4String& nam)
|
||||
: G4VEmModel(nam),isInitialised(false)
|
||||
{
|
||||
fParticleChangeForGamma = GetParticleChangeForGamma();
|
||||
G4cout << "Phonon model is constructed " << G4endl
|
||||
<< "Phonon Energy = " << phononEnergy / eV << " eV "<< G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4MicroElecLOPhononModel::~G4MicroElecLOPhononModel()
|
||||
{}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4MicroElecLOPhononModel::Initialise(const G4ParticleDefinition*,
|
||||
const G4DataVector& /*cuts*/)
|
||||
{
|
||||
{
|
||||
if (isInitialised) { return; }
|
||||
fParticleChangeForGamma = GetParticleChangeForGamma();
|
||||
isInitialised = true;
|
||||
@@ -82,58 +78,102 @@ void G4MicroElecLOPhononModel::Initialise(const G4ParticleDefinition*,
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
G4double G4MicroElecLOPhononModel::CrossSectionPerVolume(const G4Material* material,
|
||||
const G4ParticleDefinition*,
|
||||
G4double ekin,
|
||||
G4double, G4double)
|
||||
G4double G4MicroElecLOPhononModel::
|
||||
CrossSectionPerVolume(const G4Material* material,
|
||||
const G4ParticleDefinition* p,
|
||||
G4double ekin,
|
||||
G4double, G4double)
|
||||
{
|
||||
if (material->GetName()!="G4_SILICON_DIOXIDE") return 0.0;
|
||||
|
||||
const G4double e = CLHEP::eplus / CLHEP::coulomb;
|
||||
const G4double m0 = CLHEP::electron_mass_c2 / (CLHEP::c_squared*CLHEP::kg);
|
||||
const G4double h = CLHEP::hbar_Planck * CLHEP::s/ (CLHEP::m2*CLHEP::kg);
|
||||
const G4double eps0 = CLHEP::epsilon0 * CLHEP::m/ (CLHEP::farad);
|
||||
const G4double kb = CLHEP::k_Boltzmann * CLHEP::kelvin/ CLHEP::joule;
|
||||
const G4double T = 300;
|
||||
G4double eps = 9;
|
||||
G4double einf = 3;
|
||||
|
||||
// Parameters SiO2
|
||||
phononEnergy = (0.75*0.153+0.25*0.063 )* CLHEP::eV;
|
||||
const G4double eps = 3.84;
|
||||
const G4double einf = 2.25;
|
||||
const G4double T = 300; // should be taken from material property
|
||||
|
||||
G4double E =(ekin/CLHEP::eV)*e;
|
||||
|
||||
G4double hw = (phononEnergy / CLHEP::eV) * e;
|
||||
const G4DataVector cuts;
|
||||
Initialise(p, cuts);
|
||||
|
||||
if (material->GetName() != "G4_SILICON_DIOXIDE"
|
||||
&& material->GetName() != "G4_ALUMINUM_OXIDE"
|
||||
&& material->GetName() != "G4_BORON_NITRIDE")
|
||||
{
|
||||
return 1 / DBL_MAX;
|
||||
}
|
||||
|
||||
G4double E =(ekin/eV)*e;
|
||||
|
||||
if (material->GetName() == "G4_ALUMINUM_OXIDE")
|
||||
{
|
||||
eps = 9;
|
||||
einf = 3;
|
||||
phononEnergy = 0.1*eV;
|
||||
}
|
||||
if (material->GetName() == "G4_SILICON_DIOXIDE")
|
||||
{
|
||||
eps = 3.84;
|
||||
einf = 2.25;
|
||||
phononEnergy = (0.75*0.153+0.25*0.063 )* eV;
|
||||
}
|
||||
|
||||
// Nuclear Instruments and Methods in Physics Research Section B:
|
||||
// Beam Interactions with Materials and Atoms
|
||||
// Volume 454, 1 September 2019, Pages 14 - 22
|
||||
// Nuclear Instruments and Methods in Physics Research Section B:
|
||||
// Beam Interactions with Materials and Atoms
|
||||
// Monte Carlo modeling of low - energy electron - induced secondary
|
||||
// electron emission yields in micro - architected boron nitride surfaces
|
||||
|
||||
if (material->GetName() == "G4_BORON_NITRIDE")
|
||||
{
|
||||
eps = 7.1;
|
||||
einf = 4.5;
|
||||
phononEnergy = 0.17 * eV;
|
||||
}
|
||||
|
||||
G4double hw = (phononEnergy / eV) * e;
|
||||
G4double n = 1.0 / (std::exp(hw / (kb*T)) - 1); //Phonon distribution
|
||||
|
||||
G4double signe = (absor) ? -1. : 1.;
|
||||
|
||||
G4double racine = std::sqrt(1. + ((-signe*hw) / E));
|
||||
|
||||
G4double P = (std::pow(e, 2) / (4 * pi*eps0*h*h)) * (n + 0.5 + signe*0.5) * ((1 / einf) - (1 / eps))
|
||||
* std::sqrt(m0 / (2 * E)) *hw* std::log((1 + racine) / (signe * 1 + ((-signe)*racine)));
|
||||
|
||||
G4double MFP = (std::sqrt(2. * E / m0) / P)*m;
|
||||
return 2. / MFP;
|
||||
|
||||
if (absor) // Absorption
|
||||
{
|
||||
Eprim = E + hw;
|
||||
signe = -1;
|
||||
}
|
||||
else // Emission
|
||||
{
|
||||
Eprim = E - hw;
|
||||
signe = +1;
|
||||
}
|
||||
|
||||
G4double racine = std::sqrt(1 + ((-signe*hw) / E));
|
||||
G4double P = (std::pow(e, 2) / (4 * pi*eps0*h*h)) * (n + 0.5 + signe*0.5) * ((1 / einf) - (1 / eps)) * std::sqrt(m0 / (2 * E)) *hw* std::log((1 + racine) / (signe * 1 + ((-signe)*racine)));
|
||||
G4double MFP = (std::sqrt(2 * E / m0) / P)*m;
|
||||
|
||||
if (material->GetName() == "G4_SILICON_DIOXIDE") { return 2 / MFP; }
|
||||
return 1/(MFP);
|
||||
// correction CI 12/1/2023 add
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
void G4MicroElecLOPhononModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>*,
|
||||
const G4MaterialCutsCouple*,
|
||||
const G4DynamicParticle* aDynamicElectron,
|
||||
G4double, G4double)
|
||||
void G4MicroElecLOPhononModel::
|
||||
SampleSecondaries(std::vector<G4DynamicParticle*>*,
|
||||
const G4MaterialCutsCouple*,
|
||||
const G4DynamicParticle* aDynamicElectron,
|
||||
G4double, G4double)
|
||||
{
|
||||
|
||||
G4double E = aDynamicElectron->GetKineticEnergy();
|
||||
G4double Eprim = (absor) ? E + phononEnergy : E - phononEnergy;
|
||||
Eprim = (absor) ? E + phononEnergy : E - phononEnergy;
|
||||
|
||||
G4double rand = G4UniformRand();
|
||||
G4double B = (E + Eprim + 2 * std::sqrt(E*Eprim)) / (E + Eprim - 2 * std::sqrt(E*Eprim));
|
||||
G4double cosTheta = ((E + Eprim) / (2 * std::sqrt(E*Eprim)))*(1 - std::pow(B, rand)) + std::pow(B, rand);
|
||||
|
||||
if(Interband){
|
||||
G4double B = (E + Eprim + 2 * std::sqrt(E*Eprim))
|
||||
/ (E + Eprim - 2 * std::sqrt(E*Eprim));
|
||||
G4double cosTheta = ((E + Eprim) / (2 * std::sqrt(E*Eprim)))
|
||||
* (1 - std::pow(B, rand)) + std::pow(B, rand);
|
||||
if(Interband)
|
||||
{
|
||||
cosTheta = 1 - 2 * G4UniformRand(); //Isotrope
|
||||
}
|
||||
G4double phi = twopi * G4UniformRand();
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
//
|
||||
//
|
||||
// G4MicroElecSurface.cc,
|
||||
// 2020/05/20 P. Caron, C. Inguimbert are with ONERA [b]
|
||||
// Q. Gibaru is with CEA [a], ONERA [b] and CNES [c]
|
||||
// M. Raine and D. Lambert are with CEA [a]
|
||||
// 2020/05/20 P. Caron, C. Inguimbert are with ONERA [b]
|
||||
// Q. Gibaru is with CEA [a], ONERA [b] and CNES [c]
|
||||
// M. Raine and D. Lambert are with CEA [a]
|
||||
//
|
||||
// A part of this work has been funded by the French space agency(CNES[c])
|
||||
// [a] CEA, DAM, DIF - 91297 ARPAJON, France
|
||||
@@ -36,28 +36,24 @@
|
||||
//
|
||||
// Based on the following publications
|
||||
//
|
||||
// - Q.Gibaru, C.Inguimbert, P.Caron, M.Raine, D.Lambert, J.Puech,
|
||||
// Geant4 physics processes for microdosimetry and secondary electron emission simulation :
|
||||
// Extension of MicroElec to very low energies and new materials
|
||||
// NIM B, 2020, in review.
|
||||
// - Q.Gibaru, C.Inguimbert, P.Caron, M.Raine, D.Lambert, J.Puech,
|
||||
// Geant4 physics processes for microdosimetry and secondary electron emission simulation:
|
||||
// Extension of MicroElec to very low energies and new materials
|
||||
// NIM B, 2020, in review.
|
||||
//
|
||||
//
|
||||
// - Modèle de transport d'électrons à basse énergie (10 eV- 2 keV) pour
|
||||
// applications spatiales (OSMOSEE, GEANT4), PhD dissertation, 2017.
|
||||
//
|
||||
// - Modele de transport d'electrons a basse energie (10 eV- 2 keV) pour
|
||||
// applications spatiales (OSMOSEE, GEANT4), PhD dissertation, 2017.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "G4MicroElecSurface.hh"
|
||||
|
||||
#include "G4ios.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4EmProcessSubType.hh"
|
||||
#include "G4GeometryTolerance.hh"
|
||||
#include "G4EmProcessSubType.hh"
|
||||
|
||||
#include "G4SystemOfUnits.hh"
|
||||
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4MicroElecSurface::G4MicroElecSurface(const G4String& processName,G4ProcessType type)
|
||||
@@ -66,9 +62,9 @@ G4MicroElecSurface::G4MicroElecSurface(const G4String& processName,G4ProcessType
|
||||
theGlobalNormal(0.,0.,0.), theFacetNormal(0.,0.,0.)
|
||||
{
|
||||
if ( verboseLevel > 0)
|
||||
{
|
||||
G4cout << GetProcessName() << " is created " << G4endl;
|
||||
}
|
||||
{
|
||||
G4cout << GetProcessName() << " is created " << G4endl;
|
||||
}
|
||||
|
||||
isInitialised=false;
|
||||
SetProcessSubType(fSurfaceReflection);
|
||||
@@ -103,6 +99,36 @@ G4MicroElecSurface::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4MicroElecSurface::Initialise()
|
||||
{
|
||||
if (isInitialised) { return; }
|
||||
|
||||
G4ProductionCutsTable* theCoupleTable =
|
||||
G4ProductionCutsTable::GetProductionCutsTable();
|
||||
G4int numOfCouples = (G4int)theCoupleTable->GetTableSize();
|
||||
G4cout << numOfCouples << G4endl;
|
||||
|
||||
for (G4int i = 0; i < numOfCouples; ++i)
|
||||
{
|
||||
const G4Material* material =
|
||||
theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
|
||||
|
||||
G4cout << this->GetProcessName() << ", Material " << i + 1
|
||||
<< " / " << numOfCouples << " : " << material->GetName() << G4endl;
|
||||
if (material->GetName() == "Vacuum")
|
||||
{
|
||||
tableWF[material->GetName()] = 0; continue;
|
||||
}
|
||||
G4String mat = material->GetName();
|
||||
G4MicroElecMaterialStructure str = G4MicroElecMaterialStructure(mat);
|
||||
tableWF[mat] = str.GetWorkFunction();
|
||||
}
|
||||
|
||||
isInitialised = true;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4MicroElecSurface::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
if (isInitialised) { return; }
|
||||
@@ -113,12 +139,18 @@ void G4MicroElecSurface::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
G4cout << "G4MicroElecSurface::Initialise: Ncouples= "
|
||||
<< numOfCouples << G4endl;
|
||||
|
||||
for (G4int i = 0; i < numOfCouples; ++i) {
|
||||
for (G4int i = 0; i < numOfCouples; ++i)
|
||||
{
|
||||
const G4Material* material =
|
||||
theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
|
||||
|
||||
G4cout << "G4Surface, Material " << i + 1 << " / " << numOfCouples << " : " << material->GetName() << G4endl;
|
||||
if (material->GetName() == "Vacuum") { tableWF[material->GetName()] = 0; continue; }
|
||||
G4cout << "G4Surface, Material " << i + 1 << " / "
|
||||
<< numOfCouples << " : " << material->GetName() << G4endl;
|
||||
if (material->GetName() == "Vacuum")
|
||||
{
|
||||
tableWF[material->GetName()] = 0;
|
||||
continue;
|
||||
}
|
||||
G4String mat = material->GetName();
|
||||
G4MicroElecMaterialStructure str = G4MicroElecMaterialStructure(mat);
|
||||
tableWF[mat] = str.GetWorkFunction();
|
||||
@@ -130,263 +162,287 @@ void G4MicroElecSurface::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
|
||||
G4VParticleChange* G4MicroElecSurface::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
|
||||
{
|
||||
|
||||
if (!isInitialised) { Initialise(); }
|
||||
theStatus = UndefinedSurf;
|
||||
|
||||
//Definition of the parameters for the particle
|
||||
|
||||
// Definition of the parameters for the particle
|
||||
aParticleChange.Initialize(aTrack);
|
||||
aParticleChange.ProposeVelocity(aTrack.GetVelocity());
|
||||
|
||||
|
||||
G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
|
||||
G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
|
||||
|
||||
|
||||
material1 = pPreStepPoint -> GetMaterial();
|
||||
material2 = pPostStepPoint -> GetMaterial();
|
||||
|
||||
|
||||
theStatus = UndefinedSurf;
|
||||
|
||||
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
|
||||
|
||||
|
||||
theParticleMomentum = aParticle->GetTotalMomentum();
|
||||
previousMomentum = oldMomentum;
|
||||
oldMomentum = aParticle->GetMomentumDirection();
|
||||
|
||||
//First case: not a boundary
|
||||
if (pPostStepPoint->GetStepStatus() != fGeomBoundary ||
|
||||
pPostStepPoint->GetPhysicalVolume() == pPreStepPoint->GetPhysicalVolume())
|
||||
{
|
||||
theStatus = NotAtBoundarySurf;
|
||||
flag_franchissement_surface = false;
|
||||
|
||||
|
||||
// Fisrt case: not a boundary
|
||||
if (pPostStepPoint->GetStepStatus() != fGeomBoundary
|
||||
|| pPostStepPoint->GetPhysicalVolume()->GetName() == pPreStepPoint->GetPhysicalVolume()->GetName())
|
||||
{
|
||||
theStatus = NotAtBoundarySurf;
|
||||
flag_franchissement_surface = false;
|
||||
flag_reflexion = false;
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
theStatus = UndefinedSurf;
|
||||
|
||||
// Third case: same material
|
||||
if (material1 == material2)
|
||||
{
|
||||
theStatus = SameMaterialSurf;
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
if (verboseLevel > 3)
|
||||
{
|
||||
G4cout << G4endl << " Electron at Boundary! " << G4endl;
|
||||
G4VPhysicalVolume* thePrePV = pPreStepPoint->GetPhysicalVolume();
|
||||
G4VPhysicalVolume* thePostPV = pPostStepPoint->GetPhysicalVolume();
|
||||
if (thePrePV) G4cout << " thePrePV: " << thePrePV->GetName() << G4endl;
|
||||
if (thePostPV) G4cout << " thePostPV: " << thePostPV->GetName() << G4endl;
|
||||
G4cout << " Old Momentum Direction: " << oldMomentum << G4endl;
|
||||
}
|
||||
|
||||
// Definition of the parameters for the surface
|
||||
G4ThreeVector theGlobalPoint = pPostStepPoint->GetPosition();
|
||||
|
||||
G4Navigator* theNavigator = G4TransportationManager::
|
||||
GetTransportationManager()->GetNavigatorForTracking();
|
||||
|
||||
G4bool valid;
|
||||
theGlobalNormal = theNavigator->GetGlobalExitNormal(theGlobalPoint, &valid);
|
||||
|
||||
if (valid)
|
||||
{
|
||||
theGlobalNormal = -theGlobalNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << " G4MicroElecSurface/PostStepDoIt(): "
|
||||
<< " The Navigator reports that it returned an invalid normal"
|
||||
<< G4endl;
|
||||
G4Exception("G4MuElecSurf::PostStepDoIt", "OpBoun01",
|
||||
EventMustBeAborted, ed,
|
||||
"Invalid Surface Normal - Geometry must return valid surface normal");
|
||||
}
|
||||
|
||||
// Exception: the particle is not in the right direction
|
||||
if (oldMomentum * theGlobalNormal > 0.0)
|
||||
{
|
||||
theGlobalNormal = -theGlobalNormal;
|
||||
}
|
||||
|
||||
if (aTrack.GetStepLength()<=kCarTolerance/2 * 0.0000000001)
|
||||
{
|
||||
if (flag_reflexion == true)
|
||||
{
|
||||
flag_reflexion = false;
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
|
||||
}
|
||||
theStatus = UndefinedSurf;
|
||||
|
||||
//Third case: same material
|
||||
if (material1 == material2)
|
||||
{
|
||||
theStatus = SameMaterialSurf;
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
|
||||
}
|
||||
if (verboseLevel > 0)
|
||||
{
|
||||
G4cout << G4endl << " Electron at Boundary! " << G4endl;
|
||||
G4VPhysicalVolume* thePrePV = pPreStepPoint->GetPhysicalVolume();
|
||||
G4VPhysicalVolume* thePostPV = pPostStepPoint->GetPhysicalVolume();
|
||||
if (thePrePV) G4cout << " thePrePV: " << thePrePV->GetName() << G4endl;
|
||||
if (thePostPV) G4cout << " thePostPV: " << thePostPV->GetName() << G4endl;
|
||||
G4cout << " Old Momentum Direction: " << oldMomentum << G4endl;
|
||||
}
|
||||
|
||||
//Definition of the parameters for the surface
|
||||
G4ThreeVector theGlobalPoint = pPostStepPoint->GetPosition();
|
||||
|
||||
G4Navigator* theNavigator =
|
||||
G4TransportationManager::GetTransportationManager()->
|
||||
GetNavigatorForTracking();
|
||||
|
||||
G4bool valid;
|
||||
|
||||
theGlobalNormal = theNavigator->GetGlobalExitNormal(theGlobalPoint, &valid);
|
||||
// G4cout << "Global exit normal = " << theGlobalNormal << " valid = " << valid << G4endl;
|
||||
|
||||
if (valid)
|
||||
{
|
||||
theGlobalNormal = -theGlobalNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << " G4MicroElecSurface/PostStepDoIt(): "
|
||||
<< " The Navigator reports that it returned an invalid normal.\n"
|
||||
<< "PV: " << pPreStepPoint->GetPhysicalVolume()->GetName()
|
||||
<< " TrackID= " << aTrack.GetTrackID()
|
||||
<< " Ekin(MeV)= " << aTrack.GetKineticEnergy()
|
||||
<< " position: " << theGlobalPoint
|
||||
<< " direction: " << oldMomentum
|
||||
<< G4endl;
|
||||
G4Exception("G4MuElecSurf::PostStepDoIt", "OpBoun01",
|
||||
FatalException, ed,
|
||||
"Invalid Surface Normal - Geometry must return valid surface normal");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Exception: the particle is not in the right direction
|
||||
if (oldMomentum * theGlobalNormal > 0.0)
|
||||
{
|
||||
theGlobalNormal = -theGlobalNormal;
|
||||
}
|
||||
|
||||
//Second case: step too small
|
||||
//Corrections bug rotation + réflexion
|
||||
if (aTrack.GetStepLength()<=kCarTolerance)
|
||||
{
|
||||
theStatus = StepTooSmallSurf;
|
||||
|
||||
WorkFunctionTable::iterator postStepWF;
|
||||
postStepWF = tableWF.find(pPostStepPoint->GetMaterial()->GetName());
|
||||
WorkFunctionTable::iterator preStepWF;
|
||||
preStepWF = tableWF.find(pPreStepPoint->GetMaterial()->GetName());
|
||||
|
||||
if (postStepWF == tableWF.end()) {
|
||||
G4String str = "Material ";
|
||||
str += pPostStepPoint->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if (preStepWF == tableWF.end()) {
|
||||
G4String str = "Material ";
|
||||
str += pPreStepPoint->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pPreStepPoint->GetMaterial() != pPostStepPoint->GetMaterial()) {
|
||||
|
||||
flag_franchissement_surface = false;
|
||||
|
||||
if (flag_reflexion == true && flag_normal == true) {
|
||||
aParticleChange.ProposeMomentumDirection(-Reflexion(aStep.GetPostStepPoint()));
|
||||
flag_reflexion = false;
|
||||
flag_normal = false;
|
||||
}
|
||||
}
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
flag_normal = (theGlobalNormal.x() == 0.0 && theGlobalNormal.y() == 0.0);
|
||||
|
||||
theStatus = StepTooSmallSurf;
|
||||
|
||||
G4double energyThreshold_surface = 0.0*eV;
|
||||
|
||||
WorkFunctionTable::iterator postStepWF;
|
||||
postStepWF = tableWF.find(pPostStepPoint->GetMaterial()->GetName());
|
||||
WorkFunctionTable::iterator preStepWF;
|
||||
preStepWF = tableWF.find(pPreStepPoint->GetMaterial()->GetName());
|
||||
|
||||
if (postStepWF == tableWF.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += pPostStepPoint->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return nullptr;
|
||||
}
|
||||
else if (preStepWF == tableWF.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += pPreStepPoint->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4double thresholdNew_surface = postStepWF->second;
|
||||
G4double thresholdOld_surface = preStepWF->second;
|
||||
energyThreshold_surface = thresholdNew_surface - thresholdOld_surface;
|
||||
}
|
||||
|
||||
if (flag_franchissement_surface == true)
|
||||
{
|
||||
aParticleChange.ProposeEnergy(aStep.GetPostStepPoint()->GetKineticEnergy() + energyThreshold_surface);
|
||||
flag_franchissement_surface = false;
|
||||
}
|
||||
if (flag_reflexion == true && flag_normal == true)
|
||||
{
|
||||
aParticleChange.ProposeMomentumDirection(-Reflexion(aStep.GetPostStepPoint()));
|
||||
flag_reflexion = false;
|
||||
flag_normal = false;
|
||||
}
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
flag_normal = (theGlobalNormal == G4ThreeVector(0, 0, 1)
|
||||
|| theGlobalNormal == G4ThreeVector(0, 0, -1));
|
||||
|
||||
G4LogicalSurface* Surface = nullptr;
|
||||
|
||||
|
||||
Surface = G4LogicalBorderSurface::GetSurface
|
||||
(pPreStepPoint ->GetPhysicalVolume(),
|
||||
pPostStepPoint->GetPhysicalVolume());
|
||||
|
||||
(pPreStepPoint ->GetPhysicalVolume(),
|
||||
pPostStepPoint->GetPhysicalVolume());
|
||||
|
||||
if (Surface == nullptr)
|
||||
{
|
||||
G4bool enteredDaughter=(pPostStepPoint->GetPhysicalVolume()->GetMotherLogical()
|
||||
== pPreStepPoint->GetPhysicalVolume()->GetLogicalVolume());
|
||||
if(enteredDaughter)
|
||||
{
|
||||
G4bool enteredDaughter=(pPostStepPoint->GetPhysicalVolume()
|
||||
->GetMotherLogical() ==
|
||||
pPreStepPoint->GetPhysicalVolume()
|
||||
->GetLogicalVolume());
|
||||
if(enteredDaughter)
|
||||
{
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPostStepPoint->GetPhysicalVolume()->
|
||||
GetLogicalVolume());
|
||||
|
||||
if(Surface == nullptr)
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPreStepPoint->GetPhysicalVolume()->
|
||||
GetLogicalVolume());
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPreStepPoint->GetPhysicalVolume()->
|
||||
GetLogicalVolume());
|
||||
|
||||
if(Surface == nullptr)
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPostStepPoint->GetPhysicalVolume()->
|
||||
GetLogicalVolume());
|
||||
}
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPostStepPoint->GetPhysicalVolume()->GetLogicalVolume());
|
||||
|
||||
if(Surface == nullptr)
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPreStepPoint->GetPhysicalVolume()->GetLogicalVolume());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPreStepPoint->GetPhysicalVolume()->GetLogicalVolume());
|
||||
|
||||
if(Surface == nullptr)
|
||||
Surface = G4LogicalSkinSurface::GetSurface
|
||||
(pPostStepPoint->GetPhysicalVolume()->GetLogicalVolume());
|
||||
}
|
||||
}
|
||||
|
||||
// Definition of the parameters for the surface crossing
|
||||
G4VPhysicalVolume* thePrePV = pPreStepPoint->GetPhysicalVolume();
|
||||
G4VPhysicalVolume* thePostPV = pPostStepPoint->GetPhysicalVolume();
|
||||
|
||||
if (thePostPV)
|
||||
|
||||
energyThreshold = 0.0*eV;
|
||||
G4double energyDelta = 0;
|
||||
|
||||
if ((thePrePV)&&(thePostPV))
|
||||
{
|
||||
WorkFunctionTable::iterator postStepWF;
|
||||
postStepWF = tableWF.find(thePostPV->GetLogicalVolume()->GetMaterial()->GetName());
|
||||
WorkFunctionTable::iterator preStepWF;
|
||||
preStepWF = tableWF.find(thePrePV->GetLogicalVolume()->GetMaterial()->GetName());
|
||||
|
||||
if (postStepWF == tableWF.end())
|
||||
{
|
||||
WorkFunctionTable::iterator postStepWF;
|
||||
postStepWF = tableWF.find(thePostPV->GetLogicalVolume()->GetMaterial()->GetName());
|
||||
WorkFunctionTable::iterator preStepWF;
|
||||
preStepWF = tableWF.find(thePrePV->GetLogicalVolume()->GetMaterial()->GetName());
|
||||
|
||||
if (postStepWF == tableWF.end()) {
|
||||
G4String str = "Material ";
|
||||
str += thePostPV->GetLogicalVolume()->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return 0;
|
||||
}
|
||||
else if (preStepWF == tableWF.end()) {
|
||||
G4String str = "Material ";
|
||||
str += thePrePV->GetLogicalVolume()->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4double thresholdNew = postStepWF->second;
|
||||
G4double thresholdOld = preStepWF->second;
|
||||
energyThreshold = thresholdNew - thresholdOld;
|
||||
}
|
||||
G4String str = "Material ";
|
||||
str += thePostPV->GetLogicalVolume()->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ekint = pPreStepPoint->GetKineticEnergy();
|
||||
else if (preStepWF == tableWF.end())
|
||||
{
|
||||
G4String str = "Material ";
|
||||
str += thePrePV->GetLogicalVolume()->GetMaterial()->GetName() + " not found!";
|
||||
G4Exception("G4Surface::G4Surface", "em0002", FatalException, str);
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4double thresholdNew = postStepWF->second;
|
||||
G4double thresholdOld = preStepWF->second;
|
||||
|
||||
energyThreshold = thresholdNew - thresholdOld;
|
||||
energyDelta = thresholdOld- thresholdNew;
|
||||
}
|
||||
}
|
||||
|
||||
ekint=aStep.GetPostStepPoint()->GetKineticEnergy();
|
||||
thetat= GetIncidentAngle(); //angle d'incidence
|
||||
G4double ekinNormalt=ekint*std::cos(thetat)*std::cos(thetat);
|
||||
|
||||
G4double atet = std::sqrt(ekint/(ekint+energyThreshold))*std::sin(thetat);
|
||||
thetaft = (atet > 1.0) ? pi*0.5 : std::asin(atet);//Angle de réfraction
|
||||
|
||||
|
||||
thetaft=std::asin(std::sqrt(ekint/(ekint+energyThreshold))*std::sin(thetat));//Angle de refraction
|
||||
if(std::sqrt(ekint/(ekint+energyThreshold))*std::sin(thetat)>1.0)
|
||||
{
|
||||
thetaft=std::asin(1.0);
|
||||
}
|
||||
|
||||
G4double aleat=G4UniformRand();
|
||||
|
||||
const G4double waveVectort=std::sqrt(2*9.1093826E-31*1.602176487E-19)/(6.6260755E-34/(2.0*pi));
|
||||
|
||||
//Parameter for an exponential barrier of potential (Thèse P68)
|
||||
const G4double at=0.5E-10;
|
||||
|
||||
//G4double modif already declared in .hh
|
||||
|
||||
G4double waveVectort=std::sqrt(2*9.1093826E-31*1.602176487E-19)/(6.6260755E-34/(2.0*pi));
|
||||
|
||||
// Parameter for an exponential barrier of potential (Thesis P68)
|
||||
G4double at=0.5E-10;
|
||||
|
||||
crossingProbability=0;
|
||||
|
||||
|
||||
G4double kft=waveVectort*std::sqrt(ekint+energyThreshold)*std::cos(thetaft);
|
||||
G4double kit=waveVectort*std::sqrt(ekinNormalt);
|
||||
|
||||
G4double yy = std::sinh(pi*at*(kit-kft))/std::sinh(pi*at*(kit+kft));
|
||||
crossingProbability = 1 - yy*yy;
|
||||
|
||||
//First case: the electron crosses the surface
|
||||
if((aleat<=crossingProbability)&&(ekint>std::abs(energyThreshold)))
|
||||
{
|
||||
if (pPreStepPoint->GetMaterial() != pPostStepPoint->GetMaterial()) {
|
||||
flag_franchissement_surface = true;
|
||||
}
|
||||
|
||||
thetaft=std::abs(thetaft-thetat);
|
||||
|
||||
G4ThreeVector zVerst = aStep.GetPostStepPoint()->GetMomentumDirection();
|
||||
G4ThreeVector xVerst = zVerst.orthogonal();
|
||||
G4ThreeVector yVerst = zVerst.cross(xVerst);
|
||||
|
||||
G4double cost = std::cos(thetaft);
|
||||
G4double xDirt = std::sqrt(1. - cost*cost);
|
||||
G4double yDirt = xDirt;
|
||||
|
||||
G4ThreeVector zPrimeVerst = xDirt*xVerst + yDirt*yVerst + cost*zVerst;
|
||||
|
||||
aParticleChange.ProposeMomentumDirection(zPrimeVerst.unit());
|
||||
}
|
||||
else if ((aleat > crossingProbability) && (ekint>std::abs(energyThreshold)))
|
||||
crossingProbability=1-(std::pow(std::sinh(pi*at*(kit-kft)), 2.0)/std::pow(std::sinh(pi*at*(kit+kft)), 2.0));
|
||||
|
||||
// First case: the electron crosses the surface
|
||||
if((aleat<=crossingProbability)&&(ekint> energyDelta))
|
||||
{
|
||||
if (aStep.GetPreStepPoint()->GetMaterial()->GetName()
|
||||
!= aStep.GetPostStepPoint()->GetMaterial()->GetName())
|
||||
{
|
||||
flag_reflexion = true;
|
||||
if (flag_normal) { aParticleChange.ProposeMomentumDirection(-oldMomentum.unit()); }
|
||||
else { aParticleChange.ProposeMomentumDirection(Reflexion(aStep.GetPostStepPoint())); }
|
||||
|
||||
aParticleChange.ProposeEnergy(ekint - energyDelta);
|
||||
flag_franchissement_surface = true;
|
||||
}
|
||||
|
||||
thetaft=std::abs(thetaft-thetat);
|
||||
|
||||
G4ThreeVector zVerst = aStep.GetPostStepPoint()->GetMomentumDirection();
|
||||
G4ThreeVector xVerst = zVerst.orthogonal();
|
||||
G4ThreeVector yVerst = zVerst.cross(xVerst);
|
||||
|
||||
G4double xDirt = std::sqrt(1. - std::cos(thetaft)*std::cos(thetaft));
|
||||
G4double yDirt = xDirt;
|
||||
|
||||
G4ThreeVector zPrimeVerst=((xDirt*xVerst + yDirt*yVerst + std::cos(thetaft)*zVerst));
|
||||
|
||||
aParticleChange.ProposeMomentumDirection(zPrimeVerst.unit());
|
||||
}
|
||||
else if ((aleat > crossingProbability) && (ekint> energyDelta))
|
||||
{
|
||||
flag_reflexion = true;
|
||||
if (flag_normal)
|
||||
{
|
||||
aParticleChange.ProposeMomentumDirection(-oldMomentum.unit());
|
||||
}
|
||||
else
|
||||
{
|
||||
aParticleChange.ProposeMomentumDirection(Reflexion(aStep.GetPostStepPoint()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flag_normal)
|
||||
{
|
||||
aParticleChange.ProposeMomentumDirection(-oldMomentum.unit());
|
||||
}
|
||||
else
|
||||
{
|
||||
aParticleChange.ProposeMomentumDirection(Reflexion(aStep.GetPostStepPoint()));
|
||||
}
|
||||
else {
|
||||
|
||||
if (flag_normal) { aParticleChange.ProposeMomentumDirection(-oldMomentum.unit()); }
|
||||
else { aParticleChange.ProposeMomentumDirection(Reflexion(aStep.GetPostStepPoint())); }
|
||||
flag_reflexion = true;
|
||||
}
|
||||
|
||||
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4double G4MicroElecSurface::GetMeanFreePath(const G4Track&, G4double,
|
||||
G4ForceCondition* condition)
|
||||
G4ForceCondition* condition)
|
||||
{
|
||||
*condition = Forced;
|
||||
return DBL_MAX;
|
||||
@@ -411,17 +467,17 @@ G4double G4MicroElecSurface::GetIncidentAngle()
|
||||
|
||||
G4ThreeVector G4MicroElecSurface::Reflexion(const G4StepPoint* PostStepPoint)
|
||||
{
|
||||
//Normale
|
||||
// Normale
|
||||
G4double Nx = theGlobalNormal.x();
|
||||
G4double Ny = theGlobalNormal.y();
|
||||
G4double Nz = theGlobalNormal.z();
|
||||
|
||||
//PostStepPoint
|
||||
// PostStepPoint
|
||||
G4double PSx = PostStepPoint->GetPosition().x();
|
||||
G4double PSy = PostStepPoint->GetPosition().y();
|
||||
G4double PSz = PostStepPoint->GetPosition().z();
|
||||
|
||||
//P(alpha,beta,gamma) - PostStep avec translation momentum
|
||||
// P(alpha,beta,gamma) - PostStep avec translation momentum
|
||||
G4double alpha = PSx + oldMomentum.x();
|
||||
G4double beta = PSy + oldMomentum.y();
|
||||
G4double gamma = PSz + oldMomentum.z();
|
||||
@@ -429,23 +485,24 @@ G4ThreeVector G4MicroElecSurface::Reflexion(const G4StepPoint* PostStepPoint)
|
||||
G4double x, y, z, d, A, B, PM2x, PM2y, PM2z;
|
||||
d = -(Nx*PSx + Ny*PSy + Nz*PSz);
|
||||
|
||||
if (Ny == 0 && Nx == 0) {
|
||||
if (Ny == 0 && Nx == 0)
|
||||
{
|
||||
gamma = -gamma;
|
||||
}
|
||||
else {
|
||||
if (Ny == 0) {
|
||||
|
||||
else
|
||||
{
|
||||
if (Ny == 0)
|
||||
{
|
||||
A = (Nz*Nz*alpha) + (Nx*Nx*PSx) + (Nx*Nz*(PSz - gamma));
|
||||
B = r*r;
|
||||
|
||||
//M(x,y,z) - Projection de P sur la surface
|
||||
// M(x,y,z) - Projection de P sur la surface
|
||||
x = A / B;
|
||||
y = beta;
|
||||
z = (x - alpha)*(Nz / Nx) + gamma;
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
else
|
||||
{
|
||||
A = (r*r) / Ny;
|
||||
B = (beta / Ny)*(Nx*Nx + Nz*Nz) - (Nx*alpha + Nz*gamma + d);
|
||||
|
||||
@@ -455,10 +512,10 @@ G4ThreeVector G4MicroElecSurface::Reflexion(const G4StepPoint* PostStepPoint)
|
||||
z = (y - beta)*(Nz / Ny) + gamma;
|
||||
}
|
||||
|
||||
//Vecteur 2*PM
|
||||
// Vecteur 2*PM
|
||||
PM2x = 2 * (x - alpha); PM2y = 2 * (y - beta); PM2z = 2 * (z - gamma);
|
||||
|
||||
//Nouveau point P
|
||||
// Nouveau point P
|
||||
alpha += PM2x; beta += PM2y; gamma += PM2z;
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
// 24 May 2011 L Pandola Renamed (make v2008 as default Penelope)
|
||||
// 10 Jun 2011 L Pandola Migrate atomic deexcitation interface
|
||||
// 09 Oct 2013 L Pandola Migration to MT
|
||||
// 25 Jul 2023 D Iuso Fix for possible infinite loops due to FP
|
||||
//
|
||||
#include "G4PenelopeComptonModel.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
@@ -320,6 +321,13 @@ void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>*
|
||||
G4double ek1 = eks-ek2-1.0;
|
||||
|
||||
G4double taumin = 1.0/ek2;
|
||||
//This is meant to fix a possible (rare) floating point exception in the sampling of tau below,
|
||||
//causing an infinite loop. The maximum of tau is not 1., but the closest double which can
|
||||
//be represented (i.e. ~ 1. - 1e-16). Fix by Domenico Iuso
|
||||
static G4double taumax = std::nexttoward(1.0,0.0);
|
||||
if (fVerboseLevel > 3)
|
||||
G4cout << "G4PenelopeComptonModel: maximum value of tau: 1 - " << 1.-taumax << G4endl;
|
||||
//To here.
|
||||
G4double a1 = G4Log(ek2);
|
||||
G4double a2 = a1+2.0*ek*(1.0+ek)/(ek2*ek2);
|
||||
|
||||
@@ -339,6 +347,7 @@ void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>*
|
||||
//rejection function
|
||||
TST = (1.0+tau*(ek1+tau*(ek2+tau*eks)))/(eks*tau*(1.0+tau*tau));
|
||||
}while (G4UniformRand()> TST);
|
||||
if (tau > taumax) tau = taumax; //prevent FP exception causing infinite loop
|
||||
epsilon=tau;
|
||||
cosTheta = 1.0 - (1.0-tau)/(ek*tau);
|
||||
|
||||
@@ -394,6 +403,7 @@ void G4PenelopeComptonModel::SampleSecondaries(std::vector<G4DynamicParticle*>*
|
||||
tau = std::pow(taumin,G4UniformRand());
|
||||
else
|
||||
tau = std::sqrt(1.0+G4UniformRand()*(taumin*taumin-1.0));
|
||||
if (tau > taumax) tau = taumax; //prevent FP exception causing infinite loop
|
||||
cdt1 = (1.0-tau)/(ek*tau);
|
||||
//Incoherent scattering function
|
||||
S = 0.;
|
||||
|
||||
Reference in New Issue
Block a user