Files
geant4/source/particles/management/src/G4IonTable.cc
T
2020-12-04 12:30:43 +01:00

2268 lines
62 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4IonTable class implementation
//
// Author: H.Kurashige, 27 June 1998
// --------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <vector>
#include "G4ios.hh"
#include "G4Threading.hh"
#include "G4AutoDelete.hh"
#include "G4IonTable.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4ParticleTable.hh"
#include "G4StateManager.hh"
#include "G4Ions.hh"
#include "G4UImanager.hh"
#include "G4NucleiProperties.hh"
#include "G4HyperNucleiProperties.hh"
#include "G4IsotopeProperty.hh"
#include "G4VIsotopeTable.hh"
#include "G4NuclideTable.hh"
#include "G4MuonicAtom.hh"
#include "G4MuonicAtomHelper.hh"
// It is very important for multithreaded Geant4 to keep only one copy of the
// particle table pointer and the ion table pointer. However, we try to let
// each worker thread hold its own copy of the particle dictionary and the
// ion list. This implementation is equivalent to make the ion table thread
// private. The two shadow ponters are used by each worker thread to copy the
// content from the master thread.
//
G4ThreadLocal G4IonTable::G4IonList* G4IonTable::fIonList = nullptr;
G4ThreadLocal std::vector<G4VIsotopeTable*> *G4IonTable::fIsotopeTableList = nullptr;
G4IonTable::G4IonList* G4IonTable::fIonListShadow = nullptr;
std::vector<G4VIsotopeTable*> *G4IonTable::fIsotopeTableListShadow = nullptr;
namespace lightions
{
static const G4ParticleDefinition* p_proton = nullptr;
static const G4ParticleDefinition* p_deuteron = nullptr;
static const G4ParticleDefinition* p_triton = nullptr;
static const G4ParticleDefinition* p_alpha = nullptr;
static const G4ParticleDefinition* p_He3 = nullptr;
void Init()
{
if ( p_proton != nullptr ) return;
p_proton = G4ParticleTable::GetParticleTable()->FindParticle("proton");
p_deuteron = G4ParticleTable::GetParticleTable()->FindParticle("deuteron");
p_triton = G4ParticleTable::GetParticleTable()->FindParticle("triton");
p_alpha = G4ParticleTable::GetParticleTable()->FindParticle("alpha");
p_He3 = G4ParticleTable::GetParticleTable()->FindParticle("He3");
}
}
namespace antilightions
{
static const G4ParticleDefinition* p_proton = nullptr;
static const G4ParticleDefinition* p_deuteron = nullptr;
static const G4ParticleDefinition* p_triton = nullptr;
static const G4ParticleDefinition* p_alpha = nullptr;
static const G4ParticleDefinition* p_He3 = nullptr;
void Init()
{
if ( p_proton != nullptr ) return;
p_proton = G4ParticleTable::GetParticleTable()->FindParticle("anti_proton");
p_deuteron = G4ParticleTable::GetParticleTable()->FindParticle("anti_deuteron");
p_triton = G4ParticleTable::GetParticleTable()->FindParticle("anti_triton");
p_alpha = G4ParticleTable::GetParticleTable()->FindParticle("anti_alpha");
p_He3 = G4ParticleTable::GetParticleTable()->FindParticle("anti_He3");
}
}
#ifdef G4MULTITHREADED
G4Mutex G4IonTable::ionTableMutex = G4MUTEX_INITIALIZER;
#endif
// --------------------------------------------------------------------
// Constructor
//
G4IonTable::G4IonTable()
{
fIonList = new G4IonList();
// Set up the shadow pointer used by worker threads.
//
if (fIonListShadow == nullptr)
{
fIonListShadow = fIonList;
}
fIsotopeTableList = new std::vector<G4VIsotopeTable*>;
// Set up the shadow pointer used by worker threads.
//
if (fIsotopeTableListShadow == nullptr)
{
fIsotopeTableListShadow = fIsotopeTableList;
}
PrepareNuclideTable();
RegisterIsotopeTable(pNuclideTable);
}
// --------------------------------------------------------------------
// Destructor
//
G4IonTable::~G4IonTable()
{
// delete IsotopeTable if existing
if (fIsotopeTableList != nullptr )
{
for (std::size_t i=0; i<fIsotopeTableList->size(); ++i)
{
G4VIsotopeTable* fIsotopeTable= (*fIsotopeTableList)[i];
if( fIsotopeTable != G4NuclideTable::GetNuclideTable() )
{
delete fIsotopeTable;
}
}
fIsotopeTableList->clear();
delete fIsotopeTableList;
}
fIsotopeTableList = nullptr;
if (fIonList == nullptr) return;
// remove all contents in the Ion List
// No need to delete here because all particles are dynamic objects
fIonList->clear();
delete fIonList;
fIonList = nullptr;
}
// --------------------------------------------------------------------
// GetIonTable
//
G4IonTable* G4IonTable::GetIonTable()
{
return G4ParticleTable::GetParticleTable()->GetIonTable();
}
// --------------------------------------------------------------------
// WorkerG4IonTable
//
// Used by each worker thread to copy the content from the master thread
//
void G4IonTable::WorkerG4IonTable()
{
if( fIonList == nullptr ) { fIonList = new G4IonList(); }
else { fIonList->clear(); }
for (auto it = fIonListShadow->cbegin(); it != fIonListShadow->cend(); ++it )
{
fIonList->insert(*it);
}
// Do not copy Isotope Table to Worker thread
//
if( fIsotopeTableList == nullptr )
{
fIsotopeTableList = new std::vector<G4VIsotopeTable*>;
for (std::size_t i = 0; i < fIsotopeTableListShadow->size(); ++i)
{
fIsotopeTableList->push_back((*fIsotopeTableListShadow)[i]);
}
}
}
// --------------------------------------------------------------------
// InitializeLightIons
//
void G4IonTable::InitializeLightIons()
{
lightions::Init();
antilightions::Init();
}
// --------------------------------------------------------------------
// DestroyWorkerG4IonTable
//
void G4IonTable::DestroyWorkerG4IonTable()
{
// delete IsotopeTable if existing
if (fIsotopeTableList != nullptr )
{
for (std::size_t i=0; i<fIsotopeTableList->size(); ++i)
{
G4VIsotopeTable* fIsotopeTable= (*fIsotopeTableList)[i];
if( fIsotopeTable != G4NuclideTable::GetNuclideTable() )
{
delete fIsotopeTable;
}
}
fIsotopeTableList->clear();
delete fIsotopeTableList;
}
fIsotopeTableList = nullptr;
if (fIonList == nullptr) return;
// remove all contents in the Ion List
// No need to delete here because all particles are dynamic objects
fIonList->clear();
delete fIonList;
fIonList = nullptr;
}
// --------------------------------------------------------------------
// CreateIon
//
G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb)
{
G4ParticleDefinition* ion = nullptr;
// check whether GenericIon has processes
G4ParticleDefinition* genericIon =
G4ParticleTable::GetParticleTable()->GetGenericIon();
G4ProcessManager* pman = nullptr;
if (genericIon!= nullptr) { pman = genericIon->GetProcessManager(); }
if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0)
|| (pman==nullptr))
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::CreateIon() : can not create ion of "
<< " Z =" << Z << " A = " << A
<< " because GenericIon is not ready !!" << G4endl;
}
#endif
G4Exception( "G4IonTable::CreateIon()", "PART105", JustWarning,
"Can not create ions because GenericIon is not ready");
return nullptr;
}
G4double life = 0.0;
G4DecayTable* decayTable = nullptr;
G4bool stable = true;
G4double mu = 0.0;
G4double Eex = 0.0;
G4int lvl = 0;
G4int J = 0;
const G4IsotopeProperty* fProperty = FindIsotope(Z, A, E, flb);
if (fProperty != nullptr )
{
Eex = fProperty->GetEnergy();
lvl = fProperty->GetIsomerLevel();
J = fProperty->GetiSpin();
life = fProperty->GetLifeTime();
mu = fProperty->GetMagneticMoment();
decayTable = fProperty->GetDecayTable();
stable = (life <= 0.) || (decayTable == nullptr);
lvl = fProperty->GetIsomerLevel();
if (lvl <0) lvl=9;
}
else
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4ExceptionDescription ed;
ed << "G4IonTable::CreateIon(): G4IsotopeProperty object is not found for"
<< " Z = " << Z << " A = " << A << " E = " << E/keV << " (keV)";
if(flb!=G4Ions::G4FloatLevelBase::no_Float)
{
ed << " FloatingLevel +" << G4Ions::FloatLevelBaseChar(flb);
}
ed << ".\n"
<< " Physics quantities such as life are not set for this ion.";
G4Exception( "G4IonTable::CreateIon()","PART70105", JustWarning, ed);
}
#endif
// excitation energy
Eex = E;
// lvl is assigned to 9 temporarily
if (Eex>0.0) lvl=9;
}
// Eex = G4NuclideTable::Round(Eex);
if (Eex==0.0) lvl=0;
// ion name
G4String name ="";
/////////////if (lvl<9) name = GetIonName(Z, A, lvl);
if (lvl==0 && flb==G4Ions::G4FloatLevelBase::no_Float)
name = GetIonName(Z, A, lvl);
else
name = GetIonName(Z, A, Eex, flb);
// PDG encoding
G4int encoding = GetNucleusEncoding(Z,A,E,lvl);
// PDG mass
G4double mass = GetNucleusMass(Z, A)+ Eex;
// PDG charge is set to one of nucleus
G4double charge = G4double(Z)*eplus;
// create an ion
// spin, parity, isospin values are fixed
// Request lock for particle table accesses. Some changes are inside
// this critical region.
//
ion = new G4Ions( name, mass, 0.0*MeV, charge,
J, +1, 0,
0, 0, 0,
"nucleus", 0, A, encoding,
stable, life, decayTable, false,
"generic", 0,
Eex, lvl );
// Release lock for particle table accesses.
//
ion->SetPDGMagneticMoment(mu);
static_cast<G4Ions*>(ion)->SetFloatLevelBase(flb);
// No Anti particle registered
ion->SetAntiPDGEncoding(0);
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::CreateIon() : create ion of " << name
<< " " << Z << ", " << A
<< " encoding=" << encoding;
if (E>0.0)
{
G4cout << " IsomerLVL=" << lvl
<< " excited energy=" << Eex/keV << "[keV]";
}
G4cout << G4endl;
}
#endif
// Add process manager to the ion
AddProcessManager(ion);
#ifdef G4MULTITHREADED
// Fill decay channels if this method is invoked from worker
if(G4Threading::IsWorkerThread())
{
if(!stable && decayTable)
{
G4int nCh = decayTable->entries();
for(G4int iCh=0; iCh<nCh; ++iCh)
{
decayTable->GetDecayChannel(iCh)->GetDaughter(0);
}
}
}
#endif
return ion;
}
// --------------------------------------------------------------------
// CreateIon
//
G4ParticleDefinition*
G4IonTable::CreateIon(G4int Z, G4int A, G4int LL, G4double E,
G4Ions::G4FloatLevelBase flb)
{
if (LL==0) return CreateIon(Z,A,E,flb);
// create hyper nucleus
G4ParticleDefinition* ion = nullptr;
// check whether GenericIon has processes
G4ParticleDefinition* genericIon =
G4ParticleTable::GetParticleTable()->GetGenericIon();
G4ProcessManager* pman = nullptr;
if (genericIon != nullptr) pman = genericIon->GetProcessManager();
if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0)
|| (pman==nullptr))
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::CreateIon() : can not create ion of "
<< " Z =" << Z << " A = " << A
<< " because GenericIon is not ready !!" << G4endl;
}
#endif
G4Exception( "G4IonTable::CreateIon()","PART105", JustWarning,
"Can not create ions because GenericIon is not ready");
return nullptr;
}
G4int J = 0;
G4double life = 0.0;
G4DecayTable* decayTable = nullptr;
G4bool stable = true;
// excitation energy
// G4double Eex = G4NuclideTable::Round(E);
G4double Eex = E;
G4double mass = GetNucleusMass(Z, A, LL)+ Eex;
G4int lvl = 0;
// lvl is assigned to 9 temporarily
if (Eex>0.0) lvl=9;
// PDG encoding
G4int encoding = GetNucleusEncoding(Z,A,LL,E,lvl);
// PDG charge is set to one of nucleus
G4double charge = G4double(Z)*eplus;
// create an ion
// spin, parity, isospin values are fixed
//
// get ion name
G4String name = GetIonName(Z, A, LL, Eex, flb);
ion = new G4Ions( name, mass, 0.0*MeV, charge,
J, +1, 0,
0, 0, 0,
"nucleus", 0, A, encoding,
stable, life, decayTable, false,
"generic", 0,
Eex, lvl );
// Release lock for particle table accesses
G4double mu = 0.0; // magnetic moment
ion->SetPDGMagneticMoment(mu);
static_cast<G4Ions*>(ion)->SetFloatLevelBase(flb);
// No Anti particle registered
ion->SetAntiPDGEncoding(0);
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::CreateIon() : create hyper ion of " << name
<< " " << Z << ", " << A << ", " << LL
<< " encoding=" << encoding;
if (E>0.0)
{
G4cout << " IsomerLVL=" << lvl
<< " excited energy=" << Eex/keV << "[keV]";
}
G4cout << G4endl;
}
#endif
// Add process manager to the ion
AddProcessManager(ion);
return ion;
}
// --------------------------------------------------------------------
// CreateIon
//
G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4int lvl)
{
if(lvl == 0) return CreateIon(Z,A,0.0,G4Ions::G4FloatLevelBase::no_Float);
G4Exception( "G4IonTable::CreateIon()","PART105", JustWarning,
"Ion cannot be created by an isomer level. Use excitation energy.");
return nullptr;
}
// --------------------------------------------------------------------
// CreateIon
//
G4ParticleDefinition*
G4IonTable::CreateIon(G4int Z, G4int A, G4int LL, G4int lvl)
{
if (LL==0) return CreateIon(Z,A,lvl);
if(lvl == 0) return CreateIon(Z,A,0.0,G4Ions::G4FloatLevelBase::no_Float);
if (lvl>0)
{
G4ExceptionDescription ed;
ed << "Isomer level " << lvl << " is unknown for the isotope (Z="
<< Z << ", A=" << A << ", L=" << LL << "). Null pointer is returned.";
G4Exception( "G4IonTable::GetIon()","PART106", JustWarning, ed);
return nullptr;
}
return nullptr;
}
// --------------------------------------------------------------------
// -- GetIon methods ------
//
G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int lvl)
{
if ( (A<1) || (Z<=0) || (lvl<0) || (A>999) )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : illegal atomic number/mass"
<< " Z =" << Z << " A = " << A << " Lvl = " << lvl << G4endl;
}
#endif
return nullptr;
}
if ( lvl == 0 ) return GetIon(Z,A,0.0);
// Search ions with A, Z, lvl
G4ParticleDefinition* ion = FindIon(Z,A,lvl);
// create ion
#ifdef G4MULTITHREADED
if (ion == nullptr )
{
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
ion = FindIonInMaster(Z,A,lvl);
if(ion != nullptr ) InsertWorker(ion);
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
}
}
#endif
if (ion == nullptr )
{
G4Exception( "G4IonTable::GetIon()","PART105", JustWarning,
"Ion cannot be created by an isomer level. Use excitation energy.");
}
return ion;
}
// --------------------------------------------------------------------
//
G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4int lvl)
{
if (LL==0) return GetIon(Z,A,lvl);
if (A < 2 || Z < 0 || Z > A-LL || LL>A || A>999 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : illegal atomic number/mass"
<< " Z =" << Z << " A = " << A << " L = " << LL
<<" IsomerLvl = " << lvl << G4endl;
}
#endif
return nullptr;
}
else if( A==2 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : No boud state for "
<< " Z =" << Z << " A = " << A << " L = " << LL
<<" IsomerLvl = " << lvl << G4endl;
}
#endif
return nullptr;
}
// Search ions with A, Z
G4ParticleDefinition* ion = FindIon(Z,A,LL,lvl);
// create ion
if (ion == nullptr)
{
if (lvl==0)
{
#ifdef G4MULTITHREADED
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
ion = FindIonInMaster(Z,A,LL,lvl);
if(ion == nullptr) ion = CreateIon(Z, A, LL, lvl);
InsertWorker(ion);
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
}
else
{
ion = CreateIon(Z, A, LL, lvl);
}
#else
ion = CreateIon(Z, A, LL, lvl);
#endif
}
}
return ion;
}
// --------------------------------------------------------------------
//
G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4double E, G4int J)
{
return GetIon(Z,A,E,G4Ions::G4FloatLevelBase::no_Float,J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::GetIon(G4int Z, G4int A, G4double E, char flbChar, G4int J)
{
return GetIon(Z,A,E,G4Ions::FloatLevelBase(flbChar),J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb, G4int J)
{
if ( (A<1) || (Z<=0) || (E<0.0) || (A>999) || (J<0) )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : illegal atomic number/mass"
<< " Z =" << Z << " A = " << A << " E = " << E/keV << G4endl;
}
#endif
return nullptr;
}
// Search ions with A, Z
G4ParticleDefinition* ion = FindIon(Z,A,E,flb,J);
// create ion
#ifdef G4MULTITHREADED
if(ion == nullptr )
{
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
ion = FindIonInMaster(Z,A,E,flb,J);
if(ion == nullptr) ion = CreateIon(Z,A,E,flb);
InsertWorker(ion);
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
}
else
{
ion = CreateIon(Z,A,E,flb);
}
}
#else
if (ion == nullptr) ion = CreateIon(Z,A,E,flb);
#endif
return ion;
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E, G4int J)
{
return GetIon(Z,A,LL,E,G4Ions::G4FloatLevelBase::no_Float,J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E,
char flbChar, G4int J)
{
return GetIon(Z,A,LL,E,G4Ions::FloatLevelBase(flbChar),J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E,
G4Ions::G4FloatLevelBase flb, G4int J)
{
if (LL==0) return GetIon(Z,A,E,flb,J);
if (A < 2 || Z < 0 || Z > A-LL || LL>A || A>999 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : illegal atomic number/mass"
<< " Z =" << Z << " A = " << A << " L = " << LL
<<" E = " << E/keV << G4endl;
}
#endif
return nullptr;
}
else if( A==2 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : No boud state for "
<< " Z =" << Z << " A = " << A << " L = " << LL
<< " E = " << E/keV << G4endl;
}
#endif
return nullptr;
}
// Search ions with A, Z
G4ParticleDefinition* ion = FindIon(Z,A,LL,E,flb,J);
// create ion
#ifdef G4MULTITHREADED
if(ion == nullptr ){
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
ion = FindIonInMaster(Z,A,LL,E,flb,J);
if(ion == nullptr) ion = CreateIon(Z,A,LL,E,flb);
InsertWorker(ion);
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
}
else
{
ion = CreateIon(Z,A,LL,E,flb);
}
}
#else
if(ion == nullptr) ion = CreateIon(Z,A,LL,E,flb);
#endif
return ion;
}
// --------------------------------------------------------------------
//
G4ParticleDefinition* G4IonTable::GetIon(G4int encoding)
{
G4int Z, A, LL, IsoLvl;
G4double E;
if (!GetNucleusByEncoding(encoding,Z,A,LL,E,IsoLvl))
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetIon() : illegal encoding"
<< " CODE:" << encoding << G4endl;
}
#endif
G4Exception( "G4IonTable::GetIon()","PART106",
JustWarning, "illegal encoding for an ion");
return nullptr;
}
return GetIon( Z, A, LL, IsoLvl);
}
// --------------------------------------------------------------------
// -- FindIon methods ------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4double E, G4int J)
{
return FindIon(Z,A,E,G4Ions::G4FloatLevelBase::no_Float,J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4double E, char flbChar, G4int J)
{
return FindIon(Z,A,E,G4Ions::FloatLevelBase(flbChar),J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb, G4int J)
{
if ( (A<1) || (Z<=0) || (J<0) || (E<0.0) || (A>999) )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::FindIon(): illegal atomic number/mass"
<< " or excitation level:" << G4endl
<< " Z =" << Z << " A = " << A << " E = " << E/keV << G4endl;
}
#endif
G4Exception("G4IonTable::FindIon()","PART107",
JustWarning, "illegal atomic number/mass");
return nullptr;
}
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// check if light ion
ion = GetLightIon(Z,A);
if (ion!= nullptr && E == 0.0)
{
// light ion
isFound = true;
}
else
{
// -- loop over all particles in Ion table
G4int encoding = GetNucleusEncoding(Z, A);
for(auto i = fIonList->find(encoding); i != fIonList->cend(); ++i)
{
ion = i->second;
if ( (ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
// excitation level
G4double anExcitaionEnergy= ((const G4Ions*)(ion))->GetExcitationEnergy();
if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance())
{
if(((const G4Ions*)(ion))->GetFloatLevelBase()==flb)
{
isFound = true;
break;
}
}
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E, G4int J)
{
return FindIon(Z,A,LL,E,G4Ions::G4FloatLevelBase::no_Float,J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E,
char flbChar, G4int J)
{
return FindIon(Z,A,LL,E,G4Ions::FloatLevelBase(flbChar),J);
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E,
G4Ions::G4FloatLevelBase flb, G4int J)
{
if (LL==0) return FindIon(Z,A,E,flb,J);
if (A < 2 || Z < 0 || Z > A-LL || LL>A || A>999 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::FindIon(): illegal atomic number/mass"
<< " or excitation level:" << G4endl
<< " Z =" << Z << " A = " << A << " L = " << LL
<<" E = " << E/keV << G4endl;
}
#endif
G4Exception("G4IonTable::FindIon()", "PART107",
JustWarning, "illegal atomic number/mass");
return nullptr;
}
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A, LL, 0.0, 0);
for(auto i = fIonList->find(encoding); i != fIonList->cend() ; ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
if( ion->GetQuarkContent(3) != LL ) break;
// excitation level
G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy();
if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance())
{
if(((const G4Ions*)(ion))->GetFloatLevelBase()==flb)
{
isFound = true;
break;
}
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
//
G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int lvl)
{
if ( (A<1) || (Z<=0) || (lvl<0) || (A>999) )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::FindIon(): illegal atomic number/mass"
<< " or excitation level:" << G4endl
<< " Z =" << Z << " A = " << A << " IsoLvl = " << lvl << G4endl;
}
#endif
G4Exception("G4IonTable::FindIon()", "PART107",
JustWarning, "illegal atomic number/mass");
return nullptr;
}
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// check if light ion
ion = GetLightIon(Z,A);
if (ion != nullptr && lvl==0)
{
// light ion
isFound = true;
}
else
{
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A);
for(auto i = fIonList->find(encoding); i != fIonList->cend(); ++i)
{
ion = i->second;
if ( (ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
// excitation level
if ( ((const G4Ions*)(ion))->GetIsomerLevel() == lvl)
{
isFound = true;
break;
}
}
}
if ( isFound )
{
if(lvl==9)
{
G4Exception("G4IonTable::FindIon()","PART5107", JustWarning,
"Isomer level 9 may be ambiguous.");
}
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
//
G4ParticleDefinition*
G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4int lvl)
{
if (LL==0) return FindIon(Z,A,lvl);
if (A < 2 || Z < 0 || Z > A-LL || LL>A || A>999 )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::FindIon(): illegal atomic number/mass"
<< " or excitation level:" << G4endl
<< " Z =" << Z << " A = " << A << " L = " << LL
<<" IsomerLvl = " << lvl << G4endl;
}
#endif
G4Exception( "G4IonTable::FindIon()", "PART107",
JustWarning, "illegal atomic number/mass");
return nullptr;
}
// Search ions with A, Z ,E, lvl
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A, LL);
for(auto i = fIonList->find(encoding); i != fIonList->cend() ; ++i)
{
ion = i->second;
if ( (ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
if ( ion->GetQuarkContent(3) != LL) break;
// excitation level
if ( ((const G4Ions*)(ion))->GetIsomerLevel() == lvl)
{
isFound = true;
break;
}
}
if ( isFound )
{
if(lvl==9)
{
G4Exception("G4IonTable::FindIon()", "PART5107", JustWarning,
"Isomer level 9 may be ambiguous.");
}
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
// GetNucleusEncoding
//
G4int G4IonTable::GetNucleusEncoding(G4int Z, G4int A, G4double E, G4int lvl)
{
// PDG code for Ions
// Nuclear codes are given as 10-digit numbers +-100ZZZAAAI.
// For a nucleus consisting of np protons and nn neutrons
// A = np + nn and Z = np.
// I gives the isomer level, with I = 0 corresponding
// to the ground state and I >0 to excitations
if ( Z==1 && A==1 && E==0.0 ) return 2212; // proton
G4int encoding = 1000000000;
encoding += Z * 10000;
encoding += A *10;
if (lvl>0&&lvl<10) encoding +=lvl; //isomer level
else if (E>0.0) encoding += 9; //isomer level
return encoding;
}
// --------------------------------------------------------------------
// GetNucleusEncoding
//
G4int G4IonTable::GetNucleusEncoding(G4int Z, G4int A, G4int LL,
G4double E, G4int lvl)
{
// Get PDG code for Hyper-Nucleus Ions
// Nuclear codes are given as 10-digit numbers +-10LZZZAAAI.
// For a nucleus consisting of np protons and nn neutrons
// A = np + nn +nlambda and Z = np.
// LL = nlambda
// I gives the isomer level, with I = 0 corresponding
// to the ground state and I >0 to excitations
G4int encoding = GetNucleusEncoding(Z, A, E, lvl);
if (LL==0) return encoding;
encoding += LL* 10000000;
if ( Z==1 && A==1 && E==0.0 ) encoding = 3122; // Lambda
return encoding;
}
// --------------------------------------------------------------------
// GetNucleusByEncoding
//
G4bool G4IonTable::GetNucleusByEncoding(G4int encoding,
G4int& Z, G4int& A,
G4double& E, G4int& lvl)
{
if (encoding <= 0) return false; // anti particle
if (encoding == 2212) // proton
{
Z = 1; A = 1;
E = 0.0; lvl =0;
return true;
}
encoding -= 1000000000;
Z = encoding/10000;
encoding -= 10000*Z;
A = encoding/10;
lvl = encoding % 10;
return true;
}
// --------------------------------------------------------------------
// GetNucleusByEncoding
//
G4bool G4IonTable::GetNucleusByEncoding(G4int encoding,
G4int& Z, G4int& A,
G4int& LL,
G4double& E, G4int& lvl)
{
if (encoding <= 0) return false; // anti particle
if (encoding == 3122) // Lambda
{
Z = 1; A = 1; LL = 1;
E = 0.0; lvl =0;
return true;
}
if (encoding % 10 != 0)
{
// !!!not supported for excitation states !!!
return false;
}
if (encoding < 1000000000)
{
// anti particle
return false;
}
encoding -= 1000000000;
LL = encoding/10000000;
encoding -= 10000000*LL;
Z = encoding/10000;
encoding -= 10000*Z;
A = encoding/10;
lvl = encoding % 10;
return true;
}
// --------------------------------------------------------------------
// GetIonName
//
const G4String& G4IonTable::GetIonName(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb) const
{
static G4ThreadLocal G4String* pname = nullptr;
if ( pname == nullptr )
{
pname = new G4String("");
G4AutoDelete::Register(pname);
}
G4String& name = *pname;
static G4ThreadLocal std::ostringstream* os = nullptr;
if ( os == nullptr )
{
os = new std::ostringstream();
G4AutoDelete::Register(os);
os->setf(std::ios::fixed);
os->precision(3);
}
name = GetIonName(Z, A);
// Excited energy
if ( E>0 || flb!=G4Ions::G4FloatLevelBase::no_Float)
{
os->str("");
std::ostringstream& oo = *os;
// Excited nucleus
oo<<'['<<E/keV;
if (flb!=G4Ions::G4FloatLevelBase::no_Float)
{
oo<<G4Ions::FloatLevelBaseChar(flb);
}
oo<< ']';
name += os->str();
}
return name;
}
// --------------------------------------------------------------------
// GetIonName
//
const G4String& G4IonTable::GetIonName(G4int Z, G4int A, G4int LL, G4double E,
G4Ions::G4FloatLevelBase flb) const
{
if (LL==0) return GetIonName(Z, A, E, flb);
static G4ThreadLocal G4String* pname = nullptr;
if (pname == nullptr)
{
pname = new G4String("");
G4AutoDelete::Register(pname);
}
G4String& name = *pname;
name = "";
for (G4int i=0; i<LL; ++i)
{
name +="L";
}
name += GetIonName(Z, A, E, flb);
return name;
}
// --------------------------------------------------------------------
// GetIonName
//
const G4String& G4IonTable::GetIonName(G4int Z, G4int A, G4int lvl) const
{
static G4ThreadLocal G4String* pname = nullptr;
if ( pname == nullptr )
{
pname = new G4String("");
G4AutoDelete::Register(pname);
}
G4String& name = *pname;
static G4ThreadLocal std::ostringstream* os = nullptr;
if ( os == nullptr )
{
os = new std::ostringstream();
G4AutoDelete::Register(os);
os->setf(std::ios::fixed);
}
if ( (0< Z) && (Z <=numberOfElements) )
{
name = elementName[Z-1];
}
else if (Z > numberOfElements)
{
os->str("");
os->operator<<(Z);
name = "E" + os->str() + "-";
}
else
{
name = "?";
return name;
}
// Atomic Mass
os->str("");
os->operator<<(A);
if ( lvl>0 )
{
std::ostringstream& oo = *os;
// Isomer level for Excited nucelus
oo<<'['<<lvl << ']';
}
name += os->str();
return name;
}
// --------------------------------------------------------------------
// GetIonName
//
const G4String&
G4IonTable::GetIonName(G4int Z, G4int A, G4int LL, G4int lvl) const
{
if (LL==0) return GetIonName(Z, A, lvl);
static G4ThreadLocal G4String* pname = nullptr;
if ( pname == nullptr )
{
pname = new G4String("");
G4AutoDelete::Register(pname);
}
G4String &name = *pname;
for (G4int i=0; i<LL; ++i)
{
name +="L";
}
name += GetIonName(Z, A, lvl);
return name;
}
// --------------------------------------------------------------------
// IsIon
//
G4bool G4IonTable::IsIon(const G4ParticleDefinition* particle)
{
// Return true if the particle is ion
static const G4String nucleus("nucleus");
static const G4String proton("proton");
// Neutron is not ion
if ( (particle->GetAtomicMass()>0)
&& (particle->GetAtomicNumber()>0) )
{
if (particle->GetBaryonNumber()>0) return true;
else return false;
}
// Particles derived from G4Ions
if (particle->GetParticleType() == nucleus) return true;
// Proton (Hydrogen nucleus)
if (particle->GetParticleName() == proton) return true;
return false;
}
// --------------------------------------------------------------------
// IsAntiIon
//
G4bool G4IonTable::IsAntiIon(const G4ParticleDefinition* particle)
{
// Return true if the particle is ion
static const G4String anti_nucleus("anti_nucleus");
static const G4String anti_proton("anti_proton");
// Anti_neutron is not ion
if ( (particle->GetAtomicMass()>0)
&& (particle->GetAtomicNumber()>0) )
{
if (particle->GetBaryonNumber()<0) return true;
else return false;
}
// Particles derived from G4Ions
if (particle->GetParticleType() == anti_nucleus) return true;
// Anti_proton (Anti_Hydrogen nucleus)
if (particle->GetParticleName() == anti_proton) return true;
return false;
}
// --------------------------------------------------------------------
// IsLightIon
//
G4bool G4IonTable::IsLightIon(const G4ParticleDefinition* particle) const
{
static const std::string names[]
= { "proton", "alpha", "deuteron", "triton", "He3"};
// Return true if the particle is pre-defined ion
return std::find(names, names+5, particle->GetParticleName())!=names+5;
}
// --------------------------------------------------------------------
// IsLightAntiIon
//
G4bool G4IonTable::IsLightAntiIon(const G4ParticleDefinition* particle) const
{
static const std::string names[]
= { "anti_proton", "anti_alpha", "anti_deuteron", "anti_triton", "anti_He3"};
// Return true if the particle is pre-defined ion
return std::find(names, names+5, particle->GetParticleName())!=names+5;
}
// --------------------------------------------------------------------
// GetLightIon
//
G4ParticleDefinition* G4IonTable::GetLightIon(G4int Z, G4int A) const
{
// Returns pointer to pre-defined ions
const G4ParticleDefinition* ion = nullptr;
if ( (Z<=2) )
{
#ifndef G4MULTITHREADED
// In sequential use lazy-initialization
lightions::Init();
#endif
if ( (Z==1)&&(A==1) ) {
ion = lightions::p_proton;
} else if ( (Z==1)&&(A==2) ) {
ion = lightions::p_deuteron;
} else if ( (Z==1)&&(A==3) ) {
ion = lightions::p_triton;
} else if ( (Z==2)&&(A==4) ) {
ion = lightions::p_alpha;
} else if ( (Z==2)&&(A==3) ) {
ion = lightions::p_He3;
}
}
return const_cast<G4ParticleDefinition*>(ion);
}
// --------------------------------------------------------------------
// GetLightAntiIon
//
G4ParticleDefinition* G4IonTable::GetLightAntiIon(G4int Z, G4int A) const
{
// Returns pointer to pre-defined ions
const G4ParticleDefinition* ion = nullptr;
if ( (Z<=2) )
{
#ifndef G4MULTITHREADED
// In sequential use lazy-initialization
antilightions::Init();
#endif
if ( (Z==1)&&(A==1) ) {
ion = antilightions::p_proton;
} else if ( (Z==1)&&(A==2) ) {
ion = antilightions::p_deuteron;
} else if ( (Z==1)&&(A==3) ) {
ion = antilightions::p_triton;
} else if ( (Z==2)&&(A==4) ) {
ion = antilightions::p_alpha;
} else if ( (Z==2)&&(A==3) ) {
ion = antilightions::p_He3;
}
}
return const_cast<G4ParticleDefinition*>(ion);
}
// --------------------------------------------------------------------
// GetNucleusMass
//
G4double
G4IonTable::GetNucleusMass(G4int Z, G4int A, G4int LL, G4int lvl) const
{
if ( (A<1) || (Z<0) || (LL<0) || (lvl<0) || (lvl>9) )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << "G4IonTable::GetNucleusMass() : illegal atomic number/mass:"
<< G4endl
<< " Z =" << Z << " A = " << A
<< " L = " << LL << " lvl = " << lvl << G4endl;
}
#endif
G4Exception("G4IonTable::GetNucleusMass()","PART107",
EventMustBeAborted, "illegal atomic number/mass");
return -1.0;
}
G4double mass;
if (LL == 0)
{
// calculate nucleus mass
const G4ParticleDefinition* ion=GetLightIon(Z, A);
if (ion != nullptr)
{
mass = ion->GetPDGMass();
}
else
{
// Use G4NucleiProperties::GetNuclearMass
mass = G4NucleiProperties::GetNuclearMass(A, Z);
}
// Isomer
if ( lvl>0 )
{
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A);
G4bool isFound = false;
for(auto i = fIonList->find(encoding);i != fIonList->cend() ; ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber()!=Z) || (ion->GetAtomicMass()!=A) ) break;
// Excitation level
if ( ((const G4Ions*)(ion))->GetIsomerLevel() == lvl)
{
isFound = true;
break;
}
}
if (isFound)
{
// Return existing isomer mass
mass = ion->GetPDGMass();
}
else
{
// Find isomer from IsotopeTable
const G4IsotopeProperty* fProperty = FindIsotope(Z, A, lvl);
if (fProperty != nullptr ) mass += fProperty->GetEnergy();
}
}
}
else
{
mass = G4HyperNucleiProperties::GetNuclearMass(A, Z, LL);
}
return mass;
}
// --------------------------------------------------------------------
// GetIsomerMass
//
G4double G4IonTable::GetIsomerMass(G4int Z, G4int A, G4int lvl) const
{
return GetNucleusMass(Z,A,0,lvl);
}
// --------------------------------------------------------------------
// GetIonMass
//
G4double G4IonTable::GetIonMass(G4int Z, G4int A, G4int LL, G4int lvl) const
{
return GetNucleusMass(Z,A,LL,lvl);
}
// --------------------------------------------------------------------
// -- Methods for handling container ---
// --------------------------------------------------------------------
//
void G4IonTable::clear()
{
if (G4ParticleTable::GetParticleTable()->GetReadiness())
{
G4Exception("G4IonTable::clear()",
"PART116", JustWarning,
"No effects because readyToUse is true.");
return;
}
#ifdef G4VERBOSE
if (GetVerboseLevel()>2)
{
G4cout << "G4IonTable::Clear() : number of Ion registered = ";
G4cout << fIonList->size() << G4endl;
}
#endif
fIonList->clear();
}
// --------------------------------------------------------------------
//
void G4IonTable::Insert(const G4ParticleDefinition* particle)
{
if (!IsIon(particle)) return;
if (Contains(particle)) return;
G4int Z = particle->GetAtomicNumber();
G4int A = particle->GetAtomicMass();
G4int LL = particle->GetQuarkContent(3); //strangeness
G4int encoding=GetNucleusEncoding(Z, A, LL); // encoding of the groud state
// Register the ion with its encoding of the ground state
fIonListShadow->insert( std::pair<const G4int,
const G4ParticleDefinition*>(encoding, particle) );
}
// --------------------------------------------------------------------
//
void G4IonTable::InsertWorker(const G4ParticleDefinition* particle)
{
if(!particle) return;
G4int Z = particle->GetAtomicNumber();
G4int A = particle->GetAtomicMass();
G4int LL = particle->GetQuarkContent(3); //strangeness
G4int encoding=GetNucleusEncoding(Z, A, LL);
G4bool found = false;
if (encoding !=0 )
{
for(auto i = fIonList->find(encoding); i != fIonList->cend(); ++i)
{
if (particle == i->second)
{
found = true;
break;
}
}
}
if(found) return;
// Register the ion with its encoding of the gronud state
fIonList->insert( std::pair<const G4int,
const G4ParticleDefinition*>(encoding, particle) );
}
// --------------------------------------------------------------------
//
void G4IonTable::Remove(const G4ParticleDefinition* particle)
{
if(particle == nullptr) return;
#ifdef G4MULTITHREADED
if(G4Threading::IsWorkerThread())
{
G4ExceptionDescription ed;
ed << "Request of removing " << particle->GetParticleName()
<< " is ignored as it is invoked from a worker thread.";
G4Exception("G4IonTable::Remove()", "PART10117", JustWarning, ed);
return;
}
#endif
if (G4ParticleTable::GetParticleTable()->GetReadiness())
{
G4StateManager* pStateManager = G4StateManager::GetStateManager();
G4ApplicationState currentState = pStateManager->GetCurrentState();
if (currentState != G4State_PreInit)
{
G4String msg = "Request of removing ";
msg += particle->GetParticleName();
msg += " has No effects other than Pre_Init";
G4Exception("G4IonTable::Remove()",
"PART117", JustWarning, msg);
return;
}
else
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>0)
{
G4cout << particle->GetParticleName()
<< " will be removed from the IonTable " << G4endl;
}
#endif
}
}
if (IsIon(particle))
{
G4int Z = particle->GetAtomicNumber();
G4int A = particle->GetAtomicMass();
G4int LL = particle->GetQuarkContent(3); // strangeness
G4int encoding=GetNucleusEncoding(Z, A, LL);
if (encoding !=0 )
{
for(auto i = fIonListShadow->find(encoding);
i != fIonListShadow->cend() ; ++i)
{
if (particle == i->second)
{
fIonListShadow->erase(i);
break;
}
}
}
}
else
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::Remove :" << particle->GetParticleName()
<< " is not ions" << G4endl;
}
#endif
}
}
// --------------------------------------------------------------------
// -- Dump Information
//
void G4IonTable::DumpTable(const G4String& particle_name) const
{
const G4ParticleDefinition* ion;
for (auto idx = fIonList->cbegin(); idx!= fIonList->cend(); ++idx)
{
ion = idx->second;
if (( particle_name == "ALL" ) || (particle_name == "all"))
{
ion->DumpTable();
}
else if ( particle_name == ion->GetParticleName() )
{
ion->DumpTable();
}
}
}
// --------------------------------------------------------------------
//
const G4String G4IonTable::elementName[] =
{
"H", "He",
"Li", "Be", "B", "C", "N", "O", "F", "Ne",
"Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar",
"K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr",
"Rb", "Sr", "Y", "Zr", "Nb", "Mo","Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe",
"Cs", "Ba",
"La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu",
"Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn",
"Fr", "Ra",
"Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr",
"Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og"
};
// --------------------------------------------------------------------
// GetVerboseLevel
//
G4int G4IonTable::GetVerboseLevel() const
{
return G4ParticleTable::GetParticleTable()->GetVerboseLevel();
}
// --------------------------------------------------------------------
// AddProcessManager
//
void G4IonTable::AddProcessManager(G4ParticleDefinition* ion)
{
if(ion->IsGeneralIon())
{
// Check whether GenericIon has processes
G4ParticleDefinition* genericIon =
G4ParticleTable::GetParticleTable()->GetGenericIon();
G4ProcessManager* pman = nullptr;
if (genericIon != nullptr) pman = genericIon->GetProcessManager();
if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0)
|| (pman==nullptr))
{
G4String msg = "G4IonTable::AddProcessManager(): cannot create ion of ";
msg += ion->GetParticleName();
msg += "\n because GenericIon is not available!!";
G4Exception("G4IonTable::AddProcessManager()", "PART105",
FatalException, msg);
return;
}
ion->SetParticleDefinitionID(genericIon->GetParticleDefinitionID());
}
else
{
// Is this a MuonicAtom ?
G4MuonicAtom* muatom = dynamic_cast<G4MuonicAtom*> (ion);
if ( muatom != nullptr )
{
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << "G4IonTable::AddProcessManager(): "
<< "MuonicAtom dynamic_cast succeeded for "
<< ion->GetParticleName() << G4endl;
}
#endif
// Check whether GenericMuonicAtom has processes
G4ParticleDefinition* genericMA =
G4ParticleTable::GetParticleTable()->GetGenericMuonicAtom();
G4ProcessManager* pman = nullptr;
if (genericMA != nullptr) pman = genericMA->GetProcessManager();
if ((genericMA == nullptr) || (genericMA->GetParticleDefinitionID() < 0)
|| (pman==nullptr))
{
G4String msg =
"G4IonTable::AddProcessManager(): cannot create MuonicAtom ";
msg += ion->GetParticleName();
msg += "\n because GenericMuonicAtom is not available!!";
G4Exception("G4IonTable::AddProcessManager()",
"PART106", FatalException, msg);
return;
}
ion->SetParticleDefinitionID(genericMA->GetParticleDefinitionID());
}
else
{
G4String msg =
"G4IonTable::AddProcessManager(): cannot create ";
msg += ion->GetParticleName();
msg += "\n because of unsupported particle type !!";
G4Exception("G4IonTable::AddProcessManager()", "PART107",
FatalException, msg);
return;
}
}
return;
}
// --------------------------------------------------------------------
// RegisterIsotopeTable
//
void G4IonTable::RegisterIsotopeTable(G4VIsotopeTable* table)
{
//check duplication
G4String name = table->GetName();
for (std::size_t i=0; i<fIsotopeTableList->size(); ++i)
{
G4VIsotopeTable* fIsotopeTable= (*fIsotopeTableList)[i];
if (name == fIsotopeTable->GetName()) return;
}
// register
fIsotopeTableList->push_back(table);
}
// --------------------------------------------------------------------
// GetIsotopeTable
//
G4VIsotopeTable* G4IonTable::GetIsotopeTable(std::size_t index) const
{
G4VIsotopeTable* fIsotopeTable = nullptr;
if ( index < fIsotopeTableList->size() )
{
fIsotopeTable = (*fIsotopeTableList)[index];
}
return fIsotopeTable;
}
// --------------------------------------------------------------------
// FindIsotope
//
G4IsotopeProperty* G4IonTable::FindIsotope(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb) const
{
if (fIsotopeTableList == nullptr) return nullptr;
if (fIsotopeTableList->size() == 0) return nullptr;
G4IsotopeProperty* property = nullptr;
for (std::size_t i=0; i<fIsotopeTableList->size(); ++i)
{
G4VIsotopeTable* fIsotopeTable
= (*fIsotopeTableList)[fIsotopeTableList->size()-i-1];
property = fIsotopeTable->GetIsotope(Z,A,E,flb);
if(property) break;
}
return property;
}
// --------------------------------------------------------------------
// FindIsotope
//
G4IsotopeProperty* G4IonTable::FindIsotope(G4int Z, G4int A, G4int lvl) const
{
if (fIsotopeTableList == nullptr) return nullptr;
if (fIsotopeTableList->size()==0) return nullptr;
G4IsotopeProperty* property = nullptr;
// iterate
for (std::size_t i=0; i<fIsotopeTableList->size(); ++i)
{
G4VIsotopeTable* fIsotopeTable
= (*fIsotopeTableList)[fIsotopeTableList->size()-i-1];
property = fIsotopeTable->GetIsotope(Z,A,lvl);
if(property) break;
}
return property;
}
// --------------------------------------------------------------------
// CreateAllIon
//
void G4IonTable::CreateAllIon()
{
PreloadNuclide();
}
// --------------------------------------------------------------------
// CreateAllIsomer
//
void G4IonTable::CreateAllIsomer()
{
PreloadNuclide();
}
// --------------------------------------------------------------------
// PrepareNuclideTable
//
void G4IonTable::PrepareNuclideTable()
{
if (pNuclideTable == nullptr)
pNuclideTable = G4NuclideTable::GetNuclideTable();
}
// --------------------------------------------------------------------
// PreloadNuclide
//
void G4IonTable::PreloadNuclide()
{
if ( isIsomerCreated || !G4Threading::IsMultithreadedApplication() ) return;
pNuclideTable->GenerateNuclide();
for ( std::size_t i=0 ; i!=pNuclideTable->entries(); ++i )
{
const G4IsotopeProperty* fProperty = pNuclideTable->GetIsotopeByIndex( i );
G4int Z = fProperty->GetAtomicNumber();
G4int A = fProperty->GetAtomicMass();
G4double Eex = fProperty->GetEnergy();
GetIon(Z,A,Eex);
}
isIsomerCreated = true;
}
// --------------------------------------------------------------------
// GetParticle
//
G4ParticleDefinition* G4IonTable::GetParticle(G4int index) const
{
if ( (index >=0) && (index < Entries()) )
{
auto idx = fIonList->cbegin();
G4int counter = 0;
while( idx != fIonList->cend() ) // Loop checking, 09.08.2015, K.Kurashige
{
if ( counter == index )
{
return const_cast<G4ParticleDefinition*>(idx->second);
}
++counter;
++idx;
}
}
#ifdef G4VERBOSE
if (GetVerboseLevel()>1)
{
G4cout << " G4IonTable::GetParticle"
<< " invalid index (=" << index << ")"
<< " entries = " << Entries() << G4endl;
}
#endif
return nullptr;
}
// --------------------------------------------------------------------
// Contains
//
G4bool G4IonTable::Contains(const G4ParticleDefinition* particle) const
{
if (!IsIon(particle)) return false;
G4int Z = particle->GetAtomicNumber();
G4int A = particle->GetAtomicMass();
G4int LL = particle->GetQuarkContent(3); //strangeness
G4int encoding=GetNucleusEncoding(Z, A, LL);
G4bool found = false;
if (encoding != 0 )
{
for(auto i = fIonListShadow->find(encoding);
i != fIonListShadow->cend(); ++i)
{
if (particle == i->second )
{
found = true;
break;
}
}
}
return found;
}
// --------------------------------------------------------------------
// Entries
//
G4int G4IonTable::Entries() const
{
return fIonList->size();
}
// --------------------------------------------------------------------
// size
//
G4int G4IonTable::size() const
{
return fIonList->size();
}
// --------------------------------------------------------------------
// FindIonInMaster
//
G4ParticleDefinition*
G4IonTable::FindIonInMaster(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb, G4int /*J*/)
{
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A);
for(auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
// excitation level
G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy();
if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance() )
{
if(((const G4Ions*)(ion))->GetFloatLevelBase()==flb)
{
isFound = true;
break;
}
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
// FindIonInMaster
//
G4ParticleDefinition*
G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int LL, G4double E,
G4Ions::G4FloatLevelBase flb, G4int J)
{
if (LL==0) return FindIon(Z,A,E,flb,J);
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding = GetNucleusEncoding(Z, A, LL, 0.0, 0);
for(auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
if( ion->GetQuarkContent(3) != LL) break;
// Excitation level
G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy();
if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance() )
{
if(((const G4Ions*)(ion))->GetFloatLevelBase()==flb)
{
isFound = true;
break;
}
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
// FindIonInMaster
//
G4ParticleDefinition* G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int lvl)
{
// Search ions with A, Z ,E
// !! J is omitted now !!
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A);
for(auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
// Excitation level
if ( ((const G4Ions*)(ion))->GetIsomerLevel() == lvl)
{
isFound = true;
break;
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
// FindIonInMaster
//
G4ParticleDefinition*
G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int LL, G4int lvl)
{
if (LL==0) return FindIon(Z,A,lvl);
// Search ions with A, Z ,E, lvl
const G4ParticleDefinition* ion = nullptr;
G4bool isFound = false;
// -- loop over all particles in Ion table
G4int encoding=GetNucleusEncoding(Z, A, LL);
for(auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i)
{
ion = i->second;
if ( ( ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass()!=A) ) break;
if ( ion->GetQuarkContent(3) != LL) break;
// excitation level
if ( ((const G4Ions*)(ion))->GetIsomerLevel() == lvl)
{
isFound = true;
break;
}
}
if ( isFound )
{
return const_cast<G4ParticleDefinition*>(ion);
}
else
{
return nullptr;
}
}
// --------------------------------------------------------------------
// GetLifeTime
//
G4double G4IonTable::GetLifeTime(const G4ParticleDefinition* particle) const
{
if((particle->IsGeneralIon()) && (pNuclideTable == nullptr))
{
G4Exception("G4IonTable::GetLifeTime()", "ParticleIon1001", FatalException,
"Method is invoked before G4IonTable is initialized.");
return 0.;
}
return particle->GetPDGLifeTime();
}
// --------------------------------------------------------------------
// GetLifeTime
//
G4double
G4IonTable::GetLifeTime(G4int Z, G4int A, G4double E, char flbChar) const
{
return GetLifeTime(Z,A,E,G4Ions::FloatLevelBase(flbChar));
}
// --------------------------------------------------------------------
// GetLifeTime
//
G4double G4IonTable::GetLifeTime(G4int Z, G4int A, G4double E,
G4Ions::G4FloatLevelBase flb) const
{
G4double life = -1001.0;
const G4IsotopeProperty* fProperty = FindIsotope(Z, A, E, flb);
if( fProperty != nullptr ) life = fProperty->GetLifeTime();
return life;
}
// --------------------------------------------------------------------
// GetMuonicAtom
//
G4ParticleDefinition* G4IonTable::GetMuonicAtom(G4Ions const* base)
{
if (base==nullptr || !IsIon(base))
{
G4Exception("G4IonTable::GetMuonicAtom()", "PART987654321",
FatalException, "Constructor argument is not a G4Ions");
return nullptr;
}
// We're assuming here that we get a base that is actually
// constructed and unexcited ... strip excitations, Lambdas, and
// isomers from the encoding
auto const Z = base->GetAtomicNumber();
auto const A = base->GetAtomicMass();
auto const baseenc = GetNucleusEncoding(Z,A);
auto const encoding = baseenc+1000000000;
// We have to do all the MT manipulations manually, because the
// convenience functions assume a G4Ions with canonical PDG codes;
// they recalculate the encoding from particle properties rather
// than using the carried member function values. Thus, they will
// do operations on the base ion, rather than the passed in
// G4MuonicAtom
auto i = fIonList->find(encoding);
if(i!=fIonList->cend())
{
return const_cast<G4ParticleDefinition*>(i->second);
}
// not in threadlocal list; check global list ...
#ifdef G4MULTITHREADED
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
i = fIonListShadow->find(encoding);
auto end = fIonListShadow->cend();
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
if(i!=end)
{
// we found it, stuff it into the threadlocal list
fIonList->insert(*i);
// and then return it ...
return const_cast<G4ParticleDefinition*>(i->second);
}
}
#endif
// not found in either list; create and potentially insert
auto const name = "Mu"+GetIonName(Z,A);
G4MuonicAtom* muatom =
G4MuonicAtomHelper::ConstructMuonicAtom(name, encoding, base);
// Not sure this is doing the right thing...
AddProcessManager(muatom);
// Now, we have to push the muatom into the appropriate IonTables
// first, recheck global list, in case another thread came along
// before us and created this same muatom
#ifdef G4MULTITHREADED
if(G4Threading::IsWorkerThread())
{
G4MUTEXLOCK(&G4IonTable::ionTableMutex);
// first, we need to make sure it hasn't been inserted by some
// other thread
auto j = fIonListShadow->find(encoding);
if( j!= fIonListShadow->cend() )
{
// oops ... someone else built a copy when we weren't looking;
// cleanup our instantiation, and take a handle to the one in
// the global list
delete muatom;
muatom = const_cast<G4MuonicAtom*>
(static_cast<G4MuonicAtom const*>(j->second));
}
else
{
// otherwise, push onto the global list first
fIonListShadow->insert(std::make_pair(encoding, muatom));
}
G4MUTEXUNLOCK(&G4IonTable::ionTableMutex);
}
#endif
// in either case, push onto the the threadlocal list
fIonList->insert(std::make_pair(encoding,muatom));
return muatom;
}
// --------------------------------------------------------------------
// GetMuonicAtom
//
G4ParticleDefinition* G4IonTable::GetMuonicAtom(G4int Z, G4int A)
{
// Need the cast because we need a G4Ions* to pass into the
// function, but GetIon returns a G4ParticleDefinition*
auto base = static_cast<G4Ions const*>(GetIon(Z,A, 0.0));
return GetMuonicAtom(base);
}