Skip to content

Commit f3bce08

Browse files
authored
Add custom PhaseDiagram constructor (#113)
* Add custom PhaseDiagram constructor * added docstrings and changelog entries
1 parent 321102d commit f3bce08

File tree

11 files changed

+79
-29
lines changed

11 files changed

+79
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
- 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)
1010
- Added `estimator` module to documentation. [#86](https://github.com/feos-org/feos/pull/86)
1111
- Added benchmarks for the evaluation of the Helmholtz energy and some properties of the `State` object for PC-SAFT. [#89](https://github.com/feos-org/feos/pull/89)
12+
- The Python class `StateVec` is exposed in both the `feos.eos` and `feos.dft` module. [#113](https://github.com/feos-org/feos/pull/113)
1213

1314
### Changed
1415
- Export `EosVariant` and `FunctionalVariant` directly in the crate root instead of their own modules. [#62](https://github.com/feos-org/feos/pull/62)

feos-core/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## Unreleased
88
### Added
99
- Added `PhaseDiagram::par_pure` that uses rayon to calculate phase diagrams in parallel. [#57](https://github.com/feos-org/feos/pull/57)
10+
- Added `StateVec::moles` getter. [#113](https://github.com/feos-org/feos/pull/113)
11+
- Added public constructors `PhaseDiagram::new` and `StateVec::new` that allow the creation of the respective structs from a list of `PhaseEquilibrium`s or `State`s in Rust and Python. [#113](https://github.com/feos-org/feos/pull/113)
1012

1113
### Changed
1214
- Added `Sync` and `Send` as supertraits to `EquationOfState`. [#57](https://github.com/feos-org/feos/pull/57)
@@ -17,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1719
- Added `get_or_insert_with_d2_64` to `Cache`. [#94](https://github.com/feos-org/feos/pull/94)
1820
- The critical point algorithm now uses vector dual numbers to reduce the number of model evaluations and computation times. [#96](https://github.com/feos-org/feos/pull/96)
1921
- Renamed `State::molar_volume` to `State::partial_molar_volume` and `State::ln_phi_pure` to `State::ln_phi_pure_liquid`. [#107](https://github.com/feos-org/feos/pull/107)
22+
- Added a const generic parameter to `PhaseDiagram` that accounts for the number of phases analogously to `PhaseEquilibrium`. [#113](https://github.com/feos-org/feos/pull/113)
2023

2124
## [0.3.1] - 2022-08-25
2225
### Added

feos-core/src/phase_equilibria/phase_diagram_binary.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::sync::Arc;
1111

1212
const DEFAULT_POINTS: usize = 51;
1313

14-
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
14+
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E, 2> {
1515
/// Create a new binary phase diagram exhibiting a
1616
/// vapor/liquid equilibrium.
1717
///
@@ -254,12 +254,12 @@ impl<U: EosUnit, E: EquationOfState> State<U, E> {
254254

255255
/// Phase diagram (Txy or pxy) for a system with heteroazeotropic phase behavior.
256256
pub struct PhaseDiagramHetero<U, E> {
257-
pub vle1: PhaseDiagram<U, E>,
258-
pub vle2: PhaseDiagram<U, E>,
259-
pub lle: Option<PhaseDiagram<U, E>>,
257+
pub vle1: PhaseDiagram<U, E, 2>,
258+
pub vle2: PhaseDiagram<U, E, 2>,
259+
pub lle: Option<PhaseDiagram<U, E, 2>>,
260260
}
261261

262-
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
262+
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E, 2> {
263263
/// Create a new binary phase diagram exhibiting a
264264
/// vapor/liquid/liquid equilibrium.
265265
///
@@ -337,24 +337,23 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
337337
.transpose()?;
338338

339339
Ok(PhaseDiagramHetero {
340-
vle1: PhaseDiagram { states: dia1 },
341-
vle2: PhaseDiagram { states: dia2 },
340+
vle1: PhaseDiagram::new(dia1),
341+
vle2: PhaseDiagram::new(dia2),
342342
lle,
343343
})
344344
}
345345
}
346346

347347
impl<U: Clone, E> PhaseDiagramHetero<U, E> {
348-
pub fn vle(&self) -> PhaseDiagram<U, E> {
349-
PhaseDiagram {
350-
states: self
351-
.vle1
348+
pub fn vle(&self) -> PhaseDiagram<U, E, 2> {
349+
PhaseDiagram::new(
350+
self.vle1
352351
.states
353352
.iter()
354353
.chain(self.vle2.states.iter().rev())
355354
.cloned()
356355
.collect(),
357-
}
356+
)
358357
}
359358
}
360359

feos-core/src/phase_equilibria/phase_diagram_pure.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,26 @@ use rayon::{prelude::*, ThreadPool};
1111
use std::sync::Arc;
1212

1313
/// Pure component and binary mixture phase diagrams.
14-
pub struct PhaseDiagram<U, E> {
15-
pub states: Vec<PhaseEquilibrium<U, E, 2>>,
14+
pub struct PhaseDiagram<U, E, const N: usize> {
15+
pub states: Vec<PhaseEquilibrium<U, E, N>>,
1616
}
1717

18-
impl<U: Clone, E> Clone for PhaseDiagram<U, E> {
18+
impl<U: Clone, E, const N: usize> Clone for PhaseDiagram<U, E, N> {
1919
fn clone(&self) -> Self {
2020
Self {
2121
states: self.states.clone(),
2222
}
2323
}
2424
}
2525

26-
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
26+
impl<U, E, const N: usize> PhaseDiagram<U, E, N> {
27+
/// Create a phase diagram from a list of phase equilibria.
28+
pub fn new(states: Vec<PhaseEquilibrium<U, E, N>>) -> Self {
29+
Self { states }
30+
}
31+
}
32+
33+
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E, 2> {
2734
/// Calculate a phase diagram for a pure component.
2835
pub fn pure(
2936
eos: &Arc<E>,
@@ -52,7 +59,7 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
5259
}
5360
states.push(PhaseEquilibrium::from_states(sc.clone(), sc));
5461

55-
Ok(PhaseDiagram { states })
62+
Ok(PhaseDiagram::new(states))
5663
}
5764

5865
/// Return the vapor states of the diagram.
@@ -67,7 +74,7 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
6774
}
6875

6976
#[cfg(feature = "rayon")]
70-
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
77+
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E, 2> {
7178
fn solve_temperatures(
7279
eos: &Arc<E>,
7380
temperatures: ArrayView1<f64>,
@@ -125,6 +132,6 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
125132
});
126133

127134
states.push(PhaseEquilibrium::from_states(sc.clone(), sc));
128-
Ok(PhaseDiagram { states })
135+
Ok(PhaseDiagram::new(states))
129136
}
130137
}

feos-core/src/phase_equilibria/phase_envelope.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{Contributions, EosUnit};
66
use quantity::{QuantityArray1, QuantityScalar};
77
use std::sync::Arc;
88

9-
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
9+
impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E, 2> {
1010
/// Calculate the bubble point line of a mixture with given composition.
1111
pub fn bubble_point_line(
1212
eos: &Arc<E>,
@@ -56,7 +56,7 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
5656
}
5757
states.push(PhaseEquilibrium::from_states(sc.clone(), sc));
5858

59-
Ok(PhaseDiagram { states })
59+
Ok(PhaseDiagram::new(states))
6060
}
6161

6262
/// Calculate the dew point line of a mixture with given composition.
@@ -102,7 +102,7 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
102102

103103
let n_p = npoints - n_t;
104104
if vle.is_none() {
105-
return Ok(PhaseDiagram { states });
105+
return Ok(PhaseDiagram::new(states));
106106
}
107107

108108
let min_pressure = vle.as_ref().unwrap().vapor().pressure(Contributions::Total);
@@ -124,7 +124,7 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
124124

125125
states.push(PhaseEquilibrium::from_states(sc.clone(), sc));
126126

127-
Ok(PhaseDiagram { states })
127+
Ok(PhaseDiagram::new(states))
128128
}
129129

130130
/// Calculate the spinodal lines for a mixture with fixed composition.
@@ -160,6 +160,6 @@ impl<U: EosUnit, E: EquationOfState> PhaseDiagram<U, E> {
160160
}
161161
states.push(PhaseEquilibrium::from_states(sc.clone(), sc));
162162

163-
Ok(PhaseDiagram { states })
163+
Ok(PhaseDiagram::new(states))
164164
}
165165
}

feos-core/src/python/phase_equilibria.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,11 +463,25 @@ macro_rules! impl_phase_equilibrium {
463463
}
464464

465465
/// Phase diagram for a pure component or a binary mixture.
466+
///
467+
/// Parameters
468+
/// ----------
469+
/// phase_equilibria : [PhaseEquilibrium]
470+
/// A list of individual phase equilibria.
471+
///
472+
/// Returns
473+
/// -------
474+
/// PhaseDiagram : the resulting phase diagram
466475
#[pyclass(name = "PhaseDiagram")]
467-
pub struct PyPhaseDiagram(PhaseDiagram<SIUnit, $eos>);
476+
pub struct PyPhaseDiagram(PhaseDiagram<SIUnit, $eos, 2>);
468477

469478
#[pymethods]
470479
impl PyPhaseDiagram {
480+
#[new]
481+
fn new(phase_equilibria: Vec<PyPhaseEquilibrium>) -> Self {
482+
Self(PhaseDiagram::new(phase_equilibria.into_iter().map(|p| p.0).collect()))
483+
}
484+
471485
/// Calculate a pure component phase diagram.
472486
///
473487
/// Parameters

feos-core/src/python/state.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,17 @@ macro_rules! impl_state {
10101010
}
10111011

10121012

1013+
/// A list of states that provides convenient getters
1014+
/// for properties of all the individual states.
1015+
///
1016+
/// Parameters
1017+
/// ----------
1018+
/// states : [State]
1019+
/// A list of individual states.
1020+
///
1021+
/// Returns
1022+
/// -------
1023+
/// StateVec
10131024
#[pyclass(name = "StateVec")]
10141025
pub struct PyStateVec(Vec<State<SIUnit, $eos>>);
10151026

@@ -1027,6 +1038,11 @@ macro_rules! impl_state {
10271038

10281039
#[pymethods]
10291040
impl PyStateVec {
1041+
#[new]
1042+
fn new(states: Vec<PyState>) -> Self {
1043+
Self(states.into_iter().map(|s| s.0).collect())
1044+
}
1045+
10301046
fn __len__(&self) -> PyResult<usize> {
10311047
Ok(self.0.len())
10321048
}
@@ -1043,10 +1059,7 @@ macro_rules! impl_state {
10431059
Err(PyIndexError::new_err(format!("StateVec index out of range")))
10441060
}
10451061
}
1046-
}
10471062

1048-
#[pymethods]
1049-
impl PyStateVec {
10501063
#[getter]
10511064
fn get_temperature(&self) -> PySIArray1{
10521065
StateVec::from(self).temperature().into()
@@ -1067,6 +1080,11 @@ macro_rules! impl_state {
10671080
StateVec::from(self).density().into()
10681081
}
10691082

1083+
#[getter]
1084+
fn get_moles<'py>(&self, py: Python<'py>) -> PySIArray2 {
1085+
StateVec::from(self).moles().into()
1086+
}
1087+
10701088
#[getter]
10711089
fn get_molefracs<'py>(&self, py: Python<'py>) -> &'py PyArray2<f64> {
10721090
StateVec::from(self).molefracs().view().to_pyarray(py)

feos-core/src/state/properties.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,12 @@ impl<'a, U: EosUnit, E: EquationOfState> StateVec<'a, U, E> {
799799
QuantityArray1::from_shape_fn(self.0.len(), |i| self.0[i].density)
800800
}
801801

802+
pub fn moles(&self) -> QuantityArray2<U> {
803+
QuantityArray2::from_shape_fn((self.0.len(), self.0[0].eos.components()), |(i, j)| {
804+
self.0[i].moles.get(j)
805+
})
806+
}
807+
802808
pub fn molefracs(&self) -> Array2<f64> {
803809
Array2::from_shape_fn((self.0.len(), self.0[0].eos.components()), |(i, j)| {
804810
self.0[i].molefracs[j]

parameters/pcsaft/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ The files named according to the pattern `NameYear.json` correspond to published
3535
[`sauer2014_homo_joback.json`](sauer2014_homo.json) | GC segment parameters for homosegmented PC-SAFT including ideal gas parameters | [&#128279;](https://doi.org/10.1021/ie502203w) [&#128279;](https://doi.org/10.1080/00986448708960487)|
3636
[`sauer2014_hetero.json`](sauer2014_hetero.json) | GC segment parameters for heterosegmented PC-SAFT | [&#128279;](https://doi.org/10.1021/ie502203w)
3737
[`sauer2014_hetero_joback.json`](sauer2014_hetero.json) | GC segment parameters for heterosegmented PC-SAFT including ideal gas parameters | [&#128279;](https://doi.org/10.1021/ie502203w) [&#128279;](https://doi.org/10.1080/00986448708960487)
38-
[`loetgeringlin2015_homo.json`](loetgeringlin2018.json) | GC segment parameters including for homosegmented PC-SAFT including viscosity parameter | [&#128279;](https://doi.org/10.1021/acs.iecr.5b01698)
38+
[`loetgeringlin2015_homo.json`](loetgeringlin2018.json) | GC segment parameters for homosegmented PC-SAFT including viscosity parameter | [&#128279;](https://doi.org/10.1021/acs.iecr.5b01698)
3939

src/python/dft.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ pub fn dft(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
258258

259259
m.add_class::<PyFunctionalVariant>()?;
260260
m.add_class::<PyState>()?;
261+
m.add_class::<PyStateVec>()?;
261262
m.add_class::<PyPhaseDiagram>()?;
262263
m.add_class::<PyPhaseEquilibrium>()?;
263264
m.add_class::<FMTVersion>()?;

0 commit comments

Comments
 (0)