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

Commit a588a83

Browse files
authored
Refactor the handling of binary interaction parameters (#8)
* Refactor the handling of binary interaction parameters * Fix tests * new `new_pure` and `new_binary` routines for `Parameter` to compensate for the now non-optional `binary_records` * store parameters as `Rc` * fix tests * remove obsolete error variant
1 parent 7d8f0af commit a588a83

File tree

8 files changed

+266
-162
lines changed

8 files changed

+266
-162
lines changed

src/cubic.rs

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use crate::equation_of_state::{EquationOfState, HelmholtzEnergy, HelmholtzEnergyDual};
22
use crate::joback::JobackRecord;
3-
use crate::parameter::{BinaryRecord, Identifier, Parameter, ParameterError, PureRecord};
3+
use crate::parameter::{Identifier, Parameter, ParameterError, PureRecord};
44
use crate::si::{GRAM, MOL};
55
use crate::state::StateHD;
66
use crate::MolarWeight;
7-
use ndarray::{Array, Array1, Array2};
7+
use ndarray::{Array1, Array2};
88
use num_dual::DualNum;
99
use quantity::si::{SIArray1, SIUnit};
1010
use serde::{Deserialize, Serialize};
1111
use std::collections::HashMap;
1212
use std::f64::consts::SQRT_2;
13+
use std::rc::Rc;
1314

1415
const KB_A3: f64 = 13806490.0;
1516

@@ -33,7 +34,6 @@ impl std::fmt::Display for PengRobinsonRecord {
3334
}
3435

3536
/// Peng-Robinson parameters for one ore more substances.
36-
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
3737
pub struct PengRobinsonParameters {
3838
tc: Array1<f64>,
3939
a: Array1<f64>,
@@ -43,17 +43,6 @@ pub struct PengRobinsonParameters {
4343
molarweight: Array1<f64>,
4444
pure_records: Vec<PureRecord<PengRobinsonRecord, JobackRecord>>,
4545
joback_records: Option<Vec<JobackRecord>>,
46-
binary_records: Option<Vec<BinaryRecord<Identifier, f64>>>,
47-
}
48-
49-
impl PengRobinsonParameters {
50-
pub fn subset(&self, component_list: &[usize]) -> Self {
51-
let pure_records = component_list
52-
.iter()
53-
.map(|&i| self.pure_records[i].clone())
54-
.collect();
55-
Self::from_records(pure_records, self.binary_records.clone()).unwrap()
56-
}
5746
}
5847

5948
impl PengRobinsonParameters {
@@ -83,7 +72,10 @@ impl PengRobinsonParameters {
8372
PureRecord::new(id, molarweight[i], None, Some(record), None)
8473
})
8574
.collect();
86-
PengRobinsonParameters::from_records(records, None)
75+
Ok(PengRobinsonParameters::from_records(
76+
records,
77+
Array2::zeros([pc.len(); 2]),
78+
))
8779
}
8880
}
8981

@@ -94,8 +86,8 @@ impl Parameter for PengRobinsonParameters {
9486

9587
fn from_records(
9688
pure_records: Vec<PureRecord<Self::Pure, Self::IdealGas>>,
97-
binary_records: Option<Vec<crate::parameter::BinaryRecord<Identifier, Self::Binary>>>,
98-
) -> Result<Self, crate::parameter::ParameterError> {
89+
binary_records: Array2<Self::Binary>,
90+
) -> Self {
9991
let n = pure_records.len();
10092

10193
let mut tc = Array1::zeros(n);
@@ -123,44 +115,39 @@ impl Parameter for PengRobinsonParameters {
123115
};
124116
}
125117

126-
let mut k_ij = Array::zeros([n, n]);
127-
match &binary_records {
128-
Some(bs) => bs.iter().for_each(|record| {
129-
let i = component_index.get(&record.id1);
130-
let j = component_index.get(&record.id2);
131-
if let (Some(i), Some(j)) = (i, j) {
132-
k_ij[[*i, *j]] = record.model_record;
133-
k_ij[[*j, *i]] = record.model_record
134-
}
135-
}),
136-
None => (),
137-
}
138-
139118
let joback_records = pure_records
140119
.iter()
141120
.map(|r| r.ideal_gas_record.clone())
142121
.collect();
143122

144-
Ok(Self {
123+
Self {
145124
tc,
146125
a,
147126
b,
148-
k_ij,
127+
k_ij: binary_records,
149128
kappa,
150129
molarweight,
151130
pure_records,
152131
joback_records,
153-
binary_records,
154-
})
132+
}
133+
}
134+
135+
fn records(
136+
&self,
137+
) -> (
138+
&[PureRecord<PengRobinsonRecord, JobackRecord>],
139+
&Array2<f64>,
140+
) {
141+
(&self.pure_records, &self.k_ij)
155142
}
156143
}
157144

