Skip to content

Nitrogen cycle

Organic matter rots to ammonia, ammonia becomes nitrite, nitrite becomes nitrate. Two bacterial guilds run the last two stages, and both pay in dissolved oxygen — 4.57 mg of O₂ per mg of nitrogen carried the whole way, three quarters of it on the first step. The colonies grow on the work they actually do and fade on a maintenance clock that never stops, so a biofilter is a stock the tank has to keep earning.

MechanicStatusWhy
Three-stage chainsettledCompound mass converts through the molecular weights in src/simulation/core/; no tunable restates one.
Ammonia sourcesettledEvery organic pool rots — food and waste in the water, the bed’s mulm where it lies — releasing what its composition holds.
Processing capacitysettledPopulation × per-cell throughput × warmth × air, with no volume term — the same colony clears the same mass in a nano and a 300 L.
Substrate limitationsettledMonod on total ammonia for AOB and on nitrite for NOB, so a cycled tank holds hundredths of a ppm and a pulse stands until the colony works it down.
Colony growth and decaysettledLogistic growth scaled by utilization; unconditional maintenance decay on a 21-day half-life.
Oxygen limitationsettledMonod on both guilds, NOB’s half-saturation nearly 4× AOB’s — which is where standing nitrite comes from.
TemperaturesettledOne Q10 factor across oxidation, growth and decay, because they are one metabolism.
Guild seedingsettledA trickle per litre of water that never stops, so a guild is always present and grows the moment it has feedstock — no concentration gate.
RotsettledOne first-order law for every pool, each at its own rate: Q10 on temperature, a Monod on the oxygen there is, and a slow anaerobic path that runs without it.
Ammonia’s other consumerssettledPlants and the blooms take ammonia into their stores, from what the colony left; the colony works on what they leave and the hour’s arrivals.
N mass conservationsettledWater, organics, the bed’s store and every body — plant and bloom tissue and stores, fish, their guts and their clutches — conserve N per atom, whichever form it was taken in. It enters only as food, fertilizer, root tabs and stocked fish and plants, and leaves only with water changes, the gravel vac and the fish and plants taken out.
Colony sizing on inert bedssettledA colony grows to the load it is fed, not to the surface under it, so an inert bed’s smaller surface lowers the ceiling without setting the cycling clock.
Cycled seedsettledA 'cycled' colony is the one the tank’s load sustains at rest — its fish eating the ration that pays their upkeep, and its bed’s mulm rotting — floored at a fishless month’s share of the surface ceiling. A seeded colony already clears its resting load at the trace line, so a stocked setup opens without a spike; food fed past upkeep is outside that load, so an overfed tank’s colony grows on from the seed.
Nitrogen alertssettledFree NH₃, nitrite and nitrate alert at the shared *_EDGEs, the lines every fish’s own edge is read off.
Bed disturbancescaffoldingLifting hardscape stirs one slot’s share of the bed per piece, and uprooting a plant its own patch: that share of the mulm comes loose as waste and its biofilm is scraped off. The bed holds days to weeks of the tank’s waste, so a rescape shows as a bump the colony works down.
DenitrificationmissingNitrate has no biological sink. It leaves only through plant growth and water changes, so an unplanted tank accumulates it without bound.
Nitrification aciditysettledStoichiometric: the 2 H⁺ each NH₄⁺ releases spend two equivalents of KH, 7.14 mg CaCO₃ per mg of nitrogen, against the one ammonia took up as it was minted — the account is on Water & gases. A tank that nitrifies without water changes loses its buffer and its pH.
StageReactionRun by
1 · Rotfood, waste, mulm (g) → NH₃ + PO₄ + K + Fe (mg) + CO₂Decomposers, first order on each pool at what it holds — see where the ammonia comes from
2 · Ammonia oxidationNH₄⁺ + 1.5 O₂ → NO₂⁻ + 2 H⁺ + H₂OAOB, saturating on what is dissolved
3 · Nitrite oxidationNO₂⁻ + 0.5 O₂ → NO₃⁻NOB, saturating on what is dissolved

Nitrogen is conserved atom for atom across the chain. Compound mass is not — it grows with molecular weight, and every conversion reads its ratio from the shared chemistry in src/simulation/core/ so the whole engine agrees on the arithmetic.

