TkN 2.5
Toolkit for Nuclei
Loading...
Searching...
No Matches
tkensdf_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 * Licensed under the MIT License <http://opensource.org/licenses/MIT>. *
11 * SPDX-License-Identifier: MIT *
12 ********************************************************************************/
13
14#include "tkensdf_builder.h"
15
16#include <iostream>
17#include <unistd.h>
18#include <cmath>
19
20#include "tklog.h"
21#include "tkensdf_level_rec.h"
22#include "tkensdf_gamma_rec.h"
23
24namespace tkn {
31}
32
33using namespace tkn;
34using namespace std;
35
36tkensdf_builder::tkensdf_builder(tkdatabase *_database, const tkstring &_input_folder) : fDataBase(_database),
37 fensdf_reader(_input_folder)
38{
39}
40
42
44{
45 //--------------------------------------------------------
46 // read files and fill database
47 //--------------------------------------------------------
48
49 fDataBase->begin("charge,mass,symbol,isotope_id", "isotope INNER JOIN element ON isotope.element_id=element.element_id", "charge>0");
50
51 tkstring message;
52
53 if (flevel_builder) {
54 message = "Building '" + flevel_builder->get_table().get_name() + "' table";
55 }
56
57 int oldZ = 0;
58 while (fDataBase->next()) {
59 tkstring nuc = tkstring::form("%s%s", (*fDataBase)["ISOTOPE"]["mass"].get_value().data(), (*fDataBase)["ELEMENT"]["symbol"].get_value().data());
60 tkstring zz = (*fDataBase)["ELEMENT"]["charge"].get_value();
61 tkstring aa = (*fDataBase)["ISOTOPE"]["mass"].get_value();
62 fIsotopeIndex = ((tkstring)(*fDataBase)["ISOTOPE"]["isotope_id"].get_value()).atoi();
63
64 int curZ = zz.atoi();
65 if (curZ < 1) continue;
66
67 // open the ensdf file
68 bool has_levels = fensdf_reader.open_nuc(nuc, kensdf);
69 // fensdf_reader.print_datasets();
70
71 // loop over the datasets
72 for (auto &dataset : *fensdf_reader.get_datasets()) {
73 if (dataset.fdsid.begins_with("COMMENTS")) continue;
74 tkstring date = dataset.fdate.copy().remove_all(" ");
75 if (date.length() == 6) date = date.substr(0, 4) + "-" + date.substr(4, 2);
76 int datasetIdx = add_dataset(dataset, nuc.data(), get_dataset_comment(&dataset), date, "ENSDF");
77 read_dataset(&dataset, datasetIdx);
78 }
79
80 // open the xundl file
81 bool has_levelsxundl = fensdf_reader.open_nuc(nuc, kxundl);
82 // loop over the datasets
83 for (auto &dataset : *fensdf_reader.get_datasets()) {
84 if (dataset.fdsid.begins_with("COMMENTS")) continue;
85 tkstring date = dataset.fdate.copy().remove_all(" ");
86 if (date.length() == 6) date = date.substr(0, 4) + "-" + date.substr(4, 2);
87 int datasetIdx = add_dataset(dataset, nuc.data(), get_dataset_comment(&dataset), date, "XUNDL");
88 read_dataset(&dataset, datasetIdx);
89 }
90
91 if (curZ != oldZ) {
92 glog.progress_bar(117, curZ, message.data());
93 oldZ = curZ;
94 }
95
96 if (has_levels || has_levelsxundl) {
97 fDataBase->exec_sql(tkstring::form("CREATE VIEW lvl%s as select * from level INNER JOIN dataset on level.dataset_id=dataset.dataset_id INNER JOIN isotope on level.isotope_id=isotope.isotope_id INNER JOIN element on isotope.element_id=element.element_id where element.charge=%s AND isotope.mass=%s", nuc.data(), zz.data(), aa.data()));
98 if (fdecay_builder) fDataBase->exec_sql(tkstring::form("CREATE VIEW dec%s as select * from decay INNER JOIN level on decay.level_from_id=level.level_id INNER JOIN dataset on level.dataset_id=dataset.dataset_id INNER JOIN isotope on level.isotope_id=isotope.isotope_id INNER JOIN element on isotope.element_id=element.element_id where element.charge=%s AND isotope.mass=%s", nuc.data(), zz.data(), aa.data()));
99 }
100 }
101
102 fDataBase->exec_sql("CREATE INDEX isotope_index ON level(isotope_id)");
103 fDataBase->exec_sql("CREATE INDEX dataset_index ON level(dataset_id)");
104
105 fDataBase->exec_sql("CREATE INDEX levelfrom_index ON decay(level_from_id)");
106 fDataBase->exec_sql("CREATE INDEX levelto_index ON decay(level_to_id)");
107
108 fensdf_reader.print_record_counters();
109
110 return 0;
111}
112
113int tkensdf_builder::add_dataset(tkensdf_ident_rec &_dataset, const tkstring &_nucleus, const tkstring &_dataset_comment, const tkstring &_dataset_date, const tkstring &_dataset_source)
114{
115 tkstring newname = _dataset.fdsid.copy().remove_all_extra_white_space();
116 newname.replace_all("'", "`");
117
118 // use begins_with to handle at the same time:
119 // - ADOPTED LEVELS (no known gammas)
120 // - ADOPTED LEVELS, GAMMAS (known gammas)
121 if (_dataset.fdsid.begins_with("ADOPTED LEVELS") && !_dataset.fdsid.contains("TENTATIVE")) {
122 newname = tkstring::form("%s : ADOPTED LEVELS, GAMMAS", _nucleus.data()); //.prepend(tkstring::form("%s : ",_nucleus.data()));
123 _dataset.fis_adopted = true;
124 } else
125 _dataset.fis_adopted = false;
126
127 (*fDataBase)["DATASET"]["dataset_name"].set_value(newname);
128 if (!_dataset_comment.is_empty()) (*fDataBase)["DATASET"]["dataset_comment"].set_value(_dataset_comment);
129 if (!_dataset_date.is_empty()) (*fDataBase)["DATASET"]["dataset_date"].set_value(_dataset_date);
130 if (!_dataset_source.is_empty()) (*fDataBase)["DATASET"]["dataset_source"].set_value(_dataset_source);
131 (*fDataBase)["DATASET"]["dataset_id"].set_value(fDatasetIndex++);
132 (*fDataBase)["DATASET"].push_row();
133
134 return (fDatasetIndex - 1);
135}
136
137tkstring tkensdf_builder::get_dataset_comment(tkensdf_ident_rec *_data_set)
138{
139 tkstring record;
140 bool is_record = fensdf_reader.first_record(_data_set, record);
141
142 tkensdf_record the_record;
143 tkensdf_record dataset_comment;
144
145 while (is_record) {
146 if (!the_record.set_record(record)) {
147 is_record = fensdf_reader.next_record(_data_set, record);
148 continue;
149 }
150
151 if (the_record.get_record_type() == tkensdf_record::klevel) break;
152 if (the_record.is_comment()) dataset_comment.add_comment_record(record, the_record.is_continuation_record());
153
154 is_record = fensdf_reader.next_record(_data_set, record);
155 }
156
157 return dataset_comment.get_comment_record();
158}
159
160bool tkensdf_builder::read_dataset(tkensdf_ident_rec *_data_set, int _dataset_idx)
161{
162 glog.set_class("db_ensdf_builder");
163 glog.set_method(tkstring::form("read_levels(%s,%d)", _data_set->fdsid.data(), _dataset_idx));
164
165 tkensdf_record the_record;
166 tkensdf_level_rec the_level_record;
167 tkensdf_gamma_rec the_gamma_record;
168
169 tkstring record;
170 bool is_record = fensdf_reader.first_record(_data_set, record);
171
172 std::vector<tkensdf_level_rec> flist_of_levels;
173
174 char *sErrMsg = nullptr;
175 sqlite3_exec(fDataBase->get_sql_db(), "BEGIN TRANSACTION", nullptr, nullptr, &sErrMsg);
176
177 // loop over the dataset and fill temporary collections.
178 while (is_record) {
179
180 if (!the_record.set_record(record)) {
181 is_record = fensdf_reader.next_record(_data_set, record);
182 glog << error_v << "error in : " << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << do_endl;
183 continue;
184 }
185
186 // get the record type
187 tkensdf_record::record_type the_type = the_record.get_record_type();
188
189 // check and analyse the global comments records before the first level
190 if (flist_of_levels.empty() && the_record.is_comment()) {
192 // skip cases where time info is replaced by cross section data
194 the_level_record.fglobal_time_unit = "skip";
195 else if (record.contains("d|s/d|W", tkstring::ECaseCompare::kIgnoreCase))
196 the_level_record.fglobal_time_unit = "skip";
197 else if (record.contains("DS/DW", tkstring::ECaseCompare::kIgnoreCase))
198 the_level_record.fglobal_time_unit = "skip";
199 else if (record.contains("d(SIGMA)/d(OMEGA)", tkstring::ECaseCompare::kIgnoreCase))
200 the_level_record.fglobal_time_unit = "skip";
201 // skip cases where time info is replaced by Pygmy Dipole Resonance (PDR) strength (SIS)
202 else if (record.contains("S{-IS}", tkstring::ECaseCompare::kIgnoreCase))
203 the_level_record.fglobal_time_unit = "skip";
204 // no real idea of what it is..
205 else if (record.contains("G{-|g0", tkstring::ECaseCompare::kIgnoreCase))
206 the_level_record.fglobal_time_unit = "skip";
207 // here define the global witdth units
208 else if (record.contains("mev", tkstring::ECaseCompare::kIgnoreCase))
209 the_level_record.fglobal_time_unit = "MEV";
210 else if (record.contains("kev", tkstring::ECaseCompare::kIgnoreCase))
211 the_level_record.fglobal_time_unit = "KEV";
212 else if (record.contains("ev", tkstring::ECaseCompare::kIgnoreCase))
213 the_level_record.fglobal_time_unit = "EV";
214 }
215 }
216
217 if (fdecay_builder && the_type == tkensdf_record::kgamma && the_level_record.get_energy().value > 0.) {
218
219 the_gamma_record.clear();
220 the_gamma_record.set_record(record);
221
222 tkensdf_level_rec *level_to = nullptr;
223
224 // check if the following records are comments or continuation records on the level
225 is_record = fensdf_reader.next_record(_data_set, record);
226 the_record.set_record(record);
227 while (is_record && (the_record.is_continuation_record() || the_record.is_comment())) {
228 if (the_record.is_comment())
229 the_gamma_record.add_comment_record(record, the_record.is_continuation_record());
230 else if (the_record.is_continuation_record())
231 the_gamma_record.add_continuation_record(record);
232 is_record = fensdf_reader.next_record(_data_set, record);
233 the_record.set_record(record);
234 }
235
236 the_gamma_record.analyse_record();
237
238 // in specific cases that are not treated, the gamma energy is set to 0
239 if (the_gamma_record.get_energy().value == 0.) continue;
240
241 // if the level-to is manually specified:
242 if (the_gamma_record.is_final_level_set()) {
243
244 // if this is an unplaces gamma-ray, we skip it
245 if (the_gamma_record.get_final_level_energy() < 0)
246 continue;
247
248 // else we get the exact energy in the list
249 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
250 auto level = &(*it);
251 if (the_gamma_record.get_final_level_energy() == level->get_energy().value) {
252 level_to = level;
253 }
254 }
255 if (level_to == nullptr) the_gamma_record.set_final_level_set(false);
256 }
257 if (level_to == nullptr) {
258 // if the level-to is not specified, or has not been found, we take the closest one
259 double lev_to_approx_energy = the_level_record.get_energy().value - the_gamma_record.get_energy().value;
260
261 // looking for the id of the level to
262 double last_diff = numeric_limits<double>::max();
263 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
264 auto level = &(*it);
265 if (the_level_record.get_energy_offset() != level->get_energy_offset()) continue;
266 double diff = abs(lev_to_approx_energy - level->get_energy().value);
267 if (diff > last_diff) break;
268 level_to = level;
269 last_diff = diff;
270 }
271
272 if (level_to == nullptr) {
273 gdebug << "Level_to not found !" << do_endl;
274#ifdef HAS_DEBUG
275 cout << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << endl;
276 cout << "Level from record: ";
277 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
278 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err << endl;
279 cout << " record -> " << the_level_record.get_record() << endl;
280 cout << "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err << endl;
281 cout << " record -> " << the_gamma_record.get_record() << endl;
282 if (the_gamma_record.is_final_level_set()) cout << "gamma levels manually set !" << endl;
283 cout << " Looking for a level at: ";
284 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
285 cout << lev_to_approx_energy << " keV in:" << endl;
286 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
287 if (it->get_energy_offset() != the_level_record.get_energy_offset()) continue;
288 if (it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
289 cout << it->get_energy().value << " keV" << endl;
290 }
291#endif
292 continue;
293 }
294 // if no level-to found closest to 100keV above error bars, the gamma-ray is skipped
295 bool too_high_diff = ((last_diff - level_to->get_energy().err - the_level_record.get_energy().err - the_gamma_record.get_energy().err) > 100);
296 if (too_high_diff) {
297 gdebug << "High energy difference !" << do_endl;
298#ifdef HAS_DEBUG
299 cout << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << endl;
300 cout << "Level from record: ";
301 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
302 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err << endl;
303 cout << " record -> " << the_level_record.get_record() << endl;
304 cout << "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err << endl;
305 cout << " record -> " << the_gamma_record.get_record() << endl;
306 if (the_gamma_record.is_final_level_set()) cout << "gamma levels manually set !" << endl;
307 cout << " Looking for a level at: ";
308 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
309 cout << lev_to_approx_energy << " keV in:" << endl;
310 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
311 if (it->get_energy_offset() != the_level_record.get_energy_offset()) continue;
312 if (it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
313 cout << it->get_energy().value << " keV" << endl;
314 }
315 cout << " Found a level at: " << level_to->get_energy().value << " keV ==> Diff= " << last_diff << " keV" << endl;
316#endif
317 continue;
318 }
319 }
320
321 // fill level info in db
322 fdecay_builder->fill_gamma(the_level_record.flevelid, level_to->flevelid, the_gamma_record);
323 } else if (the_type == tkensdf_record::klevel) {
324 the_level_record.clear();
325 the_level_record.set_record(record);
326
327 // check if the following records are comments or continuation records on the level
328 is_record = fensdf_reader.next_record(_data_set, record);
329 the_record.set_record(record);
330 while (is_record && (the_record.is_continuation_record() || the_record.is_comment())) {
331 if (the_record.is_comment())
332 the_level_record.add_comment_record(record, the_record.is_continuation_record());
333 else if (the_record.is_continuation_record())
334 the_level_record.add_continuation_record(record);
335 is_record = fensdf_reader.next_record(_data_set, record);
336 the_record.set_record(record);
337 }
338
339 the_level_record.analyse_record();
340
341 // fill level info in db
342 if (flevel_builder && (the_level_record.get_energy().value >= 0.)) {
343
344 // if no ground state, add a dummy level a 0 energy
345 if (flist_of_levels.size() == 0 && (the_level_record.get_energy().value > 0. || the_level_record.is_energy_offset())) {
346 tkensdf_level_rec dummy_rec;
347 dummy_rec.set_record("Dummy L 0.0 ");
348 dummy_rec.analyse_record();
349 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, dummy_rec, _data_set->fis_adopted);
350 dummy_rec.flevelid = flevel_builder->get_level_id();
351 flist_of_levels.emplace_back(dummy_rec);
352 }
353
354 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, the_level_record, _data_set->fis_adopted);
355 the_level_record.flevelid = flevel_builder->get_level_id();
356 flist_of_levels.emplace_back(the_level_record);
357
358 // check that the energy is not higher thant the previous one
359 if (the_level_record.is_energy_offset()) {
360 std::vector<pair<int, tkensdf_level_rec *>> vec;
361 int idx = 0;
362 for (auto it = flist_of_levels.begin(); it != flist_of_levels.end(); it++, idx++) {
363 if (it->get_energy_offset() == the_level_record.get_energy_offset()) {
364 vec.push_back({idx, (&(*it))});
365 }
366 }
367 if (vec.size() > 1 && (vec.at(vec.size() - 1).second->get_energy().value < vec.at(vec.size() - 2).second->get_energy().value)) {
368 gdebug << "Inverted levels in: " << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " [ " << flist_of_levels.at(vec.at(vec.size() - 1).first).get_energy_offset() << "+" << flist_of_levels.at(vec.at(vec.size() - 1).first).get_energy().value << " ; " << flist_of_levels.at(vec.at(vec.size() - 2).first).get_energy_offset() << "+" << flist_of_levels.at(vec.at(vec.size() - 2).first).get_energy().value << "]" << do_endl;
369 swap(flist_of_levels[vec.at(vec.size() - 1).first], flist_of_levels[vec.at(vec.size() - 2).first]);
370 cin.get();
371 }
372 } else if (flist_of_levels.size() > 1 && (flist_of_levels.at(flist_of_levels.size() - 1).get_energy().value < flist_of_levels.at(flist_of_levels.size() - 2).get_energy().value)) {
373 gdebug << "Inverted levels in: " << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " [" << flist_of_levels.at(flist_of_levels.size() - 1).get_energy().value << " ; " << flist_of_levels.at(flist_of_levels.size() - 2).get_energy().value << "]" << do_endl;
374 swap(flist_of_levels[flist_of_levels.size() - 1], flist_of_levels[flist_of_levels.size() - 2]);
375 }
376 }
377 } else {
378 is_record = fensdf_reader.next_record(_data_set, record);
379 }
380 } // ok
381 sqlite3_exec(fDataBase->get_sql_db(), "END TRANSACTION", nullptr, nullptr, &sErrMsg);
382
383 glog.clear();
384
385 return true;
386}
387
388#ifdef HAS_ROOT
389ClassImp(tkensdf_builder);
390#endif
Interface to the sqlite database.
Definition tkdatabase.h:34
Main class dedicated to the ENSDF records decoding.
virtual ~tkensdf_builder()
int add_dataset(tkensdf_ident_rec &_dataset, const tkstring &_nucleus, const tkstring &_dataset_comment="", const tkstring &_dataset_date="", const tkstring &_dataset_source="")
tkensdf_builder(tkdatabase *_database, const tkstring &_input_folder)
virtual void analyse_record() override
analyse the record content
virtual bool set_record(const tkstring &_record) override
define the record from a string
bool is_final_level_set()
return true if the information on the final level is manually defined
double get_final_level_energy()
return true if the information on the final level is manually defined
void set_final_level_set(bool _status)
return true if the information on the final level is manually defined
Decodding of the ENSDF identification record properties.
virtual void analyse_record() override
analyse the record content
virtual bool set_record(const tkstring &_record) override
define the record from a string
bool first_record(tkensdf_ident_rec *_dataset, tkstring &record)
move in the current file to the first record of the selected data set
bool next_record(tkensdf_ident_rec *_dataset, tkstring &record)
get the next record of the selected data set
Decodding of the ENSDF records.
const tkstring & get_record()
get record
virtual void add_comment_record(const tkstring &_comment_record, bool _is_continuation=false)
add a continuation record from a string
bool is_energy_offset()
to now if the energy is given with an offset
virtual bool set_record(const tkstring &_record)
define the record from a string. Option false only checks if the record is an identification record
bool is_continuation_record()
to now if the record is a continuation record or not
virtual const tkstring & get_comment_record() const
get the continuation record
const tkdb_table::measure_data_struct & get_energy() const
tkstring get_energy_offset()
get_energy_offset
virtual void add_continuation_record(const tkstring &_continuation_record)
add a continuation record from a string
record_type get_record_type()
get record type
bool is_comment()
to now if the record is a comment
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition tkstring.h:32
tkstring copy() const
Returns a copy of this string.
Definition tkstring.cpp:391
static const char * form(const char *_format,...)
Definition tkstring.cpp:452
bool is_empty() const
Definition tkstring.h:141
tkstring & remove_all(const tkstring &_s1)
Definition tkstring.h:193
tkstring substr(size_type __pos=0, size_type __n=npos) const
Inlines.
Definition tkstring.h:157
int atoi() const
Converts a string to integer value.
Definition tkstring.cpp:196
tkstring & remove_all_extra_white_space()
Definition tkstring.cpp:547
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:175
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.h:163
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition tkstring.h:181
Definition tklog.cpp:16
tklog & error_v(tklog &log)
Definition tklog.h:407
tklog & do_endl(tklog &log)
Definition tklog.h:212