TkN 2.1
Toolkit for Nuclei
tkisotope_builder.cpp
1/********************************************************************************
2 * Copyright (c) : Université de Lyon 1, CNRS/IN2P3, UMR5822, *
3 * IP2I, F-69622 Villeurbanne Cedex, France *
4 * Normandie Université, ENSICAEN, UNICAEN, CNRS/IN2P3, *
5 * LPC Caen, F-14000 Caen, France *
6 * Contibutor(s) : *
7 * Jérémie Dudouet jeremie.dudouet@cnrs.fr [2020] *
8 * Diego Gruyer diego.gruyer@cnrs.fr [2020] *
9 * *
10 * This software is governed by the CeCILL-B license under French law and *
11 * abiding by the rules of distribution of free software. You can use, *
12 * modify and/ or redistribute the software under the terms of the *
13 * CeCILL-B license as circulated by CEA, CNRS and INRIA at the following *
14 * URL \"http://www.cecill.info\". *
15 * *
16 * As a counterpart to the access to the source code and rights to copy, *
17 * modify and redistribute granted by the license, users are provided *
18 * only with a limited warranty and the software's author, the holder of *
19 * the economic rights, and the successive licensors have only limited *
20 * liability. *
21 * *
22 * In this respect, the user's attention is drawn to the risks associated *
23 * with loading, using, modifying and/or developing or reproducing the *
24 * software by the user in light of its specific status of free software, *
25 * that may mean that it is complicated to manipulate, and that also *
26 * therefore means that it is reserved for developers and experienced *
27 * professionals having in-depth computer knowledge. Users are therefore *
28 * encouraged to load and test the software's suitability as regards *
29 * their requirements in conditions enabling the security of their *
30 * systems and/or data to be ensured and, more generally, to use and *
31 * operate it in the same conditions as regards security. *
32 * *
33 * The fact that you are presently reading this means that you have had *
34 * knowledge of the CeCILL-B license and that you accept its terms. *
35 ********************************************************************************/
36
37#include "tkisotope_builder.h"
38
39#include <iostream>
40#include <fstream>
41
42#include "tklog.h"
43
44namespace tkn {
51}
52
53using namespace tkn;
54using namespace std;
55
56// Decay Mode : decay modes.
57// Mass excess : Mass excess
58// β2 : quadrupole deformation parameter obtained from the B(E2) value, as explained in the 2001 work of Raman et al. Basically,
59// β2=(4π/3ZR0^2)[B(E2)]^(1/2), where R0=1.2A^(1/3), Z and A are the number of protons and the number of nucleons respectively,
60// and the B(E2) values are obtained from ENSDF. B(E2) values can have large uncertainties, or be defined as upper/lower limits.
61// The cell will not be colored for the latter cases and furthermore, it will not be colored if the uncertainty of the derived β2 exceeds 50%.
62// FY235U : thermal neutron-induced fission yields for 235-Uranium. The fission yields are normalized so that their sum is equal to 2.
63// FY238U : neutron-induced fission yields for 238-Uranium. The fission yields are normalized so that their sum is equal to 2.
64// FY239Pu : thermal neutron-induced fission yields for 239-Plutonium. The fission yields are normalized so that their sum is equal to 2.
65// FY241Pu : neutron-induced fission yields for 239-Plutonium. The fission yields are normalized so that their sum is equal to 2.
66// FY252Cf : spontaneous fission yields for 252-Californium. The fission yields are normalized so that their sum is equal to 2.
67// cFY235U : cumulative fission yields
68// cFY238U : cumulative fission yields
69// cFY239Pu : cumulative fission yields
70// cFY241Pu : cumulative fission yields
71// cFY252Cf : cumulative fission yields
72
73
74tkisotope_builder::tkisotope_builder(tkdatabase *_database, const char *_table_name) : tkdb_builder(_database, _table_name)
75{
76 fTable = &fDataBase->new_table(fTableName);
77
78 fTable->add_column("isotope_id", "INT PRIMARY KEY NOT NULL");
79 fTable->add_column("element_id", "INT NOT NULL");
80 fTable->add_column("mass", "INT");
81
82 // data taken from IAEA API
83
84 fTable->add_column("isotope_year_discovered", "INT");
85
86 add_measure("mass_excess",false);
87 add_measure("electric_quadrupole",false);
88 add_measure("magnetic_dipole",false);
89 add_measure("radius",false);
90
91 // data taken from NUDAT3 json file
92
93 add_measure("abundance",false);
94 add_measure("quadrupoleDeformation",false);
95
96 add_measure("FY235U",false);
97 add_measure("FY238U",false);
98 add_measure("FY239Pu",false);
99 add_measure("FY241Pu",false);
100 add_measure("FY252Cf",false);
101
102 add_measure("cFY235U",false);
103 add_measure("cFY238U",false);
104 add_measure("cFY239Pu",false);
105 add_measure("cFY241Pu",false);
106 add_measure("cFY252Cf",false);
107
108 fTable->add_column("decay_modes", "TEXT");
109
110 // columns created here but filled later by ensdf values
111
112 fTable->add_column("spin","REAL");
113 fTable->add_column("parity","INT");
114 fTable->add_column("spin_parity","TEXT");
115
116 add_measure("lifetime",false);
117
118 fTable->add_constraint("FOREIGN KEY (element_id) REFERENCES ELEMENT (element_id)"); // hold this link with a constraints
119 fTable->write_to_database();
120
121 glog << info << "Creating '" << _table_name << "' table" << do_endl;
122}
123
125
126void tkisotope_builder::fill_isotope(const json_nucleus &_json_nuc)
127{
128 fIsotopeIdx++;
129
130// glog << debug << "filling db with : " << _json_nuc.name.data() << " " << fIsotopeIdx<< do_endl;
131
132 (*fTable)["isotope_id"].set_value(fIsotopeIdx);
133 (*fTable)["element_id"].set_value(_json_nuc.Z+1);
134 (*fTable)["mass"].set_value(_json_nuc.A);
135 (*fTable)["isotope_year_discovered"].set_value(_json_nuc.year);
136
137 fill_measure("mass_excess",_json_nuc.mass_excess,false);
138 fill_measure("abundance",_json_nuc.abundance,false);
139 fill_measure("quadrupoleDeformation",_json_nuc.quadrupoleDeformation,false);
140
141 fill_measure("FY235U",_json_nuc.FY235U,false);
142 fill_measure("FY238U",_json_nuc.FY235U,false);
143 fill_measure("FY239Pu",_json_nuc.FY239Pu,false);
144 fill_measure("FY241Pu",_json_nuc.FY239Pu,false);
145 fill_measure("FY252Cf",_json_nuc.FY252Cf,false);
146
147 fill_measure("cFY235U",_json_nuc.cFY235U,false);
148 fill_measure("cFY238U",_json_nuc.cFY235U,false);
149 fill_measure("cFY239Pu",_json_nuc.cFY239Pu,false);
150 fill_measure("cFY241Pu",_json_nuc.cFY239Pu,false);
151 fill_measure("cFY252Cf",_json_nuc.cFY252Cf,false);
152
153 fill_measure("electric_quadrupole",_json_nuc.electric_quadrupole,false);
154 fill_measure("magnetic_dipole",_json_nuc.magnetic_dipole,false);
155 fill_measure("radius",_json_nuc.radius,false);
156
157 // fill the neutron lifetime
158 if(_json_nuc.Z==0 && _json_nuc.N ==1) {
160 lifetime.value = 613.9;
161 lifetime.err = 0.6;
162 lifetime.unit = "S";
163 lifetime.filled = true;
164 fill_measure("lifetime",lifetime,false);
165 }
166
167 tkstring decays;
168 for(auto &dec: _json_nuc.decay_modes) decays.append(tkstring::form("[%s;%g]",dec.first.data(),dec.second));
169 (*fTable)["decay_modes"].set_value(decays.data());
170
171 fTable->push_row();
172}
173
174int tkisotope_builder::fill_database(const char *_json_filename,const char *_gs_filename, int _only_charge, int _only_mass)
175{
176 glog.set_class("db_isotope_builder");
177 glog.set_method(tkstring::form("fill_database('%s','%s')",_json_filename,_gs_filename));
178
179 tkdb_table &fTable = (*fDataBase)[fTableName.data()];
180
181 tkstring message = "Building '" + fTable.get_name() + "' table";
182
183 std::ifstream ifs(_json_filename);
184 if(!ifs.good()) {
185 glog<< error_v << "data file cannot be opened" << do_endl;
186 glog.clear();
187 return 1;
188 }
189
190 json jf = json::parse(ifs);
191
192 auto &nuclides = jf.at("nuclides");
193 int NNucs = nuclides.size();
194 int inuc=0;
195
196 map<int, map<int, json_nucleus>> nuclei;
197 tkstring nread;
198
199 for(auto &nuc: nuclides) {
200 json_nucleus json_nuc = read_nucleus(nuc);
201
202 bool do_push = ((_only_charge==0) && (_only_mass==0));
203 if((_only_charge == json_nuc.Z) && (_only_mass == 0)) do_push = true;
204 if((_only_charge == json_nuc.Z) && (_only_mass == json_nuc.A)) do_push = true;
205 if((_only_charge == 0) && (_only_mass == json_nuc.A)) do_push = true;
206
207 if(do_push) {
208 nuclei[json_nuc.Z][json_nuc.A] = json_nuc;
209 nread += tkstring::form("(%d,%d)", json_nuc.Z, json_nuc.A);
210 }
211 glog.progress_bar(NNucs,inuc,message.data());
212 inuc++;
213 }
214
215 std::map<int,tkn::tkstring> columns;
216
217 tkn::tkstring line="";
218 fstream file (_gs_filename, ios::in);
219 if(file.is_open())
220 {
221 // read the first line to fill the <number,name> column map
222 if(!getline(file,line)) return 1;
223 int ic=0;
224 for(const auto &cname : line.tokenize(",")) columns[ic++] = cname;
225
226 // now read all lines and fill the <name, value> map
227 while(getline(file, line))
228 {
229 std::map<tkn::tkstring, tkn::tkstring> values;
230 line.replace_all(",,",", ,");
231 line.replace_all(",,",", ,");
232 ic=0;
233 for(auto val : line.tokenize(",")) {val.remove_all(" "); values[columns[ic]] = val; ic++;}
234 tkstring dum = tkstring::form("(%d,%d)",values["z"].atoi(),values["n"].atoi()+values["z"].atoi());
235
236 if(!nread.contains(tkstring::form("(%d,%d)",values["z"].atoi(),values["n"].atoi()+values["z"].atoi()))) continue;
237 auto& nuc = nuclei[values["z"].atoi()][values["n"].atoi()+values["z"].atoi()];
238 if(!values["massexcess"].is_empty()) nuc.mass_excess = {values["massexcess"].atof(),values["unc_me"].atof(),-1.,-1.,"keV",values["me_systematics"].equal_to("Y")?";ERR=SY":"",true};
239 if(!values["radius"].is_empty())nuc.radius = {values["radius"].atof(),values["unc_r"].atof(),-1.,-1.,"fm","",true};
240 if(!values["electric_quadrupole"].is_empty()) nuc.electric_quadrupole = {values["electric_quadrupole"].atof(),values["unc_eq"].atof(),-1.,-1.,"barn","",true};
241 if(!values["magnetic_dipole"].is_empty()) nuc.magnetic_dipole = {values["magnetic_dipole"].atof(),values["unc_md"].atof(),-1.,-1.,"mun","",true};
242 if(!values["discovery"].is_empty()) nuc.year = values["discovery"].atoi();
243 }
244 }
245
246 fDataBase->exec_sql("BEGIN TRANSACTION");
247
248 inuc=0;
249 for(auto &z: nuclei) {
250 for(auto &a: z.second) {
251// glog << debug << "filling db with : " << a.second.name.data() << do_endl;
252
253 fill_isotope(a.second);
254 // json_nuc.print();
255 fDataBase->exec_sql(tkstring::form("CREATE VIEW nuc%s as select * from isotope INNER JOIN element on isotope.element_id=element.element_id where element.charge=%d AND isotope.mass=%d",a.second.name.data(),a.second.Z,a.second.A));
256 glog.progress_bar(NNucs,inuc,message.data());
257 inuc++;
258 }
259 }
260
261 fDataBase->exec_sql("END TRANSACTION");
262
263 fDataBase->exec_sql("CREATE INDEX element_index ON isotope(element_id)");
264 fDataBase->exec_sql("CREATE INDEX mass_index ON isotope(mass)");
265
266
267 glog.clear();
268
269 return 0;
270}
271
272void tkisotope_builder::read_measure(const tkstring &key, const json &entry, tkdb_table::measure_data_struct &_data, bool _fromstd)
273{
274 for(auto &_item: entry.items()) {
275 const auto &_key = _item.key();
276 const auto &_val = _item.value();
277 if(_key == "formats") continue;
278 if(_key == "uncertainty") _data.err = _val.get<tkstring>().atof();
279 else if(_key == "value") _data.value = _val.get<tkstring>().atof();
280 else if(_key == "unit") _data.unit = _val.get<tkstring>();
281 else if(_key == "isSystematics" && _val == "true") _data.info.append(";ERR=SY");
282 else {
283 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
284 cout << _val << endl;
285 }
286 }
287 if(_fromstd) {
288 // extract value and err from nudat formated values
289 tkstring format = entry.at("formats").at("STD").get<tkstring>();
290 auto tokens = format.tokenize();
291 _data.value = tokens.front().atof();
292 if(tokens.size()==2) {
293 _data.err = tokens.back().atof();
294 }
295 }
296 _data.filled = true;
297}
298
299tkisotope_builder::json_nucleus tkisotope_builder::read_nucleus(json &entry) {
300 json_nucleus nuc;
301 bool pause = false;
302 for(auto &item: entry.items())
303 {
304 auto &key = item.key();
305 auto &val = item.value();
306 if(key == "name") nuc.name = val;
307 else if(key == "z") nuc.Z = val;
308 else if(key == "n") nuc.N = val;
309 else if(key == "a") nuc.A = val;
310 else if(key == "bindingEnergy") continue;
311 else if(key == "bindingEnergyLDMFit") continue;
312 else if(key == "levels") {
313 // in case of more than one level (in case of isomers) we only consider the first one
314 for(auto &_item: val.front().items()) {
315 const auto &_key = _item.key();
316 const auto &_val = _item.value();
317 if(_key == "decayModes") {
318 for(auto &mode: _val.items()) {
319 if(mode.value().size()==3) {
320 tkstring type = mode.value().at("name");
321 tkstring symbol = mode.value().at("symbol");
322 tkstring ratio;
323 // unkown ratios
324 if(symbol == "?") {
325 symbol = "=";
326 ratio = "-1";
327 }
328 else ratio = mode.value().at("value");
329 nuc.decay_modes.emplace_back(type,ratio.atof());
330 }
331 else {
332 tkstring type = mode.value().at("name");
333 type.remove_all("?");
334 tkstring symbol = "=";
335 tkstring ratio = "-1";
336 nuc.decay_modes.emplace_back(type,ratio.atof());
337 }
338 }
339 }
340 else if(_key == "energy") {
341 if(_val.empty()) continue;
342 if(_val.size()<2) continue;
343 double ener = _val.at("value").get<tkstring>().atof();
344 if(ener != 0.) {
345 glog << error << " level is not ground state ! " << _val << do_endl;
346 }
347 }
348 else if(_key == "massExcess") read_measure(_key, _val, nuc.mass_excess);
349 else if(_key == "abundance") {
350 read_measure(_key, _val, nuc.abundance,true);
351 nuc.abundance.unit = "%";
352 }
353 // include in the ensdf parsing
354 else if(_key == "halflife" || _key == "spinAndParity") continue;
355 else {
356 glog << error << "levels: unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
357 cout << _val << endl;
358 }
359 }
360 }
361 else if(key == "pairingGap") continue;
362 else if(key == "qValues") continue;
363 else if(key == "separationEnergies") continue;
364 else if(key == "webLinks") continue;
365 else if(key == "BE4DBE2") continue;
366 else if(key == "excitedStateEnergies") {
367 for(auto &_item: val.items()) {
368 auto &_key = _item.key();
369 auto &_val = _item.value();
370 if(_key == "firstExcitedStateEnergy") continue;
371 if(_key == "firstTwoPlusEnergy") continue;
372 if(_key == "firstFourPlusEnergy") continue;
373 if(_key == "firstFourPlusOverFirstTwoPlusEnergy") continue;
374 if(_key == "firstThreeMinusEnergy") continue;
375 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
376 cout << _val << endl;
377 }
378 }
379 else if(key == "fissionYields") {
380 for(auto &_item: val.items()) {
381 auto &_key = _item.key();
382 auto &_val = _item.value();
383 if(_key == "FY235U") read_measure(_key, _val, nuc.FY235U);
384 else if(_key == "FY238U") read_measure(_key, _val, nuc.FY238U);
385 else if(_key == "FY239Pu") read_measure(_key, _val, nuc.FY239Pu);
386 else if(_key == "FY241Pu") read_measure(_key, _val, nuc.FY241Pu);
387 else if(_key == "FY252Cf") read_measure(_key, _val, nuc.FY252Cf);
388 else if(_key == "cFY235U") read_measure(_key, _val, nuc.cFY235U);
389 else if(_key == "cFY238U") read_measure(_key, _val, nuc.cFY238U);
390 else if(_key == "cFY239Pu") read_measure(_key, _val, nuc.cFY239Pu);
391 else if(_key == "cFY241Pu") read_measure(_key, _val, nuc.cFY241Pu);
392 else if(_key == "cFY252Cf") read_measure(_key, _val, nuc.cFY252Cf);
393 else {
394 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
395 cout << _val << endl;
396 }
397 }
398 }
399 else if(key == "quadrupoleDeformation") read_measure(key, val, nuc.quadrupoleDeformation);
400 else if(key == "thermalNeutronCapture") continue;
401 else if(key == "thermalNeutronFission") continue;
402 else {
403 glog << warning << "unknown key: " << key << do_endl;
404 cout<< "value: " << endl;
405 cout<<val<<endl;
406 pause = true;
407 }
408 }
409 if(pause) {
410 nuc.print();
411 cin.get();
412 }
413 return nuc;
414}
415
416#ifdef HAS_ROOT
417ClassImp(tkisotope_builder);
418#endif
Interface to the sqlite database.
Definition: tkdatabase.h:57
Mother class used to fill the sqlite database.
Definition: tkdb_builder.h:50
Representaiton of a sqlite data table.
Definition: tkdb_table.h:52
tkstring get_name()
Definition: tkdb_table.h:116
Decoding of the NUDAT isotope properties.
int fill_database(const char *_json_filename, const char *_gs_filename, int _only_charge=0, int _only_mass=0)
virtual ~tkisotope_builder()
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition: tkstring.h:54
static const char * form(const char *_format,...)
Definition: tkstring.cpp:431
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition: tkstring.cpp:254
tkstring & remove_all(const tkstring &_s1)
Definition: tkstring.h:215
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition: tkstring.h:197
tkstring & append(const tkstring &_st)
Definition: tkstring.h:227
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition: tkstring.h:203
double atof() const
Converts a string to double value.
Definition: tkstring.cpp:191
Definition: tklog.cpp:39
tklog & error_v(tklog &log)
Definition: tklog.h:430
tklog & info(tklog &log)
Definition: tklog.h:336
tklog & error(tklog &log)
Definition: tklog.h:367
tklog & do_endl(tklog &log)
Definition: tklog.h:235
tklog & warning(tklog &log)
Definition: tklog.h:354
data structure used to fill a tkmeasure object from the sqlite database
Definition: tkdb_table.h:72