Skip to content

Speed up calculations - #4

Merged
olehz merged 3 commits into
mainfrom
perf/speed-up-calculations
Sep 8, 2026
Merged

olehz merged 3 commits into
mainfrom
perf/speed-up-calculations

Conversation

@olehz

@olehz olehz commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Speed up WMM calculations (~120x)

Why

wmmsub() re-read WMM.COF from disk, allocated and freed all model memory
on every single point. The Python wrapper looped point-by-point, creating
fresh ctypes objects and doing an os.chdir() round-trip per call (needed
because the C code opened the coefficient file by relative path).

For a 0.1° global grid (6.2M points) that meant 6.2M file reads.

Results

Single-threaded, per point:

main this PR
throughput 40.2 µs/pt 0.33 µs/pt

What changed

C (wmm_point_sub.c)

  • New lifecycle: wmm_init(cof_path) / wmm_free(). Coefficients and scratch
    buffers are loaded once and reused.
  • Batch entry points: wmm_eval_latlon_grid(), wmm_eval_grid(), wmm_eval_many().
  • Legendre functions and (a/r)^(n+2) depend only on latitude and altitude, so
    grid evaluation hoists them out of the longitude loop; only the cos/sin(mλ)
    recurrence and the summation run per point.
  • The Schmidt normalization ratios depend only on n/m, but MAG_PcupLow
    rebuilt them — with a malloc/free — on every point. They are now computed
    once at init.
  • Dropped the secular-variation summation, which the Python API never exposed.
  • wmmsub() is kept for backward compatibility.

Python (base.py)

  • One ctypes call per array instead of one per point; numpy buffers are passed
    through without copying.
  • Absolute path to WMM.COF, so the per-point os.chdir() hack is gone.
  • Replaced assert in the hot path with real exceptions (assert is stripped
    under -O).
  • transect() is now exported from the package.

Build

  • Defaults to Release with -O3 (previously no build type was set at all, so
    the shared library was built unoptimized).
  • Rebuilds automatically when the C sources are newer than the built library.

Breaking change

wmm() now returns a dict of numpy arrays instead of an xarray.Dataset:

mag = wmm2025.wmm(lat, lon, alt_km, yeardec)
mag["decl"]        # ndarray, was mag.decl.values
mag["glat"], mag["glon"], mag["time"]

This comment was marked as outdated.

This comment was marked as outdated.

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@olehz
olehz merged commit 710dc46 into main Sep 8, 2026
3 of 4 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.

3 participants