Skip to content

Generate indirect-many vec wrappers for formmp (P2M) - #94

Merged
inducer merged 1 commit into
inducer:mainfrom
xywei:formmp-vec
Jul 29, 2026
Merged

Generate indirect-many vec wrappers for formmp (P2M)#94
inducer merged 1 commit into
inducer:mainfrom
xywei:formmp-vec

Conversation

@xywei

@xywei xywei commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What

fmmlib's formmp routines (P2M) share their argument patterns exactly with formta (P2L) — (ier, [zk,] rscale, sources, charge|dipstr[,dipvec], ns, center, nterms, expn) in all eight variants — but only formta had generated _imany wrappers. Downstream drivers (e.g. boxtree's pyfmmlib_integration.FMMLibExpansionWrangler.form_multipoles) therefore form multipoles in a Python loop over per-box scalar formmp calls, which is serial and call-overhead-bound.

This PR generalizes the formta wrapper block in vec_wrappers.py to also emit {l,h}{2,3}dformmp[_dp]_imany with the same indirect-many addressing, sum output reduction, and OpenMP annotations. No hand-written Fortran; purely the existing generator applied to the twin routine family.

Verification

  • Bit-exact against per-box scalar formmp loops (0.0 max relative error) for 3D Laplace, 3D Helmholtz, and 2D Laplace on ragged per-box source counts (3–40 sources/box, 50 boxes).
  • With OpenMP enabled (see Restore OpenMP in the meson build (lost in the meson-python migration) #93), a 4000-box batch with 27 sources/box at nterms=20 runs 0.26 s → 0.11 s at 4 threads (4C/8T i7-8650U), identical checksums.

Complementary to #93 (which restores the OpenMP flags these annotations need); independent to merge in either order.

A follow-up in boxtree could switch form_multipoles to this wrapper; happy to send that separately if there's interest.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YYp74e5ZTE6ZHDNR3ETgM6

fmmlib's formmp routines (P2M) share their argument patterns exactly
with formta (P2L), but only formta had generated _imany wrappers.
Downstream FMM drivers (e.g. boxtree's pyfmmlib wrangler) therefore
form multipoles in a Python loop over per-box scalar formmp calls,
which is serial and call-overhead-bound.

Generalize the formta wrapper block to also emit
{l,h}{2,3}dformmp[_dp]_imany with the same indirect-many addressing,
sum reduction, and OpenMP annotations.

Verified against per-box scalar formmp calls: bit-exact (0.0 max rel
err) for 3D Laplace, 3D Helmholtz, and 2D Laplace on ragged per-box
source counts; with OpenMP enabled, a 4000-box q=3-layout batch at
nterms=20 runs 0.26s -> 0.11s at 4 threads with identical checksums.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYp74e5ZTE6ZHDNR3ETgM6
@inducer
inducer enabled auto-merge (rebase) July 29, 2026 14:18
@inducer

inducer commented Jul 29, 2026

Copy link
Copy Markdown
Owner

The follow-up in boxtree sounds good, please send it. :)

@inducer
inducer merged commit de183d7 into inducer:main Jul 29, 2026
9 checks passed
inducer pushed a commit to xywei/boxtree that referenced this pull request Aug 5, 2026
pyfmmlib now generates {l,h}{2,3}dformmp[_dp]_imany (inducer/pyfmmlib#94),
the P2M twins of the formta wrappers that form_locals already uses. Switch
form_multipoles to one indirect-many call per level, with each expansion
center drawing on the single source segment of its own box; boxes without
sources are excluded so their expansion entries stay zero, as before.

When pyfmmlib predates these wrappers, form_multipoles transparently falls
back to the previous one-box-at-a-time loop, which is kept verbatim as
_form_multipoles_one_box_at_a_time.

The batched path reproduces the loop bit for bit (tested across 2D/3D,
charges/dipoles, Laplace/Helmholtz). On a 100k-source 3D Laplace tree with
7216 source boxes at order 15, form_multipoles drops from 516 ms to 236 ms
on a 4C/8T laptop with OpenMP, and from 623 ms to 561 ms single-threaded
(the call-overhead saving alone).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYp74e5ZTE6ZHDNR3ETgM6
inducer pushed a commit to inducer/boxtree that referenced this pull request Aug 5, 2026
pyfmmlib now generates {l,h}{2,3}dformmp[_dp]_imany (inducer/pyfmmlib#94),
the P2M twins of the formta wrappers that form_locals already uses. Switch
form_multipoles to one indirect-many call per level, with each expansion
center drawing on the single source segment of its own box; boxes without
sources are excluded so their expansion entries stay zero, as before.

When pyfmmlib predates these wrappers, form_multipoles transparently falls
back to the previous one-box-at-a-time loop, which is kept verbatim as
_form_multipoles_one_box_at_a_time.

The batched path reproduces the loop bit for bit (tested across 2D/3D,
charges/dipoles, Laplace/Helmholtz). On a 100k-source 3D Laplace tree with
7216 source boxes at order 15, form_multipoles drops from 516 ms to 236 ms
on a 4C/8T laptop with OpenMP, and from 623 ms to 561 ms single-threaded
(the call-overhead saving alone).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYp74e5ZTE6ZHDNR3ETgM6
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.

2 participants