#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2025, Juan José Gómez Romera <jjgomera@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Library to multiparameter equation of state calculation using refprop and
the python binding from https://github.com/BenThelen/python-refprop. This \
library implement an old unnofficial library wrapper compatible only \
with Refprop v.9, refprop dll must be installed from NIST package.
If available, this is a optional speed up method for mEoS internal library
All the functionality is included in the main class:
* :class:`RefProp`: Stream definition using refProp external library
API reference
-------------
"""
import sys
try:
import refprop
except ImportError:
pass
from lib import unidades, mEoS
# from lib.config import Preferences
from lib.mezcla import mix_unitmassflow, mix_unitmolarflow
from lib.thermo import ThermoRefProp
# TODO: Implement the official python wrapper compatible too with REFPROP v.10
# https://github.com/usnistgov/REFPROP-wrappers/tree/master/wrappers/python
__doi__ = {
1:
{"autor": "Lemmon, E.W., Huber, M.L., McLinden, M.O.",
"title": "NIST Standard Reference Database 23: Reference Fluid"
"Thermodynamic and Transport Properties-REFPROP, Version"
"9.1, National Institute of Standards and Technology,"
"Standard Reference Data Program, Gaithersburg, 2013.",
"ref": "",
"doi": ""},
2:
{"autor": "Thelen, B.",
"title": "Python refprop wrapper, "
"https://github.com/BenThelen/python-refprop",
"ref": "",
"doi": ""},
3:
{"autor": "Huber, M.L., Lemmon, E.W., Bell, I.H., McLinden, M.O.",
"title": "The NIST REFPROP Database for Highly Accurate Properties "
"of Industrially Importants Fluids",
"ref": "Ind. Eng. Chem. Res. 61(42) (2022) 15449-15472",
"doi": "10.1021/acs.iecr.2c01427"}}
# Automatic loading of refprop name from meos subclass _refPropName property
all__ = {}
noIds = []
for cmp in mEoS.__all__:
if cmp.id and cmp._refPropName:
all__[cmp.id] = cmp._refPropName
elif cmp._refPropName:
noIds.append(cmp._refPropName)
[docs]
class RefProp(ThermoRefProp):
"""
Stream class using refProp external library
Parameters needed to define it are:
-ref: reference state
-ids: index of fluid
-fraccionMolar: molar fraction
-T: Temperature, Kelvin
-P: Pressure, Pa
-rho: Density, kg/m3
-H: Enthalpy, J/kg
-S: Entropy, J/kgK
-U: Internal energy, J/kg
-x: Quality, -
setref parameters
setref(hrf='DEF', ixflag=1, x0=[1], h0=0, s0=0, t0=273, p0=100):
hrf--reference state for thermodynamic calculations [character*3]
'NBP': h,s = 0 at normal boiling point(s)
'ASH': h,s = 0 for sat liquid at -40 C (ASHRAE convention)
'IIR': h = 200, s = 1.0 for sat liq at 0 C (IIR convention)
'DEF': default reference state as specified in fluid file is
applied to each component (ixflag = 1 is used)
'OTH': other, as specified by h0, s0, t0, p0 (real gas state)
'OT0': other, as specified by h0, s0, t0, p0 (ideal gas state)
'???': change hrf to the current reference state and exit.
ixflag--composition flag:
1 = ref state applied to pure components
2 = ref state applied to mixture icomp
following input has meaning only if ixflag = 2
x0--composition for which h0, s0 apply; list(1:nc) [mol frac]
this is useful for mixtures of a predefined composition, e.g.
refrigerant blends such as R410A
following inputs have meaning only if hrf = 'OTH'
h0--reference state enthalpy at t0,p0 {icomp} [J/mol]
s0--reference state entropy at t0,p0 {icomp} [J/mol-K]
t0--reference state temperature [K]
t0 = -1 indicates saturated liquid at normal boiling point
(bubble point for a mixture)
p0--reference state pressure [kPa]
p0 = -1 indicates saturated liquid at t0 {and icomp}
p0 = -2 indicates saturated vapor at t0 {and icomp}
setmod parameters:
setmod(htype='NBS', hmix='NBS', *hcomp):
inputs 'in string format':
htype - flag indicating which models are to be set [character*3]:
'EOS': equation of state for thermodynamic properties
'ETA': viscosity
'TCX': thermal conductivity
'STN': surface tension
'NBS': reset all of the above model types and all subsidiary
component models to 'NBS'; values of hmix and hcomp are ignored
hmix--mixture model to use for the property specified in htype
[character*3]:
ignored if number of components = 1
some allowable choices for hmix:
'NBS': use NIST recommendation for specified fluid/mixture
'HMX': mixture Helmholtz model for thermodynamic properties
'ECS': extended corresponding states for viscosity or th cond
'STX': surface tension mixture model
hcomp--component model(s) to use for property specified in htype
[array (1..nc) of character*3]:
'NBS': NIST recommendation for specified fluid/mixture
some allowable choices for an equation of state:
'FEQ': Helmholtz free energy model
'BWR': pure fluid modified Benedict-Webb-Rubin (MBWR)
'ECS': pure fluid thermo extended corresponding states
some allowable choices for viscosity:
'ECS': extended corresponding states (all fluids)
'VS1': the 'composite' model for R134a, R152a, NH3, etc.
'VS2': Younglove-Ely model for hydrocarbons
'VS4': Generalized friction theory of Quinones-Cisneros and
Deiters
'VS5': Chung et al. (1988) predictive model
some allowable choices for thermal conductivity:
'ECS': extended corresponding states (all fluids)
'TC1': the 'composite' model for R134a, R152a, etc.
'TC2': Younglove-Ely model for hydrocarbons
'TC5': Chung et al. (1988) predictive model
some allowable choices for surface tension:
'ST1': surface tension as f(tau); tau = 1 - T/Tc
setktv parameters
setktv(icomp, jcomp, hmodij, fij=([0] * _nmxpar), hfmix='HMX.BNC'):
icomp--component
jcomp--component j
hmodij--mixing rule for the binary pair i,j [character*3] e.g.:
'LJ1' (Lemmon-Jacobsen model)
'LM1' (modified Lemmon-Jacobsen model) or
'LIN' (linear mixing rules)
'RST' indicates reset all pairs to values from original call to
SETUP (i.e. those read from file) [all other inputs are
ignored]
fij--binary mixture parameters [array of dimension nmxpar; currently
nmxpar is set to 6] the parameters will vary depending on hmodij;
for example, for the Lemmon-Jacobsen model
(LJ1):
fij(1) = zeta
fij(2) = xi
fij(3) = Fpq
fij(4) = beta
fij(5) = gamma
fij(6) = 'not used'
hfmix--file name [character*255] containing generalized parameters
for the binary mixture model; this will usually be the same as the
corresponding input to SETUP (e.g.,':fluids:HMX.BNC')
"""
kwargs = {"ids": [],
"fraccionMolar": [],
"fraccionMasica": [],
"caudalUnitarioMolar": [],
"caudalUnitarioMasico": [],
"T": 0.0,
"P": 0.0,
"x": None,
"Q": None,
"rho": 0.0,
"D": 0.0,
"H": 0.0,
"S": 0.0,
"u": 0.0,
"E": 0.0,
# Configuration parameters
"preos": False,
"aga": False,
"gerg": False,
"hrf": "DEF",
"ixflag": 1,
"x0": [1],
"h0": 0,
"s0": 0,
"t0": 273,
"p0": 1e5,
"htype": "NBS",
"hmix": "NBS",
"hcomp": "",
# setktv don't implemented
}
@property
def calculable(self):
"""Check in the class is fully defined. The correct definition require
two parts:
* Thermodynamics definition: whatever pair properties between T, P,
h, s, v, rho, x
* Compound definition: Ids for compound identification, and in
multicomponent defintion any kind of mixture definition
"""
# Check mix state
self._multicomponent = False
if len(self.kwargs["ids"]) > 1:
self._multicomponent = True
# Check supported fluid
REFPROP_available = True
for id in self.kwargs["ids"]:
if id not in all__ and id not in noIds:
REFPROP_available = False
if not REFPROP_available:
raise ValueError
# Mix definition
self._mix = 0
if len(self.kwargs["fraccionMolar"]) == len(self.kwargs["ids"]):
self._mix = 1
elif len(self.kwargs["fraccionMasica"]) == len(self.kwargs["ids"]):
self._mix = 2
elif len(self.kwargs["caudalUnitarioMolar"]) == \
len(self.kwargs["ids"]):
self._mix = 3
elif len(self.kwargs["caudalUnitarioMasico"]) == \
len(self.kwargs["ids"]):
self._mix = 4
# Check correct fluid definition
if self._multicomponent:
if self.kwargs["ids"] and self._mix:
self._definition = True
else:
self._definition = False
else:
self._definition = True
# Update the kwargs with the special refprop namespace
if self.kwargs["x"] != RefProp.kwargs["x"]:
self.kwargs["Q"] = self.kwargs["x"]
if self.kwargs["rho"] != RefProp.kwargs["rho"]:
self.kwargs["D"] = self.kwargs["rho"]
if self.kwargs["u"] != RefProp.kwargs["u"]:
self.kwargs["E"] = self.kwargs["u"]
# Check thermo definition
self._thermo = ""
for def_ in ["TP", "TQ", "PQ", "TD", "PD", "PH", "PS", "HS", "TH",
"TS", "TE", "PE", "ES", "DH", "DS", "DE"]:
if self.kwargs[def_[0]] != RefProp.kwargs[def_[0]] and \
self.kwargs[def_[1]] != RefProp.kwargs[def_[1]]:
self._thermo = def_
return self._definition and self._thermo
[docs]
def args(self):
x = self._x()
# Convert to float because unit subclass raise InputError
var1 = float(self.kwargs[self._thermo[0]])
var2 = float(self.kwargs[self._thermo[1]])
# unit conversion to refprop accepted units
# P in kPa, U,H in kJ/kmol, S in kJ/kmolK
if self._thermo[0] == "P":
var1 /= 1000.
elif self._thermo[0] in ("E", "H", "S"):
var1 /= 1000. / self.M
elif self._thermo[0] == "D":
var1 /= self.M
if self._thermo[1] == "P":
var2 /= 1000.
elif self._thermo[1] in ("E", "H", "S"):
var2 /= 1000. / self.M
elif self._thermo[1] == "D":
var2 /= self.M
return self._thermo, var1, var2, x
[docs]
def _name(self):
name = []
for fld in self.kwargs["ids"]:
if fld in all__:
name.append(all__[fld])
elif fld in noIds:
name.append(fld)
return name
[docs]
def _x(self):
if self._mix == 1:
x = self.kwargs["fraccionMolar"]
elif self._mix == 2:
x = refprop.xmole(self.kwargs["fraccionMasica"])["x"]
elif self._mix == 3:
kw = mix_unitmolarflow(self.kwargs["caudalUnitarioMolar"])
x = kw["fraccionMolar"]
elif self._mix == 3:
kw = mix_unitmassflow(self.kwargs["caudalUnitarioMasico"])
x = kw["fraccionMolar"]
else:
x = [1]
return x
[docs]
def _fixed(self):
"""Calculate fixed properties with the chemical compound ids specified,
valid only for one component"""
x = self._x()
fluido = self._name()
refprop.setup("def", fluido)
info = refprop.info()
self.M = unidades.Dimensionless(info["wmm"])
self.Tt = unidades.Temperature(info["ttrp"])
self.Tb = unidades.Temperature(info["tnbpt"])
self.Tc = unidades.Temperature(info["tcrit"])
self.R = unidades.SpecificHeat(info["Rgas"]/self.M)
self.f_accent = unidades.Dimensionless(info["acf"])
self.momentoDipolar = unidades.DipoleMoment(info["dip"], "Debye")
self.rhoc = unidades.Density(info["Dcrit"]*self.M)
self.zc = unidades.Dimensionless(info["zcrit"])
self.Pc = unidades.Pressure(self.R*self.Tc*self.rhoc*self.zc, "kPa")
name = refprop.name()
self.name = name["hname"]
self.CAS = name["hcas"]
[docs]
def cleanOldValues(self, **kwargs):
"""Convert alternative input parameters"""
# Alternative rho input
if "rhom" in kwargs:
kwargs["rho"] = kwargs["rhom"]*self.M
del kwargs["rhom"]
elif kwargs.get("v", 0):
kwargs["rho"] = 1./kwargs["v"]
del kwargs["v"]
elif kwargs.get("vm", 0):
kwargs["rho"] = self.M/kwargs["vm"]
del kwargs["vm"]
if kwargs.get("s", 0):
kwargs["S"] = kwargs["s"]
del kwargs["s"]
if kwargs.get("h", 0):
kwargs["H"] = kwargs["h"]
del kwargs["h"]
self.kwargs.update(kwargs)
[docs]
def cleanOldKwargs(self):
for var in ["T", "P", "Q", "D", "H", "S", "E"]:
if var not in self._thermo:
self.kwargs[var] = RefProp.kwargs[var]
[docs]
def calculo(self):
try:
self._calculo()
except refprop.RefpropdllError as e:
self.status = 5
self.msg = str(e)
except refprop.RefpropdllWarning as e:
self.status = 5
self.msg = str(e)
[docs]
def _initialization(self):
# TODO: Add configuration section to Preferences
# preos = Preferences.getboolean("refProp", "preos")
# aga = Preferences.getboolean("refProp", "aga")
# gerg = Preferences.getboolean("refProp", "gerg")
preos = self.kwargs["preos"]
aga = self.kwargs["aga"]
gerg = self.kwargs["gerg"]
fluido = self._name()
kwmod = [self.kwargs[k] for k in ('htype', 'hmix', 'hcomp')]
refprop.setmod(*kwmod)
if gerg:
refprop.gerg04(ixflag=1)
refprop.setup("def", fluido)
# refprop.setktv()
if preos:
refprop.preos(ixflag=2)
elif aga:
refprop.setaga()
kwref = {k: self.kwargs[k] for k in (
'hrf', 'ixflag', 'x0', 'h0', 's0', 't0', 'p0')}
refprop.setref(**kwref)
[docs]
def _calculo(self):
self._initialization()
x = self._x()
m = refprop.wmol(x)["wmix"]
self.M = unidades.Dimensionless(m)
crit = refprop.critp(x)
self.Pc = unidades.Pressure(crit["pcrit"], "kPa")
self.Tc = unidades.Temperature(crit["tcrit"])
self.rhoc = unidades.Density(crit["Dcrit"]*self.M)
args = self.args()
flash = refprop.flsh(*args)
# check if ['q'] in fld
if 'q' in flash.keys():
x = flash['q']
elif 'h' in flash.keys():
x = refprop.flsh('ph', flash['p'], flash['h'], flash['x'])['q']
elif 's' in flash.keys():
x = refprop.flsh('ps', flash['p'], flash['s'], flash['x'])['q']
if 0 < x < 1:
region = 4
else:
region = 1
if x < 0:
x = 0
elif x > 1:
x = 1
self.x = unidades.Dimensionless(x)
self.T = unidades.Temperature(flash["t"])
self.P = unidades.Pressure(flash["p"], "kPa")
self.Tr = unidades.Dimensionless(self.T/self.Tc)
self.Pr = unidades.Dimensionless(self.P/self.Pc)
self.rho = unidades.Density(flash["D"]*self.M)
self.v = unidades.SpecificVolume(1./self.rho)
self.phase = self.getphase(Tc=self.Tc, Pc=self.Pc, T=self.T, P=self.Pc,
x=self.x, region=region)
if flash["nc"] == 1:
name = refprop.name(flash["nc"])
self.name = name["hname"]
self.synonim = name["hn80"]
self.CAS = name["hcas"]
info = refprop.info(flash["nc"])
self.R = unidades.SpecificHeat(info["Rgas"]/self.M)
self.Tt = unidades.Temperature(info["ttrp"])
self.Tb = unidades.Temperature(info["tnbpt"])
self.f_accent = unidades.Dimensionless(info["acf"])
self.momentoDipolar = unidades.DipoleMoment(info["dip"], "Debye")
self._doc = {}
for htype in ['EOS', 'CP0', 'ETA', 'VSK', 'TCX', 'TKK', 'STN',
'DE ', 'MLT', 'SBL', 'PS ', 'DL ', 'DV ']:
self._doc[htype] = refprop.getmod(flash["nc"], htype)["hcite"]
else:
self.name = ""
self.synonim = ""
self.CAS = ""
rmix = refprop.rmix2(flash["x"])
self.R = unidades.SpecificHeat(rmix["Rgas"]/self.M)
self.Tt = unidades.Temperature(None)
self.Tb = unidades.Temperature(None)
self.f_accent = unidades.Dimensionless(None)
self.momentoDipolar = unidades.DipoleMoment(None)
self._doc = {}
self._cp0(flash)
self.Liquido = ThermoRefProp()
self.Gas = ThermoRefProp()
if self.x == 0.:
# liquid phase
self.fill(self.Liquido, flash["t"], flash["D"], flash["x"])
self.fill(self, flash["t"], flash["D"], flash["x"])
self.fillNone(self.Gas)
elif self.x == 1.:
# vapor phase
self.fill(self.Gas, flash["t"], flash["D"], flash["x"])
self.fill(self, flash["t"], flash["D"], flash["x"])
self.fillNone(self.Liquido)
else:
# Two phase
self.fillNone(self)
self.fill(self.Liquido, flash["t"], flash["Dliq"], flash["xliq"])
self.fill(self.Gas, flash["t"], flash["Dvap"], flash["xvap"])
self.v = unidades.SpecificVolume(x*self.Gas.v+(1-x)*self.Liquido.v)
self.rho = unidades.Density(1./self.v)
self.u = unidades.Enthalpy(flash["e"]/self.M, "Jg")
self.h = unidades.Enthalpy(flash["h"]/self.M, "Jg")
self.s = unidades.SpecificHeat(flash["s"]/self.M, "JgK")
self.a = unidades.Enthalpy(self.u-self.T*self.s)
self.g = unidades.Enthalpy(self.h-self.T*self.s)
self.rhoM = unidades.MolarDensity(self.rho/self.M)
self.hM = unidades.MolarEnthalpy(self.h*self.M)
self.sM = unidades.MolarSpecificHeat(self.s*self.M)
self.uM = unidades.MolarEnthalpy(self.u*self.M)
self.aM = unidades.MolarEnthalpy(self.a*self.M)
self.gM = unidades.MolarEnthalpy(self.g*self.M)
if self.x < 1 and self.T <= self.Tc:
surten = refprop.surten(flash["t"], flash["Dliq"], flash["Dvap"],
flash["xliq"], flash["xvap"])
self.sigma = unidades.Tension(surten["sigma"])
else:
self.sigma = unidades.Tension(None)
if 0 < self.x < 1:
self.Hvap = unidades.Enthalpy(self.Gas.h-self.Liquido.h)
self.Svap = unidades.SpecificHeat(self.Gas.s-self.Liquido.s)
self.K = []
for x, y in zip(self.Liquido.fraccion, self.Gas.fraccion):
self.K.append(unidades.Dimensionless(y/x))
else:
self.Hvap = unidades.Enthalpy(None)
self.Svap = unidades.SpecificHeat(None)
self.K = [unidades.Dimensionless(1)]*flash["nc"]
self.invT = unidades.InvTemperature(-1/self.T)
# NOT supported on Windows
if sys.platform != "win32":
excess = refprop.excess(flash["t"], flash["D"], flash["x"])
self.vE = unidades.Volume(excess["vE"]/self.M)
self.uE = unidades.Enthalpy(excess["eE"]/self.M, "Jg")
self.hE = unidades.Enthalpy(excess["hE"]/self.M, "Jg")
self.sE = unidades.SpecificHeat(excess["sE"]/self.M, "JgK")
self.aE = unidades.Enthalpy(excess["aE"]/self.M, "Jg")
self.gE = unidades.Enthalpy(excess["gE"]/self.M, "Jg")
else:
self.vE = unidades.Volume(0)
self.uE = unidades.Enthalpy(0)
self.hE = unidades.Enthalpy(0)
self.sE = unidades.SpecificHeat(0)
self.aE = unidades.Enthalpy(0)
self.gE = unidades.Enthalpy(0)
self.csat = []
self.dpdt_sat = []
self.cv2p = []
if self.Tt <= flash["t"] <= self.Tc:
for i in range(1, flash["nc"]+1):
dat = refprop.dptsatk(i, flash["t"], kph=2)
cs = unidades.SpecificHeat(dat["csat"]/self.M, "JgK")
self.csat.append(cs)
self.dpdt_sat.append(
unidades.PressureTemperature(dat["dpdt"], "kPaK"))
cv2 = refprop.cv2pk(i, flash["t"], flash["D"])
cv = unidades.SpecificHeat(cv2["cv2p"]/self.M, "JgK")
self.cv2p.append(cv)
[docs]
def _cp0(self, flash):
"Set ideal properties to state"""
cp0 = refprop.therm0(flash["t"], flash["D"], flash["x"])
self.v0 = unidades.SpecificVolume(self.R*self.T/self.P.kPa)
self.rho0 = unidades.Density(1/self.v0)
self.P0 = unidades.Pressure(cp0["p"], "kPa")
self.P_Pideal = unidades.Pressure(self.P-self.P0)
self.h0 = unidades.Enthalpy(cp0["h"]/self.M, "kJkg")
self.u0 = unidades.Enthalpy(cp0["e"]/self.M, "kJkg")
self.s0 = unidades.SpecificHeat(cp0["s"]/self.M, "kJkgK")
self.a0 = unidades.Enthalpy(cp0["A"]/self.M, "kJkg")
self.g0 = unidades.Enthalpy(cp0["G"]/self.M, "kJkg")
self.w0 = unidades.Speed(cp0["w"])
cp0 = refprop.therm0(float(self.T), self.rho0/self.M, flash["x"])
self.cp0 = unidades.SpecificHeat(cp0["cp"]/self.M, "kJkgK")
self.cv0 = unidades.SpecificHeat(cp0["cv"]/self.M, "kJkgK")
self.cp0_cv = unidades.Dimensionless(self.cp0/self.cv0)
self.gamma0 = self.cp0_cv
self.rhoM0 = unidades.MolarDensity(self.rho0/self.M)
self.hM0 = unidades.MolarEnthalpy(self.h0*self.M)
self.uM0 = unidades.MolarEnthalpy(self.u0*self.M)
self.sM0 = unidades.MolarSpecificHeat(self.s0*self.M)
self.aM0 = unidades.MolarEnthalpy(self.a0*self.M)
self.gM0 = unidades.MolarEnthalpy(self.g0*self.M)
self.cpM0 = unidades.MolarSpecificHeat(self.cp0*self.M)
self.cvM0 = unidades.MolarSpecificHeat(self.cv0*self.M)
[docs]
def fill(self, fase, T, rho, x):
if sum(x) != 1:
x = [round(xi, 10) for xi in x]
mol = refprop.wmol(x)
thermo = refprop.therm2(T, rho, x)
thermo3 = refprop.therm3(T, rho, x)
fase._bool = True
fase.M = unidades.Dimensionless(mol["wmix"])
fase.rho = unidades.Density(rho*fase.M)
fase.v = unidades.SpecificVolume(1./fase.rho)
fase.Z = unidades.Dimensionless(thermo["Z"])
fase.u = unidades.Enthalpy(thermo["e"]/fase.M, "Jg")
fase.h = unidades.Enthalpy(thermo["h"]/fase.M, "Jg")
fase.s = unidades.SpecificHeat(thermo["s"]/fase.M, "JgK")
fase.a = unidades.Enthalpy(thermo["A"]/fase.M, "Jg")
fase.g = unidades.Enthalpy(thermo["G"]/fase.M, "Jg")
fase.cv = unidades.SpecificHeat(thermo["cv"]/fase.M, "JgK")
fase.cp = unidades.SpecificHeat(thermo["cp"]/fase.M, "JgK")
fase.cp_cv = unidades.Dimensionless(fase.cp/fase.cv)
fase.gamma = fase.cp_cv
fase.w = unidades.Speed(thermo["w"])
fase.rhoM = unidades.MolarDensity(fase.rho/self.M)
fase.hM = unidades.MolarEnthalpy(fase.h*self.M)
fase.sM = unidades.MolarSpecificHeat(fase.s*self.M)
fase.uM = unidades.MolarEnthalpy(fase.u*self.M)
fase.aM = unidades.MolarEnthalpy(fase.a*self.M)
fase.gM = unidades.MolarEnthalpy(fase.g*self.M)
fase.cvM = unidades.MolarSpecificHeat(fase.cv*self.M)
fase.cpM = unidades.MolarSpecificHeat(fase.cp*self.M)
residual = refprop.residual(T, rho, x)
fase.pr = unidades.Pressure(residual["pr"], "kPa")
fase.ur = unidades.Enthalpy(residual["er"]/fase.M, "Jg")
fase.hr = unidades.Enthalpy(residual["hr"]/fase.M, "Jg")
fase.sr = unidades.SpecificHeat(residual["sr"]/fase.M, "JgK")
fase.ar = unidades.Enthalpy(residual["Ar"]/fase.M, "Jg")
fase.gr = unidades.Enthalpy(residual["Gr"]/fase.M, "Jg")
fase.cvr = unidades.SpecificHeat(residual["cvr"]/fase.M, "JgK")
fase.cpr = unidades.SpecificHeat(residual["cpr"]/fase.M, "JgK")
fase.alfav = unidades.InvTemperature(thermo["beta"])
fase.kappa = unidades.InvPressure(thermo["xkappa"], "kPa")
fase.kappas = unidades.InvPressure(thermo3["betas"], "kPa")
fase.alfap = unidades.Density(fase.alfav/self.P/fase.kappa)
fase.deltat = unidades.EnthalpyPressure(
thermo3["thrott"]/fase.M, "kJkgkPa")
fase.joule = unidades.TemperaturePressure(thermo["hjt"], "KkPa")
fase.betas = unidades.TemperaturePressure(
self.derivative("T", "P", "s", fase))
fase.betap = unidades.Density(
-1/self.P*self.derivative("P", "v", "T", fase))
fase.Kt = unidades.Pressure(thermo3["xkkt"], "kPa")
fase.Ks = unidades.Pressure(thermo3["bs"], "kPa")
fase.kt = unidades.Dimensionless(thermo3["xkt"])
fase.ks = unidades.Dimensionless(thermo3["xisenk"])
dh = refprop.dhd1(T, rho, x)
fase.dhdT_rho = unidades.SpecificHeat(dh["dhdt_D"]/fase.M, "kJkgK")
fase.dhdT_P = unidades.SpecificHeat(dh["dhdt_p"]/fase.M, "kJkgK")
fase.dhdP_T = unidades.EnthalpyPressure(dh["dhdp_t"]/fase.M, "kJkgkPa")
# dhdtp_D : fix in library
fase.dhdP_rho = unidades.EnthalpyPressure(
dh["dhdtp_D"]/fase.M, "kJkgkPa")
fase.dhdrho_T = unidades.EnthalpyDensity(
dh["dhdD_t"]/fase.M**2, "kJkgkgm3")
fase.dhdrho_P = unidades.EnthalpyDensity(
dh["dhdD_p"]/fase.M**2, "kJkgkgm3")
fase.dpdT_rho = unidades.PressureTemperature(thermo["dpdt"], "kPaK")
fase.dpdrho_T = unidades.PressureDensity(
thermo["dpdD"]/fase.M, "kPakgm3")
# TODO: Add unit for derivative d^2p/dD^2 [kPa-L^2/mol^2]
# MPa·m⁶/kg²
fase.d2pdrho2 = unidades.Dimensionless(thermo["d2pdD2"]/fase.M**2/1000)
fase.drhodP_T = unidades.DensityPressure(
thermo["dDdp"]*fase.M, "kgm3kPa")
fase.drhodT_P = unidades.DensityTemperature(thermo["dDdt"]*fase.M)
fase.Gruneisen = unidades.Dimensionless(fase.v/fase.cv*fase.dpdT_rho)
fase.Z_rho = unidades.SpecificVolume((fase.Z-1)/fase.rho)
fase.IntP = unidades.Pressure(thermo3["pint"], "kPa")
fase.hInput = unidades.Enthalpy(thermo3["spht"]/fase.M, "kJkg")
fase.invT = unidades.InvTemperature(-1/self.T)
fpv = refprop.fpv(T, rho, self.P.kPa, x)["Fpv"]
fase.fpv = unidades.Dimensionless(fpv)
chempot = refprop.chempot(T, rho, x)["u"]
fase.chempot = [unidades.Enthalpy(c/fase.M) for c in chempot]
fi = refprop.fugcof(T, rho, x)["f"]
fase.fi = [unidades.Dimensionless(f) for f in fi]
f = refprop.fgcty(T, rho, x)["f"]
fase.f = [unidades.Pressure(f_i, "kPa") for f_i in f]
b = refprop.virb(T, x)["b"]
fase.virialB = unidades.SpecificVolume(b/self.M)
c = refprop.virc(T, x)["c"]
fase.virialC = unidades.SpecificVolume_square(c/self.M**2)
# viriald don't supported for windows
if sys.platform != "win32":
d = refprop.vird(T, x)["d"]
fase.virialD = unidades.Dimensionless(d/self.M**3)
else:
fase.virialD = unidades.Dimensionless(0)
ba = refprop.virba(T, x)["ba"]
fase.virialBa = unidades.SpecificVolume(ba/self.M)
ca = refprop.virca(T, x)["ca"]
fase.virialCa = unidades.SpecificVolume_square(ca/self.M**2)
dcdt = refprop.dcdt(T, x)["dct"]
fase.dCdt = unidades.Dimensionless(dcdt/self.M**2)
dcdt2 = refprop.dcdt2(T, x)["dct2"]
fase.dCdt2 = unidades.Dimensionless(dcdt2/self.M**2)
dbdt = refprop.dbdt(T, x)["dbt"]
fase.dBdt = unidades.Dimensionless(dbdt/self.M)
b12 = refprop.b12(T, x)["b"]
fase.b12 = unidades.SpecificVolume(b12*fase.M)
try:
cstar = refprop.cstar(T, self.P.kPa, 0, x)["cs"]
fase.cstar = unidades.Dimensionless(cstar)
except refprop.RefpropdllError:
fase.cstar = unidades.Dimensionless(None)
fase.fraccion = [unidades.Dimensionless(xi) for xi in x]
xg = refprop.xmass(x)["xkg"]
fase.fraccion_masica = [unidades.Dimensionless(xi) for xi in xg]
try:
transport = refprop.trnprp(T, rho, x)
fase.mu = unidades.Viscosity(transport["eta"], "muPas")
fase.nu = unidades.Diffusivity(fase.mu/fase.rho)
fase.k = unidades.ThermalConductivity(transport["tcx"])
fase.alfa = unidades.Diffusivity(fase.k/fase.rho/fase.cp)
fase.Prandt = unidades.Dimensionless(fase.mu*fase.cp/fase.k)
except refprop.RefpropdllError:
fase.mu = unidades.Viscosity(None)
fase.nu = unidades.Diffusivity(None)
fase.k = unidades.ThermalConductivity(None)
fase.alfa = unidades.Diffusivity(None)
fase.Prandt = unidades.Dimensionless(None)
dielec = refprop.dielec(T, rho, x)
fase.epsilon = unidades.Dimensionless(dielec["de"])
[docs]
def _Melting_Pressure(self, T, x):
r"""Calculate the melting pressure.
Parameters
----------
T : float
Temperature, [K]
x : list
Molar fraction composition, [-]
Returns
-------
P : float
Melting pressure, [Pa]
"""
self._initialization()
P = refprop.meltt(T, x)
return unidades.Pressure(P["p"], "kPa")
[docs]
def _Sublimation_Pressure(self, T, x):
r"""Calculate the sublimation pressure.
Parameters
----------
T : float
Temperature, [K]
x : list
Molar fraction composition, [-]
Returns
-------
P : float
Sublimation pressure, [Pa]
"""
self._initialization()
P = refprop.sublt(T, x)
return unidades.Pressure(P["p"], "kPa")
if __name__ == '__main__':
# fluido = RefProp(ids=[140], T=300, P=1e6,)
# fluido2 = RefProp(ids=[140], T=300, P=1e6, preos=True)
# print(fluido.rho, fluido2.rho)
# from lib.mEoS import Acetone
# fluido = Acetone(T=300, P=1e6)
# from pprint import pprint
# pprint(fluido._Helmholtz(fluido.Tc/fluido.T, fluido.rho/fluido.rhoc))
# pprint(fluido._PengRobinson(fluido.rho, fluido.T))
# fluido2 = Acetone(T=300, P=1e6, eq="PR")
# print(fluido.rho, fluido2.rho)
# fluido = RefProp(ids=[47], T=100, P=6e4, htype="EOS", hcomp="BWR")
# print(fluido.rho, fluido.cpM.JmolK)
# See fortran/Manual.txt and fortran/Prop_sub.for file for explanation of refprop functionality
# Code for advanced thermal test
# from lib.mEoS.H2O import H2O
# from lib.coolProp import CoolProp
# from lib.iapws97 import IAPWS97
# from lib.freeSteam import Freesteam
# P = 2e4
# T = 300
# # Fluid definition, r refprop used as reference fluid, choose a m fluid to
# # test against reference
# r = RefProp(ids=[62], T=T, P=P)
# # m = H2O(T=T, P=P)
# # ierr = 1e-5
# m = CoolProp(ids=[62], fraccionMolar=[1], T=T, P=P)
# ierr = 1e-5
# # m = IAPWS97(T=T, P=P)
# # ierr = 1
# # m = Freesteam(T=T, P=P)
# # ierr = 1
# for prop, key, unit in m.properties():
# if key == "sigma":
# try:
# error = abs(r.Liquido.__getattribute__(key)-m.Liquido.__getattribute__(key))/r.Liquido.__getattribute__(key)*100
# if error > ierr:
# msg = "ERROR %0.5g%s" % (error, "%")
# print("%s: %0.9g %0.9g %s" % (key, r.Liquido.__getattribute__(key), m.Liquido.__getattribute__(key), msg))
# except ZeroDivisionError:
# print(key, "no implementado")
# elif key == "n":
# pass
# elif isinstance(r.__getattribute__(key), list):
# error = 0
# for v1, v2 in zip(r.__getattribute__(key), m.__getattribute__(key)):
# error2 = abs(v1-v2)/v1*100
# if error2 > error:
# error = error2
# if error > ierr:
# msg = "ERROR %0.5g%s" % (error, "%")
# print("%s: " % key, r.__getattribute__(key), m.__getattribute__(key), msg)
# else:
# try:
# error = abs(r.__getattribute__(key)-m.__getattribute__(key))/r.__getattribute__(key)*100
# if error > ierr:
# msg = "ERROR %0.5g%s" % (error, "%")
# print("%s: %0.9g %0.9g %s" % (key, r.__getattribute__(key), m.__getattribute__(key), msg))
# except ZeroDivisionError:
# if r.__getattribute__(key) == m.__getattribute__(key):
# pass
st = RefProp(ids=[140])
p = st._Sublimation_Pressure(178, [1])
print(p)
from lib.mEoS import H2O
st2 = H2O(T=300)
p = st2._Sublimation_Pressure(263.16)
print(p)