Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/actions/build_madspace/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Build madspace
description: >
Build the madspace install prefix once per commit and cache it
(content-addressed on the madspace source). Shared by the build_madspace job
of every mg7 workflow so the build logic lives in exactly one place. Test jobs
restore the result with the install_madspace action (they must `needs:` the
job that runs this action). Assumes the repository is already checked out.

runs:
using: composite
steps:
# Cache key must match the one used by the install_madspace action exactly,
# otherwise the later restore misses.
- name: madspace cache key
run: echo "MS_PY=$(python3 -c 'import sys;print(f"{sys.version_info.major}{sys.version_info.minor}")')" >> $GITHUB_ENV
shell: bash

# Cache the installed madspace/install prefix directly (not just a wheel), so
# every test job restores a ready-to-use install and skips pip entirely.
# hashFiles is evaluated before the build step creates madspace/install, so
# the key is the clean-source hash and matches the install_madspace action.
- name: Cache madspace install
id: cache-madspace
uses: actions/cache@v5
with:
path: madspace/install
key: madspace-${{ runner.os }}-py${{ env.MS_PY }}-${{ hashFiles('madspace/**') }}

# Built from the in-tree source (scikit-build-core / cmake). Upgrade pip +
# packaging first: the runner ships an ancient pip whose build isolation does
# not provide packaging>=22, which scikit-build-core's vendored
# pyproject_metadata requires.
#
# ENABLE_OPENBLAS=ON builds OpenBLAS from source and links it statically into
# the extension (see madspace/CMakeLists.txt), so the cached install is
# self-contained and needs no system libopenblas at runtime. This avoids a
# dynamic dependency that would otherwise only be satisfied on cache miss
# (when apt installed libopenblas-dev) and missing on cache hit.
#
# --target installs into madspace/install, the prefix the mg7 runtime and
# madspace/install.py expect.
- name: Build and install madspace (only on cache miss)
if: steps.cache-madspace.outputs.cache-hit != 'true'
run: |
cd $GITHUB_WORKSPACE
python3 -m pip install --upgrade pip packaging
python3 -m pip install ./madspace \
-Ccmake.define.ENABLE_OPENBLAS=ON \
--target="$GITHUB_WORKSPACE/madspace/install"
shell: bash
45 changes: 45 additions & 0 deletions .github/actions/install_lhapdf_pdfset/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Install LHAPDF PDF set
description: >
Make an LHAPDF PDF grid available to the mg7 (madspace) runtime and export
LHAPDF_DATA_PATH so it is found. The mg7 runtime reads the grid file directly
(mg7/madevent.py: ms.PdfGrid on $LHAPDF_DATA_PATH/<set>/<set>_0000.dat), so it
only needs the grid data -- not the LHAPDF C++ library and not a pre-baked
HEPTools cache. The set is installed with the lhapdf-management pip package
into a cached, writable directory, so the download happens at most once.

inputs:
pdfset:
description: Name of the LHAPDF set to install
required: false
default: NNPDF23_lo_as_0130_qed

runs:
using: composite
steps:
# Writable data dir, exported so every later step (and the tests) resolve the
# grid via $LHAPDF_DATA_PATH. GITHUB_ENV persists to subsequent steps,
# including the install step below.
- name: Set LHAPDF_DATA_PATH
shell: bash
run: echo "LHAPDF_DATA_PATH=$HOME/.cache/lhapdf_data" >> "$GITHUB_ENV"

# Cache the downloaded grid (~26 MB for NNPDF23) so we only hit the CERN
# server on the first run for a given set.
- name: Cache PDF grid
id: cache-pdf
uses: actions/cache@v5
with:
path: ~/.cache/lhapdf_data
key: lhapdf-data-${{ inputs.pdfset }}

