use super::{DataSet, FeosError};
use feos_core::{
DensityInitialization, Molarweight, PhaseEquilibrium, ReferenceSystem, Residual, SolverOptions,
State,
};
use ndarray::{Array1, arr1};
use quantity::{KILOGRAM, METER, MassDensity, Moles, Pressure, Temperature};
use typenum::P3;
#[derive(Clone)]
pub struct LiquidDensity {
pub target: Array1<f64>,
unit: MassDensity,
temperature: Temperature<Array1<f64>>,
pressure: Pressure<Array1<f64>>,
}
impl LiquidDensity {
pub fn new(
target: MassDensity<Array1<f64>>,
temperature: Temperature<Array1<f64>>,
pressure: Pressure<Array1<f64>>,
) -> Self {
let unit = KILOGRAM / METER.powi::<P3>();
Self {
target: (target / unit).to_reduced(),
unit,
temperature,
pressure,
}
}
pub fn temperature(&self) -> &Temperature<Array1<f64>> {
&self.temperature
}
pub fn pressure(&self) -> &Pressure<Array1<f64>> {
&self.pressure
}
}
impl<E: Residual + Molarweight> DataSet<E> for LiquidDensity {
fn target(&self) -> &Array1<f64> {
&self.target
}
fn target_str(&self) -> &str {
"liquid density"
}
fn input_str(&self) -> Vec<&str> {
vec!["temperature", "pressure"]
}
fn predict(&self, eos: &Arc<E>) -> Result<Array1<f64>, FeosError> {
let moles = Moles::from_reduced(arr1(&[1.0]));
Ok(self
.temperature
.into_iter()
.zip(&self.pressure)
.map(|(t, p)| {
let state = State::new_npt(eos, t, p, &moles, DensityInitialization::Liquid);
if let Ok(s) = state {
(s.mass_density() / self.unit).into_value()
} else {
f64::NAN
}
})
.collect())
}
}
#[derive(Clone)]
pub struct EquilibriumLiquidDensity {
pub target: Array1<f64>,
unit: MassDensity,
temperature: Temperature<Array1<f64>>,
solver_options: SolverOptions,
}
impl EquilibriumLiquidDensity {
pub fn new(
target: MassDensity<Array1<f64>>,
temperature: Temperature<Array1<f64>>,
vle_options: Option<SolverOptions>,
) -> Self {
let unit = KILOGRAM / METER.powi::<P3>();
Self {
target: (target / unit).to_reduced(),
unit,
temperature,
solver_options: vle_options.unwrap_or_default(),
}
}
pub fn temperature(&self) -> &Temperature<Array1<f64>> {
&self.temperature
}
}
impl<E: Residual + Molarweight> DataSet<E> for EquilibriumLiquidDensity {
fn target(&self) -> &Array1<f64> {
&self.target
}
fn target_str(&self) -> &str {
"equilibrium liquid density"
}
fn input_str(&self) -> Vec<&str> {
vec!["temperature"]
}
fn predict(&self, eos: &Arc<E>) -> Result<Array1<f64>, FeosError> {
Ok(self
.temperature
.into_iter()
.map(|t| {
if let Ok(state) = PhaseEquilibrium::pure(eos, t, None, self.solver_options) {
(state.liquid().mass_density() / self.unit).into_value()
} else {
f64::NAN
}
})
.collect())
}
}