Skip to content

Faster solver: Brent search, parallel figure tabs, optional Numba (results unchanged) - #1

Merged
bpy13 merged 7 commits into
masterfrom
experiment/numba
Oct 15, 2026
Merged

bpy13 merged 7 commits into
masterfrom
experiment/numba

Conversation

@bpy13

@bpy13 bpy13 commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Speeds up the solver about 30x (default run 2.6 s -> 0.1 s; all 14 paper runs 95 s -> 1.4 s) without changing the physics.

Changes

  1. Faster Runge-Kutta step: same arithmetic, bit-for-bit identical results (1.36x).
  2. Brent's method for the last stage of the central-density search (finding r_s = r_sb), to the same 1e-12 precision. rho_0 agrees with the paper code's bisection to 2e-12; profiles move by at most 2e-4 relative; the match to the published runs is 1.7e-4 (was 2.1e-4). find_central_density(..., method=bisection) keeps the paper code's search.
  3. Figure tabs solve their runs in parallel processes when Numba is not installed (Fig. 7: 20-40 s -> 5.5 s). The app script is now guarded by if __name__ == __main__.
  4. Optional Numba extra (pip install -e .[dev,fast]): a compiled copy of the trial integration in src/outflow/_compiled.py, bit-for-bit identical to the Python code on all 14 paper runs. With it, figure tabs solve their runs in-process (about 1.5 s).

Checks

  • Local: 243 tests (fast and slow) and 27 legacy cross-checks pass; ruff and the docs check are clean.
  • Compiled vs Python: identical on 45 inputs x 2 tolerances, and on all 14 full runs (slow tests); also on Linux in CI.
  • Real app driven in headless Edge: Fig. 7 tab with and without the process pool, no errors.

Decisions and measurements: docs/decisions.md, section Speed.

bpy13 added 7 commits October 15, 2026 22:35
Weighted sums use sum(map(mul, ...)), which keeps the products and their order (and Python 3.12's compensated float summation). A unit test pins the step against the plain loop; all 14 paper runs checked identical.
Finds r_s = r_sb with about a quarter of the trials, to the same 1e-12 precision; rho_0 agrees with the paper code's bisection to 2e-12. method='bisection' keeps the paper code's search.
One worker process per run, falling back to one after another if processes cannot start. The page code is now under if __name__ == '__main__' because workers re-import the script.
src/outflow/_compiled.py repeats the trial integration line by line. Exponents are read at run time so powers call pow() as Python does, and sums repeat Python 3.12's compensated sum(), so all 14 paper runs are bit-for-bit identical (tested). Installed with the 'fast' extra; without Numba the Python code runs.
…. 7 about 1.5 s)

Starting worker processes took longer than the compiled runs; the parallel pool is kept for installs without Numba.
@bpy13
bpy13 merged commit a505fe6 into master Oct 15, 2026
2 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