12#include <boost/algorithm/string.hpp>
33 m_kappa[k] = 0.37464 + 1.54226*w - 0.26992*w*w;
35 m_kappa[k] = 0.374642 + 1.487503*w - 0.164423*w*w + 0.016666*w*w*w;
42 double sqt_alpha = 1 + m_kappa[k] * (1 - sqt_T_r);
43 m_alpha[k] = sqt_alpha*sqt_alpha;
46 double aAlpha_k = a*m_alpha[k];
47 m_aAlpha_binary(k,k) = aAlpha_k;
50 for (
size_t j = 0; j <
m_kk; j++) {
54 double a0kj = sqrt(m_a_coeffs(j,j) * a);
55 double aAlpha_j = a*m_alpha[j];
56 double a_Alpha = sqrt(aAlpha_j*aAlpha_k);
57 if (m_a_coeffs(j, k) == 0) {
58 m_a_coeffs(j, k) = a0kj;
59 m_aAlpha_binary(j, k) = a_Alpha;
60 m_a_coeffs(k, j) = a0kj;
61 m_aAlpha_binary(k, j) = a_Alpha;
68 const string& species_j,
double a0)
73 m_a_coeffs(ki, kj) = m_a_coeffs(kj, ki) = a0;
77 double alpha_ij = m_alpha[ki] * m_alpha[kj];
78 m_aAlpha_binary(ki, kj) = m_aAlpha_binary(kj, ki) = a0*alpha_ij;
111 double denom = mv * mv + 2 * mv *
m_b -
m_b *
m_b;
124 double vpb2 = mv + (1 +
Sqrt2) *
m_b;
125 double vmb2 = mv + (1 -
Sqrt2) *
m_b;
126 double vmb = mv -
m_b;
129 for (
size_t k = 0; k <
m_kk; k++) {
131 for (
size_t i = 0; i <
m_kk; i++) {
137 double denom2 =
m_b * (mv * mv + 2 * mv *
m_b -
m_b *
m_b);
139 for (
size_t k = 0; k <
m_kk; k++) {
141 ac[k] = (-RT_ * log(pres * mv/ RT_) + RT_ * log(mv / vmb)
142 + RT_ * m_b_coeffs[k] / vmb
143 - (num /denom) * log(vpb2/vmb2)
147 for (
size_t k = 0; k <
m_kk; k++) {
148 ac[k] = exp(ac[k]/ RT_);
158 for (
size_t k = 0; k <
m_kk; k++) {
160 mu[k] += RT_ * (log(xx));
164 double vmb = mv -
m_b;
165 double vpb2 = mv + (1 +
Sqrt2) *
m_b;
166 double vmb2 = mv + (1 -
Sqrt2) *
m_b;
168 for (
size_t k = 0; k <
m_kk; k++) {
170 for (
size_t i = 0; i <
m_kk; i++) {
177 double denom2 =
m_b * (mv * mv + 2 * mv *
m_b -
m_b *
m_b);
179 for (
size_t k = 0; k <
m_kk; k++) {
182 mu[k] += RT_ * log(pres/refP) - RT_ * log(pres * mv / RT_)
183 + RT_ * log(mv / vmb) + RT_ * m_b_coeffs[k] / vmb
184 - (num /denom) * log(vpb2/vmb2)
195 tmp.resize(
m_kk,0.0);
200 double vmb = mv -
m_b;
201 double vpb2 = mv + (1 +
Sqrt2) *
m_b;
202 double vmb2 = mv + (1 -
Sqrt2) *
m_b;
205 for (
size_t k = 0; k <
m_kk; k++) {
208 for (
size_t i = 0; i <
m_kk; i++) {
209 double grad_aAlpha = m_dalphadT[i]/m_alpha[i] + m_dalphadT[k]/m_alpha[k];
215 double denom = mv * mv + 2 * mv *
m_b -
m_b *
m_b;
216 double denom2 = denom * denom;
218 for (
size_t k = 0; k <
m_kk; k++) {
219 m_dpdni[k] = RT_ / vmb + RT_ * m_b_coeffs[k] / (vmb * vmb)
228 for (
size_t k = 0; k <
m_kk; k++) {
229 fac4 = T*tmp[k] -2 *
m_pp[k];
230 double hE_v = mv *
m_dpdni[k] - RT_
231 - m_b_coeffs[k] / fac3 * log(vpb2 / vmb2) * fac
232 + (mv * m_b_coeffs[k]) / (
m_b * denom) * fac
233 + 1 / (2 *
Sqrt2 *
m_b) * log(vpb2 / vmb2) * fac4;
234 hbar[k] = hbar[k] + hE_v;
245 for (
size_t k = 0; k <
m_kk; k++) {
246 sbar[k] = (sbar[k] -
m_workS[k])/T;
256 for (
size_t k = 0; k <
m_kk; k++) {
257 ubar[k] = ubar[k] - p*
m_workS[k];
268 for (
size_t k = 0; k <
m_kk; k++) {
270 for (
size_t i = 0; i <
m_kk; i++) {
276 double vmb = mv -
m_b;
277 double vpb = mv +
m_b;
278 double fac = mv * mv + 2 * mv *
m_b -
m_b *
m_b;
279 double fac2 = fac * fac;
282 for (
size_t k = 0; k <
m_kk; k++) {
283 double num = RT_ + RT_ *
m_b/ vmb + RT_ * m_b_coeffs[k] / vmb
284 + RT_ *
m_b * m_b_coeffs[k] /(vmb * vmb) - 2 * mv *
m_pp[k] / fac
288 vbar[k] = num / denom;
296 }
else if (a <= 0.0) {
308 m_b_coeffs.push_back(0.0);
310 m_kappa.push_back(0.0);
312 m_alpha.push_back(0.0);
313 m_dalphadT.push_back(0.0);
314 m_d2alphadT2.push_back(0.0);
316 m_partialMolarVolumes.push_back(0.0);
327 std::unordered_map<string, AnyMap*> dbSpecies;
332 if (m_a_coeffs(k, k) != 0.0) {
335 bool foundCoeffs =
false;
336 if (data.hasKey(
"equation-of-state") &&
337 data[
"equation-of-state"].hasMapWhere(
"model",
"Peng-Robinson"))
341 auto eos = data[
"equation-of-state"].getMapWhere(
342 "model",
"Peng-Robinson");
343 if (eos.hasKey(
"a") && eos.hasKey(
"b") && eos.hasKey(
"acentric-factor")) {
344 double a0 = eos.convert(
"a",
"Pa*m^6/kmol^2");
345 double b = eos.convert(
"b",
"m^3/kmol");
347 double w = eos[
"acentric-factor"].asDouble();
352 if (eos.hasKey(
"binary-a")) {
355 for (
auto& [name2, coeff] : binary_a) {
356 double a0 = units.
convert(coeff,
"Pa*m^6/kmol^2");
367 double Tc = NAN, Pc = NAN, omega_ac = NAN;
368 if (data.hasKey(
"critical-parameters")) {
371 auto& critProps = data[
"critical-parameters"].as<
AnyMap>();
372 Tc = critProps.
convert(
"critical-temperature",
"K");
373 Pc = critProps.convert(
"critical-pressure",
"Pa");
374 omega_ac = critProps[
"acentric-factor"].asDouble();
378 if (critPropsDb.
empty()) {
380 dbSpecies = critPropsDb[
"species"].asMap(
"name");
384 auto ucName = boost::algorithm::to_upper_copy(
name);
385 if (dbSpecies.count(ucName)) {
386 auto& spec = *dbSpecies.at(ucName);
387 auto& critProps = spec[
"critical-parameters"].as<
AnyMap>();
388 Tc = critProps.
convert(
"critical-temperature",
"K");
389 Pc = critProps.convert(
"critical-pressure",
"Pa");
390 omega_ac = critProps[
"acentric-factor"].asDouble();
402 "No Peng-Robinson model parameters or critical properties found for "
403 "species '{}'",
name);
415 auto& eosNode = speciesNode[
"equation-of-state"].getMapWhere(
416 "model",
"Peng-Robinson",
true);
417 eosNode[
"a"].setQuantity(m_a_coeffs(k, k),
"Pa*m^6/kmol^2");
418 eosNode[
"b"].setQuantity(m_b_coeffs[k],
"m^3/kmol");
421 auto& critProps = speciesNode[
"critical-parameters"];
424 critProps[
"critical-temperature"].setQuantity(Tc,
"K");
425 critProps[
"critical-pressure"].setQuantity(Pc,
"Pa");
433 auto& eosNode = speciesNode[
"equation-of-state"].getMapWhere(
434 "model",
"Peng-Robinson",
true);
437 bin_a[
species].setQuantity(coeff,
"Pa*m^6/kmol^2");
439 eosNode[
"binary-a"] = std::move(bin_a);
446 double hh =
m_b / molarV;
449 double vpb = molarV + (1.0 +
Sqrt2) *
m_b;
450 double vmb = molarV + (1.0 -
Sqrt2) *
m_b;
451 double fac = alpha_1 / (2.0 *
Sqrt2 *
m_b);
452 double sresid_mol_R = log(zz*(1.0 - hh)) + fac * log(vpb / vmb) /
GasConstant;
462 double vpb = molarV + (1 +
Sqrt2) *
m_b;
463 double vmb = molarV + (1 -
Sqrt2) *
m_b;
464 double fac = 1 / (2.0 *
Sqrt2 *
m_b);
471 double v =
m_b * 1.1;
472 double atmp, btmp, aAlphatmp;
474 double pres = std::max(
psatEst(T), presGuess);
476 bool foundLiq =
false;
478 while (m < 100 && !foundLiq) {
479 int nsol =
solveCubic(T, pres, atmp, btmp, aAlphatmp, Vroot);
480 if (nsol == 1 || nsol == 2) {
507 if (rhoGuess == -1.0) {
508 if (phaseRequested >= FLUID_LIQUID_0) {
510 rhoGuess = mmw / lqvol;
517 double volGuess = mmw / rhoGuess;
520 double molarVolLast = m_Vroot[0];
522 if (phaseRequested >= FLUID_LIQUID_0) {
523 molarVolLast = m_Vroot[0];
524 }
else if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT) {
525 molarVolLast = m_Vroot[2];
527 if (volGuess > m_Vroot[1]) {
528 molarVolLast = m_Vroot[2];
530 molarVolLast = m_Vroot[0];
533 }
else if (m_NSolns == 1) {
534 if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT
535 || phaseRequested == FLUID_UNDEFINED)
537 molarVolLast = m_Vroot[0];
541 }
else if (m_NSolns == -1) {
542 if (phaseRequested >= FLUID_LIQUID_0 || phaseRequested == FLUID_UNDEFINED
543 || phaseRequested == FLUID_SUPERCRIT)
545 molarVolLast = m_Vroot[0];
546 }
else if (T > tcrit) {
547 molarVolLast = m_Vroot[0];
552 molarVolLast = m_Vroot[0];
555 return mmw / molarVolLast;
560 double denom = molarVol * molarVol + 2 * molarVol *
m_b -
m_b *
m_b;
561 double vpb = molarVol +
m_b;
562 double vmb = molarVol -
m_b;
591 double vmb = mv -
m_b;
592 double denom = mv * mv + 2 * mv *
m_b -
m_b *
m_b;
601 for (
size_t j = 0; j <
m_kk; j++) {
603 double sqt_alpha = 1 + m_kappa[j] * (1 - sqrt(temp / critTemp_j));
604 m_alpha[j] = sqt_alpha*sqt_alpha;
608 for (
size_t i = 0; i <
m_kk; i++) {
609 for (
size_t j = 0; j <
m_kk; j++) {
610 m_aAlpha_binary(i, j) = sqrt(m_alpha[i] * m_alpha[j]) * m_a_coeffs(i,j);
621 for (
size_t i = 0; i <
m_kk; i++) {
623 for (
size_t j = 0; j <
m_kk; j++) {
632 double daAlphadT = 0.0, k, Tc, sqtTr, coeff1, coeff2;
633 for (
size_t i = 0; i <
m_kk; i++) {
637 coeff1 = 1 / (Tc*sqtTr);
640 m_dalphadT[i] = coeff1 * (k*k*coeff2 - k);
643 for (
size_t i = 0; i <
m_kk; i++) {
644 for (
size_t j = 0; j <
m_kk; j++) {
646 * m_aAlpha_binary(i, j)
647 * (m_dalphadT[i] / m_alpha[i] + m_dalphadT[j] / m_alpha[j]);
655 for (
size_t i = 0; i <
m_kk; i++) {
658 double coeff1 = 1 / (Tcrit_i*sqt_Tr);
659 double coeff2 = sqt_Tr - 1;
661 double k = m_kappa[i];
662 m_dalphadT[i] = coeff1 * (k*k*coeff2 - k);
663 m_d2alphadT2[i] = (k*k + k) * coeff1 / (2*sqt_Tr*sqt_Tr*Tcrit_i);
667 double d2aAlphadT2 = 0.0;
668 for (
size_t i = 0; i <
m_kk; i++) {
669 double alphai = m_alpha[i];
670 for (
size_t j = 0; j <
m_kk; j++) {
671 double alphaj = m_alpha[j];
672 double alphaij = alphai * alphaj;
673 double term1 = m_d2alphadT2[i] / alphai + m_d2alphadT2[j] / alphaj;
674 double term2 = 2 * m_dalphadT[i] * m_dalphadT[j] / alphaij;
675 double term3 = m_dalphadT[i] / alphai + m_dalphadT[j] / alphaj;
677 * m_aAlpha_binary(i, j)
678 * (term1 + term2 - 0.5 * term3 * term3);
684void PengRobinson::calcCriticalConditions(
double& pc,
double& tc,
double& vc)
const
704 double Vroot[3])
const
709 double aAlpha_p = aAlpha / pres;
711 double bn = (b - RT_p);
712 double cn = -(2 * RT_p * b - aAlpha_p + 3 * bsqr);
713 double dn = (bsqr * RT_p + bsqr * b - aAlpha_p * b);
720 an, bn, cn, dn, tc, vc);
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.
const UnitSystem & units() const
Return the default units that should be used to convert stored values.
bool empty() const
Return boolean indicating whether AnyMap is empty.
double convert(const string &key, const string &units) const
Convert the item stored by the given key to the units specified in units.
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
virtual void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
double critPressure() const override
Critical pressure (Pa).
void getGibbs_ref(double *g) const override
Returns the vector of the Gibbs function of the reference state at the current temperature of the sol...
double critTemperature() const override
Critical temperature (K).
virtual void _updateReferenceStateThermo() const
Updates the reference state thermodynamic functions at the current T of the solution.
int solveCubic(double T, double pres, double a, double b, double aAlpha, double Vroot[3], double an, double bn, double cn, double dn, double tc, double vc) const
Solve the cubic equation of state.
vector< double > moleFractions_
Storage for the current values of the mole fractions of the species.
void setTemperature(const double temp) override
Set the temperature of the phase.
virtual double psatEst(double TKelvin) const
Estimate for the saturation pressure.
void getStandardVolumes(double *vol) const override
Get the molar volumes of each species in their standard states at the current T and P of the solution...
vector< double > m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
double z() const
Calculate the value of z.
void getEnthalpy_RT_ref(double *hrt) const override
Returns the vector of nondimensional enthalpies of the reference state at the current temperature of ...
An error indicating that an unimplemented function has been called.
double thermalExpansionCoeff() const override
Return the volumetric thermal expansion coefficient. Units: 1/K.
void getPartialMolarEnthalpies(double *hbar) const override
Returns an array of partial molar enthalpies for the species in the mixture.
void getChemPotentials(double *mu) const override
Get the species chemical potentials. Units: J/kmol.
void setSpeciesCoeffs(const string &species, double a, double b, double w)
Set the pure fluid interaction parameters for a species.
double sresid() const override
Calculate the deviation terms for the total entropy of the mixture from the ideal gas mixture.
double soundSpeed() const override
Return the speed of sound. Units: m/s.
double pressure() const override
Return the thermodynamic pressure (Pa).
map< string, map< string, double > > m_binaryParameters
Explicitly-specified binary interaction parameters, to enable serialization.
void getSpeciesParameters(const string &name, AnyMap &speciesNode) const override
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
static const double omega_b
Omega constant: b0 (= omega_b) used in Peng-Robinson equation of state.
vector< double > m_pp
Temporary storage - length = m_kk.
void setBinaryCoeffs(const string &species_i, const string &species_j, double a)
Set values for the interaction parameter between two species.
vector< double > m_dpdni
Vector of derivatives of pressure with respect to mole number.
PengRobinson(const string &infile="", const string &id="")
Construct and initialize a PengRobinson object directly from an input file.
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
double m_dpdT
The derivative of the pressure with respect to the temperature.
void getPartialMolarVolumes(double *vbar) const override
Return an array of partial molar volumes for the species in the mixture.
double cv_mole() const override
Molar heat capacity at constant volume and composition [J/kmol/K].
double liquidVolEst(double T, double &pres) const override
Estimate for the molar volume of the liquid.
int solveCubic(double T, double pres, double a, double b, double aAlpha, double Vroot[3]) const
Prepare variables and call the function to solve the cubic equation of state.
double daAlpha_dT() const
Calculate temperature derivative .
void calculatePressureDerivatives() const
Calculate and at the current conditions.
double isothermalCompressibility() const override
Returns the isothermal compressibility. Units: 1/Pa.
double hresid() const override
Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture.
double m_aAlpha_mix
Value of in the equation of state.
double m_a
Value of in the equation of state.
static const double omega_a
Omega constant: a0 (= omega_a) used in Peng-Robinson equation of state.
static const double omega_vc
Omega constant for the critical molar volume.
vector< CoeffSource > m_coeffSource
For each species, specifies the source of the a, b, and omega coefficients.
void calculateAB(double &aCalc, double &bCalc, double &aAlpha) const
Calculate the , , and parameters given the temperature.
void getPartialMolarIntEnergies(double *ubar) const override
Return an array of partial molar internal energies for the species in the mixture.
void updateMixingExpressions() override
Update the , , and parameters.
double cp_mole() const override
Molar heat capacity at constant pressure and composition [J/kmol/K].
double m_b
Value of in the equation of state.
void getPartialMolarCp(double *cpbar) const override
Calculate species-specific molar specific heats.
double standardConcentration(size_t k=0) const override
Returns the standard concentration , which is used to normalize the generalized concentration.
AnyMap getAuxiliaryData() override
Return parameters used by the Peng-Robinson equation of state.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
double dpdVCalc(double T, double molarVol, double &presCalc) const override
Calculate the pressure and the pressure derivative given the temperature and the molar volume.
void getActivityCoefficients(double *ac) const override
Get the array of non-dimensional activity coefficients at the current solution temperature,...
double d2aAlpha_dT2() const
Calculate second derivative .
double densityCalc(double T, double pressure, int phase, double rhoguess) override
Calculates the density given the temperature and the pressure and a guess at the density.
void getPartialMolarEntropies(double *sbar) const override
Returns an array of partial molar entropies of the species in the solution.
double m_dpdV
The derivative of the pressure with respect to the volume.
double speciesCritTemperature(double a, double b) const
Calculate species-specific critical temperature.
vector< double > m_acentric
acentric factor for each species, length m_kk
vector< double > m_workS
Vector of size m_kk, used as a temporary holding area.
size_t m_kk
Number of species in the phase.
size_t speciesIndex(const string &name, bool raise=true) const
Returns the index of a species named 'name' within the Phase object.
double temperature() const
Temperature (K).
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
map< string, shared_ptr< Species > > m_species
Map of Species objects.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
double mean_X(const double *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
shared_ptr< Species > species(const string &name) const
Return the Species object for the named species.
virtual double molarVolume() const
Molar volume (m^3/kmol).
string name() const
Return the name of the phase.
double RT() const
Return the Gas Constant multiplied by the current temperature.
AnyMap parameters(bool withInput=true) const
Returns the parameters of a ThermoPhase object such that an identical one could be reconstructed usin...
virtual AnyMap getAuxiliaryData()
Return intermediate or model-specific parameters used by particular derived classes.
void initThermoFile(const string &inputFile, const string &id)
Initialize a ThermoPhase object using an input file.
virtual void getSpeciesParameters(const string &name, AnyMap &speciesNode) const
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
virtual double refPressure() const
Returns the reference pressure in Pa.
double convert(double value, const string &src, const string &dest) const
Convert value from the units of src to the units of dest.
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
const double GasConstant
Universal Gas Constant [J/kmol/K].
const double Sqrt2
Sqrt(2)
Namespace for the Cantera kernel.
const double SmallNumber
smallest number to compare to zero.
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...