Foam Fall
Quick Start
When a ball of foam falls from a given height into a pool of liquid, how long does it take to fall, with what velocity does it hit the liquid and how deep does it plunge into the liquid before coming back up to the surface?
It depends on the size of the ball, on the expansion ratio (or, the volume fraction of air φ) which affects the density and on the density of the liquid.
Credits
The app is part of the work of the LASTFIRE team working towards improved on-site knowledge of foam properties relevant to fighting fires.
Foam Fall
//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();
};
//Any global variables go here
//Main is hard wired as THE place to start calculating when input changes
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {
saveSettings();
//Send all the inputs as a structured object
//If you need to convert to, say, SI units, do it here!
const inputs = {
phi: 1 - 1 / sliders.SlideExpansion.value, //From Expansion to φ
H: sliders.SlideH.value,
R: sliders.SlideD.value / 200, //cm diameter to m radius
rho: sliders.Sliderho.value * 1000, //g/cc to kg/m3
}
//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('Vt').value = result.Vt
document.getElementById('Vimpact').value = result.Vimpact
document.getElementById('maxDepth').value = result.maxDepth
document.getElementById('floatDepth').value = result.floatDepth
document.getElementById('rhofoam').value = result.rhofoam
document.getElementById('thetar').value = result.thetar
//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 CalcIt!
}
//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ phi, H, R,rho }) {
const pi = Math.PI, g = 9.81
let Comments = ""
let Hnow = H, Vnow = 0, Volnow = 4 / 3 * pi * Math.pow(R, 3), Anow = pi * R * R
let dt = 0.001, tnow = 0, acc = 0
const VolFoam = Volnow
const rhowater = 1000, rhooil = rho, rhoair = 1.225
const rhofoam = phi * rhoair + (1 - phi) * rhowater
const thetar = 18/Math.sqrt(rhofoam/rhooil)
const m = Volnow * rhofoam
const Cd = 1 //Used a crude drag coefficient but now swapped to CDv
const Vt = Math.sqrt(2 * m * g / (rhoair * Anow * Cd))
const AF = 0.1806, BF = 0.6459, CF = 0.4251, DF = 6880.95
const ReP = 2 * R / 1.8e-5 //Pre-reynolds number for air
const RePl = 2 * R / 1e-2 //Pre-reynolds number for typical fuel 10cP
let HPlot = [], VPlot = [], Re=1 //A reasonable starting value
HPlot.push({ x: 0, y: Hnow * 100 })
VPlot.push({ x: 0, y: Vnow })
while (Hnow >= 0) {
CDv = 24 / Re * (1 + AF * Math.pow(Re, BF)) + CF / (1 + DF / Re)
acc = (m * g - 0.5 * rhoair * Anow * CDv * Vnow * Vnow) / m
Vnow += acc * dt
Re = Math.abs(ReP * Vnow)
Hnow -= Vnow * dt
tnow += dt
HPlot.push({ x: tnow, y: Math.max(Hnow * 100, 0) })
VPlot.push({ x: tnow, y: Vnow })
}
const Vimpact=Vnow
HNow = 0
let Down = true
dt = 0.0001 //No benefit from a smaller time step
let maxDepth=0, floatDepth=0
while ((Vnow > 0 || Hnow < floatDepth) && tnow<4) {
if (HNow <= R) {
Volnow = 0.333 * pi * Hnow * Hnow * (3 * R - Math.abs(Hnow))
Anow = pi * (2 * R * Math.abs(Hnow) - Hnow * Hnow)
} else {
Volnow = VolFoam / 2 + 0.333 * pi * Math.pow(R - HNow, 2) * (2 * R - HNow)
Anow = pi * R * R
}
CDv = 24 / Re * (1 + AF * Math.pow(Re, BF)) + CF / (1 + DF / Re)
acc = ((m - Volnow * rhooil) * g - 0.5 * rhooil * Anow * CDv * Vnow * Vnow) / m
Re = Math.abs(RePl * Vnow)
Vnow += acc * dt
if ((m - Volnow * rhooil)>=0) floatDepth=Hnow //Simpler than solving a quadratic equation
if (Vnow <= 0 && Down) Down = false
Hnow -= Vnow * dt
maxDepth=Math.min(maxDepth,Hnow)
tnow += dt
HPlot.push({ x: tnow, y: Hnow * 1000 })
VPlot.push({ x: tnow, y: Math.abs(Vnow)})
}
//Now set up all the graphing data detail by detail.
let plotData = [HPlot, VPlot]
let lineLabels = ["Height", "Velocity"] //An array of labels for each dataset
const prmap = {
plotData: plotData,
lineLabels: lineLabels,
xLabel: "t& s", //Label for the x axis, with an & to separate the units
yLabel: "H& cm", //Label for the y axis, with an & to separate the units
y2Label: "v& m/s", //Label for the y2 axis, null if not needed
yAxisL1R2: [1, 2], //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: [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: 'F2', //These are the sig figs for the Tooltip readout. A wide choice!
ySigFigs: 'F1', //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 {
Vt: Vt.toFixed(1),
Vimpact: Vimpact.toFixed(1),
maxDepth: (-maxDepth*100).toFixed(1),
floatDepth: (floatDepth*100).toFixed(1),
rhofoam: (rhofoam/1000).toFixed(2),
thetar: thetar.toFixed(0),
plots: [prmap],
canvas: ['canvas'],
};
}
The core equations for the foam sphere radius R (you enter Diameter) falling through air from an initial height H and then in the liquid are the same. The acceleration `a` given a velcocity v at time t is `a=(δv)/(δt)` which depends on the mass m (which, in turn, depends on the foam's volume `V=4/3πR^3` and density, see below for the calculation of how this depends on Expansion ratio, S, or air volume fraction φ), the density of the fluid `ρ_(fluid)`, the drag coefficient Cd, the cross sectional area `A=πR^2` and the velocity.
`m(δv)/(δt)=mg-0.5ρ_(fluid)CdAv^2`
By stepping through with small time intervals δt the current velocity and distance travelled, H, can be calculated as `v_(t+δt)=v_t+aδt` and `H_(t+δt)=H_t+vδt`
The difference in the calculation for the liquid is that the mg term on the right has to be replaced by `(m-Vρ_(liquid))g` which includes the buoyancy term where V is the volume immersed - which rapidly increases (equation not shown - read the code) as the sphere enters the liquid. Also the drag term uses the instantaneous cross-sectional area (up to `πR^2`, again, equation not shown). The foam slows down then moves upwards propelled by the buoyancy. It comes to rest at a float depth where the foam mass and the buoyancy forces balance.
The drag coefficient for a sphere is often said to be 0.5, but in reality it is strongly dependent on the Reynolds number. Those interested in the formula for this dependence can find CDv in the code, the velocity-dependent CD which in turn relies on calculation of the Reynolds number.
The graph shows both the height and velocity with time. The calculation stops when the foam reaches its equilibrium float depth and doesn't attempt to show it bobbing up and down. Note that the scale in the liquid is 10x larger, so read the values as mm not cm.
The textbox outputs show the plunge depth (of the lowest point of the sphere) in the liquid and the equilibrium floating depth. Then the impact velocity is shown and for interest, the terminal velocity of the foam falling from many metres is also shown.
In reality the foam might break up in the air, or on hitting the liquid, or when the liquid starts interacting with the foam. The calculations are simply to show limiting cases.
The foam density depends on the volume fraction of air, φ, which is given from the Expansion, S, as `φ=1-1/S`. The density of the foam is `ρ_(foam)=φρ_(air)+(1-φ)ρ_(water)` or, effectively, `ρ_(foam)=ρ_(water)/S`.
It has been noted that foam bounces ("ricochets") off the liquid when it hits at an angle below a critical ricochet angle `θ_c`. The standard formula (used widely even though there are many assumptions behind it) is that:
`θ_c=18/sqrt(ρ_(foam)/ρ_(liquid))`