From 8627d79494926bb401730a4c6d86754b7bb1b107 Mon Sep 17 00:00:00 2001 From: Philipp Rehner <69816385+prehner@users.noreply.github.com> Date: Fri, 20 Oct 2023 18:16:01 +0200 Subject: [PATCH] Release v0.5.0 (#178) --- CHANGELOG.md | 6 +- Cargo.toml | 28 +- README.md | 7 +- benches/state_creation.rs | 12 +- docs/theory/dft/derivatives.md | 2 +- .../pcsaft_working_with_parameters.ipynb | 360 ++++++----------- examples/pcsaft_working_with_parameters.ipynb | 360 ++++++----------- .../radial_distribution_function.ipynb | 19 +- feos-core/CHANGELOG.md | 8 +- feos-core/Cargo.toml | 18 +- feos-core/README.md | 2 +- feos-core/src/lib.rs | 2 - feos-core/src/parameter/mod.rs | 328 ++-------------- feos-core/src/parameter/model_record.rs | 51 ++- feos-core/src/phase_equilibria/bubble_dew.rs | 6 +- .../phase_equilibria/phase_diagram_binary.rs | 17 +- feos-core/src/phase_equilibria/vle_pure.rs | 18 +- feos-core/src/python/cubic.rs | 18 - feos-core/src/python/joback.rs | 17 - .../src/python/parameter/fragmentation.rs | 2 +- feos-core/src/python/parameter/mod.rs | 52 +-- feos-core/src/python/phase_equilibria.rs | 72 ++-- feos-core/src/python/state.rs | 30 +- feos-core/src/si/array.rs | 50 ++- feos-core/src/si/fmt.rs | 2 +- feos-core/src/si/mod.rs | 108 ++++- feos-core/src/si/ops.rs | 94 ++++- feos-core/src/si/python.rs | 8 +- feos-core/src/state/critical_point.rs | 11 +- feos-core/tests/parameters.rs | 289 ++++++++++++++ feos-core/tests/test_parameters1.json | 20 + feos-core/tests/test_parameters2.json | 29 ++ feos-core/tests/test_parameters_binary.json | 24 ++ feos-derive/Cargo.toml | 2 +- feos-dft/CHANGELOG.md | 6 +- feos-dft/Cargo.toml | 12 +- feos-dft/README.md | 2 +- feos-dft/src/adsorption/mod.rs | 9 +- feos-dft/src/adsorption/pore3d.rs | 2 +- feos-dft/src/functional.rs | 4 + feos-dft/src/lib.rs | 1 - feos-dft/src/profile/mod.rs | 2 +- feos-dft/src/profile/properties.rs | 8 +- feos-dft/src/python/adsorption/pore.rs | 10 +- .../interface/surface_tension_diagram.rs | 2 +- feos-dft/src/python/solvation.rs | 2 +- feos-dft/src/python/solver.rs | 2 +- feos-dft/src/solver.rs | 2 +- parameters/joback/README.md | 10 + .../joback1987.json} | 212 +++------- parameters/joback/literature.bib | 13 + parameters/pcsaft/README.md | 4 +- parameters/pcsaft/sauer2014_homo_joback.json | 368 ------------------ parameters/saftvrqmie/README.md | 2 +- src/eos.rs | 6 +- src/estimator/binary_vle.rs | 29 +- src/estimator/liquid_density.rs | 2 +- src/estimator/python.rs | 6 +- src/gc_pcsaft/dft/dispersion.rs | 2 +- src/gc_pcsaft/eos/parameter.rs | 1 + src/gc_pcsaft/python/mod.rs | 12 +- src/hard_sphere/mod.rs | 4 +- src/lib.rs | 6 +- src/pcsaft/dft/dispersion.rs | 2 +- src/pcsaft/dft/polar.rs | 2 +- src/pcsaft/eos/mod.rs | 2 +- src/pcsaft/python.rs | 6 +- src/pets/dft/dispersion.rs | 2 +- src/pets/python.rs | 32 +- src/saftvrqmie/eos/mod.rs | 2 +- src/saftvrqmie/parameters.rs | 5 +- src/saftvrqmie/python.rs | 31 +- src/uvtheory/mod.rs | 34 +- src/uvtheory/python.rs | 17 +- 74 files changed, 1307 insertions(+), 1641 deletions(-) create mode 100644 feos-core/tests/parameters.rs create mode 100644 feos-core/tests/test_parameters1.json create mode 100644 feos-core/tests/test_parameters2.json create mode 100644 feos-core/tests/test_parameters_binary.json create mode 100644 parameters/joback/README.md rename parameters/{pcsaft/sauer2014_hetero_joback.json => joback/joback1987.json} (53%) create mode 100644 parameters/joback/literature.bib delete mode 100644 parameters/pcsaft/sauer2014_homo_joback.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a3d6dade..8f710657f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.5.0] - 2023-10-20 ### Added - Added `IdealGasModel` enum that collects all implementors of the `IdealGas` trait. [#158](https://github.com/feos-org/feos/pull/158) - Added `feos.ideal_gas` module in Python from which (currently) `Joback` and `JobackParameters` are available. [#158](https://github.com/feos-org/feos/pull/158) @@ -21,7 +23,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved `molar_weight` impls to `Residual` due to removal of `MolarWeight` trait. [#177](https://github.com/feos-org/feos/pull/158) ### Packaging -- Updated `num-dual` dependency to 0.7. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `quantity` dependency to 0.7. +- Updated `num-dual` dependency to 0.8. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `numpy` and `PyO3` dependencies to 0.20. ## [0.4.3] - 2023-03-20 - Python only: Release the changes introduced in `feos-core` 0.4.2. diff --git a/Cargo.toml b/Cargo.toml index b1ffe7d43..f0eaf23d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "feos" -version = "0.4.3" +version = "0.5.0" authors = ["Gernot Bauer ", "Philipp Rehner "] -edition = "2018" +edition = "2021" readme = "README.md" license = "MIT OR Apache-2.0" description = "FeOs - A framework for equations of state and classical density functional theory." @@ -22,12 +22,12 @@ members = ["feos-core", "feos-dft", "feos-derive"] crate-type = ["rlib", "cdylib"] [dependencies] -quantity = { version = "0.6", optional = true } -num-dual = "0.7" -feos-core = { version = "0.4", path = "feos-core" } -feos-dft = { version = "0.4", path = "feos-dft", optional = true } -feos-derive = { version = "0.2", path = "feos-derive" } -numpy = { version = "0.18", optional = true } +quantity = { version = "0.7", optional = true } +num-dual = "0.8" +feos-core = { version = "0.5", path = "feos-core" } +feos-dft = { version = "0.5", path = "feos-dft", optional = true } +feos-derive = { version = "0.3", path = "feos-derive" } +numpy = { version = "0.20", optional = true } ndarray = { version = "0.15", features = ["approx"] } petgraph = { version = "0.6", optional = true } thiserror = "1.0" @@ -36,19 +36,19 @@ num-traits = "0.2" serde = "1.0" serde_json = "1.0" lazy_static = { version = "1.4", optional = true } -indexmap = "1.8" -rayon = { version = "1.5", optional = true } -itertools = "0.10" +indexmap = "2.0" +rayon = { version = "1.7", optional = true } +itertools = "0.11" typenum = "1.16" [dependencies.pyo3] -version = "0.18" +version = "0.20" features = ["extension-module", "abi3", "abi3-py37"] optional = true [dev-dependencies] -approx = "0.4" -criterion = "0.4" +approx = "0.5" +criterion = "0.5" [profile.release-lto] inherits = "release" diff --git a/README.md b/README.md index bef4e715f..8451e1ed9 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,13 @@ The `FeOs` package provides Rust implementations of different equation of state ```python from feos.eos import EquationOfState, State -from feos.pcsaft import PcSaftParameters +from feos.pcsaft import PcSaftParameters, PcSaftRecord + +# PC-SAFT parameters for methanol (Gross and Sadowski 2002) +record = PcSaftRecord(1.5255, 3.23, 188.9, kappa_ab=0.035176, epsilon_k_ab=2899.5, na=1, nb=1) # Build an equation of state -parameters = PcSaftParameters.from_json(['methanol'], 'parameters.json') +parameters = PcSaftParameters.from_model_records([record]) eos = EquationOfState.pcsaft(parameters) # Define thermodynamic conditions diff --git a/benches/state_creation.rs b/benches/state_creation.rs index 7396bb566..f4d190c16 100644 --- a/benches/state_creation.rs +++ b/benches/state_creation.rs @@ -4,7 +4,7 @@ use feos::pcsaft::{PcSaft, PcSaftParameters}; use feos_core::si::*; use feos_core::{ parameter::{IdentifierOption, Parameter}, - Contributions, DensityInitialization, PhaseEquilibrium, Residual, State, TPSpec, + Contributions, DensityInitialization, PhaseEquilibrium, Residual, State, TemperatureOrPressure, }; use ndarray::{Array, Array1}; use std::sync::Arc; @@ -28,18 +28,12 @@ fn critical_point((eos, n): (&Arc, Option<&Moles>>)) } /// Evaluate critical point constructor for binary systems at given T or p -fn critical_point_binary((eos, tp): (&Arc, TP)) -where - TPSpec: From, -{ +fn critical_point_binary((eos, tp): (&Arc, TP)) { State::critical_point_binary(eos, tp, None, None, Default::default()).unwrap(); } /// VLE for pure substance for given temperature or pressure -fn pure((eos, t_or_p): (&Arc, TP)) -where - TPSpec: From, -{ +fn pure((eos, t_or_p): (&Arc, TP)) { PhaseEquilibrium::pure(eos, t_or_p, None, Default::default()).unwrap(); } diff --git a/docs/theory/dft/derivatives.md b/docs/theory/dft/derivatives.md index 2ddffdf2f..7c6771f02 100644 --- a/docs/theory/dft/derivatives.md +++ b/docs/theory/dft/derivatives.md @@ -1,5 +1,5 @@ # Derivatives of density profiles -For converged density properties equilibrium properties can be calculated as partial derivatives of thermodynamic potentials analogous to classical (bulk) thermodynamics. The difference is that the derivatives have to be along a path of valid density profiles (solutions of the [Euler-Lagrange equation](euler_lagrange_equation.md)). +For converged density profiles equilibrium properties can be calculated as partial derivatives of thermodynamic potentials analogous to classical (bulk) thermodynamics. The difference is that the derivatives have to be along a path of valid density profiles (solutions of the [Euler-Lagrange equation](euler_lagrange_equation.md)). The density profiles are calculated implicitly from the Euler-Lagrange equation, which can be written simplified as diff --git a/docs/tutorials/eos/pcsaft/pcsaft_working_with_parameters.ipynb b/docs/tutorials/eos/pcsaft/pcsaft_working_with_parameters.ipynb index 4cdb484bb..cf415b8fc 100644 --- a/docs/tutorials/eos/pcsaft/pcsaft_working_with_parameters.ipynb +++ b/docs/tutorials/eos/pcsaft/pcsaft_working_with_parameters.ipynb @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -63,31 +63,26 @@ "\n", "Querying a substance from a file requires an *identifier*.\n", "This identifier can be one of `Name`, `Cas`, `Inchi`, `IupacName`, `Formula`, or `Smiles` with `Name` (common english name) being the default.\n", - "We can change the identifier type usig the `search_option` argument with an `IdentifierOption` object. Given a list of identifiers and a path to the parameter file, we can conveniently generate our object." + "We can change the identifier type usig the `identifier_option` argument with an `IdentifierOption` object. Given a list of identifiers and a path to the parameter file, we can conveniently generate our object." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043]\n", - "\tm=[1]\n", - "\tsigma=[3.7039]\n", - "\tepsilon_k=[150.03]\n", - ")" + "" ] }, - "execution_count": 4, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -103,33 +98,28 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043]\n", - "\tm=[1]\n", - "\tsigma=[3.7039]\n", - "\tepsilon_k=[150.03]\n", - ")" + "" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a system containing a single substance, \"methane\", using \"Smiles\" (\"C\") as identifier\n", - "parameters = PcSaftParameters.from_json(['C'], pure_path=file_na, search_option=IdentifierOption.Smiles)\n", + "parameters = PcSaftParameters.from_json(['C'], pure_path=file_na, identifier_option=IdentifierOption.Smiles)\n", "parameters" ] }, @@ -145,28 +135,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|hexane|86.177|3.0576|3.7983|236.77|0|0|0|0|1|1|\n", - "|dodecane|170.338|5.306|3.8959|249.21|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|hexane|86.177|3.0576|3.7983|236.77|0|0|0|0|0|0|0|\n", + "|dodecane|170.338|5.306|3.8959|249.21|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 86.177, 170.338]\n", - "\tm=[1, 3.0576, 5.306]\n", - "\tsigma=[3.7039, 3.7983, 3.8959]\n", - "\tepsilon_k=[150.03, 236.77, 249.21]\n", - ")" + "" ] }, - "execution_count": 6, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -197,35 +182,24 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|\n", - "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|\n", - "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", + "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", + "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 74.123, 18.015, 58.08]\n", - "\tm=[1, 2.7515, 1.0656, 2.7447]\n", - "\tsigma=[3.7039, 3.6139, 3.0007, 3.2742]\n", - "\tepsilon_k=[150.03, 259.59, 366.51, 232.99]\n", - "\tmu=[0, 0, 0, 2.88]\n", - "\tassociating=[1, 2]\n", - "\tkappa_ab=[0.006692, 0.034868]\n", - "\tepsilon_k_ab=[2544.6, 2500.7]\n", - "\tna=[1, 1]\n", - "\tnb=[1, 1]\n", - ")" + "" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -243,7 +217,7 @@ " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -263,35 +237,22 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -307,14 +268,14 @@ " (['CCCCO',], file_assoc)\n", " ],\n", " binary_path=file_binary,\n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -324,7 +285,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 9, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -352,7 +313,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -361,7 +322,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -370,7 +331,7 @@ "Identifier(cas=106-97-8, name=butane, iupac_name=butane, smiles=CCCC, inchi=InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3, formula=C4H10)" ] }, - "execution_count": 18, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -410,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -419,7 +380,7 @@ "PcSaftRecord(m=2.3316, sigma=3.7086, epsilon_k=222.88)" ] }, - "execution_count": 19, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -439,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -452,7 +413,7 @@ ")" ] }, - "execution_count": 20, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -473,26 +434,21 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123]\n", - "\tm=[2.3316]\n", - "\tsigma=[3.7086]\n", - "\tepsilon_k=[222.88]\n", - ")" + "" ] }, - "execution_count": 21, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -513,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -539,35 +495,22 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 23, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -579,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -589,7 +532,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 24, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -609,35 +552,22 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 25, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -657,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -667,7 +597,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 26, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -700,37 +630,27 @@ "- `pure_path`: a file containing the substance identifiers *and* the segments that form the molecule\n", "- `segments_path`: a file that contains the segments (identifier and model parameters)\n", "\n", - "As before, we can specify our substance identifier using `search_option` and we can provide binary interaction parameters (segment-segment `k_ij`) via the `binary_path` argument." + "As before, we can specify our substance identifier using `identifier_option` and we can provide binary interaction parameters (segment-segment `k_ij`) via the `binary_path` argument." ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|1|1|\n", - "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", + "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.122159999999994, 74.12158]\n", - "\tm=[2.1360799999999998, 2.3821600000000003]\n", - "\tsigma=[3.7945688260994523, 3.7568140627964164]\n", - "\tepsilon_k=[233.79002902513017, 278.79916705846796]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006825]\n", - "\tepsilon_k_ab=[2517]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - ")" + "" ] }, - "execution_count": 27, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -743,7 +663,7 @@ " ['CCCC', 'CCCCO'], \n", " pure_path, \n", " segments_path, \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -764,7 +684,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -804,7 +724,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -833,32 +753,22 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|1|1|\n", - "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", + "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.122159999999994, 74.12158]\n", - "\tm=[2.1360799999999998, 2.3821600000000003]\n", - "\tsigma=[3.7945688260994523, 3.7568140627964164]\n", - "\tepsilon_k=[233.79002902513017, 278.79916705846796]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006825]\n", - "\tepsilon_k_ab=[2517]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - ")" + "" ] }, - "execution_count": 30, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -885,35 +795,24 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|\n", - "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|\n", - "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", + "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", + "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 74.123, 18.015, 58.08]\n", - "\tm=[1, 2.7515, 1.0656, 2.7447]\n", - "\tsigma=[3.7039, 3.6139, 3.0007, 3.2742]\n", - "\tepsilon_k=[150.03, 259.59, 366.51, 232.99]\n", - "\tmu=[0, 0, 0, 2.88]\n", - "\tassociating=[1, 2]\n", - "\tkappa_ab=[0.006692, 0.034868]\n", - "\tepsilon_k_ab=[2544.6, 2500.7]\n", - "\tna=[1, 1]\n", - "\tnb=[1, 1]\n", - ")" + "" ] }, - "execution_count": 31, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -929,7 +828,7 @@ " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -943,23 +842,9 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 25, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0., 0., 0., 0.],\n", - " [0., 0., 0., 0.],\n", - " [0., 0., 0., 0.],\n", - " [0., 0., 0., 0.]])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "parameters.k_ij" ] @@ -979,7 +864,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -988,7 +873,7 @@ "[PureRecord(\n", " \tidentifier=Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4),\n", " \tmolarweight=16.043,\n", - " \tmodel_record=PcSaftRecord(m=1, sigma=3.7039, epsilon_k=150.03),\n", + " \tmodel_record=PcSaftRecord(m=1, sigma=3.7039, epsilon_k=150.03, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " ),\n", " PureRecord(\n", " \tidentifier=Identifier(cas=71-36-3, name=1-butanol, iupac_name=butan-1-ol, smiles=CCCCO, inchi=InChI=1/C4H10O/c1-2-3-4-5/h5H,2-4H2,1H3, formula=C4H10O),\n", @@ -1003,11 +888,11 @@ " PureRecord(\n", " \tidentifier=Identifier(cas=67-64-1, name=acetone, iupac_name=propan-2-one, smiles=CC(C)=O, inchi=InChI=1/C3H6O/c1-3(2)4/h1-2H3, formula=C3H6O),\n", " \tmolarweight=58.08,\n", - " \tmodel_record=PcSaftRecord(m=2.7447, sigma=3.2742, epsilon_k=232.99, mu=2.88),\n", + " \tmodel_record=PcSaftRecord(m=2.7447, sigma=3.2742, epsilon_k=232.99, mu=2.88, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " )]" ] }, - "execution_count": 33, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -1018,7 +903,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1039,7 +924,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -1048,7 +933,7 @@ "Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4)" ] }, - "execution_count": 35, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -1060,7 +945,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -1069,7 +954,7 @@ "16.043" ] }, - "execution_count": 36, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -1088,7 +973,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -1097,7 +982,7 @@ "'{\"identifier\":{\"cas\":\"74-82-8\",\"name\":\"methane\",\"iupac_name\":\"methane\",\"smiles\":\"C\",\"inchi\":\"InChI=1/CH4/h1H4\",\"formula\":\"CH4\"},\"molarweight\":16.043,\"model_record\":{\"m\":1.0,\"sigma\":3.7039,\"epsilon_k\":150.03}}'" ] }, - "execution_count": 37, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -1133,11 +1018,20 @@ "\n", "Hopefully you found this example helpful. If you have comments, critique or feedback, please let us know and consider [opening an issue on github](https://github.com/feos-org/feos/issues)." ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "from feos.ideal_gas import JobackParameters" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1151,7 +1045,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.6" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/examples/pcsaft_working_with_parameters.ipynb b/examples/pcsaft_working_with_parameters.ipynb index 4cdb484bb..cf415b8fc 100644 --- a/examples/pcsaft_working_with_parameters.ipynb +++ b/examples/pcsaft_working_with_parameters.ipynb @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -63,31 +63,26 @@ "\n", "Querying a substance from a file requires an *identifier*.\n", "This identifier can be one of `Name`, `Cas`, `Inchi`, `IupacName`, `Formula`, or `Smiles` with `Name` (common english name) being the default.\n", - "We can change the identifier type usig the `search_option` argument with an `IdentifierOption` object. Given a list of identifiers and a path to the parameter file, we can conveniently generate our object." + "We can change the identifier type usig the `identifier_option` argument with an `IdentifierOption` object. Given a list of identifiers and a path to the parameter file, we can conveniently generate our object." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043]\n", - "\tm=[1]\n", - "\tsigma=[3.7039]\n", - "\tepsilon_k=[150.03]\n", - ")" + "" ] }, - "execution_count": 4, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -103,33 +98,28 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043]\n", - "\tm=[1]\n", - "\tsigma=[3.7039]\n", - "\tepsilon_k=[150.03]\n", - ")" + "" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a system containing a single substance, \"methane\", using \"Smiles\" (\"C\") as identifier\n", - "parameters = PcSaftParameters.from_json(['C'], pure_path=file_na, search_option=IdentifierOption.Smiles)\n", + "parameters = PcSaftParameters.from_json(['C'], pure_path=file_na, identifier_option=IdentifierOption.Smiles)\n", "parameters" ] }, @@ -145,28 +135,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|hexane|86.177|3.0576|3.7983|236.77|0|0|0|0|1|1|\n", - "|dodecane|170.338|5.306|3.8959|249.21|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|hexane|86.177|3.0576|3.7983|236.77|0|0|0|0|0|0|0|\n", + "|dodecane|170.338|5.306|3.8959|249.21|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 86.177, 170.338]\n", - "\tm=[1, 3.0576, 5.306]\n", - "\tsigma=[3.7039, 3.7983, 3.8959]\n", - "\tepsilon_k=[150.03, 236.77, 249.21]\n", - ")" + "" ] }, - "execution_count": 6, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -197,35 +182,24 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|\n", - "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|\n", - "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", + "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", + "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 74.123, 18.015, 58.08]\n", - "\tm=[1, 2.7515, 1.0656, 2.7447]\n", - "\tsigma=[3.7039, 3.6139, 3.0007, 3.2742]\n", - "\tepsilon_k=[150.03, 259.59, 366.51, 232.99]\n", - "\tmu=[0, 0, 0, 2.88]\n", - "\tassociating=[1, 2]\n", - "\tkappa_ab=[0.006692, 0.034868]\n", - "\tepsilon_k_ab=[2544.6, 2500.7]\n", - "\tna=[1, 1]\n", - "\tnb=[1, 1]\n", - ")" + "" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -243,7 +217,7 @@ " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -263,35 +237,22 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -307,14 +268,14 @@ " (['CCCCO',], file_assoc)\n", " ],\n", " binary_path=file_binary,\n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -324,7 +285,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 9, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -352,7 +313,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -361,7 +322,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -370,7 +331,7 @@ "Identifier(cas=106-97-8, name=butane, iupac_name=butane, smiles=CCCC, inchi=InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3, formula=C4H10)" ] }, - "execution_count": 18, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -410,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -419,7 +380,7 @@ "PcSaftRecord(m=2.3316, sigma=3.7086, epsilon_k=222.88)" ] }, - "execution_count": 19, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -439,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -452,7 +413,7 @@ ")" ] }, - "execution_count": 20, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -473,26 +434,21 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123]\n", - "\tm=[2.3316]\n", - "\tsigma=[3.7086]\n", - "\tepsilon_k=[222.88]\n", - ")" + "" ] }, - "execution_count": 21, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -513,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -539,35 +495,22 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 23, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -579,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -589,7 +532,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 24, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -609,35 +552,22 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.123|2.3316|3.7086|222.88|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.123, 74.123]\n", - "\tm=[2.3316, 2.7515]\n", - "\tsigma=[3.7086, 3.6139]\n", - "\tepsilon_k=[222.88, 259.59]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006692]\n", - "\tepsilon_k_ab=[2544.6]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - "\tk_ij=\n", - "[[0, 0.015],\n", - " [0.015, 0]]\n", - ")" + "" ] }, - "execution_count": 25, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -657,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -667,7 +597,7 @@ " [0.015, 0. ]])" ] }, - "execution_count": 26, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -700,37 +630,27 @@ "- `pure_path`: a file containing the substance identifiers *and* the segments that form the molecule\n", "- `segments_path`: a file that contains the segments (identifier and model parameters)\n", "\n", - "As before, we can specify our substance identifier using `search_option` and we can provide binary interaction parameters (segment-segment `k_ij`) via the `binary_path` argument." + "As before, we can specify our substance identifier using `identifier_option` and we can provide binary interaction parameters (segment-segment `k_ij`) via the `binary_path` argument." ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|1|1|\n", - "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", + "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.122159999999994, 74.12158]\n", - "\tm=[2.1360799999999998, 2.3821600000000003]\n", - "\tsigma=[3.7945688260994523, 3.7568140627964164]\n", - "\tepsilon_k=[233.79002902513017, 278.79916705846796]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006825]\n", - "\tepsilon_k_ab=[2517]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - ")" + "" ] }, - "execution_count": 27, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -743,7 +663,7 @@ " ['CCCC', 'CCCCO'], \n", " pure_path, \n", " segments_path, \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -764,7 +684,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -804,7 +724,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -833,32 +753,22 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|1|1|\n", - "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|butane|58.122159999999994|2.1360799999999998|3.7945688260994523|233.79002902513017|0|0|0|0|0|0|0|\n", + "|1-butanol|74.12158|2.3821600000000003|3.7568140627964164|278.79916705846796|0|0|0.006825|2517|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[58.122159999999994, 74.12158]\n", - "\tm=[2.1360799999999998, 2.3821600000000003]\n", - "\tsigma=[3.7945688260994523, 3.7568140627964164]\n", - "\tepsilon_k=[233.79002902513017, 278.79916705846796]\n", - "\tassociating=[1]\n", - "\tkappa_ab=[0.006825]\n", - "\tepsilon_k_ab=[2517]\n", - "\tna=[1]\n", - "\tnb=[1]\n", - ")" + "" ] }, - "execution_count": 30, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -885,35 +795,24 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ - "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|\n", - "|-|-|-|-|-|-|-|-|-|-|-|\n", - "|methane|16.043|1|3.7039|150.03|0|0|0|0|1|1|\n", - "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|\n", - "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|\n", - "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|1|1|" + "|component|molarweight|$m$|$\\sigma$|$\\varepsilon$|$\\mu$|$Q$|$\\kappa_{AB}$|$\\varepsilon_{AB}$|$N_A$|$N_B$|$N_C$|\n", + "|-|-|-|-|-|-|-|-|-|-|-|-|\n", + "|methane|16.043|1|3.7039|150.03|0|0|0|0|0|0|0|\n", + "|1-butanol|74.123|2.7515|3.6139|259.59|0|0|0.006692|2544.6|1|1|0|\n", + "|water|18.015|1.0656|3.0007|366.51|0|0|0.034868|2500.7|1|1|0|\n", + "|acetone|58.08|2.7447|3.2742|232.99|2.88|0|0|0|0|0|0|" ], "text/plain": [ - "PcSaftParameters(\n", - "\tmolarweight=[16.043, 74.123, 18.015, 58.08]\n", - "\tm=[1, 2.7515, 1.0656, 2.7447]\n", - "\tsigma=[3.7039, 3.6139, 3.0007, 3.2742]\n", - "\tepsilon_k=[150.03, 259.59, 366.51, 232.99]\n", - "\tmu=[0, 0, 0, 2.88]\n", - "\tassociating=[1, 2]\n", - "\tkappa_ab=[0.006692, 0.034868]\n", - "\tepsilon_k_ab=[2544.6, 2500.7]\n", - "\tna=[1, 1]\n", - "\tnb=[1, 1]\n", - ")" + "" ] }, - "execution_count": 31, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -929,7 +828,7 @@ " (['CCCCO', 'O'], file_assoc), \n", " (['CC(C)=O'], file_dipolar)\n", " ], \n", - " search_option=IdentifierOption.Smiles\n", + " identifier_option=IdentifierOption.Smiles\n", ")\n", "parameters" ] @@ -943,23 +842,9 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 25, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0., 0., 0., 0.],\n", - " [0., 0., 0., 0.],\n", - " [0., 0., 0., 0.],\n", - " [0., 0., 0., 0.]])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "parameters.k_ij" ] @@ -979,7 +864,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -988,7 +873,7 @@ "[PureRecord(\n", " \tidentifier=Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4),\n", " \tmolarweight=16.043,\n", - " \tmodel_record=PcSaftRecord(m=1, sigma=3.7039, epsilon_k=150.03),\n", + " \tmodel_record=PcSaftRecord(m=1, sigma=3.7039, epsilon_k=150.03, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " ),\n", " PureRecord(\n", " \tidentifier=Identifier(cas=71-36-3, name=1-butanol, iupac_name=butan-1-ol, smiles=CCCCO, inchi=InChI=1/C4H10O/c1-2-3-4-5/h5H,2-4H2,1H3, formula=C4H10O),\n", @@ -1003,11 +888,11 @@ " PureRecord(\n", " \tidentifier=Identifier(cas=67-64-1, name=acetone, iupac_name=propan-2-one, smiles=CC(C)=O, inchi=InChI=1/C3H6O/c1-3(2)4/h1-2H3, formula=C3H6O),\n", " \tmolarweight=58.08,\n", - " \tmodel_record=PcSaftRecord(m=2.7447, sigma=3.2742, epsilon_k=232.99, mu=2.88),\n", + " \tmodel_record=PcSaftRecord(m=2.7447, sigma=3.2742, epsilon_k=232.99, mu=2.88, association_record=AssociationRecord(kappa_ab=0, epsilon_k_ab=0)),\n", " )]" ] }, - "execution_count": 33, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -1018,7 +903,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1039,7 +924,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -1048,7 +933,7 @@ "Identifier(cas=74-82-8, name=methane, iupac_name=methane, smiles=C, inchi=InChI=1/CH4/h1H4, formula=CH4)" ] }, - "execution_count": 35, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -1060,7 +945,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -1069,7 +954,7 @@ "16.043" ] }, - "execution_count": 36, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -1088,7 +973,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -1097,7 +982,7 @@ "'{\"identifier\":{\"cas\":\"74-82-8\",\"name\":\"methane\",\"iupac_name\":\"methane\",\"smiles\":\"C\",\"inchi\":\"InChI=1/CH4/h1H4\",\"formula\":\"CH4\"},\"molarweight\":16.043,\"model_record\":{\"m\":1.0,\"sigma\":3.7039,\"epsilon_k\":150.03}}'" ] }, - "execution_count": 37, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -1133,11 +1018,20 @@ "\n", "Hopefully you found this example helpful. If you have comments, critique or feedback, please let us know and consider [opening an issue on github](https://github.com/feos-org/feos/issues)." ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "from feos.ideal_gas import JobackParameters" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1151,7 +1045,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.6" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/examples/saftvrqmie/radial_distribution_function.ipynb b/examples/saftvrqmie/radial_distribution_function.ipynb index 07195cd37..3ec1068cd 100644 --- a/examples/saftvrqmie/radial_distribution_function.ipynb +++ b/examples/saftvrqmie/radial_distribution_function.ipynb @@ -5,7 +5,16 @@ "execution_count": 1, "id": "66146e02-48f2-4b2d-b2e3-50bda5cf345f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/bauer/opt/anaconda3/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.26.0\n", + " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n" + ] + } + ], "source": [ "from feos import *\n", "from feos.si import *\n", @@ -73,7 +82,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "id": "0f0a312b-5b2b-40ad-a2b4-f5edd9d30b70", "metadata": {}, "outputs": [ @@ -97,7 +106,7 @@ ")" ] }, - "execution_count": 4, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -107,7 +116,7 @@ " [\"deuterium\", \"neon\"], \n", " \"../../parameters/saftvrqmie/hammer2023.json\",\n", " \"../../parameters/saftvrqmie/aasen2020_binary.json\",\n", - " search_option=IdentifierOption.Name\n", + " identifier_option=IdentifierOption.Name\n", ")\n", "parameters" ] @@ -605,7 +614,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/feos-core/CHANGELOG.md b/feos-core/CHANGELOG.md index 4cf76977c..7f3479362 100644 --- a/feos-core/CHANGELOG.md +++ b/feos-core/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased + +## [0.5.0] - 2023-10-20 ### Added - Added new functions `isenthalpic_compressibility`, `thermal_expansivity` and `grueneisen_parameter` to `State`. [#154](https://github.com/feos-org/feos/pull/154) - Readded `PhaseEquilibrium::new_npt` to the public interface in Rust and Python. [#164](https://github.com/feos-org/feos/pull/164) @@ -35,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed `StateVec` Python getters for entropy and enthalpy to functions that accept optional `Contributions`. [#177](https://github.com/feos-org/feos/pull/177) - `PhaseDiagram.to_dict` in Python now accepts optional `Contributions` and includes mass specific properties. [#177](https://github.com/feos-org/feos/pull/177) - Replaced the run-time unit checks from the `quantity` crate with compile-time unit checks with custom implementations in the new `feos_core.si` module. [#181](https://github.com/feos-org/feos/pull/181) +- Renamed the keyword argument `search_option` to `identifier_option` in parameter constructors. [#196](https://github.com/feos-org/feos/pull/196) ### Removed - Removed `EquationOfState` trait. [#158](https://github.com/feos-org/feos/pull/158) @@ -44,9 +47,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - The vapor and liquid states in a bubble or dew point iteration are assigned correctly according to the inputs, rather than based on the mole density which can be incorrect for mixtures with large differences in molar weights. [#166](https://github.com/feos-org/feos/pull/166) +- `Parameter::from_multiple_json` returns the correct parameters if a component occurs in multiple input files. [#196](https://github.com/feos-org/feos/pull/196) ### Packaging -- Updated `num-dual` dependency to 0.7. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `quantity` dependency to 0.7. +- Updated `num-dual` dependency to 0.8. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `numpy` and `PyO3` dependencies to 0.20. ## [0.4.2] - 2023-04-03 ### Fixed diff --git a/feos-core/Cargo.toml b/feos-core/Cargo.toml index 28a75ede4..d843724a0 100644 --- a/feos-core/Cargo.toml +++ b/feos-core/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "feos-core" -version = "0.4.2" +version = "0.5.0" authors = ["Gernot Bauer ", "Philipp Rehner >, binary_records: &[BinaryRecord], - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Option> { if binary_records.is_empty() { return None; @@ -94,8 +94,8 @@ where binary_records .iter() .filter_map(|br| { - let id1 = br.id1.as_string(search_option); - let id2 = br.id2.as_string(search_option); + let id1 = br.id1.as_string(identifier_option); + let id2 = br.id2.as_string(identifier_option); id1.and_then(|id1| id2.map(|id2| ((id1, id2), br.model_record.clone()))) }) .collect() @@ -104,16 +104,16 @@ where Some(Array2::from_shape_fn([n, n], |(i, j)| { let id1 = pure_records[i] .identifier - .as_string(search_option) + .as_string(identifier_option) .expect(&format!( - "No identifier for given search_option for pure record {}.", + "No identifier for given identifier_option for pure record {}.", i )); let id2 = pure_records[j] .identifier - .as_string(search_option) + .as_string(identifier_option) .expect(&format!( - "No identifier for given search_option for pure record {}.", + "No identifier for given identifier_option for pure record {}.", j )); binary_map @@ -129,69 +129,53 @@ where substances: Vec<&str>, file_pure: P, file_binary: Option

, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Result where P: AsRef, { - Self::from_multiple_json(&[(substances, file_pure)], file_binary, search_option) + Self::from_multiple_json(&[(substances, file_pure)], file_binary, identifier_option) } /// Creates parameters from substance information stored in multiple json files. fn from_multiple_json

( input: &[(Vec<&str>, P)], file_binary: Option

, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Result where P: AsRef, { - let mut queried: IndexSet = IndexSet::new(); - let mut record_map: HashMap> = HashMap::new(); - - for (substances, file) in input { - substances.iter().try_for_each(|identifier| { - match queried.insert(identifier.to_string()) { - true => Ok(()), - false => Err(ParameterError::IncompatibleParameters(format!( - "tried to add substance '{}' to system but it is already present.", - identifier - ))), - } - })?; - let f = File::open(file)?; - let reader = BufReader::new(f); - - let pure_records: Vec> = serde_json::from_reader(reader)?; - - pure_records - .into_iter() - .filter_map(|record| { - record - .identifier - .as_string(search_option) - .map(|i| (i, record)) - }) - .for_each(|(i, r)| { - let _ = record_map.insert(i, r); - }); - } + // total number of substances queried + let nsubstances = input + .iter() + .fold(0, |acc, (substances, _)| acc + substances.len()); - // Compare queried components and available components - let available: IndexSet = record_map - .keys() - .map(|identifier| identifier.to_string()) - .collect(); - if !queried.is_subset(&available) { - let missing: Vec = queried.difference(&available).cloned().collect(); - let msg = format!("{:?}", missing); - return Err(ParameterError::ComponentsNotFound(msg)); - }; - let p = queried + // queried substances with removed duplicates + let queried: IndexSet = input .iter() - .filter_map(|identifier| record_map.remove(&identifier.clone())) + .flat_map(|(substances, _)| substances) + .map(|substance| substance.to_string()) .collect(); + // check if there are duplicates + if queried.len() != nsubstances { + return Err(ParameterError::IncompatibleParameters( + "A substance was defined more than once.".to_string(), + )); + } + + let mut records: Vec> = Vec::with_capacity(nsubstances); + + // collect parameters from files into single map + for (substances, file) in input { + records.extend(PureRecord::::from_json( + substances, + file, + identifier_option, + )?); + } + let binary_records = if let Some(path) = file_binary { let file = File::open(path)?; let reader = BufReader::new(file); @@ -199,8 +183,9 @@ where } else { Vec::new() }; - let record_matrix = Self::binary_matrix_from_records(&p, &binary_records, search_option); - Self::from_records(p, record_matrix) + let record_matrix = + Self::binary_matrix_from_records(&records, &binary_records, identifier_option); + Self::from_records(records, record_matrix) } /// Creates parameters from the molecular structure and segment information. @@ -277,7 +262,7 @@ where file_pure: P, file_segments: P, file_binary: Option

, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Result where P: AsRef, @@ -297,7 +282,7 @@ where .filter_map(|record| { record .identifier - .as_string(search_option) + .as_string(identifier_option) .map(|i| (i, record)) }) .collect(); @@ -391,7 +376,7 @@ pub trait ParameterHetero: Sized { file_pure: P, file_segments: P, file_binary: Option

, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Result where P: AsRef, @@ -409,7 +394,7 @@ pub trait ParameterHetero: Sized { .filter_map(|record| { record .identifier - .as_string(search_option) + .as_string(identifier_option) .map(|i| (i, record)) }) .collect(); @@ -481,230 +466,3 @@ pub enum ParameterError { #[error("Incompatible parameters: {0}")] IncompatibleParameters(String), } - -#[cfg(test)] -mod test { - use super::*; - use serde::{Deserialize, Serialize}; - use std::convert::TryFrom; - - #[derive(Debug, Clone, Serialize, Deserialize, Default)] - struct MyPureModel { - a: f64, - } - - #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] - struct MyBinaryModel { - b: f64, - } - - impl TryFrom for MyBinaryModel { - type Error = &'static str; - fn try_from(f: f64) -> Result { - Ok(Self { b: f }) - } - } - - struct MyParameter { - pure_records: Vec>, - binary_records: Option>, - } - - impl Parameter for MyParameter { - type Pure = MyPureModel; - type Binary = MyBinaryModel; - fn from_records( - pure_records: Vec>, - binary_records: Option>, - ) -> Result { - Ok(Self { - pure_records, - binary_records, - }) - } - - fn records(&self) -> (&[PureRecord], Option<&Array2>) { - (&self.pure_records, self.binary_records.as_ref()) - } - } - - #[test] - fn from_records() -> Result<(), ParameterError> { - let pr_json = r#" - [ - { - "identifier": { - "cas": "123-4-5" - }, - "molarweight": 16.0426, - "model_record": { - "a": 0.1 - } - }, - { - "identifier": { - "cas": "678-9-1" - }, - "molarweight": 32.08412, - "model_record": { - "a": 0.2 - } - } - ] - "#; - let br_json = r#" - [ - { - "id1": { - "cas": "123-4-5" - }, - "id2": { - "cas": "678-9-1" - }, - "model_record": { - "b": 12.0 - } - } - ] - "#; - let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); - let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); - let binary_matrix = MyParameter::binary_matrix_from_records( - &pure_records, - &binary_records, - IdentifierOption::Cas, - ); - let p = MyParameter::from_records(pure_records, binary_matrix)?; - - assert_eq!(p.pure_records[0].identifier.cas, Some("123-4-5".into())); - assert_eq!(p.pure_records[1].identifier.cas, Some("678-9-1".into())); - assert_eq!(p.binary_records.unwrap()[[0, 1]].b, 12.0); - Ok(()) - } - - #[test] - fn from_records_missing_binary() -> Result<(), ParameterError> { - let pr_json = r#" - [ - { - "identifier": { - "cas": "123-4-5" - }, - "molarweight": 16.0426, - "model_record": { - "a": 0.1 - } - }, - { - "identifier": { - "cas": "678-9-1" - }, - "molarweight": 32.08412, - "model_record": { - "a": 0.2 - } - } - ] - "#; - let br_json = r#" - [ - { - "id1": { - "cas": "123-4-5" - }, - "id2": { - "cas": "000-00-0" - }, - "model_record": { - "b": 12.0 - } - } - ] - "#; - let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); - let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); - let binary_matrix = MyParameter::binary_matrix_from_records( - &pure_records, - &binary_records, - IdentifierOption::Cas, - ); - let p = MyParameter::from_records(pure_records, binary_matrix)?; - - assert_eq!(p.pure_records[0].identifier.cas, Some("123-4-5".into())); - assert_eq!(p.pure_records[1].identifier.cas, Some("678-9-1".into())); - let br = p.binary_records.as_ref().unwrap(); - assert_eq!(br[[0, 1]], MyBinaryModel::default()); - assert_eq!(br[[0, 1]].b, 0.0); - Ok(()) - } - - #[test] - fn from_records_correct_binary_order() -> Result<(), ParameterError> { - let pr_json = r#" - [ - { - "identifier": { - "cas": "000-0-0" - }, - "molarweight": 32.08412, - "model_record": { - "a": 0.2 - } - }, - { - "identifier": { - "cas": "123-4-5" - }, - "molarweight": 16.0426, - "model_record": { - "a": 0.1 - } - }, - { - "identifier": { - "cas": "678-9-1" - }, - "molarweight": 32.08412, - "model_record": { - "a": 0.2 - } - } - ] - "#; - let br_json = r#" - [ - { - "id1": { - "cas": "123-4-5" - }, - "id2": { - "cas": "678-9-1" - }, - "model_record": { - "b": 12.0 - } - } - ] - "#; - let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); - let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); - let binary_matrix = MyParameter::binary_matrix_from_records( - &pure_records, - &binary_records, - IdentifierOption::Cas, - ); - let p = MyParameter::from_records(pure_records, binary_matrix)?; - - assert_eq!(p.pure_records[0].identifier.cas, Some("000-0-0".into())); - assert_eq!(p.pure_records[1].identifier.cas, Some("123-4-5".into())); - assert_eq!(p.pure_records[2].identifier.cas, Some("678-9-1".into())); - let br = p.binary_records.as_ref().unwrap(); - assert_eq!(br[[0, 1]], MyBinaryModel::default()); - assert_eq!(br[[1, 0]], MyBinaryModel::default()); - assert_eq!(br[[0, 2]], MyBinaryModel::default()); - assert_eq!(br[[2, 0]], MyBinaryModel::default()); - assert_eq!(br[[2, 1]].b, 12.0); - assert_eq!(br[[1, 2]].b, 12.0); - Ok(()) - } -} diff --git a/feos-core/src/parameter/model_record.rs b/feos-core/src/parameter/model_record.rs index ee86f61dc..ce048c01a 100644 --- a/feos-core/src/parameter/model_record.rs +++ b/feos-core/src/parameter/model_record.rs @@ -1,9 +1,10 @@ use super::identifier::Identifier; use super::segment::SegmentRecord; -use super::ParameterError; +use super::{IdentifierOption, ParameterError}; use conv::ValueInto; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::BufReader; use std::path::Path; @@ -46,6 +47,54 @@ impl PureRecord { Ok(Self::new(identifier, molarweight, model_record)) } + + /// Create pure substance parameters from a json file. + pub fn from_json

( + substances: &[&str], + file: P, + identifier_option: IdentifierOption, + ) -> Result, ParameterError> + where + P: AsRef, + M: Clone + DeserializeOwned, + { + // create list of substances + let mut queried: HashSet = substances.iter().map(|s| s.to_string()).collect(); + // raise error on duplicate detection + if queried.len() != substances.len() { + return Err(ParameterError::IncompatibleParameters( + "A substance was defined more than once.".to_string(), + )); + } + + let f = File::open(file)?; + let reader = BufReader::new(f); + // use stream in the future + let file_records: Vec = serde_json::from_reader(reader)?; + let mut records: HashMap = HashMap::with_capacity(substances.len()); + + // build map, draining list of queried substances in the process + for record in file_records { + if let Some(id) = record.identifier.as_string(identifier_option) { + queried.take(&id).map(|id| records.insert(id, record)); + } + // all parameters parsed + if queried.is_empty() { + break; + } + } + + // report missing parameters + if !queried.is_empty() { + return Err(ParameterError::ComponentsNotFound(format!("{:?}", queried))); + }; + + // collect into vec in correct order + Ok(substances + .iter() + .map(|s| records.get(&s.to_string()).unwrap().clone()) + .collect()) + } } impl std::fmt::Display for PureRecord diff --git a/feos-core/src/phase_equilibria/bubble_dew.rs b/feos-core/src/phase_equilibria/bubble_dew.rs index 54b2bcb3e..610afcd1b 100644 --- a/feos-core/src/phase_equilibria/bubble_dew.rs +++ b/feos-core/src/phase_equilibria/bubble_dew.rs @@ -2,6 +2,7 @@ use super::PhaseEquilibrium; use crate::equation_of_state::Residual; use crate::errors::{EosError, EosResult}; use crate::si::{Density, Dimensionless, Moles, Pressure, Quantity, SIUnit, Temperature, RGAS}; +use crate::state::TPSpec; use crate::state::{ Contributions, DensityInitialization::{InitialDensity, Liquid, Vapor}, @@ -23,8 +24,9 @@ const MAX_TSTEP: f64 = 20.0; const MAX_LNPSTEP: f64 = 0.1; const NEWTON_TOL: f64 = 1e-3; -pub trait TemperatureOrPressure: Copy { - type Other: fmt::Display + Copy; +/// Trait that enables functions to be generic over their input unit. +pub trait TemperatureOrPressure: Copy + Into { + type Other: fmt::Display + TemperatureOrPressure; const IDENTIFIER: &'static str; diff --git a/feos-core/src/phase_equilibria/phase_diagram_binary.rs b/feos-core/src/phase_equilibria/phase_diagram_binary.rs index 708a7afaa..a798ca70f 100644 --- a/feos-core/src/phase_equilibria/phase_diagram_binary.rs +++ b/feos-core/src/phase_equilibria/phase_diagram_binary.rs @@ -24,10 +24,7 @@ impl PhaseDiagram { npoints: Option, x_lle: Option<(f64, f64)>, bubble_dew_options: (SolverOptions, SolverOptions), - ) -> EosResult - where - TPSpec: From, - { + ) -> EosResult { let npoints = npoints.unwrap_or(DEFAULT_POINTS); // calculate boiling temperature/vapor pressure of pure components @@ -254,10 +251,7 @@ impl PhaseDiagram { npoints_vle: Option, npoints_lle: Option, bubble_dew_options: (SolverOptions, SolverOptions), - ) -> EosResult> - where - TPSpec: From, - { + ) -> EosResult> { let npoints_vle = npoints_vle.unwrap_or(DEFAULT_POINTS); // calculate pure components @@ -337,12 +331,9 @@ impl PhaseEquilibrium { tp_init: Option, options: SolverOptions, bubble_dew_options: (SolverOptions, SolverOptions), - ) -> EosResult - where - TPSpec: From, - { + ) -> EosResult { let tp_init = tp_init.map(|tp_init| temperature_or_pressure.temperature_pressure(tp_init)); - match TPSpec::from(temperature_or_pressure) { + match temperature_or_pressure.into() { TPSpec::Temperature(t) => PhaseEquilibrium::heteroazeotrope_t( eos, t, diff --git a/feos-core/src/phase_equilibria/vle_pure.rs b/feos-core/src/phase_equilibria/vle_pure.rs index 492b3566e..c2df4cc5f 100644 --- a/feos-core/src/phase_equilibria/vle_pure.rs +++ b/feos-core/src/phase_equilibria/vle_pure.rs @@ -3,7 +3,7 @@ use crate::equation_of_state::Residual; use crate::errors::{EosError, EosResult}; use crate::si::{Moles, Pressure, Temperature, RGAS}; use crate::state::{Contributions, DensityInitialization, State, TPSpec}; -use crate::{SolverOptions, Verbosity}; +use crate::{SolverOptions, TemperatureOrPressure, Verbosity}; use ndarray::{arr1, Array1}; use std::sync::Arc; @@ -14,16 +14,13 @@ const TOL_PURE: f64 = 1e-12; /// # Pure component phase equilibria impl PhaseEquilibrium { /// Calculate a phase equilibrium for a pure component. - pub fn pure( + pub fn pure( eos: &Arc, temperature_or_pressure: TP, initial_state: Option<&PhaseEquilibrium>, options: SolverOptions, - ) -> EosResult - where - TPSpec: From, - { - match TPSpec::from(temperature_or_pressure) { + ) -> EosResult { + match temperature_or_pressure.into() { TPSpec::Temperature(t) => Self::pure_t(eos, t, initial_state, options), TPSpec::Pressure(p) => Self::pure_p(eos, p, initial_state, options), } @@ -378,13 +375,10 @@ impl PhaseEquilibrium { /// Calculate the pure component phase equilibria of all /// components in the system. - pub fn vle_pure_comps( + pub fn vle_pure_comps( eos: &Arc, temperature_or_pressure: TP, - ) -> Vec>> - where - TPSpec: From, - { + ) -> Vec>> { (0..eos.components()) .map(|i| { let pure_eos = Arc::new(eos.subset(&[i])); diff --git a/feos-core/src/python/cubic.rs b/feos-core/src/python/cubic.rs index a74802750..132d9d630 100644 --- a/feos-core/src/python/cubic.rs +++ b/feos-core/src/python/cubic.rs @@ -33,24 +33,6 @@ impl_pure_record!(PengRobinsonRecord, PyPengRobinsonRecord); impl_binary_record!(); -/// Create a set of Peng-Robinson parameters from records. -/// -/// Parameters -/// ---------- -/// pure_records : List[PureRecord] -/// pure substance records. -/// binary_records : List[BinaryRecord], optional -/// binary parameter records -/// substances : List[str], optional -/// The substances to use. Filters substances from `pure_records` according to -/// `search_option`. -/// When not provided, all entries of `pure_records` are used. -/// search_option : {'Name', 'Cas', 'Inchi', 'IupacName', 'Formula', 'Smiles'}, optional, defaults to 'Name'. -/// Identifier that is used to search substance. -/// -/// Returns -/// ------- -/// PengRobinsonParameters #[pyclass(name = "PengRobinsonParameters")] #[derive(Clone)] pub struct PyPengRobinsonParameters(pub Arc); diff --git a/feos-core/src/python/joback.rs b/feos-core/src/python/joback.rs index de1f05031..412010ec5 100644 --- a/feos-core/src/python/joback.rs +++ b/feos-core/src/python/joback.rs @@ -62,24 +62,7 @@ pub struct PyJobackBinaryRecord(pub JobackBinaryRecord); impl_binary_record!(JobackBinaryRecord, PyJobackBinaryRecord); -/// Create a set of Joback parameters from records. -/// -/// Parameters -/// ---------- -/// pure_records : List[PureRecord] -/// pure substance records. -/// substances : List[str], optional -/// The substances to use. Filters substances from `pure_records` according to -/// `search_option`. -/// When not provided, all entries of `pure_records` are used. -/// search_option : {'Name', 'Cas', 'Inchi', 'IupacName', 'Formula', 'Smiles'}, optional, defaults to 'Name'. -/// Identifier that is used to search substance. -/// -/// Returns -/// ------- -/// JobackParameters #[pyclass(name = "JobackParameters")] -#[pyo3(text_signature = "(pure_records, substances=None, search_option='Name')")] #[derive(Clone)] pub struct PyJobackParameters(pub Arc); diff --git a/feos-core/src/python/parameter/fragmentation.rs b/feos-core/src/python/parameter/fragmentation.rs index 97fd597bd..50e5e8306 100644 --- a/feos-core/src/python/parameter/fragmentation.rs +++ b/feos-core/src/python/parameter/fragmentation.rs @@ -43,12 +43,12 @@ impl std::fmt::Display for SmartsRecord { #[pyclass(name = "SmartsRecord")] #[derive(Clone)] -#[pyo3(text_signature = "(group, smarts, max=None)")] pub struct PySmartsRecord(pub SmartsRecord); #[pymethods] impl PySmartsRecord { #[new] + #[pyo3(text_signature = "(group, smarts, max=None)")] fn new(group: String, smarts: String, max: Option) -> Self { Self(SmartsRecord::new(group, smarts, max)) } diff --git a/feos-core/src/python/parameter/mod.rs b/feos-core/src/python/parameter/mod.rs index 6170de358..c6f04b9ec 100644 --- a/feos-core/src/python/parameter/mod.rs +++ b/feos-core/src/python/parameter/mod.rs @@ -31,14 +31,14 @@ impl From for PyErr { /// Identifier #[pyclass(name = "Identifier")] #[derive(Clone)] -#[pyo3( - text_signature = "(cas=None, name=None, iupac_name=None, smiles=None, inchi=None, formula=None)" -)] pub struct PyIdentifier(pub Identifier); #[pymethods] impl PyIdentifier { #[new] + #[pyo3( + text_signature = "(cas=None, name=None, iupac_name=None, smiles=None, inchi=None, formula=None)" + )] fn new( cas: Option<&str>, name: Option<&str>, @@ -138,12 +138,12 @@ impl_json_handling!(PyIdentifier); /// ChemicalRecord #[pyclass(name = "ChemicalRecord")] #[derive(Clone)] -#[pyo3(text_signature = "(identifier, segments, bonds=None)")] pub struct PyChemicalRecord(pub ChemicalRecord); #[pymethods] impl PyChemicalRecord { #[new] + #[pyo3(text_signature = "(identifier, segments, bonds=None)")] fn new( identifier: PyIdentifier, segments: Vec, @@ -392,13 +392,13 @@ macro_rules! impl_pure_record { /// ------- /// PureRecord #[pyclass(name = "PureRecord")] - #[pyo3(text_signature = "(identifier, molarweight, model_record)")] #[derive(Clone)] pub struct PyPureRecord(pub PureRecord<$model_record>); #[pymethods] impl PyPureRecord { #[new] + #[pyo3(text_signature = "(identifier, molarweight, model_record)")] fn new( identifier: PyIdentifier, molarweight: f64, @@ -468,13 +468,13 @@ macro_rules! impl_segment_record { /// ------- /// SegmentRecord #[pyclass(name = "SegmentRecord")] - #[pyo3(text_signature = "(identifier, molarweight)")] #[derive(Clone)] pub struct PySegmentRecord(SegmentRecord<$model_record>); #[pymethods] impl PySegmentRecord { #[new] + #[pyo3(text_signature = "(identifier, molarweight, model_record)")] fn new( identifier: String, molarweight: f64, @@ -558,17 +558,17 @@ macro_rules! impl_parameter { /// binary_records : numpy.ndarray[float] or List[BinaryRecord], optional /// A matrix of binary interaction parameters or a list /// containing records for binary interactions. - /// search_option : IdentifierOption, optional, defaults to IdentifierOption.Name + /// identifier_option : IdentifierOption, optional, defaults to IdentifierOption.Name /// Identifier that is used to search binary records. #[staticmethod] #[pyo3( - signature = (pure_records, binary_records=None, search_option=IdentifierOption::Name), - text_signature = "(pure_records, binary_records=None, search_option=None)" + signature = (pure_records, binary_records=None, identifier_option=IdentifierOption::Name), + text_signature = "(pure_records, binary_records=None, identifier_option=None)" )] fn from_records( pure_records: Vec, binary_records: Option<&PyAny>, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> PyResult { let prs = pure_records.into_iter().map(|pr| pr.0).collect(); let binary_records = binary_records @@ -580,7 +580,7 @@ macro_rules! impl_parameter { Ok(<$parameter>::binary_matrix_from_records( &prs, &brs, - search_option, + identifier_option, )) } else { Err(PyErr::new::(format!( @@ -659,24 +659,24 @@ macro_rules! impl_parameter { /// Path to file containing pure substance parameters. /// binary_path : str, optional /// Path to file containing binary substance parameters. - /// search_option : IdentifierOption, optional, defaults to IdentifierOption.Name + /// identifier_option : IdentifierOption, optional, defaults to IdentifierOption.Name /// Identifier that is used to search substance. #[staticmethod] #[pyo3( - signature = (substances, pure_path, binary_path=None, search_option=IdentifierOption::Name), - text_signature = "(substances, pure_path, binary_path=None, search_option)" + signature = (substances, pure_path, binary_path=None, identifier_option=IdentifierOption::Name), + text_signature = "(substances, pure_path, binary_path=None, identifier_option)" )] fn from_json( substances: Vec<&str>, pure_path: String, binary_path: Option, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> Result { Ok(Self(Arc::new(<$parameter>::from_json( substances, pure_path, binary_path, - search_option, + identifier_option, )?))) } @@ -689,22 +689,22 @@ macro_rules! impl_parameter { /// E.g. [(["methane", "propane"], "parameters/alkanes.json"), (["methanol"], "parameters/alcohols.json")] /// binary_path : str, optional /// Path to file containing binary substance parameters. - /// search_option : IdentifierOption, optional, defaults to IdentifierOption.Name + /// identifier_option : IdentifierOption, optional, defaults to IdentifierOption.Name /// Identifier that is used to search substance. #[staticmethod] #[pyo3( - signature = (input, binary_path=None, search_option=IdentifierOption::Name), - text_signature = "(input, binary_path=None, search_option)" + signature = (input, binary_path=None, identifier_option=IdentifierOption::Name), + text_signature = "(input, binary_path=None, identifier_option)" )] fn from_multiple_json( input: Vec<(Vec<&str>, &str)>, binary_path: Option<&str>, - search_option: Option, + identifier_option: Option, ) -> Result { Ok(Self(Arc::new(<$parameter>::from_multiple_json( &input, binary_path, - search_option.unwrap_or(IdentifierOption::Name), + identifier_option.unwrap_or(IdentifierOption::Name), )?))) } @@ -771,26 +771,26 @@ macro_rules! impl_parameter_from_segments { /// Path to file containing segment parameters. /// binary_path : str, optional /// Path to file containing binary segment-segment parameters. - /// search_option : IdentifierOption, optional, defaults to IdentifierOption.Name + /// identifier_option : IdentifierOption, optional, defaults to IdentifierOption.Name /// Identifier that is used to search substance. #[staticmethod] #[pyo3( - signature = (substances, pure_path, segments_path, binary_path=None, search_option=IdentifierOption::Name), - text_signature = "(substances, pure_path, segments_path, binary_path=None, search_option)" + signature = (substances, pure_path, segments_path, binary_path=None, identifier_option=IdentifierOption::Name), + text_signature = "(substances, pure_path, segments_path, binary_path=None, identifier_option)" )] fn from_json_segments( substances: Vec<&str>, pure_path: String, segments_path: String, binary_path: Option, - search_option: IdentifierOption, + identifier_option: IdentifierOption, ) -> PyResult { Ok(Self(Arc::new(<$parameter>::from_json_segments( &substances, pure_path, segments_path, binary_path, - search_option, + identifier_option, )?))) } diff --git a/feos-core/src/python/phase_equilibria.rs b/feos-core/src/python/phase_equilibria.rs index 0a51e6477..f4e98f959 100644 --- a/feos-core/src/python/phase_equilibria.rs +++ b/feos-core/src/python/phase_equilibria.rs @@ -45,12 +45,25 @@ macro_rules! impl_phase_equilibrium { tol: Option, verbosity: Option, ) -> PyResult { - Ok(Self(PhaseEquilibrium::pure( - &eos.0, - TPSpec::try_from(temperature_or_pressure)?, - initial_state.and_then(|s| Some(&s.0)), - (max_iter, tol, verbosity).into(), - )?)) + if let Ok(t) = Temperature::::try_from(temperature_or_pressure) { + Ok(Self(PhaseEquilibrium::pure( + &eos.0, + t, + initial_state.and_then(|s| Some(&s.0)), + (max_iter, tol, verbosity).into(), + )?)) + } else if let Ok(p) = Pressure::::try_from(temperature_or_pressure) { + Ok(Self(PhaseEquilibrium::pure( + &eos.0, + p, + initial_state.and_then(|s| Some(&s.0)), + (max_iter, tol, verbosity).into(), + )?)) + } else { + Ok(Err(EosError::WrongUnits("temperature or pressure".into(), + quantity::si::SINumber::from(temperature_or_pressure).to_string() + ))?) + } } /// Create a liquid and vapor state in equilibrium @@ -328,10 +341,21 @@ macro_rules! impl_phase_equilibrium { /// list[PhaseEquilibrium] #[staticmethod] fn vle_pure_comps(eos: $py_eos, temperature_or_pressure: PySINumber) -> PyResult>> { - Ok(PhaseEquilibrium::vle_pure_comps(&eos.0, TPSpec::try_from(temperature_or_pressure)?) - .into_iter() - .map(|o| o.map(Self)) - .collect()) + if let Ok(t) = Temperature::::try_from(temperature_or_pressure) { + Ok(PhaseEquilibrium::vle_pure_comps(&eos.0, t) + .into_iter() + .map(|o| o.map(Self)) + .collect()) + } else if let Ok(p) = Pressure::::try_from(temperature_or_pressure) { + Ok(PhaseEquilibrium::vle_pure_comps(&eos.0, p) + .into_iter() + .map(|o| o.map(Self)) + .collect()) + } else { + Ok(Err(EosError::WrongUnits("temperature or pressure".into(), + quantity::si::SINumber::from(temperature_or_pressure).to_string() + ))?) + } } /// Calculate the pure component vapor pressures for all the @@ -891,20 +915,20 @@ macro_rules! impl_phase_equilibrium { dict.insert(String::from(format!("y{}", i)), ys.column(i).to_vec()); } } - dict.insert(String::from("temperature"), (self.0.vapor().temperature() / KELVIN).into_value().into_raw_vec()); - dict.insert(String::from("pressure"), (self.0.vapor().pressure() / PASCAL).into_value().into_raw_vec()); - dict.insert(String::from("density liquid"), (self.0.liquid().density() / (MOL / METER.powi::())).into_value().into_raw_vec()); - dict.insert(String::from("density vapor"), (self.0.vapor().density() / (MOL / METER.powi::())).into_value().into_raw_vec()); - dict.insert(String::from("mass density liquid"), (self.0.liquid().mass_density() / (KILOGRAM / METER.powi::())).into_value().into_raw_vec()); - dict.insert(String::from("mass density vapor"), (self.0.vapor().mass_density() / (KILOGRAM / METER.powi::())).into_value().into_raw_vec()); - dict.insert(String::from("molar enthalpy liquid"), (self.0.liquid().molar_enthalpy(contributions) / (KILO*JOULE / MOL)).into_value().into_raw_vec()); - dict.insert(String::from("molar enthalpy vapor"), (self.0.vapor().molar_enthalpy(contributions) / (KILO*JOULE / MOL)).into_value().into_raw_vec()); - dict.insert(String::from("molar entropy liquid"), (self.0.liquid().molar_entropy(contributions) / (KILO*JOULE / KELVIN / MOL)).into_value().into_raw_vec()); - dict.insert(String::from("molar entropy vapor"), (self.0.vapor().molar_entropy(contributions) / (KILO*JOULE / KELVIN / MOL)).into_value().into_raw_vec()); - dict.insert(String::from("specific enthalpy liquid"), (self.0.liquid().specific_enthalpy(contributions) / (KILO*JOULE / KILOGRAM)).into_value().into_raw_vec()); - dict.insert(String::from("specific enthalpy vapor"), (self.0.vapor().specific_enthalpy(contributions) / (KILO*JOULE / KILOGRAM)).into_value().into_raw_vec()); - dict.insert(String::from("specific entropy liquid"), (self.0.liquid().specific_entropy(contributions) / (KILO*JOULE / KELVIN / KILOGRAM)).into_value().into_raw_vec()); - dict.insert(String::from("specific entropy vapor"), (self.0.vapor().specific_entropy(contributions) / (KILO*JOULE / KELVIN / KILOGRAM)).into_value().into_raw_vec()); + dict.insert(String::from("temperature"), self.0.vapor().temperature().convert_into(KELVIN).into_raw_vec()); + dict.insert(String::from("pressure"), self.0.vapor().pressure().convert_into(PASCAL).into_raw_vec()); + dict.insert(String::from("density liquid"), self.0.liquid().density().convert_into(MOL / METER.powi::()).into_raw_vec()); + dict.insert(String::from("density vapor"), self.0.vapor().density().convert_into(MOL / METER.powi::()).into_raw_vec()); + dict.insert(String::from("mass density liquid"), self.0.liquid().mass_density().convert_into(KILOGRAM / METER.powi::()).into_raw_vec()); + dict.insert(String::from("mass density vapor"), self.0.vapor().mass_density().convert_into(KILOGRAM / METER.powi::()).into_raw_vec()); + dict.insert(String::from("molar enthalpy liquid"), self.0.liquid().molar_enthalpy(contributions).convert_into(KILO * JOULE / MOL).into_raw_vec()); + dict.insert(String::from("molar enthalpy vapor"), self.0.vapor().molar_enthalpy(contributions).convert_into(KILO * JOULE / MOL).into_raw_vec()); + dict.insert(String::from("molar entropy liquid"), self.0.liquid().molar_entropy(contributions).convert_into(KILO * JOULE / KELVIN / MOL).into_raw_vec()); + dict.insert(String::from("molar entropy vapor"), self.0.vapor().molar_entropy(contributions).convert_into(KILO * JOULE / KELVIN / MOL).into_raw_vec()); + dict.insert(String::from("specific enthalpy liquid"), self.0.liquid().specific_enthalpy(contributions).convert_into(KILO * JOULE / KILOGRAM).into_raw_vec()); + dict.insert(String::from("specific enthalpy vapor"), self.0.vapor().specific_enthalpy(contributions).convert_into(KILO * JOULE / KILOGRAM).into_raw_vec()); + dict.insert(String::from("specific entropy liquid"), self.0.liquid().specific_entropy(contributions).convert_into(KILO * JOULE / KELVIN / KILOGRAM).into_raw_vec()); + dict.insert(String::from("specific entropy vapor"), self.0.vapor().specific_entropy(contributions).convert_into(KILO * JOULE / KELVIN / KILOGRAM).into_raw_vec()); dict } diff --git a/feos-core/src/python/state.rs b/feos-core/src/python/state.rs index efc500973..497191e00 100644 --- a/feos-core/src/python/state.rs +++ b/feos-core/src/python/state.rs @@ -48,12 +48,12 @@ macro_rules! impl_state { /// When the state cannot be created using the combination of input. #[pyclass(name = "State")] #[derive(Clone)] - #[pyo3(text_signature = "(eos, temperature=None, volume=None, density=None, partial_density=None, total_moles=None, moles=None, molefracs=None, pressure=None, molar_enthalpy=None, molar_entropy=None, molar_internal_energy=None, density_initialization=None, initial_temperature=None)")] pub struct PyState(pub State<$eos>); #[pymethods] impl PyState { #[new] + #[pyo3(text_signature = "(eos, temperature=None, volume=None, density=None, partial_density=None, total_moles=None, moles=None, molefracs=None, pressure=None, molar_enthalpy=None, molar_entropy=None, molar_internal_energy=None, density_initialization=None, initial_temperature=None)")] pub fn new( eos: $py_eos, temperature: Option, @@ -214,13 +214,27 @@ macro_rules! impl_state { tol: Option, verbosity: Option, ) -> PyResult { - Ok(PyState(State::critical_point_binary( - &eos.0, - TPSpec::try_from(temperature_or_pressure)?, - initial_temperature.map(|t| t.try_into()).transpose()?, - initial_molefracs, - (max_iter, tol, verbosity).into(), - )?)) + if let Ok(t) = Temperature::::try_from(temperature_or_pressure) { + Ok(PyState(State::critical_point_binary( + &eos.0, + t, + initial_temperature.map(|t| t.try_into()).transpose()?, + initial_molefracs, + (max_iter, tol, verbosity).into(), + )?)) + } else if let Ok(p) = Pressure::::try_from(temperature_or_pressure) { + Ok(PyState(State::critical_point_binary( + &eos.0, + p, + initial_temperature.map(|t| t.try_into()).transpose()?, + initial_molefracs, + (max_iter, tol, verbosity).into(), + )?)) + } else { + Ok(Err(EosError::WrongUnits("temperature or pressure".into(), + quantity::si::SINumber::from(temperature_or_pressure).to_string() + ))?) + } } /// Calculate spinodal states for a given temperature and composition. diff --git a/feos-core/src/si/array.rs b/feos-core/src/si/array.rs index 0086b6a40..10a0b053f 100644 --- a/feos-core/src/si/array.rs +++ b/feos-core/src/si/array.rs @@ -7,16 +7,36 @@ use ndarray::{ use std::iter::FromIterator; use std::marker::PhantomData; -/// Constructors for 1D arrays impl Quantity, U> { + /// Create a one-dimensional array from a vector of scalar quantities. pub fn from_vec(v: Vec>) -> Self { Self(v.iter().map(|e| e.0).collect(), PhantomData) } + /// Create a one-dimensional array with n evenly spaced elements from `start` to `end` (inclusive). + /// + /// # Example + /// ``` + /// # use feos_core::si::{Length, METER}; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// let x = Length::linspace(1.0 * METER, 3.0 * METER, 5); + /// assert_relative_eq!(x, &(arr1(&[1.0, 1.5, 2.0, 2.5, 3.0]) * METER)); + /// ``` pub fn linspace(start: Quantity, end: Quantity, n: usize) -> Self { Self(Array1::linspace(start.0, end.0, n), PhantomData) } + /// Create a one-dimensional array with n logarithmically spaced elements from `start` to `end` (inclusive). + /// + /// # Example + /// ``` + /// # use feos_core::si::{Length, METER}; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// let x = Length::logspace(1.0 * METER, 16.0 * METER, 5); + /// assert_relative_eq!(x, &(arr1(&[1.0, 2.0, 4.0, 8.0, 16.0]) * METER)); + /// ``` pub fn logspace(start: Quantity, end: Quantity, n: usize) -> Self { Self( Array1::logspace(10.0, start.0.log10(), end.0.log10(), n), @@ -25,12 +45,13 @@ impl Quantity, U> { } } -/// Constructors for nD arrays impl Quantity, U> { + /// Create an array with all elements set to 0. pub fn zeros>(shape: Sh) -> Self { Quantity(Array::zeros(shape), PhantomData) } + /// Create an array with values created by the function f. pub fn from_shape_fn(shape: Sh, mut f: F) -> Self where Sh: ShapeBuilder, @@ -41,30 +62,46 @@ impl Quantity, U> { } impl, U, D: Dimension> Quantity, U> { + /// Return the total number of elements in the array. pub fn len(&self) -> usize { self.0.len() } + /// Return whether the array has any elements pub fn is_empty(&self) -> bool { self.0.is_empty() } + /// Return the sum of all elements in the array. + /// + /// # Example + /// ``` + /// # use feos_core::si::BAR; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// let x = arr1(&[1.5, 2.5]) * BAR; + /// assert_relative_eq!(x.sum(), &(4.0 * BAR)); + /// ``` pub fn sum(&self) -> Quantity { Quantity(self.0.sum(), PhantomData) } + /// Return an uniquely owned copy of the array. pub fn to_owned(&self) -> Quantity, U> { Quantity(self.0.to_owned(), PhantomData) } + /// Return the shape of the array as a slice. pub fn shape(&self) -> &[usize] { self.0.shape() } + /// Return the shape of the array as it’s stored in the array. pub fn raw_dim(&self) -> D { self.0.raw_dim() } + /// Call f by value on each element and create a new array with the new values. pub fn mapv(&self, mut f: F) -> Quantity, U2> where S: DataMut, @@ -73,6 +110,7 @@ impl, U, D: Dimension> Quantity, U> { Quantity(self.0.mapv(|x| f(Quantity(x, PhantomData)).0), PhantomData) } + /// Returns a view restricted to index along the axis, with the axis removed. pub fn index_axis( &self, axis: Axis, @@ -84,6 +122,7 @@ impl, U, D: Dimension> Quantity, U> { Quantity(self.0.index_axis(axis, index), PhantomData) } + /// Return a producer and iterable that traverses over all 1D lanes pointing in the direction of axis. pub fn lanes_mut(&mut self, axis: Axis) -> LanesMut where S: DataMut, @@ -91,6 +130,7 @@ impl, U, D: Dimension> Quantity, U> { self.0.lanes_mut(axis) } + /// Return sum along axis. pub fn sum_axis(&self, axis: Axis) -> Quantity, U> where D: RemoveAxis, @@ -98,14 +138,20 @@ impl, U, D: Dimension> Quantity, U> { Quantity(self.0.sum_axis(axis), PhantomData) } + /// Insert new array axis at axis and return the result. pub fn insert_axis(self, axis: Axis) -> Quantity, U> { Quantity(self.0.insert_axis(axis), PhantomData) } + /// Return the element at `index`. + /// + /// The `Index` trait can not be implemented, because a new instance has to be created, + /// when indexing a quantity array. This serves as replacement for it. pub fn get>(&self, index: I) -> Quantity { Quantity(self.0[index], PhantomData) } + /// Set the element at `index` to `scalar`. pub fn set>(&mut self, index: I, value: Quantity) where S: DataMut, diff --git a/feos-core/src/si/fmt.rs b/feos-core/src/si/fmt.rs index 752ae172d..ce0adedd1 100644 --- a/feos-core/src/si/fmt.rs +++ b/feos-core/src/si/fmt.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::fmt; use typenum::{Quot, N1, N2, N3, P2, P3, P4}; -const UNIT_SYMBOLS: [&str; 7] = ["m", "kg", "s", "A", "mol", "K", "cd"]; +const UNIT_SYMBOLS: [&str; 7] = ["s", "m", "kg", "A", "K", "mol", "cd"]; impl< Inner: fmt::Debug, diff --git a/feos-core/src/si/mod.rs b/feos-core/src/si/mod.rs index 87335cbf6..4b67b26f9 100644 --- a/feos-core/src/si/mod.rs +++ b/feos-core/src/si/mod.rs @@ -1,8 +1,12 @@ +//! Physical quantities with compile-time checked units. + +#![allow(clippy::type_complexity)] use ang::{Angle, Degrees, Radians}; +use ndarray::{Array, ArrayBase, Data, Dimension}; use num_traits::Zero; use std::marker::PhantomData; -use std::ops::{Div, Mul}; -use typenum::{ATerm, Diff, Integer, Negate, Sum, TArr, P1, Z0}; +use std::ops::{Div, Mul, Sub}; +use typenum::{ATerm, Diff, Integer, Negate, Quot, Sum, TArr, N1, N2, P1, P3, Z0}; mod array; mod fmt; @@ -13,6 +17,7 @@ mod python; pub type SIUnit = TArr>>>>>>; +/// Physical quantity with compile-time checked unit. #[derive(Clone, Copy)] #[repr(transparent)] pub struct Quantity(T, PhantomData); @@ -98,6 +103,14 @@ pub type _MolarVolume = Diff<_Volume, _Moles>; pub type MolarVolume = Quantity; pub type _EntropyDensity = Diff<_Entropy, _Volume>; pub type EntropyDensity = Quantity; +pub type _Action = Sum<_Energy, _Time>; +pub type Action = Quantity; +pub type _HeatCapacityRate = Diff<_Power, _Temperature>; +pub type HeatCapacityRate = Quantity; +pub type _MassFlowRate = Diff<_Mass, _Time>; +pub type MassFlowRate = Quantity; +pub type _MoleFlowRate = Diff<_Moles, _Time>; +pub type MoleFlowRate = Quantity; pub type _Viscosity = Sum<_Pressure, _Time>; pub type Viscosity = Quantity; @@ -108,37 +121,67 @@ pub type ThermalConductivity = Quantity; pub type _SurfaceTension = Diff<_Force, _Length>; pub type SurfaceTension = Quantity; +/// SI base unit second $\\left(\text{s}\\right)$ pub const SECOND: Time = Quantity(1.0, PhantomData); +/// SI base unit meter $\\left(\text{m}\\right)$ pub const METER: Length = Quantity(1.0, PhantomData); +/// SI base unit kilogram $\\left(\text{kg}\\right)$ pub const KILOGRAM: Mass = Quantity(1.0, PhantomData); +/// SI base unit Ampere $\\left(\text{A}\\right)$ pub const AMPERE: Current = Quantity(1.0, PhantomData); +/// SI base unit Kelvin $\\left(\text{K}\\right)$ pub const KELVIN: Temperature = Quantity(1.0, PhantomData); +/// SI base unit mol $\\left(\text{mol}\\right)$ pub const MOL: Moles = Quantity(1.0, PhantomData); +/// SI base unit candela $\\left(\text{cd}\\right)$ pub const CANDELA: LuminousIntensity = Quantity(1.0, PhantomData); +/// Derived unit Hertz $\\left(1\\,\text{Hz}=1\\,\text{s}^{-1}\\right)$ pub const HERTZ: Frequency = Quantity(1.0, PhantomData); +/// Derived unit Newton $\\left(1\\,\text{N}=1\\,\text{kg}\\frac{\text{m}}{\text{s}^2}\\right)$ pub const NEWTON: Force = Quantity(1.0, PhantomData); +/// Derived unit Pascal $\\left(1\\,\text{Pa}=1\\,\\frac{\text{kg}}{\text{m}\\cdot\text{s}^2}\\right)$ pub const PASCAL: Pressure = Quantity(1.0, PhantomData); +/// Derived unit Joule $\\left(1\\,\text{J}=1\\,\text{kg}\\frac{\text{m}^2}{\text{s}^2}\\right)$ pub const JOULE: Energy = Quantity(1.0, PhantomData); +/// Derived unit Watt $\\left(1\\,\text{J}=1\\,\text{kg}\\frac{\text{m}^2}{\text{s}^3}\\right)$ pub const WATT: Power = Quantity(1.0, PhantomData); +/// Derived unit Coulomb $\\left(1\\,\text{C}=1\\,\text{A}\cdot\text{s}\\right)$ pub const COULOMB: Charge = Quantity(1.0, PhantomData); +/// Derived unit Volt $\\left(1\\,\text{V}=1\\,\\frac{\text{W}}{\text{A}}\\right)$ pub const VOLT: ElectricPotential = Quantity(1.0, PhantomData); +/// Derived unit Farad $\\left(1\\,\text{F}=1\\,\\frac{\text{C}}{\text{V}}\\right)$ pub const FARAD: Capacitance = Quantity(1.0, PhantomData); +/// Derived unit Ohm $\\left(1\\,\text{Ω}=1\\,\\frac{\text{V}}{\text{A}}\\right)$ pub const OHM: Resistance = Quantity(1.0, PhantomData); +/// Derived unit Siemens $\\left(1\\,\text{S}=1\\,\text{Ω}^{-1}\\right)$ pub const SIEMENS: ElectricalConductance = Quantity(1.0, PhantomData); +/// Derived unit Weber $\\left(1\\,\text{Wb}=1\\,\text{V}\\cdot\text{s}\\right)$ pub const WEBER: MagneticFlux = Quantity(1.0, PhantomData); +/// Derived unit Tesla $\\left(1\\,\text{T}=1\\,\\frac{\text{Wb}}{\text{m}^2}\\right)$ pub const TESLA: MagneticFluxDensity = Quantity(1.0, PhantomData); +/// Derived unit Henry $\\left(1\\,\text{T}=1\\,\\frac{\text{Wb}}{\text{A}}\\right)$ pub const HENRY: Inductance = Quantity(1.0, PhantomData); +/// Additional unit Ångstrom $\\left(1\\,\text{\\AA}=10^{-10}\\,\text{m}\\right)$ pub const ANGSTROM: Length = Quantity(1e-10, PhantomData); +/// Additional unit unified atomic mass $\\left(1\\,\text{u}\\approx 1.660539\\times 10^{-27}\\,\text{kg}\\right)$ pub const AMU: Mass = Quantity(1.6605390671738466e-27, PhantomData); +/// Additional unit astronomical unit $\\left(1\\,\text{au}=149597870700\\,\text{m}\\right)$ pub const AU: Length = Quantity(149597870700.0, PhantomData); +/// Additional unit bar $\\left(1\\,\text{bar}=10^5\\,\text{Pa}\\right)$ pub const BAR: Pressure = Quantity(1e5, PhantomData); +/// Additional unit calorie $\\left(1\\,\text{cal}=4.184\\,\text{J}\\right)$ pub const CALORIE: Energy = Quantity(4.184, PhantomData); +/// Additional unit day $\\left(1\\,\text{d}=86400,\text{s}\\right)$ pub const DAY: Time = Quantity(86400.0, PhantomData); +/// Additional unit gram $\\left(1\\,\text{g}=10^{-3}\\,\text{kg}\\right)$ pub const GRAM: Mass = Quantity(1e-3, PhantomData); +/// Additional unit hour $\\left(1\\,\text{h}=3600,\text{s}\\right)$ pub const HOUR: Time = Quantity(3600.0, PhantomData); +/// Additional unit liter $\\left(1\\,\text{l}=10^{-3}\\,\text{m}^3\\right)$ pub const LITER: Volume = Quantity(1e-3, PhantomData); +/// Additional unit minute $\\left(1\\,\text{min}=60,\text{s}\\right)$ pub const MINUTE: Time = Quantity(60.0, PhantomData); /// Angle unit radian $\\left(\text{rad}\\right)$ @@ -150,8 +193,20 @@ pub const DEGREES: Angle = Degrees(1.0); pub const KB: Entropy = Quantity(1.380649e-23, PhantomData); /// Avogadro constant $\\left(N_\text{A}=6.02214076\times 10^{23}\\,\text{mol}^{-1}\\right)$ pub const NAV: Quantity> = Quantity(6.02214076e23, PhantomData); +/// Planck constant $\\left(h=6.62607015\times 10^{-34}\\,\text{J}\\cdot\text{s}\\right)$ +pub const PLANCK: Action = Quantity(6.62607015e-34, PhantomData); /// Ideal gas constant $\\left(R=8.31446261815324\\,\\frac{\text{J}}{\text{molK}}\\right)$ pub const RGAS: MolarEntropy = Quantity(8.31446261815324, PhantomData); +/// Hyperfine transition frequency of Cs $\\left(\Delta\\nu_\text{Cs}=9192631770\\,\text{Hz}\\right)$ +pub const DVCS: Frequency = Quantity(9192631770.0, PhantomData); +/// Elementary charge $\\left(e=1.602176634\\times 10^{-19}\\,\text{C}\\right)$ +pub const QE: Charge = Quantity(1.602176634e-19, PhantomData); +/// Speed of light $\\left(c=299792458\\,\\frac{\text{m}}{\text{s}}\\right)$ +pub const CLIGHT: Velocity = Quantity(299792458.0, PhantomData); +/// Luminous efficacy of $540\\,\text{THz}$ radiation $\\left(K_\text{cd}=683\\,\\frac{\text{lm}}{\text{W}}\\right)$ +pub const KCD: Quantity> = Quantity(683.0, PhantomData); +/// Gravitational constant $\\left(G=6.6743\\times 10^{-11}\\,\\frac{\text{m}^3}{\text{kg}\cdot\text{s}^2}\\right)$ +pub const G: Quantity> = Quantity(6.6743e-11, PhantomData); /// Prefix quecto $\\left(\text{q}=10^{-30}\\right)$ pub const QUECTO: f64 = 1e-30; @@ -202,13 +257,60 @@ pub const RONNA: f64 = 1e27; /// Prefix quetta $\\left(\text{Q}=10^{30}\\right)$ pub const QUETTA: f64 = 1e30; -/// Basic conversions and constructors +/// Additional unit degrees Celsius +pub struct CELSIUS; + +impl Mul for f64 { + type Output = Temperature; + #[allow(clippy::suspicious_arithmetic_impl)] + fn mul(self, _: CELSIUS) -> Temperature { + Quantity(self + 273.15, PhantomData) + } +} + +impl, D: Dimension> Mul for ArrayBase { + type Output = Temperature>; + #[allow(clippy::suspicious_arithmetic_impl)] + fn mul(self, _: CELSIUS) -> Temperature> { + Quantity(&self + 273.15, PhantomData) + } +} + +impl Div for Temperature { + type Output = f64; + #[allow(clippy::suspicious_arithmetic_impl)] + fn div(self, _: CELSIUS) -> Self::Output { + self.0 - 273.15 + } +} + +impl Div for Temperature> { + type Output = Array; + #[allow(clippy::suspicious_arithmetic_impl)] + fn div(self, _: CELSIUS) -> Self::Output { + self.0 - 273.15 + } +} + impl Dimensionless { + /// Return the value of a dimensionless quantity. pub fn into_value(self) -> T { self.0 } } +impl Quantity { + /// Convert a quantity into the given unit and return it + /// as a float or array. + pub fn convert_into(self, unit: Quantity) -> Quot + where + T: Div, + U: Sub, + { + (self / unit).into_value() + } +} + impl From for Dimensionless { fn from(value: T) -> Self { Quantity(value, PhantomData) diff --git a/feos-core/src/si/ops.rs b/feos-core/src/si/ops.rs index f0a9c7d86..4344745da 100644 --- a/feos-core/src/si/ops.rs +++ b/feos-core/src/si/ops.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use typenum::{Diff, Integer, Negate, Prod, Quot, Sum, P2, P3}; -/// Multiplication +// Multiplication impl Mul> for Quantity where T1: Mul, @@ -102,7 +102,7 @@ where } } -/// Division +// Division impl Div> for Quantity where T1: Div, @@ -200,7 +200,7 @@ where } } -/// Addition +// Addition impl Add> for Quantity where T1: Add, @@ -259,7 +259,7 @@ where } } -/// Subtraction +// Subtraction impl Sub> for Quantity where T1: Sub, @@ -318,7 +318,7 @@ where } } -/// Negation +// Negation impl Neg for Quantity where T: Neg, @@ -329,8 +329,18 @@ where } } -/// Operations for scalars impl Quantity { + /// Calculate the integer power of self. + /// + /// # Example + /// ``` + /// # use feos_core::si::METER; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// # use typenum::P2; + /// let x = 3.0 * METER; + /// assert_relative_eq!(x.powi::(), 9.0 * METER * METER); + /// ``` pub fn powi(self) -> Quantity> where U: Mul, @@ -338,6 +348,16 @@ impl Quantity { Quantity(self.0.powi(E::I32), PhantomData) } + /// Calculate the square root of self. + /// + /// # Example + /// ``` + /// # use feos_core::si::METER; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// let x = 9.0 * METER * METER; + /// assert_relative_eq!(x.sqrt(), 3.0 * METER); + /// ``` pub fn sqrt(self) -> Quantity> where U: Div, @@ -345,6 +365,16 @@ impl Quantity { Quantity(self.0.sqrt(), PhantomData) } + /// Calculate the cubic root of self. + /// + /// # Example + /// ``` + /// # use feos_core::si::METER; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// let x = 27.0 * METER * METER * METER; + /// assert_relative_eq!(x.cbrt(), 3.0 * METER); + /// ``` pub fn cbrt(self) -> Quantity> where U: Div, @@ -352,43 +382,91 @@ impl Quantity { Quantity(self.0.cbrt(), PhantomData) } + /// Calculate the integer root of self. + /// + /// # Example + /// ``` + /// # use feos_core::si::METER; + /// # use ndarray::arr1; + /// # use approx::assert_relative_eq; + /// # use typenum::P4; + /// let x = 81.0 * METER * METER * METER * METER; + /// assert_relative_eq!(x.root::(), 3.0 * METER); + /// ``` pub fn root(self) -> Quantity> where U: Div, { - Quantity(self.0.powf(1.0 / R::I32 as f64).cbrt(), PhantomData) + Quantity(self.0.powf(1.0 / R::I32 as f64), PhantomData) } + /// Return the absolute value of `self`. + /// + /// # Example + /// ``` + /// # use feos_core::si::KELVIN; + /// # use approx::assert_relative_eq; + /// let t = -50.0 * KELVIN; + /// assert_relative_eq!(t.abs(), &(50.0 * KELVIN)); pub fn abs(self) -> Self { Self(self.0.abs(), PhantomData) } + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` pub fn signum(self) -> f64 { self.0.signum() } + /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. pub fn is_sign_negative(&self) -> bool { self.0.is_sign_negative() } + /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. pub fn is_sign_positive(&self) -> bool { self.0.is_sign_positive() } + /// Returns true if this value is NaN. pub fn is_nan(&self) -> bool { self.0.is_nan() } + /// Return the minimum of `self` and `other`. + /// + /// # Example + /// ``` + /// # use feos_core::si::{KILO, PASCAL, BAR}; + /// # use approx::assert_relative_eq; + /// let p1 = 110.0 * KILO * PASCAL; + /// let p2 = BAR; + /// assert_relative_eq!(p1.min(p2), &p2); + /// ``` pub fn min(self, other: Self) -> Self { Self(self.0.min(other.0), PhantomData) } + /// Return the maximum of `self` and `other`. + /// + /// # Example + /// ``` + /// # use feos_core::si::{KILO, PASCAL, BAR}; + /// # use approx::assert_relative_eq; + /// let p1 = 110.0 * KILO * PASCAL; + /// let p2 = BAR; + /// assert_relative_eq!(p1.max(p2), &p1); + /// ``` pub fn max(self, other: Self) -> Self { Self(self.0.max(other.0), PhantomData) } } -/// Comparisons impl PartialEq for Quantity { fn eq(&self, other: &Self) -> bool { self.0 == other.0 diff --git a/feos-core/src/si/python.rs b/feos-core/src/si/python.rs index c7bf64cfc..877032311 100644 --- a/feos-core/src/si/python.rs +++ b/feos-core/src/si/python.rs @@ -1,5 +1,6 @@ use super::{Pressure, Quantity, SIUnit, Temperature}; -use crate::{EosError, EosResult, TPSpec}; +use crate::state::TPSpec; +use crate::{EosError, EosResult}; use ndarray::{Array1, Array2, Array3, Array4}; use quantity::python::{PySIArray1, PySIArray2, PySIArray3, PySIArray4, PySINumber}; use quantity::si; @@ -160,6 +161,9 @@ impl TryFrom for TPSpec { if let Ok(p) = Pressure::::try_from(quantity) { return Ok(TPSpec::Pressure(p)); } - Err(EosError::Error("TODO".into())) + Err(EosError::WrongUnits( + "temperature or pressure".into(), + quantity.to_string(), + )) } } diff --git a/feos-core/src/state/critical_point.rs b/feos-core/src/state/critical_point.rs index 471dd37d6..86d5739bd 100644 --- a/feos-core/src/state/critical_point.rs +++ b/feos-core/src/state/critical_point.rs @@ -2,7 +2,7 @@ use super::{DensityInitialization, State, StateHD, TPSpec}; use crate::equation_of_state::Residual; use crate::errors::{EosError, EosResult}; use crate::si::{Density, Moles, Pressure, Temperature, Volume}; -use crate::{SolverOptions, Verbosity}; +use crate::{SolverOptions, TemperatureOrPressure, Verbosity}; use nalgebra::SVector; use ndarray::{arr1, Array1, Array2}; use num_dual::linalg::smallest_ev; @@ -37,17 +37,14 @@ impl State { .collect() } - pub fn critical_point_binary( + pub fn critical_point_binary( eos: &Arc, temperature_or_pressure: TP, initial_temperature: Option, initial_molefracs: Option<[f64; 2]>, options: SolverOptions, - ) -> EosResult - where - TPSpec: From, - { - match TPSpec::from(temperature_or_pressure) { + ) -> EosResult { + match temperature_or_pressure.into() { TPSpec::Temperature(t) => { Self::critical_point_binary_t(eos, t, initial_molefracs, options) } diff --git a/feos-core/tests/parameters.rs b/feos-core/tests/parameters.rs new file mode 100644 index 000000000..d1fe0bfd8 --- /dev/null +++ b/feos-core/tests/parameters.rs @@ -0,0 +1,289 @@ +use feos_core::parameter::*; +use ndarray::Array2; +use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +struct MyPureModel { + a: f64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] +struct MyBinaryModel { + b: f64, +} + +impl TryFrom for MyBinaryModel { + type Error = &'static str; + fn try_from(f: f64) -> Result { + Ok(Self { b: f }) + } +} + +struct MyParameter { + pure_records: Vec>, + binary_records: Option>, +} + +impl Parameter for MyParameter { + type Pure = MyPureModel; + type Binary = MyBinaryModel; + fn from_records( + pure_records: Vec>, + binary_records: Option>, + ) -> Result { + Ok(Self { + pure_records, + binary_records, + }) + } + + fn records(&self) -> (&[PureRecord], Option<&Array2>) { + (&self.pure_records, self.binary_records.as_ref()) + } +} + +#[test] +fn from_records() -> Result<(), ParameterError> { + let pr_json = r#" + [ + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.1 + } + }, + { + "identifier": { + "cas": "678-9-1" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + } + ] + "#; + let br_json = r#" + [ + { + "id1": { + "cas": "123-4-5" + }, + "id2": { + "cas": "678-9-1" + }, + "model_record": { + "b": 12.0 + } + } + ] + "#; + let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); + let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); + let binary_matrix = MyParameter::binary_matrix_from_records( + &pure_records, + &binary_records, + IdentifierOption::Cas, + ); + let p = MyParameter::from_records(pure_records, binary_matrix)?; + + assert_eq!(p.pure_records[0].identifier.cas, Some("123-4-5".into())); + assert_eq!(p.pure_records[1].identifier.cas, Some("678-9-1".into())); + assert_eq!(p.binary_records.unwrap()[[0, 1]].b, 12.0); + Ok(()) +} + +#[test] +fn from_json_duplicates_input() { + let pure_records = PureRecord::::from_json( + &["123-4-5", "123-4-5"], + "tests/test_parameters2.json", + IdentifierOption::Cas, + ); + assert!(matches!( + pure_records, + Err(ParameterError::IncompatibleParameters(t)) + if t == "A substance was defined more than once." + )); +} + +#[test] +fn from_multiple_json_files_duplicates() { + let my_parameters = MyParameter::from_multiple_json( + &[ + (vec!["123-4-5"], "tests/test_parameters1.json"), + (vec!["678-9-1", "123-4-5"], "tests/test_parameters2.json"), + ], + None, + IdentifierOption::Cas, + ); + assert!(matches!( + my_parameters, + Err(ParameterError::IncompatibleParameters(t)) + if t == "A substance was defined more than once." + )); + + let my_parameters = MyParameter::from_multiple_json( + &[ + (vec!["123-4-5"], "tests/test_parameters1.json"), + (vec!["678-9-1"], "tests/test_parameters2.json"), + ], + None, + IdentifierOption::Cas, + ) + .unwrap(); + + // test_parameters1: a = 0.5 + // test_parameters2: a = 0.1 or 0.3 + assert_eq!(my_parameters.pure_records[0].model_record.a, 0.5); +} + +#[test] +fn from_multiple_json_files() { + let p = MyParameter::from_multiple_json( + &[ + (vec!["678-9-1"], "tests/test_parameters2.json"), + (vec!["123-4-5"], "tests/test_parameters1.json"), + ], + Some("tests/test_parameters_binary.json"), + IdentifierOption::Cas, + ) + .unwrap(); + + // test_parameters1: a = 0.5 + // test_parameters2: a = 0.1 or 0.3 + assert_eq!(p.pure_records[1].model_record.a, 0.5); + let br = p.binary_records.as_ref().unwrap(); + assert_eq!(br[[0, 1]].b, 12.0); + assert_eq!(br[[1, 0]].b, 12.0); +} + +#[test] +fn from_records_missing_binary() -> Result<(), ParameterError> { + let pr_json = r#" + [ + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.1 + } + }, + { + "identifier": { + "cas": "678-9-1" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + } + ] + "#; + let br_json = r#" + [ + { + "id1": { + "cas": "123-4-5" + }, + "id2": { + "cas": "000-00-0" + }, + "model_record": { + "b": 12.0 + } + } + ] + "#; + let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); + let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); + let binary_matrix = MyParameter::binary_matrix_from_records( + &pure_records, + &binary_records, + IdentifierOption::Cas, + ); + let p = MyParameter::from_records(pure_records, binary_matrix)?; + + assert_eq!(p.pure_records[0].identifier.cas, Some("123-4-5".into())); + assert_eq!(p.pure_records[1].identifier.cas, Some("678-9-1".into())); + let br = p.binary_records.as_ref().unwrap(); + assert_eq!(br[[0, 1]], MyBinaryModel::default()); + assert_eq!(br[[0, 1]].b, 0.0); + Ok(()) +} + +#[test] +fn from_records_correct_binary_order() -> Result<(), ParameterError> { + let pr_json = r#" + [ + { + "identifier": { + "cas": "000-0-0" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + }, + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.1 + } + }, + { + "identifier": { + "cas": "678-9-1" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + } + ] + "#; + let br_json = r#" + [ + { + "id1": { + "cas": "123-4-5" + }, + "id2": { + "cas": "678-9-1" + }, + "model_record": { + "b": 12.0 + } + } + ] + "#; + let pure_records = serde_json::from_str(pr_json).expect("Unable to parse json."); + let binary_records: Vec<_> = serde_json::from_str(br_json).expect("Unable to parse json."); + let binary_matrix = MyParameter::binary_matrix_from_records( + &pure_records, + &binary_records, + IdentifierOption::Cas, + ); + let p = MyParameter::from_records(pure_records, binary_matrix)?; + + assert_eq!(p.pure_records[0].identifier.cas, Some("000-0-0".into())); + assert_eq!(p.pure_records[1].identifier.cas, Some("123-4-5".into())); + assert_eq!(p.pure_records[2].identifier.cas, Some("678-9-1".into())); + let br = p.binary_records.as_ref().unwrap(); + assert_eq!(br[[0, 1]], MyBinaryModel::default()); + assert_eq!(br[[1, 0]], MyBinaryModel::default()); + assert_eq!(br[[0, 2]], MyBinaryModel::default()); + assert_eq!(br[[2, 0]], MyBinaryModel::default()); + assert_eq!(br[[2, 1]].b, 12.0); + assert_eq!(br[[1, 2]].b, 12.0); + Ok(()) +} diff --git a/feos-core/tests/test_parameters1.json b/feos-core/tests/test_parameters1.json new file mode 100644 index 000000000..63e879592 --- /dev/null +++ b/feos-core/tests/test_parameters1.json @@ -0,0 +1,20 @@ +[ + { + "identifier": { + "cas": "678-9-1" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + }, + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.5 + } + } +] \ No newline at end of file diff --git a/feos-core/tests/test_parameters2.json b/feos-core/tests/test_parameters2.json new file mode 100644 index 000000000..c60812175 --- /dev/null +++ b/feos-core/tests/test_parameters2.json @@ -0,0 +1,29 @@ +[ + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.1 + } + }, + { + "identifier": { + "cas": "678-9-1" + }, + "molarweight": 32.08412, + "model_record": { + "a": 0.2 + } + }, + { + "identifier": { + "cas": "123-4-5" + }, + "molarweight": 16.0426, + "model_record": { + "a": 0.3 + } + } +] \ No newline at end of file diff --git a/feos-core/tests/test_parameters_binary.json b/feos-core/tests/test_parameters_binary.json new file mode 100644 index 000000000..d04174b9f --- /dev/null +++ b/feos-core/tests/test_parameters_binary.json @@ -0,0 +1,24 @@ +[ + { + "id1": { + "cas": "123-4-5" + }, + "id2": { + "cas": "000-00-0" + }, + "model_record": { + "b": 12.0 + } + }, + { + "id1": { + "cas": "123-4-5" + }, + "id2": { + "cas": "678-9-1" + }, + "model_record": { + "b": 12.0 + } + } +] \ No newline at end of file diff --git a/feos-derive/Cargo.toml b/feos-derive/Cargo.toml index 1af24d155..e2ad3a8c7 100644 --- a/feos-derive/Cargo.toml +++ b/feos-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "feos-derive" -version = "0.2.0" +version = "0.3.0" authors = ["Gernot Bauer ", "Philipp Rehner "] edition = "2021" readme = "README.md" diff --git a/feos-dft/CHANGELOG.md b/feos-dft/CHANGELOG.md index a30803e66..c8fda3638 100644 --- a/feos-dft/CHANGELOG.md +++ b/feos-dft/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.5.0] - 2023-10-20 ### Added - Implemented `HelmholtzEnergyFunctional` for `EquationOfState` to be able to use functionals as equations of state. [#158](https://github.com/feos-org/feos/pull/158) - Added the possibility to specify the angles of non-orthorombic unit cells. Currently, the external potential must be specified if non-orthorombic unit cells are calculated. [#176](https://github.com/feos-org/feos/pull/176) @@ -23,7 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added an error, if the unit cells in 3D DFT are too small and violate the minimum image convention. [#176](https://github.com/feos-org/feos/pull/176) ### Packaging -- Updated `num-dual` dependency to 0.7. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `quantity` dependency to 0.7. +- Updated `num-dual` dependency to 0.8. [#137](https://github.com/feos-org/feos/pull/137) +- Updated `numpy` and `PyO3` dependencies to 0.20. ## [0.4.1] - 2023-03-20 ### Added diff --git a/feos-dft/Cargo.toml b/feos-dft/Cargo.toml index b94aa4776..a2376af12 100644 --- a/feos-dft/Cargo.toml +++ b/feos-dft/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "feos-dft" -version = "0.4.1" +version = "0.5.0" authors = ["Philipp Rehner ", "Gernot Bauer "] edition = "2021" license = "MIT OR Apache-2.0" @@ -17,9 +17,9 @@ rustdoc-args = [ "--html-in-header", "./docs-header.html" ] features = [ "rayon" ] [dependencies] -quantity = { version = "0.6", optional = true } -num-dual = "0.7" -feos-core = { version = "0.4", path = "../feos-core" } +quantity = { version = "0.7", optional = true } +num-dual = "0.8" +feos-core = { version = "0.5", path = "../feos-core" } ndarray = "0.15" nalgebra = "0.32" rustdct = "0.7" @@ -30,8 +30,8 @@ libm = "0.2" gauss-quad = { version = "0.1", optional = true } petgraph = "0.6" typenum = "1.16" -numpy = { version = "0.18", optional = true } -pyo3 = { version = "0.18", optional = true } +numpy = { version = "0.20", optional = true } +pyo3 = { version = "0.20", optional = true } [features] default = [] diff --git a/feos-dft/README.md b/feos-dft/README.md index 33d12fa23..174405aba 100644 --- a/feos-dft/README.md +++ b/feos-dft/README.md @@ -17,5 +17,5 @@ Add this to your `Cargo.toml` ```toml [dependencies] -feos-dft = "0.4" +feos-dft = "0.5" ``` \ No newline at end of file diff --git a/feos-dft/src/adsorption/mod.rs b/feos-dft/src/adsorption/mod.rs index 34ed30df7..0d476236a 100644 --- a/feos-dft/src/adsorption/mod.rs +++ b/feos-dft/src/adsorption/mod.rs @@ -146,10 +146,7 @@ where )? .profiles; Ok(Adsorption { - profiles: adsorption - .into_iter() - .chain(desorption.into_iter()) - .collect(), + profiles: adsorption.into_iter().chain(desorption).collect(), components: functional.components(), }) } else { @@ -176,8 +173,8 @@ where }); let profiles = is_ads .into_iter() - .zip(adsorption.profiles.into_iter()) - .zip(desorption.profiles.into_iter()) + .zip(adsorption.profiles) + .zip(desorption.profiles) .map(|((is_ads, a), d)| if is_ads { a } else { d }) .collect(); Ok(Adsorption::new(functional, profiles)) diff --git a/feos-dft/src/adsorption/pore3d.rs b/feos-dft/src/adsorption/pore3d.rs index acc0703d6..c069c6722 100644 --- a/feos-dft/src/adsorption/pore3d.rs +++ b/feos-dft/src/adsorption/pore3d.rs @@ -25,11 +25,11 @@ pub struct Pore3D { impl Pore3D { pub fn new( system_size: [Length; 3], - angles: Option<[Angle; 3]>, n_grid: [usize; 3], coordinates: Length>, sigma_ss: Array1, epsilon_k_ss: Array1, + angles: Option<[Angle; 3]>, potential_cutoff: Option, cutoff_radius: Option, ) -> Self { diff --git a/feos-dft/src/functional.rs b/feos-dft/src/functional.rs index c22fddcb0..913406f10 100644 --- a/feos-dft/src/functional.rs +++ b/feos-dft/src/functional.rs @@ -36,6 +36,10 @@ impl HelmholtzEnergyF fn compute_max_density(&self, moles: &Array1) -> f64 { self.residual.compute_max_density(moles) } + + fn bond_lengths(&self, temperature: f64) -> UnGraph<(), f64> { + self.residual.bond_lengths(temperature) + } } impl PairPotential for EquationOfState { diff --git a/feos-dft/src/lib.rs b/feos-dft/src/lib.rs index 4323b2303..2962fbeea 100644 --- a/feos-dft/src/lib.rs +++ b/feos-dft/src/lib.rs @@ -2,7 +2,6 @@ #![allow(clippy::suspicious_operation_groupings)] #![allow(clippy::too_many_arguments)] #![allow(clippy::new_ret_no_self)] -#![allow(deprecated)] pub mod adsorption; mod convolver; diff --git a/feos-dft/src/profile/mod.rs b/feos-dft/src/profile/mod.rs index 30a8794ec..dba11e11d 100644 --- a/feos-dft/src/profile/mod.rs +++ b/feos-dft/src/profile/mod.rs @@ -401,7 +401,7 @@ where .functional_derivative(temperature, bulk_density, &bulk_convolver)?; dfdrho .outer_iter_mut() - .zip(dfdrho_bulk.into_iter()) + .zip(dfdrho_bulk) .zip(self.dft.m().iter()) .for_each(|((mut df, df_b), &m)| { df -= df_b; diff --git a/feos-dft/src/profile/properties.rs b/feos-dft/src/profile/properties.rs index 50f073f7f..9afcdb9aa 100644 --- a/feos-dft/src/profile/properties.rs +++ b/feos-dft/src/profile/properties.rs @@ -301,7 +301,7 @@ where /// Return the partial derivatives of the density profiles w.r.t. the chemical potentials $\left(\frac{\partial\rho_i(\mathbf{r})}{\partial\mu_k}\right)_T$ pub fn drho_dmu(&self) -> EosResult> { - let shape = self.density.shape().clone(); + let shape = self.density.shape(); let shape: Vec<_> = std::iter::once(&shape[0]).chain(shape).copied().collect(); let mut drho_dmu = Array::zeros(shape).into_dimensionality().unwrap(); for (k, mut d) in drho_dmu.outer_iter_mut().enumerate() { @@ -375,12 +375,12 @@ where (self.bulk.partial_molar_volume() * self.bulk.dp_dt(Contributions::Total)).to_reduced(); let mut lhs = dfdrhodt.mapv(|d| d.eps); lhs.outer_iter_mut() - .zip(dfdrhodt_bulk.into_iter()) - .zip(x.into_iter()) + .zip(dfdrhodt_bulk) + .zip(x) .for_each(|((mut lhs, d), x)| lhs -= d.eps - x); lhs.outer_iter_mut() .zip(rho.outer_iter()) - .zip(rho_bulk.into_iter()) + .zip(rho_bulk) .zip(self.dft.m().iter()) .for_each(|(((mut lhs, rho), rho_b), &m)| lhs += &((&rho / rho_b).mapv(f64::ln) * m)); diff --git a/feos-dft/src/python/adsorption/pore.rs b/feos-dft/src/python/adsorption/pore.rs index 8be4ddea2..2e210cb28 100644 --- a/feos-dft/src/python/adsorption/pore.rs +++ b/feos-dft/src/python/adsorption/pore.rs @@ -22,7 +22,6 @@ macro_rules! impl_pore { /// Pore1D /// #[pyclass(name = "Pore1D")] - #[pyo3(text_signature = "(geometry, pore_size, potential, n_grid=None, potential_cutoff=None)")] pub struct PyPore1D(Pore1D); #[pyclass(name = "PoreProfile1D")] @@ -33,6 +32,7 @@ macro_rules! impl_pore { #[pymethods] impl PyPore1D { #[new] + #[pyo3(text_signature = "(geometry, pore_size, potential, n_grid=None, potential_cutoff=None)")] fn new( geometry: Geometry, pore_size: PySINumber, @@ -135,7 +135,6 @@ macro_rules! impl_pore { } #[pyclass(name = "Pore2D")] - #[pyo3(text_signature = "(geometry, pore_size, potential, n_grid=None, potential_cutoff=None)")] pub struct PyPore2D(Pore2D); #[pyclass(name = "PoreProfile2D")] @@ -146,6 +145,7 @@ macro_rules! impl_pore { #[pymethods] impl PyPore2D { #[new] + #[pyo3(text_signature = "(system_size, angle, n_grid)")] fn new( system_size: [PySINumber; 2], angle: PyAngle, @@ -245,7 +245,6 @@ macro_rules! impl_pore { /// Pore3D /// #[pyclass(name = "Pore3D")] - #[pyo3(text_signature = "(system_size, angles, n_grid, coordinates, sigma_ss, epsilon_k_ss, potential_cutoff=None, cutoff_radius=None)")] pub struct PyPore3D(Pore3D); #[pyclass(name = "PoreProfile3D")] @@ -256,23 +255,24 @@ macro_rules! impl_pore { #[pymethods] impl PyPore3D { #[new] + #[pyo3(text_signature = "(system_size, n_grid, coordinates, sigma_ss, epsilon_k_ss, angles=None, potential_cutoff=None, cutoff_radius=None)")] fn new( system_size: [PySINumber; 3], - angles: Option<[PyAngle; 3]>, n_grid: [usize; 3], coordinates: PySIArray2, sigma_ss: &PyArray1, epsilon_k_ss: &PyArray1, + angles: Option<[PyAngle; 3]>, potential_cutoff: Option, cutoff_radius: Option, ) -> PyResult { Ok(Self(Pore3D::new( [system_size[0].try_into()?, system_size[1].try_into()?, system_size[2].try_into()?], - angles.map(|angles| [angles[0].into(), angles[1].into(), angles[2].into()]), n_grid, coordinates.try_into()?, sigma_ss.to_owned_array(), epsilon_k_ss.to_owned_array(), + angles.map(|angles| [angles[0].into(), angles[1].into(), angles[2].into()]), potential_cutoff, cutoff_radius.map(|c| c.try_into()).transpose()?, ))) diff --git a/feos-dft/src/python/interface/surface_tension_diagram.rs b/feos-dft/src/python/interface/surface_tension_diagram.rs index b45f91be4..8808f7a50 100644 --- a/feos-dft/src/python/interface/surface_tension_diagram.rs +++ b/feos-dft/src/python/interface/surface_tension_diagram.rs @@ -31,12 +31,12 @@ macro_rules! impl_surface_tension_diagram { /// SurfaceTensionDiagram /// #[pyclass(name = "SurfaceTensionDiagram")] - #[pyo3(text_signature = "(dia, init_densities=None, n_grid=None, l_grid=None, critical_temperature=None, fix_equimolar_surface=None, solver=None)")] pub struct PySurfaceTensionDiagram(SurfaceTensionDiagram<$func>); #[pymethods] impl PySurfaceTensionDiagram { #[new] + #[pyo3(text_signature = "(dia, init_densities=None, n_grid=None, l_grid=None, critical_temperature=None, fix_equimolar_surface=None, solver=None)")] pub fn isotherm( dia: Vec, init_densities: Option, diff --git a/feos-dft/src/python/solvation.rs b/feos-dft/src/python/solvation.rs index cc9b4d6a7..fc9cd6439 100644 --- a/feos-dft/src/python/solvation.rs +++ b/feos-dft/src/python/solvation.rs @@ -27,7 +27,6 @@ macro_rules! impl_solvation_profile { /// SolvationProfile /// #[pyclass(name = "SolvationProfile")] - #[pyo3(text_signature = "(bulk, n_grid, coordinates, sigma, epsilon_k, system_size=None, cutoff_radius=None, potential_cutoff=None)")] pub struct PySolvationProfile(SolvationProfile<$func>); impl_3d_profile!(PySolvationProfile, get_x, get_y, get_z); @@ -35,6 +34,7 @@ macro_rules! impl_solvation_profile { #[pymethods] impl PySolvationProfile { #[new] + #[pyo3(text_signature = "(bulk, n_grid, coordinates, sigma, epsilon_k, system_size=None, cutoff_radius=None, potential_cutoff=None)")] fn new( bulk: &PyState, n_grid: [usize; 3], diff --git a/feos-dft/src/python/solver.rs b/feos-dft/src/python/solver.rs index 2d61d5b34..b63a99af6 100644 --- a/feos-dft/src/python/solver.rs +++ b/feos-dft/src/python/solver.rs @@ -17,12 +17,12 @@ use quantity::python::PySIArray1; /// DFTSolver #[pyclass(name = "DFTSolver")] #[derive(Clone)] -#[pyo3(text_signature = "(verbosity=None)")] pub struct PyDFTSolver(pub DFTSolver); #[pymethods] impl PyDFTSolver { #[new] + #[pyo3(text_signature = "(verbosity=None)")] fn new(verbosity: Option) -> Self { Self(DFTSolver::new(verbosity)) } diff --git a/feos-dft/src/solver.rs b/feos-dft/src/solver.rs index a0418d3d4..9f96c2449 100644 --- a/feos-dft/src/solver.rs +++ b/feos-dft/src/solver.rs @@ -548,7 +548,7 @@ where for i in (0..=iter).rev() { y[i] = (gamma[i] - (i + 1..=iter).map(|k| h[(i, k)] * y[k]).sum::()) / h[(i, i)]; } - v.iter().zip(y.into_iter()).for_each(|(v, y)| x += &(y * v)); + v.iter().zip(y).for_each(|(v, y)| x += &(y * v)); Ok(x) } diff --git a/parameters/joback/README.md b/parameters/joback/README.md new file mode 100644 index 000000000..6e4721073 --- /dev/null +++ b/parameters/joback/README.md @@ -0,0 +1,10 @@ +# Joback Parameters + +This directory contains files with parameters for the Joback model for ideal gas heat capacities. +The files named according to the pattern `NameYear.json` correspond to published parameters. The corresponding publication is provided in the [`literature.bib`](literature.bib) file. + +## Group-Contribution Parameters + +|file|description|publication(s)| +|-|-|:-:| +[`joback1987.json`](joback1987.json) | GC segment parameters for homosegmented PC-SAFT including ideal gas parameters | [🔗](https://doi.org/10.1080/00986448708960487)| diff --git a/parameters/pcsaft/sauer2014_hetero_joback.json b/parameters/joback/joback1987.json similarity index 53% rename from parameters/pcsaft/sauer2014_hetero_joback.json rename to parameters/joback/joback1987.json index 2ddb5dd7e..5ebb68674 100644 --- a/parameters/pcsaft/sauer2014_hetero_joback.json +++ b/parameters/joback/joback1987.json @@ -2,367 +2,243 @@ { "identifier": "CH3", "model_record": { - "m": 0.77247, - "sigma": 3.6937, - "epsilon_k": 181.49 - }, - "molarweight": 15.0345, - "ideal_gas_record": { "a": 19.5, "b": -0.00808, "c": 0.000153, "d": -9.67e-08, "e": 0.0 - } + }, + "molarweight": 15.0345 }, { "identifier": "CH2", "model_record": { - "m": 0.7912, - "sigma": 3.0207, - "epsilon_k": 157.23 - }, - "molarweight": 14.02658, - "ideal_gas_record": { "a": -0.909, "b": 0.095, "c": -5.44e-05, "d": 1.19e-08, "e": 0.0 - } + }, + "molarweight": 14.02658 }, { "identifier": ">CH", "model_record": { - "m": 0.52235, - "sigma": 0.99912, - "epsilon_k": 269.84 - }, - "molarweight": 13.01854, - "ideal_gas_record": { "a": -23.0, "b": 0.204, "c": -0.000265, "d": 1.2e-07, "e": 0.0 - } + }, + "molarweight": 13.01854 }, { "identifier": ">C<", "model_record": { - "m": -0.70131, - "sigma": 0.5435, - "epsilon_k": 0.0 - }, - "molarweight": 12.0107, - "ideal_gas_record": { "a": -66.2, "b": 0.427, "c": -0.000641, "d": 3.01e-07, "e": 0.0 - } + }, + "molarweight": 12.0107 }, { "identifier": "=CH2", "model_record": { - "m": 0.70581, - "sigma": 3.163, - "epsilon_k": 171.34 - }, - "molarweight": 14.02658, - "ideal_gas_record": { "a": 23.6, "b": -0.0381, "c": 0.000172, "d": -1.03e-07, "e": 0.0 - } + }, + "molarweight": 14.02658 }, { "identifier": "=CH", "model_record": { - "m": 0.90182, - "sigma": 2.8864, - "epsilon_k": 158.9 - }, - "molarweight": 13.01854, - "ideal_gas_record": { "a": -8.0, "b": 0.105, "c": -9.63e-05, "d": 3.56e-08, "e": 0.0 - } + }, + "molarweight": 13.01854 }, { "identifier": "=C<", "model_record": { - "m": 0.98505, - "sigma": 2.245, - "epsilon_k": 146.86 - }, - "molarweight": 12.0107, - "ideal_gas_record": { "a": -28.0, "b": 0.208, "c": -0.000306, "d": 1.46e-07, "e": 0.0 - } + }, + "molarweight": 12.0107 }, { "identifier": "C≡CH", "model_record": { - "m": 1.1615, - "sigma": 3.3187, - "epsilon_k": 255.13 - }, - "molarweight": 25.02924, - "ideal_gas_record": { "a": 32.37, "b": -0.006999999999999999, "c": 0.00010267, "d": -6.641e-08, "e": 0.0 - } + }, + "molarweight": 25.02924 }, { "identifier": "CH2_hex", "model_record": { - "m": 0.8793, - "sigma": 2.9995, - "epsilon_k": 157.93 - }, - "molarweight": 14.02658, - "ideal_gas_record": { "a": -6.03, "b": 0.0854, "c": -8e-06, "d": -1.8e-08, "e": 0.0 - } + }, + "molarweight": 14.02658 }, { "identifier": "CH_hex", "model_record": { - "m": 0.42115, - "sigma": 1.3078, - "epsilon_k": 131.79 - }, - "molarweight": 13.01854, - "ideal_gas_record": { "a": -20.5, "b": 0.162, "c": -0.00016, "d": 6.24e-08, "e": 0.0 - } + }, + "molarweight": 13.01854 }, { "identifier": "CH2_pent", "model_record": { - "m": 0.90057, - "sigma": 3.0437, - "epsilon_k": 158.34 - }, - "molarweight": 14.02658, - "ideal_gas_record": { "a": -6.03, "b": 0.0854, "c": -8e-06, "d": -1.8e-08, "e": 0.0 - } + }, + "molarweight": 14.02658 }, { "identifier": "CH_pent", "model_record": { - "m": 0.69343, - "sigma": 1.2894, - "epsilon_k": 140.69 - }, - "molarweight": 13.01854, - "ideal_gas_record": { "a": -20.5, "b": 0.162, "c": -0.00016, "d": 6.24e-08, "e": 0.0 - } + }, + "molarweight": 13.01854 }, { "identifier": "CH_arom", "model_record": { - "m": 0.88259, - "sigma": 2.9475, - "epsilon_k": 156.51 - }, - "molarweight": 13.01854, - "ideal_gas_record": { "a": -2.14, "b": 0.0574, "c": -1.64e-06, "d": -1.59e-08, "e": 0.0 - } + }, + "molarweight": 13.01854 }, { "identifier": "C_arom", "model_record": { - "m": 0.77531, - "sigma": 1.6719, - "epsilon_k": 178.81 - }, - "molarweight": 12.0107, - "ideal_gas_record": { "a": -8.25, "b": 0.101, "c": -0.000142, "d": 6.78e-08, "e": 0.0 - } + }, + "molarweight": 12.0107 }, { "identifier": "CH=O", "model_record": { - "m": 1.1889, - "sigma": 3.2948, - "epsilon_k": 316.91, - "mu": 2.4126 - }, - "molarweight": 29.01754, - "ideal_gas_record": { "a": 30.9, "b": -0.0336, "c": 0.00016, "d": -9.88e-08, "e": 0.0 - } + }, + "molarweight": 29.01754 }, { "identifier": ">C=O", "model_record": { - "m": 1.1889, - "sigma": 3.1026, - "epsilon_k": 280.43, - "mu": 3.4167 - }, - "molarweight": 28.0097, - "ideal_gas_record": { "a": 6.45, "b": 0.067, "c": -3.57e-05, "d": 2.86e-09, "e": 0.0 - } + }, + "molarweight": 28.0097 }, { "identifier": "OCH3", "model_record": { - "m": 1.1907, - "sigma": 2.7795, - "epsilon_k": 284.91, - "mu": 0.0 - }, - "molarweight": 31.03322, - "ideal_gas_record": { "a": 45.0, "b": -0.07128000000000001, "c": 0.000264, "d": -1.515e-07, "e": 0.0 - } + }, + "molarweight": 31.03322 }, { "identifier": "OCH2", "model_record": { - "m": 1.1817, - "sigma": 3.009, - "epsilon_k": 203.11, - "mu": 2.6945 - }, - "molarweight": 30.02538, - "ideal_gas_record": { "a": 24.591, "b": 0.031799999999999995, "c": 5.66e-05, "d": -4.29e-08, "e": 0.0 - } + }, + "molarweight": 30.02538 }, { "identifier": "HCOO", "model_record": { - "m": 1.2789, - "sigma": 3.373, - "epsilon_k": 307.44, - "mu": 2.6808 - }, - "molarweight": 45.01654, - "ideal_gas_record": { "a": 24.1, "b": 0.0427, "c": 8.04e-05, "d": -6.87e-08, "e": 0.0 - } + }, + "molarweight": 45.01654 }, { "identifier": "COO", "model_record": { - "m": 1.2869, - "sigma": 3.0643, - "epsilon_k": 273.9, - "mu": 3.3428 - }, - "molarweight": 44.0087, - "ideal_gas_record": { "a": 24.5, "b": 0.0402, "c": 4.02e-05, "d": -4.52e-08, "e": 0.0 - } + }, + "molarweight": 44.0087 }, { "identifier": "OH", "model_record": { - "m": 1.0231, - "sigma": 2.7702, - "epsilon_k": 334.29, - "epsilon_k_ab": 2575.9, - "kappa_ab": 0.009583, - "na": 1.0, - "nb": 1.0 - }, - "molarweight": 17.00734, - "ideal_gas_record": { "a": 25.7, "b": -0.0691, "c": 0.000177, "d": -9.88e-08, "e": 0.0 - } + }, + "molarweight": 17.00734 }, { "identifier": "NH2", "model_record": { - "m": 0.82284, - "sigma": 3.1129, - "epsilon_k": 309.93, - "epsilon_k_ab": 1471.5, - "kappa_ab": 0.005769, - "na": 1.0, - "nb": 1.0 - }, - "molarweight": 16.02238, - "ideal_gas_record": { "a": 26.9, "b": -0.0412, "c": 0.000164, "d": -9.76e-08, "e": 0.0 - } + }, + "molarweight": 16.02238 } ] \ No newline at end of file diff --git a/parameters/joback/literature.bib b/parameters/joback/literature.bib new file mode 100644 index 000000000..7837baf35 --- /dev/null +++ b/parameters/joback/literature.bib @@ -0,0 +1,13 @@ +@article{Joback1987Jul, + author = {Joback, K. G. and Reid, R. C.}, + title = {{ESTIMATION OF PURE-COMPONENT PROPERTIES FROM GROUP-CONTRIBUTIONS}}, + journal = {Chem. Eng. Commun.}, + volume = {57}, + number = {1-6}, + pages = {233--243}, + year = {1987}, + month = jul, + issn = {0098-6445}, + publisher = {Taylor {\&} Francis}, + doi = {10.1080/00986448708960487} +} \ No newline at end of file diff --git a/parameters/pcsaft/README.md b/parameters/pcsaft/README.md index a9a9eb645..9370e54e1 100644 --- a/parameters/pcsaft/README.md +++ b/parameters/pcsaft/README.md @@ -1,4 +1,4 @@ -# Parameters +# PC-SAFT Parameters This directory contains files with parameters for PC-SAFT (including gc-PC-SAFT). The files named according to the pattern `NameYear.json` correspond to published parameters. The corresponding publication is provided in the [`literature.bib`](literature.bib) file. @@ -33,8 +33,6 @@ The files named according to the pattern `NameYear.json` correspond to published |file|description|publication(s)| |-|-|:-:| [`sauer2014_homo.json`](sauer2014_homo.json) | GC segment parameters for homosegmented PC-SAFT | [🔗](https://doi.org/10.1021/ie502203w) | -[`sauer2014_homo_joback.json`](sauer2014_homo.json) | GC segment parameters for homosegmented PC-SAFT including ideal gas parameters | [🔗](https://doi.org/10.1021/ie502203w) [🔗](https://doi.org/10.1080/00986448708960487)| [`sauer2014_hetero.json`](sauer2014_hetero.json) | GC segment parameters for heterosegmented PC-SAFT | [🔗](https://doi.org/10.1021/ie502203w) -[`sauer2014_hetero_joback.json`](sauer2014_hetero.json) | GC segment parameters for heterosegmented PC-SAFT including ideal gas parameters | [🔗](https://doi.org/10.1021/ie502203w) [🔗](https://doi.org/10.1080/00986448708960487) [`loetgeringlin2015_homo.json`](loetgeringlin2018.json) | GC segment parameters for homosegmented PC-SAFT including viscosity parameter | [🔗](https://doi.org/10.1021/acs.iecr.5b01698) diff --git a/parameters/pcsaft/sauer2014_homo_joback.json b/parameters/pcsaft/sauer2014_homo_joback.json deleted file mode 100644 index c56e8632b..000000000 --- a/parameters/pcsaft/sauer2014_homo_joback.json +++ /dev/null @@ -1,368 +0,0 @@ -[ - { - "identifier": "CH3", - "model_record": { - "m": 0.61198, - "sigma": 3.7202, - "epsilon_k": 229.9 - }, - "molarweight": 15.0345, - "ideal_gas_record": { - "a": 19.5, - "b": -0.00808, - "c": 0.000153, - "d": -9.67e-08, - "e": 0.0 - } - }, - { - "identifier": "CH2", - "model_record": { - "m": 0.45606, - "sigma": 3.89, - "epsilon_k": 239.01 - }, - "molarweight": 14.02658, - "ideal_gas_record": { - "a": -0.909, - "b": 0.095, - "c": -5.44e-05, - "d": 1.19e-08, - "e": 0.0 - } - }, - { - "identifier": ">CH", - "model_record": { - "m": 0.14304, - "sigma": 4.8597, - "epsilon_k": 347.64 - }, - "molarweight": 13.01854, - "ideal_gas_record": { - "a": -23.0, - "b": 0.204, - "c": -0.000265, - "d": 1.2e-07, - "e": 0.0 - } - }, - { - "identifier": ">C<", - "model_record": { - "m": -0.66997, - "sigma": -1.7878, - "epsilon_k": 107.68 - }, - "molarweight": 12.0107, - "ideal_gas_record": { - "a": -66.2, - "b": 0.427, - "c": -0.000641, - "d": 3.01e-07, - "e": 0.0 - } - }, - { - "identifier": "=CH2", - "model_record": { - "m": 0.36939, - "sigma": 4.0264, - "epsilon_k": 289.49 - }, - "molarweight": 14.02658, - "ideal_gas_record": { - "a": 23.6, - "b": -0.0381, - "c": 0.000172, - "d": -1.03e-07, - "e": 0.0 - } - }, - { - "identifier": "=CH", - "model_record": { - "m": 0.56361, - "sigma": 3.5519, - "epsilon_k": 216.69 - }, - "molarweight": 13.01854, - "ideal_gas_record": { - "a": -8.0, - "b": 0.105, - "c": -9.63e-05, - "d": 3.56e-08, - "e": 0.0 - } - }, - { - "identifier": "=C<", - "model_record": { - "m": 0.86367, - "sigma": 3.1815, - "epsilon_k": 156.31 - }, - "molarweight": 12.0107, - "ideal_gas_record": { - "a": -28.0, - "b": 0.208, - "c": -0.000306, - "d": 1.46e-07, - "e": 0.0 - } - }, - { - "identifier": "C≡CH", - "model_record": { - "m": 1.3279, - "sigma": 2.9421, - "epsilon_k": 223.05 - }, - "molarweight": 25.02924, - "ideal_gas_record": { - "a": 32.37, - "b": -0.006999999999999999, - "c": 0.00010267, - "d": -6.641e-08, - "e": 0.0 - } - }, - { - "identifier": "CH2_hex", - "model_record": { - "m": 0.39496, - "sigma": 3.9126, - "epsilon_k": 289.03 - }, - "molarweight": 14.02658, - "ideal_gas_record": { - "a": -6.03, - "b": 0.0854, - "c": -8e-06, - "d": -1.8e-08, - "e": 0.0 - } - }, - { - "identifier": "CH_hex", - "model_record": { - "m": 0.0288, - "sigma": 8.9779, - "epsilon_k": 1306.7 - }, - "molarweight": 13.01854, - "ideal_gas_record": { - "a": -20.5, - "b": 0.162, - "c": -0.00016, - "d": 6.24e-08, - "e": 0.0 - } - }, - { - "identifier": "CH2_pent", - "model_record": { - "m": 0.46742, - "sigma": 3.7272, - "epsilon_k": 267.16 - }, - "molarweight": 14.02658, - "ideal_gas_record": { - "a": -6.03, - "b": 0.0854, - "c": -8e-06, - "d": -1.8e-08, - "e": 0.0 - } - }, - { - "identifier": "CH_pent", - "model_record": { - "m": 0.03314, - "sigma": 7.719, - "epsilon_k": 1297.7 - }, - "molarweight": 13.01854, - "ideal_gas_record": { - "a": -20.5, - "b": 0.162, - "c": -0.00016, - "d": 6.24e-08, - "e": 0.0 - } - }, - { - "identifier": "CH_arom", - "model_record": { - "m": 0.42335, - "sigma": 3.727, - "epsilon_k": 274.41 - }, - "molarweight": 13.01854, - "ideal_gas_record": { - "a": -2.14, - "b": 0.0574, - "c": -1.64e-06, - "d": -1.59e-08, - "e": 0.0 - } - }, - { - "identifier": "C_arom", - "model_record": { - "m": 0.15371, - "sigma": 3.9622, - "epsilon_k": 527.2 - }, - "molarweight": 12.0107, - "ideal_gas_record": { - "a": -8.25, - "b": 0.101, - "c": -0.000142, - "d": 6.78e-08, - "e": 0.0 - } - }, - { - "identifier": "CH=O", - "model_record": { - "m": 1.5774, - "sigma": 2.8035, - "epsilon_k": 242.99, - "mu": 2.4556 - }, - "molarweight": 29.01754, - "ideal_gas_record": { - "a": 30.9, - "b": -0.0336, - "c": 0.00016, - "d": -9.88e-08, - "e": 0.0 - } - }, - { - "identifier": ">C=O", - "model_record": { - "m": 1.223, - "sigma": 2.8124, - "epsilon_k": 249.04, - "mu": 3.2432 - }, - "molarweight": 28.0097, - "ideal_gas_record": { - "a": 6.45, - "b": 0.067, - "c": -3.57e-05, - "d": 2.86e-09, - "e": 0.0 - } - }, - { - "identifier": "OCH3", - "model_record": { - "m": 1.6539, - "sigma": 3.0697, - "epsilon_k": 196.05, - "mu": 1.3866 - }, - "molarweight": 31.03322, - "ideal_gas_record": { - "a": 45.0, - "b": -0.07128000000000001, - "c": 0.000264, - "d": -1.515e-07, - "e": 0.0 - } - }, - { - "identifier": "OCH2", - "model_record": { - "m": 1.1349, - "sigma": 3.2037, - "epsilon_k": 187.13, - "mu": 2.744 - }, - "molarweight": 30.02538, - "ideal_gas_record": { - "a": 24.591, - "b": 0.031799999999999995, - "c": 5.66e-05, - "d": -4.29e-08, - "e": 0.0 - } - }, - { - "identifier": "HCOO", - "model_record": { - "m": 1.7525, - "sigma": 2.9043, - "epsilon_k": 229.63, - "mu": 2.7916 - }, - "molarweight": 45.01654, - "ideal_gas_record": { - "a": 24.1, - "b": 0.0427, - "c": 8.04e-05, - "d": -6.87e-08, - "e": 0.0 - } - }, - { - "identifier": "COO", - "model_record": { - "m": 1.5063, - "sigma": 2.8166, - "epsilon_k": 222.52, - "mu": 3.1652 - }, - "molarweight": 44.0087, - "ideal_gas_record": { - "a": 24.5, - "b": 0.0402, - "c": 4.02e-05, - "d": -4.52e-08, - "e": 0.0 - } - }, - { - "identifier": "OH", - "model_record": { - "m": 0.402, - "sigma": 3.2859, - "epsilon_k": 488.66, - "epsilon_k_ab": 2517.0, - "kappa_ab": 0.006825, - "na": 1.0, - "nb": 1.0 - }, - "molarweight": 17.00734, - "ideal_gas_record": { - "a": 25.7, - "b": -0.0691, - "c": 0.000177, - "d": -9.88e-08, - "e": 0.0 - } - }, - { - "identifier": "NH2", - "model_record": { - "m": 0.40558, - "sigma": 3.6456, - "epsilon_k": 467.59, - "epsilon_k_ab": 1064.6, - "kappa_ab": 0.026662, - "na": 1.0, - "nb": 1.0 - }, - "molarweight": 16.02238, - "ideal_gas_record": { - "a": 26.9, - "b": -0.0412, - "c": 0.000164, - "d": -9.76e-08, - "e": 0.0 - } - } -] \ No newline at end of file diff --git a/parameters/saftvrqmie/README.md b/parameters/saftvrqmie/README.md index 78ab5ca70..d7c3f48f9 100644 --- a/parameters/saftvrqmie/README.md +++ b/parameters/saftvrqmie/README.md @@ -1,4 +1,4 @@ -# Parameters +# SAFT-VRQ Mie Parameters This directory contains files with parameters for SAFT-VRQ Mie equation of state. The files named according to the pattern `NameYear.json` correspond to published parameters. The corresponding publication is provided in the [`literature.bib`](literature.bib) file. diff --git a/src/eos.rs b/src/eos.rs index f96ee7be7..9820df1e2 100644 --- a/src/eos.rs +++ b/src/eos.rs @@ -17,7 +17,7 @@ use feos_core::*; use feos_derive::{Components, IdealGas, Residual}; use ndarray::Array1; -/// Collection of different [EquationOfState] implementations. +/// Collection of different [Residual] implementations. /// /// Particularly relevant for situations in which generic types /// are undesirable (e.g. FFI). @@ -40,6 +40,10 @@ pub enum ResidualModel { UVTheory(UVTheory), } +/// Collection of different [IdealGas] implementations. +/// +/// Particularly relevant for situations in which generic types +/// are undesirable (e.g. FFI). #[derive(Components, IdealGas)] pub enum IdealGasModel { NoModel(usize), diff --git a/src/estimator/binary_vle.rs b/src/estimator/binary_vle.rs index b98261cc9..b3c9d39b2 100644 --- a/src/estimator/binary_vle.rs +++ b/src/estimator/binary_vle.rs @@ -3,11 +3,12 @@ use feos_core::si::{ MolarEnergy, Moles, Pressure, Quantity, Temperature, _Dimensionless, PASCAL, RGAS, }; use feos_core::{ - Contributions, DensityInitialization, PhaseDiagram, PhaseEquilibrium, Residual, State, TPSpec, + Contributions, DensityInitialization, PhaseDiagram, PhaseEquilibrium, Residual, State, TemperatureOrPressure, }; use itertools::izip; use ndarray::{arr1, s, Array1, ArrayView1, Axis}; +use std::fmt; use std::iter::FromIterator; use std::ops::Sub; use std::sync::Arc; @@ -173,7 +174,10 @@ impl DataSet for BinaryVlePressure { ), })?; - Ok((vle.vapor().pressure(Contributions::Total) / self.unit).into_value()) + Ok(vle + .vapor() + .pressure(Contributions::Total) + .convert_into(self.unit)) }) .collect() } @@ -227,10 +231,12 @@ impl BinaryPhaseDiagram { } } -impl DataSet - for BinaryPhaseDiagram +impl< + TP: TemperatureOrPressure + Sync + Send + fmt::Display, + U: Copy + Sync + Send, + E: Residual, + > DataSet for BinaryPhaseDiagram where - TPSpec: From, Quantity, U>: FromIterator, U: Sub, { @@ -243,10 +249,7 @@ where } fn input_str(&self) -> Vec<&str> { - let mut vec = match TPSpec::from(self.specification) { - TPSpec::Temperature(_) => vec!["temperature", "pressure"], - TPSpec::Pressure(_) => vec!["pressure", "temperature"], - }; + let mut vec = vec![TP::IDENTIFIER, TP::Other::IDENTIFIER]; if self.liquid_molefracs.is_some() { vec.push("liquid molefracs") } @@ -271,14 +274,6 @@ where let x_vap = dia.vapor().molefracs(); let x_vec_vap = x_vap.index_axis(Axis(1), 0); let tp_vec = dia.vapor().iter().map(|s| TP::from_state(s)).collect(); - // let tp_vec = if self - // .temperature_or_pressure - // .has_unit(&SIUnit::reference_temperature()) - // { - // dia.vapor().temperature() - // } else { - // dia.vapor().pressure() - // }; for (x_exp, x_vec) in [ (&self.liquid_molefracs, x_vec_liq), (&self.vapor_molefracs, x_vec_vap), diff --git a/src/estimator/liquid_density.rs b/src/estimator/liquid_density.rs index 2282c86e8..156c37459 100644 --- a/src/estimator/liquid_density.rs +++ b/src/estimator/liquid_density.rs @@ -63,7 +63,7 @@ impl DataSet for LiquidDensity { Ok(self .temperature .into_iter() - .zip(self.pressure.into_iter()) + .zip(&self.pressure) .map(|(t, p)| { let state = State::new_npt(eos, t, p, &moles, DensityInitialization::Liquid); if let Ok(s) = state { diff --git a/src/estimator/python.rs b/src/estimator/python.rs index 58dcda6f0..01a398a26 100644 --- a/src/estimator/python.rs +++ b/src/estimator/python.rs @@ -485,12 +485,12 @@ macro_rules! impl_estimator { /// ------- /// Estimator #[pyclass(name = "Estimator")] - #[pyo3(text_signature = "(data, weights, losses)")] pub struct PyEstimator(Estimator<$eos>); #[pymethods] impl PyEstimator { #[new] + #[pyo3(text_signature = "(data, weights, losses)")] fn new(data: Vec, weights: Vec, losses: Vec) -> Self { Self(Estimator::new( data.iter().map(|d| d.0.clone()).collect(), @@ -658,7 +658,7 @@ macro_rules! impl_estimator_entropy_scaling { pressure: &PySIArray1, phase: Option>, ) -> PyResult { - Ok(Self(Arc::new(crate::estimator::Viscosity::new( + Ok(Self(Arc::new($crate::estimator::Viscosity::new( target.clone().try_into()?, temperature.clone().try_into()?, pressure.clone().try_into()?, @@ -691,7 +691,7 @@ macro_rules! impl_estimator_entropy_scaling { pressure: &PySIArray1, phase: Option>, ) -> PyResult { - Ok(Self(Arc::new(crate::estimator::ThermalConductivity::new( + Ok(Self(Arc::new($crate::estimator::ThermalConductivity::new( target.clone().try_into()?, temperature.clone().try_into()?, pressure.clone().try_into()?, diff --git a/src/gc_pcsaft/dft/dispersion.rs b/src/gc_pcsaft/dft/dispersion.rs index f9baea129..dfbeac2f4 100644 --- a/src/gc_pcsaft/dft/dispersion.rs +++ b/src/gc_pcsaft/dft/dispersion.rs @@ -52,7 +52,7 @@ impl + Copy + ScalarOperand> FunctionalContributionDual // packing fraction let eta = density .outer_iter() - .zip((&d * &d * &d * &p.m * FRAC_PI_6).into_iter()) + .zip(&d * &d * &d * &p.m * FRAC_PI_6) .map(|(rho, d3m)| &rho * d3m) .reduce(|a, b| a + b) .unwrap(); diff --git a/src/gc_pcsaft/eos/parameter.rs b/src/gc_pcsaft/eos/parameter.rs index a6725dfe9..9ff3e442c 100644 --- a/src/gc_pcsaft/eos/parameter.rs +++ b/src/gc_pcsaft/eos/parameter.rs @@ -13,6 +13,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt::Write; +/// [ChemicalRecord] that is used as input for the gc-PC-SAFT equation of state. #[derive(Clone)] pub struct GcPcSaftChemicalRecord { pub identifier: Identifier, diff --git a/src/gc_pcsaft/python/mod.rs b/src/gc_pcsaft/python/mod.rs index 371b6f42d..437226f69 100644 --- a/src/gc_pcsaft/python/mod.rs +++ b/src/gc_pcsaft/python/mod.rs @@ -19,14 +19,16 @@ use std::sync::Arc; mod micelles; #[pyclass(name = "GcPcSaftRecord")] -#[pyo3(text_signature = "(m, sigma, epsilon_k, mu=None, association_record=None, psi_dft=None)")] #[derive(Clone)] pub struct PyGcPcSaftRecord(GcPcSaftRecord); #[pymethods] impl PyGcPcSaftRecord { - #[pyo3(signature = (m, sigma, epsilon_k, mu=None, association_record=None, psi_dft=None))] #[new] + #[pyo3( + text_signature = "(m, sigma, epsilon_k, mu=None, association_record=None, psi_dft=None)", + signature = (m, sigma, epsilon_k, mu=None, association_record=None, psi_dft=None) + )] fn new( m: f64, sigma: f64, @@ -80,9 +82,6 @@ impl_json_handling!(PyGcPcSaftRecord); impl_segment_record!(GcPcSaftRecord, PyGcPcSaftRecord); #[pyclass(name = "GcPcSaftEosParameters")] -#[pyo3( - text_signature = "(pure_records, segmentbinary_records=None, substances=None, search_option='Name')" -)] #[derive(Clone)] pub struct PyGcPcSaftEosParameters(pub Arc); @@ -105,9 +104,6 @@ impl PyGcPcSaftEosParameters { #[cfg(feature = "dft")] #[pyclass(name = "GcPcSaftFunctionalParameters")] -#[pyo3( - text_signature = "(pure_records, segmentbinary_records=None, substances=None, search_option)" -)] #[derive(Clone)] pub struct PyGcPcSaftFunctionalParameters(pub Arc); diff --git a/src/hard_sphere/mod.rs b/src/hard_sphere/mod.rs index 51a9da45d..62b494795 100644 --- a/src/hard_sphere/mod.rs +++ b/src/hard_sphere/mod.rs @@ -28,7 +28,7 @@ pub enum MonomerShape<'a, D> { /// Properties of (generalized) hard sphere systems. pub trait HardSphereProperties { /// The [MonomerShape] used in the model. - fn monomer_shape>(&self, temperature: D) -> MonomerShape; + fn monomer_shape + Copy>(&self, temperature: D) -> MonomerShape; /// The temperature dependent hard-sphere diameters of every segment. fn hs_diameter + Copy>(&self, temperature: D) -> Array1; @@ -43,7 +43,7 @@ pub trait HardSphereProperties { } /// The geometry coefficients $C_{k,\alpha}$ for every segment. - fn geometry_coefficients>(&self, temperature: D) -> [Array1; 4] { + fn geometry_coefficients + Copy>(&self, temperature: D) -> [Array1; 4] { match self.monomer_shape(temperature) { MonomerShape::Spherical(n) => { let m = Array1::ones(n); diff --git a/src/lib.rs b/src/lib.rs index ddb0e7cba..97b89d804 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,13 @@ //! //! # Example: critical point of a pure substance using PC-SAFT //! -//! ```ignore +#![cfg_attr(not(feature = "pcsaft"), doc = "```ignore")] +#![cfg_attr(feature = "pcsaft", doc = "```")] //! # use feos_core::EosError; //! use feos::pcsaft::{PcSaft, PcSaftParameters}; //! use feos_core::parameter::{IdentifierOption, Parameter}; //! use feos_core::{Contributions, State}; -//! use quantity::si::KELVIN; +//! use feos_core::si::KELVIN; //! use std::sync::Arc; //! //! // Read parameters from json file. @@ -33,7 +34,6 @@ #![warn(clippy::all)] #![allow(clippy::too_many_arguments)] -#![allow(deprecated)] #[cfg(feature = "dft")] mod dft; diff --git a/src/pcsaft/dft/dispersion.rs b/src/pcsaft/dft/dispersion.rs index f3d7c7181..159199875 100644 --- a/src/pcsaft/dft/dispersion.rs +++ b/src/pcsaft/dft/dispersion.rs @@ -66,7 +66,7 @@ impl + Copy + ScalarOperand> FunctionalContributionDual // packing fraction let eta = density .outer_iter() - .zip((&r * &r * &r * &p.m * 4.0 * FRAC_PI_3).into_iter()) + .zip(&r * &r * &r * &p.m * 4.0 * FRAC_PI_3) .fold( Array::zeros(density.raw_dim().remove_axis(Axis(0))), |acc: Array1, (rho, r3m)| acc + &rho * r3m, diff --git a/src/pcsaft/dft/polar.rs b/src/pcsaft/dft/polar.rs index efb20adf7..16b0b4c10 100644 --- a/src/pcsaft/dft/polar.rs +++ b/src/pcsaft/dft/polar.rs @@ -19,7 +19,7 @@ pub(super) fn calculate_helmholtz_energy_density_polar + Copy + // packing fraction let eta = density .outer_iter() - .zip((&r * &r * &r * ¶meters.m * 4.0 * FRAC_PI_3).into_iter()) + .zip(&r * &r * &r * ¶meters.m * 4.0 * FRAC_PI_3) .fold( Array::zeros(density.raw_dim().remove_axis(Axis(0))), |acc: Array1, (rho, r3m)| acc + &rho * r3m, diff --git a/src/pcsaft/eos/mod.rs b/src/pcsaft/eos/mod.rs index 86af89575..d4da753a8 100644 --- a/src/pcsaft/eos/mod.rs +++ b/src/pcsaft/eos/mod.rs @@ -150,7 +150,7 @@ fn chapman_enskog_thermal_conductivity( epsilon_k: f64, ) -> ThermalConductivity { let t = temperature.to_reduced(); - 0.083235 * (t * m / (molarweight / (GRAM / MOL)).into_value()).sqrt() + 0.083235 * (t * m / molarweight.convert_into(GRAM / MOL)).sqrt() / sigma.powi(2) / omega22(t / epsilon_k) * WATT diff --git a/src/pcsaft/python.rs b/src/pcsaft/python.rs index cb492c64b..a65efaa71 100644 --- a/src/pcsaft/python.rs +++ b/src/pcsaft/python.rs @@ -43,15 +43,15 @@ use std::sync::Arc; /// thermal_conductivity : List[float], optional /// Entropy-scaling parameters for thermal_conductivity. Defaults to `None`. #[pyclass(name = "PcSaftRecord")] -#[pyo3( - text_signature = "(m, sigma, epsilon_k, mu=None, q=None, kappa_ab=None, epsilon_k_ab=None, na=None, nb=None, viscosity=None, diffusion=None, thermal_conductivity=None)" -)] #[derive(Clone)] pub struct PyPcSaftRecord(PcSaftRecord); #[pymethods] impl PyPcSaftRecord { #[new] + #[pyo3( + text_signature = "(m, sigma, epsilon_k, mu=None, q=None, kappa_ab=None, epsilon_k_ab=None, na=None, nb=None, nc=None, viscosity=None, diffusion=None, thermal_conductivity=None)" + )] fn new( m: f64, sigma: f64, diff --git a/src/pets/dft/dispersion.rs b/src/pets/dft/dispersion.rs index 89e556aee..e1e2072ad 100644 --- a/src/pets/dft/dispersion.rs +++ b/src/pets/dft/dispersion.rs @@ -65,7 +65,7 @@ impl + Copy + ScalarOperand> FunctionalContributionDual // packing fraction let eta = density .outer_iter() - .zip((&r * &r * &r * 4.0 * FRAC_PI_3).into_iter()) + .zip(&r * &r * &r * 4.0 * FRAC_PI_3) .fold( Array::zeros(density.raw_dim().remove_axis(Axis(0))), |acc: Array1, (rho, r3)| acc + &rho * r3, diff --git a/src/pets/python.rs b/src/pets/python.rs index da7aa216a..e10efb3d2 100644 --- a/src/pets/python.rs +++ b/src/pets/python.rs @@ -10,15 +10,15 @@ use std::sync::Arc; /// Create a set of PeTS parameters from records. #[pyclass(name = "PetsRecord")] -#[pyo3( - text_signature = "(sigma, epsilon_k, viscosity=None, diffusion=None, thermal_conductivity=None)" -)] #[derive(Clone)] pub struct PyPetsRecord(PetsRecord); #[pymethods] impl PyPetsRecord { #[new] + #[pyo3( + text_signature = "(sigma, epsilon_k, viscosity=None, diffusion=None, thermal_conductivity=None)" + )] fn new( sigma: f64, epsilon_k: f64, @@ -69,31 +69,11 @@ impl_json_handling!(PyPetsRecord); impl_pure_record!(PetsRecord, PyPetsRecord); #[pyclass(name = "PetsBinaryRecord")] -#[pyo3( - text_signature = "(pure_records, binary_records=None, substances=None, search_option='Name')" -)] #[derive(Clone)] pub struct PyPetsBinaryRecord(PetsBinaryRecord); impl_binary_record!(PetsBinaryRecord, PyPetsBinaryRecord); -/// Create a set of PeTS parameters from records. -/// -/// Parameters -/// ---------- -/// pure_records : List[PureRecord] -/// pure substance records. -/// binary_records : List[BinarySubstanceRecord], optional -/// binary PeTS parameter records -/// substances : List[str], optional -/// The substances to use. Filters substances from `pure_records` according to -/// `search_option`. -/// When not provided, all entries of `pure_records` are used. -/// search_option : {'Name', 'Cas', 'Inchi', 'IupacName', 'Formula', 'Smiles'}, optional, defaults to 'Name'. -/// Identifier that is used to search substance. #[pyclass(name = "PetsParameters")] -#[pyo3( - text_signature = "(pure_records, binary_records=None, substances=None, search_option='Name')" -)] #[derive(Clone)] pub struct PyPetsParameters(pub Arc); @@ -135,7 +115,7 @@ impl PyPetsParameters { ) -> PyResult { // Check if all inputs have the same length let n = sigma.len(); - let input_length = vec![ + let input_length = [ Some(sigma.len()), Some(epsilon_k.len()), k_ij.as_ref().map(|v| v.shape()[0]), @@ -145,8 +125,8 @@ impl PyPetsParameters { diffusion.as_ref().map(|v| v.len()), thermal_conductivity.as_ref().map(|v| v.len()), ] - .iter() - .filter_map(|&v| v) + .into_iter() + .flatten() .all(|v| v == n); if !input_length { diff --git a/src/saftvrqmie/eos/mod.rs b/src/saftvrqmie/eos/mod.rs index ead65bbe2..998b182b8 100644 --- a/src/saftvrqmie/eos/mod.rs +++ b/src/saftvrqmie/eos/mod.rs @@ -148,7 +148,7 @@ fn chapman_enskog_thermal_conductivity( epsilon_k: f64, ) -> ThermalConductivity { let t = temperature.to_reduced(); - 0.083235 * (t * m / (molarweight / (GRAM / MOL)).into_value()).sqrt() + 0.083235 * (t * m / molarweight.convert_into(GRAM / MOL)).sqrt() / sigma.powi(2) / omega22(t / epsilon_k) * WATT diff --git a/src/saftvrqmie/parameters.rs b/src/saftvrqmie/parameters.rs index 8bdaa02ed..28ab4d0db 100644 --- a/src/saftvrqmie/parameters.rs +++ b/src/saftvrqmie/parameters.rs @@ -68,9 +68,10 @@ impl SaftVRQMieRecord { thermal_conductivity: Option<[f64; 4]>, ) -> Result { if m != 1.0 { - return Err(ParameterError::IncompatibleParameters(format!( + return Err(ParameterError::IncompatibleParameters( "Segment number `m` is not one. Chain-contributions are currently not supported." - ))); + .to_string(), + )); } Ok(SaftVRQMieRecord { m, diff --git a/src/saftvrqmie/python.rs b/src/saftvrqmie/python.rs index 0925f03d4..6da5c2bd7 100644 --- a/src/saftvrqmie/python.rs +++ b/src/saftvrqmie/python.rs @@ -42,15 +42,15 @@ use std::sync::Arc; /// thermal_conductivity : List[float], optional /// Entropy-scaling parameters for thermal_conductivity. Defaults to `None`. #[pyclass(name = "SaftVRQMieRecord")] -#[pyo3( - text_signature = "(m, sigma, epsilon_k, lr, la, fh, viscosity=None, diffusion=None, thermal_conductivity=None)" -)] #[derive(Clone)] pub struct PySaftVRQMieRecord(SaftVRQMieRecord); #[pymethods] impl PySaftVRQMieRecord { #[new] + #[pyo3( + text_signature = "(m, sigma, epsilon_k, lr, la, fh, viscosity=None, diffusion=None, thermal_conductivity=None)" + )] fn new( m: f64, sigma: f64, @@ -120,15 +120,15 @@ impl PySaftVRQMieRecord { } } -/// Create a set of Saft-VRQ Mie parameters from records. +/// Create a binary record from k_ij and l_ij values. #[pyclass(name = "SaftVRQMieBinaryRecord")] -#[pyo3(text_signature = "(k_ij, l_ij)")] #[derive(Clone)] pub struct PySaftVRQMieBinaryRecord(SaftVRQMieBinaryRecord); #[pymethods] impl PySaftVRQMieBinaryRecord { #[new] + #[pyo3(text_signature = "(k_ij, l_ij)")] fn new(k_ij: f64, l_ij: f64) -> Self { Self(SaftVRQMieBinaryRecord { k_ij, l_ij }) } @@ -154,28 +154,7 @@ impl PySaftVRQMieBinaryRecord { } } -/// Create a set of SAFT-VRQ Mie parameters from records. -/// -/// Parameters -/// ---------- -/// pure_records : List[PureRecord] -/// pure substance records. -/// binary_records : List[BinaryRecord], optional -/// binary saft parameter records -/// substances : List[str], optional -/// The substances to use. Filters substances from `pure_records` according to -/// `search_option`. -/// When not provided, all entries of `pure_records` are used. -/// search_option : {'Name', 'Cas', 'Inchi', 'IupacName', 'Formula', 'Smiles'}, optional, defaults to 'Name'. -/// Identifier that is used to search substance. -/// -/// Returns -/// ------- -/// SaftVRQMieParameters #[pyclass(name = "SaftVRQMieParameters")] -#[pyo3( - text_signature = "(pure_records, binary_records=None, substances=None, search_option='Name')" -)] #[derive(Clone)] pub struct PySaftVRQMieParameters(pub Arc); diff --git a/src/uvtheory/mod.rs b/src/uvtheory/mod.rs index f24a800a4..d42a73887 100644 --- a/src/uvtheory/mod.rs +++ b/src/uvtheory/mod.rs @@ -6,61 +6,65 @@ //! //! [van Westen et al. (2021)](https://doi.org/10.1063/5.0073572): utilizing second virial coeffients and Barker-Henderson or Weeks-Chandler-Andersen perturbation. //! -//! ```ignore +#![cfg_attr(not(feature = "uvtheory"), doc = "```ignore")] +#![cfg_attr(feature = "uvtheory", doc = "```")] //! # use feos_core::EosError; //! use feos::uvtheory::{Perturbation, UVTheory, UVTheoryOptions, UVParameters, VirialOrder}; //! use std::sync::Arc; //! //! let parameters = Arc::new( -//! UVParameters::new_simple(24.0, 7.0, 3.0, 150.0) +//! UVParameters::new_simple(24.0, 7.0, 3.0, 150.0)? //! ); //! //! let default_options = UVTheoryOptions { -//! max_eta = 0.5, -//! perturbation = Perturbation::WeeksChandlerAndersen, -//! virial_order = VirialOrder::Second +//! max_eta: 0.5, +//! perturbation: Perturbation::WeeksChandlerAndersen, +//! virial_order: VirialOrder::Second //! }; //! // Define equation of state. -//! let uv_wca = Arc::new(UVTheory::new(parameters)); +//! let uv_wca = Arc::new(UVTheory::new(parameters.clone())); //! // this is identical to above //! let uv_wca = Arc::new( -//! UVTheory::with_options(parameters, default_options) +//! UVTheory::with_options(parameters.clone(), default_options) //! ); //! //! // use Barker-Henderson perturbation //! let options = UVTheoryOptions { -//! max_eta = 0.5, -//! perturbation = Perturbation::BarkerHenderson, -//! virial_order = VirialOrder::Second +//! max_eta: 0.5, +//! perturbation: Perturbation::BarkerHenderson, +//! virial_order: VirialOrder::Second //! }; //! let uv_bh = Arc::new( //! UVTheory::with_options(parameters, options) //! ); +//! # Ok::<(), EosError>(()) //! ``` //! //! ## uv-B3-theory //! //! - utilizing third virial coefficients for pure fluids with attractive exponent of 6 and Weeks-Chandler-Andersen perturbation. Manuscript submitted. //! -//! ```ignore +#![cfg_attr(not(feature = "uvtheory"), doc = "```ignore")] +#![cfg_attr(feature = "uvtheory", doc = "```")] //! # use feos_core::EosError; //! use feos::uvtheory::{Perturbation, UVTheory, UVTheoryOptions, UVParameters, VirialOrder}; //! use std::sync::Arc; //! //! let parameters = Arc::new( -//! UVParameters::new_simple(24.0, 6.0, 3.0, 150.0) +//! UVParameters::new_simple(24.0, 6.0, 3.0, 150.0)? //! ); //! //! // use uv-B3-theory //! let options = UVTheoryOptions { -//! max_eta = 0.5, -//! perturbation = Perturbation::WeeksChandlerAndersen, -//! virial_order = VirialOrder::Third +//! max_eta: 0.5, +//! perturbation: Perturbation::WeeksChandlerAndersen, +//! virial_order: VirialOrder::Third //! }; //! // Define equation of state. //! let uv_b3 = Arc::new( //! UVTheory::with_options(parameters, options) //! ); +//! # Ok::<(), EosError>(()) //! ``` mod eos; mod parameters; diff --git a/src/uvtheory/python.rs b/src/uvtheory/python.rs index 5aea76bd2..00d6d71c8 100644 --- a/src/uvtheory/python.rs +++ b/src/uvtheory/python.rs @@ -18,13 +18,13 @@ struct PyNoRecord(NoRecord); /// Create a set of UV Theory parameters from records. #[pyclass(name = "UVRecord")] -#[pyo3(text_signature = "(rep, att, sigma, epsilon_k)")] #[derive(Clone)] pub struct PyUVRecord(UVRecord); #[pymethods] impl PyUVRecord { #[new] + #[pyo3(text_signature = "(rep, att, sigma, epsilon_k)")] fn new(rep: f64, att: f64, sigma: f64, epsilon_k: f64) -> Self { Self(UVRecord::new(rep, att, sigma, epsilon_k)) } @@ -41,22 +41,7 @@ impl_json_handling!(PyUVRecord); pub struct PyUVBinaryRecord(UVBinaryRecord); impl_binary_record!(UVBinaryRecord, PyUVBinaryRecord); -/// Create a set of UV Theory parameters from records. -/// -/// Parameters -/// ---------- -/// pure_records : List[PureRecord] -/// pure substance records. -/// binary_records : List[BinarySubstanceRecord], optional -/// binary parameter records -/// substances : List[str], optional -/// The substances to use. Filters substances from `pure_records` according to -/// `search_option`. -/// When not provided, all entries of `pure_records` are used. -/// search_option : IdentifierOption, optional, defaults to IdentifierOption.Name -/// Identifier that is used to search binary records. #[pyclass(name = "UVParameters")] -#[pyo3(text_signature = "(pure_records, binary_records, substances, search_option)")] #[derive(Clone)] pub struct PyUVParameters(pub Arc);