Import Geant4 0.1.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-08 15:09:25 +02:00
parent b97f8d0df7
commit aaa409b6ee
2922 changed files with 55107 additions and 81674 deletions
@@ -0,0 +1,46 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4Data.hh
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 1 Giugno 1999
//
// Modifications:
//
// -------------------------------------------------------------------
#include "G4Data.hh"
G4Data::~G4Data(){
this->clear();
}
G4bool G4Data::operator == (const G4Data& input) const {
return(this->length() == input.length());
}
G4bool G4Data::operator < (const G4Data& input) const {
return(this->length() < input.length());
}
@@ -0,0 +1,177 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4Epdl89File
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 2 February 1999
//
// Modifications:
//
// -------------------------------------------------------------------
// This Class Header
#include "G4Epdl89File.hh"
//C++ Headers
#include "CLHEP/String/Strings.h"
// Constructors
G4Epdl89File::G4Epdl89File(const G4String& filename, G4int* paramVec):
G4VDataFile(filename),
_flags(paramVec)
{
SetBufferSize(80);
}
// Destructor
G4Epdl89File::~G4Epdl89File()
{
}
G4bool G4Epdl89File::FindTheElement(G4int numZ){
G4double llength = LineLength();
G4bool elementFound = FALSE;
HepString flag(GetBuf());
if(numZ){
if(llength == 70){
}
}
return elementFound;
}
G4bool G4Epdl89File::FindTheProcess(){
G4double llength = LineLength();
G4bool tableFound = FALSE;
if(llength == 68){
HepString flag(GetBuf());
if(_flags[0] == flag(0,2).toInt()){
if(_flags[1] == flag(2,3).toInt()){
if(_flags[2] == flag(5,3).toInt()){
G4int subsh;
G4int Xi3 = flag(31,1).toInt();
if(Xi3 == 0){
subsh = flag(22,1).toInt();
}
else if(Xi3 == 1){
subsh = (flag(22,1) + flag(24,1)).toInt();
}
if(_flags[3] == subsh){
tableFound = TRUE;
}
}
}
}
}
return tableFound;
}
G4bool G4Epdl89File::FindOneElemProc(G4int& subsh){
G4double llength = LineLength();
G4bool tableFound = FALSE;
if(llength == 68){
HepString flag(GetBuf());
if(_flags[0] == flag(0,2).toInt()){
if(_flags[1] == flag(2,3).toInt()){
if(_flags[2] == flag(5,3).toInt()){
G4int Xi3 = flag(31,1).toInt();
if(Xi3 == 0){
subsh = flag(22,1).toInt();
}
else if(Xi3 == 1){
subsh = (flag(22,1) + flag(24,1)).toInt();
}
tableFound = TRUE;
}
}
}
}
return tableFound;
}
void G4Epdl89File::GetDataValues(G4Data& valList){
char* token = 0;
G4int i = 0;
do{
if(i == 0){
token = strtok(GetBuf()," ");
}
else{
token = strtok(NULL," ");
}
if(token) {
valList.append(GetOneData(token));
}
i++;
}while(token);
}
G4double G4Epdl89File::GetOneData(const char* token){
HepString parts;
G4double floatTok = 0;
if(token){
parts = token;
floatTok = parts.toFloat();
}
return floatTok;
}
@@ -0,0 +1,188 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4Epdl97File
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 2 February 1999
//
// Modifications:
//
// -------------------------------------------------------------------
// This Class Header
#include "G4Epdl97File.hh"
//C++ Headers
#include "CLHEP/String/Strings.h"
// Constructors
G4Epdl97File::G4Epdl97File(const G4String& filename, G4int* paramVec):
G4VDataFile(filename),
_flags(paramVec)
{
SetBufferSize(74);
}
// Destructor
G4Epdl97File::~G4Epdl97File()
{
}
G4bool G4Epdl97File::FindTheElement(G4int numZ){
G4double llength = LineLength();
G4bool elementFound = FALSE;
HepString flag(GetBuf());
if(numZ){
if(llength == 70){
}
}
return elementFound;
}
G4bool G4Epdl97File::FindTheProcess(){
G4double llength = LineLength();
G4bool tableFound = FALSE;
HepString flag(GetBuf());
if(llength == 68 || llength == 69){
if(_flags[0] == flag(0,2).toInt()){
if(_flags[1] == flag(2,3).toInt()){
if(_flags[2] == flag(5,3).toInt()){
G4int subsh;
G4int Xi3 = flag(31,1).toInt();
if(Xi3 == 0){
subsh = flag(22,1).toInt();
}
else if(Xi3 == 1){
subsh = (flag(22,1) + flag(24,1)).toInt();
}
if(_flags[3] == subsh){
tableFound = TRUE;
}
}
}
}
}
return tableFound;
}
G4bool G4Epdl97File::FindOneElemProc(G4int& subsh){
G4double llength = LineLength();
G4bool tableFound = FALSE;
if(llength == 68){
HepString flag(GetBuf());
if(_flags[0] == flag(0,2).toInt()){
if(_flags[1] == flag(2,3).toInt()){
if(_flags[2] == flag(5,3).toInt()){
G4int Xi3 = flag(31,1).toInt();
if(Xi3 == 0){
subsh = flag(22,1).toInt();
}
else if(Xi3 == 1){
subsh = (flag(22,1) + flag(24,1)).toInt();
}
tableFound = TRUE;
}
}
}
}
return tableFound;
}
G4int* G4Epdl97File::GetTheProcFlags(){ return _flags; }
void G4Epdl97File::GetDataValues(G4Data& valList){
char* token = 0;
G4int i = 0;
do{
if(i == 0){
token = strtok(GetBuf()," ");
}
else{
token = strtok(NULL," ");
}
if(token) {
valList.append(GetOneData(token));
}
i++;
}while(token);
}
G4double G4Epdl97File::GetOneData(const char* token){
HepString parts, tot;
G4double floatTok = 0;
if(token){
parts = token;
if(parts(8,1) == "-" || parts(8,1) == "+"){
tot = parts(0,8) + "E" + parts(8,2);
}
else{
tot = parts(0,7) + "E" + parts(7,3);
}
floatTok = tot.toFloat();
}
return floatTok;
}
@@ -0,0 +1,337 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4EpdlTables
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 2 February 1999
//
// Modifications:
//
// -------------------------------------------------------------------
// This class header
#include "G4EpdlTables.hh"
// Other Class Headers
#include "G4VDataFile.hh"
#include "G4DataVector.hh"
#include "G4PhysicsFreeVector.hh"
#include "CLHEP/String/Strings.h"
// C++ Headers
#include <iostream.h>
#include <fstream.h>
// Constructors
G4EpdlTables::G4EpdlTables(G4VDataFile& DFile):
G4VTables(),
datfile(DFile)
{
theDataTable1 = 0;
theDataTable2 = 0;
theDataTable3 = 0;
// allElementList = 0;
}
// Destructor
G4EpdlTables::~G4EpdlTables()
{
}
// Member Functions
void G4EpdlTables::FillDataTable() {
// line counters
G4int numTable = 0;
// variables to flag 68 characters lines
G4bool lineMatch = FALSE;
// list of data vectors to be filled
G4FirstLevel vecList;
G4int numBin = 100;
if(theDataTable1){
theDataTable1->clearAndDestroy(); delete theDataTable1;
}
if(theDataTable2){
theDataTable2->clearAndDestroy(); delete theDataTable2;
}
if(theDataTable3){
theDataTable3->clearAndDestroy(); delete theDataTable3;
}
theDataTable1 = new G4PhysicsTable(numBin);
theDataTable2 = new G4PhysicsTable(numBin);
theDataTable3 = new G4PhysicsTable(numBin);
//open input file
datfile.OpenFile();
// loop on the stream
for(;;){
datfile.Eof();
datfile.GetLine();
// lines counters
G4int llength = datfile.LineLength();
if(llength == 0) break;
if(llength == 70){
HepString AtomicNum(datfile.GetBuf());
G4int numAtom = AtomicNum(0,3).toInt();
}
// search for the process flags line
if(llength == 68 || llength == 69) {
lineMatch = datfile.FindTheProcess();
continue;
}
G4double lvl;
if(llength < 68){
if(lineMatch == TRUE){
//list of values in one line
G4Data values;
datfile.GetDataValues(values);
lvl = values.length();
if(!vecList.entries()){
for(G4int k = 0; k < lvl; k++){
vecList.insert(new G4Data);
}
}
for(G4int h = 0; h < lvl; h++){
vecList[h]->append(values[h]);
}
// Clear the temporary list
values.clear();
}
}
if(llength == 72 || llength == 73){
// build the G4PhysicsTables
if(lineMatch == TRUE){
if(lvl >= 1){
G4PhysicsFreeVector* freevec;
freevec = new G4PhysicsFreeVector(*vecList[0],*vecList[1]);
theDataTable1->insertAt(numTable, freevec);
if(lvl == 3){
freevec = new G4PhysicsFreeVector(*vecList[0],*vecList[2]);
theDataTable2->insertAt(numTable, freevec);
}
if(lvl == 4){
freevec = new G4PhysicsFreeVector(*vecList[0],*vecList[2]);
theDataTable2->insertAt(numTable, freevec);
freevec = new G4PhysicsFreeVector(*vecList[0],*vecList[3]);
theDataTable3->insertAt(numTable, freevec);
}
}
numTable++;
lineMatch = FALSE;
vecList.clearAndDestroy();
if(numTable == 99){
break;
}
}
}
}// end for(;;)
if(theDataTable1->length() == 0){
delete theDataTable1;
}
if(theDataTable2->length() == 0){
delete theDataTable2;
}
if(theDataTable3->length() == 0){
delete theDataTable3;
}
} // end FillDataTable
//G4SecondLevel* G4EpdlTables::GetGlobalList(){
//return new G4SecondLevel((*allElementList));
//////}
G4SecondLevel* G4EpdlTables::FillTheTable(G4int numEl) {
// line counters
G4int numTable = 0;
// variables to flag 68 characters lines
G4bool lineMatch = FALSE;
// list of data vectors to be filled
G4FirstLevel* vecList = new G4FirstLevel();
// if(allElementList){
//delete allElementList;
//}
G4SecondLevel* allElementList = new G4SecondLevel();
//open input file
datfile.OpenFile();
// loop on the stream
G4int subSh = 0;
for(;;){
datfile.Eof();
datfile.GetLine();
// lines counters
G4int llength = datfile.LineLength();
if(llength == 0) break;
G4int numAtom;
if(llength == 70){
HepString AtomicNum(datfile.GetBuf());
numAtom = AtomicNum(0,3).toInt();
}
// search for the process flags line
if(llength == 68 || llength == 69) {
if(numEl){
if(numEl != numAtom){
continue;
}
else{
lineMatch = datfile.FindOneElemProc(subSh);
}
}
else{
lineMatch = datfile.FindTheProcess();
}
continue;
}
G4double lvl;
if(llength < 68){
if(lineMatch == TRUE){
//list of values in one line
G4Data values;
datfile.GetDataValues(values);
lvl = values.length();
if(!vecList->entries()){
for(G4int k = 0; k < lvl; k++){
vecList->insert(new G4Data);
}
}
for(G4int h = 0; h < lvl; h++){
(*vecList)[h]->insert(values[h]);
}
// Clear the temporary list
values.clear();
}
}
if(llength == 72 || llength == 73){
// build the G4PhysicsTables
if(lineMatch == TRUE){
allElementList->insert(vecList);
numTable++;
lineMatch = FALSE;
vecList = new G4FirstLevel();
if(numTable == 99){
break;
}
}
}
}// end for(;;)
return allElementList;
} // end FillDataTable
@@ -0,0 +1,45 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4FirstLevel.hh
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 1 Giugno 1999
//
// Modifications:
//
// -------------------------------------------------------------------
#include "G4FirstLevel.hh"
G4FirstLevel::~G4FirstLevel(){
this->clearAndDestroy();
}
G4bool G4FirstLevel::operator == (const G4FirstLevel& input) const{
return( this->entries() == input.entries());
}
G4bool G4FirstLevel::operator < (const G4FirstLevel& input) const{
return(this->entries() < input.entries());
}
@@ -0,0 +1,870 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyBremsstrahlung.cc,v 1.13 1999/07/06 14:35:47 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyBremsstrahlung physics process --------
// by Michel Maire, 24 July 1996
// **************************************************************
// 26-09-96 : extension of the total crosssection above 100 GeV, M.Maire
// 1-10-96 : new type G4OrderedTable; ComputePartialSumSigma(), M.Maire
// 16-10-96 : DoIt() call to the non static GetEnergyCuts(), L.Urban
// 13-12-96 : Sign corrected in grejmax and greject
// error definition of screenvar, L.Urban
// 20-03-97 : new energy loss+ionisation+brems scheme, L.Urban
// 07-04-98 : remove 'tracking cut' of the diffracted particle, MMa
// 13-08-98 : new methods SetBining() PrintInfo()
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyBremsstrahlung.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4UnitsTable.hh"
#include "G4Gamma.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
// constructor
G4LowEnergyBremsstrahlung::G4LowEnergyBremsstrahlung(const G4String& processName)
: G4eEnergyLoss(processName), // initialization
theCrossSectionTable(0),
theMeanFreePathTable(0),
ATable(0),
BTable(0),
ZNumVec(0),
LowestKineticEnergy (250.*eV),
HighestKineticEnergy(100.*GeV),
lowEnergyCut(0.1*eV),
CutForLowEnergySecondaryPhotons(0.),
TotBin(200)
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
// destructor
G4LowEnergyBremsstrahlung::~G4LowEnergyBremsstrahlung()
{
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
if (ATable) {
delete ATable;
}
if (BTable) {
delete BTable;
}
if (&PartialSumSigma) {
PartialSumSigma.clearAndDestroy();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::SetPhysicsTableBining(G4double lowE, G4double highE, G4int nBins)
{
LowestKineticEnergy = lowE; HighestKineticEnergy = highE; TotBin = nBins;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::SetCutForLowEnSecPhotons(G4double cut){
CutForLowEnergySecondaryPhotons = cut;
}
void G4LowEnergyBremsstrahlung::BuildPhysicsTable(const G4ParticleDefinition& aParticleType)
// just call BuildLossTable+BuildLambdaTable
{
BuildLossTable(aParticleType) ;
if (&aParticleType==G4Electron::Electron()){
RecorderOfElectronProcess[CounterOfElectronProcess] = (*this).theLossTable ;
CounterOfElectronProcess++;
}
else{
RecorderOfPositronProcess[CounterOfPositronProcess] = (*this).theLossTable ;
CounterOfPositronProcess++;
}
BuildZVec();
BuildCrossSectionTable() ;
BuildMeanFreePathTable() ;
BuildDEDXTable (aParticleType) ;
// smpling energy formula coefficient
BuildATable();
BuildBTable();
// if(&aParticleType==G4Electron::Electron())
// PrintInfoDefinition();
//}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::BuildCrossSectionTable(){
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
theCrossSectionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomCS = util.BuildFirstLevelTables(AtomInd, dataNum, "brem/br-cs-");
theCrossSectionTable->insert(oneAtomCS);
}//end for on atoms
}
void G4LowEnergyBremsstrahlung::BuildATable(){
if (ATable) {
delete ATable;
}
G4int dataNum = 2;
ATable = util.BuildSecondLevelTables(0,dataNum,"brem/br-co-a");
}
void G4LowEnergyBremsstrahlung::BuildBTable(){
if (BTable) {
delete BTable;
}
G4int dataNum = 2;
BTable = util.BuildFirstLevelTables(0, dataNum, "brem/br-co-b");
}
void G4LowEnergyBremsstrahlung::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
void G4LowEnergyBremsstrahlung::BuildLossTable(const G4ParticleDefinition& aParticleType)
// Build table for energy loss due to soft brems
// tables are built for *MATERIALS*
{
G4double KineticEnergy,TotalEnergy,bremloss,Z,x,
losslim,loss,rate,natom,Cut;
const G4double MinKinEnergy = 1.*keV;
const G4double MinCut = 1.*keV;
const G4double Thigh = 100.*GeV;
const G4double Cuthigh = 50.*GeV;
const G4double Factorhigh = 36./(1450.*GeV);
const G4double coef1 = -0.5, coef2 = 2./9.;
ParticleMass = aParticleType.GetPDGMass() ;
G4double* GammaCutInKineticEnergy = G4Gamma::Gamma()->GetEnergyCuts();
// create table
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length() ;
if (theLossTable) { theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfMaterials);
// loop for materials
for (G4int J=0; J<numOfMaterials; J++)
{
// create physics vector and fill it
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy,HighestKineticEnergy,TotBin);
// get elements in the material
const G4Material* material = (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomicNumDensityVector = material->GetAtomicNumDensityVector();
const G4int NumberOfElements = material->GetNumberOfElements();
// loop for the kinetic energy values
for (G4int i=0; i<TotBin; i++){
KineticEnergy = aVector->GetLowEdgeEnergy(i) ;
TotalEnergy = KineticEnergy+ParticleMass ;
Cut = GammaCutInKineticEnergy[J] ;
if (Cut < MinCut) Cut = MinCut ;
if (Cut > KineticEnergy) Cut = KineticEnergy ;
bremloss = 0.;
if (KineticEnergy>MinKinEnergy)
{
if (Cut > KineticEnergy) Cut = KineticEnergy ;
// loop for elements in the material
for (G4int iel=0; iel<NumberOfElements; iel++)
{
Z=(*theElementVector)(iel)->GetZ();
natom = theAtomicNumDensityVector[iel] ;
if (KineticEnergy <= Thigh)
{
//loss for MinKineticEnergy<KineticEnergy<=100 GeV
x=log(TotalEnergy/ParticleMass);
loss = ComputeBremLoss(Z,natom,KineticEnergy,Cut,x) ;
if (&aParticleType==G4Positron::Positron())
loss *= ComputePositronCorrFactorLoss(Z,KineticEnergy,Cut) ;
}
else
{
// extrapolation for KineticEnergy>100 GeV
x=log(Thigh/ParticleMass) ;
if (Cut<Thigh)
{
losslim = ComputeBremLoss(Z,natom,Thigh,Cut,x) ;
if (&aParticleType==G4Positron::Positron())
loss *= ComputePositronCorrFactorLoss(Z,Thigh,Cut) ;
rate = Cut/TotalEnergy ;
loss = losslim*(1.+coef1*rate+coef2*rate*rate) ;
rate = Cut/Thigh ;
loss /= (1.+coef1*rate+coef2*rate*rate) ;
}
else
{
losslim = ComputeBremLoss(Z,natom,Thigh,Cuthigh,x) ;
if (&aParticleType==G4Positron::Positron())
loss *= ComputePositronCorrFactorLoss(Z,Thigh,Cuthigh) ;
rate = Cut/TotalEnergy ;
loss = losslim*(1.+coef1*rate+coef2*rate*rate) ;
loss *= Factorhigh*Cut ;
}
}
bremloss += natom*loss;
}
}
// now compute the correction due to the LPM effect
const G4double MigdalConstant = classic_electr_radius*
electron_Compton_length*
electron_Compton_length/pi ;
const G4double LPMconstant = fine_structure_const*electron_mass_c2*
electron_mass_c2/(8.*pi*hbarc) ;
const G4double kmin = 1.*eV ;
const G4double klim = 1.*keV ;
G4double LPMEnergy = LPMconstant*(material->GetRadlen()) ;
G4double TotalEnergysquare = TotalEnergy*TotalEnergy ;
G4double LPMGammaEnergyLimit = TotalEnergysquare/LPMEnergy ;
if(LPMGammaEnergyLimit > klim)
{
G4double kmax = min(Cut,LPMGammaEnergyLimit) ;
G4double floss = 0. ;
G4int nmax = 1000 ;
G4int nn ;
G4double vmin=log(kmin);
G4double vmax=log(Cut) ;
nn = int(nmax*(vmax-vmin)/(log(HighestKineticEnergy)-vmin)) ;
G4double u,uu,s2lpm,sp,fac,c,v,dv,w ;
dv = (vmax-vmin)/nn ;
v = vmin-dv ;
for(G4int n=0; n<=nn; n++)
{
v += dv ;
u = exp(v) ;
uu = u*u ;
if(u<=kmax)
{
s2lpm=LPMEnergy*u/TotalEnergysquare ;
sp=uu/(uu+MigdalConstant*TotalEnergysquare*
(material->GetElectronDensity())) ;
w=s2lpm*(1.+1./sp) ;
fac=0.5*(sqrt(w*w+4.*s2lpm)-w)/sp;
if(fac>1.)
fac=1. ;
}
else
{
fac=1. ;
}
fac *= uu*u ;
if((n==0)||(n==nn))
c=0.5;
else
c=1.;
fac *= c ;
floss += fac ;
}
floss *=dv*3./(Cut*Cut*Cut-kmin*kmin*kmin) ;
if(floss > 1.) floss = 1. ;
// correct the loss
bremloss *= floss ;
}
if(bremloss < 0.) bremloss = 0. ;
aVector->PutValue(i,bremloss);
}
theLossTable->insert(aVector);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4LowEnergyBremsstrahlung::ComputeXYPolynomial(G4double x, G4double y,
G4int xSize, G4int ySize,
const G4double coeff[])
{
// Computes the polynomial (1 y y^2 ...) * matrix * (1 x x^2 ...) .
// xSize and ySize are the dimensions of the matrix,
// coeff containts the elements, stored row-wise.
G4double* a= new G4double[xSize];
G4int i, j;
for (i=0; i<xSize; i++) a[i]= 0.0;
G4int index= 0; G4double yy= 1.0;
for (j=0; j<ySize; j++)
{ for (i=0; i<xSize; i++) a[i]+= coeff[index++]*yy;
yy*= y;
}
G4double r= a[0]; G4double xx= x;
for (i=1; i<xSize; i++) { r+= a[i]*xx; xx*= x;}
delete[] a;
return r;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4LowEnergyBremsstrahlung::ComputeBremLoss(G4double Z,G4double natom,
G4double T,G4double Cut,G4double x)
// compute loss due to soft brems
// 'Migdal' version , this is the default in GEANT3
{
const G4double beta=0.99,ksi=2.51,ve=0.00004 ;
const G4double corrfac = classic_electr_radius*electron_Compton_length*electron_Compton_length/pi ;
static const G4double
CMbarn[]= {
-0.960613e-1, 0.631029e-1,-0.142819e-1, 0.150437e-2,-0.733286e-4, 0.131404e-5,
0.859343e-1,-0.529023e-1, 0.131899e-1,-0.159201e-2, 0.926958e-4,-0.208439e-5,
-0.684096e+1, 0.370364e+1,-0.786752e0, 0.822670e-1,-0.424710e-2, 0.867980e-4,
-0.200856e+1, 0.129573e+1,-0.306533e0, 0.343682e-1,-0.185931e-2, 0.392432e-4,
0.127538e+1,-0.515705e0, 0.820644e-1,-0.641997e-2, 0.245913e-3,-0.365789e-5,
0.115792e0, -0.463143e-1, 0.725442e-2,-0.556266e-3, 0.208049e-4,-0.300895e-6};
static const G4double
CPbarn[]= {
-0.960613e-1, 0.631029e-1,-0.142819e-1, 0.150437e-2,-0.733286e-4, 0.131404e-5,
0.859343e-1,-0.529023e-1, 0.131899e-1,-0.159201e-2, 0.926958e-4,-0.208439e-5,
-0.271082e-1, 0.173949e-1,-0.452531e-2, 0.569405e-3,-0.344856e-4, 0.803964e-6,
0.419855e-2,-0.277188e-2, 0.737658e-3,-0.939463e-4, 0.569748e-5,-0.131737e-6,
-0.318752e-3, 0.215144e-3,-0.579787e-4, 0.737972e-5,-0.441485e-6, 0.994726e-8,
0.938233e-5,-0.651642e-5, 0.177303e-5,-0.224680e-6, 0.132080e-7,-0.288593e-9};
static const G4double
CCMbarn[]= {
-0.245667e-3, 0.833406e-4,-0.129217e-4, 0.915099e-6,-0.247179e-7,
0.147696e-3,-0.498793e-4, 0.402375e-5, 0.989281e-7,-0.133378e-7,
-0.737702e-2, 0.333057e-2,-0.553141e-3, 0.402464e-4,-0.107977e-5,
-0.641533e-2, 0.290113e-2,-0.477641e-3, 0.342008e-4,-0.900582e-6,
0.574303e-5, 0.908521e-4,-0.256900e-4, 0.239921e-5,-0.741271e-7};
static const G4double
CCPbarn[]= {
-0.245667e-3, 0.833406e-4,-0.129217e-4, 0.915099e-6,-0.247179e-7,
0.147696e-3,-0.498793e-4, 0.402375e-5, 0.989281e-7,-0.133378e-7,
-0.341260e-4, 0.971711e-5,-0.172031e-6,-0.119455e-6, 0.704166e-8,
0.341740e-5,-0.775867e-6,-0.653231e-7, 0.225605e-7,-0.114860e-8,
-0.119391e-6, 0.194885e-7, 0.588959e-8,-0.127589e-8, 0.608247e-10};
G4double CM[36],CP[36],CCM[25],CCP[25]; //Set the unit: barn
for (G4int i=0; i<36; i++) { CM[i] = CMbarn[i]*barn;
CP[i] = CPbarn[i]*barn;
}
for (G4int ii=0; ii<25; ii++) { CCM[ii] = CCMbarn[ii]*barn;
CCP[ii] = CCPbarn[ii]*barn;
}
// -----------------------------------------------------------
G4double TotalEnergy = T + electron_mass_c2;
G4double y=log(Cut/(ve*TotalEnergy));
G4double loss;
if (y <= 0.) loss = ComputeXYPolynomial(x, y, 6, 6, CM)
+ Z * ComputeXYPolynomial(x, y, 5, 5, CCM);
else loss = ComputeXYPolynomial(x, y, 6, 6, CP)
+ Z * ComputeXYPolynomial(x, y, 5, 5, CCP);
G4double rate = TotalEnergy/Cut ;
G4double corr = 1./(1.+corrfac*natom*rate*rate) ;
G4double factor = pow(Cut*corr/T,beta);
factor *= Z*(Z+ksi)*TotalEnergy*TotalEnergy/(TotalEnergy+electron_mass_c2) ;
loss *= factor ;
return loss ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4LowEnergyBremsstrahlung::ComputePositronCorrFactorLoss(
G4double Z,G4double KineticEnergy,G4double GammaCut)
//calculates the correction factor for the energy loss due to bremsstrahlung for positrons
//the same correction is in the (discrete) bremsstrahlung
{
static const G4double K = 132.9416*eV ;
static const G4double a1=4.15e-1, a3=2.10e-3, a5=54.0e-5 ;
G4double x = log(KineticEnergy/(K*Z*Z)), x2 = x*x, x3 = x2*x;
G4double eta = 0.5+atan(a1*x+a3*x3+a5*x3*x2)/pi;
G4double e0 = GammaCut/KineticEnergy;
G4double factor(0.);
if (e0!=1.0) { factor=log(1.-e0)/eta; factor=exp(factor);}
factor = eta*(1.-factor)/e0;
return factor;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::BuildMeanFreePathTable()
// Build mean free path tables for the gamma emission by e- or e+.
// tables are Build for MATERIALS.
{
G4double FixedEnergy = (LowestKineticEnergy + HighestKineticEnergy)/2.;
//create table
if (theMeanFreePathTable) {theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
G4double NumbOfMaterials = G4Material::GetNumberOfMaterials();
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
G4Material* material;
PartialSumSigma.resize(NumbOfMaterials);
G4double LowEdgeEnergy , Value;
theMeanFreePathTable = new G4PhysicsTable(NumbOfMaterials);
G4PhysicsLogVector* ptrVector;
for ( G4int J=0 ; J < NumbOfMaterials; J++ ){
//create physics vector then fill it ....
ptrVector = new G4PhysicsLogVector(LowestKineticEnergy, HighestKineticEnergy,
TotBin ) ;
material= (*theMaterialTable)(J);
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
for ( G4int i = 0 ; i < TotBin ; i++ ){
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy( i ) ;
const G4double BigPath= DBL_MAX;
G4double SIGMA = 0 ;
for ( G4int k=0 ; k < material->GetNumberOfElements() ; k++ ){
G4int AtomIndex = (G4int) (*theElementVector)(k)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(LowEdgeEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
SIGMA += theAtomNumDensityVector[k]*interCrsSec;
}
Value = SIGMA<=0.0 ? BigPath : 1./SIGMA ;
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insert( ptrVector );
// Compute the PartialSumSigma table at a given fixed energy
ComputePartialSumSigma(FixedEnergy, material) ;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::ComputePartialSumSigma(G4double KineticEnergy,
const G4Material* aMaterial)
// Build the table of cross section per element. The table is built for MATERIALS.
// This table is used by DoIt to select randomly an element in the material.
{
G4int Imate = aMaterial->GetIndex();
G4int NbOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
PartialSumSigma(Imate) = new G4ValVector(NbOfElements);
G4double SIGMA = 0. ;
for ( G4int Ielem=0 ; Ielem < NbOfElements ; Ielem++ ){
G4int AtomIndex = (G4int) (*theElementVector)(Ielem)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(KineticEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
SIGMA += theAtomNumDensityVector[Ielem]*interCrsSec;
PartialSumSigma(Imate)->insert(SIGMA);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4VParticleChange* G4LowEnergyBremsstrahlung::PostStepDoIt(const G4Track& trackData,
const G4Step& stepData){
//
// The emitted gamma energy is sampled using a parametrized formula from L. Urban.
// This parametrization is derived from :
// cross-section values of Seltzer and Berger for electron energies 1 keV - 10 GeV,
// screened Bethe Heilter differential cross section above 10 GeV,
// Migdal corrections in both case.
// Seltzer & Berger: Nim B 12:95 (1985)
// Nelson, Hirayama & Rogers: Technical report 265 SLAC (1985)
// Migdal: Phys Rev 103:1811 (1956); Messel & Crawford: Pergamon Press (1970)
//
// A modified version of the random number techniques of Butcher & Messel is used
// (Nuc Phys 20(1960),15).
//
// GEANT4 internal units.
//
const G4double MigdalConstant = classic_electr_radius
*electron_Compton_length
*electron_Compton_length/pi;
const G4double LPMconstant = fine_structure_const*electron_mass_c2*
electron_mass_c2/(8.*pi*hbarc) ;
aParticleChange.Initialize(trackData);
G4Material* aMaterial=trackData.GetMaterial() ;
G4double LPMEnergy = LPMconstant*(aMaterial->GetRadlen()) ;
const G4DynamicParticle* aDynamicParticle=trackData.GetDynamicParticle();
G4double charge = aDynamicParticle->GetDefinition()->GetPDGCharge();
G4double ElectKinEn = aDynamicParticle->GetKineticEnergy();
if(ElectKinEn <= LowestKineticEnergy){
aParticleChange.SetStatusChange(fStopAndKill);
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit(ElectKinEn);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
G4ParticleMomentum ElectDirection = aDynamicParticle->GetMomentumDirection();
// Gamma production cut in this material
G4double GammaEnergyCut = (G4Gamma::GetCutsInEnergy())[aMaterial->GetIndex()];
// check against insufficient energy
if (ElectKinEn < GammaEnergyCut){
aParticleChange.SetMomentumChange( ElectDirection );
aParticleChange.SetEnergyChange( ElectKinEn );
aParticleChange.SetLocalEnergyDeposit (0.);
aParticleChange.SetNumberOfSecondaries(0);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
// select randomly one element constituing the material
G4Element* anElement = SelectRandomAtom(aMaterial);
// limits of the energy sampling
G4double TotalEnergy = ElectKinEn + electron_mass_c2;
G4double TotalEnergysquare = TotalEnergy*TotalEnergy ;
G4double LPMGammaEnergyLimit = TotalEnergysquare/LPMEnergy ;
//
// sample the energy rate of the emitted gamma for electron kinetic energy
// sampling formula: spet(T) = A(T)/E+B(T)
//
G4double p1 = 0, p2 = 0;
G4double coeffA = 0, coeffB = 0;
G4int AtomicNum = (G4int) anElement->GetZ();
coeffA = ComputeA(AtomicNum, ElectKinEn);
coeffB = ComputeB(AtomicNum, ElectKinEn);
p1 = coeffA*log(ElectKinEn/lowEnergyCut);
p2 = coeffB*(ElectKinEn - lowEnergyCut);
G4double IntegrProb = p1+p2;
G4double R1 = G4UniformRand()*IntegrProb;
G4double GammaEnergy;
if(R1 <= p1){
G4double R2 = G4UniformRand();
GammaEnergy = ElectKinEn*pow((lowEnergyCut/ElectKinEn),R2);
}
else if(p1 < R1 <= p1+p2){
G4double R2 = G4UniformRand();
GammaEnergy = ElectKinEn - R2*(ElectKinEn - lowEnergyCut);
}
// now comes the supression due to the LPM effect I leave it
if(GammaEnergy < LPMGammaEnergyLimit){
G4double S2LPM = LPMEnergy*GammaEnergy/TotalEnergysquare ;
G4double Spol = GammaEnergy*GammaEnergy/(GammaEnergy*GammaEnergy +
MigdalConstant*(aMaterial->GetElectronDensity())*
TotalEnergysquare) ;
G4double w = S2LPM*(1.+1./Spol) ;
G4double Supr = 0.5*(sqrt(w*w+4.*S2LPM)-w)/Spol ;
if (G4UniformRand() > Supr )
GammaEnergy = 0. ;
}
//protection: DO NOT PRODUCE a gamma with energy 0. !
if (GammaEnergy <= 0.){
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
//**********************//
// Angular distribution //
//**********************//
// angles of the emitted gamma. ( Z - axis along the parent particle)
//
// universal distribution suggested by L. Urban (Geant3 manual (1993) Phys211),
// derived from Tsai distribution (Rev Mod Phys 49,421(1977))
if(GammaEnergy > CutForLowEnergySecondaryPhotons){
G4double u;
const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
if (9./(9.+d) > G4UniformRand()) u = - log(G4UniformRand()*G4UniformRand())/a1 ;
else u = - log(G4UniformRand()*G4UniformRand())/a2 ;
G4double Teta = u*electron_mass_c2/TotalEnergy ;
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sin(Teta)*cos(Phi) , diry = sin(Teta)*sin(Phi) , dirz = cos(Teta) ;
G4ThreeVector GammaDirection ( dirx, diry, dirz);
GammaDirection.rotateUz(ElectDirection);
//
// Update the incident particle
//
G4double NewKinEnergy = ElectKinEn - GammaEnergy;
if (NewKinEnergy > 0.){
aParticleChange.SetMomentumChange( ElectDirection );
aParticleChange.SetEnergyChange( NewKinEnergy );
if(GammaEnergy < GammaEnergyCut){
aParticleChange.SetLocalEnergyDeposit (GammaEnergy);
}
else{
// create G4DynamicParticle object for the Gamma
G4DynamicParticle* aGamma= new G4DynamicParticle (G4Gamma::Gamma(),
GammaDirection, GammaEnergy);
aParticleChange.SetNumberOfSecondaries(1);
aParticleChange.AddSecondary(aGamma);
aParticleChange.SetLocalEnergyDeposit (0);
}
}
else{
aParticleChange.SetEnergyChange( 0. );
aParticleChange.SetLocalEnergyDeposit (0.);
if (charge<0.){
aParticleChange.SetStatusChange(fStopAndKill);
}
else{
aParticleChange.SetStatusChange(fStopButAlive);
}
}
}
else{
aParticleChange.SetNumberOfSecondaries(0);
}
#ifdef G4VERBOSE
if(verboseLevel > 15){
G4cout<<"LE Bremsstrahlung PostStepDoIt"<<endl;
}
#endif
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4Element* G4LowEnergyBremsstrahlung::SelectRandomAtom(G4Material* aMaterial) const
{
// select randomly 1 element within the material
const G4int Index = aMaterial->GetIndex();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
G4double rval = G4UniformRand()*((*PartialSumSigma(Index))(NumberOfElements-1));
for ( G4int i=0; i < NumberOfElements; i++ )
if (rval <= (*PartialSumSigma(Index))(i)) return ((*theElementVector)(i));
// G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
// << "' has no elements" << endl;
return (*theElementVector)(0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyBremsstrahlung::PrintInfoDefinition()
{
G4String comments = "Total cross sections from a parametrisation(L.Urban). ";
comments += "Good description from 1 KeV to 100 GeV.\n";
comments += " log scale extrapolation above 100 GeV \n";
comments += " Gamma energy sampled from a parametrised formula.";
G4cout << endl << GetProcessName() << ": " << comments
<< "\n PhysicsTables from " << G4BestUnit(LowestKineticEnergy,"Energy")
<< " to " << G4BestUnit(HighestKineticEnergy,"Energy")
<< " in " << TotBin << " bins. \n";
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -0,0 +1,421 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyCompton.cc,v 1.12 1999/07/06 15:03:02 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyCompton physics process --------
// by Michel Maire, April 1996
// **************************************************************
// 28-05-96, DoIt() small change in ElecDirection, by M.Maire
// 10-06-96, simplification in ComputeMicroscopicCrossSection(), by M.Maire
// 21-06-96, SetCuts implementation, M.Maire
// 13-09-96, small changes in DoIt for better efficiency. Thanks to P.Urban
// 06-01-97, crossection table + meanfreepath table, M.Maire
// 05-03-97, new Physics scheme, M.Maire
// 28-03-97, protection in BuildPhysicsTable, M.Maire
// 07-04-98, remove 'tracking cut' of the scattered gamma, MMa
// 04-06-98, in DoIt, secondary production condition: range>min(threshold,safety)
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyCompton.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4Electron.hh"
// constructor
G4LowEnergyCompton::G4LowEnergyCompton(const G4String& processName)
: G4VDiscreteProcess(processName),
theCrossSectionTable(0),
theMeanFreePathTable(0),
theScatteringFunctionTable(0),
ZNumVec(0),
LowestEnergyLimit (250*eV), // initialization
HighestEnergyLimit(100*GeV),
NumbBinTable(200)
{
if (verboseLevel>0) {
G4cout << GetProcessName() << " is created "<< endl;
G4cout << "LowestEnergy: " << LowestEnergyLimit/keV << "keV ";
G4cout << "HighestEnergy: " << HighestEnergyLimit/TeV << "TeV " << endl;
}
}
// destructor
G4LowEnergyCompton::~G4LowEnergyCompton()
{
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
if (theScatteringFunctionTable) {
delete theScatteringFunctionTable;
}
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
}
// methods.............................................................................
// to change with other functions like in G4eIonization
void G4LowEnergyCompton::BuildPhysicsTable(const G4ParticleDefinition& GammaType){
BuildZVec();
// Build microscopic cross section table and mean free path table
BuildCrossSectionTable();
// Build mean free path table for the Compton Scattering process
BuildMeanFreePathTable();
// build the scattering function table
BuildScatteringFunctionTable();
}
void G4LowEnergyCompton::BuildCrossSectionTable(){
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
theCrossSectionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomCS = util.BuildFirstLevelTables(AtomInd, dataNum, "comp/ce-cs-");
theCrossSectionTable->insert(oneAtomCS);
}//end for on atoms
}
void G4LowEnergyCompton::BuildScatteringFunctionTable(){
if (theScatteringFunctionTable) {
delete theScatteringFunctionTable;
}
theScatteringFunctionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomSF = util.BuildFirstLevelTables(AtomInd, dataNum, "comp/ce-sf-");
theScatteringFunctionTable->insert(oneAtomSF);
}//end for on atoms
}
void G4LowEnergyCompton::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
G4VParticleChange* G4LowEnergyCompton::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep){
//
// The scattered gamma energy is sampled according to Klein - Nishina formula.
// The random number techniques of Butcher & Messel are used
// (Nuc Phys 20(1960),15).
// GEANT4 internal units
//
aParticleChange.Initialize(aTrack);
// Dynamic particle quantities
const G4DynamicParticle* aDynamicGamma = aTrack.GetDynamicParticle();
G4double GammaEnergy0 = aDynamicGamma->GetKineticEnergy();
if(GammaEnergy0 <= LowestEnergyLimit){
aParticleChange.SetStatusChange(fStopAndKill);
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit(GammaEnergy0);
return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
}
G4double E0_m = GammaEnergy0 / electron_mass_c2 ;
G4ParticleMomentum GammaDirection0 = aDynamicGamma->GetMomentumDirection();
// Select randomly one element
G4Material* aMaterial = aTrack.GetMaterial();
const G4int numOfElem = aMaterial->GetNumberOfElements();
G4Element* theElement = SelectRandomAtom(aDynamicGamma, aMaterial);
G4int elementZ = (G4int) theElement->GetZ();
G4double epsilon, epsilonsq, onecost, sint2, greject ;
G4double epsilon0 = 1./(1. + 2*E0_m) , epsilon0sq = epsilon0*epsilon0;
G4double alpha1 = - log(epsilon0) , alpha2 = 0.5*(1.- epsilon0sq);
G4double ScatteringFunction, x;
G4double wlGamma = h_Planck*c_light/GammaEnergy0;
// sample the energy rate of the scattered gamma
do{
if ( alpha1/(alpha1+alpha2) > G4UniformRand()){
epsilon = exp(-alpha1*G4UniformRand()); // pow(epsilon0,G4UniformRand())
epsilonsq = epsilon*epsilon;
}
else{
epsilonsq = epsilon0sq + (1.- epsilon0sq)*G4UniformRand();
epsilon = sqrt(epsilonsq);
}
onecost = (1.- epsilon)/(epsilon*E0_m);
sint2 = onecost*(2.-onecost);
x = sqrt(onecost/2)/wlGamma;
const G4FirstLevel* oneAtomSF
= (*theScatteringFunctionTable)[ZNumVec->index(elementZ)];
ScatteringFunction = util.DataLogInterpolation(x, (*(*oneAtomSF)[0]),
(*(*oneAtomSF)[1]))/cm;
greject = (1. - epsilon*sint2/(1.+ epsilonsq))*ScatteringFunction;
} while(greject < elementZ*G4UniformRand());
G4double cosTeta = 1. - onecost , sinTeta = sqrt (sint2);
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sinTeta*cos(Phi) , diry = sinTeta*sin(Phi) , dirz = cosTeta ;
//
// update G4VParticleChange for the scattered gamma
//
G4ThreeVector GammaDirection1 ( dirx,diry,dirz );
GammaDirection1.rotateUz(GammaDirection0);
aParticleChange.SetMomentumChange( GammaDirection1 ) ;
G4double GammaEnergy1 = epsilon*GammaEnergy0;
if (GammaEnergy1 > 0.)
{
aParticleChange.SetEnergyChange( GammaEnergy1 ) ;
}
else
{
aParticleChange.SetEnergyChange(0.) ;
aParticleChange.SetStatusChange(fStopAndKill);
}
//
// kinematic of the scattered electron
//
G4double ElecKineEnergy = GammaEnergy0 - GammaEnergy1 ;
if (G4EnergyLossTables::GetRange(G4Electron::Electron(), ElecKineEnergy, aMaterial)
>= min(G4Electron::GetCuts(), aStep.GetPostStepPoint()->GetSafety())){
G4double ElecMomentum = sqrt(ElecKineEnergy*(ElecKineEnergy+2.*electron_mass_c2));
G4ThreeVector ElecDirection((GammaEnergy0*GammaDirection0 -
GammaEnergy1*GammaDirection1)*(1./ElecMomentum));
// create G4DynamicParticle object for the electron.
G4DynamicParticle* aElectron= new G4DynamicParticle (G4Electron::Electron(),
ElecDirection, ElecKineEnergy) ;
aParticleChange.SetNumberOfSecondaries(1);
aParticleChange.AddSecondary( aElectron );
aParticleChange.SetLocalEnergyDeposit (0.);
}
else{
aParticleChange.SetNumberOfSecondaries(0);
aParticleChange.SetLocalEnergyDeposit (ElecKineEnergy);
}
#ifdef G4VERBOSE
if(verboseLevel > 0){
G4cout<<"LE Compton Effect PostStepDoIt"<<endl;
}
#endif
return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep);
}
void G4LowEnergyCompton::BuildMeanFreePathTable(){
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy(); delete theMeanFreePathTable; }
// material
G4double NumbOfMaterials = G4Material::GetNumberOfMaterials();
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
G4Material* material;
// MeanFreePath
G4double LowEdgeEnergy, Value;
theMeanFreePathTable = new G4PhysicsTable(NumbOfMaterials);
G4PhysicsLogVector* ptrVector;
for ( G4int J = 0 ; J < NumbOfMaterials; J++ ) { // For each material
//create physics vector then fill it ....
ptrVector = new G4PhysicsLogVector(LowestEnergyLimit, HighestEnergyLimit, NumbBinTable);
material = (*theMaterialTable)(J);
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
for ( G4int i = 0 ; i < NumbBinTable ; i++ ){
//For each energy
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy(i);
const G4double BigPath= DBL_MAX;
G4double SIGMA = 0 ;
for ( G4int k=0 ; k < material->GetNumberOfElements() ; k++ ){
G4int AtomIndex = (G4int) (*theElementVector)(k)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(LowEdgeEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
SIGMA += theAtomNumDensityVector[k]*interCrsSec;
}
Value = SIGMA<=0.0 ? BigPath : 1./SIGMA ;
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector );
}
}
G4Element* G4LowEnergyCompton::SelectRandomAtom(const G4DynamicParticle* aDynamicGamma,
G4Material* aMaterial){
// select randomly 1 element within the material
G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
if (NumberOfElements == 1) return (*theElementVector)(0);
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
//GetMeanFreePath
G4double PartialSumSigma = 0.;
G4double rval = 0;
rval = G4UniformRand()/MeanFreePath;
for ( G4int i=0 ; i < NumberOfElements ; i++ ){
G4double crossSection;
if (GammaEnergy < LowestEnergyLimit)
crossSection = 0. ;
else {
if (GammaEnergy > HighestEnergyLimit) GammaEnergy = 0.99*HighestEnergyLimit ;
G4int AtomIndex = (G4int) (*theElementVector)(i)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
crossSection = util.DataLogInterpolation(GammaEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
}
PartialSumSigma += theAtomNumDensityVector[i] * crossSection;
if(rval <= PartialSumSigma) return ((*theElementVector)(i));
}
// G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
// << "' has no elements" << endl;
return (*theElementVector)(0);
}
@@ -0,0 +1,425 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyGammaConversion.cc,v 1.9 1999/06/28 15:46:00 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyGammaConversion physics process --------
// by Michel Maire, 24 May 1996
// **************************************************************
// 11-06-96, Added SelectRandomAtom() method, M.Maire
// 21-06-96, SetCuts implementation, M.Maire
// 24-06-96, simplification in ComputeMicroscopicCrossSection, M.Maire
// 24-06-96, in DoIt : change the particleType stuff, M.Maire
// 25-06-96, modification in the generation of the teta angle, M.Maire
// 16-09-96, minors optimisations in DoIt. Thanks to P.Urban
// dynamical array PartialSumSigma
// 13-12-96, fast sampling of epsil below 2 MeV, L.Urban
// 14-01-97, crossection table + meanfreepath table.
// PartialSumSigma removed, M.Maire
// 14-01-97, in DoIt the positron is always created, even with Ekine=0,
// for further annihilation, M.Maire
// 14-03-97, new Physics scheme for geant4alpha, M.Maire
// 28-03-97, protection in BuildPhysicsTable, M.Maire
// 19-06-97, correction in ComputeMicroscopicCrossSection, L.Urban
// 04-06-98, in DoIt, secondary production condition: range>min(threshold,safety)
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyGammaConversion.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4Electron.hh"
#include "G4Positron.hh"
// constructor
G4LowEnergyGammaConversion::G4LowEnergyGammaConversion(const G4String& processName)
: G4VDiscreteProcess(processName),
theCrossSectionTable(0),
theMeanFreePathTable(0),
ZNumVec(0),
LowestEnergyLimit (1.2200),
HighestEnergyLimit(100*GeV),
NumbBinTable(200)
{
if (verboseLevel>0) {
G4cout << GetProcessName() << " is created "<< endl;
G4cout << "LowestEnergy: " << LowestEnergyLimit/keV << "keV ";
G4cout << "HighestEnergy: " << HighestEnergyLimit/GeV << "GeV " << endl;
}
}
// destructor
G4LowEnergyGammaConversion::~G4LowEnergyGammaConversion()
{
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
}
// methods.............................................................................
void G4LowEnergyGammaConversion::BuildPhysicsTable(const G4ParticleDefinition& GammaType){
BuildZVec();
// Build microscopic cross section tables for the Compton Scattering process
BuildCrossSectionTable();
// Build mean free path table for the Compton Scattering process
BuildMeanFreePathTable();
}
void G4LowEnergyGammaConversion::BuildCrossSectionTable(){
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
theCrossSectionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomCS = util.BuildFirstLevelTables(AtomInd, dataNum, "pair/pp-cs-");
theCrossSectionTable->insert(oneAtomCS);
}//end for on atoms
}
void G4LowEnergyGammaConversion::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
G4VParticleChange* G4LowEnergyGammaConversion::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep){
//
// The secondaries e+e- energies are sampled using the Bethe - Heitler
// cross sections with Coulomb correction. A modified version of the random
// number techniques of Butcher & Messel is used (Nuc Phys 20(1960),15).
//
// GEANT4 internal units.
//
// Note 1 : Effects due to the breakdown of the Born approximation at low
// energy are ignored.
// Note 2 : The differential cross section implicitly takes account of
// pair creation in both nuclear and atomic electron fields. However triplet
// prodution is not generated.
aParticleChange.Initialize(aTrack);
G4Material* aMaterial = aTrack.GetMaterial();
const G4DynamicParticle* aDynamicGamma = aTrack.GetDynamicParticle();
G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
G4ParticleMomentum GammaDirection = aDynamicGamma->GetMomentumDirection();
G4double epsil ;
G4double epsil0 = electron_mass_c2 / GammaEnergy ;
// do it fast if GammaEnergy < 2. MeV
const G4double Egsmall=2.*MeV;
if (GammaEnergy<Egsmall) { epsil = epsil0 + (0.5-epsil0)*G4UniformRand(); }
else{ // now comes the case with GammaEnergy >= 2. MeV
// select randomly one element constituing the material
G4Element* anElement = SelectRandomAtom(aDynamicGamma, aMaterial);
// Extract Coulomb factor for this Element
G4double FZ = 8.*(anElement->GetIonisation()->GetlogZ3());
if (GammaEnergy > 50.*MeV) FZ += 8.*(anElement->GetfCoulomb());
// limits of the screening variable
G4double screenfac = 136.*epsil0/(anElement->GetIonisation()->GetZ3()) ;
G4double screenmax = exp ((42.24 - FZ)/8.368) - 0.952 ;
G4double screenmin = min(4.*screenfac,screenmax) ;
// limits of the energy sampling
G4double epsil1 = 0.5 - 0.5*sqrt(1. - screenmin/screenmax) ;
G4double epsilmin = max(epsil0,epsil1) , epsilrange = 0.5 - epsilmin ;
//
// sample the energy rate of the created electron (or positron)
//
//G4double epsil, screenvar, greject ;
G4double screenvar, greject ;
G4double F10 = ScreenFunction1(screenmin) - FZ , F20 = ScreenFunction2(screenmin) - FZ;
G4double NormF1 = max(F10*epsilrange*epsilrange,0.) , NormF2 = max(1.5*F20,0.);
do {
if ( NormF1/(NormF1+NormF2) > G4UniformRand() ){
epsil = 0.5 - epsilrange*pow(G4UniformRand(), 1/3) ;
screenvar = screenfac/(epsil*(1-epsil));
greject = (ScreenFunction1(screenvar) - FZ)/F10 ;
}
else {
epsil = epsilmin + epsilrange*G4UniformRand();
screenvar = screenfac/(epsil*(1-epsil));
greject = (ScreenFunction2(screenvar) - FZ)/F20 ;
}
} while( greject < G4UniformRand() );
} // end of epsil sampling.........................
//
// fixe charges randomly
//
G4double ElectTotEnergy, PositTotEnergy;
if (RandFlat::shootBit()){
ElectTotEnergy = (1.-epsil)*GammaEnergy;
PositTotEnergy = epsil*GammaEnergy;
}
else{
PositTotEnergy = (1.-epsil)*GammaEnergy;
ElectTotEnergy = epsil*GammaEnergy;
}
//
// scattered electron (positron) angles. ( Z - axis along the parent photon)
// universal distribution suggested by L. Urban (Geant3 manual (1993) Phys211),
// derived from Tsai distribution (Rev Mod Phys 49,421(1977))
G4double u;
const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
if (9./(9.+d) > G4UniformRand()){
u = - log(G4UniformRand()*G4UniformRand())/a1 ;
}
else{
u = - log(G4UniformRand()*G4UniformRand())/a2 ;
}
G4double Teta = u*electron_mass_c2/GammaEnergy ;
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sin(Teta)*cos(Phi) , diry = sin(Teta)*sin(Phi) , dirz = cos(Teta);
//
// kinematic of the created pair
// the electron and positron are assumed to have a symetric angular
// distribution with respect to the Z axis along the parent photon.
G4double LocalEnerDeposit = 0. ;
aParticleChange.SetNumberOfSecondaries(2) ;
G4double ElectKineEnergy = max(0.,ElectTotEnergy - electron_mass_c2) ;
if (G4EnergyLossTables::GetRange(G4Electron::Electron(), ElectKineEnergy, aMaterial)
>= min(G4Electron::GetCuts(), aStep.GetPostStepPoint()->GetSafety()) ){
G4ThreeVector ElectDirection ( dirx, diry, dirz );
ElectDirection.rotateUz(GammaDirection);
// create G4DynamicParticle object for the particle1
G4DynamicParticle* aParticle1= new G4DynamicParticle (G4Electron::Electron(),ElectDirection, ElectKineEnergy);
aParticleChange.AddSecondary( aParticle1 ) ;
}
else{
LocalEnerDeposit += ElectKineEnergy ;
}
// the e+ is always created (even with Ekine=0) for further annihilation.
G4double PositKineEnergy = max(0.,PositTotEnergy - electron_mass_c2) ;
if (G4EnergyLossTables::GetRange(G4Positron::Positron(),PositKineEnergy,aMaterial)
< min(G4Positron::GetCuts(), aStep.GetPostStepPoint()->GetSafety()) ){
LocalEnerDeposit += PositKineEnergy ;
PositKineEnergy = 0. ;
}
G4ThreeVector PositDirection ( -dirx, -diry, dirz );
PositDirection.rotateUz(GammaDirection);
// create G4DynamicParticle object for the particle2
G4DynamicParticle* aParticle2= new G4DynamicParticle (G4Positron::Positron(),
PositDirection, PositKineEnergy);
aParticleChange.AddSecondary( aParticle2 ) ;
aParticleChange.SetLocalEnergyDeposit( LocalEnerDeposit ) ;
//
// Kill the incident photon
//
aParticleChange.SetMomentumChange( 0., 0., 0. ) ;
aParticleChange.SetEnergyChange( 0. ) ;
aParticleChange.SetStatusChange( fStopAndKill ) ;
#ifdef G4VERBOSE
if(verboseLevel > 15){
G4cout<<"LE Gamma Conversion PostStepDoIt"<<endl;
}
#endif
// Reset NbOfInteractionLengthLeft and return aParticleChange
return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep );
}
void G4LowEnergyGammaConversion::BuildMeanFreePathTable(){
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy(); delete theMeanFreePathTable; }
// material
G4double NumbOfMaterials = G4Material::GetNumberOfMaterials();
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
G4Material* material;
// MeanFreePath
G4double LowEdgeEnergy, Value;
theMeanFreePathTable = new G4PhysicsTable(NumbOfMaterials);
G4PhysicsLogVector* ptrVector;
for ( G4int J = 0 ; J < NumbOfMaterials; J++ ) { // For each material
//create physics vector then fill it ....
ptrVector = new G4PhysicsLogVector(LowestEnergyLimit, HighestEnergyLimit, NumbBinTable);
material = (*theMaterialTable)(J);
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
for ( G4int i = 0 ; i < NumbBinTable ; i++ ){
//For each energy
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy(i);
const G4double BigPath= DBL_MAX;
G4double SIGMA = 0 ;
for ( G4int k=0 ; k < material->GetNumberOfElements() ; k++ ){
// For each element
G4int AtomIndex = (G4int) (*theElementVector)(k)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(LowEdgeEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
SIGMA += theAtomNumDensityVector[k]*interCrsSec;
}
Value = SIGMA<=0.0 ? BigPath : 1./SIGMA ;
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector ) ;
}
}
G4Element* G4LowEnergyGammaConversion::SelectRandomAtom(const G4DynamicParticle* aDynamicGamma, G4Material* aMaterial){
// select randomly 1 element within the material
G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
if (NumberOfElements == 1) return (*theElementVector)(0);
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
G4double PartialSumSigma = 0.;
G4double rval = G4UniformRand()/MeanFreePath;
for ( G4int i=0 ; i < NumberOfElements ; i++ ){
G4double crossSection;
if (GammaEnergy < LowestEnergyLimit)
crossSection = 0. ;
else {
if (GammaEnergy > HighestEnergyLimit) GammaEnergy = 0.99*HighestEnergyLimit ;
G4int AtomIndex = (G4int) (*theElementVector)(i)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
crossSection = util.DataLogInterpolation(GammaEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
}
PartialSumSigma += theAtomNumDensityVector[i] * crossSection;
if(rval <= PartialSumSigma) return ((*theElementVector)(i));
}
// G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
// << "' has no elements" << endl;
return (*theElementVector)(0);
}
@@ -0,0 +1,983 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyIonisation.cc,v 1.20 1999/07/06 13:20:25 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// -------------------------------------------------------------
// GEANT 4 class implementation file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: based on object model of
// 2nd December 1995, G.Cosmo
// ---------- G4LowEnergyIonisation physics process -----------
// by Laszlo Urban, 20 March 1997
// **************************************************************
// It is the first implementation of the NEW IONISATION PROCESS.
// It calculates the ionisation of e+/e-.
// **************************************************************
//
// 07-04-98: remove 'tracking cut' of the ionizing particle, MMa
// 04-09-98: new methods SetBining() PrintInfo()
// 07-09-98: Cleanup
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyIonisation.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4Gamma.hh"
#include "G4UnitsTable.hh"
typedef RWTPtrOrderedVector<G4DynamicParticle> G4ParticleVector;
// constructor and destructor
G4LowEnergyIonisation::G4LowEnergyIonisation(const G4String& processName)
: G4eEnergyLoss(processName),
allAtomShellCrossSec(0),
theBindingEnergyTable(0),
theFluorTransitionTable(0),
theSamplingCoeffTable(0),
LowestKineticEnergy(250.*eV),
HighestKineticEnergy(100.*GeV),
CutForLowEnergySecondaryPhotons(0.),
CutForLowEnergySecondaryElectrons(0.),
ZNumVec(0),
ZNumVecFluor(0),
TotBin(200)
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4LowEnergyIonisation::~G4LowEnergyIonisation()
{
if (allAtomShellCrossSec) {
delete allAtomShellCrossSec;
}
if (theBindingEnergyTable) {
delete theBindingEnergyTable;
}
if (theFluorTransitionTable) {
delete theFluorTransitionTable;
}
if(theSamplingCoeffTable){
delete theSamplingCoeffTable;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
if(ZNumVecFluor){
ZNumVecFluor->clear();
delete ZNumVecFluor;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::SetCutForLowEnSecPhotons(G4double cut){
CutForLowEnergySecondaryPhotons = cut;
}
void G4LowEnergyIonisation::SetCutForLowEnSecElectrons(G4double cut){
CutForLowEnergySecondaryElectrons = cut;
// LowestKineticEnergy = 2*cut;
}
void G4LowEnergyIonisation::BuildPhysicsTable(const G4ParticleDefinition& aParticleType)
// just call BuildLossTable+BuildLambdaTable
{
BuildLossTable(aParticleType) ;
if(&aParticleType==G4Electron::Electron())
{
RecorderOfElectronProcess[CounterOfElectronProcess] = (*this).theLossTable ;
CounterOfElectronProcess++;
}
else
{
RecorderOfPositronProcess[CounterOfPositronProcess] = (*this).theLossTable ;
CounterOfPositronProcess++;
}
BuildDEDXTable(aParticleType);
BuildZVec();
BuildShellCrossSectionTable();
BuildFluorTransitionTable();
BuildBindingEnergyTable();
BuildSamplingCoeffTable();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::BuildLossTable(const G4ParticleDefinition& aParticleType)
{
// Build tables for the ionization energy loss
// the tables are built for *MATERIALS*
const G4double twoln10 = 2.*log(10.);
const G4double Factor = twopi_mc2_rcl2;
G4double LowEdgeEnergy, ionloss;
// material properties
G4double ElectronDensity,Eexc,Eexcm2,Cden,Mden,Aden,X0den,X1den ;
// some local variables
G4double tau,Tmax,gamma,gamma2,bg2,beta2,d,d2,d3,d4,delta,x,y ;
ParticleMass = aParticleType.GetPDGMass();
G4double* ParticleCutInKineticEnergy = aParticleType.GetEnergyCuts() ;
// create table
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if (theLossTable) { theLossTable->clearAndDestroy();
delete theLossTable;
}
theLossTable = new G4PhysicsTable(numOfMaterials);
// loop for materials
for (G4int J=0; J<numOfMaterials; J++)
{
// create physics vector and fill it
G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
LowestKineticEnergy, HighestKineticEnergy, TotBin);
// get material parameters needed for the energy loss calculation
const G4Material* material= (*theMaterialTable)[J];
ElectronDensity = material->GetElectronDensity();
Eexc = material->GetIonisation()->GetMeanExcitationEnergy();
Eexc /= ParticleMass; Eexcm2 = Eexc*Eexc;
Cden = material->GetIonisation()->GetCdensity();
Mden = material->GetIonisation()->GetMdensity();
Aden = material->GetIonisation()->GetAdensity();
X0den = material->GetIonisation()->GetX0density();
X1den = material->GetIonisation()->GetX1density();
// now comes the loop for the kinetic energy values
for (G4int i = 0 ; i < TotBin ; i++)
{
LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
tau = LowEdgeEnergy/ParticleMass ;
// Seltzer-Berger formula
gamma = tau + 1.; gamma2 = gamma*gamma;
bg2 = tau*(tau+2.);
beta2 = bg2/gamma2;
// electron
if (&aParticleType==G4Electron::Electron())
{
Tmax = LowEdgeEnergy/2.;
d = min(ParticleCutInKineticEnergy[J], Tmax)/ParticleMass;
ionloss = log(2.*(tau+2.)/Eexcm2)-1.-beta2
+ log((tau-d)*d)+tau/(tau-d)
+ (0.5*d*d+(2.*tau+1.)*log(1.-d/tau))/gamma2;
}
else //positron
{
Tmax = LowEdgeEnergy ;
d = min(ParticleCutInKineticEnergy[J], Tmax)/ParticleMass;
d2=d*d/2.; d3=d*d*d/3.; d4=d*d*d*d/4.;
y=1./(1.+gamma);
ionloss = log(2.*(tau+2.)/Eexcm2)+log(tau*d)
- beta2*(tau+2.*d-y*(3.*d2+y*(d-d3+y*(d2-tau*d3+d4))))/tau;
}
//density correction
x = log(bg2)/twoln10;
if (x < X0den) delta = 0.;
else { delta = twoln10*x - Cden;
if (x < X1den) delta += Aden*pow((X1den-x),Mden);
}
//now you can compute the total ionization loss
ionloss -= delta ;
ionloss *= Factor*ElectronDensity/beta2 ;
if (ionloss <= 0.) ionloss = 0.;
aVector->PutValue(i,ionloss) ;
}
theLossTable->insert(aVector);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::BuildShellCrossSectionTable(){
if (allAtomShellCrossSec) {
delete allAtomShellCrossSec;
}
allAtomShellCrossSec = new allAtomTable();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
oneAtomTable* oneAtomShellCS = util.BuildSecondLevelTables(AtomInd, dataNum, "ioni/ion-ss-cs-");
allAtomShellCrossSec->insert(oneAtomShellCS);
}//end for on atoms
}
void G4LowEnergyIonisation::BuildBindingEnergyTable(){
if (theBindingEnergyTable) {
delete theBindingEnergyTable;
}
G4int dataNum = 2;
theBindingEnergyTable = util.BuildSecondLevelTables(0,dataNum,"fluor/binding");
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::BuildFluorTransitionTable(){
if (theFluorTransitionTable) {
delete theFluorTransitionTable;
}
theFluorTransitionTable = new allAtomTable();
ZNumVecFluor = new G4Data(*ZNumVec);
G4int dataNum = 3;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
if(AtomInd > 5){
oneAtomTable* oneAtomShellFL = util.BuildSecondLevelTables(AtomInd, dataNum, "fluor/fl-tr-pr-");
theFluorTransitionTable->insert(oneAtomShellFL);
}
else{
ZNumVecFluor->remove(AtomInd);
}
}//end for on atoms
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::BuildSamplingCoeffTable(){
if (theSamplingCoeffTable) {
delete theSamplingCoeffTable;
}
theSamplingCoeffTable = new allAtomTable();
G4int dataNum = 12;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
oneAtomTable* oneAtomShellSc = util.BuildSecondLevelTables(AtomInd, dataNum, "ioni/ion-co-");
theSamplingCoeffTable->insert(oneAtomShellSc);
}//end for on atoms
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
G4double G4LowEnergyIonisation::ComputeCrossSection(const G4double AtomIndex,
const G4double IncEnergy){
// calculates the microscopic cross section from subshell cross sections
//(it is called for elements , AtomicNumber = Z )
G4double TotalCrossSection(0.);
const oneAtomTable* oneAtomCS
= (*allAtomShellCrossSec)[ZNumVec->index(AtomIndex)];
for(G4int ind = 0; ind < oneAtomCS->entries(); ind++){
G4double crossSec = 0;
G4Data* EnergyVector = (*(*oneAtomCS)[ind])[0];
G4Data* CrossSecVector = (*(*oneAtomCS)[ind])[1];
if(IncEnergy < (*EnergyVector)[1]){ // First element is the shell number
crossSec = 0;
}
else{
crossSec = util.DataLogInterpolation(IncEnergy, (*EnergyVector), (*CrossSecVector));
}
TotalCrossSection += crossSec;
}
return TotalCrossSection ;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4VParticleChange* G4LowEnergyIonisation::PostStepDoIt( const G4Track& trackData,
const G4Step& stepData){
aParticleChange.Initialize(trackData);
G4Material* aMaterial = trackData.GetMaterial() ;
const G4DynamicParticle* aParticle = trackData.GetDynamicParticle() ;
// select randomly one element constituing the material.
G4Element* anElement = SelectRandomAtom(aParticle, aMaterial);
G4int AtomIndex = (G4int) anElement->GetZ();
G4double KineticEnergy = aParticle->GetKineticEnergy();
if(KineticEnergy <= LowestKineticEnergy){
aParticleChange.SetStatusChange(fStopAndKill);
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit(KineticEnergy);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
// Select the subshell WARNING!!!!
G4int subShellIndex = SelectRandomShell(AtomIndex, KineticEnergy);
G4FirstLevel* theBindEnVec = (*theBindingEnergyTable)[AtomIndex-1];
G4int thePrimaryShell = (G4int) (*(*theBindEnVec)[0])[subShellIndex];
G4double BindingEn = (*(*theBindEnVec)[1])[subShellIndex];
G4double theEnergyDeposit = BindingEn;
G4double charge = aParticle->GetDefinition()->GetPDGCharge();
ParticleMass = aParticle->GetDefinition()->GetPDGMass();
G4double Psquare = KineticEnergy*(KineticEnergy+2*ParticleMass);
G4double TotalMomentum = sqrt(Psquare);
G4ParticleMomentum ParticleDirection = aParticle->GetMomentumDirection();
// get kinetic energy cut for the electron
G4double* DeltaCutInKineticEnergy = G4Electron::Electron()->GetCutsInEnergy() ;
G4double DeltaThreshold = DeltaCutInKineticEnergy[aMaterial->GetIndex()];
// some kinematics
G4double MaxKineticEnergyTransfer;
if (charge < 0.) MaxKineticEnergyTransfer = 0.5*(KineticEnergy);
else MaxKineticEnergyTransfer = KineticEnergy;
// sampling kinetic energy of the delta ray
if (MaxKineticEnergyTransfer <= 0 || MaxKineticEnergyTransfer <= LowestKineticEnergy/2){
// pathological case (should not happen, there is no change at all)
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
// **** normal case ****
//Energy Sampling
G4double DeltaKineticEnergy = EnergySampling(AtomIndex, subShellIndex, KineticEnergy);
// protection :do not produce a secondary with 0. kinetic energy !
if (DeltaKineticEnergy <= 0.){
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
if(DeltaKineticEnergy <= DeltaThreshold){
aParticleChange.SetNumberOfSecondaries(0);
aParticleChange.SetEnergyChange(KineticEnergy - DeltaKineticEnergy - BindingEn);
aParticleChange.SetLocalEnergyDeposit(DeltaKineticEnergy+BindingEn);
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
G4double finalKineticEnergy = KineticEnergy - DeltaKineticEnergy;
// G4double finalKineticEnergy = KineticEnergy - DeltaKineticEnergy - BindingEn;
if(thePrimShVec.length() != 0){
thePrimShVec.clear();
}
thePrimShVec.insert(thePrimaryShell);
// delta ray kinematics
G4double DeltaTotalMomentum = sqrt(DeltaKineticEnergy * (DeltaKineticEnergy +
2. * electron_mass_c2 ));
if(finalKineticEnergy > 0.){
G4double finalMomentum=sqrt(finalKineticEnergy*
(finalKineticEnergy+2.*ParticleMass));
G4double costheta = (Psquare-(finalMomentum*finalMomentum)+
(DeltaTotalMomentum*DeltaTotalMomentum))/(2*DeltaTotalMomentum*TotalMomentum);
G4double costhetasc = (Psquare+(finalMomentum*finalMomentum)-
(DeltaTotalMomentum*DeltaTotalMomentum))/(2*finalMomentum*TotalMomentum);
if (costheta < -1.) costheta = -1.;
if (costheta > +1.) costheta = +1.;
// direction of the delta electron
G4double phi = twopi * G4UniformRand();
G4double sintheta = sqrt((1.+costheta)*(1.-costheta));
G4double dirx = sintheta * cos(phi), diry = sintheta * sin(phi), dirz = costheta;
G4ThreeVector DeltaDirection(dirx,diry,dirz);
DeltaDirection.rotateUz(ParticleDirection);
// finalKineticEnergy and finalMomentum defined above
// because needed for costheta computation
G4double finalPx = (TotalMomentum*ParticleDirection.x()
- DeltaTotalMomentum*DeltaDirection.x())/finalMomentum;
G4double finalPy = (TotalMomentum*ParticleDirection.y()
- DeltaTotalMomentum*DeltaDirection.y())/finalMomentum;
G4double finalPz = (TotalMomentum*ParticleDirection.z()
- DeltaTotalMomentum*DeltaDirection.z())/finalMomentum;
G4double momtot = sqrt(finalPx*finalPx + finalPy*finalPy + finalPz*finalPz);
if(momtot-1. > 1e-6){
finalPx /= momtot; finalPy /= momtot; finalPz /= momtot;
}
// Create lists of pointers to DynamicParticles (photons and electrons)
G4ParticleVector photvec;
G4int photInd = 0;
G4ParticleVector elecvec;
G4int elecInd = 0;
// create G4DynamicParticle object for delta ray
G4DynamicParticle* theDeltaRay = new G4DynamicParticle;
theDeltaRay->SetKineticEnergy( DeltaKineticEnergy );
theDeltaRay->SetMomentumDirection(DeltaDirection.x(),
DeltaDirection.y(),
DeltaDirection.z());
theDeltaRay->SetDefinition(G4Electron::Electron());
elecvec.insert(theDeltaRay);
// FLUORESCENCE
// load the transition probability table for the element
// theTable[i][j][k]
// i = subshell, j = type of information (second shell, transition energy ,
// transition probability), k = previous vectors.
// Fluorescence data start from element 6
if(AtomIndex > 5){
G4bool ThereAreShells = TRUE;
G4int AtomInd = ZNumVecFluor->index(AtomIndex);
oneAtomTable* oneAtomFluorTrans = (*theFluorTransitionTable)[AtomInd];
while(ThereAreShells == TRUE){
// Select the second transition from another subshell
// fluorPar[0] = SubShell
// fluorPar[1] = Sec SubShell (if there is),
// fluorPar[2] = Transition Probability
// fluorPar[3] = Transition Energy
// the same for augerPar
G4double fluorPar[3] = {0};
// SelectRandomTransition argument is oneAtomTable loop on shells is inside
ThereAreShells = SelectRandomTransition(thePrimaryShell,
fluorPar,
oneAtomFluorTrans);
// Daugther dynamic particle
G4DynamicParticle* newPart;
// Direction of the outcoming particle isotropic selection
G4double newcosTh = 1-2*G4UniformRand();
G4double newsinTh = sqrt(1-newcosTh*newcosTh);
G4double newPhi = twopi*G4UniformRand();
G4double dirx, diry, dirz;
dirz = newcosTh;
diry = newsinTh*cos(newPhi);
dirx = newsinTh*sin(newPhi);
G4ThreeVector newPartDirection(dirx, diry, dirz);
newPartDirection.rotateUz(ParticleDirection);
if(ThereAreShells != FALSE){
thePrimaryShell = (G4int) fluorPar[0];
theEnergyDeposit -= fluorPar[2]*MeV;
if(fluorPar[2] >= CutForLowEnergySecondaryPhotons){
newPart = new G4DynamicParticle (G4Gamma::Gamma(),
newPartDirection,
fluorPar[2]);
photvec.insert(newPart);
}
}
else{
// last shell transition from continuum
G4int k = 0;
while(thePrimaryShell != (*(*theBindEnVec)[0])[k]){
k++;
}
G4double lastTransEnergy = (*(*theBindEnVec)[1])[k];
thePrimaryShell = (G4int) fluorPar[0];
if(fluorPar[2] >= CutForLowEnergySecondaryPhotons){
theEnergyDeposit -= lastTransEnergy*MeV;
newPart = new G4DynamicParticle(G4Gamma::Gamma(),
newPartDirection,
lastTransEnergy);
photvec.insert(newPart);
}
thePrimShVec.insert(thePrimaryShell);
}
}
} //END OF THE CHECK ON ATOMIC NUMBER
G4int numOfElec = elecvec.entries(), numOfPhot = photvec.entries();
G4int numOfDau = numOfElec + numOfPhot;
aParticleChange.SetNumberOfSecondaries(numOfDau);
G4int l = 0;
for(l = 0; l<numOfElec; l++ ){
aParticleChange.AddSecondary(elecvec[l]);
}
for(l = 0; l < numOfPhot; l++) {
aParticleChange.AddSecondary(photvec[l]);
}
photvec.clear();
elecvec.clear();
// fill aParticleChange
// changed energy and momentum of the actual particle
if(theEnergyDeposit < 0){
theEnergyDeposit = 0;
}
aParticleChange.SetMomentumChange(finalPx,finalPy,finalPz);
aParticleChange.SetEnergyChange(finalKineticEnergy);
aParticleChange.SetLocalEnergyDeposit (0.);
aParticleChange.SetLocalEnergyDeposit (theEnergyDeposit);
}
else{
finalKineticEnergy = 0.;
if (charge < 0.) aParticleChange.SetStatusChange(fStopAndKill);
else aParticleChange.SetStatusChange(fStopButAlive);
}
return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyIonisation::Print()
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4int G4LowEnergyIonisation::SelectRandomShell(const G4int AtomIndex, const G4double IncEnergy){
G4double partialSum = 0;
G4double totalSum = ComputeCrossSection(AtomIndex,IncEnergy);
G4double rval = totalSum*G4UniformRand();
const oneAtomTable* oneAtomCS
= (*allAtomShellCrossSec)[ZNumVec->index(AtomIndex)];
for(G4int ind = 0; ind < oneAtomCS->entries(); ind++){
G4double crossSec;
G4Data* EnergyVector = (*(*oneAtomCS)[ind])[0];
G4Data* CrossSecVector = (*(*oneAtomCS)[ind])[1];
if(IncEnergy < (*EnergyVector)[0]){ //First element is the shell number
crossSec = 0;
}
else{
crossSec = util.DataLogInterpolation(IncEnergy, (*EnergyVector), (*CrossSecVector));
}
partialSum += crossSec;
if(rval <= partialSum) return ind;
}
G4Exception("LEIonisation: Cannot select a shell");
return 0;
}
G4Element*
G4LowEnergyIonisation::SelectRandomAtom(const G4DynamicParticle* aDynamicParticle,
G4Material* aMaterial){
// select randomly 1 element within the material
G4double KineticEnergy = aDynamicParticle->GetKineticEnergy();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
if (NumberOfElements == 1) return (*theElementVector)(0);
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
G4double PartialSumSigma = 0. ;
// G4int materialIndex = aMaterial->GetIndex();
G4double rval = G4UniformRand()/MeanFreePath;
for ( G4int i=0 ; i < NumberOfElements ; i++ ){
G4double crossSection;
if (KineticEnergy < LowestKineticEnergy)
crossSection = 0. ;
else {
if (KineticEnergy > HighestKineticEnergy) KineticEnergy = 0.99*HighestKineticEnergy;
G4int AtomIndex = (G4int) (*theElementVector)(i)->GetZ();
crossSection = ComputeCrossSection(AtomIndex, KineticEnergy);
}
PartialSumSigma += theAtomNumDensityVector[i] * crossSection;
if (rval <= PartialSumSigma) return ((*theElementVector)(i));
}
return (*theElementVector)(0);
}
G4bool G4LowEnergyIonisation::SelectRandomTransition(G4int thePrimShell,
G4double* TransParam,
const oneAtomTable* TransitionTable){
G4int SubShellCol = 0, ProbCol = 1, EnergyCol = 2;
//transitionTable means for one atom not for one shell
// too check when the subshell are finished
G4bool ColIsFull = TRUE;
G4int ShellNum = 0;
G4double TotalSum = 0;
G4int maxNumOfShells = TransitionTable->entries()-1;
if(thePrimShell <= (*(*(*TransitionTable)[maxNumOfShells])[0])[0]){
while(thePrimShell != (*(*(*TransitionTable)[ShellNum])[0])[0]){
if(ShellNum == maxNumOfShells){
break;
}
ShellNum++;
}
//TransProb start from 1 because the first element of the list is the primary shall id number
G4int TransProb = 1;
for(TransProb = 1; TransProb < (*(*TransitionTable)[ShellNum])[ProbCol]->length(); TransProb++){
TotalSum += (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
}
G4double PartialProb = G4UniformRand()*TotalSum;
G4double PartSum = 0;
TransProb = 1;
while(TransProb < (*(*TransitionTable)[ShellNum])[ProbCol]->length()){
PartSum += (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
if(PartialProb <= PartSum){
TransParam[0] = (*(*(*TransitionTable)[ShellNum])[SubShellCol])[TransProb];
TransParam[1] = (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
TransParam[2] = (*(*(*TransitionTable)[ShellNum])[EnergyCol])[TransProb];
break;
}
TransProb++;
}
}
else{
ColIsFull = FALSE;
}
return ColIsFull;
}
G4double G4LowEnergyIonisation::EnergySampling(const G4int AtomicNumber,
const G4int ShellIndex,
const G4double KinEn){
// 1) Load Coefficients (I need Z number and the index of the shell)
oneAtomTable* oneAtomCoeffTable = (*theSamplingCoeffTable)[ZNumVec->index(AtomicNumber)];
oneShellTable* oneShellCoeffTable = (*oneAtomCoeffTable)[ShellIndex];
G4double BindingEn = (*(*(*theBindingEnergyTable)[AtomicNumber-1])[1])[ShellIndex];
// 2) Interpolate coefficients (I need the incoming electron kinetic energy)
const G4int CoeffNumber = oneShellCoeffTable->entries();
const G4Data* energyVec = (*oneShellCoeffTable)[0];
const G4int LastPar = energyVec->length()-1;
G4Data Parms;
for(G4int ind = 1; ind < CoeffNumber-1; ind++){
const G4Data* oneCoeffVec = (*oneShellCoeffTable)[ind];
if(KinEn < (*energyVec)[0]){
Parms.insert((*oneCoeffVec)[0]);
}
else if(KinEn > (*energyVec)[LastPar]){
Parms.insert((*oneCoeffVec)[LastPar]);
}
else{
G4double par = util.DataSemiLogInterpolation(KinEn,(*energyVec),(*oneCoeffVec));
Parms.insert(par);
}
}
// cut in energy is always the same
Parms.insert((*(*oneShellCoeffTable)[CoeffNumber-1])[0]);
// 2') order of parameters:
// * Parms[0] = par1 LET
// * Parms[1] = par2 LET
// * Parms[2] = par3 LET
// * Parms[3] = par4 LET
// * Parms[4] = par5 LET
// * Parms[5] = par6 LET
// * Parms[6] = par1 HET
// * Parms[7] = max rejection function: g(x)
// * Parms[8] = area1
// * Parms[9] = area2
// * Parms[10] = cut in energy
// 3) Compute partial areas (with functions here the cut is used)
// minimum energy that can take an ejected electron
const G4double minEn = 0.1*eV;
const G4double argmax = 1/(BindingEn+Parms[10]);
const G4double argmin = 1/(minEn+BindingEn);
const G4double area1 = Parms[8];
//Parms[0]*log(argmin/argmax)+Parms[1]*(argmin-argmax)+
//2*Parms[2]*(pow(argmin,2)-pow(argmax,2))+3*Parms[3]*(pow(argmin,3)-pow(argmax,3))+
//4*Parms[4]*(pow(argmin,4)-pow(argmax,4))+5*Parms[5]*(pow(argmin,5)-pow(argmax,5));
const G4double maxEn = (KinEn-BindingEn)/2;
G4double area2;
if(maxEn >= Parms[10]){
area2 = Parms[9];
}
else{
area2 = 0;
}
G4double areaTot = area1+area2;
G4int which;
// 4) Generate a random number .to select the region of work
G4double rand1 = areaTot*G4UniformRand();
// 5) Sampling
G4double sample = 0;
if(rand1 < area1){
// Low energy transfer
G4double rejection = 0;
which =1;
do{
G4double rand2 = G4UniformRand();
G4double Ka = 0;
if(Parms[10] < maxEn){
Ka = (BindingEn + Parms[10])/(minEn+BindingEn);
}
else{
Ka = (BindingEn + maxEn)/(minEn+BindingEn);
}
sample = (minEn + BindingEn)*pow(Ka,rand2)-BindingEn;
G4double arg = sample + BindingEn;
rejection = Parms[0]/arg+Parms[1]/pow(arg,2)+Parms[2]/pow(arg,3)+
Parms[3]/pow(arg,4)+Parms[4]/pow(arg,5)+Parms[5]/pow(arg,6);
rejection /= Parms[7];
}while(rejection < G4UniformRand());
}
else if(area1 < rand1 && rand1 < areaTot){
which = 2;
// High energy transfer
G4double Norm = (1/Parms[10])-(1/maxEn);
G4double rand2 = Norm*G4UniformRand();
sample = 1/((1/Parms[10])-rand2);
}
//cout<<"ShellIndex: "<<ShellIndex<<" ShellId: "<<(*(*(*theBindingEnergyTable)[AtomicNumber-1])[0])[ShellIndex]<<endl;
return sample;
}
@@ -0,0 +1,683 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyPhotoElectric.cc,v 1.16 1999/07/06 15:03:03 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyPhotoElectric physics process --------
// by Michel Maire, April 1996
// **************************************************************
// 12-06-96, Added SelectRandomAtom() method, by M.Maire
// 21-06-96, SetCuts implementation, M.Maire
// 17-09-96, PartialSumSigma(i)
// split of ComputeBindingEnergy, M.Maire
// 08-01-97, crossection table + meanfreepath table, M.Maire
// 13-03-97, adapted for the new physics scheme, M.Maire
// 28-03-97, protection in BuildPhysicsTable, M.Maire
// 04-06-98, in DoIt, secondary production condition: range>min(threshold,safety)
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyPhotoElectric.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4Electron.hh"
typedef RWTPtrOrderedVector<G4DynamicParticle> G4ParticleVector;
// constructor
G4LowEnergyPhotoElectric::G4LowEnergyPhotoElectric(const G4String& processName)
: G4VDiscreteProcess(processName), // initialization
LowestEnergyLimit (250*eV),
HighestEnergyLimit(100*GeV),
theCrossSectionTable(0),
theBindingEnergyTable(0),
theMeanFreePathTable(0),
theFluorTransitionTable(0),
allAtomShellCrossSec(0),
CutForLowEnergySecondaryPhotons(0.),
ZNumVec(0),
ZNumVecFluor(0),
NumbBinTable(200)
{
if (verboseLevel>0) {
G4cout << GetProcessName() << " is created "<< endl;
G4cout << "LowestEnergy: " << LowestEnergyLimit/keV << "keV ";
G4cout << "HighestEnergy: " << HighestEnergyLimit/MeV << "MeV " << endl;
}
}
// destructor
G4LowEnergyPhotoElectric::~G4LowEnergyPhotoElectric()
{
if (theCrossSectionTable) {
// theCrossSectionTable->clearAndDestroy();
delete theCrossSectionTable;
}
if (theBindingEnergyTable) {
theBindingEnergyTable->clearAndDestroy();
delete theBindingEnergyTable;
}
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
// ClearAndDestroy of this tables is called in their destructors
if (theFluorTransitionTable) {
delete theFluorTransitionTable;
}
if (allAtomShellCrossSec) {
delete allAtomShellCrossSec;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
if(ZNumVecFluor){
ZNumVecFluor->clear();
delete ZNumVecFluor;
}
}
// methods.............................................................................
void G4LowEnergyPhotoElectric::SetCutForLowEnSecPhotons(G4double cut){
CutForLowEnergySecondaryPhotons = cut;
}
void G4LowEnergyPhotoElectric::BuildPhysicsTable(const G4ParticleDefinition& PhotonType)
// Build microscopic cross section table and mean free path table
{
BuildZVec();
BuildCrossSectionTable();
BuildShellCrossSectionTable();
BuildMeanFreePathTable();
BuildBindingEnergyTable();
BuildFluorTransitionTable();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyPhotoElectric::BuildCrossSectionTable(){
if (theCrossSectionTable) {
//theCrossSectionTable->clearAndDestroy();
delete theCrossSectionTable;
}
theCrossSectionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomCS = util.BuildFirstLevelTables(AtomInd, dataNum, "phot/pe-cs-");
theCrossSectionTable->insert(oneAtomCS);
}//end for on atoms
}
void G4LowEnergyPhotoElectric::BuildShellCrossSectionTable(){
if (allAtomShellCrossSec) {
delete allAtomShellCrossSec;
}
allAtomShellCrossSec = new allAtomTable();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
oneAtomTable* oneAtomShellCS = util.BuildSecondLevelTables(AtomInd, dataNum, "phot/pe-ss-cs-");
allAtomShellCrossSec->insert(oneAtomShellCS);
}//end for on atoms
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyPhotoElectric::BuildBindingEnergyTable(){
if (theBindingEnergyTable) {
delete theBindingEnergyTable;
}
G4int dataNum = 2;
theBindingEnergyTable = util.BuildSecondLevelTables(0,dataNum,"fluor/binding");
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyPhotoElectric::BuildFluorTransitionTable(){
if (theFluorTransitionTable) {
delete theFluorTransitionTable;
}
theFluorTransitionTable = new allAtomTable();
ZNumVecFluor = new G4Data(*ZNumVec);
G4int dataNum = 3;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
if(AtomInd > 5){
oneAtomTable* oneAtomShellFL = util.BuildSecondLevelTables(AtomInd, dataNum, "fluor/fl-tr-pr-");
theFluorTransitionTable->insert(oneAtomShellFL);
}
else{
ZNumVecFluor->remove(AtomInd);
}
}//end for on atoms
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4LowEnergyPhotoElectric::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
G4double G4LowEnergyPhotoElectric::ComputeCrossSection(const G4double AtomIndex,
const G4double IncEnergy){
// calculates the microscopic cross section from subshell cross sections
//(it is called for elements , AtomicNumber = Z )
G4double TotalCrossSection(0.);
const oneAtomTable* oneAtomCS
= (*allAtomShellCrossSec)[ZNumVec->index(AtomIndex)];
for(G4int ind = 0; ind < oneAtomCS->entries(); ind++){
G4double crossSec = 0;
G4Data* EnergyVector = (*(*oneAtomCS)[ind])[0];
G4Data* CrossSecVector = (*(*oneAtomCS)[ind])[1];
if(IncEnergy < (*EnergyVector)[1]){ // First element is the shell number
crossSec = 0;
}
else{
crossSec = util.DataLogInterpolation(IncEnergy, (*EnergyVector), (*CrossSecVector));
}
TotalCrossSection += crossSec;
}
return TotalCrossSection ;
}
void G4LowEnergyPhotoElectric::BuildMeanFreePathTable(){
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable; }
// material
G4double NumbOfMaterials = G4Material::GetNumberOfMaterials();
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
G4Material* material;
// MeanFreePath
G4double LowEdgeEnergy, Value;
theMeanFreePathTable = new G4PhysicsTable(NumbOfMaterials);
G4PhysicsLogVector* ptrVector;
for ( G4int J = 0 ; J < NumbOfMaterials; J++ ) { // For each material
//create physics vector then fill it ....
// WARNING!!! below 50 ev cross section lower limit depend on the element
ptrVector = new G4PhysicsLogVector(LowestEnergyLimit, HighestEnergyLimit, NumbBinTable);
material = (*theMaterialTable)(J);
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
for ( G4int i = 0 ; i < NumbBinTable ; i++ ){
//For each energy
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy(i);
const G4double BigPath= DBL_MAX;
G4double SIGMA = 0 ;
for ( G4int k=0 ; k < material->GetNumberOfElements() ; k++ ){
// For each element
G4int AtomIndex = (G4int) (*theElementVector)(k)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(LowEdgeEnergy, (*(*oneAtomCS)[0]), (*(*oneAtomCS)[1]))*barn;
//DataLogInterpolation(LowEdgeEnergy, tableIndex, theCrossSectionTable)*barn;
SIGMA += theAtomNumDensityVector[k]*interCrsSec;
}
Value = SIGMA<=0.0 ? BigPath : 1./SIGMA ;
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector ) ;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4VParticleChange* G4LowEnergyPhotoElectric::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep){
// incoming particle initialization
aParticleChange.Initialize(aTrack);
G4Material* aMaterial = aTrack.GetMaterial();
const G4DynamicParticle* aDynamicPhoton = aTrack.GetDynamicParticle();
const G4double PhotonEnergy = aDynamicPhoton->GetKineticEnergy();
if(PhotonEnergy <= LowestEnergyLimit){
aParticleChange.SetStatusChange(fStopAndKill);
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit(PhotonEnergy);
return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
}
const G4ParticleMomentum PhotonDirection = aDynamicPhoton->GetMomentumDirection();
// select randomly one element constituing the material.
G4Element* anElement = SelectRandomAtom(aDynamicPhoton, aMaterial);
// PAY ATTENTION TO THE MEANING OF THIS NUMBER
G4int AtomNum = (G4int) anElement->GetZ();
// Select the subshell WARNING!!!!
G4int subShellIndex = SelectRandomShell(AtomNum, PhotonEnergy);
G4FirstLevel* theBindEnVec = (*theBindingEnergyTable)[AtomNum-1];
G4int thePrimaryShell = (G4int) (*(*theBindEnVec)[0])[subShellIndex];
G4double BindingEn = (*(*theBindEnVec)[1])[subShellIndex];
if(thePrimShVec.length() != 0){
thePrimShVec.clear();
}
thePrimShVec.insert(thePrimaryShell);
// Create lists of pointers to DynamicParticles (photons and electrons)
G4ParticleVector photvec;
G4int photInd = 0;
G4ParticleVector elecvec;
G4int elecInd = 0;
// primary outcoming electron
G4double ElecKineEnergy = (PhotonEnergy - BindingEn)*MeV;
G4double theEnergyDeposit = (PhotonEnergy - ElecKineEnergy)*MeV;
if (G4EnergyLossTables::GetRange(G4Electron::Electron(),ElecKineEnergy,aMaterial)
>= min(G4Electron::GetCuts(), aStep.GetPostStepPoint()->GetSafety()) ){
// the electron is created in the direction of the incident photon ...
G4DynamicParticle* aElectron = new G4DynamicParticle (G4Electron::Electron(),
PhotonDirection, ElecKineEnergy) ;
elecvec.append(aElectron);
// load the transition probability table for the element
// theTable[i][j][k]
// i = subshell, j = type of information (second shell, transition energy ,
// transition probability), k = previous vectors.
if(AtomNum > 5){
G4bool ThereAreShells = TRUE;
G4int AtomInd = ZNumVecFluor->index(AtomNum);
oneAtomTable* oneAtomFluorTrans = (*theFluorTransitionTable)[AtomInd];
while(ThereAreShells == TRUE){
// Select the second transition from another subshell
// fluorPar[0] = SubShell
// fluorPar[1] = Sec SubShell (if there is),
// fluorPar[2] = Transition Probability
// the same for augerPar
G4double fluorPar[3] = {0};
ThereAreShells = SelectRandomTransition(thePrimaryShell,
fluorPar,
oneAtomFluorTrans);
// Daugther dynamic particle
G4DynamicParticle* newPart;
// Direction of the outcoming particle isotropic selection
G4double newcosTh = 1-2*G4UniformRand();
G4double newsinTh = sqrt(1-newcosTh*newcosTh);
G4double newPhi = twopi*G4UniformRand();
G4double dirx, diry, dirz;
dirz = newcosTh;
diry = newsinTh*cos(newPhi);
dirx = newsinTh*sin(newPhi);
G4ThreeVector newPartDirection(dirx, diry, dirz);
newPartDirection.rotateUz(PhotonDirection);
if(ThereAreShells != FALSE){
thePrimaryShell = (G4int) fluorPar[0];
if(fluorPar[2] >= CutForLowEnergySecondaryPhotons){
theEnergyDeposit -= fluorPar[2]*MeV;
newPart = new G4DynamicParticle (G4Gamma::Gamma(),
newPartDirection,
fluorPar[2]) ;
photvec.append(newPart);
}
}
else{
G4int k = 0;
while(thePrimaryShell != (*(*theBindEnVec)[0])[k]) k++;
G4double lastTransEnergy = (*(*theBindEnVec)[1])[k];
thePrimaryShell = (G4int) fluorPar[0];
if(fluorPar[2] >= CutForLowEnergySecondaryPhotons){
theEnergyDeposit -= lastTransEnergy*MeV;
newPart = new G4DynamicParticle (G4Gamma::Gamma(),
newPartDirection,
lastTransEnergy) ;
photvec.append(newPart);
}
}
thePrimShVec.insert(thePrimaryShell);
}
} //END OF THE CHECK ON ATOMIC NUMBER
G4int numOfElec = elecvec.entries(), numOfPhot = photvec.entries();
G4int numOfDau = numOfElec + numOfPhot;
aParticleChange.SetNumberOfSecondaries(numOfDau);
G4int l = 0;
for( l = 0; l<numOfElec; l++ ){
aParticleChange.AddSecondary(elecvec[l]);
}
for(l = 0; l < numOfPhot; l++) {
aParticleChange.AddSecondary(photvec[l]);
}
photvec.clear();
elecvec.clear();
if(theEnergyDeposit < 0){
theEnergyDeposit = 0;
}
} // END OF CUTS
else{
ElecKineEnergy = 0. ;
aParticleChange.SetNumberOfSecondaries(0) ;
}
// Kill the incident photon
aParticleChange.SetMomentumChange( 0., 0., 0. );
aParticleChange.SetEnergyChange( 0. );
if(theEnergyDeposit < 0){
theEnergyDeposit = 0;
}
aParticleChange.SetLocalEnergyDeposit(theEnergyDeposit) ;
aParticleChange.SetStatusChange( fStopAndKill ) ;
#ifdef G4VERBOSE
if(verboseLevel > 15){
G4cout<<"LE PhotoElectric PostStepDoIt"<<endl;
}
#endif
// Reset NbOfInteractionLengthLeft and return aParticleChange
return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep );
}
G4int G4LowEnergyPhotoElectric::SelectRandomShell(const G4int AtomIndex, const G4double IncEnergy){
G4double partialSum = 0;
G4double totalSum = ComputeCrossSection(AtomIndex,IncEnergy);
G4double rval = totalSum*G4UniformRand();
const oneAtomTable* oneAtomCS
= (*allAtomShellCrossSec)[ZNumVec->index(AtomIndex)];
for(G4int ind = 0; ind < oneAtomCS->entries(); ind++){
G4double crossSec;
G4Data* EnergyVector = (*(*oneAtomCS)[ind])[0];
G4Data* CrossSecVector = (*(*oneAtomCS)[ind])[1];
if(IncEnergy < (*EnergyVector)[0]){ //First element is the shell number
crossSec = 0;
}
else{
crossSec = util.DataLogInterpolation(IncEnergy, (*EnergyVector), (*CrossSecVector));
}
partialSum += crossSec;
if(rval <= partialSum) return ind;
}
G4Exception("LEPhotoElectric: Cannot select a shell");
return 0;
}
G4Element*
G4LowEnergyPhotoElectric::SelectRandomAtom(const G4DynamicParticle* aDynamicPhoton, G4Material* aMaterial){
// select randomly 1 element within the material
G4double GammaEnergy = aDynamicPhoton->GetKineticEnergy();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
if (NumberOfElements == 1) return (*theElementVector)(0);
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
G4double PartialSumSigma = 0. ;
G4double rval = G4UniformRand()/MeanFreePath;
for ( G4int i=0 ; i < NumberOfElements ; i++ ){
G4double crossSection;
if (GammaEnergy < LowestEnergyLimit)
crossSection = 0. ;
else {
if (GammaEnergy > HighestEnergyLimit) GammaEnergy = 0.99*HighestEnergyLimit ;
G4int AtomIndex = (G4int) (*theElementVector)(i)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
crossSection = util.DataLogInterpolation(GammaEnergy, (*(*oneAtomCS)[0]), (*(*oneAtomCS)[1]))*barn;
//DataLogInterpolation(GammaEnergy, tableIndex, theCrossSectionTable)*barn;
}
PartialSumSigma += theAtomNumDensityVector[i] * crossSection;
if (rval <= PartialSumSigma) return ((*theElementVector)(i));
}
// G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
// << "' has no elements" << endl;
return (*theElementVector)(0);
}
G4bool G4LowEnergyPhotoElectric::SelectRandomTransition(G4int thePrimShell,
G4double* TransParam,
const oneAtomTable* TransitionTable){
G4int SubShellCol = 0, ProbCol = 1, EnergyCol = 2;
//transitionTable means for one atom not for one shell
// too check when the subshell are finished
G4bool ColIsFull = TRUE;
G4int ShellNum = 0;
G4double TotalSum = 0;
G4int maxNumOfShells = TransitionTable->entries()-1;
if(thePrimShell <= (*(*(*TransitionTable)[maxNumOfShells])[0])[0]){
while(thePrimShell != (*(*(*TransitionTable)[ShellNum])[0])[0]){
if(ShellNum == maxNumOfShells){
break;
}
ShellNum++;
}
// if(ShellNum <= maxNumOfShells) {
//TransProb start from 1 because the first element of the list is the primary shall id number
G4int TransProb = 1;
for(TransProb = 1; TransProb < (*(*TransitionTable)[ShellNum])[ProbCol]->length(); TransProb++){
TotalSum += (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
}
G4double PartialProb = G4UniformRand()*TotalSum;
G4double PartSum = 0;
TransProb = 1;
while(TransProb < (*(*TransitionTable)[ShellNum])[ProbCol]->length()){
PartSum += (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
if(PartialProb <= PartSum){
TransParam[0] = (*(*(*TransitionTable)[ShellNum])[SubShellCol])[TransProb];
TransParam[1] = (*(*(*TransitionTable)[ShellNum])[ProbCol])[TransProb];
TransParam[2] = (*(*(*TransitionTable)[ShellNum])[EnergyCol])[TransProb];
break;
}
TransProb++;
}
//if(TransProb == (*(*TransitionTable)[ShellNum])[ProbCol]->length()-1) {
//ColIsFull = FALSE;
//}
//}
//else{
// ColIsFull = FALSE;
//}
}
else{
ColIsFull = FALSE;
}
return ColIsFull;
}
@@ -0,0 +1,366 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyRayleigh.cc,v 1.10 1999/07/06 15:03:04 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyRayleigh physics process --------
// by Michel Maire, April 1996
// **************************************************************
// 28-05-96, DoIt() small change in ElecDirection, by M.Maire
// 10-06-96, simplification in ComputeMicroscopicCrossSection(), by M.Maire
// 21-06-96, SetCuts implementation, M.Maire
// 13-09-96, small changes in DoIt for better efficiency. Thanks to P.Urban
// 06-01-97, crossection table + meanfreepath table, M.Maire
// 05-03-97, new Physics scheme, M.Maire
// 28-03-97, protection in BuildPhysicsTable, M.Maire
// 07-04-98, remove 'tracking cut' of the scattered gamma, MMa
// 04-06-98, in DoIt, secondary production condition: range>min(threshold,safety)
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyRayleigh.hh"
// Collaborating Class Headers
#include "G4EnergyLossTables.hh"
#include "G4Electron.hh"
// constructor
G4LowEnergyRayleigh::G4LowEnergyRayleigh(const G4String& processName)
: G4VDiscreteProcess(processName),
theCrossSectionTable(0),
theMeanFreePathTable(0),
theFormFactorTable(0),
ZNumVec(0),
LowestEnergyLimit (250*eV), // initialization
HighestEnergyLimit(100*GeV),
NumbBinTable(200)
{
if (verboseLevel>0) {
G4cout << GetProcessName() << " is created "<< endl;
G4cout << "LowestEnergy: " << LowestEnergyLimit/keV << "keV ";
G4cout << "HighestEnergy: " << HighestEnergyLimit/TeV << "TeV " << endl;
}
}
// destructor
G4LowEnergyRayleigh::~G4LowEnergyRayleigh()
{
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
if(theFormFactorTable){
delete theFormFactorTable;
}
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy();
delete theMeanFreePathTable;
}
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
}
// methods.............................................................................
void G4LowEnergyRayleigh::BuildPhysicsTable(const G4ParticleDefinition& GammaType){
BuildZVec();
// Build microscopic cross section tables for the Rayleigh process
BuildCrossSectionTable();
// Build mean free path table for the Rayleigh Scattering process
BuildMeanFreePathTable();
// build the scattering function table
BuildFormFactorTable();
}
void G4LowEnergyRayleigh::BuildCrossSectionTable(){
if (theCrossSectionTable) {
delete theCrossSectionTable;
}
theCrossSectionTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomCS = util.BuildFirstLevelTables(AtomInd, dataNum, "rayl/re-cs-");
theCrossSectionTable->insert(oneAtomCS);
}//end for on atoms
}
void G4LowEnergyRayleigh::BuildFormFactorTable(){
if (theFormFactorTable) {
delete theFormFactorTable;
}
theFormFactorTable = new G4SecondLevel();
G4int dataNum = 2;
for(G4int TableInd = 0; TableInd < ZNumVec->entries(); TableInd++){
G4int AtomInd = (G4int) (*ZNumVec)[TableInd];
G4FirstLevel* oneAtomFF = util.BuildFirstLevelTables(AtomInd, dataNum, "rayl/re-ff-");
theFormFactorTable->insert(oneAtomFF);
}//end for on atoms
}
void G4LowEnergyRayleigh::BuildZVec(){
const G4MaterialTable* theMaterialTable=G4Material::GetMaterialTable();
G4int numOfMaterials = theMaterialTable->length();
if(ZNumVec){
ZNumVec->clear();
delete ZNumVec;
}
ZNumVec = new G4Data();
for (G4int J=0 ; J < numOfMaterials; J++){
const G4Material* material= (*theMaterialTable)[J];
const G4ElementVector* theElementVector = material->GetElementVector();
const G4int NumberOfElements = material->GetNumberOfElements() ;
for (G4int iel=0; iel<NumberOfElements; iel++ ){
G4double Zel = (*theElementVector)(iel)->GetZ();
if(ZNumVec->contains(Zel) == FALSE){
ZNumVec->insert(Zel);
}
else{
continue;
}
}
}
}
G4VParticleChange* G4LowEnergyRayleigh::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep){
//
// The scattered gamma energy is sampled according to Form Factors and
// then accepted or rejected based on Rayleigh distribution.
// The random number techniques of Butcher & Messel are used
// (Nuc Phys 20(1960),15). GEANT4 internal units
//
aParticleChange.Initialize(aTrack);
// Dynamic particle quantities
const G4DynamicParticle* aDynamicGamma = aTrack.GetDynamicParticle();
G4double GammaEnergy0 = aDynamicGamma->GetKineticEnergy();
if(GammaEnergy0 <= LowestEnergyLimit){
aParticleChange.SetStatusChange(fStopAndKill);
aParticleChange.SetEnergyChange(0.);
aParticleChange.SetLocalEnergyDeposit(GammaEnergy0);
return G4VDiscreteProcess::PostStepDoIt(aTrack,aStep);
}
G4double E0_m = GammaEnergy0 / electron_mass_c2 ;
G4ParticleMomentum GammaDirection0 = aDynamicGamma->GetMomentumDirection();
// Select randomly one element
G4Material* aMaterial = aTrack.GetMaterial();
const G4int numOfElem = aMaterial->GetNumberOfElements();
G4Element* theElement = SelectRandomAtom(aDynamicGamma, aMaterial);
// sample the energy rate of the scattered gamma
G4double wlGamma = h_Planck*c_light/GammaEnergy0;
G4int elementZ = (G4int) theElement->GetZ();
G4double tableIndex = elementZ - 1;
G4double Theta, DataFormFactor;
G4double cosTheta, greject;
G4double Theta_Half, x, SinThHalf, RandomFormFactor;
G4double sinTheta;
do{
Theta_Half = G4UniformRand()*pi/2;
SinThHalf = sin(Theta_Half);
x = SinThHalf/wlGamma;
const G4FirstLevel* oneAtomFF
= (*theFormFactorTable)[ZNumVec->index(elementZ)];
DataFormFactor = util.DataLogInterpolation(x, (*(*oneAtomFF)[0]),
(*(*oneAtomFF)[1]))/cm;
RandomFormFactor = G4UniformRand()*elementZ;
Theta = Theta_Half*2;
cosTheta = cos(Theta);
sinTheta = sin(Theta);
greject = cosTheta*cosTheta*DataFormFactor;
}while( greject < RandomFormFactor);
// scattered gamma angles. ( Z - axis along the parent gamma)
G4double Phi = twopi * G4UniformRand() ;
G4double dirx = sinTheta*cos(Phi) , diry = sinTheta*sin(Phi) , dirz = cosTheta ;
// update G4VParticleChange for the scattered gamma
G4ThreeVector GammaDirection1(dirx, diry, dirz);
GammaDirection1.rotateUz(GammaDirection0);
aParticleChange.SetEnergyChange(GammaEnergy0);
aParticleChange.SetMomentumChange(GammaDirection1);
aParticleChange.SetNumberOfSecondaries(0);
#ifdef G4VERBOSE
if(verboseLevel > 15){
G4cout<<"LE Rayleigh PostStepDoIt"<<endl;
}
#endif
return G4VDiscreteProcess::PostStepDoIt( aTrack, aStep);
}
void G4LowEnergyRayleigh::BuildMeanFreePathTable(){
if (theMeanFreePathTable) {
theMeanFreePathTable->clearAndDestroy(); delete theMeanFreePathTable; }
// material
G4double NumbOfMaterials = G4Material::GetNumberOfMaterials();
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable() ;
G4Material* material;
// MeanFreePath
G4double LowEdgeEnergy, Value;
theMeanFreePathTable = new G4PhysicsTable(NumbOfMaterials);
G4PhysicsLogVector* ptrVector;
for ( G4int J = 0 ; J < NumbOfMaterials; J++ ) { // For each material
//create physics vector then fill it ....
ptrVector = new G4PhysicsLogVector(LowestEnergyLimit, HighestEnergyLimit, NumbBinTable);
material = (*theMaterialTable)(J);
const G4ElementVector* theElementVector = material->GetElementVector();
const G4double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
for ( G4int i = 0 ; i < NumbBinTable ; i++ ){
//For each energy
LowEdgeEnergy = ptrVector->GetLowEdgeEnergy(i);
const G4double BigPath= DBL_MAX;
G4double SIGMA = 0 ;
for ( G4int k=0 ; k < material->GetNumberOfElements() ; k++ ){
// For each element
G4double AtomIndex = (*theElementVector)(k)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
G4double interCrsSec = util.DataLogInterpolation(LowEdgeEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
SIGMA += theAtomNumDensityVector[k]*interCrsSec;
}
Value = SIGMA<=0.0 ? BigPath : 1./SIGMA ;
ptrVector->PutValue( i , Value ) ;
}
theMeanFreePathTable->insertAt( J , ptrVector ) ;
}
}
G4Element* G4LowEnergyRayleigh::SelectRandomAtom(const G4DynamicParticle* aDynamicGamma,
G4Material* aMaterial) {
// select randomly 1 element within the material
G4double GammaEnergy = aDynamicGamma->GetKineticEnergy();
const G4int NumberOfElements = aMaterial->GetNumberOfElements();
const G4ElementVector* theElementVector = aMaterial->GetElementVector();
if (NumberOfElements == 1) return (*theElementVector)(0);
const G4double* theAtomNumDensityVector = aMaterial->GetAtomicNumDensityVector();
G4double PartialSumSigma = 0.;
G4double rval = G4UniformRand()/MeanFreePath;
for ( G4int i=0 ; i < NumberOfElements ; i++ ){
G4double crossSection;
if (GammaEnergy < LowestEnergyLimit)
crossSection = 0. ;
else {
if (GammaEnergy > HighestEnergyLimit) GammaEnergy = 0.99*HighestEnergyLimit ;
G4double AtomIndex = (*theElementVector)(i)->GetZ();
const G4FirstLevel* oneAtomCS
= (*theCrossSectionTable)[ZNumVec->index(AtomIndex)];
crossSection = util.DataLogInterpolation(GammaEnergy,
(*(*oneAtomCS)[0]),
(*(*oneAtomCS)[1]))*barn;
}
PartialSumSigma += theAtomNumDensityVector[i] * crossSection;
if(rval <= PartialSumSigma) return ((*theElementVector)(i));
}
// G4cout << " WARNING !!! - The Material '"<< aMaterial->GetName()
// << "' has no elements" << endl;
return (*theElementVector)(0);
}
@@ -0,0 +1,212 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LowEnergyUtilities.cc,v 1.1 1999/06/28 15:46:05 aforti Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// --------------------------------------------------------------
// GEANT 4 class implementation file
// CERN Geneva Switzerland
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// History: first implementation, based on object model of
// 2nd December 1995, G.Cosmo
// ------------ G4LowEnergyUtilities physics process --------
// by Michel Maire, April 1996
// **************************************************************
// 12-06-96, Added SelectRandomAtom() method, by M.Maire
// 21-06-96, SetCuts implementation, M.Maire
// 17-09-96, PartialSumSigma(i)
// split of ComputeBindingEnergy, M.Maire
// 08-01-97, crossection table + meanfreepath table, M.Maire
// 13-03-97, adapted for the new physics scheme, M.Maire
// 28-03-97, protection in BuildPhysicsTable, M.Maire
// 04-06-98, in DoIt, secondary production condition: range>min(threshold,safety)
// --------------------------------------------------------------
// This Class Header
#include "G4LowEnergyUtilities.hh"
// Collaborating Class Headers
#include "G4Element.hh"
#include "G4DynamicParticle.hh"
#include "G4Material.hh"
#include "CLHEP/String/Strings.h"
#include <fstream.h>
G4LowEnergyUtilities::G4LowEnergyUtilities()
{}
G4LowEnergyUtilities::~G4LowEnergyUtilities()
{}
G4SecondLevel* G4LowEnergyUtilities::BuildSecondLevelTables(const G4int TableInd,
const G4int ParNum,
const char* prename){
HepString name, prenameStr(prename);
if(TableInd != 0){
HepString Znum(TableInd);
name = prenameStr + Znum + ".dat";
}
else{
name = prenameStr+ ".dat";
}
char* path = getenv("G4LEDATA");
if(!path){
HepString excep = "Error!!! G4LEDATA (Low Energy Electromagnetic processes data directory) environment variable not set";
G4Exception(excep);
}
HepString path_string(path);
HepString dir_file = path_string + "/" + name;
ifstream file(dir_file);
filebuf* lsdp = file.rdbuf();
if(!lsdp->is_open()){
HepString excep = "Error!!!! data file: " + dir_file + " NOT found";
G4Exception(excep);
}
oneAtomTable* oneAtomPar = new oneAtomTable();
oneShellTable* oneShellPar = new oneShellTable();
for(G4int j = 0; j < ParNum; j++){
oneShellPar->insertAt(j,new G4Data());
}
G4double a = 0;
G4int k = 1, s = 0;
do{
file>>a;
if(a == -1){
if(s == 0){
oneAtomPar->insert(oneShellPar);
oneShellPar = new oneShellTable();
for(G4int j = 0; j < ParNum; j++){
oneShellPar->insertAt(j,new G4Data());
}
}
s++;
if(s == ParNum){
s = 0;
}
}
else if(a == -2){
delete oneShellPar;
}
else{
if(k%ParNum != 0){
(*oneShellPar)[k-1]->insert(a);
k++;
}
else if(k%ParNum == 0){
(*oneShellPar)[k-1]->insert(a);
k = 1;
}
}
}while(a != -2); //end for on file
file.close();
return oneAtomPar;
}
G4FirstLevel* G4LowEnergyUtilities::BuildFirstLevelTables(const G4int TableInd,
const G4int ParNum,
const char* prename){
HepString name, prenameStr(prename);
if(TableInd != 0){
HepString Znum(TableInd);
name = prenameStr + Znum + ".dat";
}
else{
name = prenameStr+ ".dat";
}
char* path = getenv("G4LEDATA");
if(!path){
HepString excep = "Error!!! G4LEDATA (Low Energy Electromagnetic processes data directory) environment variable not set";
G4Exception(excep);
}
HepString path_string(path);
HepString dir_file = path_string + "/" + name;
ifstream file(dir_file);
filebuf* lsdp = file.rdbuf();
if(!lsdp->is_open()){
HepString excep = "Error!!!! data file: " + dir_file + " NOT found";
G4Exception(excep);
}
G4FirstLevel* oneAtomPar = new G4FirstLevel();
for(G4int j = 0; j < ParNum; j++){
oneAtomPar->insertAt(j,new G4Data());
}
G4double a = 0;
G4int k = 1;
do{
file>>a;
if(a == -1 || a == -2){
}
else{
if(k%ParNum != 0){
(*oneAtomPar)[k-1]->insert(a);
k++;
}
else if(k%ParNum == 0){
(*oneAtomPar)[k-1]->insert(a);
k = 1;
}
}
}while(a != -2); //end for on file
file.close();
return oneAtomPar;
}
@@ -0,0 +1,45 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4SecondLevel.hh
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 1 Giugno 1999
//
// Modifications:
//
// -------------------------------------------------------------------
#include "G4SecondLevel.hh"
G4SecondLevel::~G4SecondLevel(){
this->clearAndDestroy();
}
G4bool G4SecondLevel::operator == (const G4SecondLevel& input) const{
return( this->entries() == input.entries());
}
G4bool G4SecondLevel::operator < (const G4SecondLevel& input) const{
return(this->entries() < input.entries());
}
@@ -0,0 +1,49 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4ThirdLevel.hh
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 1 Giugno 1999
//
// Modifications:
//
// -------------------------------------------------------------------
#include "G4ThirdLevel.hh"
G4ThirdLevel::~G4ThirdLevel(){
this->clearAndDestroy();
}
G4bool G4ThirdLevel::operator == (const G4ThirdLevel& input) const{
return( this->entries() == input.entries());
}
G4bool G4ThirdLevel::operator < (const G4ThirdLevel& input) const{
return(this->entries() < input.entries());
}
@@ -0,0 +1,134 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4VDataFile
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 2 February 1999
//
// Modifications:
//
// -------------------------------------------------------------------
// This Class Header
#include "G4VDataFile.hh"
// Other Class Headers
// C++ Headers
#include <iostream.h>
#include <fstream.h>
#include <string.h>
// Constructors
G4VDataFile::G4VDataFile(const G4String& dataFile):
_filename(dataFile)
{
}
// Destructor
G4VDataFile::~G4VDataFile()
{
if(buf){
delete [] buf;
}
}
// Member Functions
void G4VDataFile::OpenFile(){
// open the stream
char* path = getenv("G4LEDATA");
if(!path){
G4Exception("G4LEDATA environment variable not set");
}
G4String path_string(path);
G4String dir_file = path_string + "/" + _filename;
_istr.open(dir_file.data(), ios::in | ios::nocreate);
filebuf* lsdp = _istr.rdbuf();
if(!lsdp->is_open()){
G4String excep = "Error!!!! data file: " + dir_file + " NOT found";
G4Exception(excep);
}
}
void G4VDataFile::CloseFile(){
_istr.close();
}
void G4VDataFile::Eof(){
if(_istr.eof()) {
_istr.close();
}
}
streampos G4VDataFile::TellPos(){
return _istr.tellg();
}
G4bool G4VDataFile::IsOpen(){
return TRUE;//_istr.is_open();
}
void G4VDataFile::SeekPos(streampos pos){
_istr.seekg(pos);
}
void G4VDataFile::SetBufferSize(G4int sz){
_bufSize = sz;
buf = new char[_bufSize+1];
}
void G4VDataFile::GetLine(){
_istr.getline(buf, _bufSize);
if(strlen(buf) >= _bufSize){
G4String excep = "Error!!!! G4VDataFile::GetLine() buffer out of boundaries";
G4Exception(excep);
}
}
G4int G4VDataFile::LineLength(){
return strlen(buf);
}
char* G4VDataFile::GetBuf(){
return buf;
}
@@ -0,0 +1,46 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// -------------------------------------------------------------------
// GEANT 4 class file
//
// For information related to this code contact:
// CERN, IT Division, ASD group
// CERN, Geneva, Switzerland
//
// File name: G4VTables
//
// Author: Alessandra Forti (Alessandra.Forti@cern.ch)
//
// Creation date: 2 February 1999
//
// Modifications:
//
// -------------------------------------------------------------------
// This Class Header
#include "G4VTables.hh"
// Constructors
G4VTables::G4VTables()
{
}
// Destructor
G4VTables::~G4VTables()
{
}