18#include "marley/Error.hh"
19#include "marley/Fragment.hh"
20#include "marley/FileManager.hh"
21#include "marley/JSON.hh"
22#include "marley/Logger.hh"
23#include "marley/MassTable.hh"
24#include "marley/StructureDatabase.hh"
25#include "marley/marley_utils.hh"
28const std::string marley::MassTable::data_file_name_ =
"mass_table.js";
35 std::string full_mt_file_name
36 = fm.find_file( data_file_name_ );
38 if ( full_mt_file_name.empty() ) {
40 " data file " + data_file_name_ +
". Please ensure that"
41 " the folder containing it is on the MARLEY search path."
42 " If needed, the folder can be appended to the MARLEY_SEARCH_PATH"
43 " environment variable.");
46 MARLEY_LOG( INFO,
"init.structure" ) <<
"Loading particle and atomic masses from "
50 auto json_table = marley::JSON::load_file( full_mt_file_name );
53 if ( !json_table.has_key(
"particle_masses") ) {
54 throw marley::Error(
"Problem reading the mass table data file "
55 + data_file_name_ +
". Missing \"particle_masses\" JSON array.");
57 const auto& pm_json = json_table.at(
"particle_masses");
58 assign_masses( pm_json,
"particle_masses", this->particle_masses_ );
60 if ( !json_table.has_key(
"atomic_masses") ) {
61 throw marley::Error(
"Problem reading the mass table data file "
62 + data_file_name_ +
". Missing \"atomic_masses\" JSON array.");
64 const auto& am_json = json_table.at(
"atomic_masses");
65 assign_masses( am_json,
"atomic_masses", this->atomic_masses_ );
73 static std::unique_ptr<marley::MassTable>
92 return micro_amu_ * particle_masses_.at(
id);
98 double mass = lookup_atomic_mass(nucleus_pid, exp,
100 if (exp) mass *= micro_amu_;
104double marley::MassTable::lookup_atomic_mass(
int nucleus_pid,
bool& exp,
105 bool theory_ok)
const
111 auto search = atomic_masses_.find(nucleus_pid);
115 if (search != atomic_masses_.end()) {
117 return search->second;
126 int Z = marley_utils::get_particle_Z(nucleus_pid);
127 int A = marley_utils::get_particle_A(nucleus_pid);
130 return liquid_drop_model_atomic_mass(Z, A);
132 else throw marley::Error(std::string(
"Entry for Z = ")
133 + std::to_string(Z) +
" and A = " + std::to_string(A)
134 +
" not found in the MARLEY atomic mass table.");
138double marley::MassTable::lookup_atomic_mass(
int Z,
int A,
bool& exp,
139 bool theory_ok)
const
141 int nucleus_pid = marley_utils::get_nucleus_pid(Z, A);
143 auto search = atomic_masses_.find(nucleus_pid);
147 if (search != atomic_masses_.end()) {
149 return search->second;
159 return liquid_drop_model_atomic_mass(Z, A);
161 else throw marley::Error(std::string(
"Entry for Z = ")
162 + std::to_string(Z) +
" and A = " + std::to_string(A)
163 +
" not found in the MARLEY atomic mass table.");
170 double m_hydrogen_1 = atomic_masses_.at(1000010010);
171 double mn = particle_masses_.at(marley_utils::NEUTRON);
174 double mN = lookup_atomic_mass(Z, A, exp, theory_ok);
179 if (exp)
return micro_amu_ * (Z*m_hydrogen_1 + N*mn - mN);
180 else return micro_amu_ * (Z*m_hydrogen_1 + N*mn) - mN;
186 double mN = lookup_atomic_mass(Z, A, exp, theory_ok);
187 if (exp)
return micro_amu_*(mN - A*1e6);
188 else return mN - micro_amu_*A*1e6;
193 double mass = lookup_atomic_mass(Z, A, exp, theory_ok);
194 if (exp) mass *= micro_amu_;
199 int frag_pdg,
bool theory_ok)
const
201 int Zi = marley_utils::get_particle_Z( nuc_pdg );
202 int Ai = marley_utils::get_particle_A( nuc_pdg );
207 bool theory_ok)
const
209 int Zx = marley_utils::get_particle_Z(pid);
211 int Af = A - marley_utils::get_particle_A(pid);
214 double extra_mass = Zx*particle_masses_.at(marley_utils::ELECTRON)
215 + particle_masses_.at(pid);
219 double m_atom_initial = lookup_atomic_mass(Z, A, exp_i, theory_ok);
220 double m_atom_final = lookup_atomic_mass(Zf, Af, exp_f, theory_ok);
226 if (exp_f)
return micro_amu_*(m_atom_final - m_atom_initial + extra_mass);
227 else return m_atom_final + micro_amu_*(extra_mass - m_atom_initial);
229 else if (exp_f)
return micro_amu_*(m_atom_final + extra_mass)
231 else return micro_amu_*extra_mass + m_atom_final - m_atom_initial;
241 static constexpr double Mn = 8.07144;
242 static constexpr double MH = 7.28899;
243 static constexpr double a1 = 15.677;
244 static constexpr double a2 = 18.56;
245 static constexpr double kappa = 1.79;
246 static constexpr double c3 = 0.717;
247 static constexpr double c4 = 1.21129;
251 double kappa_term = kappa * std::pow((N - Z) /
static_cast<double>(A), 2);
252 double c1 = a1 * (1 - kappa_term);
253 double c2 = a2 * (1 - kappa_term);
255 double Evol = -c1 * A;
256 double Esur = c2 * std::pow(A, 2.0/3.0);
257 double Ecoul = (c3 / std::pow(A, 1.0/3.0) - c4 / A) * std::pow(Z, 2);
259 double delta_LDM = 0;
264 if (z_odd && n_odd) delta_LDM = 11/std::sqrt(A);
265 else if (!z_odd && !n_odd) delta_LDM = -11/std::sqrt(A);
267 return Mn * N + MH * Z + Evol + Esur + Ecoul + delta_LDM;
286 MARLEY_LOG( TRACE,
"init.structure.masstable" ) <<
"unbound_threshold = " <<
unbound_threshold <<
'\n';
293 MARLEY_LOG( TRACE,
"init.structure.masstable" ) << f.
get_pid()
294 <<
" emission threshold = " << thresh <<
'\n';
296 MARLEY_LOG( TRACE,
"init.structure.masstable" ) <<
"unbound_threshold = "
305 int Zi = marley_utils::get_particle_Z( initial_nucleus_pdg );
306 int Ai = marley_utils::get_particle_A( initial_nucleus_pdg );
310void marley::MassTable::assign_masses(
const marley::JSON& obj_array,
311 const std::string& array_key, std::unordered_map<int, double>& map_to_use)
313 if ( !obj_array.is_array() ) {
315 " mass data file " + data_file_name_
316 +
" does not refer to a JSON array.");
318 auto elements = obj_array.array_range();
319 if ( elements.begin() == elements.end() ) {
321 " the mass data file " + data_file_name_ +
" is empty.");
323 bool pdg_ok, mass_ok;
324 for (
const auto& el : elements) {
326 if ( !el.has_key(
"pdg") ) {
327 throw marley::Error(
"Missing pdg code for an element of the"
328 " \"" + array_key +
"\" array in the mass data file " + data_file_name_);
330 else if ( !el.has_key(
"mass") ) {
331 throw marley::Error(
"Missing mass for an element of the"
332 " \"" + array_key +
"\" array in the mass data file " + data_file_name_);
335 auto pdg_json = el.at(
"pdg");
336 int pdg = pdg_json.to_long( pdg_ok );
337 if ( !pdg_ok )
throw marley::Error(std::string(
"Invalid PDG code \"")
338 + pdg_json.dump_string() +
"\" given in the \"" + array_key +
"\" array"
339 " in the mass data file " + data_file_name_);
341 auto mass_json = el.at(
"mass");
342 double mass = mass_json.to_double( mass_ok );
343 if ( !mass_ok )
throw marley::Error(std::string(
"Invalid mass value \"")
344 + mass_json.dump_string() +
"\" given in the \"" + array_key +
"\" array"
345 " in the mass data file " + data_file_name_);
347 map_to_use[ pdg ] = mass;
348 MARLEY_LOG( TRACE,
"init.structure.masstable" ) << array_key
349 <<
": PDG " << pdg <<
" -> mass = " << mass <<
" MeV";
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'...
int get_pid() const
Get the PDG particle ID for this fragment.
Singleton lookup table for particle and atomic masses.
double fragment_emission_threshold(const int Zi, const int Ai, const marley::Fragment &f) const
Get the approximate excitation energy threshold for emission of a particular nuclear fragment.
double get_fragment_separation_energy(int Z, int A, int pdg, bool theory_ok=true) const
Get the separation energy for emission of a nuclear fragment from a nucleus.
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
double get_mass_excess(int Z, int A, bool theory_ok=true) const
Get the mass excess of a nucleus.
double get_atomic_mass(int pdg_code, bool theory_ok=true) const
Get the mass of an atom.
double liquid_drop_model_atomic_mass(int Z, int A) const
Calculate a theoretical atomic mass using the liquid drop model.
double get_binding_energy(int Z, int A, bool theory_ok=true) const
Get the binding energy of a nucleus.
double get_particle_mass(int pdg_code) const
Get the mass of a particle.
double liquid_drop_model_mass_excess(int Z, int A) const
Calculate a theoretical mass excess for a nucleus using the liquid drop model.
double unbound_threshold(const int Zi, const int Ai) const
Computes the lowest excitation energy at which one of the nuclear fragments considered by the HauserF...
MassTable()
Create the singleton MassTable object.
static const std::map< int, marley::Fragment > & fragments()
Retrieves a const reference to the table of Fragment objects.