Microporous pore size distribution#

Module doc#

This module contains 'classical' methods of calculating a pore size distribution for pores in the micropore range (<2 nm). These are derived from the Horvath-Kawazoe models.

pygaps.characterisation.psd_micro.psd_microporous(isotherm: PointIsotherm | ModelIsotherm, psd_model: str = 'HK', pore_geometry: str = 'slit', branch: str = 'ads', material_model: str | dict[str, float] = 'Carbon(HK)', adsorbate_model: str | dict[str, float] = None, p_limits: tuple[float, float] = None, verbose: bool = False) dict[str, list[float]][source]#

Calculate the microporous size distribution using a Horvath-Kawazoe type model.

Expected pore geometry must be specified as pore_geometry.

Parameters:
  • isotherm (PointIsotherm, ModelIsotherm) -- Isotherm for which the pore size distribution will be calculated.

  • psd_model (str) -- Pore size distribution model to use. Available are 'HK' (original Horvath-Kawazoe), 'RY' (Rege-Yang correction) or the Cheng-Yang modification to the two models ('HK-CY', 'RY-CY').

  • pore_geometry (str) -- The geometry of the adsorbent pores.

  • branch ({'ads', 'des'}, optional) -- Branch of the isotherm to use. It defaults to adsorption.

  • material_model (str, dict) -- The material model to use for PSD, It defaults to 'Carbon(HK)', the original Horvath-Kawazoe activated carbon parameters.

  • adsorbate_model (str, dict) -- The adsorbate properties to use for PSD, If empty, properties are automatically searched from internal database for the Adsorbate.

  • p_limits (tuple[float, float]) -- Pressure range in which to calculate PSD, defaults to [0, 0.2].

  • verbose (bool) -- Print out extra information on the calculation and graphs the results.

Returns:

dict -- A dictionary with the pore widths and the pore distributions, of the form:

  • pore_widths (array) : the widths of the pores

  • pore_distribution (array) : contribution of each pore width to the overall pore distribution

Raises:

Notes

Calculates the pore size distribution using a "classical" model, which describes adsorption in micropores as a sequential instant filling of increasingly wider pores. The pressure of filling for each pore is determined by relating the global adsorption potential, \(RT \ln(p/p_0)\), with the energetic potential of individual adsorbate molecules in a pore of a particular geometry \(\Phi\). Calculation of the latter is based on the Lennard-Jones 6-12 intermolecular potential, incorporating both guest-host and guest-guest dispersion contributions through the Kirkwood-Muller formalism. The function is then solved numerically. These methods are necessarily approximations, as besides using a semi-empirical mathematical model, they are also heavily dependent on the material and adsorbate properties (polarizability and susceptibility) used to derive dispersion coefficients.

There are two main approaches which pyGAPS implements, chosen by passing the psd_model parameter:

  • The "HK", or the original Horvath-Kawazoe method [1].

  • The "RY", or the modified Rege-Yang method [4].

Detailed explanations for both methods can be found in psd_horvath_kawazoe() and psd_horvath_kawazoe_ry(), respectively. Additionally for both models, the Cheng-Yang correction [3] can be applied by appending "-CY", such as psd_model="HK-CY" or "RY-CY". This correction attempts to change the expression for the thermodynamic potential from a Henry-type to a Langmuir-type isotherm. While this new expression does not remain consistent at high pressures, it may better represent the isotherm curvature at low pressure [4].

\[\Phi = RT\ln(p/p_0) + RT (1 + \frac{\ln(1-\theta)}{\theta})\]

Currently, three geometries are supported for each model: slit-like pores, cylindrical pores and spherical pores, as described in the related papers [1] [2] [3] [4].

Caution

A common mantra of data processing is: garbage in = garbage out. Only use methods when you are aware of their limitations and shortcomings.

References

See also

pygaps.characterisation.psd_micro.psd_horvath_kawazoe

low level HK (Horvath-Kawazoe) method

pygaps.characterisation.psd_micro.psd_horvath_kawazoe_ry

low level RY (Rege-Yang) method

pygaps.characterisation.psd_micro.psd_horvath_kawazoe(pressure: list[float], loading: list[float], temperature: float, pore_geometry: str, adsorbate_properties: dict[str, float], material_properties: dict[str, float], use_cy: bool = False)[source]#

Calculate the pore size distribution using the Horvath-Kawazoe method. This function should not be used with isotherms (use instead pygaps.characterisation.psd_micro.psd_microporous()).

