Instantiate a model
Which models are available?
In yaeos
, as in thermodynamics, are two kinds of models:
Residual Helmholtz free energy models (ArModel)
Excess Gibbs free energy models (GeModel)
yaeos
provides a set of predefined models that will change in the future. You can check the list of available models in the API documentation or simply executing the following command on an interactive Python session (Jupyter Notebook, Google Colab, etc):
[1]:
import yaeos
?yaeos.models
All this models can be imported directly from yaeos
with the names in the list. For example let’s import and instantiate a PengRobinson76
model:
[2]:
from yaeos import PengRobinson76
# Critical constants
Tc = [320, 375] # critical temperatures [K]
Pc = [30, 45] # critical pressures [bar]
w = [0.0123, 0.045] # acentric factors [-]
model = PengRobinson76(Tc, Pc, w)
There we have instantiated a PengRobinson76
model with a binary mixture and stored the instance in a variable called model
. You can check the signature to instantiate any model with the ?
operator in an interactive Python session.
[3]:
?PengRobinson76
This can be done with all the listed models of yaeos
.
[4]:
from yaeos import NRTL, PengRobinson76, PengRobinson78, SoaveRedlichKwong, RKPR
?RKPR
What can we do with an instantiated model?
Residual Helmholtz free energy models (ArModel)
We will get later on what we can do with the Excess Gibbs free energy models instances.
By now we will use the PengRobinson76
instantiated in the variable model
to calculate properties of the mixture. For example the fugacity coefficients of the mixture’s components at a given composition, temperature and pressure.
[5]:
import numpy as np
n = np.array([7.0, 3.0]) # moles of each component [mol]
P = 2.0 # pressure [bar]
T = 300.0 # temperature [K]
# Calculate ln(phi) with the model (PengRobinson76)
ln_phi = model.lnphi_pt(moles=n, pressure=P, temperature=T)
# Use ln(phi) to calculate the fugacity
phi = np.exp(ln_phi)
z = n / np.sum(n)
fugacity = z * phi * P
# Print results
print("ln(phi) = ", ln_phi)
print("phi = ", phi)
print("fugacity = ", fugacity, "bar")
ln(phi) = [-0.03026809 -0.03078738]
phi = [0.9701854 0.96968172]
fugacity = [1.35825956 0.58180903] bar
Well, analyzing the previous code by parts we have:
import numpy:
yaeos
is compatible with numpy. The functions that receives arrays arguments are able to handle numpy arrays.We create three variables:
n
array with the number of moles of each componentT
with the temperature of the system in KelvinP
with the pressure of the system in bar
call the
lnphi_pt
method inside the previously instantiatedmodel
variablemodel.<thing i want to evaluate>(arguments)
For the users not familiar with Python and object-oriented programming, the dot
.
is used to access the attributes and methods of an object, in this case, themodel
object (PengRobinson76 instance).lnphi_pt
is a method of thePengRobinson76
class that calculates the natural logarithm of the fugacity coefficients of the components of the mixture at a given composition, temperature and pressure. In this case the syntax is:model.lnphi_pt(n, P, T)
Use the ln(phi) returned values to calculate the fugacity coefficients
First we calculate the fugacity coefficients.
python phi = np.exp(lnphi)
Which means: \(\phi_i = e^{\ln(\phi_i)}\)Then, we calculate the mole fractions of the mixture.
python z = n / np.sum(n)
Which means: \(z_i = \frac{n_i}{\sum n_i}\)Then we use the phi variable to calculate fugacities:
fugacity = z * phi * P
Which means: \(f = z \; \phi \; P\)
ArModel properties listing
All the properties that can be calculated with an ArModel instance can be found on the API documentation (Core Module):
https://ipqa-research.github.io/yaeos/page/python-api/core.html#yaeos.core.ArModel
There you will find all the properties that can be calculated with an ArModel, their signatures and a brief description of what they do. Also, an example to calculate each one is provided.
Some examples that we can calculate now:
[6]:
n = np.array([7.0, 3.0]) # moles of each component [mol]
P = 15.0 # pressure [bar]
V = 20.0 # volume [L]
T = 300.0 # temperature [K]
# Evaluate pressure
pressure = model.pressure(moles=n, volume=V, temperature=T)
# Evaluate ln(phi) but function of temperature and volume
ln_phi = model.lnphi_vt(moles=n, volume=V, temperature=T)
# Evaluate volume
volume = model.volume(moles=n, pressure=P, temperature=T)
And we can print the results:
[7]:
print("Pressure: ", pressure, " bar")
print("ln_phi: ", ln_phi)
print("Volume: ", volume, " L")
Pressure: 10.30361077545868 bar
ln_phi: [-0.16224585 -0.1669435 ]
Volume: 12.068572622671574 L
If you are familiar with thermodynamics, you probably may think:
"Well, which volume root is solving when `model.volume` is evaluated"
And you will be right, we didn’t tell you yet. You can get the documentation of all these properties on the API documentation (the link provided above) or by doing:
[8]:
?model.volume
If you check the API documentation you have an example of calculating “liquid” volume roots, “vapor” volume roots or “stable” volume roots, but we will explain it here too.
As you can see in the volume documentation above. There is another argument that we didn’t use: root
. This argument is set as “stable” by default, but we can change it to “vapor” or “liquid” if we want. Let’s see which was the stable root in the previous evaluation:
[9]:
n = np.array([7.0, 3.0]) # moles of each component [mol]
P = 15.0 # pressure [bar]
T = 300.0 # temperature [K]
# Stable root
print(
"Stable: ", model.volume(moles=n, pressure=P, temperature=T, root="stable")
)
# Liquid root
print(
"Liquid: ", model.volume(moles=n, pressure=P, temperature=T, root="liquid")
)
# Vapor root
print(
"Vapor: ", model.volume(moles=n, pressure=P, temperature=T, root="vapor")
)
Stable: 12.068572622671574
Liquid: 1.2405831819647626
Vapor: 12.068572622671574
As we can see, the stable root was the vapor root. But changing the root
argument we can also check the value of the liquid root if we want.
Let back to the lnphi_pt
method, there we specify temperature and pressure, but again, at which volume root is solving the model? The answer is the same as the volume
method, the stable root. But we can change it to:
[10]:
n = np.array([7.0, 3.0]) # moles of each component [mol]
P = 15.0 # pressure [bar]
T = 300.0 # temperature [K]
# Stable root
print(
"Stable: ",
model.lnphi_pt(moles=n, pressure=P, temperature=T, root="stable"),
)
# Liquid root
print(
"Liquid: ",
model.lnphi_pt(moles=n, pressure=P, temperature=T, root="liquid"),
)
# Vapor root
print(
"Vapor: ", model.lnphi_pt(moles=n, pressure=P, temperature=T, root="vapor")
)
Stable: [-0.24307099 -0.2526632 ]
Liquid: [-0.04887053 -0.3742866 ]
Vapor: [-0.24307099 -0.2526632 ]
[11]:
?model.lnphi_pt
Obtaining derivatives of the properties
We can obtain some derivatives of the properties that we have been calculating. For example, the fugacity coefficients derivatives with respect to the number of moles of the components of the mixture.
[12]:
lnphi, derivatives = model.lnphi_pt(
moles=n, pressure=P, temperature=T, dn=True
)
print("ln(phi): ", lnphi)
derivatives
ln(phi): [-0.24307099 -0.2526632 ]
[12]:
{'dt': None,
'dp': None,
'dn': array([[-2.56426727e-06, 5.98329030e-06],
[ 5.98329030e-06, -1.39610107e-05]])}
There we set the dn
argument to True
to calculate the derivatives with respect to the number of moles of the components of the mixture. When we specify any of the derivatives arguments as True
we will get another return of the method. The first will be the property evaluated as usual and the second is a Python dictionary with the calculated derivatives specified as True.
If we specify all the derivatives as True
:
[13]:
lnphi, derivatives = model.lnphi_pt(
moles=n, pressure=P, temperature=T, dt=True, dp=True, dn=True
)
print("ln(phi): ", lnphi)
print(derivatives)
ln(phi): [-0.24307099 -0.2526632 ]
{'dt': array([0.00247786, 0.00257727]), 'dp': array([-0.01786595, -0.01925548]), 'dn': array([[-2.56426727e-06, 5.98329030e-06],
[ 5.98329030e-06, -1.39610107e-05]])}
There we get all the derivatives of lnphi
. Of course, we can access the dictionary with the keys:
[14]:
derivatives["dt"]
[14]:
array([0.00247786, 0.00257727])
Check the signature of each property to see which derivatives you can calculate. For example pressure
.
[15]:
?model.pressure
Yaeos units
If you were paying attention to the previous examples, you may have noticed that the units of yaeos
are defined according to the ideal gas constant R
with units:
\(R = 0.08314462618 \frac{bar \; L}{K \; mol}\)
Because of that, pressure must be specified as bar, volume as liters, temperature as Kelvin and number of moles as moles. The returns of the properties will be in the same units as the inputs. Energetic properties as enthalpy, entropy, etc will have unit of \([bar \; L]\), which equals to centijoules \([cJ]\).