ConversionFactorDerivation
NH₃ → NO₂⁻2.702MW_NO2 / MW_NH3
NO₂⁻ → NO₃⁻1.348MW_NO3 / MW_NO2
O₂ spent per mg NH₃2.8191.5 × MW_O2 / MW_NH3
O₂ spent per mg NO₂⁻0.3480.5 × MW_O2 / MW_NO2
KH per mg NH₃ minted, as CaCO₃+2.939+1 × CACO3_PER_EQUIVALENT / MW_NH3
KH per mg NH₃ oxidised, as CaCO₃−5.877−2 × CACO3_PER_EQUIVALENT / MW_NH3

The oxygen draw is derived from the nitrogen actually oxidised, never quoted separately. A tank that cannot run the reaction does not pay for it.

StockFills itDrains itUnit
foodFeeding, at the food’s compositionFish eating; rot; settling into the bedg
wasteFish feces, dead fish and eggs, plant and bloom shedding and die-back, scrubbed film, a disturbed bedRot; settling into the bedg
mulmFood and waste settling; a fresh bed’s own organicsRot; a gravel vac; disturbance, back into wasteg
ammoniaRot; fish gill excretion — a meal’s excess and every gram burnedPlant and bloom growth, from what the colony left; AOB oxidation; water change removes proportional massmg
phosphate · potassium · ironRot, at what each pool holds; fish excretion; fertilizer dosing; the bed’s leakPlant and bloom growth; water changemg
nitriteAOB oxidation, × 2.702NOB oxidation; water changemg
nitrateNOB oxidation, × 1.348; fertilizer dosing; the bed’s leakPlant and bloom growth, for the nitrogen ammonia leaves; water changemg
aobSeeding trickle; logistic growth on utilizationMaintenance decay; surface-area capunits of 10⁶ cells
nobSeeding trickle; logistic growth on utilizationMaintenance decay; surface-area capunits of 10⁶ cells
oxygenGas exchange, elsewhereAerobic rot, 32/12 of the carbon it oxidises; 2.819 mg per mg NH₃ and 0.348 mg per mg NO₂⁻ oxidisedmg/L

A water change dilutes the three nitrogen compounds but leaves the food and waste standing in the water; only a gravel vac takes organic matter out, and only the mulm in the bed.

Nitrogen compounds are stored as mass in mg, and a concentration is derived from that mass and the standing water only where a threshold or a display needs one. Storing the conserved quantity is what makes evaporation concentrate the tank for free: same mass, less water, higher ppm, no code. Oxygen is the exception — it is stored as a concentration, so both oxidation steps divide their oxygen bill by standing water before pushing the effect.

On a drained tank that derivation returns 0, and both oxidation stages are gated on water > 0: nitrifiers oxidise what is dissolved. Maintenance decay sits outside that gate on purpose, so a colony in a drained tank dies back rather than waiting.

capacity = population × processingRate × warmth × air
consumed = capacity × S / (K + S) // S: concentration the tick ends on
utilization = consumed / capacity // 0..1, dimensionless

Each guild saturates on its own substrate as well as on oxygen: AOB on total ammonia, NOB on nitrite. Capacity is the maximum a colony reaches in a glut; in ordinary water it runs at a Monod share of it, so a colony works in proportion to what is dissolved rather than at a fixed pace up to its limit.

The curve is read at the concentration the tick ends on — the root of consumed = capacity × monod(standing − consumed). Read at the start instead, a colony with more throughput per hour than the half-saturation mass would empty the pool every tick and a cycled tank would read exactly zero. Read at the end, uptake never exceeds either the stock or the capacity, and a steady state rests where the continuous curve puts it.

GuildSubstrateHalf-saturation KSource
AOBNH₃ + NH₄⁺, as NH₃0.61 ppm (0.5 mg/L N)Nitrosomonas, low end of wastewater models’ 0.5–⁠1 mg/L N
NOBNO₂⁻0.66 ppm (0.2 mg/L N)Nitrospira, the guild that dominates aquarium biofilters, 0.1–⁠0.3 mg/L N

Capacity carries no volume term. Throughput is a property of the cell, so the same colony clears the same milligrams in a nano and in a 150 L — which is what makes a ppm reading fall with volume the way it does in a real tank.

