Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:fedebenelli/yaeos into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
fedebenelli committed Oct 3, 2024
2 parents 4f46d6f + 8194be4 commit 940b146
Show file tree
Hide file tree
Showing 25 changed files with 1,711 additions and 467 deletions.
1 change: 1 addition & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
rm -r ../../doc/ford_site/page/python-api
mv build ../../doc/ford_site/page/python-api
cd ../../
touch doc/ford_site/.nojekyll
- name: Upload Documentation
uses: actions/upload-artifact@v4
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,27 @@ extensibility of Modern Fortran for scientists to have an easy way to implement
new thermodynamic models without dealing with lower-level languages but still
getting decent performance.
And also this framework provides the possibility of using analytically obtained
derivatives so both options are easily available.
derivatives, so both options are easily available.

> This is an experimental work in progress and we recommend the before
> This is an experimental work in progress, and we recommend the before
> mentioned libraries if you are intending to use some of this in real work.
> Big part of the code comes from a refactoring process of older codes so
> not all parts are easily readable, yet.
We focus mainly on that the addition of a new thermodynamic model as easily as
possible. Also providing our models too!

## Documentation
The latest API documentation for the `main` branch can be found:
- [Fortran API documentation](https://ipqa-research.github.io/yaeos/)
- [Python API documentation](https://ipqa-research.github.io/yaeos/page/python-api/index.html)

The Fortran API documentation can also be generated by processing the source
files with [FORD](https://github.com/Fortran-FOSS-Programmers/ford). On the
other hand, the Python API documentation can be generated by processing the
source files with [Sphinx](https://github.com/sphinx-doc/sphinx).


## Available models
- CubicEoS
- SoaveRedlichKwong
Expand Down
23 changes: 23 additions & 0 deletions c_interface/yaeos_c.f90
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module yaeos_c
! GeMoels
public :: nrtl
public :: unifac_vle
public :: uniquac
public :: ln_gamma

! Thermoprops
Expand Down Expand Up @@ -93,6 +94,28 @@ subroutine unifac_vle(id, nc, ngs, g_ids, g_v)
call extend_ge_models_list(id)
end subroutine unifac_vle

subroutine uniquac(id, qs, rs, aij, bij, cij, dij, eij)
use yaeos, only: setup_uniquac
integer(c_int), intent(out) :: id
real(c_double), intent(in) :: qs(:)
!! Molecule's relative areas \(Q_i\)
real(c_double), intent(in) :: rs(size(qs))
!! Molecule's relative volumes \(R_i\)
real(c_double), intent(in) :: aij(size(qs),size(qs))
!! Interaction parameters matrix \(a_{ij}\)
real(c_double), intent(in) :: bij(size(qs),size(qs))
!! Interaction parameters matrix \(b_{ij}\)
real(c_double), intent(in) :: cij(size(qs),size(qs))
!! Interaction parameters matrix \(c_{ij}\)
real(c_double), intent(in) :: dij(size(qs),size(qs))
!! Interaction parameters matrix \(d_{ij}\)
real(c_double), intent(in) :: eij(size(qs),size(qs))
!! Interaction parameters matrix \(e_{ij}\)

ge_model = setup_uniquac(qs, rs, aij, bij, cij, dij, eij)
call extend_ge_models_list(id)
end subroutine

subroutine extend_ge_models_list(id)
!! Find the first available model container and allocate the model
!! there. Then return the found id.
Expand Down
243 changes: 243 additions & 0 deletions doc/page/usage/excessmodels/uniquac.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
---
title: UNIQUAC
---

[TOC]

# UNIQUAC

UNIQUAC (**uni**versal **qua**si**c**hemical) Excess Gibbs free energy model.

$$
\frac{G^E}{RT} = \sum_k n_k \ln\frac{\phi_k}{x_k}
+ \frac{z}{2}\sum_k q_k n_k \ln\frac{\theta_k}{\phi_k}
- \sum_k q_k n_k \ln\left(\sum_l \theta_l \tau_{lk} \right)
$$

With:

$$x_k = \frac{n_k}{\sum_l n_l}$$

$$ \phi_k = \frac{r_k n_k}{\sum_l r_l n_l} $$

$$ \theta_k = \frac{q_k n_k}{\sum_l q_l n_l} $$

$$ \tau_{lk} = \exp \left[\frac{-\Delta U_{lk}}{R T} \right] $$

$$
\frac{-\Delta U_{lk}}{R T} = a_{lk}+\frac{b_{lk}}{T}+c_{lk}\ln T + d_{lk}T +
e_{lk}{T^2}
$$

## Temperature derivatives

\(\qquad \tau_{lk}:\)

$$
\frac{d \tau_{lk}}{dT} = \tau_{lk} \left(2 T e_{lk} + d_{lk} + \frac{c_{lk}}{T}
- \frac{b_{lk}}{T^{2}}\right)
$$

$$
\frac{d^2 \tau_{lk}}{dT^2} = \tau_{lk} \left(2 T e_{lk} + d_{lk} + \frac{c_{lk}}{T}
- \frac{b_{lk}}{T^{2}}\right)^2 + \tau_{lk} \left(2 e_{lk} - \frac{c_{lk}}{T^{2}} +
\frac{2 b_{lk}}{T^{3}}\right)
$$

\(\qquad G^E\):

$$
\frac{\partial G^E}{\partial T} = \frac{G^E}{T} - RT \sum_k q_k n_k \frac{
\sum_l \theta_l \frac{\partial \tau_{lk}}{\partial T}}{\sum_l \theta_l
\tau_{lk}}
$$

$$
\frac{\partial G^E}{\partial T^2} = -R\left[T \sum_k q_k n_k
\left(\frac{(\sum_l \theta_l \frac{\partial^2 \tau_{lk}}{\partial T^2})}{\sum_l
\theta_l \tau_{lk}}
- \frac{(\sum_l \theta_l \frac{\partial \tau_{lk}}{\partial T})^2}{(\sum_l
\theta_l \tau_{lk})^2}\right) + 2\left(\sum_k q_k n_k \frac{(\sum_l \theta_l
\frac{\partial \tau_{lk}}{\partial T} )}{\sum_l \theta_l \tau_{lk}}\right)
\right]
$$

## Cross temperature-compositional derivative

$$
\frac{\partial^2 G^E}{\partial n_i \partial T} = \frac{1}{T} \frac{\partial
G^E}{\partial n_i} - R T \left(q_i \frac{\sum_l \theta_l \frac{d \tau_{li}}{d
T}}{\sum_l \theta_l \tau_{li}} + \sum_k q_k n_k \left(\frac{(\sum_l \frac{d
\theta_l}{d n_i} \frac{d \tau_{lk}}{d T})(\sum_l \theta_l \tau_{lk}) - (\sum_l
\theta_l \frac{d \tau_{lk}}{d T})(\sum_l \frac{d \theta_l}{d n_i}
\tau_{lk})}{(\sum_l \theta_l \tau_{lk})^2} \right) \right)
$$


## Compositional derivatives

\(\qquad \phi_k\):

$$
\frac{d \phi_k}{dn_i} = \begin{cases} - \frac{{n}_{i}
{r}_{i}^{2}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{2}} +
\frac{{r}_{i}}{\sum_l {n}_{l} {r}_{l}} & \text{for}\: i = k \\-
\frac{{n}_{k} {r}_{i} {r}_{k}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{2}}
& \text{otherwise} \end{cases}
$$

$$
\frac{d^2 \phi_k}{dn_i dn_j} = \begin{cases} \frac{2 {n}_{i}
{r}_{i}^{3}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{3}} - \frac{2
{r}_{i}^{2}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{2}} & \text{for}\: i
= k \wedge j = k \\\frac{2 {n}_{i} {r}_{i}^{2} {r}_{j}}{\left(\sum_l
{n}_{l} {r}_{l}\right)^{3}} - \frac{{r}_{i} {r}_{j}}{\left(\sum_l
{n}_{l} {r}_{l}\right)^{2}} & \text{for}\: i = k \wedge j \neq k \\\frac{2
{n}_{j} {r}_{i} {r}_{j}^{2}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{3}} -
\frac{{r}_{i} {r}_{j}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{2}} &
\text{for}\: j = k \wedge i \neq k \\\frac{2 {n}_{k} {r}_{i} {r}_{j}
{r}_{k}}{\left(\sum_l {n}_{l} {r}_{l}\right)^{3}} & \text{otherwise}
\end{cases}
$$

\(\qquad \theta_k\):

$$
\frac{d \theta_k}{dn_i} = \begin{cases} - \frac{{n}_{i}
{q}_{i}^{2}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{2}} +
\frac{{q}_{i}}{\sum_l {n}_{l} {q}_{l}} & \text{for}\: i = k \\-
\frac{{n}_{k} {q}_{i} {q}_{k}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{2}}
& \text{otherwise} \end{cases}
$$

$$
\frac{d^2 \theta_k}{dn_i dn_j} = \begin{cases} \frac{2 {n}_{i}
{q}_{i}^{3}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{3}} - \frac{2
{q}_{i}^{2}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{2}} & \text{for}\: i
= k \wedge j = k \\\frac{2 {n}_{i} {q}_{i}^{2} {q}_{j}}{\left(\sum_l
{n}_{l} {q}_{l}\right)^{3}} - \frac{{q}_{i} {q}_{j}}{\left(\sum_l
{n}_{l} {q}_{l}\right)^{2}} & \text{for}\: i = k \wedge j \neq k \\\frac{2
{n}_{j} {q}_{i} {q}_{j}^{2}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{3}} -
\frac{{q}_{i} {q}_{j}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{2}} &
\text{for}\: j = k \wedge i \neq k \\\frac{2 {n}_{k} {q}_{i} {q}_{j}
{q}_{k}}{\left(\sum_l {n}_{l} {q}_{l}\right)^{3}} & \text{otherwise}
\end{cases}
$$

\(\qquad G^E\):

$$
\frac{\partial \frac{G^E}{RT}}{\partial n_i} = \ln \left(\frac{\phi_i}{x_i}
\right) + \sum_k n_k \left(\frac{\frac{d \phi_k}{dn_i}}{\phi_k} -
\frac{\frac{dx_k}{dn_i}}{x_k}\right) +
\frac{z}{2}{q}_{i}\ln{\left(\frac{\theta_{i}}{\phi_{i}} \right)} + \frac{z}{2}
\sum_k {n}_{k} {q}_{k} \left(\frac{\frac{d \theta_{k}}{d {n}_{i}}}{\theta_k} -
\frac{\frac{d \phi_{k}}{d {n}_{i}}}{\phi_k} \right) - {q}_{i}
\ln{\left(\sum_l \theta_{l} {\tau}_{li} \right)} - \sum_k {n}_{k} {q}_{k}
\frac{\sum_l \frac{d \theta_{l}}{d {n}_{i}} {\tau}_{lk}}{\sum_l \theta_{l}
{\tau}_{lk}}
$$


Differentiating each term of the first compositional derivative respect to
$n_j$

\(\frac{\partial \frac{G^E}{RT}}{\partial n_i \partial n_j} =\)

$$
\frac{\frac{d \phi_i}{d n_j}}{\phi_i} - \frac{\frac{d x_i}{d n_j}}{x_i}
$$

$$
+\frac{\frac{d \phi_j}{dn_i}}{\phi_j} -
\frac{\frac{dx_j}{dn_i}}{x_j}
+ \sum_k n_k \left(\frac{\frac{d^2\phi_k}{dn_i dn_j} \phi_k -
\frac{d\phi_k}{dn_i} \frac{d\phi_k}{dn_j}}{\phi_k^2} \right)
- \sum_k n_k \left(\frac{\frac{d^2x_k}{dn_i dn_j} x_k -
\frac{dx_k}{dn_i} \frac{dx_k}{dn_j}}{x_k^2} \right)
$$

$$
+ \frac{z}{2} q_i \left( \frac{\frac{d \theta_i}{d n_j}}{\theta_i} - \frac
{\frac{d \phi_i}{d n_j}}{\phi_i} \right)
$$

$$
+ \frac{z}{2} q_j \left( \frac{\frac{d \theta_j}{d n_i}}{\theta_j} - \frac
{\frac{d \phi_j}{d n_i}}{\phi_j} \right)
+ \frac{z}{2} \sum_k n_k q_k \left(\frac{\frac{d^2\theta_k}{dn_i dn_j} \theta_k -
\frac{d\theta_k}{dn_i} \frac{d\theta_k}{dn_j}}{\theta_k^2} \right)
- \frac{z}{2} \sum_k n_k q_k \left(\frac{\frac{d^2\phi_k}{dn_i dn_j} \phi_k -
\frac{d\phi_k}{dn_i} \frac{d\phi_k}{dn_j}}{\phi_k^2} \right)
$$

$$
- q_i \left( \frac{\sum_l \frac{d \theta_l}{d n_j} \tau_{li}}{\sum_l \theta_l
\tau_{li}} \right)
$$

$$
- {q}_{j} \frac{\sum_l \frac{d \theta_{l}}{d {n}_{i}} {\tau}_{lj}}{\sum_l
\theta_{l}{\tau}_{lj}} - \sum_k {n}_{k} {q}_{k} \frac{\left(\sum_l
\frac{d^2\theta_l}{dn_idn_j} \tau_{lk} \right) \left(\sum_l
\theta_l \tau_{lk} \right) - \left(\sum_l \frac{d\theta_l}{dn_i}
\tau_{lk} \right) \left(\sum_l \frac{d\theta_l}{dn_j} \tau_{lk}
\right)}{(\sum_l \theta_{l} {\tau}_{lk})^2}
$$

## Examples
Example from: Gmehling et al. (2012) [2]

An example of having a mixture of Water-Ethanol-Bezene at 298.15 K with
constant \(\Delta U\) [K]:

|Water|Ethanol|Benzene|
|---------|--------|---------|
| 0 | 526.02 | 309.64 |
| −318.06 | 0 | −91.532 |
| 1325.1 | 302.57 | 0 |


```fortran
use yaeos, only: pr, setup_uniquac, UNIQUAC
integer, parameter :: nc = 3
real(pr) :: rs(nc), qs(nc)
real(pr) :: b(nc, nc)
real(pr) :: n(nc)
real(pr) :: ln_gammas(nc), T
type(UNIQUAC) :: model
rs = [0.92_pr, 2.1055_pr, 3.1878_pr]
qs = [1.4_pr, 1.972_pr, 2.4_pr]
T = 298.15_pr
! Calculate bij from DUij. We need -DU/R to get bij
b(1,:) = [0.0_pr, -526.02_pr, -309.64_pr]
b(2,:) = [318.06_pr, 0.0_pr, 91.532_pr]
b(3,:) = [-1325.1_pr, -302.57_pr, 0.0_pr]
model = setup_uniquac(qs, rs, bij=b)
n = [2.0_pr, 2.0_pr, 8.0_pr]
call model%ln_activity_coefficient(n, T, ln_gammas)
print *, exp(ln_gammas) ! [8.856, 0.860, 1.425]
```


## References
1. Maurer, G., & Prausnitz, J. M. (1978). On the derivation and extension of
the UNIQUAC equation. Fluid Phase Equilibria, 2(2), 91-99.
2. Gmehling, Jurgen, Barbel Kolbe, Michael Kleiber, and Jurgen Rarey. Chemical
Thermodynamics for Process Simulation. 1st edition. Weinheim: Wiley-VCH,
2012.
3. Caleb Bell and Contributors (2016-2024). Thermo: Chemical properties
component of Chemical Engineering Design Library (ChEDL)
https://github.com/CalebBell/thermo.
44 changes: 40 additions & 4 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,56 @@
# yaeos Python bindings
THIS IS A WIP SO THE API WILL DRASTICALLY CHANGE WITH TIME

Set of Python bindings to call `yaeos` functions and models.
The `yaeos` Python API is on and early stage of development. So the API will
change with time.

Editable installation
## Supported operative systems

- Linux

## Supported Python versions

- Python >= 3.10, < 3.13

## Installation
To install the last version of `yaeos` Python API, you can use `pip`:

```
pip install yaeos
```

### For developers, the editable installation is done by

```
cd python
pip install -r requirements-build.txt
pip install -e . --no-build-isolation
```

If you want to install on your environment instead
### Building from source

To build `yaeos` from source you can clone the repository and install it with
pip. The system dependencies are:

- LAPACK
- Fortran compiler

To build and install do:

```shell
git clone https://github.com/ipqa-research/yaeos.git
cd yaeos/python
pip install .
```

### Setting a Google Colab to use yaeos

To install `yaeos` on Google Colab you can do the following command to install
the last version uploaded to PyPI:

```shell
%pip install yaeos
```

To check if the installation worked correctly:

```python
Expand All @@ -33,6 +67,8 @@ model = PengRobinson76(
model.lnphi_vt(np.array([5.0, 4.0]), 2.0, 303.15)
```

You will get:

```
array([0.47647471, 0.35338115])
```
1 change: 1 addition & 0 deletions python/docs/source/models/excess_gibbs/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ Excess Gibbs Models
:maxdepth: 1

nrtl
unifacvle
Loading

0 comments on commit 940b146

Please sign in to comment.