Skip to content

Commit baf5330

Browse files
RolfStierleRolf Stierle
andauthored
Entropy scaling correlation functions for mixtures (#323)
* Entropy scaling correlation functions (viscosity, thermal conductivity, self-diffusion) corrected to be able to calculate mixtures. * Added test for mixture and pseudo mixture (pure substance as mixture) for viscosity * Changelog updated. --------- Co-authored-by: Rolf Stierle <rolf.stierle@itt.uni-stuttgart.de>
1 parent 864eee4 commit baf5330

File tree

3 files changed

+119
-20
lines changed

3 files changed

+119
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88
### Fixed
99
- Updated to `ndarray` 0.17 and `num-dual`0.13 to fix a broken dependency resolution. [#327](https://github.com/feos-org/feos/pull/327)
10+
- Fixed calculation of parameter combination in entropy scaling for mixtures in `viscosity_correlation`, `diffusion_correlation`, `thermal_conductivity_correlation`. [#323](https://github.com/feos-org/feos/pull/323)
1011

1112
## [0.9.1] - 2025-11-24
1213
### Fixed

crates/feos/src/pcsaft/eos/mod.rs

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,13 @@ impl EntropyScaling for PcSaft {
266266
.viscosity
267267
.as_ref()
268268
.expect("Missing viscosity coefficients.");
269-
let m = (x * &self.params.m).sum();
269+
let m = x.dot(&self.params.m);
270270
let s = s_res / m;
271-
let pref = (x * &self.params.m) / m;
272-
let a = coefficients.row(0).dot(x);
273-
let b = coefficients.row(1).dot(&pref);
274-
let c = coefficients.row(2).dot(&pref);
275-
let d = coefficients.row(3).dot(&pref);
271+
let pref = x.component_mul(&self.params.m) / m;
272+
let a = coefficients.row(0).transpose().dot(x);
273+
let b = coefficients.row(1).transpose().dot(&pref);
274+
let c = coefficients.row(2).transpose().dot(&pref);
275+
let d = coefficients.row(3).transpose().dot(&pref);
276276
a + b * s + c * s.powi(2) + d * s.powi(3)
277277
}
278278

@@ -307,14 +307,14 @@ impl EntropyScaling for PcSaft {
307307
.diffusion
308308
.as_ref()
309309
.expect("Missing diffusion coefficients.");
310-
let m = (x * &self.params.m).sum();
310+
let m = x.dot(&self.params.m);
311311
let s = s_res / m;
312-
let pref = (x * &self.params.m).map(|v| v / m);
313-
let a = coefficients.row(0).dot(x);
314-
let b = coefficients.row(1).dot(&pref);
315-
let c = coefficients.row(2).dot(&pref);
316-
let d = coefficients.row(3).dot(&pref);
317-
let e = coefficients.row(4).dot(&pref);
312+
let pref = x.component_mul(&self.params.m) / m;
313+
let a = coefficients.row(0).transpose().dot(x);
314+
let b = coefficients.row(1).transpose().dot(&pref);
315+
let c = coefficients.row(2).transpose().dot(&pref);
316+
let d = coefficients.row(3).transpose().dot(&pref);
317+
let e = coefficients.row(4).transpose().dot(&pref);
318318
a + b * s - c * (1.0 - s.exp()) * s.powi(2) - d * s.powi(4) - e * s.powi(8)
319319
}
320320

@@ -371,13 +371,13 @@ impl EntropyScaling for PcSaft {
371371
.thermal_conductivity
372372
.as_ref()
373373
.expect("Missing thermal conductivity coefficients");
374-
let m = (x * &self.params.m).sum();
374+
let m = x.dot(&self.params.m);
375375
let s = s_res / m;
376-
let pref = (x * &self.params.m).map(|v| v / m);
377-
let a = coefficients.row(0).dot(x);
378-
let b = coefficients.row(1).dot(&pref);
379-
let c = coefficients.row(2).dot(&pref);
380-
let d = coefficients.row(3).dot(&pref);
376+
let pref = x.component_mul(&self.params.m) / m;
377+
let a = coefficients.row(0).transpose().dot(x);
378+
let b = coefficients.row(1).transpose().dot(&pref);
379+
let c = coefficients.row(2).transpose().dot(&pref);
380+
let d = coefficients.row(3).transpose().dot(&pref);
381381
a + b * s + c * (1.0 - s.exp()) + d * s.powi(2)
382382
}
383383
}
@@ -386,7 +386,8 @@ impl EntropyScaling for PcSaft {
386386
mod tests {
387387
use super::*;
388388
use crate::pcsaft::parameters::utils::{
389-
butane_parameters, propane_butane_parameters, propane_parameters,
389+
butane_parameters, nonane_heptane_parameters, nonane_parameters, propane_butane_parameters,
390+
propane_parameters,
390391
};
391392
use approx::assert_relative_eq;
392393
use feos_core::*;
@@ -545,6 +546,28 @@ mod tests {
545546
Ok(())
546547
}
547548

549+
#[test]
550+
fn viscosity_mix() -> FeosResult<()> {
551+
// Test case: compare fig 15 of Lötgering-Lin 2018 (https://doi.org/10.1021/acs.iecr.7b04871)
552+
let e = &nonane_heptane_parameters();
553+
let nonane = &nonane_parameters();
554+
555+
let t = 303.15 * KELVIN;
556+
let p = 500.0 * BAR;
557+
let n = dvector![0.25, 0.75] * MOL;
558+
let viscosity_mix = State::new_npt(&e, t, p, &n, None)?.viscosity();
559+
let viscosity_paper = 0.68298 * MILLI * PASCAL * SECOND;
560+
assert_relative_eq!(viscosity_paper, viscosity_mix, epsilon = 1e-8);
561+
562+
// Make sure pure substance case is recovered
563+
let n_pseudo_mix = dvector![1.0, 0.0] * MOL;
564+
let viscosity_pseudo_mix = State::new_npt(&e, t, p, &n_pseudo_mix, None)?.viscosity();
565+
let n_nonane = dvector![1.0] * MOL;
566+
let viscosity_nonane = State::new_npt(&nonane, t, p, &n_nonane, None)?.viscosity();
567+
assert_relative_eq!(viscosity_pseudo_mix, viscosity_nonane, epsilon = 1e-15);
568+
Ok(())
569+
}
570+
548571
#[test]
549572
fn diffusion() -> FeosResult<()> {
550573
let e = &propane_parameters();

crates/feos/src/pcsaft/parameters.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,33 @@ pub mod utils {
391391
PcSaft::new(PcSaftParameters::new_pure(butane_record).unwrap())
392392
}
393393

394+
pub fn nonane_parameters() -> PcSaft {
395+
let nonane_json = r#"
396+
{
397+
"identifier": {
398+
"cas": "111-84-2",
399+
"name": "nonane",
400+
"iupac_name": "nonane",
401+
"smiles": "CCCCCCCCC",
402+
"inchi": "InChI=1S/C9H20/c1-3-5-7-9-8-6-4-2/h3-9H2,1-2H3",
403+
"formula": "C9H20"
404+
},
405+
"molarweight": 128.258,
406+
"m": 4.2079,
407+
"sigma": 3.8448,
408+
"epsilon_k": 244.51,
409+
"viscosity": [
410+
-1.4629,
411+
-3.0058,
412+
-0.5842,
413+
-0.1222
414+
]
415+
}"#;
416+
let nonane_record: PureRecord<PcSaftRecord, PcSaftAssociationRecord> =
417+
serde_json::from_str(nonane_json).expect("Unable to parse json.");
418+
PcSaft::new(PcSaftParameters::new_pure(nonane_record).unwrap())
419+
}
420+
394421
pub fn dme_parameters() -> PcSaftPars {
395422
let dme_json = r#"
396423
{
@@ -522,6 +549,54 @@ pub mod utils {
522549
PcSaft::new(PcSaftParameters::new_binary(binary_record, None, vec![]).unwrap())
523550
}
524551

552+
pub fn nonane_heptane_parameters() -> PcSaft {
553+
let binary_json = r#"[
554+
{
555+
"identifier": {
556+
"cas": "111-84-2",
557+
"name": "nonane",
558+
"iupac_name": "nonane",
559+
"smiles": "CCCCCCCCC",
560+
"inchi": "InChI=1S/C9H20/c1-3-5-7-9-8-6-4-2/h3-9H2,1-2H3",
561+
"formula": "C9H20"
562+
},
563+
"molarweight": 128.258,
564+
"m": 4.2079,
565+
"sigma": 3.8448,
566+
"epsilon_k": 244.51,
567+
"viscosity": [
568+
-1.4629,
569+
-3.0058,
570+
-0.5842,
571+
-0.1222
572+
]
573+
},
574+
{
575+
"identifier": {
576+
"cas": "142-82-5",
577+
"name": "heptane",
578+
"iupac_name": "heptane",
579+
"smiles": "CCCCCCC",
580+
"inchi": "InChI=1S/C7H16/c1-3-5-7-6-4-2/h3-7H2,1-2H3",
581+
"formula": "C7H16"
582+
},
583+
"molarweight": 100.204,
584+
"m": 3.4831,
585+
"sigma": 3.8049,
586+
"epsilon_k": 238.4,
587+
"viscosity": [
588+
-1.2979,
589+
-2.6936,
590+
-0.4951,
591+
-0.0988
592+
]
593+
}
594+
]"#;
595+
let binary_record: [PureRecord<PcSaftRecord, PcSaftAssociationRecord>; 2] =
596+
serde_json::from_str(binary_json).expect("Unable to parse json.");
597+
PcSaft::new(PcSaftParameters::new_binary(binary_record, None, vec![]).unwrap())
598+
}
599+
525600
#[test]
526601
pub fn test_kij() -> FeosResult<()> {
527602
let ch3: String = "CH3".into();

0 commit comments

Comments
 (0)