Skip to content

mg7 merged-flavor: single-merged-leg flavored couplings + guard (MSSM)#12

Draft
oliviermattelaer wants to merge 15 commits into
mainfrom
claude/mg7-flv-single-leg
Draft

mg7 merged-flavor: single-merged-leg flavored couplings + guard (MSSM)#12
oliviermattelaer wants to merge 15 commits into
mainfrom
claude/mg7-flv-single-leg

Conversation

@oliviermattelaer

Copy link
Copy Markdown
Contributor

Summary

Handles merged-flavor (PDG=81) coupling topologies in the mg7/madmatrix C++
output that previously crashed with a cryptic unpack error (k1, k2 = [i for i in key if i!=0]) — surfaced by MSSM generate p p > go go under the default
mg7 output. Pre-existing on the feat-madmatrix branch; unrelated to the goodhel
work this PR is based on.

This is incremental: single-merged-leg independent couplings are now fully
supported and validated; the remaining gap (event-by-event "dependent"
flavored couplings, e.g. SUSY-QCD gluino-squark-quark) is cleanly guarded
with an actionable error, not a crash. output madevent/standalone support
the full set and are unaffected.

What's here (4 commits)

  1. Guard (_assert_flv_couplings_supported): raises a clear InvalidCmd
    for the not-yet-supported cases instead of crashing / emitting uncompilable
    code. Scoped to the process's used couplings.
  2. Tests + CI: split the MSSM p p > go go check into an mg7 job
    (test_mssm_gogo_mg7_unsupportedacceptancetest_mg7.yml) and a madevent
    job (test_madevent_mssm_gogoacceptancetest_madevent.yml).
  3. Design doc (docs/mg7_merged_flavor_mssm_design.md): full diagnosis +
    how the Fortran side does it (the template we mirror).
  4. Single-merged-leg support (independent couplings):
    • serialization mirrors Fortran flavor_couplings.f (unmerged partner gets
      flavor index 1);
    • consumer fix in get_coupling_def — select the coupling by the merged
      fermion leg (cudacpp arg order can put the unmerged fermion first, unlike
      Fortran).

Validation

  • p p > n1 n1 QCD=0 (t-channel squark, EW/independent): standalone_mg7 now
    reproduces the Fortran standalone per-flavor |M|² for all flavors (before
    the consumer fix only flavor 0 matched). New test
    test_standalone_mg7_mssm_single_leg.
  • Two-leg path unchanged: test_standalone_mg7_vs_cpp still passes.
  • p p > go go still fails cleanly with the guard (dependent couplings).

CPU/SSE4 builds + check_sa.exe validated locally; CUDA path untouched here.

Remaining (separate / next)

Dependent (event-by-event) flavored couplings — the per-event idcoup +
CD_ACCESS FLV view, the analogue of Fortran's VAL%P => GC(J). This is what
unblocks full p p > go go. Tracked in the design doc.

🤖 Generated with Claude Code

oliviermattelaer and others added 5 commits June 23, 2026 13:07
…r error

MSSM "generate p p > go go" with the default mg7 (madmatrix) output crashed in
write_flv_couplings on "k1, k2 = [i for i in key if i!=0]": the merged-flavor C++
backend only models the two-merged-leg "partner" topology (the SM q q~ V case),
but MSSM has single-merged-leg vertices (gluino/chargino-squark-quark, only the
light quark merged), and the relevant flavored couplings are event-by-event
(running-alphas) couplings that cannot be referenced by the fixed value[]
pointers set once in setIndependentCouplings.

Option B (guard, not the full feature): add UFOModelConverterCPP.
_assert_flv_couplings_supported, called from both write_flv_couplings copies
(export_cpp.py and madmatrix/model_handling.py). It raises a clear, actionable
InvalidCmd when a USED flavored coupling connects a number of merged legs other
than two, or is an event-by-event coupling, telling the user to use
"output madevent" / "output standalone" instead. The check is scoped to the
process's used couplings, so valid SM two-leg merged cases (e.g.
"u u~ > j j QCD=0") still generate, and the Fortran paths are unaffected.

