SpeciesThermoInterpType* newSpeciesThermoInterpType(const std::string& stype,
    double tlow, double thigh, double pref, const double* coeffs)
{
    int itype = -1;
    std::string type = lowercase(stype);
    if (type == "nasa2" || type == "nasa") {
        itype = NASA2; // two-region 7-coefficient NASA polynomials
    } else if (type == "const_cp" || type == "simple") {
        itype = CONSTANT_CP;
    } else if (type == "shomate" || type == "shomate1") {
        itype = SHOMATE1; // single-region Shomate polynomial
    } else if (type == "shomate2") {
        itype = SHOMATE2; // two-region Shomate polynomials
    } else if (type == "nasa1") {
        itype = NASA1; // single-region, 7-coefficient NASA polynomial
    } else if (type == "nasa9") {
        itype = NASA9; // single-region, 9-coefficient NASA polynomial
    } else if (type == "nasa9multi") {
        itype = NASA9MULTITEMP; // multi-region, 9-coefficient NASA polynomials
    } else if (type == "mu0") {
        itype = MU0_INTERP;
    } else if (type == "adsorbate") {
        itype = ADSORBATE;
    } else {
        throw CanteraError("newSpeciesThermoInterpType",
                           "Unknown species thermo type: '" + stype + "'.");
    }
    return newSpeciesThermoInterpType(itype, tlow, thigh, pref, coeffs);
}
Ejemplo n.º 2
0
/*!
 * This is called if a 'NASA' node is found in the XML input.
 *
 *  @param speciesName  name of the species
 *  @param nodes        vector of 1 or 2 'NASA' XML_Nodes, each defining the
 *      coefficients for a temperature range
 */
static SpeciesThermoInterpType* newNasaThermoFromXML(
    const std::string& speciesName, vector<XML_Node*> nodes)
{
    const XML_Node& f0 = *nodes[0];
    bool dualRange = (nodes.size() > 1);

    double tmin0 = fpValue(f0["Tmin"]);
    double tmax0 = fpValue(f0["Tmax"]);

    doublereal p0 = OneAtm;
    if (f0.hasAttrib("P0")) {
        p0 = fpValue(f0["P0"]);
    }
    if (f0.hasAttrib("Pref")) {
        p0 = fpValue(f0["Pref"]);
    }
    p0 = OneAtm;

    double tmin1 = tmax0;
    double tmax1 = tmin1 + 0.0001;
    if (dualRange) {
        tmin1 = fpValue(nodes[1]->attrib("Tmin"));
        tmax1 = fpValue(nodes[1]->attrib("Tmax"));
    }

    vector_fp c0, c1;
    doublereal tmin, tmid, tmax;
    if (fabs(tmax0 - tmin1) < 0.01) {
        // f0 has the lower T data, and f1 the higher T data
        tmin = tmin0;
        tmid = tmax0;
        tmax = tmax1;
        getFloatArray(f0.child("floatArray"), c0, false);
        if (dualRange) {
            getFloatArray(nodes[1]->child("floatArray"), c1, false);
        } else {
            // if there is no higher range data, then copy c0 to c1.
            c1.resize(7,0.0);
            copy(c0.begin(), c0.end(), c1.begin());
        }
    } else if (fabs(tmax1 - tmin0) < 0.01) {
        // f1 has the lower T data, and f0 the higher T data
        tmin = tmin1;
        tmid = tmax1;
        tmax = tmax0;
        getFloatArray(nodes[1]->child("floatArray"), c0, false);
        getFloatArray(f0.child("floatArray"), c1, false);
    } else {
        throw CanteraError("installNasaThermo",
                           "non-continuous temperature ranges.");
    }

    vector_fp c(15);
    c[0] = tmid;
    copy(c1.begin(), c1.begin()+7, c.begin() + 1); // high-T coefficients
    copy(c0.begin(), c0.begin()+7, c.begin() + 8); // low-T coefficients
    return newSpeciesThermoInterpType(NASA, tmin, tmax, p0, &c[0]);
}
Ejemplo n.º 3
0
void SpeciesThermoFactory::installThermoForSpecies
(size_t k, const XML_Node& speciesNode, ThermoPhase* th_ptr,
 SpeciesThermo& spthermo, const XML_Node* phaseNode_ptr) const
{
    SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(speciesNode);
    stit->validate(speciesNode["name"]);
    stit->setIndex(k);
    spthermo.install_STIT(stit);
}
Ejemplo n.º 4
0
void SpeciesThermoFactory::installThermoForSpecies
(size_t k, const XML_Node& speciesNode, ThermoPhase* th_ptr,
 SpeciesThermo& spthermo, const XML_Node* phaseNode_ptr) const
{
    shared_ptr<SpeciesThermoInterpType> stit(
        newSpeciesThermoInterpType(speciesNode.child("thermo")));
    stit->validate(speciesNode["name"]);
    spthermo.install_STIT(k, stit);
}
Ejemplo n.º 5
0
/*!
 *  This is called if a 'MinEQ3' node is found in the XML input.
 *
 *  @param name         name of the species
 *  @param MinEQ3node   The XML_Node containing the MinEQ3 parameterization
 */
