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
Add calculation of reference pore volumes
  • Loading branch information
prehner committed Feb 16, 2022
commit f2453e645246b521a763273f38957f0e26e02724
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- The pore volume using Helium at 298 K as reference is now directly accesible from `Pore1D` and `Pore3D`. [#12](https://github.com/feos-org/feos-core/pull/12)

## [0.1.1] - 2022-02-14
### Added
Expand Down
22 changes: 11 additions & 11 deletions examples/FundamentalMeasureTheory.ipynb

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions src/adsorption/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ where
})
}

fn equilibrium<D: Dimension, F: HelmholtzEnergyFunctional>(
fn equilibrium<D: Dimension, F: HelmholtzEnergyFunctional + FluidParameters>(
&self,
equilibrium: &Adsorption<U, D, F>,
) -> EosResult<(QuantityArray1<U>, QuantityArray1<U>)>
Expand Down Expand Up @@ -111,12 +111,12 @@ pub type Adsorption1D<U, F> = Adsorption<U, Ix1, F>;
/// Container structure for adsorption isotherms in 3D pores.
pub type Adsorption3D<U, F> = Adsorption<U, Ix3, F>;

impl<U: EosUnit, D: Dimension, F: HelmholtzEnergyFunctional> Adsorption<U, D, F>
impl<U: EosUnit, D: Dimension, F: HelmholtzEnergyFunctional + FluidParameters> Adsorption<U, D, F>
where
QuantityScalar<U>: std::fmt::Display,
D::Larger: Dimension<Smaller = D>,
{
fn new<S: PoreSpecification<U, D, F>>(
fn new<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
pore: &S,
profiles: Vec<EosResult<PoreProfile<U, D, F>>>,
Expand All @@ -129,7 +129,7 @@ where
}

/// Calculate an adsorption isotherm (starting at low pressure)
pub fn adsorption_isotherm<S: PoreSpecification<U, D, F>>(
pub fn adsorption_isotherm<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
temperature: QuantityScalar<U>,
pressure: &PressureSpecification<U>,
Expand All @@ -142,7 +142,7 @@ where
}

/// Calculate an desorption isotherm (starting at high pressure)
pub fn desorption_isotherm<S: PoreSpecification<U, D, F>>(
pub fn desorption_isotherm<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
temperature: QuantityScalar<U>,
pressure: &PressureSpecification<U>,
Expand All @@ -162,7 +162,7 @@ where
}

/// Calculate an equilibrium isotherm
pub fn equilibrium_isotherm<S: PoreSpecification<U, D, F>>(
pub fn equilibrium_isotherm<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
temperature: QuantityScalar<U>,
pressure: &PressureSpecification<U>,
Expand Down Expand Up @@ -241,7 +241,7 @@ where
}
}

fn isotherm<S: PoreSpecification<U, D, F>>(
fn isotherm<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
temperature: QuantityScalar<U>,
pressure: &QuantityArray1<U>,
Expand Down Expand Up @@ -291,7 +291,7 @@ where
}

/// Calculate the phase transition from an empty to a filled pore.
pub fn phase_equilibrium<S: PoreSpecification<U, D, F>>(
pub fn phase_equilibrium<S: PoreSpecification<U, D>>(
functional: &Rc<DFT<F>>,
temperature: QuantityScalar<U>,
p_min: QuantityScalar<U>,
Expand Down
84 changes: 73 additions & 11 deletions src/adsorption/pore.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use crate::adsorption::{ExternalPotential, FluidParameters};
use crate::convolver::ConvolverFFT;
use crate::functional::{HelmholtzEnergyFunctional, DFT};
use crate::functional_contribution::FunctionalContribution;
use crate::geometry::{Axis, AxisGeometry, Grid};
use crate::profile::{DFTProfile, CUTOFF_RADIUS, MAX_POTENTIAL};
use crate::solver::DFTSolver;
use feos_core::{Contributions, EosResult, EosUnit, State};
use feos_core::{Contributions, EosResult, EosUnit, State, StateBuilder};
use ndarray::prelude::*;
use ndarray::Axis as Axis_nd;
use ndarray::Zip;
use ndarray_stats::QuantileExt;
use quantity::{QuantityArray2, QuantityScalar};
use std::rc::Rc;

const POTENTIAL_OFFSET: f64 = 2.0;
const DEFAULT_GRID_POINTS: usize = 2048;
Expand Down Expand Up @@ -76,16 +78,36 @@ impl<U> Pore3D<U> {
}

/// Trait for the generic implementation of adsorption applications.
pub trait PoreSpecification<U, D: Dimension, F> {
pub trait PoreSpecification<U: EosUnit, D: Dimension> {
/// Initialize a new single pore.
fn initialize(
fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>(
&self,
bulk: &State<U, DFT<F>>,
external_potential: Option<&Array<f64, D::Larger>>,
) -> EosResult<PoreProfile<U, D, F>>;

/// Return the number of spatial dimensions of the pore.
fn dimension(&self) -> i32;

/// Return the pore volume using Helium at 298 K as reference.
fn pore_volume(&self) -> EosResult<QuantityScalar<U>>
where
D::Larger: Dimension<Smaller = D>,
{
let bulk = StateBuilder::new(&Rc::new(Helium::new()))
.temperature(298.0 * U::reference_temperature())
.volume(U::reference_volume())
.build()?;
let pore = self.initialize(&bulk, None)?;
let pot = pore
.profile
.external_potential
.index_axis(Axis(0), 0)
.mapv(|v| (-v).exp())
* U::reference_temperature()
/ U::reference_temperature();
Ok(pore.profile.integrate(&pot))
}
}

/// Density profile and properties of a confined system in arbitrary dimensions.
Expand Down Expand Up @@ -149,10 +171,8 @@ where
}
}

impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecification<U, Ix1, F>
for Pore1D<U>
{
fn initialize(
impl<U: EosUnit> PoreSpecification<U, Ix1> for Pore1D<U> {
fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>(
&self,
bulk: &State<U, DFT<F>>,
external_potential: Option<&Array2<f64>>,
Expand Down Expand Up @@ -203,10 +223,8 @@ impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecificati
}
}

impl<U: EosUnit, F: HelmholtzEnergyFunctional + FluidParameters> PoreSpecification<U, Ix3, F>
for Pore3D<U>
{
fn initialize(
impl<U: EosUnit> PoreSpecification<U, Ix3> for Pore3D<U> {
fn initialize<F: HelmholtzEnergyFunctional + FluidParameters>(
&self,
bulk: &State<U, DFT<F>>,
external_potential: Option<&Array4<f64>>,
Expand Down Expand Up @@ -420,3 +438,47 @@ fn calculate_distance2(
rx.powi(2) + ry.powi(2) + rz.powi(2)
})
}

const EPSILON_HE: f64 = 10.9;
const SIGMA_HE: f64 = 2.64;

struct Helium {
epsilon: Array1<f64>,
sigma: Array1<f64>,
}

impl Helium {
fn new() -> DFT<Self> {
let epsilon = arr1(&[EPSILON_HE]);
let sigma = arr1(&[SIGMA_HE]);
DFT::new_homosegmented(Self { epsilon, sigma }, &Array1::ones(1))
}
}

impl HelmholtzEnergyFunctional for Helium {
fn contributions(&self) -> &[Box<dyn FunctionalContribution>] {
&[]
}

fn subset(&self, _: &[usize]) -> DFT<Self> {
Self::new()
}

fn compute_max_density(&self, _: &Array1<f64>) -> f64 {
1.0
}
}

impl FluidParameters for Helium {
fn epsilon_k_ff(&self) -> Array1<f64> {
self.epsilon.clone()
}

fn sigma_ff(&self) -> &Array1<f64> {
&self.sigma
}

fn m(&self) -> Array1<f64> {
arr1(&[1.0])
}
}
2 changes: 1 addition & 1 deletion src/python/adsorption/external_potential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl PyExternalPotential {
/// Returns
/// -------
/// Geometry
#[pyclass(name = "Geometry", unsendable)]
#[pyclass(name = "Geometry")]
#[derive(Clone)]
pub struct PyGeometry(pub AxisGeometry);

Expand Down
6 changes: 6 additions & 0 deletions src/python/adsorption/pore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ macro_rules! impl_pore {
external_potential.map(|e| e.to_owned_array()).as_ref(),
)?))
}

/// The pore volume using Helium at 298 K as reference.
#[getter]
fn get_pore_volume(&self) -> PyResult<PySINumber> {
Ok(self.0.pore_volume()?.into())
}
}

#[pymethods]
Expand Down