FERRETGame engine over Babylon.js
Ferret

Nuclear

Package @ferret/physics-nuclear, capability nuclear.

What it is for#

A cobalt source in a lead container and a counter that clicks faster as you approach. A heap of fallout you have to cross quickly. A reactor you start, hold, scram, or let melt. A lump of fissile material that goes critical when you add the last piece. A sample that becomes radioactive after a night in a neutron flux.

The physics is textbook physics: decay laws, inverse-square dose, half-value layers, point reactor kinetics. The isotope and material tables that ship with the package are sample data; a game replaces them with its own.

The ideas#

Radiation in a game comes down to three levers the player can pull: distance (the dose falls with the square of it), shielding (every half-value layer of lead or concrete halves the dose) and time (the dose is the rate multiplied by the time spent). Everything in the package serves those three.

  • Isotopes decay with a half-life into a daughter, releasing energy and particles of some kinds (alpha, beta, gamma, neutron). Part of the energy stays where the atom decayed and becomes heat. A set of ready isotopes (EXAMPLE_ISOTOPES) covers Co-60, Cs-137, Sr-90, Mo-99, Rn-222, U-238 and a few stable ones.
  • An Inventory is a pile of atoms of several isotopes. Decay is computed exactly, so chains and equilibrium come out right at any time step. A strontium source grows its own daughter, and after a few weeks the two activities match.
  • Dose is the activity times the particles per decay, times a dose coefficient, times what the shield lets through, spread over 4π r². Between a source and a receiver the capability walks the ray through the scene and takes the slant thickness of every body made of a shield material, so a thick wall seen at an angle shields more than one seen head-on.
  • A Reactor is the heart of a plant: neutrons, delayed neutrons that make control possible, temperature and steam feedback, control rods, xenon poisoning, burn-up and the decay heat that goes on after a shutdown.
  • An Assembly is fissile material measured against its critical mass. Below it nothing happens. Above it the chain runs away until the assembly blows itself apart.
  • Activation turns a stable material into a radioactive one under a flux. Fallout is a ground grid in which every cell holds an inventory that decays like any other, and rain can wash a share away.

Using it#

import { nuclear } from '@ferret/physics-nuclear';

const n = nuclear();
host.register(n);
host.enable('nuclear');

const pig = n.addSource('pig', { entity: pigEntity });      // a source on an entity
pig.addActivity('Co-60', 1e12);                              // 1 TBq
n.addReceiver('geiger', { entity: playerEntity, sensitivity: 6e9, seed: 1 });

A body whose physics material is a name in the shield library (lead, concrete, water, ...) shields whatever is behind it. A source on an entity that has a heat part warms it with the decay heat, which is how a hot waste drum works.

A receiver with a sensitivity is a counter: it draws random counts at dose rate × sensitivity (a Geiger tube is about 6·10⁹ counts per sievert) and raises radiation:counts. Receivers without it just add up a dose, and radiation:dose fires every doseStep sieverts.

Reactors#

n.addReactor('core', { power: 1e6, generation: 1e-4, rodWorth: 0.05, rodsCritical: 0.5,
  fuelHeat: 5e5, coolantHeat: 2e5, exchange: 5e4, flow: 2e4, inlet: 290, fuelCoefficient: -2e-5 });

What matters for play:

  • Delayed neutrons make control possible. A small step of reactivity makes the power jump a little and then climb slowly over seconds. A step bigger than the delayed fraction (about 0.65 %) makes it race up in milliseconds, and the capability raises reactor:prompt.
  • Feedback. With a negative fuel temperature coefficient the reactor settles by itself at the level the rods allow; with a positive one it diverges. A void coefficient models coolant boiling away.
  • Rods. setRods moves them from 0 (out) to 1 (in); rodsCritical is where they hold the reactor at nominal power. scram() drops them at once, and a trip threshold on power or fuel temperature does it automatically.
  • Decay heat. After a scram the fuel still produces 6–7 % of nominal power, falling slowly. Without cooling (flow: 0) it heats up until it melts (reactor:melt, once). That is the whole lesson of a loss-of-coolant accident, and one of the scenarios plays it out.
  • Xenon. After a shutdown, xenon-135 builds up for hours and can make a restart impossible. Burn-up makes fuel lose reactivity as it is used, until the rods run out.

The reactor has no randomness: the same inputs give the same run.

Critical assemblies#

n.addAssembly('device', { mass: 55, criticalMass: 50, disassemblyEnergy: 2e6 }, { position: [0, 0, 0] });

The assembly compares its mass with the critical mass. A reflector lowers the critical mass; compression lowers it with the square of the compression. Above critical it raises assembly:critical, then runs away until it disassembles (assembly:disassembled { energy, tnt }). The energy released is the fissioned mass times 8·10¹³ J/kg, and the capability passes it to explosions as an air blast.

Fallout#

A Fallout is a ground grid with a cell size. deposit(x, z, isotope, atoms) puts material in a cell; deposit_disc(x, z, radius, isotope, bq) spreads an activity evenly over a disc. decay(dt) ages it, and wash(fraction, at?) removes a share, which is what rain or a hose does. A wide even deposit gives the dose of an infinite plane, and a small patch far away obeys the inverse square.

Events and commands#

Events: decay, radiation:dose, radiation:counts, reactor:scram, reactor:prompt, reactor:melt, assembly:critical, assembly:disassembled.

Commands: nuclear.info, isotope.add { source, isotope, atoms | activity }, radiation.dose { receiver }, radiation.map { min, max, step, y? } (a grid of dose rates, ready for a hazard map), reactor.state, reactor.rods { name, fraction }, reactor.scram, assembly.state. cap.doseAt(receiver) returns the current dose rate by kind of radiation.

Parameters#

ValueDefaultEffect
doseStep1e-3 Svdose between two radiation:dose events

cap.coefficients hold the sievert-metres² per particle for each kind; replace them if your numbers differ.

Works with#

heat: decay heat warms the thing that carries the source. explosions: a disassembled assembly is a blast. terrain and liquids: soil and water are shields, and fallout lives on the ground grid. links: a reactor can heat a boiler and a turbine.

Cost#

A small matrix product per inventory (kept between steps, so use a constant dt), a handful of rays for every source-receiver pair, a few operations per reactor. Nuclear is cheap.

When it does not behave#

SymptomCause
isotope "x" needs a half-life above zerouse Infinity for a stable isotope
"x" is stable: it has no activityaddActivity needs a decaying isotope; use add(atoms)
The counter never clicksno sensitivity, or the walls have no half-value layer for that kind
The dose ignores a wallthe wall's material is not a shield name
The reactor will not stay criticalrods are not at rodsCritical
Power swings after a stepxenon and temperature feedback; leave maxSubstep alone unless the coast is long
An assembly never goes criticalits mass over critical mass (after reflector and compression) is below 1; k shows the value

Worked numbers (inverse square and half-value layers, equilibrium of a chain, activation, steady reactor power, decay heat, critical assembly energy) are in tests/unit/examples/physics-nuclear.test.ts.

Reference#

nuclear, NuclearCapability, Inventory, IsotopeLibrary, ShieldLibrary, doseRate, Reactor, Assembly, activate, Fallout.