loop-induced: stop the run when the poles do not cancel - #80
Open
oliviermattelaer wants to merge 6 commits into
Open
loop-induced: stop the run when the poles do not cancel#80oliviermattelaer wants to merge 6 commits into
oliviermattelaer wants to merge 6 commits into
Conversation
The vanishing-pole test of a loop-induced matrix element was emitted as Fortran comments (##W04/##W05) in the default MadLoop output and was absent altogether from the optimized one, which is the output every loop-induced madevent run uses. Nothing checked the poles. - add MLPoleCheckThres to MadLoopParams (default 1e-2, <=0 disables) - optimized output: compare |ANS(2,0)|+|ANS(3,0)| to ANS(1,0) once the result is final and STOP on failure; skipped when the reduction tool is not computing the poles (COLLIER with the pole flags off), with a one-time INFO saying so - default output: same check, plus the loop-induced squaring now builds the genuine eps^-1/eps^-2 coefficients of |M|^2 instead of a quantity linear in the pole (which is what needed the unexplained 10**5 fudge) - drop the dead ##W04 block: it tested each loop amplitude separately, but individual loop diagrams do have poles; only their sum is finite
- gate the new declarations/blocks so a process with a Born produces the exact same loop_matrix.f as before (verified for g g > t t~ [virt=QCD] and by the short_ML_SMQCD_default/optimized IO tests) - keep the COLLIER pole computation on for standalone loop-induced output, otherwise the check can never run there - madevent loop-induced: compare |1eps|+|2eps|, not the signed sum, so a positive single pole cannot hide a negative double pole - update the short_ML_SMQCD_LoopInduced/gg_hh reference
- ##E02 was already taken by the zero-reference error: use ##E03 - the ##INFO told users to flip COLLIERComputeUV/IRpoles in the card, which a madevent run overrides at init; say so instead - name the guard conditions (POLES_COMPUTED / DO_POLE_CHECK) so the writer stops splitting a 230-char line mid-identifier - say in the STOP message how to change or disable the tolerance - drop the 10*ACCURACY(0) valve. ACCURACY is the accuracy of the *finite part* and it does not bound the pole residue: a g g > z z g point at threshold comes back H=2, "stable, no rescue needed", with a residue of 5.2e-2. Keying the tolerance on it was simply the wrong instrument. It also never fired -- ACCURACY(0) is -1 whenever the stability test did not run -- so removing it leaves the effective tolerance unchanged. - non-optimized output: use WRITE_MOM like the optimized one, and stop leaving blank lines where ##W05 used to be (Born output unchanged) - IOTest gg_hh now covers BOTH exporters; the optimized one is what every real loop-induced run uses and had no golden file. process_info.inc needs 'git add -f': .gitignore's PROC* pattern matches it on a case-insensitive filesystem, so plain 'git add' skips it silently and the test then dies with "Missing ref. files".
Distribution of (|ANS(2,0)|+|ANS(3,0)|)/|ANS(1,0)| over 812 physics-phase points of g g > z z, g g > h h, g g > z z g and g g > h h g, at sqrt(s) from 1.02x to 80x threshold: process median p99 max g g > z z 8.6e-14 3.5e-10 5.9e-10 g g > h h 1.3e-14 1.0e-10 3.9e-09 g g > z z g 2.1e-11 8.1e-06 4.0e-05 g g > h h g 4.7e-13 1.2e-05 5.6e-05 The ceiling is 6e-5, so 1e-3 keeps a factor ~20 of headroom. The response is linear in the injected error, but only for the amplitudes that dominate the pole: perturbing the eps^-1 residue of one of those by d gives a ratio of 0.13*d (z z) to 0.22*d (h h), so 1e-3 catches an error of 0.7% and up where 1e-2 needed 6%. A subdominant amplitude is invisible at any usable threshold -- 10% on amplitude 5 of g g > h h, whose pole sits 3 orders of magnitude below the leading ones, reaches only 8e-6. The gap between the 2->2 and 2->3 rows is not multiplicity scaling: a 2->2 at fixed s has no soft or collinear region and a 2->3 does, so what the jump shows is a singular region appearing, not conditioning degrading with leg count. A 2->4 adds more regions of the same character rather than another four orders of magnitude, which is why 6e-5 is the ceiling worth keeping headroom over and why 1e-4, at 1.8x, is too tight. 1e-3 adds no false positive over 1e-2 on this sample. The only point above either threshold is a soft-gluon g g > z z g configuration at 1.0002x threshold (ratio 5.2e-2) which fails at 1e-2 identically. madevent never samples it because cuts are applied before the ME call, but check_sa and launch do; the durable fix there is to warn on the first violations and stop only on a repeat, which is left as a follow-up.
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.
A loop-induced amplitude is finite: its single- and double-pole coefficients must
vanish. Nothing checked that. This adds a check that stops the run when they do not.
Nothing was checking the poles
Three things looked like a pole check and none was one:
check_polesnever reaches a loop-induced process. It is linked only by the FKSexporter;
[noborn=]is exported through the LO/madevent templates, which have nocheck_poles.fand noBinothLHA.f. It is a different test in any case — it comparesMadLoop's poles to the MadFKS Born-proportional ones.
##W04/##W05blocks inmadgraph/loop/loop_exporters.pyare emitted asFortran comments AND live only in the non-optimized exporter. The optimized exporter —
the default, and what every loop-induced madevent run uses — had no pole test at all.
matrix_loop_induced_madevent.inc:418is dead three ways:WRITE-only, capped at 10 points, and it sums the signedOneEps+TwoEps, so apositive single pole can cancel a negative double pole and report clean.
The check
New
MLPoleCheckThresMadLoopParams option, default1.0d-3, negative to disable,emitted inside the generated MadLoop matrix element and gated on loop-induced at
generation time. That is the one place with access to every guard, and it covers
madevent,
check_sa, f2py and OLP at once.Also fixed along the way: the
##W04block tested each loop amplitude individually,which is wrong physics — individual loop diagrams do have poles, only the sum is finite,
and it compared them against a squared-ME scale, so it was dimensionally wrong too. The
non-optimized loop-induced squaring was linear in the pole while
ANS(1)is quadratic;the historical
10**5fudge existed only to paper over that, so the squaring is fixedrather than the fudge inherited. The signed sum in the madevent driver becomes
ABS(OneEps)+ABS(TwoEps). The standalone exporter no longer disables COLLIER's polecomputation, otherwise the check could never run there.
The threshold comes from measurement
1048 physics-phase points over four processes, check disabled so nothing truncates the
sample:
g g > z zg g > h hg g > z z gg g > h h gCeiling 6e-5.
1e-4was rejected at 1.8x headroom;1e-3gives ~20x and detects errorsof 0.7% or more, against 6% at the old
1e-2, with no additional false positive on thissample. The 2->2 / 2->3 gap is a singular region appearing, not conditioning degrading
with leg count, so a 2->4 process adds more regions of the same character rather than
another four orders.
Evidence it is not vacuous
Injecting a 10% error on the eps^-1 residue of a dominant loop amplitude gives
##E03and exit 1. End to end at the shipped default: clean run exit 0 (median 1.69e-14),0.5% error not caught, 1% caught, 10% caught. Verified independently by a second reviewer,
who also confirmed the corrupted value genuinely travels through
COMPUTE_COLOR_FLOWS -> JAMPL -> ANS(2,0)rather than being fed back into the test.Limitations, stated in the card rather than omitted
never sees them (cuts run before the matrix element), but
check_saandlaunchfeeduncut phase-space points. The card says so and says to raise the value there. Note this
is not new to the threshold change: such a point exceeds the old
1e-2too. The durablefix is to warn for the first N violations and stop only on a repeat — recorded as a
follow-up, not implemented here.
returns
rc=217, H=2, "stable, no rescue needed".turned off there for speed and the card cannot override it). The check is live in
standalone,
check_sa,launch, on any install without COLLIER, and in madevent whennhel != 0. The##INFOannouncing the skip no longer offers a remedy that cannot work.Non-loop-induced output is untouched
g g > t t~ [virt=QCD]withPYTHONHASHSEED=0: ten generated files md5-identicalbase vs branch. IOTest goldens added for the optimized loop-induced path, which had none.