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(std::string Ename, doublereal val) : SingleSpeciesTP(), chemPot_(0.0) { std::string pname = Ename + "Fixed"; setID(pname); setName(pname); setNDim(3); addUniqueElement(Ename, -12345.); freezeElements(); vector_fp ecomp(nElements(), 0.0); ecomp[0] = 1.0; double chrg = 0.0; SpeciesThermo* spth = new SimpleThermo(); setSpeciesThermo(spth); addUniqueSpecies(pname, &ecomp[0], chrg, 0.0); double c[4]; c[0] = 298.15; c[1] = val; c[2] = 0.0; c[3] = 0.0; m_spthermo->install(pname, 0, SIMPLE, c, 0.0, 1.0E30, OneAtm); freezeSpecies(); initThermo(); m_p0 = OneAtm; m_tlast = 298.15; setChemicalPotential(val); // Create an XML_Node entry for this species XML_Node* s = new XML_Node("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); delete s; s = 0; }
PDSS_Water::PDSS_Water(VPStandardStateTP* tp, int spindex, const XML_Node& speciesNode, const XML_Node& phaseRoot, bool spInstalled) : PDSS(tp, spindex), m_waterProps(&m_sub), m_dens(1000.0), m_iState(WATER_LIQUID), EW_Offset(0.0), SW_Offset(0.0), m_verbose(0), m_allowGasPhase(false) { m_pdssType = cPDSS_WATER; std::string id= ""; constructPDSSXML(tp, spindex, phaseRoot, id); initThermo(); m_spthermo = 0; m_minTemp = 200.; m_maxTemp = 10000.; }
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); }
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); }
/*! Constructor \param parent Parent widget \param name Object name */ QwtThermo::QwtThermo(QWidget *parent, const char *name): QWidget(parent, name) { initThermo(); }
/*! Constructor \param parent Parent widget */ QwtThermo::QwtThermo(QWidget *parent): QWidget(parent) { initThermo(); }
void WaterSSTP::initThermoXML(XML_Node& phaseNode, const std::string& id) { /* * Do initializations that don't depend on knowing the XML file */ initThermo(); /* * Calculate the molecular weight. Note while there may * be a very good calculated weight in the steam table * class, using this weight may lead to codes exhibiting * mass loss issues. We need to grab the elemental * atomic weights used in the Element class and calculate * a consistent H2O molecular weight based on that. */ size_t nH = elementIndex("H"); if (nH == npos) { throw CanteraError("WaterSSTP::initThermo", "H not an element"); } double mw_H = atomicWeight(nH); size_t nO = elementIndex("O"); if (nO == npos) { throw CanteraError("WaterSSTP::initThermo", "O not an element"); } double mw_O = atomicWeight(nO); m_mw = 2.0 * mw_H + mw_O; setMolecularWeight(0,m_mw); double one = 1.0; setMoleFractions(&one); /* * Set the baseline */ doublereal T = 298.15; Phase::setDensity(7.0E-8); Phase::setTemperature(T); doublereal presLow = 1.0E-2; doublereal oneBar = 1.0E5; doublereal dd = m_sub.density(T, presLow, WATER_GAS, 7.0E-8); setDensity(dd); setTemperature(T); SW_Offset = 0.0; doublereal s = entropy_mole(); s -= GasConstant * log(oneBar/presLow); if (s != 188.835E3) { SW_Offset = 188.835E3 - s; } s = entropy_mole(); s -= GasConstant * log(oneBar/presLow); doublereal h = enthalpy_mole(); if (h != -241.826E6) { EW_Offset = -241.826E6 - h; } h = enthalpy_mole(); /* * Set the initial state of the system to 298.15 K and * 1 bar. */ setTemperature(298.15); double rho0 = m_sub.density(298.15, OneAtm, WATER_LIQUID); setDensity(rho0); m_waterProps.reset(new WaterProps(&m_sub)); /* * We have to do something with the thermo function here. */ delete m_spthermo; m_spthermo = 0; /* * Set the flag to say we are ready to calculate stuff */ m_ready = true; }