Repository navigation
MadtRex: The really big PR - #333
Conversation
…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>
|
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: 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. Blockers1.
2. The library rename (
3. No CI job installs madtrex, so none of the MadtRex code is tested
Other points4. Inline
5. Multi-index blocks are mis-parsed. 6. TupperWare / WareHouse object lifetimes in the Python bindings.
7. A reweighting failure stops the rest of the run. 8. Version coupling between madtrex and madspace.
9. The default PDF for PDF reweighting. 10. Thanks again, this is a great addition! |
|
@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 :) |
- 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>
|
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 What changed
LicenceThe 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. Tested locally (macOS, after the merge)
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. |
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>
|
Summary of additions/fixes besides fast-forwarding to the last main version:
|
|
Merged!! Thanks a lot Zenny |
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