/* * constructPDSSXML: * * Initialization of a PDSS_ConstVol object using an * xml file. * * This routine is a precursor to initThermo(XML_Node*) * routine, which does most of the work. * * @param infile XML file containing the description of the * phase * * @param id Optional parameter identifying the name of the * phase. If none is given, the first XML * phase element will be used. */ void PDSS_ConstVol::constructPDSSXML(VPStandardStateTP *tp, int spindex, const XML_Node& speciesNode, const XML_Node& phaseNode, bool spInstalled) { PDSS::initThermo(); SpeciesThermo &sp = m_tp->speciesThermo(); m_p0 = sp.refPressure(m_spindex); if (!spInstalled) { throw CanteraError("PDSS_ConstVol::constructPDSSXML", "spInstalled false not handled"); } const XML_Node *ss = speciesNode.findByName("standardState"); if (!ss) { throw CanteraError("PDSS_ConstVol::constructPDSSXML", "no standardState Node for species " + speciesNode.name()); } std::string model = (*ss)["model"]; if (model != "constant_incompressible") { throw CanteraError("PDSS_ConstVol::initThermoXML", "standardState model for species isn't constant_incompressible: " + speciesNode.name()); } m_constMolarVolume = ctml::getFloat(*ss, "molarVolume", "toSI"); std::string id = ""; // initThermoXML(phaseNode, id); }
/** * 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 getFloatCurrent(const XML_Node& node, const std::string& type) { doublereal fctr = 1.0; doublereal x = node.fp_value(); const string& units = node["units"]; const string& vmin = node["min"]; const string& vmax = node["max"]; if (vmin != "" && x < fpValue(vmin) - Tiny) { writelog("\nWarning: value "+node.value()+" is below lower limit of " +vmin+".\n"); } if (node["max"] != "" && x > fpValue(vmax) + Tiny) { writelog("\nWarning: value "+node.value()+" is above upper limit of " +vmax+".\n"); } // Note, most types of converters default to toSI() type atm. // This may change and become more specific in the future. if (type == "actEnergy" && units != "") { fctr = actEnergyToSI(units); } else if (type == "toSI" && units != "") { fctr = toSI(units); } else if (type == "temperature" && units != "") { fctr = toSI(units); } else if (type == "density" && units != "") { fctr = toSI(units); } else if (type == "pressure" && units != "") { fctr = toSI(units); } else if (type != "" && units != "") { fctr = toSI(units); #ifdef DEBUG_MODE writelog("\nWarning: conversion toSI() was done on node value " + node.name() + "but wasn't explicitly requested. Type was \"" + type + "\"\n"); #endif } // Note, below currently produces a lot of output due to transport blocks. // This needs to be addressed. #ifdef DEBUG_MODE_MORE else if (type == "" && units != "") { writelog("\nWarning: XML node " + node.name() + "has a units attribute, \"" + units + "\"," "but no conversion was done because the getFloat() command didn't have a type\n"); } #endif return fctr*x; }
doublereal getFloat(const XML_Node& parent, const std::string& name, const std::string& type) { if (!parent.hasChild(name)) throw CanteraError("getFloat (called from XML Node \"" + parent.name() + "\"): ", "no child XML element named \"" + name + "\" exists"); const XML_Node& node = parent.child(name); return getFloatCurrent(node, type); }
/* * constructPDSSXML: * * Initialization of a PDSS_SSVol object using an * xml file. * * This routine is a precursor to initThermo(XML_Node*) * routine, which does most of the work. * * @param infile XML file containing the description of the * phase * * @param id Optional parameter identifying the name of the * phase. If none is given, the first XML * phase element will be used. */ void PDSS_SSVol::constructPDSSXML(VPStandardStateTP *tp, int spindex, const XML_Node& speciesNode, const XML_Node& phaseNode, bool spInstalled) { PDSS::initThermo(); SpeciesThermo &sp = m_tp->speciesThermo(); m_p0 = sp.refPressure(m_spindex); if (!spInstalled) { throw CanteraError("PDSS_SSVol::constructPDSSXML", "spInstalled false not handled"); } const XML_Node *ss = speciesNode.findByName("standardState"); if (!ss) { throw CanteraError("PDSS_SSVol::constructPDSSXML", "no standardState Node for species " + speciesNode.name()); } std::string model = (*ss)["model"]; if (model == "constant_incompressible" || model == "constant") { volumeModel_ = cSSVOLUME_CONSTANT; m_constMolarVolume = ctml::getFloat(*ss, "molarVolume", "toSI"); } else if (model == "temperature_polynomial") { volumeModel_ = cSSVOLUME_TPOLY; int num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "volumeTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); } } else if (model == "density_temperature_polynomial") { volumeModel_ = cSSVOLUME_DENSITY_TPOLY; int num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "densityTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); } } else { throw CanteraError("PDSS_SSVol::constructPDSSXML", "standardState model for species isn't constant_incompressible: " + speciesNode.name()); } std::string id = ""; }
void getString(const XML_Node& node, const std::string& titleString, std::string& valueString, std::string& typeString) { XML_Node* s = getByTitle(node, titleString); if (s && s->name() == "string") { valueString = s->value(); typeString = s->attrib("type"); } else { valueString = ""; typeString = ""; } }
/* * This function will read a child node to the current XML node, with the * name "string". It must have a title attribute, named titleString, and the body * of the XML node will be read into the valueString output argument. * * Example: * * Code snipet: * @verbatum const XML_Node &node; getString(XML_Node& node, std::string titleString, std::string valueString, std::string typeString); @endverbatum * * Reads the following the snippet in the XML file: * @verbatum <string title="titleString" type="typeString"> valueString <\string> @endverbatum * * @param node reference to the XML_Node object of the parent XML element * @param titleString String name of the title attribute of the child node * @param valueString Value string that is found in the child node. output variable * @param typeString String type. This is an optional output variable */ void getString(const Cantera::XML_Node& node, const std::string &titleString, std::string& valueString, std::string& typeString) { valueString = ""; typeString = ""; XML_Node* s = getByTitle(node, titleString); if (s) if (s->name() == "string") { valueString = (*s).value(); typeString = (*s)["type"]; return; } }
/* The transport property is constructed from the XML node, * \verbatim <propNode>, \endverbatim that is a child of the * \verbatim <transport> \endverbatim node and specifies a type of * transport property (like viscosity) */ LTPspecies_Const::LTPspecies_Const(const XML_Node& propNode, const std::string name, TransportPropertyType tp_ind, const thermo_t* const thermo) : LTPspecies(&propNode, name, tp_ind, thermo) { m_model = LTP_TD_CONSTANT; double A_k = getFloatCurrent(propNode, "toSI"); if (A_k > 0.0) { m_coeffs.push_back(A_k); } else { throw LTPError("negative or zero " + propNode.name()); } }
LTPspecies_Arrhenius::LTPspecies_Arrhenius(const XML_Node& propNode, const std::string name, TransportPropertyType tp_ind, const thermo_t* thermo) : LTPspecies(&propNode, name, tp_ind, thermo) { m_model = LTP_TD_ARRHENIUS; m_temp = 0.0; m_prop = 0.0; doublereal A_k, n_k, Tact_k; getArrhenius(propNode, A_k, n_k, Tact_k); if (A_k <= 0.0) { throw LTPError("negative or zero " + propNode.name()); } m_coeffs.push_back(A_k); m_coeffs.push_back(n_k); m_coeffs.push_back(Tact_k); m_coeffs.push_back(log(A_k)); }
int getInteger(const XML_Node& parent, const std::string& name) { if (!parent.hasChild(name)) { throw CanteraError("getInteger (called from XML Node \"" + parent.name() + "\"): ", "no child XML element named " + name); } const XML_Node& node = parent.child(name); int x = node.int_value(); const string& vmin = node["min"]; const string& vmax = node["max"]; if (vmin != "" && x < intValue(vmin)) { writelog("\nWarning: value "+node.value()+" is below lower limit of " +vmin+".\n"); } if (node["max"] != "" && x > intValue(vmax)) { writelog("\nWarning: value "+node.value()+" is above upper limit of " +vmax+".\n"); } return x; }
void PDSS_ConstVol::constructPDSSXML(VPStandardStateTP* tp, size_t spindex, const XML_Node& speciesNode, const XML_Node& phaseNode, bool spInstalled) { PDSS::initThermo(); m_p0 = m_tp->speciesThermo().refPressure(m_spindex); if (!spInstalled) { throw CanteraError("PDSS_ConstVol::constructPDSSXML", "spInstalled false not handled"); } const XML_Node* ss = speciesNode.findByName("standardState"); if (!ss) { throw CanteraError("PDSS_ConstVol::constructPDSSXML", "no standardState Node for species " + speciesNode.name()); } if (ss->attrib("model") != "constant_incompressible") { throw CanteraError("PDSS_ConstVol::initThermoXML", "standardState model for species isn't constant_incompressible: " + speciesNode.name()); } m_constMolarVolume = getFloat(*ss, "molarVolume", "toSI"); }
void RedlichKisterVPSSTP::readXMLBinarySpecies(XML_Node& xmLBinarySpecies) { std::string xname = xmLBinarySpecies.name(); if (xname != "binaryNeutralSpeciesParameters") { throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "Incorrect name for processing this routine: " + xname); } size_t Npoly = 0; vector_fp hParams, sParams; std::string iName = xmLBinarySpecies.attrib("speciesA"); if (iName == "") { throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "no speciesA attrib"); } std::string jName = xmLBinarySpecies.attrib("speciesB"); if (jName == "") { throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "no speciesB attrib"); } /* * Find the index of the species in the current phase. It's not * an error to not find the species. This means that the interaction doesn't occur for the current * implementation of the phase. */ size_t iSpecies = speciesIndex(iName); if (iSpecies == npos) { return; } string ispName = speciesName(iSpecies); if (charge(iSpecies) != 0) { throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "speciesA charge problem"); } size_t jSpecies = speciesIndex(jName); if (jSpecies == npos) { return; } std::string jspName = speciesName(jSpecies); if (charge(jSpecies) != 0) { throw CanteraError("RedlichKisterVPSSTP::readXMLBinarySpecies", "speciesB charge problem"); } /* * Ok we have found a valid interaction */ numBinaryInteractions_++; size_t iSpot = numBinaryInteractions_ - 1; m_pSpecies_A_ij.resize(numBinaryInteractions_); m_pSpecies_B_ij.resize(numBinaryInteractions_); m_pSpecies_A_ij[iSpot] = iSpecies; m_pSpecies_B_ij[iSpot] = jSpecies; for (size_t iChild = 0; iChild < xmLBinarySpecies.nChildren(); iChild++) { XML_Node& xmlChild = xmLBinarySpecies.child(iChild); string nodeName = lowercase(xmlChild.name()); /* * Process the binary species interaction child elements */ if (nodeName == "excessenthalpy") { /* * Get the string containing all of the values */ getFloatArray(xmlChild, hParams, true, "toSI", "excessEnthalpy"); Npoly = std::max(hParams.size(), Npoly); } if (nodeName == "excessentropy") { /* * Get the string containing all of the values */ getFloatArray(xmlChild, sParams, true, "toSI", "excessEntropy"); Npoly = std::max(sParams.size(), Npoly); } } hParams.resize(Npoly, 0.0); sParams.resize(Npoly, 0.0); m_HE_m_ij.push_back(hParams); m_SE_m_ij.push_back(sParams); m_N_ij.push_back(Npoly); resizeNumInteractions(numBinaryInteractions_); }
void MolarityIonicVPSSTP::readXMLBinarySpecies(XML_Node& xmLBinarySpecies) { std::string xname = xmLBinarySpecies.name(); }
bool importPhase(XML_Node& phase, ThermoPhase* th, SpeciesThermoFactory* spfactory) { // Check the the supplied XML node in fact represents a phase. if (phase.name() != "phase") { throw CanteraError("importPhase", "Current const XML_Node named, " + phase.name() + ", is not a phase element."); } /* * In this section of code, we get the reference to the * phase xml tree within the ThermoPhase object. Then, * we clear it and fill it with the current information that * we are about to use to construct the object. We will then * be able to resurrect the information later by calling xml(). */ th->setXMLdata(phase); // set the id attribute of the phase to the 'id' attribute in the XML tree. th->setID(phase.id()); th->setName(phase.id()); // Number of spatial dimensions. Defaults to 3 (bulk phase) if (phase.hasAttrib("dim")) { int idim = intValue(phase["dim"]); if (idim < 1 || idim > 3) throw CanteraError("importPhase", "phase, " + th->id() + ", has unphysical number of dimensions: " + phase["dim"]); th->setNDim(idim); } else { th->setNDim(3); // default } // Set equation of state parameters. The parameters are // specific to each subclass of ThermoPhase, so this is done // by method setParametersFromXML in each subclass. const XML_Node& eos = phase.child("thermo"); if (phase.hasChild("thermo")) { th->setParametersFromXML(eos); } else { throw CanteraError("importPhase", " phase, " + th->id() + ", XML_Node does not have a \"thermo\" XML_Node"); } VPStandardStateTP* vpss_ptr = 0; int ssConvention = th->standardStateConvention(); if (ssConvention == cSS_CONVENTION_VPSS) { vpss_ptr = dynamic_cast <VPStandardStateTP*>(th); if (vpss_ptr == 0) { throw CanteraError("importPhase", "phase, " + th->id() + ", was VPSS, but dynamic cast failed"); } } // if no species thermo factory was supplied, use the default one. if (!spfactory) { spfactory = SpeciesThermoFactory::factory(); } /*************************************************************** * Add the elements. ***************************************************************/ if (ssConvention != cSS_CONVENTION_SLAVE) { installElements(*th, phase); } /*************************************************************** * Add the species. * * Species definitions may be imported from multiple * sources. For each one, a speciesArray element must be * present. ***************************************************************/ vector<XML_Node*> sparrays; phase.getChildren("speciesArray", sparrays); if (ssConvention != cSS_CONVENTION_SLAVE) { if (sparrays.empty()) { throw CanteraError("importPhase", "phase, " + th->id() + ", has zero \"speciesArray\" XML nodes.\n" + " There must be at least one speciesArray nodes " "with one or more species"); } } vector<XML_Node*> dbases; vector_int sprule(sparrays.size(),0); // loop over the speciesArray elements for (size_t jsp = 0; jsp < sparrays.size(); jsp++) { const XML_Node& speciesArray = *sparrays[jsp]; // If the speciesArray element has a child element // // <skip element="undeclared"> // // then set sprule[jsp] to 1, so that any species with an undeclared // element will be quietly skipped when importing species. Additionally, // if the skip node has the following attribute: // // <skip species="duplicate"> // // then duplicate species names will not cause Cantera to throw an // exception. Instead, the duplicate entry will be discarded. if (speciesArray.hasChild("skip")) { const XML_Node& sk = speciesArray.child("skip"); string eskip = sk["element"]; if (eskip == "undeclared") { sprule[jsp] = 1; } string dskip = sk["species"]; if (dskip == "duplicate") { sprule[jsp] += 10; } } // Get a pointer to the node containing the species // definitions for the species declared in this // speciesArray element. This may be in the local file // containing the phase element, or may be in another // file. XML_Node* db = get_XML_Node(speciesArray["datasrc"], &phase.root()); if (db == 0) { throw CanteraError("importPhase()", " Can not find XML node for species database: " + speciesArray["datasrc"]); } // add this node to the list of species database nodes. dbases.push_back(db); } // Now, collect all the species names and all the XML_Node * pointers // for those species in a single vector. This is where we decide what // species are to be included in the phase. // The logic is complicated enough that we put it in a separate routine. std::vector<XML_Node*> spDataNodeList; std::vector<std::string> spNamesList; std::vector<int> spRuleList; formSpeciesXMLNodeList(spDataNodeList, spNamesList, spRuleList, sparrays, dbases, sprule); // Decide whether the the phase has a variable pressure ss or not SpeciesThermo* spth = 0; VPSSMgr* vp_spth = 0; if (ssConvention == cSS_CONVENTION_TEMPERATURE) { // Create a new species thermo manager. Function // 'newSpeciesThermoMgr' looks at the species in the database // to see what thermodynamic property parameterizations are // used, and selects a class that can handle the // parameterizations found. spth = newSpeciesThermoMgr(spDataNodeList); // install it in the phase object th->setSpeciesThermo(spth); } else if (ssConvention == cSS_CONVENTION_SLAVE) { /* * No species thermo manager for this type */ } else if (ssConvention == cSS_CONVENTION_VPSS) { vp_spth = newVPSSMgr(vpss_ptr, &phase, spDataNodeList); vpss_ptr->setVPSSMgr(vp_spth); spth = vp_spth->SpeciesThermoMgr(); th->setSpeciesThermo(spth); } else { throw CanteraError("importPhase()", "unknown convention"); } size_t k = 0; size_t nsp = spDataNodeList.size(); if (ssConvention == cSS_CONVENTION_SLAVE) { if (nsp > 0) { throw CanteraError("importPhase()", "For Slave standard states, number of species must be zero: " + int2str(nsp)); } } for (size_t i = 0; i < nsp; i++) { XML_Node* s = spDataNodeList[i]; AssertTrace(s != 0); bool ok = installSpecies(k, *s, *th, spth, spRuleList[i], &phase, vp_spth, spfactory); if (ok) { th->saveSpeciesData(k, s); ++k; } } if (ssConvention == cSS_CONVENTION_SLAVE) { th->installSlavePhases(&phase); } // Done adding species. Perform any required subclass-specific // initialization. th->initThermo(); // Perform any required subclass-specific initialization // that requires the XML phase object std::string id = ""; th->initThermoXML(phase, id); 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; }
void MixedSolventElectrolyte::readXMLBinarySpecies(XML_Node& xmLBinarySpecies) { string xname = xmLBinarySpecies.name(); if (xname != "binaryNeutralSpeciesParameters") { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "Incorrect name for processing this routine: " + xname); } string stemp; size_t nParamsFound; vector_fp vParams; string iName = xmLBinarySpecies.attrib("speciesA"); if (iName == "") { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesA attrib"); } string jName = xmLBinarySpecies.attrib("speciesB"); if (jName == "") { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesB attrib"); } /* * Find the index of the species in the current phase. It's not * an error to not find the species */ size_t iSpecies = speciesIndex(iName); if (iSpecies == npos) { return; } string ispName = speciesName(iSpecies); if (charge(iSpecies) != 0) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesA charge problem"); } size_t jSpecies = speciesIndex(jName); if (jSpecies == npos) { return; } string jspName = speciesName(jSpecies); if (charge(jSpecies) != 0) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesB charge problem"); } resizeNumInteractions(numBinaryInteractions_ + 1); size_t iSpot = numBinaryInteractions_ - 1; m_pSpecies_A_ij[iSpot] = iSpecies; m_pSpecies_B_ij[iSpot] = jSpecies; size_t num = xmLBinarySpecies.nChildren(); for (size_t iChild = 0; iChild < num; iChild++) { XML_Node& xmlChild = xmLBinarySpecies.child(iChild); stemp = xmlChild.name(); string nodeName = lowercase(stemp); /* * Process the binary species interaction child elements */ if (nodeName == "excessenthalpy") { /* * Get the string containing all of the values */ ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEnthalpy for " + ispName + "::" + jspName, "wrong number of params found"); } m_HE_b_ij[iSpot] = vParams[0]; m_HE_c_ij[iSpot] = vParams[1]; } if (nodeName == "excessentropy") { /* * Get the string containing all of the values */ ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEntropy for " + ispName + "::" + jspName, "wrong number of params found"); } m_SE_b_ij[iSpot] = vParams[0]; m_SE_c_ij[iSpot] = vParams[1]; } if (nodeName == "excessvolume_enthalpy") { /* * Get the string containing all of the values */ ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName + "::" + jspName, "wrong number of params found"); } m_VHE_b_ij[iSpot] = vParams[0]; m_VHE_c_ij[iSpot] = vParams[1]; } if (nodeName == "excessvolume_entropy") { /* * Get the string containing all of the values */ ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); nParamsFound = vParams.size(); if (nParamsFound != 2) { throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Entropy for " + ispName + "::" + jspName, "wrong number of params found"); } m_VSE_b_ij[iSpot] = vParams[0]; m_VSE_c_ij[iSpot] = vParams[1]; } } }
void importPhase(XML_Node& phase, ThermoPhase* th) { // Check the the supplied XML node in fact represents a phase. if (phase.name() != "phase") { throw CanteraError("importPhase", "Current const XML_Node named, " + phase.name() + ", is not a phase element."); } // In this section of code, we get the reference to the phase XML tree // within the ThermoPhase object. Then, we clear it and fill it with the // current information that we are about to use to construct the object. We // will then be able to resurrect the information later by calling xml(). th->setXMLdata(phase); // set the id attribute of the phase to the 'id' attribute in the XML tree. th->setID(phase.id()); th->setName(phase.id()); // Number of spatial dimensions. Defaults to 3 (bulk phase) if (phase.hasAttrib("dim")) { int idim = intValue(phase["dim"]); if (idim < 1 || idim > 3) { throw CanteraError("importPhase", "phase, " + th->id() + ", has unphysical number of dimensions: " + phase["dim"]); } th->setNDim(idim); } else { th->setNDim(3); // default } // Set equation of state parameters. The parameters are specific to each // subclass of ThermoPhase, so this is done by method setParametersFromXML // in each subclass. const XML_Node& eos = phase.child("thermo"); if (phase.hasChild("thermo")) { th->setParametersFromXML(eos); } else { throw CanteraError("importPhase", " phase, " + th->id() + ", XML_Node does not have a \"thermo\" XML_Node"); } VPStandardStateTP* vpss_ptr = 0; int ssConvention = th->standardStateConvention(); if (ssConvention == cSS_CONVENTION_VPSS) { vpss_ptr = dynamic_cast <VPStandardStateTP*>(th); if (vpss_ptr == 0) { throw CanteraError("importPhase", "phase, " + th->id() + ", was VPSS, but dynamic cast failed"); } } // Add the elements. if (ssConvention != cSS_CONVENTION_SLAVE) { installElements(*th, phase); } // Add the species. // // Species definitions may be imported from multiple sources. For each one, // a speciesArray element must be present. vector<XML_Node*> sparrays = phase.getChildren("speciesArray"); if (ssConvention != cSS_CONVENTION_SLAVE && sparrays.empty()) { throw CanteraError("importPhase", "phase, " + th->id() + ", has zero \"speciesArray\" XML nodes.\n" + " There must be at least one speciesArray nodes " "with one or more species"); } vector<XML_Node*> dbases; vector_int sprule(sparrays.size(),0); // Default behavior when importing from CTI/XML is for undefined elements to // be treated as an error th->throwUndefinedElements(); // loop over the speciesArray elements for (size_t jsp = 0; jsp < sparrays.size(); jsp++) { const XML_Node& speciesArray = *sparrays[jsp]; // If the speciesArray element has a child element // // <skip element="undeclared"> // // then set sprule[jsp] to 1, so that any species with an undeclared // element will be quietly skipped when importing species. Additionally, // if the skip node has the following attribute: // // <skip species="duplicate"> // // then duplicate species names will not cause Cantera to throw an // exception. Instead, the duplicate entry will be discarded. if (speciesArray.hasChild("skip")) { const XML_Node& sk = speciesArray.child("skip"); string eskip = sk["element"]; if (eskip == "undeclared") { sprule[jsp] = 1; } string dskip = sk["species"]; if (dskip == "duplicate") { sprule[jsp] += 10; } } // Get a pointer to the node containing the species definitions for the // species declared in this speciesArray element. This may be in the // local file containing the phase element, or may be in another file. XML_Node* db = get_XML_Node(speciesArray["datasrc"], &phase.root()); if (db == 0) { throw CanteraError("importPhase()", " Can not find XML node for species database: " + speciesArray["datasrc"]); } // add this node to the list of species database nodes. dbases.push_back(db); } // Now, collect all the species names and all the XML_Node * pointers for // those species in a single vector. This is where we decide what species // are to be included in the phase. The logic is complicated enough that we // put it in a separate routine. std::vector<XML_Node*> spDataNodeList; std::vector<std::string> spNamesList; vector_int spRuleList; formSpeciesXMLNodeList(spDataNodeList, spNamesList, spRuleList, sparrays, dbases, sprule); size_t nsp = spDataNodeList.size(); if (ssConvention == cSS_CONVENTION_SLAVE && nsp > 0) { throw CanteraError("importPhase()", "For Slave standard states, " "number of species must be zero: {}", nsp); } for (size_t k = 0; k < nsp; k++) { XML_Node* s = spDataNodeList[k]; AssertTrace(s != 0); if (spRuleList[k]) { th->ignoreUndefinedElements(); } th->addSpecies(newSpecies(*s)); if (vpss_ptr) { const XML_Node* const ss = s->findByName("standardState"); std::string ss_model = (ss) ? ss->attrib("model") : "ideal-gas"; unique_ptr<PDSS> kPDSS(newPDSS(ss_model)); kPDSS->setParametersFromXML(*s); vpss_ptr->installPDSS(k, std::move(kPDSS)); } th->saveSpeciesData(k, s); } // Done adding species. Perform any required subclass-specific // initialization. th->initThermo(); // Perform any required subclass-specific initialization that requires the // XML phase object std::string id = ""; th->initThermoXML(phase, id); }
void MargulesVPSSTP::readXMLBinarySpecies(XML_Node& xmLBinarySpecies) { string xname = xmLBinarySpecies.name(); if (xname != "binaryNeutralSpeciesParameters") { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies", "Incorrect name for processing this routine: " + xname); } string aName = xmLBinarySpecies.attrib("speciesA"); if (aName == "") { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies", "no speciesA attrib"); } string bName = xmLBinarySpecies.attrib("speciesB"); if (bName == "") { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies", "no speciesB attrib"); } vector_fp vParams; double h0 = 0.0; double h1 = 0.0; double s0 = 0.0; double s1 = 0.0; double vh0 = 0.0; double vh1 = 0.0; double vs0 = 0.0; double vs1 = 0.0; for (size_t iChild = 0; iChild < xmLBinarySpecies.nChildren(); iChild++) { XML_Node& xmlChild = xmLBinarySpecies.child(iChild); string nodeName = toLowerCopy(xmlChild.name()); // Process the binary species interaction parameters. // They are in subblocks labeled: // excessEnthalpy // excessEntropy // excessVolume_Enthalpy // excessVolume_Entropy // Other blocks are currently ignored. // @TODO determine a policy about ignoring blocks that should or shouldn't be there. if (nodeName == "excessenthalpy") { // Get the string containing all of the values getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy"); if (vParams.size() != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies" "excessEnthalpy for {} : {}: wrong number of params found." " Need 2", aName, bName); } h0 = vParams[0]; h1 = vParams[1]; } else if (nodeName == "excessentropy") { // Get the string containing all of the values getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy"); if (vParams.size() != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies" "excessEntropy for {} : {}: wrong number of params found." " Need 2", aName, bName); } s0 = vParams[0]; s1 = vParams[1]; } else if (nodeName == "excessvolume_enthalpy") { // Get the string containing all of the values getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy"); if (vParams.size() != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies" "excessVolume_Enthalpy for {} : {}: wrong number of params" " found. Need 2", aName, bName); } vh0 = vParams[0]; vh1 = vParams[1]; } else if (nodeName == "excessvolume_entropy") { // Get the string containing all of the values getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy"); if (vParams.size() != 2) { throw CanteraError("MargulesVPSSTP::readXMLBinarySpecies" "excessVolume_Entropy for {} : {}: wrong number of params" " found. Need 2", aName, bName); } vs0 = vParams[0]; vs1 = vParams[1]; } } addBinaryInteraction(aName, bName, h0, h1, s0, s1, vh0, vh1, vs0, vs1); }
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; }
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(); }