EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
estar_dataParser.cpp
1 /*
2 ###############################################################################
3 #
4 # EGSnrc estar
5 # Copyright (C) 2026 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Sehmimul Hoque, 2022
25 #
26 # Contributors: Martin J. Berger
27 # Johnathan S. Coursey
28 # Reid Townson
29 # Ernesto Mainegra-Hing
30 #
31 # Based on the original ESTAR code by Martin J. Berger,
32 # National Institute of Standards and Technology (NIST). Including
33 # modifications by Johnathan S. Coursey.
34 #
35 ###############################################################################
36 */
37 
38 #include <iostream>
39 #include <fstream>
40 #include <iomanip>
41 #include <assert.h>
42 #include "estar_dataParser.h"
43 #include "estar_dataTables.h"
44 #include "egs_functions.h"
45 
46 /*
47  The purpose of this module is to read data from the elementData.h
48  file and then to properly structure the data for usage in other modules.
49  There are 100 sets of data in elementData.h (indexed by atomic number)
50  where each set of data corresponds to each element.
51  * For example: the third set of data in elementData.h is the data for Lithium
52 */
53 
54 ElementOscillatorData parseData() {
56  ds.numLevelsStandard = 113; // number of elements in the standard energy grid
57 
58  const int arr_len = 14532;
59  int j = 0;
60 
61  for (int i = 0; i < 100; i++) {
62 
63  ds.nmax[i] = static_cast<int>(elementData[j]);
64 
65  if (ds.nmax[i] < 0 || j + 2 + 2*ds.nmax[i] + ds.numLevelsStandard > arr_len) {
66  egsFatal("estar::parseData: Data layout for element %d would read past end "
67  "of elementData array (j=%d, nmax=%d, arr_len=%d).\n",
68  i, j, ds.nmax[i], arr_len);
69  }
70 
71  // The second element of each set is 113 (numLevelsStandard) and is skipped
72  int k = j + 2;
73 
74  /*
75  Read nc values directly into ds.nc.
76  ds.nmax[i] is the number of oscillators for this element.
77  */
78  for (int a = 0; a < ds.nmax[i]; a++) {
79  if (a >= 26) {
80  egsFatal("estar::parseData: Oscillator index %d exceeds nc "
81  "maximum of 25 for element index %d.\n", a, i);
82  }
83  ds.nc[i][a] = static_cast<int>(elementData[k]);
84  k++;
85  }
86 
87  /*
88  Read bd values directly into ds.bd.
89  */
90  for (int a = 0; a < ds.nmax[i]; a++) {
91  if (a >= 26) {
92  egsFatal("estar::parseData: Oscillator index %d exceeds bd "
93  "maximum of 25 for element index %d.\n", a, i);
94  }
95  ds.bd[i][a] = elementData[k];
96  k++;
97  }
98 
99  // rlos (loss function) values are present in elementData but are not used
100  // by the ESTAR density correction calculation. We advance k past them
101  // to keep j correctly positioned for the next element's data block.
102  k += ds.numLevelsStandard;
103 
104  j = k;
105  }
106 
107  return ds;
108 }
109 
110 /*
111  The output of parse() below is a parseformula object. It takes input a formula string
112  and produces the object or an error message
113  for example: for MgCl2
114  we will get: str_arr = ["Mg", "Cl"]
115  num_arr = [1,2]
116  mmax = 2
117 */
118 parseformula parse(string str) {
119  parseformula pf;
120  pf.elem_types = 0;
121  int str_len = str.length(); // length of formula
122  int i = 0;
123  int j = 0;
124  while (i < str_len) {
125  if (j >= 100) {
126  egsFatal("estar::parse: Element type count exceeded maximum of 100"
127  " while parsing formula '%s'.\n", str.c_str());
128  }
129 
130  if (isupper(static_cast<unsigned char>(str[i])) != 0) { // means str[i] is uppercase
131  if (i + 1 < str_len && islower(static_cast<unsigned char>(str[i+1])) != 0) {
132  pf.str_arr[j] = str.substr(i,2);
133  i = i+2;
134  }
135  else {
136  pf.str_arr[j] = str.substr(i,1);
137  i = i+1;
138  }
139  }
140  else {
141  egsFatal("estar::parse: Formula '%s' is malformed at character '%c' (index %d).\n"
142  "Element symbols must begin with an uppercase letter.\n",
143  str.c_str(), str[i], i);
144  }
145 
146  if (i < str_len && isdigit(static_cast<unsigned char>(str[i])) != 0) {
147  int digit_start = i;
148  while (i < str_len && isdigit(static_cast<unsigned char>(str[i])) != 0) {
149  i = i + 1;
150  }
151  int digit_len = i - digit_start;
152 
153  // Guard against absurdly large numbers that would overflow strtol
154  if (digit_len > 9) {
155  egsFatal("estar::parse: Atom count in formula '%s' has %d digits which "
156  "exceeds the maximum of 9.\n", str.c_str(), digit_len);
157  }
158 
159  std::string digit_str = str.substr(digit_start, digit_len);
160  char *end;
161  errno = 0;
162  long val = std::strtol(digit_str.c_str(), &end, 10);
163 
164  if (errno != 0 || end == digit_str.c_str() || val <= 0 || val > 99) {
165  egsFatal("estar::parse: Invalid atom count '%s' in formula '%s'.\n"
166  "Atom count must be a positive integer no greater than 99.\n",
167  digit_str.c_str(), str.c_str());
168  }
169 
170  pf.num_arr[j] = static_cast<int>(val);
171  }
172  else {
173  pf.num_arr[j] = 1;
174  }
175  j = j + 1;
176  }
177  pf.elem_types = j;
178  return pf;
179 };
180 
Global egspp functions header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
Holds the dispersion oscillator data for all 100 elements.
int nc[100][26]
Number of electrons in each subshell for each element.
double bd[100][26]
Absorption edge energies (in units of hbar) for each oscillator.
int numLevelsStandard
Number of elements in the standard energy grid.
int nmax[100]
Number of dispersion oscillators for each element.
Holds the parsed representation of a chemical formula.