Skip to content

MadtRex: The really big PR - #333

Merged
oliviermattelaer merged 22 commits into
MadGraphTeam:mainfrom
zeniheisser:madtrex
Oct 30, 2026
Merged

oliviermattelaer merged 22 commits into
MadGraphTeam:mainfrom
zeniheisser:madtrex

Conversation

@zeniheisser

Copy link
Copy Markdown
Contributor

Builds on #314 and #317

Full addition of MadtRex, including a fork of Rex 1.1.0. MadtRex provides automatic reweighting for anything that can be generated and compiled with MadMatrix, as well as PDF reweighting through the MadSpace PDF interpolator.

Aside from all the MadtRex-specific materials and the parts from the PRs mentioned above:
Minor functionality modifications and additions to MadSpace I/O routines
Unified reweighting interface that automatically switches between "madtrex" and "classic" modes depending on the use case
MadtRex options in run cards and gridpacks
New reweighting tests
Minor fixes to existing tests

claude and others added 7 commits October 26, 2026 08:29
…UMAMI_IN_HELICITY_INDEX

External wavefunctions (helas.h and the FD-gauge helas_fd.h): the helicity is a
fptype_amp_sv (one value per SIMD lane / GPU thread) instead of an int, and every
helicity branch or helicity-indexed array lookup is replaced by branchless
arithmetic on the truth values tp (nh == +1) / tm (nh == -1), or |hel| = hel*hel and
hel0 = 1 - |hel| for vectors. The generated calls pass hel_sv[ipar], which
calculate_jamps builds per lane from either one helicity (the good-helicity loop)
or a per-event helicity array.

sigmaKin (cpu, simd, gpu) takes an optional per-event helicity array: with it the
helicity loop becomes a single evaluation in which the events of a SIMD page / GPU
warp carry different helicities in lock-step; the colour sum, colour and channel
choice run on that one helicity (the GPU jamp buffer stride is now passed
explicitly instead of read from dcNGoodHel). Without it everything is as before.

UMAMI: UMAMI_IN_HELICITY_INDEX (0-based index into the full helicity table) is
supported on all backends; the |M|^2 returned is that helicity's contribution to
the helicity-summed |M|^2, and UMAMI_OUT_HELICITY_INDEX echoes it. CPU rejects an
out-of-range index with UMAMI_ERROR; the GPU (asynchronous) returns |M|^2 = 0 and
helicity -1 for that event.

check_sa gets --hel-index, the GPU CI a helicity_index check (sum over helicities,
GPU vs CPU per helicity, mixed helicities per page); the FD-gauge IOTest reference
is updated and a unit test checks the per-lane helicity in the generated calls.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RGVSLcRfpx5dH8ovLoLWJ2
…braries

- umami_set_parameter / umami_get_parameter: runtime access to independent
  model parameters (by name or SLHA location) and to parton masses, for the
  MadMatrix backends (cpu/simd/gpu umami.cc) and the mg7 C++ api; the
  exporters register every scalar parameter/coupling in a name -> pointer
  table. Couplings and parameters are registered into separate maps so that
  FPTYPE=f builds compile (couplings are cxtype, parameters stay double).
- Process and common libraries now carry the model name and FPTYPE
  (libmadmatrix_<model>_<proc>_<backend>_<fptype>.so), so builds for
  different models/precisions out of the same directory never collide;
  me_path in subprocesses.json gains an {fptype} placeholder, resolved by
  mg7 launch.py and gridpack.py from [run] precision.
- madmatrix.mk/madmatrix_src.mk pass FPTYPE through to the common library
  build and clean targets.
- The MadSpin density libraries follow the new names: LIBTAG comes right
  after 'madmatrix'/'madmatrix_common', madmatrix_processes.json records
  the common and process library names (model and '{fptype}' included),
  and madmatrix/density.py builds and loads them with an explicit FPTYPE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The madspace side of umami_set_parameter/umami_get_parameter:

- MatrixElementApi::set_parameter()/get_parameter(), through the optional
  umami_set_parameter/umami_get_parameter symbols (UMAMI_ERROR_NOT_IMPLEMENTED
  when a library lacks them), with supports_set_parameter()/
  supports_get_parameter() to check first; UMAMI_ERROR_UNKNOWN_PARAMETER gets
  its own message.
