Skip to content

Fix madspace issue 292 - #303

Open
ramonpeter wants to merge 4 commits into
mainfrom
fix-madspace-issue-292
Open

ramonpeter wants to merge 4 commits into
mainfrom
fix-madspace-issue-292

Conversation

@ramonpeter

@ramonpeter ramonpeter commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

madspace: colour-ordered mapping as in AmpliCol (fixes #292)

The colour-ordered phase-space mapping gave very large weights for colour orders with a two-particle side, e.g. 0 2 3 1 4 5 in g g > g g g g. This PR aligns ColorOrderedMapping with AmpliCol's gen23 and makes its settings explicit.

Changes

  1. Function builder: sub(0, x) was simplified to x; now only sub(x, 0) is. This flipped the sign of any bound built from the literal mass of a massless particle. No existing code hit it, but the new mass ranges do.
  2. TwoToThreeParticleScattering:
    • incoming_recoil: the previous emission can be an incoming beam, and the block samples the momentum transfer |(p₂ − k)²|.
    • cut_aware_branch: both azimuthal solutions are built and the one passing the pT cuts is kept; the discrete choice only decides when both pass (AmpliCol). The weight assumes a uniformly sampled choice.
  3. ColorOrderedMapping:
    • Two-particle sides: a side of two particles, with the other side non-empty, is one 2→3 step with the opposite beam as the previous emission. Both beam-adjacent invariants are sampled (s₀₂ and s₃₁), instead of s₀₂ plus a flat azimuth. This adds one discrete choice per such side. It is the main fix.
    • Masses: composite and rest masses are sampled as 1/√s (flat in the mass), not flat in s. Where two systems make up the full final state, their ranges use the energy and ETmin bounds of gent_one_step. Empty ranges get zero weight.
    • Chain powers: with cuts, t and s23 are sampled as 1/|x| (AmpliCol). Without cuts they fall back to invariant_power, because 1/|x| would pile the points up at the regulator.
    • Arcsine map: s23 always goes through it.

API

  • ColorOrderedMapping::Options: color_order (required), chain_invariant_power (unset: as above), cut_aware_branch (default on; turn off when the discrete choices are sampled with NIS).
  • ColorOrderedMapping(options, pt_min, m_inv_min, dr_min, y_max).
  • PhaseSpaceMapping: color_ordered=Options(...) replaces color_order=. It is required in color_ordered mode and rejected in the other modes.
  • PhaseSpaceMapping(s_hat_power=...): the power of the ŝ sampling, in every mode. Unset, it is 1.2 in color_ordered mode when masses or cuts bound ŝ from below (as AmpliCol), and invariant_power otherwise.

Effect on the variance

Stand-in for |A_σ|² (sum of MHV Parke–Taylor terms, same colour-adjacent poles), g g > g g g g, pT > 20 GeV, ΔR > 0.4, 4M points, no VEGAS. Numbers are rel. std (max/mean in brackets).

At fixed √ŝ = 300 GeV:

order before after
0 1 2 3 4 5 24.7 20.9
0 2 1 3 4 5 16.1 10.7
0 2 3 1 4 5 58.2 (8.0e4) 6.2 (1.7e3)
0 2 3 4 1 5 16.8 12.0

With a toy gluon luminosity (x g(x) = x^-0.2 (1−x)^5, 13 TeV), comparing main (all powers 0.7) with this PR (ŝ power 1.2):

order main this PR
0 1 2 3 4 5 194 78
0 2 1 3 4 5 135 53
0 2 3 1 4 5 165 46

main's 165 for 0 2 3 1 4 5 is close to the 154 reported in #292. On main, the estimated cross section of that order at 4M points was also about 25% low, with an error estimate that didn't cover it: the weights were too heavy-tailed to trust.

The chain power was not conclusive. 0.8 instead of 1 gave 23 for 0 2 3 1 4 5 but was slightly worse for 0 2 1 3 4 5. A scan with the real matrix element is worth doing: Options(order, chain_invariant_power=0.8).

Tests

  • New: test_color_ordered_amplicol_steps.py (2→3 step off the beam, round trips, discrete counts, analytic volumes, fiducial volumes against RAMBO for each option setting) and test_s_hat_power.py.
  • Existing tests moved to the new API.
  • test_massless_on_shell now measures |p²|/E² through (E − |p|)(E + |p|); the 1/√s masses reach particles with E ~ 1e-8 √s.
  • Full madspace suite: 1796 passed, 11 skipped.

Follow-up for #291 ([amplicol] subprocess)

color_ordered=ms.ColorOrderedMapping.Options(self.meta["phasespace_order"]),  # was color_order=...

Not included

🤖 Generated with Claude Code

ramonpeter and others added 4 commits October 19, 2026 11:07
The builder replaced add(x, 0), add(0, x) and sub(x, 0) by x, but also
sub(0, x). Any difference with a literal zero in front, for example a
bound built from the literal mass of a massless particle, therefore came
out with the wrong sign. sub is now folded only with the zero second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
Two options of TwoToThreeParticleScattering, for the AmpliCol steps of
ColorOrderedMapping (issue #292):

- incoming_recoil: momentum3 is an incoming momentum k, and the second
  invariant is the momentum transfer (p2 - k)^2 <= 0, of which the
  absolute value is sampled (with the arcsine map, or plain). With cuts it
  is bounded by |(p2 - k)^2| >= etmin_2^2. This is gen23_one_step with a
  beam as the previous emission, which AmpliCol uses for a side of two
  particles.
- cut_aware_branch: both azimuthal solutions are formed and the one that
  passes the transverse-energy floors of p1 and p2 is kept; the discrete
  choice only picks when both pass (new instruction
  two_to_three_branch_choice). The weight assumes a uniformly sampled
  choice: 1/2 where one solution passes, 0 where none does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
…292)

The chain of ColorOrderedMapping follows AmpliCol's gen23 more closely:

- A side of exactly two particles, with the other side not empty, is one
  2->3 step with the opposite beam as the previous emission, as in
  gen23_one_step(set(i), inext, i, 3 - i): the momentum transfers of both
  particles to the beam they are next to in the color order are sampled
  (s02 and s31 for 0 2 3 1 4 5), instead of the first one and a flat
  azimuth. One more discrete choice per such side.
- Composite and rest masses are sampled as 1/sqrt(s), flat in the mass
  (they were flat in s). Where the two systems make up the full final
  state (the two sides, the first rest of a single chain) the range comes
  from the energies of both, with the transverse-mass and mass floors of
  the cuts (shatminmax and the ETmin bounds of gent_one_step). An empty
  range gets zero weight.
- With cuts the momentum transfers and s23 invariants of the chain are
  sampled as 1/|x| (AmpliCol's ip = 1). Without cuts their ranges reach
  zero, where 1/|x| piles the points up at the regulator of Invariant;
  they keep 0.8 there (invariant_power in PhaseSpaceMapping), where
  AmpliCol falls back to a flat density.
- The 2->3 steps keep the azimuthal solution that passes the pt cuts and
  let the discrete choice pick only when both pass. The weight assumes
  uniformly sampled choices, as the integrand does now.
- The s23 random numbers always go through the arcsine map.

The settings live in ColorOrderedMapping::Options: the color order
(required), chain_invariant_power (unset: as above) and cut_aware_branch
(default on; off when the discrete choices are sampled with a learned
distribution). ColorOrderedMapping takes the options and the cut bounds;
PhaseSpaceMapping takes them as color_ordered instead of color_order. They
are required for the color_ordered mode and refused by the others.

PhaseSpaceMapping also takes s_hat_power, the power of the s_hat sampling
of the PDF convolution, in every mode; unset it is invariant_power.
AmpliCol uses 1.2.

g g > g g g g, proxy colour-ordered |A|^2 (sum of the MHV Parke-Taylor
terms), sqrt(s_hat) = 300 GeV, pt > 20, dR > 0.4, |eta| < 5, 4M points:

  order          rel. std. dev.   max / mean
  0 1 2 3 4 5    24.7 -> 17.7     1.6e4 -> 5.8e3
  0 2 1 3 4 5    16.1 ->  9.5     6.6e3 -> 2.0e3
  0 2 3 1 4 5    58.2 ->  5.5     8.0e4 -> 1.2e3
  0 2 3 4 1 5    16.8 ->  9.8     8.7e3 -> 2.1e3

With a toy gluon luminosity (x g = x^-0.2 (1 - x)^5, 13 TeV), an s_hat
power of 1.2 instead of 0.7 roughly halves the rel. std. dev. again.
Massless volumes agree with the analytic ones and fiducial volumes with
RAMBO's, and forward and inverse agree.

test_massless_on_shell now measures |p^2| / E^2 through (E - |p|)(E + |p|):
the 1/sqrt(s) masses reach particles with E ~ 1e-8 sqrt(s), where
sqrt(|p^2|) / E from E^2 - |p|^2 is dominated by the rounding of the test
itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
An unset s_hat_power is now AmpliCol's 1.2 in the color_ordered mode
when masses or cuts bound s_hat from below, so that callers need not
pass it. Without such a bound 1/s_hat^1.2 piles the points up at the
regulator of Invariant (AmpliCol falls back to a flat density there),
and s_hat keeps invariant_power, as in the other modes. An explicit
s_hat_power always wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS

This branch has not been deployed

No deployments
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.

madspace: colour-ordered mapping undersamples two-particle sides (vs Fortran AmpliCol)

1 participant