Skip to content

madmatrix GPU: running flavour couplings, no good helicity, stream order, unset selections - #255

Open
oliviermattelaer wants to merge 1 commit into
mainfrom
claude/madmatrix-gpu-hardening
Open

oliviermattelaer wants to merge 1 commit into
mainfrom
claude/madmatrix-gpu-hardening

Conversation

@oliviermattelaer

@oliviermattelaer oliviermattelaer commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #244 (same GPU template files and GPU CI job list); retarget to main once #244 is merged.

Four bugs of the GPU backend of madmatrix (the CPU and SIMD backends were right), found by the review that followed the HIP cut crash (#254). Same class as that one: silent or lucky on one platform, a fault on another.

Fixes (backend/gpu, plus the generator)

  1. Running flavour couplings (nDPF > 0) read and written out of bounds. The per-thread dpf_value (the alpha_s-dependent flavour couplings of this event, gathered per event) was accessed with CD_ACCESS, which on the device adds the offset of the event in the all-events coupling buffer. Every thread past the first event page went outside dpf_value, in the gather and in the vertex routines.
    • Affects MSSM SUSY-QCD (squark–quark–gluino GC_106/GC_110). Every subprocess of p p > go go has nDPF = 16, g g > go go included, because the count accumulates over subprocesses.
    • SM p p > t t~ has nDPF = 0, so the GPU CI never saw it.
    • The calls on flvCOUPs_dep are now instantiated with a new CDPF_ACCESS: CD_ACCESS on CPU/SIMD (unchanged), the trivial one-event access on the GPU.
    • The generator refuses a vertex that mixes such a coupling with another running one (one access type per routine). None does in MSSM p p > go go.
  2. No good helicity aborted. For a subprocess whose |M|² vanishes identically (e.g. FCNC with zero Wilson coefficients), the helicity loop was launched with gridDim.y = 0, an invalid configuration, and checkGpu aborted. The loop is now skipped and |M|² = 0, as on the CPU.
  3. Selected helicity and colour left unset for a vanishing or NaN |M|², so umami returned stale pool memory. They are now 0 (none, -1 out of umami) unless one is chosen, as the zero-initialised CPU buffers give.
  4. Stream order. In async (umami) mode the memsets and the helicity, output and colour kernels went to the default stream, while everything else ran on the stream umami is given.
    • This was only correct because madspace never passes its stream (a madspace bug, fixed in a separate PR) and its streams are blocking.
    • With a non-blocking stream (a torch side stream) it races.
    • All of sigmaKin now runs on the given stream, and umami waits for its input copies before the helicity filtering of the first call (default stream).
    • Memset sizes are now computed in size_t.

GPU CI: new job madmatrix

madmatrix_gpu.sh / madmatrix_checks.py compare the GPU backend with the scalar CPU backend through umami. Each check runs in its own process, so an abort fails only that check:

  • mssm_gpu_vs_cpu: p p > go go (both subprocesses), event by event, with a random alpha_s and flavour per event, plus an alpha_s² scaling check;
  • zero_me: b b~ > ta+ ta- / z a with ymtau = 0 (no good helicity): |M|² = 0, helicity -1, colour none or the only flow;
  • nonblocking_stream: g g > t t~ g on a non-blocking stream must match the default stream over 4 calls of 16384 events.

The umami ctypes code moves to umami_harness.py, shared with interference_checks.py. Its CPU buffers now keep the host arrays alive; temporaries were freed before the call, which this PR's checks would have hit.

Validation

  • CPU: test_madmatrix_mssm_gogo (madmatrix vs Fortran standalone, MSSM p p > go go) passes. Unit tests .*madmatrix.*, .*cudacpp.*, .*flav.*: 59 OK.
  • The check script runs locally on CPU backends. mssm_gpu_vs_cpu with scalar against scalar exercises the plumbing, the nDPF parsing and the alpha_s² scaling. zero_me on simd_128 passes: the CPU gives |M|² = 0 and helicity -1.
  • GPU, all jobs green on both clusters (pp_ttx, pp_jj, interference, madmatrix):

…der, unset selections

Four GPU-only bugs of the template (the CPU and SIMD backends were right), found
by the review that followed the HIP cut crash (#254):

- Running (alpha_s-dependent) flavour couplings, nDPF > 0 (MSSM SUSY-QCD:
  squark-quark-gluino GC_106/GC_110, e.g. every subprocess of p p > go go): the
  gather into the per-thread dpf_value and the vertex routines reading it used
  CD_ACCESS, which on the device adds the offset of the event in the all-events
  coupling buffer: every thread past the first event page read and wrote outside
  dpf_value. The vertex calls on flvCOUPs_dep are now instantiated with
  CDPF_ACCESS: CD_ACCESS on the CPU/SIMD backends (unchanged), the trivial
  one-event access on the GPU, where dpf_value holds this event's values. The
  generator refuses a vertex mixing such a coupling with another running one
  (one access type per routine).
- No good helicity (a subprocess whose |M|^2 vanishes identically, e.g. FCNC
  with zero Wilson coefficients): the helicity loop was launched with
  gridDim.y = 0, an invalid configuration, and checkGpu aborted. Skipped now,
  |M|^2 = 0 as on the CPU.
- The selected helicity and colour were left unset for a vanishing or NaN |M|^2
  (umami then returned stale pool memory); now 0 (none, -1 out of umami) unless
  one is chosen, as the zero-initialised CPU buffers give.
- Stream order: in async (umami) mode the memsets and the helicity, output and
  colour kernels went to the default stream while everything else ran on the
  stream umami is given. Correct only because madspace never passes its stream
  (a separate madspace bug) and its streams are blocking; with a non-blocking
  stream (a torch side stream) it races. All of sigmaKin now runs on the given
  stream in async mode, and umami waits for its input copies before the
  helicity filtering (default stream) of the first call. The memset sizes are
  computed in size_t.

GPU CI: new job madmatrix (madmatrix_gpu.sh, madmatrix_checks.py) comparing the
GPU backend with the scalar CPU backend through umami, each check in its own
process so that an abort fails only that check:
  - mssm_gpu_vs_cpu: p p > go go event by event with random alpha_s and flavour;
  - zero_me: b b~ > ta+ ta- / z a with ymtau = 0 (no good helicity);
  - nonblocking_stream: g g > t t~ g on a non-blocking stream vs the default one.
The umami ctypes harness moves to umami_harness.py, shared with
interference_checks.py; its CPU buffers now keep the host arrays alive (they
were freed before the call when passed as temporaries).
Base automatically changed from claude/interference-computation-madmatrix-madspace-6423f4 to main October 10, 2026 20:05

This branch was previously deployed

1 inactive deployment
ceci-gpu — a70e9324 Deployed Oct 10, 2026 by oliviermattelaer via lemaitre4 / start_runner #92
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