Parameters:
  • pressure (list[float]) -- Relative pressure.

  • loading (list[float]) -- Adsorbed amount in mmol/g.

  • temperature (float) -- Temperature of the experiment, in K.

  • pore_geometry (str) -- The geometry of the pore, eg. 'sphere', 'cylinder' or 'slit'.

  • adsorbate_properties (dict) --

    Properties for the adsorbate in the form of:

    adsorbate_properties = {
        'molecular_diameter': 0,           # nm
        'polarizability': 0,               # nm3
        'magnetic_susceptibility': 0,      # nm3
        'surface_density': 0,              # molecules/m2
        'liquid_density': 0,               # g/cm3
        'adsorbate_molar_mass': 0,         # g/mol
    }
    
  • material_properties (dict) -- Properties for the adsorbate in the same form as 'adsorbate_properties'. A list of common models can be found in .characterisation.models_hk.

  • use_cy (bool:) -- Whether to use the Cheng-Yang nonlinear Langmuir term.

Returns:

  • pore widths (array) -- The widths of the pores.

  • pore_dist (array) -- The distributions for each width.

  • pore_vol_cum (array) -- Cumulative pore volume.

Notes

Description

The H-K method [5] attempts to describe adsorption within pores by calculation of the average potential energy for a pore and equating it to the change in free energy upon adsorption. The method starts by assuming the following relationship between the two:

\[\Phi = RT \ln(p/p_0) = U_0 + P_a\]

Here \(U_0\) is the potential describing the surface to adsorbent interactions and \(P_a\) is the potential describing the adsorbate-adsorbate interactions. This relationship is derived from the equation of the free energy of adsorption at constant temperature where the adsorption entropy term \(T \Delta S^{tr}(\theta)\) is assumed to be negligible. \(R\), \(T\), and \(p\) are the gas constant, temperature and pressure, respectively. The expression for the guest-host and host-host interaction in the pore is then modelled on the basis of the Lennard-Jones 12-6 potential. For two molecules 1 and 2:

\[\epsilon_{12}(z) = 4 \epsilon^{*}_{12} \Big[(\frac{\sigma}{z})^{12} - (\frac{\sigma}{z})^{6}\Big]\]

Where \(z\) is intermolecular distance, \(\epsilon^{*}\) is the depth of the potential well and \(\sigma\) is the zero-interaction energy distance. The two molecules can be identical, or different species.

The distance at zero-interaction energy, commonly defined as the "rest internuclear distance", is a function of the diameter of the molecules involved, and is calculated as \(\sigma = (2/5)^{1/6} d_0\). If the two molecules are different, \(d_0\) is the average of the diameter of the two, \(d_0=(d_g + d_h)/2\) such as between the guest and host molecules. In the case of multiple surface atom types (as for zeolites), representative averages are used.

The depth of the potential well is obtained using the Kirkwood-Muller formalism, which relates molecular polarizability \(\alpha\) and magnetic susceptibility \(\varkappa\) to the specific dispersion constant. For guest-host (\(A_{gh}\)) and guest-guest (\(A_{gg}\)) interactions they are calculated through:

\[\begin{split}A_{gh} = \frac{6mc^2\alpha_g\alpha_h}{\alpha_g/\varkappa_g + \alpha_h/\varkappa_h} \\ A_{gg} = \frac{3}{2} m_e c ^2 \alpha_g\varkappa_g\end{split}\]

In the above formulas, \(m_e\) is the mass of an electron and \(c\) is the speed of light in a vacuum. This potential equation (\(\epsilon\)) is then applied to the specific geometry of the pore (e.g. potential of an adsorbate molecule between two infinite surface slits). Individual molecular contributions as obtained through these expressions are multiplied by average surface densities for the guest (\(n_g\)) and the host (\(n_h\)) and then scaled to moles by using Avogadro's number \(N_A\). By integrating over the specific pore dimension (width, radius) an average potential for a specific pore size is obtained.

Slit pore

The original model was derived for a slit-like pore, with each pore modelled as two parallel infinite planes between which adsorption took place. [5] The effective width of the pore is related to the characterisic length by, \(W = L - d_h\) and the following relationship is derived:

\[\begin{split}RT\ln(p/p_0) = & N_A\frac{n_h A_{gh} + n_g A_{gh} }{\sigma^{4}(L-2d_0)} \\ & \times \Big[ \Big(\frac{\sigma^{10}}{9 d_0^9}\Big) - \Big(\frac{\sigma^{4}}{3 d_0^3}\Big) - \Big(\frac{\sigma^{10}}{9(L-d_0)^{9}}\Big) + \Big(\frac{\sigma^{4}}{3(L - d_0)^{3}}\Big) \Big]\end{split}\]

