Cantera 2.6.0

MaskellSolidSolnPhase.cpp
Go to the documentation of this file.
1/**
2 * @file MaskellSolidSolnPhase.cpp Implementation file for an ideal solid
3 * solution model with incompressible thermodynamics (see \ref
4 * thermoprops and \link Cantera::MaskellSolidSolnPhase
5 * MaskellSolidSolnPhase\endlink).
6 */
7
8// This file is part of Cantera. See License.txt in the top-level directory or
9// at https://cantera.org/license.txt for license and copyright information.
10
11#include "cantera/thermo/MaskellSolidSolnPhase.h"
12#include "cantera/base/stringUtils.h"
13#include "cantera/base/xml.h"
14
15#include <cassert>
16
17 namespace Cantera
18{
19
20MaskellSolidSolnPhase::MaskellSolidSolnPhase() :
21 m_Pcurrent(OneAtm),
22 h_mixing(0.0),
23 product_species_index(-1),
24 reactant_species_index(-1)
25{
26}
27
28 void MaskellSolidSolnPhase::getActivityConcentrations(doublereal* c) const
29{
30 getActivityCoefficients(c);
31 for (size_t sp = 0; sp < m_kk; ++sp) {
32 c[sp] *= moleFraction(sp);
33 }
34}
35
36// Molar Thermodynamic Properties of the Solution
37
38doublereal MaskellSolidSolnPhase::enthalpy_mole() const
39{
40 const doublereal h0 = RT() * mean_X(m_h0_RT);
41 const doublereal r = moleFraction(product_species_index);
42 const doublereal fmval = fm(r);
43 return h0 + r * fmval * h_mixing;
44}
45
46doublereal xlogx(doublereal x)
47{
48 return x * std::log(x);
49}
50
51doublereal MaskellSolidSolnPhase::entropy_mole() const
52{
53 const doublereal s0 = GasConstant * mean_X(m_s0_R);
54 const doublereal r = moleFraction(product_species_index);
55 const doublereal fmval = fm(r);
56 const doublereal rfm = r * fmval;
57 return s0 + GasConstant * (xlogx(1-rfm) - xlogx(rfm) - xlogx(1-r-rfm) - xlogx((1-fmval)*r) - xlogx(1-r) - xlogx(r));
58}
59
60// Mechanical Equation of State
61
62 void MaskellSolidSolnPhase::calcDensity()
63{
64 const vector_fp& vbar = getStandardVolumes();
65
66 vector_fp moleFracs(m_kk);
67 Phase::getMoleFractions(&moleFracs[0]);
68 doublereal vtotal = 0.0;
69 for (size_t i = 0; i < m_kk; i++) {
70 vtotal += vbar[i] * moleFracs[i];
71 }
72 Phase::assignDensity(meanMolecularWeight() / vtotal);
73}
74
75 void MaskellSolidSolnPhase::setPressure(doublereal p)
76{
77 m_Pcurrent = p;
78}
79
80// Chemical Potentials and Activities
81
82 void MaskellSolidSolnPhase::getActivityCoefficients(doublereal* ac) const
83{
84 static const int cacheId = m_cache.getId();
85 CachedArray cached = m_cache.getArray(cacheId);
86 if (!cached.validate(temperature(), pressure(), stateMFNumber())) {
87 cached.value.resize(2);
88
89 const doublereal r = moleFraction(product_species_index);
90 const doublereal pval = p(r);
91 const doublereal rfm = r * fm(r);
92 const doublereal A = (std::pow(1 - rfm, pval) * std::pow(rfm, pval) * std::pow(r - rfm, 1 - pval)) /
93 (std::pow(1 - r - rfm, 1 + pval) * (1 - r));
94 const doublereal B = pval * h_mixing / RT();
95 cached.value[product_species_index] = A * std::exp(B);
96 cached.value[reactant_species_index] = 1 / (A * r * (1-r) ) * std::exp(-B);
97 }
98 std::copy(cached.value.begin(), cached.value.end(), ac);
99}
100
101 void MaskellSolidSolnPhase::getChemPotentials(doublereal* mu) const
102{
103 const doublereal r = moleFraction(product_species_index);
104 const doublereal pval = p(r);
105 const doublereal rfm = r * fm(r);
106 const doublereal DgbarDr = pval * h_mixing +
107 RT() *
108 std::log( (std::pow(1 - rfm, pval) * std::pow(rfm, pval) * std::pow(r - rfm, 1 - pval) * r) /
109 (std::pow(1 - r - rfm, 1 + pval) * (1 - r)) );
110 mu[product_species_index] = RT() * m_g0_RT[product_species_index] + DgbarDr;
111 mu[reactant_species_index] = RT() * m_g0_RT[reactant_species_index] - DgbarDr;
112}
113
114 void MaskellSolidSolnPhase::getChemPotentials_RT(doublereal* mu) const
115{
116 getChemPotentials(mu);
117 for (size_t sp=0; sp < m_kk; ++sp) {
118 mu[sp] *= 1.0 / RT();
119 }
120}
121
122// Partial Molar Properties
123
124 void MaskellSolidSolnPhase::getPartialMolarEnthalpies(doublereal* hbar) const
125{
126 throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarEnthalpies");
127}
128
129 void MaskellSolidSolnPhase::getPartialMolarEntropies(doublereal* sbar) const
130{
131 throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarEntropies");
132}
133
134 void MaskellSolidSolnPhase::getPartialMolarCp(doublereal* cpbar) const
135{
136 throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarCp");
137}
138
139 void MaskellSolidSolnPhase::getPartialMolarVolumes(doublereal* vbar) const
140{
141 getStandardVolumes(vbar);
142}
143
144 void MaskellSolidSolnPhase::getPureGibbs(doublereal* gpure) const
145{
146 for (size_t sp=0; sp < m_kk; ++sp) {
147 gpure[sp] = RT() * m_g0_RT[sp];
148 }
149}
150
151 void MaskellSolidSolnPhase::getStandardChemPotentials(doublereal* mu) const
152{
153 // What is the difference between this and getPureGibbs? IdealSolidSolnPhase
154 // gives the same for both
155 getPureGibbs(mu);
156}
157
158// Utility Functions
159
160 void MaskellSolidSolnPhase::initThermo()
161{
162 if (!m_input.empty()) {
163 set_h_mix(m_input.convert("excess-enthalpy", "J/kmol"));
164 setProductSpecies(m_input["product-species"].asString());
165 }
166 VPStandardStateTP::initThermo();
167}
168
169 void MaskellSolidSolnPhase::getParameters(AnyMap& phaseNode) const
170{
171 VPStandardStateTP::getParameters(phaseNode);
172 phaseNode["excess-enthalpy"].setQuantity(h_mixing, "J/kmol");
173 phaseNode["product-species"] = speciesName(product_species_index);
174}
175
176 void MaskellSolidSolnPhase::initThermoXML(XML_Node& phaseNode, const std::string& id_)
177{
178 if (id_.size() > 0 && phaseNode.id() != id_) {
179 throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
180 "phasenode and Id are incompatible");
181 }
182
183 // Check on the thermo field. Must have:
184 // <thermo model="MaskellSolidSolution" />
185 if (phaseNode.hasChild("thermo")) {
186 XML_Node& thNode = phaseNode.child("thermo");
187 if (!caseInsensitiveEquals(thNode["model"], "maskellsolidsolnphase")) {
188 throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
189 "Unknown thermo model: " + thNode["model"]);
190 }
191
192 // Parse the enthalpy of mixing constant
193 if (thNode.hasChild("h_mix")) {
194 set_h_mix(fpValue(thNode.child("h_mix").value()));
195 } else {
196 throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
197 "Mixing enthalpy parameter not specified.");
198 }
199
200 if (thNode.hasChild("product_species")) {
201 setProductSpecies(thNode.child("product_species").value());
202 } else {
203 setProductSpecies(speciesName(0)); // default
204 }
205 } else {
206 throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
207 "Unspecified thermo model");
208 }
209
210 // Confirm that the phase only contains 2 species
211 if (m_kk != 2) {
212 throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
213 "MaskellSolidSolution model requires exactly 2 species.");
214 }
215
216 // Call the base initThermo, which handles setting the initial state.
217 VPStandardStateTP::initThermoXML(phaseNode, id_);
218}
219
220 void MaskellSolidSolnPhase::setProductSpecies(const std::string& name)
221{
222 product_species_index = static_cast<int>(speciesIndex(name));
223 if (product_species_index == -1) {
224 throw CanteraError("MaskellSolidSolnPhase::setProductSpecies",
225 "Species '{}' not found", name);
226 }
227 reactant_species_index = (product_species_index == 0) ? 1 : 0;
228}
229
230doublereal MaskellSolidSolnPhase::s() const
231{
232 return 1 + std::exp(h_mixing / RT());
233}
234
235doublereal MaskellSolidSolnPhase::fm(const doublereal r) const
236{
237 return (1 - std::sqrt(1 - 4*r*(1-r)/s())) / (2*r);
238}
239
240doublereal MaskellSolidSolnPhase::p(const doublereal r) const
241{
242 const doublereal sval = s();
243 return (1 - 2*r) / std::sqrt(sval*sval - 4 * sval * r + 4 * sval * r * r);
244}
245
246} // end namespace Cantera
MaskellSolidSolnPhase.h
Header file for a solid solution model following Maskell, Shaw, and Tye.
Cantera::AnyMap
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
Cantera::CanteraError
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Cantera::NotImplementedError
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:187
Cantera::XML_Node
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
Cantera::XML_Node::hasChild
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
Cantera::XML_Node::id
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:539
Cantera::XML_Node::value
std::string value() const
Return the value of an XML node as a string.
Definition: xml.cpp:442
Cantera::XML_Node::child
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:547
Cantera
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:557
Cantera::fpValue
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
Definition: stringUtils.cpp:128
Cantera::OneAtm
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:81
Cantera::caseInsensitiveEquals
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
Definition: stringUtils.cpp:266
Cantera::vector_fp
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:184
Cantera::GasConstant
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:113
stringUtils.h
Contains declarations for string manipulation functions within Cantera.
Cantera::CachedValue
Definition: ValueCache.h:32
Cantera::CachedValue::value
T value
The value of the cached property.
Definition: ValueCache.h:118
Cantera::CachedValue::validate
bool validate(double state1New)
Check whether the currently cached value is valid based on a single state variable.
Definition: ValueCache.h:44
xml.h
Classes providing support for XML data files.