Cantera  2.0
NASA9Parser.cpp
1 /**
2  * @file CKParser.cpp
3  *
4  */
5 
6 // Copyright 2001 California Institute of Technology
7 
8 #include <numeric>
9 #include <algorithm>
10 #include <fstream>
11 #include <iomanip>
12 #include <math.h>
13 
14 #include "CKParser.h"
15 #include "ckr_utils.h"
16 #include "writelog.h"
17 #include <stdio.h>
18 //#include "cantera/base/stringUtils.h"
19 
20 #include <ctype.h>
21 #include <string>
22 #include <cstdlib>
23 
24 using namespace std;
25 
26 namespace ckr
27 {
28 
29 
30 
31 /**
32  * Add an element to a species.
33  * @param symbol element symbol
34  * @param atoms number of atoms of this element in the
35  * species (may be non-integral)
36  * @param sp Species object to add element to
37  * @param log log file output stream
38  */
39 static void addElement(std::string symbol, double atoms,
40  Species& sp, std::ostream& log)
41 {
42 
43  if (atoms != 0.0) {
44  Constituent e;
45  e.name = symbol;
46  e.number = atoms;
47  sp.elements.push_back(e);
48  sp.comp[symbol] = atoms;
49  }
50 }
51 
52 
53 /**
54  * Throw an exception if number string is bad
55  */
56 static void illegalNumber(std::ostream& f,
57  std::string s, int linenum = -1)
58 {
59  string msg = "illegal number: "+s;
60  throw CK_SyntaxError(f, msg, linenum);
61 };
62 
63 
64 void CKParser::checkSpeciesName(std::string spname)
65 {
66  if (spname.size() <= 0) {
67  string sss = "Empty for string name";
68  throw CK_SyntaxError(*m_log, sss, m_line);
69  }
70  char first = spname[0];
71  if (isdigit(first)) {
72  string sss = "First char of string name is number";
73  throw CK_SyntaxError(*m_log, sss, m_line);
74  }
75  if (isspace(first)) {
76  string sss = "First char of string name is white space";
77  throw CK_SyntaxError(*m_log, sss, m_line);
78  }
79 }
80 
81 static std::string d2e(std::string s)
82 {
83  size_t n;
84  size_t sz = s.size();
85  string r = s;
86  char ch;
87  for (n = 0; n < sz; n++) {
88  ch = s[n];
89  if (ch == 'D') {
90  r[n] = 'E';
91  } else if (ch == 'd') {
92  r[n] = 'e';
93  }
94  }
95  return r;
96 }
97 
98 static double de_atof(std::string s)
99 {
100  string r = d2e(s);
101  //double rval = Cantera::atofCheck(r.c_str());
102  double rval = atof(r.c_str());
103  return rval;
104 }
105 
106 static double getNumberFromString(std::string s)
107 {
108  bool inexp = false;
109  removeWhiteSpace(s);
110  int sz = static_cast<int>(s.size());
111  char ch;
112  for (int n = 0; n < sz; n++) {
113  ch = s[n];
114  if (!inexp && (ch == 'E' || ch == 'e' || ch == 'D' || ch == 'd')) {
115  inexp = true;
116  } else if (ch == '+' || ch == '-') {
117  if (n > 0 && (s[n-1] != 'E' && s[n-1]
118  != 'e' && s[n-1] != 'd' && s[n-1] != 'D')) {
119  return UNDEF;
120  }
121  } else if (ch != '.' && (ch < '0' || ch > '9')) {
122  return UNDEF;
123  }
124  }
125  return de_atof(s);
126 }
127 
128 static int de_atoi(std::ostream& log, std::string s, int line = -1)
129 {
130  double val = getNumberFromString(s);
131  int ival = (int) val;
132  double val2 = (double) ival;
133  if (fabs(val - val2) >= 0.00001 * (val + val2)) {
134  string sss = "de_atoi: Conversion of int failed: " + s;
135  throw CK_SyntaxError(log, sss, line);
136  }
137  return ival;
138 }
139 
140 /**
141  *
142  * Read species data from THERMO section records.
143  *
144  * @param names List of species names (input).
145  * @param species Table of species objects holding data from records
146  * in THERMO section (output).
147  * @param temp Default vector of temperature region boundaries
148  * There are one more temperatures than there are
149  * temperature regions.
150  *
151  * @return True, if the THERMO section exists and the species
152  * have all been successfully processed. False, if
153  * the THERMO section doesn't exist or there were
154  * additional problems.
155  */
156 bool CKParser::readNASA9ThermoSection(std::vector<string>& names,
157  speciesTable& species, vector_fp& temp,
158  int& optionFlag, std::ostream& log)
159 {
160  // String buffer for lines
161  string s;
162  vector<string> toks;
163  string defaultDate="";
164  int nsp = static_cast<int>(names.size());
165 
166  // Comment string
167  string comment;
168 
169  // Check to see that we expect to be reading a NASA9 formatted file
170  if (!m_nasa9fmt) {
171  throw CK_SyntaxError(log,
172  "In NASA9 parser. However, we expect a different file format",
173  -1);
174  }
175 
176  // now read in all species records that have names in list 'names'
177 
178  bool getAllSpecies = (nsp > 0 && match(names[0], "<ALL>"));
179  if (getAllSpecies) {
180  names.clear();
181  }
182 
183  // Map between the number of times a species name appears in the database
184  map<string, int> dup; // used to check for duplicate THERMO records
185  bool already_read;
186 
187  while (1 > 0) {
188  // If we don't have any more species to read, break
189  if (nsp == 0) {
190  break;
191  }
192  already_read = false;
193 
194  // Read a new species record from the section
195  Species spec;
196  readNASA9ThermoRecord(spec);
197 
198  // we signal the end of the section by putting <END> as a
199  // species name. Break if you find the end of the section.
200  if (spec.name == "<END>") {
201  break;
202  }
203 
204  // check for duplicate thermo data
205  if (dup[spec.name] == 2) {
206  log << "Warning: more than one THERMO record for "
207  << "species " << spec.name << endl;
208  log << "Record at line " << m_line
209  << " of " << m_ckfilename << " ignored." << endl;
210  already_read = true;
211  }
212  // Set the record in the map to 2 to create a signal for the
213  // next time.
214  dup[spec.name] = 2;
215 
216  // Check to see whether we need this particular species name
217  if (!already_read && (getAllSpecies
218  || (find(names.begin(), names.end(), spec.name)
219  < names.end()))) {
220 
221  // Add the species object to the map. Note we are
222  // doing a copy constructor here, so we create a
223  // lasting entry.
224  species[spec.name] = spec;
225 
226  if (verbose) {
227  log << endl << "found species " << spec.name;
228  log << " at line " << m_line
229  << " of " << m_ckfilename;
230  writeSpeciesData(log, spec);
231  }
232  if (getAllSpecies) {
233  names.push_back(spec.name);
234  nsp = static_cast<int>(names.size());
235  } else {
236  nsp--;
237  }
238  }
239  }
240  return true;
241 }
242 
243 
244 /**
245  *
246  * Read one species definition in a NASA9 string.
247  *
248  */
249 void CKParser::readNASA9ThermoRecord(Species& sp)
250 {
251  string s;
252  string numstr;
253  double cf;
254  // Set to the NASA9 polynomial format
255  sp.thermoFormatType = 1;
256 
257  // look for line 1, but if a keyword is found first or the end of
258  // the file is reached, return "<END>" as the species name
259  string comment;
260 
261  // Name of the species
262  string nameid;
263  vector<string> toks;
264  size_t nToks = 0;
265 
266  // Loop forward until we get to the next nonempty line.
267  do {
268  getCKLine(s, comment);
269  if (isKeyword(s) || match(s, "<EOF>")) {
270  sp.name = "<END>";
271  putCKLine(s, comment);
272  return;
273  }
274 
275  // The first 18 spaces are devoted to the name of the species
276  string nameid = s.substr(0,18);
277  getTokens(nameid, static_cast<int>(nameid.size()), toks);
278  nToks = toks.size();
279  } while (nToks == 0);
280 
281  //------------- line 1 ---------------------------
282  // Everything after the first 18 spaces is a comment.
283  size_t nt = s.size();
284  sp.m_commentsRef = s.substr(18, nt-18);
285 
286  // Parse the species name
287  sp.name = toks[0];
288  sp.id = "";
289  if (nToks > 1) {
290  throw CK_SyntaxError(*m_log,
291  "Illegal number of tokens for string name", m_line);
292  }
293  checkSpeciesName(sp.name);
294 
295 
296  //------------- line 2 ---------------------------
297 
298  getCKLine(s, comment);
299  if (s.size() < 79) {
300  throw CK_SyntaxError(*m_log,
301  "Size of second line is too small", m_line);
302  }
303  // Read the number of temperature regions.
304  string sN = s.substr(0,2);
305  sp.nTempRegions = de_atoi(*m_log, sN);
306 
307  string refDataCode = s.substr(3,6);
308 
309  // elemental composition (first 5 elements)
310  for (int i = 0; i < 5; i++) {
311  string elementSym = "";
312  int iloc = 10 + 8*i;
313  if (s[iloc] != ' ') {
314  if (s[iloc+1] != ' ') {
315  elementSym = s.substr(iloc,2);
316  } else {
317  elementSym = s.substr(iloc,1);
318  }
319  } else if (s[iloc+1] != ' ') {
320  elementSym = s.substr(iloc+1,1);
321  }
322  double atoms = de_atof(s.substr(iloc+2,6));
323  addElement(elementSym, atoms, sp, *m_log);
324  }
325 
326 
327  // single-character phase descriptor
328  sp.phase = s.substr(50,2);
329 
330  // Molecular weight in gm per gmol
331  string molecWeight = s.substr(52, 13);
332 
333  // Heat of formation at 298.15 K in J / gmol
334  string Hf298_Jgmol = s.substr(65, 15);
335 
336  vector_fp* coeffs_ptr;
337  for (int i = 0; i < sp.nTempRegions; i++) {
338 
339  coeffs_ptr = new vector_fp(9);
340  vector_fp& coeffs = *coeffs_ptr;
341 
342  //------------- line 3 ---------------------------
343  getCKLine(s, comment);
344  if (s.size() < 79) {
345  throw CK_SyntaxError(*m_log,
346  "Size of third line is too small", m_line);
347  }
348 
349  string sTlow = s.substr(0, 11);
350  double tLow = de_atof(sTlow);
351 
352  string sTHigh = s.substr(11, 11);
353  double tHigh = de_atof(sTHigh);
354 
355  string sNCoeff = s.substr(22, 1);
356  int nCoeff = de_atoi(*m_log, sNCoeff);
357  if (nCoeff != 7) {
358  throw CK_SyntaxError(*m_log, "ncoeff ne 7", m_line);
359  }
360 
361  string sTCoeff1 = s.substr(24, 5);
362  double TCoeff1 = de_atof(sTCoeff1);
363  if (TCoeff1 != -2.0) {
364  throw CK_SyntaxError(*m_log, "TCoeff1 ne -2.0", m_line);
365  }
366 
367  string sTCoeff2 = s.substr(29, 5);
368  double TCoeff2 = de_atof(sTCoeff2);
369  if (TCoeff2 != -1.0) {
370  throw CK_SyntaxError(*m_log, "TCoeff2 ne -1.0", m_line);
371  }
372 
373  string sTCoeff3 = s.substr(34, 5);
374  double TCoeff3 = de_atof(sTCoeff3);
375  if (TCoeff3 != 0.0) {
376  throw CK_SyntaxError(*m_log, "TCoeff3 ne 0.0", m_line);
377  }
378 
379  string sTCoeff4 = s.substr(39, 5);
380  double TCoeff4 = de_atof(sTCoeff4);
381  if (TCoeff4 != 1.0) {
382  throw CK_SyntaxError(*m_log, "TCoeff4 ne 1.0", m_line);
383  }
384 
385  string sTCoeff5 = s.substr(44, 5);
386  double TCoeff5 = de_atof(sTCoeff5);
387  if (TCoeff5 != 2.0) {
388  throw CK_SyntaxError(*m_log, "TCoeff5 ne 2.0", m_line);
389  }
390 
391  string sTCoeff6 = s.substr(49, 5);
392  double TCoeff6 = de_atof(sTCoeff6);
393  if (TCoeff6 != 3.0) {
394  throw CK_SyntaxError(*m_log, "TCoeff6 ne 3.0", m_line);
395  }
396 
397  string sTCoeff7 = s.substr(54, 5);
398  double TCoeff7 = de_atof(sTCoeff7);
399  if (TCoeff7 != 4.0) {
400  throw CK_SyntaxError(*m_log, "TCoeff7 ne 4.0", m_line);
401  }
402 
403  string sHf298mHF0 = s.substr(65, 15);
404 
405  //------------- line 4 ---------------------------
406  getCKLine(s, comment);
407  if (s.size() < 79) {
408  throw CK_SyntaxError(*m_log,
409  "Size of third line is too small", m_line);
410  }
411 
412  numstr = s.substr(0, 16);
413  cf = getNumberFromString(numstr);
414  if (cf == UNDEF) {
415  illegalNumber(*m_log, numstr, m_line);
416  }
417  coeffs[0] = cf;
418 
419  numstr = s.substr(16, 16);
420  cf = getNumberFromString(numstr);
421  if (cf == UNDEF) {
422  illegalNumber(*m_log, numstr, m_line);
423  }
424  coeffs[1] = cf;
425 
426  numstr = s.substr(32, 16);
427  cf = getNumberFromString(numstr);
428  if (cf == UNDEF) {
429  illegalNumber(*m_log, numstr, m_line);
430  }
431  coeffs[2] = cf;
432 
433  numstr = s.substr(48, 16);
434  cf = getNumberFromString(numstr);
435  if (cf == UNDEF) {
436  illegalNumber(*m_log, numstr, m_line);
437  }
438  coeffs[3] = cf;
439 
440  numstr = s.substr(64, 16);
441  cf = getNumberFromString(numstr);
442  if (cf == UNDEF) {
443  illegalNumber(*m_log, numstr, m_line);
444  }
445  coeffs[4] = cf;
446 
447  //------------- line 5 ---------------------------
448  getCKLine(s, comment);
449  if (s.size() < 79) {
450  throw CK_SyntaxError(*m_log,
451  "Size of fourth line is too small", m_line);
452  }
453 
454  numstr = s.substr(0, 16);
455  cf = getNumberFromString(numstr);
456  if (cf == UNDEF) {
457  illegalNumber(*m_log, numstr, m_line);
458  }
459  coeffs[5] = cf;
460 
461  numstr = s.substr(16, 16);
462  cf = getNumberFromString(numstr);
463  if (cf == UNDEF) {
464  illegalNumber(*m_log, numstr, m_line);
465  }
466  coeffs[6] = cf;
467 
468  numstr = s.substr(48, 16);
469  cf = getNumberFromString(numstr);
470  if (cf == UNDEF) {
471  illegalNumber(*m_log, numstr, m_line);
472  }
473  coeffs[7] = cf;
474 
475  numstr = s.substr(64, 16);
476  cf = getNumberFromString(numstr);
477  if (cf == UNDEF) {
478  illegalNumber(*m_log, numstr, m_line);
479  }
480  coeffs[8] = cf;
481 
482  // Store the coefficients.
483  sp.minTemps.push_back(tLow);
484  sp.maxTemps.push_back(tHigh);
485 
486  sp.region_coeffs.push_back(coeffs_ptr);
487 
488  }
489 
490  sp.valid = 1;
491 }
492 
493 
494 
495 } // ckr namespace
496