Cantera 2.6.0
BinarySolutionTabulatedThermo.cpp
Go to the documentation of this file.
1/**
2 * @file BinarySolutionTabulatedThermo.cpp Implementation file for an binary
3 * solution model with tabulated standard state thermodynamic data (see
4 * \ref thermoprops and class
5 * \link Cantera::BinarySolutionTabulatedThermo BinarySolutionTabulatedThermo\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
12#include "cantera/thermo/PDSS.h"
16#include "cantera/base/ctml.h"
19
20namespace Cantera
21{
22
24 const std::string& id_)
25 : m_kk_tab(npos)
26 , m_xlast(-1)
27
28{
29 initThermoFile(inputFile, id_);
30}
31
33 const std::string& id_)
34 : m_kk_tab(npos)
35 , m_xlast(-1)
36{
37 importPhase(root, this);
38}
39
41{
44}
45
47{
48 double xnow = moleFraction(m_kk_tab);
49 bool x_changed = (m_xlast != xnow);
50
51 if (x_changed) {
52 m_h0_tab = interpolate(xnow, m_enthalpy_tab);
53 m_s0_tab = interpolate(xnow, m_entropy_tab);
54 if (xnow == 0) {
56 } else if (xnow == 1) {
58 } else {
59 m_s0_tab += GasConstant*std::log(xnow/(1.0-xnow)) +
62 }
63 m_xlast = xnow;
64 }
65
66 double tnow = temperature();
67 if (x_changed || m_tlast != tnow) {
68 // Update the thermodynamic functions of the reference state.
69 m_spthermo.update(tnow, m_cp0_R.data(), m_h0_RT.data(), m_s0_R.data());
70 double rrt = 1.0 / RT();
71 m_h0_RT[m_kk_tab] += m_h0_tab * rrt;
73 for (size_t k = 0; k < m_kk; k++) {
74 m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
75 }
76 m_tlast = tnow;
77 }
78}
79
80bool BinarySolutionTabulatedThermo::addSpecies(shared_ptr<Species> spec)
81{
82 if (m_kk == 2) {
83 throw CanteraError("BinarySolutionTabulatedThermo::addSpecies",
84 "No. of species should be equal to 2");
85 }
86 bool added = IdealSolidSolnPhase::addSpecies(spec);
87 return added;
88}
89
91{
92 if (m_input.hasKey("tabulated-thermo")) {
93 m_kk_tab = speciesIndex(m_input["tabulated-species"].asString());
94 if (nSpecies() != 2) {
95 throw InputFileError("BinarySolutionTabulatedThermo::initThermo",
96 m_input["species"],
97 "No. of species should be equal to 2 in phase '{}'!",name());
98 }
99 if (m_kk_tab == npos) {
100 throw InputFileError("BinarySolutionTabulatedThermo::initThermo",
101 m_input["tabulated-species"],
102 "Species '{}' is not in phase '{}'",
103 m_input["tabulated-species"].asString(), name());
104 }
105 const AnyMap& table = m_input["tabulated-thermo"].as<AnyMap>();
106 vector_fp x = table["mole-fractions"].asVector<double>();
107 size_t N = x.size();
108 vector_fp h = table.convertVector("enthalpy", "J/kmol", N);
109 vector_fp s = table.convertVector("entropy", "J/kmol/K", N);
110 vector_fp vmol(N);
111 // Check for molar-volume key in tabulatedThermo table,
112 // otherwise calculate molar volume from pure species molar volumes
113 if (table.hasKey("molar-volume")) {
114 vmol = table.convertVector("molar-volume", "m^3/kmol", N);
115 } else {
116 for(size_t i = 0; i < N; i++) {
117 vmol[i] = x[i] * m_speciesMolarVolume[m_kk_tab] + (1-x[i])
119 }
120 }
121
122 // Sort the x, h, s, vmol data in the order of increasing x
123 std::vector<std::pair<double,double>> x_h(N), x_s(N), x_vmol(N);
124 for(size_t i = 0; i < N; i++) {
125 x_h[i] = {x[i], h[i]};
126 x_s[i] = {x[i], s[i]};
127 x_vmol[i] = {x[i], vmol[i]};
128 }
129 std::sort(x_h.begin(), x_h.end());
130 std::sort(x_s.begin(), x_s.end());
131 std::sort(x_vmol.begin(), x_vmol.end());
132
133 // Store the sorted values in different arrays
134 m_molefrac_tab.resize(N);
135 m_enthalpy_tab.resize(N);
136 m_entropy_tab.resize(N);
137 m_molar_volume_tab.resize(N);
138 m_derived_molar_volume_tab.resize(N);
139 m_partial_molar_volume_1_tab.resize(N);
140 m_partial_molar_volume_2_tab.resize(N);
141
142 for (size_t i = 0; i < N; i++) {
143 m_molefrac_tab[i] = x_h[i].first;
144 m_enthalpy_tab[i] = x_h[i].second;
145 m_entropy_tab[i] = x_s[i].second;
146 m_molar_volume_tab[i] = x_vmol[i].second;
147 }
148
149 diff(m_molar_volume_tab, m_derived_molar_volume_tab);
150
151 for (size_t i = 0; i < N; i++) {
152 m_partial_molar_volume_1_tab[i] = m_molar_volume_tab[i] +
153 (1-m_molefrac_tab[i]) * m_derived_molar_volume_tab[i];
154 m_partial_molar_volume_2_tab[i] = m_molar_volume_tab[i] -
155 m_molefrac_tab[i] * m_derived_molar_volume_tab[i];
156 }
157 }
159}
160
162{
163 return !m_molefrac_tab.empty();
164}
165
167{
169 phaseNode["tabulated-species"] = speciesName(m_kk_tab);
170 AnyMap tabThermo;
171 tabThermo["mole-fractions"] = m_molefrac_tab;
172 tabThermo["enthalpy"].setQuantity(m_enthalpy_tab, "J/kmol");
173 tabThermo["entropy"].setQuantity(m_entropy_tab, "J/kmol/K");
174 phaseNode["tabulated-thermo"] = std::move(tabThermo);
175}
176
177void BinarySolutionTabulatedThermo::initThermoXML(XML_Node& phaseNode, const std::string& id_)
178{
179 vector_fp x, h, s, vmol;
180 std::vector<std::pair<double,double>> x_h_temp, x_s_temp, x_vmol_temp;
181
182 if (id_.size() > 0) {
183 if (phaseNode.id() != id_) {
184 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
185 "phasenode and Id are incompatible");
186 }
187 }
188 if (nSpecies()!=2) {
189 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
190 "No. of species should be equal to 2!");
191 }
192 if (phaseNode.hasChild("thermo")) {
193 XML_Node& thermoNode = phaseNode.child("thermo");
194 std::string mString = thermoNode["model"];
195 if (!caseInsensitiveEquals(mString, "binarysolutiontabulatedthermo")) {
196 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
197 "Unknown thermo model: " + mString);
198 }
199 if (thermoNode.hasChild("tabulatedSpecies")) {
200 XML_Node& speciesNode = thermoNode.child("tabulatedSpecies");
201 std::string tabulated_species_name = speciesNode["name"];
202 m_kk_tab = speciesIndex(tabulated_species_name);
203 if (m_kk_tab == npos) {
204 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
205 "Species " + tabulated_species_name + " not found.");
206 }
207 }
208 if (thermoNode.hasChild("tabulatedThermo")) {
209 XML_Node& dataNode = thermoNode.child("tabulatedThermo");
210 getFloatArray(dataNode, x, true, "", "moleFraction");
211 getFloatArray(dataNode, h, true, "J/kmol", "enthalpy");
212 getFloatArray(dataNode, s, true, "J/kmol/K", "entropy");
213 vmol.resize(x.size());
214 for(size_t i=0; i<vmol.size(); i++) {
215 vmol[i] = x[i] * m_speciesMolarVolume[m_kk_tab] + (1-x[i]) *
217 }
218 // Check for data length consistency
219 if ((x.size() != h.size()) || (x.size() != s.size()) ||
220 (x.size() != vmol.size())) {
221 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
222 "Species tabulated thermo data has different lengths.");
223 }
224 // Sort the x, h, s data in the order of increasing x
225 for(size_t i = 0; i < x.size(); i++){
226 x_h_temp.push_back(std::make_pair(x[i],h[i]));
227 x_s_temp.push_back(std::make_pair(x[i],s[i]));
228 x_vmol_temp.push_back(std::make_pair(x[i],vmol[i]));
229 }
230 std::sort(x_h_temp.begin(), x_h_temp.end());
231 std::sort(x_s_temp.begin(), x_s_temp.end());
232 std::sort(x_vmol_temp.begin(), x_vmol_temp.end());
233
234 // Store the sorted values in different arrays
235 m_molefrac_tab.resize(x_h_temp.size());
236 m_enthalpy_tab.resize(x_h_temp.size());
237 m_entropy_tab.resize(x_h_temp.size());
238 m_molar_volume_tab.resize(x_h_temp.size());
239 m_derived_molar_volume_tab.resize(x_h_temp.size());
240 m_partial_molar_volume_1_tab.resize(x_h_temp.size());
241 m_partial_molar_volume_2_tab.resize(x_h_temp.size());
242
243 for (size_t i = 0; i < x_h_temp.size(); i++) {
244 m_molefrac_tab[i] = x_h_temp[i].first;
245 m_enthalpy_tab[i] = x_h_temp[i].second;
246 m_entropy_tab[i] = x_s_temp[i].second;
247 m_molar_volume_tab[i] = x_vmol_temp[i].second;
248 }
249
250 diff(m_molar_volume_tab, m_derived_molar_volume_tab);
251
252 for (size_t i = 0; i < x_h_temp.size(); i++) {
253 m_partial_molar_volume_1_tab[i] = m_molar_volume_tab[i] +
254 (1-m_molefrac_tab[i]) * m_derived_molar_volume_tab[i];
255 m_partial_molar_volume_2_tab[i] = m_molar_volume_tab[i] -
256 m_molefrac_tab[i] * m_derived_molar_volume_tab[i];
257 }
258 } else {
259 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
260 "Unspecified tabulated species or thermo");
261 }
262 } else {
263 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
264 "Unspecified thermo model");
265 }
266
267 /*
268 * Form of the standard concentrations. Must have one of:
269 *
270 * <standardConc model="unity" />
271 * <standardConc model="molar_volume" />
272 * <standardConc model="solvent_volume" />
273 */
274 if (phaseNode.hasChild("standardConc")) {
275 XML_Node& scNode = phaseNode.child("standardConc");
276 setStandardConcentrationModel(scNode.attrib("model"));
277 } else {
278 throw CanteraError("BinarySolutionTabulatedThermo::initThermoXML",
279 "Unspecified standardConc model");
280 }
281
282 // Call the base initThermo, which handles setting the initial state
283 ThermoPhase::initThermoXML(phaseNode, id_);
284}
285
287 const vector_fp& inputData) const
288{
289 double c;
290 // Check if x is out of bound
291 if (x > m_molefrac_tab.back()) {
292 c = inputData.back();
293 return c;
294 }
295 if (x < m_molefrac_tab.front()) {
296 c = inputData.front();
297 return c;
298 }
299 size_t i = std::distance(m_molefrac_tab.begin(),
300 std::lower_bound(m_molefrac_tab.begin(), m_molefrac_tab.end(), x));
301 c = inputData[i-1] + (inputData[i] - inputData[i-1])
302 * (x - m_molefrac_tab[i-1]) / (m_molefrac_tab[i] - m_molefrac_tab[i-1]);
303 return c;
304}
305
307 vector_fp& derivedData) const
308{
309 if (inputData.size() > 1) {
310 derivedData[0] = (inputData[1] - inputData[0]) /
312 derivedData.back() = (inputData.back() - inputData[inputData.size()-2]) /
313 (m_molefrac_tab.back() - m_molefrac_tab[m_molefrac_tab.size()-2]);
314
315 if (inputData.size() > 2) {
316 for (size_t i = 1; i < inputData.size()-1; i++) {
317 derivedData[i] = (inputData[i+1] - inputData[i-1]) /
318 (m_molefrac_tab[i+1] - m_molefrac_tab[i-1]);
319 }
320 }
321 } else {
322 derivedData.front() = 0;
323 }
324}
325
327{
328 vbar[m_kk_tab] = interpolate(moleFraction(m_kk_tab), m_partial_molar_volume_1_tab);
330 m_partial_molar_volume_2_tab);
331}
332
334{
335 double vmol = interpolate(moleFraction(m_kk_tab), m_molar_volume_tab);
336 double dens = meanMolecularWeight()/vmol;
337
338 // Set the density in the parent State object directly, by calling the
339 // Phase::assignDensity() function.
341}
342}
Header file for an binary solution model with tabulated standard state thermodynamic data (see Thermo...
Header for a general species thermodynamic property manager for a phase (see MultiSpeciesThermo).
Declarations for the virtual base class PDSS (pressure dependent standard state) which handles calcul...
Header for factory functions to build instances of classes that manage the standard-state thermodynam...
Declaration for class Cantera::Species.
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
size_t size() const
Returns the number of elements in this map.
Definition: AnyMap.h:590
vector_fp convertVector(const std::string &key, const std::string &units, size_t nMin=npos, size_t nMax=npos) const
Convert a vector of dimensional values.
Definition: AnyMap.cpp:1528
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1406
double m_xlast
Current tabulated species mole fraction.
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
void diff(const vector_fp &inputData, vector_fp &derivedData) const
Numerical derivative of the molar volume table.
double m_s0_tab
Tabulated contribution to s0[m_kk_tab] at the current composition.
vector_fp m_molefrac_tab
Vector for storing tabulated thermo.
size_t m_kk_tab
Current tabulated species index.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
virtual void getPartialMolarVolumes(double *vbar) const
returns an array of partial molar volumes of the species in the solution.
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id_)
Import and initialize a ThermoPhase object using an XML tree.
double m_h0_tab
Tabulated contribution to h0[m_kk_tab] at the current composition.
virtual void compositionChanged()
If the compositions have changed, update the tabulated thermo lookup.
double interpolate(const double x, const vector_fp &inputData) const
Species thermodynamics linear interpolation function.
virtual void _updateThermo() const
This function gets called for every call to functions in this class.
virtual bool ready() const
Returns a bool indicating whether the object is ready for use.
BinarySolutionTabulatedThermo(const std::string &infile="", const std::string &id="")
Construct and initialize an BinarySolutionTabulatedThermo ThermoPhase object directly from an input f...
virtual void calcDensity()
Overloads the calcDensity() method of IdealSolidSoln to also consider non-ideal behavior.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
vector_fp m_g0_RT
Vector containing the species reference Gibbs functions at T = m_tlast.
vector_fp m_cp0_R
Vector containing the species reference constant pressure heat capacities at T = m_tlast.
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
vector_fp m_h0_RT
Vector containing the species reference enthalpies at T = m_tlast.
vector_fp m_s0_R
Vector containing the species reference entropies at T = m_tlast.
vector_fp m_speciesMolarVolume
Vector of molar volumes for each species in the solution.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
virtual doublereal standardConcentration(size_t k) const
The standard concentration used to normalize the generalized concentration.
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
void setStandardConcentrationModel(const std::string &model)
Set the form for the standard and generalized concentrations.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:702
virtual void update(doublereal T, doublereal *cp_R, doublereal *h_RT, doublereal *s_R) const
Compute the reference-state properties for all species.
void assignDensity(const double density_)
Set the internally stored constant density (kg/m^3) of the phase.
Definition: Phase.cpp:698
std::string name() const
Return the name of the phase.
Definition: Phase.cpp:70
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:273
size_t m_kk
Number of species in the phase.
Definition: Phase.h:943
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:200
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:751
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition: Phase.cpp:548
doublereal temperature() const
Temperature (K).
Definition: Phase.h:654
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition: Phase.cpp:187
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:782
doublereal m_tlast
last value of the temperature processed by reference state
Definition: ThermoPhase.h:1928
void initThermoFile(const std::string &inputFile, const std::string &id)
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1894
AnyMap m_input
Data supplied via setParameters.
Definition: ThermoPhase.h:1898
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:493
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:539
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
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
const double Faraday
Faraday constant [C/kmol].
Definition: ct_defs.h:128
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
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
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:113
size_t getFloatArray(const XML_Node &node, vector_fp &v, const bool convert=true, const std::string &unitsString="", const std::string &nodeName="floatArray")
This function reads the current node or a child node of the current node with the default name,...
Definition: ctml.cpp:258
const double BigNumber
largest number to compare to inf.
Definition: ct_defs.h:155
Contains declarations for string manipulation functions within Cantera.