Cylindrical pore

Using the same procedure, a cylindrical model was proposed by Saito and Foley [6] using pore radius \(L\) as the representative length (therefore pore width \(W = 2L - d_h\)), and involves a summation of probe-wall interactions for sequential axial rings of the cylinder up to infinity.

\[\begin{split}RT\ln(p/p_0) = & \frac{3}{4}\pi N_A \frac{n_h A_{gh} + n_g A_{gg} }{d_0^{4}} \\ & \times \sum^{\infty}_{k = 0} \frac{1}{k+1} \Big( 1 - \frac{d_0}{L} \Big)^{2k} \Big[ \frac{21}{32} \alpha_k \Big(\frac{d_0}{L}\Big)^{10} - \beta_k \Big(\frac{d_0}{L}\Big)^{4} \Big]\end{split}\]

Where the constants \(\alpha_k\) and \(\beta\) are recursively calculated from \(\alpha_0 = \beta_0 = 1\):

\[\alpha_k = \Big( \frac{-4.5-k}{k} \Big)^2 \alpha_{k-1} \ \text{and} \ \beta_k = \Big( \frac{-1.5-k}{k} \Big)^2 \beta_{k-1}\]

Spherical pore

Similarly, Cheng and Yang [7] introduced an extension for spherical pores by considering the interactions with a spherical cavity. This model similarly uses the sphere radius \(L\) as the representative length (therefore effective pore width \(W = 2L - d_h\)) It should be noted that realistic spherical pores would not have any communication with the adsorbent exterior.

\[\begin{split}RT\ln(p/p_0) = & N_A 6 \Big( n_1 \frac{A_{gh}}{4 d_0^6} + n_2 \frac{A_{gg}}{4 d_g^6} \Big) \frac{L^3}{(L-d_0)^{3}} \\ & \times \Big[ \Big( \frac{d_0}{L} \Big)^{12} \Big( \frac{T_9}{90} - \frac{T_8}{80} \Big) - \Big( \frac{d_0}{L} \Big)^{6} \Big( \frac{T_3}{12} - \frac{T_2}{8} \Big) \Big]\end{split}\]

Here, \(T_x\) stands for a function of the type:

\[T_x = \Big[1 + (-1)^{x} \frac{L-d_0}{L} \Big]^{-x} - \Big[1 - (-1)^{x} \frac{L-d_0}{L} \Big]^{-x}\]

While the population densities for guest and host \(n_1\) and \(n_2\) are calculated from the plane values as \(n_0 = 4\pi L^2 n_h\) and \(n_i = 4\pi (L - d_0)^2 n_g\).

Limitations

The main assumptions made by using the H-K method are:

  • It does not have a description of capillary condensation. This means that the pore size distribution can only be considered accurate up to a maximum of 5 nm.

  • The surface is made up of a single layer of atoms. Furthermore, since the HK method is reliant on knowing the properties of the surface atoms as well as the adsorbate molecules the material should ideally be homogenous.

  • Only dispersive forces are accounted for. If the adsorbate-adsorbent interactions have other contributions, such as charged interactions, the Lennard-Jones potential function will not be an accurate description of pore environment.

  • Each pore is uniform and of infinite length. Materials with varying pore shapes or highly interconnected networks may not give realistic results.

References

pygaps.characterisation.psd_micro.psd_horvath_kawazoe_ry(pressure: list[float], loading: list[float], temperature: float, pore_geometry: str, adsorbate_properties: dict[str, float], material_properties: dict[str, float], use_cy: bool = False)[source]#

Calculate the microporous size distribution using a Rege-Yang (R-Y) type model. This function should not be used with isotherms (use instead pygaps.characterisation.psd_micro.psd_microporous()).

Parameters:
  • pressure (list[float]) -- Relative pressure.

  • loading (list[float]) -- Adsorbed amount in mmol/g.

  • temperature (float) -- Temperature of the experiment, in K.

  • pore_geometry (str) -- The geometry of the pore, eg. 'sphere', 'cylinder' or 'slit'.

  • adsorbate_properties (dict) --

    Properties for the adsorbate in the form of:

    adsorbate_properties = {
        'molecular_diameter': 0,           # nm
        'polarizability': 0,               # nm3
        'magnetic_susceptibility': 0,      # nm3
        'surface_density': 0,              # molecules/m2
        'liquid_density': 0,               # g/cm3
        'adsorbate_molar_mass': 0,         # g/mol
    }
    
  • material_properties (dict) -- Properties for the adsorbate in the same form as 'adsorbate_properties'. A list of common models can be found in .characterisation.models_hk.

  • use_cy (bool:) -- Whether to use the Cheng-Yang nonlinear Langmuir term.

