void SurfPhase:: setCoveragesByName(std::string cov) { int kk = nSpecies(); int k; compositionMap cc; for (k = 0; k < kk; k++) { cc[speciesName(k)] = -1.0; } parseCompString(cov, cc); doublereal c; vector_fp cv(kk, 0.0); bool ifound = false; for (k = 0; k < kk; k++) { c = cc[speciesName(k)]; if (c > 0.0) { ifound = true; cv[k] = c; } } if (!ifound) { throw CanteraError("SurfPhase::setCoveragesByName", "Input coverages are all zero or negative"); } setCoverages(DATA_PTR(cv)); }
shared_ptr<Species> make_shomate2_species(const std::string& name, const std::string& composition, const double* shomate_coeffs) { auto species = make_shared<Species>(name, parseCompString(composition)); species->thermo.reset(new ShomatePoly2(200, 3500, 101325, shomate_coeffs)); return species; }
shared_ptr<Species> make_const_cp_species(const std::string& name, const std::string& composition, double T0, double h0, double s0, double cp) { auto species = make_shared<Species>(name, parseCompString(composition)); double coeffs[] = {T0, h0, s0, cp}; species->thermo.reset(new ConstCpPoly(200, 3500, 101325, coeffs)); return species; }
void Phase::setMassFractionsByName(const std::string& y) { compositionMap yy; int kk = nSpecies(); for (int k = 0; k < kk; k++) { yy[speciesName(k)] = -1.0; } parseCompString(y, yy); setMassFractionsByName(yy); }
/* * setMolalitiesByNames() * * Set the molalities of the solutes by name */ void MolalityVPSSTP::setMolalitiesByName(const std::string& x) { compositionMap xx; for (size_t k = 0; k < nSpecies(); k++) { xx[speciesName(k)] = -1.0; } parseCompString(x, xx); setMolalitiesByName(xx); }
shared_ptr<Species> make_species(const std::string& name, const std::string& composition, double h298, double T1, double mu1, double T2, double mu2, double pref=101325) { auto species = make_shared<Species>(name, parseCompString(composition)); double coeffs[] = {2, h298, T1, mu1*GasConstant*T1, T2, mu2*GasConstant*T2}; species->thermo.reset(new Mu0Poly(200, 3500, pref, coeffs)); return species; }
ConstructFromScratch() : sH2O(make_species("H2O", "H:2 O:1", h2o_nasa_coeffs)) , sH2(make_species("H2", "H:2", h2_nasa_coeffs)) , sO2(make_species("O2", "O:2", o2_nasa_coeffs)) , sOH(make_species("OH", "H:1 O:1", oh_nasa_coeffs)) , sCO(make_species("CO", "C:1 O:1", o2_nasa_coeffs)) , sCO2(new Species("CO2", parseCompString("C:1 O:2"))) { sCO2->thermo.reset(new ShomatePoly2(200, 3500, 101325, co2_shomate_coeffs)); }
void Phase::setMoleFractionsByName(const std::string& x) { size_t kk = nSpecies(); compositionMap xx; for (size_t k = 0; k < kk; k++) { xx[speciesName(k)] = -1.0; } parseCompString(x, xx); setMoleFractionsByName(xx); }
TEST(PureFluidFromScratch, CarbonDioxide) { PureFluidPhase p; auto sCO2 = make_shared<Species>("CO2", parseCompString("C:1 O:2")); sCO2->thermo.reset(new ShomatePoly2(200, 6000, 101325, co2_shomate_coeffs)); p.addSpecies(sCO2); p.setSubstance("carbondioxide"); p.initThermo(); p.setState_Tsat(280, 0.5); EXPECT_NEAR(p.pressure(), 4160236.987, 1e-2); }
TEST(IonsFromNeutralConstructor, fromScratch) { auto neutral = make_shared<MargulesVPSSTP>(); auto sKCl = make_shomate_species("KCl(L)", "K:1 Cl:1", kcl_shomate_coeffs); neutral->addSpecies(sKCl); std::unique_ptr<PDSS_ConstVol> ssKCl(new PDSS_ConstVol()); ssKCl->setMolarVolume(0.03757); neutral->installPDSS(0, std::move(ssKCl)); neutral->initThermo(); IonsFromNeutralVPSSTP p; p.setNeutralMoleculePhase(neutral); auto sKp = make_shared<Species>("K+", parseCompString("K:1"), 1); auto sClm = make_shared<Species>("Cl-", parseCompString("Cl:1"), -1); sClm->extra["special_species"] = true; p.addSpecies(sKp); p.addSpecies(sClm); std::unique_ptr<PDSS_IonsFromNeutral> ssKp(new PDSS_IonsFromNeutral()); std::unique_ptr<PDSS_IonsFromNeutral> ssClm(new PDSS_IonsFromNeutral()); ssKp->setNeutralSpeciesMultiplier("KCl(L)", 1.2); ssClm->setNeutralSpeciesMultiplier("KCl(L)", 1.5); ssClm->setSpecialSpecies(); p.installPDSS(0, std::move(ssKp)); p.installPDSS(1, std::move(ssClm)); p.initThermo(); ASSERT_EQ((int) p.nSpecies(), 2); p.setState_TPX(500, 2e5, "K+:0.1, Cl-:0.1"); vector_fp mu(p.nSpecies()); p.getChemPotentials(mu.data()); // Values for regression testing only -- same as XML test EXPECT_NEAR(p.density(), 1984.3225978174073, 1e-6); EXPECT_NEAR(p.enthalpy_mass(), -8035317241137.971, 1e-1); EXPECT_NEAR(mu[0], -4.66404010e+08, 1e1); EXPECT_NEAR(mu[1], -2.88157298e+06, 1e-1); }
void Phase::setMoleFractionsByName(const std::string& x) { compositionMap xx; int kk = nSpecies(); for (int k = 0; k < kk; k++) { xx[speciesName(k)] = -1.0; } parseCompString(x, xx); setMoleFractionsByName(xx); //int kk = nSpecies(); //vector_fp mf(kk); //for (int k = 0; k < kk; k++) { // mf[k] = xx[speciesName(k)]; //} //setMoleFractions(mf.begin()); }
TEST(LatticeSolidPhase, fromScratch) { auto base = make_shared<StoichSubstance>(); base->setName("Li7Si3(S)"); base->setDensity(1390.0); auto sLi7Si3 = make_shomate2_species("Li7Si3(S)", "Li:7 Si:3", li7si3_shomate_coeffs); base->addSpecies(sLi7Si3); base->initThermo(); auto interstital = make_shared<LatticePhase>(); interstital->setName("Li7Si3_Interstitial"); auto sLii = make_const_cp_species("Li(i)", "Li:1", 298.15, 0, 2e4, 2e4); auto sVac = make_const_cp_species("V(i)", "", 298.15, 8.98e4, 0, 0); sLii->extra["molar_volume"] = 0.2; interstital->setSiteDensity(10.46344); interstital->addSpecies(sLii); interstital->addSpecies(sVac); interstital->initThermo(); interstital->setMoleFractionsByName("Li(i):0.01 V(i):0.99"); LatticeSolidPhase p; p.addLattice(base); p.addLattice(interstital); p.setLatticeStoichiometry(parseCompString("Li7Si3(S):1.0 Li7Si3_Interstitial:1.0")); p.initThermo(); p.setState_TP(725, 10 * OneAtm); // Regression test based on modified version of Li7Si3_ls.xml EXPECT_NEAR(p.enthalpy_mass(), -2077821.9295456698, 1e-6); double mu_ref[] = {-4.62717474e+08, -4.64248485e+07, 1.16370186e+05}; double vol_ref[] = {0.09557086, 0.2, 0.09557086}; vector_fp mu(p.nSpecies()); vector_fp vol(p.nSpecies()); p.getChemPotentials(mu.data()); p.getPartialMolarVolumes(vol.data()); for (size_t k = 0; k < p.nSpecies(); k++) { EXPECT_NEAR(mu[k], mu_ref[k], 1e-7*fabs(mu_ref[k])); EXPECT_NEAR(vol[k], vol_ref[k], 1e-7); } }
FixedChemPotSSTP::FixedChemPotSSTP(const std::string& Ename, doublereal val) : chemPot_(0.0) { std::string pname = Ename + "Fixed"; setID(pname); setName(pname); setNDim(3); addElement(Ename); auto sp = make_shared<Species>(pname, parseCompString(Ename + ":1.0")); double c[4] = {298.15, val, 0.0, 0.0}; shared_ptr<SpeciesThermoInterpType> stit( newSpeciesThermoInterpType("const_cp", 0.1, 1e30, OneAtm, c)); sp->thermo = stit; addSpecies(sp); initThermo(); m_p0 = OneAtm; m_tlast = 298.15; setChemicalPotential(val); // Create an XML_Node entry for this species XML_Node s("species", 0); s.addAttribute("name", pname); std::string aaS = Ename + ":1"; s.addChild("atomArray", aaS); XML_Node& tt = s.addChild("thermo"); XML_Node& ss = tt.addChild("Simple"); ss.addAttribute("Pref", "1 bar"); ss.addAttribute("Tmax", "5000."); ss.addAttribute("Tmin", "100."); ss.addChild("t0", "298.15"); ss.addChild("cp0", "0.0"); std::string sval = fp2str(val); ss.addChild("h", sval); ss.addChild("s", "0.0"); saveSpeciesData(0, &s); }
void Phase::setMassFractionsByName(const std::string& y) { setMassFractionsByName(parseCompString(y)); }
void Phase::setMoleFractionsByName(const std::string& x) { setMoleFractionsByName(parseCompString(x)); }
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 Phase::setMassFractionsByName(const std::string& y) { compositionMap c = parseCompString(y, speciesNames()); setMassFractionsByName(c); }
void Phase::setMoleFractionsByName(const std::string& x) { compositionMap c = parseCompString(x, speciesNames()); setMoleFractionsByName(c); }
void MolalityVPSSTP::setMolalitiesByName(const std::string& x) { compositionMap xx = parseCompString(x, speciesNames()); setMolalitiesByName(xx); }
bool checkElectrochemReaction(const XML_Node& p, Kinetics& kin, const XML_Node& r) { // If other phases are involved in the reaction mechanism, they must be // listed in a 'phaseArray' child element. Homogeneous mechanisms do not // need to include a phaseArray element. vector<string> phase_ids; if (p.hasChild("phaseArray")) { const XML_Node& pa = p.child("phaseArray"); getStringArray(pa, phase_ids); } phase_ids.push_back(p["id"]); // Get reaction product and reactant information Composition reactants = parseCompString(r.child("reactants").value()); Composition products = parseCompString(r.child("products").value()); // If the reaction has undeclared species don't perform electrochemical check for (const auto& sp : reactants) { if (kin.kineticsSpeciesIndex(sp.first) == npos) { return true; } } for (const auto& sp : products) { if (kin.kineticsSpeciesIndex(sp.first) == npos) { return true; } } // Initialize the electron counter for each phase std::vector<double> e_counter(phase_ids.size(), 0.0); // Find the amount of electrons in the products for each phase for (const auto& sp : products) { const ThermoPhase& ph = kin.speciesPhase(sp.first); size_t k = ph.speciesIndex(sp.first); double stoich = sp.second; for (size_t m = 0; m < phase_ids.size(); m++) { if (phase_ids[m] == ph.id()) { e_counter[m] += stoich * ph.charge(k); break; } } } // Subtract the amount of electrons in the reactants for each phase for (const auto& sp : reactants) { const ThermoPhase& ph = kin.speciesPhase(sp.first); size_t k = ph.speciesIndex(sp.first); double stoich = sp.second; for (size_t m = 0; m < phase_ids.size(); m++) { if (phase_ids[m] == ph.id()) { e_counter[m] -= stoich * ph.charge(k); break; } } } // If the electrons change phases then the reaction is electrochemical bool echemical = false; for(size_t m = 0; m < phase_ids.size(); m++) { if (fabs(e_counter[m]) > 1e-4) { echemical = true; break; } } // If the reaction is electrochemical, ensure the reaction is identified as // electrochemical. If not already specified beta is assumed to be 0.5 std::string type = ba::to_lower_copy(r["type"]); if (!r.child("rateCoeff").hasChild("electrochem")) { if ((type != "butlervolmer_noactivitycoeffs" && type != "butlervolmer" && type != "surfaceaffinity") && echemical) { XML_Node& f = r.child("rateCoeff").addChild("electrochem",""); f.addAttribute("beta",0.5); } } return true; }