Foam Knudsen

When foam cell dimensions get smaller than the mean free path of gas molecules (large Knudsen numbers), thermal conductivity decreases. It turns out not to be obvious why this is the case!

Credits

A big Thank You to prof. Steven Abbott for designing and developing the app.

Foam Knudsen

gas diameter
dgas nm
cell diameter
φcell nm
mean free path
Λ nm
Knudsen number
Kn @ cell diameter
K relative
Keff @ φcell
gas molecules
in one cell

Virtual Cell : Real Cell : Thot : Tcold : ΔT reduction via T jump

//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 = {
        dgas: sliders.Slidedgas.value / 1e9, //From nm
        phicell: sliders.Slidephicell.value / 1e9, //From nm
    };

    //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
    document.getElementById('Lambda').value = result.Lambda;
    document.getElementById('Knatcell').value = result.Knatcell;
    document.getElementById('Keffcell').value = result.Keffcell;
    document.getElementById('MolsPerCell').value = result.MolsPerCell;
    //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //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({ dgas, phicell }) {
    const P = 1e5, T = 298, e = 1.64, kB = 1.38e-23
    const Lambda = kB * T / (1.414 * Math.PI * P * dgas * dgas)
    let i = 10, iinc = 1, inext = 100, Kn = 0, Keff = 0, K = [], Kcell = [], Knum = [], G = [], d = []
    Kn = Lambda / (phicell)
    const Knatcell = Kn
    const Keffcell = 1 / (1 + 2 * e * Kn)
    Kcell.push({ x: phicell * 1e9, y: 0 })
    Kcell.push({ x: phicell * 1e9, y: 1 })
    while (i <= 10000) {
        Kn = Lambda / (i * 1e-9)
        Knum.push({ x: i, y: Kn })
        Keff = 1 / (1 + 2 * e * Kn)
        K.push({ x: i, y: Keff })
        i += iinc
        if (i >= inext) {
            iinc *= 10
            inext *= 10
        }
    }
    const molm3 = 2.5e25 //A good general purpose value
    const volcell = 4 / 3 * Math.PI * Math.pow(phicell / 2, 3)
    const MolsPerCell = molm3 * volcell

    //Graphics stuff
    const dpr = window.devicePixelRatio || 1;
    const theCanvas = document.getElementById('canvas1')
    const ctx = setupCanvas(theCanvas, dpr);

    const w = theCanvas.width / dpr / 2, h = theCanvas.height / dpr

    //The virtual cell
    let myrng = new Math.seedrandom('hello.');

    ctx.beginPath();
    ctx.fillStyle = "white"
    ctx.rect(0, 0, w, h);
    ctx.fill();
    ctx.beginPath();
    ctx.strokeStyle = "orangered"
    ctx.arc(w / 2, h / 2, w / 10, 0, 2 * Math.PI);
    ctx.stroke()
    ctx.beginPath();
    ctx.strokeStyle = "orange"
    ctx.arc(w / 2, h / 2, w / 10 * (1 + 2 * e * Knatcell), 0, 2 * Math.PI);
    ctx.stroke()
    let x, y
    const inner = Math.pow(w / 10, 2), outer = Math.pow(w / 10 * (1 + 2 * e * Knatcell), 2)
    const iLimit = Math.max(50, Math.min(20000, MolsPerCell))
    for (i = 0; i < iLimit; i++) {
        x = w * myrng(); y = h * myrng()
        d = Math.pow(w / 2 - x, 2) + Math.pow(h / 2 - y, 2)
        if (d < inner) {
            drawDots(ctx, 'orangered', 2, x, y)
        } else {
            if (d < outer) {
                drawDots(ctx, 'orange', 2, x, y)
            }
        }
    }
    //The T jump
    const wt = w * 2, we = 2 * w - 4
    ctx.beginPath();
    ctx.fillStyle = "white"
    ctx.rect(w, 0, w * 2, h);
    ctx.fill();

    ctx.beginPath();
    ctx.fillStyle = "red"
    ctx.rect(w, 0, w - 4, 10);
    ctx.fill();
    ctx.beginPath();
    ctx.fillStyle = "blue"
    ctx.rect(w, h - 10, w - 4, 10);
    ctx.fill();

    ctx.lineWidth = 2
    ctx.beginPath();
    ctx.strokeStyle = "black"
    ctx.moveTo(w, 0)
    ctx.lineTo(w, h)
    ctx.moveTo(we, 0)
    ctx.lineTo(we, h)
    ctx.stroke()

    const delta = h / 2 * (1 - Keffcell)
    ctx.beginPath();
    ctx.strokeStyle = "magenta"
    ctx.moveTo(we, 0 + delta)
    ctx.lineTo(w, h - delta)
    ctx.stroke()


    //Now set up all the graphing data.
    //We use the amazing Open Source Chart.js, https://www.chartjs.org/
    //A lot of the sophistication is addressed directly here
    //But if you need something more, read the Chart.js documentation or search Stack Overflow
    const plotData = [Knum, K, Kcell]
    const plotData1 = [G, d]
    const lineLabels = ["Kn", "Keff", "φ Cell"]
    const lineLabels1 = ["Gaussian", "φ/2"]
    const myColors = ["blue", "orange", "green"]
    const dottedLine = [false, false, true]

    //Now set up all the graphing data detail by detail.
    const prmap = {
        plotData: plotData, //An array of 1 or more datasets
        lineLabels: lineLabels, //An array of labels for each dataset
        colors: myColors, //An array of colors for each dataset
        borderWidth: [2, 2, 1],
        hideLegend: false,
        dottedLine: dottedLine,
        xLabel: 'φ&nm', //Label for the x axis, with an & to separate the units
        yLabel: 'Kn& ', //Label for the y axis, with an & to separate the units
        y2Label: "Keff& ", //Label for the y2 axis, null if not needed
        yAxisL1R2: [1, 2, 2], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: true, //Is the x-axis in log form?
        xTicks: function(value, index, ticks) { return value.toFixed(0); }, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [0,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [,], //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: 'F0', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'F2', //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],
        canvas: ['canvas'],
        Lambda: (Lambda * 1e9).toFixed(1),
        Knatcell: Knatcell.toFixed(2),
        Keffcell: Keffcell.toFixed(2),
        MolsPerCell: MolsPerCell.toFixed(0),
    };
}
function drawDots(ctx, col, lw, xv, yv) {
    ctx.fillStyle = col;
    ctx.beginPath();
    ctx.arc(xv, yv, lw, 0, 2 * Math.PI);
    ctx.fill();
}

