Import Geant4 11.3.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2024-06-28 13:08:51 +02:00
parent f7b23877ed
commit e58e650b32
5232 changed files with 239416 additions and 244360 deletions
@@ -0,0 +1,439 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// Author: E.Mendoza
//
// Creation date: May 2024
//
// Modifications:
//
// -------------------------------------------------------------------
//
// NuDEX code (https://doi.org/10.1016/j.nima.2022.167894)
//
#include "G4NuDEXInternalConversion.hh"
//If alpha>0, use that value
G4bool G4NuDEXInternalConversion::SampleInternalConversion(G4double Ene,G4int multipolarity,G4double alpha,G4bool CalculateProducts){
if(theZ<MINZINTABLES){ //then we have no info
if(alpha<0){
Ne=0;
Ng=0;
return false;
}
else{
G4double rand=theRandom4->Uniform(0,alpha+1);
if(rand<alpha){ //then electron conversion
Ne=1;
Ng=0;
Eele[0]=Ene; //which is not correct, but we don't know the binding energy
return true;
}
return false;
}
}
Ne=0;
Ng=0;
if(multipolarity==0){ //maybe it is better to return true ... ?? --> no
//return true;
if(alpha<=0){
return false;
}
//NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
G4bool usegivenalpha=true;
if(NShells==0 || std::abs(multipolarity)>ICC_NMULTIP){return false;}
if(alpha<0){
usegivenalpha=false;
alpha=GetICC(Ene,multipolarity);
}
G4double rand=theRandom4->Uniform(0,alpha+1);
if(rand<alpha){ //then electron conversion
if(!CalculateProducts){return true;}
//Select the orbital:
if(usegivenalpha){rand=rand*GetICC(Ene,multipolarity)/alpha;} //renormalize rand to our alpha
G4double cumul=0;
for(G4int i=1;i<NShells;i++){
cumul+=GetICC(Ene,multipolarity,i);
//std::cout<<Ene<<" "<<multipolarity<<" "<<i<<" "<<GetICC(Ene,multipolarity,i)<<" "<<rand-1<<std::endl;
if(cumul>=rand || multipolarity==0){ //then is this orbital
Ne=1;
Eele[0]=Ene-BindingEnergy[i];
FillElectronHole(i); //now there is a hole there, in the filling procedure we emitt gammas and/or electrons
if(Eele[0]<0){
std::cout<<" For Z = "<<theZ<<" and orbital "<<OrbitalName[i]<<" --> Ene = "<<Ene<<" and BindingEnergy = "<<BindingEnergy[i]<<std::endl;
std::cout<<" Given alpha is "<<alpha<<" ("<<usegivenalpha<<"), rand = "<<rand<<" and tabulated alpha for Ene = "<<Ene<<" and mult = "<<multipolarity<<" is "<<GetICC(Ene,multipolarity)<<" -- cumul = "<<cumul<<std::endl;
for(G4int j=1;j<=NShells;j++){
std::cout<<j<<" "<<GetICC(Ene,multipolarity,j)<<std::endl;
}
Eele[0]=0;
}
return true;
}
}
std::cout<<" ############ Warning in "<<__FILE__<<", line "<<__LINE__<<" ############"<<std::endl;
std::cout<<" Given alpha is "<<alpha<<" and tabulated alpha for Ene = "<<Ene<<" and mult = "<<multipolarity<<" is "<<GetICC(Ene,multipolarity)<<" -- cumul = "<<cumul<<std::endl;
for(G4int i=1;i<=NShells;i++){
std::cout<<i<<" "<<GetICC(Ene,multipolarity,i)<<std::endl;
}
Ne=1;
Eele[0]=Ene-BindingEnergy[NShells-1];
return true;
}
return false;
}
void G4NuDEXInternalConversion::FillElectronHole(G4int i_shell){
//A very simplified version of the process (... and false). It can be done with accuracy with G4AtomicTransitionManager
G4double fluoyield=0;
if(i_shell==1){ //K-shell
//Hubbell et al. (1994) formula for the fluorescence yield:
G4double C0=0.0370,C1=0.03112,C2=5.44e-5,C3=-1.25e-6;
G4double w_fac=std::pow(C0+C1*theZ+C2*theZ*theZ+C3*theZ*theZ*theZ,4);
fluoyield=w_fac/(1.+w_fac);
}
else if(i_shell>=2 && i_shell<=4){ //L-shell
//Hubbell et al. (1994) formula for the fluorescence yield:
if(theZ>=3 && theZ<=36){
fluoyield=1.939e-8*std::pow(theZ,3.8874);
}
else if(theZ>36){
G4double C0=0.17765,C1=0.00298937,C2=8.91297e-5,C3=-2.67184e-7;
G4double w_fac=std::pow(C0+C1*theZ+C2*theZ*theZ+C3*theZ*theZ*theZ,4);
fluoyield=w_fac/(1.+w_fac);
}
}
G4double rand=theRandom4->Uniform(0,1);
if(rand<fluoyield){ //gamma emission
Egam[Ng]=BindingEnergy[i_shell];
Ng++;
}
else{ //electron emission
Eele[Ne]=BindingEnergy[i_shell];
Ne++;
}
}
//If i_shell<0 --> the total alpha
G4double G4NuDEXInternalConversion::GetICC(G4double Ene,G4int multipolarity,G4int i_shell){
if(theZ<MINZINTABLES){ //then we have no info
return 0;
}
if(NShells==0 || std::abs(multipolarity)>ICC_NMULTIP){return 0;}
//-----------------------------------------
//Total:
//The following line does not work, due to interpolation below binding energies:
//if(i_shell<0){i_shell=NShells;}
if(i_shell<0){
G4double result=0;
for(G4int i=1;i<NShells;i++){
result+=GetICC(Ene,multipolarity,i);
}
return result;
}
//-----------------------------------------
if(Ene<BindingEnergy[i_shell]){return 0;}
if(np[i_shell]==0){
std::cout<<" shell "<<i_shell<<" has not been initialized"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
if(i_shell==NShells && Ene<Eg[i_shell][0]){ //then we cannot extrapolate, because of the binding energies of the different shells
G4double total=0;
for(G4int i=1;i<NShells;i++){total+=GetICC(Ene,multipolarity,i);}
return total;
}
if(multipolarity>0){
return Interpolate(Ene,np[i_shell],Eg[i_shell],Icc_E[multipolarity-1][i_shell]);
}
else if(multipolarity<0){
return Interpolate(Ene,np[i_shell],Eg[i_shell],Icc_M[(-multipolarity)-1][i_shell]);
}
return 0;
}
G4NuDEXInternalConversion::G4NuDEXInternalConversion(G4int Z){
theZ=Z;
NShells=0;
for(G4int i=0;i<ICC_MAXNSHELLS;i++){
Eg[i]=0; np[i]=0; BindingEnergy[i]=0;
for(G4int j=0;j<ICC_NMULTIP;j++){
Icc_E[j][i]=0; Icc_M[j][i]=0;
}
}
theRandom4= new G4NuDEXRandom(1234567);
}
G4NuDEXInternalConversion::~G4NuDEXInternalConversion(){
for(G4int i=0;i<ICC_MAXNSHELLS;i++){
if(Eg[i]!=0){delete [] Eg[i];}
for(G4int j=0;j<ICC_NMULTIP;j++){
if(Icc_E[j][i]!=0){delete [] Icc_E[j][i];}
if(Icc_M[j][i]!=0){delete [] Icc_M[j][i];}
}
}
delete theRandom4;
}
void G4NuDEXInternalConversion::PrintICC(std::ostream &out){
char word[1000];
out<<" ######################################################################################################################################### "<<std::endl;
out<<" ICC"<<std::endl;
out<<" Z = "<<theZ<<std::endl;
out<<" NShells = "<<NShells<<std::endl;
out<<" ----------------------------------------------------------------------------------------------------------------------------------------"<<std::endl;
out<<" Total calculated from the sum of the partials:"<<std::endl;
out<<" E_g E1 E2 E3 E4 E5 M1 M2 M3 M4 M5 "<<std::endl;
for(G4int j=0;j<np[NShells];j++){
snprintf(word,1000,"%10.4g",Eg[NShells][j]); out<<word;
for(G4int k=0;k<ICC_NMULTIP;k++){
snprintf(word,1000," %10.4g",Icc_E[k][NShells][j]); out<<word;
}
for(G4int k=0;k<ICC_NMULTIP;k++){
snprintf(word,1000," %10.4g",Icc_M[k][NShells][j]); out<<word;
}
out<<std::endl;
}
out<<" ----------------------------------------------------------------------------------------------------------------------------------------"<<std::endl;
for(G4int i=0;i<NShells;i++){
out<<" ----------------------------------------------------------------------------------------------------------------------------------------"<<std::endl;
out<<" Binding energy = "<<BindingEnergy[i]<<" MeV - OrbitalName = "<<OrbitalName[i]<<" - np = "<<np[i]<<std::endl;
out<<" E_g E1 E2 E3 E4 E5 M1 M2 M3 M4 M5 "<<std::endl;
for(G4int j=0;j<np[i];j++){
snprintf(word,1000,"%10.4g",Eg[i][j]); out<<word;
for(G4int k=0;k<ICC_NMULTIP;k++){
snprintf(word,1000," %10.4g",Icc_E[k][i][j]); out<<word;
}
for(G4int k=0;k<ICC_NMULTIP;k++){
snprintf(word,1000," %10.4g",Icc_M[k][i][j]); out<<word;
}
out<<std::endl;
}
out<<" ----------------------------------------------------------------------------------------------------------------------------------------"<<std::endl;
}
out<<" ########################################################################################################################################## "<<std::endl;
}
void G4NuDEXInternalConversion::Init(const char* fname){
if(theZ<MINZINTABLES){ //then we have no info
return;
}
if(NShells!=0){ //Init only once
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
std::ifstream in(fname);
if(!in.good()){
std::cout<<" ################ Error opening "<<fname<<" ################"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
std::string word;
NShells=1;
while(in>>word){
if(word.c_str()[0]=='Z' && word.c_str()[1]=='='){
if(std::atoi(&(word.c_str()[2]))==theZ){
in>>word>>word;
G4int orbindex;
if(word==std::string("Total")){
in.ignore(1000,'\n');
in.ignore(1000,'\n');
orbindex=0;
}
else{
orbindex=NShells;
in>>word>>word>>BindingEnergy[NShells]>>word;
BindingEnergy[NShells]*=1.e-6; // all in MeV
in.ignore(1000,'\n');
in.ignore(1000,'\n');
}
//--------------------------------------------------------------------------------
size_t sz,sz2;
G4int np_tmp=0;
G4double Eg_tmp[1000],Icc_E_tmp[ICC_NMULTIP][100],Icc_M_tmp[ICC_NMULTIP][100];
while(getline(in,word)){
if(word.size()<100){
np[orbindex]=np_tmp;
Eg[orbindex]=new G4double[np_tmp];
for(G4int j=0;j<np_tmp;j++){
Eg[orbindex][j]=Eg_tmp[j];
}
for(G4int i=0;i<ICC_NMULTIP;i++){
Icc_E[i][orbindex]=new G4double[np_tmp];
Icc_M[i][orbindex]=new G4double[np_tmp];
}
for(G4int i=0;i<ICC_NMULTIP;i++){
for(G4int j=0;j<np_tmp;j++){
Icc_E[i][orbindex][j]=Icc_E_tmp[i][j];
Icc_M[i][orbindex][j]=Icc_M_tmp[i][j];
}
}
if(orbindex!=0){NShells++;}
break;
}
else{
sz=0;
Eg_tmp[np_tmp]=std::stof(word,&sz2);
Eg_tmp[np_tmp]*=1.e-3; //all to MeV
sz+=sz2;
for(G4int i=0;i<ICC_NMULTIP;i++){
Icc_E_tmp[i][np_tmp]=std::stof(word.substr(sz),&sz2); sz+=sz2;
}
for(G4int i=0;i<ICC_NMULTIP;i++){
Icc_M_tmp[i][np_tmp]=std::stof(word.substr(sz),&sz2); sz+=sz2;
}
if((G4int)(std::stof(word.substr(sz),&sz2)+0.01)!=theZ){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
sz+=sz2;
sz2=word.find_first_not_of(' ',sz);
if(np_tmp==0){OrbitalName[orbindex]=word.substr(sz2,word.substr(sz2).size()-1);}
np_tmp++;
}
}
if(orbindex==0){break;}
//--------------------------------------------------------------------------------
}
}
}
if(!in.good()){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
in.close();
MakeTotal();
}
// Total Icc goes to nShell=NShells
void G4NuDEXInternalConversion::MakeTotal(){
if(np[0]==0 || Eg[0]==0){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
//We evaluate it in the same frame as the total given by the data:
BindingEnergy[NShells]=0;
np[NShells]=np[0];
Eg[NShells]=new G4double[np[NShells]];
for(G4int i=0;i<ICC_NMULTIP;i++){
Icc_E[i][NShells]=new G4double[np[NShells]];
Icc_M[i][NShells]=new G4double[np[NShells]];
}
for(G4int k=0;k<np[NShells];k++){
for(G4int j=0;j<ICC_NMULTIP;j++){
Icc_E[j][NShells][k]=0;
Icc_M[j][NShells][k]=0;
}
}
for(G4int k=0;k<np[NShells];k++){
Eg[NShells][k]=Eg[0][k];
for(G4int i=1;i<NShells;i++){
for(G4int j=0;j<ICC_NMULTIP;j++){
Icc_E[j][NShells][k]+=GetICC(Eg[NShells][k],j+1,i);
Icc_M[j][NShells][k]+=GetICC(Eg[NShells][k],-j-1,i);
}
}
}
}
//if val>x[npmax] then ---> return 0
G4double G4NuDEXInternalConversion::Interpolate(G4double val,G4int npoints,G4double* x,G4double* y){
G4int i_interp=-1;
for(G4int i=1;i<npoints;i++){
if(x[i]>=val){i_interp=i-1; break;}
}
if(i_interp<0){return 0;}
/*
//y=a0+a1*x
G4double a1=(y[i_interp+1]-y[i_interp])/(x[i_interp+1]-x[i_interp]);
G4double a0=y[i_interp]-a1*x[i_interp];
return (a0+a1*val);
*/
//It is better a log-log interpolation:
if(y[i_interp+1]<=0 || y[i_interp]<=0 || x[i_interp+1]<=0 || x[i_interp]<=0){
//y=a0+a1*x
G4double a1=(y[i_interp+1]-y[i_interp])/(x[i_interp+1]-x[i_interp]);
G4double a0=y[i_interp]-a1*x[i_interp];
return (a0+a1*val);
}
//log(y)=a0+a1*log(x)
G4double a1=std::log(y[i_interp+1]/y[i_interp])/std::log(x[i_interp+1]/x[i_interp]);
G4double a0=std::log(y[i_interp])-a1*std::log(x[i_interp]);
G4double result=std::exp(a0+a1*std::log(val));
return result;
}
@@ -0,0 +1,400 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// Author: E.Mendoza
//
// Creation date: May 2024
//
// Modifications:
//
// -------------------------------------------------------------------
//
// NuDEX code (https://doi.org/10.1016/j.nima.2022.167894)
//
#include "G4NuDEXRandom.hh"
#include "G4NuDEXLevelDensity.hh"
G4NuDEXLevelDensity::G4NuDEXLevelDensity(G4int aZ,G4int aA,G4int ldtype){
Z_Int=aZ;
A_Int=aA;
LDType=ldtype;
if(LDType<0){LDType=DEFAULTLDTYPE;}
A_mass=A_Int;
if(LDType!=1 && LDType!=2 && LDType!=3){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
HasData=false;
Sn=-1; D0=-1; I0=-1000;
Ed=0;
ainf_ldpar=0; gamma_ldpar=0; dW_ldpar=0; Delta_ldpar=0; T_ldpar=0; E0_ldpar=0; Ex_ldpar=0;
}
G4int G4NuDEXLevelDensity::ReadLDParameters(const char* dirname,const char* inputfname,const char* defaultinputfname){
char fname[100];
if(LDType==1 || LDType==3){ // Back-Shifted-Fermi-Gas model
snprintf(fname,100,"%s/LevelDensities/level-densities-bfmeff.dat",dirname);
}
else{ // Constant Temperature
snprintf(fname,100,"%s/LevelDensities/level-densities-ctmeff.dat",dirname);
}
G4double EL=0,EU=0;
std::ifstream in(fname);
if(!in.good()){
std::cout<<" ######## Error opening file "<<fname<<" ########"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
G4int aZ,aA;
char word[200];
in.ignore(10000,'\n');
//std::cout<<" LDType="<<LDType<<" "<<fname<<" "<<Z_Int<<" "<<A_Int<<std::endl;
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
if(LDType==1 || LDType==3){
in>>word>>I0>>Sn>>D0>>word>>word>>EL>>word>>EU>>dW_ldpar>>gamma_ldpar>>ainf_ldpar>>word>>Delta_ldpar;
Ex_ldpar=0; E0_ldpar=0; T_ldpar=0;
Ed=(EL+EU)/2.;
}
else if(LDType==2){
in>>word>>I0>>Sn>>D0>>word>>word>>EL>>word>>EU>>dW_ldpar>>gamma_ldpar>>ainf_ldpar>>word>>Delta_ldpar>>Ex_ldpar>>E0_ldpar>>T_ldpar;
Ed=(EL+EU)/2.;
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
if(in.good()){
HasData=true;
break;
}
}
in.ignore(10000,'\n');
}
in.close();
//Re-write some parameters if inputfname!=0
if(defaultinputfname!=0){
SearchLDParametersInInputFile(defaultinputfname);
}
if(inputfname!=0){
SearchLDParametersInInputFile(inputfname);
}
if(!HasData){ //no data
G4int check=CalculateLDParameters_BSFG(dirname);
if(check==0){
HasData=true;
if(LDType==2){
LDType=1;
std::cout<<" ##### WARNING: level density model for ZA="<<Z_Int*1000+A_Int<<" changed to Back-Shifted-Fermi-Gas model #####"<<std::endl;
}
}
}
if(HasData){return 0;}
//else, some problem reading ...
return -1;
}
G4int G4NuDEXLevelDensity::CalculateLDParameters_BSFG(const char* dirname){
//Eq. 61 of RIPL-3:
G4double alpha=0.0722396; //MeV^{-1}
G4double beta= 0.195267; //MeV^{-1}
G4double gamma0=0.410289; //MeV^{-1}
G4double delta=0.173015; //MeV
//Delta_ldpar: Eq. 50 of RIPL-3:
G4double n_par=0;
if((Z_Int%2)==1 && ((A_Int-Z_Int)%2)==1){n_par=-1;} //odd-odd (impar-impar)
if((Z_Int%2)==0 && ((A_Int-Z_Int)%2)==0){n_par=1;} //even-even (par-par)
Delta_ldpar=n_par*12/std::sqrt(A_mass)+delta;
//ainf_ldpar: Eq. 52 of RIPL-3:
ainf_ldpar=alpha*A_Int+beta*std::pow(A_mass,2./3.);
//gamma_ldpar: Eq. 53 of RIPL-3:
gamma_ldpar=gamma0/std::pow(A_mass,1./3.);
//dW_ldpar --> from data file
char fname[100];
snprintf(fname,100,"%s/LevelDensities/shellcor-ms.dat",dirname);
std::ifstream in(fname);
if(!in.good()){
std::cout<<" ######## Error opening file "<<fname<<" ########"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
G4int aZ,aA;
char word[200];
in.ignore(10000,'\n');
in.ignore(10000,'\n');
in.ignore(10000,'\n');
in.ignore(10000,'\n');
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
in>>word>>dW_ldpar;
if(in.good()){break;}
}
in.ignore(10000,'\n');
}
if(!in.good()){//no data found
return -1;
}
in.close();
Ex_ldpar=0; E0_ldpar=0; T_ldpar=0;
Ed=0;
return 0;
}
G4int G4NuDEXLevelDensity::SearchLDParametersInInputFile(const char* inputfname){
if(inputfname!=0){
std::ifstream in2(inputfname);
if(!in2.good()){
std::cout<<" ############## Error opening "<<inputfname<<" ##############"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
std::string word_tmp;
while(in2>>word_tmp){
if(word_tmp[0]=='#'){in2.ignore(10000,'\n');}
if(word_tmp==std::string("END")){break;}
if(word_tmp==std::string("LDPARAMETERS")){
in2>>LDType;
if(LDType==1){
in2>>dW_ldpar>>gamma_ldpar>>ainf_ldpar>>Delta_ldpar;
}
else if(LDType==2){
in2>>dW_ldpar>>gamma_ldpar>>ainf_ldpar>>Delta_ldpar>>Ex_ldpar>>E0_ldpar>>T_ldpar;
}
else if(LDType==3){
in2>>ainf_ldpar>>Delta_ldpar;
}
else{
std::cout<<" ############## Error: Unknown LDType="<<LDType<<" in "<<inputfname<<" ##############"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
if(!in2.good()){
std::cout<<" ############## Error reading "<<inputfname<<" ##############"<<std::endl;
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
HasData=true;
break;
}
}
in2.close();
}
return 0;
}
void G4NuDEXLevelDensity::PrintParametersInInputFileFormat(std::ostream &out){
out<<"LDPARAMETERS"<<std::endl;
out<<LDType<<std::endl;
out.precision(15);
if(LDType==1){
out<<dW_ldpar<<" "<<gamma_ldpar<<" "<<ainf_ldpar<<" "<<Delta_ldpar<<std::endl;
}
else if(LDType==2){
out<<dW_ldpar<<" "<<gamma_ldpar<<" "<<ainf_ldpar<<" "<<Delta_ldpar<<" "<<Ex_ldpar<<" "<<E0_ldpar<<" "<<T_ldpar<<std::endl;
}
else if(LDType==3){
out<<ainf_ldpar<<" "<<Delta_ldpar<<std::endl;
}
out<<std::endl;
}
G4double G4NuDEXLevelDensity::GetNucleusTemperature(G4double ExcEnergy){
if(!HasData){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
if(ExcEnergy<Ex_ldpar && LDType==2){
return T_ldpar;
}
G4double Uval=ExcEnergy-Delta_ldpar;
if(Uval<=0){return 0;}
G4double a_ldpar=ainf_ldpar*(1.+dW_ldpar/Uval*(1.-std::exp(-gamma_ldpar*Uval)));
if(LDType==3){
a_ldpar=ainf_ldpar;
}
return std::sqrt(Uval/a_ldpar);
}
//Gilbert-Cameron:
G4double G4NuDEXLevelDensity::GetLevelDensity(G4double ExcEnergy,G4double spin,G4bool ,G4bool TotalLevelDensity){
if(!HasData){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
//If A_Int even/odd --> spinx2 (spin_val*2) should be even/odd
if(((A_Int+(G4int)(spin*2+0.01))%2)!=0 && (TotalLevelDensity==false)){
return 0;
}
G4double Uval=ExcEnergy-Delta_ldpar;
if(Uval<0){Uval=1.e-6;}
//----------------------------------------------------------------
// Back shifted: von Egidy et al., NP A481 (1988) 189
if(LDType==3){
G4double sig2=0.0888*std::pow(A_mass,2./3.)*std::sqrt(ainf_ldpar*Uval);
G4double sig=std::sqrt(sig2);
G4double rho=0.05893*std::exp(2.*std::sqrt(ainf_ldpar*Uval))/sig/std::pow(ainf_ldpar,0.25)/std::pow(Uval,1.25);
G4double xj2=(spin+0.5)*(spin+0.5);
G4double fj=(2.*spin+1.)/2./sig2*std::exp(-xj2/2./sig2);
return 0.5*fj*rho;
}
//----------------------------------------------------------------
//--------------------------------------------------------------------------------
//statistical factor from eq. 39 of RIPL-3 manual, and sigma2 from eqs. 57-60
G4double Uval_Sn=Sn-Delta_ldpar;
G4double a_ldpar=ainf_ldpar*(1.+dW_ldpar/Uval*(1.-std::exp(-gamma_ldpar*Uval)));
G4double a_ldpar_Sn=ainf_ldpar*(1.+dW_ldpar/Uval_Sn*(1.-std::exp(-gamma_ldpar*Uval_Sn)));
G4double sigma2_f=0.01389*std::pow(A_mass,5./3.)/ainf_ldpar*std::sqrt(a_ldpar*Uval);
G4double sigma2_f_Sn=0.01389*std::pow(A_mass,5./3.)/ainf_ldpar*std::sqrt(a_ldpar_Sn*Uval);
G4double sigma2_d=(0.83*std::pow(A_mass,0.26))*(0.83*std::pow(A_mass,0.26));
G4double sigma2;
if(ExcEnergy<=Ed){
sigma2=sigma2_d;//if ExcEnergy<Ed
}
else if(ExcEnergy<=Sn){
sigma2=sigma2_d+(ExcEnergy-Ed)/(Sn-Ed)*(sigma2_f_Sn-sigma2_d);
}
else{
sigma2=sigma2_f;
}
G4double statfactor=1./2.*(2.*spin+1.)/(2.*sigma2)*std::exp(-(spin+1/2.)*(spin+1/2.)/2./sigma2);
if(TotalLevelDensity==true){
statfactor=1;
}
//--------------------------------------------------------------------------------
//CT + BSFG: Gilbert & Cameron, Can.J.Phys. 43 (1965) 1446
if(LDType==2 && ExcEnergy<Ex_ldpar){
G4double totalrho=std::exp((ExcEnergy-E0_ldpar)/T_ldpar)/T_ldpar;
return totalrho*statfactor;
}
//Else: BSFGM (LDType==1 or ExcEnergy>Ex_ldpar)
G4double rhotot_f=1./std::sqrt(2.*sigma2)/12.*std::exp(2.*std::sqrt(a_ldpar*Uval))/std::pow(a_ldpar,1./4.)/std::pow(Uval,5./4.);
G4double rhotot_0=std::exp(1.)*a_ldpar/12./std::sqrt(sigma2)*std::exp(a_ldpar*Uval);
G4double totalrho=1./(1./rhotot_f+1./rhotot_0);
return totalrho*statfactor;
}
G4double G4NuDEXLevelDensity::EstimateInverse(G4double LevDen_iMeV,G4double spin,G4bool parity){
//We assume that rho is a monotonically increasing function
G4double tolerance=0.001; //the result will have this relative tolerance. 0.01 means 1%
G4double xmin=0;
G4double xmax=1;
while(GetLevelDensity(xmax,spin,parity)<LevDen_iMeV){
xmax*=2;
}
while(xmin/xmax<1-tolerance){
G4double x0=(xmin+xmax)/2.;
if(GetLevelDensity(x0,spin,parity)<LevDen_iMeV){
xmin=x0;
}
else{
xmax=x0;
}
}
return (xmin+xmax)/2.;
}
G4double G4NuDEXLevelDensity::Integrate(G4double Emin,G4double Emax,G4double spin,G4bool parity){
G4int nb=1000;
G4double Integral=0,x1,x2,y1,y2;
for(G4int i=0;i<nb;i++){
x1=Emin+(Emax-Emin)*i/(G4double)(nb-1.);
x2=Emin+(Emax-Emin)*(i+1.)/(G4double)(nb-1.);
y1=GetLevelDensity(x1,spin,parity);
y2=GetLevelDensity(x2,spin,parity);
Integral+=(y1+y2)/2.*(x2-x1);
}
return Integral;
}
void G4NuDEXLevelDensity::PrintParameters(std::ostream &out){
out<<" Level density type: "<<LDType<<std::endl;
if(LDType==1){ // Back-Shifted-Fermi-Gas model
out<<" ainf = "<<ainf_ldpar<<" gamma = "<<gamma_ldpar<<" dW = "<<dW_ldpar<<" Delta = "<<Delta_ldpar<<std::endl;
}
else{
out<<" ainf = "<<ainf_ldpar<<" gamma = "<<gamma_ldpar<<" dW = "<<dW_ldpar<<" Delta = "<<Delta_ldpar<<" T = "<<T_ldpar<<" E0 = "<<E0_ldpar<<" Ex = "<<Ex_ldpar<<std::endl;
}
}
@@ -0,0 +1,351 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// GEANT4 source file
//
// File name: G4NuDEXNeutronCaptureModel
//
// Author: E.Mendoza & A.Ribon
//
// Creation date: 29 May 2024
//
// Description: This class (a proxy of the class G4NuDEX) uses
// the NuDEX model to produce gammas and internal
// conversion electrons from neutron capture.
// Whenever NuDEX is not applicable, G4PhotonEvaporation
// is used.
// The implementation of this class follows the code
// of the class G4NeutronRadCapture.
//
// Modifications:
//
// -------------------------------------------------------------------
//
#include "G4NuDEXNeutronCaptureModel.hh"
#include "G4NuDEXStatisticalNucleus.hh"
#include "Randomize.hh"
#include "G4SystemOfUnits.hh"
#include "G4PhysicalConstants.hh"
#include "G4LorentzVector.hh"
#include "G4Gamma.hh"
#include "G4Electron.hh"
#include "G4Positron.hh"
#include "G4Deuteron.hh"
#include "G4Triton.hh"
#include "G4He3.hh"
#include "G4Alpha.hh"
#include "G4NucleiProperties.hh"
#include "G4IonTable.hh"
#include "G4ParticleTable.hh"
#include "G4HadronicParameters.hh"
#include "G4DeexPrecoParameters.hh"
#include "G4NuclearLevelData.hh"
#include "G4PhotonEvaporation.hh"
#include "G4PhysicsModelCatalog.hh"
G4NuDEXNeutronCaptureModel::G4NuDEXNeutronCaptureModel() : G4HadronicInteraction( "nuDEX_neutronCapture" ) {
for ( G4int i = 0; i < G4NUDEX_MAXZA; i++ ) {
theStatisticalNucleus[i] = nullptr;
HasData[i] = 0;
}
BrOption = -1;
BandWidth = 0;
NuDEXLibDirectory = "";
photonEvaporation = nullptr;
auto ch = G4FindDataDir( "G4NUDEXLIBDATA" );
if ( ch == nullptr ) {
G4Exception( "G4NuDEXNeutronCaptureModel()", "had0707", FatalException, "Environment variable G4NUDEXLIBDATA is not defined" );
} else {
NuDEXLibDirectory = G4String(ch);
}
}
void G4NuDEXNeutronCaptureModel::InitialiseModel() {
if ( photonEvaporation != nullptr ) return;
G4DeexPrecoParameters* param = G4NuclearLevelData::GetInstance()->GetParameters();
minExcitation = param->GetMinExcitation();
photonEvaporation = new G4PhotonEvaporation;
photonEvaporation->Initialise();
photonEvaporation->SetICM( true );
secID = G4PhysicsModelCatalog::GetModelID( "model_" + GetModelName() );
lowestEnergyLimit = 10.0*CLHEP::eV;
minExcitation = 0.1*CLHEP::keV;
}
G4NuDEXNeutronCaptureModel::~G4NuDEXNeutronCaptureModel(){
for ( G4int i = 0; i < G4NUDEX_MAXZA; i++ ) {
if ( theStatisticalNucleus[i] ) delete theStatisticalNucleus[i];
}
}
G4HadFinalState* G4NuDEXNeutronCaptureModel::ApplyYourself( const G4HadProjectile &aTrack, G4Nucleus &theNucleus ) {
theParticleChange.Clear();
theParticleChange.SetStatusChange( stopAndKill );
G4int A = theNucleus.GetA_asInt();
G4int Z = theNucleus.GetZ_asInt();
G4double time = aTrack.GetGlobalTime(); // Time in the lab frame
// Create initial state
G4LorentzVector lab4mom( 0.0, 0.0, 0.0, G4NucleiProperties::GetNuclearMass(A, Z) );
lab4mom += aTrack.Get4Momentum();
G4double systemMass = lab4mom.mag();
++A; // Compound nucleus: target nucleus + neutron
G4double compoundMass = G4NucleiProperties::GetNuclearMass(A, Z);
// If the energy available is to small to do anything interesting, gives up
if ( systemMass - compoundMass <= lowestEnergyLimit ) return &theParticleChange;
G4ThreeVector boostFromCMtoLAB = lab4mom.boostVector();
G4double neutronEnergy = aTrack.GetKineticEnergy();
// Try to apply NuDEX
//G4int lspin = 0; // l-spin = 0, 1, 2 --> s-wave, p-wave, d-wave ...
//G4int jspinx2 = -1; // A negative value of jspinx2 means that is sampled according to the 2J+1 rule.
//G4int initialLevel = SelectInitialLevel( Z, A, neutronEnergy, lspin, jspinx2 );
G4int initialLevel = -1; // thermal neutron capture
std::vector< char > pType;
std::vector< G4double > pEnergy, pTime;
G4int npar = GenerateNeutronCaptureCascade( Z, A, neutronEnergy, initialLevel, pType, pEnergy, pTime );
if ( npar > 0 ) { // NuDEX can be applied
G4LorentzVector remainingLab4mom = lab4mom;
G4double latestEmission = time;
// Loop over the EM particles produced by 'GenerateNeutronCaptureCascade' and add them to the
// theParticleChange as secondaries. These particles are produced by NuDEX in the nucleus' rest-frame.
for ( G4int i = 0; i < npar; i++ ) {
G4ParticleDefinition* particleDef = nullptr;
if ( pType.at(i) == 'g' ) {
particleDef = G4Gamma::Definition();
} else if (pType.at(i) == 'e' ) {
particleDef = G4Electron::Definition();
} else if ( pType.at(i) == 'p' ) {
particleDef = G4Positron::Definition();
} else {
G4Exception( "G4NUDEXNeutronCaptureModel::ApplyYourself()", "had0707", FatalException, "Unknown particle type" );
}
G4double phi = G4UniformRand()*twopi;
G4double costheta = 2.0*G4UniformRand() - 1.0;
G4double sintheta = std::sqrt( 1.0 - costheta*costheta );
G4ThreeVector direction( sintheta*std::cos(phi), sintheta*std::sin(phi), costheta );
G4double mass = particleDef->GetPDGMass();
G4double particle3momMod = std::sqrt( pEnergy.at(i) * ( pEnergy.at(i) + 2.0*mass ) );
G4LorentzVector particle4mom( particle3momMod*direction, mass + pEnergy.at(i) ); // In the center-of-mass frame
particle4mom.boost( boostFromCMtoLAB ); // Now in the Lab frame
G4HadSecondary* secondary = new G4HadSecondary( new G4DynamicParticle( particleDef, particle4mom ) );
remainingLab4mom -= particle4mom;
// For simplicity, we neglect below the different frames of time (Lab) and pTime (center-of-mass)
secondary->SetTime( time + pTime.at(i) );
if ( latestEmission < time + pTime.at(i) ) latestEmission = time + pTime.at(i);
secondary->SetCreatorModelID( secID );
theParticleChange.AddSecondary( *secondary );
delete secondary;
}
// Treat now the residual nucleus (which is neglected by NuDEX)
const G4ParticleDefinition* resNuclDef = nullptr;
if ( Z == 1 && A == 2 ) resNuclDef = G4Deuteron::Definition();
else if ( Z == 1 && A == 3 ) resNuclDef = G4Triton::Definition();
else if ( Z == 2 && A == 3 ) resNuclDef = G4He3::Definition();
else if ( Z == 2 && A == 4 ) resNuclDef = G4Alpha::Alpha();
else resNuclDef = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon( Z, A, 0.0, noFloat, 0 );
if ( resNuclDef ) {
// To conserve energy-momentum, remainingLab4mom should be the Lorentz 4-momentum of the residual nucleus.
// Imposing the mass 'compoundMass' to the residual nucleus, and trying to conserve the total energy
// while keeping as low as possible the violation of the 3-momentum; in the case that the total energy
// cannot be conserved, the residual nucleus is produced at rest (in the Lab frame).
G4double resNuclLabEkin = std::max( remainingLab4mom.e() - compoundMass, 0.0 );
G4double resNuclLab3momMod = 0.0;
G4ThreeVector resNuclLabDir( 0.0, 0.0, 0.0 );
if ( resNuclLabEkin > 0.0 ) {
resNuclLab3momMod = std::sqrt( resNuclLabEkin * ( resNuclLabEkin + 2.0*compoundMass ) );
resNuclLabDir = remainingLab4mom.vect().unit();
}
G4LorentzVector resNuclLab4mom( resNuclLab3momMod*resNuclLabDir, resNuclLabEkin + compoundMass );
G4HadSecondary* secondary = new G4HadSecondary( new G4DynamicParticle( resNuclDef, resNuclLab4mom ) );
secondary->SetTime( latestEmission );
secondary->SetCreatorModelID( secID );
theParticleChange.AddSecondary( *secondary );
delete secondary;
}
} else { // NuDEX cannot be applied: use G4PhotonEvaporation
// Code taken from G4NeutronRadCapture
G4Fragment* aFragment = new G4Fragment( A, Z, lab4mom );
G4FragmentVector* fv = photonEvaporation->BreakUpFragment( aFragment );
if ( fv == nullptr ) fv = new G4FragmentVector;
fv->push_back( aFragment );
size_t n = fv->size();
for ( size_t i = 0; i < n; ++i ) {
G4Fragment* f = (*fv)[i];
G4double etot = f->GetMomentum().e();
Z = f->GetZ_asInt();
A = f->GetA_asInt();
const G4ParticleDefinition* theDef = nullptr;
if ( Z == 0 && A == 0 ) { theDef = f->GetParticleDefinition(); }
else if ( Z == 1 && A == 2 ) { theDef = G4Deuteron::Definition(); }
else if ( Z == 1 && A == 3 ) { theDef = G4Triton::Definition(); }
else if ( Z == 2 && A == 3 ) { theDef = G4He3::Definition(); }
else if ( Z == 2 && A == 4 ) { theDef = G4Alpha::Definition(); }
else {
G4double eexc = f->GetExcitationEnergy();
if ( eexc <= minExcitation ) eexc = 0.0;
theDef = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon( Z, A, eexc, noFloat, 0 );
}
G4double ekin = std::max( 0.0, etot - theDef->GetPDGMass() );
G4HadSecondary* news = new G4HadSecondary( new G4DynamicParticle( theDef, f->GetMomentum().vect().unit(), ekin ) );
G4double timeF = f->GetCreationTime();
if ( timeF < 0.0 ) timeF = 0.0;
news->SetTime( time + timeF );
news->SetCreatorModelID( secID );
theParticleChange.AddSecondary( *news );
delete news;
delete f;
}
delete fv;
}
return &theParticleChange;
}
G4int G4NuDEXNeutronCaptureModel::GenerateNeutronCaptureCascade( G4int theZ, G4int theA, G4double NeutronEnergy, G4int InitialLevel,
std::vector< char >& pType, std::vector< G4double >& pEnergy,
std::vector< G4double >& pTime ) {
// Returns the number of emitted particles. Returns -1 if the nucleus is not in the database.
G4int theZA = 1000*theZ + theA;
G4int check = Init( theZA );
if ( check < 0 ) return -1;
G4double Sn, I0;
theStatisticalNucleus[theZA]->GetSnAndI0( Sn, I0 ); Sn *= MeV; // I0 is the spin of the A-1 nucleus in the g.s.
G4double ExcitationEnergy = Sn + (theA-1.0)/(G4double)theA*NeutronEnergy;
G4int nPar = theStatisticalNucleus[theZA]->GenerateCascade( InitialLevel, ExcitationEnergy/MeV, pType, pEnergy, pTime );
for ( G4int i = 0; i < nPar; i++ ) {
pEnergy.at(i) *= MeV;
pTime.at(i) *= s;
}
return nPar;
}
G4int G4NuDEXNeutronCaptureModel::Init( G4int theZA, unsigned int seed1, unsigned int seed2, unsigned int seed3 ) {
if ( HasData[theZA] == -1 ) return -1;
if ( HasData[theZA] == 1 ) return 0;
if ( theStatisticalNucleus[theZA] == 0 ) {
G4int theZ = theZA/1000;
G4int theA = theZA-1000*theZ;
theStatisticalNucleus[theZA] = new G4NuDEXStatisticalNucleus( theZ, theA );
if ( BandWidth != 0 ) theStatisticalNucleus[theZA]->SetBandWidth( BandWidth );
theStatisticalNucleus[theZA]->SetBrOption( BrOption );
if ( seed1 > 0 ) theStatisticalNucleus[theZA]->SetRandom1Seed( seed1 );
if ( seed2 > 0 ) theStatisticalNucleus[theZA]->SetRandom1Seed( seed2 );
if ( seed3 > 0 ) theStatisticalNucleus[theZA]->SetRandom1Seed( seed3 );
G4int check = theStatisticalNucleus[theZA]->Init( NuDEXLibDirectory.c_str() );
if ( check < 0 ) {
HasData[theZA] = -1;
return -1;
} else {
HasData[theZA] = 1;
}
}
return 0;
}
G4int G4NuDEXNeutronCaptureModel::SelectInitialLevel( G4int theCompoundZ, G4int theCompoundA, G4double NeutronEnergy, G4int lspin, G4int jspinx2 ) {
// Initial level for neutron capture. If jspinx2 < 0 it is sampled according to the 2J+1 rule.
// l-spin = 0, 1, 2 --> s-wave, p-wave, d-wave ...
G4int theZ = theCompoundZ;
G4int theA = theCompoundA;
G4int theZA = 1000*theZ + theA;
G4int check = Init( theZA );
if ( check < 0 ) return -1;
G4double Sn, I0;
theStatisticalNucleus[theZA]->GetSnAndI0( Sn, I0 ); Sn *= MeV; // I0 is the spin of the A-1 nucleus in the g.s.
G4double ExcitationEnergy = Sn + (theA-1.0)/(G4double)theA*NeutronEnergy;
if ( lspin < 0 ) lspin = 0;
if ( jspinx2 < 0 ) jspinx2 = SampleJ( theZ, theA, lspin );
G4bool parity = false;
if ( ( I0 >= 0 && (lspin%2) == 0 ) || ( I0 < 0 && (lspin%2) == 1 ) ) parity = true;
G4int InitialLevel = theStatisticalNucleus[theZA]->GetClosestLevel( ExcitationEnergy/MeV, jspinx2, parity );
return InitialLevel;
}
G4int G4NuDEXNeutronCaptureModel ::SampleJ( G4int theCompoundZ, G4int theCompoundA, G4int lspin ) {
// Samples J for this l-spin (l-spin = 0, 1, 2 --> s-wave, p-wave, d-wave ...)
// The probability will be proportional to 2J+1
// Returns Jx2
G4int AllowedJx2[100];
G4int NAllowedJvals = GetAllowedJx2values( theCompoundZ, theCompoundA, lspin, AllowedJx2 );
G4double AllowedJx2CumulProb[100], TotalCumul = 0.0;
for ( G4int i = 0; i < NAllowedJvals; i++ ) {
AllowedJx2CumulProb[i] = AllowedJx2[i] + 1.0;
TotalCumul += AllowedJx2CumulProb[i];
}
for ( G4int i = 0; i < NAllowedJvals; i++ ) {
AllowedJx2CumulProb[i] /= TotalCumul;
if ( i > 0 ) AllowedJx2CumulProb[i] += AllowedJx2CumulProb[i-1];
}
G4double rand = G4UniformRand();
G4int i_result = -1;
for ( G4int i = 0; i < NAllowedJvals; i++ ) {
if ( rand < AllowedJx2CumulProb[i] ) {
i_result = i; break;
}
}
if ( i_result < 0 ) {
G4cerr << " ############ Error in " << __FILE__ << ", line " << __LINE__ << " ############"<< G4endl;
exit(1);
}
G4int jspinx2 = AllowedJx2[i_result];
return jspinx2;
}
G4int G4NuDEXNeutronCaptureModel::GetAllowedJx2values( G4int theCompoundZ, G4int theCompoundA, G4int lspin, G4int* jx2vals ) {
// Provides the allowed jx2 values in neutron capture for a certain l-spin (l-spin = 0, 1, 2 --> s-wave, p-wave, d-wave ...)
G4int theZA = 1000*theCompoundZ + theCompoundA;
G4int check = Init( theZA );
if ( check < 0 ) return -1;
G4double Sn, I0;
theStatisticalNucleus[theZA]->GetSnAndI0( Sn, I0 ); Sn *= MeV; // I0 is the spin of the A-1 nucleus in the g.s.
G4int Ix2 = (G4int)( ( std::fabs(I0) + 0.1 )*2.0 );
G4int Jx2min = std::min( std::abs( Ix2-1-2*lspin ), std::abs( Ix2+1-2*lspin ) );
G4int Jx2max = Ix2 + 1 + 2*lspin;
G4int NAllowedJvals = 0;
for ( G4int Jx2 = Jx2min; Jx2 <= Jx2max; Jx2 += 2 ) {
if ( Jx2 >= 0 ) {
jx2vals[NAllowedJvals] = Jx2;
NAllowedJvals++;
}
}
return NAllowedJvals;
}
@@ -0,0 +1,942 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// Author: E.Mendoza
//
// Creation date: May 2024
//
// Modifications:
//
// -------------------------------------------------------------------
//
// NuDEX code (https://doi.org/10.1016/j.nima.2022.167894)
//
#include "G4NuDEXRandom.hh"
#include "G4NuDEXLevelDensity.hh"
#include "G4NuDEXPSF.hh"
G4NuDEXPSF::G4NuDEXPSF(G4int aZ,G4int aA){
Z_Int=aZ;
A_Int=aA;
nR_E1=0; nR_M1=0; nR_E2=0;
x_E1=0; y_E1=0;
x_M1=0; y_M1=0;
x_E2=0; y_E2=0;
E1_normFac=-1; M1_normFac=-1; E2_normFac=-1;
NormEmin=0; NormEmax=6; //Integral between 0 and 6 MeV
ScaleFactor_E1=1;
ScaleFactor_M1=1;
ScaleFactor_E2=1;
}
G4NuDEXPSF::~G4NuDEXPSF(){
if(x_E1!=0){delete [] x_E1;}
if(y_E1!=0){delete [] y_E1;}
if(x_M1!=0){delete [] x_M1;}
if(y_M1!=0){delete [] y_M1;}
if(x_E2!=0){delete [] x_E2;}
if(y_E2!=0){delete [] y_E2;}
}
//If inputfname!=0 then we take the PSF data from the inputfname instead of the dirname
G4int G4NuDEXPSF::Init(const char* dirname,G4NuDEXLevelDensity* aLD,const char* inputfname,const char* defaultinputfname,G4int PSFflag){
theLD=aLD;
//Three options: very detailed model, if not --> gdr-parameters&errors-exp-MLO.dat (RIPL-3), if not --> theorethical values
char fname[500];
G4bool IsDone=false;
//input:
if(inputfname!=0){
IsDone=TakePSFFromInputFile(inputfname);
if(IsDone){return 0;}
}
//default input:
if(defaultinputfname!=0){
IsDone=TakePSFFromInputFile(defaultinputfname);
if(IsDone){return 0;}
}
//Detailed model
snprintf(fname,500,"%s/PSF/PSF_param.dat",dirname);
IsDone=TakePSFFromDetailedParFile(fname);
if(IsDone){return 0;}
//IAEA - 2019 values:
if(PSFflag==0){
snprintf(fname,500,"%s/PSF/CRP_IAEA_SMLO_E1_v01.dat",dirname);
IsDone=TakePSFFromIAEA01(fname);
if(IsDone){return 0;}
}
else if(PSFflag!=1){
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
//RIPL-MLO values:
snprintf(fname,500,"%s/PSF/gdr-parameters&errors-exp-MLO.dat",dirname);
IsDone=TakePSFFromRIPL01(fname);
if(IsDone){return 0;}
//RIPL-Theorethical values:
snprintf(fname,500,"%s/PSF/gdr-parameters-theor.dat",dirname);
IsDone=TakePSFFromRIPL02(fname);
if(IsDone){return 0;}
//Theorethical values:
// E1 for spherical nucleus:
nR_E1=0;
PSFType_E1[nR_E1]=2;
//G4double a=31.2,b=20.6,c=0.026,d=1.05; //SLO-old (RIPL-2)
//G4double a=27.47,b=22.063,c=0.0277,d=1.222;//SLO (RIPL-3)
G4double a=28.69,b=21.731,c=0.0285,d=1.267;//MLO (RIPL-3)
E_E1[nR_E1]=a*std::pow(A_Int,-1./3.)+b*std::pow(A_Int,-1./6.);
G_E1[nR_E1]=c*std::pow(E_E1[nR_E1],1.9);
s_E1[nR_E1]=120/3.141592*d*(A_Int-Z_Int)*Z_Int/(G4double)A_Int/G_E1[nR_E1];
nR_E1++;
GenerateM1AndE2FromE1();
return 0;
}
void G4NuDEXPSF::GenerateM1AndE2FromE1(){
//M1:
nR_M1=0;
E_M1[nR_M1]=41*std::pow(A_Int,-1./3.);
G_M1[nR_M1]=4;
s_M1[nR_M1]=1;
PSFType_M1[nR_M1]=0;
nR_M1++;
//f(E1)/f(M1) = 0.0588*A**0.878 at +-7 MeV
G4double fE1=GetE1(7,7);
G4double fM1=GetM1(7,7);
s_M1[0]=fE1/0.0588/std::pow(A_Int,0.878)/fM1;
//E2:
nR_E2=0;
E_E2[nR_E2]=63*std::pow(A_Int,-1./3.);
G_E2[nR_E2]=6.11-0.021*A_Int;
s_E2[nR_E2]=0.00014*Z_Int*Z_Int*E_E2[nR_E2]/std::pow(A_Int,1./3)/G_E2[nR_E2];
PSFType_E2[nR_E2]=0;
nR_E2++;
}
G4bool G4NuDEXPSF::TakePSFFromRIPL02(const char* fname){
G4bool result=false;
G4int aA,aZ;
std::ifstream in(fname);
char dum[200];
for(G4int i=0;i<4;i++){in.ignore(10000,'\n');}
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
result=true;
in>>dum>>dum;
nR_E1=2;
in>>E_E1[0]>>G_E1[0]>>E_E1[1]>>G_E1[1];
PSFType_E1[0]=2; PSFType_E1[1]=2; //SMLO
G4double a=28.69,b=21.731,c=0.0285,d=1.267;//MLO
G4double E_E1_0=a*std::pow(A_Int,-1./3.)+b*std::pow(A_Int,-1./6.);
G4double G_E1_0=c*std::pow(E_E1_0,1.9);
G4double s_E1_0=120/3.141592*d*(A_Int-Z_Int)*Z_Int/(G4double)A_Int/G_E1_0;
s_E1[0]=s_E1_0/3.;
s_E1[1]=2.*s_E1_0/3.;
break;
}
in.ignore(10000,'\n');
}
in.close();
if(result){GenerateM1AndE2FromE1();}
return result;
}
G4bool G4NuDEXPSF::TakePSFFromRIPL01(const char* fname){
G4bool result=false;
G4int aA,aZ;
std::ifstream in(fname);
char dum[200];
for(G4int i=0;i<7;i++){in.ignore(10000,'\n');}
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
result=true;
in>>dum>>dum;
nR_E1=0;
in>>E_E1[nR_E1]>>s_E1[nR_E1]>>G_E1[nR_E1];
PSFType_E1[nR_E1]=2; //SMLO
nR_E1++;
//sometimes there is a second resonance:
in>>E_E1[nR_E1]>>dum>>G_E1[nR_E1];
if(dum[0]!='-'){ //there is a second resonance
s_E1[nR_E1]=std::atof(dum);
PSFType_E1[nR_E1]=2;
nR_E1++;
}
break;
}
in.ignore(10000,'\n');
}
in.close();
if(result){GenerateM1AndE2FromE1();}
return result;
}
G4bool G4NuDEXPSF::TakePSFFromIAEA01(const char* fname){
G4bool result=false;
G4int aA,aZ;
char dum[200];
G4double beta=0;
std::ifstream in(fname);
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
result=true;
nR_E1=0;
in>>dum>>dum>>E_E1[nR_E1]>>dum>>dum>>G_E1[nR_E1]>>dum>>dum>>s_E1[nR_E1];
PSFType_E1[nR_E1]=11;
nR_E1++;
in>>dum;
if(std::string(dum)==std::string("beta=")){
in>>beta;
break;
}
else if(std::string(dum)==std::string("Er2")){
in>>dum>>E_E1[nR_E1]>>dum>>dum>>G_E1[nR_E1]>>dum>>dum>>s_E1[nR_E1]>>dum>>beta;
PSFType_E1[nR_E1]=11;
nR_E1++;
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
break;
}
in.ignore(10000,'\n');
}
if(!result){
return result;
}
//---------------------------------------------------
//Now M1 (https://doi.org/10.1140/epja/i2019-12840-1)
nR_M1=0;
//Spin-flip:
PSFType_M1[nR_M1]=0;
E_M1[nR_M1]=18.0*std::pow(A_Int,-1./6.);
G_M1[nR_M1]=4;
s_M1[nR_M1]=0.03*std::pow(A_Int,5./6.);
nR_M1++;
//Scissors-mode:
PSFType_M1[nR_M1]=0;
E_M1[nR_M1]=5.0*std::pow(A_Int,-1./10.);
G_M1[nR_M1]=1.5;
s_M1[nR_M1]=0.02*std::fabs(beta)*std::pow(A_Int,9./10.);
nR_M1++;
//upbend:
PSFType_M1[nR_M1]=21;
E_M1[nR_M1]=0.4035*std::exp(-6.0*std::fabs(beta));
G_M1[nR_M1]=0.8;
s_M1[nR_M1]=0;
nR_M1++;
//---------------------------------------------------
//---------------------------------------------------
//E2 same as in the old RIPL recommendations:
nR_E2=0;
E_E2[nR_E2]=63*std::pow(A_Int,-1./3.);
G_E2[nR_E2]=6.11-0.021*A_Int;
s_E2[nR_E2]=0.00014*Z_Int*Z_Int*E_E2[nR_E2]/std::pow(A_Int,1./3)/G_E2[nR_E2];
PSFType_E2[nR_E2]=0;
nR_E2++;
//---------------------------------------------------
return result;
}
G4bool G4NuDEXPSF::TakePSFFromInputFile(const char* fname){
G4bool result=false;
char word[1000];
std::ifstream in(fname);
while(in>>word){
if(word[0]=='#'){in.ignore(10000,'\n');}
if(std::string(word)==std::string("END")){break;}
if(std::string(word)==std::string("PSF")){
result=true;
in>>nR_E1;
for(G4int i=0;i<nR_E1;i++){
in>>PSFType_E1[i]>>E_E1[i]>>G_E1[i]>>s_E1[i];
if(PSFType_E1[i]==7){in>>p1_E1[i];}
if(PSFType_E1[i]==8){in>>p1_E1[i]>>p2_E1[i];}
if(PSFType_E1[i]==9){in>>p1_E1[i]>>p2_E1[i];}
if(PSFType_E1[i]==10){in>>p1_E1[i]>>p2_E1[i]>>p3_E1[i];}
if(PSFType_E1[i]==40 || PSFType_E1[i]==41){ //only one pointwise function is allowed
if(x_E1!=0){NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");}
in>>np_E1;
x_E1=new G4double[np_E1]; y_E1=new G4double[np_E1];
for(G4int j=0;j<np_E1;j++){in>>x_E1[j]>>y_E1[j];}
in>>E1_normFac;
}
}
in>>nR_M1;
for(G4int i=0;i<nR_M1;i++){
in>>PSFType_M1[i]>>E_M1[i]>>G_M1[i]>>s_M1[i];
if(PSFType_M1[i]==7){in>>p1_M1[i];}
if(PSFType_M1[i]==8){in>>p1_M1[i]>>p2_M1[i];}
if(PSFType_M1[i]==9){in>>p1_M1[i]>>p2_M1[i];}
if(PSFType_M1[i]==10){in>>p1_M1[i]>>p2_M1[i]>>p3_M1[i];}
if(PSFType_M1[i]==40 || PSFType_M1[i]==41){//only one pointwise function is allowed
if(x_M1!=0){NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");}
in>>np_M1;
x_M1=new G4double[np_M1]; y_M1=new G4double[np_M1];
for(G4int j=0;j<np_M1;j++){in>>x_M1[j]>>y_M1[j];}
in>>M1_normFac;
}
}
in>>nR_E2;
for(G4int i=0;i<nR_E2;i++){
in>>PSFType_E2[i]>>E_E2[i]>>G_E2[i]>>s_E2[i];
if(PSFType_E2[i]==7){in>>p1_E2[i];}
if(PSFType_E2[i]==8){in>>p1_E2[i]>>p2_E2[i];}
if(PSFType_E2[i]==9){in>>p1_E2[i]>>p2_E2[i];}
if(PSFType_E2[i]==10){in>>p1_E2[i]>>p2_E2[i]>>p3_E2[i];}
if(PSFType_E2[i]==40 || PSFType_E2[i]==41){//only one pointwise function is allowed
if(x_E2!=0){NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");}
in>>np_E2;
x_E2=new G4double[np_E2]; y_E2=new G4double[np_E2];
for(G4int j=0;j<np_E2;j++){in>>x_E2[j]>>y_E2[j];}
in>>E2_normFac;
}
}
break;
}
}
Renormalize(); // if XX_normFac>0 --> renormalization of the PSF
return result;
}
void G4NuDEXPSF::Renormalize(){
G4int npIntegral=1000;
G4double Integral=0,x_eval,y_eval;
G4double binWidth=(NormEmax-NormEmin)/npIntegral;
//-------------------------------------------------
if(E1_normFac>0){
Integral=0;
for(G4int i=0;i<npIntegral;i++){
x_eval=NormEmin+binWidth*(i+0.5);
y_eval=GetE1(x_eval,NormEmax);
Integral+=y_eval;
}
Integral*=binWidth;
ScaleFactor_E1=E1_normFac/Integral;
}
//-------------------------------------------------
//-------------------------------------------------
if(M1_normFac>0){
Integral=0;
for(G4int i=0;i<npIntegral;i++){
x_eval=NormEmin+binWidth*(i+0.5);
y_eval=GetM1(x_eval,NormEmax);
Integral+=y_eval;
}
Integral*=binWidth;
ScaleFactor_M1=M1_normFac/Integral;
//std::cout<<M1_normFac<<" "<<Integral<<" "<<ScaleFactor_M1<<std::endl; getchar();
}
//-------------------------------------------------
//-------------------------------------------------
if(E2_normFac>0){
Integral=0;
for(G4int i=0;i<npIntegral;i++){
x_eval=NormEmin+binWidth*(i+0.5);
y_eval=GetE2(x_eval,NormEmax);
Integral+=y_eval;
}
Integral*=binWidth;
ScaleFactor_E2=E2_normFac/Integral;
}
//-------------------------------------------------
}
G4bool G4NuDEXPSF::TakePSFFromDetailedParFile(const char* fname){
G4bool result=false;
G4int aA,aZ;
std::ifstream in(fname);
while(in>>aZ>>aA){
if(aZ==Z_Int && aA==A_Int){
result=true;
in>>nR_E1;
for(G4int i=0;i<nR_E1;i++){
in>>PSFType_E1[i]>>E_E1[i]>>G_E1[i]>>s_E1[i];
if(PSFType_E1[i]==7){in>>p1_E1[i];}
if(PSFType_E1[i]==8){in>>p1_E1[i]>>p2_E1[i];}
if(PSFType_E1[i]==9){in>>p1_E1[i]>>p2_E1[i];}
if(PSFType_E1[i]==10){in>>p1_E1[i]>>p2_E1[i]>>p3_E1[i];}
}
in>>nR_M1;
for(G4int i=0;i<nR_M1;i++){
in>>PSFType_M1[i]>>E_M1[i]>>G_M1[i]>>s_M1[i];
if(PSFType_M1[i]==7){in>>p1_M1[i];}
if(PSFType_M1[i]==8){in>>p1_M1[i]>>p2_M1[i];}
if(PSFType_M1[i]==9){in>>p1_M1[i]>>p2_M1[i];}
if(PSFType_M1[i]==10){in>>p1_M1[i]>>p2_M1[i]>>p3_M1[i];}
}
in>>nR_E2;
for(G4int i=0;i<nR_E2;i++){
in>>PSFType_E2[i]>>E_E2[i]>>G_E2[i]>>s_E2[i];
if(PSFType_E2[i]==7){in>>p1_E2[i];}
if(PSFType_E2[i]==8){in>>p1_E2[i]>>p2_E2[i];}
if(PSFType_E2[i]==9){in>>p1_E2[i]>>p2_E2[i];}
if(PSFType_E2[i]==10){in>>p1_E2[i]>>p2_E2[i]>>p3_E2[i];}
}
break;
}
in.ignore(10000,'\n');
}
in.close();
return result;
}
G4double G4NuDEXPSF::GetE1(G4double Eg,G4double ExcitationEnergy){
G4double result=0;
for(G4int i=0;i<nR_E1;i++){
if(PSFType_E1[i]==0){
result+=8.674E-8*SLO(Eg,E_E1[i],G_E1[i],s_E1[i]);
}
else if(PSFType_E1[i]==1){
result+=8.674E-8*EGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==2){
result+=8.674E-8*SMLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==3){
result+=8.674E-8*GLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==4){
result+=8.674E-8*MGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==5){
result+=8.674E-8*KMF(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==6){
result+=8.674E-8*GH(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==7){
result+=8.674E-8*MEGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy,p1_E1[i],p1_E1[i]);
}
else if(PSFType_E1[i]==8){
result+=8.674E-8*MEGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy,p1_E1[i],p2_E1[i]);
}
else if(PSFType_E1[i]==9){
result+=8.674E-8*MEGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy,p1_E1[i],p1_E1[i],p2_E1[i]);
}
else if(PSFType_E1[i]==10){
result+=8.674E-8*MEGLO(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy,p1_E1[i],p2_E1[i],p3_E1[i]);
}
else if(PSFType_E1[i]==11){
result+=8.674E-8*SMLO_v2(Eg,E_E1[i],G_E1[i],s_E1[i],ExcitationEnergy);
}
else if(PSFType_E1[i]==20){
result+=8.674E-8*Gauss(Eg,E_E1[i],G_E1[i],s_E1[i]);
}
else if(PSFType_E1[i]==21){
result+=8.674E-8*Expo(Eg,E_E1[i],G_E1[i]);
}
else if(PSFType_E1[i]==40){
result+=EvaluateFunction(Eg,np_E1,x_E1,y_E1);
}
else if(PSFType_E1[i]==41){
result+=std::pow(10.,EvaluateFunction(Eg,np_E1,x_E1,y_E1));
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
}
if(result!=result){ // nan
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
return result*ScaleFactor_E1;
}
G4double G4NuDEXPSF::GetM1(G4double Eg,G4double ExcitationEnergy){
G4double result=0;
for(G4int i=0;i<nR_M1;i++){
if(PSFType_M1[i]==0){
result+=8.674E-8*SLO(Eg,E_M1[i],G_M1[i],s_M1[i]);
}
else if(PSFType_M1[i]==1){
result+=8.674E-8*EGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==2){
result+=8.674E-8*SMLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==3){
result+=8.674E-8*GLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==4){
result+=8.674E-8*MGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==5){
result+=8.674E-8*KMF(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==6){
result+=8.674E-8*GH(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==7){
result+=8.674E-8*MEGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy,p1_M1[i],p1_M1[i]);
}
else if(PSFType_M1[i]==8){
result+=8.674E-8*MEGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy,p1_M1[i],p2_M1[i]);
}
else if(PSFType_M1[i]==9){
result+=8.674E-8*MEGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy,p1_M1[i],p1_M1[i],p2_M1[i]);
}
else if(PSFType_M1[i]==10){
result+=8.674E-8*MEGLO(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy,p1_M1[i],p2_M1[i],p3_M1[i]);
}
else if(PSFType_M1[i]==11){
result+=8.674E-8*SMLO_v2(Eg,E_M1[i],G_M1[i],s_M1[i],ExcitationEnergy);
}
else if(PSFType_M1[i]==20){
result+=8.674E-8*Gauss(Eg,E_M1[i],G_M1[i],s_M1[i]);
}
else if(PSFType_M1[i]==21){
result+=8.674E-8*Expo(Eg,E_M1[i],G_M1[i]);
}
else if(PSFType_M1[i]==40){
result+=EvaluateFunction(Eg,np_M1,x_M1,y_M1);
}
else if(PSFType_M1[i]==41){
result+=std::pow(10.,EvaluateFunction(Eg,np_M1,x_M1,y_M1));
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
}
if(result!=result){ // nan
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
return result*ScaleFactor_M1;
}
G4double G4NuDEXPSF::GetE2(G4double Eg,G4double ExcitationEnergy){
G4double result=0;
for(G4int i=0;i<nR_E2;i++){
if(PSFType_E2[i]==0){
result+=5.22E-8*SLO(Eg,E_E2[i],G_E2[i],s_E2[i]);
}
else if(PSFType_E2[i]==1){
result+=5.22E-8*EGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==2){
result+=5.22E-8*SMLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==3){
result+=5.22E-8*GLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==4){
result+=5.22E-8*MGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==5){
result+=5.22E-8*KMF(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==6){
result+=5.22E-8*GH(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==7){
result+=5.22E-8*MEGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy,p1_E2[i],p1_E2[i]);
}
else if(PSFType_E2[i]==8){
result+=5.22E-8*MEGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy,p1_E2[i],p2_E2[i]);
}
else if(PSFType_E2[i]==9){
result+=5.22E-8*MEGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy,p1_E2[i],p1_E2[i],p2_E2[i]);
}
else if(PSFType_E2[i]==10){
result+=5.22E-8*MEGLO(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy,p1_E2[i],p2_E2[i],p3_E2[i]);
}
else if(PSFType_E2[i]==11){
result+=5.22E-8*SMLO_v2(Eg,E_E2[i],G_E2[i],s_E2[i],ExcitationEnergy);
}
else if(PSFType_E2[i]==20){
result+=5.22E-8*Gauss(Eg,E_E2[i],G_E2[i],s_E2[i]);
}
else if(PSFType_E2[i]==21){
result+=5.22E-8*Expo(Eg,E_E2[i],G_E2[i]);
}
else if(PSFType_E2[i]==40){
result+=EvaluateFunction(Eg,np_E2,x_E2,y_E2);
}
else if(PSFType_E2[i]==41){
result+=std::pow(10.,EvaluateFunction(Eg,np_E2,x_E2,y_E2));
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
}
if(result!=result){ // nan
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
return result*ScaleFactor_E2;
}
//**********************************************************************************************************
//**********************************************************************************************************
//**********************************************************************************************************
//Defined as in RIPL-3 when possible. Some of them come from other references:
//http://dx.doi.org/10.1103/PhysRevC.88.034317
G4double G4NuDEXPSF::SLO(G4double Eg,G4double Er,G4double Gr,G4double sr){
return sr*Gr*Eg*Gr/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gr*Gr);
}
//Kadmenskij-Markushev-Furman model (KMF) --> not well described in RIPL-3 manual, taken from another document
G4double G4NuDEXPSF::KMF(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double Tf=0;
if(theLD!=0){
Tf=theLD->GetNucleusTemperature(ExcitationEnergy-Eg);
}
G4double Gc=Gr/Er/Er*(Eg*Eg+4*3.141592*3.141592*Tf*Tf);
if(Eg==Er){return 0;}
return 0.7*Er*Gr*sr*Gc/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er));
}
G4double G4NuDEXPSF::EGLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double result=EGLO_GLO_MGLO(Eg,Er,Gr,sr,ExcitationEnergy,0);
return result;
}
G4double G4NuDEXPSF::GLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double result=EGLO_GLO_MGLO(Eg,Er,Gr,sr,ExcitationEnergy,1);
return result;
}
G4double G4NuDEXPSF::MGLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double result=EGLO_GLO_MGLO(Eg,Er,Gr,sr,ExcitationEnergy,2);
return result;
}
//Hybrid model
G4double G4NuDEXPSF::GH(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double Tf=0;
if(theLD!=0){
Tf=theLD->GetNucleusTemperature(ExcitationEnergy-Eg);
}
G4double Gamma_h=0.63*Gr/Eg/Er*(Eg*Eg+4*3.141592*3.141592*Tf*Tf);
return sr*Gr*Eg*Gamma_h/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gr*Gamma_h);
}
G4double G4NuDEXPSF::SMLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double Tf=0;
if(theLD!=0){
Tf=theLD->GetNucleusTemperature(ExcitationEnergy-Eg);
}
G4double Lambda=1/(1.-std::exp(-Eg/Tf));
G4double Gk_Eg=Gr/Er*ExcitationEnergy;
return Lambda*sr*Gr*Eg*Gk_Eg/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gk_Eg*Gk_Eg);
}
G4double G4NuDEXPSF::SMLO_v2(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy){
G4double Tf=0;
if(Eg<ExcitationEnergy){
Tf=std::sqrt((ExcitationEnergy-Eg)/(A_Int/10.));
}
G4double Lambda=1/(1.-std::exp(-Eg/Tf));
G4double sig_trk=60.*(A_Int-Z_Int)*Z_Int/(G4double)A_Int;
G4double Gk_Eg=Gr/Er*(Eg+4*3.141592*3.141592*Tf*Tf/Er);
return Lambda*sig_trk*2./3.141592*sr*Eg*Gk_Eg/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gk_Eg*Gk_Eg);
}
G4double G4NuDEXPSF::Gauss(G4double Eg,G4double Er,G4double sigma,G4double Area){
return Area*(1./(sigma*std::sqrt(2.*3.141592)))*std::exp(-0.5*std::pow((Eg-Er)/sigma,2.));
}
G4double G4NuDEXPSF::Expo(G4double Eg,G4double C,G4double eta){
return C*std::exp(-eta*Eg);
}
G4double G4NuDEXPSF::MEGLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy,G4double k_param1,G4double k_param2,G4double Temp){
G4double /*Ti=0,*/Tf=0;
if(Temp>=0){
//Ti=Temp;
Tf=Temp;
}
else if(theLD!=0){
//Ti=theLD->GetNucleusTemperature(ExcitationEnergy);
Tf=theLD->GetNucleusTemperature(ExcitationEnergy-Eg);
}
G4double Gk_Eg=Gamma_k(Eg,Er,Gr,Tf,k_param1);
//G4double Gk_0=Gamma_k(0,Er,Gr,Ti,k_param2);
G4double Gk_0=Gamma_k(0,Er,Gr,Tf,k_param2); // in most of the references they use just one temperature
return sr*Gr*(Eg*Gk_Eg/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gk_Eg*Gk_Eg)+0.7*Gk_0/Er/Er/Er);
}
//Ti, Tf --> initial/final temperature of the nucleus
//Opt = 0,1,2 --> EGLO, GLO, MGLO
G4double G4NuDEXPSF::EGLO_GLO_MGLO(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double ExcitationEnergy,G4int Opt){
G4double Ti=0,Tf=0;
if(theLD!=0){
Ti=theLD->GetNucleusTemperature(ExcitationEnergy);
Tf=theLD->GetNucleusTemperature(ExcitationEnergy-Eg);
}
//k_param could be modified according to experimental data.
//The following expression is just a general recomendation
//If k_param==1 --> GLO
G4double k_param=1;
if(A_Int>=148){
k_param=1+0.09*(A_Int-148)*(A_Int-148)*std::exp(-0.18*(A_Int-148));
}
G4double result=0;
if(Opt==0){//EGLO
result=FlexibleGLOType(Eg,Er,Gr,sr,Tf,k_param,Ti,k_param);
}
else if(Opt==1){//GLO --> same as EGLO, but k_param=1
result=FlexibleGLOType(Eg,Er,Gr,sr,Tf,1,Ti,1);
}
else if(Opt==2){//MGLO --> same as EGLO, but k_param2=1
result=FlexibleGLOType(Eg,Er,Gr,sr,Tf,k_param,Ti,1);
}
else{
NuDEXException(__FILE__,std::to_string(__LINE__).c_str(),"##### Error in NuDEX #####");
}
return result;
}
G4double G4NuDEXPSF::FlexibleGLOType(G4double Eg,G4double Er,G4double Gr,G4double sr,G4double Temp1,G4double k_param1,G4double /*Temp2*/,G4double k_param2){
G4double Gk_Eg=Gamma_k(Eg,Er,Gr,Temp1,k_param1);
//G4double Gk_0=Gamma_k(0,Er,Gr,Temp2,k_param2);
G4double Gk_0=Gamma_k(0,Er,Gr,Temp1,k_param2); // in most of the references they use just one temperature
return sr*Gr*(Eg*Gk_Eg/((Eg*Eg-Er*Er)*(Eg*Eg-Er*Er)+Eg*Eg*Gk_Eg*Gk_Eg)+0.7*Gk_0/Er/Er/Er);
}
G4double G4NuDEXPSF::Gamma_k(G4double Eg,G4double Er,G4double Gr,G4double Temp,G4double k_param){
G4double eps0_param=4.5;
G4double Chi=1;
if(Er>eps0_param){
Chi=k_param+(1-k_param)*(Eg-eps0_param)/(Er-eps0_param);
}
G4double C_coll=Gr/Er/Er*Chi;
G4double Gamma_k=C_coll*(Eg*Eg+4*3.141592*3.141592*Temp*Temp);
return Gamma_k;
}
//**********************************************************************************************************
//**********************************************************************************************************
//**********************************************************************************************************
void G4NuDEXPSF::PrintPSFParameters(std::ostream &out){
out<<" ###################################################################################### "<<std::endl;
out<<" PSF_PARAMS"<<std::endl;
out<<" E1: nRes = "<<nR_E1<<std::endl;
for(G4int i=0;i<nR_E1;i++){
out<<" "<<PSFType_E1[i]<<" "<<E_E1[i]<<" "<<G_E1[i]<<" "<<s_E1[i]<<std::endl;
if(PSFType_E1[i]==7){out<<" "<<p1_E1[i]<<std::endl;}
if(PSFType_E1[i]==8){out<<" "<<p1_E1[i]<<" "<<p2_E1[i]<<std::endl;}
if(PSFType_E1[i]==9){out<<" "<<p1_E1[i]<<" "<<p2_E1[i]<<std::endl;}
if(PSFType_E1[i]==10){out<<" "<<p1_E1[i]<<" "<<p2_E1[i]<<" "<<p3_E1[i]<<std::endl;}
if(PSFType_E1[i]==40 || PSFType_E1[i]==41){out<<np_E1; for(G4int j=0;j<np_E1;j++){out<<" "<<x_E1[j]<<" "<<y_E1[j];} out<<std::endl;}
}
out<<" M1: nRes = "<<nR_M1<<std::endl;
for(G4int i=0;i<nR_M1;i++){
out<<" "<<PSFType_M1[i]<<" "<<E_M1[i]<<" "<<G_M1[i]<<" "<<s_M1[i]<<std::endl;
if(PSFType_M1[i]==7){out<<" "<<p1_M1[i]<<std::endl;}
if(PSFType_M1[i]==8){out<<" "<<p1_M1[i]<<" "<<p2_M1[i]<<std::endl;}
if(PSFType_M1[i]==9){out<<" "<<p1_M1[i]<<" "<<p2_M1[i]<<std::endl;}
if(PSFType_M1[i]==10){out<<" "<<p1_M1[i]<<" "<<p2_M1[i]<<" "<<p3_M1[i]<<std::endl;}
if(PSFType_M1[i]==40 || PSFType_M1[i]==41){out<<np_M1; for(G4int j=0;j<np_M1;j++){out<<" "<<x_M1[j]<<" "<<y_M1[j];} out<<std::endl;}
}
out<<" E2: nRes = "<<nR_E2<<std::endl;
for(G4int i=0;i<nR_E2;i++){
out<<" "<<PSFType_E2[i]<<" "<<E_E2[i]<<" "<<G_E2[i]<<" "<<s_E2[i]<<std::endl;
if(PSFType_E2[i]==7){out<<" "<<p1_E2[i]<<std::endl;}
if(PSFType_E2[i]==8){out<<" "<<p1_E2[i]<<" "<<p2_E2[i]<<std::endl;}
if(PSFType_E2[i]==9){out<<" "<<p1_E2[i]<<" "<<p2_E2[i]<<std::endl;}
if(PSFType_E2[i]==10){out<<" "<<p1_E2[i]<<" "<<p2_E2[i]<<" "<<p3_E2[i]<<std::endl;}
if(PSFType_E2[i]==40 || PSFType_E2[i]==41){out<<np_E2; for(G4int j=0;j<np_E2;j++){out<<" "<<x_E2[j]<<" "<<y_E2[j];} out<<std::endl;}
}
out<<" ###################################################################################### "<<std::endl;
}
void G4NuDEXPSF::PrintPSFParametersInInputFileFormat(std::ostream &out){
out<<" PSF"<<std::endl;
out.precision(15);
out<<nR_E1<<std::endl;
for(G4int i=0;i<nR_E1;i++){
out<<" "<<PSFType_E1[i]<<" "<<E_E1[i]<<" "<<G_E1[i]<<" "<<s_E1[i];
if(PSFType_E1[i]==7){out<<" "<<p1_E1[i];}
if(PSFType_E1[i]==8){out<<" "<<p1_E1[i]<<" "<<p2_E1[i];}
if(PSFType_E1[i]==9){out<<" "<<p1_E1[i]<<" "<<p2_E1[i];}
if(PSFType_E1[i]==10){out<<" "<<p1_E1[i]<<" "<<p2_E1[i]<<" "<<p3_E1[i];}
if(PSFType_E1[i]==40 || PSFType_E1[i]==41){out<<np_E1; for(G4int j=0;j<np_E1;j++){out<<" "<<x_E1[j]<<" "<<y_E1[j];} }
out<<std::endl;
}
out<<nR_M1<<std::endl;
for(G4int i=0;i<nR_M1;i++){
out<<" "<<PSFType_M1[i]<<" "<<E_M1[i]<<" "<<G_M1[i]<<" "<<s_M1[i];
if(PSFType_M1[i]==7){out<<" "<<p1_M1[i];}
if(PSFType_M1[i]==8){out<<" "<<p1_M1[i]<<" "<<p2_M1[i];}
if(PSFType_M1[i]==9){out<<" "<<p1_M1[i]<<" "<<p2_M1[i];}
if(PSFType_M1[i]==10){out<<" "<<p1_M1[i]<<" "<<p2_M1[i]<<" "<<p3_M1[i];}
if(PSFType_M1[i]==40 || PSFType_M1[i]==41){out<<np_M1; for(G4int j=0;j<np_M1;j++){out<<" "<<x_M1[j]<<" "<<y_M1[j];}}
out<<std::endl;
}
out<<nR_E2<<std::endl;
for(G4int i=0;i<nR_E2;i++){
out<<" "<<PSFType_E2[i]<<" "<<E_E2[i]<<" "<<G_E2[i]<<" "<<s_E2[i];
if(PSFType_E2[i]==7){out<<" "<<p1_E2[i];}
if(PSFType_E2[i]==8){out<<" "<<p1_E2[i]<<" "<<p2_E2[i];}
if(PSFType_E2[i]==9){out<<" "<<p1_E2[i]<<" "<<p2_E2[i];}
if(PSFType_E2[i]==10){out<<" "<<p1_E2[i]<<" "<<p2_E2[i]<<" "<<p3_E2[i];}
if(PSFType_E2[i]==40 || PSFType_E2[i]==41){out<<np_E2; for(G4int j=0;j<np_E2;j++){out<<" "<<x_E2[j]<<" "<<y_E2[j];}}
out<<std::endl;
}
}
G4double G4NuDEXPSF::EvaluateFunction(G4double xval,G4int np,G4double* x,G4double* y){
if(xval<x[0]){return y[0];}
if(xval>x[np-1]){return y[np-1];}
G4double m,b;
G4int i_eval=np-1;
for(G4int i=1;i<np;i++){
if(x[i]>=xval){
i_eval=i;
break;
}
}
m=(y[i_eval]-y[i_eval-1])/(x[i_eval]-x[i_eval-1]);
b=y[i_eval]-m*x[i_eval];
return m*xval+b;
}
@@ -0,0 +1,124 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// -------------------------------------------------------------------
//
// Author: E.Mendoza
//
// Creation date: May 2024
//
// Modifications:
//
// -------------------------------------------------------------------
//
// NuDEX code (https://doi.org/10.1016/j.nima.2022.167894)
//
#include "G4NuDEXRandom.hh"
#if COMPILATIONTYPE == 1
//==============================================================================
G4NuDEXRandom::G4NuDEXRandom(unsigned int seed){
theRandom=new TRandom2(seed);
}
G4NuDEXRandom::~G4NuDEXRandom(){
delete theRandom;
}
void G4NuDEXRandom::SetSeed(unsigned int seed){
theRandom->SetSeed(seed);
}
unsigned int G4NuDEXRandom::GetSeed(){
return theRandom->GetSeed();
}
G4double G4NuDEXRandom::Uniform(G4double Xmin,G4double Xmax){
return theRandom->Uniform(Xmin,Xmax);
}
unsigned int G4NuDEXRandom::Integer(unsigned int IntegerMax){
return theRandom->Integer(IntegerMax);
}
G4double G4NuDEXRandom::Exp(G4double tau){
return theRandom->Exp(tau);
}
G4double G4NuDEXRandom::Gaus(G4double mean,G4double sigma){
return theRandom->Gaus(mean,sigma);
}
G4int G4NuDEXRandom::Poisson(G4double mean){
return theRandom->Poisson(mean);
}
//==============================================================================
void NuDEXException(const char* originOfException, const char* exceptionCode,const char* ){
std::cout<<" ############## Error in "<<originOfException<<", line "<<exceptionCode<<" ##############"<<std::endl; exit(1);
}
//==============================================================================
#elif COMPILATIONTYPE == 2
//==============================================================================
G4NuDEXRandom::G4NuDEXRandom(unsigned int seed){
theEngine=new CLHEP::HepJamesRandom(seed);
theRandFlat=new CLHEP::RandFlat(theEngine);
theRandExponential=new CLHEP::RandExponential(theEngine);
theRandGauss=new CLHEP::RandGauss(theEngine);
theRandPoisson=new CLHEP::RandPoisson(theEngine);
}
G4NuDEXRandom::~G4NuDEXRandom(){
//delete theRandFlat;
//delete theRandExponential;
//delete theRandGauss;
//delete theRandPoisson;
//delete theEngine;
}
void G4NuDEXRandom::SetSeed(unsigned int seed){
theEngine->setSeed(seed);
theRandGauss->setF(false);
}
unsigned int G4NuDEXRandom::GetSeed(){
return (unsigned int)theEngine->getSeed();
}
G4double G4NuDEXRandom::Uniform(G4double Xmin,G4double Xmax){
return theRandFlat->fire(Xmin,Xmax);
}
unsigned int G4NuDEXRandom::Integer(unsigned int IntegerMax){
return (unsigned int)theRandFlat->fireInt(IntegerMax); //bikerful!!!
}
G4double G4NuDEXRandom::Exp(G4double tau){
return theRandExponential->fire(tau);
}
G4double G4NuDEXRandom::Gaus(G4double mean,G4double sigma){
return theRandGauss->fire(mean,sigma);
}
G4long G4NuDEXRandom::Poisson(G4double mean){
return theRandPoisson->fire(mean);
}
//==============================================================================
void NuDEXException(const char* originOfException, const char* exceptionCode,const char* description){
G4Exception(originOfException,exceptionCode,FatalException,description);
}
//==============================================================================
#endif
File diff suppressed because it is too large Load Diff