22#include "tkdatabase.h"
37using json = nlohmann::json;
47 std::lock_guard<std::recursive_mutex> lock(get_mutex());
57 const auto scheme = fmap_of_level_scheme.find(_nuc);
58 return scheme != fmap_of_level_scheme.end() &&
59 std::atomic_load_explicit(&scheme->second, std::memory_order_acquire) !=
nullptr;
62shared_ptr<tklevel_scheme> tkmanager::get_level_scheme(
const tkn::tkstring &_nuc,
int _zz,
int _aa)
64 const auto scheme = fmap_of_level_scheme.find(_nuc);
65 const auto once = fmap_of_level_scheme_once.find(_nuc);
66 if (scheme == fmap_of_level_scheme.end() || once == fmap_of_level_scheme_once.end())
67 return make_shared<tklevel_scheme>(_nuc, _zz, _aa);
69 std::call_once(*once->second, [&] {
73 std::lock_guard<std::mutex> load_lock(flevel_scheme_load_mutex);
74 auto loaded = make_shared<tklevel_scheme>(_nuc, _zz, _aa);
75 std::atomic_store_explicit(&scheme->second, std::move(loaded), std::memory_order_release);
77 return std::atomic_load_explicit(&scheme->second, std::memory_order_acquire);
80void tkmanager::preload_nuclei()
83 if (!gdatabase->get_sql_db())
return;
85 fvector_of_nuclei.reserve(4000);
88 tkdb_table &iso_table = (*gdatabase)[
"ISOTOPE"];
90 static const std::array<tkstring, 17> property_names = {
92 "abundance",
"quadrupoleDeformation",
"FY235U",
"FY238U",
"FY239Pu",
"FY241Pu",
"FY252Cf",
"cFY235U",
"cFY238U",
"cFY239Pu",
"cFY241Pu",
"cFY252Cf",
93 "mass_excess",
"radius",
"magnetic_dipole",
"electric_quadrupole"
96 for (std::size_t index = 0; index < property_names.size(); ++index)
100 gdatabase->begin(
"isotope.*, element.*",
"isotope INNER JOIN element on isotope.element_id=element.element_id");
102 while (gdatabase->next()) {
103 shared_ptr<tknucleus> anucleus = make_shared<tknucleus>();
105 tkstring name = element[
"symbol"].get_value();
106 anucleus->felement_symbol = name;
107 anucleus->felement_name = element[
"element_name"].get_value();
109 int zz = element[
"charge"].get_value().atoi();
110 int aa = iso_table[
"mass"].get_value().atoi();
112 gdebug << aa << name <<
" loaded" <<
do_endl;
114 name.
prepend(iso_table[
"mass"].get_value());
116 anucleus->set_name(name.data());
119 anucleus->fN = aa - zz;
120 anucleus->fis_known =
true;
124 tkstring colname = col.first;
125 if (colname ==
"element_id")
continue;
126 if (colname.
ends_with(
"_unit"))
continue;
128 tkstring colname_unit = colname +
"_unit";
130 tkstring value = col.second.get_value();
135 unit = element.
get_columns().at(colname_unit).get_value();
137 if (colname ==
"atomic_mass" ||
138 colname ==
"atomic_radius_van_der_Waals" ||
139 colname ==
"boiling_point" ||
140 colname ==
"density" ||
141 colname ==
"ionization_energy" ||
142 colname ==
"melting_point") {
143 shared_ptr<tkmeasure> data = make_shared<tkmeasure>(value.
atof(), unit);
145 data->set_type(colname);
146 anucleus->add_property(colname, data);
149 shared_ptr<tkmeasure> data = make_shared<tkmeasure>(value.
atof(), unit);
151 data->set_type(colname);
152 if (value.
atof() > 0) anucleus->add_property(colname, data);
154 anucleus->add_property_str(colname, value, unit);
159 for (std::size_t index = 0; index < property_names.size(); ++index) {
160 const auto &property_name = property_names[index];
161 tkdb_table::measure_data_struct data_struct;
162 iso_table.
read_measure(data_struct, property_columns[index]);
164 shared_ptr<tkmeasure> data;
166 data = make_shared<tkmeasure>(data_struct.
value, data_struct.
unit,
169 data = make_shared<tkmeasure>(data_struct.
value, data_struct.
unit, data_struct.
err);
172 data->set_type(property_name);
173 if (property_name ==
"lifetime")
174 data->set_type(gunits->get_type(data->get_unit_key()) == gunits->kEnergy ?
"decay width" :
"half-life");
176 if (property_name ==
"lifetime") {
177 if (data->get_info_tag().contains(
"STABLE")) {
178 anucleus->fis_stable =
true;
180 anucleus->add_property(property_name, data,
"STABLE",
"");
182 anucleus->add_property(property_name, data,
tkstring::form(
"%g", data->get_value()));
184 anucleus->add_property(property_name, data);
189 tkstring discovery_year = iso_table[
"isotope_year_discovered"].get_value();
191 anucleus->add_property_str(
"isotope_year_discovered", discovery_year,
"");
193 tkstring decay_modes = iso_table[
"decay_modes"].get_value();
195 anucleus->add_property_str(
"decay_modes", decay_modes,
"");
197 tkstring spin_parity_str = iso_table[
"spin_parity"].get_value();
199 double spin = iso_table[
"spin"].get_value().atof();
200 int parity = iso_table[
"parity"].get_value().atoi();
202 anucleus->fspin_parity.set_spin(spin);
203 anucleus->fspin_parity.set_parity(parity);
204 anucleus->fspin_parity.set_from_str(spin_parity_str);
206 anucleus->add_property_str(
"spin_parity", spin_parity_str,
"");
209 fmap_of_nuclei[name] = anucleus;
210 fmap_of_nuclei_per_z[anucleus->fZ].push_back(anucleus);
211 fmap_of_nuclei_per_a[anucleus->fA].push_back(anucleus);
212 fmap_of_nuclei_per_n[anucleus->fN].push_back(anucleus);
213 fmap_of_nuclei_per_z_and_a[anucleus->fZ][anucleus->fA] = anucleus;
214 fvector_of_nuclei.push_back(anucleus);
215 fmap_of_level_scheme.emplace(name,
nullptr);
216 fmap_of_level_scheme_once.emplace(name, make_shared<std::once_flag>());
218 if (!fmap_of_symbols.count(anucleus->get_z()))
219 fmap_of_symbols[anucleus->get_z()] = anucleus->get_element_symbol();
224 auto neutron_ME = fmap_of_nuclei_per_z_and_a.at(0).at(1)->get(
"mass_excess");
225 auto proton_ME = fmap_of_nuclei_per_z_and_a.at(1).at(1)->get(
"mass_excess");
226 auto alpha_ME = fmap_of_nuclei_per_z_and_a.at(2).at(4)->get(
"mass_excess");
227 tkmeasure electron_mass(0.51099895000,
"MeV", 0.00000000015);
228 for (
auto &nuc : fmap_of_nuclei) {
229 auto ME = nuc.second->get(
"mass_excess");
232 auto daughter =
get_nucleus(nuc.second->get_z(), nuc.second->get_a() - 1);
233 if (daughter && daughter->get(
"mass_excess")) {
234 shared_ptr<tkmeasure> Sn = make_shared<tkmeasure>(-*ME + *daughter->get(
"mass_excess") + *neutron_ME);
235 Sn->set_type(
"neutronSeparationEnergy");
236 nuc.second->add_property(
"neutronSeparationEnergy", Sn);
239 daughter =
get_nucleus(nuc.second->get_z(), nuc.second->get_a() - 2);
240 if (daughter && daughter->get(
"mass_excess")) {
241 shared_ptr<tkmeasure> S2n = make_shared<tkmeasure>(-*ME + *daughter->get(
"mass_excess") + 2. * (*neutron_ME));
242 S2n->set_type(
"twoNeutronSeparationEnergy");
243 nuc.second->add_property(
"twoNeutronSeparationEnergy", S2n);
246 daughter =
get_nucleus(nuc.second->get_z() - 1, nuc.second->get_a() - 1);
247 if (daughter && daughter->get(
"mass_excess")) {
248 shared_ptr<tkmeasure> Sp = make_shared<tkmeasure>(-*ME + *daughter->get(
"mass_excess") + *proton_ME);
249 Sp->set_type(
"protonSeparationEnergy");
250 nuc.second->add_property(
"protonSeparationEnergy", Sp);
253 daughter =
get_nucleus(nuc.second->get_z() - 2, nuc.second->get_a() - 2);
254 if (daughter && daughter->get(
"mass_excess")) {
255 shared_ptr<tkmeasure> S2p = make_shared<tkmeasure>(-*ME + *daughter->get(
"mass_excess") + 2. * (*proton_ME));
256 S2p->set_type(
"twoProtonSeparationEnergy");
257 nuc.second->add_property(
"twoProtonSeparationEnergy", S2p);
261 daughter =
get_nucleus(nuc.second->get_z() - 2, nuc.second->get_a() - 4);
262 if (daughter && daughter->get(
"mass_excess")) {
263 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess") - *alpha_ME);
264 Q->set_type(
"Qalpha");
265 nuc.second->add_property(
"Qalpha", Q);
268 daughter =
get_nucleus(nuc.second->get_z() + 1, nuc.second->get_a());
269 if (daughter && daughter->get(
"mass_excess")) {
270 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess"));
271 Q->set_type(
"QbetaMinus");
272 nuc.second->add_property(
"QbetaMinus", Q);
275 daughter =
get_nucleus(nuc.second->get_z() + 1, nuc.second->get_a() - 1);
276 if (daughter && daughter->get(
"mass_excess")) {
277 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess") - *neutron_ME);
278 Q->set_type(
"QbetaMinusOneNeutronEmission");
279 nuc.second->add_property(
"QbetaMinusOneNeutronEmission", Q);
282 daughter =
get_nucleus(nuc.second->get_z() + 1, nuc.second->get_a() - 2);
283 if (daughter && daughter->get(
"mass_excess")) {
284 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess") - 2. * (*neutron_ME));
285 Q->set_type(
"QbetaMinusTwoNeutronEmission");
286 nuc.second->add_property(
"QbetaMinusTwoNeutronEmission", Q);
289 daughter =
get_nucleus(nuc.second->get_z() + 2, nuc.second->get_a() + 4);
290 auto alpha_daughter =
get_nucleus(nuc.second->get_z() - 2, nuc.second->get_a() - 4);
291 if (daughter && daughter->get(
"mass_excess") && alpha_daughter && alpha_daughter->get(
"mass_excess")) {
294 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(
295 0.5 * (*daughter->get(
"mass_excess") + *alpha_daughter->get(
"mass_excess") - 2. * (*ME)));
296 Q->set_type(
"QdeltaAlpha");
297 nuc.second->add_property(
"QdeltaAlpha", Q);
300 daughter =
get_nucleus(nuc.second->get_z() + 2, nuc.second->get_a());
301 if (daughter && daughter->get(
"mass_excess")) {
302 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess"));
303 Q->set_type(
"QdoubleBetaMinus");
304 nuc.second->add_property(
"QdoubleBetaMinus", Q);
307 daughter =
get_nucleus(nuc.second->get_z() - 1, nuc.second->get_a());
308 if (daughter && daughter->get(
"mass_excess")) {
309 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess"));
310 Q->set_type(
"QelectronCapture");
311 nuc.second->add_property(
"QelectronCapture", Q);
314 daughter =
get_nucleus(nuc.second->get_z() - 2, nuc.second->get_a());
315 if (daughter && daughter->get(
"mass_excess")) {
316 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess"));
317 Q->set_type(
"QdoubleElectronCapture");
318 nuc.second->add_property(
"QdoubleElectronCapture", Q);
321 daughter =
get_nucleus(nuc.second->get_z() - 2, nuc.second->get_a() - 1);
322 if (daughter && daughter->get(
"mass_excess")) {
323 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess") - *proton_ME);
324 Q->set_type(
"QelectronCaptureOneProtonEmission");
325 nuc.second->add_property(
"QelectronCaptureOneProtonEmission", Q);
328 daughter =
get_nucleus(nuc.second->get_z() - 1, nuc.second->get_a());
329 if (daughter && daughter->get(
"mass_excess")) {
330 auto q_positron = make_shared<tkmeasure>(*ME - *daughter->get(
"mass_excess") - 2. * electron_mass);
331 q_positron->set_type(
"QpositronEmission");
332 nuc.second->add_property(
"QpositronEmission", q_positron);
336 auto q_binding = make_shared<tkmeasure>(1. / nuc.second->get_a() * (nuc.second->get_z() * (*proton_ME) + nuc.second->get_n() * (*neutron_ME) - *ME));
337 q_binding->set_type(
"binding_energy_overA");
338 nuc.second->add_property(
"binding_energy_overA", q_binding);
341 auto nuc_minus =
get_nucleus(nuc.second->get_z(), nuc.second->get_a() - 1);
342 auto nuc_plus =
get_nucleus(nuc.second->get_z(), nuc.second->get_a() + 1);
343 if (nuc_minus && nuc_plus && nuc_minus->get(
"mass_excess") && nuc_plus->get(
"mass_excess")) {
344 auto q_pairing = make_shared<tkmeasure>(0.5 * pow(-1, nuc.second->get_n()) * (-2 * (*ME) + *nuc_minus->get(
"mass_excess") + *nuc_plus->get(
"mass_excess")));
345 q_pairing->set_type(
"pairingGap");
346 nuc.second->add_property(
"pairingGap", q_pairing);
353 size_t nnuc = fvector_of_nuclei.size(), inuc = 0;
354 for (
const auto &nuc : fvector_of_nuclei) {
355 if (_verbose) glog.progress_bar(nnuc, inuc,
"... pre-loading");
356 get_level_scheme(nuc->get_symbol(), nuc->get_z(), nuc->get_a());
378 vector<shared_ptr<tknucleus>> res;
379 std::copy_if(fvector_of_nuclei.begin(), fvector_of_nuclei.end(), std::back_inserter(res),
380 [&_selection](
const auto &nuc) { return _selection(nuc); });
387 for (
auto &nuc_test : fmap_of_nuclei) {
388 if (nuc_test.first.copy().extract_alpha() == symbol) {
389 _z = nuc_test.second->get_z();
398 std::lock_guard<std::recursive_mutex> lock(get_mutex());
400 return fmax_level_id;
405 std::lock_guard<std::recursive_mutex> lock(get_mutex());
407 return fmax_decay_id;
412 std::lock_guard<std::recursive_mutex> lock(get_mutex());
413 if (_id > fmax_level_id) fmax_level_id = _id;
418 std::lock_guard<std::recursive_mutex> lock(get_mutex());
419 if (_id > fmax_decay_id) fmax_decay_id = _id;
450void tkmanager::load_drip_lines(
const tkstring &json_path)
452 std::ifstream f(json_path);
454 glog <<
error <<
"tkmanager::load_drip_lines: cannot open " << json_path <<
do_endl;
461 }
catch (
const std::exception &e) {
462 glog <<
error <<
"tkmanager::load_drip_lines: JSON parse error in "
463 << json_path <<
" : " << e.what() <<
do_endl;
468 glog <<
error <<
"tkmanager::load_drip_lines: root is not an array in "
475 auto push_if_present = [&](
const json &o,
const char *qname,
const char *sname) {
476 if (!o.contains(qname))
return;
477 if (o[qname].is_null())
return;
480 p.
Z = o.value(
"Z", 0);
481 p.
N = o.value(
"N", 0);
482 p.
value_mev = o.value(qname, std::numeric_limits<double>::quiet_NaN());
484 if (o.contains(sname) && !o[sname].is_null()) {
485 p.
sigma_mev = o.value(sname, std::numeric_limits<double>::quiet_NaN());
489 fdrip_lines[p.
type].push_back(std::move(p));
493 for (
const auto &o : j) {
494 if (!o.is_object())
continue;
496 if (!o.contains(
"Z") || !o.contains(
"N"))
continue;
498 push_if_present(o,
"S1n",
"S1n_sigma");
499 push_if_present(o,
"S2n",
"S2n_sigma");
500 push_if_present(o,
"S1p",
"S1p_sigma");
501 push_if_present(o,
"S2p",
"S2p_sigma");
503 }
catch (
const std::exception &e) {
504 glog <<
error <<
"tkmanager::load_drip_lines: error while iterating JSON: "
511 for (
auto &kv : fdrip_lines) {
512 auto &vec = kv.second;
513 std::sort(vec.begin(), vec.end(), [](
const tkn_drip_point &a,
const tkn_drip_point &b) {
514 if (a.Z != b.Z) return a.Z < b.Z;
519 glog <<
info <<
"load_drip_lines: loaded " << j.size()
520 <<
" nuclei objects from " << json_path <<
do_endl;
549 std::lock_guard<std::recursive_mutex> lock(get_mutex());
550 if (fdrip_lines.empty()) {
555 auto it = fdrip_lines.find(_type);
556 if (it == fdrip_lines.end()) {
557 glog <<
warning <<
"get_drip_line: unknown type '" << _type <<
"'" <<
do_endl;
561 const auto &vec = it->second;
568 std::unordered_map<int, tkn_drip_point> best_by_Z;
569 for (
const auto &p : vec) {
570 auto itZ = best_by_Z.find(p.
Z);
571 if (itZ == best_by_Z.end()) {
574 const auto &cur = itZ->second;
575 if (std::isnan(cur.value_mev) ||
582 std::vector<tkn_drip_point> reduced;
583 reduced.reserve(best_by_Z.size());
584 std::transform(best_by_Z.begin(), best_by_Z.end(), std::back_inserter(reduced),
585 [](
const auto &kv) { return kv.second; });
588 if (a.Z != b.Z) return a.Z < b.Z;
Representaiton of a sqlite data table.
std::array< tkdb_column *, 6 > measure_columns
void read_measure(measure_data_struct &_struct, const tkstring &_col_base_name)
measure_columns get_measure_columns(const tkstring &_col_base_name)
Manages the database loading and provides access to the physics properties.
void set_max_level_id(int _id)
define the max value of the attributed level ids
static tkmanager * the_data_manager()
int get_new_level_id()
define a new unique level id
std::vector< tkn_drip_point > get_drip_line(const std::string &_type, bool reduce_per_Z=true)
Get the drip line for a given type (optionally reduced per Z)
shared_ptr< tknucleus > get_nucleus(const tkstring &_nuc)
return a shared pointer to a nucleus from its name
const vector< shared_ptr< tknucleus > > & get_nuclei()
return a vector containing all the known nuclei
int get_new_decay_id()
define a new unique decay id
void set_max_decay_id(int _id)
define the max value of the attributed level ids
bool known_element(tkstring _nuc, int &_z)
is the element symbol is known (ex: "C")
void preload_level_schemes(bool _verbose=false)
preload all the level schemes from the database
bool is_level_scheme_loaded(const tkstring &_nuc)
returns true if the level scheme has already been loaded
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
tkstring extract_alpha()
Returns a tkstring composed only of the alphabetic letters of the original tkstring.
static const char * form(const char *_format,...)
static tkstring Form(const char *_format,...)
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
tkstring & prepend(const tkstring &_st)
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
double atof() const
Converts a string to double value.
tklog & error(tklog &log)
tklog & do_endl(tklog &log)
tklog & warning(tklog &log)
A single drip-line data point.
double value_mev
Quantity value (MeV)
std::string type
Quantity type: "S1n", "S2n", "S1p", or "S2p".
double sigma_mev
Quantity uncertainty (MeV)