## Pore Size

### Quick Start

Here we show two techniques for measuring pore size - CFP, Capillary Flow Porometry, and MIP, Mercury Intrusion Porosimitry. Each has its uses, their core theory is the same, but there are also plenty of differences between them

### Credits

This is an amalgam of explanations from the on-line community.

### Pore Size

```
//One universal basic required here to get things going once loaded
window.onload = function () {
//restoreDefaultValues(); //Un-comment this if you want to start with defaults
Main();
};
//Main() is hard wired as THE place to start calculating when inputs change
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
//Save settings every time you calculate, so they're always ready on a reload
saveSettings();
//Send all the inputs as a structured object
//If you need to convert to, say, SI units, do it here!
const inputs = {
D: sliders.SlideD.value, //keep in nm for the plot
W: sliders.SlideW.value,
CFP: document.getElementById('CFP').checked,
};
//Send inputs off to CalcIt where the names are instantly available
//Get all the resonses as an object, result
const result = CalcIt(inputs);
//Set all the text box outputs
//plotIt is part of the app infrastructure in app.new.js
if (result.plots) {
for (let i = 0; i < result.plots.length; i++) {
plotIt(result.plots[i], result.canvas[i]);
}
}
//You might have some other stuff to do here, but for most apps that's it for Main!
}
//Here's the app calculation
function CalcIt({ D, W, CFP }) {
let DPts = [], PPts = [], dv, h, i, maxh = 0, tV = 0, PMax, P, Vol = 0, Dmin = 5, Dmax = 5, FInc = 10
for (dv = 5; dv <= 1500; dv += 10) { //Extend the range for calcs of wide distributions
h = Math.exp(-Math.pow((dv - D) / W, 2))
if (h > 0.01 && Dmin == 5) Dmin = dv //First take-off of pressure
if (h < 0.01 && Dmin > 5 && Dmax == 5) Dmax = dv //Lowest take-off of pressure
maxh = Math.max(h, maxh)
DPts.push({ x: dv, y: h })
}
for (i = 0; i < DPts.length; i++) {
DPts[i].y *= 100 / maxh
}
const MV = CFP ? 4 * 0.016 : 4 * 0.48 * 0.766//ST 16 mN/m cosθ = 1 : ST 480 mN/m, θ=140, cosθ=-0.766
const NPts = DPts.length
PMax = 1050 * MV / Dmin
if (CFP) PMax *= 1e3
i = NPts
while (i > 0) {
i--
P = 1e3 * MV / DPts[i].x //1e9 for nm but then 1e-6 for MPa
if (CFP) {
P *= 1e3 //to kPa
//Simulate the increasing flow at higher P's
FInc = DPts[i].x > Dmax ? 0 : 20
Vol += DPts[i].y + FInc * P / PMax
} else {
Vol += DPts[i].y
}
if (P <= PMax) PPts.push({ x: P, y: Vol })
}
for (i = 0; i < PPts.length; i++) {
PPts[i].y *= 100 / Vol
}
const plotData = [DPts]
const plotData1 = [PPts]
const Pressure = CFP ? 'Pressure&kPa' : 'Pressure&MPa'
const yLabel = CFP ? 'Rel Flow&' : 'Rel Volume&'
//Now set up all the graphing data detail by detail.
const prmap = {
plotData: plotData, //An array of 1 or more datasets
lineLabels: "Size", //An array of labels for each dataset
colors: ["blue"], //An array of colors for each dataset
hideLegend: true,
borderWidth: 2,
xLabel: 'Pore D&nm', //Label for the x axis, with an & to separate the units
yLabel: 'φ&', //Label for the y axis, with an & to separate the units
y2Label: null, //Label for the y2 axis, null if not needed
yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
logX: false, //Is the x-axis in log form?
xTicks: null, //We can define a tick function if we're being fancy
logY: false, //Is the y-axis in log form?
yTicks: null, //We can define a tick function if we're being fancy
legendPosition: 'top', //Where we want the legend - top, bottom, left, right
xMinMax: [10, 1000], //Set min and max, e.g. [-10,100], leave one or both blank for auto
yMinMax: [0,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
xSigFigs: 'P3', //These are the sig figs for the Tooltip readout. A wide choice!
ySigFigs: 'P3', //F for Fixed, P for Precision, E for exponential
};
const prmap1 = {
plotData: plotData1, //An array of 1 or more datasets
lineLabels: "Pressure", //An array of labels for each dataset
colors: ["orange"], //An array of colors for each dataset
hideLegend: true,
borderWidth: 2,
xLabel: Pressure, //Label for the x axis, with an & to separate the units
yLabel: yLabel, //Label for the y axis, with an & to separate the units
y2Label: null, //Label for the y2 axis, null if not needed
yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
logX: false, //Is the x-axis in log form?
xTicks: null,
logY: false, //Is the y-axis in log form?
yTicks: null,
legendPosition: 'top', //Where we want the legend - top, bottom, left, right
xMinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
yMinMax: [0,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
xSigFigs: 'P3', //These are the sig figs for the Tooltip readout. A wide choice!
ySigFigs: 'P3', //F for Fixed, P for Precision, E for exponential
};
//Now we return everything - text boxes, plot and the name of the canvas, which is 'canvas' for a single plot
return {
plots: [prmap, prmap1],
canvas: ['canvas', 'canvas1'],
// ASI: ASI.toFixed(1),
// ASIVals: ASIVals,
};
}
```

### Pore pressure

If we assume that our porous material has a bunch of capillaries each with a radius D, then the pressure required to get a liquid of surface tension σ with a contact angle θ into the pore is given by `P=(4σcosθ)/D`

If we start squeezing some non-wetting mercury (σ = 480 mN/m, θ=140°) into a sample of porous material after removing all the air, and can follow the volume of mercury that disappears into the pores then we should see a volume versus pressure curve that reflects the fraction of pores of a given size.

If we start with a sample filled with a fully-wetting non-volatile fluorocarbon (σ = 16 mN/m, θ=0°) and increase the air pressure to empty the liquid, we get a similar curve, though once the sample is empty the curve carries on rising as more and more air squeezes through.

The app is very simple. You choose your (simplified) size distribution and width, and choose either MIP for the Mercury Intrusion Porosimitry or CFP for Capillary Flow Porometry.

In MIP it's straightforward to get the total volume of pores from the absolute volume of mercury that flows into the pores compared to the known volume of particles. No attempt is made to do that here.

To look at super-small pore sizes using MIP, the equipment has to be seriously upgraded to allow super-high pressures. Here we stay in the safer area away from those high pressures.

For CFP a "dry run" is done once the liquid has been expelled. It catches up with the top right of the graph, to define the smallest pore size. The arithmetic "half dry" line crosses the flow graph at the pressure equivalent to half pore size. The lowest pressure for which some air flows is the First Bubble Point, FBP, from which the largest pore size is calculated. Because our size distribution is an input rather than an output, we don't need to show those extra features.

In real CFP you either have to increase the pressure very slowly, or do it in steps, or use a special pressure profile, to give the flow time to equilibrate. Again, no attempt is made to do that here.

### What about N2 porosimetry?

The interpretation of liquid N2 isotherms is complex, convoluted and controversial. No attempt is made to model this form of porosimetry.