Source code for pygaps.characterisation.models_kelvin

"""
Module contains functions to calculate the critical
evaporation/condensation pore radius the mesopore range,
as a function of pressure.
"""
import typing as t
from functools import partial

import numpy
from scipy import constants

from pygaps.utilities.exceptions import ParameterError


[docs]def get_meniscus_geometry(branch: str, pore_geometry: str): """ Determine the meniscus geometry. Parameters ---------- branch : {'ads', 'des'} Branch of the isotherm used. geometry : {'slit', 'cylinder', 'halfopen-cylinder', 'sphere'} Geometry of the pore. Returns ------- str Geometry of the meniscus in the pore. """ if branch == 'ads': if pore_geometry == 'slit': m_geometry = 'hemicylindrical' elif pore_geometry == 'cylinder': m_geometry = 'cylindrical' elif pore_geometry == 'halfopen-cylinder': m_geometry = 'hemispherical' elif pore_geometry == 'sphere': m_geometry = 'hemispherical' else: raise ParameterError( "Pore geometry must be either 'slit', 'cylinder', 'halfopen-cylinder', or 'sphere'" ) elif branch == 'des': if pore_geometry == 'slit': m_geometry = 'hemicylindrical' elif pore_geometry == 'cylinder': m_geometry = 'hemispherical' elif pore_geometry == 'halfopen-cylinder': m_geometry = 'hemispherical' elif pore_geometry == 'sphere': m_geometry = 'hemispherical' else: raise ParameterError( "Pore geometry must be either 'slit', 'cylinder', 'halfopen-cylinder', or 'sphere'" ) else: raise ParameterError("Adsorption branch must be either 'ads' or 'des'.") return m_geometry
[docs]def kelvin_radius( pressure: "list[float]", meniscus_geometry: str, temperature: float, liquid_density: float, adsorbate_molar_mass: float, adsorbate_surface_tension: float, ): r""" Calculate the kelvin radius of the pore, using the standard form of the kelvin equation. Parameters ---------- pressure : Relative pressure (p/p0), unitless. meniscus_geometry : str Geometry of the interface of the vapour and liquid phase. **WARNING**: it is not the same as the pore geometry. temperature : float Temperature in kelvin. liquid_density : float Density of the adsorbed phase, assuming it can be approximated as a liquid g/cm3. adsorbate_molar_mass : float Molar area of the adsorbate, g/mol. adsorbate_surface_tension : float Surface tension of the adsorbate, in mN/m. Returns ------- float Kelvin radius(nm). Notes ----- *Description* The standard kelvin equation for determining critical pore radius for condensation or evaporation. .. math:: \ln\Big(\frac{p}{p_0}\Big) = -\frac{2 \cos\theta M_m \gamma}{r_K\rho_l RT} *Limitations* The Kelvin equation assumes that adsorption in a pore is not different than adsorption on a standard surface. Therefore, no interactions with the adsorbent is accounted for. Furthermore, the geometry of the pore itself is considered to be invariant accross the entire adsorbate. See Also -------- pygaps.characterisation.models_kelvin.kelvin_radius_kjs : KJS corrected Kelvin function """ # Define geometry factor depending on meniscus if meniscus_geometry == 'cylindrical': geometry_factor = 2.0 elif meniscus_geometry == 'hemispherical': geometry_factor = 1.0 elif meniscus_geometry == 'hemicylindrical': geometry_factor = 0.5 adsorbate_molar_density = adsorbate_molar_mass / liquid_density return - (2 * adsorbate_surface_tension * adsorbate_molar_density) / \ (geometry_factor * constants.gas_constant * temperature * numpy.log(pressure))
[docs]def kelvin_radius_kjs( pressure: "list[float]", meniscus_geometry: str, temperature: float, liquid_density: float, adsorbate_molar_mass: float, adsorbate_surface_tension: float, ): r""" Calculate the kelvin radius of the pore, using the Kruck-Jaroniec-Sayari correction. Parameters ---------- pressure : Relative pressure (p/p0), unitless. meniscus_geometry : str Geometry of the interface of the vapour and liquid phase. **WARNING**: it is not the same as the pore geometry. temperature : float Temperature in kelvin. liquid_density : float Density of the adsorbed phase, assuming it can be approximated as a liquid g/cm3. adsorbate_molar_mass : float Molar area of the adsorbate, g/mol. adsorbate_surface_tension : float Surface tension of the adsorbate, in mN/m. Returns ------- float Kelvin radius(nm). Notes ----- *Description* The KJS correction to the kelvin equation equation is modified with a constant term of 0.3 nm. The authors arrived at this constant by using the adsorption branch of the isotherm on several MCM-41 materials calibrated with XRD data. .. math:: \ln\Big(\frac{p}{p_0}\Big) = -\frac{2 \cos\theta M_m \gamma}{r_K\rho_l RT} + 0.3 *Limitations* Besides the standard limitations of the Kelvin equation, the KJS correction is empirical in nature. References ---------- .. [#] M. Kruk, M. Jaroniec, A. Sayari, Langmuir 13, 6267 (1997) See Also -------- pygaps.characterisation.models_kelvin.kelvin_radius : standard Kelvin function """ # Check for correct geometry if meniscus_geometry != 'cylindrical': raise ParameterError( "The KJS Kelvin correction is not applicable for meniscus " "geometries other than cylindrical (adsorption branch + cylindrical pore geometry)." ) adsorbate_molar_density = adsorbate_molar_mass / liquid_density return - (2 * adsorbate_surface_tension * adsorbate_molar_density) / \ (constants.gas_constant * temperature * numpy.log(pressure)) + 0.3
#: List of kelvin model functions _KELVIN_MODELS = { 'Kelvin': kelvin_radius, 'Kelvin-KJS': kelvin_radius_kjs, }
[docs]def get_kelvin_model(model: t.Union[str, t.Callable], **model_args): """ Return a function calculating an kelvin-based critical radius. The ``model`` parameter is a string which names the Kelvin model to be used. Alternatively, a user can implement their own model, as a function which returns the critical radius the adsorbed layer. In that case, instead of a string, pass a callable function as the ``model`` parameter. Parameters ---------- model : str or callable Name of the kelvin model to use or function that returns a critical radius. model_args: dict any arguments needed for the model Returns ------- callable A callable that takes pressure in and returns a critical kelvin radius at that point. Raises ------ ParameterError When string is not in the dictionary of models. """ # If the model is a string, get a model from the _THICKNESS_MODELS if isinstance(model, str): if model not in _KELVIN_MODELS: raise ParameterError( f"Model {model} not an implemented Kelvin model. ", f"Available models are {_KELVIN_MODELS.keys()}" ) return partial(_KELVIN_MODELS[model], **model_args) # If the model is an callable, return it instead else: return partial(model, **model_args)