TkN 2.7
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 fDataBase->exec_sql("BEGIN TRANSACTION");
59
60 while (fDataBase->next()) {
61 tkstring nuc = tkstring::form("%s%s", (*fDataBase)["ISOTOPE"]["mass"].get_value().data(), (*fDataBase)["ELEMENT"]["symbol"].get_value().data());
62 tkstring zz = (*fDataBase)["ELEMENT"]["charge"].get_value();
63 fIsotopeIndex = ((tkstring)(*fDataBase)["ISOTOPE"]["isotope_id"].get_value()).atoi();
64
65 int curZ = zz.atoi();
66 if (curZ < 1) continue;
67
68 // open the ensdf file
69 fensdf_reader.open_nuc(nuc, kensdf);
70 // fensdf_reader.print_datasets();
71
72 // loop over the datasets
73 for (auto &dataset : *fensdf_reader.get_datasets()) {
74 if (dataset.fdsid.begins_with("COMMENTS")) continue;
75 tkstring date = dataset.fdate.copy().remove_all(" ");
76 if (date.length() == 6) date = date.substr(0, 4) + "-" + date.substr(4, 2);
77 int datasetIdx = add_dataset(dataset, nuc.data(), get_dataset_comment(&dataset), date, "ENSDF");
78 read_dataset(&dataset, datasetIdx);
79 }
80
81 // open the xundl file
82 fensdf_reader.open_nuc(nuc, kxundl);
83 // loop over the datasets
84 for (auto &dataset : *fensdf_reader.get_datasets()) {
85 if (dataset.fdsid.begins_with("COMMENTS")) continue;
86 tkstring date = dataset.fdate.copy().remove_all(" ");
87 if (date.length() == 6) date = date.substr(0, 4) + "-" + date.substr(4, 2);
88 int datasetIdx = add_dataset(dataset, nuc.data(), get_dataset_comment(&dataset), date, "XUNDL");
89 read_dataset(&dataset, datasetIdx);
90 }
91
92 if (curZ != oldZ) {
93 glog.progress_bar(117, curZ, message.data());
94 oldZ = curZ;
95 }
96 }
97
98 fDataBase->exec_sql("COMMIT");
99
100 fDataBase->exec_sql("CREATE INDEX isotope_index ON level(isotope_id)");
101 fDataBase->exec_sql("CREATE INDEX dataset_index ON level(dataset_id)");
102 fDataBase->exec_sql("CREATE INDEX dataset_isotope_index ON dataset(isotope_id)");
103
104 fDataBase->exec_sql("CREATE INDEX levelfrom_index ON decay(level_from_id)");
105 fDataBase->exec_sql("CREATE INDEX levelto_index ON decay(level_to_id)");
106
107 fensdf_reader.print_record_counters();
108
109 return 0;
110}
111
112int tkensdf_builder::add_dataset(tkensdf_ident_rec &_dataset, const tkstring &_nucleus, const tkstring &_dataset_comment, const tkstring &_dataset_date, const tkstring &_dataset_source)
113{
114 tkstring newname = _dataset.fdsid.copy().remove_all_extra_white_space();
115 newname.replace_all("'", "`");
116
117 // use begins_with to handle at the same time:
118 // - ADOPTED LEVELS (no known gammas)
119 // - ADOPTED LEVELS, GAMMAS (known gammas)
120 if (_dataset.fdsid.begins_with("ADOPTED LEVELS") && !_dataset.fdsid.contains("TENTATIVE")) {
121 newname = tkstring::form("%s : ADOPTED LEVELS, GAMMAS", _nucleus.data()); //.prepend(tkstring::form("%s : ",_nucleus.data()));
122 _dataset.fis_adopted = true;
123 } else
124 _dataset.fis_adopted = false;
125
126 (*fDataBase)["DATASET"]["dataset_name"].set_value(newname);
127 (*fDataBase)["DATASET"]["isotope_id"].set_value(fIsotopeIndex);
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 // loop over the dataset and fill temporary collections.
175 while (is_record) {
176
177 if (!the_record.set_record(record)) {
178 is_record = fensdf_reader.next_record(_data_set, record);
179 glog << error_v << "error in : " << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << do_endl;
180 continue;
181 }
182
183 // get the record type
184 tkensdf_record::record_type the_type = the_record.get_record_type();
185
186 // check and analyse the global comments records before the first level
187 if (flist_of_levels.empty() && the_record.is_comment()) {
189 // skip cases where time info is replaced by cross section data
191 the_level_record.fglobal_time_unit = "skip";
192 else if (record.contains("d|s/d|W", tkstring::ECaseCompare::kIgnoreCase))
193 the_level_record.fglobal_time_unit = "skip";
194 else if (record.contains("DS/DW", tkstring::ECaseCompare::kIgnoreCase))
195 the_level_record.fglobal_time_unit = "skip";
196 else if (record.contains("d(SIGMA)/d(OMEGA)", tkstring::ECaseCompare::kIgnoreCase))
197 the_level_record.fglobal_time_unit = "skip";
198 // skip cases where time info is replaced by Pygmy Dipole Resonance (PDR) strength (SIS)
199 else if (record.contains("S{-IS}", tkstring::ECaseCompare::kIgnoreCase))
200 the_level_record.fglobal_time_unit = "skip";
201 // no real idea of what it is..
202 else if (record.contains("G{-|g0", tkstring::ECaseCompare::kIgnoreCase))
203 the_level_record.fglobal_time_unit = "skip";
204 // here define the global witdth units
205 else if (record.contains("mev", tkstring::ECaseCompare::kIgnoreCase))
206 the_level_record.fglobal_time_unit = "MEV";
207 else if (record.contains("kev", tkstring::ECaseCompare::kIgnoreCase))
208 the_level_record.fglobal_time_unit = "KEV";
209 else if (record.contains("ev", tkstring::ECaseCompare::kIgnoreCase))
210 the_level_record.fglobal_time_unit = "EV";
211 }
212 }
213
214 if (fdecay_builder && the_type == tkensdf_record::kgamma && the_level_record.get_energy().value > 0.) {
215
216 the_gamma_record.clear();
217 the_gamma_record.set_record(record);
218
219 tkensdf_level_rec *level_to = nullptr;
220
221 // check if the following records are comments or continuation records on the level
222 is_record = fensdf_reader.next_record(_data_set, record);
223 the_record.set_record(record);
224 while (is_record && (the_record.is_continuation_record() || the_record.is_comment())) {
225 if (the_record.is_comment())
226 the_gamma_record.add_comment_record(record, the_record.is_continuation_record());
227 else if (the_record.is_continuation_record())
228 the_gamma_record.add_continuation_record(record);
229 is_record = fensdf_reader.next_record(_data_set, record);
230 the_record.set_record(record);
231 }
232
233 the_gamma_record.analyse_record();
234
235 // in specific cases that are not treated, the gamma energy is set to 0
236 if (the_gamma_record.get_energy().value == 0.) continue;
237
238 // if the level-to is manually specified:
239 if (the_gamma_record.is_final_level_set()) {
240
241 // if this is an unplaces gamma-ray, we skip it
242 if (the_gamma_record.get_final_level_energy() < 0)
243 continue;
244
245 // else we get the exact energy in the list
246 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
247 auto level = &(*it);
248 if (the_gamma_record.get_final_level_energy() == level->get_energy().value) {
249 level_to = level;
250 }
251 }
252 if (level_to == nullptr) the_gamma_record.set_final_level_set(false);
253 }
254 if (level_to == nullptr) {
255 // if the level-to is not specified, or has not been found, we take the closest one
256 double lev_to_approx_energy = the_level_record.get_energy().value - the_gamma_record.get_energy().value;
257
258 // looking for the id of the level to
259 double last_diff = numeric_limits<double>::max();
260 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
261 auto level = &(*it);
262 if (the_level_record.get_energy_offset() != level->get_energy_offset()) continue;
263 double diff = abs(lev_to_approx_energy - level->get_energy().value);
264 if (diff > last_diff) break;
265 level_to = level;
266 last_diff = diff;
267 }
268
269 if (level_to == nullptr) {
270 gdebug << "Level_to not found !" << do_endl;
271#ifdef HAS_DEBUG
272 cout << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << endl;
273 cout << "Level from record: ";
274 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
275 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err << endl;
276 cout << " record -> " << the_level_record.get_record() << endl;
277 cout << "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err << endl;
278 cout << " record -> " << the_gamma_record.get_record() << endl;
279 if (the_gamma_record.is_final_level_set()) cout << "gamma levels manually set !" << endl;
280 cout << " Looking for a level at: ";
281 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
282 cout << lev_to_approx_energy << " keV in:" << endl;
283 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
284 if (it->get_energy_offset() != the_level_record.get_energy_offset()) continue;
285 if (it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
286 cout << it->get_energy().value << " keV" << endl;
287 }
288#endif
289 continue;
290 }
291 // if no level-to found closest to 100keV above error bars, the gamma-ray is skipped
292 bool too_high_diff = ((last_diff - level_to->get_energy().err - the_level_record.get_energy().err - the_gamma_record.get_energy().err) > 100);
293 if (too_high_diff) {
294 gdebug << "High energy difference !" << do_endl;
295#ifdef HAS_DEBUG
296 cout << _data_set->fnuclide.data() << ": " << _data_set->fdsid.data() << " line: " << _data_set->fcurrentPosition << endl;
297 cout << "Level from record: ";
298 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
299 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err << endl;
300 cout << " record -> " << the_level_record.get_record() << endl;
301 cout << "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err << endl;
302 cout << " record -> " << the_gamma_record.get_record() << endl;
303 if (the_gamma_record.is_final_level_set()) cout << "gamma levels manually set !" << endl;
304 cout << " Looking for a level at: ";
305 if (the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
306 cout << lev_to_approx_energy << " keV in:" << endl;
307 for (auto it = flist_of_levels.rbegin() + 1; it != flist_of_levels.rend(); ++it) {
308 if (it->get_energy_offset() != the_level_record.get_energy_offset()) continue;
309 if (it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
310 cout << it->get_energy().value << " keV" << endl;
311 }
312 cout << " Found a level at: " << level_to->get_energy().value << " keV ==> Diff= " << last_diff << " keV" << endl;
313#endif
314 continue;
315 }
316 }
317
318 // fill level info in db
319 fdecay_builder->fill_gamma(the_level_record.flevelid, level_to->flevelid, the_gamma_record);
320 } else if (the_type == tkensdf_record::klevel) {
321 the_level_record.clear();
322 the_level_record.set_record(record);
323
324 // check if the following records are comments or continuation records on the level
325 is_record = fensdf_reader.next_record(_data_set, record);
326 the_record.set_record(record);
327 while (is_record && (the_record.is_continuation_record() || the_record.is_comment())) {
328 if (the_record.is_comment())
329 the_level_record.add_comment_record(record, the_record.is_continuation_record());
330 else if (the_record.is_continuation_record())
331 the_level_record.add_continuation_record(record);
332 is_record = fensdf_reader.next_record(_data_set, record);
333 the_record.set_record(record);
334 }
335
336 the_level_record.analyse_record();
337
338 // fill level info in db
339 if (flevel_builder && (the_level_record.get_energy().value >= 0.)) {
340
341 // if no ground state, add a dummy level a 0 energy
342 if (flist_of_levels.size() == 0 && (the_level_record.get_energy().value > 0. || the_level_record.is_energy_offset())) {
343 tkensdf_level_rec dummy_rec;
344 dummy_rec.set_record("Dummy L 0.0 ");
345 dummy_rec.analyse_record();
346 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, dummy_rec, _data_set->fis_adopted);
347 dummy_rec.flevelid = flevel_builder->get_level_id();
348 flist_of_levels.emplace_back(dummy_rec);
349 }
350
351 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, the_level_record, _data_set->fis_adopted);
352 the_level_record.flevelid = flevel_builder->get_level_id();
353 flist_of_levels.emplace_back(the_level_record);
354
355 // check that the energy is not higher thant the previous one
356 if (the_level_record.is_energy_offset()) {
357 std::vector<pair<int, tkensdf_level_rec *>> vec;
358 int idx = 0;
359 for (auto it = flist_of_levels.begin(); it != flist_of_levels.end(); it++, idx++) {
360 if (it->get_energy_offset() == the_level_record.get_energy_offset()) {
361 vec.push_back({idx, (&(*it))});
362 }
363 }
364 if (vec.size() > 1 && (vec.at(vec.size() - 1).second->get_energy().value < vec.at(vec.size() - 2).second->get_energy().value)) {
365 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;
366 swap(flist_of_levels[vec.at(vec.size() - 1).first], flist_of_levels[vec.at(vec.size() - 2).first]);
367 cin.get();
368 }
369 } 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)) {
370 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;
371 swap(flist_of_levels[flist_of_levels.size() - 1], flist_of_levels[flist_of_levels.size() - 2]);
372 }
373 }
374 } else {
375 is_record = fensdf_reader.next_record(_data_set, record);
376 }
377 } // ok
378 glog.clear();
379
380 return true;
381}
382
383#ifdef HAS_ROOT
384ClassImp(tkensdf_builder);
385#endif
Interface to the sqlite database.
Definition tkdatabase.h:33
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)
return the identification record and set its physical 1-based line position
bool next_record(tkensdf_ident_rec *_dataset, tkstring &record)
return the next record; on false, the terminator is not returned and record is unchanged
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:33
tkstring copy() const
Returns a copy of this string.
Definition tkstring.cpp:377
static const char * form(const char *_format,...)
Definition tkstring.cpp:438
bool is_empty() const
Definition tkstring.h:145
tkstring & remove_all(const tkstring &_s1)
Definition tkstring.h:208
tkstring substr(size_type __pos=0, size_type __n=npos) const
Inlines.
Definition tkstring.h:160
int atoi() const
Converts a string to integer value.
Definition tkstring.cpp:210
tkstring & remove_all_extra_white_space()
Definition tkstring.cpp:525
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:184
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.h:166
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition tkstring.h:196
Definition tklog.cpp:16
tklog & error_v(tklog &log)
Definition tklog.h:407
tklog & do_endl(tklog &log)
Definition tklog.h:212