158145
pub struct PengRobinson {
159-
parameters: PengRobinsonParameters,
146+
parameters: Rc<PengRobinsonParameters>,
160147
}
161148

162149
impl PengRobinson {
163-
pub fn new(parameters: PengRobinsonParameters) -> Self {
150+
pub fn new(parameters: Rc<PengRobinsonParameters>) -> Self {
164151
Self { parameters }
165152
}
166153
}
@@ -171,7 +158,7 @@ impl EquationOfState for PengRobinson {
171158
}
172159

173160
fn subset(&self, component_list: &[usize]) -> Self {
174-
Self::new(self.parameters.subset(component_list))
161+
Self::new(Rc::new(self.parameters.subset(component_list)))
175162
}
176163

177164
fn compute_max_density(&self, moles: &Array1<f64>) -> f64 {
@@ -280,9 +267,9 @@ mod tests {
280267
let propane = mixture[0].clone();
281268
let tc = propane.model_record.clone().unwrap().tc;
282269
let pc = propane.model_record.clone().unwrap().pc;
283-
let parameters = PengRobinsonParameters::from_records(vec![propane.clone()], None)
284-
.expect("Error reading parameters!");
285-
let pr = Rc::new(PengRobinson::new(parameters));
270+
let parameters =
271+
PengRobinsonParameters::from_records(vec![propane.clone()], Array2::zeros((1, 1)));
272+
let pr = Rc::new(PengRobinson::new(Rc::new(parameters)));
286273
let cp = State::critical_point(&pr, None, None, VLEOptions::default())?;
287274
println!("{} {}", cp.temperature, cp.pressure(Contributions::Total));
288275
assert_relative_eq!(cp.temperature, tc * KELVIN, max_relative = 1e-4);

src/joback.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,7 @@ impl fmt::Display for JobackRecord {
4646
/// Implementation of the combining rules as described in
4747
/// [Joback and Reid, 1987](https://doi.org/10.1080/00986448708960487).
4848
impl FromSegments for JobackRecord {
49-
type Binary = ();
50-
fn from_segments(
51-
segments: &[(Self, f64)],
52-
_binary_records: Option<&[BinaryRecord<String, Self::Binary>]>,
53-
) -> Result<Self, ParameterError> {
49+
fn from_segments(segments: &[(Self, f64)]) -> Self {
5450
let mut a = -37.93;
5551
let mut b = 0.21;
5652
let mut c = -3.91e-4;
@@ -63,7 +59,7 @@ impl FromSegments for JobackRecord {
6359
d += s.d * *n;
6460
e += s.e * *n;
6561
});
66-
Ok(Self { a, b, c, d, e })
62+
Self { a, b, c, d, e }
6763
}
6864
}
6965

@@ -238,7 +234,7 @@ mod tests {
238234
.iter()
239235
.map(|(s, &n)| (s.ideal_gas_record.clone().unwrap(), n))
240236
.collect();
241-
let jr = JobackRecord::from_segments(&joback_segments, None).unwrap();
237+
let jr = JobackRecord::from_segments(&joback_segments);
242238
assert_relative_eq!(
243239
jr.a,
244240
33.3 * 2.0 - 2.14 * 4.0 - 8.25 * 2.0 - 37.93,

src/parameter/chemical_record.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ impl ChemicalRecord {
5656
Ok(counts)
5757
}
5858

59+
/// Count the number of occurences of each individual segment identifier in the
60+
/// chemical record.
61+
///
62+
/// The map contains the segment identifier as key and the count as (float) value.
63+
pub fn segment_id_count(&self) -> HashMap<String, f64> {
64+
let mut counts = HashMap::with_capacity(self.segments.len());
65+
for si in &self.segments {
66+
let entry = counts.entry(si.clone()).or_insert(0.0);
67+
*entry += 1.0;
68+
}
69+
counts
70+
}
71+
5972
/// Build a HashMap from SegmentRecords for the segments.
6073
///
6174
/// The map contains the segment identifier (String) as key
@@ -80,19 +93,6 @@ impl ChemicalRecord {
8093
.map(|s| segments.remove_entry(s).unwrap())
8194
.collect())
8295
}
83-
84-
/// Compute the molar weight from SegmentRecords
85-
pub fn molarweight_from_segments<M: Clone, I: Clone>(
86-
&self,
87-
segment_records: &[SegmentRecord<M, I>],
88-
) -> Result<f64, ParameterError> {
89-
let segment_map = self.segment_map(segment_records)?;
90-
Ok(self
91-
.segments
92-
.iter()
93-
.map(|s| segment_map.get(s).unwrap().molarweight)
94-
.sum())
95-
}
9696
}
9797

9898
impl std::fmt::Display for ChemicalRecord {

0 commit comments

Comments
 (0)