TkN 2.4
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):
37 fDataBase(_database),
38 fensdf_reader(_input_folder)
39{
40}
41
43
45{
46 //--------------------------------------------------------
47 // read files and fill database
48 //--------------------------------------------------------
49
50 fDataBase->begin("charge,mass,symbol,isotope_id","isotope INNER JOIN element ON isotope.element_id=element.element_id","charge>0");
51
52 tkstring message;
53
54 if(flevel_builder) {
55 message = "Building '" + flevel_builder->get_table().get_name() + "' table";
56 }
57
58 int oldZ=0;
59 while(fDataBase->next())
60 {
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 tkstring aa = (*fDataBase)["ISOTOPE"]["mass"].get_value();
64 fIsotopeIndex = ((tkstring)(*fDataBase)["ISOTOPE"]["isotope_id"].get_value()).atoi();
65
66 int curZ = zz.atoi();
67 if(curZ<1) continue;
68
69 // open the ensdf file
70 bool has_levels = fensdf_reader.open_nuc(nuc,kensdf);
71 // fensdf_reader.print_datasets();
72
73 // loop over the datasets
74 for(auto &dataset: *fensdf_reader.get_datasets()) {
75 if(dataset.fdsid.begins_with("COMMENTS")) continue;
76 int datasetIdx = add_dataset(dataset,nuc.data());
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 int datasetIdx = add_dataset(dataset,nuc.data());
86 read_dataset(&dataset, datasetIdx);
87 }
88
89 if(curZ!=oldZ) {
90 glog.progress_bar(117,curZ,message.data()); oldZ=curZ;
91 }
92
93 if(has_levels||has_levelsxundl){
94 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()));
95 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()));
96 }
97 }
98
99 fDataBase->exec_sql("CREATE INDEX isotope_index ON level(isotope_id)");
100 fDataBase->exec_sql("CREATE INDEX dataset_index ON level(dataset_id)");
101
102 fDataBase->exec_sql("CREATE INDEX levelfrom_index ON decay(level_from_id)");
103 fDataBase->exec_sql("CREATE INDEX levelto_index ON decay(level_to_id)");
104
105 fensdf_reader.print_record_counters();
106
107 return 0;
108}
109
111{
112 tkstring newname = _dataset.fdsid.copy().remove_all_extra_white_space();
113 newname.replace_all("'","`");
114
115 // use begins_with to handle at the same time:
116 // - ADOPTED LEVELS (no known gammas)
117 // - ADOPTED LEVELS, GAMMAS (known gammas)
118 if(_dataset.fdsid.begins_with("ADOPTED LEVELS") && !_dataset.fdsid.contains("TENTATIVE")) {
119 newname = tkstring::form("%s : ADOPTED LEVELS, GAMMAS",_comment.data());//.prepend(tkstring::form("%s : ",_comment.data()));
120 _dataset.fis_adopted = true;
121 }
122 else _dataset.fis_adopted = false;
123
124 (*fDataBase)["DATASET"]["dataset_name"].set_value(newname);
125 (*fDataBase)["DATASET"]["dataset_comment"].set_value(_comment);
126 (*fDataBase)["DATASET"]["dataset_id"].set_value(fDatasetIndex++);
127 (*fDataBase)["DATASET"].push_row();
128
129 return (fDatasetIndex-1);
130}
131
132bool tkensdf_builder::read_dataset(tkensdf_ident_rec *_data_set, int _dataset_idx)
133{
134 glog.set_class("db_ensdf_builder");
135 glog.set_method(tkstring::form("read_levels(%s,%d)", _data_set->fdsid.data(),_dataset_idx));
136
137 tkensdf_record the_record;
138 tkensdf_level_rec the_level_record;
139 tkensdf_gamma_rec the_gamma_record;
140
141 tkstring record;
142 bool is_record = fensdf_reader.first_record(_data_set,record);
143
144 std::vector<tkensdf_level_rec> flist_of_levels;
145
146 char * sErrMsg = nullptr;
147 sqlite3_exec(fDataBase->get_sql_db(), "BEGIN TRANSACTION", nullptr, nullptr, &sErrMsg);
148
149 // loop over the dataset and fill temporary collections.
150 while( is_record ) {
151
152 if(!the_record.set_record(record)) {
153 is_record = fensdf_reader.next_record(_data_set,record);
154 glog << error_v << "error in : " << _data_set->fnuclide.data()<<": "<<_data_set->fdsid.data()<<" line: "<<_data_set->fcurrentPosition<< do_endl;
155 continue;
156 }
157
158 // get the record type
159 tkensdf_record::record_type the_type = the_record.get_record_type();
160
161 // check and analyse the global comments records before the first level
162 if(flist_of_levels.empty() && the_record.is_comment()) {
164 // skip cases where time info is replaced by cross section data
165 if(record.contains("mb/sr",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
166 else if(record.contains("d|s/d|W",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
167 else if(record.contains("DS/DW",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
168 else if(record.contains("d(SIGMA)/d(OMEGA)",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
169 // skip cases where time info is replaced by Pygmy Dipole Resonance (PDR) strength (SIS)
170 else if(record.contains("S{-IS}",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
171 // no real idea of what it is..
172 else if(record.contains("G{-|g0",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "skip";
173 // here define the global witdth units
174 else if(record.contains("mev",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "MEV";
175 else if(record.contains("kev",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "KEV";
176 else if(record.contains("ev",tkstring::ECaseCompare::kIgnoreCase)) the_level_record.fglobal_time_unit = "EV";
177 }
178 }
179
180 if(fdecay_builder && the_type == tkensdf_record::kgamma && the_level_record.get_energy().value>0.) {
181
182 the_gamma_record.clear();
183 the_gamma_record.set_record(record);
184
185 tkensdf_level_rec *level_to = nullptr;
186
187 // check if the following records are comments or continuation records on the level
188 is_record = fensdf_reader.next_record(_data_set,record);
189 the_record.set_record(record);
190 while( is_record && (the_record.is_continuation_record() || the_record.is_comment()) ) {
191 if(the_record.is_comment()) the_gamma_record.add_comment_record(record,the_record.is_continuation_record());
192 else if(the_record.is_continuation_record()) the_gamma_record.add_continuation_record(record);
193 is_record = fensdf_reader.next_record(_data_set,record);
194 the_record.set_record(record);
195 }
196
197 the_gamma_record.analyse_record();
198
199 // in specific cases that are not treated, the gamma energy is set to 0
200 if(the_gamma_record.get_energy().value==0.) continue;
201
202 // if the level-to is manually specified:
203 if(the_gamma_record.is_final_level_set()) {
204
205 // if this is an unplaces gamma-ray, we skip it
206 if(the_gamma_record.get_final_level_energy()<0)
207 continue;
208
209 // else we get the exact energy in the list
210 for(auto it = flist_of_levels.rbegin()+1 ; it != flist_of_levels.rend() ; ++it) {
211 auto level = &(*it);
212 if(the_gamma_record.get_final_level_energy() == level->get_energy().value) {
213 level_to = level;
214 }
215 }
216 if(level_to == nullptr) the_gamma_record.set_final_level_set(false);
217 }
218 if(level_to == nullptr) {
219 // if the level-to is not specified, or has not been found, we take the closest one
220 double lev_to_approx_energy = the_level_record.get_energy().value - the_gamma_record.get_energy().value;
221
222 // looking for the id of the level to
223 double last_diff = numeric_limits<double>::max();
224 for(auto it = flist_of_levels.rbegin()+1 ; it != flist_of_levels.rend() ; ++it) {
225 auto level = &(*it);
226 if(the_level_record.get_energy_offset() != level->get_energy_offset()) continue;
227 double diff = abs(lev_to_approx_energy-level->get_energy().value);
228 if(diff>last_diff) break;
229 level_to = level;
230 last_diff = diff;
231 }
232
233 if(level_to == nullptr) {
234 gdebug <<"Level_to not found !"<< do_endl;
235#ifdef HAS_DEBUG
236 cout<<_data_set->fnuclide.data()<<": "<<_data_set->fdsid.data()<<" line: "<<_data_set->fcurrentPosition<<endl;
237 cout<< "Level from record: ";
238 if(the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
239 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err <<endl;
240 cout<<" record -> " << the_level_record.get_record() << endl;
241 cout<< "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err <<endl;
242 cout<<" record -> " << the_gamma_record.get_record() << endl;
243 if(the_gamma_record.is_final_level_set()) cout<<"gamma levels manually set !" << endl;
244 cout<< " Looking for a level at: ";
245 if(the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
246 cout << lev_to_approx_energy<< " keV in:"<<endl;
247 for(auto it = flist_of_levels.rbegin()+1 ; it != flist_of_levels.rend() ; ++it) {
248 if(it->get_energy_offset()!=the_level_record.get_energy_offset()) continue;
249 if(it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
250 cout << it->get_energy().value << " keV" << endl;
251 }
252#endif
253 continue;
254 }
255 // if no level-to found closest to 100keV above error bars, the gamma-ray is skipped
256 bool too_high_diff = ((last_diff-level_to->get_energy().err-the_level_record.get_energy().err-the_gamma_record.get_energy().err) > 100);
257 if(too_high_diff) {
258 gdebug <<"High energy difference !"<< do_endl;
259#ifdef HAS_DEBUG
260 cout<<_data_set->fnuclide.data()<<": "<<_data_set->fdsid.data()<<" line: "<<_data_set->fcurrentPosition<<endl;
261 cout<< "Level from record: ";
262 if(the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
263 cout << the_level_record.get_energy().value << " " << the_level_record.get_energy().err <<endl;
264 cout<<" record -> " << the_level_record.get_record() << endl;
265 cout<< "gamma record : " << the_gamma_record.get_energy().value << " " << the_gamma_record.get_energy().err <<endl;
266 cout<<" record -> " << the_gamma_record.get_record() << endl;
267 if(the_gamma_record.is_final_level_set()) cout<<"gamma levels manually set !" << endl;
268 cout<< " Looking for a level at: ";
269 if(the_level_record.is_energy_offset()) cout << the_level_record.get_energy_offset() << " + ";
270 cout << lev_to_approx_energy<< " keV in:"<<endl;
271 for(auto it = flist_of_levels.rbegin()+1 ; it != flist_of_levels.rend() ; ++it) {
272 if(it->get_energy_offset()!=the_level_record.get_energy_offset()) continue;
273 if(it->is_energy_offset()) cout << it->get_energy_offset() << " + ";
274 cout << it->get_energy().value << " keV" << endl;
275 }
276 cout<< " Found a level at: " << level_to->get_energy().value<< " keV ==> Diff= "<<last_diff<< " keV" << endl;
277#endif
278 continue;
279 }
280 }
281
282 // fill level info in db
283 fdecay_builder->fill_gamma(the_level_record.flevelid, level_to->flevelid, the_gamma_record);
284 }
285 else if(the_type == tkensdf_record::klevel) {
286 the_level_record.clear();
287 the_level_record.set_record(record);
288
289 // check if the following records are comments or continuation records on the level
290 is_record = fensdf_reader.next_record(_data_set,record);
291 the_record.set_record(record);
292 while( is_record && (the_record.is_continuation_record() || the_record.is_comment()) ) {
293 if(the_record.is_comment()) the_level_record.add_comment_record(record,the_record.is_continuation_record());
294 else if(the_record.is_continuation_record()) the_level_record.add_continuation_record(record);
295 is_record = fensdf_reader.next_record(_data_set,record);
296 the_record.set_record(record);
297 }
298
299 the_level_record.analyse_record();
300
301 // fill level info in db
302 if(flevel_builder && (the_level_record.get_energy().value>=0.)) {
303
304 // if no ground state, add a dummy level a 0 energy
305 if(flist_of_levels.size()==0 && (the_level_record.get_energy().value>0. || the_level_record.is_energy_offset())) {
306 tkensdf_level_rec dummy_rec;
307 dummy_rec.set_record("Dummy L 0.0 ");
308 dummy_rec.analyse_record();
309 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, dummy_rec, _data_set->fis_adopted);
310 dummy_rec.flevelid = flevel_builder->get_level_id();
311 flist_of_levels.emplace_back(dummy_rec);
312 }
313
314 flevel_builder->fill_level(_dataset_idx, fIsotopeIndex, the_level_record, _data_set->fis_adopted);
315 the_level_record.flevelid = flevel_builder->get_level_id();
316 flist_of_levels.emplace_back(the_level_record);
317
318 // check that the energy is not higher thant the previous one
319 if(the_level_record.is_energy_offset()) {
320 std::vector<pair<int,tkensdf_level_rec*>> vec;
321 int idx=0;
322 for(auto it = flist_of_levels.begin() ; it != flist_of_levels.end() ; it++, idx++) {
323 if(it->get_energy_offset() == the_level_record.get_energy_offset()) {
324 vec.push_back({idx,(&(*it))});
325 }
326 }
327 if(vec.size()>1 && (vec.at(vec.size()-1).second->get_energy().value < vec.at(vec.size()-2).second->get_energy().value)) {
328 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;
329 swap(flist_of_levels[vec.at(vec.size()-1).first],flist_of_levels[vec.at(vec.size()-2).first]);
330 cin.get();
331 }
332 }
333 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)) {
334 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;
335 swap(flist_of_levels[flist_of_levels.size()-1],flist_of_levels[flist_of_levels.size()-2]);
336 }
337 }
338 }
339 else {
340 is_record = fensdf_reader.next_record(_data_set,record);
341 }
342 } // ok
343 sqlite3_exec(fDataBase->get_sql_db(), "END TRANSACTION", nullptr, nullptr, &sErrMsg);
344
345
346 glog.clear();
347
348 return true;
349}
350
351#ifdef HAS_ROOT
352ClassImp(tkensdf_builder);
353#endif
Interface to the sqlite database.
Definition tkdatabase.h:34
sqlite3 * get_sql_db()
Definition tkdatabase.h:62
Main class dedicated to the ENSDF records decoding.
virtual ~tkensdf_builder()
tkensdf_builder(tkdatabase *_database, const tkstring &_input_folder)
int add_dataset(tkensdf_ident_rec &_dataset, const tkstring &_comment)
Decodding of the ENSDF gamma 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 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.
Decodding of the ENSDF level 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
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:31
tkstring copy() const
Returns a copy of this string.
Definition tkstring.cpp:347
static const char * form(const char *_format,...)
Definition tkstring.cpp:408
int atoi() const
Converts a string to integer value.
Definition tkstring.cpp:152
tkstring & remove_all_extra_white_space()
Definition tkstring.cpp:503
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:174
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.h:162
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition tkstring.h:180
Definition tklog.cpp:16
tklog & error_v(tklog &log)
Definition tklog.h:407
tklog & do_endl(tklog &log)
Definition tklog.h:212