From b60f41df58561b5639ca73d4a30c2356fff00a01 Mon Sep 17 00:00:00 2001 From: Gernot Bauer Date: Tue, 13 Dec 2022 12:47:25 +0100 Subject: [PATCH 1/4] Add critical_temperature to `VaporPressure::new` and Python constructor. Add estimator module to documentation --- CHANGELOG.md | 2 ++ docs/api/eos.md | 16 +++++++++++++++- src/estimator/python.rs | 17 +++++++++++++++-- src/estimator/vapor_pressure.rs | 18 +++++++++++------- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2236aba7e..680bb7775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Added SAFT-VRQ Mie equation of state and Helmholtz energy functional for first order Feynman-Hibbs corrected Mie fluids. [#79](https://github.com/feos-org/feos/pull/79) +Added `estimator` module to documentation. [#86](https://github.com/feos-org/feos/pull/86) ### Changed - Export `EosVariant` and `FunctionalVariant` directly in the crate root instead of their own modules. [#62](https://github.com/feos-org/feos/pull/62) +- Changed constructors `VaporPressure::new` and `DataSet.vapor_pressure` (Python) to take a new optional argument `critical_temperature`. [#86](https://github.com/feos-org/feos/pull/86) ## [0.3.0] - 2022-09-14 - Major restructuring of the entire `feos` project. All individual models are reunited in the `feos` crate. `feos-core` and `feos-dft` still live as individual crates within the `feos` workspace. diff --git a/docs/api/eos.md b/docs/api/eos.md index ccf4bd0fe..526ef5887 100644 --- a/docs/api/eos.md +++ b/docs/api/eos.md @@ -34,4 +34,18 @@ The `State` and `PhaseEquilibrium` objects are used to define thermodynamic cond State PhaseEquilibrium PhaseDiagram -``` \ No newline at end of file +``` + +## Estimator + +```{eval-rst} +.. currentmodule:: feos.eos.estimator + +.. autosummary:: + :toctree: generated/ + + DataSet + Loss + Estimator + Phase +``` diff --git a/src/estimator/python.rs b/src/estimator/python.rs index 4a88e69ef..b790c23df 100644 --- a/src/estimator/python.rs +++ b/src/estimator/python.rs @@ -11,6 +11,7 @@ impl From for PyErr { #[macro_export] macro_rules! impl_estimator { ($eos:ty, $py_eos:ty) => { + /// Loss function that is applied to the residuum to calculate costs. #[pyclass(name = "Loss")] #[derive(Clone)] pub struct PyLoss(Loss); @@ -221,6 +222,10 @@ macro_rules! impl_estimator { /// Use Antoine type equation to extrapolate vapor /// pressure if experimental data is above critial /// point of model. Defaults to False. + /// critical_temperature : SINumber, optional + /// Estimate of the critical temperature used as initial + /// value for critical point calculation. Defaults to None. + /// For additional information, see note. /// max_iter : int, optional /// The maximum number of iterations for critical point /// and VLE algorithms. @@ -234,12 +239,19 @@ macro_rules! impl_estimator { /// Returns /// ------- /// ``DataSet`` + /// + /// Note + /// ---- + /// If no critical temperature is provided, the maximum of the `temperature` input + /// is used. If that fails, the default temperatures of the critical point routine + /// are used. #[staticmethod] - #[pyo3(text_signature = "(target, temperature, extrapolate)")] + #[pyo3(text_signature = "(target, temperature, extrapolate, critical_temperature=None, max_iter=None, verbosity=None)")] fn vapor_pressure( target: &PySIArray1, temperature: &PySIArray1, extrapolate: Option, + critical_temperature: Option<&PySINumber>, max_iter: Option, tol: Option, verbosity: Option, @@ -248,6 +260,7 @@ macro_rules! impl_estimator { target.clone().into(), temperature.clone().into(), extrapolate.unwrap_or(false), + critical_temperature.and_then(|tc| Some(tc.clone().into())), Some((max_iter, tol, verbosity).into()), )?))) } @@ -439,7 +452,7 @@ macro_rules! impl_estimator { PySIArray1::from(self.0.target().clone()) } - /// Return `target` as ``SIArray1``. + /// Return number of stored data points. #[getter] fn get_datapoints(&self) -> usize { self.0.datapoints() diff --git a/src/estimator/vapor_pressure.rs b/src/estimator/vapor_pressure.rs index 69707a82f..e9ecd5d92 100644 --- a/src/estimator/vapor_pressure.rs +++ b/src/estimator/vapor_pressure.rs @@ -29,15 +29,18 @@ impl VaporPressure { target: QuantityArray1, temperature: QuantityArray1, extrapolate: bool, + critical_temperature: Option>, solver_options: Option, ) -> Result { let datapoints = target.len(); - let max_temperature = temperature - .to_reduced(U::reference_temperature())? - .into_iter() - .reduce(|a, b| a.max(b)) - .unwrap() - * U::reference_temperature(); + let max_temperature = critical_temperature.unwrap_or( + temperature + .to_reduced(U::reference_temperature())? + .into_iter() + .reduce(|a, b| a.max(b)) + .unwrap() + * U::reference_temperature(), + ); Ok(Self { target, temperature, @@ -72,7 +75,8 @@ impl DataSet for VaporPressure { QuantityScalar: std::fmt::Display + std::fmt::LowerExp, { let critical_point = - State::critical_point(eos, None, Some(self.max_temperature), self.solver_options)?; + State::critical_point(eos, None, Some(self.max_temperature), self.solver_options) + .or_else(|_| State::critical_point(eos, None, None, self.solver_options))?; let tc = critical_point.temperature; let pc = critical_point.pressure(Contributions::Total); From fdebf40a9d7657912300a260660eacfae4fd51fe Mon Sep 17 00:00:00 2001 From: Gernot Bauer Date: Tue, 13 Dec 2022 13:04:26 +0100 Subject: [PATCH 2/4] improvements to documentation --- docs/api/eos.md | 12 +++++++-- src/estimator/python.rs | 56 ++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/docs/api/eos.md b/docs/api/eos.md index 526ef5887..e524101c7 100644 --- a/docs/api/eos.md +++ b/docs/api/eos.md @@ -3,6 +3,8 @@ The `eos` module contains the `EquationOfState` object that contains all implemented equations of state. The `State` and `PhaseEquilibrium` objects are used to define thermodynamic conditions and -- once created -- can be used to compute properties. +If you want to adjust parameters of a model to experimental data you can use classes and utilities from the `estimator` module. + ## `EquationOfState` ```{eval-rst} @@ -36,7 +38,13 @@ The `State` and `PhaseEquilibrium` objects are used to define thermodynamic cond PhaseDiagram ``` -## Estimator +## The `estimator` module + +### Import + +```python +from feos.eos.estimator import Estimator, DataSet, Loss, Phase +``` ```{eval-rst} .. currentmodule:: feos.eos.estimator @@ -44,8 +52,8 @@ The `State` and `PhaseEquilibrium` objects are used to define thermodynamic cond .. autosummary:: :toctree: generated/ + Estimator DataSet Loss - Estimator Phase ``` diff --git a/src/estimator/python.rs b/src/estimator/python.rs index b790c23df..706d3180f 100644 --- a/src/estimator/python.rs +++ b/src/estimator/python.rs @@ -11,7 +11,8 @@ impl From for PyErr { #[macro_export] macro_rules! impl_estimator { ($eos:ty, $py_eos:ty) => { - /// Loss function that is applied to the residuum to calculate costs. + /// Loss function that is applied to the residuals to + /// weight to in- and outliers. #[pyclass(name = "Loss")] #[derive(Clone)] pub struct PyLoss(Loss); @@ -122,20 +123,26 @@ macro_rules! impl_estimator { impl PyDataSet { /// Compute the cost function for each input value. /// - /// The cost function that is used depends on the - /// property. See the class constructors to learn - /// about the cost functions of the properties. - /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. + /// loss : Loss + /// The loss function that is applied to residuals + /// to distinguish between in- and outliers. /// /// Returns /// ------- /// numpy.ndarray[Float] /// The cost function evaluated for each experimental data point. - #[pyo3(text_signature = "($self, eos)")] + /// + /// Note + /// ---- + /// The cost function that is used depends on the + /// property. For most properties it is the absolute relative difference. + /// See the constructors of the respective properties + /// to learn about the cost functions that are used. + #[pyo3(text_signature = "($self, eos, loss)")] fn cost<'py>( &self, eos: &$py_eos, @@ -150,18 +157,12 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns /// ------- /// SIArray1 - /// - /// See also - /// -------- - /// eos_python.saft.estimator.DataSet.vapor_pressure : ``DataSet`` for vapor pressure. - /// eos_python.saft.estimator.DataSet.liquid_density : ``DataSet`` for liquid density. - /// eos_python.saft.estimator.DataSet.equilibrium_liquid_density : ``DataSet`` for liquid density at vapor liquid equilibrium. #[pyo3(text_signature = "($self, eos)")] fn predict(&self, eos: &$py_eos) -> PyResult { Ok(self.0.predict(&eos.0)?.into()) @@ -176,7 +177,7 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns @@ -199,7 +200,7 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns @@ -496,15 +497,9 @@ macro_rules! impl_estimator { /// Compute the cost function for each ``DataSet``. /// - /// The cost function is: - /// - The relative difference between prediction and target value, - /// - to which a loss function is applied, - /// - and which is weighted according to the number of datapoints, - /// - and the relative weights as defined in the Estimator object. - /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns @@ -512,6 +507,15 @@ macro_rules! impl_estimator { /// numpy.ndarray[Float] /// The cost function evaluated for each experimental data point /// of each ``DataSet``. + /// + /// Note + /// ---- + /// The cost function is: + /// + /// - The relative difference between prediction and target value, + /// - to which a loss function is applied, + /// - and which is weighted according to the number of datapoints, + /// - and the relative weights as defined in the Estimator object. #[pyo3(text_signature = "($self, eos)")] fn cost<'py>(&self, eos: &$py_eos, py: Python<'py>) -> PyResult<&'py PyArray1> { Ok(self.0.cost(&eos.0)?.view().to_pyarray(py)) @@ -522,7 +526,7 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns @@ -547,7 +551,7 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns @@ -575,7 +579,7 @@ macro_rules! impl_estimator { /// /// Parameters /// ---------- - /// eos : PyEos + /// eos : EquationOfState /// The equation of state that is used. /// /// Returns From 80410d770fd129414b025b6609d2ad7dc8d92bf4 Mon Sep 17 00:00:00 2001 From: Gernot Bauer Date: Tue, 13 Dec 2022 13:15:08 +0100 Subject: [PATCH 3/4] fixed typo in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 680bb7775..1c03b4bb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Added SAFT-VRQ Mie equation of state and Helmholtz energy functional for first order Feynman-Hibbs corrected Mie fluids. [#79](https://github.com/feos-org/feos/pull/79) -Added `estimator` module to documentation. [#86](https://github.com/feos-org/feos/pull/86) +- Added `estimator` module to documentation. [#86](https://github.com/feos-org/feos/pull/86) ### Changed - Export `EosVariant` and `FunctionalVariant` directly in the crate root instead of their own modules. [#62](https://github.com/feos-org/feos/pull/62) From 4cce7d5a464037515d6b34d80bcade5f22f1ef88 Mon Sep 17 00:00:00 2001 From: Gernot Bauer Date: Tue, 13 Dec 2022 14:17:12 +0100 Subject: [PATCH 4/4] better docstring for Loss --- src/estimator/python.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/estimator/python.rs b/src/estimator/python.rs index 706d3180f..646dfd428 100644 --- a/src/estimator/python.rs +++ b/src/estimator/python.rs @@ -11,8 +11,8 @@ impl From for PyErr { #[macro_export] macro_rules! impl_estimator { ($eos:ty, $py_eos:ty) => { - /// Loss function that is applied to the residuals to - /// weight to in- and outliers. + /// Collection of loss functions that can be applied to residuals + /// to handle outliers. #[pyclass(name = "Loss")] #[derive(Clone)] pub struct PyLoss(Loss); @@ -129,7 +129,7 @@ macro_rules! impl_estimator { /// The equation of state that is used. /// loss : Loss /// The loss function that is applied to residuals - /// to distinguish between in- and outliers. + /// to handle outliers. /// /// Returns /// -------