function setupCanvas(canvas, dpr) {
    // Get the device pixel ratio, falling back to 1.
    var rect = canvas.getBoundingClientRect();
    // Give the canvas pixel dimensions of their CSS
    // size * the device pixel ratio.
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    var ctx = canvas.getContext('2d');
    // Scale all drawing operations by the dpr, so you
    // don't have to worry about the difference.
    ctx.scale(dpr, dpr);
    return ctx;
}
            

The standard equation

Everyone quotes a standard equation for the conductivity as a function of cell size. Those who cite a source either mention a 1969 Israeli paper that Google Scholar can't track down or Kennard's 1938 book, The Kinetic Theory of Gases which doesn't actually contain that equation but has a similar one which readers are supposed to derive as a problem exercise. Here's the equation for the thermal conductivity relative to it's unconstrained value Krel, which includes a parameter ξ typically cited as 1.64 or 2:

`K_"rel"=1/(1+2ξKn)`

where Kn is the Knudsen number given by:

`Kn=Λ/φ`

Where φ is the diameter of the cell and Λ is the mean-free path of the gas molecule, depending on the molecular size ρ:

`Λ=(kB.T)/(1.414πρ^2P`

Note that for low bulk thermal conductivity, a large ρ is good, but for the Knudsen effect, a small ρ is good. So open cell foams with air, which is "bad" for large-cell foams compared to, say, pentane, is "good" for Knudsen-sized cells.

What does it mean?

It turns out that no one really knows the full equation for the dependence of Krel with size. Instead they assume that the conductivity is a mix of Kbulk and Kcell via:

`1/K_"tot"=1/K_"bulk"+1/K_"cell"`

So in `(1+2ξKn)` the "1" is from the bulk and the 2ξKn is the value we need to understand.

