From d51c45b68fdfa50b8877b6690781277d5b2a24ca Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Thu, 11 Jan 2024 09:58:41 +0100 Subject: [PATCH 1/2] Convergence improvement for tp_flash --- CHANGELOG.md | 3 +++ Cargo.toml | 2 +- feos-core/CHANGELOG.md | 4 ++++ feos-core/Cargo.toml | 2 +- feos-core/src/phase_equilibria/tp_flash.rs | 25 ++++++++++++++++------ 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d72ccb2..db02a09fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.6.1] - 2024-01-11 +- Python only: Release the changes introduced in `feos-core` 0.6.1. + ## [0.6.0] - 2023-12-19 ### Added - Added `EquationOfState.ideal_gas()` to initialize an equation of state that only consists of an ideal gas contribution. [#204](https://github.com/feos-org/feos/pull/204) diff --git a/Cargo.toml b/Cargo.toml index 5b71ee18b..ec08c0824 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "feos" -version = "0.6.0" +version = "0.6.1" authors = ["Gernot Bauer ", "Philipp Rehner "] edition = "2021" readme = "README.md" diff --git a/feos-core/CHANGELOG.md b/feos-core/CHANGELOG.md index aca44b101..fb8cf0b4d 100644 --- a/feos-core/CHANGELOG.md +++ b/feos-core/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.6.1] 2024-01-11 +### Fixed +- Improved convergence of `tp_flash` for certain edge cases. [#219](https://github.com/feos-org/feos/pull/219) + ## [0.6.0] 2023-12-19 ### Added - Added `EquationOfState::ideal_gas` to initialize an equation of state that only consists of an ideal gas contribution. [#204](https://github.com/feos-org/feos/pull/204) diff --git a/feos-core/Cargo.toml b/feos-core/Cargo.toml index 71dd348fc..ee1d60e79 100644 --- a/feos-core/Cargo.toml +++ b/feos-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "feos-core" -version = "0.6.0" +version = "0.6.1" authors = ["Gernot Bauer ", "Philipp Rehner State { Some(init) => init .clone() .update_pressure(self.temperature, self.pressure(Contributions::Total))?, - None => PhaseEquilibrium::vle_init_stability(self)?, + None => { + let (init1, init2) = PhaseEquilibrium::vle_init_stability(self)?; + let vle1 = self.tp_flash(Some(&init1), options, non_volatile_components.clone()); + return if vle1.is_err() && init2.is_some() { + self.tp_flash(init2.as_ref(), options, non_volatile_components) + } else { + vle1 + }; + } }; log_iter!( @@ -297,14 +305,19 @@ impl PhaseEquilibrium { Ok(()) } - fn vle_init_stability(feed_state: &State) -> EosResult { + fn vle_init_stability(feed_state: &State) -> EosResult<(Self, Option)> { let mut stable_states = feed_state.stability_analysis(SolverOptions::default())?; let state1 = stable_states.pop(); let state2 = stable_states.pop(); - match (state1, state2) { - (Some(s1), Some(s2)) => Ok(Self::from_states(s1, s2)), - (Some(s1), None) => Ok(Self::from_states(s1, feed_state.clone())), - _ => Err(EosError::NoPhaseSplit), + if let Some(s1) = state1 { + let init1 = Self::from_states(s1.clone(), feed_state.clone()); + if let Some(s2) = state2 { + Ok((Self::from_states(s1, s2), Some(init1))) + } else { + Ok((init1, None)) + } + } else { + Err(EosError::NoPhaseSplit) } } } From 3bd697ae241104d52834212f3918f552b149415c Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Thu, 11 Jan 2024 10:52:06 +0100 Subject: [PATCH 2/2] also use stability analysis if no convergence with provided initial guess --- feos-core/src/phase_equilibria/tp_flash.rs | 48 ++++++++++++++-------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/feos-core/src/phase_equilibria/tp_flash.rs b/feos-core/src/phase_equilibria/tp_flash.rs index f19542a5b..f422b6b0b 100644 --- a/feos-core/src/phase_equilibria/tp_flash.rs +++ b/feos-core/src/phase_equilibria/tp_flash.rs @@ -52,24 +52,40 @@ impl State { options: SolverOptions, non_volatile_components: Option>, ) -> EosResult> { - // set options - let (max_iter, tol, verbosity) = options.unwrap_or(MAX_ITER_TP, TOL_TP); - // initialization - let mut new_vle_state = match initial_state { - Some(init) => init - .clone() - .update_pressure(self.temperature, self.pressure(Contributions::Total))?, - None => { - let (init1, init2) = PhaseEquilibrium::vle_init_stability(self)?; - let vle1 = self.tp_flash(Some(&init1), options, non_volatile_components.clone()); - return if vle1.is_err() && init2.is_some() { - self.tp_flash(init2.as_ref(), options, non_volatile_components) - } else { - vle1 - }; + if let Some(init) = initial_state { + let vle = self.tp_flash_( + init.clone() + .update_pressure(self.temperature, self.pressure(Contributions::Total))?, + options, + non_volatile_components.clone(), + ); + if vle.is_ok() { + return vle; } - }; + } + + let (init1, init2) = PhaseEquilibrium::vle_init_stability(self)?; + let vle = self.tp_flash_(init1, options, non_volatile_components.clone()); + if vle.is_ok() { + return vle; + } + + if let Some(init2) = init2 { + self.tp_flash_(init2, options, non_volatile_components) + } else { + vle + } + } + + pub fn tp_flash_( + &self, + mut new_vle_state: PhaseEquilibrium, + options: SolverOptions, + non_volatile_components: Option>, + ) -> EosResult> { + // set options + let (max_iter, tol, verbosity) = options.unwrap_or(MAX_ITER_TP, TOL_TP); log_iter!( verbosity,