NOB take the same per-cell throughput scaled by ≈ 2.951. That is the 2.702 mass ratio re-quoted through each guild’s own oxygen factor at air saturation, rather than the bare ratio, which would hand NOB AOB’s correction on top of their own and leave them 8.4 % under parity.

FlowFormGated on
Seedingwater × seedingRate, both guildsStanding water; held under the surface ceiling
Growthpop × growthRate × warmth × air × utilization × (1 − pop/max)Utilization — nothing to oxidise means no growth
Decaypop × deathRate × warmthNothing. It is unconditional
Surface capPopulation truncated to surface × bacteriaPerCm2Surface leaving the tank — a rescape, a media change
DisturbanceThe disturbed share of the bed’s colony scraped off; a lifted piece takes its own biofilmA keeper digging into the bed

Seeding is how a colony starts: cells settle out of the fill water and the air every tick, so a guild is never absent and emerges on exponential growth the moment its feedstock appears. With nothing to eat, a guild idles at seedingRate / deathRate — about 73 cells/mL. The rate is the cycling clock, and logarithmic in it: each tenfold cut adds three to four days.

air scales oxidation and growth alike, because a colony cannot divide on a reaction it cannot run. It deliberately does not scale maintenance decay, which is what makes an anoxic tank lose its biofilter rather than merely pause it.

Decay is maintenance loss, not starvation. Bacteria fade over weeks rather than collapsing when the meal ends, which is why a tank survives a holiday.

A colony under a steady load settles where the two flows cancel:

utilization_rest = deathRate / (growthRate × air × (1 − pop/max))

In air-saturated water with the ceiling far off, that is 4.0 % for AOB and 7.1 % for NOB. The rest point moves with oxygen, and not with temperature — warmth cancels out of it, because a cell that oxidises half as fast also divides and starves half as fast.

Utilization is the substrate curve, so the rest point fixes the concentration a cycled tank holds: S = K × u / (1 − u) — about 0.03 ppm ammonia and 0.05 ppm nitrite, almost whatever the load. A heavier load grows a bigger colony, not a higher reading. A pulse lifts S and with it the colony’s pace, so it clears in hours on a mature colony with headroom and in days on one still growing into its load.

GuildHalf-saturation KRate left at 8.38 mg/LRate left at 0.10 mg/L
AOB0.30 mg/L96.5 %25.0 %
NOB1.10 mg/L88.4 %8.3 %

Every base rate multiplied by that factor is a Monod maximum, reached only at infinite oxygen. The three nitrifier rates divide the shortfall back out, so what a tank at air saturation reproduces is the quoted 20 h doubling rather than the 20.7 h an uncorrected constant would give.

Both guilds read their oxygen where the hour leaves it, once rot, both oxidations and the air have drawn on the one stock together (Water & gases). The ratio between the two guilds runs from 1.000 at air saturation to 0.364 at 0.10 mg/L. That gap is the whole story of standing nitrite: a tank short of air goes on oxidising its ammonia long after it has stopped clearing the nitrite that ammonia becomes.

Oxygen, not surface, is the binding constraint on a mature colony. Held under a saturating dose, a bare 200 L settles at 95 % of its surface ceiling for AOB and 53 % for NOB — against 96 % / 94 % with the oxygen term switched off. Circulation decides how far short a guild stops: NOB run from 1.4 % with nothing moving the water to 90.1 % on a canister, an air pump and a powerhead.

Plants and the blooms take their nitrogen as ammonia first (Plants), and they run in the living tier, before the cycle: each hour they draw on what the colony left, and the colony meets what they leave beside the hour’s gill excretion; what rots lands beside the colony’s work and meets it the next hour. Each side draws through its own end-of-tick Monod, so neither overdraws the stock.

Flora take ammonia only as their stores lack it, so beside a stocked tank’s load they are a small drain — about 1 % in a community tank with a few easy plants, 5–15 % in a planted one — and a colony that still gets the rest settles at its usual trace. Where they take most of it, the colony shrinks to what is left and ammonia falls under that trace, to where the flora’s draw meets the supply. An uncycled tank’s rising ammonia feeds them fully.

warmth = q10 ^ ((temperature − referenceTemp) / 10)

One metabolism, one factor: oxidation, growth and maintenance all carry it. A cold tank therefore needs a larger colony to clear the same load and takes longer to build it — an 18 °C cycle runs about twice the days a 25 °C one does — while the utilization the colony rests at does not move.

