Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/particles/management/src/G4NuclideTable.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 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::GetNuclideTable()
 51 {
 52   return GetInstance();
 53 }
 54 
 55 G4NuclideTable::G4NuclideTable()
 56   : G4VIsotopeTable("Isomer"), mean_life_threshold(1.0 * ns), flevelTolerance(1.0 * eV)
 57 {
 58   fMessenger = new G4NuclideTableMessenger(this);
 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(G4int Z, G4int A, G4double E,
 87                                               G4Ions::G4FloatLevelBase flb)
 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 == it->GetAtomicMass()) {
 95         G4double levelE = it->GetEnergy();
 96         if (levelE - flevelTolerance / 2 <= E && E < levelE + flevelTolerance / 2) {
 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 for pre_load_list
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_bound(E - flevelTolerance / 2);
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 && E < levelE + flevelTolerance / 2) {
118         if (flb == (lower_bound_itr->second)->GetFloatLevelBase() || E == 0.0) {
119           return lower_bound_itr->second;  // found
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(G4double eex)
133 {
134   G4double tolerance = G4NuclideTable::GetInstance()->GetLevelTolerance();
135   return eex - (G4long)(eex / tolerance) * tolerance;
136 }
137 
138 G4double G4NuclideTable::Round(G4double eex)
139 {
140   G4double tolerance = G4NuclideTable::GetInstance()->GetLevelTolerance();
141   return round(eex / tolerance) * tolerance;
142 }
143 
144 G4long G4NuclideTable::Truncate(G4double eex)
145 {
146   G4double tolerance = G4NuclideTable::GetInstance()->GetLevelTolerance();
147   return (G4long)(eex / tolerance);
148 }
149 
150 G4double G4NuclideTable::Tolerance()
151 {
152   return G4NuclideTable::GetInstance()->GetLevelTolerance();
153 }
154 
155 G4IsotopeProperty* G4NuclideTable::GetIsotopeByIsoLvl(G4int Z, G4int A, G4int lvl)
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_threshold) {
164     // Need to update full list
165     const char* path = G4FindDataDir("G4ENSDFSTATEDATA");
166 
167     if (path == nullptr) {
168       G4Exception("G4NuclideTable", "PART70000", FatalException,
169                   "G4ENSDFSTATEDATA environment variable must be set");
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", FatalException, "ENSDFSTATE.dat is not found.");
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 lives
194     ifs >> ionZ >> ionA >> ionE >> ionFL >> ionLife >> ionJ >> ionMu;
195 
196     while (ifs.good())  // Loop checking, 09.08.2015, K.Kurashige
197     {
198       if (ionCode != 1000 * ionZ + ionA) {
199         iLevel = 0;
200         ionCode = 1000 * ionZ + ionA;
201       }
202 
203       ionE *= keV;
204       G4Ions::G4FloatLevelBase flb = StripFloatLevelBase(ionFL);
205       ionLife *= ns;
206       ionMu *= (joule / tesla);
207 
208       if ((ionE == 0 && flb == G4Ions::G4FloatLevelBase::no_Float)
209           || (mean_life_threshold <= ionLife && ionLife < minimum_mean_life_threshold))
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, G4IsotopeProperty*> aMultiMap;
232           itf = (map_full_list.insert(std::pair<G4int, std::multimap<G4double, G4IsotopeProperty*>>(
233                    ionCode, aMultiMap)))
234                   .first;
235         }
236         itf->second.insert(std::pair<G4double, G4IsotopeProperty*>(ionE, fProperty));
237       }
238 
239       ifs >> ionZ >> ionA >> ionE >> ionFL >> ionLife >> ionJ >> ionMu;
240     }  // End while
241 
242     minimum_mean_life_threshold = mean_life_threshold;
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 value
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, G4IsotopeProperty*> aMultiMap;
257       itf = (map_pre_load_list.insert(
258                std::pair<G4int, std::multimap<G4double, G4IsotopeProperty*>>(ionCode, aMultiMap)))
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->GetLifeTime();
266       if (exEnergy == 0.0 || meanLife > mean_life_threshold) {
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, G4IsotopeProperty*>(exEnergy, itt.second));
271       }
272     }
273   }
274 }
275 
276 void G4NuclideTable::AddState(G4int ionZ, G4int ionA, G4double ionE, G4double ionLife, G4int ionJ,
277                               G4double ionMu)
278 {
279   if (G4Threading::IsMasterThread()) {
280     G4int flbIndex = 0;
281     ionE = StripFloatLevelBase(ionE, flbIndex);
282     AddState(ionZ, ionA, ionE, flbIndex, ionLife, ionJ, ionMu);
283   }
284 }
285 
286 void G4NuclideTable::AddState(G4int ionZ, G4int ionA, G4double ionE, G4int flbIndex,
287                               G4double ionLife, G4int ionJ, G4double ionMu)
288 {
289   if (G4Threading::IsMasterThread()) {
290     if (fUserDefinedList == nullptr) fUserDefinedList = new G4IsotopeList();
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, G4int ionA, G4double ionE, G4Ions::G4FloatLevelBase flb,
311                               G4double ionLife, G4int ionJ, G4double ionMu)
312 {
313   if (G4Threading::IsMasterThread()) {
314     if (fUserDefinedList == nullptr) fUserDefinedList = new G4IsotopeList();
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(G4double t)
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 this value are created
344 // for this run
345 void G4NuclideTable::SetMeanLifeThreshold(G4double t)
346 {
347   if (G4Threading::IsMasterThread()) {
348     mean_life_threshold = t;
349     GenerateNuclide();
350   }
351 }
352 
353 G4double G4NuclideTable::StripFloatLevelBase(G4double E, G4int& flbIndex)
354 {
355   G4double rem = std::fmod(E / (1.0E-3 * eV), 10.0);
356   flbIndex = G4int(rem);
357   return E - rem;
358 }
359 
360 G4Ions::G4FloatLevelBase G4NuclideTable::StripFloatLevelBase(const G4String& sFLB)
361 {
362   if (sFLB.empty() || 2 < sFLB.size()) {
363     G4String text;
364     text += sFLB;
365     text += " is not valid indicator of G4Ions::G4FloatLevelBase.\n";
366     text += "You may use a wrong version of ENSDFSTATE data.\n";
367     text += "Please use G4ENSDFSTATE-2.0 or later.";
368 
369     G4Exception("G4NuclideTable", "PART70002", FatalException, text);
370   }
371   G4Ions::G4FloatLevelBase flb = noFloat;
372   if (!(sFLB == "-")) {
373     flb = G4Ions::FloatLevelBase(sFLB.back());
374   }
375   return flb;
376 }
377