45 double h_nonideal =
hresid();
46 return h_ideal + h_nonideal;
54 double s_nonideal =
sresid();
55 return s_ideal + s_nonideal;
65 for (
size_t k = 0; k <
m_kk; k++) {
66 g[k] =
RT() * (g[k] + tmp);
80 for (
size_t k = 0; k <
m_kk; k++) {
90 for (
size_t k = 0; k <
m_kk; k++) {
99 for (
size_t i = 0; i <
m_kk; i++) {
113 for (
size_t i = 0; i <
m_kk; i++) {
153 for (
size_t i = 0; i <
m_kk; i++) {
180 updateMixingExpressions();
216 if (
iState_ < FLUID_LIQUID_0) {
221 if (
iState_ >= FLUID_LIQUID_0) {
231 if (
iState_ >= FLUID_LIQUID_0) {
252 updateMixingExpressions();
259 for (
size_t k = 0; k <
m_kk; k++) {
286 double lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918;
287 return pcrit*exp(lpr);
296 int phase,
double rhoguess)
300 if (rhoguess == -1.0) {
302 if (TKelvin > tcrit) {
305 if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) {
307 }
else if (phase >= FLUID_LIQUID_0) {
309 rhoguess = mmw / lqvol;
319 double molarVolBase = mmw / rhoguess;
320 double molarVolLast = molarVolBase;
325 double molarVolSpinodal = vc;
329 bool gasSide = molarVolBase > vc;
338 for (
int n = 0; n < 200; n++) {
343 double dpdVBase =
dpdVCalc(TKelvin, molarVolBase, presBase);
348 if (dpdVBase >= 0.0) {
349 if (TKelvin > tcrit) {
351 "T > tcrit unexpectedly");
358 if (molarVolBase >= vc) {
359 molarVolSpinodal = molarVolBase;
360 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
362 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
365 if (molarVolBase <= vc) {
366 molarVolSpinodal = molarVolBase;
367 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
369 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
376 if (fabs(presBase-presPa) < 1.0E-30 + 1.0E-8 * presPa) {
382 double dpdV = dpdVBase;
384 dpdV = dpdVBase * 1.5;
389 double delMV = - (presBase - presPa) / dpdV;
390 if ((!gasSide || delMV < 0.0) && fabs(delMV) > 0.2 * molarVolBase) {
391 delMV = delMV / fabs(delMV) * 0.2 * molarVolBase;
394 if (TKelvin < tcrit) {
396 if (delMV < 0.0 && -delMV > 0.5 * (molarVolBase - molarVolSpinodal)) {
397 delMV = - 0.5 * (molarVolBase - molarVolSpinodal);
400 if (delMV > 0.0 && delMV > 0.5 * (molarVolSpinodal - molarVolBase)) {
401 delMV = 0.5 * (molarVolSpinodal - molarVolBase);
406 molarVolLast = molarVolBase;
407 molarVolBase += delMV;
409 if (fabs(delMV/molarVolBase) < 1.0E-14) {
415 if (molarVolBase <= 0.0) {
416 molarVolBase = std::min(1.0E-30, fabs(delMV*1.0E-4));
421 double densBase = 0.0;
425 "Process did not converge");
427 densBase = mmw / molarVolBase;
432void MixtureFugacityTP::updateMixingExpressions()
437 double& densGasGuess,
double& liqGRT,
double& gasGRT)
440 double densLiq =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess);
441 if (densLiq <= 0.0) {
444 densLiqGuess = densLiq;
449 double densGas =
densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess);
450 if (densGas <= 0.0) {
453 "Error occurred trying to find gas density at (T,P) = {} {}",
458 densGasGuess = densGas;
473 return FLUID_SUPERCRIT;
475 double tmid = tcrit - 100.;
483 double densLiqTmid = mmw / molVolLiqTmid;
484 double densGasTmid = mmw / molVolGasTmid;
485 double densMidTmid = 0.5 * (densLiqTmid + densGasTmid);
486 double rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid);
489 int iStateGuess = FLUID_LIQUID_0;
491 iStateGuess = FLUID_GAS;
493 double molarVol = mmw / rho;
496 double dpdv =
dpdVCalc(t, molarVol, presCalc);
509 double molarVolLiquid;
514 double& molarVolLiquid)
544 double RhoLiquidGood = mw / volLiquid;
545 double RhoGasGood = pres * mw / (
GasConstant * TKelvin);
546 double delGRT = 1.0E6;
547 double liqGRT, gasGRT;
551 double presLiquid = 0.;
553 double presBase = pres;
554 bool foundLiquid =
false;
555 bool foundGas =
false;
557 double densLiquid =
densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood);
558 if (densLiquid > 0.0) {
561 RhoLiquidGood = densLiquid;
564 for (
int i = 0; i < 50; i++) {
566 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
567 if (densLiquid > 0.0) {
570 RhoLiquidGood = densLiquid;
577 double densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
578 if (densGas <= 0.0) {
583 RhoGasGood = densGas;
586 for (
int i = 0; i < 50; i++) {
588 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
592 RhoGasGood = densGas;
598 if (foundGas && foundLiquid && presGas != presLiquid) {
599 pres = 0.5 * (presLiquid + presGas);
602 for (
int i = 0; i < 50; i++) {
603 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
604 if (densLiquid <= 0.0) {
608 RhoLiquidGood = densLiquid;
611 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
612 if (densGas <= 0.0) {
616 RhoGasGood = densGas;
619 if (goodGas && goodLiq) {
622 if (!goodLiq && !goodGas) {
623 pres = 0.5 * (pres + presLiquid);
625 if (goodLiq || goodGas) {
626 pres = 0.5 * (presLiquid + presGas);
630 if (!foundGas || !foundLiquid) {
631 warn_user(
"MixtureFugacityTP::calculatePsat",
632 "could not find a starting pressure; exiting.");
635 if (presGas != presLiquid) {
636 warn_user(
"MixtureFugacityTP::calculatePsat",
637 "could not find a starting pressure; exiting");
642 double presLast = pres;
643 double RhoGas = RhoGasGood;
644 double RhoLiquid = RhoLiquidGood;
647 for (
int i = 0; i < 20; i++) {
648 int stab =
corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT);
651 delGRT = liqGRT - gasGRT;
652 double delV = mw * (1.0/RhoLiquid - 1.0/RhoGas);
653 double dp = - delGRT *
GasConstant * TKelvin / delV;
655 if (fabs(dp) > 0.1 * pres) {
663 }
else if (stab == -1) {
665 if (presLast > pres) {
666 pres = 0.5 * (presLast + pres);
671 }
else if (stab == -2) {
672 if (presLast < pres) {
673 pres = 0.5 * (presLast + pres);
679 molarVolGas = mw / RhoGas;
680 molarVolLiquid = mw / RhoLiquid;
682 if (fabs(delGRT) < 1.0E-8) {
688 molarVolGas = mw / RhoGas;
689 molarVolLiquid = mw / RhoLiquid;
697 molarVolLiquid = molarVolGas;
719 for (
size_t k = 0; k <
m_kk; k++) {
724 throw CanteraError(
"MixtureFugacityTP::_updateReferenceStateThermo",
725 "negative reference pressure");
733 calcCriticalConditions(pc, tc, vc);
740 calcCriticalConditions(pc, tc, vc);
747 calcCriticalConditions(pc, tc, vc);
754 calcCriticalConditions(pc, tc, vc);
761 calcCriticalConditions(pc, tc, vc);
766void MixtureFugacityTP::calcCriticalConditions(
double& pc,
double& tc,
double& vc)
const
772 double aAlpha, span<double> Vroot,
double an,
773 double bn,
double cn,
double dn,
double tc,
double vc)
const
775 checkArraySize(
"MixtureFugacityTP::solveCubic: Vroot", Vroot.size(), 3);
776 fill(Vroot.begin(), Vroot.end(), 0.0);
779 "negative temperature T = {}", T);
783 double xN = - bn /(3 * an);
786 double delta2 = (bn * bn - 3 * an * cn) / (9 * an * an);
791 double ratio1 = 3.0 * an * cn / (bn * bn);
793 if (fabs(ratio1) < 1.0E-7) {
795 if (fabs(ratio2) < 1.0E-5 && fabs(ratio3) < 1.0E-5) {
798 for (
int i = 0; i < 10; i++) {
799 double znew = zz / (zz - ratio2) - ratio3 / (zz + ratio1);
800 double deltaz = znew - zz;
802 if (fabs(deltaz) < 1.0E-14) {
812 int nSolnValues = -1;
813 double h2 = 4. * an * an * delta2 * delta2 * delta2;
815 delta = sqrt(delta2);
818 double h = 2.0 * an * delta * delta2;
819 double yN = 2.0 * bn * bn * bn / (27.0 * an * an) - bn * cn / (3.0 * an) + dn;
820 double disc = yN * yN - h2;
823 if (fabs(fabs(h) - fabs(yN)) < 1.0E-10) {
826 "value of yN and h are too high, unrealistic roots may be obtained");
834 }
else if (fabs(disc) < 1e-14) {
838 }
else if (disc > 1e-14) {
846 double tmpD = sqrt(disc);
847 double tmp1 = (- yN + tmpD) / (2.0 * an);
853 double tmp2 = (- yN - tmpD) / (2.0 * an);
859 double p1 = pow(tmp1, 1./3.);
860 double p2 = pow(tmp2, 1./3.);
861 double alpha = xN + sgn1 * p1 + sgn2 * p2;
865 }
else if (disc < 0.0) {
867 double val = acos(-yN / h);
868 double theta = val / 3.0;
869 double twoThirdPi = 2. *
Pi / 3.;
870 double alpha = xN + 2. * delta * cos(theta);
871 double beta = xN + 2. * delta * cos(theta + twoThirdPi);
872 double gamma = xN + 2. * delta * cos(theta + 2.0 * twoThirdPi);
877 for (
int i = 0; i < 3; i++) {
878 tmp = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
879 if (fabs(tmp) > 1.0E-4) {
880 for (
int j = 0; j < 3; j++) {
881 if (j != i && fabs(Vroot[i] - Vroot[j]) < 1.0E-4 * (fabs(Vroot[i]) + fabs(Vroot[j]))) {
882 warn_user(
"MixtureFugacityTP::solveCubic",
883 "roots have merged for T = {}, p = {}: {}, {}",
884 T, pres, Vroot[i], Vroot[j]);
889 }
else if (disc == 0.0) {
891 if (yN < 1e-18 && h < 1e-18) {
899 tmp = pow(yN/(2*an), 1./3.);
901 if (fabs(tmp - delta) > 1.0E-9) {
903 "Inconsistency in solver: solver is ill-conditioned.");
905 Vroot[1] = xN + delta;
906 Vroot[0] = xN - 2.0*delta;
908 tmp = pow(yN/(2*an), 1./3.);
910 if (fabs(tmp - delta) > 1.0E-9) {
912 "Inconsistency in solver: solver is ill-conditioned.");
915 Vroot[0] = xN + delta;
916 Vroot[1] = xN - 2.0*delta;
922 double res, dresdV = 0.0;
923 for (
int i = 0; i < nSolnValues; i++) {
924 for (
int n = 0; n < 20; n++) {
925 res = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
926 if (fabs(res) < 1.0E-14) {
929 dresdV = 3.0 * an * Vroot[i] * Vroot[i] + 2.0 * bn * Vroot[i] + cn;
930 double del = - res / dresdV;
932 if (fabs(del) / (fabs(Vroot[i]) + fabs(del)) < 1.0E-14) {
935 double res2 = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
936 if (fabs(res2) < fabs(res)) {
940 Vroot[i] += 0.1 * del;
943 if ((fabs(res) > 1.0E-14) && (fabs(res) > 1.0E-14 * fabs(dresdV) * fabs(Vroot[i]))) {
945 "root failed to converge for T = {}, p = {} with "
946 "V = {}", T, pres, Vroot[i]);
950 if (nSolnValues == 1) {
967 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...