12#include <boost/algorithm/string.hpp>
13#include <boost/math/tools/roots.hpp>
15namespace bmt = boost::math::tools;
30 double a0,
double a1,
double b)
38 size_t counter = k +
m_kk * k;
39 a_coeff_vec(0, counter) = a0;
40 a_coeff_vec(1, counter) = a1;
43 for (
size_t j = 0; j <
m_kk; j++) {
49 if (isnan(a_coeff_vec(0, j +
m_kk * j))) {
52 }
else if (isnan(a_coeff_vec(0, j +
m_kk * k))) {
55 double a0kj = sqrt(a_coeff_vec(0, j +
m_kk * j) * a0);
56 double a1kj = sqrt(a_coeff_vec(1, j +
m_kk * j) * a1);
57 a_coeff_vec(0, j +
m_kk * k) = a0kj;
58 a_coeff_vec(1, j +
m_kk * k) = a1kj;
59 a_coeff_vec(0, k +
m_kk * j) = a0kj;
60 a_coeff_vec(1, k +
m_kk * j) = a1kj;
63 a_coeff_vec.
getRow(0, a_vec_Curr_.data());
79 size_t counter1 = ki +
m_kk * kj;
80 size_t counter2 = kj +
m_kk * ki;
81 a_coeff_vec(0, counter1) = a_coeff_vec(0, counter2) = a0;
82 a_coeff_vec(1, counter1) = a_coeff_vec(1, counter2) = a1;
83 a_vec_Curr_[counter1] = a_vec_Curr_[counter2] = a0;
92 double sqt = sqrt(TKelvin);
97 double dadt = da_dt();
98 double fac = TKelvin * dadt - 3.0 *
m_a_current / 2.0;
100 +1.0/(
m_b_current * sqt) * log(vpb/mv) * (-0.5 * dadt));
108 double sqt = sqrt(TKelvin);
112 double dadt = da_dt();
113 double fac = TKelvin * dadt - 3.0 *
m_a_current / 2.0;
114 return (cvref - 1.0/(2.0 *
m_b_current * TKelvin * sqt) * log(vpb/mv)*fac
115 +1.0/(
m_b_current * sqt) * log(vpb/mv)*(-0.5*dadt));
142 for (
size_t k = 0; k <
m_kk; k++) {
144 for (
size_t i = 0; i <
m_kk; i++) {
145 size_t counter = k +
m_kk*i;
151 for (
size_t k = 0; k <
m_kk; k++) {
152 ac[k] = (-
RT() * log(pres * mv /
RT())
153 +
RT() * log(mv / vmb)
154 +
RT() * b_vec_Curr_[k] / vmb
160 for (
size_t k = 0; k <
m_kk; k++) {
161 ac[k] = exp(ac[k]/
RT());
170 for (
size_t k = 0; k <
m_kk; k++) {
172 mu[k] +=
RT()*(log(xx));
180 for (
size_t k = 0; k <
m_kk; k++) {
182 for (
size_t i = 0; i <
m_kk; i++) {
183 size_t counter = k +
m_kk*i;
190 for (
size_t k = 0; k <
m_kk; k++) {
191 mu[k] += (
RT() * log(pres/refP) -
RT() * log(pres * mv /
RT())
192 +
RT() * log(mv / vmb)
193 +
RT() * b_vec_Curr_[k] / vmb
210 double sqt = sqrt(TKelvin);
213 for (
size_t k = 0; k <
m_kk; k++) {
215 for (
size_t i = 0; i <
m_kk; i++) {
216 size_t counter = k +
m_kk*i;
220 for (
size_t k = 0; k <
m_kk; k++) {
221 dpdni_[k] =
RT()/vmb +
RT() * b_vec_Curr_[k] / (vmb * vmb) - 2.0 *
m_pp[k] / (sqt * mv * vpb)
222 +
m_a_current * b_vec_Curr_[k]/(sqt * mv * vpb * vpb);
224 double dadt = da_dt();
225 double fac = TKelvin * dadt - 3.0 *
m_a_current / 2.0;
227 for (
size_t k = 0; k <
m_kk; k++) {
229 for (
size_t i = 0; i <
m_kk; i++) {
230 size_t counter = k +
m_kk*i;
237 for (
size_t k = 0; k <
m_kk; k++) {
240 + b_vec_Curr_[k] / vpb / (
m_b_current * sqt) * fac);
241 hbar[k] = hbar[k] + hE_v;
242 hbar[k] -= fac2 *
dpdni_[k];
251 double sqt = sqrt(TKelvin);
255 for (
size_t k = 0; k <
m_kk; k++) {
259 for (
size_t k = 0; k <
m_kk; k++) {
261 for (
size_t i = 0; i <
m_kk; i++) {
262 size_t counter = k +
m_kk*i;
266 for (
size_t k = 0; k <
m_kk; k++) {
268 for (
size_t i = 0; i <
m_kk; i++) {
269 size_t counter = k +
m_kk*i;
274 double dadt = da_dt();
278 for (
size_t k = 0; k <
m_kk; k++) {
286 - 1.0 / (
m_b_current * sqt) * b_vec_Curr_[k] / vpb * fac
292 for (
size_t k = 0; k <
m_kk; k++) {
293 sbar[k] -= -m_partialMolarVolumes[k] *
dpdT_;
303 for (
size_t k = 0; k <
nSpecies(); k++) {
304 ubar[k] -= p * m_partialMolarVolumes[k];
310 for (
size_t k = 0; k <
m_kk; k++) {
312 for (
size_t i = 0; i <
m_kk; i++) {
313 size_t counter = k +
m_kk*i;
317 for (
size_t k = 0; k <
m_kk; k++) {
319 for (
size_t i = 0; i <
m_kk; i++) {
320 size_t counter = k +
m_kk*i;
329 for (
size_t k = 0; k <
m_kk; k++) {
332 - 2.0 *
m_pp[k] / (sqt * vpb)
337 vbar[k] = num / denom;
345 a_vec_Curr_.resize(
m_kk *
m_kk, 0.0);
349 b_vec_Curr_.push_back(NAN);
354 m_partialMolarVolumes.push_back(0.0);
364 std::unordered_map<string, AnyMap*> dbSpecies;
369 if (!isnan(a_coeff_vec(0, k +
m_kk * k))) {
372 bool foundCoeffs =
false;
374 if (data.hasKey(
"equation-of-state") &&
375 data[
"equation-of-state"].hasMapWhere(
"model",
"Redlich-Kwong"))
379 auto eos = data[
"equation-of-state"].getMapWhere(
380 "model",
"Redlich-Kwong");
382 if (eos.hasKey(
"a") && eos.hasKey(
"b")) {
383 double a0 = 0, a1 = 0;
384 if (eos[
"a"].isScalar()) {
385 a0 = eos.convert(
"a",
"Pa*m^6/kmol^2*K^0.5");
387 auto avec = eos[
"a"].asVector<
AnyValue>(2);
388 a0 = eos.units().convert(avec[0],
"Pa*m^6/kmol^2*K^0.5");
389 a1 = eos.units().convert(avec[1],
"Pa*m^6/kmol^2/K^0.5");
391 double b = eos.convert(
"b",
"m^3/kmol");
397 if (eos.hasKey(
"binary-a")) {
400 for (
auto& [name2, coeff] : binary_a) {
401 double a0 = 0, a1 = 0;
402 if (coeff.isScalar()) {
403 a0 = units.
convert(coeff,
"Pa*m^6/kmol^2*K^0.5");
405 auto avec = coeff.asVector<
AnyValue>(2);
406 a0 = units.convert(avec[0],
"Pa*m^6/kmol^2*K^0.5");
407 a1 = units.convert(avec[1],
"Pa*m^6/kmol^2/K^0.5");
419 double Tc = NAN, Pc = NAN;
420 if (data.hasKey(
"critical-parameters")) {
423 auto& critProps = data[
"critical-parameters"].as<
AnyMap>();
424 Tc = critProps.
convert(
"critical-temperature",
"K");
425 Pc = critProps.convert(
"critical-pressure",
"Pa");
429 if (critPropsDb.
empty()) {
431 dbSpecies = critPropsDb[
"species"].asMap(
"name");
435 auto ucName = boost::algorithm::to_upper_copy(
name);
436 if (dbSpecies.count(ucName)) {
437 auto& spec = *dbSpecies.at(ucName);
438 auto& critProps = spec[
"critical-parameters"].as<
AnyMap>();
439 Tc = critProps.
convert(
"critical-temperature",
"K");
440 Pc = critProps.convert(
"critical-pressure",
"Pa");
453 "No critical property or Redlich-Kwong parameters found "
454 "for species {}.",
name);
460 AnyMap& speciesNode)
const
465 auto& eosNode = speciesNode[
"equation-of-state"].getMapWhere(
466 "model",
"Redlich-Kwong",
true);
468 size_t counter = k +
m_kk * k;
469 if (a_coeff_vec(1, counter) != 0.0) {
470 vector<AnyValue> coeffs(2);
471 coeffs[0].setQuantity(a_coeff_vec(0, counter),
"Pa*m^6/kmol^2*K^0.5");
472 coeffs[1].setQuantity(a_coeff_vec(1, counter),
"Pa*m^6/kmol^2/K^0.5");
473 eosNode[
"a"] = std::move(coeffs);
475 eosNode[
"a"].setQuantity(a_coeff_vec(0, counter),
476 "Pa*m^6/kmol^2*K^0.5");
478 eosNode[
"b"].setQuantity(b_vec_Curr_[k],
"m^3/kmol");
480 auto& critProps = speciesNode[
"critical-parameters"];
481 double a = a_coeff_vec(0, k +
m_kk * k);
482 double b = b_vec_Curr_[k];
485 critProps[
"critical-temperature"].setQuantity(Tc,
"K");
486 critProps[
"critical-pressure"].setQuantity(Pc,
"Pa");
490 auto& eosNode = speciesNode[
"equation-of-state"].getMapWhere(
491 "model",
"Redlich-Kwong",
true);
494 if (coeffs.second == 0) {
495 bin_a[name2].setQuantity(coeffs.first,
"Pa*m^6/kmol^2*K^0.5");
497 vector<AnyValue> C(2);
498 C[0].setQuantity(coeffs.first,
"Pa*m^6/kmol^2*K^0.5");
499 C[1].setQuantity(coeffs.second,
"Pa*m^6/kmol^2/K^0.5");
500 bin_a[name2] = std::move(C);
503 eosNode[
"binary-a"] = std::move(bin_a);
512 double molarV = mmw / rho;
515 double dadt = da_dt();
517 double sqT = sqrt(T);
528 double molarV = mmw / rho;
531 double dadt = da_dt();
533 double sqT = sqrt(T);
544 double pres = std::max(
psatEst(TKelvin), presGuess);
546 bool foundLiq =
false;
548 while (m < 100 && !foundLiq) {
549 int nsol =
solveCubic(TKelvin, pres, atmp, btmp, Vroot);
550 if (nsol == 1 || nsol == 2) {
577 if (rhoguess == -1.0) {
578 if (phaseRequested >= FLUID_LIQUID_0) {
580 rhoguess = mmw / lqvol;
588 double volguess = mmw / rhoguess;
591 double molarVolLast = Vroot_[0];
593 if (phaseRequested >= FLUID_LIQUID_0) {
594 molarVolLast = Vroot_[0];
595 }
else if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT) {
596 molarVolLast = Vroot_[2];
598 if (volguess > Vroot_[1]) {
599 molarVolLast = Vroot_[2];
601 molarVolLast = Vroot_[0];
604 }
else if (NSolns_ == 1) {
605 if (phaseRequested == FLUID_GAS || phaseRequested == FLUID_SUPERCRIT || phaseRequested == FLUID_UNDEFINED) {
606 molarVolLast = Vroot_[0];
610 }
else if (NSolns_ == -1) {
611 if (phaseRequested >= FLUID_LIQUID_0 || phaseRequested == FLUID_UNDEFINED || phaseRequested == FLUID_SUPERCRIT) {
612 molarVolLast = Vroot_[0];
613 }
else if (TKelvin > tcrit) {
614 molarVolLast = Vroot_[0];
619 molarVolLast = Vroot_[0];
622 return mmw / molarVolLast;
634 auto resid = [
this, T](
double v) {
639 boost::uintmax_t maxiter = 100;
640 auto [lower, upper] = bmt::toms748_solve(
641 resid, Vroot[0], Vroot[1], bmt::eps_tolerance<double>(48), maxiter);
644 return mmw / (0.5 * (lower + upper));
656 auto resid = [
this, T](
double v) {
661 boost::uintmax_t maxiter = 100;
662 auto [lower, upper] = bmt::toms748_solve(
663 resid, Vroot[1], Vroot[2], bmt::eps_tolerance<double>(48), maxiter);
666 return mmw / (0.5 * (lower + upper));
671 double sqt = sqrt(TKelvin);
677 double dpdv = (-
GasConstant * TKelvin / (vmb * vmb)
707 double sqt = sqrt(TKelvin);
710 double dadt = da_dt();
719 for (
size_t i = 0; i <
m_kk; i++) {
720 for (
size_t j = 0; j <
m_kk; j++) {
721 size_t counter = i *
m_kk + j;
722 a_vec_Curr_[counter] = a_coeff_vec(0,counter) + a_coeff_vec(1,counter) * temp;
729 for (
size_t i = 0; i <
m_kk; i++) {
731 for (
size_t j = 0; j <
m_kk; j++) {
737 fmt::memory_buffer b;
738 for (
size_t k = 0; k <
m_kk; k++) {
739 if (isnan(b_vec_Curr_[k])) {
747 throw CanteraError(
"RedlichKwongMFTP::updateMixingExpressions",
748 "Missing Redlich-Kwong coefficients for species: {}", to_string(b));
757 for (
size_t i = 0; i <
m_kk; i++) {
759 for (
size_t j = 0; j <
m_kk; j++) {
760 size_t counter = i *
m_kk + j;
761 double a_vec_Curr = a_coeff_vec(0,counter) + a_coeff_vec(1,counter) * temp;
766 for (
size_t i = 0; i <
m_kk; i++) {
768 for (
size_t j = 0; j <
m_kk; j++) {
769 size_t counter = i *
m_kk + j;
770 double a_vec_Curr = a_coeff_vec(0,counter);
777double RedlichKwongMFTP::da_dt()
const
781 for (
size_t i = 0; i <
m_kk; i++) {
782 for (
size_t j = 0; j <
m_kk; j++) {
783 size_t counter = i *
m_kk + j;
791void RedlichKwongMFTP::calcCriticalConditions(
double& pc,
double& tc,
double& vc)
const
795 for (
size_t i = 0; i <
m_kk; i++) {
796 for (
size_t j = 0; j <
m_kk; j++) {
797 size_t counter = i +
m_kk * j;
821 double sqrttc, f, dfdt, deltatc;
827 for (
int j = 0; j < 10; j++) {
831 deltatc = - f / dfdt;
835 throw CanteraError(
"RedlichKwongMFTP::calcCriticalConditions",
850 double sqt = sqrt(T);
851 double cn = - (
GasConstant * T * b / pres - a/(pres * sqt) + b * b);
852 double dn = - (a * b / (pres * sqt));
856 double tc = pow(tmp, pp);
860 int nSolnValues =
MixtureFugacityTP::solveCubic(T, pres, a, b, a, Vroot, 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.
A wrapper for a variable whose type is determined at runtime.
void getRow(size_t n, double *const rw)
Get the nth row and return it in a vector.
virtual void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
Base class for exceptions thrown by Cantera classes.
double critPressure() const override
Critical pressure (Pa).
double critDensity() const override
Critical density (kg/m3).
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 getEntropy_R_ref(double *er) const override
Returns the vector of nondimensional entropies of the reference state at the current temperature of t...
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 ...
vector< double > m_workS
Vector of size m_kk, used as a temporary holding area.
size_t nSpecies() const
Returns the number of species in the phase.
size_t m_kk
Number of species in the phase.
double temperature() const
Temperature (K).
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
string speciesName(size_t k) const
Name of the species with index k.
map< string, shared_ptr< Species > > m_species
Map of Species objects.
size_t speciesIndex(const string &name) const
Returns the index of a species named 'name' within the Phase object.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
virtual double density() const
Density (kg/m^3).
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 dpdT_
The derivative of the pressure wrt the temperature.
void calculateAB(double temp, double &aCalc, double &bCalc) const
Calculate the a and the b parameters given the temperature.
double thermalExpansionCoeff() const override
Return the volumetric thermal expansion coefficient. Units: 1/K.
void setBinaryCoeffs(const string &species_i, const string &species_j, double a0, double a1)
Set values for the interaction parameter between two species.
double densSpinodalLiquid() const override
Return the value of the density at the liquid spinodal point (on the liquid side) for the current tem...
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.
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).
int m_formTempParam
Form of the temperature parameterization.
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...
RedlichKwongMFTP(const string &infile="", const string &id="")
Construct a RedlichKwongMFTP object from an input file.
static const double omega_b
Omega constant for b.
vector< double > m_pp
Temporary storage - length = m_kk.
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
double densSpinodalGas() const override
Return the value of the density at the gas spinodal point (on the gas side) for the current temperatu...
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].
void pressureDerivatives() const
Calculate dpdV and dpdT 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.
static const double omega_a
Omega constant for a -> value of a in terms of critical properties.
double liquidVolEst(double TKelvin, double &pres) const override
Estimate for the molar volume of the liquid.
double dpdVCalc(double TKelvin, double molarVol, double &presCalc) const override
Calculate the pressure and the pressure derivative given the temperature and the molar volume.
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 and b coefficients.
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 a and b parameters.
double cp_mole() const override
Molar heat capacity at constant pressure and composition [J/kmol/K].
double m_a_current
Value of a in the equation of state.
double standardConcentration(size_t k=0) const override
Returns the standard concentration , which is used to normalize the generalized concentration.
double dpdV_
The derivative of the pressure wrt the volume.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
double m_b_current
Value of b in the equation of state.
void getActivityCoefficients(double *ac) const override
Get the array of non-dimensional activity coefficients at the current solution temperature,...
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.
vector< double > dpdni_
Vector of derivatives of pressure wrt mole number.
void getPartialMolarEntropies(double *sbar) const override
Returns an array of partial molar entropies of the species in the solution.
map< string, map< string, pair< double, double > > > m_binaryParameters
Explicitly-specified binary interaction parameters.
void setSpeciesCoeffs(const string &species, double a0, double a1, double b)
Set the pure fluid interaction parameters for a species.
int solveCubic(double T, double pres, double a, double b, double Vroot[3]) const
Prepare variables and call the function to solve the cubic equation of state.
double RT() const
Return the Gas Constant multiplied by the current temperature.
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].
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...