The Reynolds number, live¶
How much a flow's inertia outweighs its viscosity past a body, Re = ρ |u| L / μ, with ρ the fluid's density, |u| the body's speed through it, L its length (a sphere's diameter) and μ the fluid's dynamic viscosity. It says which drag law holds: below about 1 Stokes's, linear in the speed (lusine.laws.drag); from about 10³ to a sphere's drag crisis near 2 × 10⁵ the wake's, quadratic (lusine.laws.quadratic_drag). Below, a boule (74 mm across) and a jack (30 mm) in air at 20 °C are swept in speed from rest to 10 m/s, a sixteenth of a metre a second a step, twenty steps a second, and at each the library's law (lusine.properties.reynolds_number) gives their Reynolds numbers on your GPU as you read.
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.
- In air: the chart draws the boule's and the jack's Reynolds numbers against their speed on a log scale, a point a step over one whole sweep, between the two bounds drawn flat: above Stokes's 1 from the first few centimetres a second, and below the drag crisis at every speed a game throws them. Below it, the speed, the boule's number and the same number from the kinematic viscosity ν = μ / ρ, |u| L / ν, a different order of the same operations.
- The cases: the boule and the jack thrown at 7 m/s, and a 0.1 mm grain of sand settling at 1 mm/s in water.
- The checks, each held at every step: the reference values, the boule at Re = 34,457 and the jack at 13,969, each within 5, and the grain at 0.1 within 0.0001%; the drag regimes, the boule and the jack in the wake's drag and the grain in Stokes's; kinematic viscosity, the number within 0.0001% of |u| L / ν; proportional, twice the speed giving exactly twice the number.
Every number here is computed by the program on the GPU; the page only reads the values back and draws them. The air, the water, the bodies and the sweep 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 boule, the jack and the grain, and the checks are taken.
// The Reynolds number's live page: a boule and a jack in air, their speed swept from rest, the library's Reynolds
// number at each against the bounds of the drag laws it chooses between, and the number held to the kinematic
// viscosity's form of it and to its reference values, with the page's checks computed here on the GPU and shown by the
// panels the program declares.
namespace reynolds_number;
lusine.version version = { { number = 1 } };
// The reader's settings: air at 20 C, its density and dynamic viscosity; a boule's diameter and a jack's; the speed a
// game throws them at; a grain of sand settling in water (its diameter, its speed, water's density and viscosity);
// where Stokes's drag gives way, about 1, and a sphere's drag crisis, near 2 x 10^5; and how far each step moves the
// speed, from rest.
host struct {
float<kg/m3> air_density = 1.204 kg/m3; float<Pa*s> air_viscosity = 0.0000181 Pa*s;
float<m> boule = 0.074 m; float<m> jack = 0.03 m; float<m/s> thrown = 7.0 m/s;
float<m> grain = 0.0001 m; float<m/s> settling = 0.001 m/s; float<kg/m3> water_density = 1000.0 kg/m3;
float<Pa*s> water_viscosity = 0.001 Pa*s;
float stokes = 1.0; float crisis = 200000.0; float<m/s> stride = 0.0625 m/s;
} settings;
// The sweep: the step it is at, from 0 to 159 and round again, and the speed there.
struct { integer step = -1; float<m/s> speed; } sweep;
// The boule's and the jack's Reynolds numbers at the speed and at the speed thrown; the boule's from its kinematic
// viscosity, |u| L / nu with nu = mu / rho; the grain's; and the two bounds, to draw.
struct {
float boule; float jack; float boule_thrown; float jack_thrown; float kinematic; float grain; float stokes;
float crisis;
} law;
// The checks: the boule and the jack at 7 m/s at Re = 34457 and 13969, each within 5; the grain at 0.1, within
// 0.0001%; the boule and the jack in the wake's drag (above 10^3, below the crisis) and the grain in Stokes's (below
// 1); the number the kinematic form's within 0.0001% at every speed; and twice the speed exactly twice the number.
struct { bool reference = true; bool regimes = true; bool kinematic = true; bool proportional = 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);
}
// The number from the kinematic viscosity: the speed times the length over mu / rho.
float kinematic(float<kg/m3> density, float<m/s> speed, float<m> length, float<Pa*s> viscosity)
{
let nu = viscosity / density;
return speed * length / nu;
}
bool doubles(float<kg/m3> density, float<m/s> speed, float<m> length, float<Pa*s> viscosity)
{
return lusine.properties.reynolds_number(density, speed = 2.0 * speed, length, viscosity)
== 2.0 * lusine.properties.reynolds_number(density, speed, length, viscosity);
}
output table<lusine.widget> panels = {
lusine.series { { panel = "in air", chart = "Reynolds number", quantity = law.boule, steps = 160,
against = sweep.speed, log = true, label = "boule" } },
lusine.series { { panel = "in air", chart = "Reynolds number", quantity = law.jack, steps = 160,
against = sweep.speed, log = true, label = "jack" } },
lusine.series { { panel = "in air", chart = "Reynolds number", quantity = law.crisis, steps = 160,
against = sweep.speed, log = true, label = "drag crisis" } },
lusine.series { { panel = "in air", chart = "Reynolds number", quantity = law.stokes, steps = 160,
against = sweep.speed, log = true, label = "Stokes's below" } },
lusine.value { { panel = "in air", quantity = sweep.speed, label = "speed" } },
lusine.value { { panel = "in air", quantity = law.boule, label = "boule" } },
lusine.value { { panel = "in air", quantity = law.kinematic, label = "boule, |u| L / nu" } },
lusine.value { { panel = "the cases", quantity = law.boule_thrown, label = "boule at 7 m/s" } },
lusine.value { { panel = "the cases", quantity = law.jack_thrown, label = "jack at 7 m/s" } },
lusine.value { { panel = "the cases", quantity = law.grain, label = "grain settling in water" } },
lusine.value { { panel = "the checks", quantity = checks.reference, label = "the reference values" } },
lusine.value { { panel = "the checks", quantity = checks.regimes, label = "the drag regimes" } },
lusine.value { { panel = "the checks", quantity = checks.kinematic, label = "kinematic viscosity" } },
lusine.value { { panel = "the checks", quantity = checks.proportional, label = "proportional" } },
};
void main()
{
sweep.step = sweep.step >= 159 ? 0 : sweep.step + 1;
sweep.speed = float(sweep.step) * settings.stride;
law.boule = lusine.properties.reynolds_number(density = settings.air_density, sweep.speed, length = settings.boule,
viscosity = settings.air_viscosity);
law.jack = lusine.properties.reynolds_number(density = settings.air_density, sweep.speed, length = settings.jack,
viscosity = settings.air_viscosity);
law.kinematic = kinematic(density = settings.air_density, sweep.speed, length = settings.boule,
viscosity = settings.air_viscosity);
law.boule_thrown = lusine.properties.reynolds_number(density = settings.air_density, speed = settings.thrown,
length = settings.boule, viscosity = settings.air_viscosity);
law.jack_thrown = lusine.properties.reynolds_number(density = settings.air_density, speed = settings.thrown,
length = settings.jack, viscosity = settings.air_viscosity);
law.grain = lusine.properties.reynolds_number(density = settings.water_density, speed = settings.settling,
length = settings.grain, viscosity = settings.water_viscosity);
law.stokes = settings.stokes;
law.crisis = settings.crisis;
checks.reference = checks.reference && abs(law.boule_thrown - 34457.0) <= 5.0 && abs(law.jack_thrown - 13969.0) <= 5.0
&& abs(law.grain / 0.1 - 1.0) <= 0.000001;
checks.regimes = checks.regimes && law.jack_thrown > 1000.0 && law.boule_thrown > law.jack_thrown
&& law.boule_thrown < settings.crisis && law.grain < settings.stokes;
checks.kinematic = checks.kinematic && abs(law.boule - law.kinematic) <= 0.000001 * law.kinematic;
checks.proportional = checks.proportional && doubles(density = settings.air_density, sweep.speed,
length = settings.boule, viscosity = settings.air_viscosity);
lamps.colour = lamp_colour(holds = checks.reference && checks.regimes && checks.kinematic && checks.proportional);
}
The law's other proof (the same cases against a reference in double precision) is on its proof page.