void installElements(Phase& th, const XML_Node& phaseNode) { // get the declared element names if (!phaseNode.hasChild("elementArray")) { throw CanteraError("installElements", "phase XML node doesn't have \"elementArray\" XML Node"); } XML_Node& elements = phaseNode.child("elementArray"); vector<string> enames; getStringArray(elements, enames); // // element database defaults to elements.xml string element_database = "elements.xml"; if (elements.hasAttrib("datasrc")) { element_database = elements["datasrc"]; } XML_Node* doc = get_XML_File(element_database); XML_Node* dbe = &doc->child("elementData"); XML_Node& root = phaseNode.root(); XML_Node* local_db = 0; if (root.hasChild("elementData")) { local_db = &root.child("elementData"); } for (size_t i = 0; i < enames.size(); i++) { // Find the element data XML_Node* e = 0; if (local_db) { e = local_db->findByAttr("name",enames[i]); } if (!e) { e = dbe->findByAttr("name",enames[i]); } if (!e) { throw CanteraError("addElementsFromXML","no data for element " +enames[i]); } // Add the element doublereal weight = 0.0; if (e->hasAttrib("atomicWt")) { weight = fpValue(e->attrib("atomicWt")); } int anum = 0; if (e->hasAttrib("atomicNumber")) { anum = intValue(e->attrib("atomicNumber")); } string symbol = e->attrib("name"); doublereal entropy298 = ENTROPY298_UNKNOWN; if (e->hasChild("entropy298")) { XML_Node& e298Node = e->child("entropy298"); if (e298Node.hasAttrib("value")) { entropy298 = fpValueCheck(e298Node["value"]); } } th.addElement(symbol, weight, anum, entropy298); } }
void Phase::addElement(const XML_Node& e) { warn_deprecated("Phase::addElement(XML_Node&)", "To be removed after Cantera 2.2."); doublereal weight = 0.0; if (e.hasAttrib("atomicWt")) { weight = fpValue(stripws(e["atomicWt"])); } int anum = 0; if (e.hasAttrib("atomicNumber")) { anum = atoi(stripws(e["atomicNumber"]).c_str()); } string symbol = e["name"]; doublereal entropy298 = ENTROPY298_UNKNOWN; if (e.hasChild("entropy298")) { XML_Node& e298Node = e.child("entropy298"); if (e298Node.hasAttrib("value")) { entropy298 = fpValueCheck(stripws(e298Node["value"])); } } if (weight != 0.0) { addElement(symbol, weight, anum, entropy298); } else { addElement(symbol); } }
compositionMap parseCompString(const std::string& ss, const std::vector<std::string>& names) { compositionMap x; for (size_t k = 0; k < names.size(); k++) { x[names[k]] = 0.0; } size_t start = 0; size_t stop = 0; while (stop < ss.size()) { size_t colon = ss.find(':', start); if (colon == npos) { break; } size_t valstart = ss.find_first_not_of(" \t\n", colon+1); stop = ss.find_first_of(", ;\n\t", valstart); std::string name = stripws(ss.substr(start, colon-start)); if (!names.empty() && x.find(name) == x.end()) { throw CanteraError("parseCompString", "unknown species '" + name + "'"); } x[name] = fpValueCheck(ss.substr(valstart, stop-colon-1)); start = ss.find_first_not_of(", ;\n\t", stop+1); } if (stop != npos && !stripws(ss.substr(stop)).empty()) { throw CanteraError("parseCompString", "Found non-key:value data " "in composition string: '" + ss.substr(stop) + "'"); } return x; }
void LatticeSolidPhase::setParametersFromXML(const XML_Node& eosdata) { eosdata._require("model","LatticeSolid"); XML_Node& la = eosdata.child("LatticeArray"); std::vector<XML_Node*> lattices = la.getChildren("phase"); size_t nl = lattices.size(); m_nlattice = nl; for (size_t n = 0; n < nl; n++) { XML_Node& i = *lattices[n]; m_lattice.push_back((LatticePhase*)newPhase(i)); } std::vector<string> pnam; std::vector<string> pval; XML_Node& ls = eosdata.child("LatticeStoichiometry"); int np = ctml::getPairs(ls, pnam, pval); theta_.resize(nl); for (int i = 0; i < np; i++) { double val = fpValueCheck(pval[i]); bool found = false; for (size_t j = 0; j < nl; j++) { ThermoPhase& tp = *(m_lattice[j]); string idj = tp.id(); if (idj == pnam[i]) { theta_[j] = val; found = true; break; } } if (!found) { throw CanteraError("", "not found"); } } }
/** * constructPDSSXML: * * Initialization of a PDSS_IonsFromNeutral object using an * xml file. * @param id Optional parameter identifying the name of the * phase. If none is given, the first XML * phase element will be used. */ void PDSS_IonsFromNeutral::constructPDSSXML(VPStandardStateTP *tp, int spindex, const XML_Node& speciesNode, const XML_Node& phaseNode, std::string id) { const XML_Node *tn = speciesNode.findByName("thermo"); if (!tn) { throw CanteraError("PDSS_IonsFromNeutral::constructPDSSXML", "no thermo Node for species " + speciesNode.name()); } std::string model = lowercase((*tn)["model"]); if (model != "ionfromneutral") { throw CanteraError("PDSS_IonsFromNeutral::constructPDSSXML", "thermo model for species isn't IonsFromNeutral: " + speciesNode.name()); } const XML_Node *nsm = tn->findByName("neutralSpeciesMultipliers"); if (!nsm) { throw CanteraError("PDSS_IonsFromNeutral::constructPDSSXML", "no Thermo::neutralSpeciesMultipliers Node for species " + speciesNode.name()); } IonsFromNeutralVPSSTP *ionPhase = dynamic_cast<IonsFromNeutralVPSSTP *>(tp); if (!ionPhase) { throw CanteraError("PDSS_IonsFromNeutral::constructPDSSXML", "Dynamic cast failed"); } neutralMoleculePhase_ = ionPhase->neutralMoleculePhase_; std::vector<std::string> key; std::vector<std::string> val; /* * */ numMult_ = ctml::getPairs(*nsm, key, val); idNeutralMoleculeVec.resize(numMult_); factorVec.resize(numMult_); tmpNM.resize(neutralMoleculePhase_->nSpecies()); for (int i = 0; i < numMult_; i++) { idNeutralMoleculeVec[i] = neutralMoleculePhase_->speciesIndex(key[i]); factorVec[i] = fpValueCheck(val[i]); } specialSpecies_ = 0; const XML_Node *ss = tn->findByName("specialSpecies"); if (ss) { specialSpecies_ = 1; } const XML_Node *sss = tn->findByName("secondSpecialSpecies"); if (sss) { specialSpecies_ = 2; } add2RTln2_ = true; if (specialSpecies_ == 1) { add2RTln2_ = false; } }
doublereal strSItoDbl(const std::string& strSI) { std::vector<std::string> v; tokenizeString(strSI, v); doublereal fp = 1.0; size_t n = v.size(); if (n > 2 || n < 1) { throw CanteraError("strSItoDbl", "number of tokens is too high"); } else if (n == 2) { fp = toSI(v[1]); } doublereal val = fpValueCheck(v[0]); return val * fp; }
int fillArrayFromString(const std::string& str, doublereal* const a, const char delim) { warn_deprecated("fillArrayFromString", "To be removed after Cantera 2.2."); std::string::size_type iloc; int count = 0; std::string num; std::string s = str; while (s.size() > 0) { iloc = s.find(delim); if (iloc > 0) { num = s.substr(0, iloc); s = s.substr(iloc+1,s.size()); } else { num = s; s = ""; } a[count] = fpValueCheck(num); count++; } return count; }
compositionMap parseCompString(const std::string& ss, const std::vector<std::string>& names) { compositionMap x; for (size_t k = 0; k < names.size(); k++) { x[names[k]] = 0.0; } size_t start = 0; size_t stop = 0; size_t left = 0; while (stop < ss.size()) { size_t colon = ss.find(':', left); if (colon == npos) { break; } size_t valstart = ss.find_first_not_of(" \t\n", colon+1); stop = ss.find_first_of(", ;\n\t", valstart); std::string name = ba::trim_copy(ss.substr(start, colon-start)); if (!names.empty() && x.find(name) == x.end()) { throw CanteraError("parseCompString", "unknown species '" + name + "'"); } double value; try { value = fpValueCheck(ss.substr(valstart, stop-valstart)); } catch (CanteraError&) { // If we have a key containing a colon, we expect this to fail. In // this case, take the current substring as part of the key and look // to the right of the next colon for the corresponding value. // Otherwise, this is an invalid composition string. std::string testname = ss.substr(start, stop-start); if (testname.find_first_of(" \n\t") != npos) { // Space, tab, and newline are never allowed in names throw; } else if (ss.substr(valstart, stop-valstart).find(':') != npos) { left = colon + 1; stop = 0; // Force another iteration of this loop continue; } else { throw; } } if (getValue(x, name, 0.0) != 0.0) { throw CanteraError("parseCompString", "Duplicate key: '" + name + "'."); } x[name] = value; start = ss.find_first_not_of(", ;\n\t", stop+1); left = start; } if (left != start) { throw CanteraError("parseCompString", "Unable to parse key-value pair:" "\n'{}'", ss.substr(start, stop)); } if (stop != npos && !ba::trim_copy(ss.substr(stop)).empty()) { throw CanteraError("parseCompString", "Found non-key:value data " "in composition string: '" + ss.substr(stop) + "'"); } return x; }
size_t Phase::addElement(const std::string& symbol, doublereal weight, int atomic_number, doublereal entropy298, int elem_type) { // Look up the atomic weight if not given if (weight == 0.0) { try { weight = getElementWeight(symbol); } catch (CanteraError&) { // assume this is just a custom element with zero atomic weight } } else if (weight == -12345.0) { weight = getElementWeight(symbol); } // Try to look up the standard entropy if not given. Fail silently. if (entropy298 == ENTROPY298_UNKNOWN) { try { XML_Node* db = get_XML_File("elements.xml"); XML_Node* elnode = db->findByAttr("name", symbol); if (elnode && elnode->hasChild("entropy298")) { entropy298 = fpValueCheck(elnode->child("entropy298")["value"]); } } catch (CanteraError&) { } } // Check for duplicates auto iter = find(m_elementNames.begin(), m_elementNames.end(), symbol); if (iter != m_elementNames.end()) { size_t m = iter - m_elementNames.begin(); if (m_atomicWeights[m] != weight) { throw CanteraError("Phase::addElement", "Duplicate elements ({}) have different weights", symbol); } else { // Ignore attempt to add duplicate element with the same weight return m; } } // Add the new element m_atomicWeights.push_back(weight); m_elementNames.push_back(symbol); m_atomicNumbers.push_back(atomic_number); m_entropy298.push_back(entropy298); if (symbol == "E") { m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); } else { m_elem_type.push_back(elem_type); } m_mm++; // Update species compositions if (m_kk) { vector_fp old(m_speciesComp); m_speciesComp.resize(m_kk*m_mm, 0.0); for (size_t k = 0; k < m_kk; k++) { size_t m_old = m_mm - 1; for (size_t m = 0; m < m_old; m++) { m_speciesComp[k * m_mm + m] = old[k * (m_old) + m]; } m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0; } } return m_mm-1; }
void getMatrixValues(const XML_Node& node, const std::vector<std::string>& keyStringRow, const std::vector<std::string>& keyStringCol, Array2D& retnValues, const bool convert, const bool matrixSymmetric) { if (keyStringRow.size() > retnValues.nRows()) { throw CanteraError("getMatrixValues", "size of key1 greater than numrows"); } else if (keyStringCol.size() > retnValues.nColumns()) { throw CanteraError("getMatrixValues", "size of key2 greater than num cols"); } else if (matrixSymmetric && retnValues.nRows() != retnValues.nColumns()) { throw CanteraError("getMatrixValues", "nrow != ncol for a symmetric matrix"); } /* * Get the attributes field, units, from the XML node * and determine the conversion factor, funit. */ doublereal funit = 1.0; if (convert && node["units"] != "") { funit = toSI(node["units"]); } vector<string> v; getStringArray(node, v); for (size_t i = 0; i < v.size(); i++) { size_t icolon = v[i].find(":"); if (icolon == string::npos) { throw CanteraError("getMatrixValues","Missing two colons (" +v[i]+")"); } string key1 = v[i].substr(0,icolon); string rmm = v[i].substr(icolon+1, v[i].size()); icolon = rmm.find(":"); if (icolon == string::npos) { throw CanteraError("getMatrixValues","Missing one colon (" +v[i]+")"); } size_t irow = find(keyStringRow.begin(), keyStringRow.end(), key1) - keyStringRow.begin(); if (irow == keyStringRow.size()) { throw CanteraError("getMatrixValues","Row not matched by string: " + key1); } string key2 = rmm.substr(0,icolon); size_t icol = find(keyStringCol.begin(), keyStringCol.end(), key2) - keyStringCol.begin(); if (icol == keyStringCol.size()) { throw CanteraError("getMatrixValues","Col not matched by string: " + key2); } double dval = fpValueCheck(rmm.substr(icolon+1, rmm.size())) * funit; /* * Finally, insert the value; */ retnValues(irow, icol) = dval; if (matrixSymmetric) { retnValues(icol, irow) = dval; } } }
size_t getFloatArray(const XML_Node& node, std::vector<doublereal> & v, const bool convert, const std::string& unitsString, const std::string& nodeName) { const XML_Node* readNode = &node; if (node.name() != nodeName) { vector<XML_Node*> ll = node.getChildren(nodeName); if (ll.size() == 0) { throw CanteraError("getFloatArray", "wrong XML element type/name: was expecting " + nodeName + "but accessed " + node.name()); } else { readNode = ll[0]; ll = readNode->getChildren("floatArray"); if (ll.size() > 0) { readNode = ll[0]; } } } v.clear(); doublereal vmin = Undef, vmax = Undef; doublereal funit = 1.0; /* * Get the attributes field, units, from the XML node */ std::string units = readNode->attrib("units"); if (units != "" && convert) { if (unitsString == "actEnergy" && units != "") { funit = actEnergyToSI(units); } else if (unitsString != "" && units != "") { funit = toSI(units); } } if (readNode->attrib("min") != "") { vmin = fpValueCheck(readNode->attrib("min")); } if (readNode->attrib("max") != "") { vmax = fpValueCheck(readNode->attrib("max")); } std::string val = readNode->value(); while (true) { size_t icom = val.find(','); if (icom != string::npos) { string numstr = val.substr(0,icom); val = val.substr(icom+1,val.size()); v.push_back(fpValueCheck(numstr)); } else { /* * This little bit of code is to allow for the * possibility of a comma being the last * item in the value text. This was allowed in * previous versions of Cantera, even though it * would appear to be odd. So, we keep the * possibility in for backwards compatibility. */ if (!val.empty()) { v.push_back(fpValueCheck(val)); } break; } doublereal vv = v.back(); if (vmin != Undef && vv < vmin - Tiny) { writelog("\nWarning: value "+fp2str(vv)+ " is below lower limit of " +fp2str(vmin)+".\n"); } if (vmax != Undef && vv > vmax + Tiny) { writelog("\nWarning: value "+fp2str(vv)+ " is above upper limit of " +fp2str(vmin)+".\n"); } } for (size_t n = 0; n < v.size(); n++) { v[n] *= funit; } return v.size(); }
bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, SpeciesThermo* spthermo_ptr, int rule, XML_Node* phaseNode_ptr, VPSSMgr* vpss_ptr, SpeciesThermoFactory* factory) { std::string xname = s.name(); if (xname != "species") { throw CanteraError("installSpecies", "Unexpected XML name of species XML_Node: " + xname); } // get the composition of the species const XML_Node& a = s.child("atomArray"); map<string,string> comp; getMap(a, comp); // check that all elements in the species exist in 'p'. If rule != 0, // quietly skip this species if some elements are undeclared; otherwise, // throw an exception map<string,string>::const_iterator _b = comp.begin(); for (; _b != comp.end(); ++_b) { if (th.elementIndex(_b->first) == npos) { if (rule == 0) { throw CanteraError("installSpecies", "Species " + s["name"] + " contains undeclared element " + _b->first); } else { return false; } } } // construct a vector of atom numbers for each element in phase th. Elements // not declared in the species (i.e., not in map comp) will have zero // entries in the vector. size_t nel = th.nElements(); vector_fp ecomp(nel, 0.0); for (size_t m = 0; m < nel; m++) { std::string& es = comp[th.elementName(m)]; if (!es.empty()) { ecomp[m] = fpValueCheck(es); } } // get the species charge, if any. Note that the charge need // not be explicitly specified if special element 'E' // (electron) is one of the elements. doublereal chrg = 0.0; if (s.hasChild("charge")) { chrg = getFloat(s, "charge"); } // get the species size, if any. (This is used by surface // phases to represent how many sites a species occupies.) doublereal sz = 1.0; if (s.hasChild("size")) { sz = getFloat(s, "size"); } // add the species to phase th th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); if (vpss_ptr) { VPStandardStateTP* vp_ptr = dynamic_cast<VPStandardStateTP*>(&th); factory->installVPThermoForSpecies(k, s, vp_ptr, phaseNode_ptr); } else { // install the thermo parameterization for this species into // the species thermo manager for phase th factory->installThermoForSpecies(k, s, &th, *spthermo_ptr, phaseNode_ptr); } return true; }
bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, SpeciesThermo* spthermo_ptr, int rule, XML_Node* phaseNode_ptr, VPSSMgr* vpss_ptr, SpeciesThermoFactory* factory) { std::string xname = s.name(); if (xname != "species") { throw CanteraError("installSpecies", "Unexpected XML name of species XML_Node: " + xname); } if (rule) { th.ignoreUndefinedElements(); } // get the composition of the species const XML_Node& a = s.child("atomArray"); map<string,string> comp; getMap(a, comp); // construct a vector of atom numbers for each element in phase th. Elements // not declared in the species (i.e., not in map comp) will have zero // entries in the vector. size_t nel = th.nElements(); vector_fp ecomp(nel, 0.0); compositionMap comp_map = parseCompString(a.value()); for (size_t m = 0; m < nel; m++) { std::string& es = comp[th.elementName(m)]; if (!es.empty()) { ecomp[m] = fpValueCheck(es); } } // get the species charge, if any. Note that the charge need // not be explicitly specified if special element 'E' // (electron) is one of the elements. doublereal chrg = 0.0; if (s.hasChild("charge")) { chrg = getFloat(s, "charge"); } // get the species size, if any. (This is used by surface // phases to represent how many sites a species occupies.) doublereal sz = 1.0; if (s.hasChild("size")) { sz = getFloat(s, "size"); } if (vpss_ptr) { th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); VPStandardStateTP* vp_ptr = dynamic_cast<VPStandardStateTP*>(&th); vp_ptr->createInstallPDSS(k, s, phaseNode_ptr); } else { SpeciesThermoInterpType* st = newSpeciesThermoInterpType(s); Species sp(s["name"], comp_map, st, chrg, sz); // Read gas-phase transport data, if provided if (s.hasChild("transport") && s.child("transport")["model"] == "gas_transport") { XML_Node& tr = s.child("transport"); string geometry, dummy; getString(tr, "geometry", geometry, dummy); double diam = getFloat(tr, "LJ_diameter"); double welldepth = getFloat(tr, "LJ_welldepth"); double dipole = 0.0; getOptionalFloat(tr, "dipoleMoment", dipole); double polar = 0.0; getOptionalFloat(tr, "polarizability", polar); double rot = 0.0; getOptionalFloat(tr, "rotRelax", rot); double acentric = 0.0; getOptionalFloat(tr, "acentric_factor", acentric); GasTransportData* gastran = new GasTransportData; gastran->setCustomaryUnits(sp.name, geometry, diam, welldepth, dipole, polar, rot, acentric); sp.transport.reset(gastran); gastran->validate(sp); } th.addSpecies(sp); } return true; }