The 3D scene animates each molecule by relaxing it toward an authored bias band (a hand-picked target radius clamped between 0.15 and 0.85) — a visual heuristic, not a solved equation. This 2D simulator instead integrates the actual governing physics: in the rotor's rotating frame, each UF6 molecule is a Brownian particle drifting outward under the centrifugal pseudo-force and diffusing thermally. Written in the radial coordinate r (with the polar-coordinate Jacobian term that a correct 2D reduction requires), that overdamped Langevin equation is:
dr = [a·r + D/r] dt + √(2D) dW, a/D = Mᵢω²/(2RT)
stationary solution (zero probability current): p(r) ∝ r·exp(Mᵢω²r²/(2RT))
— exactly the barometric law the 3D scene's formula assumes, but here it is
the emergent steady state of simulated stochastic dynamics, not looked up.
This 2D solver uses the exact closed-form update for the linear part of that SDE every substep (no Euler time-discretization error), reflects molecules at the rotor wall and axis, and every couple of seconds re-bins the live ensemble by radius and performs a least-squares regression of ln(density) against r² for each isotope separately — the slope of that regression is Mᵢω²/(2RT) by construction. The live "measured" separation factor α₀ is exp(slopeheavy − slopelight), read straight off the simulated molecules, not computed from the formula.
Because the two isotopologues differ in mass by under 1%, this difference-of-slopes is a small signal riding on a much larger shared drift — light and heavy molecules share the identical random draw at every timestep (a variance-reduction trick, common random numbers) so the tiny mass-dependent separation isn't swamped by independent sampling noise between species. A standalone Node verification of this exact algorithm (paired-path Langevin integration, log-density regression, repeated across several thousand-molecule / tens-of-thousands-of-timestep runs) confirms the core physical claim solidly: each species' own regression slope independently lands within a few percent of the analytic Mᵢω²/(2RT). The differential α₀, however, is a percent-level effect riding on that shared slope, so a single finite run can be off by anywhere from a few percent to order-100% — this is genuine statistical noise from measuring a small effect with a finite ensemble, not a modeling error, and it shrinks as more samples accumulate. That's why the live "measured" readout is a long rolling average (~30 seconds): watch it keep drifting toward the closed-form value the longer the simulation runs, the same way a real bench measurement needs a longer integration time to resolve a small isotope-separation signal above its shot noise.
- Peripheral speed — sets ω via v=ωr (note R cancels: the barometric exponent depends only on v², not on the rotor's radius); higher v drives both molecules harder against the wall and widens the mass-dependent slope gap.
- Gas temperature — higher T randomizes molecular motion (raises D relative to drift) and flattens the radial profile, shrinking α₀.
- Countercurrent flow / Cascade stages — model the same internal axial recirculation and stage-compounding used by the 3D scene's cascade formula (identical closed-form odds-ratio recursion, computed independently here), turning the tiny single-pass α₀ into a usable product assay.
- Reseed Molecules — restarts the ensemble from a fresh uniform-in-area distribution so you can watch the Boltzmann profile build up from scratch.