# lhapdf-management honours $LHAPDF_DATA_PATH (set above) as the install
# location. `update --init` creates the data dir and pulls the set index;
# `install` downloads and unpacks the grid.
- name: Install PDF set via lhapdf-management (on cache miss)
if: steps.cache-pdf.outputs.cache-hit != 'true'
shell: bash
run: |
python3 -m pip install lhapdf-management
mkdir -p "$LHAPDF_DATA_PATH"
lhapdf-management update --init
lhapdf-management install "${{ inputs.pdfset }}"
52 changes: 8 additions & 44 deletions .github/workflows/acceptancetest_mg7.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,55 +30,19 @@ concurrency:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# Build the madspace wheel exactly once per workflow run. The wheel is cached
# with a content-addressed key (hash of the madspace sources), so it is only
# rebuilt when madspace actually changes and is never shared between differing
# builds. Every test job below depends on this job (needs: build_madspace) and
# installs the cached wheel via the install_madspace action instead of
# recompiling the C++/CUDA extension itself.
# Build the madspace install exactly once per workflow run. It is cached with a
# content-addressed key (hash of the madspace sources), so it is only rebuilt
# when madspace actually changes and is never shared between differing builds.
# Every test job below depends on this job (needs: build_madspace) and restores
# the cached install via the install_madspace action instead of recompiling the
# C++/CUDA extension itself. The build logic lives in the build_madspace
# composite action so it stays in sync with check_xsec_processes_mg7.yml.
build_madspace:
runs-on: ubuntu-24.04
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == true
steps:
- uses: actions/checkout@v4

- name: madspace cache key
run: echo "MS_PY=$(python3 -c 'import sys;print(f"{sys.version_info.major}{sys.version_info.minor}")')" >> $GITHUB_ENV
shell: bash

# Cache the installed madspace/install prefix directly (not just a wheel),
# so every test job restores a ready-to-use install and skips pip entirely.
# hashFiles is evaluated before the build step creates madspace/install, so
# the key is the clean-source hash and matches the install_madspace action.
- name: Cache madspace install
id: cache-madspace
uses: actions/cache@v5
with:
path: madspace/install
key: madspace-${{ runner.os }}-py${{ env.MS_PY }}-${{ hashFiles('madspace/**') }}

# Built from the in-tree source (scikit-build-core / cmake). Upgrade pip +
# packaging first: the runner ships an ancient pip whose build isolation
# does not provide packaging>=22, which scikit-build-core's vendored
# pyproject_metadata requires.
#
# ENABLE_OPENBLAS=ON builds OpenBLAS from source and links it statically
# into the extension (see madspace/CMakeLists.txt), so the cached install
# is self-contained and needs no system libopenblas at runtime. This avoids
# a dynamic dependency that would otherwise only be satisfied on cache miss
# (when apt installed libopenblas-dev) and missing on cache hit.
#
# --target installs into madspace/install, the prefix the mg7 runtime and
# madspace/install.py expect.
- name: Build and install madspace (only on cache miss)
if: steps.cache-madspace.outputs.cache-hit != 'true'
run: |
cd $GITHUB_WORKSPACE
python3 -m pip install --upgrade pip packaging
python3 -m pip install ./madspace \
-Ccmake.define.ENABLE_OPENBLAS=ON \
--target="$GITHUB_WORKSPACE/madspace/install"
shell: bash
- uses: ./.github/actions/build_madspace

acceptancetest_mg7_ufo_aloha:
needs: build_madspace
Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/check_xsec_processes_mg7.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: systematic cross-section tests (mg7)

# Regression test that MadGraph7 reproduces the reference cross-sections
# recorded in tests/acceptance_tests/check_xsec_processes_reference.json.
#
# The tests live in the test_manager.py framework
# (tests/acceptance_tests/test_check_xsec_processes_mg7.py): one
# unittest.TestCase with a test_<section>_<id>_mg7 method per process. This
# workflow launches them through test_manager.py, one job per section, so the
# exact same tests can also be run locally, e.g.
# ./tests/test_manager.py test_ttx_decay_.*_mg7 -pA -t0
#
# For every process the framework generates it, runs the mg7 (madspace)
# integrator with the run_card.toml defaults (fixed scale mu = 91.188 GeV,
# e_cm = 13000 GeV, NNPDF23_lo_as_0130_qed) and compares the resulting
# cross-section to the reference. A run passes only if the relative difference
# stays below `tolerance` for every process in the section.