- docs/mg7_merged_flavor_mssm_design.md: full diagnosis + the deferred Option A
  plan (proper single-leg + dependent-flavored-coupling support).
- test_mg7_merged_flavor_unsupported_is_clean: asserts standalone_mg7 refuses
  MSSM p p > go go with InvalidCmd and that madevent still supports it.

Pre-existing on the feat-madmatrix branch; unrelated to the goodhel merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The combined guard test asserted both that standalone_mg7 refuses MSSM
p p > go go and that madevent supports it. Split it so each side runs in its
own CI workflow (there was no madevent equivalent before):

  * test_mssm_gogo_mg7_unsupported  -> acceptancetest_mg7.yml
    (mg7/madmatrix must refuse the merged-flavor squark/gluino vertices with a
     clear InvalidCmd).
  * test_madevent_mssm_gogo         -> acceptancetest_madevent.yml
    (the Fortran madevent output supports the same process; reference for the
     eventual mg7 fix).

Both verified passing locally.
Generated the Fortran flavor_couplings.f and validated the single-leg attempt
on p p > n1 n1 QCD=0 (single merged leg, independent EW couplings). Findings:

- Fortran serializes a single merged leg as a two-leg partner with the unmerged
  leg at flavor index 1, and stores VAL as a pointer into the per-event coupling
  array (so dependent/running couplings work uniformly).
- Serializing single-leg that way in mg7 compiles and runs but gives WRONG
  per-flavor |M|^2 (only flavor 0 matches Fortran). Root cause is the consumer
  gating in get_coupling_def (FFSxM): it is hard-wired to F1/F2 and assumes the
  merged fermion is F1, so it mis-indexes partner1 when the unmerged fermion is
  F1. The squark diagram masses are correct and goodhel is not the cause.

The attempt was reverted; the guard still blocks single-leg so no wrong physics
ships. Updated the Option A plan: single-leg needs a real consumer fix (parity /
partner2, mirroring Fortran), then the dependent-coupling mechanism.
…pendent)

Single-merged-leg vertices (one merged fermion + an unmerged partner + a
squark/boson, e.g. the electroweak MSSM squark-quark-neutralino vertices) are
now generated correctly by the mg7/madmatrix C++ backend, for flavor-
independent couplings.

Two parts, mirroring the Fortran side:

- write_flv_couplings (export_cpp.py + madmatrix/model_handling.py): a single
  non-zero flavor key is serialized like Fortran flavor_couplings.f -- the
  unmerged partner is given flavor index 1, i.e. the two-leg formula with k2=1
  (partner1[k-1]=0, partner2[0]=k-1, value[k-1]=&coup).

- get_coupling_def (MadMatrixALOHAWriter): the flavored coupling is selected by
  the *merged* fermion leg. Unlike the Fortran routines (where F1 is the merged
  leg by argument-order convention), the cudacpp argument order can put the
  unmerged fermion first, so the consumer now picks whichever leg is the
  partner-populated (merged) one. The two-leg case (partner1[flv1]==flv2)
  reproduces the previous behaviour unchanged.

The guard (_assert_flv_couplings_supported) is narrowed to allow one- and
two-merged-leg INDEPENDENT couplings; it still raises a clear InvalidCmd for
event-by-event ("dependent", running-alphas) flavored couplings (the remaining
gap, e.g. SUSY-QCD gluino-squark-quark in p p > go go) and for >2 merged legs.

Validated: p p > n1 n1 QCD=0 (t-channel squark, EW/independent) now reproduces
the Fortran standalone per-flavor |M|^2 for ALL flavors (before the consumer fix
only the first flavor matched). Regression test test_standalone_mg7_mssm_single_leg;
the two-leg test_standalone_mg7_vs_cpp still passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…uplings)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Qubitol Qubitol mentioned this pull request Jun 24, 2026
6 tasks
@Qubitol Qubitol added this to the Alpha release milestone Jun 24, 2026
@Qubitol

Qubitol commented Jun 24, 2026

Copy link
Copy Markdown
Member

Claude report on the implementation of Step 3 of the design document docs/mg7_merged_flavor_mssm_design.md