Rot and the fish. Every organic pool rots on one law: first order on what it holds, Q10 on temperature, aerobic on a Monod of the oxygen there is, and a slow anaerobic path, anaerobicShare of the pace, taking over as the oxygen runs out. What rots releases what the pool is made of — its nitrogen as ammonia, its phosphorus, potassium and iron to the water, its carbon as CO₂. Food and waste also settle into the bed as mulm, fastest in still water and halving at settlingHalfTurnover tank turnovers an hour; a bare bottom holds none. Every pool moves its content with its grams, so the nitrogen in the bed is the nitrogen that left the water.

PoolWhereHalf-life, 25 °C, oxygenated
foodThe water~14 h
wasteThe water~1.5 d
mulmThe bed~10 d

A fish excretes the rest at its gills: a meal’s nitrogen past what its reserve builds, and every gram of reserve it burns (Livestock) — so a richer food makes more ammonia.

A fresh bed’s mulm rots down until what settles in balances what rots. A water change can vacuum the bed, taking a share of its mulm out of the tank.

SubstrateColony surfaceOrganic reserve
none0 cm²/L0 g/L
sand400 cm²/L0.011 g/L
gravel800 cm²/L0.013 g/L
aqua_soil1200 cm²/L0.05 g/L

Surface and reserve are separate properties of the same bed: surface is the colony ceiling, the reserve is mulm, rotting.

Digging into the bed stirs a share of it: that share of the mulm comes loose as waste, and that share of the bed’s biofilm is scraped off.

MoveShare of the bed disturbed
Uprooting a rooted plantits footprint’s share of the floor — footprint / floor; an epiphyte disturbs nothing
Lifting a piece of hardscapeone hardscape slot — 1 / slots; the piece’s own biofilm leaves with it
Setting a piece downnothing; it arrives sterile
Swapping the bedall of it — the colony on it goes out with it and the new bed brings a fresh reserve

A release lifts the concentration the colony works against, so it stands as a bump until worked down. An established bed holds days to weeks of the tank’s waste as mulm, so rescaping a cycled tank shows as a bump, and digging up most of the bed at once as a larger one. An inert bed holds less mulm than soil does, so its colony grows to a smaller load, but it cycles on the same seeding clock. A 'cycled' seed skips the clock: each guild opens at the population where growth on its resting load meets decay, never below a fishless month’s share of the ceiling. That load counts the ration that pays the fish’s upkeep, not food fed past it, so a tank whose keeper feeds more grows its colony on from the seed.

The tunables are listed in the reference under Nitrogen cycle, and rot and settling under Decomposition.

ConstantMeaningValue
AIR_SATURATED_O2The water every nitrifier rate is quoted in8.38 mg/L
NeighbourReadWritten
Water & gasesoxygen, where the hour leaves it — rot’s aerobic share and both guilds’ oxidation and growthoxygen — rot’s draw and both oxidation steps’; co2, the carbon rot oxidises; kh, returned as rot mints ammonia and spent by ammonia oxidation
Environmentwater for ppm and the submerged gate, temperature for the Q10 factor—
Equipmentsurface — the colony ceiling, from filter media, substrate, hardscape and glass; the bed’s mulm, rotting where it liesFood and waste settle into the bed as mulm
Livestock—Fish eat food, write ammonia and the minerals through gill excretion, and waste as feces, dead bodies and dead eggs
Plants—Plants draw ammonia first and nitrate for the rest, with phosphate, potassium and iron, into their stores — the ammonia from what the colony left — and hand tissue back as waste when it is shed or dies, a dead plant’s stores with it
Algae—Each bloom draws the same forms from the water as plants do, ammonia first, and its shed, dead and scrubbed tissue comes back as waste, a die-back’s and a scrub’s stores with it; green water a water change takes leaves the tank
Actions—Feeding adds food; a water change removes ammonia, nitrite and nitrate mass proportionally, and a gravel vac a share of the bed’s mulm; dosing adds nitrate; uprooting a plant disturbs the bed
Alerts & logging—Free NH₃ > 0.02 ppm, nitrite > 0.5 ppm and nitrate > 80 ppm each raise an alert once per crossing

src/simulation/systems/ — with tunables in config/, molecular weights and rate shapes in core/, the mass ↔ ppm conversion in resources/, the bed in equipment/, and the cross-system accounting in tests/.