Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // G4IonTable class implementation 26 // G4IonTable class implementation 27 // 27 // 28 // Author: H.Kurashige, 27 June 1998 28 // Author: H.Kurashige, 27 June 1998 29 // ------------------------------------------- 29 // -------------------------------------------------------------------- 30 30 31 #include "G4IonTable.hh" 31 #include "G4IonTable.hh" 32 32 33 #include "G4AutoDelete.hh" 33 #include "G4AutoDelete.hh" 34 #include "G4HyperNucleiProperties.hh" 34 #include "G4HyperNucleiProperties.hh" 35 #include "G4Ions.hh" 35 #include "G4Ions.hh" 36 #include "G4IsotopeProperty.hh" 36 #include "G4IsotopeProperty.hh" 37 #include "G4MuonicAtom.hh" 37 #include "G4MuonicAtom.hh" 38 #include "G4MuonicAtomHelper.hh" 38 #include "G4MuonicAtomHelper.hh" 39 #include "G4NucleiProperties.hh" 39 #include "G4NucleiProperties.hh" 40 #include "G4NuclideTable.hh" 40 #include "G4NuclideTable.hh" 41 #include "G4ParticleTable.hh" 41 #include "G4ParticleTable.hh" 42 #include "G4PhysicalConstants.hh" 42 #include "G4PhysicalConstants.hh" 43 #include "G4StateManager.hh" 43 #include "G4StateManager.hh" 44 #include "G4SystemOfUnits.hh" 44 #include "G4SystemOfUnits.hh" 45 #include "G4Threading.hh" 45 #include "G4Threading.hh" 46 #include "G4UImanager.hh" 46 #include "G4UImanager.hh" 47 #include "G4VIsotopeTable.hh" 47 #include "G4VIsotopeTable.hh" 48 #include "G4ios.hh" 48 #include "G4ios.hh" 49 49 50 #include <algorithm> 50 #include <algorithm> 51 #include <iomanip> 51 #include <iomanip> 52 #include <iostream> 52 #include <iostream> 53 #include <sstream> 53 #include <sstream> 54 #include <vector> 54 #include <vector> 55 55 56 // It is very important for multithreaded Gean 56 // It is very important for multithreaded Geant4 to keep only one copy of the 57 // particle table pointer and the ion table po 57 // particle table pointer and the ion table pointer. However, we try to let 58 // each worker thread hold its own copy of the 58 // each worker thread hold its own copy of the particle dictionary and the 59 // ion list. This implementation is equivalent 59 // ion list. This implementation is equivalent to make the ion table thread 60 // private. The two shadow ponters are used by 60 // private. The two shadow ponters are used by each worker thread to copy the 61 // content from the master thread. 61 // content from the master thread. 62 // 62 // 63 G4ThreadLocal G4IonTable::G4IonList* G4IonTabl 63 G4ThreadLocal G4IonTable::G4IonList* G4IonTable::fIonList = nullptr; 64 G4ThreadLocal std::vector<G4VIsotopeTable*>* G 64 G4ThreadLocal std::vector<G4VIsotopeTable*>* G4IonTable::fIsotopeTableList = nullptr; 65 G4IonTable::G4IonList* G4IonTable::fIonListSha 65 G4IonTable::G4IonList* G4IonTable::fIonListShadow = nullptr; 66 std::vector<G4VIsotopeTable*>* G4IonTable::fIs 66 std::vector<G4VIsotopeTable*>* G4IonTable::fIsotopeTableListShadow = nullptr; 67 67 68 namespace lightions 68 namespace lightions 69 { 69 { 70 static const G4ParticleDefinition* p_proton = 70 static const G4ParticleDefinition* p_proton = nullptr; 71 static const G4ParticleDefinition* p_deuteron 71 static const G4ParticleDefinition* p_deuteron = nullptr; 72 static const G4ParticleDefinition* p_triton = 72 static const G4ParticleDefinition* p_triton = nullptr; 73 static const G4ParticleDefinition* p_alpha = n 73 static const G4ParticleDefinition* p_alpha = nullptr; 74 static const G4ParticleDefinition* p_He3 = nul 74 static const G4ParticleDefinition* p_He3 = nullptr; 75 void Init() 75 void Init() 76 { 76 { 77 if (p_proton != nullptr) return; 77 if (p_proton != nullptr) return; 78 p_proton = G4ParticleTable::GetParticleTable 78 p_proton = G4ParticleTable::GetParticleTable()->FindParticle("proton"); 79 p_deuteron = G4ParticleTable::GetParticleTab 79 p_deuteron = G4ParticleTable::GetParticleTable()->FindParticle("deuteron"); 80 p_triton = G4ParticleTable::GetParticleTable 80 p_triton = G4ParticleTable::GetParticleTable()->FindParticle("triton"); 81 p_alpha = G4ParticleTable::GetParticleTable( 81 p_alpha = G4ParticleTable::GetParticleTable()->FindParticle("alpha"); 82 p_He3 = G4ParticleTable::GetParticleTable()- 82 p_He3 = G4ParticleTable::GetParticleTable()->FindParticle("He3"); 83 } 83 } 84 } // namespace lightions 84 } // namespace lightions 85 85 86 namespace antilightions 86 namespace antilightions 87 { 87 { 88 static const G4ParticleDefinition* p_proton = 88 static const G4ParticleDefinition* p_proton = nullptr; 89 static const G4ParticleDefinition* p_deuteron 89 static const G4ParticleDefinition* p_deuteron = nullptr; 90 static const G4ParticleDefinition* p_triton = 90 static const G4ParticleDefinition* p_triton = nullptr; 91 static const G4ParticleDefinition* p_alpha = n 91 static const G4ParticleDefinition* p_alpha = nullptr; 92 static const G4ParticleDefinition* p_He3 = nul 92 static const G4ParticleDefinition* p_He3 = nullptr; 93 void Init() 93 void Init() 94 { 94 { 95 if (p_proton != nullptr) return; 95 if (p_proton != nullptr) return; 96 p_proton = G4ParticleTable::GetParticleTable 96 p_proton = G4ParticleTable::GetParticleTable()->FindParticle("anti_proton"); 97 p_deuteron = G4ParticleTable::GetParticleTab 97 p_deuteron = G4ParticleTable::GetParticleTable()->FindParticle("anti_deuteron"); 98 p_triton = G4ParticleTable::GetParticleTable 98 p_triton = G4ParticleTable::GetParticleTable()->FindParticle("anti_triton"); 99 p_alpha = G4ParticleTable::GetParticleTable( 99 p_alpha = G4ParticleTable::GetParticleTable()->FindParticle("anti_alpha"); 100 p_He3 = G4ParticleTable::GetParticleTable()- 100 p_He3 = G4ParticleTable::GetParticleTable()->FindParticle("anti_He3"); 101 } 101 } 102 } // namespace antilightions 102 } // namespace antilightions 103 103 104 #ifdef G4MULTITHREADED 104 #ifdef G4MULTITHREADED 105 G4Mutex G4IonTable::ionTableMutex = G4MUTEX_IN 105 G4Mutex G4IonTable::ionTableMutex = G4MUTEX_INITIALIZER; 106 #endif 106 #endif 107 107 108 // ------------------------------------------- 108 // -------------------------------------------------------------------- 109 109 110 G4IonTable::G4IonTable() 110 G4IonTable::G4IonTable() 111 { 111 { 112 fIonList = new G4IonList(); 112 fIonList = new G4IonList(); 113 113 114 // Set up the shadow pointer used by worker 114 // Set up the shadow pointer used by worker threads. 115 // 115 // 116 if (fIonListShadow == nullptr) { 116 if (fIonListShadow == nullptr) { 117 fIonListShadow = fIonList; 117 fIonListShadow = fIonList; 118 } 118 } 119 119 120 fIsotopeTableList = new std::vector<G4VIsoto 120 fIsotopeTableList = new std::vector<G4VIsotopeTable*>; 121 121 122 // Set up the shadow pointer used by worker 122 // Set up the shadow pointer used by worker threads. 123 // 123 // 124 if (fIsotopeTableListShadow == nullptr) { 124 if (fIsotopeTableListShadow == nullptr) { 125 fIsotopeTableListShadow = fIsotopeTableLis 125 fIsotopeTableListShadow = fIsotopeTableList; 126 } 126 } 127 127 128 PrepareNuclideTable(); 128 PrepareNuclideTable(); 129 RegisterIsotopeTable(pNuclideTable); 129 RegisterIsotopeTable(pNuclideTable); 130 } 130 } 131 131 132 G4IonTable::~G4IonTable() 132 G4IonTable::~G4IonTable() 133 { 133 { 134 // delete IsotopeTable if existing 134 // delete IsotopeTable if existing 135 if (fIsotopeTableList != nullptr) { 135 if (fIsotopeTableList != nullptr) { 136 for (const auto fIsotopeTable : *fIsotopeT 136 for (const auto fIsotopeTable : *fIsotopeTableList) { 137 if (fIsotopeTable != G4NuclideTable::Get 137 if (fIsotopeTable != G4NuclideTable::GetNuclideTable()) { 138 delete fIsotopeTable; 138 delete fIsotopeTable; 139 } 139 } 140 } 140 } 141 fIsotopeTableList->clear(); 141 fIsotopeTableList->clear(); 142 delete fIsotopeTableList; 142 delete fIsotopeTableList; 143 } 143 } 144 fIsotopeTableList = nullptr; 144 fIsotopeTableList = nullptr; 145 145 146 if (fIonList == nullptr) return; 146 if (fIonList == nullptr) return; 147 147 148 // remove all contents in the Ion List 148 // remove all contents in the Ion List 149 // No need to delete here because all partic 149 // No need to delete here because all particles are dynamic objects 150 fIonList->clear(); 150 fIonList->clear(); 151 delete fIonList; 151 delete fIonList; 152 fIonList = nullptr; 152 fIonList = nullptr; 153 } 153 } 154 154 155 G4IonTable* G4IonTable::GetIonTable() 155 G4IonTable* G4IonTable::GetIonTable() 156 { 156 { 157 return G4ParticleTable::GetParticleTable()-> 157 return G4ParticleTable::GetParticleTable()->GetIonTable(); 158 } 158 } 159 159 160 // Used by each worker thread to copy the cont 160 // Used by each worker thread to copy the content from the master thread 161 void G4IonTable::WorkerG4IonTable() 161 void G4IonTable::WorkerG4IonTable() 162 { 162 { 163 if (fIonList == nullptr) { 163 if (fIonList == nullptr) { 164 fIonList = new G4IonList(); 164 fIonList = new G4IonList(); 165 } 165 } 166 else { 166 else { 167 fIonList->clear(); 167 fIonList->clear(); 168 } 168 } 169 169 170 for (const auto& it : *fIonListShadow) { 170 for (const auto& it : *fIonListShadow) { 171 fIonList->insert(it); 171 fIonList->insert(it); 172 } 172 } 173 173 174 // Do not copy Isotope Table to Worker threa 174 // Do not copy Isotope Table to Worker thread 175 // 175 // 176 if (fIsotopeTableList == nullptr) { 176 if (fIsotopeTableList == nullptr) { 177 fIsotopeTableList = new std::vector<G4VIso 177 fIsotopeTableList = new std::vector<G4VIsotopeTable*>; 178 for (const auto i : *fIsotopeTableListShad 178 for (const auto i : *fIsotopeTableListShadow) { 179 fIsotopeTableList->push_back(i); 179 fIsotopeTableList->push_back(i); 180 } 180 } 181 } 181 } 182 } 182 } 183 183 184 void G4IonTable::InitializeLightIons() 184 void G4IonTable::InitializeLightIons() 185 { 185 { 186 lightions::Init(); 186 lightions::Init(); 187 antilightions::Init(); 187 antilightions::Init(); 188 } 188 } 189 189 190 void G4IonTable::DestroyWorkerG4IonTable() 190 void G4IonTable::DestroyWorkerG4IonTable() 191 { 191 { 192 // delete IsotopeTable if existing 192 // delete IsotopeTable if existing 193 if (fIsotopeTableList != nullptr) { 193 if (fIsotopeTableList != nullptr) { 194 for (auto fIsotopeTable : *fIsotopeTableLi 194 for (auto fIsotopeTable : *fIsotopeTableList) { 195 if (fIsotopeTable != G4NuclideTable::Get 195 if (fIsotopeTable != G4NuclideTable::GetNuclideTable()) { 196 delete fIsotopeTable; 196 delete fIsotopeTable; 197 } 197 } 198 } 198 } 199 fIsotopeTableList->clear(); 199 fIsotopeTableList->clear(); 200 delete fIsotopeTableList; 200 delete fIsotopeTableList; 201 } 201 } 202 fIsotopeTableList = nullptr; 202 fIsotopeTableList = nullptr; 203 203 204 if (fIonList == nullptr) return; 204 if (fIonList == nullptr) return; 205 205 206 // remove all contents in the Ion List 206 // remove all contents in the Ion List 207 // No need to delete here because all partic 207 // No need to delete here because all particles are dynamic objects 208 fIonList->clear(); 208 fIonList->clear(); 209 delete fIonList; 209 delete fIonList; 210 fIonList = nullptr; 210 fIonList = nullptr; 211 } 211 } 212 212 213 G4ParticleDefinition* G4IonTable::CreateIon(G4 213 G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4double E, 214 G4 214 G4Ions::G4FloatLevelBase flb) 215 { 215 { 216 G4ParticleDefinition* ion = nullptr; 216 G4ParticleDefinition* ion = nullptr; 217 217 218 // check whether GenericIon has processes 218 // check whether GenericIon has processes 219 G4ParticleDefinition* genericIon = G4Particl 219 G4ParticleDefinition* genericIon = G4ParticleTable::GetParticleTable()->GetGenericIon(); 220 G4ProcessManager* pman = nullptr; 220 G4ProcessManager* pman = nullptr; 221 if (genericIon != nullptr) { 221 if (genericIon != nullptr) { 222 pman = genericIon->GetProcessManager(); 222 pman = genericIon->GetProcessManager(); 223 } 223 } 224 if ((genericIon == nullptr) || (genericIon-> 224 if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0) || (pman == nullptr)) { 225 #ifdef G4VERBOSE 225 #ifdef G4VERBOSE 226 if (GetVerboseLevel() > 1) { 226 if (GetVerboseLevel() > 1) { 227 G4cout << "G4IonTable::CreateIon() : can 227 G4cout << "G4IonTable::CreateIon() : can not create ion of " 228 << " Z =" << Z << " A = " << A < 228 << " Z =" << Z << " A = " << A << " because GenericIon is not ready !!" << G4endl; 229 } 229 } 230 #endif 230 #endif 231 G4Exception("G4IonTable::CreateIon()", "PA 231 G4Exception("G4IonTable::CreateIon()", "PART105", JustWarning, 232 "Can not create ions because G 232 "Can not create ions because GenericIon is not ready"); 233 return nullptr; 233 return nullptr; 234 } 234 } 235 235 236 G4double life = 0.0; 236 G4double life = 0.0; 237 G4DecayTable* decayTable = nullptr; 237 G4DecayTable* decayTable = nullptr; 238 G4bool stable = true; 238 G4bool stable = true; 239 G4double mu = 0.0; 239 G4double mu = 0.0; 240 G4double Eex = 0.0; 240 G4double Eex = 0.0; 241 G4int lvl = 0; 241 G4int lvl = 0; 242 G4int J = 0; 242 G4int J = 0; 243 243 244 const G4IsotopeProperty* fProperty = FindIso 244 const G4IsotopeProperty* fProperty = FindIsotope(Z, A, E, flb); 245 if (fProperty != nullptr) { 245 if (fProperty != nullptr) { 246 Eex = fProperty->GetEnergy(); 246 Eex = fProperty->GetEnergy(); 247 lvl = fProperty->GetIsomerLevel(); 247 lvl = fProperty->GetIsomerLevel(); 248 J = fProperty->GetiSpin(); 248 J = fProperty->GetiSpin(); 249 life = fProperty->GetLifeTime(); 249 life = fProperty->GetLifeTime(); 250 mu = fProperty->GetMagneticMoment(); 250 mu = fProperty->GetMagneticMoment(); 251 decayTable = fProperty->GetDecayTable(); 251 decayTable = fProperty->GetDecayTable(); 252 stable = (life <= 0.) || (decayTable == nu 252 stable = (life <= 0.) || (decayTable == nullptr); 253 lvl = fProperty->GetIsomerLevel(); 253 lvl = fProperty->GetIsomerLevel(); 254 if (lvl < 0) lvl = 9; 254 if (lvl < 0) lvl = 9; 255 } 255 } 256 else { 256 else { 257 #ifdef G4VERBOSE 257 #ifdef G4VERBOSE 258 if (GetVerboseLevel() > 1) { 258 if (GetVerboseLevel() > 1) { 259 G4ExceptionDescription ed; 259 G4ExceptionDescription ed; 260 ed << "G4IonTable::CreateIon(): G4Isotop 260 ed << "G4IonTable::CreateIon(): G4IsotopeProperty object is not found for" 261 << " Z = " << Z << " A = " << A << " 261 << " Z = " << Z << " A = " << A << " E = " << E / keV << " (keV)"; 262 if (flb != G4Ions::G4FloatLevelBase::no_ 262 if (flb != G4Ions::G4FloatLevelBase::no_Float) { 263 ed << " FloatingLevel +" << G4Ions::Fl 263 ed << " FloatingLevel +" << G4Ions::FloatLevelBaseChar(flb); 264 } 264 } 265 ed << ".\n" 265 ed << ".\n" 266 << " Physics quantities such as life 266 << " Physics quantities such as life are not set for this ion."; 267 G4Exception("G4IonTable::CreateIon()", " 267 G4Exception("G4IonTable::CreateIon()", "PART70105", JustWarning, ed); 268 } 268 } 269 #endif 269 #endif 270 // excitation energy 270 // excitation energy 271 Eex = E; 271 Eex = E; 272 // lvl is assigned to 9 temporarily 272 // lvl is assigned to 9 temporarily 273 if (Eex > 0.0) lvl = 9; 273 if (Eex > 0.0) lvl = 9; 274 } 274 } 275 275 276 // Eex = G4NuclideTable::Round(Eex); 276 // Eex = G4NuclideTable::Round(Eex); 277 if (Eex == 0.0) lvl = 0; 277 if (Eex == 0.0) lvl = 0; 278 // ion name 278 // ion name 279 G4String name = ""; 279 G4String name = ""; 280 /////////////if (lvl<9) name = GetIonName(Z, 280 /////////////if (lvl<9) name = GetIonName(Z, A, lvl); 281 if (lvl == 0 && flb == G4Ions::G4FloatLevelB 281 if (lvl == 0 && flb == G4Ions::G4FloatLevelBase::no_Float) 282 name = GetIonName(Z, A, lvl); 282 name = GetIonName(Z, A, lvl); 283 else 283 else 284 name = GetIonName(Z, A, Eex, flb); 284 name = GetIonName(Z, A, Eex, flb); 285 285 286 // PDG encoding 286 // PDG encoding 287 G4int encoding = GetNucleusEncoding(Z, A, E, 287 G4int encoding = GetNucleusEncoding(Z, A, E, lvl); 288 288 289 // PDG mass 289 // PDG mass 290 G4double mass = GetNucleusMass(Z, A) + Eex; 290 G4double mass = GetNucleusMass(Z, A) + Eex; 291 291 292 // PDG charge is set to one of nucleus 292 // PDG charge is set to one of nucleus 293 G4double charge = G4double(Z) * eplus; 293 G4double charge = G4double(Z) * eplus; 294 294 295 // create an ion 295 // create an ion 296 // spin, parity, isospin values are fixed 296 // spin, parity, isospin values are fixed 297 297 298 // Request lock for particle table accesses. 298 // Request lock for particle table accesses. Some changes are inside 299 // this critical region. 299 // this critical region. 300 // 300 // 301 // clang-format off 301 // clang-format off 302 ion = new G4Ions( name, mass, 302 ion = new G4Ions( name, mass, 0.0*MeV, charge, 303 J, +1, 303 J, +1, 0, 304 0, 0, 304 0, 0, 0, 305 "nucleus", 0, 305 "nucleus", 0, A, encoding, 306 stable, life, 306 stable, life, decayTable, false, 307 "generic", 0, 307 "generic", 0, 308 Eex, lvl 308 Eex, lvl ); 309 // clang-format on 309 // clang-format on 310 310 311 // Release lock for particle table accesses. 311 // Release lock for particle table accesses. 312 // 312 // 313 ion->SetPDGMagneticMoment(mu); 313 ion->SetPDGMagneticMoment(mu); 314 static_cast<G4Ions*>(ion)->SetFloatLevelBase 314 static_cast<G4Ions*>(ion)->SetFloatLevelBase(flb); 315 315 316 // No Anti particle registered 316 // No Anti particle registered 317 ion->SetAntiPDGEncoding(0); 317 ion->SetAntiPDGEncoding(0); 318 318 319 #ifdef G4VERBOSE 319 #ifdef G4VERBOSE 320 if (GetVerboseLevel() > 1) { 320 if (GetVerboseLevel() > 1) { 321 G4cout << "G4IonTable::CreateIon() : creat 321 G4cout << "G4IonTable::CreateIon() : create ion of " << name << " " << Z << ", " << A 322 << " encoding=" << encoding; 322 << " encoding=" << encoding; 323 if (E > 0.0) { 323 if (E > 0.0) { 324 G4cout << " IsomerLVL=" << lvl << " exci 324 G4cout << " IsomerLVL=" << lvl << " excited energy=" << Eex / keV << "[keV]"; 325 } 325 } 326 G4cout << G4endl; 326 G4cout << G4endl; 327 } 327 } 328 #endif 328 #endif 329 329 330 // Add process manager to the ion 330 // Add process manager to the ion 331 AddProcessManager(ion); 331 AddProcessManager(ion); 332 332 333 #ifdef G4MULTITHREADED 333 #ifdef G4MULTITHREADED 334 // Fill decay channels if this method is inv 334 // Fill decay channels if this method is invoked from worker 335 if (G4Threading::IsWorkerThread()) { 335 if (G4Threading::IsWorkerThread()) { 336 if (!stable && (decayTable != nullptr)) { 336 if (!stable && (decayTable != nullptr)) { 337 G4int nCh = decayTable->entries(); 337 G4int nCh = decayTable->entries(); 338 for (G4int iCh = 0; iCh < nCh; ++iCh) { 338 for (G4int iCh = 0; iCh < nCh; ++iCh) { 339 decayTable->GetDecayChannel(iCh)->GetD 339 decayTable->GetDecayChannel(iCh)->GetDaughter(0); 340 } 340 } 341 } 341 } 342 } 342 } 343 #endif 343 #endif 344 344 345 return ion; 345 return ion; 346 } 346 } 347 347 348 G4ParticleDefinition* G4IonTable::CreateIon(G4 348 G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4int LL, G4double E, 349 G4 349 G4Ions::G4FloatLevelBase flb) 350 { 350 { 351 if (LL == 0) return CreateIon(Z, A, E, flb); 351 if (LL == 0) return CreateIon(Z, A, E, flb); 352 352 353 // create hyper nucleus 353 // create hyper nucleus 354 G4ParticleDefinition* ion = nullptr; 354 G4ParticleDefinition* ion = nullptr; 355 355 356 // check whether GenericIon has processes 356 // check whether GenericIon has processes 357 G4ParticleDefinition* genericIon = G4Particl 357 G4ParticleDefinition* genericIon = G4ParticleTable::GetParticleTable()->GetGenericIon(); 358 G4ProcessManager* pman = nullptr; 358 G4ProcessManager* pman = nullptr; 359 if (genericIon != nullptr) pman = genericIon 359 if (genericIon != nullptr) pman = genericIon->GetProcessManager(); 360 if ((genericIon == nullptr) || (genericIon-> 360 if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0) || (pman == nullptr)) { 361 #ifdef G4VERBOSE 361 #ifdef G4VERBOSE 362 if (GetVerboseLevel() > 1) { 362 if (GetVerboseLevel() > 1) { 363 G4cout << "G4IonTable::CreateIon() : can 363 G4cout << "G4IonTable::CreateIon() : can not create ion of " 364 << " Z =" << Z << " A = " << A < 364 << " Z =" << Z << " A = " << A << " because GenericIon is not ready !!" << G4endl; 365 } 365 } 366 #endif 366 #endif 367 G4Exception("G4IonTable::CreateIon()", "PA 367 G4Exception("G4IonTable::CreateIon()", "PART105", JustWarning, 368 "Can not create ions because G 368 "Can not create ions because GenericIon is not ready"); 369 return nullptr; 369 return nullptr; 370 } 370 } 371 371 372 G4int J = 0; 372 G4int J = 0; 373 G4double life = 0.0; 373 G4double life = 0.0; 374 G4DecayTable* decayTable = nullptr; 374 G4DecayTable* decayTable = nullptr; 375 G4bool stable = true; 375 G4bool stable = true; 376 376 377 // excitation energy 377 // excitation energy 378 // G4double Eex = G4NuclideTable::Round(E); 378 // G4double Eex = G4NuclideTable::Round(E); 379 G4double Eex = E; 379 G4double Eex = E; 380 G4double mass = GetNucleusMass(Z, A, LL) + E 380 G4double mass = GetNucleusMass(Z, A, LL) + Eex; 381 G4int lvl = 0; 381 G4int lvl = 0; 382 // lvl is assigned to 9 temporarily 382 // lvl is assigned to 9 temporarily 383 if (Eex > 0.0) lvl = 9; 383 if (Eex > 0.0) lvl = 9; 384 384 385 // PDG encoding 385 // PDG encoding 386 G4int encoding = GetNucleusEncoding(Z, A, LL 386 G4int encoding = GetNucleusEncoding(Z, A, LL, E, lvl); 387 387 388 // PDG charge is set to one of nucleus 388 // PDG charge is set to one of nucleus 389 G4double charge = G4double(Z) * eplus; 389 G4double charge = G4double(Z) * eplus; 390 390 391 // create an ion 391 // create an ion 392 // spin, parity, isospin values are fixed 392 // spin, parity, isospin values are fixed 393 // 393 // 394 // get ion name 394 // get ion name 395 G4String name = GetIonName(Z, A, LL, Eex, fl 395 G4String name = GetIonName(Z, A, LL, Eex, flb); 396 396 397 // clang-format off 397 // clang-format off 398 ion = new G4Ions( name, mass, 398 ion = new G4Ions( name, mass, 0.0*MeV, charge, 399 J, +1, 399 J, +1, 0, 400 0, 0, 400 0, 0, 0, 401 "nucleus", 0, 401 "nucleus", 0, A, encoding, 402 stable, life, 402 stable, life, decayTable, false, 403 "generic", 0, 403 "generic", 0, 404 Eex, lvl 404 Eex, lvl ); 405 // clang-format on 405 // clang-format on 406 406 407 // Release lock for particle table accesses 407 // Release lock for particle table accesses 408 408 409 G4double mu = 0.0; // magnetic moment 409 G4double mu = 0.0; // magnetic moment 410 ion->SetPDGMagneticMoment(mu); 410 ion->SetPDGMagneticMoment(mu); 411 static_cast<G4Ions*>(ion)->SetFloatLevelBase 411 static_cast<G4Ions*>(ion)->SetFloatLevelBase(flb); 412 412 413 // No Anti particle registered 413 // No Anti particle registered 414 ion->SetAntiPDGEncoding(0); 414 ion->SetAntiPDGEncoding(0); 415 415 416 #ifdef G4VERBOSE 416 #ifdef G4VERBOSE 417 if (GetVerboseLevel() > 1) { 417 if (GetVerboseLevel() > 1) { 418 G4cout << "G4IonTable::CreateIon() : creat 418 G4cout << "G4IonTable::CreateIon() : create hyper ion of " << name << " " << Z << ", " << A 419 << ", " << LL << " encoding=" << en 419 << ", " << LL << " encoding=" << encoding; 420 if (E > 0.0) { 420 if (E > 0.0) { 421 G4cout << " IsomerLVL=" << lvl << " exci 421 G4cout << " IsomerLVL=" << lvl << " excited energy=" << Eex / keV << "[keV]"; 422 } 422 } 423 G4cout << G4endl; 423 G4cout << G4endl; 424 } 424 } 425 #endif 425 #endif 426 426 427 // Add process manager to the ion 427 // Add process manager to the ion 428 AddProcessManager(ion); 428 AddProcessManager(ion); 429 429 430 return ion; 430 return ion; 431 } 431 } 432 432 433 G4ParticleDefinition* G4IonTable::CreateIon(G4 433 G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4int lvl) 434 { 434 { 435 // always create an ion for any lvl 435 // always create an ion for any lvl 436 return CreateIon(Z, A, 0.0, G4Ions::FloatLev 436 return CreateIon(Z, A, 0.0, G4Ions::FloatLevelBase(lvl)); 437 } 437 } 438 438 439 G4ParticleDefinition* G4IonTable::CreateIon(G4 439 G4ParticleDefinition* G4IonTable::CreateIon(G4int Z, G4int A, G4int LL, G4int lvl) 440 { 440 { 441 return (LL == 0) ? CreateIon(Z, A, 0.0, G4Io 441 return (LL == 0) ? CreateIon(Z, A, 0.0, G4Ions::G4FloatLevelBase(lvl)) 442 : CreateIon(Z, A, LL, 0.0, 442 : CreateIon(Z, A, LL, 0.0, G4Ions::G4FloatLevelBase::no_Float); 443 } 443 } 444 444 445 G4ParticleDefinition* G4IonTable::GetIon(G4int 445 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int lvl) 446 { 446 { 447 return GetIon(Z, A, 0.0, G4Ions::G4FloatLeve 447 return GetIon(Z, A, 0.0, G4Ions::G4FloatLevelBase(lvl), 0); 448 } 448 } 449 449 450 G4ParticleDefinition* G4IonTable::GetIon(G4int 450 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4int lvl) 451 { 451 { 452 return (LL == 0) ? GetIon(Z, A, 0.0, G4Ions: 452 return (LL == 0) ? GetIon(Z, A, 0.0, G4Ions::G4FloatLevelBase(lvl), 0) 453 : GetIon(Z, A, LL, 0.0, G4I 453 : GetIon(Z, A, LL, 0.0, G4Ions::G4FloatLevelBase::no_Float, 0); 454 } 454 } 455 455 456 G4ParticleDefinition* G4IonTable::GetIon(G4int 456 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4double E, G4int J) 457 { 457 { 458 return GetIon(Z, A, E, G4Ions::G4FloatLevelB 458 return GetIon(Z, A, E, G4Ions::G4FloatLevelBase::no_Float, J); 459 } 459 } 460 460 461 G4ParticleDefinition* G4IonTable::GetIon(G4int 461 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4double E, char flbChar, G4int J) 462 { 462 { 463 return GetIon(Z, A, E, G4Ions::FloatLevelBas 463 return GetIon(Z, A, E, G4Ions::FloatLevelBase(flbChar), J); 464 } 464 } 465 465 466 G4ParticleDefinition* G4IonTable::GetIon(G4int 466 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4double E, G4Ions::G4FloatLevelBase flb, 467 G4int 467 G4int J) 468 { 468 { 469 if ((A < 1) || (Z <= 0) || (E < 0.0) || (A > 469 if ((A < 1) || (Z <= 0) || (E < 0.0) || (A > 999) || (J < 0)) { 470 #ifdef G4VERBOSE 470 #ifdef G4VERBOSE 471 if (GetVerboseLevel() > 0) { 471 if (GetVerboseLevel() > 0) { 472 G4cout << "G4IonTable::GetIon() : illega 472 G4cout << "G4IonTable::GetIon() : illegal atomic number/mass" 473 << " Z =" << Z << " A = " << A < 473 << " Z =" << Z << " A = " << A << " E = " << E / keV << G4endl; 474 } 474 } 475 #endif 475 #endif 476 return nullptr; 476 return nullptr; 477 } 477 } 478 auto flb1 = flb; 478 auto flb1 = flb; 479 479 480 // Search ions with A, Z 480 // Search ions with A, Z 481 G4ParticleDefinition* ion = FindIon(Z, A, E, 481 G4ParticleDefinition* ion = FindIon(Z, A, E, flb, J); 482 482 483 // find out ground state floating level 483 // find out ground state floating level 484 if (ion == nullptr && E == 0.0) { 484 if (ion == nullptr && E == 0.0) { 485 const G4IsotopeProperty* fProperty = FindI 485 const G4IsotopeProperty* fProperty = FindIsotope(Z, A, E, flb); 486 if (nullptr != fProperty) { 486 if (nullptr != fProperty) { 487 flb1 = fProperty->GetFloatLevelBase(); 487 flb1 = fProperty->GetFloatLevelBase(); 488 if (flb != flb1) { 488 if (flb != flb1) { 489 ion = FindIon(Z, A, E, flb1, J); 489 ion = FindIon(Z, A, E, flb1, J); 490 } 490 } 491 } 491 } 492 } 492 } 493 493 494 // create ion 494 // create ion 495 #ifdef G4MULTITHREADED 495 #ifdef G4MULTITHREADED 496 if (ion == nullptr) { 496 if (ion == nullptr) { 497 if (G4Threading::IsWorkerThread()) { 497 if (G4Threading::IsWorkerThread()) { 498 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 498 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 499 ion = FindIonInMaster(Z, A, E, flb1, J); 499 ion = FindIonInMaster(Z, A, E, flb1, J); 500 if (ion == nullptr) ion = CreateIon(Z, A 500 if (ion == nullptr) ion = CreateIon(Z, A, E, flb1); 501 InsertWorker(ion); 501 InsertWorker(ion); 502 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex 502 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex); 503 } 503 } 504 else { 504 else { 505 ion = CreateIon(Z, A, E, flb1); 505 ion = CreateIon(Z, A, E, flb1); 506 } 506 } 507 } 507 } 508 #else 508 #else 509 if (ion == nullptr) ion = CreateIon(Z, A, E, 509 if (ion == nullptr) ion = CreateIon(Z, A, E, flb1); 510 #endif 510 #endif 511 511 512 return ion; 512 return ion; 513 } 513 } 514 514 515 G4ParticleDefinition* G4IonTable::GetIon(G4int 515 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E, G4int J) 516 { 516 { 517 return GetIon(Z, A, LL, E, G4Ions::G4FloatLe 517 return GetIon(Z, A, LL, E, G4Ions::G4FloatLevelBase::no_Float, J); 518 } 518 } 519 519 520 G4ParticleDefinition* G4IonTable::GetIon(G4int 520 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E, char flbChar, 521 G4int 521 G4int J) 522 { 522 { 523 return GetIon(Z, A, LL, E, G4Ions::FloatLeve 523 return GetIon(Z, A, LL, E, G4Ions::FloatLevelBase(flbChar), J); 524 } 524 } 525 525 526 G4ParticleDefinition* G4IonTable::GetIon(G4int 526 G4ParticleDefinition* G4IonTable::GetIon(G4int Z, G4int A, G4int LL, G4double E, 527 G4Ion 527 G4Ions::G4FloatLevelBase flb, G4int J) 528 { 528 { 529 if (LL == 0) return GetIon(Z, A, E, flb, J); 529 if (LL == 0) return GetIon(Z, A, E, flb, J); 530 530 531 if (A < 2 || Z < 0 || Z > A - LL || LL > A | 531 if (A < 2 || Z < 0 || Z > A - LL || LL > A || A > 999) { 532 #ifdef G4VERBOSE 532 #ifdef G4VERBOSE 533 if (GetVerboseLevel() > 0) { 533 if (GetVerboseLevel() > 0) { 534 G4cout << "G4IonTable::GetIon() : illega 534 G4cout << "G4IonTable::GetIon() : illegal atomic number/mass" 535 << " Z =" << Z << " A = " << A < 535 << " Z =" << Z << " A = " << A << " L = " << LL << " E = " << E / keV << G4endl; 536 } 536 } 537 #endif 537 #endif 538 return nullptr; 538 return nullptr; 539 } 539 } 540 if (A == 2) { 540 if (A == 2) { 541 #ifdef G4VERBOSE 541 #ifdef G4VERBOSE 542 if (GetVerboseLevel() > 0) { 542 if (GetVerboseLevel() > 0) { 543 G4cout << "G4IonTable::GetIon() : No bou 543 G4cout << "G4IonTable::GetIon() : No boud state for " 544 << " Z =" << Z << " A = " << A < 544 << " Z =" << Z << " A = " << A << " L = " << LL << " E = " << E / keV << G4endl; 545 } 545 } 546 #endif 546 #endif 547 return nullptr; 547 return nullptr; 548 } 548 } 549 549 550 // Search ions with A, Z 550 // Search ions with A, Z 551 G4ParticleDefinition* ion = FindIon(Z, A, LL 551 G4ParticleDefinition* ion = FindIon(Z, A, LL, E, flb, J); 552 552 553 // create ion 553 // create ion 554 #ifdef G4MULTITHREADED 554 #ifdef G4MULTITHREADED 555 if (ion == nullptr) { 555 if (ion == nullptr) { 556 if (G4Threading::IsWorkerThread()) { 556 if (G4Threading::IsWorkerThread()) { 557 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 557 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 558 ion = FindIonInMaster(Z, A, LL, E, flb, 558 ion = FindIonInMaster(Z, A, LL, E, flb, J); 559 if (ion == nullptr) ion = CreateIon(Z, A 559 if (ion == nullptr) ion = CreateIon(Z, A, LL, E, flb); 560 InsertWorker(ion); 560 InsertWorker(ion); 561 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex 561 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex); 562 } 562 } 563 else { 563 else { 564 ion = CreateIon(Z, A, LL, E, flb); 564 ion = CreateIon(Z, A, LL, E, flb); 565 } 565 } 566 } 566 } 567 #else 567 #else 568 if (ion == nullptr) ion = CreateIon(Z, A, LL 568 if (ion == nullptr) ion = CreateIon(Z, A, LL, E, flb); 569 #endif 569 #endif 570 570 571 return ion; 571 return ion; 572 } 572 } 573 573 574 G4ParticleDefinition* G4IonTable::GetIon(G4int 574 G4ParticleDefinition* G4IonTable::GetIon(G4int encoding) 575 { 575 { 576 G4int Z, A, LL, IsoLvl; 576 G4int Z, A, LL, IsoLvl; 577 G4double E; 577 G4double E; 578 if (!GetNucleusByEncoding(encoding, Z, A, LL 578 if (!GetNucleusByEncoding(encoding, Z, A, LL, E, IsoLvl)) { 579 #ifdef G4VERBOSE 579 #ifdef G4VERBOSE 580 if (GetVerboseLevel() > 0) { 580 if (GetVerboseLevel() > 0) { 581 G4cout << "G4IonTable::GetIon() : illega 581 G4cout << "G4IonTable::GetIon() : illegal encoding" 582 << " CODE:" << encoding << G4endl 582 << " CODE:" << encoding << G4endl; 583 } 583 } 584 #endif 584 #endif 585 G4Exception("G4IonTable::GetIon()", "PART1 585 G4Exception("G4IonTable::GetIon()", "PART106", JustWarning, "illegal encoding for an ion"); 586 return nullptr; 586 return nullptr; 587 } 587 } 588 return GetIon(Z, A, LL, IsoLvl); 588 return GetIon(Z, A, LL, IsoLvl); 589 } 589 } 590 590 591 G4ParticleDefinition* G4IonTable::FindIon(G4in 591 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4double E, G4int J) 592 { 592 { 593 return FindIon(Z, A, E, G4Ions::G4FloatLevel 593 return FindIon(Z, A, E, G4Ions::G4FloatLevelBase::no_Float, J); 594 } 594 } 595 595 596 G4ParticleDefinition* G4IonTable::FindIon(G4in 596 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4double E, char flbChar, G4int J) 597 { 597 { 598 return FindIon(Z, A, E, G4Ions::FloatLevelBa 598 return FindIon(Z, A, E, G4Ions::FloatLevelBase(flbChar), J); 599 } 599 } 600 600 601 G4ParticleDefinition* G4IonTable::FindIon(G4in 601 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4double E, 602 G4Io 602 G4Ions::G4FloatLevelBase flb, G4int J) 603 { 603 { 604 if ((A < 1) || (Z <= 0) || (J < 0) || (E < 0 604 if ((A < 1) || (Z <= 0) || (J < 0) || (E < 0.0) || (A > 999)) { 605 #ifdef G4VERBOSE 605 #ifdef G4VERBOSE 606 if (GetVerboseLevel() > 0) { 606 if (GetVerboseLevel() > 0) { 607 G4cout << "G4IonTable::FindIon(): illega 607 G4cout << "G4IonTable::FindIon(): illegal atomic number/mass" 608 << " or excitation level:" << G4e 608 << " or excitation level:" << G4endl << " Z =" << Z << " A = " << A 609 << " E = " << E / keV << G4endl; 609 << " E = " << E / keV << G4endl; 610 } 610 } 611 #endif 611 #endif 612 G4Exception("G4IonTable::FindIon()", "PART 612 G4Exception("G4IonTable::FindIon()", "PART107", JustWarning, "illegal atomic number/mass"); 613 return nullptr; 613 return nullptr; 614 } 614 } 615 // Search ions with A, Z ,E 615 // Search ions with A, Z ,E 616 // !! J is omitted now !! 616 // !! J is omitted now !! 617 const G4ParticleDefinition* ion = nullptr; 617 const G4ParticleDefinition* ion = nullptr; 618 G4bool isFound = false; 618 G4bool isFound = false; 619 619 620 // check if light ion 620 // check if light ion 621 ion = GetLightIon(Z, A); 621 ion = GetLightIon(Z, A); 622 if (ion != nullptr && E == 0.0) { 622 if (ion != nullptr && E == 0.0) { 623 // light ion 623 // light ion 624 isFound = true; 624 isFound = true; 625 } 625 } 626 else { 626 else { 627 // -- loop over all particles in Ion table 627 // -- loop over all particles in Ion table 628 G4int encoding = GetNucleusEncoding(Z, A); 628 G4int encoding = GetNucleusEncoding(Z, A); 629 const G4ParticleDefinition* ion1 = nullptr 629 const G4ParticleDefinition* ion1 = nullptr; 630 for (auto i = fIonList->find(encoding); i 630 for (auto i = fIonList->find(encoding); i != fIonList->cend(); ++i) { 631 ion = i->second; 631 ion = i->second; 632 if ((ion->GetAtomicNumber() != Z) || (io 632 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 633 // excitation level 633 // excitation level 634 G4double anExcitaionEnergy = ((const G4I 634 G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy(); 635 635 636 if (std::fabs(E - anExcitaionEnergy) < p 636 if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance()) { 637 if (nullptr == ion1) ion1 = ion; 637 if (nullptr == ion1) ion1 = ion; 638 if (((const G4Ions*)(ion))->GetFloatLe 638 if (((const G4Ions*)(ion))->GetFloatLevelBase() == flb) { 639 isFound = true; 639 isFound = true; 640 break; 640 break; 641 } 641 } 642 } 642 } 643 } 643 } 644 // rerun search on ground level without ch 644 // rerun search on ground level without check on floating 645 if (!isFound && E == 0.0 && nullptr != ion 645 if (!isFound && E == 0.0 && nullptr != ion1) { 646 isFound = true; 646 isFound = true; 647 ion = ion1; 647 ion = ion1; 648 } 648 } 649 } 649 } 650 650 651 if (isFound) { 651 if (isFound) { 652 return const_cast<G4ParticleDefinition*>(i 652 return const_cast<G4ParticleDefinition*>(ion); 653 } 653 } 654 654 655 return nullptr; 655 return nullptr; 656 } 656 } 657 657 658 G4ParticleDefinition* G4IonTable::FindIon(G4in 658 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E, G4int J) 659 { 659 { 660 return (LL == 0) ? FindIon(Z, A, E, G4Ions:: 660 return (LL == 0) ? FindIon(Z, A, E, G4Ions::G4FloatLevelBase::no_Float, J) 661 : FindIon(Z, A, LL, E, G4Io 661 : FindIon(Z, A, LL, E, G4Ions::G4FloatLevelBase::no_Float, J); 662 } 662 } 663 663 664 G4ParticleDefinition* G4IonTable::FindIon(G4in 664 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E, char flbChar, 665 G4in 665 G4int J) 666 { 666 { 667 return FindIon(Z, A, LL, E, G4Ions::FloatLev 667 return FindIon(Z, A, LL, E, G4Ions::FloatLevelBase(flbChar), J); 668 } 668 } 669 669 670 G4ParticleDefinition* G4IonTable::FindIon(G4in 670 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4double E, 671 G4Io 671 G4Ions::G4FloatLevelBase flb, G4int J) 672 { 672 { 673 if (LL == 0) return FindIon(Z, A, E, flb, J) 673 if (LL == 0) return FindIon(Z, A, E, flb, J); 674 674 675 if (A < 2 || Z < 0 || Z > A - LL || LL > A | 675 if (A < 2 || Z < 0 || Z > A - LL || LL > A || A > 999) { 676 #ifdef G4VERBOSE 676 #ifdef G4VERBOSE 677 if (GetVerboseLevel() > 0) { 677 if (GetVerboseLevel() > 0) { 678 G4cout << "G4IonTable::FindIon(): illega 678 G4cout << "G4IonTable::FindIon(): illegal atomic number/mass" 679 << " or excitation level:" << G4e 679 << " or excitation level:" << G4endl << " Z =" << Z << " A = " << A << " L = " << LL 680 << " E = " << E / keV << G4endl; 680 << " E = " << E / keV << G4endl; 681 } 681 } 682 #endif 682 #endif 683 G4Exception("G4IonTable::FindIon()", "PART 683 G4Exception("G4IonTable::FindIon()", "PART107", JustWarning, "illegal atomic number/mass"); 684 return nullptr; 684 return nullptr; 685 } 685 } 686 // Search ions with A, Z ,E 686 // Search ions with A, Z ,E 687 // !! J is omitted now !! 687 // !! J is omitted now !! 688 const G4ParticleDefinition* ion = nullptr; 688 const G4ParticleDefinition* ion = nullptr; 689 G4bool isFound = false; 689 G4bool isFound = false; 690 690 691 // -- loop over all particles in Ion table 691 // -- loop over all particles in Ion table 692 G4int encoding = GetNucleusEncoding(Z, A, LL 692 G4int encoding = GetNucleusEncoding(Z, A, LL, 0.0, 0); 693 for (auto i = fIonList->find(encoding); i != 693 for (auto i = fIonList->find(encoding); i != fIonList->cend(); ++i) { 694 ion = i->second; 694 ion = i->second; 695 if ((ion->GetAtomicNumber() != Z) || (ion- 695 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 696 if (ion->GetQuarkContent(3) != LL) break; 696 if (ion->GetQuarkContent(3) != LL) break; 697 // excitation level 697 // excitation level 698 G4double anExcitaionEnergy = ((const G4Ion 698 G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy(); 699 if (std::fabs(E - anExcitaionEnergy) < pNu 699 if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance()) { 700 if (((const G4Ions*)(ion))->GetFloatLeve 700 if (((const G4Ions*)(ion))->GetFloatLevelBase() == flb) { 701 isFound = true; 701 isFound = true; 702 break; 702 break; 703 } 703 } 704 } 704 } 705 } 705 } 706 706 707 if (isFound) { 707 if (isFound) { 708 return const_cast<G4ParticleDefinition*>(i 708 return const_cast<G4ParticleDefinition*>(ion); 709 } 709 } 710 710 711 return nullptr; 711 return nullptr; 712 } 712 } 713 713 714 G4ParticleDefinition* G4IonTable::FindIon(G4in 714 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int lvl) 715 { 715 { 716 return FindIon(Z, A, 0.0, G4Ions::FloatLevel 716 return FindIon(Z, A, 0.0, G4Ions::FloatLevelBase(lvl), 0); 717 } 717 } 718 718 719 G4ParticleDefinition* G4IonTable::FindIon(G4in 719 G4ParticleDefinition* G4IonTable::FindIon(G4int Z, G4int A, G4int LL, G4int lvl) 720 { 720 { 721 return (LL == 0) ? FindIon(Z, A, 0.0, G4Ions 721 return (LL == 0) ? FindIon(Z, A, 0.0, G4Ions::FloatLevelBase(lvl), 0) 722 : FindIon(Z, A, LL, 0.0, G4 722 : FindIon(Z, A, LL, 0.0, G4Ions::G4FloatLevelBase::no_Float, 0); 723 } 723 } 724 724 725 G4int G4IonTable::GetNucleusEncoding(G4int Z, 725 G4int G4IonTable::GetNucleusEncoding(G4int Z, G4int A, G4double E, G4int lvl) 726 { 726 { 727 // PDG code for Ions 727 // PDG code for Ions 728 // Nuclear codes are given as 10-digit numbe 728 // Nuclear codes are given as 10-digit numbers +-100ZZZAAAI. 729 // For a nucleus consisting of np protons an 729 // For a nucleus consisting of np protons and nn neutrons 730 // A = np + nn and Z = np. 730 // A = np + nn and Z = np. 731 // I gives the isomer level, with I = 0 corr 731 // I gives the isomer level, with I = 0 corresponding 732 // to the ground state and I >0 to excitatio 732 // to the ground state and I >0 to excitations 733 733 734 if (Z == 1 && A == 1 && E == 0.0) return 221 734 if (Z == 1 && A == 1 && E == 0.0) return 2212; // proton 735 735 736 G4int encoding = 1000000000; 736 G4int encoding = 1000000000; 737 encoding += Z * 10000; 737 encoding += Z * 10000; 738 encoding += A * 10; 738 encoding += A * 10; 739 if (lvl > 0 && lvl < 10) 739 if (lvl > 0 && lvl < 10) 740 encoding += lvl; // isomer level 740 encoding += lvl; // isomer level 741 else if (E > 0.0) 741 else if (E > 0.0) 742 encoding += 9; // isomer level 742 encoding += 9; // isomer level 743 743 744 return encoding; 744 return encoding; 745 } 745 } 746 746 747 G4int G4IonTable::GetNucleusEncoding(G4int Z, 747 G4int G4IonTable::GetNucleusEncoding(G4int Z, G4int A, G4int LL, G4double E, G4int lvl) 748 { 748 { 749 // Get PDG code for Hyper-Nucleus Ions 749 // Get PDG code for Hyper-Nucleus Ions 750 // Nuclear codes are given as 10-digit numbe 750 // Nuclear codes are given as 10-digit numbers +-10LZZZAAAI. 751 // For a nucleus consisting of np protons an 751 // For a nucleus consisting of np protons and nn neutrons 752 // A = np + nn +nlambda and Z = np. 752 // A = np + nn +nlambda and Z = np. 753 // LL = nlambda 753 // LL = nlambda 754 // I gives the isomer level, with I = 0 corr 754 // I gives the isomer level, with I = 0 corresponding 755 // to the ground state and I >0 to excitatio 755 // to the ground state and I >0 to excitations 756 756 757 G4int encoding = GetNucleusEncoding(Z, A, E, 757 G4int encoding = GetNucleusEncoding(Z, A, E, lvl); 758 if (LL == 0) return encoding; 758 if (LL == 0) return encoding; 759 encoding += LL * 10000000; 759 encoding += LL * 10000000; 760 if (Z == 1 && A == 1 && E == 0.0) encoding = 760 if (Z == 1 && A == 1 && E == 0.0) encoding = 3122; // Lambda 761 761 762 return encoding; 762 return encoding; 763 } 763 } 764 764 765 G4bool G4IonTable::GetNucleusByEncoding(G4int 765 G4bool G4IonTable::GetNucleusByEncoding(G4int encoding, G4int& Z, G4int& A, G4double& E, G4int& lvl) 766 { 766 { 767 if (encoding <= 0) return false; // anti pa 767 if (encoding <= 0) return false; // anti particle 768 768 769 if (encoding == 2212) // proton 769 if (encoding == 2212) // proton 770 { 770 { 771 Z = 1; 771 Z = 1; 772 A = 1; 772 A = 1; 773 E = 0.0; 773 E = 0.0; 774 lvl = 0; 774 lvl = 0; 775 return true; 775 return true; 776 } 776 } 777 777 778 encoding -= 1000000000; 778 encoding -= 1000000000; 779 Z = encoding / 10000; 779 Z = encoding / 10000; 780 encoding -= 10000 * Z; 780 encoding -= 10000 * Z; 781 A = encoding / 10; 781 A = encoding / 10; 782 lvl = encoding % 10; 782 lvl = encoding % 10; 783 return true; 783 return true; 784 } 784 } 785 785 786 G4bool G4IonTable::GetNucleusByEncoding(G4int 786 G4bool G4IonTable::GetNucleusByEncoding(G4int encoding, G4int& Z, G4int& A, G4int& LL, G4double& E, 787 G4int& 787 G4int& lvl) 788 { 788 { 789 if (encoding <= 0) return false; // anti pa 789 if (encoding <= 0) return false; // anti particle 790 790 791 if (encoding == 3122) // Lambda 791 if (encoding == 3122) // Lambda 792 { 792 { 793 Z = 1; 793 Z = 1; 794 A = 1; 794 A = 1; 795 LL = 1; 795 LL = 1; 796 E = 0.0; 796 E = 0.0; 797 lvl = 0; 797 lvl = 0; 798 return true; 798 return true; 799 } 799 } 800 800 801 if (encoding % 10 != 0) { 801 if (encoding % 10 != 0) { 802 // !!!not supported for excitation states 802 // !!!not supported for excitation states !!! 803 return false; 803 return false; 804 } 804 } 805 if (encoding < 1000000000) { 805 if (encoding < 1000000000) { 806 // anti particle 806 // anti particle 807 return false; 807 return false; 808 } 808 } 809 809 810 encoding -= 1000000000; 810 encoding -= 1000000000; 811 LL = encoding / 10000000; 811 LL = encoding / 10000000; 812 encoding -= 10000000 * LL; 812 encoding -= 10000000 * LL; 813 Z = encoding / 10000; 813 Z = encoding / 10000; 814 encoding -= 10000 * Z; 814 encoding -= 10000 * Z; 815 A = encoding / 10; 815 A = encoding / 10; 816 lvl = encoding % 10; 816 lvl = encoding % 10; 817 return true; 817 return true; 818 } 818 } 819 819 820 G4String G4IonTable::GetIonName(G4int Z, G4int 820 G4String G4IonTable::GetIonName(G4int Z, G4int A, G4double E, 821 G4Ions::G4Floa 821 G4Ions::G4FloatLevelBase flb) const 822 { 822 { 823 G4String name = GetIonName(Z, A, 0); 823 G4String name = GetIonName(Z, A, 0); 824 824 825 // Excited energy or floating level 825 // Excited energy or floating level 826 if (E > 0 || flb != G4Ions::G4FloatLevelBase 826 if (E > 0 || flb != G4Ions::G4FloatLevelBase::no_Float) { 827 std::ostringstream os; 827 std::ostringstream os; 828 os.setf(std::ios::fixed); 828 os.setf(std::ios::fixed); 829 os.precision(3); 829 os.precision(3); 830 // Excited nucleus 830 // Excited nucleus 831 os << '[' << E / keV; 831 os << '[' << E / keV; 832 if (flb != G4Ions::G4FloatLevelBase::no_Fl 832 if (flb != G4Ions::G4FloatLevelBase::no_Float) { 833 os << G4Ions::FloatLevelBaseChar(flb); 833 os << G4Ions::FloatLevelBaseChar(flb); 834 } 834 } 835 os << ']'; 835 os << ']'; 836 name += os.str(); 836 name += os.str(); 837 } 837 } 838 838 839 return name; 839 return name; 840 } 840 } 841 841 842 G4String G4IonTable::GetIonName(G4int Z, G4int 842 G4String G4IonTable::GetIonName(G4int Z, G4int A, G4int LL, G4double E, 843 G4Ions::G4Floa 843 G4Ions::G4FloatLevelBase flb) const 844 { 844 { 845 if (LL == 0) return GetIonName(Z, A, E, flb) 845 if (LL == 0) return GetIonName(Z, A, E, flb); 846 G4String name = ""; 846 G4String name = ""; 847 for (G4int i = 0; i < LL; ++i) { 847 for (G4int i = 0; i < LL; ++i) { 848 name += "L"; 848 name += "L"; 849 } 849 } 850 name += GetIonName(Z, A, E, flb); 850 name += GetIonName(Z, A, E, flb); 851 return name; 851 return name; 852 } 852 } 853 853 854 G4String G4IonTable::GetIonName(G4int Z, G4int 854 G4String G4IonTable::GetIonName(G4int Z, G4int A, G4int lvl) const 855 { 855 { 856 std::ostringstream os; 856 std::ostringstream os; 857 857 858 // Atomic number 858 // Atomic number 859 if ((0 < Z) && (Z <= numberOfElements)) { 859 if ((0 < Z) && (Z <= numberOfElements)) { 860 os << elementName[Z - 1]; 860 os << elementName[Z - 1]; 861 } 861 } 862 else { 862 else { 863 os << "E" << Z << "-"; 863 os << "E" << Z << "-"; 864 } 864 } 865 // Atomic Mass 865 // Atomic Mass 866 os << A; 866 os << A; 867 867 868 if (lvl > 0) { 868 if (lvl > 0) { 869 // Isomer level for Excited nucelus 869 // Isomer level for Excited nucelus 870 os << '[' << lvl << ']'; 870 os << '[' << lvl << ']'; 871 } 871 } 872 G4String name = os.str(); 872 G4String name = os.str(); 873 return name; 873 return name; 874 } 874 } 875 875 876 G4String G4IonTable::GetIonName(G4int Z, G4int 876 G4String G4IonTable::GetIonName(G4int Z, G4int A, G4int LL, G4int lvl) const 877 { 877 { 878 if (LL == 0) return GetIonName(Z, A, lvl); 878 if (LL == 0) return GetIonName(Z, A, lvl); 879 G4String name = ""; 879 G4String name = ""; 880 for (G4int i = 0; i < LL; ++i) { 880 for (G4int i = 0; i < LL; ++i) { 881 name += "L"; 881 name += "L"; 882 } 882 } 883 name += GetIonName(Z, A, lvl); 883 name += GetIonName(Z, A, lvl); 884 return name; 884 return name; 885 } 885 } 886 886 887 G4bool G4IonTable::IsIon(const G4ParticleDefin 887 G4bool G4IonTable::IsIon(const G4ParticleDefinition* particle) 888 { 888 { 889 // Return true if the particle is ion 889 // Return true if the particle is ion 890 static const G4String nucleus("nucleus"); 890 static const G4String nucleus("nucleus"); 891 static const G4String proton("proton"); 891 static const G4String proton("proton"); 892 892 893 // Neutron is not ion 893 // Neutron is not ion 894 if ((particle->GetAtomicMass() > 0) && (part 894 if ((particle->GetAtomicMass() > 0) && (particle->GetAtomicNumber() > 0)) { 895 return particle->GetBaryonNumber() > 0; 895 return particle->GetBaryonNumber() > 0; 896 } 896 } 897 897 898 // Particles derived from G4Ions 898 // Particles derived from G4Ions 899 if (particle->GetParticleType() == nucleus) 899 if (particle->GetParticleType() == nucleus) return true; 900 900 901 // Proton (Hydrogen nucleus) 901 // Proton (Hydrogen nucleus) 902 if (particle->GetParticleName() == proton) r 902 if (particle->GetParticleName() == proton) return true; 903 903 904 return false; 904 return false; 905 } 905 } 906 906 907 G4bool G4IonTable::IsAntiIon(const G4ParticleD 907 G4bool G4IonTable::IsAntiIon(const G4ParticleDefinition* particle) 908 { 908 { 909 // Return true if the particle is ion 909 // Return true if the particle is ion 910 static const G4String anti_nucleus("anti_nuc 910 static const G4String anti_nucleus("anti_nucleus"); 911 static const G4String anti_proton("anti_prot 911 static const G4String anti_proton("anti_proton"); 912 912 913 // Anti_neutron is not ion 913 // Anti_neutron is not ion 914 if ((particle->GetAtomicMass() > 0) && (part 914 if ((particle->GetAtomicMass() > 0) && (particle->GetAtomicNumber() > 0)) { 915 return particle->GetBaryonNumber() < 0; 915 return particle->GetBaryonNumber() < 0; 916 } 916 } 917 917 918 // Particles derived from G4Ions 918 // Particles derived from G4Ions 919 if (particle->GetParticleType() == anti_nucl 919 if (particle->GetParticleType() == anti_nucleus) return true; 920 920 921 // Anti_proton (Anti_Hydrogen nucleus) 921 // Anti_proton (Anti_Hydrogen nucleus) 922 if (particle->GetParticleName() == anti_prot 922 if (particle->GetParticleName() == anti_proton) return true; 923 923 924 return false; 924 return false; 925 } 925 } 926 926 927 G4bool G4IonTable::IsLightIon(const G4Particle 927 G4bool G4IonTable::IsLightIon(const G4ParticleDefinition* particle) const 928 { 928 { 929 static const std::string names[] = {"proton" 929 static const std::string names[] = {"proton", "alpha", "deuteron", "triton", "He3"}; 930 930 931 // Return true if the particle is pre-define 931 // Return true if the particle is pre-defined ion 932 return std::find(names, names + 5, (particle 932 return std::find(names, names + 5, (particle->GetParticleName()).c_str()) != names + 5; 933 } 933 } 934 934 935 G4bool G4IonTable::IsLightAntiIon(const G4Part 935 G4bool G4IonTable::IsLightAntiIon(const G4ParticleDefinition* particle) const 936 { 936 { 937 static const std::string names[] = {"anti_pr 937 static const std::string names[] = {"anti_proton", "anti_alpha", "anti_deuteron", "anti_triton", 938 "anti_He 938 "anti_He3"}; 939 939 940 // Return true if the particle is pre-define 940 // Return true if the particle is pre-defined ion 941 return std::find(names, names + 5, (particle 941 return std::find(names, names + 5, (particle->GetParticleName()).c_str()) != names + 5; 942 } 942 } 943 943 944 G4ParticleDefinition* G4IonTable::GetLightIon( 944 G4ParticleDefinition* G4IonTable::GetLightIon(G4int Z, G4int A) const 945 { 945 { 946 // Returns pointer to pre-defined ions 946 // Returns pointer to pre-defined ions 947 const G4ParticleDefinition* ion = nullptr; 947 const G4ParticleDefinition* ion = nullptr; 948 if ((Z <= 2)) { 948 if ((Z <= 2)) { 949 #ifndef G4MULTITHREADED 949 #ifndef G4MULTITHREADED 950 // In sequential use lazy-initialization 950 // In sequential use lazy-initialization 951 lightions::Init(); 951 lightions::Init(); 952 #endif 952 #endif 953 if ((Z == 1) && (A == 1)) { 953 if ((Z == 1) && (A == 1)) { 954 ion = lightions::p_proton; 954 ion = lightions::p_proton; 955 } 955 } 956 else if ((Z == 1) && (A == 2)) { 956 else if ((Z == 1) && (A == 2)) { 957 ion = lightions::p_deuteron; 957 ion = lightions::p_deuteron; 958 } 958 } 959 else if ((Z == 1) && (A == 3)) { 959 else if ((Z == 1) && (A == 3)) { 960 ion = lightions::p_triton; 960 ion = lightions::p_triton; 961 } 961 } 962 else if ((Z == 2) && (A == 4)) { 962 else if ((Z == 2) && (A == 4)) { 963 ion = lightions::p_alpha; 963 ion = lightions::p_alpha; 964 } 964 } 965 else if ((Z == 2) && (A == 3)) { 965 else if ((Z == 2) && (A == 3)) { 966 ion = lightions::p_He3; 966 ion = lightions::p_He3; 967 } 967 } 968 } 968 } 969 return const_cast<G4ParticleDefinition*>(ion 969 return const_cast<G4ParticleDefinition*>(ion); 970 } 970 } 971 971 972 G4ParticleDefinition* G4IonTable::GetLightAnti 972 G4ParticleDefinition* G4IonTable::GetLightAntiIon(G4int Z, G4int A) const 973 { 973 { 974 // Returns pointer to pre-defined ions 974 // Returns pointer to pre-defined ions 975 const G4ParticleDefinition* ion = nullptr; 975 const G4ParticleDefinition* ion = nullptr; 976 if ((Z <= 2)) { 976 if ((Z <= 2)) { 977 #ifndef G4MULTITHREADED 977 #ifndef G4MULTITHREADED 978 // In sequential use lazy-initialization 978 // In sequential use lazy-initialization 979 antilightions::Init(); 979 antilightions::Init(); 980 #endif 980 #endif 981 if ((Z == 1) && (A == 1)) { 981 if ((Z == 1) && (A == 1)) { 982 ion = antilightions::p_proton; 982 ion = antilightions::p_proton; 983 } 983 } 984 else if ((Z == 1) && (A == 2)) { 984 else if ((Z == 1) && (A == 2)) { 985 ion = antilightions::p_deuteron; 985 ion = antilightions::p_deuteron; 986 } 986 } 987 else if ((Z == 1) && (A == 3)) { 987 else if ((Z == 1) && (A == 3)) { 988 ion = antilightions::p_triton; 988 ion = antilightions::p_triton; 989 } 989 } 990 else if ((Z == 2) && (A == 4)) { 990 else if ((Z == 2) && (A == 4)) { 991 ion = antilightions::p_alpha; 991 ion = antilightions::p_alpha; 992 } 992 } 993 else if ((Z == 2) && (A == 3)) { 993 else if ((Z == 2) && (A == 3)) { 994 ion = antilightions::p_He3; 994 ion = antilightions::p_He3; 995 } 995 } 996 } 996 } 997 return const_cast<G4ParticleDefinition*>(ion 997 return const_cast<G4ParticleDefinition*>(ion); 998 } 998 } 999 999 1000 G4double G4IonTable::GetNucleusMass(G4int Z, 1000 G4double G4IonTable::GetNucleusMass(G4int Z, G4int A, G4int LL, G4int lvl) const 1001 { 1001 { 1002 if ((A < 1) || (Z < 0) || (LL < 0) || (lvl 1002 if ((A < 1) || (Z < 0) || (LL < 0) || (lvl < 0) || (lvl > 9)) { 1003 #ifdef G4VERBOSE 1003 #ifdef G4VERBOSE 1004 if (GetVerboseLevel() > 0) { 1004 if (GetVerboseLevel() > 0) { 1005 G4cout << "G4IonTable::GetNucleusMass() 1005 G4cout << "G4IonTable::GetNucleusMass() : illegal atomic number/mass:" << G4endl 1006 << " Z =" << Z << " A = " << A 1006 << " Z =" << Z << " A = " << A << " L = " << LL << " lvl = " << lvl << G4endl; 1007 } 1007 } 1008 #endif 1008 #endif 1009 G4Exception("G4IonTable::GetNucleusMass() 1009 G4Exception("G4IonTable::GetNucleusMass()", "PART107", EventMustBeAborted, 1010 "illegal atomic number/mass") 1010 "illegal atomic number/mass"); 1011 return -1.0; 1011 return -1.0; 1012 } 1012 } 1013 1013 1014 G4double mass; 1014 G4double mass; 1015 if (LL == 0) { 1015 if (LL == 0) { 1016 // calculate nucleus mass 1016 // calculate nucleus mass 1017 const G4ParticleDefinition* ion = GetLigh 1017 const G4ParticleDefinition* ion = GetLightIon(Z, A); 1018 1018 1019 if (ion != nullptr) { 1019 if (ion != nullptr) { 1020 mass = ion->GetPDGMass(); 1020 mass = ion->GetPDGMass(); 1021 } 1021 } 1022 else { 1022 else { 1023 // Use G4NucleiProperties::GetNuclearMa 1023 // Use G4NucleiProperties::GetNuclearMass 1024 mass = G4NucleiProperties::GetNuclearMa 1024 mass = G4NucleiProperties::GetNuclearMass(A, Z); 1025 } 1025 } 1026 1026 1027 // Isomer 1027 // Isomer 1028 if (lvl > 0) { 1028 if (lvl > 0) { 1029 // -- loop over all particles in Ion ta 1029 // -- loop over all particles in Ion table 1030 G4int encoding = GetNucleusEncoding(Z, 1030 G4int encoding = GetNucleusEncoding(Z, A); 1031 G4bool isFound = false; 1031 G4bool isFound = false; 1032 for (auto i = fIonList->find(encoding); 1032 for (auto i = fIonList->find(encoding); i != fIonList->cend(); ++i) { 1033 ion = i->second; 1033 ion = i->second; 1034 if ((ion->GetAtomicNumber() != Z) || 1034 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 1035 // Excitation level 1035 // Excitation level 1036 if (((const G4Ions*)(ion))->GetIsomer 1036 if (((const G4Ions*)(ion))->GetIsomerLevel() == lvl) { 1037 isFound = true; 1037 isFound = true; 1038 break; 1038 break; 1039 } 1039 } 1040 } 1040 } 1041 if (isFound) { 1041 if (isFound) { 1042 // Return existing isomer mass 1042 // Return existing isomer mass 1043 mass = ion->GetPDGMass(); 1043 mass = ion->GetPDGMass(); 1044 } 1044 } 1045 else { 1045 else { 1046 // Find isomer from IsotopeTable 1046 // Find isomer from IsotopeTable 1047 const G4IsotopeProperty* fProperty = 1047 const G4IsotopeProperty* fProperty = FindIsotope(Z, A, lvl); 1048 if (fProperty != nullptr) mass += fPr 1048 if (fProperty != nullptr) mass += fProperty->GetEnergy(); 1049 } 1049 } 1050 } 1050 } 1051 } 1051 } 1052 else { 1052 else { 1053 mass = G4HyperNucleiProperties::GetNuclea 1053 mass = G4HyperNucleiProperties::GetNuclearMass(A, Z, LL); 1054 } 1054 } 1055 return mass; 1055 return mass; 1056 } 1056 } 1057 1057 1058 G4double G4IonTable::GetIsomerMass(G4int Z, G 1058 G4double G4IonTable::GetIsomerMass(G4int Z, G4int A, G4int lvl) const 1059 { 1059 { 1060 return GetNucleusMass(Z, A, 0, lvl); 1060 return GetNucleusMass(Z, A, 0, lvl); 1061 } 1061 } 1062 1062 1063 G4double G4IonTable::GetIonMass(G4int Z, G4in 1063 G4double G4IonTable::GetIonMass(G4int Z, G4int A, G4int LL, G4int lvl) const 1064 { 1064 { 1065 return GetNucleusMass(Z, A, LL, lvl); 1065 return GetNucleusMass(Z, A, LL, lvl); 1066 } 1066 } 1067 1067 1068 void G4IonTable::clear() 1068 void G4IonTable::clear() 1069 { 1069 { 1070 if (G4ParticleTable::GetParticleTable()->Ge 1070 if (G4ParticleTable::GetParticleTable()->GetReadiness()) { 1071 G4Exception("G4IonTable::clear()", "PART1 1071 G4Exception("G4IonTable::clear()", "PART116", JustWarning, 1072 "No effects because readyToUs 1072 "No effects because readyToUse is true."); 1073 return; 1073 return; 1074 } 1074 } 1075 1075 1076 #ifdef G4VERBOSE 1076 #ifdef G4VERBOSE 1077 if (GetVerboseLevel() > 2) { 1077 if (GetVerboseLevel() > 2) { 1078 G4cout << "G4IonTable::Clear() : number o 1078 G4cout << "G4IonTable::Clear() : number of Ion registered = "; 1079 G4cout << fIonList->size() << G4endl; 1079 G4cout << fIonList->size() << G4endl; 1080 } 1080 } 1081 #endif 1081 #endif 1082 fIonList->clear(); 1082 fIonList->clear(); 1083 } 1083 } 1084 1084 1085 void G4IonTable::Insert(const G4ParticleDefin 1085 void G4IonTable::Insert(const G4ParticleDefinition* particle) 1086 { 1086 { 1087 if (!IsIon(particle)) return; 1087 if (!IsIon(particle)) return; 1088 if (Contains(particle)) return; 1088 if (Contains(particle)) return; 1089 1089 1090 G4int Z = particle->GetAtomicNumber(); 1090 G4int Z = particle->GetAtomicNumber(); 1091 G4int A = particle->GetAtomicMass(); 1091 G4int A = particle->GetAtomicMass(); 1092 G4int LL = particle->GetQuarkContent(3); / 1092 G4int LL = particle->GetQuarkContent(3); // strangeness 1093 G4int encoding = GetNucleusEncoding(Z, A, L 1093 G4int encoding = GetNucleusEncoding(Z, A, LL); // encoding of the groud state 1094 1094 1095 // Register the ion with its encoding of th 1095 // Register the ion with its encoding of the ground state 1096 fIonListShadow->insert(std::pair<const G4in 1096 fIonListShadow->insert(std::pair<const G4int, const G4ParticleDefinition*>(encoding, particle)); 1097 } 1097 } 1098 1098 1099 void G4IonTable::InsertWorker(const G4Particl 1099 void G4IonTable::InsertWorker(const G4ParticleDefinition* particle) 1100 { 1100 { 1101 if (particle == nullptr) return; 1101 if (particle == nullptr) return; 1102 1102 1103 G4int Z = particle->GetAtomicNumber(); 1103 G4int Z = particle->GetAtomicNumber(); 1104 G4int A = particle->GetAtomicMass(); 1104 G4int A = particle->GetAtomicMass(); 1105 G4int LL = particle->GetQuarkContent(3); / 1105 G4int LL = particle->GetQuarkContent(3); // strangeness 1106 G4int encoding = GetNucleusEncoding(Z, A, L 1106 G4int encoding = GetNucleusEncoding(Z, A, LL); 1107 G4bool found = false; 1107 G4bool found = false; 1108 if (encoding != 0) { 1108 if (encoding != 0) { 1109 for (auto i = fIonList->find(encoding); i 1109 for (auto i = fIonList->find(encoding); i != fIonList->cend(); ++i) { 1110 if (particle == i->second) { 1110 if (particle == i->second) { 1111 found = true; 1111 found = true; 1112 break; 1112 break; 1113 } 1113 } 1114 } 1114 } 1115 } 1115 } 1116 if (found) return; 1116 if (found) return; 1117 1117 1118 // Register the ion with its encoding of th 1118 // Register the ion with its encoding of the gronud state 1119 fIonList->insert(std::pair<const G4int, con 1119 fIonList->insert(std::pair<const G4int, const G4ParticleDefinition*>(encoding, particle)); 1120 } 1120 } 1121 1121 1122 void G4IonTable::Remove(const G4ParticleDefin 1122 void G4IonTable::Remove(const G4ParticleDefinition* particle) 1123 { 1123 { 1124 if (particle == nullptr) return; 1124 if (particle == nullptr) return; 1125 #ifdef G4MULTITHREADED 1125 #ifdef G4MULTITHREADED 1126 if (G4Threading::IsWorkerThread()) { 1126 if (G4Threading::IsWorkerThread()) { 1127 G4ExceptionDescription ed; 1127 G4ExceptionDescription ed; 1128 ed << "Request of removing " << particle- 1128 ed << "Request of removing " << particle->GetParticleName() 1129 << " is ignored as it is invoked from 1129 << " is ignored as it is invoked from a worker thread."; 1130 G4Exception("G4IonTable::Remove()", "PART 1130 G4Exception("G4IonTable::Remove()", "PART10117", JustWarning, ed); 1131 return; 1131 return; 1132 } 1132 } 1133 #endif 1133 #endif 1134 if (G4ParticleTable::GetParticleTable()->Ge 1134 if (G4ParticleTable::GetParticleTable()->GetReadiness()) { 1135 G4StateManager* pStateManager = G4StateMa 1135 G4StateManager* pStateManager = G4StateManager::GetStateManager(); 1136 G4ApplicationState currentState = pStateM 1136 G4ApplicationState currentState = pStateManager->GetCurrentState(); 1137 if (currentState != G4State_PreInit) { 1137 if (currentState != G4State_PreInit) { 1138 G4String msg = "Request of removing "; 1138 G4String msg = "Request of removing "; 1139 msg += particle->GetParticleName(); 1139 msg += particle->GetParticleName(); 1140 msg += " has No effects other than Pre_ 1140 msg += " has No effects other than Pre_Init"; 1141 G4Exception("G4IonTable::Remove()", "PA 1141 G4Exception("G4IonTable::Remove()", "PART117", JustWarning, msg); 1142 return; 1142 return; 1143 } 1143 } 1144 1144 1145 #ifdef G4VERBOSE 1145 #ifdef G4VERBOSE 1146 if (GetVerboseLevel() > 0) { 1146 if (GetVerboseLevel() > 0) { 1147 G4cout << particle->GetParticleName() < 1147 G4cout << particle->GetParticleName() << " will be removed from the IonTable " << G4endl; 1148 } 1148 } 1149 #endif 1149 #endif 1150 } 1150 } 1151 1151 1152 if (IsIon(particle)) { 1152 if (IsIon(particle)) { 1153 G4int Z = particle->GetAtomicNumber(); 1153 G4int Z = particle->GetAtomicNumber(); 1154 G4int A = particle->GetAtomicMass(); 1154 G4int A = particle->GetAtomicMass(); 1155 G4int LL = particle->GetQuarkContent(3); 1155 G4int LL = particle->GetQuarkContent(3); // strangeness 1156 G4int encoding = GetNucleusEncoding(Z, A, 1156 G4int encoding = GetNucleusEncoding(Z, A, LL); 1157 if (encoding != 0) { 1157 if (encoding != 0) { 1158 for (auto i = fIonListShadow->find(enco 1158 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1159 if (particle == i->second) { 1159 if (particle == i->second) { 1160 fIonListShadow->erase(i); 1160 fIonListShadow->erase(i); 1161 break; 1161 break; 1162 } 1162 } 1163 } 1163 } 1164 } 1164 } 1165 } 1165 } 1166 else { 1166 else { 1167 #ifdef G4VERBOSE 1167 #ifdef G4VERBOSE 1168 if (GetVerboseLevel() > 1) { 1168 if (GetVerboseLevel() > 1) { 1169 G4cout << "G4IonTable::Remove :" << par 1169 G4cout << "G4IonTable::Remove :" << particle->GetParticleName() << " is not ions" << G4endl; 1170 } 1170 } 1171 #endif 1171 #endif 1172 } 1172 } 1173 } 1173 } 1174 1174 1175 void G4IonTable::DumpTable(const G4String& pa 1175 void G4IonTable::DumpTable(const G4String& particle_name) const 1176 { 1176 { 1177 const G4ParticleDefinition* ion; 1177 const G4ParticleDefinition* ion; 1178 for (const auto& idx : *fIonList) { 1178 for (const auto& idx : *fIonList) { 1179 ion = idx.second; 1179 ion = idx.second; 1180 if ((particle_name == "ALL") || (particle 1180 if ((particle_name == "ALL") || (particle_name == "all")) { 1181 ion->DumpTable(); 1181 ion->DumpTable(); 1182 } 1182 } 1183 else if (particle_name == ion->GetParticl 1183 else if (particle_name == ion->GetParticleName()) { 1184 ion->DumpTable(); 1184 ion->DumpTable(); 1185 } 1185 } 1186 } 1186 } 1187 } 1187 } 1188 1188 1189 // ------------------------------------------ 1189 // -------------------------------------------------------------------- 1190 // 1190 // 1191 // clang-format off 1191 // clang-format off 1192 const G4String G4IonTable::elementName[] = 1192 const G4String G4IonTable::elementName[] = 1193 { 1193 { 1194 "H", 1194 "H", "He", 1195 "Li", "Be", 1195 "Li", "Be", "B", "C", "N", "O", "F", "Ne", 1196 "Na", "Mg", 1196 "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", 1197 "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe 1197 "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", 1198 "Rb", "Sr", "Y", "Zr", "Nb", "Mo","Tc", "Ru 1198 "Rb", "Sr", "Y", "Zr", "Nb", "Mo","Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", 1199 "Cs", "Ba", 1199 "Cs", "Ba", 1200 "La", "Ce", "Pr", "Nd", "Pm", " 1200 "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", 1201 "Hf", "Ta", "W", "Re", "Os 1201 "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", 1202 "Fr", "Ra", 1202 "Fr", "Ra", 1203 "Ac", "Th", "Pa", "U", "Np", " 1203 "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", 1204 "Rf", "Db", "Sg", "Bh", "Hs", " 1204 "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og" 1205 }; 1205 }; 1206 // clang-format on 1206 // clang-format on 1207 1207 1208 G4int G4IonTable::GetVerboseLevel() const 1208 G4int G4IonTable::GetVerboseLevel() const 1209 { 1209 { 1210 return G4ParticleTable::GetParticleTable()- 1210 return G4ParticleTable::GetParticleTable()->GetVerboseLevel(); 1211 } 1211 } 1212 1212 1213 void G4IonTable::AddProcessManager(G4Particle 1213 void G4IonTable::AddProcessManager(G4ParticleDefinition* ion) 1214 { 1214 { 1215 if (ion->IsGeneralIon()) { 1215 if (ion->IsGeneralIon()) { 1216 // Check whether GenericIon has processes 1216 // Check whether GenericIon has processes 1217 G4ParticleDefinition* genericIon = G4Part 1217 G4ParticleDefinition* genericIon = G4ParticleTable::GetParticleTable()->GetGenericIon(); 1218 1218 1219 G4ProcessManager* pman = nullptr; 1219 G4ProcessManager* pman = nullptr; 1220 if (genericIon != nullptr) pman = generic 1220 if (genericIon != nullptr) pman = genericIon->GetProcessManager(); 1221 if ((genericIon == nullptr) || (genericIo 1221 if ((genericIon == nullptr) || (genericIon->GetParticleDefinitionID() < 0) || (pman == nullptr)) 1222 { 1222 { 1223 G4String msg = "G4IonTable::AddProcessM 1223 G4String msg = "G4IonTable::AddProcessManager(): cannot create ion of "; 1224 msg += ion->GetParticleName(); 1224 msg += ion->GetParticleName(); 1225 msg += "\n because GenericIon is not av 1225 msg += "\n because GenericIon is not available!!"; 1226 G4Exception("G4IonTable::AddProcessMana 1226 G4Exception("G4IonTable::AddProcessManager()", "PART105", FatalException, msg); 1227 return; 1227 return; 1228 } 1228 } 1229 1229 1230 ion->SetParticleDefinitionID(genericIon-> 1230 ion->SetParticleDefinitionID(genericIon->GetParticleDefinitionID()); 1231 } 1231 } 1232 else { 1232 else { 1233 // Is this a MuonicAtom ? 1233 // Is this a MuonicAtom ? 1234 auto muatom = dynamic_cast<G4MuonicAtom*> 1234 auto muatom = dynamic_cast<G4MuonicAtom*>(ion); 1235 1235 1236 if (muatom != nullptr) { 1236 if (muatom != nullptr) { 1237 #ifdef G4VERBOSE 1237 #ifdef G4VERBOSE 1238 if (GetVerboseLevel() > 1) { 1238 if (GetVerboseLevel() > 1) { 1239 G4cout << "G4IonTable::AddProcessMana 1239 G4cout << "G4IonTable::AddProcessManager(): " 1240 << "MuonicAtom dynamic_cast su 1240 << "MuonicAtom dynamic_cast succeeded for " << ion->GetParticleName() << G4endl; 1241 } 1241 } 1242 #endif 1242 #endif 1243 // Check whether GenericMuonicAtom has 1243 // Check whether GenericMuonicAtom has processes 1244 G4ParticleDefinition* genericMA = G4Par 1244 G4ParticleDefinition* genericMA = G4ParticleTable::GetParticleTable()->GetGenericMuonicAtom(); 1245 1245 1246 G4ProcessManager* pman = nullptr; 1246 G4ProcessManager* pman = nullptr; 1247 if (genericMA != nullptr) pman = generi 1247 if (genericMA != nullptr) pman = genericMA->GetProcessManager(); 1248 if ((genericMA == nullptr) || (genericM 1248 if ((genericMA == nullptr) || (genericMA->GetParticleDefinitionID() < 0) || (pman == nullptr)) 1249 { 1249 { 1250 G4String msg = "G4IonTable::AddProces 1250 G4String msg = "G4IonTable::AddProcessManager(): cannot create MuonicAtom "; 1251 msg += ion->GetParticleName(); 1251 msg += ion->GetParticleName(); 1252 msg += "\n because GenericMuonicAtom 1252 msg += "\n because GenericMuonicAtom is not available!!"; 1253 G4Exception("G4IonTable::AddProcessMa 1253 G4Exception("G4IonTable::AddProcessManager()", "PART106", FatalException, msg); 1254 return; 1254 return; 1255 } 1255 } 1256 1256 1257 ion->SetParticleDefinitionID(genericMA- 1257 ion->SetParticleDefinitionID(genericMA->GetParticleDefinitionID()); 1258 } 1258 } 1259 else { 1259 else { 1260 G4String msg = "G4IonTable::AddProcessM 1260 G4String msg = "G4IonTable::AddProcessManager(): cannot create "; 1261 msg += ion->GetParticleName(); 1261 msg += ion->GetParticleName(); 1262 msg += "\n because of unsupported parti 1262 msg += "\n because of unsupported particle type !!"; 1263 G4Exception("G4IonTable::AddProcessMana 1263 G4Exception("G4IonTable::AddProcessManager()", "PART107", FatalException, msg); 1264 return; 1264 return; 1265 } 1265 } 1266 } 1266 } 1267 return; 1267 return; 1268 } 1268 } 1269 1269 1270 void G4IonTable::RegisterIsotopeTable(G4VIsot 1270 void G4IonTable::RegisterIsotopeTable(G4VIsotopeTable* table) 1271 { 1271 { 1272 // check duplication 1272 // check duplication 1273 G4String name = table->GetName(); 1273 G4String name = table->GetName(); 1274 for (const auto fIsotopeTable : *fIsotopeTa 1274 for (const auto fIsotopeTable : *fIsotopeTableList) { 1275 if (name == fIsotopeTable->GetName()) ret 1275 if (name == fIsotopeTable->GetName()) return; 1276 } 1276 } 1277 // register 1277 // register 1278 fIsotopeTableList->push_back(table); 1278 fIsotopeTableList->push_back(table); 1279 } 1279 } 1280 1280 1281 G4VIsotopeTable* G4IonTable::GetIsotopeTable( 1281 G4VIsotopeTable* G4IonTable::GetIsotopeTable(std::size_t index) const 1282 { 1282 { 1283 G4VIsotopeTable* fIsotopeTable = nullptr; 1283 G4VIsotopeTable* fIsotopeTable = nullptr; 1284 if (index < fIsotopeTableList->size()) { 1284 if (index < fIsotopeTableList->size()) { 1285 fIsotopeTable = (*fIsotopeTableList)[inde 1285 fIsotopeTable = (*fIsotopeTableList)[index]; 1286 } 1286 } 1287 return fIsotopeTable; 1287 return fIsotopeTable; 1288 } 1288 } 1289 1289 1290 G4IsotopeProperty* G4IonTable::FindIsotope(G4 1290 G4IsotopeProperty* G4IonTable::FindIsotope(G4int Z, G4int A, G4double E, 1291 G4 1291 G4Ions::G4FloatLevelBase flb) const 1292 { 1292 { 1293 if (fIsotopeTableList == nullptr) return nu 1293 if (fIsotopeTableList == nullptr) return nullptr; 1294 if (fIsotopeTableList->empty()) return null 1294 if (fIsotopeTableList->empty()) return nullptr; 1295 1295 1296 G4IsotopeProperty* property = nullptr; 1296 G4IsotopeProperty* property = nullptr; 1297 1297 1298 for (std::size_t i = 0; i < fIsotopeTableLi 1298 for (std::size_t i = 0; i < fIsotopeTableList->size(); ++i) { 1299 G4VIsotopeTable* fIsotopeTable = (*fIsoto 1299 G4VIsotopeTable* fIsotopeTable = (*fIsotopeTableList)[fIsotopeTableList->size() - i - 1]; 1300 property = fIsotopeTable->GetIsotope(Z, A 1300 property = fIsotopeTable->GetIsotope(Z, A, E, flb); 1301 if (property != nullptr) break; 1301 if (property != nullptr) break; 1302 } 1302 } 1303 1303 1304 return property; 1304 return property; 1305 } 1305 } 1306 1306 1307 G4IsotopeProperty* G4IonTable::FindIsotope(G4 1307 G4IsotopeProperty* G4IonTable::FindIsotope(G4int Z, G4int A, G4int lvl) const 1308 { 1308 { 1309 if (fIsotopeTableList == nullptr) return nu 1309 if (fIsotopeTableList == nullptr) return nullptr; 1310 if (fIsotopeTableList->empty()) return null 1310 if (fIsotopeTableList->empty()) return nullptr; 1311 1311 1312 G4IsotopeProperty* property = nullptr; 1312 G4IsotopeProperty* property = nullptr; 1313 1313 1314 // iterate 1314 // iterate 1315 for (std::size_t i = 0; i < fIsotopeTableLi 1315 for (std::size_t i = 0; i < fIsotopeTableList->size(); ++i) { 1316 G4VIsotopeTable* fIsotopeTable = (*fIsoto 1316 G4VIsotopeTable* fIsotopeTable = (*fIsotopeTableList)[fIsotopeTableList->size() - i - 1]; 1317 property = fIsotopeTable->GetIsotope(Z, A 1317 property = fIsotopeTable->GetIsotope(Z, A, lvl); 1318 if (property != nullptr) break; 1318 if (property != nullptr) break; 1319 } 1319 } 1320 1320 1321 return property; 1321 return property; 1322 } 1322 } 1323 1323 1324 void G4IonTable::CreateAllIon() 1324 void G4IonTable::CreateAllIon() 1325 { 1325 { 1326 PreloadNuclide(); 1326 PreloadNuclide(); 1327 } 1327 } 1328 1328 1329 void G4IonTable::CreateAllIsomer() 1329 void G4IonTable::CreateAllIsomer() 1330 { 1330 { 1331 PreloadNuclide(); 1331 PreloadNuclide(); 1332 } 1332 } 1333 1333 1334 void G4IonTable::PrepareNuclideTable() 1334 void G4IonTable::PrepareNuclideTable() 1335 { 1335 { 1336 if (pNuclideTable == nullptr) pNuclideTable 1336 if (pNuclideTable == nullptr) pNuclideTable = G4NuclideTable::GetNuclideTable(); 1337 } 1337 } 1338 1338 1339 void G4IonTable::PreloadNuclide() 1339 void G4IonTable::PreloadNuclide() 1340 { 1340 { 1341 if (isIsomerCreated || !G4Threading::IsMult 1341 if (isIsomerCreated || !G4Threading::IsMultithreadedApplication()) return; 1342 1342 1343 pNuclideTable->GenerateNuclide(); 1343 pNuclideTable->GenerateNuclide(); 1344 1344 1345 for (std::size_t i = 0; i != pNuclideTable- 1345 for (std::size_t i = 0; i != pNuclideTable->entries(); ++i) { 1346 const G4IsotopeProperty* fProperty = pNuc 1346 const G4IsotopeProperty* fProperty = pNuclideTable->GetIsotopeByIndex(i); 1347 G4int Z = fProperty->GetAtomicNumber(); 1347 G4int Z = fProperty->GetAtomicNumber(); 1348 G4int A = fProperty->GetAtomicMass(); 1348 G4int A = fProperty->GetAtomicMass(); 1349 G4double Eex = fProperty->GetEnergy(); 1349 G4double Eex = fProperty->GetEnergy(); 1350 GetIon(Z, A, Eex); 1350 GetIon(Z, A, Eex); 1351 } 1351 } 1352 1352 1353 isIsomerCreated = true; 1353 isIsomerCreated = true; 1354 } 1354 } 1355 1355 1356 G4ParticleDefinition* G4IonTable::GetParticle 1356 G4ParticleDefinition* G4IonTable::GetParticle(G4int index) const 1357 { 1357 { 1358 if ((index >= 0) && (index < Entries())) { 1358 if ((index >= 0) && (index < Entries())) { 1359 auto idx = fIonList->cbegin(); 1359 auto idx = fIonList->cbegin(); 1360 G4int counter = 0; 1360 G4int counter = 0; 1361 while (idx != fIonList->cend()) // Loop 1361 while (idx != fIonList->cend()) // Loop checking, 09.08.2015, K.Kurashige 1362 { 1362 { 1363 if (counter == index) { 1363 if (counter == index) { 1364 return const_cast<G4ParticleDefinitio 1364 return const_cast<G4ParticleDefinition*>(idx->second); 1365 } 1365 } 1366 ++counter; 1366 ++counter; 1367 ++idx; 1367 ++idx; 1368 } 1368 } 1369 } 1369 } 1370 #ifdef G4VERBOSE 1370 #ifdef G4VERBOSE 1371 if (GetVerboseLevel() > 1) { 1371 if (GetVerboseLevel() > 1) { 1372 G4cout << " G4IonTable::GetParticle" 1372 G4cout << " G4IonTable::GetParticle" 1373 << " invalid index (=" << index << 1373 << " invalid index (=" << index << ")" 1374 << " entries = " << Entries() << G 1374 << " entries = " << Entries() << G4endl; 1375 } 1375 } 1376 #endif 1376 #endif 1377 return nullptr; 1377 return nullptr; 1378 } 1378 } 1379 1379 1380 G4bool G4IonTable::Contains(const G4ParticleD 1380 G4bool G4IonTable::Contains(const G4ParticleDefinition* particle) const 1381 { 1381 { 1382 if (!IsIon(particle)) return false; 1382 if (!IsIon(particle)) return false; 1383 1383 1384 G4int Z = particle->GetAtomicNumber(); 1384 G4int Z = particle->GetAtomicNumber(); 1385 G4int A = particle->GetAtomicMass(); 1385 G4int A = particle->GetAtomicMass(); 1386 G4int LL = particle->GetQuarkContent(3); / 1386 G4int LL = particle->GetQuarkContent(3); // strangeness 1387 G4int encoding = GetNucleusEncoding(Z, A, L 1387 G4int encoding = GetNucleusEncoding(Z, A, LL); 1388 G4bool found = false; 1388 G4bool found = false; 1389 if (encoding != 0) { 1389 if (encoding != 0) { 1390 for (auto i = fIonListShadow->find(encodi 1390 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1391 if (particle == i->second) { 1391 if (particle == i->second) { 1392 found = true; 1392 found = true; 1393 break; 1393 break; 1394 } 1394 } 1395 } 1395 } 1396 } 1396 } 1397 return found; 1397 return found; 1398 } 1398 } 1399 1399 1400 G4int G4IonTable::Entries() const 1400 G4int G4IonTable::Entries() const 1401 { 1401 { 1402 return (G4int)fIonList->size(); 1402 return (G4int)fIonList->size(); 1403 } 1403 } 1404 1404 1405 G4int G4IonTable::size() const 1405 G4int G4IonTable::size() const 1406 { 1406 { 1407 return (G4int)fIonList->size(); 1407 return (G4int)fIonList->size(); 1408 } 1408 } 1409 1409 1410 G4ParticleDefinition* G4IonTable::FindIonInMa 1410 G4ParticleDefinition* G4IonTable::FindIonInMaster(G4int Z, G4int A, G4double E, 1411 1411 G4Ions::G4FloatLevelBase flb, G4int /*J*/) 1412 { 1412 { 1413 // Search ions with A, Z ,E 1413 // Search ions with A, Z ,E 1414 // !! J is omitted now !! 1414 // !! J is omitted now !! 1415 const G4ParticleDefinition* ion = nullptr; 1415 const G4ParticleDefinition* ion = nullptr; 1416 G4bool isFound = false; 1416 G4bool isFound = false; 1417 1417 1418 // -- loop over all particles in Ion table 1418 // -- loop over all particles in Ion table 1419 G4int encoding = GetNucleusEncoding(Z, A); 1419 G4int encoding = GetNucleusEncoding(Z, A); 1420 for (auto i = fIonListShadow->find(encoding 1420 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1421 ion = i->second; 1421 ion = i->second; 1422 if ((ion->GetAtomicNumber() != Z) || (ion 1422 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 1423 // excitation level 1423 // excitation level 1424 G4double anExcitaionEnergy = ((const G4Io 1424 G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy(); 1425 if (std::fabs(E - anExcitaionEnergy) < pN 1425 if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance()) { 1426 if (((const G4Ions*)(ion))->GetFloatLev 1426 if (((const G4Ions*)(ion))->GetFloatLevelBase() == flb) { 1427 isFound = true; 1427 isFound = true; 1428 break; 1428 break; 1429 } 1429 } 1430 } 1430 } 1431 } 1431 } 1432 1432 1433 if (isFound) { 1433 if (isFound) { 1434 return const_cast<G4ParticleDefinition*>( 1434 return const_cast<G4ParticleDefinition*>(ion); 1435 } 1435 } 1436 1436 1437 return nullptr; 1437 return nullptr; 1438 } 1438 } 1439 1439 1440 G4ParticleDefinition* G4IonTable::FindIonInMa 1440 G4ParticleDefinition* G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int LL, G4double E, 1441 1441 G4Ions::G4FloatLevelBase flb, G4int J) 1442 { 1442 { 1443 if (LL == 0) return FindIon(Z, A, E, flb, J 1443 if (LL == 0) return FindIon(Z, A, E, flb, J); 1444 1444 1445 // Search ions with A, Z ,E 1445 // Search ions with A, Z ,E 1446 // !! J is omitted now !! 1446 // !! J is omitted now !! 1447 const G4ParticleDefinition* ion = nullptr; 1447 const G4ParticleDefinition* ion = nullptr; 1448 G4bool isFound = false; 1448 G4bool isFound = false; 1449 1449 1450 // -- loop over all particles in Ion table 1450 // -- loop over all particles in Ion table 1451 G4int encoding = GetNucleusEncoding(Z, A, L 1451 G4int encoding = GetNucleusEncoding(Z, A, LL, 0.0, 0); 1452 for (auto i = fIonListShadow->find(encoding 1452 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1453 ion = i->second; 1453 ion = i->second; 1454 if ((ion->GetAtomicNumber() != Z) || (ion 1454 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 1455 if (ion->GetQuarkContent(3) != LL) break; 1455 if (ion->GetQuarkContent(3) != LL) break; 1456 // Excitation level 1456 // Excitation level 1457 G4double anExcitaionEnergy = ((const G4Io 1457 G4double anExcitaionEnergy = ((const G4Ions*)(ion))->GetExcitationEnergy(); 1458 if (std::fabs(E - anExcitaionEnergy) < pN 1458 if (std::fabs(E - anExcitaionEnergy) < pNuclideTable->GetLevelTolerance()) { 1459 if (((const G4Ions*)(ion))->GetFloatLev 1459 if (((const G4Ions*)(ion))->GetFloatLevelBase() == flb) { 1460 isFound = true; 1460 isFound = true; 1461 break; 1461 break; 1462 } 1462 } 1463 } 1463 } 1464 } 1464 } 1465 1465 1466 if (isFound) { 1466 if (isFound) { 1467 return const_cast<G4ParticleDefinition*>( 1467 return const_cast<G4ParticleDefinition*>(ion); 1468 } 1468 } 1469 1469 1470 return nullptr; 1470 return nullptr; 1471 } 1471 } 1472 1472 1473 G4ParticleDefinition* G4IonTable::FindIonInMa 1473 G4ParticleDefinition* G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int lvl) 1474 { 1474 { 1475 // Search ions with A, Z ,E 1475 // Search ions with A, Z ,E 1476 // !! J is omitted now !! 1476 // !! J is omitted now !! 1477 const G4ParticleDefinition* ion = nullptr; 1477 const G4ParticleDefinition* ion = nullptr; 1478 G4bool isFound = false; 1478 G4bool isFound = false; 1479 1479 1480 // -- loop over all particles in Ion table 1480 // -- loop over all particles in Ion table 1481 G4int encoding = GetNucleusEncoding(Z, A); 1481 G4int encoding = GetNucleusEncoding(Z, A); 1482 for (auto i = fIonListShadow->find(encoding 1482 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1483 ion = i->second; 1483 ion = i->second; 1484 if ((ion->GetAtomicNumber() != Z) || (ion 1484 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 1485 // Excitation level 1485 // Excitation level 1486 if (((const G4Ions*)(ion))->GetIsomerLeve 1486 if (((const G4Ions*)(ion))->GetIsomerLevel() == lvl) { 1487 isFound = true; 1487 isFound = true; 1488 break; 1488 break; 1489 } 1489 } 1490 } 1490 } 1491 1491 1492 if (isFound) { 1492 if (isFound) { 1493 return const_cast<G4ParticleDefinition*>( 1493 return const_cast<G4ParticleDefinition*>(ion); 1494 } 1494 } 1495 1495 1496 return nullptr; 1496 return nullptr; 1497 } 1497 } 1498 1498 1499 G4ParticleDefinition* G4IonTable::FindIonInMa 1499 G4ParticleDefinition* G4IonTable::FindIonInMaster(G4int Z, G4int A, G4int LL, G4int lvl) 1500 { 1500 { 1501 if (LL == 0) return FindIon(Z, A, lvl); 1501 if (LL == 0) return FindIon(Z, A, lvl); 1502 1502 1503 // Search ions with A, Z ,E, lvl 1503 // Search ions with A, Z ,E, lvl 1504 const G4ParticleDefinition* ion = nullptr; 1504 const G4ParticleDefinition* ion = nullptr; 1505 G4bool isFound = false; 1505 G4bool isFound = false; 1506 1506 1507 // -- loop over all particles in Ion table 1507 // -- loop over all particles in Ion table 1508 G4int encoding = GetNucleusEncoding(Z, A, L 1508 G4int encoding = GetNucleusEncoding(Z, A, LL); 1509 for (auto i = fIonListShadow->find(encoding 1509 for (auto i = fIonListShadow->find(encoding); i != fIonListShadow->cend(); ++i) { 1510 ion = i->second; 1510 ion = i->second; 1511 if ((ion->GetAtomicNumber() != Z) || (ion 1511 if ((ion->GetAtomicNumber() != Z) || (ion->GetAtomicMass() != A)) break; 1512 if (ion->GetQuarkContent(3) != LL) break; 1512 if (ion->GetQuarkContent(3) != LL) break; 1513 // excitation level 1513 // excitation level 1514 if (((const G4Ions*)(ion))->GetIsomerLeve 1514 if (((const G4Ions*)(ion))->GetIsomerLevel() == lvl) { 1515 isFound = true; 1515 isFound = true; 1516 break; 1516 break; 1517 } 1517 } 1518 } 1518 } 1519 1519 1520 if (isFound) { 1520 if (isFound) { 1521 return const_cast<G4ParticleDefinition*>( 1521 return const_cast<G4ParticleDefinition*>(ion); 1522 } 1522 } 1523 1523 1524 return nullptr; 1524 return nullptr; 1525 } 1525 } 1526 1526 1527 G4double G4IonTable::GetLifeTime(const G4Part 1527 G4double G4IonTable::GetLifeTime(const G4ParticleDefinition* particle) const 1528 { 1528 { 1529 if ((particle->IsGeneralIon()) && (pNuclide 1529 if ((particle->IsGeneralIon()) && (pNuclideTable == nullptr)) { 1530 G4Exception("G4IonTable::GetLifeTime()", 1530 G4Exception("G4IonTable::GetLifeTime()", "ParticleIon1001", FatalException, 1531 "Method is invoked before G4I 1531 "Method is invoked before G4IonTable is initialized."); 1532 return 0.; 1532 return 0.; 1533 } 1533 } 1534 return particle->GetPDGLifeTime(); 1534 return particle->GetPDGLifeTime(); 1535 } 1535 } 1536 1536 1537 G4double G4IonTable::GetLifeTime(G4int Z, G4i 1537 G4double G4IonTable::GetLifeTime(G4int Z, G4int A, G4double E, char flbChar) const 1538 { 1538 { 1539 return GetLifeTime(Z, A, E, G4Ions::FloatLe 1539 return GetLifeTime(Z, A, E, G4Ions::FloatLevelBase(flbChar)); 1540 } 1540 } 1541 1541 1542 G4double G4IonTable::GetLifeTime(G4int Z, G4i 1542 G4double G4IonTable::GetLifeTime(G4int Z, G4int A, G4double E, G4Ions::G4FloatLevelBase flb) const 1543 { 1543 { 1544 G4double life = -1001.0; 1544 G4double life = -1001.0; 1545 const G4IsotopeProperty* fProperty = FindIs 1545 const G4IsotopeProperty* fProperty = FindIsotope(Z, A, E, flb); 1546 if (fProperty != nullptr) life = fProperty- 1546 if (fProperty != nullptr) life = fProperty->GetLifeTime(); 1547 return life; 1547 return life; 1548 } 1548 } 1549 1549 1550 G4ParticleDefinition* G4IonTable::GetMuonicAt 1550 G4ParticleDefinition* G4IonTable::GetMuonicAtom(G4Ions const* base) 1551 { 1551 { 1552 if (base == nullptr || !IsIon(base)) { 1552 if (base == nullptr || !IsIon(base)) { 1553 G4Exception("G4IonTable::GetMuonicAtom()" 1553 G4Exception("G4IonTable::GetMuonicAtom()", "PART987654321", FatalException, 1554 "Constructor argument is not 1554 "Constructor argument is not a G4Ions"); 1555 return nullptr; 1555 return nullptr; 1556 } 1556 } 1557 1557 1558 // We're assuming here that we get a base t 1558 // We're assuming here that we get a base that is actually 1559 // constructed and unexcited ... strip exci 1559 // constructed and unexcited ... strip excitations, Lambdas, and 1560 // isomers from the encoding 1560 // isomers from the encoding 1561 1561 1562 auto const Z = base->GetAtomicNumber(); 1562 auto const Z = base->GetAtomicNumber(); 1563 auto const A = base->GetAtomicMass(); 1563 auto const A = base->GetAtomicMass(); 1564 auto const baseenc = GetNucleusEncoding(Z, 1564 auto const baseenc = GetNucleusEncoding(Z, A); 1565 auto const encoding = baseenc + 1000000000; 1565 auto const encoding = baseenc + 1000000000; 1566 1566 1567 // We have to do all the MT manipulations m 1567 // We have to do all the MT manipulations manually, because the 1568 // convenience functions assume a G4Ions wi 1568 // convenience functions assume a G4Ions with canonical PDG codes; 1569 // they recalculate the encoding from parti 1569 // they recalculate the encoding from particle properties rather 1570 // than using the carried member function v 1570 // than using the carried member function values. Thus, they will 1571 // do operations on the base ion, rather th 1571 // do operations on the base ion, rather than the passed in 1572 // G4MuonicAtom 1572 // G4MuonicAtom 1573 1573 1574 auto i = fIonList->find(encoding); 1574 auto i = fIonList->find(encoding); 1575 if (i != fIonList->cend()) { 1575 if (i != fIonList->cend()) { 1576 return const_cast<G4ParticleDefinition*>( 1576 return const_cast<G4ParticleDefinition*>(i->second); 1577 } 1577 } 1578 // not in threadlocal list; check global li 1578 // not in threadlocal list; check global list ... 1579 #ifdef G4MULTITHREADED 1579 #ifdef G4MULTITHREADED 1580 if (G4Threading::IsWorkerThread()) { 1580 if (G4Threading::IsWorkerThread()) { 1581 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 1581 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 1582 i = fIonListShadow->find(encoding); 1582 i = fIonListShadow->find(encoding); 1583 auto end = fIonListShadow->cend(); 1583 auto end = fIonListShadow->cend(); 1584 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex) 1584 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex); 1585 if (i != end) { 1585 if (i != end) { 1586 // we found it, stuff it into the threa 1586 // we found it, stuff it into the threadlocal list 1587 fIonList->insert(*i); 1587 fIonList->insert(*i); 1588 // and then return it ... 1588 // and then return it ... 1589 return const_cast<G4ParticleDefinition* 1589 return const_cast<G4ParticleDefinition*>(i->second); 1590 } 1590 } 1591 } 1591 } 1592 #endif 1592 #endif 1593 1593 1594 // not found in either list; create and pot 1594 // not found in either list; create and potentially insert 1595 auto const name = "Mu" + GetIonName(Z, A); 1595 auto const name = "Mu" + GetIonName(Z, A); 1596 1596 1597 G4MuonicAtom* muatom = G4MuonicAtomHelper:: 1597 G4MuonicAtom* muatom = G4MuonicAtomHelper::ConstructMuonicAtom(name, encoding, base); 1598 1598 1599 // Not sure this is doing the right thing.. 1599 // Not sure this is doing the right thing... 1600 AddProcessManager(muatom); 1600 AddProcessManager(muatom); 1601 1601 1602 // Now, we have to push the muatom into the 1602 // Now, we have to push the muatom into the appropriate IonTables 1603 // first, recheck global list, in case anot 1603 // first, recheck global list, in case another thread came along 1604 // before us and created this same muatom 1604 // before us and created this same muatom 1605 1605 1606 #ifdef G4MULTITHREADED 1606 #ifdef G4MULTITHREADED 1607 if (G4Threading::IsWorkerThread()) { 1607 if (G4Threading::IsWorkerThread()) { 1608 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 1608 G4MUTEXLOCK(&G4IonTable::ionTableMutex); 1609 // first, we need to make sure it hasn't 1609 // first, we need to make sure it hasn't been inserted by some 1610 // other thread 1610 // other thread 1611 auto j = fIonListShadow->find(encoding); 1611 auto j = fIonListShadow->find(encoding); 1612 if (j != fIonListShadow->cend()) { 1612 if (j != fIonListShadow->cend()) { 1613 // oops ... someone else built a copy w 1613 // oops ... someone else built a copy when we weren't looking; 1614 // cleanup our instantiation, and take 1614 // cleanup our instantiation, and take a handle to the one in 1615 // the global list 1615 // the global list 1616 delete muatom; 1616 delete muatom; 1617 muatom = const_cast<G4MuonicAtom*>(stat 1617 muatom = const_cast<G4MuonicAtom*>(static_cast<G4MuonicAtom const*>(j->second)); 1618 } 1618 } 1619 else { 1619 else { 1620 // otherwise, push onto the global list 1620 // otherwise, push onto the global list first 1621 fIonListShadow->insert(std::make_pair(e 1621 fIonListShadow->insert(std::make_pair(encoding, muatom)); 1622 } 1622 } 1623 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex) 1623 G4MUTEXUNLOCK(&G4IonTable::ionTableMutex); 1624 } 1624 } 1625 #endif 1625 #endif 1626 // in either case, push onto the the thread 1626 // in either case, push onto the the threadlocal list 1627 fIonList->insert(std::make_pair(encoding, m 1627 fIonList->insert(std::make_pair(encoding, muatom)); 1628 1628 1629 return muatom; 1629 return muatom; 1630 } 1630 } 1631 1631 1632 G4ParticleDefinition* G4IonTable::GetMuonicAt 1632 G4ParticleDefinition* G4IonTable::GetMuonicAtom(G4int Z, G4int A) 1633 { 1633 { 1634 // Need the cast because we need a G4Ions* 1634 // Need the cast because we need a G4Ions* to pass into the 1635 // function, but GetIon returns a G4Particl 1635 // function, but GetIon returns a G4ParticleDefinition* 1636 auto base = static_cast<G4Ions const*>(GetI 1636 auto base = static_cast<G4Ions const*>(GetIon(Z, A, 0.0)); 1637 return GetMuonicAtom(base); 1637 return GetMuonicAtom(base); 1638 } 1638 } 1639 1639