Source code for pygaps.modelling.da

"""Dubinin-Astakov isotherm model."""

import numpy
from scipy import constants
from scipy import integrate

from pygaps.modelling.base_model import IsothermBaseModel


[docs]class DA(IsothermBaseModel): r""" Dubinin-Astakov (DA) adsorption isotherm. .. math:: n(p) = n_t \exp\Big[-\Big(\frac{-RT\ln(p/p_0)}{\varepsilon}\Big)^{m}\Big] The pressure passed should be in a relative basis. Notes ----- The Dubinin-Astakov isotherm model [#]_ extends the Dubinin-Radushkevich model, itself based on the potential theory of Polanyi, which asserts that molecules near a surface are subjected to a potential field. The adsorbate at the surface is in a liquid state and its local pressure is conversely equal to the vapour pressure at the adsorption temperature. The Polanyi theory attempts to relate the surface coverage with the Gibbs free energy of adsorption, :math:`\Delta G^{ads} = - R T \ln p/p_0` and the total coverage :math:`\theta`. There are three parameters which define the model: * The total amount adsorbed (`n_t`), analogous to the monolayer capacity in the Langmuir model. * A potential energy term `e`. * A power term, `m`, which can vary between 1 and 3. The DA model becomes the DR model when m=2. It describes adsorption in a single uniform type of pores. To note that the model does not reduce to Henry's law at low pressure and is therefore not strictly physical. References ---------- .. [#] M. M. Dubinin, “Physical Adsorption of Gases and Vapors in Micropores,” in Progress in Surface and Membrane Science, vol. 9, Elsevier, 1975, pp. 1–70. """ # Model parameters name = 'DA' formula = r"n(p) = n_t \exp[-(\frac{-RT\ln(p/p_0)}{\varepsilon})^{m}]" calculates = 'loading' param_names = ("n_m", "e", "m") param_default_bounds = ( (0, numpy.inf), (0, numpy.inf), (1, 3), ) minus_rt = -1000 # initial value for guess def __init_parameters__(self, params): """Initialize model parameters from isotherm data.""" self.minus_rt = -constants.gas_constant * params['temperature']
[docs] def loading(self, pressure): """ Calculate loading at specified pressure. Parameters ---------- pressure : float The pressure at which to calculate the loading. Returns ------- float Loading at specified pressure. """ nm = self.params['n_m'] e = self.params['e'] m = self.params['m'] return nm * numpy.exp(-(self.minus_rt * numpy.log(pressure) / e)**m)
[docs] def pressure(self, loading): r""" Calculate pressure at specified loading. For the DA model, a direct relationship can be found analytically. .. math:: p/p_0 = \exp\Big( -\frac{\varepsilon}{RT}\sqrt[m]{-\ln n/n_m} \Big) Parameters ---------- loading : float The loading at which to calculate the pressure. Returns ------- float Pressure at specified loading. """ nm = self.params['n_m'] e = self.params['e'] m = self.params['m'] return numpy.exp(e / self.minus_rt * numpy.power(-numpy.log(loading / nm), 1 / m))
[docs] def spreading_pressure(self, pressure): r""" Calculate spreading pressure at specified gas pressure. Function that calculates spreading pressure by solving the following integral at each point i. .. math:: \pi = \int_{0}^{p_i} \frac{n_i(p_i)}{p_i} dp_i The integral for the DA model cannot be solved analytically and must be calculated numerically. Parameters ---------- pressure : float The pressure at which to calculate the spreading pressure. Returns ------- float Spreading pressure at specified pressure. """ return integrate.quad(lambda x: self.loading(x) / x, 0, pressure)[0]
[docs] def initial_guess(self, pressure, loading): """ Return initial guess for fitting. Parameters ---------- pressure : ndarray Pressure data. loading : ndarray Loading data. Returns ------- dict Dictionary of initial guesses for the parameters. """ saturation_loading, langmuir_k = super().initial_guess(pressure, loading) guess = {"n_m": saturation_loading, "e": -self.minus_rt, "m": 1} guess = self.initial_guess_bounds(guess) return guess