Skip to content

Design and validation

Design and validation

Faithful first, corrected by choice. The default reproduces the shipped C bug-for-bug, because that is what every published RUMP result was produced with. Known defects — and there are several — are reproduced exactly, with the mathematically correct behaviour available behind explicit flags. The shell exposes this as a session setting, session.settings.faithful, toggled with the FAITHFUL command and persisted through ~/.pyrumprc (see Config) rather than a separate branch or fork — corrected and faithful behaviour live in the same codebase so they stay comparable against the C oracle side by side. FAITHFUL governs physics only — for pyRUMP's own command-surface additions beyond stock RUMP, see the Changelog's versioning note. See RUMP quirks and defects found while porting.

Validated against the original, at two levels. The legacy C is compiled into a shared library and called directly from the test suite, so each stage is compared function-by-function rather than by eyeballing a final spectrum.

Unit oracle — the physics translation units (ziegler.c, stopping.c, sigma.c, …) are compiled into libpyrump_oracle and called via cffi. No TTY, no graphics, no buffers. When a number disagrees, this isolates the cause to one function.

python tests/oracle/build_oracle.py
pytest -m oracle

End-to-end oracle — the original rump binary is driven through a pseudo-terminal to produce reference spectra.

Both require the legacy C tree, which is not redistributed (see Licensing and provenance). Point PYRUMP_C_REFERENCE at it, or place it at C-code/. Tests skip cleanly when it is absent.

pytest              # unit tests
pytest -m oracle    # comparison against the C

Current agreement

Quantity Agreement Limited by
ZBL85 stopping, all 92 targets, H/He/Cu/Au beams, 10 keV–10 MeV 6.1e-7 rel float32 tables in the C
Fitted stopping polynomial (what the simulation consumes) 1.3e-5 rel float32 coefficient storage
Polynomial evaluation, given identical coefficients 1.1e-14 rel float64 round-off
Cross-sections and kinematics 1e-10 rel closed forms, nothing to fit
Bricks — 630 across 36 configurations 5e-7 energies, 6e-6 heights float32 coefficients
Full spectrum, total counts 3e-6 rel float32 coefficients
Full spectrum, per channel 1e-5 of peak float32 brick edges
With straggling and detector resolution 3e-6 total, 1e-5 of peak float32 brick edges
Depth profiles, all 11 evaluable forms 2.6e-5 brick heights float32 coefficients
Absorber, fuzz, multiple scattering 3e-6 total, 4e-5 of peak float32 brick edges
.RBS files read vs RUMP's own reader bit-identical
Poisson objective vs EvalChiPoisson 1e-5 reduced chi2 float32 in the C
.lcm round-trip vs RUMP's own writer byte-identical

The oracle is the float build. RUMP cannot be built in double precision — its table readers use scanf("%f") against REAL fields, so -DREAL_IS_DOUBLE silently corrupts every table. That caps how tightly any float64 port can agree, and the tolerances above are set by that floor rather than by choice.

Accuracy

Stage-by-stage agreement with the original C is in Design and validation § Current agreement — every figure there is limited by float32 storage in the C, not by pyRUMP. For a realistic multi-layer sample with micron-thick polymer layers, agreement loosens to ~3e-3: thousands of sublayers accumulate single-precision differences, and part of the beam falls below the stopping cutoff.

Full bibliography in References.

Atomic data provenance

The stage-by-stage agreement above is internal — pyRUMP against the shipped C, both consuming the same bundled tables. It says nothing about whether those tables' underlying physical constants are still correct. That's checked separately, against external reference sources, and re-verified periodically rather than assumed from the tables' 1990s origin.

Atomic masses and isotope abundances (atom4.dat) — checked against CIAAW (Commission on Isotopic Abundances and Atomic Weights) current standard atomic weights, Z=1-92. Every sampled mass matches within <0.1% relative. Two elements have isotope-abundance intervals CIAAW has revised since the table's origin — magnesium (post-2011 remeasurement) and zirconium (revised 2024) — but the effect on each element's average mass is negligible (<0.03% and <0.1% respectively) and was left as-is rather than patched, to avoid disturbing the isotope table's internal normalization.

Elemental densities (atomic_density) — checked against NIST's X-Ray Mass Attenuation Coefficients reference densities (Hubbell & Seltzer, NISTIR 5632). Median relative difference 0.3% across 75 comparable elements. Three of the four elements differing by more than 5% are allotrope-convention mismatches rather than errors (carbon: graphite vs. a lower bulk value; phosphorus: white vs. red; selenium: grey vs. an amorphous form) — both values are individually defensible, they just describe different physical forms of the element. The fourth, calcium, had no such explanation and was corrected to NIST's reference value.

Full detail, including per-element figures, in SOURCES.md alongside the tables themselves.