The amount of heat conducted depends on the distance, φ, over which the temperature difference if found. Without the Knudsen effect, that distance is simply φ. But suppose that when the molecules hit the walls, they lose all knowledge of their temperature. And suppose that this gives a dead zone of length g (using Kennard and Knudsen's letter)where there is no effective conductivity. This means that the effective distance the molecules have to diffuse is φ+2g, with the factor of 2 because there is a dead zone at each wall. Because heat conducted depends on distance, the effective conductivity is now reduced by φ/(φ+2g)

In kinetic theory, g is called the temperature jump distance meaning the distance across which the gas takes on the temperature of the wall. The value of g depends on the mean free path, Λ, which is why the Knudsen number appears via Λ/φ, and also the accommodation coefficient α which says by how much the gas molecules are influenced by the wall. If α=0 the molecules bounce off with their initial energy so the walls have no effect on thermal conductivity. It turns out that g also depends on the heat capacity ratio γ (usually taken as 1.4) and the Prandtl number Pr(typically 0.7). So we end up with:

`K_"rel"=1/(1+2(2γ)/(γ+1)1/"Pr"(2-α)/αKn`

It turns out that for normal foams and gases, α~1, i.e. the molecules lose all knowledge of their thermal state, and we end up by bundling the α, γ, and Pr terms into a single value ξ=1.64

The cause of reduced heat flow

It seems intuitive that whatever Kn does, you would expect thermal conductivity to do something dramatic when the cell size is ~ Kn. But the graph shows that you halve the conductivity at ~3x Kn. This makes no intuitive sense till you realise that Kn is amplified by 2 (one for each wall) and by the extra temperature jump factor ξ.

We can explain the effect by recognising that the heat flow across a gap of distance φ and a temperature difference ΔT is proportional to ΔT/φ. So to reduce the heat flow you either increase φ, via the T-Jump distance or decrease ΔT via the T-Jump. The images on the right show both views.

The T-Jump Distance view

The first image on the right shows that the effective or Virtual size of a cell is much larger (i.e. φ is larger) so the heat flow from ΔT/φ is smaller than the Real size. When the cell size is the same as the mean free path, 70nm, and Kn=1, then the effective cell diameter is 1+2*1.64 = 4.7x larger than the real size and, indeed, the conductivity is 1/4.7 ~ 0.23 because the gas has to conduct over that larger virtual distance.

The T-Jump view

In the second image on the right shows Temperature on the y-axis and distance across a cell in the x-axis. The real temperatures Thot and Tcold imply a real ΔT. But thanks to the T-Jump, the molecules feel that the hot wall is at Thot-Tjump and the cold wall is at Tcold+Tjump. So ΔT is smaller as Kn increase until at high Kn it's zero because no molecules hit each other so classic thermal conductivity is zero.

So what is the T-Jump caused by? It's rather simple - some of the hotter flow coming to the cold wall gets effectively trapped in the dead zone (because all specific molecular information is lost) next to the wall so the gas between the walls sees a higher temperature in this area. At the hot wall, incoming colder gas gets trapped, so the gas between the walls sees a lower temperature. So the effective ΔT is reduced. This jump (up and down) in temperature can be calculated from the α, γ and Pr numbers and varies from 0 at low Kn to 0.5(Thot-Tcold)at high Kn. OK it's really the geometric mean, but the mean is good enough.

Numbers of molecules

A popular, but erroneous, explanation for Knudsen effects is that there are too few molecules in a small cell to conduct the heat. But given that gases typically have 2.5e25 molecules per m³, it turns out that for a cell equal to the mean free path of ~70 nm, the volume is ~ 2e-22 m³, so there are ~5000 molecules in the cell. At 230nm when the conductivity is halved, there are 160000 molecules. As a reminder, the actual number is provided as an output, and we have a visual reminder (it's an illustrative calculation) of the number of molecules in the right-hand image.

Is it the Knudsen Effect?

It is clear that if those responsible for the effect were to be acknowledged it would be called the Poisson-Maxwell-Smoluchowski-Knudsen effect. It is clearly the case that Knudsen's focus was on what happened to a number of phenomena when physical size was comparable to the mean free path of the gas and that he didn't develop the Knudsen theory of thermal conductivity. But it's also clearly the case that he actively contributed to the debates that led to the formulation we know now, that he proposed the current version of the accommodation coefficient and that expressing the effects in terms of Kn gives an elegant simplicity to rather obscure formulae..

Is it totally fair to call it the Knudsen effect? No! Did an unscrupulous Knudsen steal the idea to gain false credit? Absolutely not! If there was to be a single name to the effect, is Knudsen a fair choice? Yes! Are we ever going to change it to the PMSK effect? No! So let's carry on calling it the Knudsen effect. Poisson, Maxwell and Smouchowski have their own effects and equations so they aren't lost to history.