Skip to content

chore(release): v0.2.0 - #1

Merged
wahln merged 6 commits into
mainfrom
rc/0.2.0
Sep 5, 2026
Merged

chore(release): v0.2.0#1
wahln merged 6 commits into
mainfrom
rc/0.2.0

Conversation

@wahln

@wahln wahln commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Release candidate for v0.2.0 — the first public release (PyPI + GitHub Releases).
Cut from develop per AGENTS.md 9.4.

What is in it beyond main

  • fix(data): MSC strength anchored to the Class-II transport moment of the
    Moliere-screened Rutherford law, replacing the Rossi-Greisen/Highland core width.
    This moves dose in the build-up and laterally; the measurements are in
    CHANGELOG.md.
  • test(validation): the electron R50 gate re-derived against the EGS4 broad-beam
    table (Rogers & Bielajew 1986, Table III).

Everything else in the release is the accumulated develop history recorded in
CHANGELOG.md.

Gates (AGENTS.md 7 and 9.4)

  • CI green on this branch
  • Validation tier green (pytest -m "" including validation; workflow dispatched
    manually since the schedule has not run for this tree)
  • Review
  • chore(release): v0.2.0 bump commit — pyradmc/__init__.py::__version__,
    CITATION.cff, CHANGELOG.md — pushed after review, before merge

Merge with a merge commit (never squash): main keeps the release shape, and the
v0.2.0 tag lands on that merge commit.

🤖 Generated with Claude Code

wahln and others added 2 commits September 4, 2026 15:45
The multiple-scattering strength (`scattering_power`) was the
Rossi-Greisen/Highland core width (14.1/pv)^2 / X_0, a fit to the
Moliere core that lacks the energy-growing ln(1/eta) - 1 factor of the
first transport moment Goudsmit-Saunderson actually pins
(<cos theta> = exp(-s N sigma_tr)). Multi-MeV electrons were therefore
under-scattered by 1.25x at 1 MeV rising to 1.77x at 15 MeV in water,
while the GS *shape* was already built from the same Moliere screening.

The strength is now 2 (N_A/A) [Z^2 sigma_tr + Z (sigma_tr -
sigma_tr,Moller^hard(E, ECUT))]: nuclear elastic plus the atomic-
electron moment below ECUT, with the moment of explicit hard Moller
events removed so the Class-II loop does not count it twice (0.4-4.2 %
of the Z(Z+1) strength over 0.5-15 MeV). `delta_cut` joins the
interface like the other restricted quantities; the tabulated source
adds the same soft-electron term to EEDL's nuclear-only elastic moment
and bumps the table format to v2 so nuclear-only tables cannot load
silently.

Measured on monoenergetic pencil kernels in water against EGSnrc and
TOPAS (1 mm voxels, 1 mm axial shell): integrated build-up at half
dmax 0.95-0.97 -> 0.99-1.01 of EGSnrc (1/6/15 MeV), central-ray excess
+4/+14/+19 % -> +3/+2/+7 %, dmax onto EGSnrc at 6 MeV; nothing moves
beyond dmax (CPE). Electron-beam R50/R_CSDA falls (10 MeV 0.90 ->
0.84) and the 2 MeV R50 validation gate now trips; that gate's
geometry and window are to be re-derived against reference electron
depth doses, not widened.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replace the empirical R50/R_CSDA detour window [0.72, 0.92] at 2/5/10 MeV,
which bracketed the code's own behaviour under the Highland anchor and
tripped once the scattering strength was corrected, with a reference:
R50 of broad parallel monoenergetic beams in water at infinite SSD from
Rogers & Bielajew, Med. Phys. 13, 687 (1986), Table III (EGS4, 1983
Berger-Seltzer stopping powers), at 3/5/10 MeV, +-4 %.

The gate geometry now has lateral equilibrium (24 cm phantom, 16 cm
beam, central 8 cm scored); a beam filling the phantom face loses
out-scatter across its edge and reads R50 low. Tolerance from measured
reference-engine seed scatter (1.1-2.2 % at 4000 histories, ~1 % at the
16000 used). With the Class-II transport moment R50 sits +0.5 to +2.3 %
above the table; Highland read +8-9 % long at 5-10 MeV. E0 = 2.33 R50
is the AAPM/ETRAN approximation and must not be used as the reference.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

@read-the-docs-community

read-the-docs-community Bot commented Sep 4, 2026

Copy link
Copy Markdown

Documentation build overview

📚 pyRadMC | 🛠️ Build #34405962 | 📁 Comparing 352fc52 against latest (3af33f2)

  🔍 Preview build  

3 files changed
± api/index.html
± decisions/index.html
± getting-started/index.html

@wahln

wahln commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T23:41:24.414447Z d9001ef Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9001efa07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/validation/test_ranges_and_pdd.py
wahln and others added 2 commits September 5, 2026 03:43
The gate compared a single-run R50 against Rogers-Bielajew Table III with a
fixed 4 % threshold and no uncertainty estimate, leaving AGENTS.md 2.4
unsatisfied: a stream-changing edit could pass or fail the gate on Monte
Carlo fluctuation alone, and the seed-scatter figure justifying the
tolerance lived in a docstring rather than in the run.

