From 0fe5201ebcf3dc6c2dab6bee12be4c0e05d297dc Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Mon, 6 Jun 2022 20:16:46 +0200 Subject: [PATCH 1/3] Make FMT functional more flexible --- Cargo.toml | 2 +- src/fundamental_measure_theory.rs | 41 ++++++++++++++++++------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a974e19..37a96e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "feos-dft" version = "0.2.0" authors = ["Philipp Rehner "] -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" diff --git a/src/fundamental_measure_theory.rs b/src/fundamental_measure_theory.rs index a8279e1..637a45b 100644 --- a/src/fundamental_measure_theory.rs +++ b/src/fundamental_measure_theory.rs @@ -19,6 +19,11 @@ pub trait FMTProperties { fn component_index(&self) -> Array1; fn chain_length(&self) -> Array1; fn hs_diameter>(&self, temperature: N) -> Array1; + + fn geometry_coefficients>(&self, _temperature: N) -> [Array1; 4] { + let m = self.chain_length().mapv(|m| N::from(m)); + [m.clone(), m.clone(), m.clone(), m] + } } /// Different versions of fundamental measure theory @@ -60,8 +65,8 @@ impl

FMTContribution

{ impl> FunctionalContributionDual for FMTContribution

{ fn weight_functions(&self, temperature: N) -> WeightFunctionInfo { 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![ @@ -70,8 +75,9 @@ impl> FunctionalContributionDual 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, }) @@ -83,9 +89,9 @@ impl> FunctionalContributionDual 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, }, @@ -93,9 +99,9 @@ impl> FunctionalContributionDual for FMTCon ) .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, }, @@ -103,7 +109,7 @@ impl> FunctionalContributionDual for FMTCon ) .add( WeightFunction { - prefactor: m.mapv(|m| m.into()), + prefactor: c2, kernel_radius: r.clone(), shape: WeightFunctionShape::Delta, }, @@ -111,7 +117,7 @@ impl> FunctionalContributionDual for FMTCon ) .add( WeightFunction { - prefactor: m.mapv(|m| m.into()), + prefactor: c3.clone(), kernel_radius: r.clone(), shape: WeightFunctionShape::Theta, }, @@ -119,9 +125,9 @@ impl> FunctionalContributionDual for FMTCon ) .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, }, @@ -129,8 +135,8 @@ impl> FunctionalContributionDual for FMTCon ) .add( WeightFunction { - prefactor: m.mapv(|m| m.into()), - kernel_radius: r.clone(), + prefactor: c3, + kernel_radius: r, shape: WeightFunctionShape::DeltaVec, }, true, @@ -145,8 +151,9 @@ impl> FunctionalContributionDual 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, }) @@ -165,7 +172,7 @@ impl> FunctionalContributionDual 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 { From 2cd5d8385c74fdbdd13a8f5ced406d5357e1e8f1 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Fri, 10 Jun 2022 09:36:07 +0200 Subject: [PATCH 2/3] change return type to enum --- src/functional.rs | 6 ++++-- src/fundamental_measure_theory.rs | 32 +++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index 8fe1818..33b9fcc 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -123,9 +123,11 @@ impl EquationOfState for DFT { 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), - /// 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), } diff --git a/src/fundamental_measure_theory.rs b/src/fundamental_measure_theory.rs index 637a45b..9112699 100644 --- a/src/fundamental_measure_theory.rs +++ b/src/fundamental_measure_theory.rs @@ -14,15 +14,35 @@ 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), + /// For non-spherical molecules in a heterosegmented approach, + /// the geometry factors for every segment. + Heterosegmented([Array1; 4]), +} + /// Properties of (generalized) hard sphere systems. pub trait FMTProperties { fn component_index(&self) -> Array1; - fn chain_length(&self) -> Array1; + fn monomer_shape>(&self, temperature: N) -> MonomerShape; fn hs_diameter>(&self, temperature: N) -> Array1; - fn geometry_coefficients>(&self, _temperature: N) -> [Array1; 4] { - let m = self.chain_length().mapv(|m| N::from(m)); - [m.clone(), m.clone(), m.clone(), m] + fn geometry_coefficients>(&self, temperature: N) -> [Array1; 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, + } } } @@ -277,8 +297,8 @@ impl FMTProperties for HardSphereProperties { Array1::from_shape_fn(self.sigma.len(), |i| i) } - fn chain_length(&self) -> Array1 { - Array::ones(self.sigma.len()) + fn monomer_shape(&self, _: N) -> MonomerShape { + MonomerShape::Spherical(self.sigma.len()) } fn hs_diameter>(&self, _: N) -> Array1 { From dce23d9c0fdb8757cbac84fc6873082c13a83184 Mon Sep 17 00:00:00 2001 From: Philipp Rehner Date: Fri, 10 Jun 2022 13:24:28 +0200 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae2c751..8e7f1d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)