Buoyancy, live¶
The upward acceleration of a block of one density in a surrounding of another, Archimedes' reduced gravity g′ = g (ρₛ − ρ) / ρ: a lighter block rises, a denser one sinks, a neutral one is still. Below, a block in air of 1.2 kg/m³ is swept from 0.4 kg/m³ lighter than the air to 0.4 kg/m³ denser, 0.005 kg/m³ a step, twenty steps a second, and at each the library's law (lusine.laws.buoyancy) gives its acceleration on your GPU as you read. Beside it, a block of air ten degrees warmer than the 290 K air around it, both densities the library's (lusine.properties.gas_density), against the closed form for air at one pressure, g′ = g ΔT / T.
This page runs the program on your GPU through WebGPU, so it needs a browser with WebGPU (a recent Chrome, Edge, Safari or Firefox). Without it the program does not run and nothing is drawn below.
What it shows¶
- The strip above the controls is green while every check holds, and turns red for good once one fails.
- The block: the chart draws the block's upward acceleration against how much denser than the air it is, a point a step over one whole sweep: up where it is lighter, down where it is denser, through zero where it is neither. Below it, the difference and the acceleration there.
- Warm air: the warm block's acceleration from its two densities, about 0.34 m/s², beside g ΔT / T.
- The checks, each held at every step: lighter rises, the acceleration up exactly where the block is lighter than the air and down exactly where it is denser; falls with density, the acceleration lower at every step of the sweep than at the one before; neutral is still, a block of the surroundings' own density, in air or in water, feeling nothing at all; warm air, the warm block within 0.002% of the closed form.
Every number here is computed by the program on the GPU; the page only reads the values back and draws them. Gravity, the air's density, the sweep and the warm block's temperatures are the program's settings, which the host may write; this page offers no control to change them yet.
The program¶
The sweep, the law's answers and the checks, the panels the page draws, and the one procedure, main, run each step: the sweep moves on, the law is asked for the block, the warm block and the neutral ones, and the checks are taken.
// Archimedes' reduced gravity's live page: a block's density swept from lighter than the air around it to denser, the
// library's buoyancy at each, and a block of warm air in cooler air beside the closed form for air, with the page's
// checks computed here on the GPU and shown by the panels the program declares.
namespace buoyancy;
lusine.version version = { { number = 1 } };
// The reader's settings: gravity, the surrounding air's density, and the sweep: how much denser than the air the
// block starts and how far each step moves it; and a block of warm air, its temperature and the air's around it, at
// one pressure, of dry air's molar mass.
host struct {
float<m/s2> gravity = 9.80665 m/s2; float<kg/m3> surrounding = 1.2 kg/m3;
float<kg/m3> lowest = -0.4 kg/m3; float<kg/m3> stride = 0.005 kg/m3;
float<K> warm = 300.0 K; float<K> cool = 290.0 K; float<Pa> pressure = 101325.0 Pa;
float<kg/mol> molar_mass = 0.0289645 kg/mol;
} settings;
// The sweep: the step it is at, from 0 to 160 and round again, starting from the middle, how much denser than the air
// around it the block is there and the block's density; and whether a step has been taken before this one.
struct { integer step = 79; float<kg/m3> difference; float<kg/m3> density; bool begun; } sweep;
// The block's upward acceleration at the sweep, and the last step's; the warm block's, with its closed form for air at
// one pressure, g (T_warm - T_cool) / T_cool.
struct { float<m/s2> lift; float<m/s2> before; float<m/s2> warm; float<m/s2> closed_form; } law;
// The checks: the sign the density's (a lighter block rises, a denser one sinks); the lift falling as the block grows
// denser, at every step of the sweep; a block of the surroundings' own density, of air or of water, feeling nothing;
// and the warm block's lift within 0.002% of the closed form.
struct { bool sign = true; bool falls = true; bool neutral = true; bool warm_air = true; } checks;
// A strip of lamps the page draws, lit green while every check holds and red once one fails.
struct lamp { vector<float, 4> colour; };
lattice<lamp, 2> lamps(spacing = 1 m, boundary = wall);
vector<float, 4> lamp_colour(bool holds)
{
return holds ? vector<float, 4>(0.15, 0.6, 0.3, 1.0) : vector<float, 4>(0.75, 0.15, 0.15, 1.0);
}
output table<lusine.widget> panels = {
lusine.series { { panel = "the block", chart = "reduced gravity", quantity = law.lift, steps = 161,
against = sweep.difference, label = "g'" } },
lusine.value { { panel = "the block", quantity = sweep.difference, label = "denser than the air by" } },
lusine.value { { panel = "the block", quantity = law.lift, label = "upward acceleration" } },
lusine.value { { panel = "warm air", quantity = law.warm, label = "10 K warmer" } },
lusine.value { { panel = "warm air", quantity = law.closed_form, label = "g dT / T" } },
lusine.value { { panel = "the checks", quantity = checks.sign, label = "lighter rises" } },
lusine.value { { panel = "the checks", quantity = checks.falls, label = "falls with density" } },
lusine.value { { panel = "the checks", quantity = checks.neutral, label = "neutral is still" } },
lusine.value { { panel = "the checks", quantity = checks.warm_air, label = "warm air" } },
};
void main()
{
sweep.step = sweep.step >= 160 ? 0 : sweep.step + 1;
sweep.difference = settings.lowest + float(sweep.step) * settings.stride;
sweep.density = settings.surrounding + sweep.difference;
law.before = law.lift;
law.lift = lusine.laws.buoyancy(sweep.density, settings.surrounding, settings.gravity);
law.warm = lusine.laws.buoyancy(density = lusine.properties.gas_density(settings.pressure,
temperature = settings.warm,
settings.molar_mass),
surrounding = lusine.properties.gas_density(settings.pressure,
temperature = settings.cool,
settings.molar_mass),
settings.gravity);
law.closed_form = settings.gravity * (settings.warm - settings.cool) / settings.cool;
checks.sign = checks.sign && (law.lift > 0.0 m/s2) == (sweep.density < settings.surrounding)
&& (law.lift < 0.0 m/s2) == (sweep.density > settings.surrounding);
checks.falls = checks.falls && (!sweep.begun || sweep.step == 0 || law.lift < law.before);
sweep.begun = true;
checks.neutral = checks.neutral
&& lusine.laws.buoyancy(density = settings.surrounding, settings.surrounding, settings.gravity)
== 0.0 m/s2
&& lusine.laws.buoyancy(density = 1000.0 kg/m3, surrounding = 1000.0 kg/m3, settings.gravity)
== 0.0 m/s2;
checks.warm_air = checks.warm_air && abs(law.warm / law.closed_form - 1.0) <= 0.00002;
lamps.colour = lamp_colour(holds = checks.sign && checks.falls && checks.neutral && checks.warm_air);
}
The law's other proof (the reduced gravity over a sweep of densities, and a block of each surrounding's own density) is on its proof page.