|
1 | 1 | use crate::adsorption::{ExternalPotential, FluidParameters}; |
2 | 2 | use crate::convolver::ConvolverFFT; |
3 | 3 | use crate::functional::{HelmholtzEnergyFunctional, DFT}; |
| 4 | +use crate::functional_contribution::FunctionalContribution; |
4 | 5 | use crate::geometry::{Axis, AxisGeometry, Grid}; |
5 | 6 | use crate::profile::{DFTProfile, CUTOFF_RADIUS, MAX_POTENTIAL}; |
6 | 7 | use crate::solver::DFTSolver; |
7 | | -use feos_core::{Contributions, EosResult, EosUnit, State}; |
| 8 | +use feos_core::{Contributions, EosResult, EosUnit, State, StateBuilder}; |
8 | 9 | use ndarray::prelude::*; |
9 | 10 | use ndarray::Axis as Axis_nd; |
10 | 11 | use ndarray::Zip; |
11 | 12 | use ndarray_stats::QuantileExt; |
12 | 13 | use quantity::{QuantityArray2, QuantityScalar}; |
| 14 | +use std::rc::Rc; |
13 | 15 |
|
14 | 16 | const POTENTIAL_OFFSET: f64 = 2.0; |
15 | 17 | const DEFAULT_GRID_POINTS: usize = 2048; |
@@ -76,16 +78,36 @@ impl<U> Pore3D<U> { |
76 | 78 | } |
77 | 79 |
|
78 | 80 | /// Trait for the generic implementation of adsorption applications. |
79 | | -pub trait PoreSpecification<U, D: Dimension, F> { |
| 81 | +pub trait PoreSpecification<U: EosUnit, D: Dimension> { |
80 | 82 | /// Initialize a new single pore. |
81 | | - fn initialize( |
| 83 | + fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>( |
82 | 84 | &self, |
83 | 85 | bulk: &State<U, DFT<F>>, |
84 | 86 | external_potential: Option<&Array<f64, D::Larger>>, |
85 | 87 | ) -> EosResult<PoreProfile<U, D, F>>; |
86 | 88 |
|
87 | 89 | /// Return the number of spatial dimensions of the pore. |
88 | 90 | fn dimension(&self) -> i32; |
| 91 | + |
| 92 | + /// Return the pore volume using Helium at 298 K as reference. |
| 93 | + fn pore_volume(&self) -> EosResult<QuantityScalar<U>> |
| 94 | + where |
| 95 | + D::Larger: Dimension<Smaller = D>, |
| 96 | + { |
| 97 | + let bulk = StateBuilder::new(&Rc::new(Helium::new())) |
| 98 | + .temperature(298.0 * U::reference_temperature()) |
| 99 | + .volume(U::reference_volume()) |
| 100 | + .build()?; |
| 101 | + let pore = self.initialize(&bulk, None)?; |
| 102 | + let pot = pore |
| 103 | + .profile |
| 104 | + .external_potential |
| 105 | + .index_axis(Axis(0), 0) |
| 106 | + .mapv(|v| (-v).exp()) |
| 107 | + * U::reference_temperature() |
| 108 | + / U::reference_temperature(); |
| 109 | + Ok(pore.profile.integrate(&pot)) |
| 110 | + } |
89 | 111 | } |
90 | 112 |
|
91 | 113 | /// Density profile and properties of a confined system in arbitrary dimensions. |
@@ -149,10 +171,8 @@ where |
149 | 171 | } |
150 | 172 | } |
151 | 173 |
|
152 | | -impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecification<U, Ix1, F> |
153 | | - for Pore1D<U> |
154 | | -{ |
155 | | - fn initialize( |
| 174 | +impl<U: EosUnit> PoreSpecification<U, Ix1> for Pore1D<U> { |
| 175 | + fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>( |
156 | 176 | &self, |
157 | 177 | bulk: &State<U, DFT<F>>, |
158 | 178 | external_potential: Option<&Array2<f64>>, |
@@ -203,10 +223,8 @@ impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecificati |
203 | 223 | } |
204 | 224 | } |
205 | 225 |
|
206 | | -impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecification<U, Ix3, F> |
207 | | - for Pore3D<U> |
208 | | -{ |
209 | | - fn initialize( |
| 226 | +impl<U: EosUnit> PoreSpecification<U, Ix3> for Pore3D<U> { |
| 227 | + fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>( |
210 | 228 | &self, |
211 | 229 | bulk: &State<U, DFT<F>>, |
212 | 230 | external_potential: Option<&Array4<f64>>, |
@@ -420,3 +438,47 @@ fn calculate_distance2( |
420 | 438 | rx.powi(2) + ry.powi(2) + rz.powi(2) |
421 | 439 | }) |
422 | 440 | } |
| 441 | + |
| 442 | +const EPSILON_HE: f64 = 10.9; |
| 443 | +const SIGMA_HE: f64 = 2.64; |
| 444 | + |
| 445 | +struct Helium { |
| 446 | + epsilon: Array1<f64>, |
| 447 | + sigma: Array1<f64>, |
| 448 | +} |
| 449 | + |
| 450 | +impl Helium { |
| 451 | + fn new() -> DFT<Self> { |
| 452 | + let epsilon = arr1(&[EPSILON_HE]); |
| 453 | + let sigma = arr1(&[SIGMA_HE]); |
| 454 | + DFT::new_homosegmented(Self { epsilon, sigma }, &Array1::ones(1)) |
| 455 | + } |
| 456 | +} |
| 457 | + |
| 458 | +impl HelmholtzEnergyFunctional for Helium { |
| 459 | + fn contributions(&self) -> &[Box<dyn FunctionalContribution>] { |
| 460 | + &[] |
| 461 | + } |
| 462 | + |
| 463 | + fn subset(&self, _: &[usize]) -> DFT<Self> { |
| 464 | + Self::new() |
| 465 | + } |
| 466 | + |
| 467 | + fn compute_max_density(&self, _: &Array1<f64>) -> f64 { |
| 468 | + 1.0 |
| 469 | + } |
| 470 | +} |
| 471 | + |
| 472 | +impl FluidParameters for Helium { |
| 473 | + fn epsilon_k_ff(&self) -> Array1<f64> { |
| 474 | + self.epsilon.clone() |
| 475 | + } |
| 476 | + |
| 477 | + fn sigma_ff(&self) -> &Array1<f64> { |
| 478 | + &self.sigma |
| 479 | + } |
| 480 | + |
| 481 | + fn m(&self) -> Array1<f64> { |
| 482 | + arr1(&[1.0]) |
| 483 | + } |
| 484 | +} |
0 commit comments