Skip to content
This repository was archived by the owner on Jun 14, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build_wheel/src/cubic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use feos_core::python::cubic::{
use feos_core::*;
use numpy::convert::ToPyArray;
use numpy::{PyArray1, PyArray2};
use pyo3::exceptions::PyValueError;
use pyo3::exceptions::{PyIndexError, PyValueError};
use pyo3::prelude::*;
use quantity::python::*;
use quantity::si::*;
Expand Down
2 changes: 1 addition & 1 deletion build_wheel/src/user_defined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use feos_core::python::user_defined::*;
use feos_core::*;
use numpy::convert::ToPyArray;
use numpy::{PyArray1, PyArray2};
use pyo3::exceptions::PyValueError;
use pyo3::exceptions::{PyIndexError, PyValueError};
use pyo3::prelude::*;
use quantity::python::*;
use quantity::si::*;
Expand Down
39 changes: 27 additions & 12 deletions src/python/phase_equilibria.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,8 @@ macro_rules! impl_phase_equilibrium {

/// Returns the phase diagram as dictionary.
///
/// Note
/// ----
/// Units
/// -----
/// temperature : K
/// pressure : Pa
/// densities : mol / m³
Expand All @@ -541,17 +541,32 @@ macro_rules! impl_phase_equilibrium {
/// -------
/// dict[str, list[float]]
/// Keys: property names. Values: property for each state.
///
/// Notes
/// -----
/// xi: liquid molefraction of component i
/// yi: vapor molefraction of component i
/// i: component index according to order in parameters.
pub fn to_dict(&self) -> PyResult<HashMap<String, Vec<f64>>> {
let mut result = HashMap::with_capacity(8);
result.insert(String::from("temperature"), (self.0.vapor().temperature() / KELVIN).into_value()?.into_raw_vec());
result.insert(String::from("pressure"), (self.0.vapor().pressure() / PASCAL).into_value()?.into_raw_vec());
result.insert(String::from("density liquid"), (self.0.liquid().density() / (MOL / METER.powi(3))).into_value()?.into_raw_vec());
result.insert(String::from("density vapor"), (self.0.vapor().density() / (MOL / METER.powi(3))).into_value()?.into_raw_vec());
result.insert(String::from("molar enthalpy liquid"), (self.0.liquid().molar_enthalpy() / (KILO*JOULE / MOL)).into_value()?.into_raw_vec());
result.insert(String::from("molar enthalpy vapor"), (self.0.vapor().molar_enthalpy() / (KILO*JOULE / MOL)).into_value()?.into_raw_vec());
result.insert(String::from("molar entropy liquid"), (self.0.liquid().molar_entropy() / (KILO*JOULE / KELVIN / MOL)).into_value()?.into_raw_vec());
result.insert(String::from("molar entropy vapor"), (self.0.vapor().molar_entropy() / (KILO*JOULE / KELVIN / MOL)).into_value()?.into_raw_vec());
Ok(result)
let n = self.0.states[0].liquid().eos.components();
let mut dict = HashMap::with_capacity(8 + 2 * n);
if n != 1 {
let xs = self.0.liquid().molefracs();
let ys = self.0.vapor().molefracs();
for i in 0..n {
dict.insert(String::from(format!("x{}", i)), xs.column(i).to_vec());
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(3))).into_value()?.into_raw_vec());
dict.insert(String::from("density vapor"), (self.0.vapor().density() / (MOL / METER.powi(3))).into_value()?.into_raw_vec());
dict.insert(String::from("molar enthalpy liquid"), (self.0.liquid().molar_enthalpy() / (KILO*JOULE / MOL)).into_value()?.into_raw_vec());
dict.insert(String::from("molar enthalpy vapor"), (self.0.vapor().molar_enthalpy() / (KILO*JOULE / MOL)).into_value()?.into_raw_vec());
dict.insert(String::from("molar entropy liquid"), (self.0.liquid().molar_entropy() / (KILO*JOULE / KELVIN / MOL)).into_value()?.into_raw_vec());
dict.insert(String::from("molar entropy vapor"), (self.0.vapor().molar_entropy() / (KILO*JOULE / KELVIN / MOL)).into_value()?.into_raw_vec());
Ok(dict)
}

/// Binary phase diagram calculated using bubble/dew point iterations.
Expand Down
30 changes: 25 additions & 5 deletions src/python/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,10 @@ macro_rules! impl_state {
}

/// Return logarithmic pure substance fugacity coefficient.
///
///
/// For each component, the hypothetical liquid fugacity coefficient
/// at mixture temperature and pressure is computed.
///
///
/// Returns
/// -------
/// numpy.ndarray
Expand All @@ -539,7 +539,7 @@ macro_rules! impl_state {
}

/// Return logarithmic symmetric activity coefficient.
///
///
/// Returns
/// -------
/// numpy.ndarray
Expand Down Expand Up @@ -977,13 +977,33 @@ macro_rules! impl_state {

impl From<StateVec<'_, SIUnit, $eos>> for PyStateVec {
fn from(vec: StateVec<SIUnit, $eos>) -> Self {
Self(vec.states.iter().map(|&s| s.clone()).collect())
Self(vec.into_iter().map(|s| s.clone()).collect())
}
}

impl<'a> From<&'a PyStateVec> for StateVec<'a, SIUnit, $eos> {
fn from(vec: &'a PyStateVec) -> Self {
Self { states: vec.0.iter().collect() }
Self(vec.0.iter().collect())
}
}

#[pymethods]
impl PyStateVec {
fn __len__(&self) -> PyResult<usize> {
Ok(self.0.len())
}

fn __getitem__(&self, idx: isize) -> PyResult<PyState> {
let i = if idx < 0 {
self.0.len() as isize + idx
} else {
idx
};
if (0..self.0.len()).contains(&(i as usize)) {
Ok(PyState(self.0[i as usize].clone()))
} else {
Err(PyIndexError::new_err(format!("StateVec index out of range")))
}
}
}

Expand Down
71 changes: 40 additions & 31 deletions src/state/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ndarray::{arr1, Array1, Array2};
use num_dual::DualNum;
use quantity::{QuantityArray, QuantityArray1, QuantityArray2, QuantityScalar};
use std::iter::FromIterator;
use std::ops::{Add, Sub};
use std::ops::{Add, Deref, Sub};
use std::rc::Rc;

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -737,80 +737,89 @@ impl<U: EosUnit, E: EquationOfState + EntropyScaling<U>> State<U, E> {

/// A list of states for a simple access to properties
/// of multiple states.
pub struct StateVec<'a, U, E> {
pub states: Vec<&'a State<U, E>>,
}
pub struct StateVec<'a, U, E>(pub Vec<&'a State<U, E>>);

