Phase Identification (thermo.phase_identification)¶
This module contains functions for identifying phases as liquid, solid, and gas.
Solid identification is easy using the
phase identification parameter
.
There is never more than one gas by definition. For pure species, the
phase identification parameter is a clear vapor-liquid differentiator in the
subcritical region and it provides line starting at the critical point for the
supercritical region.
However for mixtures, there is no clear calcuation that can be performed to
identify the phase of a mixture. Many different criteria that have been
proposed are included here. The
phase identification parameter or PIP
.
is recommended in general and is the default.
For reporting bugs, adding feature requests, or submitting pull requests, please use the GitHub issue tracker.
Phase Identification¶
Main Interface¶
- thermo.phase_identification.identify_sort_phases(phases, betas, constants, correlations, settings, skip_solids=False)[source]¶
Identify and sort all phases given the provided parameters.
- Parameters
- phases
list
[Phase
] Phases to be identified and sorted, [-]
- betas
list
[float
] Phase molar fractions, [-]
- constants
ChemicalConstantsPackage
Constants used in the identification, [-]
- correlations
PropertyCorrelationsPackage
Correlations used in the identification, [-]
- settings
BulkSettings
Settings object controlling the phase ID, [-]
- skip_solidsbool
Set this to True if no phases are provided which can represent a solid phase, [-]
- phases
- Returns
Notes
This step is very important as although phase objects are designed to represent a single phase, cubic equations of state can be switched back and forth by the flash algorithms. Thermodynamics doesn’t care about gases, liquids, or solids; it just cares about minimizing Gibbs energy!
Examples
A butanol-water-ethanol flash yields three phases. For brevity we skip the flash and initialize our gas, liq0, and liq1 object with the correct phase composition. Then we identify the phases into liquid, gas, and solid.
>>> from thermo import ChemicalConstantsPackage, PropertyCorrelationsPackage, HeatCapacityGas, SRKMIX, CEOSGas, CEOSLiquid >>> constants = ChemicalConstantsPackage(Tcs=[563.0, 647.14, 514.0], Vcs=[0.000274, 5.6e-05, 0.000168], Pcs=[4414000.0, 22048320.0, 6137000.0], omegas=[0.59, 0.344, 0.635], MWs=[74.1216, 18.01528, 46.06844], CASs=['71-36-3', '7732-18-5', '64-17-5']) >>> properties = PropertyCorrelationsPackage(constants=constants, skip_missing=True, ... HeatCapacityGases=[HeatCapacityGas(load_data=False, poly_fit=(50.0, 1000.0, [-3.787200194613107e-20, 1.7692887427654656e-16, -3.445247207129205e-13, 3.612771874320634e-10, -2.1953250181084466e-07, 7.707135849197655e-05, -0.014658388538054169, 1.5642629364740657, -7.614560475001724])), ... HeatCapacityGas(load_data=False, poly_fit=(50.0, 1000.0, [5.543665000518528e-22, -2.403756749600872e-18, 4.2166477594350336e-15, -3.7965208514613565e-12, 1.823547122838406e-09, -4.3747690853614695e-07, 5.437938301211039e-05, -0.003220061088723078, 33.32731489750759])), ... HeatCapacityGas(load_data=False, poly_fit=(50.0, 1000.0, [-1.162767978165682e-20, 5.4975285700787494e-17, -1.0861242757337942e-13, 1.1582703354362728e-10, -7.160627710867427e-08, 2.5392014654765875e-05, -0.004732593693568646, 0.5072291035198603, 20.037826650765965])),], ) >>> eos_kwargs = dict(Tcs=constants.Tcs, Pcs=constants.Pcs, omegas=constants.omegas) >>> gas = CEOSGas(SRKMIX, eos_kwargs, HeatCapacityGases=properties.HeatCapacityGases) >>> liq = CEOSLiquid(SRKMIX, eos_kwargs, HeatCapacityGases=properties.HeatCapacityGases) >>> T, P = 361, 1e5 >>> gas = gas.to(T=T, P=P, zs=[0.2384009970908655, 0.5786839935180925, 0.1829150093910419]) >>> liq0 = liq.to(T=T, P=P, zs=[7.619975052238032e-05, 0.9989622883894993, 0.0009615118599781474]) >>> liq1 = liq.to(T=T, P=P, zs=[0.6793120076703771, 0.19699746328631124, 0.12369052904331178]) >>> res = identity_phase_states(phases=[liq0, liq1, gas], constants=constants, correlations=properties, VL_method='PIP') >>> res[0] is gas, res[1][0] is liq0, res[1][1] is liq1, res[2] (True, True, True, [])
Secondary Interfaces¶
- thermo.phase_identification.identity_phase_states(phases, constants, correlations, VL_method='PIP', S_method='d2P_dVdT', VL_ID_settings=None, S_ID_settings=None, skip_solids=False)[source]¶
Identify and the actial phase of all the given phases given the provided settings.
- Parameters
- phases
list
[Phase
] Phases to be identified and sorted, [-]
- constants
ChemicalConstantsPackage
Constants used in the identification, [-]
- correlations
PropertyCorrelationsPackage
Correlations used in the identification, [-]
- VL_method
str
,optional
One of
VL_ID_METHODS
, [-]- S_method
str
,optional
One of
S_ID_METHODS
, [-]- VL_ID_settings
dict
[str
float
]or
None
,optional
Additional configuration options for vapor-liquid phase ID, [-]
- S_ID_settings
dict
[str
float
]or
None
,optional
Additional configuration options for solid-liquid phase ID, [-]
- skip_solidsbool
Set this to True if no phases are provided which can represent a solid phase, [-]
- phases
- Returns
- thermo.phase_identification.VL_ID_METHODS = ['Tpc', 'Vpc', 'Tpc Vpc weighted', 'Tpc Vpc', 'Wilson', 'Poling', 'PIP', 'Bennett-Schmidt', 'Traces']¶
List of all the methods available to perform the Vapor-Liquid phase ID.
- thermo.phase_identification.S_ID_METHODS = ['d2P_dVdT']¶
List of all the methods available to perform the solid-liquid phase ID.
Scoring Functions¶
- thermo.phase_identification.score_phases_VL(phases, constants, correlations, method)[source]¶
Score all phases given the provided parameters and a selected method.
A score above zero indicates a potential gas. More than one phase may have a score above zero, in which case the highest scoring phase is the gas, and the other is a liquid.
- Parameters
- phases
list
[thermo.phases.Phase
] Phases to be identified and sorted, [-]
- constants
ChemicalConstantsPackage
Constants used in the identification, [-]
- correlations
PropertyCorrelationsPackage
Correlations used in the identification, [-]
- method
str
Setting configuring how the scoring is performed; one of ‘Tpc’, ‘Vpc’, ‘Tpc Vpc weighted’, ‘Tpc Vpc’, ‘Wilson’, ‘Poling’, ‘PIP’, ‘Bennett-Schmidt’, ‘Traces’, [-]
- phases
- Returns
Examples
>>> from thermo import ChemicalConstantsPackage, PropertyCorrelationsPackage, CEOSGas, CEOSLiquid, PRMIX, HeatCapacityGas >>> constants = ChemicalConstantsPackage(CASs=['124-38-9', '110-54-3'], Vcs=[9.4e-05, 0.000368], MWs=[44.0095, 86.17536], names=['carbon dioxide', 'hexane'], omegas=[0.2252, 0.2975], Pcs=[7376460.0, 3025000.0], Tbs=[194.67, 341.87], Tcs=[304.2, 507.6], Tms=[216.65, 178.075]) >>> correlations = PropertyCorrelationsPackage(constants=constants, skip_missing=True, HeatCapacityGases=[HeatCapacityGas(poly_fit=(50.0, 1000.0, [-3.1115474168865828e-21, 1.39156078498805e-17, -2.5430881416264243e-14, 2.4175307893014295e-11, -1.2437314771044867e-08, 3.1251954264658904e-06, -0.00021220221928610925, 0.000884685506352987, 29.266811602924644])), HeatCapacityGas(poly_fit=(200.0, 1000.0, [1.3740654453881647e-21, -8.344496203280677e-18, 2.2354782954548568e-14, -3.4659555330048226e-11, 3.410703030634579e-08, -2.1693611029230923e-05, 0.008373280796376588, -1.356180511425385, 175.67091124888998]))]) >>> T, P, zs = 300.0, 1e6, [.5, .5] >>> eos_kwargs = {'Pcs': constants.Pcs, 'Tcs': constants.Tcs, 'omegas': constants.omegas} >>> gas = CEOSGas(PRMIX, eos_kwargs, HeatCapacityGases=correlations.HeatCapacityGases, T=T, P=P, zs=zs) >>> liq = CEOSLiquid(PRMIX, eos_kwargs, HeatCapacityGases=correlations.HeatCapacityGases, T=T, P=P, zs=zs)
A sampling of different phase identification methods is below:
>>> score_phases_VL([gas, liq], constants, correlations, method='PIP') [1.6409446310, -7.5692120928] >>> score_phases_VL([gas, liq], constants, correlations, method='Vpc') [0.00144944049, -0.0001393075288] >>> score_phases_VL([gas, liq], constants, correlations, method='Tpc Vpc') [113.181283525, -29.806038704] >>> score_phases_VL([gas, liq], constants, correlations, method='Bennett-Schmidt') [0.0003538299416, -2.72255439503e-05] >>> score_phases_VL([gas, liq], constants, correlations, method='Poling') [0.1767828268, -0.004516837897]
- thermo.phase_identification.score_phases_S(phases, constants, correlations, method='d2P_dVdT', S_ID_settings=None)[source]¶
Score all phases according to how wolid they appear given the provided parameters and a selected method.
A score above zero indicates a solid. More than one phase may have a score above zero. A score under zero means the phase is a liquid or gas.
- Parameters
- phases
list
[thermo.phases.Phase
] Phases to be identified and sorted, [-]
- constants
ChemicalConstantsPackage
Constants used in the identification, [-]
- correlations
PropertyCorrelationsPackage
Correlations used in the identification, [-]
- method
str
Setting configuring how the scoring is performed; one of (‘d2P_dVdT’,), [-]
- S_ID_settings
dict
[str
float
]or
None
,optional
Additional configuration options for solid-liquid phase ID, [-]
- phases
- Returns
- thermo.phase_identification.vapor_score_traces(zs, CASs, Tcs, trace_CASs=['74-82-8', '7727-37-9'], min_trace=0.0)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the concept of which phase has the most of the lightest compound. This nicely sidesteps issues in many other methods, at the expense that it cannot be applied when there is only one phase and it is not smart enough to handle liquid-liquid cases.
If no trace components are present, the component with the lowest critical temperature’s concentration is returned. Because of the way this is implemented, the score is always larger than 1.0.
- Parameters
- zs
list
[float
] Mole fractions of the phase being identified, [-]
- CASs
list
[str
] CAS numbers of all components, [-]
- Tcs
list
[float
] Critical temperatures of all species, [K]
- trace_CASs
list
[str
] Trace components to use for identification; if more than one component is given, the first component present in both CASs and trace_CASs is the one used, [-]
- min_trace
float
Minimum concentration to make a phase appear vapor-like; subtracted from the concentration which would otherwise be returned, [-]
- zs
- Returns
- score
float
Vapor like score, [-]
- score
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_traces(zs=[.218, .782], Tcs=[304.2, 507.6], CASs=['124-38-9', '110-54-3']) 0.218
Vapor-like phase:
>>> vapor_score_traces(zs=[.975, .025], Tcs=[304.2, 507.6], CASs=['124-38-9', '110-54-3']) 0.975
- thermo.phase_identification.vapor_score_Tpc(T, Tcs, zs)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the following criteria
$T - \sum_i z_i T_{c,i}$- Parameters
- Returns
- score
float
Vapor like score, [-]
- score
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_Tpc(T=300.0, Tcs=[304.2, 507.6], zs=[0.21834418746784942, 0.7816558125321506]) -163.18879226903942
Vapor-like phase:
>>> vapor_score_Tpc(T=300.0, Tcs=[304.2, 507.6], zs=[0.9752234962374878, 0.024776503762512052]) -9.239540865294941
In this result, the vapor phase is not identified as a gas at all! It has a mass density of ~ 20 kg/m^3, which would usually be called a gas by most people.
- thermo.phase_identification.vapor_score_Vpc(V, Vcs, zs)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the following criteria
$V - \sum_i z_i V_{c,i}$- Parameters
- Returns
- score
float
Vapor like score, [-]
- score
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_Vpc(V=0.00011316308855449715, Vcs=[9.4e-05, 0.000368], zs=[0.21834418746784942, 0.7816558125321506]) -0.000195010604079
Vapor-like phase:
>>> vapor_score_Vpc(V=0.0023406573328250335, Vcs=[9.4e-05, 0.000368], zs=[0.9752234962374878, 0.024776503762512052]) 0.002239868570
- thermo.phase_identification.vapor_score_Tpc_weighted(T, Tcs, Vcs, zs, r1=1.0)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the following criteria, said to be implemented in ECLIPSE [1]:
$T - T_{pc}$$T_{p,c} = r_1 \frac{\sum_j x_j V_{c,j}T_{c,j}}{\sum_j x_j V_{c,j}}$- Parameters
- Returns
- score
float
Vapor like score, [-]
- score
References
- 1
Bennett, Jim, and Kurt A. G. Schmidt. “Comparison of Phase Identification Methods Used in Oil Industry Flow Simulations.” Energy & Fuels 31, no. 4 (April 20, 2017): 3370-79. https://doi.org/10.1021/acs.energyfuels.6b02316.
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_Tpc_weighted(T=300.0, Tcs=[304.2, 507.6], Vcs=[9.4e-05, 0.000368], zs=[0.21834418746784942, 0.7816558125321506]) -194.0535694431
Vapor-like phase:
>>> vapor_score_Tpc_weighted(T=300.0, Tcs=[304.2, 507.6], Vcs=[9.4e-05, 0.000368], zs=[0.9752234962374878, 0.024776503762512052]) -22.60037521107
As can be seen, the CO2-phase is incorrectly identified as a liquid.
- thermo.phase_identification.vapor_score_Tpc_Vpc(T, V, Tcs, Vcs, zs)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the following criteria, said to be implemented in Multiflash [1]:
$VT^2 - V_{pc} T_{pc}^2$- Parameters
- Returns
- score
float
Vapor like score, [-]
- score
References
- 1
Bennett, Jim, and Kurt A. G. Schmidt. “Comparison of Phase Identification Methods Used in Oil Industry Flow Simulations.” Energy & Fuels 31, no. 4 (April 20, 2017): 3370-79. https://doi.org/10.1021/acs.energyfuels.6b02316.
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_Tpc_Vpc(T=300.0, V=0.00011316308855449715, Tcs=[304.2, 507.6], Vcs=[9.4e-05, 0.000368], zs=[0.21834418746784942, 0.7816558125321506]) -55.932094761
Vapor-like phase:
>>> vapor_score_Tpc_Vpc(T=300.0, V=0.0023406573328250335, Tcs=[304.2, 507.6], Vcs=[9.4e-05, 0.000368], zs=[0.9752234962374878, 0.024776503762512052]) 201.020821992
- thermo.phase_identification.vapor_score_Wilson(T, P, zs, Tcs, Pcs, omegas)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the Rachford-Rice Wilson method of Perschke [1].
After calculating Wilson’s K values, the following expression is evaluated at $\frac{V}{F} = 0.5$; the result is the score.
$\sum_i \frac{z_i(K_i-1)}{1 + \frac{V}{F}(K_i-1)}$- Parameters
- Returns
- score
float
Vapor like score, [-]
- score
References
- 1
Chang, Yih-Bor. “Development and Application of an Equation of State Compositional Simulator,” 1990. https://repositories.lib.utexas.edu/handle/2152/80585.
Examples
A flash of equimolar CO2/n-hexane at 300 K and 1 MPa is computed, and there is a two phase solution. The phase must be identified for each result:
Liquid-like phase:
>>> vapor_score_Wilson(T=300.0, P=1e6, zs=[.218, .782], Tcs=[304.2, 507.6], Pcs=[7376460.0, 3025000.0], omegas=[0.2252, 0.2975]) -1.16644793
Vapor-like phase:
>>> vapor_score_Wilson(T=300.0, P=1e6, zs=[.975, .025], Tcs=[304.2, 507.6], Pcs=[7376460.0, 3025000.0], omegas=[0.2252, 0.2975]) 1.397678492
This method works well in many conditions, like the Wilson equation itself, but fundamentally it cannot do a great job because it is not tied to the phase model itself.
A dew point flash at P = 100 Pa for the same mixture shows both phases being identified as vapor-like:
>>> T_dew = 206.40935716944634 >>> P = 100.0 >>> vapor_score_Wilson(T=T_dew, P=P, zs=[0.5, 0.5], Tcs=[304.2, 507.6], Pcs=[7376460.0, 3025000.0], omegas=[0.2252, 0.2975]) 1.074361930956633 >>> vapor_score_Wilson(T=T_dew, P=P, zs=[0.00014597910182360052, 0.9998540208981763], Tcs=[304.2, 507.6], Pcs=[7376460.0, 3025000.0], omegas=[0.2252, 0.2975]) 0.15021784286075726
- thermo.phase_identification.vapor_score_Poling(kappa)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the isothermal compressibility kappa concept by Poling [1].
$\text{score} = (\kappa - 0.005 \text{atm}^{-1})$- Parameters
- kappa
float
Isothermal coefficient of compressibility, [1/Pa]
- kappa
- Returns
- score
float
Vapor like score, [-]
- score
Notes
A second criteria which is not implemented as it does not fit with the scoring concept is for liquids:
$\frac{0.9}{P} < \beta < \frac{3}{P}$References
- 1
Poling, Bruce E., Edward A. Grens, and John M. Prausnitz. “Thermodynamic Properties from a Cubic Equation of State: Avoiding Trivial Roots and Spurious Derivatives.” Industrial & Engineering Chemistry Process Design and Development 20, no. 1 (January 1, 1981): 127-30. https://doi.org/10.1021/i200012a019.
Examples
CO2 vapor properties computed with Peng-Robinson at 300 K and 1 bar:
>>> vapor_score_Poling(1.0054239121594122e-05) 1.013745778995
n-hexane liquid properties computed with Peng-Robinson at 300 K and 10 bar:
>>> vapor_score_Poling(2.121777078782957e-09) -0.00478501093
- thermo.phase_identification.vapor_score_PIP(V, dP_dT, dP_dV, d2P_dV2, d2P_dVdT)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the PIP concept.
$\text{score} = -(\Pi - 1)$$\Pi = V \left[\frac{\frac{\partial^2 P}{\partial V \partial T}} {\frac{\partial P }{\partial T}}- \frac{\frac{\partial^2 P}{\partial V^2}}{\frac{\partial P}{\partial V}} \right]$- Parameters
- V
float
Molar volume at T and P, [m^3/mol]
- dP_dT
float
Derivative of P with respect to T, [Pa/K]
- dP_dV
float
Derivative of P with respect to V, [Pa*mol/m^3]
- d2P_dV2
float
Second derivative of P with respect to V, [Pa*mol^2/m^6]
- d2P_dVdT
float
Second derivative of P with respect to both V and T, [Pa*mol/m^3/K]
- V
- Returns
- score
float
Vapor like score, [-]
- score
References
- 1
Venkatarathnam, G., and L. R. Oellrich. “Identification of the Phase of a Fluid Using Partial Derivatives of Pressure, Volume, and Temperature without Reference to Saturation Properties: Applications in Phase Equilibria Calculations.” Fluid Phase Equilibria 301, no. 2 (February 25, 2011): 225-33. doi:10.1016/j.fluid.2010.12.001.
Examples
CO2 vapor properties computed with Peng-Robinson at 300 K and 1 bar:
>>> vapor_score_PIP(0.024809176851423774, 337.0119286073647, -4009021.959558917, 321440573.3615088, -13659.63987996052) 0.016373735005
n-hexane liquid properties computed with Peng-Robinson at 300 K and 10 bar:
>>> vapor_score_PIP(0.00013038156684574785, 578477.8796379718, -3614798144591.8984, 4.394997991022487e+17, -20247865009.795322) -10.288635225
- thermo.phase_identification.vapor_score_Bennett_Schmidt(dbeta_dT)[source]¶
Compute a vapor score representing how vapor-like a phase is (higher, above zero = more vapor like) using the Bennet-Schmidt temperature derivative of isobaric expansion suggestion.
$\text{score} = -\left(\frac{\partial \beta}{\partial T}\right)$- Parameters
- dbeta_dT
float
Temperature derivative of isobaric coefficient of a thermal expansion, [1/K^2]
- dbeta_dT
- Returns
- score
float
Vapor like score, [-]
- score
References
- 1
Bennett, Jim, and Kurt A. G. Schmidt. “Comparison of Phase Identification Methods Used in Oil Industry Flow Simulations.” Energy & Fuels 31, no. 4 (April 20, 2017): 3370-79. https://doi.org/10.1021/acs.energyfuels.6b02316.
Examples
CO2 vapor properties computed with Peng-Robinson at 300 K and 1 bar:
>>> vapor_score_Bennett_Schmidt(-1.1776172267959163e-05) 1.1776172267959163e-05
n-hexane liquid properties computed with Peng-Robinson at 300 K and 10 bar:
>>> vapor_score_Bennett_Schmidt(7.558572848883679e-06) -7.558572848883679e-06
Sorting Phases¶
- thermo.phase_identification.sort_phases(liquids, solids, constants, settings)[source]¶
Identify and sort all phases given the provided parameters. This is not a thermodynamic concept; it is just a convinience method to make the results of the flash more consistent, because the flash algorithms don’t care about density or ordering the phases.
- Parameters
- liquids
list
[Phase
] Liquids that were identified, [-]
- solids
list
[Phase
] Solids that were identified, [-]
- constants
ChemicalConstantsPackage
Constants used in the identification, [-]
- correlations
PropertyCorrelationsPackage
Correlations used in the identification, [-]
- settings
BulkSettings
Settings object controlling the phase sorting, [-]
- liquids
- Returns
Notes
The settings object uses the preferences liquid_sort_method, liquid_sort_prop, liquid_sort_cmps, liquid_sort_cmps_neg, and phase_sort_higher_first.