mg7 merged-flavor — Step 3: dependent (running-αs) flavored couplings

Branch claude/mg7-flv-single-leg, commit d20a583036.

What was implemented

Dependent (event-by-event, running-αs) flavored couplings for the mg7/madmatrix
standalone_mg7 backend — the MSSM SUSY-QCD squark-quark-gluino case
(p p > go go, couplings GC_106/GC_110g_s). This completes Step 3 of
docs/mg7_merged_flavor_mssm_design.md.

Mechanism (per-event AoSoA; flavor index constant across a SIMD lane)

A running-αs coupling cannot be addressed by the fixed FLV_COUPLING value[]
pointers set once in setIndependentCouplings. Instead:

  • The FFSxM vertex routines are templated on the coupling access type, so
    dependent flavored calls are instantiated with CD_ACCESS (per-event SIMD)
    and independent ones keep CI_ACCESS (broadcast). The consumer body
    (get_coupling_def) is unchanged except the per-flavor stride 2
    C_ACCESS::flv_stride.
  • Per event page, calculate_jamps gathers the running coupling values into
    an aligned AoSoA buffer dpf_value and wraps it in
    FLV_COUPLING_ARRAY<nDPF,nMF,CD_ACCESS::flv_stride> flvCOUPs_dep.
  • Direct analogue of Fortran's FLV_xx%VAL(k)%P => GC_yyy(J). The independent
    path stays numerically identical. By construction all SIMD lanes share the
    same flavor index but read their own per-event running value.

Files changed

  • MemoryAccessCouplings.h / MemoryAccessCouplingsFixed.h — add
    C_ACCESS::flv_stride (nx2*neppC for CD_ACCESS, nx2 for CI_ACCESS).
  • cpp_hel_amps_h.incFLV_COUPLING_ARRAY gains a 3rd template param
    FSTRIDE (default nx2, so the independent path is byte-for-byte unchanged).
  • model_handling.py
    • consumer get_coupling_def strides by C_ACCESS::flv_stride;
    • format_coupling splits FLV routing into flvCOUPs / flvCOUPs_dep
      (dependent calls keep CD_ACCESS);
    • get_process_function_definitions emits nDPF + constant
      cDPF_partner1/2/idcoup (idcoup symbolic via
      Parameters_dependentCouplings::idcoup_<GC>);
    • the per-event AoSoA gather + flvCOUPs_dep view in calculate_jamps;
    • set_flv_couplings now serializes only independent flavored couplings.
  • export_cpp.py — same set_flv_couplings change; guard now only rejects
    vertices with >2 merged legs.
  • process_function_definitions.incnDPF constant + cdpfdecl block.
  • Tests/CI — test_mssm_gogo_mg7_unsupportedtest_standalone_mg7_mssm_gogo
    (positive per-flavor consistency check), with the two CI workflow refs updated.
  • docs/mg7_merged_flavor_mssm_design.md — Status/Step 3 marked done with the
    as-implemented design.

Validation (CPU/SIMD cppavx2)

p p > go go standalone_mg7 vs Fortran standalone, √s = 3000 GeV:

mg7 Fortran
QQx d d~ / s s~ 1.1166755580 1.1166755121
QQx u u~ / c c~ 1.1177869029 1.1177868883
gg 6.2551194240 6.2551192425

All agree to ~1e-7 (the mg7 mixed-precision-float floor).

Green regression tests: test_standalone_mg7_mssm_gogo,
test_standalone_mg7_mssm_single_leg, test_standalone_mg7_vs_cpp,
test_standalone_cpp_fd_output_consistency.

Caveat

GPU was not validated (no GPU in the dev environment). The gather/routing is
written to be CPU+GPU uniform, but a CUDA build+run cross-check is advisable
before relying on the CUDA path.

Gotcha (for the test)

The two check drivers disagree on the energy-argument semantics below the
gluino-pair threshold (the Fortran check auto-bumps to ~1215 GeV/beam), so the
test uses √s = 3000 GeV where both evaluate the same phase-space point. Without
that, a naive comparison looks ~18% off purely from mismatched momenta.

