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

Commit 984ab47

Browse files
authored
Make FMT functional more flexible w.r.t. the shape of the weight functions (#31)
* Make FMT functional more flexible * change return type to enum * update changelog
1 parent d6fa1d7 commit 984ab47

File tree

4 files changed

+55
-23
lines changed

4 files changed

+55
-23
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
### Added
99
- Added getters for the fields of `Pore1D` in Python. [#30](https://github.com/feos-org/feos-dft/pull/30)
1010

11+
### Changed
12+
- Made FMT functional more flexible w.r.t. the shape of the weight functions. [#31](https://github.com/feos-org/feos-dft/pull/31)
13+
1114
## [0.2.0] - 2022-04-12
1215
### Added
1316
- Added `grand_potential_density` getter for DFT profiles in Python. [#22](https://github.com/feos-org/feos-dft/pull/22)

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "feos-dft"
33
version = "0.2.0"
44
authors = ["Philipp Rehner <prehner@ethz.ch>"]
5-
edition = "2018"
5+
edition = "2021"
66
license = "MIT OR Apache-2.0"
77
description = "Generic classical DFT implementations for the `feos` project."
88
homepage = "https://github.com/feos-org"

src/functional.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,11 @@ impl<T: HelmholtzEnergyFunctional> EquationOfState for DFT<T> {
123123
pub enum MoleculeShape<'a> {
124124
/// For spherical molecules, the number of components.
125125
Spherical(usize),
126-
/// For non-spherical molecules in a homosegmented approach, the chain length parameter $m$.
126+
/// For non-spherical molecules in a homosegmented approach, the
127+
/// chain length parameter $m$.
127128
NonSpherical(&'a Array1<f64>),
128-
/// For non-spherical molecules in a heterosegmented approach, the component index for every segment.
129+
/// For non-spherical molecules in a heterosegmented approach,
130+
/// the component index for every segment.
129131
Heterosegmented(&'a Array1<usize>),
130132
}
131133

src/fundamental_measure_theory.rs

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,36 @@ use std::rc::Rc;
1414
const PI36M1: f64 = 1.0 / (36.0 * PI);
1515
const N3_CUTOFF: f64 = 1e-5;
1616

17+
/// Different monomer shapes for FMT.
18+
pub enum MonomerShape<'a, N> {
19+
/// For spherical monomers, the number of components.
20+
Spherical(usize),
21+
/// For non-spherical molecules in a homosegmented approach, the
22+
/// chain length parameter $m$.
23+
NonSpherical(&'a Array1<N>),
24+
/// For non-spherical molecules in a heterosegmented approach,
25+
/// the geometry factors for every segment.
26+
Heterosegmented([Array1<N>; 4]),
27+
}
28+
1729
/// Properties of (generalized) hard sphere systems.
1830
pub trait FMTProperties {
1931
fn component_index(&self) -> Array1<usize>;
20-
fn chain_length(&self) -> Array1<f64>;
32+
fn monomer_shape<N: DualNum<f64>>(&self, temperature: N) -> MonomerShape<N>;
2133
fn hs_diameter<N: DualNum<f64>>(&self, temperature: N) -> Array1<N>;
34+
35+
fn geometry_coefficients<N: DualNum<f64>>(&self, temperature: N) -> [Array1<N>; 4] {
36+
match self.monomer_shape(temperature) {
37+
MonomerShape::Spherical(n) => {
38+
let m = Array1::ones(n);
39+
[m.clone(), m.clone(), m.clone(), m]
40+
}
41+
MonomerShape::NonSpherical(m) => {
42+
[m.to_owned(), m.to_owned(), m.to_owned(), m.to_owned()]
43+
}
44+
MonomerShape::Heterosegmented(g) => g,
45+
}
46+
}
2247
}
2348

2449
/// Different versions of fundamental measure theory
@@ -60,8 +85,8 @@ impl<P> FMTContribution<P> {
6085
impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTContribution<P> {
6186
fn weight_functions(&self, temperature: N) -> WeightFunctionInfo<N> {
6287
let r = self.properties.hs_diameter(temperature) * 0.5;
63-
let m = self.properties.chain_length();
64-
match (self.version, m.len()) {
88+
let [c0, c1, c2, c3] = self.properties.geometry_coefficients(temperature);
89+
match (self.version, r.len()) {
6590
(FMTVersion::WhiteBear | FMTVersion::AntiSymWhiteBear, 1) => {
6691
WeightFunctionInfo::new(self.properties.component_index(), false).extend(
6792
vec![
@@ -70,8 +95,9 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
7095
WeightFunctionShape::DeltaVec,
7196
]
7297
.into_iter()
73-
.map(|s| WeightFunction {
74-
prefactor: self.properties.chain_length().mapv(|m| m.into()),
98+
.zip([c2, c3.clone(), c3])
99+
.map(|(s, c)| WeightFunction {
100+
prefactor: c,
75101
kernel_radius: r.clone(),
76102
shape: s,
77103
})
@@ -83,54 +109,54 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
83109
WeightFunctionInfo::new(self.properties.component_index(), false)
84110
.add(
85111
WeightFunction {
86-
prefactor: Zip::from(&m)
112+
prefactor: Zip::from(&c0)
87113
.and(&r)
88-
.map_collect(|&m, &r| r.powi(-2) * m / (4.0 * PI)),
114+
.map_collect(|&c, &r| r.powi(-2) * c / (4.0 * PI)),
89115
kernel_radius: r.clone(),
90116
shape: WeightFunctionShape::Delta,
91117
},
92118
true,
93119
)
94120
.add(
95121
WeightFunction {
96-
prefactor: Zip::from(&m)
122+
prefactor: Zip::from(&c1)
97123
.and(&r)
98-
.map_collect(|&m, &r| r.recip() * m / (4.0 * PI)),
124+
.map_collect(|&c, &r| r.recip() * c / (4.0 * PI)),
99125
kernel_radius: r.clone(),
100126
shape: WeightFunctionShape::Delta,
101127
},
102128
true,
103129
)
104130
.add(
105131
WeightFunction {
106-
prefactor: m.mapv(|m| m.into()),
132+
prefactor: c2,
107133
kernel_radius: r.clone(),
108134
shape: WeightFunctionShape::Delta,
109135
},
110136
true,
111137
)
112138
.add(
113139
WeightFunction {
114-
prefactor: m.mapv(|m| m.into()),
140+
prefactor: c3.clone(),
115141
kernel_radius: r.clone(),
116142
shape: WeightFunctionShape::Theta,
117143
},
118144
true,
119145
)
120146
.add(
121147
WeightFunction {
122-
prefactor: Zip::from(&m)
148+
prefactor: Zip::from(&c3)
123149
.and(&r)
124-
.map_collect(|&m, &r| r.recip() * m / (4.0 * PI)),
150+
.map_collect(|&c, &r| r.recip() * c / (4.0 * PI)),
125151
kernel_radius: r.clone(),
126152
shape: WeightFunctionShape::DeltaVec,
127153
},
128154
true,
129155
)
130156
.add(
131157
WeightFunction {
132-
prefactor: m.mapv(|m| m.into()),
133-
kernel_radius: r.clone(),
158+
prefactor: c3,
159+
kernel_radius: r,
134160
shape: WeightFunctionShape::DeltaVec,
135161
},
136162
true,
@@ -145,8 +171,9 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
145171
WeightFunctionShape::Theta,
146172
]
147173
.into_iter()
148-
.map(|s| WeightFunction {
149-
prefactor: self.properties.chain_length().mapv(|m| m.into()),
174+
.zip(self.properties.geometry_coefficients(temperature))
175+
.map(|(s, c)| WeightFunction {
176+
prefactor: c,
150177
kernel_radius: r.clone(),
151178
shape: s,
152179
})
@@ -165,7 +192,7 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
165192
let pure_component_weighted_densities = matches!(
166193
self.version,
167194
FMTVersion::WhiteBear | FMTVersion::AntiSymWhiteBear
168-
) && self.properties.chain_length().len() == 1;
195+
) && self.properties.component_index().len() == 1;
169196

170197
// scalar weighted densities
171198
let (n2, n3) = if pure_component_weighted_densities {
@@ -270,8 +297,8 @@ impl FMTProperties for HardSphereProperties {
270297
Array1::from_shape_fn(self.sigma.len(), |i| i)
271298
}
272299

273-
fn chain_length(&self) -> Array1<f64> {
274-
Array::ones(self.sigma.len())
300+
fn monomer_shape<N>(&self, _: N) -> MonomerShape<N> {
301+
MonomerShape::Spherical(self.sigma.len())
275302
}
276303

277304
fn hs_diameter<N: DualNum<f64>>(&self, _: N) -> Array1<N> {

0 commit comments

Comments
 (0)