- MatrixElementApi::device(), the device the library was loaded on, for
  callers that stage umami_matrix_element inputs/outputs themselves.
- Python bindings for these and for file_name(), supported_inputs(),
  required_inputs() and supported_outputs().
- Install umami.h with the public headers, for libraries and callers built
  against an installed madspace.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lassic module

MadtRex reweights MG7 events with the MG7 matrix-element libraries (UMAMI)
and the Rex/teaRex event library. It lives in its own top-level madtrex/
directory and depends on madspace; madspace does not depend on it.

madspace (generic, no MadtRex dependency):
- event-file helpers, npy 2.0/3.0 headers (large headers no longer
  corrupt the file), header/particle-count checks fixed, EventFile load
  mode read-only, a failed backend dlopen() raises instead of segfaulting,
  mixmax_skip_N17.c installed with the headers.

madtrex/ (new):
- TupperWare/WareHouse (MatrixElementApi -> REX::tea weightors), Driver
  (subprocesses.json, device/fptype priorities, normaliser fptype),
  ParamHandler, PdfDriver (PDF and scale reweighting), binary (.npy) event
  I/O, the _madtrex_py bindings, the Python package, CMake + install.py.
- Rex/: vendored copy of github.com/zeniheisser/Rex (94b4ed4, pyrex), with
  the <initrwgt> header-parsing fix and process::helicity_ for events
  without a fixed helicity.
- helicity reweighting (default on): matrix elements at each event's own
  helicity via UMAMI_IN_HELICITY_INDEX, beam-swapped events in library leg
  order, helicity-map checks per subprocess, error for samples without
  helicity information; tools/check_helicity_map.py.
- reads lhe_npy events that carry the systematics' rwgt_ columns.

MadGraph / MG7:
- 'install madtrex' (madgraph_interface), [gridpack] include_madtrex /
  include_madtrex_source: gridpacks ship madtrex and bin/reweight.
- mg7/madtrex_driver.py: standalone driver (madspace + madtrex only; the
  gridpack's bin/reweight), mg7/madtrex.py: MadGraph side ('change model'
  regeneration), run_reweighting() routing parameter/PDF/generic cards.
- Reweighting backend switch: madgraph/various/reweight_backend.py chooses
  the classic module or MadtRex for Cards/reweight_card.dat
  (--reweight-backend > launch switch classic/madtrex/density > card
  'change backend' > auto, which prefers MadtRex when it can run the card;
  every reason given when a choice cannot run, before the generation).
  Reweighting runs once, after the systematics; --reweight=CARD switches it
  on with that card. The launch question offers OFF/ON/classic/madtrex/
  density for MG7 outputs (madevent/aMC@NLO unchanged). The decision is
  logged and recorded in Events/<run>/reweighting.json.
- One card vocabulary (classic): 'change' for options (backend, helicity,
  mode LO|pdf, fptype, driver and PDF options), 'set' for parameters,
  including 'set MT 175' by param_card name; former MadtRex 'set'
  spellings deprecated; directives of the other backend are clear errors on
  both sides. MG7 outputs get their own default reweight card.
- Common output: both backends add their weights to the run's own event
  file (events.lhe[.gz], or rwgt_<name> columns of events.npy, carried by
  npy_to_lhe), after the systematics weights; bin/reweight --output still
  writes elsewhere.

Fixes found on the way:
- f2py: the running Python's own f2py is used when none is configured
  (f2py3 on the PATH may build for another Python).
- lhapdf: libLHAPDF is loaded before importing its python module (HEPTools'
  has no rpath; LD_LIBRARY_PATH set in-process is too late).

