Skip to content
This repository was archived by the owner on Jun 14, 2022. It is now read-only.

Commit badb511

Browse files
authored
Pr impl residual (#51)
* Add loss function to estimator, and Antoine equation for vapor pressure estimation * Impl PR Helmholtz energy as contribution * updated docstrings
1 parent 9cd78e6 commit badb511

File tree

2 files changed

+47
-43
lines changed

2 files changed

+47
-43
lines changed

src/cubic.rs

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use num_dual::DualNum;
1717
use quantity::si::{SIArray1, SIUnit};
1818
use serde::{Deserialize, Serialize};
1919
use std::f64::consts::SQRT_2;
20+
use std::fmt;
2021
use std::rc::Rc;
2122

2223
const KB_A3: f64 = 13806490.0;
@@ -165,12 +166,51 @@ impl Parameter for PengRobinsonParameters {
165166
}
166167
}
167168

169+
struct PengRobinsonContribution {
170+
parameters: Rc<PengRobinsonParameters>,
171+
}
172+
173+
impl<D: DualNum<f64>> HelmholtzEnergyDual<D> for PengRobinsonContribution {
174+
fn helmholtz_energy(&self, state: &StateHD<D>) -> D {
175+
// temperature dependent a parameter
176+
let p = &self.parameters;
177+
let x = &state.molefracs;
178+
let ak = (&p.tc.mapv(|tc| (D::one() - (state.temperature / tc).sqrt())) * &p.kappa + 1.0)
179+
.mapv(|x| x.powi(2))
180+
* &p.a;
181+
182+
// Mixing rules
183+
let mut ak_mix = D::zero();
184+
for i in 0..ak.len() {
185+
for j in 0..ak.len() {
186+
ak_mix += (ak[i] * ak[j]).sqrt() * (x[i] * x[j] * (1.0 - p.k_ij[(i, j)]));
187+
}
188+
}
189+
let b = (x * &p.b).sum();
190+
191+
// Helmholtz energy
192+
let n = state.moles.sum();
193+
let v = state.volume;
194+
n * ((v / (v - b * n)).ln()
195+
- ak_mix / (b * SQRT_2 * 2.0 * state.temperature)
196+
* ((v * (SQRT_2 - 1.0) + b * n) / (v * (SQRT_2 + 1.0) - b * n)).ln())
197+
}
198+
}
199+
200+
impl fmt::Display for PengRobinsonContribution {
201+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202+
write!(f, "Peng Robinson")
203+
}
204+
}
205+
168206
/// A simple version of the Peng-Robinson equation of state.
169207
pub struct PengRobinson {
170208
/// Parameters
171209
parameters: Rc<PengRobinsonParameters>,
172210
/// Ideal gas contributions to the Helmholtz energy
173211
ideal_gas: Joback,
212+
/// Non-ideal contributions to the Helmholtz energy
213+
contributions: Vec<Box<dyn HelmholtzEnergy>>,
174214
}
175215

176216
impl PengRobinson {
@@ -180,9 +220,14 @@ impl PengRobinson {
180220
|| Joback::default(parameters.tc.len()),
181221
|j| Joback::new(j.clone()),
182222
);
223+
let contributions: Vec<Box<dyn HelmholtzEnergy>> =
224+
vec![Box::new(PengRobinsonContribution {
225+
parameters: parameters.clone(),
226+
})];
183227
Self {
184228
parameters,
185229
ideal_gas,
230+
contributions,
186231
}
187232
}
188233
}
@@ -202,42 +247,7 @@ impl EquationOfState for PengRobinson {
202247
}
203248

204249
fn residual(&self) -> &[Box<dyn HelmholtzEnergy>] {
205-
unreachable!()
206-
}
207-
208-
fn evaluate_residual<D: DualNum<f64>>(&self, state: &StateHD<D>) -> D {
209-
// temperature dependent a parameter
210-
let p = &self.parameters;
211-
let x = &state.molefracs;
212-
let ak = (&p.tc.mapv(|tc| (D::one() - (state.temperature / tc).sqrt())) * &p.kappa + 1.0)
213-
.mapv(|x| x.powi(2))
214-
* &p.a;
215-
216-
// Mixing rules
217-
let mut ak_mix = D::zero();
218-
for i in 0..ak.len() {
219-
for j in 0..ak.len() {
220-
ak_mix += (ak[i] * ak[j]).sqrt() * (x[i] * x[j] * (1.0 - p.k_ij[(i, j)]));
221-
}
222-
}
223-
let b = (x * &p.b).sum();
224-
225-
// Helmholtz energy
226-
let n = state.moles.sum();
227-
let v = state.volume;
228-
n * ((v / (v - b * n)).ln()
229-
- ak_mix / (b * SQRT_2 * 2.0 * state.temperature)
230-
* ((v * (SQRT_2 - 1.0) + b * n) / (v * (SQRT_2 + 1.0) - b * n)).ln())
231-
}
232-
233-
fn evaluate_residual_contributions<D: DualNum<f64>>(
234-
&self,
235-
state: &StateHD<D>,
236-
) -> Vec<(String, D)>
237-
where
238-
dyn HelmholtzEnergy: HelmholtzEnergyDual<D>,
239-
{
240-
vec![("Peng-Robinson".into(), self.evaluate_residual(state))]
250+
&self.contributions
241251
}
242252

243253
fn ideal_gas(&self) -> &dyn IdealGasContribution {

src/equation_of_state.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,6 @@ pub trait EquationOfState {
165165
fn residual(&self) -> &[Box<dyn HelmholtzEnergy>];
166166

167167
/// Evaluate the residual reduced Helmholtz energy $\beta A^\mathrm{res}$.
168-
///
169-
/// For simple equations of state (see e.g. `PengRobinson`) it might be
170-
/// easier to overwrite this function instead of implementing `residual`.
171168
fn evaluate_residual<D: DualNum<f64>>(&self, state: &StateHD<D>) -> D
172169
where
173170
dyn HelmholtzEnergy: HelmholtzEnergyDual<D>,
@@ -179,10 +176,7 @@ pub trait EquationOfState {
179176
}
180177

181178
/// Evaluate the reduced Helmholtz energy of each individual contribution
182-
/// and return them together with a string representatino of the contribution.
183-
///
184-
/// If `evaluate_residual` is implemented instead of `residual`, this function
185-
/// also needs to be overwritten to avoid panics.
179+
/// and return them together with a string representation of the contribution.
186180
fn evaluate_residual_contributions<D: DualNum<f64>>(
187181
&self,
188182
state: &StateHD<D>,

0 commit comments

Comments
 (0)