Per-voxel dose_sigma cannot serve here. R50 is a nonlinear functional of
the whole curve -- a half-maximum crossing whose maximum is estimated from
the same noisy data -- and one run's voxel sigmas are correlated through
the shared histories, so no quadrature over them bounds the crossing depth.

Split the existing 16000-history budget across 8 independently seeded
replicates instead: the pooled curve keeps the full statistics for the
point estimate (and stays free of the upward bias dose_z.max() acquires at
low statistics), while the scatter of the per-replicate R50 values gives
its standard error. Transport cost is unchanged.

The 4 % physics tolerance is untouched. A noise budget now runs ahead of
it, failing the test if 2 sigma ever reaches the tolerance, so the gate
cannot silently become noise-limited. Measured headroom on the reference
engine: 2 sigma / R50 = 1.76 / 1.20 / 1.13 % at 3 / 5 / 10 MeV against the
4 % gate, with the engine 1.7 / 1.1 / 1.6 sigma from EGS4.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test matrix ran pytest --cov on all five jobs while Codecov consumes a
single report, and coverage.py's C tracer is not cheap on this suite: two
interleaved rounds of the full fast tiers measured 637 s with --cov against
304 s without, a 2.09x overhead paid five times over.

Restrict --cov to the ubuntu/3.13 job and put coverage.py on CPython's
sys.monitoring backend there (COVERAGE_CORE=sysmon, 3.12+). Measured on the
same suite: 630 s under the C tracer, 308 s under sysmon, 304 s with no
coverage at all -- 2.09x overhead down to 1.01x. So the job that still
measures coverage costs what an uninstrumented job costs, and the other
four shed the instrumentation entirely.

COVERAGE_CORE is set at job level and is inert where no --cov is passed;
the coverage job is 3.13, so the pre-3.12 jobs never request a core they
lack. Coverage is now measured on Linux only: a Windows-only branch that
the 3.13 Windows job still executes no longer reaches the report.

This does not touch the dominant cost. Transport tests are dominated by
lazy Goudsmit-Saunderson node construction, ~80 s once per process on the
reference backend (measured: an identical run_dij call takes 94.49 s cold
and 0.39 s warm), which build_gs_grid already persists to disk for the Warp
backend but which pyradmc/data/interface.py rebuilds every process.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@wahln

wahln commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 1b5621f.

You are right that the helper discarded the uncertainty, and AGENTS.md 2.4 requires one. Per-voxel dose_sigma could not supply it: R50 is a nonlinear functional of the whole curve (a half-maximum crossing whose maximum is itself estimated from the same noisy data), and one run's voxel sigmas are correlated through the shared histories, so no quadrature over them bounds the crossing depth.

Preserved batch information instead, as you suggested, via independent runs: the existing 16000-history budget is now split across 8 independently seeded replicates. The pooled curve keeps the full statistics for the point estimate; the scatter of the per-replicate R50 values gives its standard error. Transport cost is unchanged.

The 4% physics tolerance is untouched. A noise budget now runs ahead of it and fails the test if 2 sigma ever reaches the tolerance, so the gate cannot silently become noise-limited -- which was the failure mode you identified. Measured headroom on the reference engine:

E (MeV) R50 (cm) sigma vs EGS4 2 sigma / R50
3 1.1136 0.0096 +1.51% (1.7 s) 1.76%
5 1.9645 0.0117 +0.64% (1.1 s) 1.20%
10 4.1761 0.0234 +0.92% (1.6 s) 1.13%

against the 4% gate. All three pass.

wahln and others added 2 commits September 5, 2026 10:49
Corrects the scope of d0c5dd0, which removed --cov from four of the five
test jobs. Two reasons were given and only one survives.

The 2.09x overhead measured there is the C tracer's. Under sysmon, which
that same commit introduced, coverage costs 1.01x -- so on every job
running 3.12 or newer there was no runtime case for dropping it, and the
restriction cost real signal: the Windows job still executes Windows-only
branches that no longer reached the report. The second reason, that Codecov
consumes a single report, was simply wrong; Codecov merges the uploads for
a commit, which is why five of them existed.

Restore coverage on ubuntu/3.12, ubuntu/3.13 and windows/3.13, all of which
get it for ~1%. It stays off on 3.10 and 3.11, where sys.monitoring does
not exist and the C tracer would double those jobs -- the part of the
original change the measurement does support.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
First version published to PyPI and tagged on GitHub. __version__ moves
from the 0.0.1.dev0 placeholder and CITATION.cff from 0.1.0, which had
drifted apart; the release workflow refuses a tag disagreeing with either.

CHANGELOG: the Unreleased section becomes 0.2.0, dated today. The 0.1.0
section is kept and relabelled "never released" -- it was prepared as the
first release and never tagged, so no v0.1.0 exists to install or compare
against, and its tag and compare links are dropped rather than left
pointing at a ref that will never resolve. Its contents ship in 0.2.0.

Also records what the Class-II transport moment costs in runtime, which
the accuracy entry did not state: electron transport on the reference
backend measured ~12 % slower than the Highland width it replaced.

Gates: fast tiers 1292 passed; validation tier green on this branch;
mkdocs --strict builds; tag, __version__ and CITATION.cff agree at 0.2.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@wahln
wahln merged commit 6de40a3 into main Sep 5, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant