47 double h_nonideal =
hresid();
48 return h_ideal + h_nonideal;
56 double s_nonideal =
sresid();
57 return s_ideal + s_nonideal;
67 for (
size_t k = 0; k <
m_kk; k++) {
68 g[k] =
RT() * (g[k] + tmp);
82 for (
size_t k = 0; k <
m_kk; k++) {
92 for (
size_t k = 0; k <
m_kk; k++) {
101 for (
size_t i = 0; i <
m_kk; i++) {
115 for (
size_t i = 0; i <
m_kk; i++) {
155 for (
size_t i = 0; i <
m_kk; i++) {
182 updateMixingExpressions();
218 if (
iState_ < FLUID_LIQUID_0) {
223 if (
iState_ >= FLUID_LIQUID_0) {
233 if (
iState_ >= FLUID_LIQUID_0) {
254 updateMixingExpressions();
261 for (
size_t k = 0; k <
m_kk; k++) {
288 double lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918;
289 return pcrit*exp(lpr);
298 int phase,
double rhoguess)
302 if (rhoguess == -1.0) {
304 if (TKelvin > tcrit) {
307 if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) {
309 }
else if (phase >= FLUID_LIQUID_0) {
311 rhoguess = mmw / lqvol;
321 double molarVolBase = mmw / rhoguess;
322 double molarVolLast = molarVolBase;
327 double molarVolSpinodal = vc;
331 bool gasSide = molarVolBase > vc;
340 for (
int n = 0; n < 200; n++) {
345 double dpdVBase =
dpdVCalc(TKelvin, molarVolBase, presBase);
350 if (dpdVBase >= 0.0) {
351 if (TKelvin > tcrit) {
353 "T > tcrit unexpectedly");
360 if (molarVolBase >= vc) {
361 molarVolSpinodal = molarVolBase;
362 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
364 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
367 if (molarVolBase <= vc) {
368 molarVolSpinodal = molarVolBase;
369 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
371 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
378 if (fabs(presBase-presPa) < 1.0E-30 + 1.0E-8 * presPa) {
384 double dpdV = dpdVBase;
386 dpdV = dpdVBase * 1.5;
391 double delMV = - (presBase - presPa) / dpdV;
392 if ((!gasSide || delMV < 0.0) && fabs(delMV) > 0.2 * molarVolBase) {
393 delMV = delMV / fabs(delMV) * 0.2 * molarVolBase;
396 if (TKelvin < tcrit) {
398 if (delMV < 0.0 && -delMV > 0.5 * (molarVolBase - molarVolSpinodal)) {
399 delMV = - 0.5 * (molarVolBase - molarVolSpinodal);
402 if (delMV > 0.0 && delMV > 0.5 * (molarVolSpinodal - molarVolBase)) {
403 delMV = 0.5 * (molarVolSpinodal - molarVolBase);
408 molarVolLast = molarVolBase;
409 molarVolBase += delMV;
411 if (fabs(delMV/molarVolBase) < 1.0E-14) {
417 if (molarVolBase <= 0.0) {
418 molarVolBase = std::min(1.0E-30, fabs(delMV*1.0E-4));
423 double densBase = 0.0;
427 "Process did not converge");
429 densBase = mmw / molarVolBase;
434void MixtureFugacityTP::updateMixingExpressions()
439 double& densGasGuess,
double& liqGRT,
double& gasGRT)
442 double densLiq =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess);
443 if (densLiq <= 0.0) {
446 densLiqGuess = densLiq;
451 double densGas =
densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess);
452 if (densGas <= 0.0) {
455 "Error occurred trying to find gas density at (T,P) = {} {}",
460 densGasGuess = densGas;
475 return FLUID_SUPERCRIT;
477 double tmid = tcrit - 100.;
485 double densLiqTmid = mmw / molVolLiqTmid;
486 double densGasTmid = mmw / molVolGasTmid;
487 double densMidTmid = 0.5 * (densLiqTmid + densGasTmid);
488 double rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid);
491 int iStateGuess = FLUID_LIQUID_0;
493 iStateGuess = FLUID_GAS;
495 double molarVol = mmw / rho;
498 double dpdv =
dpdVCalc(t, molarVol, presCalc);
511 double molarVolLiquid;
516 double& molarVolLiquid)
546 double RhoLiquidGood = mw / volLiquid;
547 double RhoGasGood = pres * mw / (
GasConstant * TKelvin);
548 double delGRT = 1.0E6;
549 double liqGRT, gasGRT;
553 double presLiquid = 0.;
555 double presBase = pres;
556 bool foundLiquid =
false;
557 bool foundGas =
false;
559 double densLiquid =
densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood);
560 if (densLiquid > 0.0) {
563 RhoLiquidGood = densLiquid;
566 for (
int i = 0; i < 50; i++) {
568 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
569 if (densLiquid > 0.0) {
572 RhoLiquidGood = densLiquid;
579 double densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
580 if (densGas <= 0.0) {
585 RhoGasGood = densGas;
588 for (
int i = 0; i < 50; i++) {
590 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
594 RhoGasGood = densGas;
600 if (foundGas && foundLiquid && presGas != presLiquid) {
601 pres = 0.5 * (presLiquid + presGas);
604 for (
int i = 0; i < 50; i++) {
605 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
606 if (densLiquid <= 0.0) {
610 RhoLiquidGood = densLiquid;
613 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
614 if (densGas <= 0.0) {
618 RhoGasGood = densGas;
621 if (goodGas && goodLiq) {
624 if (!goodLiq && !goodGas) {
625 pres = 0.5 * (pres + presLiquid);
627 if (goodLiq || goodGas) {
628 pres = 0.5 * (presLiquid + presGas);
632 if (!foundGas || !foundLiquid) {
633 warn_user(
"MixtureFugacityTP::calculatePsat",
634 "could not find a starting pressure; exiting.");
637 if (presGas != presLiquid) {
638 warn_user(
"MixtureFugacityTP::calculatePsat",
639 "could not find a starting pressure; exiting");
644 double presLast = pres;
645 double RhoGas = RhoGasGood;
646 double RhoLiquid = RhoLiquidGood;
649 for (
int i = 0; i < 20; i++) {
650 int stab =
corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT);
653 delGRT = liqGRT - gasGRT;
654 double delV = mw * (1.0/RhoLiquid - 1.0/RhoGas);
655 double dp = - delGRT *
GasConstant * TKelvin / delV;
657 if (fabs(dp) > 0.1 * pres) {
665 }
else if (stab == -1) {
667 if (presLast > pres) {
668 pres = 0.5 * (presLast + pres);
673 }
else if (stab == -2) {
674 if (presLast < pres) {
675 pres = 0.5 * (presLast + pres);
681 molarVolGas = mw / RhoGas;
682 molarVolLiquid = mw / RhoLiquid;
684 if (fabs(delGRT) < 1.0E-8) {
690 molarVolGas = mw / RhoGas;
691 molarVolLiquid = mw / RhoLiquid;
699 molarVolLiquid = molarVolGas;
721 for (
size_t k = 0; k <
m_kk; k++) {
726 throw CanteraError(
"MixtureFugacityTP::_updateReferenceStateThermo",
727 "negative reference pressure");
735 calcCriticalConditions(pc, tc, vc);
742 calcCriticalConditions(pc, tc, vc);
749 calcCriticalConditions(pc, tc, vc);
756 calcCriticalConditions(pc, tc, vc);
763 calcCriticalConditions(pc, tc, vc);
768void MixtureFugacityTP::calcCriticalConditions(
double& pc,
double& tc,
double& vc)
const
774 double aAlpha, span<double> Vroot,
double an,
775 double bn,
double cn,
double dn,
double tc,
double vc)
const
777 checkArraySize(
"MixtureFugacityTP::solveCubic: Vroot", Vroot.size(), 3);
778 fill(Vroot.begin(), Vroot.end(), 0.0);
781 "negative temperature T = {}", T);
785 double xN = - bn /(3 * an);
788 double delta2 = (bn * bn - 3 * an * cn) / (9 * an * an);
793 double ratio1 = 3.0 * an * cn / (bn * bn);
795 if (fabs(ratio1) < 1.0E-7) {
797 if (fabs(ratio2) < 1.0E-5 && fabs(ratio3) < 1.0E-5) {
800 for (
int i = 0; i < 10; i++) {
801 double znew = zz / (zz - ratio2) - ratio3 / (zz + ratio1);
802 double deltaz = znew - zz;
804 if (fabs(deltaz) < 1.0E-14) {
814 int nSolnValues = -1;
815 double h2 = 4. * an * an * delta2 * delta2 * delta2;
817 delta = sqrt(delta2);
820 double h = 2.0 * an * delta * delta2;
821 double yN = 2.0 * bn * bn * bn / (27.0 * an * an) - bn * cn / (3.0 * an) + dn;
822 double disc = yN * yN - h2;
825 if (fabs(fabs(h) - fabs(yN)) < 1.0E-10) {
828 "value of yN and h are too high, unrealistic roots may be obtained");
836 }
else if (fabs(disc) < 1e-14) {
840 }
else if (disc > 1e-14) {
846 auto physicalRoot = [b](
double v) {
848 double vmin = std::max(0.0, b * (1.0 + 1e-12));
849 return std::isfinite(v) && v > vmin;
853 double tmpD = sqrt(disc);
854 double tmp1 = (- yN + tmpD) / (2.0 * an);
860 double tmp2 = (- yN - tmpD) / (2.0 * an);
866 double p1 = pow(tmp1, 1./3.);
867 double p2 = pow(tmp2, 1./3.);
868 double alpha = xN + sgn1 * p1 + sgn2 * p2;
872 }
else if (disc < 0.0) {
874 double val = acos(-yN / h);
875 double theta = val / 3.0;
876 double twoThirdPi = 2. *
Pi / 3.;
877 double alpha = xN + 2. * delta * cos(theta);
878 double beta = xN + 2. * delta * cos(theta + twoThirdPi);
879 double gamma = xN + 2. * delta * cos(theta + 2.0 * twoThirdPi);
884 for (
int i = 0; i < 3; i++) {
885 tmp = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
886 if (fabs(tmp) > 1.0E-4) {
887 for (
int j = 0; j < 3; j++) {
888 if (j != i && fabs(Vroot[i] - Vroot[j]) < 1.0E-4 * (fabs(Vroot[i]) + fabs(Vroot[j]))) {
889 warn_user(
"MixtureFugacityTP::solveCubic",
890 "roots have merged for T = {}, p = {}: {}, {}",
891 T, pres, Vroot[i], Vroot[j]);
896 }
else if (disc == 0.0) {
898 if (yN < 1e-18 && h < 1e-18) {
906 tmp = pow(yN/(2*an), 1./3.);
908 if (fabs(tmp - delta) > 1.0E-9) {
910 "Inconsistency in solver: solver is ill-conditioned.");
912 Vroot[1] = xN + delta;
913 Vroot[0] = xN - 2.0*delta;
915 tmp = pow(yN/(2*an), 1./3.);
917 if (fabs(tmp - delta) > 1.0E-9) {
919 "Inconsistency in solver: solver is ill-conditioned.");
922 Vroot[0] = xN + delta;
923 Vroot[1] = xN - 2.0*delta;
929 double res, dresdV = 0.0;
930 for (
int i = 0; i < nSolnValues; i++) {
931 if (!physicalRoot(Vroot[i])) {
936 for (
int n = 0; n < 20; n++) {
937 res = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
938 if (fabs(res) < 1.0E-14) {
941 dresdV = 3.0 * an * Vroot[i] * Vroot[i] + 2.0 * bn * Vroot[i] + cn;
942 double del = - res / dresdV;
944 if (fabs(del) / (fabs(Vroot[i]) + fabs(del)) < 1.0E-14) {
947 double res2 = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
948 if (fabs(res2) < fabs(res)) {
952 Vroot[i] += 0.1 * del;
955 if ((fabs(res) > 1.0E-14) && (fabs(res) > 1.0E-14 * fabs(dresdV) * fabs(Vroot[i]))) {
957 "root failed to converge for T = {}, p = {} with "
958 "V = {}", T, pres, Vroot[i]);
961 if (nSolnValues == 1 && !physicalRoot(Vroot[0])) {
963 "single real root is non-physical for T = {}, p = {} "
964 "(V = {}, b = {})", T, pres, Vroot[0], b);
967 if (nSolnValues == 1) {
984 if (nSolnValues == 2 && delta > 1e-14) {
Header file for a derived class of ThermoPhase that handles non-ideal mixtures based on the fugacity ...
#define FLUID_UNSTABLE
Various states of the Fugacity object.
Base class for exceptions thrown by Cantera classes.
int iState_
Current state of the fluid.
void getGibbs_ref(span< double > g) const override
Returns the vector of the Gibbs function of the reference state at the current temperature of the sol...
int reportSolnBranchActual() const
Report the solution branch which the solution is actually on.
double enthalpy_mole() const override
Molar enthalpy. Units: J/kmol.
void getCp_R(span< double > cpr) const override
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
int standardStateConvention() const override
This method returns the convention used in specification of the standard state, of which there are cu...
void getEntropy_R_ref(span< double > er) const override
Returns the vector of nondimensional entropies of the reference state at the current temperature of t...
vector< double > m_g0_RT
Temporary storage for dimensionless reference state Gibbs energies.
void getIntEnergy_RT(span< double > urt) const override
Returns the vector of nondimensional internal Energies of the standard state at the current temperatu...
double critPressure() const override
Critical pressure (Pa).
double critDensity() const override
Critical density (kg/m3).
vector< double > m_h0_RT
Temporary storage for dimensionless reference state enthalpies.
void getStandardChemPotentials(span< double > mu) const override
Get the array of chemical potentials at unit activity.
double critTemperature() const override
Critical temperature (K).
void getGibbs_RT(span< double > grt) const override
Get the nondimensional Gibbs functions for the species at their standard states of solution at the cu...
void getCp_R_ref(span< double > cprt) const override
Returns the vector of nondimensional constant pressure heat capacities of the reference state at the ...
virtual void _updateReferenceStateThermo() const
Updates the reference state thermodynamic functions at the current T of the solution.
double satPressure(double TKelvin) override
Calculate the saturation pressure at the current mixture content for the given temperature.
double critCompressibility() const override
Critical compressibility (unitless).
void setPressure(double p) override
Set the internally stored pressure (Pa) at constant temperature and composition.
void getEnthalpy_RT_ref(span< double > hrt) const override
Returns the vector of nondimensional enthalpies of the reference state at the current temperature of ...
void getEnthalpy_RT(span< double > hrt) const override
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
double calculatePsat(double TKelvin, double &molarVolGas, double &molarVolLiquid)
Calculate the saturation pressure at the current mixture content for the given temperature.
vector< double > moleFractions_
Storage for the current values of the mole fractions of the species.
int solveCubic(double T, double pres, double a, double b, double aAlpha, span< double > Vroot, double an, double bn, double cn, double dn, double tc, double vc) const
Solve the cubic equation of state.
void getEntropy_R(span< double > sr) const override
Get the array of nondimensional Enthalpy functions for the standard state species at the current T an...
void setTemperature(const double temp) override
Set the temperature of the phase.
vector< double > m_s0_R
Temporary storage for dimensionless reference state entropies.
virtual double dpdVCalc(double TKelvin, double molarVol, double &presCalc) const
Calculate the pressure and the pressure derivative given the temperature and the molar volume.
double entropy_mole() const override
Molar entropy. Units: J/kmol/K.
virtual double densityCalc(double TKelvin, double pressure, int phaseRequested, double rhoguess)
Calculates the density given the temperature and the pressure and a guess at the density.
double critVolume() const override
Critical volume (m3/kmol).
virtual double psatEst(double TKelvin) const
Estimate for the saturation pressure.
void getGibbs_RT_ref(span< double > grt) const override
Returns the vector of nondimensional Gibbs Free Energies of the reference state at the current temper...
virtual double sresid() const
Calculate the deviation terms for the total entropy of the mixture from the ideal gas mixture.
int forcedState_
Force the system to be on a particular side of the spinodal curve.
virtual double liquidVolEst(double TKelvin, double &pres) const
Estimate for the molar volume of the liquid.
int forcedSolutionBranch() const
Report the solution branch which the solution is restricted to.
void getStandardVolumes(span< double > vol) const override
Get the molar volumes of each species in their standard states at the current T and P of the solution...
void compositionChanged() override
Apply changes to the state which are needed after the composition changes.
vector< double > m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
int corr0(double TKelvin, double pres, double &densLiq, double &densGas, double &liqGRT, double &gasGRT)
Utility routine in the calculation of the saturation pressure.
void setForcedSolutionBranch(int solnBranch)
Set the solution branch to force the ThermoPhase to exist on one branch or another.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
virtual double hresid() const
Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture.
void getActivityConcentrations(span< double > c) const override
This method returns an array of generalized concentrations.
double z() const
Calculate the value of z.
void getStandardVolumes_ref(span< double > vol) const override
Get the molar volumes of the species reference states at the current T and P_ref of the solution.
int phaseState(bool checkState=false) const
Returns the Phase State flag for the current state of the object.
virtual void update(double T, span< double > cp_R, span< double > h_RT, span< double > s_R) const
Compute the reference-state properties for all species.
An error indicating that an unimplemented function has been called.
void getMoleFractions(span< double > x) const
Get the species mole fraction vector.
size_t m_kk
Number of species in the phase.
void setState_TD(double t, double rho)
Set the internally stored temperature (K) and density (kg/m^3)
double temperature() const
Temperature (K).
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
double sum_xlogx() const
Evaluate .
double mean_X(span< const double > Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
virtual double density() const
Density (kg/m^3).
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
virtual double pressure() const
Return the thermodynamic pressure (Pa).
virtual void setState_TP(double t, double p)
Set the temperature (K) and pressure (Pa)
double RT() const
Return the Gas Constant multiplied by the current temperature.
double m_tlast
last value of the temperature processed by reference state
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
virtual double refPressure() const
Returns the reference pressure in Pa.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
virtual double gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
virtual void getActivityCoefficients(span< double > ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
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].
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Namespace for the Cantera kernel.
const int cSS_CONVENTION_TEMPERATURE
Standard state uses the molar convention.
void checkArraySize(const char *procedure, size_t available, size_t required)
Wrapper for throwing ArraySizeError.
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...