From 561771c36be1c2b5e74f98dba70140f6e3e2c241 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Fri, 7 Jul 2023 13:49:13 +0200 Subject: [PATCH] Fixes for the bubble and dew point calculations --- feos-core/CHANGELOG.md | 20 ++++--- feos-core/src/phase_equilibria/bubble_dew.rs | 60 ++++++++++---------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/feos-core/CHANGELOG.md b/feos-core/CHANGELOG.md index d44de111c..a7ed73f82 100644 --- a/feos-core/CHANGELOG.md +++ b/feos-core/CHANGELOG.md @@ -7,22 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added - Added `Components`, `Residual`, `IdealGas` and `DeBroglieWavelength` traits to decouple ideal gas models from residual models. [#158](https://github.com/feos-org/feos/pull/158) -- Added `JobackParameters` struct that implements `Parameters` including Python bindings. [#158](https://github.com/feos-org/feos/pull/) +- Added `JobackParameters` struct that implements `Parameters` including Python bindings. [#158](https://github.com/feos-org/feos/pull/158) ### Changed -- Changed `EquationOfState` from a trait to a `struct` that is generic over `Residual` and `IdealGas` and implements all necessary traits to be used as equation of state including the ideal gas contribution. [#158](https://github.com/feos-org/feos/pull/) -- The `Parameter` trait no longer has an associated type `IdealGas`. [#158](https://github.com/feos-org/feos/pull/) -- Split properties of `State` into those that require the `Residual` trait (`residual_properties.rs`) and those that require both `Residual + IdealGas` (`properties.rs`). [#158](https://github.com/feos-org/feos/pull/) +- Changed `EquationOfState` from a trait to a `struct` that is generic over `Residual` and `IdealGas` and implements all necessary traits to be used as equation of state including the ideal gas contribution. [#158](https://github.com/feos-org/feos/pull/158) +- The `Parameter` trait no longer has an associated type `IdealGas`. [#158](https://github.com/feos-org/feos/pull/158) +- Split properties of `State` into those that require the `Residual` trait (`residual_properties.rs`) and those that require both `Residual + IdealGas` (`properties.rs`). [#158](https://github.com/feos-org/feos/pull/158) - State creation routines are split into those that can be used with `Residual` and those that require `Residual + IdealGas`. [#158](https://github.com/feos-org/feos/pull/158) - `Contributions` enum no longer includes the `ResidualNpt` variant. `ResidualNvt` variant is renamed to `Residual`. [#158](https://github.com/feos-org/feos/pull/158) -- Moved `Verbosity` and `SolverOption` from `phase_equilibria` module to `lib.rs`. [#158](https://github.com/feos-org/feos/pull/) +- Moved `Verbosity` and `SolverOption` from `phase_equilibria` module to `lib.rs`. [#158](https://github.com/feos-org/feos/pull/158) - Moved `StateVec` into own file and module. [#158](https://github.com/feos-org/feos/pull/158) -- Ideal gas and residual Helmholtz energy models can now be separately implemented in Python via the `PyIdealGas` and `PyResidual` structs. [#158](https://github.com/feos-org/feos/pull/) +- Ideal gas and residual Helmholtz energy models can now be separately implemented in Python via the `PyIdealGas` and `PyResidual` structs. [#158](https://github.com/feos-org/feos/pull/158) +- Bubble and dew point iterations will not attempt a second iteration if no solution is found for the given initial pressure. [#166](https://github.com/feos-org/feos/pull/166) ### Removed - Removed `EquationOfState` trait. [#158](https://github.com/feos-org/feos/pull/158) -- Removed ideal gas dependencies from `PureRecord` and `SegmentRecord`. [#158](https://github.com/feos-org/feos/pull/) -- Removed Python getter and setter functions and optional arguments for ideal gas records in macros. [#158](https://github.com/feos-org/feos/pull/) +- Removed ideal gas dependencies from `PureRecord` and `SegmentRecord`. [#158](https://github.com/feos-org/feos/pull/158) +- Removed Python getter and setter functions and optional arguments for ideal gas records in macros. [#158](https://github.com/feos-org/feos/pull/158) + +### 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) ### Packaging - Updated `num-dual` dependency to 0.7. [#137](https://github.com/feos-org/feos/pull/137) diff --git a/feos-core/src/phase_equilibria/bubble_dew.rs b/feos-core/src/phase_equilibria/bubble_dew.rs index ee9a133db..4a13a65b4 100644 --- a/feos-core/src/phase_equilibria/bubble_dew.rs +++ b/feos-core/src/phase_equilibria/bubble_dew.rs @@ -119,51 +119,44 @@ impl PhaseEquilibrium { match tp_spec { TPSpec::Temperature(t) => { // First use given initial pressure if applicable - let mut vle = tp_init - .map(|p| { + if let Some(p) = tp_init { + return Self::iterate_bubble_dew( + eos, + tp_spec, + p, + molefracs_spec, + molefracs_init, + bubble, + options, + ); + } + + // Next try to initialize with an ideal gas assumption + let vle = Self::starting_pressure_ideal_gas(eos, t, molefracs_spec, bubble) + .and_then(|(p, x)| { Self::iterate_bubble_dew( eos, tp_spec, p, molefracs_spec, - molefracs_init, + molefracs_init.or(Some(&x)), bubble, options, ) - }) - .and_then(Result::ok); + }); - // Next try to initialize with an ideal gas assumption - vle = vle.or_else(|| { - let (p, x) = - Self::starting_pressure_ideal_gas(eos, t, molefracs_spec, bubble).ok()?; + // Finally use the spinodal to initialize the calculation + vle.or_else(|_| { Self::iterate_bubble_dew( eos, tp_spec, - p, + Self::starting_pressure_spinodal(eos, t, molefracs_spec)?, molefracs_spec, - molefracs_init.or(Some(&x)), + molefracs_init, bubble, options, ) - .ok() - }); - - // Finally use the spinodal to initialize the calculation - vle.map_or_else( - || { - Self::iterate_bubble_dew( - eos, - tp_spec, - Self::starting_pressure_spinodal(eos, t, molefracs_spec)?, - molefracs_spec, - molefracs_init, - bubble, - options, - ) - }, - Ok, - ) + }) } TPSpec::Pressure(_) => { let temperature = tp_init.expect("An initial temperature is required for the calculation of bubble/dew points at given pressure!"); @@ -198,7 +191,7 @@ impl PhaseEquilibrium { } else { starting_x2_dew(eos, t, p, molefracs_spec, molefracs_init) }?; - bubble_dew(tp_spec, var, state1, state2, options) + bubble_dew(tp_spec, var, state1, state2, bubble, options) } fn starting_pressure_ideal_gas( @@ -358,6 +351,7 @@ fn bubble_dew( mut var_tp: TPSpec, mut state1: State, mut state2: State, + bubble: bool, options: (SolverOptions, SolverOptions), ) -> EosResult> where @@ -434,7 +428,11 @@ where "Bubble/dew point: calculation converged in {} step(s)\n", k_out ); - Ok(PhaseEquilibrium::from_states(state1, state2)) + if bubble { + Ok(PhaseEquilibrium([state2, state1])) + } else { + Ok(PhaseEquilibrium([state1, state2])) + } } else { // not converged, return EosError Err(EosError::NotConverged(String::from("bubble-dew-iteration")))