Cantera  2.5.1
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 
13 #include "cantera/base/xml.h"
14 
15 #include <cassert>
16 
17 namespace Cantera
18 {
19 
20 MaskellSolidSolnPhase::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 
38 doublereal 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 
46 doublereal xlogx(doublereal x)
47 {
48  return x * std::log(x);
49 }
50 
51 doublereal 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::setDensity(const doublereal rho)
63 {
64  // Unless the input density is exactly equal to the density calculated and
65  // stored in the State object, we throw an exception. This is because the
66  // density is NOT an independent variable.
67  warn_deprecated("MaskellSolidSolnPhase::setDensity",
68  "Overloaded function to be removed after Cantera 2.5. "
69  "Error will be thrown by Phase::setDensity instead");
70  double dens = density();
71  if (rho != dens) {
72  throw CanteraError("MaskellSolidSolnPhase::setDensity",
73  "Density is not an independent variable");
74  }
75 }
76 
77 void MaskellSolidSolnPhase::calcDensity()
78 {
79  const vector_fp& vbar = getStandardVolumes();
80 
81  vector_fp moleFracs(m_kk);
82  Phase::getMoleFractions(&moleFracs[0]);
83  doublereal vtotal = 0.0;
84  for (size_t i = 0; i < m_kk; i++) {
85  vtotal += vbar[i] * moleFracs[i];
86  }
87  Phase::assignDensity(meanMolecularWeight() / vtotal);
88 }
89 
90 void MaskellSolidSolnPhase::setPressure(doublereal p)
91 {
92  m_Pcurrent = p;
93 }
94 
95 void MaskellSolidSolnPhase::setMolarDensity(const doublereal n)
96 {
97  warn_deprecated("MaskellSolidSolnPhase::setMolarDensity",
98  "Overloaded function to be removed after Cantera 2.5. "
99  "Error will be thrown by Phase::setMolarDensity instead");
100  throw CanteraError("MaskellSolidSolnPhase::setMolarDensity",
101  "Density is not an independent variable");
102 }
103 
104 // Chemical Potentials and Activities
105 
106 void MaskellSolidSolnPhase::getActivityCoefficients(doublereal* ac) const
107 {
108  static const int cacheId = m_cache.getId();
109  CachedArray cached = m_cache.getArray(cacheId);
110  if (!cached.validate(temperature(), pressure(), stateMFNumber())) {
111  cached.value.resize(2);
112 
113  const doublereal r = moleFraction(product_species_index);
114  const doublereal pval = p(r);
115  const doublereal rfm = r * fm(r);
116  const doublereal A = (std::pow(1 - rfm, pval) * std::pow(rfm, pval) * std::pow(r - rfm, 1 - pval)) /
117  (std::pow(1 - r - rfm, 1 + pval) * (1 - r));
118  const doublereal B = pval * h_mixing / RT();
119  cached.value[product_species_index] = A * std::exp(B);
120  cached.value[reactant_species_index] = 1 / (A * r * (1-r) ) * std::exp(-B);
121  }
122  std::copy(cached.value.begin(), cached.value.end(), ac);
123 }
124 
125 void MaskellSolidSolnPhase::getChemPotentials(doublereal* mu) const
126 {
127  const doublereal r = moleFraction(product_species_index);
128  const doublereal pval = p(r);
129  const doublereal rfm = r * fm(r);
130  const doublereal DgbarDr = pval * h_mixing +
131  RT() *
132  std::log( (std::pow(1 - rfm, pval) * std::pow(rfm, pval) * std::pow(r - rfm, 1 - pval) * r) /
133  (std::pow(1 - r - rfm, 1 + pval) * (1 - r)) );
134  mu[product_species_index] = RT() * m_g0_RT[product_species_index] + DgbarDr;
135  mu[reactant_species_index] = RT() * m_g0_RT[reactant_species_index] - DgbarDr;
136 }
137 
138 void MaskellSolidSolnPhase::getChemPotentials_RT(doublereal* mu) const
139 {
140  getChemPotentials(mu);
141  for (size_t sp=0; sp < m_kk; ++sp) {
142  mu[sp] *= 1.0 / RT();
143  }
144 }
145 
146 // Partial Molar Properties
147 
148 void MaskellSolidSolnPhase::getPartialMolarEnthalpies(doublereal* hbar) const
149 {
150  throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarEnthalpies");
151 }
152 
153 void MaskellSolidSolnPhase::getPartialMolarEntropies(doublereal* sbar) const
154 {
155  throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarEntropies");
156 }
157 
158 void MaskellSolidSolnPhase::getPartialMolarCp(doublereal* cpbar) const
159 {
160  throw NotImplementedError("MaskellSolidSolnPhase::getPartialMolarCp");
161 }
162 
163 void MaskellSolidSolnPhase::getPartialMolarVolumes(doublereal* vbar) const
164 {
165  getStandardVolumes(vbar);
166 }
167 
168 void MaskellSolidSolnPhase::getPureGibbs(doublereal* gpure) const
169 {
170  for (size_t sp=0; sp < m_kk; ++sp) {
171  gpure[sp] = RT() * m_g0_RT[sp];
172  }
173 }
174 
175 void MaskellSolidSolnPhase::getStandardChemPotentials(doublereal* mu) const
176 {
177  // What is the difference between this and getPureGibbs? IdealSolidSolnPhase
178  // gives the same for both
179  getPureGibbs(mu);
180 }
181 
182 // Utility Functions
183 
184 void MaskellSolidSolnPhase::initThermo()
185 {
186  if (m_input.hasKey("excess-enthalpy")) {
187  set_h_mix(m_input.convert("excess-enthalpy", "J/kmol"));
188  }
189  if (m_input.hasKey("product-species")) {
190  setProductSpecies(m_input["product-species"].asString());
191  }
192  VPStandardStateTP::initThermo();
193 }
194 
195 
196 void MaskellSolidSolnPhase::initThermoXML(XML_Node& phaseNode, const std::string& id_)
197 {
198  if (id_.size() > 0 && phaseNode.id() != id_) {
199  throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
200  "phasenode and Id are incompatible");
201  }
202 
203  // Check on the thermo field. Must have:
204  // <thermo model="MaskellSolidSolution" />
205  if (phaseNode.hasChild("thermo")) {
206  XML_Node& thNode = phaseNode.child("thermo");
207  if (!caseInsensitiveEquals(thNode["model"], "maskellsolidsolnphase")) {
208  throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
209  "Unknown thermo model: " + thNode["model"]);
210  }
211 
212  // Parse the enthalpy of mixing constant
213  if (thNode.hasChild("h_mix")) {
214  set_h_mix(fpValue(thNode.child("h_mix").value()));
215  } else {
216  throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
217  "Mixing enthalpy parameter not specified.");
218  }
219 
220  if (thNode.hasChild("product_species")) {
221  setProductSpecies(thNode.child("product_species").value());
222  } else {
223  setProductSpecies(speciesName(0)); // default
224  }
225  } else {
226  throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
227  "Unspecified thermo model");
228  }
229 
230  // Confirm that the phase only contains 2 species
231  if (m_kk != 2) {
232  throw CanteraError("MaskellSolidSolnPhase::initThermoXML",
233  "MaskellSolidSolution model requires exactly 2 species.");
234  }
235 
236  // Call the base initThermo, which handles setting the initial state.
237  VPStandardStateTP::initThermoXML(phaseNode, id_);
238 }
239 
240 void MaskellSolidSolnPhase::setProductSpecies(const std::string& name)
241 {
242  product_species_index = static_cast<int>(speciesIndex(name));
243  if (product_species_index == -1) {
244  throw CanteraError("MaskellSolidSolnPhase::setProductSpecies",
245  "Species '{}' not found", name);
246  }
247  reactant_species_index = (product_species_index == 0) ? 1 : 0;
248 }
249 
250 doublereal MaskellSolidSolnPhase::s() const
251 {
252  return 1 + std::exp(h_mixing / RT());
253 }
254 
255 doublereal MaskellSolidSolnPhase::fm(const doublereal r) const
256 {
257  return (1 - std::sqrt(1 - 4*r*(1-r)/s())) / (2*r);
258 }
259 
260 doublereal MaskellSolidSolnPhase::p(const doublereal r) const
261 {
262  const doublereal sval = s();
263  return (1 - 2*r) / std::sqrt(sval*sval - 4 * sval * r + 4 * sval * r * r);
264 }
265 
266 } // end namespace Cantera
Header file for a solid solution model following Maskell, Shaw, and Tye.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:187
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:104
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:528
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:538
std::string value() const
Return the value of an XML node as a string.
Definition: xml.cpp:441
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:546
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:54
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:78
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:180
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:109
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
Contains declarations for string manipulation functions within Cantera.
T value
The value of the cached property.
Definition: ValueCache.h:118
bool validate(double state1New)
Check whether the currently cached value is valid based on a single state variable.
Definition: ValueCache.h:44
Classes providing support for XML data files.