Foam Diffusion

Quick Start

We all rely on foam insulation. But the Diffusion of gas through foam changes the thermal conductivity. Here we see two gases going out and air coming in. It's up to you to work out the impact on thermal conductivity.

Credits

There are many different papers on diffusion through foam cells, this captures the spirit of the more insightful ones.

Foam Diffusion

Pstart1 Bar
Drel1
Pstart2 Bar
Drel2
Cells per Width
tmax
//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 = {
        Pstart1: sliders.SlidePstart1.value,
        Drel1: sliders.SlideDrel1.value,
        Pstart2: sliders.SlidePstart2.value,
        Drel2: sliders.SlideDrel2.value,
        Cells: sliders.SlideCells.value,
        tMax: sliders.SlidetMax.value,
    };

    //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('phiStrut').value = result.phiStrut; 
    //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({ Pstart1, Drel1, Pstart2, Drel2, Cells, tMax }) {
    const tinc = (tMax>1000)?0.1:0.01, step = 0.1*tinc
    let tnext = tMax / 100, tninc = tnext
    Drel1 *= step; Drel2 *= step
    const Drel3 = 1 * step
    let i = 0, j = 0, t = 0
    let P1 = [], P2 = [], P3 = [], t1 = [], t2 = [], t3 = [], Pcell1 = [], Pcell2 = [], Pcell3 = [], Delta1 = [], Delta2 = [], Delta3 = []
    t1.push({ x: 0, y: Pstart1 })
    t2.push({ x: 0, y: Pstart2 })
    t3.push({ x: 0, y: 0 })
    for (i = 0; i < Cells; i++) {
        Pcell1[i] = Pstart1; Pcell2[i] = Pstart2; Pcell3[i] = 0
        Delta1[i] = 0; Delta2[i] = 0; Delta3[i] = 0
    }
    Pcell1[Cells] = 0; Pcell2[Cells] = 0; Pcell3[i] = 1
    Delta1[Cells - 1] = 0; Delta2[Cells - 1] = 0; Delta3[i - 1] = -1
    while (t <= tMax) {
        Pcell1[0] -= Drel1 * Delta1[0]
        Pcell2[0] -= Drel2 * Delta2[0]
        Pcell3[0] -= Drel3 * Delta3[0]
        for (i = 1; i < Cells; i++) {
            Pcell1[i] -= Drel1 * (Delta1[i] - Delta1[i - 1])
            Pcell2[i] -= Drel2 * (Delta2[i] - Delta2[i - 1])
            Pcell3[i] -= Drel3 * (Delta3[i] - Delta3[i - 1])
        }
        for (i = 0; i < Cells; i++) {
            Delta1[i] = Pcell1[i] - Pcell1[i + 1]
            Delta2[i] = Pcell2[i] - Pcell2[i + 1]
            Delta3[i] = Pcell3[i] - Pcell3[i + 1]
        }
        Delta1[Cells - 1] = Pcell1[Cells - 1] - Pcell1[Cells]
        Delta2[Cells - 1] = Pcell2[Cells - 1] - Pcell2[Cells]
        Delta3[Cells - 1] = Pcell3[Cells - 1] - Pcell3[Cells]

        t += tinc
        if (t >= tnext) {
            let tot1 = 0, tot2 = 0, tot3 = 0
            for (i = 0; i < Cells; i++) {
                tot1 += Pcell1[i]
                tot2 += Pcell2[i]
                tot3 += Pcell3[i]
            }
            t1.push({ x: t, y: tot1 / Cells })
            t2.push({ x: t, y: tot2 / Cells })
            t3.push({ x: t, y: tot3 / Cells })
            tnext += tninc
        }
    }
    for (i = 0; i <= Cells; i++) {
        j = 100 * i / Cells
        P1.push({ x: j, y: Pcell1[i] })
        P2.push({ x: j, y: Pcell2[i] })
        P3.push({ x: j, y: Pcell3[i] })
    }
    //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 = [P1, P2, P3]
    const plotData1 = [t1, t2, t3]
    const lineLabels = ["Gas1", "Gas2", "Air"]
    const myColors = ["blue", "orange", "green"]
    const borderWidth = [2, 2, 2]

    //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
        hideLegend: false,
        borderWidth: borderWidth,
        xLabel: 'X&%', //Label for the x axis, with an & to separate the units
        yLabel: 'P& ', //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: undefined, //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: [,], //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
    };
    const prmap1 = {
        plotData: plotData1, //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
        hideLegend: false,
        borderWidth: borderWidth,
        xLabel: 'Time& ', //Label for the x axis, with an & to separate the units
        yLabel: 'Total P& ', //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: undefined, //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: [,Math.round(tMax)], //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, prmap1],
        canvas: ['canvas', 'canvas1'],
        // phiStrut: (phiStrut).toPrecision(2),
        // rhoFoam: (rhoFoam).toFixed(0),
    };
}
            

A typical insulating panel for a house or a refrigerator will be made from polyurethane (PU) foam containing a gas which might be air, CO2 or something like pentane (chloro/fluoro gases are very efficient but have obvious environmental downsides) or, very often a mixture. Here we allow two internal gases.

