Geant4 Cross Reference |
1 // 1 2 // ******************************************* 3 // * License and Disclaimer 4 // * 5 // * The Geant4 software is copyright of th 6 // * the Geant4 Collaboration. It is provided 7 // * conditions of the Geant4 Software License 8 // * LICENSE and available at http://cern.ch/ 9 // * include a list of copyright holders. 10 // * 11 // * Neither the authors of this software syst 12 // * institutes,nor the agencies providing fin 13 // * work make any representation or warran 14 // * regarding this software system or assum 15 // * use. Please see the license in the file 16 // * for the full disclaimer and the limitatio 17 // * 18 // * This code implementation is the result 19 // * technical work of the GEANT4 collaboratio 20 // * By using, copying, modifying or distri 21 // * any work based on the software) you ag 22 // * use in resulting scientific publicati 23 // * acceptance of all terms of the Geant4 Sof 24 // ******************************************* 25 // 26 // G4NuclideTable class implementation 27 // 28 // Author: T.Koi, SLAC - 10 October 2013 29 // ------------------------------------------- 30 31 #include "G4NuclideTable.hh" 32 33 #include "G4NuclideTableMessenger.hh" 34 #include "G4PhysicalConstants.hh" 35 #include "G4String.hh" 36 #include "G4SystemOfUnits.hh" 37 #include "G4ios.hh" 38 #include "globals.hh" 39 40 #include <fstream> 41 #include <iomanip> 42 #include <sstream> 43 44 G4NuclideTable* G4NuclideTable::GetInstance() 45 { 46 static G4NuclideTable instance; 47 return &instance; 48 } 49 50 G4NuclideTable* G4NuclideTable::GetNuclideTabl 51 { 52 return GetInstance(); 53 } 54 55 G4NuclideTable::G4NuclideTable() 56 : G4VIsotopeTable("Isomer"), mean_life_thres 57 { 58 fMessenger = new G4NuclideTableMessenger(thi 59 fIsotopeList = new G4IsotopeList(); 60 GenerateNuclide(); 61 } 62 63 G4NuclideTable::~G4NuclideTable() 64 { 65 for (auto& it : map_pre_load_list) { 66 it.second.clear(); 67 } 68 map_pre_load_list.clear(); 69 70 for (auto& it : map_full_list) { 71 it.second.clear(); 72 } 73 map_full_list.clear(); 74 75 if (fIsotopeList != nullptr) { 76 for (const auto& i : *fIsotopeList) { 77 delete i; 78 } 79 fIsotopeList->clear(); 80 delete fIsotopeList; 81 fIsotopeList = nullptr; 82 } 83 delete fMessenger; 84 } 85 86 G4IsotopeProperty* G4NuclideTable::GetIsotope( 87 88 { 89 G4IsotopeProperty* fProperty = nullptr; 90 91 // At first searching UserDefined 92 if (fUserDefinedList != nullptr) { 93 for (const auto it : *fUserDefinedList) { 94 if (Z == it->GetAtomicNumber() && A == i 95 G4double levelE = it->GetEnergy(); 96 if (levelE - flevelTolerance / 2 <= E 97 if (flb == it->GetFloatLevelBase()) 98 return it; 99 } // found 100 } 101 } 102 } 103 } 104 105 // Searching pre-load 106 // Note: isomer level is properly set only f 107 // 108 G4int ionCode = 1000 * Z + A; 109 auto itf = map_pre_load_list.find(ionCode); 110 111 if (itf != map_pre_load_list.cend()) { 112 auto lower_bound_itr = itf->second.lower_b 113 G4double levelE = DBL_MAX; 114 115 while (lower_bound_itr != itf->second.cend 116 levelE = lower_bound_itr->first; 117 if (levelE - flevelTolerance / 2 <= E && 118 if (flb == (lower_bound_itr->second)-> 119 return lower_bound_itr->second; // 120 } 121 } 122 else { 123 break; 124 } 125 ++lower_bound_itr; 126 } 127 } 128 129 return fProperty; // not found 130 } 131 132 G4double G4NuclideTable::GetTruncationError(G4 133 { 134 G4double tolerance = G4NuclideTable::GetInst 135 return eex - (G4long)(eex / tolerance) * tol 136 } 137 138 G4double G4NuclideTable::Round(G4double eex) 139 { 140 G4double tolerance = G4NuclideTable::GetInst 141 return round(eex / tolerance) * tolerance; 142 } 143 144 G4long G4NuclideTable::Truncate(G4double eex) 145 { 146 G4double tolerance = G4NuclideTable::GetInst 147 return (G4long)(eex / tolerance); 148 } 149 150 G4double G4NuclideTable::Tolerance() 151 { 152 return G4NuclideTable::GetInstance()->GetLev 153 } 154 155 G4IsotopeProperty* G4NuclideTable::GetIsotopeB 156 { 157 if (lvl == 0) return GetIsotope(Z, A, 0.0); 158 return nullptr; 159 } 160 161 void G4NuclideTable::GenerateNuclide() 162 { 163 if (mean_life_threshold < minimum_mean_life_ 164 // Need to update full list 165 const char* path = G4FindDataDir("G4ENSDFS 166 167 if (path == nullptr) { 168 G4Exception("G4NuclideTable", "PART70000 169 "G4ENSDFSTATEDATA environmen 170 return; 171 } 172 173 std::ifstream ifs; 174 G4String filename(path); 175 filename += "/ENSDFSTATE.dat"; 176 177 ifs.open(filename.c_str()); 178 if (!ifs.good()) { 179 G4Exception("G4NuclideTable", "PART70001 180 return; 181 } 182 183 G4int ionCode = 0; 184 G4int iLevel = 0; 185 G4int ionZ; 186 G4int ionA; 187 G4double ionE; 188 G4String ionFL; 189 G4double ionLife; 190 G4int ionJ; 191 G4double ionMu; 192 193 // Lifetimes read from ENSDFSTATE are mean 194 ifs >> ionZ >> ionA >> ionE >> ionFL >> io 195 196 while (ifs.good()) // Loop checking, 09.0 197 { 198 if (ionCode != 1000 * ionZ + ionA) { 199 iLevel = 0; 200 ionCode = 1000 * ionZ + ionA; 201 } 202 203 ionE *= keV; 204 G4Ions::G4FloatLevelBase flb = StripFloa 205 ionLife *= ns; 206 ionMu *= (joule / tesla); 207 208 if ((ionE == 0 && flb == G4Ions::G4Float 209 || (mean_life_threshold <= ionLife & 210 { 211 if (ionE > 0) ++iLevel; 212 if (iLevel > 9) iLevel = 9; 213 214 auto fProperty = new G4IsotopeProperty 215 216 // Set Isotope Property 217 fProperty->SetAtomicNumber(ionZ); 218 fProperty->SetAtomicMass(ionA); 219 fProperty->SetIsomerLevel(iLevel); 220 fProperty->SetEnergy(ionE); 221 fProperty->SetiSpin(ionJ); 222 fProperty->SetLifeTime(ionLife); 223 fProperty->SetDecayTable(nullptr); 224 fProperty->SetMagneticMoment(ionMu); 225 fProperty->SetFloatLevelBase(flb); 226 227 fIsotopeList->push_back(fProperty); 228 229 auto itf = map_full_list.find(ionCode) 230 if (itf == map_full_list.cend()) { 231 std::multimap<G4double, G4IsotopePro 232 itf = (map_full_list.insert(std::pai 233 ionCode, aMultiMap))) 234 .first; 235 } 236 itf->second.insert(std::pair<G4double, 237 } 238 239 ifs >> ionZ >> ionA >> ionE >> ionFL >> 240 } // End while 241 242 minimum_mean_life_threshold = mean_life_th 243 } 244 245 // Clear current map 246 for (auto& it : map_pre_load_list) { 247 it.second.clear(); 248 } 249 map_pre_load_list.clear(); 250 251 // Build map based on current threshold valu 252 for (const auto& it : map_full_list) { 253 G4int ionCode = it.first; 254 auto itf = map_pre_load_list.find(ionCode) 255 if (itf == map_pre_load_list.cend()) { 256 std::multimap<G4double, G4IsotopePropert 257 itf = (map_pre_load_list.insert( 258 std::pair<G4int, std::multimap< 259 .first; 260 } 261 262 G4int iLevel = 0; 263 for (const auto& itt : it.second) { 264 G4double exEnergy = itt.first; 265 G4double meanLife = itt.second->GetLifeT 266 if (exEnergy == 0.0 || meanLife > mean_l 267 if (itt.first != 0.0) ++iLevel; 268 if (iLevel > 9) iLevel = 9; 269 itt.second->SetIsomerLevel(iLevel); 270 itf->second.insert(std::pair<G4double, 271 } 272 } 273 } 274 } 275 276 void G4NuclideTable::AddState(G4int ionZ, G4in 277 G4double ionMu) 278 { 279 if (G4Threading::IsMasterThread()) { 280 G4int flbIndex = 0; 281 ionE = StripFloatLevelBase(ionE, flbIndex) 282 AddState(ionZ, ionA, ionE, flbIndex, ionLi 283 } 284 } 285 286 void G4NuclideTable::AddState(G4int ionZ, G4in 287 G4double ionLife 288 { 289 if (G4Threading::IsMasterThread()) { 290 if (fUserDefinedList == nullptr) fUserDefi 291 292 auto fProperty = new G4IsotopeProperty(); 293 294 // Set Isotope Property 295 fProperty->SetAtomicNumber(ionZ); 296 fProperty->SetAtomicMass(ionA); 297 fProperty->SetIsomerLevel(9); 298 fProperty->SetEnergy(ionE); 299 fProperty->SetiSpin(ionJ); 300 fProperty->SetLifeTime(ionLife); 301 fProperty->SetDecayTable(nullptr); 302 fProperty->SetMagneticMoment(ionMu); 303 fProperty->SetFloatLevelBase(flbIndex); 304 305 fUserDefinedList->push_back(fProperty); 306 fIsotopeList->push_back(fProperty); 307 } 308 } 309 310 void G4NuclideTable::AddState(G4int ionZ, G4in 311 G4double ionLife 312 { 313 if (G4Threading::IsMasterThread()) { 314 if (fUserDefinedList == nullptr) fUserDefi 315 316 auto fProperty = new G4IsotopeProperty(); 317 318 // Set Isotope Property 319 fProperty->SetAtomicNumber(ionZ); 320 fProperty->SetAtomicMass(ionA); 321 fProperty->SetIsomerLevel(9); 322 fProperty->SetEnergy(ionE); 323 fProperty->SetiSpin(ionJ); 324 fProperty->SetLifeTime(ionLife); 325 fProperty->SetDecayTable(nullptr); 326 fProperty->SetMagneticMoment(ionMu); 327 fProperty->SetFloatLevelBase(flb); 328 329 fUserDefinedList->push_back(fProperty); 330 fIsotopeList->push_back(fProperty); 331 } 332 } 333 334 void G4NuclideTable::SetThresholdOfHalfLife(G4 335 { 336 if (G4Threading::IsMasterThread()) { 337 mean_life_threshold = t / 0.69314718; 338 GenerateNuclide(); 339 } 340 } 341 342 // Set the mean life threshold for nuclides 343 // All nuclides with mean lives greater than t 344 // for this run 345 void G4NuclideTable::SetMeanLifeThreshold(G4do 346 { 347 if (G4Threading::IsMasterThread()) { 348 mean_life_threshold = t; 349 GenerateNuclide(); 350 } 351 } 352 353 G4double G4NuclideTable::StripFloatLevelBase(G 354 { 355 G4double rem = std::fmod(E / (1.0E-3 * eV), 356 flbIndex = G4int(rem); 357 return E - rem; 358 } 359 360 G4Ions::G4FloatLevelBase G4NuclideTable::Strip 361 { 362 if (sFLB.empty() || 2 < sFLB.size()) { 363 G4String text; 364 text += sFLB; 365 text += " is not valid indicator of G4Ions 366 text += "You may use a wrong version of EN 367 text += "Please use G4ENSDFSTATE-2.0 or la 368 369 G4Exception("G4NuclideTable", "PART70002", 370 } 371 G4Ions::G4FloatLevelBase flb = noFloat; 372 if (!(sFLB == "-")) { 373 flb = G4Ions::FloatLevelBase(sFLB.back()); 374 } 375 return flb; 376 } 377