Source code for pygaps.modelling.wvst

"""Wilson-VST isotherm model."""

import numpy
from scipy import optimize

from pygaps.modelling.base_model import IsothermBaseModel
from pygaps.utilities.exceptions import CalculationError


[docs]class WVST(IsothermBaseModel): r""" Wilson Vacancy Solution Theory isotherm model. Notes ----- As a part of the Vacancy Solution Theory (VST) family of models, it is based on concept of a “vacancy” species, denoted v, and assumes that the system consists of a mixture of these vacancies and the adsorbate [#]_. The VST model is defined as follows: * A vacancy is an imaginary entity defined as a vacuum space which acts as the solvent in both the gas and adsorbed phases. * The properties of the adsorbed phase are defined as excess properties in relation to a dividing surface. * The entire system including the material are in thermal equilibrium however only the gas and adsorbed phases are in thermodynamic equilibrium. * The equilibrium of the system is maintained by the spreading pressure which arises from a potential field at the surface It is possible to derive expressions for the vacancy chemical potential in both the adsorbed phase and the gas phase, which when equated give the following equation of state for the adsorbed phase: .. math:: \pi = - \frac{R_g T}{\sigma_v} \ln{y_v x_v} where :math:`y_v` is the activity coefficient and :math:`x_v` is the mole fraction of the vacancy in the adsorbed phase. This can then be introduced into the Gibbs equation to give a general isotherm equation for the Vacancy Solution Theory where :math:`K_H` is the Henry’s constant and :math:`f(\theta)` is a function that describes the non-ideality of the system based on activity coefficients: .. math:: p = \frac{n_{ads}}{K_H} \frac{\theta}{1-\theta} f(\theta) The general VST equation requires an expression for the activity coefficients. The Wilson equation can be used, which expresses the activity coefficient in terms of the mole fractions of the two species (adsorbate and vacancy) and two constants :math:`\Lambda_{1v}` and :math:`\Lambda_{1v}`. The equation becomes: .. math:: p = \bigg( \frac{n_{ads}}{K_H} \frac{\theta}{1-\theta} \bigg) \bigg( \Lambda_{1v} \frac{1-(1-\Lambda_{v1})\theta}{\Lambda_{1v}+(1-\Lambda_{1v})\theta} \bigg) \exp{\bigg( -\frac{\Lambda_{v1}(1-\Lambda_{v1})\theta}{1-(1-\Lambda_{v1})\theta} -\frac{(1 - \Lambda_{1v})\theta}{\Lambda_{1v} + (1-\Lambda_{1v}\theta)} \bigg)} References ---------- .. [#] Suwanayuen, S.; Danner, R. P., Gas-Adsorption Isotherm Equation Based On Vacancy Solution Theory. AIChE Journal 1980, 26, (1), 68-76. """ # Model parameters name = 'WVST' calculates = 'pressure' param_names = ("n_m", "K", "L1v", "Lv1") param_default_bounds = ( (0, numpy.inf), (0, numpy.inf), (-numpy.inf, numpy.inf), (-numpy.inf, numpy.inf), )
[docs] def loading(self, pressure): """ Calculate loading at specified pressure. Careful! For the W-VST model, the loading has to be computed numerically. Parameters ---------- pressure : float The pressure at which to calculate the loading. Returns ------- float Loading at specified pressure. """ def fun(x): return self.pressure(x) - pressure opt_res = optimize.root(fun, numpy.zeros_like(pressure), method='hybr') if not opt_res.success: raise CalculationError(f"Root finding for value {pressure} failed.") return opt_res.x
[docs] def pressure(self, loading): """ Calculate pressure at specified loading. The W-VST model calculates the pressure directly. Parameters ---------- loading : float The loading at which to calculate the pressure. Returns ------- float Pressure at specified loading. """ n_m = self.params["n_m"] Lv1 = self.params["Lv1"] L1v = self.params["L1v"] cov = loading / n_m covX1minLv1 = (1 - Lv1) * cov covX1minL1v = (1 - L1v) * cov coef = L1v * (1 - covX1minLv1) / (L1v + covX1minL1v) expcoef = -((Lv1 * covX1minLv1) / (1 - covX1minLv1)) - (covX1minL1v / (L1v + covX1minL1v)) res = (n_m / self.params["K"] * cov / (1 - cov)) * coef * numpy.exp(expcoef) return res
[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 W-VST 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 NotImplementedError
[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, "L1v": 1, "Lv1": 1} guess = self.initial_guess_bounds(guess) return guess