21#include "marley/marley_utils.hh"
22#include "marley/BackshiftedFermiGasModel.hh"
23#include "marley/Error.hh"
24#include "marley/FileManager.hh"
25#include "marley/Fragment.hh"
26#include "marley/JSON.hh"
27#include "marley/KoningDelarocheOpticalModel.hh"
28#include "marley/Logger.hh"
29#include "marley/NuclearFormFactor.hh"
30#include "marley/StandardLorentzianModel.hh"
31#include "marley/StructureDatabase.hh"
32#include "marley/TargetAtom.hh"
36 const std::string DEFAULT_OM_KEY(
"Default" );
40std::map< int, std::pair< int, marley::Parity > >
41 marley::StructureDatabase::jpi_table_;
43std::map<int, marley::Fragment> marley::StructureDatabase::fragment_table_;
45std::unordered_map<int, std::unique_ptr< marley::DecayScheme > >
46 marley::StructureDatabase::decay_scheme_table_;
50const std::string marley::StructureDatabase
51 ::jpi_data_file_name_ =
"gs_spin_parity_table.txt";
55bool marley::StructureDatabase::initialized_gs_spin_parity_table_ =
false;
60 std::unique_ptr<marley::DecayScheme>& ds )
62 auto* temp_ptr = ds.release();
63 decay_scheme_table_.emplace(pdg, std::unique_ptr<marley::DecayScheme>(temp_ptr));
69 int Z_ds = (pdg % 10000000)/10000;
70 int A_ds = (pdg % 10000)/10;
73 decay_scheme_table_.erase(pdg);
76 decay_scheme_table_.emplace(pdg, std::make_unique<marley::DecayScheme>(
77 Z_ds, A_ds, filename, format));
83 if (format != DecayScheme::FileFormat::talys)
85 +
"find_all_nuclides() is not implemented for"
86 +
" formats other than TALYS.");
91 static const std::regex nuclide_line(
"[0-9 ]{18} {56}[0-9 ]{4}.{2}");
94 std::ifstream file_in(filename);
98 if (!file_in.good())
throw marley::Error(std::string(
"Could not")
99 +
" read from the TALYS data file " + filename);
104 std::istringstream iss;
113 while (std::getline(file_in, line)) {
114 if (std::regex_match(line, nuclide_line)) {
123 PDGs.insert(marley_utils::get_nucleus_pid(Z, A));
133 const int particle_id)
137 auto iter = decay_scheme_table_.find( particle_id );
138 if ( iter != decay_scheme_table_.end() )
return iter->second.get();
143 MARLEY_LOG( DEBUG,
"init.structure.decay" )
144 <<
"Looking up structure data for " << ta_requested;
146 if ( !loaded_structure_index_ ) this->load_structure_index();
147 auto ds_file_iter = decay_scheme_filenames_.find( particle_id );
150 if ( ds_file_iter == decay_scheme_filenames_.end() ) {
151 MARLEY_LOG( NOTICE,
"init.structure.decay" ) <<
"No tabulated decay"
152 " scheme available for " << ta_requested <<
". The Hauser-Feshbach"
153 " statistical model will be used for de-excitation.";
155 decay_scheme_table_[ particle_id ] =
nullptr;
163 std::string ds_file_name = ds_file_iter->second;
165 std::string full_ds_file_name = fm.find_file( ds_file_name );
166 std::ifstream ds_data_file( full_ds_file_name );
167 bool found_it =
false;
168 auto temp_ds = std::make_unique< marley::DecayScheme >();
169 int loaded_nuclide_count = 0;
170 while ( ds_data_file >> *temp_ds ) {
171 int ds_pdg = temp_ds->pdg();
172 if ( particle_id == ds_pdg ) found_it =
true;
175 MARLEY_LOG( DEBUG,
"init.structure.decay" ) <<
"Added decay scheme for "
176 << ta <<
" from " << full_ds_file_name;
177 ++loaded_nuclide_count;
178 temp_ds = std::make_unique< marley::DecayScheme >();
181 MARLEY_LOG( WARN,
"init.structure.decay" )
182 <<
"Failed to load nuclear structure data for " << ta_requested
183 <<
" from the file " << ds_file_name;
186 decay_scheme_table_[ particle_id ] =
nullptr;
188 if ( loaded_nuclide_count > 0 ) {
189 MARLEY_LOG( INFO,
"init.structure.decay" ) <<
"Loaded structure data for "
190 << loaded_nuclide_count <<
" nuclides from the file "
191 << full_ds_file_name;
203 int particle_id = marley_utils::get_nucleus_pid(Z, A);
211 auto iter = optical_model_table_.find( nucleus_pid );
213 if ( iter == optical_model_table_.end() ) {
217 int Z = marley_utils::get_particle_Z( nucleus_pid );
218 int A = marley_utils::get_particle_A( nucleus_pid );
226 auto iter = om_config_map_.find( std::to_string(nucleus_pid) );
227 if ( iter == om_config_map_.end() ) {
228 iter = om_config_map_.find( DEFAULT_OM_KEY );
229 if ( iter == om_config_map_.end() )
throw marley::Error(
"Missing '"
230 + DEFAULT_OM_KEY +
"' key in optical model JSON configuration" );
233 const auto& om_config = iter->second;
235 return *( optical_model_table_.emplace( nucleus_pid,
236 std::make_unique< marley::KoningDelarocheOpticalModel >(
237 Z, A, om_config) ).first->second.get() );
239 else return *( iter->second.get() );
243 const int Z,
const int A )
245 int nucleus_pid = marley_utils::get_nucleus_pid( Z, A );
246 auto iter = optical_model_table_.find( nucleus_pid );
248 if ( iter == optical_model_table_.end() ) {
256 auto iter = om_config_map_.find( std::to_string(nucleus_pid) );
257 if ( iter == om_config_map_.end() ) {
258 iter = om_config_map_.find( DEFAULT_OM_KEY );
259 if ( iter == om_config_map_.end() )
throw marley::Error(
"Missing '"
260 + DEFAULT_OM_KEY +
"' key in optical model JSON configuration" );
263 const auto& om_config = iter->second;
268 return *( optical_model_table_.emplace( nucleus_pid,
269 std::make_unique< marley::KoningDelarocheOpticalModel >(
270 Z, A, om_config) ).first->second.get() );
272 else return *( iter->second.get() );
278 auto iter = level_density_table_.find(nucleus_pid);
280 if (iter == level_density_table_.end()) {
284 int Z = marley_utils::get_particle_Z( nucleus_pid );
285 int A = marley_utils::get_particle_A( nucleus_pid );
286 return *(level_density_table_.emplace(nucleus_pid,
287 std::make_unique<marley::BackshiftedFermiGasModel>(Z, A)).first
290 else return *(iter->second.get());
294 const int Z,
const int A)
296 int pid = marley_utils::get_nucleus_pid(Z, A);
304 int Z = marley_utils::get_particle_Z( nuc_pdg );
305 int A = marley_utils::get_particle_A( nuc_pdg );
313 int pid = marley_utils::get_nucleus_pid(Z, A);
315 auto iter = gamma_strength_function_table_.find(pid);
317 if (iter == gamma_strength_function_table_.end()) {
321 return *(gamma_strength_function_table_.emplace(pid,
322 std::make_unique<marley::StandardLorentzianModel>(Z, A)).first
325 else return *(iter->second.get());
332 decay_scheme_table_.erase( pdg );
336 decay_scheme_table_.clear();
340 const int fragment_pdg)
344 if ( !initialized_gs_spin_parity_table_ ) initialize_jpi_table();
345 auto iter = fragment_table_.find( fragment_pdg );
346 if ( iter == fragment_table_.end() )
return nullptr;
347 else return &iter->second;
351 const int Z,
const int A)
353 int fragment_pdg = marley_utils::get_nucleus_pid( Z, A );
360 int nuc_pdg = marley_utils::get_nucleus_pid( Z, A );
367 if ( !initialized_gs_spin_parity_table_ ) initialize_jpi_table();
368 auto iter = jpi_table_.find( nuc_pdg );
369 if ( iter == jpi_table_.end() )
throw marley::Error(
"Unrecognized"
370 " nuclear PDG code " + std::to_string(nuc_pdg) +
" passed to"
371 " marley::StructureDatabase::get_gs_spin_parity()" );
372 auto pair = iter->second;
377void marley::StructureDatabase::initialize_jpi_table() {
383 std::string full_jpi_file_name
384 = fm.find_file( jpi_data_file_name_ );
386 if ( full_jpi_file_name.empty() ) {
387 throw marley::Error(
"Could not find the MARLEY nuclear ground-state"
388 " spin-parity data file " + jpi_data_file_name_ +
". Please ensure that"
389 " the folder containing it is on the MARLEY search path."
390 " If needed, the folder can be appended to the MARLEY_SEARCH_PATH"
391 " environment variable." );
394 MARLEY_LOG( INFO,
"init.structure" ) <<
"Loading ground-state nuclear spin-parities from "
395 << full_jpi_file_name;
397 std::ifstream table_file( full_jpi_file_name );
400 while ( table_file >> nuc_pdg >> twoJ >> Pi ) {
401 MARLEY_LOG( TRACE,
"init.structure" ) <<
"Nucleus with PDG code " << nuc_pdg
402 <<
" has spin-parity " <<
static_cast<double>( twoJ ) / 2. << Pi;
403 jpi_table_[ nuc_pdg ] = std::pair<int, marley::Parity>( twoJ, Pi );
408 initialized_gs_spin_parity_table_ =
true;
412 using namespace marley_utils;
413 constexpr std::array< int, 6 > FRAGMENTS_TO_CONSIDER =
414 { NEUTRON, PROTON, DEUTERON, TRITON, HELION, ALPHA };
416 for (
int f_pdg : FRAGMENTS_TO_CONSIDER ) {
427 marley::StructureDatabase::fragment_table_.emplace(
428 std::make_pair( f_pdg, marley::Fragment(f_pdg, f_twoJ, f_Pi) ));
433void marley::StructureDatabase::load_structure_index() {
438 std::string full_index_file_name = fm.find_file( structure_index_filename_ );
440 if ( full_index_file_name.empty() ) {
441 throw marley::Error(
"Could not find the MARLEY structure data index file "
442 + structure_index_filename_ +
". Please ensure that"
443 " the folder containing it is on the MARLEY search path."
444 " If needed, the folder can be appended to the MARLEY_SEARCH_PATH"
445 " environment variable." );
448 MARLEY_LOG( INFO,
"init.structure" ) <<
"Loaded structure data index from "
449 << full_index_file_name;
451 std::ifstream index_file( full_index_file_name );
453 std::string data_file_name;
454 while ( index_file >> nuc_pdg >> data_file_name ) {
455 MARLEY_LOG( TRACE,
"init.structure.decay" ) <<
"Nucleus with PDG code "
456 << nuc_pdg <<
" has a tabulated decay scheme in the file "
458 decay_scheme_filenames_[ nuc_pdg ] = data_file_name;
461 MARLEY_LOG( DEBUG,
"init.structure.decay" ) <<
"Structure index loaded: "
462 << decay_scheme_filenames_.size() <<
" nuclide(s) indexed";
466 loaded_structure_index_ =
true;
477 om_config_map_ = assign_from_json< std::map<std::string, marley::JSON> >(
483 const std::string om_file_name(
"optical_model_kduq_federal_cv.js" );
484 std::string om_full_file_name = fm.find_file( om_file_name );
486 if ( om_full_file_name.empty() ) {
487 throw marley::Error(
"Could not find the MARLEY nuclear optical model"
488 " configuration file " + om_file_name +
". Please ensure that"
489 " the folder containing it is on the MARLEY search path."
490 " If needed, the folder can be appended to the MARLEY_SEARCH_PATH"
491 " environment variable." );
494 MARLEY_LOG( INFO,
"init.structure" ) <<
"Loading nuclear optical model parameters from "
495 << om_full_file_name;
497 auto temp_config = marley::JSON::load_file( om_full_file_name );
498 om_config_map_ = assign_from_json< std::map<std::string, marley::JSON> >(
502 if ( !ok )
throw marley::Error(
"Failed to parse optical model"
503 " JSON configuration" );
Discrete level and γ-ray data for a specific nuclide.
FileFormat
The FileFormat type is used to tell the DecayScheme class which format to assume when parsing a discr...
Base class for all exceptions thrown by MARLEY functions.
static const FileManager & Instance()
Get a const reference to the singleton instance of the FileManager.
Simple container for storing reference data about each of the nuclear fragments considered by MARLEY'...
Abstract base class for models of gamma-ray strength functions.
Abstract base class for models of nuclear level densities.
Abstract base class for nuclear optical model implementations.
Type-safe representation of a parity value (either +1 or -1)
marley::GammaStrengthFunctionModel & get_gamma_strength_function_model(const int Z, const int A)
Retrieves a gamma-ray strength function model object from the database, creating it if one did not al...
void remove_decay_scheme(int pdg)
Deletes the discrete level data in the database associated with a given nuclide.
static const marley::Fragment * get_fragment(const int fragment_pdg)
Retrieves nuclear fragment data from the database.
void load_optical_model_params(const marley::JSON *om_config=nullptr)
Helper function that initializes the map of JSON settings for the optical model parameters.
marley::OpticalModel & get_optical_model(int nucleus_pid)
Retrieves an optical model object from the database, creating it if one did not already exist.
void add_decay_scheme(int pdg, std::unique_ptr< marley::DecayScheme > &ds)
Add a DecayScheme object to the database that contains discrete level data for a specific nuclide.
std::set< int > find_all_nuclides(const std::string &filename, DecayScheme::FileFormat format=DecayScheme::FileFormat::talys)
Create a set of Particle Data Group codes for every nuclide in a discrete level data file.
static void get_gs_spin_parity(int nuc_pdg, int &twoJ, marley::Parity &Pi)
Looks up the ground-state spin-parity for a particular nuclide.
StructureDatabase()
Creates an empty database.
void emplace_decay_scheme(int pdg, const std::string &filename, DecayScheme::FileFormat format=DecayScheme::FileFormat::talys)
Construct and add a DecayScheme object to the database that contains discrete level data for a specif...
marley::DecayScheme * get_decay_scheme(const int particle_id)
Retrieves discrete level data from the database.
marley::LevelDensityModel & get_level_density_model(const int nucleus_pid)
Retrieves a level density model object from the database, creating it if one did not already exist.
void clear()
Removes all previously stored data from the database.
An atomic target for a lepton scattering reaction.