Tests: test_reweight_backend (new), test_madtrex_standalone (new),
test_mg7_launch, test_misc, acceptance test_reweight_backends (both
backends agree event by event, same output file); test_cmd_reweight's MG7
test asks for the classic module; hj_nlo.lhe.gz regenerated in the current
NLO event format (test_nlo_output2). Docs: madtrex/README.md ("Choosing a
backend"), UpdateNotes.txt.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The 'install madtrex' help block was inserted in the middle of the
'install madspace' option list, so --openblas/--simd/--debug/--cuda-arch/...
appeared as madtrex options. Move the madtrex block after the madspace list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oliviermattelaer

Copy link
Copy Markdown
Contributor

Hi @zeniheisser,

This is very close to being ready to merge. Thanks a lot: the backend selection, with one reweight-card vocabulary for both backends, is really nice.

I asked an AI (Claude) to review the PR, with a focus on integration and user-friendliness. Below are the points it found; I removed the more minor ones. I already pushed one trivial fix to your branch (e560f32: help install listed madspace's build options under madtrex). If you prefer, I can use my AI to fix all of the points below. Just tell me.

On the merge order: this PR also carries the commits of #314 (single-helicity UMAMI entry point) and #317 (UMAMI setters/getters and model/fptype-tagged libraries), which are still open. It is better to merge those two first; this PR then shrinks to the MadtRex part only and is easier to review. Note that blocker 2 below comes from the library rename in #317.

Blockers

1. install madtrex cannot succeed (reproduced by building on macOS)

  • madtrex/Rex/pyproject.toml:11: license = { file = "lgpl-3.0.txt" }, but that file is not in the PR, so pip install ./Rex fails at the metadata step on every platform. Related: there is no LGPL text anywhere under madtrex/, and the README points to Rex/FORKED_FROM.md, which does not exist.
  • madtrex/Rex/include/Rex.h:1669: std::bad_any_cast has no string constructor, so clang refuses to compile it. GCC probably accepts it only because the template is never instantiated.
  • madtrex/Rex/CMakeLists.txt:36,69: INSTALL_RPATH "$ORIGIN" is Linux-only. On macOS import pyrex then fails with Library not loaded: @rpath/libtearex.dylib; it needs @loader_path. madtrex's own CMakeLists already handles this.

2. The library rename (libmadmatrix_<model>_<proc>_<backend>_<fptype>.so) breaks existing tests

  • tests/acceptance_tests/test_cmd.py:1475 and :1701 still glob the old libmadmatrix_P* names, so acceptancetest_uncovered currently fails. The second glob is also used by the GPU acceptance job (test_standalone_umami_first_call_gpu).
  • docs/source/madspace/examples/{matrix-element,integrator,integrator-madnis,flow-training}.rst hardcode libmadmatrix_P0_gg_ttxg_scalar.so. The docs_examples job triggers on madspace/**, which this PR touches, so it will fail as well.

3. No CI job installs madtrex, so none of the MadtRex code is tested

  • test_madtrex_standalone.py and test_reweight_backends.py are not referenced in any workflow, and both skip when madtrex is missing.
  • test_reweight_backend.py is pure Python, but it is not in unittest.yml either.
  • This is how blocker 1 got through. Suggestion: add a job that installs madtrex and runs these tests by name, so a missing madtrex fails instead of skipping.

Other points

4. Inline ! comments are not stripped. The card parsers and reweight_backend.classify_card only strip #, but the default card's own examples use !:

  • set MT scan:[170, 180] ! one weight per value fails with "invalid scan definition".
  • set MT 173 ! named is parsed as block MT, id 173, value ! named.
  • classify_card does not recognise set PDF_SET 331700 ! x as a MadtRex-only line, so the backend chooser can pick the wrong backend.

5. Multi-index blocks are mis-parsed. _SET_RE (param_reweight_card.py:127) reads set NMIX 1 2 0.5 as id 1 with value 2 0.5. The classic module supports multi-index blocks (MSSM, CKM, ...), so these should be parsed, or at least rejected with a clear error.

6. TupperWare / WareHouse object lifetimes in the Python bindings.

  • TupperWare and ParamHandler.add_api keep raw MatrixElementApi* pointers (tupperware.hpp:373,378), and the bindings (src/python/madtrex.cpp:113-158) do not keep the owner alive. Deleting the context or the api before build() means using freed memory, because the library is already unloaded. py::keep_alive<1,2> would fix it.
  • WareHouse.add_process() and process(i) (madtrex.cpp:286-297) return references into a std::vector<TupperWare>. The next add_process() can reallocate that vector, which leaves earlier references dangling.
  • The chaining methods return copies under the default return-value policy, so tw.add_api(a).set_normaliser(b) silently configures a temporary copy.

7. A reweighting failure stops the rest of the run. run_reweighting runs inside run_single (launch.py), after generation and before the post-processing tools. If it raises (for example on SPINUP=9 events), MadSpin, the shower and the analyses are all skipped. It would be friendlier to log the error, continue, and tell the user how to re-run the reweighting on the existing events. Related: there is no reweight run_01 command at the MG7 prompt to reweight an existing run; the only route is the standalone driver.

8. Version coupling between madtrex and madspace.

  • madtrex/install.py:95 only checks that import madspace works. madtrex needs API that this PR adds: MatrixElementApi::device(), supports_set_parameter, EventFile::layout() and the newly installed umami.h. A madspace installed before this PR, or install madspace --bin, passes the check and then fails with compile errors deep inside CMake.
  • Reinstalling madspace after madtrex leaves a silent binary mismatch: the class layouts change and EventFile::read/write are inline. Suggestion: record madspace's version or hash at build time and check it when madtrex is imported.

9. The default PDF for PDF reweighting. madtrex_driver.py:319-347 and 354-387 take the baseline PDF, and the normaliser precision, from the current Cards/run_card.toml, not from the run that produced the events. Example: generate run_01, change pdf1, then PDF-reweight run_01 with a card that sets no PDF_SET. The baseline is the wrong PDF, so every weight is scaled by the wrong ratio. It should come from the run's own banner or header.lhe (the LHAPDF ids in <init>).

10. include_madtrex_source does nothing useful. It copies the sources into the gridpack, but nothing builds them there, and bin/reweight is only written when an installed madtrex is included (include_madtrex). Also, when gridpack.py rebuilds madspace on another machine, the prebuilt madtrex is not rebuilt, which brings back the mismatch in point 8.

Thanks again, this is a great addition!

@zeniheisser

Copy link
Copy Markdown
Contributor Author

@oliviermattelaer As far as I'm concerned, you can do it with Claude since it's all detail semantics; since you already have everything set up, it's probably easier for you to do it from your end than for me doing it by hand or having my own agent do it :)

oliviermattelaer and others added 11 commits October 27, 2026 09:11
- Rex/lgpl-3.0.txt restored: Rex/pyproject.toml's license points at it
  (pip stopped at the metadata step without it), and the vendored LGPL
  code has to ship its licence text. README gives the fork's origin
  commit instead of the removed FORKED_FROM.md.
- Rex.h: event::get<T>() const threw std::bad_any_cast("..."), which has
  no string constructor (clang rejects it); throw std::runtime_error as
  the non-const overload does.
- Rex/CMakeLists.txt: $ORIGIN is ELF-only; use @loader_path on macOS so
  that pyrex finds libtearex/librex after install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rocess refs

- Every TupperWare/ParamHandler/WareHouse method storing a
  MatrixElementApi (or TupperWare) keeps that argument alive
  (keep_alive<1, 2>): they keep raw pointers, so dropping the api/context
  in Python before build() used freed memory.
- The builder methods of TupperWare and WareHouse return *this
  (reference_internal) instead of a copy, so tw.add_api(a).set_normaliser(b)
  configures tw itself.
- WareHouse stores its processes in a std::deque: add_process()/process(i)
  hand out references to them, which a later add_process() no longer
  invalidates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_cmd.py globbed libmadmatrix_P*.so (acceptancetest_uncovered and the
GPU acceptance job failed) and the madspace docs examples hardcoded
libmadmatrix_P0_gg_ttxg_scalar.so; the libraries are now
libmadmatrix_<model>_<Pdir>_<backend>_<fptype>.so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CMake records a digest of the madspace headers _madtrex_py is compiled
  against (madtrex/_build_info.json); madtrex/__init__.py compares it with
  the madspace it would import and raises an ImportError telling to
  rebuild madtrex, instead of a silent binary mismatch after madspace was
  reinstalled. madtrex/_compat.py is pure Python, so the reweighting
  backend chooser reads it without importing anything compiled: auto
  falls back to the classic module, an explicit madtrex request gives the
  reason before the generation.
- madtrex/install.py checks that madspace has the API MadtRex needs
  (umami.h installed, MatrixElementApi.set_parameter, ...) and otherwise
  says to reinstall madspace from source, instead of failing deep in CMake.
- 'install madspace'/'install madtrex' at the MadGraph prompt report a
  failing install.py instead of returning silently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-runs it

- run_single reports a reweighting failure (log line + traceback file in
  the run directory) and goes on with MadSpin, the shower and the
  analyses, as the post-processing tools do; the event file is only ever
  replaced atomically, so the events are kept, without the weights.
- MG7Cmd.do_reweight ('launch PROC -i', then 'reweight run_01
  [--reweight=CARD] [--reweight-backend=...]') reweights the events of an
  earlier run, with the same backend choice and output as after a
  generation; the failure message points to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- bin/reweight (and the subprocesses.json it reads) is written with
  include_madtrex_source too, not only with an installed madtrex.
- In such a gridpack, bin/reweight builds madtrex from the included
  sources when there is no install, and rebuilds it (--clean) when the
  install was compiled against another madspace, e.g. the one the
  gridpack rebuilt on this machine; a precompiled madspace (no headers)
  gives an error naming the gridpack options to use instead.
- The MadGraph VERSION file is shipped with madspace or madtrex sources:
  both pyproject.toml read it (a source build in a gridpack failed at the
  metadata step without it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2 0.5')

- '!' starts a comment (at the start of a line or after whitespace), as
  '#' does, in every MadtRex card reader and in the backend chooser: the
  default card's own examples ('set MT scan:[170, 180]   ! one weight per
  value') failed to parse, and 'set PDF_SET X ! ...' was not seen as a
  PDF line when choosing the backend.
- 'set BLOCK I J ... VALUE' keeps every index: the parser read
  'set NMIX 1 2 0.5' as id 1 with value '2 0.5'. Rex's rwgt_slha stores
  multi-index entries (rwgt_block::multi_params, slha get/set with run-time
  indices, also for the file-based param_rwgt), and ParamHandler sets them
  through their UMAMI location 'NMIX 1 2'. Parameters named in the
  param_card ('set nmix12 0.5') resolve to all their indices too.
- test_gridpack_layout compares resolved paths (macOS /var -> /private/var).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e events

run_pdf_reweighting() took the baseline PDF set of a card without
PDF_SET, and run_parameter_reweighting() the normaliser fptype, from the
process directory's current Cards/run_card.toml. After an edit of the card
(another run with another PDF) an older run was reweighted from the wrong
baseline, scaling every weight by the wrong ratio. Both now come from the
run card the events were generated with -- the <MG7RunCard> block of their
LHE header (header.lhe next to events.npy, or the LHE file itself) -- and
fall back to Cards/ only when the events carry none; the log line says
which one was used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- unittest.yml: the pure-Python ones (test_reweight_backend, the MadtRex
  card readers, npy_to_lhe named weights, bin/reweight's source build in a
  gridpack), next to the other reweighting unit tests.
- acceptancetest_mg7.yml: a new acceptancetest_mg7_madtrex job installing
  madtrex on top of the cached madspace and running test_madtrex_standalone
  and test_reweight_backends; both skip without madtrex, which fails the
  step, so a broken madtrex build no longer passes CI unnoticed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/unittest.yml
#	UpdateNotes.txt
The vendored Rex is part of the MadGraph7 distribution, whose license is
more permissive than the LGPL: shipping lgpl-3.0.txt as the license of this
copy would conflict with it. Rex is dual licensed instead (LGPL-3.0-or-later
as upstream, or the MadGraph7 license as part of MadGraph7):
Rex/pyproject.toml states it as text (it pointed at the removed file, which
broke the build), and Rex/README.md and madtrex/README.md say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oliviermattelaer

Copy link
Copy Markdown
Contributor

Hi @zeniheisser,

As agreed, I (with Claude) pushed fixes for all the points of my review to your branch, and merged main into it (two trivial conflicts, in unittest.yml and UpdateNotes.txt).

What changed

  1. install madtrex builds again. The bad_any_cast in Rex.h that clang rejected is fixed, and Rex/CMakeLists.txt now uses @loader_path on macOS. madtrex now builds, installs and imports on macOS.
  2. Library rename. The test_cmd.py globs and the four madspace docs examples now use the new library names (libmadmatrix_<model>_<Pdir>_<backend>_<fptype>.so).
  3. CI.
    • The pure-Python tests (test_reweight_backend and the MadtRex card readers) are added to unittest.yml.
    • A new job, acceptancetest_mg7_madtrex, installs madtrex on top of the cached madspace and runs test_madtrex_standalone and test_reweight_backends. A skipped test fails the step, so a broken madtrex build can no longer pass CI quietly.
  4. ! comments are stripped like # in all the MadtRex card readers and in the backend chooser.
  5. Multi-index parameters. set NMIX 1 2 0.5 keeps all its indices, also when the parameter is given by its param_card name. This needed a small change in Rex: rwgt_block::multi_params, slha get/set with indices known at run time (also used by the file-based param_rwgt), and ParamHandler setting the UMAMI location "NMIX 1 2".
  6. Bindings.
    • Every method that stores an api keeps it alive (keep_alive<1, 2>).
    • The builder methods return *this (reference_internal) instead of a copy.
    • WareHouse stores its processes in a std::deque, so the references handed out by add_process()/process(i) stay valid.
  7. A failing reweighting no longer stops the run. The error is logged with a traceback file, and MadSpin, the shower and the analyses still run. A new MG7 command, reweight RUN [--reweight=CARD] [--reweight-backend=...] (after launch PROC -i), reweights the events of an earlier run.
  8. madtrex/madspace coupling.
    • CMake records a digest of the madspace headers madtrex is built against (_build_info.json). import madtrex refuses any other madspace and gives the command to rebuild, instead of a silent binary mismatch.
    • The backend chooser reads the same check (madtrex/_compat.py, pure Python), so auto then falls back to the classic module.
    • install.py rejects a madspace that is too old before building.
    • install madspace/install madtrex at the MadGraph prompt now report a failing installer.
  9. Default PDF. The baseline PDF set and the normaliser precision come from the run card stored in the events' own LHE header (<MG7RunCard>), not from the current Cards/run_card.toml.
  10. include_madtrex_source now also gives the gridpack bin/reweight. On first use, bin/reweight builds madtrex from the shipped sources when there is no install, or rebuilds it when it was compiled against another madspace. The MadGraph VERSION file is now shipped with the sources (source builds in a gridpack needed it).

Licence

The LGPL text is not shipped in the repository: as part of MadGraph7 it would conflict with the MadGraph7 licence, which is more permissive. The vendored Rex is treated as dual licensed instead: LGPL-3.0-or-later as upstream, or the MadGraph7 licence as part of MadGraph7. Rex/pyproject.toml now states this as text (it pointed at the missing file, which broke pip install), and Rex/README.md and madtrex/README.md say so.

Tested locally (macOS, after the merge)

  • All passing:
    • the unit tests: test_mg7_launch, test_reweight_backend, the madmatrix density/writer tests, and the 36 test_madtrex_standalone tests against a real madtrex install;
    • testIO_FDgauge_madmatrix;
    • the two test_cmd.py acceptance tests that were failing;
    • test_reweight_backends (classic and MadtRex agree event by event);
    • the matrix-element.rst docs example.
  • Multi-index reweighting was checked in the Python parser and with a small C++ check of Rex's card parser and writer, but not end to end on an MSSM process.

The individual commits are on the branch if you want to look at any of them. Let me know if anything does not match what you intended.

oliviermattelaer and others added 3 commits October 27, 2026 14:15
unittest_mg7_launch failed (MG7ReweightingTest: "module 'madtrex' has no
attribute 'Driver'"). On the CI runner madtrex is not installed, and with
the MadGraph directory on sys.path 'import madtrex' finds the madtrex/
source directory as an empty namespace package; Python < 3.14 then
evaluated the mtx.Driver/mtx.PdfDriver return annotations at import.
Locally (3.14, lazy annotations, madtrex installed) it passed.

- from __future__ import annotations: annotations are not evaluated.
- A madtrex without Driver (that namespace package) counts as not
  installed. The module still imports, as MadGraph needs to choose and
  drive the reweighting (and the tests mock madtrex), and using madtrex
  raises the usual ImportError on how to install it; run_reweighting()
  and main() check it before doing any work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: madspace/src/driver/io.cpp, upstream's header validation and _event_size recompute kept next to madtrex's append mode.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… integration, normalise with the generation's matrix elements

Removal:
- madmatrix no longer ships the old CUDACPP-based MadtRex (madmatrix/MadtRex/, trex.py, the standalone_trex output and the old madtrex reweight plugin).

Fixes:
- "change max_batch" gave reweighted weights equal to the originals: batch-reloaded matrix element instances now get the launch's parameters back (detail::set_api_parameter()/reload_matrix_element(), parameters_lock()).
- A later fptype or change-model group no longer has its normaliser reloaded at the previous group's last launch parameters (load_process() forgets the record of every library it loads).
- MadtRex reads MLM npy events (per-particle cluster_scale).

Performance:
- Rex classifies the events and computes the normalisations in parallel; MadtRex reweights on as many threads as the generation (cpu_thread_pool_size) and splits large subprocesses into batches of at least min_batch events (new card options "change nb_core N|auto", "change min_batch N", default 1000).
- An output_format = "lhe" run that MadtRex reweights is generated as npy, reweighted in place and converted to the requested LHE file (still written, without the reweighting weights, when the reweighting fails).

Normalisation:
- madspace can store each event's helicity-summed |M|^2 (DifferentialCrossSection matrix_element_output, EventRecord::f_matrix_element; opt-in, no MadtRex dependency); MG7 requests it for MadtRex runs and MadtRex normalises helicity-summed launches with it (TupperWare::set_stored_normalisation()), dropping the column from the output afterwards. In MLM runs whose cross section is a rescaled first evaluation, the stored value is rescaled to the event's alpha_s too.
- "change model" launches are normalised by the original matrix element (new over original |M|^2, MadGraph's convention); regenerated processes get a LIBTAG of their own, and each regenerated subprocess must match an original one exactly.
- The normaliser, and the original model's launches by default, use the param_card from the events' header (the one they were generated with), with a warning listing how Cards/param_card.dat differs; 32 stored matrix elements are checked against a re-evaluation (1e-6 relative).

Tests: test_madtrex_standalone (threads, batch sizes), test_mg7_launch (LHE via npy, fallback), test_reweight_backends (LHE via npy, stored matrix elements, change model, generation param_card, later groups after a parameter launch, MLM events).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@zeniheisser

Copy link
Copy Markdown
Contributor Author

Summary of additions/fixes besides fast-forwarding to the last main version:

  1. Removed the old MadtRex implementation (CUDACPP); the MadtRex shipped with MadGraph7 is completely independent from the old implementation, and utilises UMAMI to avoid having to rewrite and recompile code by just loading the amplitude codes as libraries
  2. Bugfixes where the original weight was not evaluated against the original physics model for a couple of different reasons
  3. Ensure binary interfacing between MadtRex and event generation; when MadtRex is activated, the output will always be binary and the "real" output format is only evaluated by MadtRex itself rather than at event generation
  4. Small optimisations: When MadtRex is activated, the values of the matrix elements squared are written to disk; additionally, MadtRex is standardised to reweight across as many CPU cores as event generation (including splitting individual parton configurations into several sub-jobs to maximise utilisation)
  5. Fixed output from MLM to work with MadtRex

@oliviermattelaer
oliviermattelaer merged commit 047925a into MadGraphTeam:main Oct 30, 2026
101 of 102 checks passed
@oliviermattelaer

Copy link
Copy Markdown
Contributor

Merged!! Thanks a lot Zenny

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