madspace: stable 2->3 Jacobian when a particle is soft - #174
Conversation
TwoToThreeParticleScattering weighted each point with the Byckling-Kajantie
Jacobian 1 / (8 sqrt(-G4)), forming the 4x4 Gram determinant G4 (and
cos(phi)) directly from invariants of order s. On its s23 range G4
factorises as
-G4 = lambda(s12, ma^2, t2) / 16 * (s23 - s23_min) * (s23_max - s23),
so when a particle is soft and the range is narrow, terms of order s^4 had
to cancel to a result smaller than their rounding error. The block then
returned garbage Jacobians or NaN (at block level 1e14 instead of O(1)),
starting from about 1e-8 of relative softness.
In ColorOrderedMapping that is about one point in a few million, enough to
wreck an integration. Checked on the massless 4- and 5-body phase-space
volumes at 1 TeV (8 batches of 2M points), per-batch estimates came out
at 20x, 100x, 700x, 5000x and 1e12x the analytic value for the 4-parton
single chain, the {d}|{u s c} split and the 5-parton chain. With this
change every batch is within 2% (4 partons) or 10% (5 partons), and the
combined estimates are 1.003, 0.998 and 1.009.
cos(phi) = 2u - 1 and the Jacobian 1 / (sqrt(lambda) (s23_max - s23_min)
|sin(phi)|) are now computed from u = (s23 - s23_min) / (s23_max - s23_min),
the position of s23 in the same range the invariant was sampled from. Any
rounding in that range cancels between the two. The inverse reads |sin(phi)|
off the momenta. At regular points the old and new weights agree to 1e-13
(median), and forward/inverse round trips improve where the old
determinant was ill-conditioned. bk_gram4, get_phi_from_s23 and lup_det4
have no remaining users and are removed.
The integrable 1/sin(phi) peak at the edges of the s23 range remains: it
comes from sampling s23 rather than phi, gives correct means with a
log-divergent variance, and is left as a sampling design choice.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ants The previous commit stopped forming the 4x4 Gram determinant, but the Jacobian and cos(phi) are now read off the s23 range, which s23_min_max still built from sqrt(G3i * G3im1) of Byckling-Kajantie. Those 3x3 Gram determinants vanish in the soft limit too and cancel down to the square of the range width, so below a softness of about 1e-8 the range came out as noise: NaN on arm64, and NaN or an exact zero Jacobian on x86_64, where the new soft-limit tests failed in the wheel CI. In the p12 rest frame with z along pa and p3 in the phi = 0 half-plane, s23 = m0^2 + m1^2 - 2[(sqrt(s12) + E3) E1 - p3_z p1_z] + 2 p3_x p1_t cos(phi), so the range has width 4 p3_x p1_t, every factor of which is read off momenta at full relative precision. With flat s23 sampling the soft-limit Jacobians now reach their constant limit to 1e-7 down to delta = 1e-14, and agree with the old code to 7 digits wherever it was finite. bk_V, bk_sqrt_g3i_g3im1 and the LU helpers in lup_det.hpp have no users left and go. assert_smooth now demands every point be finite, which fails on the previous commit on every platform. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@oliviermattelaer , thats nice. I will also check how to update the inverse then. |
On its kinematic range s23 is linear in cos(phi) and the Byckling-Kajantie Jacobian is 1 / (sqrt(lambda) (s23_max - s23_min) |sin(phi)|), so the measure is flat in phi. Sampling s23 with any density that is finite at the kinematic limits (flat or 1/s^nu) leaves an integrable 1/|sin(phi)| in the weight: correct mean, log-divergent variance. This is the remaining tail noted in #174. TwoToThreeParticleScattering now first maps the random number flat in theta = phi / 2, x = (sin^2 theta - sin^2 theta_a) / (sin^2 theta_b - sin^2 theta_a), and hands x to the existing s23 Invariant, so the 1/s^nu importance sampling (and Breit-Wigner) is kept. theta_a, theta_b locate the sampled range inside the kinematic one: without cuts they are 0 and pi/2 and dx/dr vanishes like |sin(phi)| at both edges, cancelling the peak; at an edge set by a cut there is no peak, and dx/dr stays finite there. With flat s23 sampling the block weight becomes exactly independent of r_s23. New instructions s23_arcsine / s23_arcsine_inverse; option arcsine_s23 (default true) on TwoToThreeParticleScattering and ColorOrderedMapping. Massless volumes at 1 TeV, 8 x 1M points, flat -> arcsine: 4-parton chain sigma/mu 11.3 -> 4.5, max w/mu 8.1e3 -> 340 1+3 split sigma/mu 7.9 -> 4.6, max w/mu 5.4e3 -> 350 5-parton chain sigma/mu 25.1 -> 6.0, max w/mu 3.1e4 -> 920 4-chain, cuts sigma/mu 8.8 -> 3.4, max w/mu 9.6e3 -> 190 with unchanged volumes (analytic, and the fiducial volume with cuts). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
…inverse With cuts, ColorOrderedMapping failed the forward/inverse round trip for about 3% of the points (4-parton chain, pt > 20, m_ij > 10, dR > 0.4 at 1 TeV), carrying about 4% of the fiducial volume. Two causes: - rotate(p, q), the frame of the 2->2 LAB block around the incoming momentum, took the identity when q_t == 0 exactly and otherwise an azimuth set by atan2(q_y, q_x). The walk builds that momentum along the beam up to rounding, differently in forward and inverse, so the recovered r_phi was off by an arbitrary angle, often pi/2. rotate is now the minimal rotation z -> q (and F R(F q) with F = diag(-1, 1, -1) in the lower hemisphere), smooth across the beam axis and equal to the old one on it. - s23_etmin_clamp applies the smin bound only for a massless peeled particle, tested as m2_2 < EPS = 1e-12. The inverse reads m2_2 off the momentum, where a massless particle comes out at ~1e-16 E^2, so the bound switched off and the sampled s23 range changed. The test is now relative, m2_2 < 1e-10 E^2. The forward is unchanged (m2_2 = 0 there). With both, no point of 200k fails (|det det_inv - 1| < 1e-2), the 99th percentile is 1e-10, and every random number is recovered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
…truction Light-like momenta of ColorOrderedMapping came out off shell by up to sqrt|p^2|/E ~ 4e-5 (massless 4-parton chain at 13 TeV), about 1e-3 of the points above 2e-6; test_t_channel_masses[4 particles, massless-color_ordered] failed for 2 of 40 seeds on main. Three causes: - rotate_two_ref, the frame of the 2->3 block, did one Gram-Schmidt pass. With p3 close to pa in the p_12 rest frame the x axis kept a component along z of relative size eps |p3| / |p3 perp|, the rotation was not orthogonal and changed |p1|, and the back-to-back daughters came out off shell even for p_12 almost at rest. A second pass fixes it. - A soft daughter was formed as p_12 - p1 in the lab, or thrown backwards through `boost`, and lost a factor gamma^2 (or E_12 / E) of relative precision. boost_two_body now boosts the softer daughter on its mass shell (boost_light_cone: light-cone components along the boost axis, the smaller one from the mass shell) and takes the harder one as p_12 minus it. That keeps p1 + p2 = p_12 by construction, as before, and the harder one carries at least half the energy, so it loses no precision. Used in the 2->3 and the 2->2 LAB kernels. - In the color-ordered walk each 2->3 block got its system as pa + pb - p3 with pb = R_a + R_b - beam + im1, all beam-sized, so a soft system had an absolute error of order the beam energy. The kernels now take p_12 itself (input p12 in place of pb; TwoToThreeParticleScattering forms it as pa + pb - p3 unless p12_condition is set), and the walk hands each block the chain output of the previous one. The last particle is the chain of the last block, and the inverse sums the chain systems from the soft end. Maximum sqrt|p^2|/E in the partonic frame: 4e-5 -> 3.5e-7 (4-parton chain), 4e-5 -> 3.9e-7 (5-parton chain); none above 2e-6 in 1M points. Momentum conservation is unchanged: |sum p_out - sum p_in| <= 3.6e-12 at 13 TeV, as on main, and the existing conservation tests pass unchanged. The block-level round trip in test_2to3_scattering now runs with and without the arcsine map; with it, points close to the edges of the s23 range recover r_s23 to ~1e-8 only, since the inverse has to resolve s23 - s23_min from s23. The beam boost to the hadronic frame (boost_beam) is untouched and still leaves up to ~1e-5 there (3e-5 on main). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
With the arcsine map most weight sits close to the edges of the s23 range, where u = (s23 - s23_min) / (s23_max - s23_min) is small. Forward and inverse both went through s23 itself, which only knows s23 - s23_min to ~1e-16 s, so near the edges the round trip recovered r_s23 to ~1e-8 only and det * det_inv to ~1e-5. Now the position in the range is carried as the pair u, 1 - u in both directions: - s23_arcsine_sample composes the arcsine map with the s23 importance sampling of Invariant (flat, logarithmic or 1/(s - m^2)^nu, same regularisation) in one kernel, carrying every quantity as its distances to both ends of its range, with the power maps through expm1 and log1p. s23_arcsine_sample_inverse inverts it from u, 1 - u. - two_to_three_particle_scattering takes u, 1 - u instead of s23 and builds cos(phi) = (u - (1 - u)) / (u + (1 - u)) and |sin(phi)| from them; the inverse returns u, 1 - u read off the momentum, the one close to zero as p_y^2 / (2 p_t (p_t -+ p_x)). - Without the arcsine map, or with a Breit-Wigner, s23 is sampled as before and s23_position gives u, 1 - u. Near the edges r_s23 now comes back to ~1e-17 absolute (the precision of the momenta) and det * det_inv to ~1e-11. The round-trip tests are strict again, with a new one within 1e-12 of both edges. The mapping, and so the volumes and weight distributions, are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
boost_beam wrote the boost along z as E cosh y + p_z sinh y. A momentum
moving against the boost comes out of the cancellation of terms of order
e^{|y|} E and loses a factor e^{2|y|} of relative precision; after the
fixes in the color-ordered chain this was the largest remaining source,
with |p^2 - m^2| / E^2 up to ~3e-10 (sqrt|p^2| / E ~ 2e-5) for massless
momenta at 13 TeV.
boost_beam and boost_beam_inverse now take the external masses
(PhaseSpaceMapping passes them in the order after the channel permutation,
-1 where permutations disagree). A momentum whose lab energy drops below its
partonic one is boosted in light-cone components along z, the smaller one
from the mass shell. It is only done for momenta that are on their mass
shell to rounding (|p^2 - m^2| <= 1e-13 E^2); others, from degenerate
points or from mappings whose partonic momenta carry larger errors, keep
the linear boost. The shifts this makes are handed to the outgoing momentum
with the largest energy, so momentum is conserved exactly as with the
linear boost.
Color-ordered, massless 4-parton chain at 13 TeV: max |p^2 - m^2| / E^2
2.8e-10 -> 9.5e-13 in the lab frame, conservation unchanged. Other modes
are not worse (propagator 5.9e-11 -> 7.8e-12, RAMBO 5e-12 -> 1.9e-13); what
remains there comes from their partonic momenta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
|
@oliviermattelaer I pushed five commits on top of yours. Your two commits are unchanged. They address the "Not addressed" list (the 1/sin φ edge peak and the unreliable inverse) plus a few precision issues found while checking it. The full madspace suite passes on this branch and also merged with current 1. Arcsine map for s23 (removes the 1/sin φ tail)s23 is linear in cos φ and the 2→3 measure is flat in φ. Any s23 density that is finite at the kinematic limits therefore leaves an integrable 1/|sin φ| in the weight, with a log-divergent variance. The random number of s23 is now first mapped flat in φ/2 and then handed to the existing s23 importance sampling, which is kept. The weight is bounded at the edges. With flat s23 sampling the block weight is exactly independent of r_s23. New option Massless phase space at 1 TeV, 8 × 1M points, flat → arcsine:
Volumes are unchanged: the analytic value without cuts, and the fiducial volume with cuts. 2. Inverse / round trip
3. On-shell momenta, momentum still conserved by constructionLight-like momenta came out off shell by up to √|p²|/E ≈ 4e-5. This is why
Max √|p²|/E is now ~4e-7 in the partonic frame (was 4e-5). Momentum conservation is unchanged, and the existing conservation tests pass with their original tolerances. 4. Boost to the hadronic frame
Lab-frame max |p² − m²|/E²:
What remains in the other modes comes from their partonic momenta. Behaviour changes
6. Soft and collinear limitsThis fixes the NaNs deep in the soft limit. I probed the block down to 1e-16 softness at the corners of the random numbers, and about a quarter of those points gave a non-finite inverse. There were two causes:
All probed points are now finite in both directions, and on shell to 1e-9 wherever the weight is nonzero. Round trips below ~1e-8 softness are still limited by the precision of the float momenta.
New tests: |
#174 left a few points deep in the soft limit that came out as NaN. Probing the 2->3 block at softness and collinearity down to 1e-16, at the corners of the random numbers (6 configurations x 4 deltas x 72 corners), the forward was always finite, but on #174 about a quarter of the points gave a non-finite inverse. Three causes: - rotate_two_ref floored |p3 perp| at sqrt(EPS2) = 1e-12. For p3 below ~1e-12 GeV the x axis came out shorter than 1, the rotation shrank p1, and the momenta were off shell by ~1e4 GeV^2 at nonzero weight. boost_light_cone (from the previous commits) had the same floor on |p| of the boost axis, for a p_12 almost at rest. Both frames are now normalised scale-free; a p3 with no usable part perpendicular to pa gets a fixed perpendicular axis. rotate uses the same normalisation. - Where p1 or p3 is along pa (t1 at an end of its range, a collinear or vanishing p3) the s23 range has zero width, the azimuth is undefined and the weight is zero; the inverse divided 0 / 0. The guards for an empty range added an absolute EPS = 1e-12, below one ulp of s23 or t for values above ~1e4. The ranges handed to the s23 and t sampling now get a relative minimum width; the Jacobian of the scattering kernel keeps the true width, so the weight there stays zero. Now every one of these points is finite in both directions, with and without the arcsine map, and on shell to |p^2 - m^2| / E^2 < 1e-9 wherever the weight is nonzero. Round trips at softness below ~1e-8 remain limited by what the momenta can carry. Also drop the separate s23_arcsine kernels: they only served a Breit-Wigner s23 sampling combined with the arcsine map, and no resonance is expected in this block. TwoToThreeParticleScattering now rejects arcsine_s23 together with s_width != 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q34kWgihoQCVRUFwMq2xS
Problem
ColorOrderedMappingoccasionally returns weights up to ~1e20 times the typical one, which can throw an integration off by orders of magnitude. The source isTwoToThreeParticleScattering, the 2→3 peel used for any color-ordered set of three or more particles. It weights each point with the Byckling–Kajantie Jacobian1/(8 sqrt(-G4)), forming the 4×4 Gram determinant G4 (and cos φ) directly from invariants of order s ~ 1e6 GeV². On the s23 range, G4 factorises:When a particle is soft the range is narrow. Terms of order s⁴ then have to cancel to a result smaller than their rounding error. Beyond ~1e-8 of relative softness the block returns garbage or NaN: 1e14 instead of O(1) at block level, in both the "peeled particle soft" and "previous particle soft" limits.
How often it hits
Massless 4- and 5-body phase-space volume at √s = 1 TeV, 8 batches × 2M points, estimate ÷ analytic
(π/2)^(n−1) s^(n−2)/((n−1)!(n−2)!):[0,2,3,4,5,1][0,2,1,3,4,5]The largest weight in the 4-parton chain falls from 2e18× to 1.6e4× the exact volume.
Fix
Both cos φ and the Jacobian are now computed from
u = (s23 − s23_min)/(s23_max − s23_min), the position of s23 in the same range the invariant was sampled from:cos φ = 2u − 18 sqrt(−G4) = sqrt(λ) · (s23_max − s23_min) · |sin φ|, with|sin φ| = 2 sqrt(u(1−u))Any rounding in the range cancels between the invariant's Jacobian and this one. The inverse reads |sin φ| off the momenta.
bk_gram4,get_phi_from_s23andlup_det4have no remaining users and are removed.At regular points old and new agree: median relative weight difference 1e-13, 99.9% of points within 1e-6. Forward/inverse round trips improve where the old determinant was ill-conditioned; for example, the worst |det·det_inv − 1| for a 5-body chain with t and W masses goes from 1.0 to 5e-4.
Tests
New
madspace/tests/test_two_to_three_soft_limit.py:test_jacobian_with_soft_peeled_particle,test_jacobian_with_soft_third_particle: drive the block into both soft limits down to δ = 1e-14 and require the Jacobian to follow its smooth limit (within a factor of 2).test_color_ordered_massless_volume: the analytic 4-body volume for the single chain and the 1+3 split, averaged over 8 × 2M points, within 5%.All 4 fail on origin/main and pass here. Full madspace suite: 1571 passed. The only local failures are 4
test_double_ttests needingscipy, the same on origin/main, plus 2 torch-only modules I skipped. Also built withENABLE_SIMD=ON(arm64); the 2→3, t-channel, cut and new tests (288) pass there. The CUDA/HIP builds could not be tried locally; the kernel only uses functions already used on those backends (min,max,where,sqrt,acos,fabs).Not addressed
u = sin²(πr/2)would cancel it, but that changes the s23 importance sampling, so it is left as a design decision.🤖 Generated with Claude Code