Returns:

  • pore widths (array) -- The widths of the pores.

  • pore_dist (array) -- The distributions for each width.

  • pore_vol_cum (array) -- Cumulative pore volume.

Notes

This approach attempts to address two main shortcomings of the H-K method, (see details here psd_horvath_kawazoe_ry()) namely its odd summation of contributions from the adsorbate-surface and adsorbate-adsorbate contributions and the assumption of a continuous distributions of guest molecules inside a pore.

Rege and Yang [8] propose a more granular model, where molecules occupy fixed positions according to a minimum energy potential. Depending on the size of the pore in relation to the guest, pores are categorised based on the number of adsorbed layers \(M\), with molecules adsorbed inside described on a layer-by-layer basis. In a similar assumption to the BET theory, a molecule would experience a surface-guest potential only if adjacent to the pore wall, with subsequent layers interacting through pure guest-guest interactions. While they do not assign a weighted distribution to the guest position (i.e. according to Boltzmann's law) and thus disregard thermal motion, this model is theoretically a more accurate representation of how spherical molecules would pack in the pore. The potential equations were derived for slit, cylindrical and spherical pores.

Slit pore

For a slit geometry, the number of layers in a pore of width \(L\) is calculated as a function of guest molecule and host surface atom diameter as \(M = (L - d_h)/d_g\). If the number of adsorbed layers is between 1 and 2, the guest molecule will see only the two pore walls, and its potential will be:

\[\epsilon_{hgh} = \frac{n_h A_{gh}}{2\sigma^{4}} \Big[ \Big(\frac{\sigma}{d_0}\Big)^{10} - \Big(\frac{\sigma}{d_0}\Big)^{4} - \Big(\frac{\sigma}{L - d_0}\Big)^{10} + \Big(\frac{\sigma}{L - d_0}\Big)^{4} \Big]\]

If the number of layers is larger than two, there will be two types of guest molecular potentials, namely (i) the first layer which interacts on one side with the host surface and a layer of guests on the other and (ii) a middle-type layer which interacts with two other guest layers. Internuclear distance at zero energy for two guest molecules is introduced as \(\sigma_g = (2/5)^{1/6} d_g\). The functions describing the potentials of the two types of potential \(\epsilon_{hgg}\) and \(\epsilon_{ggg}\) are then:

\[\epsilon_{hgg} = \frac{n_h A_{gh}}{2\sigma^{4}} \Big[ \Big(\frac{\sigma}{d_0}\Big)^{10} - \Big(\frac{\sigma}{d_0}\Big)^{4} \Big] + \frac{n_g A_{gg}}{2\sigma_g^{4}} \Big[ \Big(\frac{\sigma_g}{d_g}\Big)^{10} - \Big(\frac{\sigma_g}{d_g}\Big)^{4} \Big]\]
\[\epsilon_{ggg} = 2 \times \frac{n_g A_{gg}}{2\sigma_g^{4}} \Big[ \Big(\frac{\sigma_g}{d_g}\Big)^{10} - \Big(\frac{\sigma_g}{d_g}\Big)^{4} \Big]\]

The average potential for a pore with more than two layers is a weighted combination of the two types of layers \(\bar{\epsilon} = [2 \epsilon_{hgg} + (M-2)\epsilon_{ggg}] / M\), while while for a single layer it is equal to \(\bar{\epsilon} = \epsilon_{hgh}\). With a potential formula for both types of pores, the change in free energy can be calculated similarly to the original H-K method: \(RT\ln(p/p_0) = N_A \bar{\epsilon}\).

Cylindrical pore

In a cylindrical pore, the number of concentric layers of guest molecules which can be arranged in a cross-section of radius \(L\) is mathematically represented as:

\[M = \text{int}\Big[ \frac{(2L - d_h)/d_g - 1}{2} \Big] + 1\]

Here, \(int\) truncates to an integer number rounded down. Molecules can then either be part of the first layer, interacting with the surface, or in subsequent layers, interacting with adsorbate layers, with their number for each layer estimated using its diameter. In this particular geometry, an assumption is made that only outer-facing layers contribute to the interaction energy. The potentials corresponding to the two situations are then determined as:

\[\begin{split}\epsilon_{hg} = \frac{3}{4}\pi \frac{n_h A_{gh}}{d_0^{4}} \times \Big[ \frac{21}{32} a_1^{10} \sum^{\infty}_{k = 0} \alpha_k b_1^{2k} - a_1^{4} \sum^{\infty}_{k = 0} \beta_k b_1^{2k} \Big] \\\end{split}\]
\[\epsilon_{gg} = \frac{3}{4}\pi \frac{n_g A_{gg}}{d_g^{4}} \times \Big[ \frac{21}{32} a_i^{10} \sum^{\infty}_{k = 0} \alpha_k b_i^{2k} - a_i^{4} \sum^{\infty}_{k = 0} \beta_k b_i^{2k} \Big]\]

Where:

\[a_1 = d_0 / L \ \text{and} \ b_1 = (L - d_0) / L\]
\[a_i = \frac{d_g}{L - d_0 - (i - 2) d_g} \ \text{and} \ b_i = \frac{L - d_0 - (i - 1) d_g}{L - d_0 - (i - 2) d_g}\]

With the symbols having the same connotation as those in the original H-K cylindrical model. The number of molecules accommodated in each concentric layer is calculated as:

\[n_i = \frac{\pi}{\sin^{-1} \Big[\frac{d_g}{2(L - d_0 - (i - 1) d_g)}\Big]}\]

The average potential for a pore is then a weighted average defined as \(\bar{\epsilon} = \sum^{M}_{i = 1} n_i \epsilon_i / \sum^{M}_{i = 1} n_i\) and then equated to change in free energy by multiplication with Avogadro's number.

Spherical pore

In a spherical pore of radius \(L\), the number of layers that can be accommodated \(M\) is assumed identical to that in a cylindrical pore of similar radius. The equations describing the potential for the initial and subsequent layers are then given as:

\[\epsilon_1 = 2 \frac{n_0 A_{gh}}{4 d_0^6} \Big[ \frac{a_1^{12}}{10 b_1} \Big( \frac{1}{(1-b_1)^{10}} - \frac{1}{(1+b_1)^{10}} \Big) - \frac{a_1^{6}}{4 b_1} \Big( \frac{1}{(1-b_1)^{4}} - \frac{1}{(1+b_1)^{4}} \Big) \Big]\]
\[\epsilon_i = 2 \frac{n_{i-1} A_{gg}}{4 d_g^6} \Big[ \frac{a_i^{12}}{10 b_i} \Big( \frac{1}{(1-b_i)^{10}} - \frac{1}{(1+b_i)^{10}} \Big) - \frac{a_i^{6}}{4 b_i} \Big( \frac{1}{(1-b_i)^{4}} - \frac{1}{(1+b_i)^{4}} \Big) \Big]\]

The number of molecules each layer interacts with (\(n\)) is calculated based on known surface density and a spherical geometry correction. For the first layer \(n_0 = 4\pi L^2 n_h\) and for subsequent layers \(n_i = 4\pi (L - d_0 - (i-1) d_g)^2 n_g\). The constants \(a\) and \(b\) are calculated as for a cylindrical geometry, as in the case with the average potential \(\bar{\epsilon}\).

References

Available HK models#

Dictionaries or generators which provide properties for use in the Horvath-Kawazoe method.

pygaps.characterisation.models_hk.HK_KEYS = {'magnetic_susceptibility': 'nm3', 'molecular_diameter': 'nm', 'polarizability': 'nm3', 'surface_density': 'molecules/m2'}#

List of parameters for an HK model

pygaps.characterisation.models_hk.PROPERTIES_CARBON = {'magnetic_susceptibility': 1.35e-07, 'molecular_diameter': 0.34, 'polarizability': 0.00102, 'surface_density': 3.845e+19}#

List of parameters for the carbon model

pygaps.characterisation.models_hk.PROPERTIES_AlSi_OXIDE_ION = {'magnetic_susceptibility': 1.3e-08, 'molecular_diameter': 0.276, 'polarizability': 0.0025, 'surface_density': 1.315e+19}#

List of parameters for the AlSi-Oxide model

pygaps.characterisation.models_hk.PROPERTIES_AlPh_OXIDE_ION = {'magnetic_susceptibility': 1.3e-08, 'molecular_diameter': 0.26, 'polarizability': 0.0025, 'surface_density': 1e+19}#

List of parameters for the AlPh-Oxide model

pygaps.characterisation.models_hk.get_hk_model(model: str | dict)[source]#

Get the adsorbent model for HK PSD.

The model parameter is a string which names the parameters which should be returned. Alternatively, a user can implement their own adsorbent model, by passing a dict.

Parameters:

model (str, dict) -- Name of the model to use or a dict with the parameters.

Returns:

dict -- A dict with parameters for the HK model.

Raises:

ParameterError -- When string is not in the dictionary of models.