22 forcedState_(FLUID_UNDEFINED)
50 double h_nonideal =
hresid();
51 return h_ideal + h_nonideal;
59 double s_nonideal =
sresid();
60 return s_ideal + s_nonideal;
68 for (
size_t k = 0; k <
m_kk; k++) {
69 muRT[k] *= 1.0 /
RT();
79 for (
size_t k = 0; k <
m_kk; k++) {
80 g[k] =
RT() * (g[k] + tmp);
93 for (
size_t k = 0; k <
m_kk; k++) {
102 for (
size_t k = 0; k <
m_kk; k++) {
111 for (
size_t k = 0; k <
m_kk; k++) {
119 for (
size_t i = 0; i <
m_kk; i++) {
131 for (
size_t i = 0; i <
m_kk; i++) {
151 scale(gibbsrt.begin(), gibbsrt.end(), g,
RT());
171 for (
size_t i = 0; i <
m_kk; i++) {
193 if (state.
hasChild(
"temperature")) {
194 t =
getFloat(state,
"temperature",
"temperature");
198 double p =
getFloat(state,
"pressure",
"pressure");
200 }
else if (state.
hasChild(
"density")) {
201 double rho =
getFloat(state,
"density",
"density");
232 updateMixingExpressions();
268 if (
iState_ < FLUID_LIQUID_0) {
273 if (
iState_ >= FLUID_LIQUID_0) {
283 if (
iState_ >= FLUID_LIQUID_0) {
304 updateMixingExpressions();
311 for (
size_t k = 0; k <
m_kk; k++) {
338 doublereal lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918;
339 return pcrit*exp(lpr);
348 int phase, doublereal rhoguess)
352 if (rhoguess == -1.0) {
354 if (TKelvin > tcrit) {
357 if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) {
359 }
else if (phase >= FLUID_LIQUID_0) {
361 rhoguess = mmw / lqvol;
371 double molarVolBase = mmw / rhoguess;
372 double molarVolLast = molarVolBase;
377 double molarVolSpinodal = vc;
381 bool gasSide = molarVolBase > vc;
390 for (
int n = 0; n < 200; n++) {
395 double dpdVBase =
dpdVCalc(TKelvin, molarVolBase, presBase);
400 if (dpdVBase >= 0.0) {
401 if (TKelvin > tcrit) {
403 "T > tcrit unexpectedly");
410 if (molarVolBase >= vc) {
411 molarVolSpinodal = molarVolBase;
412 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
414 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
417 if (molarVolBase <= vc) {
418 molarVolSpinodal = molarVolBase;
419 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
421 molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
428 if (fabs(presBase-presPa) < 1.0E-30 + 1.0E-8 * presPa) {
434 doublereal dpdV = dpdVBase;
436 dpdV = dpdVBase * 1.5;
441 double delMV = - (presBase - presPa) / dpdV;
442 if ((!gasSide || delMV < 0.0) && fabs(delMV) > 0.2 * molarVolBase) {
443 delMV = delMV / fabs(delMV) * 0.2 * molarVolBase;
446 if (TKelvin < tcrit) {
448 if (delMV < 0.0 && -delMV > 0.5 * (molarVolBase - molarVolSpinodal)) {
449 delMV = - 0.5 * (molarVolBase - molarVolSpinodal);
452 if (delMV > 0.0 && delMV > 0.5 * (molarVolSpinodal - molarVolBase)) {
453 delMV = 0.5 * (molarVolSpinodal - molarVolBase);
458 molarVolLast = molarVolBase;
459 molarVolBase += delMV;
461 if (fabs(delMV/molarVolBase) < 1.0E-14) {
467 if (molarVolBase <= 0.0) {
468 molarVolBase = std::min(1.0E-30, fabs(delMV*1.0E-4));
473 double densBase = 0.0;
477 "Process did not converge");
479 densBase = mmw / molarVolBase;
484void MixtureFugacityTP::updateMixingExpressions()
489 doublereal& densGasGuess, doublereal& liqGRT, doublereal& gasGRT)
492 doublereal densLiq =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess);
493 if (densLiq <= 0.0) {
496 densLiqGuess = densLiq;
501 doublereal densGas =
densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess);
502 if (densGas <= 0.0) {
505 "Error occurred trying to find gas density at (T,P) = {} {}",
510 densGasGuess = densGas;
525 return FLUID_SUPERCRIT;
527 double tmid = tcrit - 100.;
535 double densLiqTmid = mmw / molVolLiqTmid;
536 double densGasTmid = mmw / molVolGasTmid;
537 double densMidTmid = 0.5 * (densLiqTmid + densGasTmid);
538 doublereal rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid);
541 int iStateGuess = FLUID_LIQUID_0;
543 iStateGuess = FLUID_GAS;
545 double molarVol = mmw / rho;
548 double dpdv =
dpdVCalc(t, molarVol, presCalc);
570 doublereal molarVolGas;
571 doublereal molarVolLiquid;
576 doublereal& molarVolLiquid)
606 double RhoLiquidGood = mw / volLiquid;
607 double RhoGasGood = pres * mw / (
GasConstant * TKelvin);
608 doublereal delGRT = 1.0E6;
609 doublereal liqGRT, gasGRT;
613 doublereal presLiquid = 0.;
615 doublereal presBase = pres;
616 bool foundLiquid =
false;
617 bool foundGas =
false;
619 doublereal densLiquid =
densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood);
620 if (densLiquid > 0.0) {
623 RhoLiquidGood = densLiquid;
626 for (
int i = 0; i < 50; i++) {
628 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
629 if (densLiquid > 0.0) {
632 RhoLiquidGood = densLiquid;
639 doublereal densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
640 if (densGas <= 0.0) {
645 RhoGasGood = densGas;
648 for (
int i = 0; i < 50; i++) {
650 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
654 RhoGasGood = densGas;
660 if (foundGas && foundLiquid && presGas != presLiquid) {
661 pres = 0.5 * (presLiquid + presGas);
664 for (
int i = 0; i < 50; i++) {
665 densLiquid =
densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
666 if (densLiquid <= 0.0) {
670 RhoLiquidGood = densLiquid;
673 densGas =
densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
674 if (densGas <= 0.0) {
678 RhoGasGood = densGas;
681 if (goodGas && goodLiq) {
684 if (!goodLiq && !goodGas) {
685 pres = 0.5 * (pres + presLiquid);
687 if (goodLiq || goodGas) {
688 pres = 0.5 * (presLiquid + presGas);
692 if (!foundGas || !foundLiquid) {
693 warn_user(
"MixtureFugacityTP::calculatePsat",
694 "could not find a starting pressure; exiting.");
697 if (presGas != presLiquid) {
698 warn_user(
"MixtureFugacityTP::calculatePsat",
699 "could not find a starting pressure; exiting");
704 double presLast = pres;
705 double RhoGas = RhoGasGood;
706 double RhoLiquid = RhoLiquidGood;
709 for (
int i = 0; i < 20; i++) {
710 int stab =
corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT);
713 delGRT = liqGRT - gasGRT;
714 doublereal delV = mw * (1.0/RhoLiquid - 1.0/RhoGas);
715 doublereal dp = - delGRT *
GasConstant * TKelvin / delV;
717 if (fabs(dp) > 0.1 * pres) {
725 }
else if (stab == -1) {
727 if (presLast > pres) {
728 pres = 0.5 * (presLast + pres);
733 }
else if (stab == -2) {
734 if (presLast < pres) {
735 pres = 0.5 * (presLast + pres);
741 molarVolGas = mw / RhoGas;
742 molarVolLiquid = mw / RhoLiquid;
744 if (fabs(delGRT) < 1.0E-8) {
750 molarVolGas = mw / RhoGas;
751 molarVolLiquid = mw / RhoLiquid;
759 molarVolLiquid = molarVolGas;
781 for (
size_t k = 0; k <
m_kk; k++) {
786 throw CanteraError(
"MixtureFugacityTP::_updateReferenceStateThermo",
787 "negative reference pressure");
795 calcCriticalConditions(pc, tc, vc);
802 calcCriticalConditions(pc, tc, vc);
809 calcCriticalConditions(pc, tc, vc);
816 calcCriticalConditions(pc, tc, vc);
823 calcCriticalConditions(pc, tc, vc);
828void MixtureFugacityTP::calcCriticalConditions(
double& pc,
double& tc,
double& vc)
const
834 double aAlpha,
double Vroot[3],
double an,
835 double bn,
double cn,
double dn,
double tc,
double vc)
const
837 fill_n(Vroot, 3, 0.0);
840 "negative temperature T = {}", T);
844 double xN = - bn /(3 * an);
847 double delta2 = (bn * bn - 3 * an * cn) / (9 * an * an);
852 double ratio1 = 3.0 * an * cn / (bn * bn);
854 if (fabs(ratio1) < 1.0E-7) {
856 if (fabs(ratio2) < 1.0E-5 && fabs(ratio3) < 1.0E-5) {
859 for (
int i = 0; i < 10; i++) {
860 double znew = zz / (zz - ratio2) - ratio3 / (zz + ratio1);
861 double deltaz = znew - zz;
863 if (fabs(deltaz) < 1.0E-14) {
873 int nSolnValues = -1;
874 double h2 = 4. * an * an * delta2 * delta2 * delta2;
876 delta = sqrt(delta2);
879 double h = 2.0 * an * delta * delta2;
880 double yN = 2.0 * bn * bn * bn / (27.0 * an * an) - bn * cn / (3.0 * an) + dn;
881 double disc = yN * yN - h2;
884 if (fabs(fabs(h) - fabs(yN)) < 1.0E-10) {
887 "value of yN and h are too high, unrealistic roots may be obtained");
895 }
else if (fabs(disc) < 1e-14) {
899 }
else if (disc > 1e-14) {
907 double tmpD = sqrt(disc);
908 double tmp1 = (- yN + tmpD) / (2.0 * an);
914 double tmp2 = (- yN - tmpD) / (2.0 * an);
920 double p1 = pow(tmp1, 1./3.);
921 double p2 = pow(tmp2, 1./3.);
922 double alpha = xN + sgn1 * p1 + sgn2 * p2;
926 }
else if (disc < 0.0) {
928 double val = acos(-yN / h);
929 double theta = val / 3.0;
930 double twoThirdPi = 2. *
Pi / 3.;
931 double alpha = xN + 2. * delta * cos(theta);
932 double beta = xN + 2. * delta * cos(theta + twoThirdPi);
933 double gamma = xN + 2. * delta * cos(theta + 2.0 * twoThirdPi);
938 for (
int i = 0; i < 3; i++) {
939 tmp = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
940 if (fabs(tmp) > 1.0E-4) {
941 for (
int j = 0; j < 3; j++) {
942 if (j != i && fabs(Vroot[i] - Vroot[j]) < 1.0E-4 * (fabs(Vroot[i]) + fabs(Vroot[j]))) {
943 writelog(
"MixtureFugacityTP::solveCubic(T ={}, p ={}):"
944 " WARNING roots have merged: {}, {}\n",
945 T, pres, Vroot[i], Vroot[j]);
950 }
else if (disc == 0.0) {
952 if (yN < 1e-18 && h < 1e-18) {
960 tmp = pow(yN/(2*an), 1./3.);
962 if (fabs(tmp - delta) > 1.0E-9) {
964 "Inconsistency in solver: solver is ill-conditioned.");
966 Vroot[1] = xN + delta;
967 Vroot[0] = xN - 2.0*delta;
969 tmp = pow(yN/(2*an), 1./3.);
971 if (fabs(tmp - delta) > 1.0E-9) {
973 "Inconsistency in solver: solver is ill-conditioned.");
976 Vroot[0] = xN + delta;
977 Vroot[1] = xN - 2.0*delta;
983 double res, dresdV = 0.0;
984 for (
int i = 0; i < nSolnValues; i++) {
985 for (
int n = 0; n < 20; n++) {
986 res = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
987 if (fabs(res) < 1.0E-14) {
990 dresdV = 3.0 * an * Vroot[i] * Vroot[i] + 2.0 * bn * Vroot[i] + cn;
991 double del = - res / dresdV;
993 if (fabs(del) / (fabs(Vroot[i]) + fabs(del)) < 1.0E-14) {
996 double res2 = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
997 if (fabs(res2) < fabs(res)) {
1001 Vroot[i] += 0.1 * del;
1004 if ((fabs(res) > 1.0E-14) && (fabs(res) > 1.0E-14 * fabs(dresdV) * fabs(Vroot[i]))) {
1005 writelog(
"MixtureFugacityTP::solveCubic(T = {}, p = {}): "
1006 "WARNING root didn't converge V = {}", T, pres, Vroot[i]);
1011 if (nSolnValues == 1) {
1015 if (Vroot[0] < vc) {
1020 if (Vroot[0] < xN) {
1028 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.
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.
int iState_
Current state of the fluid.
vector_fp m_g0_RT
Temporary storage for dimensionless reference state Gibbs energies.
virtual int reportSolnBranchActual() const
Report the solution branch which the solution is actually on.
vector_fp m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
virtual double entropy_mole() const
Molar entropy. Units: J/kmol/K.
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void getGibbs_RT_ref(doublereal *grt) const
Returns the vector of nondimensional Gibbs Free Energies of the reference state at the current temper...
virtual double enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
virtual void getGibbs_RT(doublereal *grt) const
Get the nondimensional Gibbs functions for the species at their standard states of solution at the cu...
virtual doublereal hresid() const
Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture.
virtual double critCompressibility() const
Critical compressibility (unitless).
doublereal z() const
Calculate the value of z.
vector_fp m_h0_RT
Temporary storage for dimensionless reference state enthalpies.
virtual doublereal satPressure(doublereal TKelvin)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual void _updateReferenceStateThermo() const
Updates the reference state thermodynamic functions at the current T of the solution.
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of each species in their standard states at the current T and P of the solution...
vector_fp m_s0_R
Temporary storage for dimensionless reference state entropies.
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.
virtual doublereal dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const
Calculate the pressure and the pressure derivative given the temperature and the molar volume.
virtual doublereal sresid() const
Calculate the deviation terms for the total entropy of the mixture from the ideal gas mixture.
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
virtual double critVolume() const
Critical volume (m3/kmol).
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Enthalpy functions for the standard state species at the current T an...
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
virtual doublereal densityCalc(doublereal TKelvin, doublereal pressure, int phaseRequested, doublereal rhoguess)
Calculates the density given the temperature and the pressure and a guess at the density.
virtual doublereal psatEst(doublereal TKelvin) const
Estimate for the saturation pressure.
virtual doublereal liquidVolEst(doublereal TKelvin, doublereal &pres) const
Estimate for the molar volume of the liquid.
const vector_fp & gibbs_RT_ref() const
Returns the vector of nondimensional Gibbs free energies of the reference state at the current temper...
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
virtual void getEntropy_R_ref(doublereal *er) const
Returns the vector of nondimensional entropies of the reference state at the current temperature of t...
virtual doublereal densSpinodalGas() const
Return the value of the density at the gas spinodal point (on the gas side) for the current temperatu...
virtual double critDensity() const
Critical density (kg/m3).
virtual void getIntEnergy_RT(doublereal *urt) const
Returns the vector of nondimensional internal Energies of the standard state at the current temperatu...
virtual void setTemperature(const doublereal temp)
Set the temperature of the phase.
virtual void getCp_R_ref(doublereal *cprt) const
Returns the vector of nondimensional constant pressure heat capacities of the reference state at the ...
vector_fp moleFractions_
Storage for the current values of the mole fractions of the species.
doublereal calculatePsat(doublereal TKelvin, doublereal &molarVolGas, doublereal &molarVolLiquid)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity.
virtual void getStandardVolumes_ref(doublereal *vol) const
Get the molar volumes of the species reference states at the current T and P_ref of the solution.
int forcedState_
Force the system to be on a particular side of the spinodal curve.
virtual int forcedSolutionBranch() const
Report the solution branch which the solution is restricted to.
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
virtual double critTemperature() const
Critical temperature (K).
virtual void getChemPotentials_RT(doublereal *mu) const
Get the array of non-dimensional species chemical potentials These are partial molar Gibbs free energ...
virtual void getActivityConcentrations(double *c) const
This method returns an array of generalized concentrations.
virtual void setForcedSolutionBranch(int solnBranch)
Set the solution branch to force the ThermoPhase to exist on one branch or another.
int corr0(doublereal TKelvin, doublereal pres, doublereal &densLiq, doublereal &densGas, doublereal &liqGRT, doublereal &gasGRT)
Utility routine in the calculation of the saturation pressure.
virtual doublereal densSpinodalLiquid() const
Return the value of the density at the liquid spinodal point (on the liquid side) for the current tem...
MixtureFugacityTP()
Constructor.
virtual void getGibbs_ref(doublereal *g) const
Returns the vector of the Gibbs function of the reference state at the current temperature of the sol...
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
virtual void getPureGibbs(doublereal *gpure) const
Get the pure Gibbs free energies of each species.
vector_fp m_tmpV
Temporary storage - length = m_kk.
virtual double critPressure() const
Critical pressure (Pa).
int phaseState(bool checkState=false) const
Returns the Phase State flag for the current state of the object.
virtual void getEnthalpy_RT_ref(doublereal *hrt) const
virtual void update(doublereal T, doublereal *cp_R, doublereal *h_RT, doublereal *s_R) const
Compute the reference-state properties for all species.
An error indicating that an unimplemented function has been called.
doublereal mean_X(const doublereal *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
void setMoleFractionsByName(const compositionMap &xMap)
Set the species mole fractions by name.
size_t m_kk
Number of species in the phase.
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
void setState_TR(doublereal t, doublereal rho)
Set the internally stored temperature (K) and density (kg/m^3)
virtual double density() const
Density (kg/m^3).
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
doublereal temperature() const
Temperature (K).
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
void setMassFractionsByName(const compositionMap &yMap)
Set the species mass fractions by name.
virtual double pressure() const
Return the thermodynamic pressure (Pa).
doublereal sum_xlogx() const
Evaluate .
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
doublereal m_tlast
last value of the temperature processed by reference state
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
virtual doublereal refPressure() const
Returns the reference pressure in Pa.
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Class XML_Node is a tree-based representation of the contents of an XML file.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
void writelog(const std::string &fmt, const Args &... args)
Write a formatted message to the screen.
Namespace for the Cantera kernel.
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type="")
Get a floating-point value from a child element.
std::string getChildValue(const XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its XML value as the return s...
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
const double GasConstant
Universal Gas Constant [J/kmol/K].
void warn_user(const std::string &method, const std::string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
const int cSS_CONVENTION_TEMPERATURE
void writelogendl()
Write an end of line character to the screen and flush output.
Contains declarations for string manipulation functions within Cantera.