545 lines
14 KiB
C++
545 lines
14 KiB
C++
/**
|
|
* @file CKParser.cpp
|
|
*
|
|
*/
|
|
|
|
// Copyright 2001 California Institute of Technology
|
|
//
|
|
// $Id$
|
|
//
|
|
|
|
|
|
#include <numeric>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <math.h>
|
|
|
|
#include "CKParser.h"
|
|
#include "ckr_utils.h"
|
|
#include "writelog.h"
|
|
#include <stdio.h>
|
|
//#include "../stringUtils.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
|
|
using namespace std;
|
|
|
|
namespace ckr {
|
|
|
|
|
|
|
|
/**
|
|
* Add an element to a species.
|
|
* @param symbol element symbol
|
|
* @param atoms number of atoms of this element in the
|
|
* species (may be non-integral)
|
|
* @param sp Species object to add element to
|
|
* @param log log file output stream
|
|
*/
|
|
static void addElement(std::string symbol, double atoms,
|
|
Species& sp, std::ostream& log) {
|
|
|
|
if (atoms != 0.0) {
|
|
Constituent e;
|
|
e.name = symbol;
|
|
e.number = atoms;
|
|
sp.elements.push_back(e);
|
|
sp.comp[symbol] = atoms;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Throw an exception if number string is bad
|
|
*/
|
|
static void illegalNumber(std::ostream& f,
|
|
std::string s, int linenum = -1)
|
|
{
|
|
string msg = "illegal number: "+s;
|
|
throw CK_SyntaxError(f, msg, linenum);
|
|
};
|
|
|
|
|
|
void CKParser::checkSpeciesName(std::string spname) {
|
|
if (spname.size() <= 0) {
|
|
string sss = "Empty for string name";
|
|
throw CK_SyntaxError(*m_log, sss, m_line);
|
|
}
|
|
char first = spname[0];
|
|
if (isdigit(first)) {
|
|
string sss = "First char of string name is number";
|
|
throw CK_SyntaxError(*m_log, sss, m_line);
|
|
}
|
|
if (isspace(first)) {
|
|
string sss = "First char of string name is white space";
|
|
throw CK_SyntaxError(*m_log, sss, m_line);
|
|
}
|
|
}
|
|
|
|
static std::string d2e(std::string s) {
|
|
size_t n;
|
|
size_t sz = s.size();
|
|
string r = s;
|
|
char ch;
|
|
for (n = 0; n < sz; n++) {
|
|
ch = s[n];
|
|
if (ch == 'D') r[n] = 'E';
|
|
else if (ch == 'd') r[n] = 'e';
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static double de_atof(std::string s) {
|
|
string r = d2e(s);
|
|
//double rval = Cantera::atofCheck(r.c_str());
|
|
double rval = atof(r.c_str());
|
|
return rval;
|
|
}
|
|
|
|
/**
|
|
* Check validity of the three temperatures defining the two
|
|
* temperature ranges for the NASA polynomial species thermodynamic
|
|
* property fits.
|
|
* @param log log file output stream
|
|
* @param tmin minimum temperature
|
|
* @param tmid intermediate temperature
|
|
* @param tmax maximum temperature
|
|
*/
|
|
// static void checkTemps(std::ostream& log, double tmin,
|
|
// double tmid, double tmax)
|
|
// {
|
|
// if (tmin == 0.0 || tmid == 0.0 || tmax == 0.0) {
|
|
// throw CK_SyntaxError(log,
|
|
// "error reading Tmin, Tmid, or Tmax");
|
|
// }
|
|
//}
|
|
|
|
static double getNumberFromString(std::string s) {
|
|
bool inexp = false;
|
|
removeWhiteSpace(s);
|
|
int sz = static_cast<int>(s.size());
|
|
char ch;
|
|
for (int n = 0; n < sz; n++) {
|
|
ch = s[n];
|
|
if (!inexp && (ch == 'E' || ch == 'e' || ch == 'D' || ch == 'd'))
|
|
inexp = true;
|
|
else if (ch == '+' || ch == '-') {
|
|
if (n > 0 && (s[n-1] != 'E' && s[n-1]
|
|
!= 'e' && s[n-1] != 'd' && s[n-1] != 'D')) {
|
|
return UNDEF;
|
|
}
|
|
}
|
|
else if (ch != '.' && (ch < '0' || ch > '9')) {
|
|
return UNDEF;
|
|
}
|
|
}
|
|
return de_atof(s);
|
|
}
|
|
|
|
static int de_atoi(std::ostream &log, std::string s, int line = -1) {
|
|
double val = getNumberFromString(s);
|
|
int ival = (int) val;
|
|
double val2 = (double) ival;
|
|
if (fabs(val - val2) >= 0.00001 * (val + val2)) {
|
|
string sss = "de_atoi: Conversion of int failed: " + s;
|
|
throw CK_SyntaxError(log, sss, line);
|
|
}
|
|
return ival;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check validity of the temperatures defining the
|
|
* temperature ranges for the NASA9 polynomial species thermodynamic
|
|
* property fits.
|
|
* @param log log file output stream
|
|
* @param temp Vector of temperatures
|
|
*/
|
|
static void checkNASA9Temps(std::ostream& log, vector_fp &temp) {
|
|
int i;
|
|
for (i = 1; i <= (int) temp.size(); i++) {
|
|
double tlow = temp[i-1];
|
|
double thigh = temp[i];
|
|
if (thigh <= tlow) {
|
|
string sss = "error reading temperature";
|
|
throw CK_SyntaxError(log, sss);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* Read species data from THERMO section records.
|
|
*
|
|
* @param names List of species names (input).
|
|
* @param species Table of species objects holding data from records
|
|
* in THERMO section (output).
|
|
* @param temp Devault vector of temperature region boundaries
|
|
* There are one more temperatures than there are
|
|
* temperature regions.
|
|
* @param allowExtThermoData True if 'THERMO' specified, false if
|
|
* 'THERMO ALL' specified.
|
|
*
|
|
* @return True, if the THERMO section exists and the species
|
|
* have all been successfully processed. False, if
|
|
* the THERMO section doesn't exist or there were
|
|
* additional problems.
|
|
*/
|
|
bool CKParser::readNASA9ThermoSection(std::vector<string>& names,
|
|
speciesTable& species, vector_fp& temp,
|
|
int& optionFlag, std::ostream& log) {
|
|
// String buffer for lines
|
|
string s;
|
|
vector<string> toks;
|
|
string defaultDate="";
|
|
int nreg = 2;
|
|
int i;
|
|
|
|
int nsp = static_cast<int>(names.size());
|
|
|
|
// Comment string
|
|
string comment;
|
|
|
|
|
|
// if "THERMO ALL" specified, or if optionFlag is set to HasTempRange,
|
|
// then the next line must be the default temperatures for the database.
|
|
//
|
|
// This line will have nreg+2 tokens on it
|
|
// The last token is a date.
|
|
if (0) {
|
|
if (optionFlag == NoThermoDatabase || optionFlag == HasTempRange) {
|
|
getCKLine(s, comment);
|
|
getTokens(s, static_cast<int>(s.size()), toks);
|
|
nreg = toks.size();
|
|
if (nreg >= 1) {
|
|
temp.resize(nreg+1);
|
|
for (i = 0; i <= nreg; i++) {
|
|
temp[i] = de_atof(toks[i]);
|
|
}
|
|
defaultDate = toks[nreg+1];
|
|
}
|
|
|
|
if (verbose) {
|
|
log.flags(ios::showpoint | ios::fixed);
|
|
log.precision(2);
|
|
log << endl << " Default # of temperature regions: " << nreg << endl;
|
|
log << " ";
|
|
for (i = 0; i <= nreg; i++) {
|
|
log << temp[i] << " ";
|
|
}
|
|
log << endl;
|
|
}
|
|
checkNASA9Temps(log, temp);
|
|
}
|
|
}
|
|
|
|
// Check to see that we expect to be reading a NASA9 formatted file
|
|
if (!m_nasa9fmt) {
|
|
throw CK_SyntaxError(log,
|
|
"In NASA9 parser. However, we expect a different file format",
|
|
-1);
|
|
}
|
|
|
|
// now read in all species records that have names in list 'names'
|
|
|
|
bool getAllSpecies = (nsp > 0 && match(names[0], "<ALL>"));
|
|
if (getAllSpecies) names.clear();
|
|
|
|
// Map between the number of times a species name appears in the database
|
|
map<string, int> dup; // used to check for duplicate THERMO records
|
|
bool already_read;
|
|
|
|
while (1 > 0) {
|
|
// If we don't have any more species to read, break
|
|
if (nsp == 0) break;
|
|
already_read = false;
|
|
|
|
// Read a new species record from the section
|
|
Species spec;
|
|
readNASA9ThermoRecord(spec);
|
|
|
|
// we signal the end of the section by putting <END> as a
|
|
// species name. Break if you find the end of the section.
|
|
if (spec.name == "<END>") {
|
|
break;
|
|
}
|
|
|
|
// check for duplicate thermo data
|
|
if (dup[spec.name] == 2) {
|
|
log << "Warning: more than one THERMO record for "
|
|
<< "species " << spec.name << endl;
|
|
log << "Record at line " << m_line
|
|
<< " of " << m_ckfilename << " ignored." << endl;
|
|
already_read = true;
|
|
}
|
|
// Set the record in the map to 2 to create a signal for the
|
|
// next time.
|
|
dup[spec.name] = 2;
|
|
|
|
// Check to see whether we need this particlar species name
|
|
if (!already_read && (getAllSpecies
|
|
|| (find(names.begin(), names.end(), spec.name)
|
|
< names.end()))) {
|
|
|
|
// Add the species object to the map. Note we are
|
|
// doing a copy constructor here, so we create a
|
|
// lasting entry.
|
|
species[spec.name] = spec;
|
|
|
|
if (verbose) {
|
|
log << endl << "found species " << spec.name;
|
|
log << " at line " << m_line
|
|
<< " of " << m_ckfilename;
|
|
writeSpeciesData(log, spec);
|
|
}
|
|
//checkTemps(log, spec.tlow, spec.tmid, spec.thigh);
|
|
if (getAllSpecies) {
|
|
names.push_back(spec.name);
|
|
nsp = static_cast<int>(names.size());
|
|
}
|
|
else
|
|
nsp--;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* Read one species definition in a NASA9 string.
|
|
*
|
|
*/
|
|
void CKParser::readNASA9ThermoRecord(Species& sp) {
|
|
string s;
|
|
string numstr;
|
|
double cf;
|
|
// Set to the NASA9 polynomial format
|
|
sp.thermoFormatType = 1;
|
|
|
|
// look for line 1, but if a keyword is found first or the end of
|
|
// the file is reached, return "<END>" as the species name
|
|
string comment;
|
|
|
|
// Name of the species
|
|
string nameid;
|
|
vector<string> toks;
|
|
int nToks = 0;
|
|
|
|
// Loop forward until we get to the next nonempty line.
|
|
do {
|
|
getCKLine(s, comment);
|
|
if (isKeyword(s) || match(s, "<EOF>")) {
|
|
sp.name = "<END>";
|
|
putCKLine(s, comment);
|
|
return;
|
|
}
|
|
|
|
// The first 18 spaces are devoted to the name of the species
|
|
string nameid = s.substr(0,18);
|
|
getTokens(nameid, static_cast<int>(nameid.size()), toks);
|
|
nToks = toks.size();
|
|
} while (nToks == 0);
|
|
|
|
//------------- line 1 ---------------------------
|
|
// Everything after the first 18 spaces is a comment.
|
|
int nt = s.size();
|
|
sp.m_commentsRef = s.substr(18, nt-18);
|
|
|
|
// Parse the species name
|
|
sp.name = toks[0];
|
|
sp.id = "";
|
|
if (nToks > 1) {
|
|
throw CK_SyntaxError(*m_log,
|
|
"Illegal number of tokens for string name", m_line);
|
|
}
|
|
checkSpeciesName(sp.name);
|
|
|
|
|
|
//------------- line 2 ---------------------------
|
|
|
|
getCKLine(s, comment);
|
|
if (s.size() < 79) {
|
|
throw CK_SyntaxError(*m_log,
|
|
"Size of second line is too small", m_line);
|
|
}
|
|
// Read the number of temperature regions.
|
|
string sN = s.substr(0,2);
|
|
sp.nTempRegions = de_atoi(*m_log, sN);
|
|
|
|
string refDataCode = s.substr(3,6);
|
|
|
|
// elemental composition (first 5 elements)
|
|
for (int i = 0; i < 5; i++) {
|
|
string elementSym = "";
|
|
int iloc = 10 + 8*i;
|
|
if (s[iloc] != ' ') {
|
|
if (s[iloc+1] != ' ') {
|
|
elementSym = s.substr(iloc,2);
|
|
} else {
|
|
elementSym = s.substr(iloc,1);
|
|
}
|
|
} else if (s[iloc+1] != ' ') {
|
|
elementSym = s.substr(iloc+1,1);
|
|
}
|
|
double atoms = de_atof(s.substr(iloc+2,6));
|
|
addElement(elementSym, atoms, sp, *m_log);
|
|
}
|
|
|
|
|
|
// single-character phase descriptor
|
|
sp.phase = s.substr(50,2);
|
|
|
|
// Molecular weight in gm per gmol
|
|
string molecWeight = s.substr(52, 13);
|
|
|
|
// Heat of formation at 298.15 K in J / gmol
|
|
string Hf298_Jgmol = s.substr(65, 15);
|
|
|
|
vector_fp *coeffs_ptr;
|
|
for (int i = 0; i < sp.nTempRegions; i++) {
|
|
|
|
coeffs_ptr = new vector_fp(9);
|
|
vector_fp &coeffs = *coeffs_ptr;
|
|
|
|
//------------- line 3 ---------------------------
|
|
getCKLine(s, comment);
|
|
if (s.size() < 79) {
|
|
throw CK_SyntaxError(*m_log,
|
|
"Size of third line is too small", m_line);
|
|
}
|
|
|
|
string sTlow = s.substr(0, 11);
|
|
double tLow = de_atof(sTlow);
|
|
|
|
string sTHigh = s.substr(11, 11);
|
|
double tHigh = de_atof(sTHigh);
|
|
|
|
string sNCoeff = s.substr(22, 1);
|
|
int nCoeff = de_atoi(*m_log, sNCoeff);
|
|
if (nCoeff != 7) {
|
|
throw CK_SyntaxError(*m_log, "ncoeff ne 7", m_line);
|
|
}
|
|
|
|
string sTCoeff1 = s.substr(24, 5);
|
|
double TCoeff1 = de_atof(sTCoeff1);
|
|
if (TCoeff1 != -2.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff1 ne -2.0", m_line);
|
|
}
|
|
|
|
string sTCoeff2 = s.substr(29, 5);
|
|
double TCoeff2 = de_atof(sTCoeff2);
|
|
if (TCoeff2 != -1.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff2 ne -1.0", m_line);
|
|
}
|
|
|
|
string sTCoeff3 = s.substr(34, 5);
|
|
double TCoeff3 = de_atof(sTCoeff3);
|
|
if (TCoeff3 != 0.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff3 ne 0.0", m_line);
|
|
}
|
|
|
|
string sTCoeff4 = s.substr(39, 5);
|
|
double TCoeff4 = de_atof(sTCoeff4);
|
|
if (TCoeff4 != 1.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff4 ne 1.0", m_line);
|
|
}
|
|
|
|
string sTCoeff5 = s.substr(44, 5);
|
|
double TCoeff5 = de_atof(sTCoeff5);
|
|
if (TCoeff5 != 2.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff5 ne 2.0", m_line);
|
|
}
|
|
|
|
string sTCoeff6 = s.substr(49, 5);
|
|
double TCoeff6 = de_atof(sTCoeff6);
|
|
if (TCoeff6 != 3.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff6 ne 3.0", m_line);
|
|
}
|
|
|
|
string sTCoeff7 = s.substr(54, 5);
|
|
double TCoeff7 = de_atof(sTCoeff7);
|
|
if (TCoeff7 != 4.0) {
|
|
throw CK_SyntaxError(*m_log, "TCoeff7 ne 4.0", m_line);
|
|
}
|
|
|
|
string sHf298mHF0 = s.substr(65, 15);
|
|
|
|
//------------- line 4 ---------------------------
|
|
getCKLine(s, comment);
|
|
if (s.size() < 79) {
|
|
throw CK_SyntaxError(*m_log,
|
|
"Size of third line is too small", m_line);
|
|
}
|
|
|
|
numstr = s.substr(0, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[0] = cf;
|
|
|
|
numstr = s.substr(16, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[1] = cf;
|
|
|
|
numstr = s.substr(32, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[2] = cf;
|
|
|
|
numstr = s.substr(48, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[3] = cf;
|
|
|
|
numstr = s.substr(64, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[4] = cf;
|
|
|
|
//------------- line 5 ---------------------------
|
|
getCKLine(s, comment);
|
|
if (s.size() < 79) {
|
|
throw CK_SyntaxError(*m_log,
|
|
"Size of fourth line is too small", m_line);
|
|
}
|
|
|
|
numstr = s.substr(0, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[5] = cf;
|
|
|
|
numstr = s.substr(16, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[6] = cf;
|
|
|
|
numstr = s.substr(48, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[7] = cf;
|
|
|
|
numstr = s.substr(64, 16);
|
|
cf = getNumberFromString(numstr);
|
|
if (cf == UNDEF) illegalNumber(*m_log, numstr, m_line);
|
|
coeffs[8] = cf;
|
|
|
|
// Store the coefficients.
|
|
sp.minTemps.push_back(tLow);
|
|
sp.maxTemps.push_back(tHigh);
|
|
|
|
sp.region_coeffs.push_back(coeffs_ptr);
|
|
|
|
}
|
|
|
|
sp.valid = 1;
|
|
}
|
|
|
|
|
|
|
|
} // ckr namespace
|
|
|