🦠 Eutrophication
Interactive lake eutrophication simulator: phosphorus loading, algae blooms, dissolved oxygen crash and fish kill. Explore regime shifts and hysteresis.
About this simulation
This model runs a five-variable system of ordinary differential equations — phosphorus (P), algae biomass (A), dissolved oxygen (O), fish biomass (F) and dead organic matter (D) — integrated step by step with fourth-order Runge-Kutta. Algal uptake of phosphorus follows Monod kinetics, whilst oxygen is replenished by reaeration and drawn down by respiration and decomposition. Push phosphorus loading past a threshold and the lake tips from a clear, oxygenated state into a turbid, oxygen-starved one, and winding the loading back down does not retrace the same path, producing a hysteresis loop you can watch trace out on the phase plot.
🔬 What it shows
A lake tank sits alongside live bar readouts for phosphorus, algae, oxygen and fish, plus a loading-versus-algae phase plot. Four regimes — clear, transition, blooming and anoxic — are colour-coded and update in real time as the underlying equations are integrated.
🎮 How to use
Choose a starting preset (Oligotrophic, Mesotrophic, Eutrophic, Collapsing), then drag Phosphorus loading, Fish stocking (grazing) and Reaeration to see how each shifts the balance. Heavy rain and Drought inject short nutrient shocks, Sim speed rescales time, and Pause/Reset control the run.
💡 Did you know?
Real dead zones, such as the one in the Gulf of Mexico, can exceed ten thousand square kilometres in a single summer — driven by exactly the phosphorus loading this model condenses into a single slider.
Frequently asked questions
Why doesn't lowering phosphorus loading immediately clear the lake again?
Dead algae settle as organic matter, and once oxygen falls low enough that matter recycles phosphorus back out of the sediment faster than it settles, so the lake's internal phosphorus supply keeps feeding blooms even after external loading drops. This delayed feedback is what produces the hysteresis loop traced on the phase plot.
What determines when fish start dying in the model?
Fish biomass loses mass through a constant background mortality plus an oxygen-linked term that switches on once dissolved oxygen drops below 3 mg/L; the further oxygen falls beneath that threshold, the faster fish die off, which is why the regime label flips to anoxic once oxygen or fish biomass crosses its critical value.
What does the Reaeration slider actually change?
It scales how quickly oxygen exchanges with the atmosphere at the lake surface, pulling dissolved oxygen back towards its saturation value of 10 mg/L. Turning reaeration up can partly offset a deficit caused by algal respiration and decomposition, but cannot by itself stop a bloom from forming.
Why do Heavy rain and Drought behave differently from the loading slider?
Heavy rain adds a temporary pulse to phosphorus input that decays away over time, while Drought temporarily raises the concentration multiplier on existing loading. Both effects fade exponentially, modelling short-lived weather events rather than a permanent change in nutrient management.
What is the hysteresis area statistic tracking?
It is a running shoelace-formula estimate of the area enclosed by the loop traced in the loading-versus-algae phase plot. A larger area means the clear and turbid states are more strongly separated, so more effort is needed to push the lake back to clear once it has tipped into bloom.
Slowly raise phosphorus loading and a clear lake tips into algal blooms, anoxia and fish kill — and may not recover when loading is reduced. A regime-shift ecosystem with hysteresis.
3D · Three.js / WebGL renderer · 60 FPS target · runs fully client-side, no install