feos_dft/interface/
surface_tension_diagram.rs1use super::PlanarInterface;
2use crate::functional::{HelmholtzEnergyFunctional, DFT};
3use crate::solver::DFTSolver;
4use feos_core::{PhaseEquilibrium, ReferenceSystem, StateVec};
5use ndarray::{Array1, Array2};
6use quantity::{Length, Moles, SurfaceTension, Temperature};
7
8const DEFAULT_GRID_POINTS: usize = 2048;
9
10pub struct SurfaceTensionDiagram<F: HelmholtzEnergyFunctional> {
12 pub profiles: Vec<PlanarInterface<F>>,
13}
14
15impl<F: HelmholtzEnergyFunctional> SurfaceTensionDiagram<F> {
17 pub fn new(
18 dia: &[PhaseEquilibrium<DFT<F>, 2>],
19 init_densities: Option<bool>,
20 n_grid: Option<usize>,
21 l_grid: Option<Length>,
22 critical_temperature: Option<Temperature>,
23 fix_equimolar_surface: Option<bool>,
24 solver: Option<&DFTSolver>,
25 ) -> Self {
26 let n_grid = n_grid.unwrap_or(DEFAULT_GRID_POINTS);
27 let mut profiles: Vec<PlanarInterface<F>> = Vec::with_capacity(dia.len());
28 for vle in dia.iter() {
29 let profile = if PhaseEquilibrium::is_trivial_solution(vle.vapor(), vle.liquid()) {
31 Ok(PlanarInterface::from_tanh(
32 vle,
33 10,
34 Length::from_reduced(100.0),
35 Temperature::from_reduced(500.0),
36 fix_equimolar_surface.unwrap_or(false),
37 ))
38 } else {
39 if vle.vapor().eos.component_index().len() == 1 {
41 PlanarInterface::from_pdgt(vle, n_grid, false)
42 } else {
43 Ok(PlanarInterface::from_tanh(
44 vle,
45 n_grid,
46 l_grid.unwrap_or(Length::from_reduced(100.0)),
47 critical_temperature.unwrap_or(Temperature::from_reduced(500.0)),
48 fix_equimolar_surface.unwrap_or(false),
49 ))
50 }
51 .map(|mut profile| {
52 if let Some(init) = profiles.last() {
53 if init.profile.density.shape() == profile.profile.density.shape() {
54 if let Some(scale) = init_densities {
55 profile.set_density_inplace(&init.profile.density, scale)
56 }
57 }
58 }
59 profile
60 })
61 }
62 .and_then(|profile| profile.solve(solver));
63 if let Ok(profile) = profile {
64 profiles.push(profile);
65 }
66 }
67 Self { profiles }
68 }
69
70 pub fn vapor(&self) -> StateVec<'_, DFT<F>> {
71 self.profiles.iter().map(|p| p.vle.vapor()).collect()
72 }
73
74 pub fn liquid(&self) -> StateVec<'_, DFT<F>> {
75 self.profiles.iter().map(|p| p.vle.liquid()).collect()
76 }
77
78 pub fn surface_tension(&mut self) -> SurfaceTension<Array1<f64>> {
79 SurfaceTension::from_shape_fn(self.profiles.len(), |i| {
80 self.profiles[i].surface_tension.unwrap()
81 })
82 }
83
84 pub fn relative_adsorption(&self) -> Vec<Moles<Array2<f64>>> {
85 self.profiles
86 .iter()
87 .map(|planar_interf| planar_interf.relative_adsorption())
88 .collect()
89 }
90
91 pub fn interfacial_enrichment(&self) -> Vec<Array1<f64>> {
92 self.profiles
93 .iter()
94 .map(|planar_interf| planar_interf.interfacial_enrichment())
95 .collect()
96 }
97
98 pub fn interfacial_thickness(&self) -> Length<Array1<f64>> {
99 self.profiles
100 .iter()
101 .map(|planar_interf| planar_interf.interfacial_thickness().unwrap())
102 .collect()
103 }
104}