Skip to content

Rates into stocks

Subsystems compute rates; the resource layer integrates those rates into stocks. A subsystem answers one biological question — how much of a compound this biomass moves in one hour — and hands back a mass. It does not decide what the tank then holds.

ComputesOwns
SubsystemA rate, as the mass moved this hourThe biology — what that rate depends on
Resource layerNothingThe stock, and the physical bounds it is held inside

The two halves never blur. A subsystem that wrote a stock would be settling the tank’s state from inside one mechanism, and the next mechanism to touch the same compound would be arguing with it rather than adding to it.

Every transfer is a plain value: a resource, a signed amount, and the mechanism that produced it. Nothing changes a stock by any other route.

A stock stores what is actually conserved, and concentration is derived from it wherever a threshold or a display needs one. Nitrogen compounds are held as mass, so evaporation concentrates a tank for free — same mass, less water, a higher reading, no code.

Dissolved gases are the exception, held as concentrations because that is what their equilibria are quoted in. A system that moves a gas therefore divides its mass by standing water before handing the effect over.

RejectedWhyInstead
A gateA condition flipping a rate between zero and full puts a cliff in the tank’s behaviour that no real tank hasA rate that reaches zero on its own as its driver does
A clampA rate that only stays sane because something truncated it is wrong just below the truncation tooA response shape that cannot overdraw the stock it reads
A special caseA branch for one species, one tank size or one preset is an admission the model doesn’t hold, carried as code instead of fixedA term that produces the special case as an ordinary output

The resource layer does hold each stock inside declared physical bounds, on what a step’s transfers net to, so the order they arrive in never decides what a stock holds. That is a floor under the arithmetic, not a mechanism — a mechanic that relies on it to stay sane is a defect the bound is hiding.

Consumption of a stock is [S] / (K + [S]): full rate while the substrate is plentiful, half rate at the half-saturation constant, nothing once it is gone. Each process quotes its own K, the way each quotes its own Q10.

The property that earns it the default is that a stock drawn through a Monod factor is never overdrawn. Demand falls with supply, so the stock approaches zero rather than crossing it. Two systems drawing on one pool in the same hour both slow down, which is exactly the job a rationing scheduler would otherwise have been written to do.

ShapeFormReads
Monod[S] / (K + [S])A stock something consumes — dissolved oxygen, a nutrient, a store
Q10q10 ^ ((T − Tref) / 10)Temperature, on anything enzymatic
Arrheniusexp(T_A / Tref − T_A / T), in kelvinTemperature on a fish’s energy budget, each species on its own T_A, 1 at 20 °C
Jassby–Platttanh(PAR / Ik)Light. Nothing can overdraw it, so the curve comes from the leaf rather than from the pool
Beer–Lambertexp(−k × x)Light on its way down, x the water or the leaf area above — so depth and a canopy share one exponent
First order1 − e^−k of the stock over the hourA stock or gap closing in proportion to itself — a gut digesting, a store filling
Shortfallmax(0, 1 − x / edge)A need short of its edge — a plant’s Droop limit under the edge its stores count as fed
Band comfortSymmetric parabola 4(x − lo)(hi − x) / (hi − lo)²The in-band benefit of a tolerance band — full at the centre, zero at each edge where the band’s damage starts
Log doseln(x / edge) past an edge, or ln((edge + a) / (x + a)) under one, the offset a keeping it finite at zeroA toxin, where every doubling costs the same, or a shortfall like oxygen’s — and, between two anchors, the fish O₂ benefit

None in the organism layer: everything an organism earns, suffers and grows on is a rate, and what one organism does to another goes through a stock or the light between them — a bloom shades a plant by the light it takes, not a charge. Two things look like switches and are not. A band edge where a rate starts from zero is a rate — nothing jumps, the slope merely stops being zero. And death at condition 0 is a real discontinuity, because an organism past it is genuinely a different thing.

src/simulation/systems/ and src/simulation/core/ hold the rates and the shapes they are built from; src/simulation/resources/ holds the stocks and their bounds.