Conversation
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>
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 ☂️ |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 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".
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>
|
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 against the 4% gate. All three pass. |
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>
Release candidate for v0.2.0 — the first public release (PyPI + GitHub Releases).
Cut from
developper AGENTS.md 9.4.What is in it beyond
mainfix(data): MSC strength anchored to the Class-II transport moment of theMoliere-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-beamtable (Rogers & Bielajew 1986, Table III).
Everything else in the release is the accumulated
develophistory recorded inCHANGELOG.md.Gates (AGENTS.md 7 and 9.4)
pytest -m ""including validation; workflow dispatchedmanually since the schedule has not run for this tree)
chore(release): v0.2.0bump commit —pyradmc/__init__.py::__version__,CITATION.cff,CHANGELOG.md— pushed after review, before mergeMerge with a merge commit (never squash):
mainkeeps the release shape, and thev0.2.0tag lands on that merge commit.🤖 Generated with Claude Code