At the start the cells will contain a given pressure of each gas Pstart1 & Pstart2 (either or both can be below atmospheric)and none of the external gas, air, which is assumed to be a single component even though O2 and N2 have different diffusion rates. The air has a pressure of 1 and is assumed to have a diffusion coefficient D = 1 (all calculations are relative) and the D values of the internal gases can be larger or smaller via Drel1 & Drel2

Whatever the gases, the more cell walls in the way (i.e. the smaller the cell size), the slower the diffusion. The Cells slider lets you go from a coarse foam with, say, 5 cells across the width up to a fine foam with 200, in other words, the cell size is decreasing by a factor of 40 over that range. If you imagine the 5 cell foam to be 200μm then the 200 cell foam is 5μm.

One more input is tmax, the maximum time (in arbitrary units) for the simulation. The parameters are set up so that if you imagine t to be in days and the foam to be a few cm thick, the graphs match the relatively few papers containing relevant data.

2 Graphs

We are interested in two different views of the data:

  1. The gas distribution through the (half) panel (the other half is the mirror image) at the end of your chosen time. Obviously you see the internal gas pressures reducing at that outside edge, on the right, and see the air coming in from that side. How far the changes extend inside depends on your settings.
  2. The total amount of each gas in the foam over your chosen timescale.

As you change the tmax slider obviously both graphs will shift accordingly.

Pressures less than 1 atm

As far as each gas is concerned, the other gases don't exist (in this approximation). So a pressure below 1 atm in a cell doesn't "suck in" more air. As far as the air is concerned, the concentration in each cell at the start is 0. This feels odd at first but starts to make sense. We are not modelling pressure-driven flows through pores, we're modelling gas diffusion against a concentration gradient of each gas.

Diffusion in each cell is fast

It might seem that high/low pressures or the presence of other gases would affect the diffusion rate across each cell. While this is true, these rates are orders of magnitude higher than diffusion through the cell walls, so all models assume that diffusion in the cells is "instantaneous".

Drel values

There are only two things that control diffusion:

  1. The concentration gradient across the polymer
  2. The diffusion coefficient of the gas inside the polymer

These two effects cause confusion. Of course pentane has a lower diffusion coefficient than nitrogen - it's a bigger molecule that has a hard time getting through the polymer. Maybe pentane, MWt=77 diffuses ~3x slower than N2=28. But as has often been observed, the diffusion rates of CO2 > O2 > N2 are the opposite to their expected size-dependent diffusion coefficient.

The difference, often neglected, is that the solubility of CO2 > O2 > N2 in any typical polymer. So for a given pressure differential, the concentration of CO2 in the polymer surface, in contact with the gas, is higher than N2, so the concentration gradient is higher, so the diffusion rate ("flux") is higher. For those interested in solubility theory, a simple explanation is that the solubility parameters go as CO2 > O2 > N2. Solubility depends on matching of solubility parameters. Given that polymers have higher solubility parameters, the "distance" between the gas and the polymer goes as CO2 < O2 < N2 so the solubility is in the order we've said: CO2 > O2 > N2. If you can find Henry constants for these gases and your PU (and they are hard to find!) you will find them in this order. If (even harder) you can estimate the size-dependence of the diffusion coefficient then you can factor the two parameters to get the relative diffusion rates.

Because measuring diffusion in PU foams is hard, there is a tendency to quote a single diffusion factor that mixes diffusion coefficient with solubility effects. So using Drel as a single number isn't such a bad idea. My reading of the literature is that the values should be CO2 = 4, Pentane = 0.2, N2 (by definition) = 1 and O2 = 1.5.

Pressure effects

If you set Drel equal for the two gases and set one as 2 bar and the other at 1 bar, the general shapes of the curves look identical. This seems odd at first. The concentration gradient for 2 bar is twice that of 1 bar, so the diffusion rate is double. So why doesn't the concentration gradient fall off faster? Because you have to move twice the amount of gas to halve the concentration!

When you play around with the time slider and the pressure sliders, you start to get a feel for all this. That's why we have apps.

No ρrel input

Why is there no input for ρrel, the relative density of the foam. Surely at a lower density there is less solid to block the gas diffusion, so diffusion should be faster. It turns out, however, that cell foam wall thicknesses don't change all that much over a relevant range of ρrel values; reduction in the mass of polymer takes place in the struts. To put it another way, although the wall:strut area ratio is high, the wall:strut mass ratio is low. The effect of cell size (cells/width) dominates the behaviour and by the time we need to start worrying about wall thickness, we have bigger concerns about broken walls; i.e. the % open cells starts to dominate the diffusion.

Effect on thermal conductivity

We worry about the gas diffusion because thermal conductivites of gases (mW/m.K) go as pentane = 14, CO2 = 17, N2 = O2 = 26, approximately reflecting their molar masses/sizes. If you go from 50:50 CO2/pentane to air/pentane the official calculation is quite complex, but we can say it's roughly 15 going to 20. Maybe after 1 year, the system has gone 50% of the way there, so it's something like 17-18.

Given (see the Foam Conductivity app) that diffusion through the gas is typically 80% of the overall conductivity, that's a 12% increase in conductibity, a significant effect. Hence the Al barriers on many panels that make this whole diffusion app irrelevant.