24#include "tkensdf_reader.h"
41bool ascii_equivalent(std::uint32_t codepoint,
char &equivalent)
78std::string hex_value(std::uint32_t value,
int width)
80 std::ostringstream output;
81 output << std::uppercase << std::hex << std::setfill(
'0') << std::setw(width) << value;
85bool is_comment_record(
const std::string &record)
87 if (record.size() < 9)
return false;
88 const auto field7 =
static_cast<char>(std::toupper(
static_cast<unsigned char>(record[6])));
89 return field7 ==
'C' || field7 ==
'D' || field7 ==
'T';
92bool decode_utf8(
const std::string &input, std::size_t &position, std::uint32_t &codepoint)
94 const auto lead =
static_cast<unsigned char>(input[position]);
95 std::size_t length = 0;
96 std::uint32_t minimum = 0;
98 if ((lead & 0xe0U) == 0xc0U) {
100 codepoint = lead & 0x1fU;
102 }
else if ((lead & 0xf0U) == 0xe0U) {
104 codepoint = lead & 0x0fU;
106 }
else if ((lead & 0xf8U) == 0xf0U) {
108 codepoint = lead & 0x07U;
114 if (position + length > input.size())
return false;
115 for (std::size_t offset = 1; offset < length; ++offset) {
116 const auto byte =
static_cast<unsigned char>(input[position + offset]);
117 if ((
byte & 0xc0U) != 0x80U)
return false;
118 codepoint = (codepoint << 6U) | (
byte & 0x3fU);
121 if (codepoint < minimum || codepoint > 0x10ffffU ||
122 (codepoint >= 0xd800U && codepoint <= 0xdfffU))
131bool tkensdf_reader::normalize_record(
tkstring &record,
int line_number,
bool report)
133 if (!record.empty() && record.back() ==
'\r') record.pop_back();
135 const bool ascii_only = std::none_of(
136 record.begin(), record.end(),
137 [](
const unsigned char byte) { return byte >= 0x80U; });
141 glog <<
error_v <<
"record at line " << line_number <<
" has " << record.size()
150 for (std::size_t position = 0; position < 9 && position < record.size(); ++position) {
151 const auto byte =
static_cast<unsigned char>(record[position]);
154 glog <<
error_v <<
"non-ASCII byte 0x" << hex_value(
byte, 2)
155 <<
" in the structural ENSDF prefix at line " << line_number
156 <<
", column " << position + 1 <<
do_endl;
163 const bool comment_record = is_comment_record(record);
165 std::string normalized;
166 normalized.reserve(record.size());
168 std::uint32_t codepoint;
172 std::vector<replacement> replacements;
174 for (std::size_t position = 0; position < record.size();) {
175 const auto byte =
static_cast<unsigned char>(record[position]);
177 normalized.push_back(
static_cast<char>(
byte));
182 std::uint32_t codepoint = 0;
183 const auto invalid_position = position;
184 const auto column = normalized.size() + 1;
185 if (!decode_utf8(record, position, codepoint)) {
187 const auto invalid_byte =
static_cast<unsigned char>(record[invalid_position]);
188 glog <<
error_v <<
"invalid UTF-8 byte 0x" << hex_value(invalid_byte, 2)
189 <<
" at ENSDF line " << line_number <<
", column " << column <<
do_endl;
195 if (!comment_record || column < 10) {
197 glog <<
error_v <<
"refusing Unicode U+" << hex_value(codepoint, 4)
198 <<
" outside comment text at ENSDF line " << line_number
199 <<
", column " << column <<
do_endl;
205 char equivalent =
'\0';
206 if (!ascii_equivalent(codepoint, equivalent)) {
208 glog <<
error_v <<
"unsupported Unicode U+" << hex_value(codepoint, 4)
209 <<
" at ENSDF line " << line_number <<
", column " << column <<
do_endl;
214 normalized.push_back(equivalent);
215 replacements.push_back({codepoint, column, equivalent});
220 glog <<
error_v <<
"UTF-8 normalization at ENSDF line " << line_number
221 <<
" produced " << normalized.size() <<
" columns instead of "
229 for (
const auto &item : replacements) {
230 glog <<
warning_v <<
"normalized Unicode U+" << hex_value(item.codepoint, 4)
231 <<
" to '" << item.equivalent <<
"' at ENSDF line " << line_number
232 <<
", column " << item.column <<
do_endl;
241 glog.set_class(
"ensdf_ascii_reader");
242 glog.set_method(
tkstring::form(
"open_nuc(%s,%d)", _nuc_name.data(), _ftype));
249 file_name =
tkstring::Form(
"%s/ENSDF/%s.ens", finput_folder.data(), _nuc_name.data());
250 else if (_ftype ==
kxundl)
251 file_name =
tkstring::Form(
"%s/XUNDL/%s.ens", finput_folder.data(), _nuc_name.data());
253 glog <<
warning_v <<
" database for nucleus " << _nuc_name <<
" not found" <<
do_endl;
262 return open_file(file_name);
265bool tkensdf_reader::open_file(
const tkstring &_file_name)
267 glog.set_class(
"ensdf_ascii_reader");
268 glog.set_method(
tkstring::form(
"open_file(%s)", _file_name.data()));
270 if (fEnsdf_file.is_open()) {
273 fEnsdf_file.open(_file_name);
283 bool new_dataset =
false;
287 const std::streampos record_byte_position = fEnsdf_file.tellg();
288 getline(fEnsdf_file, record);
290 if (!fEnsdf_file.good())
break;
292 if (!normalize_record(record, read_record + 1,
true)) {
307 if (!fEnsdf_file && new_dataset) {
308 the_identification_record.
fposition.second = read_record;
309 fDataSets.push_back(the_identification_record);
310 the_identification_record.
clear();
322 if (fVerbose) the_identification_record.
print(std::cout);
327 fDataSets.push_back(the_identification_record);
328 the_identification_record.
clear();
332 if (fVerbose) glog <<
info << fDataSets.size() <<
" datasets have been found in the ENSDF file " << _file_name <<
do_endl;
336 return fEnsdf_file.is_open();
341 if (!fEnsdf_file.is_open()) {
346 if (fdata_type ==
kxundl) data_type =
"XUNDL";
347 glog <<
info <<
"Database type: " << data_type <<
do_endl;
348 glog <<
info << fDataSets.size() <<
" datasets have been found for nucleus " << fNucleus <<
":" <<
do_endl;
349 for (
auto &key : fDataSets) key.print(std::cout);
357 if (_dataset ==
nullptr)
return false;
360 getline(fEnsdf_file, record);
362 return fEnsdf_file.good();
367 if (_dataset ==
nullptr)
return false;
370 getline(fEnsdf_file, record);
372 return fEnsdf_file.good();
375void tkensdf_reader::close_file()
385 std::cout << std::endl;
390 for (
auto i : frecords_counter) {
394 std::cout << left <<
" - Record Type : counts without(with) continuation records" << std::endl;
395 for (
auto i : frecords_counter) {
397 std::cout << left <<
" - identification : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
399 std::cout << left <<
" - History : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
401 std::cout << left <<
" - Q-value : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
403 std::cout << left <<
" - X-ref : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
405 std::cout << left <<
" - Comment : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
407 std::cout << left <<
" - Parent : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
409 std::cout << left <<
" - Normalisation : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
411 std::cout << left <<
" - Production norm : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
413 std::cout << left <<
" - Level : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
415 std::cout << left <<
" - Beta : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
417 std::cout << left <<
" - EC : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
419 std::cout << left <<
" - Alpha : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
421 std::cout << left <<
" - Particle : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
423 std::cout << left <<
" - Gamma : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
425 std::cout << left <<
" - Reference : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
427 std::cout << left <<
" - End : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
429 std::cout << left <<
" - Unknown : " << setw(maxsize1 + 1) << i.second.first <<
" (" << setw(maxsize2) << i.second.second <<
")" << std::endl;
431 std::cout << std::endl;
Decodding of the ENSDF identification record properties.
void print(std::ostream &) const override
virtual bool set_record(const tkstring &_record) override
define the record from a string
std::pair< int, int > fposition
void set_stpop_position(int _pos)
void set_current_position(int _pos)
void set_start_position(int _pos)
int get_current_position()
void set_byte_position(std::streampos _pos)
std::streampos get_byte_position() const
void print_datasets()
print the list of loaded data sets for the current nucleus and data type
bool open_nuc(const tkstring &_nuc_name, const ensdf_data_type &_ftype=kensdf)
open the file for the slected nucleus and data type, and extract the available data sets
bool first_record(tkensdf_ident_rec *_dataset, tkstring &record)
return the identification record and set its physical 1-based line position
void print_record_counters()
print record counters
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.
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
record_type get_record_type()
get record type
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
tkstring copy() const
Returns a copy of this string.
tkstring & to_lower()
Change all letters to lower case.
static const char * form(const char *_format,...)
static tkstring Form(const char *_format,...)
tkstring & capitalize()
Change first letter of string from lower to upper case.
tklog & error_v(tklog &log)
tklog & warning_v(tklog &log)
tklog & error(tklog &log)
tklog & do_endl(tklog &log)