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
//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:
- 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.
- 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:
- The concentration gradient across the polymer
- 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.