on:
push:
paths-ignore:
- 'docs/**'
# - '.github/**'

pull_request:
types: [opened, synchronize, reopened]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
message:
description: 'running cross section check test'
required: true
tolerance:
description: 'Max allowed relative difference (e.g. 0.01 = 1%)'
required: false
default: '0.01'
events:
description: 'Events per process (reference used 1M; reduced here for CI)'
required: false
default: '100000'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# Read by tests/acceptance_tests/test_check_xsec_processes_mg7.py. The
# `|| 'default'` fallback covers push/PR triggers where inputs are absent.
MG7_XSEC_TOLERANCE: ${{ inputs.tolerance || '0.01' }}
MG7_XSEC_EVENTS: ${{ inputs.events || '100000' }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

jobs:
# Build madspace once (content-addressed cache), shared by every section job.
# The build logic lives in the build_madspace composite action so it stays in
# sync with acceptancetest_mg7.yml.
build_madspace:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build_madspace

check_xsec_processes:
needs: build_madspace
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
# Each job runs every process in the selected section and fails if any
# process exceeds the tolerance.
section: [3jets, ttx1j, ttx2j, ttx_decay, dy1j, dy2j]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/checkout_mg5
- uses: ./.github/actions/install_madspace
- uses: ./.github/actions/restore-pip-cache
# Provides the NNPDF23 grid + LHAPDF_DATA_PATH the mg7 runtime needs.
- uses: ./.github/actions/install_lhapdf_pdfset
- name: run systematic cross-section test (${{ matrix.section }})
run: |
cd $GITHUB_WORKSPACE
./tests/test_manager.py "test_${{ matrix.section }}_.*_mg7" -pA -t0 -l INFO
58 changes: 58 additions & 0 deletions tests/acceptance_tests/check_xsec_processes_reference.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"_comment": "Reference cross-sections (pb) for systematic MG7 testing. Source of truth: #28. Reference runs used fixed scale (mu = 91.188 GeV, the run_card.toml default), e_cm = 13000 GeV, NNPDF23_lo_as_0130_qed, 1M events.",
"defines": [],
"sections": {
"3jets": [
{"id": "ppjjj", "process": "p p > j j j", "cross": 4.639e+07, "error": 1.323e+04},
{"id": "ggggg", "process": "g g > g g g", "cross": 2.439e+07, "error": 7044},
{"id": "gg_g_q_qbar", "process": "g g > g _quark _anti_quark", "cross": 2.143e+06, "error": 849.2},
{"id": "gq_ggq", "process": "g _quark > g g _quark", "cross": 6.264e+06, "error": 1676},
{"id": "gq_qqqbar", "process": "g _quark > _quark _quark _anti_quark", "cross": 2.589e+05, "error": 91.76},
{"id": "gqbar_ggqbar", "process": "g _anti_quark > g g _anti_quark", "cross": 2.197e+06, "error": 639.1},
{"id": "gqbar_qqbarqbar", "process": "g _anti_quark > _quark _anti_quark _anti_quark", "cross": 9.63e+04, "error": 34.19},
{"id": "qq_gqq", "process": "_quark _quark > g _quark _quark", "cross": 1.047e+06, "error": 273.6},
{"id": "qqbar_ggg", "process": "_quark _anti_quark > g g g", "cross": 5944, "error": 2.437},
{"id": "qqbar_gqqbar", "process": "_quark _anti_quark > g _quark _anti_quark", "cross": 5.26e+05, "error": 142.7},
{"id": "qbarqbar_gqbarqbar","process": "_anti_quark _anti_quark > g _anti_quark _anti_quark","cross": 1.916e+05, "error": 59.33}
],
"ttx1j": [
{"id": "pp_ttxj", "process": "p p > t t~ j", "cross": 994, "error": 0.276},
{"id": "gg_ttxg", "process": "g g > t t~ g", "cross": 723.5, "error": 0.2165},
{"id": "gq_ttxq", "process": "g _quark > t t~ _quark", "cross": 98.74, "error": 0.02542},
{"id": "gqbar_ttxqbar","process": "g _anti_quark > t t~ _anti_quark","cross": 20.06, "error": 0.004919},
{"id": "qqbar_ttxg", "process": "_quark _anti_quark > t t~ g", "cross": 17.04, "error": 0.00451}
],
"ttx2j": [
{"id": "pp_ttxjj", "process": "p p > t t~ j j", "cross": 906.4, "error": 0.2643},
{"id": "gg_ttxgg", "process": "g g > t t~ g g", "cross": 546, "error": 0.1632},
{"id": "gg_ttxqqbar", "process": "g g > t t~ _quark _anti_quark", "cross": 17.92, "error": 0.005483},
{"id": "gq_ttxgq", "process": "g _quark > t t~ g _quark", "cross": 130.9, "error": 0.03545},
{"id": "gqbar_ttxgqbar", "process": "g _anti_quark > t t~ g _anti_quark", "cross": 22.1, "error": 0.006179},
{"id": "qq_ttxqq", "process": "_quark _quark > t t~ _quark _quark", "cross": 15.37, "error": 0.004464},
{"id": "qqbar_ttxgg", "process": "_quark _anti_quark > t t~ g g", "cross": 5.944, "error": 0.002005},
{"id": "qqbar_ttxqqbar", "process": "_quark _anti_quark > t t~ _quark _anti_quark", "cross": 3.595, "error": 0.001049},
{"id": "qbarqbar_ttxqbarqbar", "process": "_anti_quark _anti_quark > t t~ _anti_quark _anti_quark", "cross": 0.5119, "error": 0.0001495}
],
"ttx_decay": [
{"id": "pp_had", "process": "p p > t t~, ( t > W+ b, W+ > j j), ( t~ > W- b~, W- > j j)", "cross": 291.7, "error": 0.06962, "disable_jet_cuts": true},
{"id": "gg_had", "process": "g g > t t~, ( t > W+ b, W+ > _quark _anti_quark), ( t~ > W- b~, W- > _quark _anti_quark)", "cross": 257.7, "error": 0.05345, "disable_jet_cuts": true},
{"id": "qqbar_had", "process": "_quark _anti_quark > t t~, ( t > W+ b, W+ > _quark _anti_quark), ( t~ > W- b~, W- > _quark _anti_quark)", "cross": 16.98, "error": 0.002692, "disable_jet_cuts": true}
],
"dy1j": [
{"id": "pp_eej", "process": "p p > e+ e- j", "cross": 257.5, "error": 0.08979},
{"id": "gq_eeq", "process": "g _quark > e+ e- _quark", "cross": 58.97, "error": 0.02517},
{"id": "gqbar_eeqbar","process": "g _anti_quark > e+ e- _anti_quark","cross": 37.47, "error": 0.01296},
{"id": "qqbar_eeg", "process": "_quark _anti_quark > e+ e- g", "cross": 32.35, "error": 0.009621}
],
"dy2j": [
{"id": "pp_eejj", "process": "p p > e+ e- j j", "cross": 116.1, "error": 0.0377},
{"id": "gg_eeqqbar", "process": "g g > e+ e- _quark _anti_quark", "cross": 8.62, "error": 0.003529},
{"id": "gq_eegq", "process": "g _quark > e+ e- g _quark", "cross": 27.32, "error": 0.008703},
{"id": "gqbar_eegqbar", "process": "g _anti_quark > e+ e- g _anti_quark", "cross": 13.64, "error": 0.004341},
{"id": "qq_eeqq", "process": "_quark _quark > e+ e- _quark _quark", "cross": 7.566, "error": 0.001927},
{"id": "qqbar_eegg", "process": "_quark _anti_quark > e+ e- g g", "cross": 3.95, "error": 0.001233},
{"id": "qqbar_eeqqbar", "process": "_quark _anti_quark > e+ e- _quark _anti_quark", "cross": 4.407, "error": 0.001189},
{"id": "qbarqbar_eeqbarqbar", "process": "_anti_quark _anti_quark > e+ e- _anti_quark _anti_quark", "cross": 1.467, "error": 0.0004163}
]
}
}
Loading
Loading