SpeciesThermoInterpType* newShomateForMineralEQ3(const std::string& name,
                                                 const XML_Node& MinEQ3node)
{
    doublereal tmin0 = strSItoDbl(MinEQ3node["Tmin"]);
    doublereal tmax0 = strSItoDbl(MinEQ3node["Tmax"]);
    doublereal p0 = strSItoDbl(MinEQ3node["Pref"]);

    doublereal deltaG_formation_pr_tr =
        getFloatDefaultUnits(MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy");
    doublereal deltaH_formation_pr_tr =
        getFloatDefaultUnits(MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy");
    doublereal Entrop_pr_tr = getFloatDefaultUnits(MinEQ3node, "S0_Pr_Tr", "cal/gmol/K");
    doublereal a = getFloatDefaultUnits(MinEQ3node, "a", "cal/gmol/K");
    doublereal b = getFloatDefaultUnits(MinEQ3node, "b", "cal/gmol/K2");
    doublereal c = getFloatDefaultUnits(MinEQ3node, "c", "cal-K/gmol");
    doublereal dg = deltaG_formation_pr_tr * 4.184 * 1.0E3;
    doublereal DHjmol = deltaH_formation_pr_tr * 1.0E3 * 4.184;
    doublereal fac = DHjmol - dg - 298.15 * Entrop_pr_tr * 1.0E3 * 4.184;
    doublereal Mu0_tr_pr = fac + dg;
    doublereal e = Entrop_pr_tr * 1.0E3 * 4.184;
    doublereal Hcalc = Mu0_tr_pr + 298.15 * e;

    /*
     * Now calculate the shomate polynomials
     *
     * Cp first
     *
     *  Shomate: (Joules / gmol / K)
     *    Cp = As + Bs * t + Cs * t*t + Ds * t*t*t + Es / (t*t)
     *     where
     *          t = temperature(Kelvin) / 1000
     */
    double As = a * 4.184;
    double Bs = b * 4.184 * 1000.;
    double Cs = 0.0;
    double Ds = 0.0;
    double Es = c * 4.184 / (1.0E6);

    double t = 298.15 / 1000.;
    double H298smFs = As * t + Bs * t * t / 2.0 - Es / t;

    double HcalcS = Hcalc / 1.0E6;
    double Fs = HcalcS - H298smFs;

    double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
    double ScalcS = e / 1.0E3;
    double Gs = ScalcS - S298smGs;

    double c0[7] = {As, Bs, Cs, Ds, Es, Fs, Gs};

    return newSpeciesThermoInterpType(SHOMATE1, tmin0, tmax0, p0, c0);
}
/*!
 * This is called if a 'const_cp' XML node is found
 *
 *  @param f            'const_cp' XML node
 */
static SpeciesThermoInterpType* newConstCpThermoFromXML(XML_Node& f)
{
    double tmin = fpValue(f["Tmin"]);
    double tmax = fpValue(f["Tmax"]);
    if (tmax == 0.0) {
        tmax = 1.0e30;
    }

    vector_fp c(4);
    c[0] = getFloat(f, "t0", "toSI");
    c[1] = getFloat(f, "h0", "toSI");
    c[2] = getFloat(f, "s0", "toSI");
    c[3] = getFloat(f, "cp0", "toSI");
    doublereal p0 = OneAtm;
    return newSpeciesThermoInterpType(CONSTANT_CP, tmin, tmax, p0, &c[0]);
}
Ejemplo n.º 7
0
PDSS* VPSSMgr_IdealGas::createInstallPDSS(size_t k, const XML_Node& speciesNode,
                                          const XML_Node* const phaseNode_ptr)
{
    const XML_Node* ss = speciesNode.findByName("standardState");
    if (ss && ss->attrib("model") != "ideal_gas") {
        throw CanteraError("VPSSMgr_IdealGas::createInstallPDSS",
                           "standardState model for species isn't "
                           "ideal_gas: " + speciesNode["name"]);
    }
    if (m_Vss.size() < k+1) {
        m_Vss.resize(k+1, 0.0);
    }

    shared_ptr<SpeciesThermoInterpType> stit(
        newSpeciesThermoInterpType(speciesNode.child("thermo")));
    stit->validate(speciesNode["name"]);
    m_spthermo->install_STIT(k, stit);

    PDSS* kPDSS = new PDSS_IdealGas(m_vptp_ptr, k, speciesNode,
                                    *phaseNode_ptr, true);

    m_p0 = m_spthermo->refPressure(k);
    return kPDSS;
}
Ejemplo n.º 8
0
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);
}
/*!
 *  This is called if a 'Shomate' node is found in the XML input.
 *
 *  @param nodes        vector of 1 or 2 'Shomate' XML_Nodes, each defining the
 *      coefficients for a temperature range
 */
