cantera/Cantera/src/converters/NASA9Parser.cpp
2009-11-09 23:36:49 +00:00

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