impl<'a, U, E> FromIterator<&'a State<U, E>> for StateVec<'a, U, E> {
fn from_iter<I: IntoIterator<Item = &'a State<U, E>>>(iter: I) -> Self {
Self {
states: iter.into_iter().collect(),
}
Self(iter.into_iter().collect())
}
}

impl<'a, U, E> IntoIterator for StateVec<'a, U, E> {
type Item = &'a State<U, E>;
type IntoIter = std::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

impl<'a, U, E> Deref for StateVec<'a, U, E> {
type Target = Vec<&'a State<U, E>>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'a, U: EosUnit, E: EquationOfState> StateVec<'a, U, E> {
pub fn temperature(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| self.states[i].temperature)
QuantityArray1::from_shape_fn(self.0.len(), |i| self.0[i].temperature)
}

pub fn pressure(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| {
self.states[i].pressure(Contributions::Total)
})
QuantityArray1::from_shape_fn(self.0.len(), |i| self.0[i].pressure(Contributions::Total))
}

pub fn compressibility(&self) -> Array1<f64> {
Array1::from_shape_fn(self.states.len(), |i| {
self.states[i].compressibility(Contributions::Total)
Array1::from_shape_fn(self.0.len(), |i| {
self.0[i].compressibility(Contributions::Total)
})
}

pub fn density(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| self.states[i].density)
QuantityArray1::from_shape_fn(self.0.len(), |i| self.0[i].density)
}

pub fn molefracs(&self) -> Array2<f64> {
Array2::from_shape_fn(
(self.states.len(), self.states[0].eos.components()),
|(i, j)| self.states[i].molefracs[j],
)
Array2::from_shape_fn((self.0.len(), self.0[0].eos.components()), |(i, j)| {
self.0[i].molefracs[j]
})
}

pub fn molar_enthalpy(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| {
self.states[i].molar_enthalpy(Contributions::Total)
QuantityArray1::from_shape_fn(self.0.len(), |i| {
self.0[i].molar_enthalpy(Contributions::Total)
})
}

pub fn molar_entropy(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| {
self.states[i].molar_entropy(Contributions::Total)
QuantityArray1::from_shape_fn(self.0.len(), |i| {
self.0[i].molar_entropy(Contributions::Total)
})
}
}

impl<'a, U: EosUnit, E: EquationOfState + MolarWeight<U>> StateVec<'a, U, E> {
pub fn mass_density(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| self.states[i].mass_density())
QuantityArray1::from_shape_fn(self.0.len(), |i| self.0[i].mass_density())
}

pub fn massfracs(&self) -> Array2<f64> {
Array2::from_shape_fn(
(self.states.len(), self.states[0].eos.components()),
|(i, j)| self.states[i].massfracs()[j],
)
Array2::from_shape_fn((self.0.len(), self.0[0].eos.components()), |(i, j)| {
self.0[i].massfracs()[j]
})
}

pub fn specific_enthalpy(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| {
self.states[i].specific_enthalpy(Contributions::Total)
QuantityArray1::from_shape_fn(self.0.len(), |i| {
self.0[i].specific_enthalpy(Contributions::Total)
})
}

pub fn specific_entropy(&self) -> QuantityArray1<U> {
QuantityArray1::from_shape_fn(self.states.len(), |i| {
self.states[i].specific_entropy(Contributions::Total)
QuantityArray1::from_shape_fn(self.0.len(), |i| {
self.0[i].specific_entropy(Contributions::Total)
})
}
}