@ferret/physics-nuclear
decay, activation, radiation dose and shielding, reactor kinetics, fallout.
Read the guide: how to use it →
Classes
Assembly class
class Assemblyspec: AssemblySpec | |
F: number | fission rate now, 1/s |
fissions: number | fissions so far |
time: number | |
critical: boolean | |
disassembled: boolean | |
onEvent: ((e: AssemblyEvent) => void) | null | |
constructor(spec: AssemblySpec) | |
get energy() | J released so far |
get fissioned() | kg of nuclei that fissioned |
get expansion() | compression that the heating has undone: the assembly expands as the energy per kg approaches its disassembly energy |
get criticalMassNow() | the effective critical mass now, kg |
get k() | multiplication |
step(dt: number) |
packages/physics-nuclear/src/assembly.ts:34
Fallout class
class FalloutWhat a release leaves on the ground: a grid of cells, each with its own inventory that decays exactly like any other, so a cell that holds Cs-137 loses its activity by the half-life and one that holds Ba-137m next to it keeps the daughter in step. Washing (rain, a hose) takes a share of every isotope off a cell, to a sink that is not tracked here.
readonly cell: number | |
readonly library: IsotopeLibrary | |
constructor(cell = 1, library: IsotopeLibrary = new IsotopeLibrary()) | |
deposit(x: number, z: number, isotope: string, atoms: number) | Put atoms of an isotope on the cell holding (x, z). |
deposit_disc(x: number, z: number, radius: number, isotope: string, bq: number) | Spread an activity (Bq) of an isotope evenly over a disc of the given radius. |
surfaceActivity(x: number, z: number, isotope?: string): number | Bq per m² on the cell holding (x, z): all isotopes, or one (a daughter grows in beside its parent, so the sum can rise as the parent falls). |
get total(): number | Bq on the whole ground. |
decay(dt: number) | Let every cell decay. |
wash(fraction: number, at?: [number, number]) | Take the share fraction of every isotope off the cell holding (x, z) or, with no position, off all of them. |
doseRate(x: number, z: number, height = 1, o: { mu?: number; coefficient?: number; reach?: number } = {}): number | The gamma dose rate (Sv/s) at (x, z) and height m above the ground: every cell is a point source of its gamma photons per second (activity
x the gamma yield of each isotope), seen through the air as e^(-mu r) / (4 pi r^2), summed over the cells within reach m. mu is the
attenuation of air for ~0.7 MeV photons (0.0035 /m); the dose coefficient is the library's fluence-to-dose for gammas. |
packages/physics-nuclear/src/fallout.ts:9
Inventory class
class InventoryAtoms of each isotope in a body, a vessel or a patch of soil.
readonly library: IsotopeLibrary | |
readonly atoms: Map<string, number> | |
stream: (() => number) | null | when set, the number of decays in a step is drawn from the Poisson law instead of taken at its expectation |
constructor(library: IsotopeLibrary = new IsotopeLibrary()) | |
add(isotope: string, atoms: number) | |
addActivity(isotope: string, bq: number) | Add an amount by its activity in Bq. |
amount(isotope: string) | |
activity(isotope?: string): number | Bq |
get mass(): number | kg |
get power(): number | Heat power now, W |
decay(dt: number): DecayResult | Decay for dt seconds. Exact for the expectation (matrix exponential of the network, with the decays integrated alongside). |
packages/physics-nuclear/src/decay.ts:108
IsotopeLibrary class
class IsotopeLibraryconstructor(initial: Record<string, IsotopeDef> = EXAMPLE_ISOTOPES) | |
add(name: string, d: IsotopeDef) | |
get(name: string): IsotopeDef | |
has(name: string) | |
names() | |
lambda(name: string): number | 1/s |
packages/physics-nuclear/src/decay.ts:49
Reactor class
class Reactorreadonly spec: Required<Pick<ReactorSpec, 'power' | 'generation' | 'rodWorth' | 'rodsCritical' | 'fuelHeat' | 'coolantHeat' | 'exchange' | 'inlet' | 'scramSpeed'>> & ReactorSpec | |
readonly beta: number[] | |
readonly lambda: number[] | |
P: number | fission power now, W |
C: number[] | delayed precursor groups in power units, W |
Tf: number | |
Tc: number | |
sink: number | heat taken from the fuel by whatever it is linked to (a structure, a pool), W; set by a link |
readonly Tf0: number | |
readonly Tc0: number | |
rods: number | |
target: number | a rod position the controller is driving to (the scram sets it to 1) |
external: number | extra reactivity from outside (a game's own cause) |
iodine: number | iodine-135 and xenon-135 as a share of their equilibrium at nominal power (1 = nominal equilibrium) |
xe: number | |
flow: number | |
scrammed: boolean | |
melted: boolean | |
time: number | |
fissions: number | |
energy: number | J of fission energy released |
maxSubstep: number | the longest sub-step, s; raise it for a long coast where nothing changes quickly |
onEvent: ((e: ReactorEvent) => void) | null | |
constructor(spec: ReactorSpec) | |
get betaTotal() | |
get void(): number | |
get rho(): number | reactivity (Δk/k) |
get decayHeat(): number | decay heat power now, W |
get thermal(): number | heat into the fuel, W |
get fissionRate() | fissions per second |
get period(): number | e-folding time of the power, s (Infinity when steady) |
scram() | |
setRods(position: number) | |
step(dt: number) | Advance dt seconds. Sub-steps follow the fastest rate of the kinetics. |
packages/physics-nuclear/src/reactor.ts:84
ShieldLibrary class
class ShieldLibraryconstructor(initial: Record<string, ShieldMaterial> = EXAMPLE_SHIELDS) | |
add(name: string, s: ShieldMaterial) | |
get(name: string): ShieldMaterial | undefined | |
names() | |
transmission(kind: RadiationKind, layers: Layer[]): number | The share of a beam of this kind that gets through the layers. |
packages/physics-nuclear/src/radiation.ts:35
Functions
activate function
function activate(inv: Inventory, captures: readonly Capture[], flux: number, dt: number): numberNeutron activation. A flux Φ (neutrons per m² and s) turns the nuclei of a target into its radioactive product at the rate σ Φ per nucleus:
N_to gains N_from (1 - e^(-σΦt)) over t and the target loses the same, so what is made is never more than there was. The product then decays
with the rest of the inventory (call inv.decay(dt) after this, which makes the activity rise to the saturation value N_from σ Φ and no further).
Returns the atoms made.
packages/physics-nuclear/src/activation.ts:15
chord function
function chord(b: Body, origin: Vec3, dir: Vec3, maxDistance: number): { enter: number; length: number } | nullLength of the chord a ray cuts through a body, from the point it enters, m (planes have no thickness here).
packages/physics-nuclear/src/radiation.ts:62
doseRate function
function doseRate( inventory: Inventory, r: number, layers: Layer[], shields: ShieldLibrary, coefficients: Record<RadiationKind, number> = EXAMPLE_DOSE_COEFFICIENTS, ): Record<RadiationKind, number>Dose rate (Sv/s) of a source at a point through the given layers, by kind.
packages/physics-nuclear/src/radiation.ts:121
expm function
function expm(A: number[][]): number[][]exp of a small dense matrix by scaling and squaring
packages/physics-nuclear/src/decay.ts:84
inhourRoot function
function inhourRoot(rho: number, generation: number, groups = DELAYED_GROUPS): numberThe stable period of the point-kinetics model for a reactivity step: the largest root ω of the inhour equation ρ = Λω + Σ βᵢω/(ω+λᵢ).
packages/physics-nuclear/src/reactor.ts:236
layersBetween function
function layersBetween(host: PhysicsHost, from: Vec3, to: Vec3, shieldOf: (b: Body) => string | undefined, except: Body[] = []): Layer[]The layers a ray crosses between two points: every body in the way, by the shield material its physics material names, plus the air between. except bodies (the source and the receiver themselves) are not counted.
packages/physics-nuclear/src/radiation.ts:91
nuclear function
function nuclear(isotopes = new IsotopeLibrary(), shields = new ShieldLibrary()): NuclearCapabilitypackages/physics-nuclear/src/index.ts:69
poisson function
function poisson(mean: number, rand: () => number): numberA count drawn from the Poisson law (Knuth for small means, the normal approximation above 50).
packages/physics-nuclear/src/decay.ts:71
rng function
function rng(seed: number)Deterministic seeded stream (mulberry32).
packages/physics-nuclear/src/decay.ts:65
solve function
function solve(A: number[][], b: number[]): number[]Solve A·x = b by Gaussian elimination with partial pivoting.
packages/physics-nuclear/src/reactor.ts:222
totalOf function
function totalOf: (r: Record<RadiationKind, number>) => numberpackages/physics-nuclear/src/radiation.ts:137
wayWigner function
function wayWigner(tau: number, top = Infinity): numberWay–Wigner: fraction of the operating power left as decay heat τ seconds after shutdown from top seconds of operation.
packages/physics-nuclear/src/reactor.ts:16
Interfaces
AssemblyEntry interface
interface AssemblyEntry extends Placedassembly: Assembly | |
spent: boolean |
packages/physics-nuclear/src/index.ts:46
AssemblyEvent interface
interface AssemblyEventtype: 'critical' | 'disassembled' | |
energy: number | |
fissioned: number | |
time: number |
packages/physics-nuclear/src/assembly.ts:32
AssemblySpec interface
interface AssemblySpecmass: number | kg of fissile material |
criticalMass: number | the bare critical mass of the material in this shape, kg (data) |
reflector?: number | critical mass is multiplied by this (a reflector < 1) |
compression?: number | density relative to the data's (compression > 1 lowers the critical mass as 1/c²) |
exponent?: number | exponent of k against m / m_c (1 = k equals the ratio) |
generation?: number | generation time, s |
source?: number | stray neutrons per second that start a chain |
disassemblyEnergy: number | J/kg of the assembly that blows it apart (data) |
nucleusMass?: number | kg per nucleus |
packages/physics-nuclear/src/assembly.ts:11
Capture interface
interface CaptureA capture that makes a radioactive nucleus: the stable from takes a neutron and becomes to, with a cross-section in barns (thermal Co-59: 37, Na-23: 0.53).
from: string | |
to: string | |
sigma: number |
packages/physics-nuclear/src/activation.ts:7
DecayResult interface
interface DecayResultheat: number | J left in the matter by the decays of the step |
decays: Map<string, number> | decays of each isotope in the step |
emitted: Record<RadiationKind, number> | particles of each kind that left |
packages/physics-nuclear/src/decay.ts:98
IsotopeDef interface
interface IsotopeDefhalfLife: number | seconds; Infinity for a stable nucleus |
daughter?: string | what it becomes (a name in the library); missing = leaves the books |
energy: number | total energy per decay, J |
retained?: number | share of it that stays in the matter and becomes heat (1 when the radiation is absorbed where it is born) |
emits?: Partial<Record<RadiationKind, number>> | particles of each kind that leave the source per decay |
atomicMass?: number | kg per atom (for the mass of a quantity) |
packages/physics-nuclear/src/decay.ts:10
Layer interface
interface Layermaterial: string | |
thickness: number |
packages/physics-nuclear/src/radiation.ts:33
NuclearCapability interface
interface NuclearCapability extends Capabilityreadonly isotopes: IsotopeLibrary | |
readonly shields: ShieldLibrary | |
readonly sources: Map<string, SourceEntry> | |
readonly receivers: Map<string, ReceiverEntry> | |
readonly reactors: Map<string, ReactorEntry> | |
readonly assemblies: Map<string, AssemblyEntry> | |
coefficients: Record<RadiationKind, number> | |
addSource(name: string, o?: Placed & { body?: Body; inventory?: Inventory }): Inventory | |
addReceiver(name: string, o: Placed & { sensitivity?: number; seed?: number; body?: Body }): ReceiverEntry | |
addReactor(name: string, spec: ReactorSpec, o?: Placed): Reactor | |
addAssembly(name: string, spec: AssemblySpec, o?: Placed): Assembly | |
doseAt(receiver: string): Record<RadiationKind, number> | Dose rate by kind at a receiver now, Sv/s (through the scene's shielding). |
packages/physics-nuclear/src/index.ts:48
ReactorEntry interface
interface ReactorEntry extends Placedreactor: Reactor |
packages/physics-nuclear/src/index.ts:45
ReactorEvent interface
interface ReactorEventtype: 'scram' | 'prompt' | 'melt' | |
time: number |
packages/physics-nuclear/src/reactor.ts:82
ReactorSpec interface
interface ReactorSpecpower: number | nominal fission power, W |
generation?: number | prompt neutron generation time, s |
groups?: { beta: number[]; lambda: number[] } | delayed groups (defaults to thermal fission) |
rodWorth: number | reactivity worth of the whole rod travel, Δρ, and the rod position (0 out .. 1 in) at which the core is critical at nominal |
rodsCritical: number | |
rods?: number | |
fuelCoefficient?: number | temperature coefficients, Δρ per K (negative = self-stabilising) |
coolantCoefficient?: number | |
voidCoefficient?: number | Δρ for a fully voided core and the coolant temperature span over which it boils out |
boil?: [number, number] | |
fuelHeat: number | J/K of the fuel and of the coolant with its structure |
coolantHeat: number | |
exchange: number | W/K from fuel to coolant, and the W/K the coolant loses to the heat sink (flow·cp) at inlet temperature |
flow: number | |
inlet?: number | |
xenon?: { worth: number; burnout?: number; iodine?: number } | Xenon-135 poisoning. worth is the reactivity the equilibrium xenon takes at nominal power (about 0.025 for a thermal core; the rods are
critical with it, so a core at nominal power has no xenon term). burnout is the burn-out rate at nominal flux over the decay rate of
xenon (about 3 to 4); iodine the share of the xenon yield that comes by iodine-135 (0.95). |
burnup?: { worth: number; energy: number } | Burn-up: the fuel loses reactivity as it burns, worth (Δρ) for each energy joules of fission energy released (a core of 1 GW(th) for
500 days is 4e16 J; ~30 000 MWd/t is about 0.1 of the fissile loss). The rods make up for it, so a core whose rods are at the end of their travel
is a spent core. Both are linear: the model has no fission-product poisoning but xenon. |
melt?: number | the fuel melts here, K |
scramSpeed?: number | rod speed in a scram, 1/s of the full travel |
trip?: { power?: number; fuel?: number } | trips: scram automatically above this power (× nominal) or this fuel temperature |
packages/physics-nuclear/src/reactor.ts:38
ReceiverEntry interface
interface ReceiverEntry extends Placeddose: number | Sv so far and Sv/s now |
rate: number | |
sensitivity?: number | counts per Sv for a counter (a Geiger tube is about 6·10⁹) |
counts: number | |
body?: Body | |
next: number | |
stream: () => number |
packages/physics-nuclear/src/index.ts:34
ShieldMaterial interface
interface ShieldMaterialRadiation transport, lumped: a point source gives a fluence that falls as 1/(4πr²); each material along the ray takes a part of it away by its half-value layer; a dose coefficient turns the fluence into a dose. Alphas stop by range, not by a half-value layer.
halfValue?: Partial<Record<RadiationKind, number>> | half-value layer by kind, m: the thickness that halves the beam |
alphaRange?: number | how far an alpha gets in it, m |
buildup?: number | build-up of scattered radiation behind the shield: B = 1 + buildup·μx (0 = none) |
packages/physics-nuclear/src/radiation.ts:9
SourceDef interface
interface SourceDefpackages/physics-nuclear/src/radiation.ts:113
SourceEntry interface
interface SourceEntry extends Placedpackages/physics-nuclear/src/index.ts:33
Types
RadiationKind type
type RadiationKind = 'alpha' | 'beta' | 'gamma' | 'neutron'packages/physics-nuclear/src/decay.ts:8
Constants
BARN const
const BARN: 1e-281 barn in m².
packages/physics-nuclear/src/activation.ts:4
DECAY_FRACTION const
const DECAY_FRACTION: numberthe steady share of the fission energy that comes out later as decay heat
packages/physics-nuclear/src/reactor.ts:36
DELAYED_GROUPS const
const DELAYED_GROUPS: { beta: number[]; lambda: number[]; }Standard thermal-fission delayed groups: fractions and decay constants (1/s).
packages/physics-nuclear/src/reactor.ts:10
E_FISSION const
const E_FISSION: 3.2e-11A lumped power reactor: point kinetics with six delayed-neutron groups, reactivity from the rods and from the temperatures of the fuel and the coolant, a two-lump thermal model, and the decay heat of the fission products. Everything is data; there is no geometry.
packages/physics-nuclear/src/reactor.ts:7
EXAMPLE_DOSE_COEFFICIENTS const
const EXAMPLE_DOSE_COEFFICIENTS: Record<RadiationKind, number>Sv·m² per particle that crosses a square metre (fluence-to-dose, order of magnitude for ~1 MeV).
packages/physics-nuclear/src/radiation.ts:31
EXAMPLE_ISOTOPES const
const EXAMPLE_ISOTOPES: Record<string, IsotopeDef>A few real isotopes with their well-known half-lives, as sample data; a game writes its own.
packages/physics-nuclear/src/decay.ts:29
EXAMPLE_SHIELDS const
const EXAMPLE_SHIELDS: Record<string, ShieldMaterial>Textbook values for roughly 1 MeV photons and fast neutrons (as sample data).
packages/physics-nuclear/src/radiation.ts:19
FISSION_ENERGY_PER_KG const
const FISSION_ENERGY_PER_KG: numberA runaway assembly in the one-group, lumped sense: the multiplication k follows from the mass against a critical mass the game supplies (with a reflector factor and a compression), the fission rate grows on the generation time as dF/dt = (k − 1)/Λ · F + S, and the assembly comes apart as it heats, which ends the reaction. This is a model for a game's accident or device record, with the numbers in the data; it has no geometry and is too coarse to be a design tool.
packages/physics-nuclear/src/assembly.ts:9
MEV const
const MEV: 1.602176634e-13Radioactive decay: isotopes with half-lives and daughters, an inventory that decays exactly (the matrix exponential of the decay network, so a chain of any length closes), the heat the decays leave in the matter, and a seeded Poisson stream for counters.
packages/physics-nuclear/src/decay.ts:5
NUCLEAR_DEFAULTS const
const NUCLEAR_DEFAULTS: { doseStep: number; }nuclear processes. Inventories of isotopes decay with the world (the heat goes to H when the carrier has a temperature), dose accumulates in receivers through the shielding the scene puts in the way, reactors run on point kinetics with feedback and decay heat, and a runaway assembly ends in an energy that is handed to X as a blast.
values (each at world / level / zone / entity scope):
doseStep dose between two `radiation:dose` events, Sv (1e-3)
events: decay { source, decays }, radiation:dose { receiver, dose }, radiation:counts { receiver, n },
`reactor:scram` / `reactor:prompt` / `reactor:melt` { name }, `assembly:critical` { name }, `assembly:disassembled` { name, energy, tnt }.packages/physics-nuclear/src/index.ts:30
Sv_PER_MSV const
const Sv_PER_MSV: 0.001packages/physics-nuclear/src/radiation.ts:138
YEAR const
const YEAR: numberpackages/physics-nuclear/src/decay.ts:6