static SpeciesThermoInterpType* newShomateThermoFromXML(
    vector<XML_Node*>& nodes)
{
    bool dualRange = false;
    if (nodes.size() == 2) {
        dualRange = true;
    }
    double tmin0 = fpValue(nodes[0]->attrib("Tmin"));
    double tmax0 = fpValue(nodes[0]->attrib("Tmax"));

    doublereal p0 = OneAtm;
    if (nodes[0]->hasAttrib("P0")) {
        p0 = fpValue(nodes[0]->attrib("P0"));
    }
    if (nodes[0]->hasAttrib("Pref")) {
        p0 = fpValue(nodes[0]->attrib("Pref"));
    }
    p0 = OneAtm;

    double tmin1 = tmax0;
    double tmax1 = tmin1 + 0.0001;
    if (dualRange) {
        tmin1 = fpValue(nodes[1]->attrib("Tmin"));
        tmax1 = fpValue(nodes[1]->attrib("Tmax"));
    }

    vector_fp c0, c1;
    doublereal tmin, tmid, tmax;
    if (fabs(tmax0 - tmin1) < 0.01) {
        tmin = tmin0;
        tmid = tmax0;
        tmax = tmax1;
        getFloatArray(nodes[0]->child("floatArray"), c0, false);
        if (dualRange) {
            getFloatArray(nodes[1]->child("floatArray"), c1, false);
        } else {
            if(c0.size() != 7)
            {
              throw CanteraError("installShomateThermoFromXML",
                                 "Shomate thermo requires 7 coefficients in float array.");
            }
            c1.resize(7,0.0);
            copy(c0.begin(), c0.begin()+7, c1.begin());
        }
    } else if (fabs(tmax1 - tmin0) < 0.01) {
        tmin = tmin1;
        tmid = tmax1;
        tmax = tmax0;
        getFloatArray(nodes[1]->child("floatArray"), c0, false);
        getFloatArray(nodes[0]->child("floatArray"), c1, false);
    } else {
        throw CanteraError("installShomateThermoFromXML",
                           "non-continuous temperature ranges.");
    }
    if(c0.size() != 7 || c1.size() != 7)
    {
      throw CanteraError("installShomateThermoFromXML",
                         "Shomate thermo requires 7 coefficients in float array.");
    }
    vector_fp c(15);
    c[0] = tmid;
    copy(c0.begin(), c0.begin()+7, c.begin() + 1);
    copy(c1.begin(), c1.begin()+7, c.begin() + 8);
    return newSpeciesThermoInterpType(SHOMATE, tmin, tmax, p0, &c[0]);
}
Ejemplo n.º 10
0
void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode)
{
    size_t kk = 0;
    size_t kstart = 0;
    m_speciesData.clear();

    XML_Node& eosdata = phaseNode->child("thermo");
    XML_Node& la = eosdata.child("LatticeArray");
    std::vector<XML_Node*> lattices = la.getChildren("phase");
    for (size_t n = 0; n < m_nlattice; n++) {
        LatticePhase* lp = m_lattice[n];
        size_t nsp =  lp->nSpecies();
        vector<doublereal> constArr(lp->nElements());
        const vector_fp& aws = lp->atomicWeights();
        for (size_t es = 0; es < lp->nElements(); es++) {
            string esName = lp->elementName(es);
            double wt = aws[es];
            int an = lp->atomicNumber(es);
            int e298 = lp->entropyElement298(es); //! @todo Why is this an int instead of a double?
            int et = lp->elementType(es);
            addElement(esName, wt, an, e298, et);
        }
        const std::vector<const XML_Node*> & spNode =  lp->speciesData();
        kstart = kk;


        for (size_t k = 0; k < nsp; k++) {
            std::string sname = lp->speciesName(k);
            std::map<std::string, double> comp;
            lp->getAtoms(k, DATA_PTR(constArr));
            size_t nel = nElements();
            vector_fp ecomp(nel, 0.0);
            for (size_t m = 0; m < lp->nElements(); m++) {
                if (constArr[m] != 0.0) {
                    std::string oldEname = lp->elementName(m);
                    size_t newIndex = elementIndex(oldEname);
                    if (newIndex == npos) {
                        throw CanteraError("LatticeSolidPhase::installSlavePhases",
                                           "element not found");
                    }
                    ecomp[newIndex] = constArr[m];
                }
            }
            double chrg = lp->charge(k);
            double sz = lp->size(k);
            addUniqueSpecies(sname, &ecomp[0], chrg, sz);
            SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(*spNode[k]);
            stit->setIndex(kk);
            stit->validate(spNode[k]->attrib("name"));
            m_spthermo->install_STIT(stit);
            m_speciesData.push_back(new XML_Node(*(spNode[k])));
            kk++;
        }
        /*
         *  Add in the lattice stoichiometry constraint
         */
        if (n > 0) {
            string econ = "LC_";
            econ += int2str(n);
            econ += "_" + id();
            size_t m = addElement(econ, 0.0, 0, 0.0, CT_ELEM_TYPE_LATTICERATIO);
            size_t mm = nElements();
            LatticePhase* lp0 = m_lattice[0];
            size_t nsp0 =  lp0->nSpecies();
            for (size_t k = 0; k < nsp0; k++) {
                m_speciesComp[k * mm + m] = -theta_[0];
            }
            for (size_t k = 0; k < nsp; k++) {
                size_t ks = kstart + k;
                m_speciesComp[ks * mm + m] = theta_[n];
            }
        }
    }
}
Ejemplo n.º 11
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;
}