Beispiel #1
0
  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));
  }
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
 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);
 }
Beispiel #5
0
/*
 * 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);
}
Beispiel #6
0
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;
}
Beispiel #7
0
 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));
 }
Beispiel #8
0
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);
}
Beispiel #9
0
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);
}
Beispiel #10
0
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);
}
Beispiel #11
0
 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());
 }
Beispiel #12
0
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);
}
Beispiel #14
0
void Phase::setMassFractionsByName(const std::string& y)
{
    setMassFractionsByName(parseCompString(y));
}
Beispiel #15
0
void Phase::setMoleFractionsByName(const std::string& x)
{
    setMoleFractionsByName(parseCompString(x));
}
Beispiel #16
0
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;
}
Beispiel #17
0
void Phase::setMassFractionsByName(const std::string& y)
{
    compositionMap c = parseCompString(y, speciesNames());
    setMassFractionsByName(c);
}
Beispiel #18
0
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;
}