Cookbook: water, boats and plumbing
The guides behind these: liquids, vehicles, media. Each recipe says what to build and what to expect; the runnable versions, with the numbers they must produce, are in tests/unit/examples/physics-cookbook-water-and-boats.test.ts.
1. Two tanks find their level#
Join two reservoirs with a pipe and the levels meet, with the right time constant and no water lost. Tanks are Reservoirs in a LiquidNetwork, the pipe is a link between them:
const a = net.addReservoir({ id: 'a', liquid: 'water', container: boxContainer(1, 1, 3), level: 2 });
const b = net.addReservoir({ id: 'b', liquid: 'water', container: boxContainer(1, 1, 3), level: 0.2 });
net.addLink({ id: 'pipe', from: 'a', to: 'b', fromElevation: 0, toElevation: 0, diameter: 0.05, length: 2 });
Two equal tanks settle at the mean of the two starting levels. Put the pipe above the bottom (fromElevation: 0.5) and the lower tank never fills past it. Add check: true and the flow runs one way only; set valve: 0 and it stops. A tap is a link with main: { liquid, pressure }.
2. A U-tube of water and oil#
Two liquids of different density balance when ρ₁h₁ = ρ₂h₂, so the lighter one stands higher. Build two narrow cylinders with a link at the bottom and give each its own liquid:
net.addReservoir({ id: 'w', liquid: 'water', container: cylinderContainer(0.05, 1), level: 0.3 });
net.addReservoir({ id: 'o', liquid: 'oil', container: cylinderContainer(0.05, 1), level: 0.3 });
net.addLink({ id: 'u', from: 'w', to: 'o', fromElevation: 0, toElevation: 0, diameter: 0.02, length: 0.3 });
This is a manometer, and a hydraulic puzzle.
3. Waves slow down on a beach#
Shallow-water waves travel at √(g h) in the local depth, so a hump that runs over deep water arrives before the same hump over shallow water: twice the speed in four times the depth. WaterSurface is a grid of surface heights:
const sea = new WaterSurface({ nx: 400, nz: 4, dx: 0.5, depth: 2 });
sea.eta[i] = 0.01; // raise a cell to start a wave
sea.step(0.05);
Give depth as a function (x, z) => ... to build a shelving beach: waves bunch up and slow as they come in, reflect from the banks, and fade at open edges. Float a body on it with the surface capability's float and it rides the swell.
4. A boat sinks deeper with cargo#
The draft of a floating box is m / (ρ A): Archimedes. Double the load, double the draft. A Vessel takes a mass, an inertia and a hull of cells:
const boat = new Vessel({ mass, inertia, hull: { size: [4, 1, 10], cells: [8, 8, 12] },
position: [0, 0.5, 0], hullDamping: [0, 1e5, 0] });
boat.step(1 / 120, 1);
boat.draft; // how deep it sits
boat.stability().gm; // metacentric height
gm is positive and the boat rights itself, negative and it rolls over. A wide flat box is stable. Load goes high (raise cog) and gm falls. A part-filled tank takes more of it away by free surface; the vehicles guide shows compartments, breach and doors.
5. A wing that lifts, and stalls#
Lift is proportional to the angle of attack until the stall; after it, lift falls and drag climbs. Use it for a wing, a keel, a rudder, a sail. thinFoil makes a flat-plate polar and foilForce gives the force for a given flow:
const polar = thinFoil({ aspect: 6, Cd0: 0.01, stall: 0.3 });
const { force } = foilForce({ area: 2, polar, chord, span }, velocity, [0, 0, 0], 1.2);
thinFoil({ aspect, Cd0, stall, efficiency }) is a flat-plate polar; give your own Cl(α) and Cd(α) for a real profile. The force is lift across the flow and the span, drag along the flow. At zero angle there is no lift; the stall here is at 0.3 rad, about 17 degrees.
6. A ball that curves#
A spinning ball moving through air feels a force across both its spin and its velocity: a free kick, a spinning cue ball, a slice. magnus takes the velocity, the spin, the radius and the air density:
const force = magnus([30, 0, 0], [0, 0, 100], 0.11, 1.2);
host.kernel.applyForce(ball.body, force);
No spin gives no force; more spin gives more, saturating at a lift coefficient of 0.4 as the spin ratio rises. Apply the result each step to the ball's body.