"""Langmuir isotherm model."""
import numpy
from pygaps.modelling.base_model import IsothermBaseModel
[docs]class Langmuir(IsothermBaseModel):
r"""
Langmuir isotherm model.
.. math::
n(p) = n_m\frac{K p}{1 + K p}
Notes
-----
The Langmuir theory [#]_, proposed at the start of the 20th century, states that
adsorption takes place on specific sites on a surface, until
all sites are occupied.
It was originally derived from a kinetic model of gas adsorption and
is based on several assumptions.
* All sites are equivalent and have the same chance of being occupied
* Each adsorbate molecule can occupy one adsorption site
* There are no interactions between adsorbed molecules
* The rates of adsorption and desorption are proportional to the number of
sites currently free and currently occupied, respectively
* Adsorption is complete when all sites are filled.
Using these assumptions we can define rates for both adsorption and
desorption. The adsorption rate :math:`r_a`
will be proportional to the number of sites available on
the surface, as well as the number of molecules in the gas,
which is given by pressure.
The desorption rate :math:`r_d`, on the other hand, will
be proportional to the number of occupied sites and the energy
of adsorption. It is also useful to define
:math:`\theta = n_{ads}/n_{ads}^m` as the fractional
surface coverage, the number of sites occupied divided by the total
sites. At equilibrium, the rate of adsorption and the rate of
desorption are equal, therefore the two equations can be combined.
The equation can then be arranged to obtain an expression for the
loading called the Langmuir model. Mathematically:
.. math::
r_a = k_a p (1 - \theta)
r_d = k_d \theta \exp{\Big(-\frac{E_{ads}}{R_g T}\Big)}
At equilibrium, the rate of adsorption and the rate of
desorption are equal, therefore the two equations can be combined.
.. math::
k_a p (1 - \theta) = k_d \theta \exp{\Big(-\frac{E_{ads}}{R_gT}\Big)}
Rearranging to get an expression for the loading, the Langmuir equation becomes:
.. math::
n(p) = n_m \frac{K p}{1 + K p}
Here, :math:`n_m` is the moles adsorbed at the completion of the
monolayer, and therefore the maximum possible loading.
The Langmuir constant is the product of the individual desorption
and adsorption constants :math:`k_a` and :math:`k_d` and exponentially
related to the energy of adsorption
:math:`\exp{(-\frac{E}{RT})}`.
References
----------
.. [#] I. Langmuir, J. American Chemical Society 38, 2219(1916); 40, 1368(1918)
"""
# Model parameters
name = 'Langmuir'
formula = r"n(p) = n_m\frac{K p}{1 + K p}"
calculates = 'loading'
param_names = ("K", "n_m")
param_default_bounds = (
(0., numpy.inf),
(0., numpy.inf),
)
[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.
"""
kp = self.params["K"] * pressure
return self.params["n_m"] * kp / (1.0 + kp)
[docs] def pressure(self, loading):
r"""
Calculate pressure at specified loading.
For the Langmuir model, a direct relationship can be found
by rearranging the function.
.. math::
p = \frac{n}{K (n_m - n)}
Parameters
----------
loading : float
The loading at which to calculate the pressure.
Returns
-------
float
Pressure at specified loading.
"""
return loading / (self.params["K"] * (self.params["n_m"] - loading))
[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 Langmuir model is solved analytically.
.. math::
\pi = n_m \log{1 + K p}
Parameters
----------
pressure : float
The pressure at which to calculate the spreading pressure.
Returns
-------
float
Spreading pressure at specified pressure.
"""
return self.params["n_m"] * numpy.log(1.0 + self.params["K"] * pressure)
[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, "K": langmuir_k}
guess = self.initial_guess_bounds(guess)
return guess