diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 42e2a5491..395bd50ca 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,25 +1,35 @@ name: CI on: [push] + jobs: - Build: + tests_and_coverage: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] - gcc_v: [10] # Version of GFortran we want to use. python-version: [3.9] - env: - FC: gfortran-${{ matrix.gcc_v }} - GCC_V: ${{ matrix.gcc_v }} - + toolchain: + - {compiler: gcc, version: 10} + - {compiler: gcc, version: 11} + - {compiler: gcc, version: 12} + - {compiler: gcc, version: 13} + - {compiler: intel, version: '2024.1'} + - {compiler: intel, version: '2023.2'} steps: - name: Checkout code uses: actions/checkout@v2 with: submodules: false + - name: Setup Fortran Compiler + uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: ${{ matrix.toolchain.compiler }} + version: ${{ matrix.toolchain.version }} + - name: Install Python uses: actions/setup-python@v1 # Use pip to install latest CMake, & FORD/Jin2For, etc. with: @@ -33,39 +43,69 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Install Python dependencies - if: contains( matrix.os, 'ubuntu') + - name: Install dependencies run: | python -m pip install --upgrade pip pip install ford numpy matplotlib gcovr numpy scipy if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - - name: Install GFortran Linux - if: contains( matrix.os, 'ubuntu') - run: | - sudo apt-get install lcov - sudo update-alternatives \ - --install /usr/bin/gcc gcc /usr/bin/gcc-${{ matrix.gcc_v }} 100 \ - --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${{ matrix.gcc_v }} \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-${{ matrix.gcc_v }} - - - name: Install NLopt - run: sudo apt-get install libnlopt-dev - - name: Compile - run: fpm build --profile release + - name: Run tests without coverage + if: ${{ env.FC != 'gfortran' }} + run: | + fpm test --profile debug --compiler ${{ env.FC }} --c-compiler gcc - - name: Run tests + - name: Run tests with coverage + if: ${{ env.FC == 'gfortran' }} run: | - fpm test --profile debug --flag -coverage + fpm test --profile debug --flag -coverage --compiler ${{ env.FC }} --c-compiler gcc bash ci/ci.sh - + - name: Coverage run: bash ci/ci.sh coverage + if: ${{ env.FC == 'gfortran' }} - name: Upload coverage reports to Codecov + if: ${{ env.FC == 'gfortran' }} uses: codecov/codecov-action@v4.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} slug: ipqa-research/yaeos + + Python-API: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + gcc_v: [10] # Version of GFortran we want to use. + python-version: [3.9] + env: + FC: gfortran-${{ matrix.gcc_v }} + GCC_V: ${{ matrix.gcc_v }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + submodules: false + + - name: Install Python + uses: actions/setup-python@v1 # Use pip to install latest CMake, & FORD/Jin2For, etc. + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + working-directory: ./python + run: | + sudo apt-get install libnlopt-dev meson + pip install meson tox + + - name: Install yaeos + working-directory: ./python + run: + pip install . + +# - name: tox +# working-directory: ./python +# run: tox -r diff --git a/.gitignore b/.gitignore index 90b2de1a8..5ede0ddcf 100644 --- a/.gitignore +++ b/.gitignore @@ -8,10 +8,12 @@ doc/ford_site *.smod *mypy* *.so +*.egg-info tools/uml tools/uml.png tools/uml.svg python/yaeos/script.py +__pycache__ iso log coverage.xml @@ -44,3 +46,23 @@ log_srk-hv srk srk_hv fort.2 +*.egg-info +*ipynb_checkpoints +chulia +flang.rsp +flash +flash_log_para +flash_log_sequ +fort.4 +log2 +para.py +tools/plotting/pt_envel_2ph.gnu +tools/notebooks/other.ipynb +dist +.tox +.coverage +tmp_editable +hsprpxy +iters +n2c8data +prpxy diff --git a/README.md b/README.md index eb8306229..467026fed 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - [![Fortran](https://img.shields.io/badge/Fortran-734f96?logo=fortran&style=flat)](https://fortran-lang.org) [![fpm](https://img.shields.io/badge/fpm-Fortran_package_manager-734f96)](https://fpm.fortran-lang.org) [![Documentation](https://img.shields.io/badge/ford-Documentation%20-blueviolet.svg)](https://ipqa-research.github.io/yaeos/) @@ -6,7 +5,6 @@ [![CI](https://github.com/fedebenelli/yaeos/actions/workflows/CI.yml/badge.svg)](https://github.com/ipqa-research/yaeos/actions/workflows/CI.yml) [![codecov](https://codecov.io/gh/ipqa-research/yaeos/graph/badge.svg?token=IDJYKV8XK6)](https://codecov.io/gh/ipqa-research/yaeos) -

@@ -36,15 +34,39 @@ derivatives so both options are easily available. We focus mainly on that the addition of a new thermodynamic model as easily as possible. Also providing our models too! -For now, we only include residual Helmholtz model (like Cubic or Saft Equations -of State). But we'll be adding other models like $G^E$ (UNIFAC for example). +For now, we only include residual Helmholtz model (like Cubic or SAFT Equations +of State). + +## Available models +- CubicEoS + - SoaveRedlichKwong + - PengRobinson76 + - PengRobinson78 +- ExcessGibbs models + - NRTL + - UNIFAC VLE + +## Available properties +- Bulk Properties + - Volume(n, P, T) + - Pressure(n, V, T) +- Residual Properties + - H^R(n, V, T) + - S^R(n, V, T) + - G^R(n, V, T) + - Cv^R(n, V, T) + - Cp^R(n, V, T) +- Phase-Equilibria + - FlashPT, FlashVT + - Saturation points (bubble, dew and liquid-liquid) + - Phase Envelope PT (isopleths) # A little taste of `yaeos` A lot of users get the bad picture of Fortran being old and archaic since most of the codes they've seen are written in ancient `F77`. ```fortran -use yaeos, only: PengRobinson76, pressure, ArModel +use yaeos, only: PengRobinson76, ArModel integer, parameter :: n=2 ! Number of components real(8) :: V, T, P, dPdN(n) ! variables to calculate @@ -64,7 +86,7 @@ model = PengRobinson76(tc, pc, w, kij, lij) V = 1 T = 150 -call pressure(model, z, V, T, P) +call model%pressure(z, V, T, P) print *, P ! Obtain derivatives adding them as optional arguments! @@ -83,30 +105,42 @@ with: Not providing any example will show all the possible examples that can be run. # How to install/run it -`yaeos` is intended to use as a [`fpm`](fpm.fortran-lang.org) -You can either: - -- Generate a new project that uses `yaeos` as a dependency +## Dependencies +`yaeos` needs to have both `lapack` and `nlopt` libraries on your system. +### Debian/Ubuntu-like ```bash -fpm new my_project +sudo apt install libnlopt-dev libblas-dev liblapack-dev ``` -In the `fpm.toml` file add: +## Installing `yaeos` +`yaeos` is intended to use as a [`fpm`](fpm.fortran-lang.org) package. `fpm` +is the Fortran Package Manager, which automates the compilation and running +process of Fortran libraries/programs. -```toml -[dependencies] -yaeos = {git="https://github.com/ipqa-research/yaeos"} -``` +You can either: + +- Generate a new project that uses `yaeos` as a dependency with: + +> ```bash +> fpm new my_project +> ``` +> +> In the `fpm.toml` file add: +> +> ```toml +> [dependencies] +> yaeos = {git="https://github.com/ipqa-research/yaeos"} +> ``` - Clone this repository and just modify the executables in the `app` directory -```bash -git clone https://github.com/ipqa-research/yaeos -cd yaeos -fpm run -``` +> ```bash +> git clone https://github.com/ipqa-research/yaeos +> cd yaeos +> fpm run +> ``` ## Developing with vscode If your intention is either to develop for `yaeos` or to explore in more detail @@ -131,6 +165,8 @@ fpm run --example ``` # Including new models with Automatic Differentiation. + +## Hyperdual Numbers autodiff We are using the `hyperdual` module developed by [Philipp Rehner](https://github.com/prehner) and [Gernot Bauer](https://github.com/g-bauer) @@ -138,56 +174,15 @@ and [Gernot Bauer](https://github.com/g-bauer) > The automatic differentiation API isn't fully optimized yet so performance is > much slower than it should be. -```fortran -type, extends(ArModelAdiff) :: YourNewModel - type(Substances) :: composition - real(8), allocatable :: parameters(:) ! A vector of parameters -contains - procedure :: Ar => arfun - procedure :: get_v0 => v0 -end type -``` - -```fortran -subroutine arfun(self, n, v, t, Ar) - class(YourNewModel), intent(in) :: self - type(hyperdual), intent(in) :: n(:) ! Number of moles - type(hyperdual), intent(in) :: v ! Volume [L] - type(hyperdual), intent(in) :: t ! Temperature [K] - type(hyperdual), intent(out) :: ar_value ! Residual Helmholtz Energy - - ! A very complicated residual helmholtz function of a mixture - Ar = sum(n) * v * t / self%parameters(1) -end subroutine - -function v0(self, n, p, t) - class(YourNewModel), intent(in) :: self - real(pr), intent(in) :: n(:) ! Number of moles - real(pr), intent(in) :: p ! Pressure [bar] - real(pr), intent(in) :: t ! Temperature [K] - real(pr) :: v0 - - v0 = self%parameters(3) -end function -``` - A complete implementation of the PR76 Equation of State can me found in -`example/adiff/adiff_pr76.f90`. - -All the thermodynamic properties can be found in `yaeos_thermoprops` and called -like: +`example/adiff/adiff_pr76.f90`. Or in the documentation pages. -```fortran -use yaeos_thermoprops, only: fugacity_vt -use my_new_model, only: YourNewModel -... -type(YourNewModel) :: eos -eos%parameters = [1, 2, 3] -call fugacity_vt(eos, n, v, t, lnfug=lnfug, dlnphidn=dlnphidn) -``` +## Tapenade-based autodiff +It is also possible to differentiate with `tapenade`. Examples can be seen +in the documentation pages or in [The tools directory](tools/tapenade_diff/) # Documentation The latest API documentation for the `main` branch can be found [here](https://ipqa-research.github.io/yaeos). This was generated from the source code using [FORD](https://github.com/Fortran-FOSS-Programmers/ford). We're -working in extending it more. +working in extending it more. \ No newline at end of file diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index ef7ed19af..c0f180ff0 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -8,13 +8,28 @@ This style guide is a living document and proposed changes may be adopted after ## Use (modern) standard Fortran -* Do not use obsolescent or deleted language features +* Do **not** use obsolescent or deleted language features E.g., `common`, `pause`, `entry`, arithmetic `if` and computed `goto` -* Do not use vendor extensions in the form of non-standard syntax and vendor supplied intrinsic procedures +* Do **not** use vendor extensions in the form of non-standard syntax and vendor supplied intrinsic procedures E.g., `real*8` or `etime()`, use `real(pr)` -## File naming conventions +## Naming of variables and constructs +- Variable and procedure names, as well as Fortran keywords, should be written in lowercase +- All constants (like the `R` gas constant) should be upper case +- All variables should be in lowercase unless they are represented in uppercase in the bibliography. + for example, the molar volume would be `v` and the total volume would be `V`. +- In the case of derivatives, for general properties they should be written as `dXdy` for first derivatives and `dXdyz` or `dXdy2` for second order derivatives. The only exception is with energetic properties, like `Ar`, where derivatives are written like `ArV`, `ArVn`, etc. +- All thermodynamic variables that are input of a subroutine/function should + have the order: + - `n, V, T` + - `n, P, T` +- Variable and procedure names should be made up of one or more full words separated by an underscore, + for example `has_failed` is preferred over `hasfailed` +- Where conventional and appropriate shortening of a word is used then the underscore may be omitted, + for example `linspace` is preferred over `lin_space` +- For derived types use CamelCase, like `ArModel` +## File naming conventions * Source files should contain at most one `program`, `module`, or `submodule` * The filename should match the program or module name and have the file extension `.f90` or `.F90` if preprocessing is required * `module` names should include it's subdirectory, using `yaeos__` for the parent @@ -34,18 +49,11 @@ than style and formatting. We recommend ~~enforce~~ the use of `findent` to format your files. -* The body of every Fortran construct should be indented by __four (4) spaces__ +* The body of every Fortran construct should be indented by __three (3) spaces__ * Line length *should be limited to 80 characters* and __must not exceed 132__ * **Do not** use Tab characters for indentation * **Remove** trailing white space before committing code -## Variable and procedure naming - -* Variable and procedure names, as well as Fortran keywords, should be written in lowercase -* Variable and procedure names should be made up of one or more full words separated by an underscore, - for example `has_failed` is preferred over `hasfailed` -* Where conventional and appropriate shortening of a word is used then the underscore may be omitted, - for example `linspace` is preferred over `lin_space` ## Attributes diff --git a/app/fit.f90 b/app/fit.f90 index 148c267e2..d12a5309f 100644 --- a/app/fit.f90 +++ b/app/fit.f90 @@ -1,101 +1,11 @@ -module yaeos__fitting_fit_nrtl - use yaeos__constants, only: pr - use yaeos__fitting, only: FittingProblem - use yaeos__models, only: ArModel, NRTL, CubicEoS, MHV - use forsus, only: Substance - implicit none - - integer, parameter :: nc = 2 - - type, extends(FittingProblem) :: FitMHVNRTL - contains - procedure :: get_model_from_X => model_from_X - end type - -contains - - subroutine init_model(problem, sus) - use yaeos, only: R, ArModel, CubicEoS, PengRobinson78, RKPR, SoaveRedlichKwong - class(FitMHVNRTL), intent(in out) :: problem - type(Substance), intent(in) :: sus(2) - type(MHV) :: mixrule - type(NRTL) :: ge - real(pr) :: tc(nc), pc(nc), w(nc), vc(nc), zc(nc) - real(pr) :: a(nc, nc), b(nc, nc), c(nc, nc), bi(nc) - - a=0; b=0; c=0 - - tc = sus%critical%critical_temperature%value - pc = sus%critical%critical_pressure%value/1e5 - w = sus%critical%acentric_factor%value - vc = sus%critical%critical_volume%value - zc = pc*vc/(R*tc) - - ge = NRTL(a, b, c) - - ! problem%model = RKPR(tc, pc, w, zc) - allocate(CubicEoS :: problem%model) - problem%model = SoaveRedlichKwong(tc, pc, w) - - associate(m => problem%model) - select type(m) - type is (CubicEoS) - bi = m%b - mixrule = MHV(ge=ge, q=-0.593_pr, b=bi) - deallocate(m%mixrule) - m%mixrule = mixrule - end select - end associate - end subroutine init_model - - function model_from_X(problem, X) result(model) - use yaeos, only: R, RKPR, PengRobinson78, ArModel, QMR, CubicEoS - use yaeos__models_ar_cubic_quadratic_mixing, only: RKPR_D1mix - real(pr), intent(in) :: X(:) - class(FitMHVNRTL), intent(in) :: problem - class(ArModel), allocatable :: model - type(NRTL) :: ge - - real(pr) :: a(nc, nc), b(nc, nc), c(nc, nc) - - a=0; b=0; c=0 - - a(1, 2) = x(1) - a(2, 1) = x(2) - - b(1, 2) = x(3) - b(2, 1) = x(4) - - c(1, 2) = x(5) - c(2, 1) = x(6) - - ge = NRTL(a, b, c) - - model = problem%model - - select type(model) - class is (CubicEoS) - associate(mr => model%mixrule) - select type (mr) - class is (MHV) - mr%l(1, 2) = x(7) - mr%l(2, 1) = x(7) - mr%ge = ge - model%del1 = x(8:) - model%del2 = (1._pr - model%del1)/(1._pr + model%del1) - end select - end associate - end select - end function model_from_X -end module - program main !! Binary system parameter optimization - use yaeos, only: EquilibriaState, pr, ArModel, PengRobinson78, CubicEoS, saturation_pressure + use yaeos, only: EquilibriaState, pr, ArModel, SoaveRedlichKwong, CubicEoS, saturation_pressure + use yaeos, only: MHV use forsus, only: Substance, forsus_dir use yaeos__fitting, only: FittingProblem, fobj, optimize - use yaeos__fitting_fit_nrtl, only: FitMHVNRTL, init_model - integer, parameter :: nc = 2, np=7 + nc + use yaeos__fitting_fit_nrtl_mhv, only: FitMHVNRTL + integer, parameter :: nc = 2, np=7 integer :: i, infile, iostat type(EquilibriaState), allocatable :: exp_points(:) @@ -135,15 +45,21 @@ program main ! ========================================================================== ! Setup optimization problem and call the optimization function ! -------------------------------------------------------------------------- - call init_model(prob, sus) - + model = SoaveRedlichKwong(& + sus%critical%critical_temperature%value, & + sus%critical%critical_pressure%value/1e5, & + sus%critical%acentric_factor%value & + ) + + prob%model = model + prob%experimental_points = exp_points X = 0 X(1:2) = [0.1, 0.3] X(5:6) = [0.1, 0.2] - X(8:) = [1, 1] + prob%fit_nrtl = .true. prob%parameter_step = [(0.5_pr, i=1,size(x))] prob%solver_tolerance = 1e-7 prob%verbose = .true. @@ -153,8 +69,8 @@ program main print *, "FO:", error print *, "Xf:", X - if (allocated(model)) deallocate (model) - model = prob%get_model_from_X(X) + call prob%get_model_from_X(X) + model = prob%model ! =========================================================================== ! Write out results and experimental values diff --git a/app/flash.f90 b/app/flash.f90 index 1907c4f86..1f6a83502 100644 --- a/app/flash.f90 +++ b/app/flash.f90 @@ -3,7 +3,7 @@ program flasher !! EoS model. ! Import the relevant - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel implicit none ! Variables definition: diff --git a/app/isotherm.f90 b/app/isotherm.f90 index 952cae11c..7fd13a43d 100644 --- a/app/isotherm.f90 +++ b/app/isotherm.f90 @@ -1,6 +1,9 @@ program main - use yaeos, only: pr, ArModel, PengRobinson76, volume, pressure, SoaveRedlichKwong + use yaeos, only: pr, ArModel, PengRobinson76, SoaveRedlichKwong + use yaeos__models_ar, only: nvolume => volume + use yaeos__models_solvers, only: volume_michelsen use forsus, only: Substance, forsus_dir + use fortime, only: timer implicit none class(ArModel), allocatable :: eos @@ -8,52 +11,39 @@ program main real(pr), dimension(nc) :: n, tc, pc, w real(pr), dimension(nc, nc) :: kij, lij + type(timer) :: tim + type(Substance) :: sus(2) - real(pr) :: v - real(pr) :: p0, pf, dp, p - real(pr) :: t0, tf, dt, t - integer :: i, j, n_p_points=500, n_t_points=5 + real(pr) :: v, T, P + real(pr) :: lnphip(nc) + + integer :: i, nevals=100000 forsus_dir = "build/dependencies/forsus/data/json" sus(1) = Substance("propane", only=["critical"]) sus(2) = Substance("n-butane", only=["critical"]) - n = [0.7, 0.3] + n = [0.99, 0.01] tc = sus%critical%critical_temperature%value pc = sus%critical%critical_pressure%value/1e5 w = sus%critical%acentric_factor%value - kij = reshape([0., 0.0, 0.0, 0.], [nc,nc]) - lij = kij / 2 - eos = SoaveRedlichKwong(tc, pc, w, kij, lij) + eos = SoaveRedlichKwong(tc, pc, w) + T = 350 + P = 500 - p0 = 100 - pf = 0.1 - dp = (pf-p0)/n_p_points + do i=1,10000 + P = real(i, pr)/10 + call eos%volume(n, P, T, V, "stable") + print *, V, P + end do - t0 = 150 - tf = 350 - dt = (tf-t0)/n_t_points + print "(/)" - T = 300 do i=1,1000 - V = real(i, pr)/1000._pr - call pressure(eos, n, V, T, P=P) + P = real(i, pr)/10 + call volume_michelsen(eos, n, P, T, V, "stable") print *, V, P end do - - - - ! do j=0, n_t_points - 1 - ! t = t0 + dt * j - ! print *, "# ", t - ! do i=0,n_p_points-1 - ! p = p0 + dp * i - ! call volume(eos, n, p, t, v, root_type="stable") - ! print *, v, p - ! end do - ! print *, "" - ! print *, "" - ! end do end program main diff --git a/app/main.f90 b/app/main.f90 index 49ffcbe57..c225cf06a 100644 --- a/app/main.f90 +++ b/app/main.f90 @@ -1,17 +1,12 @@ program main - use yaeos, only: pr, R, Substances, AlphaSoave, CubicEoS, GenericCubic_Ar, fugacity_vt, fugacity_tp, volume, QMR + use yaeos, only: pr, R, Substances, AlphaSoave, CubicEoS, GenericCubic_Ar use yaeos, only: ArModel, PengRobinson76 implicit none - type(Substances) :: compos - type(CubicEoS), target :: eos, eos2 - type(AlphaSoave) :: alpha - type(QMR) :: mixrule - - class(ArModel), pointer :: this + type(CubicEoS), target :: eos integer, parameter :: n=2 - real(pr) :: z(n), b, dbi(n), dbij(n,n) + real(pr) :: z(n) real(pr) :: v=1.0, t=150.0, p real(pr) :: ar @@ -19,12 +14,9 @@ program main real(pr) :: arn(n), arvn(n), artn(n), arn2(n,n) real(pr) :: lnfug(n), dlnphidp(n), dlnphidt(n), dlnphidn(n, n) - class(ArModel), allocatable :: models(:) real(pr) :: tc(n), pc(n), w(n), kij(n, n), lij(n, n) - integer :: i - z = [0.3_pr, 0.7_pr] tc = [190._pr, 310._pr] pc = [14._pr, 30._pr] @@ -38,7 +30,7 @@ program main v = 1 t = 150 - call fugacity_vt(eos, & + call eos%lnphi_vt(& z, V, T, P, lnfug, dlnPhidP, dlnphidT, dlnPhidn & ) diff --git a/app/phase_diagram.f90 b/app/phase_diagram.f90 index 3250b5ff9..3b59e559c 100644 --- a/app/phase_diagram.f90 +++ b/app/phase_diagram.f90 @@ -1,53 +1,58 @@ program phase_diagram + !! Program for calculation of phase diagrams. use forsus, only: Substance, forsus_dir, forsus_default_dir - use yaeos + use yaeos, only: pr, & + SoaveRedlichKwong, PengRobinson76, PengRobinson78, RKPR, & + EquilibriaState, ArModel, PTEnvel2, & + pt_envelope_2ph, saturation_pressure, saturation_temperature use yaeos__phase_equilibria_auxiliar, only: k_wilson implicit none - class(ArModel), allocatable :: model - type(EquilibriaState) :: init - type(PTEnvel2) :: envelope - - integer, parameter :: nc=2 - integer :: i - real(pr) :: n(nc), tc(nc), pc(nc), w(nc), kij(nc, nc), lij(nc, nc), T - type(Substance) :: sus(nc) - + ! =========================================================================== + ! Variables definition + ! --------------------------------------------------------------------------- + integer, parameter :: nc=2 + class(ArModel), allocatable :: model ! Thermodynamic model to be used + type(EquilibriaState) :: sat_point ! Init + type(PTEnvel2) :: envelope ! PT Phase envelope + real(pr) :: tc(nc), pc(nc), w(nc) ! Component's critical constants + real(pr) :: n(nc) ! Termodynamic variables + type(Substance) :: sus(nc) ! Substances to use + ! =========================================================================== + + ! forsus database directory forsus_dir = "build/dependencies/forsus/" // forsus_default_dir + + ! Find the selected substances on the database and extract their + ! critical constants sus(1) = Substance("methane") sus(2) = Substance("n-hexane") + call get_critical_constants(sus, tc, pc, w) - n = [0.9_pr, 0.1_pr] ! Composition - tc = sus%critical%critical_temperature%value - pc = sus%critical%critical_pressure%value/1e5 - w = sus%critical%acentric_factor%value - - kij = 0 - kij(1, 2) = 0.0 - kij(2, 1) = kij(1, 2) - - lij = 0 + ! Model definition + model = PengRobinson76(tc, pc, w) - model = PengRobinson76(tc, pc, w, kij, lij) + ! Composition vector + n = [0.9_pr, 0.1_pr] + + ! Calculate a dew point at low pressure to later + ! initialize the phase envelope + sat_point = saturation_temperature(model, n, P=1._pr, kind="dew", t0=150._pr) - ! Calculate a dew point - T = 150 - do i=0, 6 - kij(1, 2) = 0._pr + real(i,pr)/10 - kij(2, 1) = kij(1, 2) - lij = kij/10 + ! Calculate phase envelope + envelope = pt_envelope_2ph(model, n, sat_point) - model = PengRobinson78(tc, pc, w, kij, lij) + ! Write the phase envelope to screen + write(*, *) envelope - init = saturation_temperature(model, n, P=1._pr, kind="dew", t0=150._pr) - init%x = 1/k_wilson(model, init%T, init%P) * init%y - envelope = pt_envelope_2ph(model, n, init, delta_0=0.01_pr, points=1000) - write(1, *) envelope +contains - init = saturation_pressure(model, n, T=150._pr, kind="bubble", p0=40._pr) - envelope = pt_envelope_2ph(model, n, init, points=1000) - write(1, *) envelope + subroutine get_critical_constants(subs, tc_in, pc_in, w_in) + type(Substance) :: subs(:) + real(pr), intent(out) :: tc_in(:), pc_in(:), w_in(:) - end do - + tc_in = subs%critical%critical_temperature%value + pc_in = subs%critical%critical_pressure%value/1e5 + w_in = subs%critical%acentric_factor%value + end subroutine end program phase_diagram diff --git a/app/saturation.f90 b/app/saturation.f90 new file mode 100644 index 000000000..a186c0dec --- /dev/null +++ b/app/saturation.f90 @@ -0,0 +1,64 @@ +program main + use yaeos + integer, parameter :: nc=2 + type(NRTL) :: ge_model + + real(pr), dimension(nc,nc) :: a, b, c + real(pr), dimension(nc) :: tc, pc, w + type(MHV) :: mixrule + type(CubicEOS) :: eos + type(EquilibriaState) :: eq + real(pr) :: n(nc) + + integer :: i + + tc = [647.13999999999999, 513.91999999999996] + pc = [220.63999999999999, 61.479999999999997] + w = [0.34399999999999997, 0.64900000000000002] + a = 0; b = 0; c = 0 + + ! NRTL model parameters + a(1, 2) = 3.458 + a(2, 1) = -0.801 + + b(1, 2) = -586.1 + b(2, 1) = 246.2 + + c(1, 2) = 0.3 + c(2, 1) = 0.3 + + eos = PengRobinson76(tc, pc, w) + ge_model = NRTL(a, b, c) + mixrule = MHV(ge=ge_model, q=-0.53_pr, b=eos%b) + + deallocate(eos%mixrule) + eos%mixrule = mixrule + + do i=1,99 + n(1) = real(i, pr)/100 + n(2) = 1 - n(1) + eq = saturation_pressure(eos, n, 273._pr + 100._pr, kind="bubble") + print *, eq%x(1), eq%y(1), eq%P + end do + + call ge_model%ln_activity_coefficient([0.3_pr, 0.7_pr], 250._pr, n) + print *, n +end program main + + +! for i, T in enumerate(np.linspace(50+273, 200+273, 5)): +! i=4 +! xs = np.linspace(0.001, 0.999, 100) +! ys = [] +! ps = [] +! +! for x1 in xs: +! x = [x1, 1-x1] +! p, x, y, vx, vy, beta = yaeos.yaeos_c.saturation_pressure(model.id, x, T, "bubble") +! ps.append(p) +! ys.append(y[0]) +! +! plt.plot(xs, ps, color=colors[i]) +! plt.plot(ys, ps, color=colors[i]) +! end program +! diff --git a/app/tpd.f90 b/app/tpd.f90 new file mode 100644 index 000000000..efbb8615e --- /dev/null +++ b/app/tpd.f90 @@ -0,0 +1,39 @@ +program phase_diagram + use forsus, only: Substance, forsus_dir + use yaeos + use yaeos__phase_equilibria_stability, only: tm, min_tpd + use yaeos, only: flash + implicit none + + integer, parameter :: nc=2 + + class(ArModel), allocatable :: model + type(Substance) :: sus(nc) + real(pr) :: tc(nc), pc(nc), ac(nc) + real(pr) :: z(nc), T, P + real(pr) :: w(nc), mintpd + + forsus_dir = "build/dependencies/forsus/data/json" + sus(1) = Substance("methane") + sus(2) = Substance("hydrogen sulfide") + + z = [0.13, 1-0.13] + z = z/sum(z) + + P = 20.0_pr + T = 190._pr + + tc = sus%critical%critical_temperature%value + pc = sus%critical%critical_pressure%value/1e5_pr + ac = sus%critical%acentric_factor%value + + model = SoaveRedlichKwong(tc, pc, ac) + + call min_tpd(model, z, P, T, mintpd, w) + print *, mintpd, w/sum(w) + + P = 15 + call min_tpd(model, z, P, T, mintpd, w) + print *, mintpd, w/sum(w) + +end program phase_diagram diff --git a/ci/ci.sh b/ci/ci.sh index 4b357b9b7..bbe297c11 100644 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -71,6 +71,16 @@ run_coverage() { --fail-under-line 90 } +python_wrappers(){ + BUILD_DIR="build/python" + fpm install --profile release --prefix "$BUILD_DIR" + cd python/yaeos + f2py \ + -I ../../$BUILD_DIR/include \ + -L ../../$BUILD_DIR/lib/libyaeos.a \ + -m yaeos -c ../yaeos_c.f90 ../../$BUILD_DIR/lib/libyaeos.a +} + resumee() { [ $DID_TEST = 1 ] && echo There has been $NAMING_ERRORS test naming errors @@ -86,9 +96,9 @@ case $1 in "install") install_fpm;; "test") run_test;; "coverage") run_coverage;; + "python") python_wrappers;; *) run_test run_coverage resumee;; -esac - +esac \ No newline at end of file diff --git a/doc/page/index.md b/doc/page/index.md index da1b89dfb..d182fe490 100644 --- a/doc/page/index.md +++ b/doc/page/index.md @@ -1,7 +1,6 @@ --- title: User documentation ordered_subpage: usage - theory contributing --- @@ -31,4 +30,4 @@ model = setup_model() ! Once the model is set up, the user has access to the properties call pressure(model, V, T, P, dPdN=dPdN) -``` +``` \ No newline at end of file diff --git a/doc/page/theory/index.md b/doc/page/theory/index.md deleted file mode 100644 index 6d1f993ef..000000000 --- a/doc/page/theory/index.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: Theorical background ---- \ No newline at end of file diff --git a/doc/page/usage/cubics.md b/doc/page/usage/cubics.md deleted file mode 100644 index 539f5958e..000000000 --- a/doc/page/usage/cubics.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cubic Models ---- - - diff --git a/doc/page/usage/eos/cubics/alpha.md b/doc/page/usage/eos/cubics/alpha.md new file mode 100644 index 000000000..b4cbf7cfd --- /dev/null +++ b/doc/page/usage/eos/cubics/alpha.md @@ -0,0 +1,3 @@ +--- +title: alpha functions +--- \ No newline at end of file diff --git a/doc/page/usage/eos/cubics/index.md b/doc/page/usage/eos/cubics/index.md new file mode 100644 index 000000000..08325e7be --- /dev/null +++ b/doc/page/usage/eos/cubics/index.md @@ -0,0 +1,14 @@ +--- +title: Cubics +--- + +** Table of contents** +[TOC] + +## SoaveRedlichKwong + +## PengRobinson76 + +## PengRobinson78 + +## RKPR \ No newline at end of file diff --git a/doc/page/usage/eos/cubics/mixing.md b/doc/page/usage/eos/cubics/mixing.md new file mode 100644 index 000000000..e46c64ccf --- /dev/null +++ b/doc/page/usage/eos/cubics/mixing.md @@ -0,0 +1,69 @@ +--- +title: Mixing Rules +--- + +# Cubic Mixing Rules +All [[CubicEoS]] in `yaeos` include a [[CubicMixRule]] derived type, which +handles how the \(D\) and \(B\) parameters in the CubicEoS are calculated. + +## Quadratic Mixing Rules (QMR) +Quadratic mixing rules are the ussually most used mixing rules for cubic +equations of state. + +\[ + nB = \sum_i \sum_j n_i n_j \frac{b_i + b_j}{2} (1 - l_{ij}) +\] + +\[ + D = \sum_i \sum_j n_i n_j a_{ij} +\] + +QMR are handled by the [[QMR]] derived type. Which can be used like: + +```fortran +use yaeos, only: pr, QMR + +type(QMR) :: mixrule +real(pr) :: kij(2, 2), lij(2, 2) + +kij(1, :) = [0.0, 0.1] +kij(2, :) = [0.1, 0.0] + +lij(1, :) = [0.0, 0.01] +lij(2, :) = [0.01, 0.0] + +mixrule = QMR(k=kij, l=lij) +``` + +By default the \(a_{ij}\) matrix will be calculated with a constant \(k_{ij}\) +value (as shown below). But this functionality can be modified by replacing +the `get_aij` procedure + +```fortran +use yaeos, only: pr, QMR + +type(QMR) :: mixrule +real(pr) :: kij(2, 2), lij(2, 2) + +kij(1, :) = [0.0, 0.1] +kij(2, :) = [0.1, 0.0] + +lij(1, :) = [0.0, 0.01] +lij(2, :) = [0.01, 0.0] + +mixrule = QMR(k=kij, l=lij) +mixrule%get_aij => my_aij_implementation + +subroutine my_aij_implementation(self, ai, daidt, daidt2, aij, daijdt, daijdt2) + class(QMR) :: self + real(pr), intent(in) :: ai(:), daidt(:), daidt2(:) + real(pr), intent(out) :: aij(:, :), daijdt(:, .), daijdt2(:, :) + ! Implementation here +end subroutine +``` + +### Constant \(k_{ij}\) + +## \(G^E\) Models Mixing Rules + +### Michelsen's Modified Huron-Vidal Mixing Rules \ No newline at end of file diff --git a/doc/page/usage/eos/index.md b/doc/page/usage/eos/index.md new file mode 100644 index 000000000..c828b5b17 --- /dev/null +++ b/doc/page/usage/eos/index.md @@ -0,0 +1,6 @@ +--- +title: Equations of State +ordered_subpage: cubics +--- + +Explain ArModels thermoprops here \ No newline at end of file diff --git a/doc/page/usage/excessmodels/index.md b/doc/page/usage/excessmodels/index.md new file mode 100644 index 000000000..397e3a111 --- /dev/null +++ b/doc/page/usage/excessmodels/index.md @@ -0,0 +1,5 @@ +--- +title: Gibbs Excess Models +--- + +Explain thermoprops of Ge models here \ No newline at end of file diff --git a/doc/page/usage/excessmodels/nrtl.md b/doc/page/usage/excessmodels/nrtl.md new file mode 100644 index 000000000..59ebcbf4b --- /dev/null +++ b/doc/page/usage/excessmodels/nrtl.md @@ -0,0 +1,3 @@ +--- +title: NRTL +--- \ No newline at end of file diff --git a/doc/page/usage/excessmodels/unifaclv.md b/doc/page/usage/excessmodels/unifaclv.md new file mode 100644 index 000000000..384b0293c --- /dev/null +++ b/doc/page/usage/excessmodels/unifaclv.md @@ -0,0 +1,106 @@ +--- +title: UNIFAC-LV +--- + +# UNIFAC + +[[UNIFAC]] (UNIQUAC Functional-group Activity Coefficients) is an Excess Gibbs +free energy model used to estimate activity coefficients in non-ideal mixtures. +It is particularly useful for predicting the phase behavior of chemical +mixtures, including liquid-liquid equilibrium (LLE) and vapor-liquid +equilibrium (VLE). In this model the Excess Gibbs free energy is calculated +from the contribution of a combinatorial term and a residual term. + +$$ \frac{G^E}{RT} = \frac{G^{E,r}}{RT} + \frac{G^{E,c}}{RT} $$ + +Being: + +- Combinatorial: Accounts for the size and shape of the molecules. The involved +equations can be checked in the API documentation: +[[yaeos__models_ge_group_contribution_unifac:Ge_combinatorial]] + +- Residual: Accounts for the energy interactions between different functional +groups. The involved equations can be checked in the API documentation: +[[yaeos__models_ge_group_contribution_unifac:Ge_residual]] + +Each substance of a mixture modeled with [[UNIFAC]] must be represented by a +list a functional groups and other list with the ocurrence of each functional +group on the substance. The list of the functional groups culd be accesed on +the DDBST web page: +[https://www.ddbst.com/published-parameters-unifac.html](https://www.ddbst.com/published-parameters-unifac.html) + +# Examples +## Calculating activity coefficients +We can instantiate a [[UNIFAC]] model with a mixture ethanol-water and +evaluate the logarithm of activity coefficients of the model for a 0.5 mole +fraction of each, and a temperature of 298.0 K. + +```fortran +use yaeos__constants, only: pr +use yaeos__models_ge_group_contribution_unifac, only: Groups, UNIFAC, setup_unifac + +! Variables declarations +type(UNIFAC) :: model +type(Groups) :: molecules(2) +real(pr) :: ln_gammas(2) + +! Variables instances +! Ethanol definition [CH3, CH2, OH] +molecules(1)%groups_ids = [1, 2, 14] ! Subgroups ids +molecules(1)%number_of_groups = [1, 1, 1] ! Subgroups occurrences + +! Water definition [H2O] +molecules(2)%groups_ids = [16] +molecules(2)%number_of_groups = [1] + +! Model setup +model = setup_unifac(molecules) + +! Calculate ln_gammas +call model%ln_activity_coefficient([0.5_pr, 0.5_pr], 298.0_pr, ln_gammas) + +print *, ln_gammas +``` + +You will obtain: + +``` +>>> 0.18534142000449058 0.40331395945417559 +``` + +# References +1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst +.com/published-parameters-unifac.html) +2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). Group‐contribution +estimation of activity coefficients in nonideal liquid mixtures. AIChE Journal, +21(6), 1086–1099. +[https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) +3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). +Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and Extension. +Industrial & Engineering Chemistry Process Design and Development, 18(4), +714–722. +[https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) +4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid +equilibriums by UNIFAC group contribution. Revision and extension. 2. +Industrial & Engineering Chemistry Process Design and Development, 21(1), +118–127. +[https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) +5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). +Vapor-liquid equilibriums by UNIFAC group contribution. Revision and extension. +3. Industrial & Engineering Chemistry Process Design and Development, 22(4), +676–678. +[https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) +6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). +Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and +extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. +[https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) +7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & Gmehling, J. +(1991). Vapor-liquid equilibria by UNIFAC group contribution. 5. Revision and +extension. Industrial & Engineering Chemistry Research, 30 (10), 2352–2355. +[https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) +8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria by +UNIFAC Group Contribution. 6. Revision and Extension. Industrial & Engineering +Chemistry Research, 42(1), 183–188. +[https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) +9. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) + diff --git a/doc/page/usage/figs/PTEnvel2.png b/doc/page/usage/figs/PTEnvel2.png new file mode 100644 index 000000000..6ce136c6d Binary files /dev/null and b/doc/page/usage/figs/PTEnvel2.png differ diff --git a/doc/page/usage/index.md b/doc/page/usage/index.md index 190fdc552..4e421e8ac 100644 --- a/doc/page/usage/index.md +++ b/doc/page/usage/index.md @@ -1,5 +1,9 @@ --- title: Using yaeos +ordered_subpage: eos + excessmodels + phase_equilibrium + newmodels --- [TOC] @@ -54,7 +58,7 @@ extening to a broader variety. In this example we'll show how a model in `yaeos` can be used. We'll take the `Peng-Robinson` equation of state as an example, but all the implemented -models can be seen at [[yaeos_models(module)]]. Inside +models can be seen at [[yaeos__models(module)]]. Inside your `app/main.f90` file use ```fortran @@ -119,6 +123,6 @@ call pressure(model, n, v, t, p, dpdv=dpdv) ! Calculate pressure and dPdV ``` The available thermodynamic properties to calculate can be seen at the -[[yaeos_thermoprops(module)]] module. +[[yaeos__thermoprops(module)]] module. # Phase equilibria diff --git a/doc/page/usage/newmodels/analtical.md b/doc/page/usage/newmodels/analtical.md new file mode 100644 index 000000000..cd0960fa6 --- /dev/null +++ b/doc/page/usage/newmodels/analtical.md @@ -0,0 +1,3 @@ +--- +title: Analytical derivatives +--- diff --git a/doc/page/usage/newmodels/autodiff.md b/doc/page/usage/newmodels/autodiff.md new file mode 100644 index 000000000..e1424ae5e --- /dev/null +++ b/doc/page/usage/newmodels/autodiff.md @@ -0,0 +1,153 @@ +--- +title: Automatic differentiation +--- +# Autodiff +The implementation of new models and all their required derivatives can be +an endeavours and error-prone task. A tool that helps with this, at a small +performance cost, can be automatic differentiation. + +Automatic differentiation can be implemented in two ways: + +- Forward Differentiation +- Backward Differentiation + +With can be combined to obtain higher order derivatives. + +In `yaeos` it is possible to add new models via two different kind of +implementations. Operator overloading with `hyperdual` numbers and +source-to-source automatic differentiation with `tapenade`. + +@warn +Remember to use the `R`constant from `yaeos__constants`, and all models +should have a `type(Substances)` attribute! +@endwarn + +## Hyperdual autodiff + +### ArModel +Automatic differentiation with `hyperdual` numbers can be done with the +[[ArModelAdiff]] derived type. This implementation requires just to extend +that derived type with your own implementation and a volume initializer. + +```fortran +module hyperdual_pr76 + use yaeos__constants, only: pr, R + use yaeos__ar_models_hyperdual + use yaeos__substance, only: Substances + implicit none + + type, extends(ArModelAdiff) :: PR76 + !! PengRobinson 76 EoS + ! Composition + type(Substances) :: composition + + ! Mixing rule Parameters + real(pr), allocatable :: kij(:, :), lij(:, :) + + ! EoS parameters + real(pr), allocatable :: ac(:), b(:), k(:) + real(pr), allocatable :: tc(:), pc(:), w(:) + contains + procedure :: Ar => arfun + procedure :: get_v0 => v0 + end type + + real(pr), parameter :: del1 = 1._pr + sqrt(2._pr) + real(pr), parameter :: del2 = 1._pr - sqrt(2._pr) + +contains + + type(PR76) function setup(tc, pc, w, kij, lij) result(self) + !! Function to obtain a defined PR76 model with setted up parameters + !! as function of Tc, Pc, and w + real(pr) :: tc(:) + real(pr) :: pc(:) + real(pr) :: w(:) + real(pr) :: kij(:, :) + real(pr) :: lij(:, :) + + self%composition%tc = tc + self%composition%pc = pc + self%composition%w = w + + self%ac = 0.45723553_pr * R**2 * tc**2 / pc + self%b = 0.07779607_pr * R * tc_in/pc_in + self%k = 0.37464_pr + 1.54226_pr * w - 0.26993_pr * w**2 + + self%kij = kij + self%lij = lij + end function + + function arfun(self, n, v, t) result(ar) + !! Residual Helmholtz calculation for a generic cubic with + !! quadratic mixing rules. + class(PR76) :: self + type(hyperdual), intent(in) :: n(:), v, t + type(hyperdual) :: ar + + type(hyperdual) :: amix, a(size(n)), ai(size(n)), n2(size(n)) + type(hyperdual) :: bmix + type(hyperdual) :: b_v, nij + + integer :: i, j + + associate(& + pc => self%composition%pc, ac => self%ac, b => self%b, k => self%k,& + kij => self%kij, lij => self%lij, tc => self%compostion%tc & + ) + + ! Soave alpha function + a = 1.0_pr + k * (1.0_pr - sqrt(t/tc)) + a = ac * a ** 2 + ai = sqrt(a) + + ! Quadratic Mixing Rule + amix = 0.0_pr + bmix = 0.0_pr + + do i=1,size(n)-1 + do j=i+1,size(n) + nij = n(i) * n(j) + amix = amix + 2 * nij * (ai(i) * ai(j)) * (1 - kij(i, j)) + bmix = bmix + nij * (b(i) + b(j)) * (1 - lij(i, j)) + end do + end do + + amix = amix + sum(n**2*a) + bmix = bmix + sum(n**2 * b) + + bmix = bmix/sum(n) + + b_v = bmix/v + + ! Generic Cubic Ar function + ar = (& + - sum(n) * log(1.0_pr - b_v) & + - amix / (R*T*bmix)*1.0_pr / (del1 - del2) & + * log((1.0_pr + del1 * b_v) / (1.0_pr + del2 * b_v)) & + ) * (R * T) + + end associate + end function + + function v0(self, n, p, t) + !! Initialization of liquid volume solving with covolume + class(PR76), intent(in) :: self + real(pr), intent(in) :: n(:) + real(pr), intent(in) :: p + real(pr), intent(in) :: t + real(pr) :: v0 + + v0 = sum(n * self%b) / sum(n) + end function +end module +``` + + +## Tapenade Adiff +And alternative to `hyperdual` that takes a bit more work, but can end in a more +performant model, is doing `tapenade` source-to-source differentiation. For +this `tapenade` must be installed and accessible from a terminal +[donwload link](https://tapenade.gitlabpages.inria.fr/userdoc/build/html/download.html). + +{!tools/tapenade_diff/README.md!} \ No newline at end of file diff --git a/doc/page/usage/newmodel.md b/doc/page/usage/newmodels/index.md similarity index 62% rename from doc/page/usage/newmodel.md rename to doc/page/usage/newmodels/index.md index b98547e77..459e2756f 100644 --- a/doc/page/usage/newmodel.md +++ b/doc/page/usage/newmodels/index.md @@ -3,11 +3,11 @@ title: Adding your own models --- Most of thermodynamic properties calculated in `yaeos` heavily depend on -different kind of models and their respective derivatives. -Since obtaining the derivatives of complex models can be a tedious and -error-prone task. We provide two different ways of getting them automatically -(in some cases with some performance-cost), but there is also the possibility -of using anallyitical obtained expressions instead. +different kind of models and their respective derivatives. Since obtaining the +derivatives of complex models can be a tedious and error-prone task. We provide +two different ways of getting them automatically (in some cases with some +performance-cost), but there is also the possibility of using analytical +obtained expressions instead. The calculation of thermodynamic properties heavily depends on @@ -18,7 +18,8 @@ On `yaeos` there are three different ways of adding your own model:W # Residual Helmholtz models Residual Helmholtz models are the basis to obtain the residual properties. -The main basis in `yaeos` to define a new object that extends the `abstract type` called `ArModel`. Which enforces the expected functionality of these +The main basis in `yaeos` to define a new object that extends the `abstract +type `called` [[ArModel]]. Which enforces the expected functionality of this kind of models. ```fortran @@ -30,8 +31,10 @@ end type The definition of an `ArModel` expects that two procedures are defined: -- [[abs_residual_helmholtz(interface)]]: Procedure to calculate residual Helmholtz energy and it's derivatives -- [[abs_volume_initializer(interface)]]: Volume initializer to find a liquid root, given a pressure and temperature. +- [[abs_residual_helmholtz(interface)]]: Procedure to calculate residual + Helmholtz energy and it's derivatives +- [[abs_volume_initializer(interface)]]: Volume initializer to find a liquid + root, given a pressure and temperature. ```fortran use yaeos, only: ArModel @@ -53,10 +56,4 @@ type(MyNewModel) :: model ! Assuming model parameters are set-up call pressure(model, n, V, T, P) -``` - -## Using operator overloading automatic differentiation with hyperdual numbers - -## Using source-to-source automatic differentiation with tapenade - -## Using analytical obtained expressions +``` \ No newline at end of file diff --git a/doc/page/usage/phase_equilibrium/envelopes.md b/doc/page/usage/phase_equilibrium/envelopes.md new file mode 100644 index 000000000..422fe01cb --- /dev/null +++ b/doc/page/usage/phase_equilibrium/envelopes.md @@ -0,0 +1,108 @@ +--- +title: Phase envelopes +copy_subdir: ../figs +--- + +## Two-phase envelopes +Two-phase envelopes show all the saturation points of a mixture, they can +be seen as the boundary line of transition between monophasic regions to +two-phase equilibria regions. + +In `yaeos` it is possible to calculate two-phase of different kinds. + +- Isoplets + +### Isoplets +Isoplets are the phase boundaries at constant composition +(the global composition) of the system. Here is a simple example with +commentaries on how a phase boundary can be calculated: + +```fortran +program phase_diagram + !! Program for calculation of phase diagrams. + use forsus, only: Substance, forsus_dir, forsus_default_dir + use yaeos, only: pr, & + SoaveRedlichKwong, PengRobinson76, PengRobinson78, RKPR, & + EquilibriaState, ArModel, PTEnvel2, & + pt_envelope_2ph, saturation_pressure, saturation_temperature + use yaeos__phase_equilibria_auxiliar, only: k_wilson + implicit none + + ! =========================================================================== + ! Variables definition + ! --------------------------------------------------------------------------- + integer, parameter :: nc=2 + class(ArModel), allocatable :: model ! Thermodynamic model to be used + type(EquilibriaState) :: sat_point ! Init + type(PTEnvel2) :: envelope ! PT Phase envelope + real(pr) :: tc(nc), pc(nc), w(nc) ! Component's critical constants + real(pr) :: n(nc) ! Termodynamic variables + type(Substance) :: sus(nc) ! Substances to use + ! =========================================================================== + + ! forsus database directory + forsus_dir = "build/dependencies/forsus/" // forsus_default_dir + + ! Find the selected substances on the database and extract their + ! critical constants + sus(1) = Substance("methane") + sus(2) = Substance("n-hexane") + call get_critical_constants(sus, tc, pc, w) + + ! Model definition + model = PengRobinson76(tc, pc, w) + + ! Composition vector + n = [0.9_pr, 0.1_pr] + + ! Calculate a dew point at low pressure to later + ! initialize the phase envelope + sat_point = saturation_temperature(model, n, P=1._pr, kind="dew", t0=150._pr) + + ! Calculate phase envelope + envelope = pt_envelope_2ph(model, n, sat_point) + + ! Write the phase envelope to screen + write(*, *) envelope + +contains + + subroutine get_critical_constants(subs, tc_in, pc_in, w_in) + type(Substance) :: subs(:) + real(pr), intent(out) :: tc_in(:), pc_in(:), w_in(:) + + tc_in = subs%critical%critical_temperature%value + pc_in = subs%critical%critical_pressure%value/1e5 + w_in = subs%critical%acentric_factor%value + end subroutine +end program phase_diagram +``` + +The output of the `write` command will be pre-formatted. Showing in tabular +data with this + +``` +# PTEnvel2 + +# kind of sat point +kind T P [liquid-phase composition vector] [gas-phase composition vector] + +# other kind of sat point +kind T P [liquid-phase composition vector] [gas-phase composition vector] + +# Critical +T P +``` + +Which when plotted with `gnuplot` with: + +```gnuplot +plot "outfile" \ + index "dew" u 2:3 w l title "Dew", \ + "" index "bubble" u 2:3 w l t "Bubble", \ + "" index "Critical" u 1:2 w p pt 7 lc rgb "black" t "CP" +``` + +Gives the following plot: + +![PTEnvel2](../figs/PTEnvel2.png) \ No newline at end of file diff --git a/doc/page/usage/phase_equilibrium/flash.md b/doc/page/usage/phase_equilibrium/flash.md new file mode 100644 index 000000000..8bb965438 --- /dev/null +++ b/doc/page/usage/phase_equilibrium/flash.md @@ -0,0 +1,3 @@ +--- +title: Flash calculations +--- \ No newline at end of file diff --git a/doc/page/usage/phase_equilibria.md b/doc/page/usage/phase_equilibrium/index.md similarity index 52% rename from doc/page/usage/phase_equilibria.md rename to doc/page/usage/phase_equilibrium/index.md index 260c1ed19..171b03891 100644 --- a/doc/page/usage/phase_equilibria.md +++ b/doc/page/usage/phase_equilibrium/index.md @@ -1,5 +1,6 @@ --- -title: Phase Equilibria +title: Phase Equilibrium +copy_subdir: ../figs --- Phase Equilibria calculations are fundamental for the majority of EoS based @@ -14,7 +15,27 @@ The implemented methods, and their usage are: [TOC] # Flash calculations -Flash calcuations +Flash calcuations are one of the most used phase-equilibria calculations during +modelling of processes. + +In `yaeos` it is possible to make Flash calculations either specifying: + +- \( zPT \rightarrow x, y, \beta (V) \) +- \( zVT \rightarrow x, y, \beta (P) \) + +```fortran +type(EquilibriaState) :: result + +! zPT flash +result = flash(model, z, p_spec=P, T=T) + +! zVT flash +result = flash(model, z, v_spec=P, T=T) + +! It is possible to provide initialization compositions in terms of the +! K-factors. Where k0=y/x +result = flash(model, z, v_spec=P, T=T, k0=k0) +``` # Saturation points Single saturation point calculations are included with the procedures @@ -28,6 +49,16 @@ f(T \lor P) = \sum ln K_i - 1 = 0 With a newton procedure with respect to the desired variable (either \(P\) or \(T\). +```fortran +type(EquilibriaState) :: sat_point + +sat = saturation_pressure(model, z, T=T, kind="bubble") +sat = saturation_pressure(model, z, T=T, kind="dew") + +sat = saturation_temperature(model, z, P=P, kind="bubble") +sat = saturation_temperature(model, z, P=P, kind="dew") +``` + ## Phase envelopes Phase envelopes are the conection of all the saturation points of a system. When the interest is in calculating a whole phase diagram instead of a single @@ -35,3 +66,12 @@ point, or the point is hard to converge. It is better to use a robust mathematical algorithm that eases the calcuation providing an easy-to-converge point and using its information to initialize a next one and continue along the whole phase-boundary. This can be done with the procedure [[pt_envelope_2ph]] + +```fortran +type(PTEnvel2) :: env + +sat = saturation_pressure(model, z, T=150._pr, kind="bubble") +env = pt_envelope_2ph(model, z, sat) +``` + +![PTEnvel2](../figs/PTEnvel2.png) \ No newline at end of file diff --git a/doc/page/usage/phase_equilibrium/saturation_points.md b/doc/page/usage/phase_equilibrium/saturation_points.md new file mode 100644 index 000000000..6c99bc5e5 --- /dev/null +++ b/doc/page/usage/phase_equilibrium/saturation_points.md @@ -0,0 +1,3 @@ +--- +title: Saturation Points +--- \ No newline at end of file diff --git a/example/extra/adiff_pr76.f90 b/example/extra/adiff_pr76.f90 index cea2cab5f..c7646047a 100644 --- a/example/extra/adiff_pr76.f90 +++ b/example/extra/adiff_pr76.f90 @@ -5,10 +5,8 @@ module hyperdual_pr76 implicit none type, extends(ArModelAdiff) :: PR76 - type(Substances) :: composition real(pr), allocatable :: kij(:, :), lij(:, :) real(pr), allocatable :: ac(:), b(:), k(:) - real(pr), allocatable :: tc(:), pc(:), w(:) contains procedure :: Ar => arfun procedure :: get_v0 => v0 @@ -19,24 +17,24 @@ module hyperdual_pr76 contains - type(PR76) function setup(tc_in, pc_in, w_in, kij_in, lij_in) result(self) + type(PR76) function setup(tc, pc, w, kij, lij) result(self) !! Seup an Autodiff_PR76 model - real(pr) :: tc_in(:) - real(pr) :: pc_in(:) - real(pr) :: w_in(:) - real(pr) :: kij_in(:, :) - real(pr) :: lij_in(:, :) - - self%tc = tc_in - self%pc = pc_in - self%w = w_in - - self%ac = 0.45723553_pr * R**2 * self%tc**2 / self%pc - self%b = 0.07779607_pr * R * self%tc/self%pc - self%k = 0.37464_pr + 1.54226_pr * self%w - 0.26993_pr * self%w**2 - - self%kij = kij_in - self%lij = lij_in + real(pr) :: tc(:) + real(pr) :: pc(:) + real(pr) :: w(:) + real(pr) :: kij(:, :) + real(pr) :: lij(:, :) + + self%components%tc = tc + self%components%pc = pc + self%components%w = w + + self%ac = 0.45723553_pr * R**2 * tc**2 / pc + self%b = 0.07779607_pr * R * tc/pc + self%k = 0.37464_pr + 1.54226_pr * w - 0.26993_pr * w**2 + + self%kij = kij + self%lij = lij end function function arfun(self, n, v, t) result(ar) @@ -50,8 +48,8 @@ function arfun(self, n, v, t) result(ar) integer :: i, j - associate(pc => self%pc, ac => self%ac, b => self%b, k => self%k, & - kij => self%kij, lij => self%lij, tc => self%tc & + associate(pc => self%components%pc, ac => self%ac, b => self%b, k => self%k, & + kij => self%kij, lij => self%lij, tc => self%components%tc & ) a = 1.0_pr + k * (1.0_pr - sqrt(t/tc)) a = ac * a ** 2 diff --git a/example/extra/benchmark.f90 b/example/extra/benchmark.f90 index 3d4b7ee75..6cd8661f0 100644 --- a/example/extra/benchmark.f90 +++ b/example/extra/benchmark.f90 @@ -1,6 +1,6 @@ module bench use yaeos, only: pr, R, Substances, AlphaSoave, CubicEoS, & - fugacity_vt, QMR, PengRobinson76, ArModel, fugacity_tp + QMR, PengRobinson76, ArModel use hyperdual_pr76, only: PR76, setup_adiff_pr76 => setup use TapeRobinson, only: setup_taperobinson => setup_model implicit none @@ -49,14 +49,14 @@ subroutine yaeos__run(n, dn, f_p, model_name) if (dn) then if (f_p) then - call fugacity_tp(& - model, z, T, P, root_type="stable", & - lnphip=lnfug, dlnphidp=dlnphidp, dlnphidn=dlnphidn) + call model%lnphi_pt(& + z, P, T, root_type="stable", & + lnPhi=lnfug, dlnphidp=dlnphidp, dlnphidn=dlnphidn) else - call fugacity_vt(model, z, V, T, P, lnfug, dlnPhidP, dlnphidT, dlnphidn) + call model%lnphi_vt(z, V, T, P, lnfug, dlnPhidP, dlnphidT, dlnphidn) end if else - call fugacity_vt(model, z, V, T, lnphip=lnfug) + call model%lnphi_vt(z, V, T, lnPhi=lnfug) end if end subroutine diff --git a/example/extra/flash.f90 b/example/extra/flash.f90 index cd1581367..cc1ddbe84 100644 --- a/example/extra/flash.f90 +++ b/example/extra/flash.f90 @@ -1,5 +1,5 @@ module flashing - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel implicit none contains diff --git a/example/extra/hard_spheres_mixing.f90 b/example/extra/hard_spheres_mixing.f90 new file mode 100644 index 000000000..14e7adf11 --- /dev/null +++ b/example/extra/hard_spheres_mixing.f90 @@ -0,0 +1,209 @@ +module yaeos__HardSpheresCubicEoS + use yaeos, only: pr, R, Substances + use yaeos__ar_models_hyperdual, only: ArModelAdiff + use yaeos__autodiff + implicit none + + type, extends(ArModelAdiff) :: HardSpheresCubicEoS + real(pr), allocatable :: ac(:), b(:), k(:), kij(:, :), lij(:, :) + contains + procedure :: Ar => arfun + procedure :: get_v0 => v0 + end type HardSpheresCubicEoS + + real(pr), parameter :: del1 = 1._pr + sqrt(2._pr) + real(pr), parameter :: del2 = 1._pr - sqrt(2._pr) + +contains + + function arfun(self, n, v, t) result(Ar) + class(HardSpheresCubicEoS) :: self !! Model + type(hyperdual), intent(in) :: n(:) !! Number of moles vector + type(hyperdual), intent(in) :: v !! Volume [L/mol] + type(hyperdual), intent(in) :: t !! Temperature [K] + type(hyperdual) :: Ar !! Residual Helmholtz energy + + type(hyperdual), dimension(size(n)) :: a + type(hyperdual) :: nij + + ! Cubic Parameters + type(hyperdual) :: Ar_att + type(hyperdual) :: amix, bmix + type(hyperdual) :: b_v + + ! HardMixing parameters + type(hyperdual) :: Ar_rep + type(hyperdual) :: lambda(0:3), eta + type(hyperdual) :: l1l2_l3l0 + type(hyperdual) :: l23_l0l32 + type(hyperdual) :: logContribution + real(pr), parameter :: xi = 4.0_pr + + integer :: i, j + integer :: nc + + nc = size(n) + + ! Alpha function + associate(& + ac => self%ac, b => self%b, k => self%k, & + tc => self%components%tc, & + kij => self%kij, lij => self%lij) + + ! Attractive parameter + a = self%ac*(1.0_pr + self%k*(1.0_pr - sqrt(t/self%components%tc)))**2 + + ! Mixing rule + amix = 0.0_pr + bmix = 0.0_pr + lambda = 0.0_pr + do i = 1, nc + do j = 1, nc + nij = n(i)*n(j) + amix = amix + nij * sqrt(a(i)*a(j)) * (1 - kij(i, j)) + bmix = bmix + nij * 0.5_pr * (b(i) + b(j)) *(1 - lij(i, j)) + end do + lambda(1) = lambda(1) + n(i)*b(i)**(1.0_pr/3.0_pr) + lambda(2) = lambda(2) + n(i)*b(i)**(2.0_pr/3.0_pr) + end do + bmix = bmix/sum(n) + + lambda(0) = sum(n) + lambda(3) = bmix + eta = bmix/v/xi + l1l2_l3l0 = lambda(1)*lambda(2)/lambda(3)/lambda(0) + l23_l0l32 = lambda(2)**3/lambda(0)/lambda(3)**2 + logContribution = log(1._pr - xi*eta)/xi + + Ar_rep = -sum(n)*((1._pr + 3._pr*l1l2_l3l0)*logContribution & + + 3._pr/xi*(l23_l0l32 - 1._pr/2._pr - l1l2_l3l0/2._pr) & + *(eta + logContribution)) + b_v = bmix/v + Ar_att = (- sum(n) * log(1.0_pr - b_v) & + - amix / (R*t*bmix)*1.0_pr / (del1 - del2) & + * log((1.0_pr + del1 * b_v) / (1.0_pr + del2 * b_v)) & + ) * (R * t) + + ar = Ar_rep + Ar_att + end associate + end function arfun + + function v0(self, n, P, T) + class(HardSpheresCubicEoS), intent(in) :: self !! Model + real(pr), intent(in) :: n(:) !! Moles vector + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(in) :: T !! Temperature [K] + real(pr) :: v0 + + v0 = sum(n * self%b) + end function v0 + + + subroutine main + use yaeos + use forsus, only: Substance, forsus_dir, forsus_default_dir + use hyperdual_pr76, only: hPr76 => PR76, set_hpr => setup + + integer, parameter :: nc=2 + + real(pr) :: n(nc), V, P, Phs, T + real(pr) :: tc(nc), pc(nc), w(nc), kij(nc,nc), lij(nc,nc) + type(Substance) :: sus(nc) + + type(CubicEoS) :: pr76 + type(hPR76) :: hdpr76 + type(HardSpheresCubicEoS) :: hspr76 + + type(EquilibriaState) :: eq + type(PTEnvel2) :: env + + real(pr) :: Ar, ArT, ArV, ArTV, ArT2, ArV2, Arn(nc), Artn(nc), ArVn(nc), arn2(nc,nc) + + integer :: i + + forsus_dir = "build/dependencies/forsus/" // forsus_default_dir + + sus(1) = Substance("methane") + sus(2) = Substance("n-decane") + + tc = sus%critical%critical_temperature%value + pc = sus%critical%critical_pressure%value/1e5 + w = sus%critical%acentric_factor%value + + tc(2) = 874.0 + pc(2) = 6.8 + w(2) = 1.52596 + + kij = 0 + lij = 0 + + pr76 = PengRobinson76(tc, pc, w, kij, lij) + hdpr76 = set_hpr(tc, pc, w, kij, lij) + + ! Copy PR76 into HSPR76 + hspr76%components%tc = tc + hspr76%components%pc = pc + hspr76%components%w = w + hspr76%ac = pr76%ac + hspr76%b = pr76%b + + associate(alpha => pr76%alpha) + select type(alpha) + type is (AlphaSoave) + hspr76%k = alpha%k + end select + end associate + + hspr76%kij = kij + hspr76%lij = lij + + n = [0.3, 0.7] + V = 1 + T = 400 + + block + real(pr) :: dPdV, k, khs + do i=1,100 + P = real(i, pr) + call volume(pr76, n, P, T, V, root_type="stable") + call pressure(pr76, n, V, T, P, dPdV) + k = -1/V * 1/dPdV + + call volume(hspr76, n, P, T, V, root_type="stable") + call pressure(hspr76, n, V, T, P, dPdV) + khs = -1/V * 1/dPdV + + print *, P, k, khs + end do + end block + + P = 50 + do i=1,99 + n(1) = real(i)/100 + n(2) = 1 - n(1) + + eq = saturation_pressure(pr76, n, T=T, kind="bubble", P0=P) + P = eq%p + if (eq%iters < 1000) write(1, *) eq%x(1), eq%y(1), eq%p + + eq = saturation_pressure(hspr76, n, T=T, kind="bubble", p0=eq%P) + if (eq%iters < 1000) write(2, *) eq%x(1), eq%y(1), eq%p + end do + call exit + + T = 150 + eq = saturation_pressure(pr76, n, T=T, kind="bubble") + print *, eq%iters, eq + env = pt_envelope_2ph(pr76, n, eq) + + print *, size(env%points) + write(1, *) env + + eq = saturation_pressure(hspr76, n, T=T, kind="bubble", p0=eq%P) + print *, eq%iters, eq + + env = pt_envelope_2ph(hspr76, n, eq) + print *, size(env%points) + write(2, *) env + end subroutine main +end module yaeos__HardSpheresCubicEoS diff --git a/example/extra/pure_psat.f90 b/example/extra/pure_psat.f90 new file mode 100644 index 000000000..90ed05307 --- /dev/null +++ b/example/extra/pure_psat.f90 @@ -0,0 +1,70 @@ +!! Program to calculate the vapor pressure of pure components +!! + +module pure_psat + !! Module used to calculate the saturation pressure of pure components at + !! a given temperature. + use yaeos +contains + real(pr) function Psat(eos, ncomp, T) + use yaeos__math, only: solve_system + class(ArModel), intent(in) :: eos + integer, intent(in) :: ncomp + real(pr), intent(in) :: T + + real(pr) :: P1, P2 + real(pr) :: f1, f2 + + real(pr) :: n(size(eos)) + + n = 0 + n(ncomp) = 1 + + P1 = 0.5 + P2 = 1 + + do while(abs(diff(P2)) > 1e-10) + f1 = diff(P1) + f2 = diff(P2) + Psat = (P1 * f2 - P2 * f1)/(f2 - f1) + P1 = P2 + P2 = Psat + end do + + contains + real(pr) function diff(P) + real(pr), intent(in) :: P + real(pr) :: V_l, V_v + real(pr) :: phi_v(size(eos)), phi_l(size(eos)) + call eos%lnphi_pt(n, P, T, V=V_v, lnPhi=phi_v, root_type="vapor") + call eos%lnphi_pt(n, P, T, V=V_l, lnPhi=phi_l, root_type="liquid") + diff = phi_v(1) - phi_l(1) + end function + end function Psat +end module + +program main + use yaeos + use forsus, only: Substance, forsus_default_dir, forsus_dir + use pure_psat, only: Psat + implicit none + integer, parameter :: nc=2 + type(CubicEoS) :: eos + type(Substance) :: sus(nc) + real(pr) :: n(nc), T, f + integer :: i, j + + forsus_dir = "build/dependencies/forsus/" // forsus_default_dir + sus(1) = Substance("water") + sus(2) = Substance("ethanol") + eos = SoaveRedlichKwong(& + sus%critical%critical_temperature%value, & + sus%critical%critical_pressure%value/1e5,& + sus%critical%acentric_factor%value & + ) + T = 273.15_pr + 50 + do i=273+90, nint(maxval(sus%critical%critical_temperature%value)) + T = real(i,pr) + print *, T, (Psat(eos, j, T), j=1,nc) + end do +end program main diff --git a/example/extra/taperobinson.f90 b/example/extra/taperobinson.f90 index ed417849c..72dba51ad 100644 --- a/example/extra/taperobinson.f90 +++ b/example/extra/taperobinson.f90 @@ -16,6 +16,7 @@ MODULE TAPENADE_PR USE YAEOS__CONSTANTS, ONLY : pr, r USE YAEOS__TAPENADE_AR_API, ONLY : armodeltapenade + use yaeos__tapenade_interfaces IMPLICIT NONE type, extends(ArModelTapenade) :: TPR76 REAL(pr), ALLOCATABLE :: kij(:, :), lij(:, :) @@ -794,12 +795,6 @@ SUBROUTINE AR_D_B(model, n, nb, nd, ndb, v, vb, vd, vdb, t, tb, td, & INTEGER :: ad_from INTEGER :: ad_to INTEGER :: ad_to0 - EXTERNAL PUSHREAL8ARRAY - EXTERNAL PUSHINTEGER4 - EXTERNAL PUSHREAL8 - EXTERNAL POPREAL8 - EXTERNAL POPINTEGER4 - EXTERNAL POPREAL8ARRAY INTEGER :: arg12 LOGICAL, DIMENSION(SIZE(n)) :: mask1 LOGICAL, DIMENSION(SIZE(n)) :: mask2 diff --git a/example/tutorials/basics.f90 b/example/tutorials/basics.f90 index b83caa51d..0b6e2b653 100644 --- a/example/tutorials/basics.f90 +++ b/example/tutorials/basics.f90 @@ -32,10 +32,10 @@ program basics n = [0.3, 0.7] ! Pressure calculation - call pressure(model, n, v=2.5_pr, T=150._pr, P=P) + call model%pressure(n, v=2.5_pr, T=150._pr, P=P) print *, "P: ", P ! Derivatives can also be calculated when included as optional arguments! - call pressure(model, n, v=2.5_pr, T=150._pr, P=P, dPdV=dPdV) + call model%pressure(n, v=2.5_pr, T=150._pr, P=P, dPdV=dPdV) print *, "dPdV: ", dPdV end program basics diff --git a/example/tutorials/cubic_eos.f90 b/example/tutorials/cubic_eos.f90 new file mode 100644 index 000000000..7b86c88c4 --- /dev/null +++ b/example/tutorials/cubic_eos.f90 @@ -0,0 +1,66 @@ +!> We have seen that some cubic models are available in yaeos. But will show +!> here how it is possible to make your own CubicEoS by choosing which piece +!> of the model you want to use. +!> +!> This is just an example model and it is not intended to be used in real +!> applications. It is just to show how to create a CubicEoS model. +program main + use yaeos + integer, parameter :: nc = 2 !! Number of components + type(CubicEoS) :: eos !! The CubicEoS model + + real(pr) :: tc(nc), pc(nc), w(nc) !! Critical constants + real(pr) :: kij(nc, nc), lij(nc, nc) !! Binary interaction parameters + character(len=50) :: name(nc) !! Name of the components + + type(Substances) :: composition + !! All models should have their own composition + type(AlphaRKPR) :: alpha_function + !! The RKPR Alpha Function + type(QMR) :: mixrule + !! A Quadratic mixing rule (ClassicVdW) + + integer :: i + real(pr) :: n(nc), V, P, T + + ! First we define the components critical constants + Tc = [190._pr, 310._pr] + Pc = [14._pr, 30._pr ] + w = [0.001_pr, 0.03_pr] + name = ["Component 1", "Component 2"] + composition = Substances(name, Tc, Pc, w) + + + ! RKPR Alpha function uses a set of k parameters + alpha_function%k = [0.48_pr, 0.58_pr] + + ! The mixrule + kij = 0 + lij = 0 + kij(1,2) = 0.1_pr + kij(2,1) = kij(1, 2) + mixrule = QMR(k=kij, l=lij) + + ! We need to set up the model parameters + eos%ac = [0.042748_pr, 0.052748_pr] + eos%b = [0.005, 0.001] + eos%del1 = [0.1, 0.2] + eos%del2 = [0.4, 0.5] + + ! We now add the before defined components and mixrule + eos%alpha = alpha_function + eos%components = composition + eos%mixrule = mixrule + + + T = 50 + n = [0.5, 0.5] + do i=1,100 + V = real(i, pr)/100 + call eos%pressure(n, V, T, P) + print *, V, P + + end do + + +end program \ No newline at end of file diff --git a/example/tutorials/huron_vidal.f90 b/example/tutorials/huron_vidal.f90 index 34639455a..a3acc00b1 100644 --- a/example/tutorials/huron_vidal.f90 +++ b/example/tutorials/huron_vidal.f90 @@ -10,7 +10,6 @@ program main implicit none integer, parameter :: nc = 2 - real(pr) :: n(nc) real(pr) :: a(nc, nc), b(nc, nc), c(nc, nc) ! NRTL parameters @@ -26,16 +25,14 @@ program main type(Substance) :: sus(nc) - integer :: i, j - molecules(1)%groups_ids = [16] molecules(1)%number_of_groups = [1] molecules(2)%groups_ids = [1, 2, 14] molecules(2)%number_of_groups = [1, 1, 1] - forsus_dir = "./build/dependencies/forsus/data/json" + sus(1) = Substance("water") sus(2) = Substance("ethanol") @@ -46,50 +43,34 @@ program main a = 0; b = 0; c = 0 ! NRTL model parameters - a(1, 2) = 3.458 - a(2, 1) = -0.801 - - b(1, 2) = -586.1 - b(2, 1) = 246.2 - - c(1, 2) = 0.3 - c(2, 1) = 0.3 - + a(1, 2) = 3.458; a(2, 1) = -0.801 + b(1, 2) = -586.1; b(2, 1) = 246.2 + c(1, 2) = 0.3; c(2, 1) = 0.3 + ge_model = NRTL(a, b, c) - n = [0.2, 0.8] + + ! Moles vector n = [0.9, 0.1] - ! n = [0.8, 0.2] + ! Define the model to be SRK model = SoaveRedlichKwong(tc, pc, w) call phase_envel(1) - ! mixrule = MHV(ge_model, model%b) - ! mixrule%q = -0.593_pr - ! deallocate (model%mixrule) - ! model%mixrule = mixrule - ! call phase_envel(2) - - ! mixrule = MHV(ge_model, model%b) - ! mixrule%q = -0.593_pr - ! deallocate (model%mixrule) - ! model%mixrule = mixrule - ! call phase_envel(2) - - ! ge_model_unifac = setup_unifac(molecules) + mixrule = MHV(ge=ge_model, q=-0.593_pr, b=model%b) + + ! SoaveRedlichKwong uses by default QMR mixing rules. + ! We will change it to Huron-Vidal + deallocate(model%mixrule) + model%mixrule = mixrule + call phase_envel(2) + + ge_model_unifac = setup_unifac(molecules) - ! mixrule = MHV(ge_model_unifac, model%b) - ! mixrule%q = -0.593_pr - ! deallocate (model%mixrule) - ! model%mixrule = mixrule - ! call phase_envel(3) - - do i=1,99 - n(2) = real(i,pr)/100 - n(1) = 1 - n(2) - sat = saturation_pressure(model, n, T=473._pr, kind="bubble") - write (*, *) sat - end do + mixrule = MHV(ge=ge_model_unifac, q=-0.593_pr, b=model%b) + deallocate (model%mixrule) + model%mixrule = mixrule + call phase_envel(3) contains @@ -99,7 +80,7 @@ subroutine phase_envel(fu) type(EquilibriaState) :: sat type(PTEnvel2) :: env - sat = saturation_pressure(model, n, T=250._pr, kind="bubble", y0=[0.1_pr, 0.9_pr]) + sat = saturation_pressure(model, n, T=300._pr, kind="bubble") write (*, *) sat, sat%iters env = pt_envelope_2ph(model, n, sat, specified_variable_0=nc + 1, delta_0=0.001_pr) diff --git a/example/tutorials/new_alpha_function.f90 b/example/tutorials/new_alpha_function.f90 index 8ef43e024..c222936c9 100644 --- a/example/tutorials/new_alpha_function.f90 +++ b/example/tutorials/new_alpha_function.f90 @@ -45,7 +45,6 @@ end module alpha_mathias_copeman program new_alpha_example use yaeos__example_tools, only: methane_butane_pr76 - use yaeos, only: fugacity_vt, pressure use yaeos, only: pr, PengRobinson76, CubicEoS, QMR use alpha_mathias_copeman, only: MathiasCopeman type(CubicEoS) :: eos @@ -67,14 +66,14 @@ program new_alpha_example v = 2 t = 150 - call pressure(eos, n, V, T, P=P) + call eos%pressure(n, V, T, P=P) print *, "Peng-Robinson76:", P ! Replace the original alpha deallocate(eos%alpha) ! Remove the already defined alpha eos%alpha = alpha ! assign the new defined alpha - call pressure(eos, n, V, T, P=P) + call eos%pressure(n, V, T, P=P) print *, "Peng-Robinson76-MC:", P diff --git a/fpm.toml b/fpm.toml index 1a361a51b..d1906b24b 100644 --- a/fpm.toml +++ b/fpm.toml @@ -1,5 +1,5 @@ name = "yaeos" -version = "0.3.0" +version = "1.0.0" license = "MPL" author = "Federico E. Benelli" maintainer = "federico.benelli@mi.unc.edu.ar" @@ -17,22 +17,22 @@ library = true [fortran] implicit-typing = false -implicit-external = true +implicit-external = false source-form = "free" [dependencies] stdlib = "*" forbear = {git="https://github.com/szaghi/forbear"} json-fortran = {git="https://github.com/jacobwilliams/json-fortran"} +nlopt-f = {git="https://github.com/grimme-lab/nlopt-f"} forsus = {git="https://github.com/ipqa-research/forsus"} -nlopt-f.git = "https://github.com/grimme-lab/nlopt-f" +fortime = { git = "https://github.com/gha3mi/fortime.git" } [dev-dependencies] test-drive = {git = "https://github.com/fortran-lang/test-drive"} - [[example]] -name = "benchmarks" +name = "demo" source-dir = "example/extra" main = "demo.f90" @@ -61,4 +61,13 @@ name = "huron_vidal" source-dir = "example/tutorials" main = "huron_vidal.f90" +[[example]] +name = "pure_psat" +source-dir = "example/extra" +main = "pure_psat.f90" + +[[example]] +name = "cubic_eos" +source-dir = "example/tutorials" +main = "cubic_eos.f90" diff --git a/media/PTEnvel2.png b/media/PTEnvel2.png new file mode 100644 index 000000000..6c67366cb Binary files /dev/null and b/media/PTEnvel2.png differ diff --git a/python/MANIFEST.in b/python/MANIFEST.in new file mode 100644 index 000000000..ac5aca89d --- /dev/null +++ b/python/MANIFEST.in @@ -0,0 +1,19 @@ +include LICENCE +include README.md +include CONTRIBUTING.md +include requirements.txt +include pyproject.toml + +recursive-include yaeos *.py +include yaeos/compiled_module/*.so + +exclude tox.ini +exclude requirements-dev.txt +exclude _build +exclude __pycache__ +exclude compiled_flag + +recursive-exclude tmp_dir * +recursive-exclude dist * +recursive-exclude tests * +recursive-exclude docs * diff --git a/python/README.md b/python/README.md new file mode 100644 index 000000000..fb9682a6a --- /dev/null +++ b/python/README.md @@ -0,0 +1,36 @@ +# yaeos Python bindings +THIS IS A WIP SO THE API WILL DRASTRICALLY CHANGE WITH TIME + +Set of Python bindings to call `yaeos` functions and models. + +Editable instalation + +``` +cd python +pip install -e . +python setup.py build_fortran_editable +``` + +If you want to install on your environment instead + +``` +pip install . +``` + +To check if the instalation worked correctly: + +```python +from yaeos import PengRobinson76, QMR + +import numpy as np + +mr = QMR(np.zeros((2,2)), np.zeros((2,2))) + +model = PengRobinson76(np.array([320, 375]), np.array([30, 45]), np.array([0.0123, 0.045]), mr) + +model.fugacity(np.array([5.0, 4.0]), 2.0, 303.15) +``` + +``` +{'ln_phi': array([2.61640775, 2.49331419]), 'dt': None, 'dp': None, 'dn': None} +``` \ No newline at end of file diff --git a/python/docs/tutorials/tutorial.ipynb b/python/docs/tutorials/tutorial.ipynb new file mode 100644 index 000000000..f9945f998 --- /dev/null +++ b/python/docs/tutorials/tutorial.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "3a2bdbde-7f69-4b8f-ad42-4eb89c90167f", + "metadata": {}, + "outputs": [], + "source": [ + "import yaeos\n", + "from yaeos import PengRobinson76, QMR\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "85ff95ba-7a1a-4ca3-bec1-3c5bb50325ea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'ln_phi': array([-0.18662712, -0.16554916]),\n", + " 'dt': None,\n", + " 'dp': None,\n", + " 'dn': array([[-0.00186921, 0.00934604],\n", + " [ 0.00934604, -0.04673019]])}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Number of components, for easier definition\n", + "nc = 2\n", + "\n", + "# kij and lij matrices\n", + "k12 = 0.1\n", + "lij = kij = np.zeros((nc,nc))\n", + "kij[0,1] = kij[1,0] = k12\n", + "\n", + "mixrule = QMR(kij, lij)\n", + "\n", + "# Critical constants\n", + "Tc = [320, 375]\n", + "Pc = [30, 45]\n", + "w = [0.0123, 0.045]\n", + "\n", + "model = PengRobinson76(Tc, Pc, w, mixrule)\n", + "\n", + "\n", + "n = [1.0, 0.2]\n", + "model.fugacity(n, v=2.0, t=303.15, dn=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "cf0a8e95", + "metadata": {}, + "outputs": [], + "source": [ + "n = [0.4, 0.6]\n", + "Tc = [190.564, 425.12]\n", + "Pc = [45.99, 37.96]\n", + "w = [0.0115478, 0.200164]\n", + "\n", + "lij = kij = np.zeros((nc,nc))\n", + "mixrule = QMR(kij, lij)\n", + "model = PengRobinson76(Tc, Pc, w, mixrule)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5e06f2a9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 530 ms, sys: 0 ns, total: 530 ms\n", + "Wall time: 539 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "P, T = 60.0, 294.0\n", + "\n", + "ts = np.linspace(200, 400, 50)\n", + "ps = np.linspace(30, 100, 50)\n", + "betas = []\n", + "\n", + "t = []\n", + "p = []\n", + "\n", + "for T in ts:\n", + " for P in ps:\n", + " flash = model.flash_pt(n, P, T)\n", + " x = flash[\"x\"]\n", + " y = flash[\"y\"]\n", + " P = flash[\"P\"]\n", + " T = flash[\"T\"]\n", + " beta = flash[\"beta\"]\n", + " t.append(T)\n", + " p.append(P)\n", + " betas.append(beta)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7c42b4fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOy9d6AkSXXl/YvIzPJVr5637X33dE+PZ2A8wzgEg5G0rKRduRXSOu1qpdXCSsgjhKTlkxeLJBa0QqwsEkgCGawAMcB4zNie7mnfz9tymRnfH1kmqyozogYeTc9MHXjT71XdijgZFRlxM+LEvUIppeijjz766KOPPvq4hCC/2QT66KOPPvroo48+OtF3UProo48++uijj0sOfQeljz766KOPPvq45NB3UProo48++uijj0sOfQeljz766KOPPvq45NB3UProo48++uijj0sOfQeljz766KOPPvq45NB3UProo48++uijj0sO9jebwNcC3/c5c+YM+XweIcQ3m04fffTRRx999NEDlFKsrq4yNTWFlPo1kuelg3LmzBm2bNnyzabRRx999NFHH318DTh58iQzMzNam+elg5LP54HgAguFwjeZTR999NFHH3300QtWVlbYsmVLcx7X4XnpoDS2dQqFQt9B6aOPPvroo4/nGXqRZ/RFsn300UcfffTRxyWHvoPSRx999NFHH31ccug7KH300UcfffTRxyWHvoPSRx999NFHH31ccug7KH300UcfffTRxyWHvoPSRx999NFHH31ccug7KH300UcfffTRxyWHvoPSRx999NFHH31ccnheBmrr45uH9ZUNHvjHRyivV9h6cIa9V+3sCrhT8z0+N3uM+co6E+kC14xsxxLtvrBSiocWTnFibZ68k+KlY7tI205XfU+vzPLo0lkS0uIlo9sZSma7bM6XVvnC3Ak85XN0aIZtuaEum7Vahc9eOMaGW2VnfoTDg1ORvP/lwjPMV9YZT+e5bjSa94MLpzixtkDeSfKyHnhfN7Kd4VQ37wulVT5f53350DTbc8NfM+/PzT7DXHmdsVSO60Z3YMvo9j5e5/3SsZ1k7ERXfcdW5/jS4hksIbludDsjqVyXzWx5jc/PHsdTPocHp9mR7+a97lb57IWnWXer7MgNc2Rwuou36/vcN/sMs+VVRlP5WN6PLJ7i+No8WTvJ9WM7ydrJrvqe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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.scatter(t, p, c=betas)" + ] + }, + { + "cell_type": "markdown", + "id": "73924e0d", + "metadata": {}, + "source": [ + "## Modified Huron-Vidal MixingRule" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "a0a29755", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.62 s, sys: 0 ns, total: 3.62 s\n", + "Wall time: 3.63 s\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%time\n", + "from yaeos import NRTL, MHV, PengRobinson76, yaeos_c, QMR\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "nc = 2\n", + "tc = [647.14, 513.92]\n", + "pc = [220.64, 61.48]\n", + "w = [0.344, 0.649]\n", + "\n", + "a = [[0, 3.458], [-0.801, 0]]\n", + "b = [[0, -586.1], [246.2, 0]]\n", + "c = [[0, 0.3], [0.3, 0]]\n", + "\n", + "b = np.array(b)\n", + "\n", + "ge_model = NRTL(a, b, c)\n", + "mixrule = MHV(ge_model, q=-0.53)\n", + "\n", + "null_mixing = QMR(np.zeros((nc,nc)), np.zeros((nc,nc)))\n", + "\n", + "model_stock = PengRobinson76(tc, pc, w, null_mixing)\n", + "model_mhv = PengRobinson76(tc, pc, w, mixrule)\n", + "\n", + "colors = [\"red\", \"green\", \"blue\", \"orange\", \"black\"]\n", + "ts = np.linspace(50+273, 200+273, 9)\n", + "import time\n", + "for i, T in enumerate(ts):\n", + " i=4\n", + " xs = np.linspace(0.001, 0.999, 100)\n", + " ys = []\n", + " ps = []\n", + "\n", + " st = time.time()\n", + " \n", + " for x1 in xs:\n", + " x = [x1, 1-x1]\n", + " sat = model_mhv.saturation_pressure(x, T, \"bubble\")\n", + " p, y = sat[\"P\"], sat[\"y\"]\n", + " ps.append(p)\n", + " ys.append(y[0])\n", + "\n", + " plt.plot(xs, ps, color=colors[i])\n", + " plt.plot(ys, ps, color=colors[i])" + ] + }, + { + "cell_type": "markdown", + "id": "9ba9be74", + "metadata": {}, + "source": [ + "# Phase envelope tracing" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "bac65808", + "metadata": {}, + "outputs": [], + "source": [ + "import yaeos\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import chemicals\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "9de1de8b", + "metadata": {}, + "outputs": [], + "source": [ + "names = [\"methane\", \"n-decane\", \"water\", \"hexatriacontane\"]\n", + "chems = []\n", + "\n", + "Tc = []\n", + "Pc = []\n", + "w = []\n", + "for c in names:\n", + " chem = chemicals.CAS_from_any(c)\n", + " Tc.append(chemicals.Tc(chem))\n", + " Pc.append(chemicals.Pc(chem)/1e5)\n", + " w.append(chemicals.acentric.omega(chem))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "21c0ea1a", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "49e6c6e5908c42529dfdd26ca2572480", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "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", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure 11\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "z = np.ones(len(names))\n", + "z = z/z.sum()\n", + "\n", + "models = [\n", + " yaeos.PengRobinson76,\n", + " yaeos.PengRobinson78,\n", + " yaeos.SoaveRedlichKwong,\n", + "]\n", + "\n", + "for m in models:\n", + " model = m(Tc, Pc, w)\n", + " T, P, Tcs, Pcs = yaeos.yaeos_c.pt2_phase_envelope(model.id, z, kind=\"dew\", t0=150, p0=0.01)\n", + " plt.plot(T, P, label=model.name)\n", + " plt.scatter(Tcs, Pcs, label=model.name + \"-CP\")\n", + "\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "da909167", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import interact, fixed\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "61e58514", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3544535a0a484cc29759fd8a07a81145", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(Dropdown(description='i', options=(0, 1, 2, 3), value=0), FloatSlider(value=0.4901, desc…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f2291cda697b49cf8c127fff2371992d", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABkxElEQVR4nO3dd3wUdf7H8dfupvcCKUDoNXSpMSgogYBYAQvyU/A8PREUC4icHQvFfop6ZwFOQTwLiBxKE1ABAUF6l0AoKQjpZbNlfn8s7BkBRYEsYd7Px2MesDOzM5/ZGZ0335n5jsUwDAMRERERMQ2rrwsQERERkaqlACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMn6+LqA6c7vdHDp0iPDwcCwWi6/LERERkdNgGAZFRUXUqlULq9WcbWEKgGfg0KFDJCUl+boMERER+RP2799PnTp1fF2GTygAnoHw8HDAcwBFRET4uBoRERE5HYWFhSQlJXnP42akAHgGjl/2jYiIUAAUERGpZsx8+5Y5L3yLiIiImJgCoIiIiIjJKACKiIiImIzuARQRMQnDMHA6nbhcLl+XInJO2Ww2/Pz8TH2P3+9RABQRMYGKigqysrIoLS31dSkiVSIkJITExEQCAgJ8Xcp5SQFQROQC53a7ycjIwGazUatWLQICAtQyIhcswzCoqKjg8OHDZGRk0KRJE9N29vxbFABFRC5wFRUVuN1ukpKSCAkJ8XU5IudccHAw/v7+7Nu3j4qKCoKCgnxd0nlHkVhExCTUCiJmouP9t+nXERERETEZBUAREZFzbOnSpVgsFvLz8085z9SpU4mKiqqymsTcFABFROS8NXToUCwWCxaLhYCAABo3bsy4ceNwOp0+qcHf358GDRrw0EMPUV5eflbXc+ONN7Jz586zuswz9eSTT3q3/ZdDaGhopfny8/MZPnw4iYmJBAYG0rRpU+bNm+ejquV06CEQERE5r/Xp04cpU6Zgt9uZN28ew4cPx9/fn7Fjx1Z5DQ6Hg7Vr1zJkyBAsFgsTJ048a+sIDg4mODj4rC3vbBg1ahR33XVXpXE9e/akU6dO3s8VFRX06tWLuLg4PvnkE2rXrs2+ffvUmnmeUwugiIic1wIDA0lISKBevXoMGzaMtLQ05syZg91uZ9SoUdSuXZvQ0FC6dOnC0qVLvd87fkl1/vz5tGjRgrCwMPr06UNWVpZ3HqfTyb333ktUVBSxsbGMGTOGIUOGcO211560hqSkJK699lrS0tJYuHChd7rdbufee+8lLi6OoKAgunXrxpo1a07YluXLl9OmTRuCgoLo2rUrmzdvPqHe45588knatWvH+++/T/369YmMjOSmm26iqKjIO88nn3xC69atCQ4OJjY2lrS0NEpKSgBP9z/jxo2jTp06BAYG0q5dO7766ivvd/fu3YvFYuGzzz7jsssuIyQkhLZt27Jy5UrvPGFhYSQkJHiHnJwctm7dyu233+6d57333uPo0aPMnj2b1NRU6tevT/fu3Wnbtu1p7F3xFQVAERETMgyD0gqnTwbDMM6o9uDgYCoqKhgxYgQrV65k5syZbNy4keuvv54+ffqwa9cu77ylpaW88MILvP/++3zzzTdkZmYyatQo7/SJEycyffp0pkyZwvLlyyksLGT27Nm/uf7NmzezYsWKSh0MP/TQQ3z66adMmzaNdevW0bhxY9LT0zl69Gil744ePZoXX3yRNWvWULNmTa666iocDscp1/XTTz8xe/Zs5s6dy9y5c1m2bBkTJkwAICsri0GDBvGXv/yFbdu2sXTpUvr37+/9fV999VVefPFFXnjhBTZu3Eh6ejpXX311pd8H4JFHHmHUqFGsX7+epk2bMmjQoFNeYn/nnXdo2rQpl1xyiXfcnDlzSElJYfjw4cTHx9OqVSuee+45vXHmPKdLwCIiJlTmcJH8+HyfrHvruHRCAv746ccwDBYvXsz8+fMZNGgQU6ZMITMzk1q1agGey5VfffUVU6ZM4bnnngPA4XDw1ltv0ahRIwBGjBjBuHHjvMt87bXXGDt2LNdddx0Ar7/++knvXZs7dy5hYWE4nU7sdjtWq5XXX38dgJKSEt58802mTp1K3759AXj77bdZuHAh7777LqNHj/Yu54knnqBXr14ATJs2jTp16jBr1ixuuOGGk26z2+1m6tSphIeHA3DLLbewePFinn32WbKysnA6nfTv35969eoB0Lp1a+93X3jhBcaMGcNNN90EeMLukiVLeOWVV5g8ebJ3vlGjRtGvXz8AnnrqKVq2bMnu3btp3rx5pVrKy8uZPn06Dz/8cKXxe/bs4euvv2bw4MHMmzeP3bt3c/fdd+NwOHjiiSdOul3iewqAIiJyXjsevhwOB263m5tvvpmBAwcydepUmjZtWmleu91ObGys93NISIg3/AEkJiaSm5sLQEFBATk5OXTu3Nk73Waz0aFDB9xud6XlXnbZZbz55puUlJTw8ssv4+fnx4ABAwBPK53D4SA1NdU7v7+/P507d2bbtm2VlpOSkuL9e0xMDM2aNTthnl+qX7++N/z9uv62bdvSs2dPWrduTXp6Or1792bgwIFER0dTWFjIoUOHKtUEkJqayoYNGyqNa9OmTaXlA+Tm5p4QAGfNmkVRURFDhgypNN7tdhMXF8e//vUv7+938OBBnn/+eQXA85gCoIiICQX729g6Lt1n6/4jjoevgIAAatWqhZ+fHx999BE2m421a9dis1VeXlhYmPfv/v7+laZZLJY/dQk6NDSUxo0bA5573tq2bcu7775b6V64c+Fk9R8PpzabjYULF7JixQoWLFjAa6+9xiOPPMKqVasqheA/so7jrwj8dQAGz+XfK6+8kvj4+ErjExMT8ff3r7QfWrRoQXZ2NhUVFXoX73lK9wCKiJiQxWIhJMDPJ8MffQ/x8fBVt25d/Pw87Rbt27fH5XKRm5tL48aNKw0JCQmntdzIyEji4+MrPazhcrlYt27db37ParXy97//nUcffZSysjIaNWpEQEAAy5cv987jcDhYs2YNycnJlb77/fffe/+el5fHzp07adGixWnVezIWi4XU1FSeeuopfvzxRwICApg1axYRERHUqlWrUk3geQjl1zWdjoyMDJYsWXLSwJuamsru3bsrhcadO3eSmJio8HceUwAUEZFqp2nTpgwePJhbb72Vzz77jIyMDFavXs348eP573//e9rLueeeexg/fjyff/45O3bsYOTIkeTl5f1uSL3++uux2WxMnjyZ0NBQhg0bxujRo/nqq6/YunUrd9xxB6WlpScEpnHjxrF48WI2b97M0KFDqVGjxglPHJ+uVatW8dxzz/HDDz+QmZnJZ599xuHDh72BcvTo0UycOJGPPvqIHTt28PDDD7N+/XpGjhz5h9f13nvvkZiY6L3H8ZeGDRvG0aNHGTlyJDt37uS///0vzz33HMOHD/9T2yVVQ5eARUSkWpoyZQrPPPMMDz74IAcPHqRGjRp07dqVK6+88rSXMWbMGLKzs7n11lux2WzceeedpKenn3BZ+df8/PwYMWIEkyZNYtiwYUyYMAG3280tt9xCUVERHTt2ZP78+URHR1f63oQJExg5ciS7du2iXbt2fPHFF3+6lSwiIoJvvvmGV155hcLCQurVq8eLL77oDWn33nsvBQUFPPjgg+Tm5pKcnMycOXNo0qTJH1rP8QdRhg4detLfJSkpifnz53P//ffTpk0bateuzciRIxkzZsyf2i6pGhbjTJ/HN7HCwkIiIyMpKCggIiLC1+WIiJxUeXk5GRkZNGjQgKCgIF+Xc15zu920aNGCG264gaefftrX5cgZ+K3jXudvtQCKiIiJ7du3jwULFtC9e3fsdjuvv/46GRkZ3Hzzzb4uTeSc0j2AIiJiWlarlalTp9KpUydSU1PZtGkTixYtOqMHM0SqA7UAioiIaSUlJZ3wpKyIGagFUERERMRkFABFRERETKZaBsAnn3wSi8VSafjlK2vKy8sZPnw4sbGxhIWFMWDAAHJyciotIzMzk379+hESEkJcXByjR48+5cuvRURERC4k1fYewJYtW7Jo0SLv5+O9wwPcf//9/Pe//+Xjjz8mMjKSESNG0L9/f+99Hi6Xi379+pGQkMCKFSvIysri1ltvxd/f3/sCcREREZELVbUNgH5+fid93U9BQQHvvvsuM2bM4PLLLwc8nYW2aNGC77//nq5du7JgwQK2bt3KokWLiI+Pp127djz99NOMGTOGJ598Uq+uERERkQtatbwEDLBr1y5q1apFw4YNGTx4MJmZ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D3qfbn722Wf/1HZJ1bAYap/90woLC4mMjKSgoICIiAhflyMiclLl5eVkZGTQoEEDgoKCfF3Oec3tdtOiRQtuuOEGnn76aV+XI2fgt457nb/VAigiIia2b98+FixYQPfu3bHb7bz++utkZGRw8803+7o0kXNKD4GIiIhpWa1Wpk6dSqdOnUhNTWXTpk0sWrTojB7MEKkO1AIoIiKmlZSUdMKTsiJmoBZAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAERGR88TQoUN/993APXr04L777vN+rl+/Pq+88sppLX/q1KlERUX96frkwqEAKCIi57XDhw8zbNgw6tatS2BgIAkJCaSnp593/fdZLBbvEBERQadOnfj888/P+XrXrFnDnXfeedaW9+STT9KuXbtK47799luioqK477770BtkLwwKgCIicl4bMGAAP/74I9OmTWPnzp3MmTOHHj16cOTIEV+XdoIpU6aQlZXFDz/8QGpqKgMHDmTTpk3ndJ01a9YkJCTknC3/v//9L+np6TzwwAO88sorWCyWc7YuqToKgCIict7Kz8/n22+/ZeLEiVx22WXUq1ePzp07M3bsWK6++moAMjMzueaaawgLCyMiIoIbbriBnJwc7zJ++uknrrnmGuLj4wkLC6NTp04sWrTIO/3vf/87Xbp0OWHdbdu2Zdy4cd7P77zzDi1atCAoKIjmzZvzxhtvnPCdqKgoEhISaNq0KU8//TROp5MlS5Z4p+/fv58bbriBqKgoYmJiuOaaa9i7d+8pt7+kpIRbb72VsLAwEhMTefHFF0+Y59eXgPPz8/nb3/5GfHw8QUFBtGrVirlz51b6zvz582nRogVhYWH06dOHrKysk65/xowZ9O/fn0mTJvH4448DsHnzZqxWK4cPHwbg6NGjWK1WbrrpJu/3nnnmGbp16+b9vGzZMjp37kxgYCCJiYk8/PDDOJ1O7/QePXpw77338tBDDxETE0NCQgJPPvlkpVq2b99Ot27dCAoKIjk5mUWLFmGxWJg9e/Ypfz85NQVAERETMgyDUkepT4Y/cgkxLCyMsLAwZs+ejd1uP2G62+3mmmuu4ejRoyxbtoyFCxeyZ88ebrzxRu88xcXFXHHFFSxevJgff/yRPn36cNVVV5GZmQnA4MGDWb16NT/99JP3O1u2bGHjxo3cfPPNAEyfPp3HH3+cZ599lm3btvHcc8/x2GOPMW3atJPW7XQ6effddwEICAgAwOFwkJ6eTnh4ON9++y3Lly/3BrCKioqTLmf06NEsW7aMzz//nAULFrB06VLWrVt3yt/L7XbTt29fli9fzgcffMDWrVuZMGECNpvNO09paSkvvPAC77//Pt988w2ZmZmMGjXqhGVNnjyZ2267jffee48RI0Z4x7ds2ZLY2FiWLVsGeC4P//IzeAJfjx49ADh48CBXXHEFnTp1YsOGDbz55pu8++67PPPMM5XWN23aNEJDQ1m1ahWTJk1i3LhxLFy4EACXy8W1115LSEgIq1at4l//+hePPPLIKX8H+X16F7CIiAmVOcvoMuPEVq+qsOrmVYT4n94lSz8/P6ZOncodd9zBW2+9xUUXXUT37t256aabaNOmDYsXL2bTpk1kZGSQlJQEwL///W9atmzJmjVr6NSpE23btqVt27beZT799NPMmjWLOXPmMGLECFq2bEnbtm2ZMWMGjz32GOAJfF26dKFx48YAPPHEE7z44ov0798fgAYNGrB161b++c9/MmTIEO+yBw0ahM1mo6ysDLfbTf369bnhhhsA+Oijj3C73bzzzjvey6hTpkwhKiqKpUuX0rt370rbXlxczLvvvssHH3xAz549AU9IqlOnzil/r0WLFrF69Wq2bdtG06ZNAWjYsGGleRwOB2+99RaNGjUCYMSIEZVaOgG2bdvGiBEjePfddxk8eHClaRaLhUsvvZSlS5cycOBAli5dym233cY777zD9u3badSoEStWrOChhx4C4I033iApKYnXX38di8VC8+bNOXToEGPGjOHxxx/HavW0RbVp04YnnngCgCZNmvD666+zePFievXqxcKFC/npp59YunQpCQkJADz77LP06tXrlL+F/Da1AIqIyHltwIABHDp0iDlz5tCnTx+WLl3KRRddxNSpU9m2bRtJSUne8AeQnJxMVFQU27ZtAzxBatSoUbRo0YKoqCjCwsLYtm2btwUQPK2AM2bMADytox9++KE3+JSUlPDTTz9x++23e1skw8LCeOaZZyq1GgK8/PLLrF+/ni+//JLk5GTeeecdYmJiANiwYQO7d+8mPDzcu4yYmBjKy8tPWA54Ll1XVFRUujwdExNDs2bNTvlbrV+/njp16njD38mEhIR4wx9AYmIiubm5leapU6cOF110Ec8///xJLw93796dpUuXAp7Wvssvv9wbCtesWYPD4SA1NRXwhMmUlJRK9w6mpqZSXFzMgQMHvOPatGlTaR2/rGvHjh0kJSV5wx9A586dT7mN8vvUAigiYkLBfsGsunmVz9b9RwUFBdGrVy969erFY489xl//+leeeOIJHnzwwd/97qhRo1i4cCEvvPACjRs3Jjg4mIEDB1a67Dpo0CDGjBnDunXrKCsrY//+/d7LyMXFxQC8/fbbJ9wr+MtLqwAJCQk0btyYxo0bM2XKFK644gq2bt1KXFwcxcXFdOjQgenTp59QY82aNf/wb3IywcG//9v6+/tX+myxWE64LB8eHs6iRYvo1asXl112GUuWLCExMdE7/XhXNLt27WLr1q1069aN7du3s3TpUvLy8ujYseMffjDlZHW53e4/tAw5fQqAIiImZLFYTvsy7PkoOTmZ2bNn06JFC/bv38/+/fu9rYBbt24lPz+f5ORkAJYvX87QoUO57rrrAE+g+/WDF3Xq1KF79+5Mnz6dsrIyevXqRVxcHADx8fHUqlWLPXv2nHA59Ld07tyZDh068Oyzz/Lqq69y0UUX8dFHHxEXF0dERMTvfr9Ro0b4+/uzatUq6tatC0BeXh47d+6ke/fuJ/1OmzZtOHDgADt37vzNVsDTER0dzaJFi+jduzc9evRgyZIl1KpVC4DWrVsTHR3NM888Q7t27QgLC6NHjx5MnDiRvLw87/1/AC1atODTTz/FMAxvK+Dy5csJDw//zcvZv9SsWTP2799PTk4O8fHxgKf7G/nzdAlYRETOW0eOHOHyyy/ngw8+YOPGjWRkZPDxxx8zadIkrrnmGtLS0mjdujWDBw9m3bp1rF69mltvvZXu3bvTsWNHwHM/2Weffcb69evZsGEDN99880lblgYPHszMmTP5+OOPTwh6Tz31FOPHj+cf//gHO3fuZNOmTUyZMoWXXnrpN+u/7777+Oc//8nBgwcZPHgwNWrU4JprruHbb78lIyODpUuXcu+991a6FHpcWFgYt99+O6NHj+brr79m8+bNDB061HvP3Ml0796dSy+9lAEDBrBw4UIyMjL48ssv+eqrr07n5z5BVFQUCxcuJDo6mh49enDo0CHgf/cBTp8+3Rv22rRpg91uZ/HixZUC6t13383+/fu555572L59O59//jlPPPEEDzzwwG9uyy/16tWLRo0aMWTIEDZu3Mjy5ct59NFHvbXIH6cAKCIi562wsDC6dOnCyy+/zKWXXkqrVq147LHHuOOOO7wPFXz++edER0dz6aWXkpaWRsOGDfnoo4+8y3jppZeIjo7m4osv5qqrriI9PZ2LLrrohHUNHDiQI0eOUFpaesLbOP7617/yzjvvMGXKFFq3bk337t2ZOnUqDRo0+M36+/TpQ4MGDXj22WcJCQnhm2++oW7duvTv358WLVpw++23U15efsoWweeff55LLrmEq666irS0NLp160aHDh1+c52ffvopnTp1YtCgQSQnJ/PQQw/hcrl+8zu/JTIykgULFlCjRg26d+/OwYMHAU/YdLlc3gBotVq59NJLsVgs3vv/AGrXrs28efNYvXo1bdu25a677uL222/3BrjTYbPZmD17NsXFxXTq1Im//vWv3qeAg4KC/vS2mZnFUJfef1phYSGRkZEUFBScVnO+iIgvlJeXk5GRQYMGDXSylAvG8uXL6datG7t37670UMtxv3Xc6/ytewBFRESkGpg1axZhYWE0adKE3bt3M3LkSFJTU08a/uT3KQCKiIjIea+oqIgxY8aQmZlJjRo1SEtLO+mbUeT0KACKiIjIee/WW2/l1ltv9XUZFww9BCIiIiJiMgqAIiIiIiajACgiYhLq9EHMRMf7b1MAFBG5wB1/xVZpaamPKxGpOseP91+/Yk489BCIiMgFzmazERUVRW5uLgAhISF6e4JcsAzDoLS0lNzcXKKiok54X7N4KACKiJhAQkICgDcEilzooqKivMe9nEgBUETEBCwWC4mJicTFxeFwOHxdjsg55e/vr5a/36EAKCJiIjabTSdGEdFDICIiIiJmowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImowAoIiIiYjIKgCIiIiImc0EEwAkTJmCxWLjvvvu848rLyxk+fDixsbGEhYUxYMAAcnJyKn0vMzOTfv36ERISQlxcHKNHj8bpdFZx9SIiIiJVq9oHwDVr1vDPf/6TNm3aVBp///3388UXX/Dxxx+zbNkyDh06RP/+/b3TXS4X/fr1o6KighUrVjBt2jSmTp3K448/XtWbICIiIlKlqnUALC4uZvDgwbz99ttER0d7xxcUFPDuu+/y0ksvcfnll9OhQwemTJnCihUr+P777wFYsGABW7du5YMPPqBdu3b07duXp59+msmTJ1NRUeGrTRIRERE556p1ABw+fDj9+vUjLS2t0vi1a9ficDgqjW/evDl169Zl5cqVAKxcuZLWrVsTHx/vnSc9PZ3CwkK2bNly0vXZ7XYKCwsrDSIiIiLVjZ+vC/izZs6cybp161izZs0J07KzswkICCAqKqrS+Pj4eLKzs73z/DL8HZ9+fNrJjB8/nqeeeuosVC8iIiLiO9WyBXD//v2MHDmS6dOnExQUVGXrHTt2LAUFBd5h//79VbZuERERkbOlWgbAtWvXkpuby0UXXYSfnx9+fn4sW7aMf/zjH/j5+REfH09FRQX5+fmVvpeTk0NCQgIACQkJJzwVfPzz8Xl+LTAwkIiIiEqDiIiISHVTLQNgz5492bRpE+vXr/cOHTt2ZPDgwd6/+/v7s3jxYu93duzYQWZmJikpKQCkpKSwadMmcnNzvfMsXLiQiIgIkpOTq3ybRERERKpKtbwHMDw8nFatWlUaFxoaSmxsrHf87bffzgMPPEBMTAwRERHcc889pKSk0LVrVwB69+5NcnIyt9xyC5MmTSI7O5tHH32U4cOHExgYWOXbJCIiIlJVqmUAPB0vv/wyVquVAQMGYLfbSU9P54033vBOt9lszJ07l2HDhpGSkkJoaChDhgxh3LhxPqxaRERE5NyzGIZh+LqI6qqwsJDIyEgKCgp0P6CIiEg1ofN3Nb0HUERERET+PAVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZOplgHwzTffpE2bNkRERBAREUFKSgpffvmld3p5eTnDhw8nNjaWsLAwBgwYQE5OTqVlZGZm0q9fP0JCQoiLi2P06NE4nc6q3hQRERGRKlctA2CdOnWYMGECa9eu5YcffuDyyy/nmmuuYcuWLQDcf//9fPHFF3z88ccsW7aMQ4cO0b9/f+/3XS4X/fr1o6KighUrVjBt2jSmTp3K448/7qtNEhEREakyFsMwDF8XcTbExMTw/PPPM3DgQGrWrMmMGTMYOHAgANu3b6dFixasXLmSrl278uWXX3LllVdy6NAh4uPjAXjrrbcYM2YMhw8fJiAg4LTWWVhYSGRkJAUFBURERJyzbRMREZGzR+fvatoC+Esul4uZM2dSUlJCSkoKa9euxeFwkJaW5p2nefPm1K1bl5UrVwKwcuVKWrdu7Q1/AOnp6RQWFnpbEUVEREQuVH6+LuDP2rRpEykpKZSXlxMWFsasWbNITk5m/fr1BAQEEBUVVWn++Ph4srOzAcjOzq4U/o5PPz7tVOx2O3a73fu5sLDwLG2NiIiISNWpti2AzZo1Y/369axatYphw4YxZMgQtm7dek7XOX78eCIjI71DUlLSOV2fiIiIyLlQbQNgQEAAjRs3pkOHDowfP562bdvy6quvkpCQQEVFBfn5+ZXmz8nJISEhAYCEhIQTngo+/vn4PCczduxYCgoKvMP+/fvP7kaJiIiIVIFqGwB/ze12Y7fb6dChA/7+/ixevNg7bceOHWRmZpKSkgJASkoKmzZtIjc31zvPwoULiYiIIDk5+ZTrCAwM9HY9c3wQERERqW6q5T2AY8eOpW/fvtStW5eioiJmzJjB0qVLmT9/PpGRkdx+++088MADxMTEEBERwT333ENKSgpdu3YFoHfv3iQnJ3PLLbcwadIksrOzefTRRxk+fDiBgYE+3joRERGRc6taBsDc3FxuvfVWsrKyiIyMpE2bNsyfP59evXoB8PLLL2O1WhkwYAB2u5309HTeeOMN7/dtNhtz585l2LBhpKSkEBoaypAhQxg3bpyvNklERESkylww/QD6gvoREhERqX50/r6A7gEUERERkdOjACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMgqAIiIiIiajACgiIiJiMtUyAI4fP55OnToRHh5OXFwc1157LTt27Kg0T3l5OcOHDyc2NpawsDAGDBhATk5OpXkyMzPp168fISEhxMXFMXr0aJxOZ1VuioiIiEiVq5YBcNmyZQwfPpzvv/+ehQsX4nA46N27NyUlJd557r//fr744gs+/vhjli1bxqFDh+jfv793usvlol+/flRUVLBixQqmTZvG1KlTefzxx32xSSIiIiJVxmIYhuHrIs7U4cOHiYuLY9myZVx66aUUFBRQs2ZNZsyYwcCBAwHYvn07LVq0YOXKlXTt2pUvv/ySK6+8kkOHDhEfHw/AW2+9xZgxYzh8+DABAQG/u97CwkIiIyMpKCggIiLinG6jiIiInB06f1fTFsBfKygoACAmJgaAtWvX4nA4SEtL887TvHlz6taty8qVKwFYuXIlrVu39oY/gPT0dAoLC9myZUsVVi8iIiJStfx8XcCZcrvd3HfffaSmptKqVSsAsrOzCQgIICoqqtK88fHxZGdne+f5Zfg7Pv34tJOx2+3Y7Xbv58LCwrO1GSIiIiJVptq3AA4fPpzNmzczc+bMc76u8ePHExkZ6R2SkpLO+TpFREREzrZqHQBHjBjB3LlzWbJkCXXq1PGOT0hIoKKigvz8/Erz5+TkkJCQ4J3n108FH/98fJ5fGzt2LAUFBd5h//79Z3FrRERERKpGtQyAhmEwYsQIZs2axddff02DBg0qTe/QoQP+/v4sXrzYO27Hjh1kZmaSkpICQEpKCps2bSI3N9c7z8KFC4mIiCA5Ofmk6w0MDCQiIqLSICIiIlLdVMt7AIcPH86MGTP4/PPPCQ8P996zFxkZSXBwMJGRkdx+++088MADxMTEEBERwT333ENKSgpdu3YFoHfv3iQnJ3PLLbcwadIksrOzefTRRxk+fDiBgYG+3DwRERGRc6padgNjsVhOOn7KlCkMHToU8HQE/eCDD/Lhhx9it9tJT0/njTfeqHR5d9++fQwbNoylS5cSGhrKkCFDmDBhAn5+p5eL9Ri5iIhI9aPzdzUNgOcLHUAiIiLVj87f1fQeQBERERH58xQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARURERExGAVBERETEZBQARUREREzGz9cFiIhUK4YBFSVQchhKfgZ7AdiLoaIY7EXH/n7sT1cFuF3gdoDbeWxweQar7djgB1b/Y3/awD8YAsIgMAwCwiEw/NjfwyA4GkJrQmgN8Av09S8hItWYAqCIyHEuJxRlQcEBKNjvGfL3e8aVHPYMxYfBWebrSiEw0hMEQ2tCWE2IqANRdSEqCSKTPH8PjgaLxdeVish5SAFQRMzF7YbCg3BkF/y8+9ifu+DIT57xhuv0luMX7AlfQZGVW+kCwyAwAgJCPa10Vr+TDLZjLYHOyoPLAc5y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vB9AERERETMy7T2AIiIiImalACgiIiJiMgqAIiIiIiajACgiIiJiMgqAf9LkyZOpX78+QUFBdOnShdWrV/u6pAvO+PHj6dSpE+Hh4cTFxXHttdeyY8eOSvOUl5czfPhwYmNjCQsLY8CAASd07p2ZmUm/fv0ICQkhLi6O0aNH43Q6q3JTLjgTJkzAYrFw3333ecdpX1SdgwcP8n//93/ExsYSHBxM69at+eGHH7zTDcPg8ccfJzExkeDgYNLS0ti1a1elZRw9epTBgwcTERFBVFQUt99+O8XFxVW9KdWey+Xiscceo0GDBgQHB9OoUSOefvrpSu+Y1f44N7755huuuuoqatWqhcViYfbs2ZWmn63ffePGjVxyySUEBQWRlJTEpEmTzvWmVQ1D/rCZM2caAQEBxnvvvWds2bLFuOOOO4yoqCgjJyfH16VdUNLT040pU6YYmzdvNtavX29cccUVRt26dY3i4mLvPHfddZeRlJRkLF682Pjhhx+Mrl27GhdffLF3utPpNFq1amWkpaUZP/74ozFv3jyjRo0axtixY32xSReE1atXG/Xr1zfatGljjBw50jte+6JqHD161KhXr54xdOhQY9WqVcaePXuM+fPnG7t37/bOM2HCBCMyMtKYPXu2sWHDBuPqq682GjRoYJSVlXnn6dOnj9G2bVvj+++/N7799lujcePGxqBBg3yxSdXas88+a8TGxhpz5841MjIyjI8//tgICwszXn31Ve882h/nxrx584xHHnnE+OyzzwzAmDVrVqXpZ+N3LygoMOLj443BgwcbmzdvNj788EMjODjY+Oc//1lVm3nOKAD+CZ07dzaGDx/u/exyuYxatWoZ48eP92FVF77c3FwDMJYtW2YYhmHk5+cb/v7+xscff+ydZ9u2bQZgrFy50jAMz/8grFarkZ2d7Z3nzTffNCIiIgy73V61G3ABKCoqMpo0aWIsXLjQ6N69uzcAal9UnTFjxhjdunU75XS3220kJCQYzz//vHdcfn6+ERgYaHz44YeGYRjG1q1bDcBYs2aNd54vv/zSsFgsxsGDB89d8Regfv36GX/5y18qjevfv78xePBgwzC0P6rKrwPg2frd33jjDSM6OrrS/6PGjBljNGvW7Bxv0bmnS8B/UEVFBWvXriUtLc07zmq1kpaWxsqVK31Y2YWvoKAAwPvy7rVr1+JwOCrti+bNm1O3bl3vvli5ciWtW7eu1Ll3eno6hYWFbNmypQqrvzAMHz6cfv36VfrNQfuiKs2ZM4eOHTty/fXXExcXR/v27Xn77be90zMyMsjOzq60LyIjI+nSpUulfREVFUXHjh2986SlpWG1Wlm1alXVbcwF4OKLL2bx4sXs3LkTgA0bNvDdd9/Rt29fQPvDV87W775y5UouvfRSAgICvPOkp6ezY8cO8vLyqmhrzg1Tvwnkz/j5559xuVwnvC0kPj6e7du3+6iqC5/b7ea+++4jNTWVVq1aAZCdnU1AQABRUVGV5o2Pjyc7O9s7z8n21fFpcvpmzpzJunXrWLNmzQnTtC+qzp49e3jzzTd54IEH+Pvf/86aNWu49957CQgIYMiQId7f8mS/9S/3RVxcXKXpfn5+xMTEaF/8QQ8//DCFhYU0b94cm82Gy+Xi2WefZfDgwQDaHz5ytn737OxsGjRocMIyjk+Ljo4+J/VXBQVAqRaGDx/O5s2b+e6773xdiint37+fkSNHsnDhQoKCgnxdjqm53W46duzIc889B0D79u3ZvHkzb731FkOGDPFxdebzn//8h+nTpzNjxgxatmzJ+vXrue+++6hVq5b2h5zXdAn4D6pRowY2m+2EpxtzcnJISEjwUVUXthEjRjB37lyWLFlCnTp1vOMTEhKoqKggPz+/0vy/3BcJCQkn3VfHp8npWbt2Lbm5uVx00UX4+fnh5+fHsmXL+Mc//oGfnx/x8fHaF1UkMTGR5OTkSuNatGhBZmYm8L/f8rf+H5WQkEBubm6l6U6nk6NHj2pf/EGjR4/m4Ycf5qabbqJ169bccsst3H///YwfPx7Q/vCVs/W7X8j/31IA/IMCAgLo0KEDixcv9o5zu90sXryYlJQUH1Z24TEMgxEjRjBr1iy+/vrrE5rhO3TogL+/f6V9sWPHDjIzM737IiUlhU2bNlX6j3zhwoVERESccBKVU+vZsyebNm1i/fr13qFjx44MHjzY+3fti6qRmpp6QndIO3fupF69egA0aNCAhISESvuisLCQVatWVdoX+fn5rF271jvP119/jdvtpkuXLlWwFReO0tJSrNbKp1KbzYbb7Qa0P3zlbP3uKSkpfPPNNzgcDu88CxcupFmzZtX68i+gbmD+jJkzZxqBgYHG1KlTja1btxp33nmnERUVVenpRjlzw4YNMyIjI42lS5caWVlZ3qG0tNQ7z1133WXUrVvX+Prrr40ffvjBSElJMVJSUrzTj3c90rt3b2P9+vXGV199ZdSsWVNdj5wFv3wK2DC0L6rK6tWrDT8/P+PZZ581du3aZUyfPt0ICQkxPvjgA+88EyZMMKKioozPP//c2Lhxo3HNNdectPuL9u3bG6tWrTK+++47o0mTJup25E8YMmSIUbt2bW83MJ999plRo0YN46GHHvLOo/1xbhQVFRk//vij8eOPPxqA8dJLLxk//vijsW/fPsMwzs7vnp+fb8THxxu33HKLsXnzZmPmzJlGSEiIuoExs9dee82oW7euERAQYHTu3Nn4/vvvfV3SBQc46TBlyhTvPGVlZcbdd99tREdHGyEhIcZ1111nZGVlVVrO3r17jb59+xrBwcFGjRo1jAcffNBwOBxVvDUXnl8HQO2LqvPFF18YrVq1MgIDA43mzZsb//rXvypNd7vdxmOPPWbEx8cbgYGBRs+ePY0dO3ZUmufIkSPGoEGDjLCwMCMiIsK47bbbjKKioqrcjAtCYWGhMXLkSKNu3bpGUFCQ0bBhQ+ORRx6p1G2I9se5sWTJkpOeI4YMGWIYxtn73Tds2GB069bNCAwMNGrXrm1MmDChqjbxnLIYxi+6KxcRERGRC57uARQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExGQVAEREREZNRABQRERExmf8HezbYB5otwKgAAAAASUVORK5CYII=", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib widget\n", + "x = np.linspace(-10, 10,100)\n", + "\n", + "def f(x, A, B, C):\n", + " return A*x**2 + B*x + C\n", + "\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(1, 1, 1)\n", + "line, = ax.plot(x, f(x, A=1, B=1, C=1))\n", + "\n", + "\n", + "def run(i, x, n):\n", + " z = np.ones(n)\n", + " z[i] = x\n", + " exclude = [i]\n", + " mask = np.ones(z.shape, bool)\n", + " mask[exclude] = False\n", + " z[mask] = (1 - x)/2\n", + " \n", + " z = z/sum(z)\n", + " print(z)\n", + "\n", + " models = [\n", + " yaeos.PengRobinson76,\n", + " yaeos.PengRobinson78,\n", + " yaeos.SoaveRedlichKwong,\n", + " ]\n", + "\n", + " ax.clear()\n", + " for m in models:\n", + " model = m(Tc, Pc, w)\n", + " T, P, Tcs, Pcs = yaeos.yaeos_c.pt2_phase_envelope(model.id, z, kind=\"dew\", t0=150, p0=0.01)\n", + " ax.plot(T, P, label=model.name)\n", + " plt.legend()\n", + " \n", + " ax.set_xlim(0, 1000)\n", + " ax.set_ylim(0, 550)\n", + " return T, P\n", + "\n", + "def update(i, x, n):\n", + " T, P = run(i, x, n)\n", + " #line.set_xdata(T)\n", + " #line.set_ydata(P)\n", + " #fig.canvas.draw_idle()\n", + "\n", + "interact(update, i=[i for i in range(len(Tc))], x=(0.0001, 0.9999, 0.01), n=fixed(len(Tc)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a15f127d-d055-4c96-92bb-baf643afe24b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/pyproject.toml b/python/pyproject.toml new file mode 100644 index 000000000..185668349 --- /dev/null +++ b/python/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = ["fpm", "meson", "ninja", "numpy", "setuptools", "wheel"] + + +[tool.black] +line-length = 79 +target-version = ["py310"] + + +[tool.pytest.ini_options] +markers = [ + "marker_name: marker_description", +] \ No newline at end of file diff --git a/python/requirements-dev.txt b/python/requirements-dev.txt new file mode 100644 index 000000000..dcd196456 --- /dev/null +++ b/python/requirements-dev.txt @@ -0,0 +1,29 @@ +# Style +flake8-nb +flake8-black +flake8-builtins +flake8-import-order +pep8-naming +pydocstyle + +# documentation (also pandoc must be installed) +nbsphinx +sphinx +sphinx_copybutton +sphinx_rtd_theme +sphinxcontrib.bibtex + +# Testing +check-manifest +pytest +pytest-cov +tox + +# General purpose +ipdb +ipython +jupyter +matplotlib + +# Build +build diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 000000000..fe320a738 --- /dev/null +++ b/python/setup.py @@ -0,0 +1,241 @@ +import shutil +import subprocess +from pathlib import Path + +from setuptools import Command, setup +from setuptools.command.editable_wheel import editable_wheel +from setuptools.command.egg_info import egg_info + + +# ============================================================================= +# Directories and constants +# ============================================================================= +THIS_DIR = Path(__file__).parent +BUILD_DIR = (THIS_DIR.parent / "build" / "python").absolute() +LINK_DIR = BUILD_DIR / "lib" +INCL_DIR = BUILD_DIR / "include" +COMPILED_FLAG = THIS_DIR / "compiled_flag" + +FFLAGS = "-g -fPIC -funroll-loops -fstack-arrays -Ofast -frepack-arrays -faggressive-function-elimination -fopenmp" # noqa +CFLAGS = "-fPIC" + + +# ============================================================================= +# Usefull functions +# ============================================================================= +def pre_build(): + """Execute fpm and f2py compilations commands.""" + print(THIS_DIR) + + if COMPILED_FLAG.exists(): + return + + subprocess.check_call( + [ + "fpm", + "install", + "--profile", + "release", + "--flag", + f"{FFLAGS}", + "--c-flag", + f"{CFLAGS}", + "--prefix", + BUILD_DIR, + ] + ) + + subprocess.check_call( + [ + "f2py", + "-m", + "yaeos_compiled", + f"-L{LINK_DIR}", + f"-I{INCL_DIR}", + "-c", + "yaeos/fortran_wrap/yaeos_c.f90", + "-lyaeos", "-llapack", + "--backend", + "meson", + ] + ) + + COMPILED_FLAG.touch() + + +def initial_compiled_clean(): + """Erase all compiled files from development directory""" + # Clear fpm build + if BUILD_DIR.exists(): + shutil.rmtree(BUILD_DIR) + + # Clear compiled files on compiled_files + compiled_module_dir = THIS_DIR / "yaeos" / "compiled_module" + + if compiled_module_dir.exists(): + for so_file in compiled_module_dir.glob("*.so"): + so_file.unlink() + + # Additionally, clear any .so files in the root directory if present + for so_file in THIS_DIR.glob("yaeos_compiled*.so"): + so_file.unlink() + + +def final_build_clean(): + """Clean the build of setuptools.""" + + if (THIS_DIR / "build").exists(): + print((THIS_DIR / "build").absolute()) + shutil.rmtree(THIS_DIR / "build") + + # Clear compiled files on compiled_files + compiled_module_dir = THIS_DIR / "yaeos" / "compiled_module" + + if compiled_module_dir.exists(): + for so_file in compiled_module_dir.glob("*.so"): + so_file.unlink() + + # Clean COMPILED_FLAG + if COMPILED_FLAG.exists(): + COMPILED_FLAG.unlink() + + +def move_compiled_to_editable_loc(): + """Move compiled files to 'compiled_module' directory""" + + for file in THIS_DIR.glob("yaeos_compiled.*"): + target_dir = THIS_DIR / "yaeos" / "compiled_module" + target_dir.mkdir(parents=True, exist_ok=True) + + shutil.move(file.absolute(), (target_dir / file.name).absolute()) + + +def save_editable_compiled(): + """Temporaly save the editable compiled from install and sdist commands""" + tmp_dir = THIS_DIR / "tmp_editable" + + if not tmp_dir.exists(): + tmp_dir.mkdir() + + compiled_module_dir = THIS_DIR / "yaeos" / "compiled_module" + + if compiled_module_dir.exists(): + for so_file in compiled_module_dir.glob("*.so"): + if ((tmp_dir / so_file.name).absolute()).exists(): + ((tmp_dir / so_file.name).absolute()).unlink() + + shutil.move( + so_file.absolute(), (tmp_dir / so_file.name).absolute() + ) + + +def restore_save_editable_compiled(): + tmp_dir = THIS_DIR / "tmp_editable" + + compiled_module_dir = THIS_DIR / "yaeos" / "compiled_module" + + if tmp_dir.exists(): + for so_file in tmp_dir.glob("*.so"): + shutil.move( + so_file.absolute(), + (compiled_module_dir / so_file.name).absolute(), + ) + + tmp_dir.rmdir() + + +# ============================================================================= +# Build command +# ============================================================================= +class BuildFortran(Command): + description = "Compile Fortran library with fpm and f2py" + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + dir = str(THIS_DIR.absolute()) + + if ("build" in dir) or ("check-manifest" in dir): + # Do not compile, we are building, the compilation has been already + # done at this point. + ... + else: + pre_build() + + +# ============================================================================= +# - Building for developers (editable installation) +# pip install -e . +# ============================================================================= +class CustomEditable(editable_wheel): + def run(self): + self.run_command("build_fortran") + move_compiled_to_editable_loc() + save_editable_compiled() + + # Run base editable_wheel run method + super().run() + + +# ============================================================================= +# - Custom egg_info command +# ============================================================================= +class CustomEgg(egg_info): + def run(self): + self.run_command("build_fortran") + move_compiled_to_editable_loc() + super().run() + + +# ============================================================================= +# Call setup +# ============================================================================= +name = "yaeos" +version = "0.3.0" +author = "Federico E. Benelli" +author_email = "federico.benelli@mi.unc.edu.ar" +maintainer = "Federico E. Benelli" +maintainer_email = "federico.benelli@mi.unc.edu.ar" +lic = "MPL" + + +save_editable_compiled() + +initial_compiled_clean() + +setup( + name=name, + version=version, + author=author, + author_email=author_email, + maintainer=maintainer, + maintainer_email=maintainer_email, + description="", + license=lic, + keywords="thermodynamics equation-of-state", + url="https://github.com/ipqa-research/yaeos", + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research/Engineering", + "Topic :: Thermodynamics", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + ], + install_requires=["numpy"], + cmdclass={ + "build_fortran": BuildFortran, + "editable_wheel": CustomEditable, + "egg_info": CustomEgg + }, + packages=["yaeos"], + package_data={"yaeos": ["compiled_module/*.so"]}, + include_package_data=True, +) + +final_build_clean() + +restore_save_editable_compiled() diff --git a/python/tests/__init__.py b/python/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/python/tests/test_dummy.py b/python/tests/test_dummy.py new file mode 100644 index 000000000..1e297f87d --- /dev/null +++ b/python/tests/test_dummy.py @@ -0,0 +1,48 @@ +import numpy as np +import numpy.testing as npt + +from yaeos import SoaveRedlichKwong, PengRobinson76, QMR + + +def test_dummy(): + mr = QMR(np.zeros((2, 2)), np.zeros((2, 2))) + + model = PengRobinson76( + np.array([300, 350]), np.array([30, 40]), np.array([0.152, 0.325]), mr + ) + + fug = model.fugacity(np.array([5, 6]), 2.0, 303.15)["ln_phi"] + + assert np.allclose(fug, np.array([0.65960035, 0.30581106])) + + +def test_flash(): + nc = 2 + n = [0.4, 0.6] + Tc = [190.564, 425.12] + Pc = [45.99, 37.96] + w = [0.0115478, 0.200164] + + lij = kij = np.zeros((nc, nc)) + mixrule = QMR(kij, lij) + model = PengRobinson76(Tc, Pc, w, mixrule) + + P, T = 60.0, 294.0 + flash = model.flash_pt(n, pressure=T, temperature=P) + + npt.assert_allclose(flash["x"], [0.32424472, 0.67575528], rtol=1e-5) + + +def test_saturation(): + nc = 2 + n = [0.4, 0.6] + tc = [190.564, 425.12] + pc = [45.99, 37.96] + w = [0.0115478, 0.200164] + + lij = kij = np.zeros((nc, nc)) + mixrule = QMR(kij, lij) + model = SoaveRedlichKwong(tc, pc, w, mixrule) + + bub = model.saturation_pressure(n, temperature=303.15, kind="bubble") + npt.assert_allclose(bub["y"], [0.899642, 0.100358], rtol=1e-5) diff --git a/python/tox.ini b/python/tox.ini new file mode 100644 index 000000000..8b00d2e6a --- /dev/null +++ b/python/tox.ini @@ -0,0 +1,79 @@ +[tox] +isolated_build = True +envlist = + style, + docstyle, + check-manifest, + py310, + py311, + py312, + coverage, + + +# ============================================================================= +# ENVS +# ============================================================================= +[gh-actions] +python = + 3.10: py310, style, docstyle, coverage, check-manifest + 3.11: py311 + 3.12: py312 + +[testenv] +deps = + ipdb + pytest +skip_install = False +usedevelop = True +commands = + pytest tests/ {posargs} + + +[testenv:style] +skip_install = True +usedevelop = False +deps = + flake8 + flake8-black + flake8-builtins + flake8-import-order + pep8-naming +commands = + flake8 tests/ yaeos/ {posargs} + + +[testenv:docstyle] +deps = + pydocstyle + tomli +commands = pydocstyle yaeos --convention=numpy + + +[testenv:check-manifest] +skip_install = True +usedevelop = False +allowlist_externals = touch, rm +deps = check-manifest +commands = + check-manifest + + +; [testenv:docs] +; description = "Invoke sphinx-build to build the HTML docs" +; whitelist_externals = make +; usedevelop = True +; skip_install = False +; changedir = docs +; deps = -r {toxinidir}/docs/requirements.txt +; commands = sphinx-build -W -b html -d {envtmpdir}/doctrees source {envtmpdir}/html + + +[testenv:coverage] +deps = + {[testenv]deps} # same dependencies of [testenv] + coverage + pytest-cov +commands = + coverage erase + pytest tests/ --cov=yaeos/ --cov-append --cov-report=term-missing + coverage report --fail-under=70 -m diff --git a/python/yaeos/__init__.py b/python/yaeos/__init__.py new file mode 100644 index 000000000..9787061ac --- /dev/null +++ b/python/yaeos/__init__.py @@ -0,0 +1,23 @@ +from yaeos.compiled_module.yaeos_compiled import yaeos_c + +from yaeos.core import ( + SoaveRedlichKwong, + PengRobinson76, + PengRobinson78, + RKPR, + NRTL, + MHV, + QMR, +) + + +__all__ = [ + "yaeos_c", + "SoaveRedlichKwong", + "PengRobinson76", + "PengRobinson78", + "RKPR", + "QMR", + "NRTL", + "MHV", +] diff --git a/python/yaeos/compiled_module/__init__.py b/python/yaeos/compiled_module/__init__.py new file mode 100644 index 000000000..00fe9522e --- /dev/null +++ b/python/yaeos/compiled_module/__init__.py @@ -0,0 +1,4 @@ +from .yaeos_compiled import yaeos_c + + +__all__ = ["yaeos_c"] diff --git a/python/yaeos/core.py b/python/yaeos/core.py new file mode 100644 index 000000000..dd54940b1 --- /dev/null +++ b/python/yaeos/core.py @@ -0,0 +1,194 @@ +"""CubicEoS interface +""" + +from abc import ABC, abstractmethod + +import numpy as np + +from yaeos import yaeos_c + + +class GeModel(ABC): + """Excess Gibbs model.""" + + def __del__(self): + yaeos_c.make_available_ge_models_list(self.id) + + +class ArModel(ABC): + """Residual Helmholtz (Ar) model""" + + def fugacity(self, n, v, t, dt=None, dp=None, dn=None): + + nc = len(n) + + if dt: + dt = np.empty(nc, order="F") + if dp: + dp = np.empty(nc, order="F") + if dn: + dn = np.empty((nc, nc), order="F") + + res = yaeos_c.fug_vt( + self.id, n, v, t, dlnphidt=dt, dlnphidp=dp, dlnphidn=dn + ) + res = {"ln_phi": res, "dt": dt, "dp": dp, "dn": dn} + return res + + def flash_pt(self, z, pressure, temperature): + """Two-phase split with specification of temperature and pressure. + + Calculates the phase split at a given pressure and temperature + """ + + x, y, pressure, temperature, volume_x, volume_y, beta = yaeos_c.flash( + self.id, z, pressure, temperature + ) + + flash_result = { + "x": x, + "y": y, + "P": pressure, + "T": temperature, + "beta": beta, + } + + return flash_result + + def saturation_pressure(self, z, temperature, kind="bubble"): + """Saturation pressure at specified temperature + + Arguments + --------- + z: array + Global molar fractions + temperature: float + Temperature [K] + kind: string + Kind of saturation point, defaults to "bubble". Options are + - "bubble" + - "dew" + - "liquid-liquid" + """ + p, x, y, volume_x, volume_y, beta = yaeos_c.saturation_pressure( + self.id, z, temperature, kind + ) + + return { + "x": x, + "y": y, + "Vx": volume_x, + "Vy": volume_y, + "T": temperature, + "P": p, + "beta": beta, + } + + def __del__(self): + yaeos_c.make_available_ar_models_list(self.id) + + +class NRTL: + + def __init__(self, a, b, c): + self.a = a + self.b = b + self.c = c + self.id = yaeos_c.nrtl(a, b, c) + + +class CubicMixRule(ABC): + @abstractmethod + def set_mixrule(self, ar_model_id): + raise NotImplementedError + + +class CubicEoS(ArModel): + def __init__(self, tc, pc, w): + nc = len(tc) + self.nc = nc + self.tc = tc + self.pc = pc + self.w = w + + def set_mixrule(self, mixrule: CubicMixRule): + self.mixrule = mixrule + self.mixrule.set_mixrule(self.id) + + +class QMR(ABC): + + def __init__(self, kij, lij): + self.kij = kij + self.lij = lij + + def set_mixrule(self, ar_model_id): + yaeos_c.set_qmr(ar_model_id, self.kij, self.lij) + + +class MHV(ABC): + + def __init__(self, ge, q, lij=None): + self.ge = ge + self.q = q + self.lij = lij + + def set_mixrule(self, ar_model_id): + yaeos_c.set_mhv(ar_model_id, self.ge.id, self.q) + + +class PengRobinson76(CubicEoS): + name = "PengRobinson76" + + def __init__(self, tc, pc, w, mixrule: CubicMixRule = None): + super(PengRobinson76, self).__init__(tc, pc, w) + self.id = yaeos_c.pr76(self.tc, self.pc, self.w) + self.mixrule = mixrule + if mixrule: + mixrule.set_mixrule(self.id) + + +class PengRobinson78(CubicEoS): + name = "PengRobinson78" + + def __init__(self, tc, pc, w, mixrule: CubicMixRule = None): + super(PengRobinson78, self).__init__(tc, pc, w) + self.id = yaeos_c.pr78(self.tc, self.pc, self.w) + self.mixrule = mixrule + if mixrule: + mixrule.set_mixrule(self.id) + + +class SoaveRedlichKwong(CubicEoS): + name = "SoaveReldichKwong" + + def __init__(self, tc, pc, w, mixrule: CubicMixRule = None): + super(SoaveRedlichKwong, self).__init__(tc, pc, w) + self.id = yaeos_c.srk(self.tc, self.pc, self.w) + if mixrule: + mixrule.set_mixrule(self.id) + + +class RKPR(CubicEoS): + name = "RKPR" + + def __init__( + self, tc, pc, w, zc, k=None, delta_1=None, mixrule: CubicMixRule = None + ): + super(RKPR, self).__init__(tc, pc, w) + self.zc = zc + match (k is None, delta_1 is None): + case (True, True): + self.id = yaeos_c.rkpr(self.tc, self.pc, self.w, self.zc) + case (False, True): + self.id = yaeos_c.rkpr(self.tc, self.pc, self.w, self.zc, k=k) + case (True, False): + self.id = yaeos_c.rkpr( + self.tc, self.pc, self.w, self.zc, delta_1=delta_1 + ) + case (False, False): + self.id = yaeos_c.rkpr( + self.tc, self.pc, self.w, self.zc, k=k, delta_1=delta_1 + ) + if mixrule: + mixrule.set_mixrule(self.id) diff --git a/python/yaeos/fortran_wrap/yaeos_c.f90 b/python/yaeos/fortran_wrap/yaeos_c.f90 new file mode 100644 index 000000000..837a95868 --- /dev/null +++ b/python/yaeos/fortran_wrap/yaeos_c.f90 @@ -0,0 +1,381 @@ +module yaeos_c + !! # Yaeos C Interface + !! C interface intended to be used on external languanges. With an emphasis + !! on using it on Python. + !! + !! # Description + !! The interface holds two lists of models (one for `ArModels` and another + !! for`GeModels`), and two lists of logicals that represent wich models are + !! in those lists are allocated. + !! + !! When a model is instanciated/allocated, it is stored in the singleton + !! object `x_model` and right after that the `extend_x_models_list` procedure + !! is called. This procedure searches for the first `free_x_models` id and + !! allocates the singleton model there, returning the `id` of the procedure. + use iso_c_binding, only: c_double, c_int, c_int64_t + use yaeos, only: ArModel, GeModel + implicit none + + private + + ! CubicEoS + public :: srk, pr76, pr78, rkpr + ! Mixing rules + public :: set_mhv, set_qmr + + ! __del__ + public :: make_available_ar_models_list + public :: make_available_ge_models_list + ! GeMoels + public :: nrtl + public :: ln_gamma + + ! Thermoprops + public :: fug_vt + + ! Phase equilibria + public :: flash + public :: saturation_pressure + public :: pt2_phase_envelope + + type :: ArModelContainer + !! Container type for ArModels + class(ArModel), allocatable :: model + end type ArModelContainer + + type :: GeModelContainer + !! Container type for GeModels + class(GeModel), allocatable :: model + end type GeModelContainer + + class(ArModel), allocatable :: ar_model !! Singleton to hold temporal ArModels + class(GeModel), allocatable :: ge_model !! Singleton to hold temporal GeModels + + ! Containers of models + integer, parameter :: max_models = 1000000 + logical :: free_ar_model(max_models) = .true. + logical :: free_ge_model(max_models) = .true. + + class(ArModelContainer), allocatable :: ar_models(:) + class(GeModelContainer), allocatable :: ge_models(:) + +contains + + ! ========================================================================== + ! Ge Models + ! -------------------------------------------------------------------------- + subroutine nrtl(a, b, c, id) + use yaeos, only: fNRTL => NRTL + real(c_double), intent(in) :: a(:,:), b(:,:), c(:,:) + integer(c_int), intent(out) :: id + ge_model = fNRTL(a, b, c) + call extend_ge_models_list(id) + end subroutine nrtl + + subroutine extend_ge_models_list(id) + !! Find the first available model container and allocate the model + !! there. Then return the found id. + integer(c_int), intent(out) :: id + integer :: i + if (.not. allocated(ge_models)) allocate(ge_models(max_models)) + + ! Find the first not allocated model + do i=1,max_models + if (free_ge_model(i)) then + free_ge_model(i) = .false. + id = i + call move_alloc(ge_model, ge_models(i)%model) + exit + end if + end do + if (id == max_models) error stop 1 + end subroutine extend_ge_models_list + + subroutine make_available_ge_models_list(id) + !! Make the geModel id available for allocation + integer(c_int), intent(in) :: id + free_ge_model(id) = .true. + end subroutine make_available_ge_models_list + + subroutine ln_gamma(id, n, T, lngamma) + integer(c_int), intent(in) :: id + real(c_double), intent(in) :: n(:) + real(c_double), intent(in) :: T + real(c_double), intent(out) :: lngamma(size(n)) + call ge_models(id)%model%ln_activity_coefficient(n, T, lngamma) + end subroutine ln_gamma + + ! ============================================================================= + ! Ar Models + ! ----------------------------------------------------------------------------- + subroutine extend_ar_models_list(id) + !! Find the first available model container and allocate the model + !! there. Then return the found id. + integer(c_int), intent(out) :: id + integer :: i + if (.not. allocated(ar_models)) allocate(ar_models(max_models)) + + ! Find the first not allocated model + do i=1,max_models + if (free_ar_model(i)) then + free_ar_model(i) = .false. + id = i + call move_alloc(ar_model, ar_models(i)%model) + exit + end if + end do + if (id == max_models) error stop 1 + end subroutine extend_ar_models_list + + subroutine make_available_ar_models_list(id) + !! Make the ArModel id available for allocation + integer(c_int), intent(in) :: id + free_ar_model(id) = .true. + end subroutine make_available_ar_models_list + + ! ========================================================================== + ! Cubic Mixing rules + ! -------------------------------------------------------------------------- + subroutine set_mhv(ar_id, ge_id, q) + !! Michelsen's Modified Huron-Vidal 1 with constant `q_1` parameter + use yaeos, only: MHV, CubicEoS + integer(c_int), intent(in) :: ar_id + integer(c_int), intent(in) :: ge_id + real(c_double), intent(in) :: q + + type(MHV) :: mixrule + + ar_model = ar_models(ar_id)%model + ge_model = ge_models(ge_id)%model + + select type(ar_model) + class is(CubicEoS) + mixrule = MHV(ge=ge_model, b=ar_model%b, q=q) + deallocate(ar_model%mixrule) + ar_model%mixrule = mixrule + end select + + call move_alloc(ar_model, ar_models(ar_id)%model) + end subroutine set_mhv + + subroutine set_qmr(ar_id, kij, lij) + use yaeos, only: QMR, CubicEoS + integer(c_int), intent(in) :: ar_id + real(c_double) :: kij(:, :) + real(c_double) :: lij(:, :) + + type(QMR) :: mixrule + + ar_model = ar_models(ar_id)%model + + select type(ar_model) + class is(CubicEoS) + mixrule = QMR(k=kij, l=lij) + deallocate(ar_model%mixrule) + ar_model%mixrule = mixrule + end select + + call move_alloc(ar_model, ar_models(ar_id)%model) + end subroutine set_qmr + + ! ========================================================================== + ! Cubic EoS implementations + ! -------------------------------------------------------------------------- + subroutine pr76(tc, pc, w, id) + use yaeos, only: PengRobinson76 + real(c_double), intent(in) :: tc(:), pc(:), w(:) + integer(c_int), intent(out) :: id + + ar_model = PengRobinson76(tc, pc, w) + call extend_ar_models_list(id) + end subroutine pr76 + + subroutine pr78(tc, pc, w, id) + use yaeos, only: PengRobinson78 + real(c_double), intent(in) :: tc(:), pc(:), w(:) + integer(c_int), intent(out) :: id + + ar_model = PengRobinson78(tc, pc, w) + call extend_ar_models_list(id) + end subroutine pr78 + + subroutine srk(tc, pc, w, id) + use yaeos, only: SoaveRedlichKwong + real(c_double), intent(in) :: tc(:), pc(:), w(:) + integer(c_int), intent(out) :: id + ar_model = SoaveRedlichKwong(tc, pc, w) + call extend_ar_models_list(id) + end subroutine srk + + subroutine rkpr(tc, pc, w, zc, delta_1, k, id) + use yaeos, only: fRKPR => RKPR + real(c_double), intent(in) :: tc(:), pc(:), w(:), zc(:) + real(c_double), optional, intent(in) :: delta_1(:), k(:) + integer(c_int), intent(out) :: id + + if (present(delta_1) .and. present(k)) then + ar_model = fRKPR(tc, pc, w, zc, delta_1=delta_1, k=k) + elseif (present(delta_1)) then + ar_model = fRKPR(tc, pc, w, zc, delta_1=delta_1) + elseif (present(k)) then + ar_model = fRKPR(tc, pc, w, zc, k=k) + else + ar_model = fRKPR(tc, pc, w, zc) + end if + call extend_ar_models_list(id) + end subroutine rkpr + + ! ========================================================================== + ! Thermodynamic properties + ! -------------------------------------------------------------------------- + subroutine fug_vt(id, n, v, t, lnfug, dlnphidp, dlnphidt, dlnphidn) + integer(c_int), intent(in) :: id + real(c_double), intent(in) :: n(:), v, t + real(c_double), intent(out) :: lnfug(size(n)) + real(c_double) :: p + + real(c_double), optional, intent(in out) :: & + dlnphidp(size(n)), dlnphidt(size(n)), dlnphidn(size(n), size(n)) + + call ar_models(id)%model%lnphi_vt(& + n, V, T, P, lnfug, dlnPhidP, dlnphidT, dlnPhidn & + ) + end subroutine fug_vt + + ! ========================================================================== + ! Phase equilibria + ! -------------------------------------------------------------------------- + subroutine equilibria_state_to_arrays(eq_state, x, y, P, T, Vx, Vy, beta) + use yaeos, only: EquilibriaState + type(EquilibriaState) :: eq_state + real(c_double), intent(out) :: x(:) + real(c_double), intent(out) :: y(:) + real(c_double), intent(out) :: P + real(c_double), intent(out) :: T + real(c_double), intent(out) :: Vx + real(c_double), intent(out) :: Vy + real(c_double), intent(out) :: Beta + + x = eq_state%x + y = eq_state%y + P = eq_state%p + T = eq_state%T + Vx = eq_state%Vx + Vy = eq_state%Vy + beta = eq_state%beta + end subroutine equilibria_state_to_arrays + + subroutine flash(id, z, T, P, x, y, k0, Pout, Tout, Vx, Vy, beta) + use yaeos, only: EquilibriaState, fflash => flash + integer(c_int), intent(in) :: id + real(c_double), intent(in) :: z(:) + real(c_double), intent(in) :: T + real(c_double), intent(in) :: P + real(c_double), optional, intent(in out) :: k0(size(z)) + real(c_double), intent(out) :: x(size(z)) + real(c_double), intent(out) :: y(size(z)) + real(c_double), intent(out) :: Pout + real(c_double), intent(out) :: Tout + real(c_double), intent(out) :: Vx + real(c_double), intent(out) :: Vy + real(c_double), intent(out) :: beta + + type(EquilibriaState) :: result + integer :: iters + + result = fflash(ar_models(id)%model, z, t, p_spec=p, iters=iters) + if (.not. allocated(result%x) .or. .not. allocated(result%y)) then + Pout = P + Tout = T + x = z + y = z + beta = -1 + Vx = 1 + Vy = 1 + return + end if + + call equilibria_state_to_arrays(result, x, y, Pout, Tout, Vx, Vy, beta) + end subroutine flash + + subroutine saturation_pressure(id, z, T, kind, P, x, y, Vx, Vy, beta) + use yaeos, only: EquilibriaState, fsaturation_pressure => saturation_pressure + integer(c_int), intent(in) :: id + real(c_double), intent(in) :: z(:) + real(c_double), intent(in) :: T + character(len=15), intent(in) :: kind + + real(c_double), intent(out) :: P + real(c_double), intent(out) :: x(size(z)) + real(c_double), intent(out) :: y(size(z)) + real(c_double), intent(out) :: Vx, Vy, beta + + real(c_double) :: aux + + type(EquilibriaState) :: sat + + sat = fsaturation_pressure(ar_models(id)%model, z, T, kind) + call equilibria_state_to_arrays(sat, x, y, P, aux, Vx, Vy, beta) + end subroutine saturation_pressure + + subroutine pt2_phase_envelope(id, z, kind, Ts, Ps, tcs, pcs, T0, P0) + use yaeos, only: & + saturation_pressure, saturation_temperature, pt_envelope_2ph, & + EquilibriaState, PTEnvel2 + integer(c_int), intent(in) :: id + real(c_double), intent(in) :: z(:) + character(len=15), intent(in) :: kind + real(c_double), intent(out) :: Ts(1000) + real(c_double), intent(out) :: Ps(1000) + real(c_double), intent(out) :: Tcs(5), Pcs(5) + real(c_double), optional, intent(in) :: T0, P0 + + real(8) :: makenan, nan + type(EquilibriaState) :: sat + type(PTEnvel2) :: env + + integer :: i, neval=0 + + real(c_double) :: T, P + + makenan=0 + + neval = neval + 1 + nan = makenan/makenan + Ts = nan + Ps = nan + Tcs = nan + Pcs = nan + + if (present(T0)) then + T = T0 + else + T = 150 + end if + + if (present(P0)) then + P = P0 + else + P = 1 + end if + + select case(kind) + case("bubble") + sat = saturation_pressure(ar_models(id)%model, z, T=T, kind=kind) + case("dew") + sat = saturation_temperature(ar_models(id)%model, z, P=P, kind=kind) + case("liquid-liquid") + sat = saturation_temperature(ar_models(id)%model, z, P=P, kind=kind) + end select + + + env = pt_envelope_2ph(ar_models(id)%model, z, sat) + i = size(env%points) + Ts(:i) = env%points%T + Ps(:i) = env%points%P + + i = size(env%cps) + Tcs(:i) = env%cps%T + Pcs(:i) = env%cps%P + end subroutine pt2_phase_envelope +end module yaeos_c diff --git a/src/adiff/autodiff_api/tapenade/interfaces.f90 b/src/adiff/autodiff_api/tapenade/interfaces.f90 index 57dbb1fc9..576911992 100644 --- a/src/adiff/autodiff_api/tapenade/interfaces.f90 +++ b/src/adiff/autodiff_api/tapenade/interfaces.f90 @@ -1,37 +1,36 @@ -module tapenade_interfaces +module yaeos__tapenade_interfaces + use yaeos__constants, only: pr implicit none - interface pushreal8 - subroutine pushreal8(realnum) - real(8) :: realnum - end subroutine - - subroutine pushreal8array(realnum) - real(8) :: realnum(:) - end subroutine - end interface + interface + subroutine pushinteger4(i) + integer :: i + end subroutine + + subroutine popinteger4(i) + integer :: i + end subroutine - interface popreal8 - subroutine popreal8(realnum) - real(8) :: realnum - end subroutine - end interface + subroutine pushreal8array(a, n) + import pr + real(pr), dimension(n) :: a + integer :: n + end subroutine - interface pushinteger4 - subroutine pushinteger4(intnum) - integer :: intnum - end subroutine - end interface + subroutine pushreal8(a) + import pr + real(pr) :: a + end subroutine - interface popinteger4 - subroutine popinteger4(intnum) - integer :: intnum - end subroutine - end interface + subroutine POPREAL8(a) + import pr + real(pr) :: a + end subroutine - interface pushcontrol1b - subroutine pushcontrol1b(intnum) - integer :: intnum - end subroutine - end interface + subroutine POPREAL8ARRAY(a, n) + import pr + real(pr), dimension(n) :: a + integer :: n + end subroutine + end interface end module \ No newline at end of file diff --git a/src/consistency/consistency.f90 b/src/consistency/consistency.f90 index f3e2f98fe..d6543bed9 100644 --- a/src/consistency/consistency.f90 +++ b/src/consistency/consistency.f90 @@ -1,7 +1,25 @@ module yaeos__consistency - !! Tools to evalaute the consistency of Ar and Ge models. This module also - !! provides subroutines for numeric evaluations of Ar and Ge derivatives from - !! central finite differences. + !! # yaeos__consistency + !! Subroutine to evaluate the consistency of thermodynamic models. + !! + !! # Description + !! Tools to evaluate the consistency of \(A^r\) and \(G^E\) models. This + !! module also provides subroutines for numerical evaluations of \(A^r\) and + !! \(G^E\) derivatives using central finite differences. The purpose of the + !! module is to assist in the development of new models and ensure the + !! accuracy of the derivatives implementation. + !! + !! # Examples + !! For detailed explanations and examples of each consistency test, please + !! refer to the API documentation of each submodule. + !! + !! - \(A^r\) consistency tests: [[yaeos__consistency_armodel]] + !! - \(G^E\) consistency tests: [[yaeos__consistency_gemodel]] + !! + !! # References + !! 1. Michelsen, M. L., & Mollerup, J. M. (2007). Thermodynamic models: + !! Fundamentals & computational aspects (2. ed). Tie-Line Publications. + !! ! Consistency test for ArModels use yaeos__consistency_armodel use yaeos__consistency_gemodel diff --git a/src/consistency/consistency_tests/consistency_armodel.f90 b/src/consistency/consistency_tests/consistency_armodel.f90 index 39f38ffe1..9775cfc36 100644 --- a/src/consistency/consistency_tests/consistency_armodel.f90 +++ b/src/consistency/consistency_tests/consistency_armodel.f90 @@ -1,34 +1,39 @@ module yaeos__consistency_armodel - !! Consistency checks of Helmholtz free energy models. + !! # yaeos__consistency_armodel + !! Consistency checks of Helmholtz free energy models ([[ArModel]]). !! + !! # Description !! This module contains tools to validate the analityc derivatives of - !! implmented Helmholtz free energy models (ArModel). Also, allows to + !! implmented Helmholtz free energy models ([[ArModel]]). Also, allows to !! evaluate the consistency tests described in Thermodynamic Models: !! Fundamentals & Computational Aspects 2 ed. by Michelsen and Mollerup !! Chapter 2 section 3. !! !! Available tools: !! - !! - numeric_ar_derivatives: From an instantiated ArModel evaluate all the - !! Helmholtz free energy derivatives from the central finite difference - !! method. + !! - [[numeric_ar_derivatives]]: From an instantiated [[ArModel]] evaluate + !! all the Helmholtz free energy derivatives from the central finite + !! difference method. !! - !! - ar_consistency: From an instantiated ArModel evaluate all the Michelsen - !! and Mollerup consistency tests (refer to ar_consistency docs for more - !! explanations) + !! - [[ar_consistency]]: From an instantiated [[ArModel]] evaluate all the + !! Michelsen and Mollerup consistency tests. + !! + !! # References + !! 1. Michelsen, M. L., & Mollerup, J. M. (2007). Thermodynamic models: + !! Fundamentals & computational aspects (2. ed). Tie-Line Publications. !! use yaeos__constants, only: pr, R use yaeos__models_ar, only: ArModel - use yaeos__thermoprops, only: enthalpy_residual_vt, gibbs_residual_vt - use yaeos__thermoprops, only: fugacity_vt, pressure implicit none contains subroutine ar_consistency(& - eos, n, v, t, eq31, eq33, eq34, eq36, eq37 & + eos, n, V, T, eq31, eq33, eq34, eq36, eq37 & ) - !! Evaluates the Michelsen and Mollerup (MM) consistency tests. + !! # ar_consistency + !! \(A^r\) models consistency tests. !! + !! # Description !! The evaluated equations are taken from Fundamentals & Computational !! Aspects 2 ed. by Michelsen and Mollerup Chapter 2 section 3. The !! "eq" are evaluations of the left hand side of the following @@ -68,16 +73,19 @@ subroutine ar_consistency(& !! \right)_{P,n} + \frac{H^r(T,P,n)}{RT^2} = 0 !! \] !! + !! The consistency test could be applied to any instantiated [[ArModel]] + !! as shown in the following example. + !! !! # Examples !! !! ```fortran !! use yaeos, only: pr, SoaveRedlichKwong, ArModel - !! use yaeos__consistency, only: ar_consistency + !! use yaeos__consistency_armodel, only: ar_consistency !! !! class(ArModel), allocatable :: model !! real(pr) :: tc(4), pc(4), w(4) !! - !! real(pr) :: n(4), t, v + !! real(pr) :: n(4), T, V !! !! real(pr) :: eq31, eq33(size(n), size(n)), eq34(size(n)), eq36, eq37 !! @@ -86,20 +94,25 @@ subroutine ar_consistency(& !! pc = [45.99, 37.96, 39.23, 40.21] !! w = [0.0115478, 0.200164, 0.3624, 0.298] !! - !! t = 600_pr - !! v = 0.5_pr + !! T = 600_pr + !! V = 0.5_pr !! !! model = SoaveRedlichKwong(tc, pc, w) !! !! call ar_consistency(& - !! model, n, v, t, eq31=eq31, eq33=eq33, eq34=eq34, eq36=eq36, eq37=eq37 & + !! model, n, V, T, eq31=eq31, eq33=eq33, eq34=eq34, eq36=eq36, eq37=eq37 & !! ) !! ``` + !! All `eqXX` variables should be close to zero. + !! + !! # References + !! 1. Michelsen, M. L., & Mollerup, J. M. (2007). Thermodynamic models: + !! Fundamentals & computational aspects (2. ed). Tie-Line Publications. !! - class(ArModel), intent(in) :: eos !! Model + class(ArModel), intent(in) :: eos !! Equation of state real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(in) :: V !! Volume [L] real(pr), optional, intent(out) :: eq31 !! MM Eq. 31 ! TODO real(pr), optional, intent(out) :: eq32 real(pr), optional, intent(out) :: eq33(size(n), size(n)) !! MM Eq. 33 @@ -112,33 +125,31 @@ subroutine ar_consistency(& ! ======================================================================== ! Previous calculations ! ------------------------------------------------------------------------ - real(pr) :: Grp, Grv, Hrv, p, dpdn(size(n)), ntot, z - real(pr) :: lnphi(size(n)), lnphip(size(n)), dlnPhidP(size(n)) + real(pr) :: Grp, Grv, Hrv, P, dPdn(size(n)), ntot, z + real(pr) :: lnphi(size(n)), dlnPhidP(size(n)) real(pr) :: dlnPhidT(size(n)), dlnPhidn(size(n), size(n)) - call pressure(eos, n, v, t, p, dpdn=dpdn) + call eos%pressure(n, V, T, P, dPdn=dPdn) - call gibbs_residual_vt(eos, n, v, t, Grv) + call eos%gibbs_residual_vt(n, V, T, Grv) - call enthalpy_residual_vt(eos, n, v, t, Hr=Hrv) + call eos%enthalpy_residual_vt(n, V, T, Hr=Hrv) - call fugacity_vt(& - eos, n, v, t, lnphip=lnphip, & + call eos%lnphi_vt(& + n, V, T, lnPhi=lnPhi, & dlnPhidP=dlnPhidP, dlnPhidT=dlnPhidT, dlnPhidn=dlnPhidn & ) ntot = sum(n) - lnphi(:) = lnphip(:) - log(p) + z = P * V / ntot / R / T - z = p * v / ntot / R / t - - Grp = Grv - ntot * R * t * log(z) + Grp = Grv - ntot * R * T * log(Z) ! ======================================================================== ! Equation 31 ! ------------------------------------------------------------------------ - if (present(eq31)) eq31 = sum(n(:) * lnphi(:)) - Grp / (R * t) + if (present(eq31)) eq31 = sum(n(:) * lnPhi(:)) - Grp / (R * T) ! ======================================================================== ! Equation 32 @@ -172,32 +183,37 @@ subroutine ar_consistency(& ! ======================================================================== ! Equation 36 ! ------------------------------------------------------------------------ - if (present(eq36)) eq36 = sum(n(:) * dlnPhidP(:)) - (z - 1) * ntot / p + if (present(eq36)) eq36 = sum(n(:) * dlnPhidP(:)) - (z - 1) * ntot / P ! ======================================================================== ! Equation 37 ! ------------------------------------------------------------------------ if (present(eq37)) then - eq37 = sum(n(:) * dlnPhidT(:)) + Hrv / (R * t**2) + eq37 = sum(n(:) * dlnPhidT(:)) + Hrv / (R * T**2) end if end subroutine ar_consistency subroutine numeric_ar_derivatives(& - eos, n, v, t, d_n, d_v, d_t, & + eos, n, V, T, d_n, d_v, d_t, & Ar, ArV, ArT, Arn, ArV2, ArT2, ArTV, ArVn, ArTn, Arn2 & ) + !! # numeric_ar_derivatives !! Evaluate the Helmholtz derivatives with central finite difference. !! + !! # Description + !! Tool to facilitate the development of new [[ArModel]] by testing + !! the implementation of analytic derivatives. + !! !! # Examples !! !! ```fortran !! use yaeos, only: pr, SoaveRedlichKwong, ArModel - !! use yaeos__consistency, only: numeric_ar_derivatives + !! use yaeos__consistency_armodel, only: numeric_ar_derivatives !! !! class(ArModel), allocatable :: model !! real(pr) :: tc(4), pc(4), w(4) !! - !! real(pr) :: n(4), t, v + !! real(pr) :: n(4), T, V !! !! real(pr) :: Ar_num, ArV_num, ArT_num, Arn_num(size(n)), ArV2_num, ArT2_num !! real(pr) :: ArTV_num, ArVn_num(size(n)), ArTn_num(size(n)) @@ -208,23 +224,23 @@ subroutine numeric_ar_derivatives(& !! pc = [45.99, 37.96, 39.23, 40.21] !! w = [0.0115478, 0.200164, 0.3624, 0.298] !! - !! t = 600_pr - !! v = 0.5_pr + !! T = 600_pr + !! V = 0.5_pr !! !! model = SoaveRedlichKwong(tc, pc, w) !! !! call numeric_ar_derivatives(& - !! model, n, v, t, d_n = 0.0001_pr, d_v = 0.0001_pr, d_t = 0.01_pr, & + !! model, n, V, T, d_n = 0.0001_pr, d_v = 0.0001_pr, d_t = 0.01_pr, & !! Ar=Ar_num, ArV=ArV_num, ArT=ArT_num, ArTV=ArTV_num, ArV2=ArV2_num, & !! ArT2=ArT2_num, Arn=Arn_num, ArVn=ArVn_num, ArTn=ArTn_num, & !! Arn2=Arn2_num & !! ) !! ``` !! - class(ArModel), intent(in) :: eos !! Model + class(ArModel), intent(in) :: eos !! Equation of state real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(in) :: V !! Volume [L] real(pr), intent(in) :: d_n !! Moles finite difference step real(pr), intent(in) :: d_t !! Temperature finite difference step real(pr), intent(in) :: d_v !! Volume finite difference step @@ -248,15 +264,15 @@ subroutine numeric_ar_derivatives(& ! Ar valuations ! ------------------------------------------------------------------------ ! on point valuation - call eos%residual_helmholtz(n, v, t, Ar=Ar) + call eos%residual_helmholtz(n, V, T, Ar=Ar) ! ======================================================================== ! Central numeric derivatives ! ------------------------------------------------------------------------ ! Volume if (present(ArV) .or. present(ArV2)) then - call eos%residual_helmholtz(n, v + d_v, t, Ar=Ar_aux1) - call eos%residual_helmholtz(n, v - d_v, t, Ar=Ar_aux2) + call eos%residual_helmholtz(n, V + d_v, T, Ar=Ar_aux1) + call eos%residual_helmholtz(n, V - d_v, T, Ar=Ar_aux2) if (present(ArV)) ArV = (Ar_aux1 - Ar_aux2) / (2 * d_v) if (present(ArV2)) ArV2 = (Ar_aux1 - 2 * Ar + Ar_aux2) / d_v**2 @@ -264,8 +280,8 @@ subroutine numeric_ar_derivatives(& ! Temperature if (present(ArT) .or. present(ArT2)) then - call eos%residual_helmholtz(n, v, t + d_t, Ar=Ar_aux1) - call eos%residual_helmholtz(n, v, t - d_t, Ar=Ar_aux2) + call eos%residual_helmholtz(n, V, T + d_t, Ar=Ar_aux1) + call eos%residual_helmholtz(n, V, T - d_t, Ar=Ar_aux2) if (present(ArT)) ArT = (Ar_aux1 - Ar_aux2) / (2 * d_t) if (present(ArT2)) ArT2 = (Ar_aux1 - 2 * Ar + Ar_aux2) / d_t**2 @@ -279,8 +295,8 @@ subroutine numeric_ar_derivatives(& dn_aux1 = 0.0_pr dn_aux1(i) = d_n - call eos%residual_helmholtz(n + dn_aux1, v, t, Ar=Ar_aux1) - call eos%residual_helmholtz(n - dn_aux1, v, t, Ar=Ar_aux2) + call eos%residual_helmholtz(n + dn_aux1, V, T, Ar=Ar_aux1) + call eos%residual_helmholtz(n - dn_aux1, V, T, Ar=Ar_aux2) Arn(i) = (Ar_aux1 - Ar_aux2) / (2 * d_n) end do @@ -291,10 +307,10 @@ subroutine numeric_ar_derivatives(& ! ------------------------------------------------------------------------ ! Temperature - Volume if (present(ArTV)) then - call eos%residual_helmholtz(n, v + d_v, t + d_t, Ar=Ar_aux1) - call eos%residual_helmholtz(n, v + d_v, t - d_t, Ar=Ar_aux2) - call eos%residual_helmholtz(n, v - d_v, t + d_t, Ar=Ar_aux3) - call eos%residual_helmholtz(n, v - d_v, t - d_t, Ar=Ar_aux4) + call eos%residual_helmholtz(n, V + d_v, T + d_t, Ar=Ar_aux1) + call eos%residual_helmholtz(n, V + d_v, T - d_t, Ar=Ar_aux2) + call eos%residual_helmholtz(n, V - d_v, T + d_t, Ar=Ar_aux3) + call eos%residual_helmholtz(n, V - d_v, T - d_t, Ar=Ar_aux4) ArTV = (Ar_aux1 - Ar_aux2 - Ar_aux3 + Ar_aux4) / (4 * d_t * d_v) end if @@ -307,10 +323,10 @@ subroutine numeric_ar_derivatives(& dn_aux1 = 0.0_pr dn_aux1(i) = d_n - call eos%residual_helmholtz(n + dn_aux1, v, t + d_t, Ar=Ar_aux1) - call eos%residual_helmholtz(n + dn_aux1, v, t - d_t, Ar=Ar_aux2) - call eos%residual_helmholtz(n - dn_aux1, v, t + d_t, Ar=Ar_aux3) - call eos%residual_helmholtz(n - dn_aux1, v, t - d_t, Ar=Ar_aux4) + call eos%residual_helmholtz(n + dn_aux1, V, T + d_t, Ar=Ar_aux1) + call eos%residual_helmholtz(n + dn_aux1, V, T - d_t, Ar=Ar_aux2) + call eos%residual_helmholtz(n - dn_aux1, V, T + d_t, Ar=Ar_aux3) + call eos%residual_helmholtz(n - dn_aux1, V, T - d_t, Ar=Ar_aux4) ArTn(i) = & (Ar_aux1 - Ar_aux2 - Ar_aux3 + Ar_aux4) / (4 * d_t * d_n) @@ -325,10 +341,10 @@ subroutine numeric_ar_derivatives(& dn_aux1 = 0.0_pr dn_aux1(i) = d_n - call eos%residual_helmholtz(n + dn_aux1, v + d_v, t, Ar=Ar_aux1) - call eos%residual_helmholtz(n + dn_aux1, v - d_v, t, Ar=Ar_aux2) - call eos%residual_helmholtz(n - dn_aux1, v + d_v, t, Ar=Ar_aux3) - call eos%residual_helmholtz(n - dn_aux1, v - d_v, t, Ar=Ar_aux4) + call eos%residual_helmholtz(n + dn_aux1, V + d_v, T, Ar=Ar_aux1) + call eos%residual_helmholtz(n + dn_aux1, V - d_v, T, Ar=Ar_aux2) + call eos%residual_helmholtz(n - dn_aux1, V + d_v, T, Ar=Ar_aux3) + call eos%residual_helmholtz(n - dn_aux1, V - d_v, T, Ar=Ar_aux4) ArVn(i) = & (Ar_aux1 - Ar_aux2 - Ar_aux3 + Ar_aux4) / (4 * d_v * d_n) @@ -345,8 +361,8 @@ subroutine numeric_ar_derivatives(& dn_aux1 = 0.0_pr dn_aux1(i) = d_n - call eos%residual_helmholtz(n + dn_aux1, v, t, Ar=Ar_aux1) - call eos%residual_helmholtz(n - dn_aux1, v, t, Ar=Ar_aux2) + call eos%residual_helmholtz(n + dn_aux1, V, T, Ar=Ar_aux1) + call eos%residual_helmholtz(n - dn_aux1, V, T, Ar=Ar_aux2) Arn2(i, j) = (Ar_aux1 - 2 * Ar + Ar_aux2) / d_n**2 else @@ -357,16 +373,16 @@ subroutine numeric_ar_derivatives(& dn_aux2(j) = d_n call eos%residual_helmholtz(& - n + dn_aux1 + dn_aux2, v, t, Ar=Ar_aux1 & + n + dn_aux1 + dn_aux2, V, T, Ar=Ar_aux1 & ) call eos%residual_helmholtz(& - n + dn_aux1 - dn_aux2, v, t, Ar=Ar_aux2 & + n + dn_aux1 - dn_aux2, V, T, Ar=Ar_aux2 & ) call eos%residual_helmholtz(& - n - dn_aux1 + dn_aux2, v, t, Ar=Ar_aux3 & + n - dn_aux1 + dn_aux2, V, T, Ar=Ar_aux3 & ) call eos%residual_helmholtz(& - n - dn_aux1 - dn_aux2, v, t, Ar=Ar_aux4 & + n - dn_aux1 - dn_aux2, V, T, Ar=Ar_aux4 & ) Arn2(i, j) = & diff --git a/src/consistency/consistency_tests/consistency_gemodel.f90 b/src/consistency/consistency_tests/consistency_gemodel.f90 index bc1df08b9..35be22413 100644 --- a/src/consistency/consistency_tests/consistency_gemodel.f90 +++ b/src/consistency/consistency_tests/consistency_gemodel.f90 @@ -1,21 +1,26 @@ module yaeos__consistency_gemodel - !! Consistency checks of excess Gibbs free energy models. + !! # yaeos__consistency_gemodel + !! Consistency checks of Helmholtz free energy models ([[GeModel]]). !! + !! # Description !! This module contains tools to validate the analityc derivatives of - !! implmented excess Gibbs free energy models (GeModel). Also, allows to + !! implmented excess Gibbs free energy models ([[GeModel]]). Also, allows to !! evaluate the consistency tests described in Thermodynamic Models: !! Fundamentals & Computational Aspects 2 ed. by Michelsen and Mollerup !! Chapter 5 section 4. !! !! Available tools: !! - !! - numeric_ge_derivatives: From an instantiated GeModel evaluate all the - !! excess Gibbs free energy derivatives from the central finite difference - !! method. + !! - [[numeric_ge_derivatives]]: From an instantiated [[GeModel]] evaluate + !! all the excess Gibbs free energy derivatives from the central finite + !! difference method. !! - !! - ge_consistency: From an instantiated GeModel evaluate all the Michelsen - !! and Mollerup consistency tests (refer to ge_consistency docs for more - !! explanations) + !! - [[ge_consistency]]: From an instantiated GeModel evaluate all the + !! Michelsen and Mollerup consistency tests + !! + !! # References + !! 1. Michelsen, M. L., & Mollerup, J. M. (2007). Thermodynamic models: + !! Fundamentals & computational aspects (2. ed). Tie-Line Publications. !! use yaeos__constants, only: pr, R use yaeos__models_ge, only: GeModel @@ -23,29 +28,39 @@ module yaeos__consistency_gemodel implicit none contains subroutine ge_consistency(model, n, t, eq58, eq59, eq60, eq61) + !! # ge_consistency !! \(G^E\) models consistency tests !! !! # Description !! Evaluate the \(G^E\) models consistency tests described in !! Thermodynamic Models: Fundamentals & Computational Aspects 2 ed. by - !! Michelsen and Mollerup (MM) Chapter 5 section 4. + !! Michelsen and Mollerup (MM) Chapter 5 section 4. The "eq" are + !! evaluations of the left hand side of the following expressions: + !! + !! Equation 58 !! !! \[ - !! eq58 = \sum_i^{NC} n_i \text{ln} \gamma_i - \frac{G^E}{RT} = 0 + !! \sum_i^{NC} n_i \text{ln} \gamma_i - \frac{G^E}{RT} = 0 !! \] !! + !! Equation 59 + !! !! \[ - !! eq59 = \text{ln} \gamma_i - \frac{1}{RT} + !! \text{ln} \gamma_i - \frac{1}{RT} !! \frac{\partial G^E}{\partial n_i} = 0 !! \] !! + !! Equation 60 + !! !! \[ - !! eq60 = \frac{\partial \text{ln} \gamma_i}{\partial n_j} - + !! \frac{\partial \text{ln} \gamma_i}{\partial n_j} - !! \frac{\partial \text{ln} \gamma_j}{\partial n_i} = 0 !! \] !! + !! Equation 61 + !! !! \[ - !! eq61 = \sum_i^{NC} n_i + !! \sum_i^{NC} n_i !! \frac{\partial \text{ln} \gamma_i}{\partial n_j} = 0 !! \] !! @@ -95,7 +110,8 @@ subroutine ge_consistency(model, n, t, eq58, eq59, eq60, eq61) !! ``` !! !! # References - !! Thermodynamic Models: Fundamentals & Computational Aspects 2 ed. Michelsen and Mollerup + !! 1. Michelsen, M. L., & Mollerup, J. M. (2007). Thermodynamic models: + !! Fundamentals & computational aspects (2. ed). Tie-Line Publications. !! class(GeModel), intent(in) :: model !! \(G^E\) model @@ -160,8 +176,12 @@ end subroutine ge_consistency subroutine numeric_ge_derivatives(& model, n, t, d_n, d_t, Ge, GeT, Gen, GeT2, GeTn, Gen2 & ) - !! # Numeric \(G^E\) model derivatives - !! Evaluate the excess Gibbs derivatives with central finite difference. + !! # numeric_ge_derivatives + !! Numeric \(G^E\) model derivatives + !! + !! # Description + !! Tool to facilitate the development of new [[GeModel]] by testing + !! the implementation of analytic derivatives. !! !! # Examples !! @@ -222,7 +242,7 @@ subroutine numeric_ge_derivatives(& !! ``` !! class(GeModel), intent(in) :: model - !!Ge Model + !! \(G^E\) model real(pr), intent(in) :: n(:) !! Moles number vector real(pr), intent(in) :: t diff --git a/src/fitting/kij_lij.f90 b/src/fitting/fit_kij_lij.f90 similarity index 91% rename from src/fitting/kij_lij.f90 rename to src/fitting/fit_kij_lij.f90 index d58cc300a..5ba755727 100644 --- a/src/fitting/kij_lij.f90 +++ b/src/fitting/fit_kij_lij.f90 @@ -46,11 +46,10 @@ module yaeos__fitting_fit_kij_lij contains - function model_from_X(problem, X) result(model) + subroutine model_from_X(problem, X) use yaeos, only: R, RKPR, PengRobinson78, ArModel, QMR, CubicEoS real(pr), intent(in) :: X(:) - class(FitKijLij), intent(in) :: problem - class(ArModel), allocatable :: model + class(FitKijLij), intent(in out) :: problem real(pr) :: kij(nc, nc), lij(nc, nc) @@ -62,8 +61,7 @@ function model_from_X(problem, X) result(model) lij(1, 2) = X(2) lij(2, 1) = X(2) - model = problem%model - + associate(model => problem%model) select type (model) class is (CubicEoS) associate (mr => model%mixrule) @@ -74,6 +72,7 @@ function model_from_X(problem, X) result(model) end select end associate end select - end function model_from_X + end associate + end subroutine end module yaeos__fitting_fit_kij_lij diff --git a/src/fitting/fit_nrtl_mhv.f90 b/src/fitting/fit_nrtl_mhv.f90 new file mode 100644 index 000000000..a3e2ee77e --- /dev/null +++ b/src/fitting/fit_nrtl_mhv.f90 @@ -0,0 +1,55 @@ +module yaeos__fitting_fit_nrtl_mhv + use yaeos__constants, only: pr + use yaeos__fitting, only: FittingProblem + use yaeos__models, only: ArModel, NRTL, CubicEoS, MHV + use forsus, only: Substance + implicit none + + integer, parameter :: nc = 2 + + type, extends(FittingProblem) :: FitMHVNRTL + logical :: fit_nrtl = .false. + logical :: fit_lij = .false. + contains + procedure :: get_model_from_X => model_from_X + end type FitMHVNRTL + +contains + + subroutine model_from_X(problem, X) + use yaeos, only: R, RKPR, PengRobinson78, ArModel, QMR, CubicEoS + use yaeos__models_ar_cubic_quadratic_mixing, only: RKPR_D1mix + class(FitMHVNRTL), intent(in out) :: problem + real(pr), intent(in) :: X(:) + type(NRTL) :: ge + + real(pr) :: a(nc, nc), b(nc, nc), c(nc, nc) + + a=0; b=0; c=0 + + a(1, 2) = x(1) + a(2, 1) = x(2) + + b(1, 2) = x(3) + b(2, 1) = x(4) + + c(1, 2) = x(5) + c(2, 1) = x(6) + + ge = NRTL(a, b, c) + + associate (model => problem%model) + select type(model) + class is (CubicEoS) + associate(mr => model%mixrule) + select type (mr) + class is (MHV) + if (problem%fit_lij) mr%l(1, 2) = x(7) + if (problem%fit_lij) mr%l(2, 1) = x(7) + if (problem%fit_nrtl) mr%ge = ge + end select + end associate + end select + end associate + end subroutine model_from_X +end module yaeos__fitting_fit_nrtl_mhv diff --git a/src/fitting/fitting.f90 b/src/fitting/fitting.f90 index 8ba3b9611..761081e97 100644 --- a/src/fitting/fitting.f90 +++ b/src/fitting/fitting.f90 @@ -26,21 +26,17 @@ module yaeos__fitting end type FittingProblem abstract interface - function model_from_X(problem, X) + subroutine model_from_X(problem, X) !! Function that returns a setted model from the parameters vector import ArModel, FittingProblem, pr - class(FittingProblem), intent(in) :: problem + class(FittingProblem), intent(in out) :: problem real(pr), intent(in) :: X(:) - - class(ArModel), allocatable :: model_from_X - end function model_from_X + end subroutine model_from_X end interface type(bar_object), private :: bar integer, private :: count - class(ArModel), private, allocatable :: model - contains real(pr) function optimize(X, func_data) result(y) @@ -55,13 +51,14 @@ real(pr) function optimize(X, func_data) result(y) type(nlopt_opt) :: opt !! Optimizer type(nlopt_func) :: f !! Function to optimize integer :: stat - + integer :: i + count = 0 call bar%initialize(& prefix_string='Fitting... ',& width=1, spinner_string='⠋', spinner_color_fg='blue', & min_value=0._pr, max_value=100._pr & - ) + ) call bar%start ! opt = nlopt_opt(nlopt_algorithm_enum%LN_NELDERMEAD, size(X)) @@ -71,7 +68,12 @@ real(pr) function optimize(X, func_data) result(y) f = create_nlopt_func(fobj, f_data=func_data) - dx = func_data%parameter_step + if (.not. allocated(func_data%parameter_step)) then + dx = [(0.05_pr, i=1, size(X))] + else + dx = func_data%parameter_step + end if + call opt%set_ftol_rel(func_data%solver_tolerance) call opt%set_initial_step(dx) @@ -106,60 +108,76 @@ real(pr) function fobj(x, gradient, func_data) class is(FittingProblem) fobj = error_function(X, func_data) if (func_data%verbose) then - call bar%update(current=real(count,pr)/(count + 100)) - write(*, "(E15.4, 2x)", advance="no") fobj + call bar%update(current=real(count,pr)/(count + 100)) + write(*, "(E15.4, 2x)", advance="no") fobj end if end select - write(2, *) X, fobj + write(2, "(*(E15.4,2x))") X, fobj write(1, "(/)") - + count = count + 1 end function fobj real(pr) function error_function(X, func_data) result(fobj) + !! # `error_function` + !! Error function for phase-equilibria optimization. Using two-phase + !! points and an error function of: + !! + !! \[ + !! FO = \sum_i (\frac{P_i^{exp} - P_i^{calc}}{P_i^{exp}})^2 + !! + \sum_i (y_i^{exp} - y_i^{calc})**2 + !! + \sum_i (x_i^{exp} - x_i^{calc})**2 + !! \] use yaeos__math, only: sq_error real(pr), intent(in) :: X(:) - class(FittingProblem), intent(in) :: func_data + class(FittingProblem) :: func_data type(EquilibriaState) :: model_point !! Each solved point type(EquilibriaState) :: exp_point integer :: i - model = func_data%get_model_from_X(X) + ! Update the problem model to the new vector of parameters + call func_data%get_model_from_X(X) + fobj = 0 - do i=1, size(func_data%experimental_points) - exp_point = func_data%experimental_points(i) - - select case(exp_point%kind) - case("bubble") - model_point = saturation_pressure(& - model, exp_point%x, exp_point%t, kind="bubble", & - p0=exp_point%p, y0=exp_point%y & - ) - case("dew") - model_point = saturation_pressure(& - model, exp_point%y, exp_point%t, kind="dew", & - p0=exp_point%p, y0=exp_point%x & - ) - case("liquid-liquid") - model_point = saturation_pressure(& - model, exp_point%x, exp_point%t, kind="liquid-liquid", & - p0=exp_point%p, y0=exp_point%y & - ) - - end select - - fobj = fobj + sq_error(exp_point%p, model_point%p) - fobj = fobj + maxval(sq_error(exp_point%y, model_point%y)) - fobj = fobj + maxval(sq_error(exp_point%x, model_point%x)) - write(1, *) exp_point, model_point - - if(isnan(fobj)) then - fobj = 1e6 - exit - end if - end do + associate( model => func_data%model ) + + ! Calculate each point and calculate its error. + ! if at some point there is a NaN value, assign a big number and + ! exit + do i=1, size(func_data%experimental_points) + exp_point = func_data%experimental_points(i) + + select case(exp_point%kind) + case("bubble") + model_point = saturation_pressure(& + model, exp_point%x, exp_point%t, kind="bubble", & + p0=exp_point%p, y0=exp_point%y & + ) + case("dew") + model_point = saturation_pressure(& + model, exp_point%y, exp_point%t, kind="dew", & + p0=exp_point%p, y0=exp_point%x & + ) + case("liquid-liquid") + model_point = saturation_pressure(& + model, exp_point%x, exp_point%t, kind="liquid-liquid", & + p0=exp_point%p, y0=exp_point%y & + ) + end select + + fobj = fobj + sq_error(exp_point%p, model_point%p) + fobj = fobj + maxval(sq_error(exp_point%y, model_point%y)) + fobj = fobj + maxval(sq_error(exp_point%x, model_point%x)) + write(1, *) exp_point, model_point + + if(isnan(fobj)) then + ! fobj = 1e6 + exit + end if + end do + end associate end function error_function end module yaeos__fitting diff --git a/src/math/linalg.f90 b/src/math/linalg.f90 index d293fefde..82523eb85 100644 --- a/src/math/linalg.f90 +++ b/src/math/linalg.f90 @@ -26,7 +26,7 @@ subroutine dgesv(n, nrhs, a, lda, ipiv, b, ldb, info) real(dp) :: b(n) integer :: ldb integer :: info - end subroutine + end subroutine dgesv end interface n = size(a, dim=1) @@ -42,4 +42,110 @@ subroutine dgesv(n, nrhs, a, lda, ipiv, b, ldb, info) x = b_lapack end function solve_system -end module \ No newline at end of file + + subroutine cubic_roots(parameters, real_roots, complex_roots, flag) + use stdlib_sorting, only: sort + real(pr), parameter :: pi=atan(1.0_pr) * 4.0_pr + real(pr), intent(in) :: parameters(4) + real(pr), intent(out) :: real_roots(3) + complex(pr), intent(out) :: complex_roots(3) + integer, intent(out) :: flag + !! flag that identifies which case the solution is + !! - `0`: 3 real rotos, one of them repeated (use real_roots(1) and real_roots(2)) + !! - `1`: 1 real root, 2 complex roots. + !! Use real_roots(1) and complex_roots(1) and complex_roots(2) + !! - `-1`: 3 real roots, all different + + real(pr) :: p, q, u, v, nan + real(pr) :: disc, theta + + nan = 0 + nan = nan/nan + + associate(& + a => parameters(1), b => parameters(2), & + c => parameters(3), d => parameters(4)& + ) + + p = c/a - b**2/(3*a**2) + q = d/a - b*c/(3*a**2) + 2*b**3/(27*a**3) + + disc = q**2 + 4 * p**3 / 27 + real_roots = nan + complex_roots = nan + + if (abs(disc) < 1e-15) then + flag = 0 + real_roots(1) = 3*q/p + real_roots(2) = -3*q/(2*p) + real_roots(3) = real_roots(2) + elseif (disc < 0) then + flag = -1 + theta = acos(0.5_pr * 3 * q / p * sqrt(-3/p)) + real_roots(1) = 2 * sqrt(-p/3) * cos(theta/3) + real_roots(2) = 2 * sqrt(-p/3) * cos((theta + 2*pi)/3) + real_roots(3) = 2 * sqrt(-p/3) * cos((theta + 4*pi)/3) + call sort(real_roots) + elseif (disc > 0) then + flag = 1 + u = ((-q + sqrt(disc))/2) + v = ((-q - sqrt(disc))/2) + + u = sign(abs(u)**(1.0_pr/3.0_pr), u) + v = sign(abs(v)**(1.0_pr/3.0_pr), v) + real_roots(1) = u + v + endif + real_roots = real_roots - b/(3*a) + end associate + end subroutine cubic_roots + + subroutine cubic_roots_rosendo(parameters, real_roots, complex_roots, flag) + use stdlib_sorting, only: sort + real(pr), parameter :: pi=atan(1.0_pr) * 4.0_pr + real(pr), intent(in) :: parameters(4) + real(pr), intent(out) :: real_roots(3) + complex(pr), intent(out) :: complex_roots(3) + integer, intent(out) :: flag + + real(pr) :: d1, d2, d3, Q, R, A, B, theta, alp, bet, gam + integer :: i + + d1 = parameters(2) / parameters(1) + d2 = parameters(3) / parameters(1) + d3 = parameters(4) / parameters(1) + + Q = (d1**2 - 3*d2) / 9.0_pr + R = (2*d1**3 - 9*d1*d2 + 27*d3) / 54.0_pr + + if (R**2 <= Q**3) then + theta = acos(R / sqrt(Q**3)) + + real_roots(1) = -2 * sqrt(Q) * cos(theta / 3.0_pr) - d1 / 3.0_pr + real_roots(2) = -2 * sqrt(Q) * cos((theta + 2 * pi) / 3.0_pr) - d1 / 3.0_pr + real_roots(3) = -2 * sqrt(Q) * cos((theta - 2 * pi) / 3.0_pr) - d1 / 3.0_pr + + ! Correction?? + ! do i=1,100 + ! real_roots(1) = -d1 - (real_roots(2) + real_roots(3)) + ! real_roots(2) = (d2 - real_roots(1) * real_roots(3)) / (real_roots(1) + real_roots(3)) + ! real_roots(3) = -d3 / (real_roots(1) * real_roots(2)) + ! end do + + call sort(real_roots) + flag = -1 + else + A = - sign((abs(R) + sqrt(R**2 - Q**3))**(1.0_pr/3.0_pr), R) + + if (abs(A) < 1e-6) then + A = 0.0_pr + B = 0.0_pr + else + B = Q / A + end if + + real_roots = (A + B) - d1 / 3.0_pr + flag = 1 + end if + end subroutine + +end module yaeos__math_linalg diff --git a/src/math/math.f90 b/src/math/math.f90 index 292b1ac0b..6e42d8610 100644 --- a/src/math/math.f90 +++ b/src/math/math.f90 @@ -27,7 +27,23 @@ module yaeos__math !! ``` use yaeos__math_continuation, only: continuation - use yaeos__math_linalg, only: solve_system + use yaeos__math_linalg, only: solve_system, cubic_roots + use yaeos__constants, only: pr + + implicit none + + abstract interface + subroutine f_1d(x, f, df) + import pr + real(pr), intent(in) :: x + real(pr), intent(out) :: f + real(pr), intent(out) :: df + end subroutine f_1d + end interface + + interface newton + module procedure :: newton_1d + end interface newton contains elemental real(pr) function sq_error(exp, pred) @@ -62,11 +78,38 @@ function dx_to_dn(x, dx) result(dn) real(pr) :: dn(size(x)) real(pr) :: sum_xdx - + dn = 0 sum_xdx = sum(x * dx) dn = dx - sum_xdx end function dx_to_dn + + subroutine newton_1d(f, x, tol, max_iters) + procedure(f_1d) :: f + real(pr), intent(in out) :: x + real(pr), intent(in) :: tol + integer, intent(in) :: max_iters + + integer :: i + real(pr) :: fval, df, step + + + fval = 10 + step = 10 + + do i=1, max_iters + if (abs(fval) < tol .or. abs(step) < tol) exit + call f(x, fval, df) + + step = fval/df + + do while (abs(step) > 0.5 * abs(x)) + step = step/2 + end do + + x = x - step + end do + end subroutine newton_1d end module yaeos__math diff --git a/src/models/excess_gibbs/group_contribution/model_parameters.f90 b/src/models/excess_gibbs/group_contribution/model_parameters.f90 index 16ec0fa74..0b029f4d8 100644 --- a/src/models/excess_gibbs/group_contribution/model_parameters.f90 +++ b/src/models/excess_gibbs/group_contribution/model_parameters.f90 @@ -23,10 +23,14 @@ module yaeos__models_ge_group_contribution_model_parameters !! \(c_{ij}\) for the maingroups interaction parameters. In the case of !! the classic UNIFAC model that only requires \(a_{ij}\) parameters, the !! \(b_{ij}\) and \(c_{ij}\) must be set as null matrixes. - !! The documentation and source code of `yaeos` `UNIFACParameters` + !! The documentation and source code of `yaeos` [[UNIFACParameters]] !! function could be consulted to understand how to instantiate a - !! `GeGCModelParameters` object with the classic liquid-vapor UNIFAC - !! parameters defined in: https://www.ddbst.com/published-parameters-unifac.html + !! [[GeGCModelParameters]] object with the classic liquid-vapor UNIFAC + !! parameters defined in DDBST. + !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) !! integer, allocatable :: subgroups_ids(:) !! ID of each model's subgroup @@ -82,6 +86,10 @@ function get_subgroup_index(self, subgroup_id) result(subgroup_idx) !! print *, parameters%get_subgroup_index(178) ! Will print: 112 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_id @@ -114,6 +122,10 @@ function get_maingroup_index(self, maingroup_id) result(maingroup_idx) !! print *, parameters%get_maingroup_index(55) ! Will print: 52 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: maingroup_id @@ -146,6 +158,10 @@ function get_subgroup_maingroup(self, subgroup_id) result(subgroup_maingroup) !! print *, parameters%get_subgroup_maingroup(16) ! Will print: 7 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_id @@ -182,6 +198,10 @@ function get_subgroup_R(self, subgroup_id) result(subgroup_R) !! print *, parameters%get_subgroup_R(1) ! Will print: 0.9011 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_id @@ -218,6 +238,10 @@ function get_subgroup_Q(self, subgroup_id) result(subgroup_Q) !! print *, parameters%get_subgroup_Q(1) ! Will print: 0.8480 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_id @@ -234,10 +258,10 @@ end function get_subgroup_Q function get_maingroups_aij(self, maingroup_i_id, maingroup_j_id) result(aij) !! # get_maingroups_aij - !! Get the interaction parameter \(a_{ij} \) + !! Get the interaction parameter \(a_{ij}\) !! !! # Description - !! Get the interaction parameter \(a_{ij} \) of the maingroups `i` and `j` + !! Get the interaction parameter \(a_{ij}\) of the maingroups `i` and `j` !! ids. !! !! # Examples @@ -254,6 +278,10 @@ function get_maingroups_aij(self, maingroup_i_id, maingroup_j_id) result(aij) !! print *, parameters%get_maingroups_aij(1, 7) ! prints: 1318.0000 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: maingroup_i_id @@ -261,7 +289,7 @@ function get_maingroups_aij(self, maingroup_i_id, maingroup_j_id) result(aij) integer, intent(in) :: maingroup_j_id !! ID of the maingroup `j` real(pr) :: aij - !! Interaction parameter \(a_{ij} \) + !! Interaction parameter \(a_{ij}\) integer :: i, j @@ -273,10 +301,10 @@ end function get_maingroups_aij function get_maingroups_bij(self, maingroup_i_id, maingroup_j_id) result(bij) !! # get_maingroups_bij - !! Get the interaction parameter \(b_{ij} \) + !! Get the interaction parameter \(b_{ij}\) !! !! # Description - !! Get the interaction parameter \(b_{ij} \) of the maingroups `i` and `j` + !! Get the interaction parameter \(b_{ij}\) of the maingroups `i` and `j` !! ids. !! !! # Examples @@ -293,9 +321,13 @@ function get_maingroups_bij(self, maingroup_i_id, maingroup_j_id) result(bij) !! print *, parameters%get_maingroups_bij(1, 7) ! prints: 0.0 !! ``` !! - !! In the example we obtain 0.0 because UNIFAC only have \(a_{ij} \) + !! In the example we obtain 0.0 because UNIFAC only have \(a_{ij}\) !! parameters !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: maingroup_i_id @@ -303,7 +335,7 @@ function get_maingroups_bij(self, maingroup_i_id, maingroup_j_id) result(bij) integer, intent(in) :: maingroup_j_id !! ID of the maingroup `j` real(pr) :: bij - !! Interaction parameter \(b_{ij} \) + !! Interaction parameter \(b_{ij}\) integer :: i, j @@ -315,10 +347,10 @@ end function get_maingroups_bij function get_maingroups_cij(self, maingroup_i_id, maingroup_j_id) result(cij) !! # get_maingroups_cij - !! Get the interaction parameter \(c_{ij} \) + !! Get the interaction parameter \(c_{ij}\) !! !! # Description - !! Get the interaction parameter \(c_{ij} \) of the maingroups `i` and `j` + !! Get the interaction parameter \(c_{ij}\) of the maingroups `i` and `j` !! ids. !! !! # Examples @@ -338,6 +370,10 @@ function get_maingroups_cij(self, maingroup_i_id, maingroup_j_id) result(cij) !! In the example we obtain 0.0 because UNIFAC only have \(a_{ij} \) !! parameters !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: maingroup_i_id @@ -345,7 +381,7 @@ function get_maingroups_cij(self, maingroup_i_id, maingroup_j_id) result(cij) integer, intent(in) :: maingroup_j_id !! ID of the maingroup `j` real(pr) :: cij - !! Interaction parameter \(c_{ij} \) + !! Interaction parameter \(c_{ij}\) integer :: i, j @@ -357,10 +393,10 @@ end function get_maingroups_cij function get_subgroups_aij(self, subgroup_i_id, subgroup_j_id) result(aij) !! # get_subgroups_aij - !! Get the interaction parameter \(a_{ij} \) + !! Get the interaction parameter \(a_{ij}\) !! !! # Description - !! Get the interaction parameter \(a_{ij} \) of the subgroups `i` and `j` + !! Get the interaction parameter \(a_{ij}\) of the subgroups `i` and `j` !! ids. !! !! # Examples @@ -378,6 +414,10 @@ function get_subgroups_aij(self, subgroup_i_id, subgroup_j_id) result(aij) !! print *, parameters%get_subgroups_aij(1, 16) ! prints: 1318.0000 !! ``` !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_i_id @@ -385,7 +425,7 @@ function get_subgroups_aij(self, subgroup_i_id, subgroup_j_id) result(aij) integer, intent(in) :: subgroup_j_id !! ID of the subgroup `j` real(pr) :: aij - !! Interaction parameter \(a_{ij} \) + !! Interaction parameter \(a_{ij}\) integer :: mi_id, mj_id, i, j @@ -400,10 +440,10 @@ end function get_subgroups_aij function get_subgroups_bij(self, subgroup_i_id, subgroup_j_id) result(bij) !! # get_subgroups_bij - !! Get the interaction parameter \(b_{ij} \) + !! Get the interaction parameter \(b_{ij}\) !! !! # Description - !! Get the interaction parameter \(b_{ij} \) of the subgroups `i` and `j` + !! Get the interaction parameter \(b_{ij}\) of the subgroups `i` and `j` !! ids. !! !! # Examples @@ -424,6 +464,10 @@ function get_subgroups_bij(self, subgroup_i_id, subgroup_j_id) result(bij) !! In the example we obtain 0.0 because UNIFAC only have \(a_{ij} \) !! parameters !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_i_id @@ -431,7 +475,7 @@ function get_subgroups_bij(self, subgroup_i_id, subgroup_j_id) result(bij) integer, intent(in) :: subgroup_j_id !! ID of the subgroup `j` real(pr) :: bij - !! Interaction parameter \(b_{ij} \) + !! Interaction parameter \(b_{ij}\) integer :: mi_id, mj_id, i, j @@ -446,10 +490,10 @@ end function get_subgroups_bij function get_subgroups_cij(self, subgroup_i_id, subgroup_j_id) result(cij) !! # get_subgroups_cij - !! Get the interaction parameter \(c_{ij} \) + !! Get the interaction parameter \(c_{ij}\) !! !! # Description - !! Get the interaction parameter \(c_{ij} \) of the subgroups `i` and `j` + !! Get the interaction parameter \(c_{ij}\) of the subgroups `i` and `j` !! ids. !! !! # Examples @@ -470,6 +514,10 @@ function get_subgroups_cij(self, subgroup_i_id, subgroup_j_id) result(cij) !! In the example we obtain 0.0 because UNIFAC only have \(a_{ij} \) !! parameters !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.dd + !! bst.com/published-parameters-unifac.html) + !! class(GeGCModelParameters) :: self integer, intent(in) :: subgroup_i_id @@ -477,7 +525,7 @@ function get_subgroups_cij(self, subgroup_i_id, subgroup_j_id) result(cij) integer, intent(in) :: subgroup_j_id !! ID of the subgroup `j` real(pr) :: cij - !! Interaction parameter \(c_{ij} \) + !! Interaction parameter \(c_{ij}\) integer :: mi_id, mj_id, i, j diff --git a/src/models/excess_gibbs/group_contribution/unifac.f90 b/src/models/excess_gibbs/group_contribution/unifac.f90 index ca852312b..f89c96174 100644 --- a/src/models/excess_gibbs/group_contribution/unifac.f90 +++ b/src/models/excess_gibbs/group_contribution/unifac.f90 @@ -34,6 +34,41 @@ module yaeos__models_ge_group_contribution_unifac !! ``` !! !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! 9. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) !! use yaeos__constants, only: pr, R use yaeos__models_ge, only: GeModel @@ -64,7 +99,8 @@ module yaeos__models_ge_group_contribution_unifac !! ``` !! !! # References - !! https://www.ddbst.com/published-parameters-unifac.html + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) integer, allocatable :: groups_ids(:) !! Indexes (ids) of each subgroup in the main group matrix integer, allocatable :: number_of_groups(:) @@ -114,6 +150,44 @@ module yaeos__models_ge_group_contribution_unifac !! !! print *, ln_gammas ! result: 0.10505475697637946 0.28073129552766890 !! ``` + !! + !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! 9. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) + !! integer :: ngroups !! Total number of individual groups in the mixture integer :: nmolecules @@ -193,6 +267,41 @@ end subroutine temperature_dependence !! \] !! !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! 9. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) !! real(pr), allocatable :: Aij(:, :) contains @@ -263,8 +372,6 @@ subroutine excess_gibbs(self, n, T, Ge, GeT, GeT2, Gen, GeTn, Gen2) !! print *, "ln_gammas: ", ln_gammas !! ``` !! - !! # References - !! class(UNIFAC), intent(in) :: self !! UNIFAC model real(pr), intent(in) :: n(:) @@ -384,7 +491,7 @@ subroutine Ge_combinatorial(self, n, T, Ge, dGe_dn, dGe_dn2) !! \] !! !! # References - !! SINTEF (https://github.com/thermotools/thermopack) + !! 1. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) class(UNIFAC) :: self real(pr), intent(in) :: n(self%nmolecules) @@ -598,7 +705,7 @@ subroutine Ge_residual(self, n, T, Ge, dGe_dn, dGe_dn2, dGe_dT, dGe_dT2, dGe_dTn !! \] !! !! # References - !! SINTEF (https://github.com/thermotools/thermopack) + !! 1. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) class(UNIFAC) :: self real(pr), intent(in) :: n(self%nmolecules) @@ -896,6 +1003,41 @@ subroutine UNIFAC_temperature_dependence(& !! \] !! !! # References + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! 9. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) !! class(UNIFACPsi) :: self !! \(\psi\) function @@ -906,9 +1048,9 @@ subroutine UNIFAC_temperature_dependence(& real(pr), optional, intent(out) :: psi(:, :) !! \(\psi\) real(pr), optional, intent(out) :: dpsi_dt(:, :) - !! \(\frac{d \psi\}{dT} \) + !! \(\frac{d \psi}{dT}\) real(pr), optional, intent(out) :: dpsi_dt2(:, :) - !! \(\frac{d^2 \psi\}{dT^2} \) + !! \(\frac{d^2 \psi}{dT^2}\) integer :: i, j integer :: ngroups @@ -942,7 +1084,7 @@ function thetas_i(nm, ng, parameters, stew, molecules) result(thetas_ij) !! dependence) !! !! # References - !! + !! 1. [SINTEF - Thermopack](https://github.com/thermotools/thermopack) integer, intent(in) :: nm !! Number of molecules integer, intent(in) :: ng !! Number of groups type(GeGCModelParameters), intent(in) :: parameters !! UNIFAC parameters @@ -1027,7 +1169,8 @@ type(UNIFAC) function setup_unifac(molecules, parameters) !! ``` !! !! # References - !! https://www.ddbst.com/published-parameters-unifac.html + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) !! type(Groups), intent(in) :: molecules(:) !! Molecules (Group type) objects diff --git a/src/models/excess_gibbs/group_contribution/unifac_parameters.f90 b/src/models/excess_gibbs/group_contribution/unifac_parameters.f90 index e87be941d..1c9faf958 100644 --- a/src/models/excess_gibbs/group_contribution/unifac_parameters.f90 +++ b/src/models/excess_gibbs/group_contribution/unifac_parameters.f90 @@ -21,7 +21,41 @@ module yaeos__models_ge_group_contribution_unifac_parameters !! ``` !! !! # References - !! https://www.ddbst.com/published-parameters-unifac.html + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! use yaeos__constants, only: pr use yaeos__models_ge_group_contribution_model_parameters, only: GeGCModelParameters implicit none @@ -61,7 +95,7 @@ type(GeGCModelParameters) function UNIFACParameters() !! !! ! Model setup !! ! Disclaimer: the default parameters object can be ommited in the - !! ! setup_unifac call, because if the parameters argument is not + !! ! setup_unifac call, because if the parameters argument is not !! ! provided, the return of the constructor UNIFACParameters() will be !! ! used either way. This is just a demostration. !! model = setup_unifac(molecules, parameters) @@ -73,7 +107,41 @@ type(GeGCModelParameters) function UNIFACParameters() !! ``` !! !! # References - !! https://www.ddbst.com/published-parameters-unifac.html + !! 1. [Dortmund Data Bank Software & Separation Technology](https://www.ddbst + !! .com/published-parameters-unifac.html) + !! 2. Fredenslund, A., Jones, R. L., & Prausnitz, J. M. (1975). + !! Group‐contribution estimation of activity coefficients in nonideal liquid + !! mixtures. AIChE Journal, 21(6), 1086–1099. + !! [https://doi.org/10.1002/aic.690210607](https://doi.org/10.1002/aic.690210607) + !! 3. Skjold-Jorgensen, S., Kolbe, B., Gmehling, J., & Rasmussen, P. (1979). + !! Vapor-Liquid Equilibria by UNIFAC Group Contribution. Revision and + !! Extension. Industrial & Engineering Chemistry Process Design and + !! Development, 18(4), 714–722. + !! [https://doi.org/10.1021/i260072a024](https://doi.org/10.1021/i260072a024) + !! 4. Gmehling, J., Rasmussen, P., & Fredenslund, A. (1982). Vapor-liquid + !! equilibriums by UNIFAC group contribution. Revision and extension. 2. + !! Industrial & Engineering Chemistry Process Design and Development, 21(1), + !! 118–127. + !! [https://doi.org/10.1021/i200016a021](https://doi.org/10.1021/i200016a021) + !! 5. Macedo, E. A., Weidlich, U., Gmehling, J., & Rasmussen, P. (1983). + !! Vapor-liquid equilibriums by UNIFAC group contribution. Revision and + !! extension. 3. Industrial & Engineering Chemistry Process Design and + !! Development, 22(4), 676–678. + !! [https://doi.org/10.1021/i200023a023](https://doi.org/10.1021/i200023a023) + !! 6. Tiegs, D., Rasmussen, P., Gmehling, J., & Fredenslund, A. (1987). + !! Vapor-liquid equilibria by UNIFAC group contribution. 4. Revision and + !! extension. Industrial & Engineering Chemistry Research, 26(1), 159–161. + !! [https://doi.org/10.1021/ie00061a030](https://doi.org/10.1021/ie00061a030) + !! 7. Hansen, H. K., Rasmussen, P., Fredenslund, A., Schiller, M., & + !! Gmehling, J. (1991). Vapor-liquid equilibria by UNIFAC group + !! contribution. 5. Revision and extension. Industrial & Engineering + !! Chemistry Research, 30 (10), 2352–2355. + !! [https://doi.org/10.1021/ie00058a017](https://doi.org/10.1021/ie00058a017) + !! 8. Wittig, R., Lohmann, J., & Gmehling, J. (2003). Vapor−Liquid Equilibria + !! by UNIFAC Group Contribution. 6. Revision and Extension. Industrial & + !! Engineering Chemistry Research, 42(1), 183–188. + !! [https://doi.org/10.1021/ie020506l](https://doi.org/10.1021/ie020506l) + !! ! ======================================================================== ! UNIFAC subgroups ids definition ! ------------------------------------------------------------------------ diff --git a/src/models/excess_gibbs/nrtl.f90 b/src/models/excess_gibbs/nrtl.f90 index c55fcf297..7d6224854 100644 --- a/src/models/excess_gibbs/nrtl.f90 +++ b/src/models/excess_gibbs/nrtl.f90 @@ -1,5 +1,6 @@ module yaeos__models_ge_NRTL use yaeos__tapenade_ge_api, only: gemodeltapenade + use yaeos__tapenade_interfaces use yaeos__constants, only: pr, R implicit none @@ -29,6 +30,8 @@ module yaeos__models_ge_NRTL interface NRTL module procedure :: init end interface + + contains type(NRTL) function init(a, b, c) @@ -376,12 +379,6 @@ subroutine EXCESS_GIBBS_D_B(model, n, nb, nd, ndb, t, tb, td, tdb, ge& real(pr) :: tempb4 real(pr) :: tempb5 integer :: ad_to - external PUSHREAL8ARRAY - external PUSHREAL8 - external PUSHINTEGER4 - external POPINTEGER4 - external POPREAL8 - external POPREAL8ARRAY integer :: arg10 real(pr) :: result1 temp = sum(n) diff --git a/src/models/models.f90 b/src/models/models.f90 index 74ad6e164..336a8f3a6 100644 --- a/src/models/models.f90 +++ b/src/models/models.f90 @@ -24,7 +24,7 @@ module yaeos__models use yaeos__models_base, only: BaseModel ! Residual Helmholtz Models - use yaeos__models_ar, only: ArModel + use yaeos__models_ar, only: ArModel, size ! Cubic EoS models use yaeos__models_ar_genericcubic, only: & diff --git a/src/models/residual_helmholtz/ar_models.f90 b/src/models/residual_helmholtz/ar_models.f90 index 306b3979d..583ad108f 100644 --- a/src/models/residual_helmholtz/ar_models.f90 +++ b/src/models/residual_helmholtz/ar_models.f90 @@ -1,5 +1,6 @@ module yaeos__models_ar - !! Module that defines the basics of a residual Helmholtz energy. + + !! # Module that defines the basics of a residual Helmholtz energy. !! !! All the residual properties that are calculated in this library are !! based on residual Helmholtz Equations of State. Following the book by @@ -9,9 +10,29 @@ module yaeos__models_ar !! are used. Because they're the fundamentals for phase equilibria !! calculation. !! - !! @note Later on, third derivative with respect to volume will be included + !! @note + !! Later on, third derivative with respect to volume will be included !! since it's importance on calculation of critical points. - use yaeos__constants, only: pr + !! @endnote + !! + !! # Properties + !! + !! ## Available properties: + !! + !! - pressure(n, V, T) + !! - fugacity(n, V, T) + !! - fugacity(n, P, T, root=[vapor, liquid, stable]) + !! - volume + !! + !! Calculate thermodynamic properties using Helmholtz energy as a basis. + !! All the routines in this module work with the logic: + !! + !! ```fortran + !! call foo(x, V, T, [dfoodv, dfoodT, ...]) + !! ``` + !! Where the user can call the routine of the desired property. And include + !! as optional values the desired derivatives of said properties. + use yaeos__constants, only: pr, R use yaeos__models_base, only: BaseModel implicit none @@ -27,10 +48,21 @@ module yaeos__models_ar character(len=:), allocatable :: name !! Name of the model contains procedure(abs_residual_helmholtz), deferred :: residual_helmholtz - !! Method to calculate residual helmholtz energy and derivatives. procedure(abs_volume_initializer), deferred :: get_v0 - !! Volume initializer - end type + procedure :: lnphi_vt => fugacity_vt + procedure :: lnphi_pt => fugacity_pt + procedure :: pressure + procedure :: volume + procedure :: enthalpy_residual_vt + procedure :: gibbs_residual_vt + procedure :: entropy_residual_vt + procedure :: Cv_residual_vt + procedure :: Cp_residual_vt + end type ArModel + + interface size + module procedure :: size_ar_model + end interface size abstract interface subroutine abs_residual_helmholtz(& @@ -67,16 +99,396 @@ subroutine abs_residual_helmholtz(& real(pr), optional, intent(out) :: ArVn(size(n)) !! \(\frac{d^2Ar}{dVn_i}\) real(pr), optional, intent(out) :: ArTn(size(n)) !! \(\frac{d^2Ar}{dTn_i}\) real(pr), optional, intent(out) :: Arn2(size(n), size(n))!! \(\frac{d^2Ar}{dn_{ij}}\) - end subroutine + end subroutine abs_residual_helmholtz function abs_volume_initializer(self, n, p, t) - !! Initialization of volume. + !! Function that provides an initializer value for the liquid-root + !! of newton solver of volume. In the case the model will use the + !! `volume_michelsen` routine this value should provide the co-volume + !! of the model. import ArModel, pr class(ArModel), intent(in) :: self !! Ar Model real(pr), intent(in) :: n(:) !! Moles vector real(pr), intent(in) :: p !! Pressure [bar] real(pr), intent(in) :: t !! Temperature [K] real(pr) :: abs_volume_initializer !! Initial volume [L] - end function + end function abs_volume_initializer end interface -end module + +contains + + integer pure function size_ar_model(eos) + !! Get the size of the model. + class(ArModel), intent(in) :: eos + size_ar_model = size(eos%components%pc) + end function size_ar_model + + subroutine volume(eos, n, P, T, V, root_type) + !! # Volume solver routine for residual Helmholtz models. + !! Solves volume roots using newton method. Given pressure and temperature. + !! + !! # Description + !! This subroutine solves the volume using a newton method. The variable + !! `root_type` + !! + !! # Examples + !! + !! ```fortran + !! class(ArModel) :: eos + !! call eos%volume(n, P, T, V, root_type="liquid") + !! call eos%volume(n, P, T, V, root_type="vapor") + !! call eos%volume(n, P, T, V, root_type="stable") + !! ``` + use yaeos__constants, only: pr, R + use yaeos__math, only: newton + class(ArModel), intent(in) :: eos + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(out) :: V !! Volume [L] + character(len=*), intent(in) :: root_type + !! Desired root-type to solve. Options are: + !! `["liquid", "vapor", "stable"]` + + integer :: max_iters=30 + real(pr) :: tol=1e-7 + + real(pr) :: totnRT, GrL, GrV, Gr + real(pr) :: Vliq, Vvap + + GrL = HUGE(GrL) + GrV = HUGE(GrV) + + totnRT = sum(n) * R * T + select case(root_type) + case("liquid") + Vliq = eos%get_v0(n, P, T) * 1.001_pr + call newton(foo, Vliq, tol=tol, max_iters=max_iters) + GrL = Gr + case("vapor") + Vvap = R * T / P + call newton(foo, Vvap, tol=tol, max_iters=max_iters) + GrV = Gr + case("stable") + Vliq = eos%get_v0(n, P, T)*1.00001_pr + call newton(foo, Vliq, tol=tol, max_iters=max_iters) + GrL = Gr + + Vvap = R * T / P + call newton(foo, Vvap, tol=tol, max_iters=max_iters) + GrV = Gr + end select + + if (GrL < GrV) then + V = Vliq + else + V = Vvap + end if + + contains + subroutine foo(x, f, df) + real(pr), intent(in) :: x + real(pr), intent(out) :: f, df + real(pr) :: Ar, ArV, ArV2, Pcalc, dPcalcdV, Vin + Vin = x + call eos%residual_helmholtz(n, Vin, T, Ar=Ar, ArV=ArV, ArV2=ArV2) + Pcalc = totnRT / Vin - ArV + dPcalcdV = -totnRT / Vin**2 - ArV2 + f = Pcalc - p + df = dPcalcdV + Gr = Ar + P * Vin - totnRT - totnRT * log(P*Vin/(R*T)) + end subroutine foo + end subroutine volume + + subroutine pressure(eos, n, V, T, P, dPdV, dPdT, dPdn) + !! Pressure calculation. + !! + !! Calculate pressure using residual helmholtz models. + !! + !! # Examples + !! ```fortran + !! class(ArModel), allocatable :: eos + !! real(pr) :: n(2), t, v, p, dPdV, dPdT, dPdn(2) + !! eos = PengRobinson(Tc, Pc, w) + !! n = [1.0_pr, 1.0_pr] + !! t = 300.0_pr + !! v = 1.0_pr + !! call eos%pressure(n, V, T, P, dPdV=dPdV, dPdT=dPdT, dPdn=dPdn) + !! ``` + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: t !! Temperature [K] + real(pr), intent(in) :: v !! Volume [L] + real(pr), intent(out) :: p !! Pressure [bar] + real(pr), optional, intent(out) :: dPdV !! \(\frac{dP}}{dV}\) + real(pr), optional, intent(out) :: dPdT !! \(\frac{dP}}{dT}\) + real(pr), optional, intent(out) :: dPdn(:) !! \(\frac{dP}}{dn_i}\) + + real(pr) :: totn + + real(pr) :: Ar, ArV, ArV2, ArTV, ArVn(size(eos)) + integer :: nc + logical :: dn + + totn = sum(n) + nc = size(n) + + if (present(dPdn)) then + call eos%residual_helmholtz(& + n, v, t, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, ArVn=ArVn & + ) + else + call eos%residual_helmholtz(& + n, v, t, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV & + ) + end if + + P = totn * R * T/V - ArV + if (present(dPdV)) dPdV = -ArV2 - R*t*totn/V**2 + if (present(dPdT)) dPdT = -ArTV + totn*R/V + if (present(dPdn)) dPdn(:) = R*T/V - ArVn(:) + end subroutine pressure + + subroutine fugacity_pt(eos, & + n, P, T, V, root_type, lnPhi, dlnPhidP, dlnPhidT, dlnPhidn & + ) + !! Calculate logarithm of fugacity, given pressure and temperature. + !! + !! This routine will obtain the desired volume root at the specified + !! pressure and calculate fugacity at that point. + use iso_fortran_env, only: error_unit + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Mixture mole numbers + character(len=*), intent(in) :: root_type !! Type of root desired ["liquid", "vapor", "stable"] + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(in) :: T !! Temperature [K] + + real(pr), optional, intent(out) :: lnPhi(size(n)) !! \(\ln(phi)\) vector + real(pr), optional, intent(out) :: V !! Volume [L] + real(pr), optional, intent(out) :: dlnPhidT(size(n)) !! ln(phi) Temp derivative + real(pr), optional, intent(out) :: dlnPhidP(size(n)) !! ln(phi) Presssure derivative + real(pr), optional, intent(out) :: dlnPhidn(size(n), size(n)) !! ln(phi) compositional derivative + + real(pr) :: V_in, P_in + + call eos%volume(n, P=P, T=T, V=V_in, root_type=root_type) + call eos%lnphi_vt(n, V_in, T, P_in, lnPhi, dlnPhidP, dlnPhidT, dlnPhidn) + + if(present(V)) V = V_in + + ! Check if the calculated pressure is the same as the input pressure. + if(abs(P_in - P) > 1e-2) then + write(error_unit, *) "WARN: possible bad root solving: ", P_in, P + end if + end subroutine fugacity_pt + + subroutine fugacity_vt(eos, & + n, V, T, P, lnPhi, dlnPhidP, dlnPhidT, dlnPhidn, dPdV, dPdT, dPdn & + ) + !! Calculate fugacity coefficent given volume and temperature. + !! + !!@note + !!While the natural output variable is \(ln \phi_i P\). The calculated + !!derivatives will be the derivatives of the fugacity coefficient + !!\(ln \phi_i\) + !!@endnote + !! + class(ArModel) :: eos !! Model + real(pr), intent(in) :: n(:) !! Mixture mole numbers + real(pr), intent(in) :: V !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + + real(pr), optional, intent(out) :: P !! Pressure [bar] + real(pr), optional, intent(out) :: lnPhi(size(n)) !! \(\ln(\phi_i*P)\) vector + real(pr), optional, intent(out) :: dlnPhidT(size(n)) !! \(ln(phi_i)\) Temp derivative + real(pr), optional, intent(out) :: dlnPhidP(size(n)) !! \(ln(phi_i)\) Presssure derivative + real(pr), optional, intent(out) :: dlnPhidn(size(n), size(n)) !! \(ln(phi_i)\) compositional derivative + real(pr), optional, intent(out) :: dPdV !! \(\frac{dP}{dV}\) + real(pr), optional, intent(out) :: dPdT !! \(\frac{dP}{dT}\) + real(pr), optional, intent(out) :: dPdn(:) !! \(\frac{dP}{dn_i}\) + + real(pr) :: Ar, ArTV, ArV, ArV2 + real(pr), dimension(size(n)) :: Arn, ArVn, ArTn + real(pr) :: Arn2(size(n), size(n)) + + real(pr) :: dPdV_in, dPdT_in, dPdn_in(size(n)) + real(pr) :: P_in + + real(pr) :: RT, Z + + real(pr) :: totn + integer :: nc, i, j + + totn = sum(n) + nc = size(n) + + RT = R*T + + if (present(lnPhi) .and. .not. (& + present(dlnPhidn) & + .or. present(dlnPhidP) & + .or. present(dlnPhidT) & + .or. present(P) & + )) then + call eos%residual_helmholtz(n, v, t, Arn=Arn, ArV=ArV) + P_in = totn*RT/V - ArV + Z = P_in*V/(totn*RT) + lnPhi(:) = Arn(:)/RT - log(Z) + return + else if (present(dlnPhidn)) then + call eos%residual_helmholtz(& + n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, & + Arn=Arn, ArVn=ArVn, ArTn=ArTn, Arn2=Arn2 & + ) + else + call eos%residual_helmholtz(& + n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, & + Arn=Arn, ArVn=ArVn, ArTn=ArTn & + ) + end if + + P_in = totn*RT/V - ArV + + Z = P_in*V/(totn*RT) + if (present(P)) P = P_in + + dPdV_in = -ArV2 - RT*totn/V**2 + dPdT_in = -ArTV + totn*R/V + dPdn_in = RT/V - ArVn + + if (present(lnPhi)) lnPhi = Arn(:)/RT - log(Z) + if (present(dlnPhidP)) then + dlnPhidP(:) = -dPdn_in(:)/dPdV_in/RT - 1._pr/P_in + end if + if (present(dlnPhidT)) then + dlnPhidT(:) = (ArTn(:) - Arn(:)/T)/RT + dPdn_in(:)*dPdT_in/dPdV_in/RT + 1._pr/T + end if + + if (present(dlnPhidn)) then + do i = 1, nc + do j = i, nc + dlnPhidn(i, j) = 1._pr/totn + (Arn2(i, j) + dPdn_in(i)*dPdn_in(j)/dPdV_in)/RT + dlnPhidn(j, i) = dlnPhidn(i, j) + end do + end do + end if + + if (present(dPdV)) dPdV = dPdV_in + if (present(dPdT)) dPdT = dPdT_in + if (present(dPdn)) dPdn = dPdn_in + end subroutine fugacity_vt + + subroutine enthalpy_residual_vt(eos, n, V, T, Hr, HrT, HrV, Hrn) + !! Calculate residual enthalpy given volume and temperature. + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: t !! Temperature [K] + real(pr), intent(in) :: v !! Volume [L] + real(pr), intent(out) :: Hr !! Residual enthalpy [bar L / mol] + real(pr), optional, intent(out) :: HrT !! \(\frac{dH^r}}{dT}\) + real(pr), optional, intent(out) :: HrV !! \(\frac{dH^r}}{dV}\) + real(pr), optional, intent(out) :: Hrn(size(n)) !! \(\frac{dH^r}}{dn}\) + + real(pr) :: Ar, ArV, ArT, Arn(size(n)) + real(pr) :: ArV2, ArT2, ArTV, ArVn(size(n)), ArTn(size(n)) + + call eos%residual_helmholtz(& + n, v, t, Ar=Ar, ArV=ArV, ArT=ArT, ArTV=ArTV, ArV2=ArV2, ArT2=ArT2, Arn=Arn, ArVn=ArVn, ArTn=ArTn & + ) + + Hr = Ar - t*ArT - v*ArV + + if (present(HrT)) HrT = - t*ArT2 - v*ArTV + if (present(HrV)) HrV = - t*ArTV - v*ArV2 + if (present(HrN)) HrN(:) = Arn(:) - t*ArTn(:) - v*ArVn(:) + end subroutine enthalpy_residual_vt + + subroutine gibbs_residual_VT(eos, n, V, T, Gr, GrT, GrV, Grn) + !! Calculate residual Gibbs energy given volume and temperature. + use yaeos__constants, only: R + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: V !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(out) :: Gr !! Gibbs energy [bar L / mol] + real(pr), optional, intent(out) :: GrT !! \(\frac{dG^r}}{dT}\) + real(pr), optional, intent(out) :: GrV !! \(\frac{dG^r}}{dV}\) + real(pr), optional, intent(out) :: Grn(size(n)) !! \(\frac{dG^r}}{dn}\) + + real(pr) :: Ar, ArV, ArT, Arn(size(n)) + real(pr) :: p, dPdV, dPdT, dPdn(size(n)), z, totn + + totn = sum(n) + call pressure(eos, n, V, T, P, dPdV=dPdV, dPdT=dPdT, dPdn=dPdn) + z = P*V/(totn*R*T) + + call eos%residual_helmholtz(n, v, t, Ar=Ar, ArV=ArV, ArT=ArT, Arn=Arn) + + Gr = Ar + P*V - totn*R*T + + if (present(GrT)) GrT = ArT + V*dPdT - totn*R + if (present(GrV)) GrV = ArV + V*dPdV + P + if (present(GrN)) GrN(:) = Arn(:) + V*dPdn(:) - R*T + end subroutine gibbs_residual_VT + + subroutine entropy_residual_vt(eos, n, V, T, Sr, SrT, SrV, Srn) + !! Calculate residual entropy given volume and temperature. + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: V !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(out) :: Sr !! Entropy [bar L / K / mol] + real(pr), optional, intent(out) :: SrT !! \(\frac{dS^r}}{dT}\) + real(pr), optional, intent(out) :: SrV !! \(\frac{dS^r}}{dV}\) + real(pr), optional, intent(out) :: Srn(size(n)) !! \(\frac{dS^r}}{dn}\) + + real(pr) :: Ar, ArT, ArT2, ArTV, ArTn(size(n)) + + call eos%residual_helmholtz(& + n, v, t, Ar=Ar, ArT=ArT, ArTV=ArTV, ArT2=ArT2, ArTn=ArTn & + ) + + Sr = - ArT + + if (present(SrT)) SrT = - ArT2 + if (present(SrV)) SrV = - ArTV + if (present(SrN)) SrN = - ArTn + end subroutine entropy_residual_vt + + subroutine Cv_residual_vt(eos, n, V, T, Cv) + !! Calculate residual heat capacity volume constant given v and t. + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(in) :: V !! Volume [L] + real(pr), intent(out) :: Cv !! heat capacity v constant [bar L / K / mol] + + real(pr) :: Ar, ArT2 + + call eos%residual_helmholtz(n, V, T, Ar=Ar, ArT2=ArT2) + + Cv = -T*ArT2 + end subroutine Cv_residual_vt + + subroutine Cp_residual_vt(eos, n, V, T, Cp) + !! Calculate residual heat capacity pressure constant given v and t. + use yaeos__constants, only: R + class(ArModel), intent(in) :: eos !! Model + real(pr), intent(in) :: n(:) !! Moles number vector + real(pr), intent(in) :: V !! Volume [L] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(out) :: Cp !! heat capacity p constant [bar L / K / mol] + + real(pr) :: Ar, ArT2, Cv, p, dPdT, dPdV, totn + + totn = sum(n) + + call eos%residual_helmholtz(n, V, T, Ar=Ar, ArT2=ArT2) + + call Cv_residual_vt(eos, n, V, T, Cv) + + call pressure(eos, n, V, T, P, dPdV=dPdV, dPdT=dPdT) + + Cp = Cv - T*dPdT**2/dPdV - totn*R + end subroutine Cp_residual_vt +end module yaeos__models_ar diff --git a/src/models/residual_helmholtz/cubic/generic_cubic.f90 b/src/models/residual_helmholtz/cubic/generic_cubic.f90 index 9821c746d..ea80156b6 100644 --- a/src/models/residual_helmholtz/cubic/generic_cubic.f90 +++ b/src/models/residual_helmholtz/cubic/generic_cubic.f90 @@ -21,12 +21,72 @@ module yaeos__models_ar_genericcubic end type type, extends(ArModel) :: CubicEoS - !! Cubic Equation of State. + !! # Cubic Equation of State. !! !! Generic Cubic Equation of State as defined by Michelsen and Mollerup - !! with constant \(\delta_1\) and \(\delta_2\) parameters. + !! with a \(\delta_1\) parameter that is not constant, + !! and a \(\delta_2\) parameter that depends on it. In the case of a + !! two parameter EoS like PengRobinson the \(\delta_1\) is the same for + !! all components so it can be considered as a constant instead of a + !! variable. The expression of the Equation is: + !! + !! \[ + !! P = \frac{RT}{V-B} + !! - \frac{D(T_r)}{(V+B\Delta_1)(V+B\Delta_2)} + !! \] class(CubicMixRule), allocatable :: mixrule - class(AlphaFunction), allocatable :: alpha + !! # CubicMixRule derived type. + !! Uses the abstract derived type `CubicMixRule` to define the + !! mixing rule that the CubicEoS will use. It includes internally + !! three methods to calculate the corresponding parameters for the + !! Cubic EoS: `Dmix`, `Bmix` and `D1mix`. + !! + !! # Examples + !! ## Calculation of the B parameter. + !! ```fortran + !! use yaeos, only: CubicEoS, PengRobinson76 + !! type(CubicEoS) :: eos + !! eos = PengRobinson76(tc, pc, w) + !! call eos%mixrule%Bmix(n, eos%b, B, dBi, dBij) + !! ``` + !! ## Calculation of the D parameter. + !! ```fortran + !! use yaeos, only: CubicEoS, PengRobinson76 + !! type(CubicEoS) :: eos + !! eos = PengRobinson76(tc, pc, w) + !! + !! ! The mixing rule takes the `a` parameters of the components so + !! ! they should be calculated externally + !! call eos%alpha%alpha(Tr, a, dadt, dadt2) + !! a = a * eos%ac + !! dadt = dadt * eos%ac / eos%components%Tc + !! dadt = dadt * eos%ac / eos%components%Tc**2 + !! ! Calculate parameter + !! call eos%mixrule%Dmix(n, T, a, dadt, dadt2, D, dDdT, dDdT2, dDi, dDidT, dDij) + !! ``` + !! ## Calculation of the D1 parameter. + !! ```fortran + !! use yaeos, only: CubicEoS, PengRobinson76 + !! type(CubicEoS) :: eos + !! eos = PengRobinson76(tc, pc, w) + !! call eos%mixrule%D1mix(n, eos%del1, D1, dD1i, dD1ij) + !! ``` + class(AlphaFunction), allocatable :: alpha + !! # AlphaFunction derived type. + !! Uses the abstract derived type `AlphaFunction` to define the + !! Alpha function that the CubicEoS will use. The Alpha function + !! receives the reduced temperature and returns the values of alpha + !! and its derivatives, named `a`, `dadt` and `dadt2` respectively. + !! + !! # Examples + !! ## Callign the AlphaFunction of a setted up model. + !! ```fortran + !! use yaeos, only: CubicEoS, PengRobinson76 + !! + !! type(CubicEoS) :: eos + !! eos = PengRobinson76(tc, pc, w) + !! call eos%alpha%alpha(Tr, a, dadt, dadt2) + !! ``` real(pr), allocatable :: ac(:) !! Attractive critical parameter real(pr), allocatable :: b(:) !! Repulsive parameter real(pr), allocatable :: del1(:) !! \(\delta_1\) paramter @@ -34,6 +94,7 @@ module yaeos__models_ar_genericcubic contains procedure :: residual_helmholtz => GenericCubic_Ar procedure :: get_v0 => v0 + procedure :: volume => volume end type abstract interface @@ -85,7 +146,7 @@ subroutine GenericCubic_Ar(& !! !! \[ !! P = \frac{RT}{V-b} - ! - \frac{a_c\alpha(T_r)}{(V+b\delta_1)(V+b\delta_2)} + !! - \frac{a_c\alpha(T_r)}{(V+b\delta_1)(V+b\delta_2)} !! \] !! !! This routine assumes that the \(\delta_1\) is not a constant parameter @@ -222,4 +283,130 @@ function v0(self, n, p, t) call self%mixrule%Bmix(n, self%b, v0, dbi, dbij) end function + subroutine volume(eos, n, P, T, V, root_type) + !! # Cubic EoS volume solver + !! Volume solver optimized for Cubic Equations of State. + !! + !! @warn + !! This routine intends to use the analyitical solution of the cubic + !! equation, but due to errors in the solutions it is not used. And + !! the general volume solver by Michelsen is used instead. + !! @endwarn + !! + !! # Description + !! Cubic equations can be analytically solved. Using an anallytical + !! solution provides the best possible solution in terms of speed and + !! precision. This subroutine uses the modified cardano method proposed + !! by Rosendo. + !! + !! # Examples + !! + !! ```fortran + !! use yaeos, only: CubicEoS, PengRobinson + !! type(CubicEoS) :: eos + !! + !! eos = PengRobinson(tc, pc, w) + !! ! Possible roots to solve + !! call eos%volume(n, P, T, V, "liquid") + !! call eos%volume(n, P, T, V, "vapor") + !! call eos%volume(n, P, T, V, "stable") + !! ``` + !! + !! # References + !! + !! - [1] "Thermodynamic Models: Fundamental and Computational Aspects", + !! Michael L. Michelsen, Jørgen M. Mollerup. + !! Tie-Line Publications, Denmark (2004) + !! [doi](http://dx.doi.org/10.1016/j.fluid.2005.11.032) + !! + !! - [2] "A Note on the Analytical Solution of Cubic Equations of State + !! in Process Simulation", Rosendo Monroy-Loperena + !! [doi](https://dx.doi.org/10.1021/ie2023004) + use yaeos__constants, only: R + use yaeos__math_linalg, only: cubic_roots, cubic_roots_rosendo + use yaeos__models_solvers, only: volume_michelsen + class(CubicEoS), intent(in) :: eos + real(pr), intent(in) :: n(:), P, T + real(pr), intent(out) :: V + character(len=*), intent(in) :: root_type + + real(pr) :: z(size(n)) + real(pr) :: cp(4), rr(3) + complex(pr) :: cr(3) + integer :: flag + + real(pr) :: V_liq, V_vap + real(pr) :: Ar, AT_Liq, AT_Vap + + real(pr) :: Bmix, dBi(size(n)), dBij(size(n), size(n)) + real(pr) :: D, dDi(size(n)), dDij(size(n), size(n)), dDidT(size(n)), dDdT, dDdT2 + real(pr) :: D1, D2, dD1i(size(n)), dD1ij(size(n), size(n)) + real(pr) :: Tr(size(n)) + real(pr) :: a(size(n)), dadt(size(n)), dadt2(size(n)) + real(pr) :: totn + + call volume_michelsen(eos, n, P, T, V, root_type) + return + + totn = sum(n) + z = n/totn + Tr = T/eos%components%Tc + ! ======================================================================== + ! Attractive parameter and derivatives + ! ------------------------------------------------------------------------ + call eos%alpha%alpha(Tr, a, dadt, dadt2) + a = eos%ac * a + dadt = eos%ac * dadt / eos%components%Tc + dadt2 = eos%ac * dadt2 / eos%components%Tc**2 + + ! ======================================================================== + ! Mixing rules + ! ------------------------------------------------------------------------ + call eos%mixrule%D1mix(z, eos%del1, D1, dD1i, dD1ij) + call eos%mixrule%Bmix(z, eos%b, Bmix, dBi, dBij) + call eos%mixrule%Dmix(& + z, T, a, dadt, dadt2, D, dDdT, dDdT2, dDi, dDidT, dDij& + ) + D2 = (1._pr - D1)/(1._pr + D1) + + cp(1) = -P + cp(2) = -P*Bmix*(D1 + D2 - 1) + R*T + cp(3) = -P*(D1*D2*Bmix**2 - D1*Bmix**2 - D2*Bmix**2) + R*T*Bmix*(D1+D2) - D + cp(4) = P*D1*D2*Bmix**3 + R*T *D1*D2*Bmix**2 + D*Bmix + + ! call cubic_roots(cp, rr, cr, flag) + ! call cubic_roots_rosendo(cp, rr, cr, flag) + + select case(flag) + case(-1) + V_liq = rr(1) + V_vap = rr(3) + if (V_liq < 0) V_liq = V_vap + case(1) + V_liq = rr(1) + V_vap = rr(1) + end select + + select case(root_type) + case("liquid") + V = V_liq + case("vapor") + V = V_vap + case("stable") + ! AT is something close to Gr(P,T) + call eos%residual_helmholtz(z, V_liq, T, Ar=Ar) + AT_Liq = (Ar + V_liq*P)/(T*R) - sum(z)*log(V_liq) + + call eos%residual_helmholtz(z, V_vap, T, Ar=Ar) + AT_Vap = (Ar + V_vap*P)/(T*R) - sum(z)*log(V_vap) + + if (AT_liq <= AT_vap) then + V = V_liq + else + V = V_vap + end if + end select + + V = totn * V + end subroutine end module diff --git a/src/models/residual_helmholtz/cubic/mixing_rules/base.f90 b/src/models/residual_helmholtz/cubic/mixing_rules/base.f90 index 64b238953..bdae22d57 100644 --- a/src/models/residual_helmholtz/cubic/mixing_rules/base.f90 +++ b/src/models/residual_helmholtz/cubic/mixing_rules/base.f90 @@ -22,7 +22,7 @@ module yaeos__models_ar_cubic_mixing_base implicit none contains - subroutine bmix_linear(n, bi, b, dbi, dbij) + pure subroutine bmix_linear(n, bi, b, dbi, dbij) real(pr), intent(in) :: n(:) real(pr), intent(in) :: bi(:) real(pr), intent(out) :: b, dbi(:), dbij(:, :) @@ -32,7 +32,7 @@ subroutine bmix_linear(n, bi, b, dbi, dbij) dbij = 0 end subroutine - subroutine bmix_qmr(n, bi, lij, b, dbi, dbij) + pure subroutine bmix_qmr(n, bi, lij, b, dbi, dbij) real(pr), intent(in) :: n(:) real(pr), intent(in) :: bi(:) real(pr), intent(in) :: lij(:, :) @@ -70,7 +70,7 @@ subroutine bmix_qmr(n, bi, lij, b, dbi, dbij) end do end subroutine - subroutine d1mix_rkpr(n, d1i, d1, dd1i, dd1ij) + pure subroutine d1mix_rkpr(n, d1i, d1, dd1i, dd1ij) !! RKPR \(\delta_1\) parameter mixing rule. !! !! The RKPR EoS doesn't have a constant \(\delta_1\) value for each diff --git a/src/models/solvers/volume.f90 b/src/models/solvers/volume.f90 new file mode 100644 index 000000000..a3bfac8a8 --- /dev/null +++ b/src/models/solvers/volume.f90 @@ -0,0 +1,142 @@ +module yaeos__models_solvers + !! # `models solvers` + !! Set of different specialized solvers for different models + !! + !! # Description + !! This module holds specialized solvers for different kind of applications + !! and models. + !! + !! ## Volume solving + !! This module holds the routine `volume_michelsen` which is a solver for + !! volume that takes advantage over a simple newton on the function of + !! pressure by solving the function of pressure over the covolume instead, + !! which solution is limited in the range [0, 1]. This solver requires that + !! the EoS uses the method `get_v0` to return the covolume. + !! + !! # Examples + !! + !! ```fortran + !! A basic code example + !! ``` + !! + !! # References + !! + use yaeos__constants, only: pr, R + use yaeos__models_ar, only: ArModel + implicit none + +contains + + subroutine volume_michelsen(eos, n, P, T, V, root_type, max_iters) + !! Volume solver at a given pressure. + !! + !! Obtain the volume using the method described by Michelsen and Møllerup. + !! While \(P(V, T)\) can be obtained with a simple Newton method, a better + !! approach is solving \(P(B/V, T)\) where \(B\) is the EoS covolume. + !! This method is easier to solve because: + !! \[ + !! V(P, T) \in [0, \infty) + !! \] + !! and + !! \[ + !! \frac{B}{V}(P, T) \in [0, 1] + !! \] + !! + !! At chapter 3 page 94 of Michelsen and Møllerup's book a more complete + !! explanation can be seen + use iso_fortran_env, only: error_unit + use stdlib_optval, only: optval + class(ArModel), intent(in) :: eos + real(pr), intent(in) :: n(:) !! Mixture moles + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(out) :: V !! Volume [L] + character(len=*), optional, intent(in) :: root_type !! Type of root ["vapor" | "liquid" | "stable"] + integer, optional, intent(in) :: max_iters !! Maxiumum number of iterations, defaults to 100 + + character(len=10) :: root + + real(pr) :: Ar, ArV, ArV2 + + real(pr) :: totn + real(pr) :: B !! Covolume + real(pr) :: ZETMIN, ZETA, ZETMAX + real(pr) :: pcalc, AT, AVAP, VVAP + + integer :: iter, maximum_iterations + + maximum_iterations = optval(max_iters, 100) + root = optval(root_type, "stable") + + TOTN = sum(n) + B = eos%get_v0(n, p, t) + ITER = 0 + + ! Limits + ZETMIN = 0._pr + ZETMAX = 1._pr + + select case(root_type) + case("liquid") + ZETA = 0.5_pr + call solve_point(P, V, Pcalc, AT, iter) + case("vapor","stable") + ZETA = min(0.5_pr, B*P/(TOTN*R*T)) + call solve_point(P, V, Pcalc, AT, iter) + + if (root_type == "stable") then + ! Run first for vapor and then for liquid + VVAP = V + AVAP = AT + ZETA = 0.5_pr + ZETMAX = 1._pr + call solve_point(P, V, Pcalc, AT, iter) + if (AT .gt. AVAP) V = VVAP + end if + case default + write(error_unit, *) "ERROR [VCALC]: Wrong specification" + error stop 1 + end select + contains + subroutine solve_point(P, V, Pcalc, AT, iter) + real(pr), intent(in) :: P !! Objective pressure [bar] + real(pr), intent(out) :: V !! Obtained volume [L] + real(pr), intent(out) :: Pcalc !! Calculated pressure at V [bar] + real(pr), intent(out) :: AT !! + integer, intent(out) :: iter + + real(pr) :: del, der + + iter = 0 + DEL = 1 + pcalc = 2*p + do while(abs(DEL) > 1.e-10_pr .and. iter < maximum_iterations) + V = B/ZETA + iter = iter + 1 + call eos%residual_helmholtz(n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2) + + Pcalc = TOTN*R*T/V - ArV + + if (Pcalc .gt. P) then + ZETMAX = ZETA + else + ZETMIN = ZETA + end if + + ! AT is something close to Gr(P,T) + AT = (Ar + V*P)/(T*R) - TOTN*log(V) + + DER = (ArV2*V**2 + TOTN*R*T)/B ! this is dPdrho/B + DEL = -(Pcalc - P)/DER + ZETA = ZETA + max(min(DEL, 0.1_pr), -.1_pr) + + if (ZETA .gt. ZETMAX .or. ZETA .lt. ZETMIN) then + ZETA = 0.5_pr*(ZETMAX + ZETMIN) + end if + end do + + if (iter >= maximum_iterations) write(error_unit, *) & + "WARN: Volume solver exceeded maximum number of iterations" + end subroutine solve_point + end subroutine volume_michelsen +end module \ No newline at end of file diff --git a/src/phase_equilibria/boundaries/phase_envelopes_pt.f90 b/src/phase_equilibria/boundaries/phase_envelopes_pt.f90 index 498baf623..c31423a02 100644 --- a/src/phase_equilibria/boundaries/phase_envelopes_pt.f90 +++ b/src/phase_equilibria/boundaries/phase_envelopes_pt.f90 @@ -3,7 +3,6 @@ module yaeos__phase_equilibria_boundaries_phase_envelopes_pt use yaeos__constants, only: pr use yaeos__models, only: ArModel use yaeos__equilibria_equilibria_state, only: EquilibriaState - use yaeos__thermoprops, only: fugacity_tp use yaeos__math_continuation, only: & continuation, continuation_solver, continuation_stopper implicit none @@ -70,7 +69,7 @@ function pt_envelope_2ph(& real(pr) :: S0 !! Initial specification value integer :: max_points !! Maximum number of points - integer :: max_iterations + integer :: max_iterations !! Maximum number of iterations real(pr) :: X(size(z) + 2) real(pr), allocatable :: XS(:, :) @@ -107,10 +106,12 @@ function pt_envelope_2ph(& XS = continuation(& foo, X, ns0=ns, S0=S0, & dS0=dS0, max_points=max_points, solver_tol=1.e-9_pr, & - update_specification=update_specification, & + update_specification=update_spec, & solver=solver, stop=stop_conditions & ) + contains + subroutine foo(X, ns, S, F, dF, dFdS) !! Function that needs to be solved at each envelope point real(pr), intent(in) :: X(:) @@ -124,7 +125,7 @@ subroutine foo(X, ns, S, F, dF, dFdS) character(len=14) :: kind_z, kind_y real(pr) :: y(nc) - real(pr) :: Vz, Vy, lnphip_z(nc), lnphip_y(nc) + real(pr) :: Vz, Vy, lnPhi_z(nc), lnPhi_y(nc) real(pr) :: dlnphi_dt_z(nc), dlnphi_dt_y(nc) real(pr) :: dlnphi_dp_z(nc), dlnphi_dp_y(nc) real(pr) :: dlnphi_dn_z(nc, nc), dlnphi_dn_y(nc, nc) @@ -143,29 +144,29 @@ subroutine foo(X, ns, S, F, dF, dFdS) y = K*z select case(kind) - case ("bubble") + case ("bubble") kind_z = "liquid" kind_y = "vapor" - case ("dew") + case ("dew") kind_z = "vapor" kind_y = "liquid" - case default + case default kind_z = "stable" kind_y = "stable" end select - - call fugacity_tp(& - model, z, T, P, V=Vz, root_type=kind_z, & - lnphip=lnphip_z, dlnPhidt=dlnphi_dt_z, & + + call model%lnphi_pt(& + z, P, T, V=Vz, root_type=kind_z, & + lnPhi=lnphi_z, dlnPhidt=dlnphi_dt_z, & dlnPhidp=dlnphi_dp_z, dlnphidn=dlnphi_dn_z & ) - call fugacity_tp(& - model, y, T, P, V=Vy, root_type=kind_y, & - lnphip=lnphip_y, dlnPhidt=dlnphi_dt_y, & + call model%lnphi_pt(& + y, P, T, V=Vy, root_type=kind_y, & + lnPhi=lnphi_y, dlnPhidt=dlnphi_dt_y, & dlnPhidp=dlnphi_dp_y, dlnphidn=dlnphi_dn_y & ) - F(:nc) = X(:nc) + lnphip_y - lnphip_z + F(:nc) = X(:nc) + lnPhi_y - lnPhi_z F(nc + 1) = sum(y - z) F(nc + 2) = X(ns) - S @@ -187,7 +188,7 @@ subroutine foo(X, ns, S, F, dF, dFdS) dFdS(nc+2) = -1 end subroutine foo - subroutine update_specification(X, ns, S, dS, dXdS, iterations) + subroutine update_spec(X, ns, S, dS, dXdS, step_iters) !! Update the specification during continuation. real(pr), intent(in out) :: X(:) !! Vector of variables \([lnK_i \dots , lnT, lnP]\) @@ -199,20 +200,17 @@ subroutine update_specification(X, ns, S, dS, dXdS, iterations) !! Step in specification real(pr), intent(in out) :: dXdS(:) !! Variation of variables with respect to specification - integer, intent(in) :: iterations + integer, intent(in) :: step_iters !! Iterations used in the solver - real(pr) :: Xnew(nc+2), Xold(nc+2), maxdS - - Xold = X + real(pr) :: maxdS - ! ============================================================== + ! ===================================================================== ! Update specification - ! - Dont select T or P near critical poitns + ! - Dont select T or P near critical points ! - Update dS wrt specification units ! - Set step - ! -------------------------------------------------------------- - + ! --------------------------------------------------------------------- if (maxval(abs(X(:nc))) < 0.1_pr) then ns = maxloc(abs(dXdS(:nc)), dim=1) maxdS=0.01_pr @@ -226,64 +224,97 @@ subroutine update_specification(X, ns, S, dS, dXdS, iterations) dS = sign(1.0_pr, dS) * minval([ & max(sqrt(abs(X(ns))/10._pr), 0.1_pr), & - abs(dS)*3/iterations & + abs(dS)*3/step_iters & ] & ) dS = sign(1.0_pr, dS) * maxval([abs(dS), maxdS]) - ! ============================================================== - ! Save the point - ! -------------------------------------------------------------- - envelopes%points = [& - envelopes%points, & - EquilibriaState(& - kind=kind, & - x=z, Vx=0._pr, y=exp(X(:nc))*z, Vy=0, & - T=exp(X(nc+1)), P=exp(X(nc+2)), beta=0._pr, iters=iterations) & - ] - - - ! ============================================================== - ! Handle critical point - ! -------------------------------------------------------------- - cp: block - !! Critical point detection - !! If the values of lnK (X[:nc]) change sign then a critical point - !! Has passed - real(pr) :: Xc(nc+2) !! Value at (near) critical point - real(pr) :: a !! Parameter for interpolation - - do while (maxval(abs(X(:nc))) < 0.1) - ! If near a critical point, jump over it - S = S + dS - X = X + dXdS*dS - end do - - Xnew = X + dXdS*dS - - if (all(Xold(:nc) * (Xnew(:nc)) < 0)) then - select case(kind) - case("dew") - kind = "bubble" - case("bubble") - kind = "dew" - case default - kind = "liquid-liquid" - end select - - ! 0 = a*X(ns) + (1-a)*Xnew(ns) < Interpolation equation to get X(ns) = 0 - a = -Xnew(ns)/(X(ns) - Xnew(ns)) - Xc = a * X + (1-a)*Xnew - envelopes%cps = [& - envelopes%cps, CriticalPoint(T=exp(Xc(nc+1)), P=exp(X(nc+2))) & - ] - ! X = Xc + dXdS*dS - end if - - end block cp - - end subroutine update_specification + call save_point(X, step_iters) + call detect_critical(X, dXdS, ns, S, dS) + end subroutine update_spec + + subroutine save_point(X, iters) + !! Save the converged point + real(pr), intent(in) :: X(:) + integer, intent(in) :: iters + type(EquilibriaState) :: point + + real(pr) :: y(nc), T, P + + T = exp(X(nc+1)) + P = exp(X(nc+2)) + y = exp(X(:nc))*z + point = EquilibriaState(& + kind=kind, x=z, Vx=0._pr, y=y, Vy=0._pr, & + T=T, P=P, beta=0._pr, iters=iters & + ) + + envelopes%points = [envelopes%points, point] + end subroutine save_point + + subroutine detect_critical(X, dXdS, ns, S, dS) + !! # `detect_critical` + !! Critical point detection + !! + !! # Description + !! If the values of lnK (X[:nc]) change sign then a critical point + !! Has passed, since for this to happen all variables should pass + !! through zero. Near critical points (lnK < 0.05) points are harder + !! to converge, so more steps in the extrapolation vector are made to + !! jump over the critical point. + !! If the critical point is detected then the kind of the point is + !! changed and the point is saved using an interpolation knowing that + !! + !! \[ + !! X_c = a * X + (1-a)*X_{new} + !! \] + !! + !! With \(X_c\) is the variables at the critical point, \(X_{new}\) + !! is the new initialization point of the method and \(a\) is the + !! parameter to interpolate the values. This subroutine finds the + !! value of \(a\) to obtain \(X_c\). + real(pr), intent(in out) :: X(:) !! Vector of variables + real(pr), intent(in out) :: dXdS(:) !! Variation of variables wrt S + integer, intent(in out) :: ns !! Number of specified variable + real(pr), intent(in out) :: S !! Specification value + real(pr), intent(in out) :: dS !! Step in specification + real(pr) :: Xc(nc+2) !! Value at (near) critical point + real(pr) :: a !! Parameter for interpolation + + real(pr) :: Xold(size(X)) !! Old value of X + real(pr) :: Xnew(size(X)) !! Value of the next initialization + + Xold = X + + do while (maxval(abs(X(:nc))) < 0.05) + ! If near a critical point, jump over it + S = S + dS + X = X + dXdS*dS + end do + + Xnew = X + dXdS*dS + + if (all(Xold(:nc) * (Xnew(:nc)) < 0)) then + select case(kind) + case("dew") + kind = "bubble" + case("bubble") + kind = "dew" + case default + kind = "liquid-liquid" + end select + + ! 0 = a*X(ns) + (1-a)*Xnew(ns) < Interpolation equation to get X(ns) = 0 + a = -Xnew(ns)/(X(ns) - Xnew(ns)) + Xc = a * X + (1-a)*Xnew + + envelopes%cps = [& + envelopes%cps, CriticalPoint(T=exp(Xc(nc+1)), P=exp(Xc(nc+2))) & + ] + X = Xc + dXdS*dS + end if + end subroutine detect_critical end function pt_envelope_2ph subroutine write_PTEnvel2(pt2, unit, iotype, v_list, iostat, iomsg) @@ -299,6 +330,7 @@ subroutine write_PTEnvel2(pt2, unit, iotype, v_list, iostat, iomsg) integer :: i, nc + if (size(pt2%points) == 0) return allocate(cps(0)) do i=1,size(pt2%cps) cp = minloc(& @@ -308,7 +340,7 @@ subroutine write_PTEnvel2(pt2, unit, iotype, v_list, iostat, iomsg) cps = [cps, cp] end do - write(unit, "(A, /, /)") "#PTEnvel2" + write(unit, "(A, /, /)", iostat=iostat) "#PTEnvel2" write(unit, "(A, /)") "#" // pt2%points(1)%kind diff --git a/src/phase_equilibria/equilibria_state.f90 b/src/phase_equilibria/equilibria_state.f90 index 9903b673a..c4e2f8aa1 100644 --- a/src/phase_equilibria/equilibria_state.f90 +++ b/src/phase_equilibria/equilibria_state.f90 @@ -43,7 +43,7 @@ subroutine write_EquilibriaState(eq, unit, iotype, v_list, iostat, iomsg) character(*), parameter :: nl = new_line("G") - write(unit, *) eq%kind, eq%T, eq%P, eq%x, eq%y + write(unit, *) eq%kind, eq%T, eq%P, eq%beta, eq%x, eq%y end subroutine write_EquilibriaState end module yaeos__equilibria_equilibria_state diff --git a/src/phase_equilibria/flash.f90 b/src/phase_equilibria/flash.f90 index 3de9618b3..b658181b4 100644 --- a/src/phase_equilibria/flash.f90 +++ b/src/phase_equilibria/flash.f90 @@ -2,7 +2,6 @@ module yaeos__equilibria_flash use yaeos__constants, only: pr use yaeos__models, only: ArModel use yaeos__equilibria_equilibria_state, only: EquilibriaState - use yaeos__thermoprops, only: fugacity_vt, fugacity_tp, pressure use yaeos__phase_equilibria_rachford_rice, only: betato01, betalimits, rachford_rice, solve_rr use yaeos__phase_equilibria_auxiliar, only: k_wilson implicit none @@ -72,7 +71,7 @@ type(EquilibriaState) function flash(model, z, t, v_spec, p_spec, k0, iters) Vx = 0.0 if (.not. present(k0)) then ! the EoS one-phase pressure will be used to estimate Wilson K factors - call pressure(model, z, v_spec, t, p=p) + call model%pressure(z, v_spec, t, p=p) if (P < 0) P = 1.0 end if end if @@ -110,11 +109,11 @@ type(EquilibriaState) function flash(model, z, t, v_spec, p_spec, k0, iters) case("TV") ! find Vy,Vx (vV and vL) from V balance and P equality equations call tv_loop_solve_pressures(model, T, V, beta, x, y, Vx, Vy, P) - call fugacity_tp(model, y, T, P, V=Vy, root_type="stable", lnphip=lnfug_y) - call fugacity_tp(model, x, T, P, V=Vx, root_type="liquid", lnphip=lnfug_x) + call model%lnphi_pt(y, P, T, V=Vy, root_type="stable", lnPhi=lnfug_y) + call model%lnphi_pt(x, P, T, V=Vx, root_type="liquid", lnPhi=lnfug_x) case("TP") - call fugacity_tp(model, y, T, P, V=Vy, root_type="stable", lnphip=lnfug_y) - call fugacity_tp(model, x, T, P, V=Vx, root_type="liquid", lnphip=lnfug_x) + call model%lnphi_pt(y, P, T, V=Vy, root_type="stable", lnPhi=lnfug_y) + call model%lnphi_pt(x, P, T, V=Vx, root_type="liquid", lnPhi=lnfug_x) end select dKold = dK @@ -161,6 +160,7 @@ type(EquilibriaState) function flash(model, z, t, v_spec, p_spec, k0, iters) if (spec == 'TP') v = beta*Vy + (1 - beta)*Vx if (maxval(K) < 1.001 .and. minval(K) > 0.999) then ! trivial solution + flash%kind = "failed" P = -1.0 flash%x = x/x flash%y = y/y @@ -170,6 +170,7 @@ type(EquilibriaState) function flash(model, z, t, v_spec, p_spec, k0, iters) return end if + flash%kind = "split" flash%iters = iters flash%p = p flash%t = t @@ -184,7 +185,6 @@ end function flash subroutine tv_loop_solve_pressures(model, T, V, beta, x, y, vx, vy, P) !! Solve pressure equality between two phases at a given temperature, !! total volume, vapor molar fractions and compositions. - use yaeos__thermoprops, only: fugacity_vt, pressure use iso_fortran_env, only: error_unit class(ArModel), intent(in) :: model @@ -216,11 +216,11 @@ subroutine tv_loop_solve_pressures(model, T, V, beta, x, y, vx, vy, P) ! First evaluation will be with Vx = 1.5*Bx if (Vx < Bx) Vx = 1.625_pr*Bx - call pressure(model, x, Vx, T, Px, dpdv=dPxdV) + call model%pressure(x, Vx, T, Px, dpdv=dPxdV) do while (Px < 0 .or. dPxdV >= 0) Vx = Vx - 0.2*(Vx - Bx) - call pressure(model, x, Vx, T, Px, dpdv=dPxdV) + call model%pressure(x, Vx, T, Px, dpdv=dPxdV) end do Vy = (V - (1 - beta)*Vx)/beta @@ -231,8 +231,8 @@ subroutine tv_loop_solve_pressures(model, T, V, beta, x, y, vx, vy, P) ! Newton for solving P equality, with Vx as independent variable its = its + 1 - call pressure(model, x, Vx, T, Px, dpdv=dPxdV) - call pressure(model, y, Vy, T, Py, dpdv=dPydV) + call model%pressure(x, Vx, T, Px, dpdv=dPxdV) + call model%pressure(y, Vy, T, Py, dpdv=dPydV) h = Py - Px dh = -dPydV * dVydVx - dPxdV @@ -256,8 +256,8 @@ subroutine tv_loop_solve_pressures(model, T, V, beta, x, y, vx, vy, P) end if end do - call pressure(model, x, Vx, T, Px) - call pressure(model, y, Vy, T, Py) + call model%pressure(x, Vx, T, Px) + call model%pressure(y, Vy, T, Py) P = (Px + Py) * 0.5_pr end subroutine tv_loop_solve_pressures end module yaeos__equilibria_flash diff --git a/src/phase_equilibria/saturations_points.f90 b/src/phase_equilibria/saturations_points.f90 index b30a12ddf..4dc1a8e22 100644 --- a/src/phase_equilibria/saturations_points.f90 +++ b/src/phase_equilibria/saturations_points.f90 @@ -1,7 +1,6 @@ module yaeos__equilibria_saturation_points use yaeos__constants, only: pr use yaeos__models, only: ArModel - use yaeos__thermoprops, only: fugacity_vt, fugacity_tp use yaeos__equilibria_equilibria_state, only: EquilibriaState use yaeos__phase_equilibria_auxiliar, only: k_wilson @@ -22,7 +21,6 @@ type(EquilibriaState) function saturation_pressure(model, n, t, kind, p0, y0, ma !! - Dew point: `kind="dew"` !! - Liquid-Liquid point: `kind="liquid-liquid"` use stdlib_optval, only: optval - use yaeos__thermoprops, only: pressure class(ArModel), intent(in) :: model real(pr), intent(in) :: n(:) !! Composition vector [moles / molar fraction] real(pr), intent(in) :: t !! Temperature [K] @@ -50,7 +48,7 @@ type(EquilibriaState) function saturation_pressure(model, n, t, kind, p0, y0, ma if (present (p0)) then p = p0 else - call pressure(model, z, T, 10._pr, P=P) + call model%pressure(z, T, 10._pr, P=P) end if if (present(y0)) then @@ -85,8 +83,8 @@ type(EquilibriaState) function saturation_pressure(model, n, t, kind, p0, y0, ma ! ------------------------------------------------------------------------ do its=1, iterations y = k*z - call fugacity_tp(model, y, T, P, vy, incipient, lnphip=lnfug_y, dlnphidp=dlnphi_dp_y) - call fugacity_tp(model, z, T, P, vz, main, lnphip=lnfug_z, dlnphidp=dlnphi_dp_z) + call model%lnphi_pt(y, P, T, vy, incipient, lnPhi=lnfug_y, dlnphidp=dlnphi_dp_y) + call model%lnphi_pt(z, P, T, vz, main, lnPhi=lnfug_z, dlnphidp=dlnphi_dp_z) k = exp(lnfug_z - lnfug_y) @@ -132,7 +130,6 @@ type(EquilibriaState) function saturation_temperature(model, n, p, kind, t0, y0, !! - Dew point: `kind="dew"` !! - Liquid-Liquid point: `kind="liquid-liquid"` use stdlib_optval, only: optval - use yaeos__thermoprops, only: pressure class(ArModel), intent(in) :: model real(pr), intent(in) :: n(:) !! Composition vector [moles / molar fraction] real(pr), intent(in) :: p !! Pressure [bar] @@ -195,8 +192,8 @@ type(EquilibriaState) function saturation_temperature(model, n, p, kind, t0, y0, ! ------------------------------------------------------------------------ do its=1, iterations y = k*z - call fugacity_tp(model, y, T, P, vy, incipient, lnphip=lnfug_y, dlnphidt=dlnphi_dt_y) - call fugacity_tp(model, z, T, P, vz, main, lnphip=lnfug_z, dlnphidt=dlnphi_dt_z) + call model%lnphi_pt(y, P, T, vy, incipient, lnPhi=lnfug_y, dlnphidt=dlnphi_dt_y) + call model%lnphi_pt(z, P, T, vz, main, lnPhi=lnfug_z, dlnphidt=dlnphi_dt_z) k = exp(lnfug_z - lnfug_y) f = sum(z*k) - 1 diff --git a/src/phase_equilibria/stability.f90 b/src/phase_equilibria/stability.f90 new file mode 100644 index 000000000..c351cd906 --- /dev/null +++ b/src/phase_equilibria/stability.f90 @@ -0,0 +1,177 @@ +module yaeos__phase_equilibria_stability + !! # Phase Stability module + !! Phase stability related calculations. + !! + !! # Description + !! Contains the basics rotuines to make phase stability analysis for + !! phase-equilibria detection. + !! + !! - `tpd(model, z, w, P, T)`: reduced Tangent-Plane-Distance + !! - `min_tpd(model, z, P, T, mintpd, w)`: Find minimal tpd for a multicomponent mixture + !! + !! # Examples + !! + !! ```fortran + !! ! Obtain the minimal tpd for a binary mixture at \(z_1 = 0.13\) + !! model = PengRobinson76(tc, pc, ac, kij, lij) + !! + !! z = [0.13, 1-0.13] + !! w = [0.1, 0.9] + !! + !! P = 45.6_pr + !! T = 190._pr + !! + !! z = z/sum(z) + !! ----------------------------------------------- + !! ``` + !! + !! # References + !! 1. Thermodynamic Models: Fundamental and Computational Aspects, Michael L. + !! Michelsen, Jørgen M. Mollerup. Tie-Line Publications, Denmark (2004) + !! [doi](http://dx.doi.org/10.1016/j.fluid.2005.11.032) + use yaeos__constants, only: pr, r + use yaeos__models_ar, only: ArModel + implicit none + +contains + + real(pr) function tm(model, z, w, P, T, d, dtpd) + !! # Alternative formulation of tangent-plane-distance + !! Michelsen's modified \(tpd\) function, \(tm\). + !! + !! # Description + !! Alternative formulation of the reduced tangent plane \(tpd\) function, + !! where the test phase is defined in moles, which enables for unconstrained + !! minimization. + !! \[ + !! tm(W) = 1 + \sum_i W_i (\ln W_i + \ln \phi_i(W) - d_i - 1) + !! \] + !! + !! # Examples + !! + !! ## Calculation of `tm` + !! ```fortran + !! tm = tpd(model, z, w, P, T) + !! --------------------------- + !! ``` + !! + !! ## Using precalculated trial-phase data + !! It is possible to calculate externaly the `d_i` vector and use it for + !! later calculations. + !! ```fortran + !! call fugacity_tp(& + !! model, z, T=T, P=P, V=Vz, root_type="stable", lnphip=lnphi_z& + !! ) + !! lnphi_z = lnphi_z - log(P) + !! di = log(z) + lnphi_z + !! tm = tpd(model, z, w, P, T, d=di) + !! --------------------------- + !! ``` + !! + !! # References + !! 1. Thermodynamic Models: Fundamental and Computational Aspects, Michael L. + !! Michelsen, Jørgen M. Mollerup. Tie-Line Publications, Denmark (2004) + !! [doi](http://dx.doi.org/10.1016/j.fluid.2005.11.032) + class(ArModel), intent(in) :: model !! Thermodynamic model + real(pr), intent(in) :: z(:) !! Feed composition + real(pr), intent(in) :: w(:) !! Test-phase mole numbers vector + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), optional, intent(in) :: d(:) !! \(d_i\) vector + real(pr), optional, intent(out) :: dtpd(:) + + real(pr) :: di(size(z)), vz, vw + real(pr) :: lnphi_z(size(z)), lnphi_w(size(z)) + + call model%lnphi_pt(& + w, T=T, P=P, V=Vw, root_type="stable", lnPhi=lnPhi_w & + ) + + if (.not. present(d)) then + call model%lnphi_pt(& + z, T=T, P=P, V=Vz, root_type="stable", lnPhi=lnPhi_z& + ) + di = log(z) + lnphi_z + else + di = d + end if + + + ! tpd = sum(w * (log(w) + lnphi_w - di)) + tm = 1 + sum(w * (log(w) + lnPhi_w - di - 1)) + + if (present(dtpd)) then + dtpd = log(w) + lnPhi_w - di + end if + end function tm + + subroutine min_tpd(model, z, P, T, mintpd, w, all_minima) + use nlopt_wrap, only: create, destroy, nlopt_opt, nlopt_algorithm_enum + use nlopt_callback, only: nlopt_func, create_nlopt_func + class(ArModel) :: model + real(pr), intent(in) :: z(:) !! Feed composition + real(pr), intent(in) :: P !! Pressure [bar] + real(pr), intent(in) :: T !! Temperature [K] + real(pr), intent(out) :: w(:) !! Trial composition + real(pr), intent(out) :: mintpd !! Minimal value of \(tm\) + real(pr), optional, intent(out) :: all_minima(:, :) + !! All the found minima + + real(pr) :: dx(size(w)) + real(pr) :: lnphi_z(size(z)), di(size(z)) + + real(pr) :: mins(size(w)), ws(size(w), size(w)), V + integer :: i + + type(nlopt_opt) :: opt !! Optimizer + type(nlopt_func) :: f !! Function to optimize + + integer :: stat + + f = create_nlopt_func(foo) + dx = 0.001_pr + + ! Calculate feed di + call model%lnphi_pt(z, T=T, P=P, V=V, root_type="stable", lnPhi=lnPhi_z) + di = log(z) + lnphi_z + + + ! ============================================================== + ! Setup optimizer + ! -------------------------------------------------------------- + opt = nlopt_opt(nlopt_algorithm_enum%LN_NELDERMEAD, size(w)) + call opt%set_ftol_rel(0.001_pr) + call opt%set_ftol_abs(0.00001_pr) + call opt%set_min_objective(f) + call opt%set_initial_step(dx) + + ! ============================================================== + ! Minimize for each component using each quasi-pure component + ! as initialization. + ! -------------------------------------------------------------- + !$OMP PARALLEL DO PRIVATE(i, w, mintpd, stat) SHARED(opt, ws, mins) + do i=1,size(w) + w = 0.001_pr + w(i) = 0.999_pr + call opt%optimize(w, mintpd, stat) + mins(i) = mintpd + ws(i, :) = w + end do + !$OMP END PARALLEL DO + + i = minloc(mins, dim=1) + mintpd = mins(i) + w = ws(i, :) + + if(present(all_minima)) all_minima = ws + + call destroy(opt) + contains + real(pr) function foo(x, gradient, func_data) + real(pr), intent(in) :: x(:) + real(pr), optional, intent(in out) :: gradient(:) + class(*), optional, intent(in) :: func_data + foo = tm(model, z, x, P, T, d=di) + end function foo + end subroutine min_tpd +end module yaeos__phase_equilibria_stability diff --git a/src/thermoprops.f90 b/src/thermoprops.f90 deleted file mode 100644 index 86dbe7115..000000000 --- a/src/thermoprops.f90 +++ /dev/null @@ -1,425 +0,0 @@ -module yaeos__thermoprops - !! Residual thermodyamic properties using residual Helmholtz model. - !! - !! Available properties: - !! - !! - pressure(n, V, T) - !! - fugacity(n, V, T) - !! - fugacity(n, P, T, root=[vapor, liquid, stable]) - !! - volume - !! - !! Calculate thermodynamic properties using Helmholtz energy as a basis. - !! All the routines in this module work with the logic: - !! - !! ```fortran - !! call foo(x, V, T, [dfoodv, dfoodt, ...]) - !! ``` - !! Where the user can call the routine of the desired property. And include - !! as optional values the desired derivatives of said properties. - use yaeos__constants, only: R, pr - use yaeos__models_ar, only: ArModel - implicit none -contains - subroutine pressure(eos, n, v, t, p, dpdv, dpdt, dpdn) - !! Pressure calculation. - !! - !! Calculate pressure using residual helmholtz models. - !! - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: p !! Pressure [bar] - real(pr), optional, intent(out) :: dpdv !! \(\frac{dP}}{dV}\) - real(pr), optional, intent(out) :: dpdt !! \(\frac{dP}}{dT}\) - real(pr), optional, intent(out) :: dpdn(:) !! \(\frac{dP}}{dn_i}\) - - real(pr) :: totn - - real(pr) :: Ar, ArV, ArV2, ArTV, ArVn(size(n)) - integer :: nc - - TOTN = sum(n) - nc = size(n) - - call eos%residual_helmholtz(& - n, v, t, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, ArVn=ArVn & - ) - P = TOTN*R*T/V - ArV - if (present(dPdV)) dPdV = -ArV2 - R*t*TOTN/V**2 - if (present(dPdT)) dPdT = -ArTV + TOTN*R/V - if (present(dPdN)) dPdN(:) = R*T/V - ArVn(:) - end subroutine pressure - - subroutine fugacity_tp(eos, & - n, T, P, V, root_type, lnphip, dlnPhidP, dlnphidT, dlnPhidn & - ) - !! Calculate logarithm of fugacity, given pressure and temperature. - !! - !! This routine will obtain the desired volume root at the specified - !! pressure and calculate fugacity at that point. - !! - !! @note - !! While the natural output variable is \(ln f_i\). The calculated - !! derivatives will be the derivatives of the fugacity coefficient - !! \(ln \phi_i\) - !! @endnote - !! - use iso_fortran_env, only: error_unit - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Mixture mole numbers - character(len=*), intent(in) :: root_type !! Type of root desired ["liquid", "vapor", "stable"] - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: p !! Pressure [bar] - - real(pr), optional, intent(out) :: lnphip(size(n)) !! \(\ln(f_i)\) vector - real(pr), optional, intent(out) :: v !! Volume [L] - real(pr), optional, intent(out) :: dlnphidt(size(n)) !! ln(phi) Temp derivative - real(pr), optional, intent(out) :: dlnphidp(size(n)) !! ln(phi) Presssure derivative - real(pr), optional, intent(out) :: dlnphidn(size(n), size(n)) !! ln(phi) compositional derivative - - real(pr) :: v_in, p_in - - call volume(eos, n, P, T, V_in, root_type) - call fugacity_vt(eos, n, v_in, T, P_in, lnphip, dlnphidp, dlnphidt, dlnphidn) - if(present(v)) v = v_in - if(abs(P_in - p) > 1e-2) then - write(error_unit, *) "WARN: possible bad root solving: ", p_in, p - end if - end subroutine fugacity_tp - - subroutine fugacity_vt(eos, & - n, V, T, P, lnphip, dlnPhidP, dlnphidT, dlnPhidn, dPdV, dPdT, dPdN & - ) - !! Calculate fugacity coefficent given volume and temperature. - !! - !!@note - !!While the natural output variable is \(ln \phi_i P\). The calculated - !!derivatives will be the derivatives of the fugacity coefficient - !!\(ln \phi_i\) - !!@endnote - !! - class(ArModel) :: eos !! Model - real(pr), intent(in) :: n(:) !! Mixture mole numbers - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(in) :: t !! Temperature [K] - - real(pr), optional, intent(out) :: p !! Pressure [bar] - real(pr), optional, intent(out) :: lnphip(size(n)) !! \(\ln(\phi_i*P)\) vector - real(pr), optional, intent(out) :: dlnphidt(size(n)) !! \(ln(phi_i)\) Temp derivative - real(pr), optional, intent(out) :: dlnphidp(size(n)) !! \(ln(phi_i)\) Presssure derivative - real(pr), optional, intent(out) :: dlnphidn(size(n), size(n)) !! \(ln(phi_i)\) compositional derivative - real(pr), optional, intent(out) :: dPdV !! \(\frac{dP}{dV}\) - real(pr), optional, intent(out) :: dPdT !! \(\frac{dP}{dT}\) - real(pr), optional, intent(out) :: dPdN(:) !! \(\frac{dP}{dn_i}\) - - real(pr) :: Ar, ArTV, ArV, ArV2 - real(pr), dimension(size(n)) :: Arn, ArVn, ArTn - real(pr) :: Arn2(size(n), size(n)) - - real(pr) :: dPdV_in, dPdT_in, dPdN_in(size(n)) - real(pr) :: P_in - - real(pr) :: RT, Z - - real(pr) :: totn - integer :: nc, i, j - - - totn = sum(n) - nc = size(n) - - RT = R*T - Z = V/(TOTN*RT) ! this is Z/P - - if (present(lnphip) .and. .not. (& - present(dlnphidn) & - .or. present(dlnphidp) & - .or. present(dlnphidt) & - .or. present(p) & - )) then - call eos%residual_helmholtz(n, v, t, Arn=Arn) - lnphip(:) = Arn(:)/RT - log(Z) - return - else if (present(dlnphidn)) then - call eos%residual_helmholtz(& - n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, & - Arn=Arn, ArVn=ArVn, ArTn=ArTn, Arn2=Arn2 & - ) - else - call eos%residual_helmholtz(& - n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2, ArTV=ArTV, & - Arn=Arn, ArVn=ArVn, ArTn=ArTn & - ) - end if - - lnphip(:) = Arn(:)/RT - log(Z) - - P_in = TOTN*RT/V - ArV - if (present(P)) P = P_in - - dPdV_in = -ArV2 - RT*TOTN/V**2 - dPdT_in = -ArTV + TOTN*R/V - dPdN_in = RT/V - ArVn - - if (present(dlnphidp)) then - dlnphidp(:) = -dPdN_in(:)/dPdV_in/RT - 1._pr/P_in - end if - if (present(dlnphidt)) then - dlnphidt(:) = (ArTn(:) - Arn(:)/T)/RT + dPdN_in(:)*dPdT_in/dPdV_in/RT + 1._pr/T - end if - - if (present(dlnphidn)) then - do i = 1, nc - do j = i, nc - dlnphidn(i, j) = 1._pr/TOTN + (Arn2(i, j) + dPdN_in(i)*dPdN_in(j)/dPdV_in)/RT - dlnphidn(j, i) = dlnphidn(i, j) - end do - end do - end if - - if (present(dPdV)) dPdV = dPdV_in - if (present(dPdT)) dPdT = dPdT_in - if (present(dPdN)) dPdN = dPdN_in - end subroutine fugacity_vt - - subroutine volume(eos, n, P, T, V, root_type, max_iters) - !! Volume solver at a given pressure. - !! - !! Obtain the volume using the method described by Michelsen and Møllerup. - !! While \(P(V, T)\) can be obtained with a simple Newton method, a better - !! approach is solving \(P(B/V, T)\) where \(B\) is the EoS covolume. - !! This method is easier to solve because: - !! \[ - !! V(P, T) \in [0, \infty) - !! \] - !! and - !! \[ - !! \frac{B}{V}(P, T) \in [0, 1] - !! \] - !! - !! At chapter 3 page 94 of Michelsen and Møllerup's book a more complete - !! explanation can be seen - use iso_fortran_env, only: error_unit - use stdlib_optval, only: optval - class(ArModel), intent(in) :: eos - real(pr), intent(in) :: n(:) !! Mixture moles - real(pr), intent(in) :: T !! Temperature [K] - real(pr), intent(in) :: P !! Pressure [bar] - real(pr), intent(out) :: V !! Volume [L] - character(len=*), optional, intent(in) :: root_type !! Type of root ["vapor" | "liquid" | "stable"] - integer, optional, intent(in) :: max_iters !! Maxiumum number of iterations, defaults to 100 - - character(len=10) :: root - - real(pr) :: Ar, ArV, ArV2 - - real(pr) :: totn - real(pr) :: B !! Covolume - real(pr) :: ZETMIN, ZETA, ZETMAX - real(pr) :: pcalc, AT, AVAP, VVAP - - integer :: iter, maximum_iterations - - maximum_iterations = optval(max_iters, 100) - root = optval(root_type, "stable") - - TOTN = sum(n) - B = eos%get_v0(n, p, t) - ITER = 0 - - ! Limits - ZETMIN = 0._pr - ZETMAX = 1._pr - - select case(root_type) - case("liquid") - ZETA = 0.5_pr - call solve_point(P, V, Pcalc, AT, iter) - case("vapor","stable") - ZETA = min(0.5_pr, B*P/(TOTN*R*T)) - call solve_point(P, V, Pcalc, AT, iter) - - if (root_type == "stable") then - ! Run first for vapor and then for liquid - VVAP = V - AVAP = AT - ZETA = 0.5_pr - ZETMAX = 1._pr - call solve_point(P, V, Pcalc, AT, iter) - if (AT .gt. AVAP) V = VVAP - end if - case default - write(error_unit, *) "ERROR [VCALC]: Wrong specification" - error stop 1 - end select - contains - subroutine solve_point(P, V, Pcalc, AT, iter) - real(pr), intent(in) :: P !! Objective pressure [bar] - real(pr), intent(out) :: V !! Obtained volume [L] - real(pr), intent(out) :: Pcalc !! Calculated pressure at V [bar] - real(pr), intent(out) :: AT !! - integer, intent(out) :: iter - - real(pr) :: del, der - - iter = 0 - DEL = 1 - pcalc = 2*p - do while(abs(DEL) > 1.e-10_pr .and. iter < maximum_iterations) - V = B/ZETA - iter = iter + 1 - call eos%residual_helmholtz(n, V, T, Ar=Ar, ArV=ArV, ArV2=ArV2) - - Pcalc = TOTN*R*T/V - ArV - - if (Pcalc .gt. P) then - ZETMAX = ZETA - else - ZETMIN = ZETA - end if - - ! AT is something close to Gr(P,T) - AT = (Ar + V*P)/(T*R) - TOTN*log(V) - - DER = (ArV2*V**2 + TOTN*R*T)/B ! this is dPdrho/B - DEL = -(Pcalc - P)/DER - ZETA = ZETA + max(min(DEL, 0.1_pr), -.1_pr) - - if (ZETA .gt. ZETMAX .or. ZETA .lt. ZETMIN) then - ZETA = 0.5_pr*(ZETMAX + ZETMIN) - end if - end do - - if (iter >= maximum_iterations) write(error_unit, *) & - "WARN: Volume solver exceeded maximum number of iterations" - end subroutine solve_point - end subroutine volume - - ! ========================================================================== - ! Residual Enthalpy - ! -------------------------------------------------------------------------- - subroutine enthalpy_residual_vt(eos, n, v, t, Hr, HrT, HrV, Hrn) - !! Calculate residual enthalpy given volume and temperature. - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: Hr !! Residual enthalpy [bar L / mol] - real(pr), optional, intent(out) :: HrT !! \(\frac{dH^r}}{dT}\) - real(pr), optional, intent(out) :: HrV !! \(\frac{dH^r}}{dV}\) - real(pr), optional, intent(out) :: Hrn(size(n)) !! \(\frac{dH^r}}{dn}\) - - real(pr) :: Ar, ArV, ArT, Arn(size(n)) - real(pr) :: ArV2, ArT2, ArTV, ArVn(size(n)), ArTn(size(n)) - - call eos%residual_helmholtz(& - n, v, t, Ar=Ar, ArV=ArV, ArT=ArT, ArTV=ArTV, ArV2=ArV2, ArT2=ArT2, Arn=Arn, ArVn=ArVn, ArTn=ArTn & - ) - - Hr = Ar - t*ArT - v*ArV - - if (present(HrT)) HrT = - t*ArT2 - v*ArTV - if (present(HrV)) HrV = - t*ArTV - v*ArV2 - if (present(HrN)) HrN(:) = Arn(:) - t*ArTn(:) - v*ArVn(:) - end subroutine enthalpy_residual_vt - - ! ========================================================================== - ! Residual Gibbs energy - ! -------------------------------------------------------------------------- - subroutine gibbs_residual_vt(eos, n, v, t, Gr, GrT, GrV, Grn) - !! Calculate residual Gibbs energy given volume and temperature. - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: Gr !! Gibbs energy [bar L / mol] - real(pr), optional, intent(out) :: GrT !! \(\frac{dG^r}}{dT}\) - real(pr), optional, intent(out) :: GrV !! \(\frac{dG^r}}{dV}\) - real(pr), optional, intent(out) :: Grn(size(n)) !! \(\frac{dG^r}}{dn}\) - - real(pr) :: Ar, ArV, ArT, Arn(size(n)) - real(pr) :: p, dpdv, dpdt, dpdn(size(n)), z, ntot - - ntot = sum(n) - call pressure(eos, n, v, t, p, dpdv=dpdv, dpdt=dpdt, dpdn=dpdn) - z = p*v/(ntot*R*t) - - call eos%residual_helmholtz(n, v, t, Ar=Ar, ArV=ArV, ArT=ArT, Arn=Arn) - - Gr = Ar + p*v - ntot*R*t - - if (present(GrT)) GrT = ArT + v*dpdt - ntot*R - if (present(GrV)) GrV = ArV + v*dpdv + p - if (present(GrN)) GrN(:) = Arn(:) + v*dpdn(:) - R*t - end subroutine gibbs_residual_vt - - ! ========================================================================== - ! Residual entropy - ! -------------------------------------------------------------------------- - subroutine entropy_residual_vt(eos, n, v, t, Sr, SrT, SrV, Srn) - !! Calculate residual entropy given volume and temperature. - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: Sr !! Entropy [bar L / K / mol] - real(pr), optional, intent(out) :: SrT !! \(\frac{dS^r}}{dT}\) - real(pr), optional, intent(out) :: SrV !! \(\frac{dS^r}}{dV}\) - real(pr), optional, intent(out) :: Srn(size(n)) !! \(\frac{dS^r}}{dn}\) - - real(pr) :: Ar, ArT, ArT2, ArTV, ArTn(size(n)) - - call eos%residual_helmholtz(& - n, v, t, Ar=Ar, ArT=ArT, ArTV=ArTV, ArT2=ArT2, ArTn=ArTn & - ) - - Sr = - ArT - - if (present(SrT)) SrT = - ArT2 - if (present(SrV)) SrV = - ArTV - if (present(SrN)) SrN = - ArTn - end subroutine entropy_residual_vt - - ! ========================================================================== - ! Residual Cv - ! -------------------------------------------------------------------------- - subroutine Cv_residual_vt(eos, n, v, t, Cv) - !! Calculate residual heat capacity volume constant given v and t. - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: Cv !! heat capacity v constant [bar L / K / mol] - - real(pr) :: Ar, ArT2 - - call eos%residual_helmholtz(n, v, t, Ar=Ar, ArT2=ArT2) - - Cv = -t*ArT2 - end subroutine Cv_residual_vt - - ! ========================================================================== - ! Residual Cp - ! -------------------------------------------------------------------------- - subroutine Cp_residual_vt(eos, n, v, t, Cp) - !! Calculate residual heat capacity pressure constant given v and t. - class(ArModel), intent(in) :: eos !! Model - real(pr), intent(in) :: n(:) !! Moles number vector - real(pr), intent(in) :: t !! Temperature [K] - real(pr), intent(in) :: v !! Volume [L] - real(pr), intent(out) :: Cp !! heat capacity p constant [bar L / K / mol] - - real(pr) :: Ar, ArT2, Cv, p, dpdt, dpdv, ntot - - ntot = sum(n) - - call eos%residual_helmholtz(n, v, t, Ar=Ar, ArT2=ArT2) - - call Cv_residual_vt(eos, n, v, t, Cv) - - call pressure(eos, n, v, t, p, dpdv=dpdv, dpdt=dpdt) - - Cp = Cv - t*dpdt**2/dpdv - ntot*R - end subroutine Cp_residual_vt -end module yaeos__thermoprops diff --git a/src/yaeos.f90 b/src/yaeos.f90 index 86bf7ffce..e2320667d 100644 --- a/src/yaeos.f90 +++ b/src/yaeos.f90 @@ -9,13 +9,11 @@ module yaeos !! - [[yaeos__consistency(module)]]: Tools to evalaute the consistency of Ar and Ge models. !! - [[yaeos__substance(module)]]: Derived type that holds the important data (for example, critical constants) from a mixture. !! - [[yaeos__models(module)]]: All the implemented models, also their base types for making extensions. - !! - [[yaeos__thermoprops(module)]]: Available thermodynamic properties to calculate. !! - [[yaeos__equilibria(module)]]: Phase equilibria related procedures. use yaeos__constants use yaeos__consistency use yaeos__substance use yaeos__models - use yaeos__thermoprops use yaeos__equilibria - character(len=*), parameter :: version="0.3.0" !! This version. + character(len=*), parameter :: version="1.0.0" !! This version. end module diff --git a/test/fixtures/taperobinson.f90 b/test/fixtures/taperobinson.f90 index b2e4b004f..936b3ec35 100644 --- a/test/fixtures/taperobinson.f90 +++ b/test/fixtures/taperobinson.f90 @@ -16,6 +16,7 @@ MODULE autodiff_tapenade_pr76 USE YAEOS__CONSTANTS, ONLY : pr, r USE YAEOS__TAPENADE_AR_API, ONLY : armodeltapenade + use yaeos__tapenade_interfaces IMPLICIT NONE type, extends(ArModelTapenade) :: TPR76 REAL(pr), ALLOCATABLE :: kij(:, :), lij(:, :) @@ -800,12 +801,6 @@ SUBROUTINE AR_D_B(model, n, nb, nd, ndb, v, vb, vd, vdb, t, tb, td, & INTEGER :: ad_from INTEGER :: ad_to INTEGER :: ad_to0 - EXTERNAL PUSHREAL8ARRAY - EXTERNAL PUSHINTEGER4 - EXTERNAL PUSHREAL8 - EXTERNAL POPREAL8 - EXTERNAL POPINTEGER4 - EXTERNAL POPREAL8ARRAY INTEGER :: arg12 LOGICAL, DIMENSION(SIZE(n)) :: mask1 LOGICAL, DIMENSION(SIZE(n)) :: mask2 diff --git a/test/flash_tv.f90 b/test/flash_tv.f90 deleted file mode 100644 index 85e45d670..000000000 --- a/test/flash_tv.f90 +++ /dev/null @@ -1,215 +0,0 @@ -program flash_tv - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp, pressure - use yaeos__math_linalg, only: solve_system - use fixtures_models, only: binary_PR76 - - implicit none - - integer, parameter :: nc = 2 - - real(pr) :: z(nc) = [0.4, 0.6] - real(pr) :: x(nc) = [0.32424471950363210, 0.67575531029866709] - real(pr) :: y(nc) = [0.91683466155334536, 8.3165368249135715E-002] - real(pr) :: vx = 8.4918883298198036E-002 - real(pr) :: vy = 0.32922132295944545 - - real(pr) :: F(nc+3), dF(nc+3, nc+3) - real(pr) :: Fdx(nc+3),dFdx(nc+3, nc+3) - real(pr) :: dxold(nc+3) - - real(pr) :: K(nc), T=200, V, P - real(pr) :: beta=0.12 - - real(pr) :: vars(nc+3), dx(nc+3) - - class(ArModel), allocatable :: model - type(EquilibriaState) :: flash_result - - integer :: its - - model = binary_PR76() - - V = beta*vy + (1-beta) * vx - - K = y/x - dfdX=0 - df = 0 - - flash_result = flash(model, z, T, p_spec=5._pr, iters=its) - - x = flash_result%x - y = flash_result%y - y(1) = y(1) + 0.2 - y = y/sum(y) - beta = flash_result%beta - vx = flash_result%vx - vy = flash_result%vy - - K = (model%components%Pc/5._pr) & - * exp(5.373_pr*(1 + model%components%w)& - * (1 - model%components%Tc/T)) - - V = beta *vy + (1-beta)*vx - - print *, "true Results" - print *, flash_result%vx, flash_result%vy, flash_result%beta, beta * vy + (1-beta)*vx - print *, flash_result%x - print *, flash_result%y - print *, "------------" - - call flash_TV_DF(model, z, T, V, log(K), beta, vx, vy, F, dF) - print *, "numdiff" - do its = 1,nc+3 - print *, df(its, :) - end do - - call flash_TV_F(model, z, T, V, log(K), beta, vx, vy, F, dF) - print *, "anadiff" - do its = 1,nc+3 - print *, df(its, :) - end do - - stop - - print *, "solve?" - do its=1,1000 - call flash_TV_DF(model, z, T, V, K, beta, vx, vy, F, dF) - - dxold = dx - dx = solve_system(dF, -F) - - ! if (any(isnan(dx)) .or. any(isnan(F))) then - ! K = K - dxold(:nc) - ! beta = beta - dxold(nc+1) - ! vx = vx - dxold(nc+2) - ! vy = vy - dxold(nc+3) - - ! dx = dxold/2 - ! end if - - print *, its, F - - do while (beta + dx(nc+1) > 1 .or. beta + dx(nc+1) < 0) - dx = dx/5 - end do - - K = K + dx(:nc) - beta = beta + dx(nc+1) - vx = vx + dx(nc+2) - vy = vy + dx(nc+3) - - if (maxval(abs(F)) < 1e-3) then - print *, "conv" - exit - end if - end do - - x = z / (beta * (K - 1) + 1) - y = K * x - print *, vx, vy, beta, beta*vy + (1-beta)*vx - print *, x - print *, y - -contains - subroutine flash_TV_F(model, z, T, V, lnK, beta, vx, vy, F, dF) - use yaeos, only: fugacity_vt - class(ArModel), intent(in) :: model - real(pr), intent(in) :: z(:) - real(pr), intent(in) :: T - real(pr), intent(in) :: V - real(pr), intent(in) :: lnK(:) - real(pr), intent(in) :: beta - real(pr), intent(in) :: vx - real(pr), intent(in) :: vy - real(pr), intent(out) :: F(:) - real(pr), optional, intent(out) :: dF(:, :) - - real(pr) :: K(nc) - real(pr) :: x(nc), Px, dPxdn(nc), lnphip_x(nc), dlnPhidx(nc, nc), dPxdV - real(pr) :: y(nc), Py, dPydn(nc), lnphip_y(nc), dlnPhidy(nc, nc), dPydV - - real(pr) :: dxdK(nc), dydK(nc), dxdbeta(nc), dydbeta(nc) - real(pr) :: dVxdbeta, dVydbeta - - integer :: i, j - - F = 0 - K = exp(lnK) - - x = z / (beta * (K - 1) + 1) - y = K * x - - dxdbeta = z * (1-k)/ (beta*(K - 1) + 1)**2 - dydbeta = K * dxdbeta - - dxdK = - beta * z / (beta*(K - 1)+1)**2 - dydK = x + K * dxdK - - call fugacity_vt(model, x, vx, T, P=Px, dPdN=dPxdn, lnphip=lnphip_x, dlnphidn=dlnPhidx, dPdV=dPxdV) - call fugacity_vt(model, y, vy, T, P=Py, dPdN=dPydn, lnphip=lnphip_y, dlnphidn=dlnPhidy, dPdV=dPydV) - - F(:nc) = lnK - lnphip_x + lnphip_y - F(nc + 1) = Px !- Py - F(nc + 2) = V - (beta*Vy + (1-beta)*Vx) - F(nc + 3) = sum((z * (1 - K)) /(1 + beta*(K - 1))) - - if (present(df)) then - df = 0 - do i=1,nc - do j=1,nc - end do - end do - - df(nc+1, :nc) = K * (dPxdn * dxdK - dPydn * dydK) - - df(nc+2, :nc) = 0 - df(nc+2, nc+1) = Vx - Vy - - df(nc+3, :nc) = K*(beta * z * (K-1)/(beta*(K-1)+1)**2 - z/(beta*(K-1)+1)) - end if - end subroutine flash_TV_F - - subroutine flash_TV_DF(model, z, T, V, lnK, beta, vx, vy, F, dF) - class(ArModel), intent(in) :: model - real(pr), intent(in) :: z(:) - real(pr), intent(in) :: T - real(pr), intent(in) :: V - real(pr), intent(in) :: lnK(:) - real(pr), intent(in) :: beta - real(pr), intent(in) :: vx - real(pr), intent(in) :: vy - real(pr), intent(out) :: F(:) - real(pr), intent(out) :: dF(:, :) - - real(pr) :: dx - integer :: i, nc - real(pr) :: lnKdx(size(z)), betadx, vxdx, vydx, Fdx(size(F)) - - nc = size(z) - - dx = 1e-5 - - f = 0 - df = 0 - call flash_TV_F(model, z, T, V, lnK, beta, vx, vy, F, dF) - - do i=1, nc - lnKdx = lnK - lnKdx(i) = lnK(i) + dx - call flash_TV_F(model, z, T, V, lnKdx, beta, vx, vy, Fdx) - df(:, i) = (Fdx - F)/dx - end do - - betadx = beta + dx - call flash_TV_F(model, z, T, V, lnK, betadx, vx, vy, Fdx) - df(:, nc+1) = (Fdx - F)/dx - - vxdx = vx + dx - call flash_TV_F(model, z, T, V, lnK, beta, vxdx, vy, Fdx) - df(:, nc+2) = (Fdx - F)/dx - - vydx = vy + dx - call flash_TV_F(model, z, T, V, lnK, beta, vydx, vy, Fdx) - df(:, nc+3) = (Fdx - F)/dx - end subroutine flash_TV_DF -end program flash_tv \ No newline at end of file diff --git a/test/test_fitting/test_fitting.f90 b/test/test_fitting/test_fitting.f90 index 7eb9f4e93..8fa7dd6dc 100644 --- a/test/test_fitting/test_fitting.f90 +++ b/test/test_fitting/test_fitting.f90 @@ -9,7 +9,9 @@ subroutine collect_suite(testsuite) !> Collection of tests type(unittest_type), allocatable, intent(out) :: testsuite(:) - testsuite = [new_unittest("FitKijLij", test_fit_kij_lij) & + testsuite = [& + new_unittest("FitKijLij", test_fit_kij_lij), & + new_unittest("FitMHVNRTL", test_fit_MHV_NRTL) & ] end subroutine collect_suite @@ -20,7 +22,7 @@ subroutine test_fit_kij_lij(error) use yaeos__equilibria, only: EquilibriaState type(error_type), allocatable, intent(out) :: error class(ArModel), allocatable :: model - type(EquilibriaState) :: exp_point + type(EquilibriaState) :: exp_points real(pr) :: Tc(2) = [126.2, 568.7] real(pr) :: pc(2) = [33.98, 24.90] @@ -30,14 +32,15 @@ subroutine test_fit_kij_lij(error) type(FitKijLij) :: fitting_problem - exp_point = EquilibriaState( & + exp_points = & + EquilibriaState( & kind="bubble", T=344.5_pr, P=23.9_pr, & x=[0.0309_pr, 1 - 0.0309_pr], y=[0.9883_pr, 1 - 0.9883_pr], & Vx=0._pr, Vy=0._pr, beta=0.0_pr & ) fitting_problem%model = SoaveRedlichKwong(tc, pc, w) - fitting_problem%experimental_points = [exp_point] + fitting_problem%experimental_points = [exp_points] fitting_problem%parameter_step = [0.1, 0.1] fitting_problem%fit_kij = .true. @@ -49,9 +52,75 @@ subroutine test_fit_kij_lij(error) call check(error, err_kij < err0) fitting_problem%fit_lij = .true. + fitting_problem%verbose = .true. X = 0 err_kij_lij = optimize(X, fitting_problem) call check(error, err_kij_lij < err_kij) end subroutine + + subroutine test_fit_mhv_nrtl(error) + use yaeos__fitting, only: optimize, error_function + use yaeos__fitting_fit_nrtl_mhv, only: FitMHVNRTL + use yaeos__models, only: CubicEoS, GeModel, NRTL, SoaveRedlichKwong, MHV + use yaeos__equilibria, only: EquilibriaState + type(error_type), allocatable, intent(out) :: error + type(CubicEoS) :: model + type(NRTL) :: ge_model + type(MHV) :: mixrule + type(EquilibriaState) :: exp_point + + real(pr) :: Tc(2) = [126.2, 568.7] + real(pr) :: pc(2) = [33.98, 24.90] + real(pr) :: w(2) = [3.7e-2_pr, 0.397_pr] + real(pr) :: X(7) + real(pr) :: err0, err_lij, err_ge, err_ge_lij + + type(FitMHVNRTL) :: fitting_problem + + exp_point = EquilibriaState( & + kind="bubble", T=344.5_pr, P=23.9_pr, & + x=[0.0309_pr, 1 - 0.0309_pr], y=[0.9883_pr, 1 - 0.9883_pr], & + Vx=0._pr, Vy=0._pr, beta=0.0_pr & + ) + + + ! Provide initials for the NRTL model + ! reshape (a11 a12 a21 a22) + ge_model%a=reshape([0.0, 3.1, 0.1, 0.0], [2, 2]) + ge_model%b=reshape([0.0, 503.1, 200.1, 0.0], [2, 2]) + ge_model%c=reshape([0.0, 0.1, 0.1, 0.0], [2, 2]) + + + model = SoaveRedlichKwong(tc, pc, w) + mixrule = MHV(ge=ge_model, q=-0.593_pr, b=model%b) + deallocate(model%mixrule) + model%mixrule = mixrule + + fitting_problem%experimental_points = [exp_point] + + X = [3.1, 0.1, -500.00, 200.00, 0.1, 0.1, 0.0] + fitting_problem%model = model + fitting_problem%fit_lij = .true. + err0 = error_function(x, func_data=fitting_problem) + err_lij = optimize(X, fitting_problem) + + X = [3.1, 0.1, -500.00, 200.00, 0.1, 0.1, 0.0] + fitting_problem%model = model + fitting_problem%fit_lij = .false. + fitting_problem%fit_nrtl = .true. + err_ge = optimize(X, fitting_problem) + + X = [3.1, 0.1, -500.00, 200.00, 0.1, 0.1, 0.0] + fitting_problem%model = model + fitting_problem%fit_lij = .true. + fitting_problem%fit_nrtl = .true. + err_ge_lij = optimize(X, fitting_problem) + + + call check(error, err_lij < err0) + call check(error, err_ge < err_lij) + call check(error, err_ge_lij < err_lij) + + end subroutine end module test_fitting diff --git a/test/test_flash.f90 b/test/test_flash.f90 index 9aa9151a7..53dd1a03d 100644 --- a/test/test_flash.f90 +++ b/test/test_flash.f90 @@ -11,12 +11,55 @@ subroutine collect_suite(testsuite) new_unittest("FlashPT", test_flash_pt), & new_unittest("FlashTV", test_flash_tv), & new_unittest("FlashPT Failed", test_flash_pt_failed), & - new_unittest("FlashPT Bad Specification", test_flash_pt_bad_spec) & + new_unittest("FlashPT Bad Specification", test_flash_pt_bad_spec), & + new_unittest("Stability tm minimization", test_tm) & ] end subroutine collect_suite + subroutine test_tm(error) + use forsus, only: Substance, forsus_dir + use yaeos + use yaeos__phase_equilibria_stability, only: tm, min_tpd + use yaeos, only: flash + implicit none + type(error_type), allocatable, intent(out) :: error + + integer, parameter :: nc=2 + + class(ArModel), allocatable :: model + type(Substance) :: sus(nc) + real(pr) :: tc(nc), pc(nc), ac(nc) + real(pr) :: z(nc), T, P + real(pr) :: w(nc), mintpd + + forsus_dir = "build/dependencies/forsus/data/json" + sus(1) = Substance("methane") + sus(2) = Substance("hydrogen sulfide") + + z = [0.13, 1-0.13] + z = z/sum(z) + + P = 20.0_pr + T = 190._pr + + tc = sus%critical%critical_temperature%value + pc = sus%critical%critical_pressure%value/1e5_pr + ac = sus%critical%acentric_factor%value + + model = SoaveRedlichKwong(tc, pc, ac) + + call min_tpd(model, z, P, T, mintpd, w) + call check(error, abs(mintpd - 5.3e-6_pr) < 1e-5) + + P = 15 + call min_tpd(model, z, P, T, mintpd, w) + call check(error, abs(mintpd - (-0.1883_pr)) < 1e-4) + + call check(error, abs(tm(model, z, w, p, t) - mintpd) < 1e-10_pr) + end subroutine test_tm + subroutine test_flash_pt(error) - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel type(error_type), allocatable, intent(out) :: error integer, parameter :: nc = 2 @@ -52,7 +95,7 @@ subroutine test_flash_pt(error) end subroutine test_flash_pt subroutine test_flash_tv(error) - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel use fixtures_models, only: binary_PR76 type(error_type), allocatable, intent(out) :: error @@ -61,7 +104,7 @@ subroutine test_flash_tv(error) real(pr) :: x(nc) = [6.8598497458814592E-002, 0.93140153234346601] real(pr) :: y(nc) = [0.61055654015073813, 0.38944348965161085] real(pr) :: vx = 9.3682339483042124E-002 - real(pr) :: vy = 2.3935064128338039 + real(pr) :: vy = 2.3935064128338039 real(pr) :: beta = 0.61148923421371815 real(pr) :: P = 6.097517429661468 @@ -78,8 +121,8 @@ subroutine test_flash_tv(error) V = 1.5_pr t = 210 k0 = (model%components%Pc/10._pr) & - * exp(5.373_pr*(1 + model%components%w)& - * (1 - model%components%Tc/T)) + * exp(5.373_pr*(1 + model%components%w)& + * (1 - model%components%Tc/T)) flash_result = flash(model, n, t=t, v_spec=v, k0=k0, iters=iters) @@ -92,7 +135,7 @@ subroutine test_flash_tv(error) end subroutine test_flash_tv subroutine test_flash_pt_failed(error) - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel type(error_type), allocatable, intent(out) :: error integer, parameter :: nc = 2 @@ -124,7 +167,7 @@ subroutine test_flash_pt_failed(error) end subroutine test_flash_pt_failed subroutine test_flash_pt_bad_spec(error) - use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel, fugacity_tp + use yaeos, only: pr, EquilibriaState, flash, PengRobinson76, ArModel type(error_type), allocatable, intent(out) :: error integer, parameter :: nc = 2 diff --git a/test/test_implementations/ar_models/cubics/test_pr76.f90 b/test/test_implementations/ar_models/cubics/test_pr76.f90 index 8df8e1eca..61459b8ab 100644 --- a/test/test_implementations/ar_models/cubics/test_pr76.f90 +++ b/test/test_implementations/ar_models/cubics/test_pr76.f90 @@ -96,11 +96,11 @@ subroutine test_pr76_cons_mixture(error) Ar=Ar_num, Arn2=Arn2_num) ! Calling individually just because coverage - call ar_consistency(model, n, v, t, eq31=eq31) - call ar_consistency(model, n, v, t, eq33=eq33) - call ar_consistency(model, n, v, t, eq34=eq34) - call ar_consistency(model, n, v, t, eq36=eq36) - call ar_consistency(model, n, v, t, eq37=eq37) + call ar_consistency(model, n, V, T, eq31=eq31) + call ar_consistency(model, n, V, T, eq33=eq33) + call ar_consistency(model, n, V, T, eq34=eq34) + call ar_consistency(model, n, V, T, eq36=eq36) + call ar_consistency(model, n, V, T, eq37=eq37) ! Numeric derivatives call check(error, rel_error(Ar, Ar_num) < 1e-6) @@ -115,11 +115,11 @@ subroutine test_pr76_cons_mixture(error) call check(error, maxval(rel_error(Arn2, Arn2_num)) < 1e-5) ! Consistency tests - call check(error, abs(eq31) <= 1e-15) - call check(error, maxval(abs(eq33)) < 1e-15) + call check(error, abs(eq31) <= 1e-14) + call check(error, maxval(abs(eq33)) < 1e-14) call check(error, maxval(abs(eq34)) < 1e-14) - call check(error, abs(eq36) <= 1e-15) - call check(error, abs(eq37) <= 1e-15) + call check(error, abs(eq36) <= 1e-14) + call check(error, abs(eq37) <= 1e-14) ! ======================================================================== ! Model with kij and lij @@ -241,7 +241,6 @@ end subroutine test_pr76_cons_pure subroutine test_pr76_compressibility_factor(error) ! From original paper. use yaeos, only: pr, R, PengRobinson76, ArModel - use yaeos__thermoprops, only: volume type(error_type), allocatable, intent(out) :: error integer :: i @@ -272,7 +271,7 @@ subroutine test_pr76_compressibility_factor(error) Z1 = [0.151_pr, 0.248_pr, 0.482_pr, 0.707_pr, 0.926_pr] do i=1,5 - call volume(model, z, P1(i), T, V=v, root_type="stable") + call model%volume(z, P1(i), T, V=v, root_type="stable") Zcomp = P1(i) * v / (R * T) call check(error, abs(Zcomp - Z1(i)) < 1e-3) @@ -284,7 +283,7 @@ subroutine test_pr76_compressibility_factor(error) Z2 = [0.289_pr, 0.482_pr, 0.665_pr, 0.840_pr] do i=1,4 - call volume(model, z, P2(i), T, V=v, root_type="stable") + call model%volume(z, P2(i), T, V=v, root_type="stable") Zcomp = P2(i) * v / (R * T) call check(error, abs(Zcomp - Z2(i)) < 1e-3) @@ -296,7 +295,7 @@ subroutine test_pr76_compressibility_factor(error) Z3 = [0.804_pr, 0.696_pr, 0.643_pr, 0.744_pr, 0.869_pr] do i=1,5 - call volume(model, z, P3(i), T, V=v, root_type="stable") + call model%volume(z, P3(i), T, V=v, root_type="stable") Zcomp = P3(i) * v / (R * T) call check(error, abs(Zcomp - Z3(i)) < 1e-3) @@ -311,7 +310,7 @@ subroutine test_pr76_compressibility_factor(error) Z4 = [0.215_pr, 0.404_pr, 0.580_pr, 0.750_pr] do i=1,4 - call volume(model, z, P4(i), T, V=v, root_type="stable") + call model%volume(z, P4(i), T, V=v, root_type="stable") Zcomp = P4(i) * v / (R * T) call check(error, abs(Zcomp - Z4(i)) < 1e-3) @@ -323,7 +322,7 @@ subroutine test_pr76_compressibility_factor(error) Z5 = [0.782_pr, 0.638_pr, 0.545_pr, 0.645_pr, 0.765_pr] do i=1,5 - call volume(model, z, P5(i), T, V=v, root_type="stable") + call model%volume( z, P5(i), T, V=v, root_type="stable") Zcomp = P5(i) * v / (R * T) call check(error, abs(Zcomp - Z5(i)) < 1e-3) @@ -335,7 +334,7 @@ subroutine test_pr76_compressibility_factor(error) Z6 = [0.920_pr, 0.870_pr, 0.796_pr, 0.806_pr, 0.877_pr] do i=1,5 - call volume(model, z, P6(i), T, V=v, root_type="stable") + call model%volume(z, P6(i), T, V=v, root_type="stable") Zcomp = P6(i) * v / (R * T) call check(error, abs(Zcomp - Z6(i)) < 2e-2) @@ -345,21 +344,23 @@ end subroutine test_pr76_compressibility_factor subroutine test_pr76_co2_volume(error) ! From Elliot's book. use yaeos, only : pr, PengRobinson76, ArModel - use yaeos__thermoprops, only: volume + use yaeos__models_ar, only: volume type(error_type), allocatable, intent(out) :: error class(ArModel), allocatable :: model real(pr) :: mw, V, n(1) - integer :: i model = PengRobinson76([304.2_pr], [73.82_pr], [0.228_pr]) n = [1.0_pr] mw = 44.01 ! g / mol - call volume(model, n, 8.0_pr, 310.0_pr, V=V, root_type="stable") + call model%volume(n, 8.0_pr, 310.0_pr, V=V, root_type="stable") call check(error, abs(V / mw * 1000 - 70.37) < 0.06) + call model%volume(n, 75.0_pr, 310.0_pr, V=V, root_type="stable") + call check(error, abs(V / mw * 1000 - 3.84) < 0.01) + call volume(model, n, 75.0_pr, 310.0_pr, V=V, root_type="stable") call check(error, abs(V / mw * 1000 - 3.84) < 0.01) end subroutine test_pr76_co2_volume @@ -367,12 +368,11 @@ end subroutine test_pr76_co2_volume subroutine test_pr76_fugacities(error) ! K values of N2-CH4 (0.5, 0.5) mixture from Elliot's book. use yaeos, only: pr, R, PengRobinson76, ArModel - use yaeos__thermoprops, only: fugacity_tp, volume type(error_type), allocatable, intent(out) :: error class(ArModel), allocatable :: model - real(pr) :: T, P, z_v(2), z_l(2), v_v, lnphip_l(2), lnphip_v(2) + real(pr) :: T, P, z_v(2), z_l(2), v_v, lnphi_l(2), lnphi_v(2) T = 100 ! K P = 4.119 ! bar @@ -385,20 +385,20 @@ subroutine test_pr76_fugacities(error) [0.040_pr, 0.011_pr] & ) - call volume(model, z_v, P, T, root_type="vapor", V=v_v) - call fugacity_tp(model, z_v, T, P, root_type="vapor", lnphip = lnphip_v) - call fugacity_tp(model, z_l, T, P, root_type="liquid", lnphip = lnphip_l) + call model%volume(z_v, P, T, root_type="vapor", V=v_v) + call model%lnphi_pt(z_v, P, T, root_type="vapor", lnPhi = lnphi_v) + call model%lnphi_pt(z_l, P, T, root_type="liquid", lnPhi = lnphi_l) ! Elliot Z value of vapor call check(error, abs(P * v_v / R / T - 0.9059) < 1e-4) ! Elliot vapor fugacities - call check(error, abs(exp(lnphip_v(1) - log(P)) - 0.9162) < 1e-4) - call check(error, abs(exp(lnphip_v(2) - log(P)) - 0.8473) < 1e-4) + call check(error, abs(exp(lnPhi_v(1)) - 0.9162) < 1e-4) + call check(error, abs(exp(lnPhi_v(2)) - 0.8473) < 1e-4) ! Elliot liquid fugacities - call check(error, abs(exp(lnphip_l(1) - log(P)) - 1.791) < 1e-3) - call check(error, abs(exp(lnphip_l(2) - log(P)) - 0.0937) < 1e-4) + call check(error, abs(exp(lnPhi_l(1)) - 1.791) < 1e-3) + call check(error, abs(exp(lnPhi_l(2)) - 0.0937) < 1e-4) end subroutine test_pr76_fugacities subroutine test_pr76_txy_methanol_benzene(error) diff --git a/test/test_math/test_math.f90 b/test/test_math/test_math.f90 index b3b6bb5e3..9b94146c6 100644 --- a/test/test_math/test_math.f90 +++ b/test/test_math/test_math.f90 @@ -12,7 +12,10 @@ subroutine collect_suite(testsuite) testsuite = [ & new_unittest("Test dx_to_dn", test_dx_to_dn), & - new_unittest("Test sq_error", test_sq_error) & + new_unittest("Test sq_error", test_sq_error), & + new_unittest("Test cardano", test_cardano_method), & + new_unittest("Test rosendo", test_rosendo_method), & + new_unittest("Test newton", test_newton_method) & ] end subroutine collect_suite @@ -45,6 +48,138 @@ subroutine test_sq_error(error) call check(error, allclose(errors_sq, (sim - exps)**2, 1e10_pr)) end subroutine test_sq_error -end module test_math + subroutine test_cardano_method(error) + use yaeos__math_linalg, only: pr, cubic_roots + type(error_type), allocatable, intent(out) :: error + real(pr) :: p(4) + real(pr) :: rr(3) + complex(pr) :: cr(3) + real(pr) :: num + integer :: flag + + p = [1, -10, 35, -50] + call cubic_roots(p, rr, cr, flag) + call check(error, flag == 1) + call check(error, abs(rr(1) - 5.0_pr) < 1e-10_pr) + + p = [0.1, -2.6, 1., 1.] + call cubic_roots(p, rr, cr, flag) + call check(error, flag == -1) + call check(error, & + maxval(abs(rr - [-0.454216, 0.8601986, 25.594016])) < 1e-5_pr & + ) + + ! ======================================================================= + ! 3 Real roots + ! x1 = 1, x2 = 3, x3 = 4 + ! ----------------------------------------------------------------------- + p = [1._pr, -8._pr, 19._pr, -12._pr] + + call cubic_roots(p, rr, cr, flag) + + call check(error, maxval(rr - [1.0_pr, 3.0_pr, 4.0_pr]) < 1e-7) + call check(error, flag == -1) + + ! ======================================================================= + ! 1 real root different, 2 equal real roots + ! x1 = 1, x2 = x3 = 4 + ! ----------------------------------------------------------------------- + p = [1._pr, -9._pr, 24._pr, -16._pr] + + call cubic_roots(p, rr, cr, flag) + + call check(error, maxval(rr - [1.0_pr, 4.0_pr, 4.0_pr]) < 1e-7) + call check(error, flag == 0) + + ! ======================================================================= + ! 1 real root, 2 complex + ! x1 = 1, x2 = i, x3 = -i + ! ----------------------------------------------------------------------- + p = [1._pr, -1._pr, 1._pr, -1._pr] + + call cubic_roots(p, rr, cr, flag) + + call check(error, (rr(1) - 1.0_pr) < 1e-7) + call check(error, flag == 1) + end subroutine test_cardano_method + + subroutine test_rosendo_method(error) + use yaeos__math_linalg, only: pr, cubic_roots_rosendo + + type(error_type), allocatable, intent(out) :: error + + real(pr) :: p(4) + real(pr) :: a, b + real(pr) :: roots(3) + complex(pr) :: c_roots(3) + integer :: flag + ! ======================================================================= + ! 3 Real roots + ! x1 = 1, x2 = 3, x3 = 4 + ! ----------------------------------------------------------------------- + p = [1._pr, -8._pr, 19._pr, -12._pr] + + call cubic_roots_rosendo(p, roots, c_roots, flag) + + call check(error, maxval(roots - [1.0_pr, 3.0_pr, 4.0_pr]) < 1e-7) + call check(error, flag == -1) + + ! ======================================================================= + ! 1 real root different, 2 equal real roots + ! x1 = 1, x2 = x3 = 4 + ! ----------------------------------------------------------------------- + p = [1._pr, -9._pr, 24._pr, -16._pr] + + call cubic_roots_rosendo(p, roots, c_roots, flag) + + call check(error, maxval(roots - [1.0_pr, 4.0_pr, 4.0_pr]) < 1e-7) + call check(error, flag == -1) + + ! ======================================================================= + ! 1 real root, 2 complex + ! x1 = 1, x2 = i, x3 = -i + ! ----------------------------------------------------------------------- + p = [1._pr, -1._pr, 1._pr, -1._pr] + + call cubic_roots_rosendo(p, roots, c_roots, flag) + + call check(error, maxval(roots - [1.0_pr, 1.0_pr, 1.0_pr]) < 1e-7) + call check(error, flag == 1) + + ! ======================================================================= + ! 1 real root and two small complex roots + ! x1 = 1, x2 = a+bi, x3 = a-bi + ! ----------------------------------------------------------------------- + a = 1._pr + b = 1e-6_pr + + p = [1._pr, -(2*a + 1), (a**2 + b**2 + 2 * a), -(a**2 + b**2)] + + call cubic_roots_rosendo(p, roots, c_roots, flag) + + call check(error, maxval(roots - [1.0_pr, 1.0_pr, 1.0_pr]) < 1e-7) + call check(error, flag == 1) + end subroutine test_rosendo_method + + subroutine test_newton_method(error) + use yaeos__math, only: pr, newton + type(error_type), allocatable, intent(out) :: error + real(pr) :: x + real(pr) :: tol=1e-5 + integer :: max_iters = 100 + + x = 0.5 + call newton(foo, x, tol, max_iters) + call check(error, abs(x - sqrt(2._pr)) < tol) + contains + subroutine foo(xx, f, df) + real(pr), intent(in) :: xx + real(pr), intent(out) :: f + real(pr), intent(out) :: df + f = xx**2 - 2 + df = 2*xx + end subroutine foo + end subroutine test_newton_method +end module test_math diff --git a/test/test_runner.f90 b/test/test_runner.f90 index 3d49bc456..50efbda3f 100644 --- a/test/test_runner.f90 +++ b/test/test_runner.f90 @@ -32,7 +32,7 @@ program tester ! ------------------------------------------------------------------------- use test_fitting, only: suite_fitting => collect_suite - use stdlib_ansi, only: fg_color_green, fg_color_red, operator(//), style_reset + use stdlib_ansi, only: style_bold, fg_color_green, fg_color_red, operator(//), style_reset implicit none @@ -74,7 +74,8 @@ program tester do is = 1, size(testsuites) - write (error_unit, fmt) "Testing:", testsuites(is)%name + write (error_unit, fmt) "Testing:", & + style_bold // testsuites(is)%name // style_reset call run_testsuite(testsuites(is)%collect, error_unit, stat) end do diff --git a/test/test_saturation.f90 b/test/test_saturation.f90 index 9c408dea7..36e1b807a 100644 --- a/test/test_saturation.f90 +++ b/test/test_saturation.f90 @@ -107,7 +107,7 @@ subroutine test_dew_temperature(error) end subroutine subroutine test_bubble_temperature(error) - use yaeos, only: pr, EquilibriaState, saturation_temperature, ArModel + use yaeos, only: pr, EquilibriaState, saturation_temperature, ArModel, saturation_pressure, PTEnvel2, pt_envelope_2ph use fixtures_models, only: binary_PR76 type(error_type), allocatable, intent(out) :: error @@ -125,8 +125,7 @@ subroutine test_bubble_temperature(error) n = [0.4_pr, 0.6_pr] T = 200 model = binary_PR76() - - bubble = saturation_temperature(model, n, P, kind="bubble", t0=300._pr) + bubble = saturation_temperature(model, n, P, kind="bubble",t0=201._pr) call check(error, maxval(abs(bubble%x - x)) < abs_tolerance) call check(error, maxval(abs(bubble%y - y)) < abs_tolerance) call check(error, abs(bubble%p - p) < abs_tolerance) diff --git a/test/test_thermoprops.f90 b/test/test_thermoprops.f90 index fe3a5f1fc..9a7e495c8 100644 --- a/test/test_thermoprops.f90 +++ b/test/test_thermoprops.f90 @@ -21,7 +21,7 @@ end subroutine collect_suite subroutine test_fugacity_VT(error) use fixtures_models, only: binary_PR76 - use yaeos, only: pr, CubicEoS, fugacity_vt + use yaeos, only: pr, CubicEoS type(error_type), allocatable, intent(out) :: error type(CubicEoS) :: eos @@ -33,7 +33,7 @@ subroutine test_fugacity_VT(error) real(pr) :: lnfug_val(2), dlnphidp_val(2), dlnphidt_val(2) - lnfug_val = [2.0758887796938881, -2.2852154042663555] + lnfug_val = [2.0785927055052529, -2.2825114783106386] dlnphidp_val = [-0.99328668293856137, -0.9965756859512391] dlnphidt_val = [3.0263825169536504E-002, 7.6204959316774373E-002] @@ -43,14 +43,9 @@ subroutine test_fugacity_VT(error) v = 8.8780451065729321E-002_pr t = 150 - call fugacity_vt(eos, & + call eos%lnphi_vt(& z, V, T, P, lnfug, dlnPhidP, dlnphidT, dlnPhidn & ) - - print * , lnfug - print * , dlnphidP - print * , dlnphidT - call check( & error, maxval(abs(lnfug - lnfug_val)) < 1e-5 & ) @@ -64,7 +59,7 @@ end subroutine test_fugacity_VT subroutine test_fugacity_TP(error) use fixtures_models, only: binary_PR76 - use yaeos, only: pr, CubicEoS, fugacity_tp + use yaeos, only: pr, CubicEoS type(error_type), allocatable, intent(out) :: error type(CubicEoS) :: eos @@ -90,9 +85,8 @@ subroutine test_fugacity_TP(error) t = 150 root_type = "liquid" - - call fugacity_tp(eos, & - z, T, P, V, root_type, lnfug, dlnPhidP, dlnphidT, dlnPhidn& + call eos%lnphi_pt(& + z, P, T, V, root_type, lnfug, dlnPhidP, dlnphidT, dlnPhidn& ) call check(& @@ -111,7 +105,6 @@ end subroutine test_fugacity_TP ! -------------------------------------------------------------------------- subroutine test_enthalpy_residual_vt(error) use yaeos, only: pr, R, CubicEoS, PengRobinson76 - use yaeos, only: enthalpy_residual_vt, fugacity_vt type(error_type), allocatable, intent(out) :: error @@ -143,11 +136,11 @@ subroutine test_enthalpy_residual_vt(error) eos = PengRobinson76(tc, pc, w, kij, lij) ! yaeos residual enthalpies - call enthalpy_residual_vt(eos, z, v, t, Hr, HrT=HrT, HrV=HrV, Hrn=Hrn) + call eos%enthalpy_residual_vt(z, v, t, Hr, HrT=HrT, HrV=HrV, Hrn=Hrn) ! test against fugacity coefficient derivatives ! (Michelsen and Mollerup chapter 2 eq 37) - call fugacity_vt(eos, z, v, t, lnphip=lnfug, dlnphidt=dlnphidt) + call eos%lnphi_vt(z, v, t, lnPhi=lnfug, dlnphidt=dlnphidt) Hr_fromphi = -1_pr * sum(z * dlnphidT) * R * t**2 ! Hr(T,P) = Hr(T,V) @@ -157,7 +150,7 @@ subroutine test_enthalpy_residual_vt(error) ! numeric derivatives residual enthalpies ! HrT_num - call enthalpy_residual_vt(eos, z, v, t + delta_t, Hr_delta_t) + call eos%enthalpy_residual_vt(z, v, t + delta_t, Hr_delta_t) HrT_num = (Hr_delta_t - Hr) / delta_t @@ -166,7 +159,7 @@ subroutine test_enthalpy_residual_vt(error) ) ! HrV_num - call enthalpy_residual_vt(eos, z, v + delta_v, t, Hr_delta_v) + call eos%enthalpy_residual_vt(z, v + delta_v, t, Hr_delta_v) HrV_num = (Hr_delta_v - Hr) / delta_v @@ -176,10 +169,10 @@ subroutine test_enthalpy_residual_vt(error) ! Hrn_num zd1 = [0.3_pr + delta_n, 0.7_pr] - call enthalpy_residual_vt(eos, zd1, v, t, Hr_delta_n1) + call eos%enthalpy_residual_vt(zd1, v, t, Hr_delta_n1) zd2 = [0.3_pr, 0.7_pr + delta_n] - call enthalpy_residual_vt(eos, zd2, v, t, Hr_delta_n2) + call eos%enthalpy_residual_vt(zd2, v, t, Hr_delta_n2) Hrn_num = [(Hr_delta_n1 - Hr) / delta_n, (Hr_delta_n2 - Hr) / delta_n] @@ -194,7 +187,6 @@ end subroutine test_enthalpy_residual_vt ! -------------------------------------------------------------------------- subroutine test_gibss_residual_vt(error) use yaeos, only: pr, R, CubicEoS, SoaveRedlichKwong - use yaeos, only: gibbs_residual_vt, fugacity_vt, pressure type(error_type), allocatable, intent(out) :: error @@ -225,22 +217,22 @@ subroutine test_gibss_residual_vt(error) eos = SoaveRedlichKwong(tc, pc, w, kij, lij) - call pressure(eos, z, v, t, p) + call eos%pressure(z, v, t, p) ntot = sum(z) Zcomp = p*v/(ntot*R*t) ! yaeos residual gibbs - call gibbs_residual_vt(eos, z, v, t, Gr, GrT=GrT, GrV=GrV, Grn=Grn) + call eos%gibbs_residual_vt(z, V, T, Gr, GrT=GrT, GrV=GrV, Grn=Grn) ! test against fugacity coefficient ! (Michelsen and Mollerup chapter 2 eq 31) - call fugacity_vt(eos, z, v, t, lnphip=lnfug) + call eos%lnphi_vt(z, V, T, lnPhi=lnfug) - lnfugcoeffs = lnfug - log(p) ! lnfug is = ln(phi * p) + lnfugcoeffs = lnfug - Gr_tp = Gr - ntot*R*t*log(Zcomp) ! M and M chapter 1 Table 6 + Gr_tp = Gr - ntot*R*T*log(Zcomp) ! M and M chapter 1 Table 6 - Gr_fromphi = sum(z * lnfugcoeffs) * R * t + Gr_fromphi = sum(z * lnfugcoeffs) * R * T call check(& error, rel_error(Gr_tp, Gr_fromphi) < 1e-14 & @@ -248,7 +240,7 @@ subroutine test_gibss_residual_vt(error) ! numeric derivatives residual enthalpies ! GrT_num - call gibbs_residual_vt(eos, z, v, t + delta_t, Gr_delta_t) + call eos%gibbs_residual_vt(z, v, t + delta_t, Gr_delta_t) GrT_num = (Gr_delta_t - Gr) / delta_t @@ -257,7 +249,7 @@ subroutine test_gibss_residual_vt(error) ) ! GrV_num - call gibbs_residual_vt(eos, z, v + delta_v, t, Gr_delta_v) + call eos%gibbs_residual_vt(z, v + delta_v, t, Gr_delta_v) GrV_num = (Gr_delta_v - Gr) / delta_v @@ -267,10 +259,10 @@ subroutine test_gibss_residual_vt(error) ! Grn_num zd1 = [0.3_pr + delta_n, 0.7_pr] - call gibbs_residual_vt(eos, zd1, v, t, Gr_delta_n1) + call eos%gibbs_residual_vt(zd1, v, t, Gr_delta_n1) zd2 = [0.3_pr, 0.7_pr + delta_n] - call gibbs_residual_vt(eos, zd2, v, t, Gr_delta_n2) + call eos%gibbs_residual_vt(zd2, v, t, Gr_delta_n2) Grn_num = [(Gr_delta_n1 - Gr) / delta_n, (Gr_delta_n2 - Gr) / delta_n] @@ -284,10 +276,7 @@ end subroutine test_gibss_residual_vt ! Sr ! -------------------------------------------------------------------------- subroutine test_entropy_residual_vt(error) - use yaeos, only: pr, R, CubicEoS, SoaveRedlichKwong, pressure - use yaeos, only: entropy_residual_vt - use yaeos, only: enthalpy_residual_vt - use yaeos, only: gibbs_residual_vt + use yaeos, only: pr, R, CubicEoS, SoaveRedlichKwong type(error_type), allocatable, intent(out) :: error @@ -321,14 +310,14 @@ subroutine test_entropy_residual_vt(error) eos = SoaveRedlichKwong(tc, pc, w, kij, lij) - call pressure(eos, z, v, t, p) + call eos%pressure(z, v, t, p) Zcomp = p*v/(ntot*R*t) ! yaeos residual gibbs - call entropy_residual_vt(eos, z, v, t, Sr, SrT=SrT, SrV=SrV, Srn=Srn) - call enthalpy_residual_vt(eos, z, v, t, Hr) - call gibbs_residual_vt(eos, z, v, t, Gr) + call eos%entropy_residual_vt(z, v, t, Sr, SrT=SrT, SrV=SrV, Srn=Srn) + call eos%enthalpy_residual_vt(z, v, t, Hr) + call eos%gibbs_residual_vt(z, v, t, Gr) ! test against Hr and Gr ! (Michelsen and Mollerup chapter 2 eq 22) @@ -341,7 +330,7 @@ subroutine test_entropy_residual_vt(error) ) ! SrT_num - call entropy_residual_vt(eos, z, v, t + delta_t, Sr_delta_t) + call eos%entropy_residual_vt(z, v, t + delta_t, Sr_delta_t) SrT_num = (Sr_delta_t - Sr) / delta_t @@ -350,7 +339,7 @@ subroutine test_entropy_residual_vt(error) ) ! SrV_num - call entropy_residual_vt(eos, z, v + delta_v, t, Sr_delta_v) + call eos%entropy_residual_vt(z, v + delta_v, t, Sr_delta_v) SrV_num = (Sr_delta_v - Sr) / delta_v @@ -360,10 +349,10 @@ subroutine test_entropy_residual_vt(error) ! Srn_num zd1 = [0.3_pr + delta_n, 0.7_pr] - call entropy_residual_vt(eos, zd1, v, t, Sr_delta_n1) + call eos%entropy_residual_vt(zd1, v, t, Sr_delta_n1) zd2 = [0.3_pr, 0.7_pr + delta_n] - call entropy_residual_vt(eos, zd2, v, t, Sr_delta_n2) + call eos%entropy_residual_vt(zd2, v, t, Sr_delta_n2) Srn_num = [(Sr_delta_n1 - Sr) / delta_n, (Sr_delta_n2 - Sr) / delta_n] @@ -377,8 +366,7 @@ end subroutine test_entropy_residual_vt ! -------------------------------------------------------------------------- subroutine cp_and_cv(error) ! TODO need derivatives dvdt to complete the test - use yaeos, only: pr, R, CubicEoS, SoaveRedlichKwong, pressure - use yaeos, only: Cp_residual_vt, Cv_residual_vt + use yaeos, only: pr, R, CubicEoS, SoaveRedlichKwong type(error_type), allocatable, intent(out) :: error @@ -406,12 +394,12 @@ subroutine cp_and_cv(error) eos = SoaveRedlichKwong(tc, pc, w, kij, lij) - call pressure(eos, z, v, t, p, dpdv=dpdv, dpdt=dpdt) + call eos%pressure(z, v, t, p, dpdv=dpdv, dpdt=dpdt) ! Dumb test need derivative dvdt to complete the test ! Michelsen and Mollerup chapter 2 eq 19 - call Cp_residual_vt(eos, z, v, t, Cpr) - call Cv_residual_vt(eos, z, v, t, Cvr) + call eos%Cp_residual_vt(z, v, t, Cpr) + call eos%Cv_residual_vt(z, v, t, Cvr) lefths = (Cpr - Cvr)/R righths = -t/R*dpdt**2/dpdv - ntot diff --git a/tools/notebooks/sympy.ipynb b/tools/notebooks/sympy.ipynb new file mode 100644 index 000000000..d0a93f81a --- /dev/null +++ b/tools/notebooks/sympy.ipynb @@ -0,0 +1,682 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sympy as sp" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - \\frac{K \\beta z}{\\left(\\beta \\left(K - 1\\right) + 1\\right)^{2}} + \\frac{z}{\\beta \\left(K - 1\\right) + 1}$" + ], + "text/plain": [ + "-K*\\beta*z/(\\beta*(K - 1) + 1)**2 + z/(\\beta*(K - 1) + 1)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z, beta, K = sp.symbols(r\"z \\beta K\")\n", + "\n", + "x = z / (beta * (K - 1) + 1)\n", + "y = K * x\n", + "\n", + "dxdk = sp.diff(x, K)\n", + "sp.diff(y, K)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{v_{x}}{v_{x} - v_{y}}$" + ], + "text/plain": [ + "v_x/(v_x - v_y)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vx, vy, v = sp.symbols(r\"v_x, v_y, v\")\n", + "\n", + "v = beta * vy + (1-beta)*vx\n", + "\n", + "sp.solve(v, beta)[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " -\\beta*v_y/(\\beta - 1)**2 + v_y/(\\beta - 1)\n" + ] + } + ], + "source": [ + "sp.print_fcode(sp.diff(sp.solve(v, vx)[0], beta))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{v_{x}}{\\beta^{2}}$" + ], + "text/plain": [ + "v_x/\\beta**2" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sp.diff(sp.solve(v, vy)[0], beta)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " -\\beta*z*(K - 1)/(\\beta*(K - 1) + 1)**2 + z/(\\beta*(K - 1) + 1)\n" + ] + } + ], + "source": [ + "sp.print_fcode(sp.diff(z * (K - 1)/(1 + beta*(K-1)), K))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "c1, c2, c3, Tr = sp.symbols(\"c1 c2 c3 Tr\")\n", + "\n", + "# sqrt_Tr = sp.Function(\"(1-\\sqrt{Tr})\")(Tr) # 1 - sp.sqrt(Tr)\n", + "\n", + "sqrt_Tr = 1 - sp.sqrt(Tr)\n", + "\n", + "a = (1 + c1 * (sqrt_Tr) + c2 * (sqrt_Tr) + c3 * (sqrt_Tr))**2\n", + "dadt = sp.diff(a, Tr)\n", + "dadt2 = sp.diff(dadt, Tr)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " -k*(3/(Tr + 2))**k/(Tr + 2)\n", + " k*(3/(Tr + 2))**k*(k + 1)/(Tr + 2)**2\n" + ] + } + ], + "source": [ + "k, Tr = sp.symbols(\"k Tr\")\n", + "a = (3/(2 + Tr))**k\n", + "\n", + "dadtr = sp.diff(a, Tr).simplify()\n", + "dadtr2 = sp.diff(dadtr, Tr).simplify()\n", + "\n", + "sp.print_fcode(dadtr.simplify())\n", + "sp.print_fcode(dadtr2.simplify())" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " (c1 + c2 + c3)*(c1*(sqrt(Tr) - 1) + c2*(sqrt(Tr) - 1) + c3*(sqrt(\n", + " @ Tr) - 1) - 1)/sqrt(Tr)\n", + " (1.0d0/2.0d0)*(c1**2 + 2*c1*c2 + 2*c1*c3 + c1 + c2**2 + 2*c2*c3 +\n", + " @ c2 + c3**2 + c3)/Tr**(3.0d0/2.0d0)\n" + ] + } + ], + "source": [ + "sp.print_fcode(dadt.simplify())\n", + "sp.print_fcode(dadt2.simplify())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Combining rules" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "i, j = sp.symbols(\"i j\",cls=sp.Idx)\n", + "k = sp.IndexedBase(\"k\")\n", + "T = sp.symbols(\"T\")\n", + "ai = sp.Function(\"a_i\")(T)\n", + "aj = sp.Function(\"a_j\")(T)\n", + "\n", + "daijdt = sp.diff(sp.sqrt(ai*aj) * (1 - k[i,j]), T).simplify()\n", + "daijdt2 = sp.diff(daijdt, T)#.simplify()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - \\frac{\\sqrt{a_{i}{\\left(T \\right)} a_{j}{\\left(T \\right)}} \\left(\\frac{a_{i}{\\left(T \\right)} \\frac{d}{d T} a_{j}{\\left(T \\right)}}{2} + \\frac{a_{j}{\\left(T \\right)} \\frac{d}{d T} a_{i}{\\left(T \\right)}}{2}\\right) \\left(a_{i}{\\left(T \\right)} \\frac{d}{d T} a_{j}{\\left(T \\right)} + a_{j}{\\left(T \\right)} \\frac{d}{d T} a_{i}{\\left(T \\right)}\\right) \\left({k}_{i,j} - 1\\right)}{2 a_{i}^{2}{\\left(T \\right)} a_{j}^{2}{\\left(T \\right)}} + \\frac{\\sqrt{a_{i}{\\left(T \\right)} a_{j}{\\left(T \\right)}} \\left(a_{i}{\\left(T \\right)} \\frac{d}{d T} a_{j}{\\left(T \\right)} + a_{j}{\\left(T \\right)} \\frac{d}{d T} a_{i}{\\left(T \\right)}\\right) \\left({k}_{i,j} - 1\\right) \\frac{d}{d T} a_{j}{\\left(T \\right)}}{2 a_{i}{\\left(T \\right)} a_{j}^{2}{\\left(T \\right)}} + \\frac{\\sqrt{a_{i}{\\left(T \\right)} a_{j}{\\left(T \\right)}} \\left(a_{i}{\\left(T \\right)} \\frac{d}{d T} a_{j}{\\left(T \\right)} + a_{j}{\\left(T \\right)} \\frac{d}{d T} a_{i}{\\left(T \\right)}\\right) \\left({k}_{i,j} - 1\\right) \\frac{d}{d T} a_{i}{\\left(T \\right)}}{2 a_{i}^{2}{\\left(T \\right)} a_{j}{\\left(T \\right)}} - \\frac{\\sqrt{a_{i}{\\left(T \\right)} a_{j}{\\left(T \\right)}} \\left({k}_{i,j} - 1\\right) \\left(a_{i}{\\left(T \\right)} \\frac{d^{2}}{d T^{2}} a_{j}{\\left(T \\right)} + a_{j}{\\left(T \\right)} \\frac{d^{2}}{d T^{2}} a_{i}{\\left(T \\right)} + 2 \\frac{d}{d T} a_{i}{\\left(T \\right)} \\frac{d}{d T} a_{j}{\\left(T \\right)}\\right)}{2 a_{i}{\\left(T \\right)} a_{j}{\\left(T \\right)}}$" + ], + "text/plain": [ + "-sqrt(a_i(T)*a_j(T))*(a_i(T)*Derivative(a_j(T), T)/2 + a_j(T)*Derivative(a_i(T), T)/2)*(a_i(T)*Derivative(a_j(T), T) + a_j(T)*Derivative(a_i(T), T))*(k[i, j] - 1)/(2*a_i(T)**2*a_j(T)**2) + sqrt(a_i(T)*a_j(T))*(a_i(T)*Derivative(a_j(T), T) + a_j(T)*Derivative(a_i(T), T))*(k[i, j] - 1)*Derivative(a_j(T), T)/(2*a_i(T)*a_j(T)**2) + sqrt(a_i(T)*a_j(T))*(a_i(T)*Derivative(a_j(T), T) + a_j(T)*Derivative(a_i(T), T))*(k[i, j] - 1)*Derivative(a_i(T), T)/(2*a_i(T)**2*a_j(T)) - sqrt(a_i(T)*a_j(T))*(k[i, j] - 1)*(a_i(T)*Derivative(a_j(T), (T, 2)) + a_j(T)*Derivative(a_i(T), (T, 2)) + 2*Derivative(a_i(T), T)*Derivative(a_j(T), T))/(2*a_i(T)*a_j(T))" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "daijdt2" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - \\frac{{n}_{i} \\sum_{i=1}^{N} 1}{\\left(\\sum_{i=1}^{N} {n}_{i}\\right)^{2}} + \\frac{1}{\\sum_{i=1}^{N} {n}_{i}}$" + ], + "text/plain": [ + "-n[i]*Sum(1, (i, 1, N))/Sum(n[i], (i, 1, N))**2 + 1/Sum(n[i], (i, 1, N))" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "i, N = sp.symbols('i N', integer=True)\n", + "n = sp.IndexedBase(\"n\", shape=(N))\n", + "\n", + "zi = n[i]/sp.Sum(n[i], (i, 1, N))\n", + "\n", + "sp.diff(zi, n[i])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Huron-Vidal -like" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\sum_{i=1}^{N} \\frac{a{\\left(T \\right)} {n}_{i}}{{b}_{i}} + \\frac{G^{E}{\\left(n{\\left({n}_{i} \\right)},T \\right)} + \\sum_{i=1}^{N} R T \\log{\\left(\\frac{B{\\left(n{\\left({n}_{i} \\right)} \\right)}}{n{\\left({n}_{i} \\right)} {b}_{i}} \\right)} {n}_{i}}{q}$" + ], + "text/plain": [ + "Sum(a(T)*n[i]/b[i], (i, 1, N)) + (G^E(n(n[i]), T) + Sum(R*T*log(B(n(n[i]))/(n(n[i])*b[i]))*n[i], (i, 1, N)))/q" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sympy as sp\n", + "def sum_i(exp):\n", + " N = sp.Idx(\"N\")\n", + " return sp.Sum(exp, (i, 1, N))\n", + "\n", + "q, R, T = sp.symbols(\"q R T\")\n", + "ni, bi = sp.symbols(\"n b\", cls=sp.IndexedBase)\n", + "i = sp.Idx(\"i\")\n", + "j = sp.Idx(\"j\")\n", + "ni = ni[i]\n", + "bi = bi[i]\n", + "\n", + "i = sp.Idx(\"i\")\n", + "a = sp.Function(\"a\")(T)\n", + "n = sp.Function(\"n\")(ni)\n", + "B = sp.Function(\"B\")(n)\n", + "\n", + "ge = sp.Function(r\"G^E\")(n, T)\n", + "\n", + "DB = sum_i(ni * a/bi) + 1/q * (ge + sum_i(ni * R*T*sp.log(B/(n*bi))))\n", + "DB" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\log{\\left(\\frac{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}{\\left({n}_{1} + {n}_{2} + {n}_{3}\\right) {b}_{1}} \\right)} {n}_{1} + \\log{\\left(\\frac{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}{\\left({n}_{1} + {n}_{2} + {n}_{3}\\right) {b}_{2}} \\right)} {n}_{2} + \\log{\\left(\\frac{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}{\\left({n}_{1} + {n}_{2} + {n}_{3}\\right) {b}_{3}} \\right)} {n}_{3}$" + ], + "text/plain": [ + "log(B(n[1], n[2], n[3])/((n[1] + n[2] + n[3])*b[1]))*n[1] + log(B(n[1], n[2], n[3])/((n[1] + n[2] + n[3])*b[2]))*n[2] + log(B(n[1], n[2], n[3])/((n[1] + n[2] + n[3])*b[3]))*n[3]" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "n = sp.symbols(\"N\")\n", + "ni, bi = sp.symbols(\"n b\", cls=sp.IndexedBase)\n", + "n1, b1 = ni[1], bi[1]\n", + "n2, b2 = ni[2], bi[2]\n", + "n3, b3 = ni[3], bi[3]\n", + "\n", + "B = sp.Function(\"B\")(n1, n2, n3)\n", + "\n", + "lnB = (\n", + " n1 * sp.log(B/((n1 + n2 + n3)*b1)) + \n", + " n2 * sp.log(B/((n1 + n2 + n3)*b2)) +\n", + " n3 * sp.log(B/((n1 + n2 + n3)*b3))\n", + ")\n", + "dD1 = sp.diff(lnB, n1).simplify()\n", + "dD12 = sp.diff(dD1, n2).simplify()\n", + "\n", + "lnB" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} \\log{\\left(\\frac{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}{\\left({n}_{1} + {n}_{2} + {n}_{3}\\right) {b}_{1}} \\right)} - B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} + \\frac{\\partial}{\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{1} + \\frac{\\partial}{\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{2} + \\frac{\\partial}{\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{3}}{B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}$" + ], + "text/plain": [ + "(B(n[1], n[2], n[3])*log(B(n[1], n[2], n[3])/((n[1] + n[2] + n[3])*b[1])) - B(n[1], n[2], n[3]) + Derivative(B(n[1], n[2], n[3]), n[1])*n[1] + Derivative(B(n[1], n[2], n[3]), n[1])*n[2] + Derivative(B(n[1], n[2], n[3]), n[1])*n[3])/B(n[1], n[2], n[3])" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lnB.diff(n1).simplify()#.diff(n2).simplify()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\sum_{i=1}^{N} \\begin{cases} \\frac{\\left(\\log{\\left(\\frac{B{\\left({n}_{j} \\right)}}{{b}_{j} \\sum_{i=1}^{N} {n}_{i}} \\right)} - 1 + \\frac{\\frac{\\partial}{\\partial {n}_{j}} B{\\left({n}_{j} \\right)} {n}_{j}}{B{\\left({n}_{j} \\right)}}\\right) {n}_{j}}{\\sum_{i=1}^{N} {n}_{i}} & \\text{for}\\: N \\geq j \\wedge j \\geq 1 \\\\0 & \\text{otherwise} \\end{cases}$" + ], + "text/plain": [ + "Sum(Piecewise(((log(B(n[j])/(b[j]*Sum(n[i], (i, 1, N)))) - 1 + Derivative(B(n[j]), n[j])*n[j]/B(n[j]))*n[j]/Sum(n[i], (i, 1, N)), (j >= 1) & (N >= j)), (0, True)), (i, 1, N))" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "B=sp.Function(\"B\")(ni[i])\n", + "logB_nbi = sum_i(ni[i] * sp.log(B/(sum_i(ni[i]) * bi[i])))\n", + "\n", + "logB_nbi.diff(ni[j]).simplify()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{- \\left({n}_{1} + {n}_{2} + {n}_{3}\\right) \\frac{\\partial}{\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} \\frac{\\partial}{\\partial {n}_{2}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} + \\left(\\frac{\\partial}{\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} + \\frac{\\partial^{2}}{\\partial {n}_{2}\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{1} + \\frac{\\partial^{2}}{\\partial {n}_{2}\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{2} + \\frac{\\partial^{2}}{\\partial {n}_{2}\\partial {n}_{1}} B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)} {n}_{3}\\right) B{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}{B^{2}{\\left({n}_{1},{n}_{2},{n}_{3} \\right)}}$" + ], + "text/plain": [ + "(-(n[1] + n[2] + n[3])*Derivative(B(n[1], n[2], n[3]), n[1])*Derivative(B(n[1], n[2], n[3]), n[2]) + (Derivative(B(n[1], n[2], n[3]), n[1]) + Derivative(B(n[1], n[2], n[3]), n[1], n[2])*n[1] + Derivative(B(n[1], n[2], n[3]), n[1], n[2])*n[2] + Derivative(B(n[1], n[2], n[3]), n[1], n[2])*n[3])*B(n[1], n[2], n[3]))/B(n[1], n[2], n[3])**2" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dBi = sp.diff(B, n1)\n", + "\n", + "coso = (\n", + " n1 * dBi + n2 * dBi + n3 * dBi\n", + ")/B\n", + "\n", + "coso.diff(n2).simplify()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ge Models" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{E e^{- \\frac{E}{T}}}{T^{2}}$" + ], + "text/plain": [ + "E*exp(-E/T)/T**2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t, e = sp.symbols(\"T E\")\n", + "\n", + "psi = sp.exp(-e / t)\n", + "\n", + "sp.diff(psi, t)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'psi' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[5], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m sp\u001b[38;5;241m.\u001b[39mdiff(sp\u001b[38;5;241m.\u001b[39mdiff(\u001b[43mpsi\u001b[49m, t),t)\u001b[38;5;241m.\u001b[39msimplify()\n", + "\u001b[0;31mNameError\u001b[0m: name 'psi' is not defined" + ] + } + ], + "source": [ + "sp.diff(sp.diff(psi, t),t).simplify()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cubic roots" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sympy as sp\n", + "P, R, T, v, b, a, d1, d2 = sp.symbols(r\"P R T v b a \\delta_1 \\delta_2\")\n", + "zero = R*T/(v-b) - a/((v+d1*b)*(v+d2*b)) - P" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - P - \\frac{R T}{b - v} - \\frac{a}{\\left(\\delta_{1} b + v\\right) \\left(\\delta_{2} b + v\\right)}$" + ], + "text/plain": [ + "-P - R*T/(b - v) - a/((\\delta_1*b + v)*(\\delta_2*b + v))" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "zero.simplify()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - P \\left(- b + v\\right) \\left(\\delta_{1} b + v\\right) \\left(\\delta_{2} b + v\\right) + R T \\left(\\delta_{1} b + v\\right) \\left(\\delta_{2} b + v\\right) - a \\left(- b + v\\right)$" + ], + "text/plain": [ + "-P*(-b + v)*(\\delta_1*b + v)*(\\delta_2*b + v) + R*T*(\\delta_1*b + v)*(\\delta_2*b + v) - a*(-b + v)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "exp_2 = (v+d1*b)*(v+d2*b)# v**2 + (d1+d2)*b*v + d1*d2*b**2\n", + "exp_1 = v - b\n", + "\n", + "exp = R*T*exp_2 - a * exp_1 - P * exp_1 * exp_2\n", + "exp" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "poly = sp.Poly(exp, gens=v)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - P$" + ], + "text/plain": [ + "-P" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "poly.coeffs()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - P \\delta_{1} b - P \\delta_{2} b + P b + R T$" + ], + "text/plain": [ + "-P*\\delta_1*b - P*\\delta_2*b + P*b + R*T" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "poly.coeffs()[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle - P \\delta_{1} \\delta_{2} b^{2} + P \\delta_{1} b^{2} + P \\delta_{2} b^{2} + R T \\delta_{1} b + R T \\delta_{2} b - a$" + ], + "text/plain": [ + "-P*\\delta_1*\\delta_2*b**2 + P*\\delta_1*b**2 + P*\\delta_2*b**2 + R*T*\\delta_1*b + R*T*\\delta_2*b - a" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "poly.coeffs()[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle P \\delta_{1} \\delta_{2} b^{3} + R T \\delta_{1} \\delta_{2} b^{2} + a b$" + ], + "text/plain": [ + "P*\\delta_1*\\delta_2*b**3 + R*T*\\delta_1*\\delta_2*b**2 + a*b" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "poly.coeffs()[3]\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "thermo", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tools/tapenade_diff/ge_models/gen_ge_tapemodel.sh b/tools/tapenade_diff/ge_models/gen_ge_tapemodel.sh index 150e54985..bf9885832 100644 --- a/tools/tapenade_diff/ge_models/gen_ge_tapemodel.sh +++ b/tools/tapenade_diff/ge_models/gen_ge_tapemodel.sh @@ -60,63 +60,9 @@ mv tapeout/${name}_d_d_d_b_b.f90 tapeout/${name}_diff.f90 sed -i "s/$modflag//g" tapeout/${name}_diff.f90 sed -i "s/TYPE(UNKNOWNTYPE).*//g" tapeout/${name}_diff.f90 sed -i "s/TYPE(NRTL) :: model/CLASS(NRTL) :: model/" tapeout/${name}_diff.f90 + # sed -i "s/model%\(.*\) \(=\) \(.*\)/model%\1 => \3/g" tapeout/${name}_diff.f90 sed -i 's/REAL\*8/REAL(pr)/' tapeout/${name}_diff.f90 -# cp tapeout/${name}_diff.f90 ../example/taperobinson.f90 -# findent < tapeout/${name}_diff.f90 > tapeout/${name}_diff.f90 - -# lfortran fmt -i tapeout/${infile}_diff.f90 -# ============================================================================= - - -# Tapenade 3.16 (develop) - 13 Sep 2023 12:36 - Java 17.0.9 Linux -# @@ TAPENADE_HOME=/home/ruther/downs/tapenade_3.16/bin/.. -# Builds a differentiated program. -# Usage: tapenade [options]* filenames -# options: -# -head, -root set the differentiation root procedure(s) -# See FAQ for refined invocation syntax, e.g. -# independent and dependent arguments, multiple heads... -# -tangent, -d differentiate in forward/tangent mode (default) -# -reverse, -b differentiate in reverse/adjoint mode -# -vector, -multi turn on "vector" mode (i.e. multi-directional) -# -specializeactivity Allow for several activity patterns per routine -# -primal, -p turn off differentiation. Show pointer destinations -# -output, -o put all generated code into a single -# -splitoutputfiles split generated code, one file per top unit -# -outputdirectory, -O put all generated files in (default: .) -# -I add a new search path for include files -# -tgtvarname set extension for tangent variables (default %d) -# -tgtfuncname set extension for tangent procedures (default %_d) -# -tgtmodulename set extension for tangent modules and types (default %_diff) -# -adjvarname set extension for adjoint variables (default %b) -# -adjfuncname set extension for adjoint procedures (default %_b) -# -adjmodulename set extension for adjoint modules and types (default %_diff) -# -modulename set extension for tangent&adjoint modules and types (default %_diff) -# -inputlanguage language of input files (fortran, fortran90, -# fortran95, or C) -# -outputlanguage language of output files (fortran, fortran90, -# fortran95, or C) -# -ext incorporate external library description -# -nolib don't load standard libraries descriptions -# -i count bytes for an integer (default -i4) -# -r count bytes for a real (default -r4) -# -dr count bytes for a double real (default -dr8) -# -p count bytes for a pointer (default -p8) -# -fixinterface don't use activity to filter user-given (in)dependent vars -# -noinclude inline include files -# -debugTGT insert instructions for debugging tangent mode -# -debugADJ insert instructions for debugging adjoint mode -# -tracelevel set the level of detail of trace milestones -# -msglevel set the level of detail of error messages -# -msginfile insert error messages in output files -# -dump write a dump -# -html display results in a web browser -# -nooptim turn off optimization (in {activity, difftypes, -# diffarguments, stripprimalmodules, spareinit, splitdiff, -# mergediff, saveonlyused, tbr, snapshot, diffliveness, -# deadcontrol, recomputeintermediates, -# everyoptim} -# -version display Tapenade version information -# Report bugs to . +# remove all the external definition of functions. we use interfaces now +sed -i '/EXTERNAL.*/d' tapeout/${name}_diff.f90 \ No newline at end of file diff --git a/tools/tapenade_diff/ge_models/template.f90 b/tools/tapenade_diff/ge_models/template.f90 index 12e7a552c..bca93d67c 100644 --- a/tools/tapenade_diff/ge_models/template.f90 +++ b/tools/tapenade_diff/ge_models/template.f90 @@ -1,6 +1,7 @@ module tapenade_ge_model_template use yaeos__constants, only: pr, R use yaeos__tapenade_ge_api, only: GeModelTapenade + use yaeos__tapenade_interfaces implicit none diff --git a/tools/tapenade_diff/gen_tapemodel.sh b/tools/tapenade_diff/gen_tapemodel.sh index b0c3d44be..a7c5e02cc 100644 --- a/tools/tapenade_diff/gen_tapemodel.sh +++ b/tools/tapenade_diff/gen_tapemodel.sh @@ -76,6 +76,9 @@ sed -i "s/REAL :: r//g" tapeout/${name}_diff.f90 # make the types into classes for polymorphism sed -i 's/TYPE(\(.*\)),/class(\1),/' tapeout/${name}_diff.f90 +# remove all the external definition of functions. we use interfaces now +sed -i '/EXTERNAL.*/d' tapeout/${name}_diff.f90 + # Options to format document # fprettify -i 3 --case 1 1 1 1 # findent < tapeout/${name}_diff.f90 > tapeout/${name}_diff.f90 diff --git a/tools/tapenade_diff/template.f90 b/tools/tapenade_diff/template.f90 index 780760b94..f93f5b5d3 100644 --- a/tools/tapenade_diff/template.f90 +++ b/tools/tapenade_diff/template.f90 @@ -1,5 +1,6 @@ module tapenade_model_template use yaeos__tapenade_ar_api, only: ArModelTapenade + use yaeos__tapenade_interfaces use yaeos, only: R !! Ideal gas constants used on yaeos implicit none