# "Cookbook: water, boats and plumbing"

# Cookbook: water, boats and plumbing

The guides behind these: [liquids](../reference/liquids.md), vehicles (skill `ferret-physics-vehicles`), media (skill `ferret`). 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 `Reservoir`s in a `LiquidNetwork`, the pipe is a link between them:

```ts
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:

```ts
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:

```ts
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:

```ts
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 (skill `ferret-physics-vehicles`) 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:

```ts
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:

```ts
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.
