Skip to content
This repository was archived by the owner on Jul 28, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added getters for the fields of `Pore1D` in Python. [#30](https://github.com/feos-org/feos-dft/pull/30)

### Changed
- Made FMT functional more flexible w.r.t. the shape of the weight functions. [#31](https://github.com/feos-org/feos-dft/pull/31)

## [0.2.0] - 2022-04-12
### Added
- Added `grand_potential_density` getter for DFT profiles in Python. [#22](https://github.com/feos-org/feos-dft/pull/22)
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "feos-dft"
version = "0.2.0"
authors = ["Philipp Rehner <prehner@ethz.ch>"]
edition = "2018"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Generic classical DFT implementations for the `feos` project."
homepage = "https://github.com/feos-org"
Expand Down
6 changes: 4 additions & 2 deletions src/functional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,11 @@ impl<T: HelmholtzEnergyFunctional> EquationOfState for DFT<T> {
pub enum MoleculeShape<'a> {
/// For spherical molecules, the number of components.
Spherical(usize),
/// For non-spherical molecules in a homosegmented approach, the chain length parameter $m$.
/// For non-spherical molecules in a homosegmented approach, the
/// chain length parameter $m$.
NonSpherical(&'a Array1<f64>),
/// For non-spherical molecules in a heterosegmented approach, the component index for every segment.
/// For non-spherical molecules in a heterosegmented approach,
/// the component index for every segment.
Heterosegmented(&'a Array1<usize>),
}

Expand Down
67 changes: 47 additions & 20 deletions src/fundamental_measure_theory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,36 @@ use std::rc::Rc;
const PI36M1: f64 = 1.0 / (36.0 * PI);
const N3_CUTOFF: f64 = 1e-5;

/// Different monomer shapes for FMT.
pub enum MonomerShape<'a, N> {
/// For spherical monomers, the number of components.
Spherical(usize),
/// For non-spherical molecules in a homosegmented approach, the
/// chain length parameter $m$.
NonSpherical(&'a Array1<N>),
/// For non-spherical molecules in a heterosegmented approach,
/// the geometry factors for every segment.
Heterosegmented([Array1<N>; 4]),
}

/// Properties of (generalized) hard sphere systems.
pub trait FMTProperties {
fn component_index(&self) -> Array1<usize>;
fn chain_length(&self) -> Array1<f64>;
fn monomer_shape<N: DualNum<f64>>(&self, temperature: N) -> MonomerShape<N>;
fn hs_diameter<N: DualNum<f64>>(&self, temperature: N) -> Array1<N>;

fn geometry_coefficients<N: DualNum<f64>>(&self, temperature: N) -> [Array1<N>; 4] {
match self.monomer_shape(temperature) {
MonomerShape::Spherical(n) => {
let m = Array1::ones(n);
[m.clone(), m.clone(), m.clone(), m]
}
MonomerShape::NonSpherical(m) => {
[m.to_owned(), m.to_owned(), m.to_owned(), m.to_owned()]
}
MonomerShape::Heterosegmented(g) => g,
}
}
}

/// Different versions of fundamental measure theory
Expand Down Expand Up @@ -60,8 +85,8 @@ impl<P> FMTContribution<P> {
impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTContribution<P> {
fn weight_functions(&self, temperature: N) -> WeightFunctionInfo<N> {
let r = self.properties.hs_diameter(temperature) * 0.5;
let m = self.properties.chain_length();
match (self.version, m.len()) {
let [c0, c1, c2, c3] = self.properties.geometry_coefficients(temperature);
match (self.version, r.len()) {
(FMTVersion::WhiteBear | FMTVersion::AntiSymWhiteBear, 1) => {
WeightFunctionInfo::new(self.properties.component_index(), false).extend(
vec![
Expand All @@ -70,8 +95,9 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
WeightFunctionShape::DeltaVec,
]
.into_iter()
.map(|s| WeightFunction {
prefactor: self.properties.chain_length().mapv(|m| m.into()),
.zip([c2, c3.clone(), c3])
.map(|(s, c)| WeightFunction {
prefactor: c,
kernel_radius: r.clone(),
shape: s,
})
Expand All @@ -83,54 +109,54 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
WeightFunctionInfo::new(self.properties.component_index(), false)
.add(
WeightFunction {
prefactor: Zip::from(&m)
prefactor: Zip::from(&c0)
.and(&r)
.map_collect(|&m, &r| r.powi(-2) * m / (4.0 * PI)),
.map_collect(|&c, &r| r.powi(-2) * c / (4.0 * PI)),
kernel_radius: r.clone(),
shape: WeightFunctionShape::Delta,
},
true,
)
.add(
WeightFunction {
prefactor: Zip::from(&m)
prefactor: Zip::from(&c1)
.and(&r)
.map_collect(|&m, &r| r.recip() * m / (4.0 * PI)),
.map_collect(|&c, &r| r.recip() * c / (4.0 * PI)),
kernel_radius: r.clone(),
shape: WeightFunctionShape::Delta,
},
true,
)
.add(
WeightFunction {
prefactor: m.mapv(|m| m.into()),
prefactor: c2,
kernel_radius: r.clone(),
shape: WeightFunctionShape::Delta,
},
true,
)
.add(
WeightFunction {
prefactor: m.mapv(|m| m.into()),
prefactor: c3.clone(),
kernel_radius: r.clone(),
shape: WeightFunctionShape::Theta,
},
true,
)
.add(
WeightFunction {
prefactor: Zip::from(&m)
prefactor: Zip::from(&c3)
.and(&r)
.map_collect(|&m, &r| r.recip() * m / (4.0 * PI)),
.map_collect(|&c, &r| r.recip() * c / (4.0 * PI)),
kernel_radius: r.clone(),
shape: WeightFunctionShape::DeltaVec,
},
true,
)
.add(
WeightFunction {
prefactor: m.mapv(|m| m.into()),
kernel_radius: r.clone(),
prefactor: c3,
kernel_radius: r,
shape: WeightFunctionShape::DeltaVec,
},
true,
Expand All @@ -145,8 +171,9 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
WeightFunctionShape::Theta,
]
.into_iter()
.map(|s| WeightFunction {
prefactor: self.properties.chain_length().mapv(|m| m.into()),
.zip(self.properties.geometry_coefficients(temperature))
.map(|(s, c)| WeightFunction {
prefactor: c,
kernel_radius: r.clone(),
shape: s,
})
Expand All @@ -165,7 +192,7 @@ impl<P: FMTProperties, N: DualNum<f64>> FunctionalContributionDual<N> for FMTCon
let pure_component_weighted_densities = matches!(
self.version,
FMTVersion::WhiteBear | FMTVersion::AntiSymWhiteBear
) && self.properties.chain_length().len() == 1;
) && self.properties.component_index().len() == 1;

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

fn chain_length(&self) -> Array1<f64> {
Array::ones(self.sigma.len())
fn monomer_shape<N>(&self, _: N) -> MonomerShape<N> {
MonomerShape::Spherical(self.sigma.len())
}

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