Qubitol and others added 6 commits June 24, 2026 15:59
C++ template-side foundation for dependent (event-by-event, running-alphas)
flavored couplings. Inert until the codegen emits the new arrays.

- MemoryAccessCouplings.h: flv_stride = nx2*neppC (per-event AoSoA record).
- MemoryAccessCouplingsFixed.h: flv_stride = nx2 (scalar complex, broadcast).
- cpp_hel_amps_h.inc: FLV_COUPLING_ARRAY gains an FSTRIDE template param so the
  per-flavor value offset is i*FSTRIDE*STRIDE.
- process_function_definitions.inc: nDPF + %(cdpfdecl)s placeholders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Step 3 of the MSSM merged-flavor plan: SUSY-QCD squark-quark-gluino vertices
(GC_106/GC_110 ~ g_s) are running-alphas couplings and cannot be addressed by
the fixed value[] pointers of setIndependentCouplings. They are gathered per
event page into an AoSoA dpf_value buffer and consumed by the *same* templated
vertex routines instantiated with CD_ACCESS instead of CI_ACCESS -- the direct
analogue of Fortran's FLV_xx%VAL(k)%P => GC_yyy(J).

- model_handling.py: format_coupling splits flavored couplings into independent
  (flvCOUPs / couporderflv, CI_ACCESS) vs dependent (flvCOUPs_dep /
  couporderflv_dep, CD_ACCESS) via model.is_running_coupling;
  get_process_function_definitions emits cDPF_partner1/2 + cDPF_idcoup
  (symbolic Parameters_dependentCouplings::idcoup_<GC>) and the per-event
  gather into flvCOUPs_dep; get_coupling_def uses C_ACCESS::flv_stride instead
  of the hardcoded 2; set_flv_couplings serializes only independent couplings.
- export_cpp.py: drop the is_dep guard (now only >2 merged legs is rejected);
  write_flv_couplings restricted to independent flavored couplings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert test_mssm_gogo_mg7_unsupported into the positive
test_standalone_mg7_mssm_gogo: standalone_mg7 now reproduces the Fortran
standalone per-flavor |M|^2 for both subprocesses (~1e-7). Update the
test_madevent_mssm_gogo docstring and the CI workflow test-name/comments to
match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mark the Status and Step 3 sections of the merged-flavor design note as
implemented and CPU/SIMD-validated (GPU path still unverified).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Base automatically changed from claude/zen-hofstadter-cd863c to main June 25, 2026 12:51
oliviermattelaer and others added 2 commits June 25, 2026 20:29
test_generation_from_file_1 drives generate_events from the input file
tests/input_files/test_mssm_generation, which used a bare `output` that now
defaults to mg7. mg7 has no event-generation pipeline for this MSSM
p p > go go process, so the run crashed. Pin the input file to
`output madevent` (the MadEvent reference cross-sections / banner / LHE
assertions are MadEvent-specific), matching the branch-wide convention for
generate_events tests.

Add the missing mg7 counterpart as an explicit (intentionally red) tracker:
test_generation_from_file_1_mg7 runs the full mg7 (madspace) pipeline for
p p > go go and pins the cross-section to the madevent reference (4.541638 pb,
run_01 of test_generation_from_file_1). standalone_mg7 already reproduces the
per-flavor |M|^2 (test_standalone_mg7_mssm_gogo), but full mg7 event generation
for merged-flavor processes is not wired up yet (the madspace integrator does
not produce the cross-section, cf. the SM tracker
test_madevent_merged_flavor_uq_mg7). Left undecorated so the gap stays visible.
New CI job acceptancetest_mg7_mssm_gogo_xsec runs it (self-skips without the
madspace + LHAPDF stack).

Also refresh the stale acceptancetest_mg7_mssm_gogo comment: mg7 no longer
refuses MSSM gogo with InvalidCmd; it generates the matrix element and is
checked per-flavor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…7d2e

mg7: fix gogo generation CI crash (move it back to madevent)+ add red mg7 xsec tracker for madspace
@oliviermattelaer

Copy link
Copy Markdown
Contributor Author

@Qubitol I think that we can merge this after your final change.
Maybe we can consider remove the file in the docs directory

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