/** * 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 = 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; } }
void LatticePhase::initThermoXML(XML_Node& phaseNode, const std::string& id_) { if (!id_.empty() && id_ != phaseNode.id()) { throw CanteraError("LatticePhase::initThermoXML", "ids don't match"); } // Check on the thermo field. Must have: // <thermo model="Lattice" /> if (phaseNode.hasChild("thermo")) { XML_Node& thNode = phaseNode.child("thermo"); std::string mString = thNode.attrib("model"); if (lowercase(mString) != "lattice") { throw CanteraError("LatticePhase::initThermoXML", "Unknown thermo model: " + mString); } } else { throw CanteraError("LatticePhase::initThermoXML", "Unspecified thermo model"); } // Now go get the molar volumes. use the default if not found XML_Node& speciesList = phaseNode.child("speciesArray"); XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"], &phaseNode.root()); for (size_t k = 0; k < m_kk; k++) { m_speciesMolarVolume[k] = m_site_density; XML_Node* s = speciesDB->findByAttr("name", speciesName(k)); if (!s) { throw CanteraError(" LatticePhase::initThermoXML", "database problems"); } XML_Node* ss = s->findByName("standardState"); if (ss && ss->findByName("molarVolume")) { m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI"); } } // Call the base initThermo, which handles setting the initial state. ThermoPhase::initThermoXML(phaseNode, id_); }
/* * 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 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"); }
TransportFromScratch() : sH2(new Species("H2", parseCompString("H:2"))) , sO2(new Species("O2", parseCompString("O:2"))) , sH2O(new Species("H2O", parseCompString("H:2 O:1"))) , tH2(new GasTransportData()) , tO2(new GasTransportData()) , tH2O(new GasTransportData()) { sH2->thermo.reset(new NasaPoly2(200, 3500, 101325, h2_nasa_coeffs)); sO2->thermo.reset(new NasaPoly2(200, 3500, 101325, o2_nasa_coeffs)); sH2O->thermo.reset(new NasaPoly2(200, 3500, 101325, h2o_nasa_coeffs)); tH2->setCustomaryUnits("linear", 2.92, 38.0, 0.0, 0.79, 280.0); tO2->setCustomaryUnits("linear", 3.46, 107.40, 0.0, 1.60, 3.80); tH2O->setCustomaryUnits("nonlinear", 2.60, 572.4, 1.84, 0.0, 4.00); sH2->transport = tH2; sO2->transport = tO2; sH2O->transport = tH2O; std::string phase_def = "ideal_gas(name='test', elements='O H'," "species='gri30: H2 O2 H2O')"; XML_Node* fxml = get_XML_from_string(phase_def); ref.reset(newPhase(*fxml->findByName("phase"))); test.reset(new IdealGasPhase()); test->addElement("O"); test->addElement("H"); test->addSpecies(sH2); test->addSpecies(sO2); test->addSpecies(sH2O); test->initThermo(); ref->setState_TPX(400, 5e5, "H2:0.5, O2:0.3, H2O:0.2"); test->setState_TPX(400, 5e5, "H2:0.5, O2:0.3, H2O:0.2"); }
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 IdealSolidSolnPhase::initThermoXML(XML_Node& phaseNode, const std::string& id_) { if (id_.size() > 0 && phaseNode.id() != id_) { throw CanteraError("IdealSolidSolnPhase::initThermoXML", "phasenode and Id are incompatible"); } /* * Check on the thermo field. Must have: * <thermo model="IdealSolidSolution" /> */ if (phaseNode.hasChild("thermo")) { XML_Node& thNode = phaseNode.child("thermo"); string mString = thNode.attrib("model"); if (lowercase(mString) != "idealsolidsolution") { throw CanteraError("IdealSolidSolnPhase::initThermoXML", "Unknown thermo model: " + mString); } } else { throw CanteraError("IdealSolidSolnPhase::initThermoXML", "Unspecified thermo model"); } /* * Form of the standard concentrations. Must have one of: * * <standardConc model="unity" /> * <standardConc model="molar_volume" /> * <standardConc model="solvent_volume" /> */ if (phaseNode.hasChild("standardConc")) { XML_Node& scNode = phaseNode.child("standardConc"); string formStringa = scNode.attrib("model"); string formString = lowercase(formStringa); if (formString == "unity") { m_formGC = 0; } else if (formString == "molar_volume") { m_formGC = 1; } else if (formString == "solvent_volume") { m_formGC = 2; } else { throw CanteraError("IdealSolidSolnPhase::initThermoXML", "Unknown standardConc model: " + formStringa); } } else { throw CanteraError("IdealSolidSolnPhase::initThermoXML", "Unspecified standardConc model"); } /* * Initialize all of the lengths now that we know how many species * there are in the phase. */ initLengths(); /* * Now go get the molar volumes */ XML_Node& speciesList = phaseNode.child("speciesArray"); XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"], &phaseNode.root()); for (size_t k = 0; k < m_kk; k++) { XML_Node* s = speciesDB->findByAttr("name", speciesName(k)); XML_Node* ss = s->findByName("standardState"); m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI"); } /* * Call the base initThermo, which handles setting the initial * state. */ ThermoPhase::initThermoXML(phaseNode, id_); }
void setup(const std::string& elements="H C O N Ar") { XML_Node* phase = get_XML_from_string( "ideal_gas(elements='" + elements + "', species='gri30: CH C2H2')"); gas.reset(newPhase(*phase->findByName("phase"))); gas->setState_TPX(1000, 1e5, "C2H2:0.9, CH:0.1"); }