Often, pore size distributions are a very important part of adsorbent characterisation. The pyGAPS framework includes several common classical methods which are applicable to mesoporous or microporous materials. A DFT-fitting method is also provided together with an internal N2/carbon applicable DFT kernel. The user can also specify their own DFT kernel. A complete aplicability guide and info on each function parameters can be found in the manual.
First, make sure the data is imported.
In [1]:
%run import.ipynb
Let's start by analysing the mesoporous size distribution of some of our nitrogen physisorption samples.
The MCM-41 sample should have a very well defined, singular pore size in the mesopore range, with the pores as open-ended cylinders. We can use a common method, relying on a description of the adsorbate in the pores based on the Kelvin equation and the thickness of the adsorbed layer. These methods are derivatives of the BJH (Barrett, Joyner and Halenda) method.
In [2]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='MCM-41')
print(isotherm.material)
result_dict = pygaps.psd_mesoporous(
isotherm,
pore_geometry='cylinder',
verbose=True)
The distribution is what we expected, a single narrow peak. Since we asked for extra verbosity, the function has generated a graph which we can display with plt.show()
. The graph automaticaly sets a minimum limit of 1.5 angstrom, where the Kelvin equation methods break down.
The result dictionary returned contains the x and y points of the graph.
Depending on the sample, the distribution can be a well defined or broad, single or multimodal, or, in the case of adsorbents without mesoporoes, not relevant at all. For example, using the Takeda 5A carbon, and specifying a slit pore geometry:
In [3]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='Takeda 5A')
print(isotherm.material)
result_dict_meso = pygaps.psd_mesoporous(
isotherm,
psd_model='pygaps-DH',
pore_geometry='slit',
verbose=True)
Now let's break down the available settings with the mesoporous PSD function.
psd_model
parameter to select specific implementations of the methods, such as the original BJH method or the DH method.pore_geometry
parameter can be used to specify the known pore geometry of the pore. The Kelvin equation parameters change appropriately.branch
parameter.thickness_model
parameter. Either a named internal model ('Halsey', 'Harkins/Jura', etc.) or a cusom user function which takes pressure as an argument is accepted.kelvin_model
parameters. This must be a name of an internal model ('Kelvin', 'Kelvin-KJS', etc.) or a custom function.Below we use the adsorption branch and the Halsey thickness curve to look at the MCM-41 pores. We use the Kruck-Jaroniec-Sayari correction of the Kelvin model.
In [4]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='MCM-41')
print(isotherm.material)
result_dict = pygaps.psd_mesoporous(
isotherm,
psd_model='DH',
pore_geometry='cylinder',
branch='ads',
thickness_model='Halsey',
kelvin_model='Kelvin-KJS',
verbose=True)
For microporous samples, we can use the psd_microporous
function. The available model is an implementation of the Horvath-Kawazoe (HK) method.
The HK model uses a list of parameters which describe the interaction between the adsorbate and the adsorbent. These should be selected on a per case basis by using the adsorbate_model
and adsorbent_model
keywords. If they are not specified, the function assumes a carbon model for the sample surface and takes the required adsorbate properties (magnetic susceptibility, polarizability, molecular diameter, surface density, liquid density and molar mass) from the specific internal adsorbate. The pore geometry is also assumed to be slit-like.
Let's look at using the function on the carbon sample:
In [5]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='Takeda 5A')
print(isotherm.material)
result_dict_micro = pygaps.psd_microporous(
isotherm,
psd_model='HK',
verbose=True)
We see that we could have a peak around 0.7 nm, but could use more adsorption data at low pressure for better resolution. It should be noted that the model breaks down with pores bigger than around 3 nm.
The framework comes with other models for the surface, like as the Saito-Foley derived oxide-ion model. Below is an attempt to use the HK method with these parameters for the UiO-66 sample and some user-specified parameters for the adsorbate interaction. We should not expect the results to be very accurate, due to the different surface properties and heterogeneity of the MOF.
In [6]:
adsorbate_params = {
'molecular_diameter': 0.3,
'polarizability': 1.76e-3,
'magnetic_susceptibility': 3.6e-8,
'surface_density': 6.71e+18,
'liquid_density': 0.806,
'adsorbate_molar_mass': 28.0134
}
isotherm = next(i for i in isotherms_n2_77k if i.material=='UiO-66(Zr)')
print(isotherm.material)
result_dict = pygaps.psd_microporous(
isotherm,
psd_model='HK',
adsorbent_model='AlSiOxideIon',
adsorbate_model=adsorbate_params,
verbose=True)
A bimodal pore size distribution is seen, with peaks at around 0.7 and 0.8 nanometers. UiO-66 does indeed have two cages, a tetrahedral cage and an octahedral one, with the sizes of 0.8 and 1.1 nm respectively.
The DFT method is the most powerful method for pore size distribution calculations. It requires a DFT kernel, or a collection of previously simulated adsorption isotherms which cover the entire pore range which we want to investigate. The calculation of the DFT kernel is currently not in the scope of this framework.
The user can specify their own kernel, in a CSV format, which will be used for the isotherm fitting on the psd_dft
function. Alternatively, a common DFT kernel is included with the framework, which is
simulated with nitrogen on a carbon material and slit-like pores in the range of 0.4-10 nanometres.
Let's run the fitting of this internal kernel on the carbon sample:
In [7]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='Takeda 5A')
result_dict_dft = pygaps.psd_dft(
isotherm,
kernel='DFT-N2-77K-carbon-slit',
verbose=True)
The output is automatically smoothed using a b-spline method. Further (or less) smoothing can be specified by the bspline_order
parameter. The higher the order, more smoothing is applied. Specify "0" to return the data as-fitted.
In [8]:
isotherm = next(i for i in isotherms_n2_77k if i.material=='Takeda 5A')
result_dict_dft = pygaps.psd_dft(
isotherm,
bspline_order=5,
verbose=True)
For comparison purposes, we will compare the pore size distributions obtained through all the methods above. The sample on which all methods are applicable is the Takeda carbon.
We will first plot the data using the existing function plot, then use the graph returned to plot the remaining results.
In [9]:
from pygaps.graphing.calcgraph import psd_plot
ax = psd_plot(result_dict_dft['pore_widths'], result_dict_dft['pore_distribution'],
method='comparison', labeldiff='DFT', labelcum=None, left=0.4, right=8)
ax.plot(result_dict_micro['pore_widths'], result_dict_micro['pore_distribution'], label='microporous')
ax.plot(result_dict_meso['pore_widths'], result_dict_meso['pore_distribution'], label='mesoporous')
ax.legend(loc='best')
plt.show()