/** * @file CKParser.cpp * */ // Copyright 2001 California Institute of Technology // // $Id$ // #include #include #include #include #include #include "CKParser.h" #include "ckr_utils.h" #include "writelog.h" #include //#include "../stringUtils.h" #include #include #include 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(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& names, speciesTable& species, vector_fp& temp, int& optionFlag, std::ostream& log) { // String buffer for lines string s; vector toks; string defaultDate=""; int nreg = 2; int i; int nsp = static_cast(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(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], "")); if (getAllSpecies) names.clear(); // Map between the number of times a species name appears in the database map 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 as a // species name. Break if you find the end of the section. if (spec.name == "") { 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(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 "" as the species name string comment; // Name of the species string nameid; vector toks; int nToks = 0; // Loop forward until we get to the next nonempty line. do { getCKLine(s, comment); if (isKeyword(s) || match(s, "")) { sp.name = ""; 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(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