mg7: support the run_card me_frame, the frame the matrix element is evaluated in - #171
Draft
oliviermattelaer wants to merge 2 commits into
Draft
oliviermattelaer wants to merge 2 commits into
oliviermattelaer wants to merge 2 commits into
Conversation
…valuated in
me_frame names the external particles whose momentum sum is put at rest, the
same convention madevent has used for polarised processes. The matrix element
is then evaluated on momenta boosted into that frame; everything else -- the
cuts, the scales, the momentum fractions, the event that gets written -- keeps
the momenta as generated. It only changes the result for a matrix element that
is not Lorentz invariant, i.e. a polarised one, and it is then the frame the
polarisations are defined in.
The default is [], which applies no boost at all, so no existing run changes
and nothing is paid for a feature it does not use. [1, 2] asks for the partonic
centre of mass, the frame madevent evaluates in, and [1] is its equivalent for
a 1 -> n decay. Note this is the one place mg7 deliberately differs from
madevent's default, which is [1, 2]: madevent gets that frame for free because
its matrix element is already handed partonic-CM momenta, whereas here it costs
a boost per event.
madspace generates momenta in the lab frame, which is why the boost is built in
two steps -- first into the rest frame of the incoming system, then into the
requested one. Going straight there from the lab is a different frame: boosts
along different directions do not compose into the boost between the end
frames, and the leftover Wigner rotation turns the polarisation axes away from
madevent's. Measured on g q > z{0} q, me_frame=[3]: one boost gives 4.4886e-02
where the two-step gives 6.8931e-02, and only the latter is independent of the
frame the momenta arrive in.
The new boost_to_frame instruction is a port of madevent's boost_to_frame
(Template/LO/SubProcesses/genps.f), including its rule that a single selected
particle must come out at exactly zero three-momentum -- vxxxxx branches on
pp == 0 and otherwise builds a massive vector's polarisation vectors out of the
rounding noise. Validated against the Fortran routine on the momenta madevent
feeds it: agreement to <= 4e-16 for me_frame = [1,2], [3], [4], [3,4] and
[3,4,5].
madmatrix needs nothing: it already emits only the generic
ixxxxx/oxxxxx/vxxxxx/sxxxxx and never the z-axis-optimised ipzxxx/imzxxx/ixzxxx,
which assume the beams run along z and would be wrong in a boosted frame. A
comment and a test now pin that down.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
oliviermattelaer
marked this pull request as draft
September 18, 2026 07:00
… me_frame branch
Four conflicts, all from main moving under the branch:
- .github/workflows/acceptancetest_mg7.yml: main bundled the per-test jobs,
deleting the block the polarised-mirror job sat in. Took main's structure
and re-added the test as a step of acceptancetest_mg7_bundle_2, which is
the bundle that installs madspace and restores heptools (bundle_4, where
the other mirroring test lives, has neither).
- madspace/include/.../matrix_element.hpp: main documented the constructor
with Doxygen @PARAM. Adopted that style and documented me_frame and
incoming_count in it.
- madspace/src/python/madspace.cpp: main added the pydoc::doc() docstrings
and fixed matrix_element_index, which was bound to diagram_count. Kept all
of that and re-applied the new arguments and the frame_mask /
reference_mask accessors. The two constant-tensor Value constructors are
left without a docstring key: it would be an overload-indexed
"Value::Value#N" that only generate_docstrings.py can assign, and doc() is
consteval, so a guessed key is a compile error.
- UpdateNotes.txt: both sides added an entry at the top of 0.3.0.
Verified on the merged tree: madspace builds and its suite passes (1636),
test_me_frame 17, test_mg7_launch / test_madmatrix_writer / test_banner 114,
and test_polarised_mirror_symmetry_mg7 passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
me_framenames the external particles whose momentum sum is put at rest, thesame convention madevent has used for polarised processes. The matrix element is
then evaluated on momenta boosted into that frame; everything else — the cuts,
the scales, the momentum fractions, the event that gets written — keeps the
momenta as generated. It only changes the result for a matrix element that is
not Lorentz invariant, i.e. a polarised one, and it is then the frame the
polarisations are defined in.
The default is
[], not madevent's[1, 2][]applies no boost at all, so no existing run changes and nothing is paid fora feature it does not use.
[1, 2]asks for the partonic centre of mass, theframe madevent evaluates in, and
[1]is its equivalent for a1 -> ndecay.This is the one place mg7 deliberately differs from madevent's default. madevent
gets the partonic CM for free, because its matrix element is already handed
partonic-CM momenta and
frame_id == 6is skipped outright. madspace generatesin the lab frame, so the same default would cost a boost per event for every
process. A polarised mg7 run therefore has to ask for
me_frame = [1, 2]explicitly, and a converter from the LO run_card must carry the value over
rather than treat LO's
[1, 2]as "the default, nothing to do" (noted inRunCardLO_to_MG7_mapping.md).Two boosts, not one
Because madspace works in the lab frame, the requested frame is reached in two
steps — first into the rest frame of the incoming system, then into the
requested one.
Going straight there from the lab is a different frame: boosts along different
directions do not compose into the boost between the end frames, and the
leftover Wigner rotation turns the polarisation axes away from madevent's. On
g q > z{0} qwithme_frame = [3], at a fixed phase-space point, one boostgives
4.4886e-02where the two-step gives6.8931e-02. Only the latter isindependent of the frame the momenta arrive in — after the fix,
ME(frame(lab p))andME(frame(cm p))are bit-identical.Validation
boost_to_frameinstruction is a port of madevent'sboost_to_frame(
Template/LO/SubProcesses/genps.f), including its rule that a singleselected particle must come out at exactly zero three-momentum —
vxxxxxbranches on
pp == 0and otherwise builds a massive vector's polarisationvectors out of the rounding noise. Compared against the Fortran routine on the
momenta madevent actually feeds it (partonic CM — feed it lab momenta and its
trivial_boostbranch makes the comparison look broken): agreement to<= 4e-16 for
[1,2],[3],[4],[3,4]and[3,4,5].p p > z{0} j:[]2107(15),[1,2]2104(12),[3,4]2104(12),[3]1807(16) pb.[1,2]and[3,4]agreeing is theself-check — both are the partonic centre of mass.
me_framehas no rest frame and used toreturn NaN silently; it is now rejected, as is an out-of-range particle number
— before the matrix-element libraries are compiled, rather than minutes later
when the integrands are built.
madmatrix
Nothing needed: it already emits only the generic
ixxxxx/oxxxxx/vxxxxx/sxxxxxand never the z-axis-optimisedipzxxx/imzxxx/ixzxxx, which assumethe beams run along z and would be wrong in a boosted frame (cudacpp dropped
them with the ALOHAOBJ rewrite). A comment and
TestExternalWavefunctionCallsnow pin that down so they cannot come back unnoticed.
Tests
madspace/tests/test_me_frame.py(17): the kernel against an independentnumpy boost, the invariants it must preserve, the exact-zero rule, the
frame-independence property, the degenerate empty mask, and the number of
boost_to_framecallsMatrixElementactually emits (0 / 1 / 2).tests/acceptance_tests/test_mg7_polarised_mirror.py+ CI jobacceptancetest_mg7_polarised_mirror: the regression test for madspace: evaluate the matrix element on the momenta the event is written with #170, whichneeds
me_frame = [3]to reach the broken branch at all. Verified to fail onmadspace: evaluate the matrix element on the momenta the event is written with #170's parent and pass with it.
test_mg7_launch(5 new),test_madmatrix_writer(2 new).madspace suite 1562 pass; full unit suite unchanged against main.
🤖 Generated with Claude Code