diff --git a/.github/actions/install_lhapdf_pdfset/action.yml b/.github/actions/install_lhapdf_pdfset/action.yml index a0aafe0a6c..06455d7b87 100644 --- a/.github/actions/install_lhapdf_pdfset/action.yml +++ b/.github/actions/install_lhapdf_pdfset/action.yml @@ -2,7 +2,7 @@ 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//_0000.dat), so it + (mg7/launch.py: ms.PdfGrid on $LHAPDF_DATA_PATH//_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. @@ -11,6 +11,11 @@ inputs: pdfset: description: Name of the LHAPDF set to install required: false + # NNPDF23_lo_as_0130_qed on purpose: this action's only consumer is + # check_xsec_processes_mg7.yml, whose ~40 reference cross-sections are + # pinned to that set (_REFERENCE_PDF, written into every run_card.toml). + # It is deliberately NOT the mg7 run_card default, which is now + # NNPDF40MC_lo_as_01180 and comes from the heptools cache. default: NNPDF23_lo_as_0130_qed runs: diff --git a/.github/actions/restore_heptools_lhapdf/action.yml b/.github/actions/restore_heptools_lhapdf/action.yml index 6dac678e13..4748184386 100644 --- a/.github/actions/restore_heptools_lhapdf/action.yml +++ b/.github/actions/restore_heptools_lhapdf/action.yml @@ -38,4 +38,23 @@ runs: if: ${{ env.CACHE_KEY == 'lhapdf-ubuntu24' }} run: | echo "PYTHONPATH=$PYTHONPATH:/home/runner/.cache/HEPtools/lhapdf6_py3/lib/python3.12/dist-packages" >> $GITHUB_ENV - shell: bash + shell: bash + + # The mg7 run_card.toml default PDF (NNPDF40MC_lo_as_01180). warm_cache.yml + # bakes it into the lhapdf cache, but that cache is only rebuilt when + # warm_cache runs with a reset, so a branch that changes the default would + # otherwise face a cache that predates it: the mg7 tests guard on the set + # being present and would all self-skip (test_manager.py counts a skip as a + # failure). Fetching it here costs ~0.7 MB and is a no-op once the cache + # carries it. Non-fatal on failure: the tests skip as they did before. + - name: ensure the mg7 default PDF set is present + run: | + DATADIR=/home/runner/.cache/HEPtools/lhapdf6_py3/share/LHAPDF + SET=NNPDF40MC_lo_as_01180 + if [ -d "$DATADIR" ] && [ ! -d "$DATADIR/$SET" ]; then + ( cd "$DATADIR" \ + && wget -q https://lhapdfsets.web.cern.ch/current/$SET.tar.gz \ + && tar -xzpf $SET.tar.gz \ + && rm -f $SET.tar.gz ) || echo "::warning::could not fetch $SET" + fi + shell: bash diff --git a/.github/workflows/acceptancetest.yml b/.github/workflows/acceptancetest.yml index 27a1c818ae..081f0284f8 100644 --- a/.github/workflows/acceptancetest.yml +++ b/.github/workflows/acceptancetest.yml @@ -307,7 +307,7 @@ jobs: run: | cd $GITHUB_WORKSPACE ./tests/test_manager.py test_standalone_cpp_output_consistency -pA -t0 -l INFO - ./tests/test_manager.py test_standalone_mg7_vs_cpp -pA -t0 -l INFO + ./tests/test_manager.py test_madmatrix_vs_fortran -pA -t0 -l INFO @@ -389,7 +389,7 @@ jobs: # cd $GITHUB_WORKSPACE # echo "install lhapdf6" > cmd # echo "install pythia8" >> cmd -# ./bin/mg5_aMC cmd +# ./bin/madgraph cmd # # # Runs a set of commands using the runners shell @@ -635,7 +635,7 @@ jobs: run: | cd $GITHUB_WORKSPACE echo "set acknowledged_v3.1_syntax True --global" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd ./tests/test_manager.py test_amcatnlo_from_file -pA -t0 -l INFO diff --git a/.github/workflows/acceptancetest_madevent.yml b/.github/workflows/acceptancetest_madevent.yml index d173796936..bd3ae593c2 100644 --- a/.github/workflows/acceptancetest_madevent.yml +++ b/.github/workflows/acceptancetest_madevent.yml @@ -461,7 +461,7 @@ jobs: cd $GITHUB_WORKSPACE cp input/.mg5_configuration_default.txt input/mg5_configuration.txt echo "install RunningCoupling" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd ./tests/test_manager.py test_eft_running -pA -t0 -l INFO @@ -985,7 +985,7 @@ jobs: acceptancetest_mssm_gogo: # Fortran madevent supports MSSM p p > go go (merged-flavor squark/gluino # vertices); the mg7/madmatrix counterpart now also supports it and is - # checked per-flavor (test_standalone_mg7_mssm_gogo in acceptancetest_mg7.yml). + # checked per-flavor (test_madmatrix_mssm_gogo in acceptancetest_mg7.yml). runs-on: ubuntu-24.04 if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == true steps: diff --git a/.github/workflows/acceptancetest_mg7.yml b/.github/workflows/acceptancetest_mg7.yml index c854def997..b6dcef7f8d 100644 --- a/.github/workflows/acceptancetest_mg7.yml +++ b/.github/workflows/acceptancetest_mg7.yml @@ -73,7 +73,7 @@ jobs: - name: test FD gauge madmatrix vs fortran run: | cd $GITHUB_WORKSPACE - ./tests/test_manager.py test_standalone_mg7_fd_vs_fortran test_standalone_mg7_fd_simd_lanes -pA -t0 -l INFO + ./tests/test_manager.py test_madmatrix_fd_vs_fortran test_madmatrix_fd_simd_lanes -pA -t0 -l INFO acceptancetest_mg7_output_directory: needs: build_madspace @@ -136,8 +136,8 @@ jobs: acceptancetest_mg7_madspin_mixed_flavor: needs: build_madspace # mg7 + MadSpin density-summary check driven through the madevent-style - # launch command interface. restore_heptools provides LHAPDF/NNPDF23 for the - # u u~ > z g generation. + # launch command interface. restore_heptools provides LHAPDF and the mg7 + # default PDF set for the u u~ > z g generation. runs-on: ubuntu-24.04 if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == true steps: @@ -201,7 +201,7 @@ jobs: acceptancetest_mg7_group_subprocess: needs: build_madspace # mg7 cross-section run (u u > u u). madspace is installed by checkout_mg5; - # LHAPDF (incl. NNPDF23_lo_as_0130_qed) comes from the heptools cache. + # LHAPDF (incl. NNPDF40MC_lo_as_01180) comes from the heptools cache. # The test self-skips if that stack is unavailable. runs-on: ubuntu-24.04 if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == true @@ -307,8 +307,9 @@ jobs: acceptancetest_mg7_mssm_gogo: # mg7/madmatrix now generates the MSSM merged-flavor squark/gluino vertices - # (single-merged-leg / event-by-event flavored couplings); standalone_mg7 - # reproduces the Fortran standalone per-flavor |M|^2 (~1e-4). This is a + # (single-merged-leg / event-by-event flavored couplings); `output + # standalone` reproduces the standalone_fortran per-flavor |M|^2 (~1e-4). + # This is a # matrix-element (standalone) check only -- full mg7 event generation for # merged-flavor processes is not wired up yet (see test_madevent_merged_ # flavor_uq_mg7). The madevent counterpart is test_madevent_mssm_gogo in @@ -320,15 +321,15 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/checkout_mg5 - uses: ./.github/actions/restore-pip-cache - - name: test one of the test test_standalone_mg7_mssm_gogo + - name: test one of the test test_madmatrix_mssm_gogo run: | cd $GITHUB_WORKSPACE - ./tests/test_manager.py test_standalone_mg7_mssm_gogo -pA -t0 -l INFO + ./tests/test_manager.py test_madmatrix_mssm_gogo -pA -t0 -l INFO acceptancetest_mg7_mssm_gogo_xsec: # Pins the mg7 (madspace) cross-section for MSSM p p > go go to the madevent # reference (5.024 pb, run_01 of test_generation_from_file_1), on top of the - # per-flavor |M|^2 check in test_standalone_mg7_mssm_gogo. This job used to + # per-flavor |M|^2 check in test_madmatrix_mssm_gogo. This job used to # be red at random rather than for a physics reason: the 1% assertion sat # below the ~1.1% statistical error of a 2000-event run, so it failed on # roughly 40% of runs. _run_mg7_xsec now runs 50000 events (error ~0.08%). diff --git a/.github/workflows/aloha.yml b/.github/workflows/aloha.yml index b19b5c1be6..58a9276b15 100644 --- a/.github/workflows/aloha.yml +++ b/.github/workflows/aloha.yml @@ -47,7 +47,7 @@ jobs: run: | cd $GITHUB_WORKSPACE echo "import model MSSM_SLHA2" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd ./tests/test_manager.py -pP -t0 test_aloha.* -e test_short_mssm_subset_creation test_excluded: diff --git a/.github/workflows/warm_cache.yml b/.github/workflows/warm_cache.yml index 08241d0385..20161157d8 100644 --- a/.github/workflows/warm_cache.yml +++ b/.github/workflows/warm_cache.yml @@ -107,7 +107,7 @@ jobs: mkdir -p /home/runner/.cache/UFOMODEL echo "PYTHONPATH=$PYTHONPATH:$HOME/.cache/UFOMODEL" >> $GITHUB_ENV echo "import model 2HDM" >> cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd - name: move UFO model to cache if: steps.cache-ufo.outputs.cache-hit != 'true' @@ -146,7 +146,7 @@ jobs: echo "heptools_install_dir=/home/runner/.cache/HEPtools" >> input/mg5_configuration.txt cp Template/LO/Source/.make_opts Template/LO/Source/make_opts echo "install lhapdf6" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd - name: get pdf set for NLO if: steps.cache-lhapdf.outputs.cache-hit != 'true' @@ -157,6 +157,10 @@ jobs: wget https://lhapdfsets.web.cern.ch/lhapdfsets/current/cteq6l1.tar.gz tar -xzpvf cteq6l1.tar.gz # LO set used by the mg7 run_card.toml default (madspace integration) + wget https://lhapdfsets.web.cern.ch/current/NNPDF40MC_lo_as_01180.tar.gz + tar -xzpvf NNPDF40MC_lo_as_01180.tar.gz + # previous mg7 default; still pinned by the mg7 cross-section + # reference tests (tests/acceptance_tests/test_check_xsec_processes_mg7.py) wget https://lhapdfsets.web.cern.ch/current/NNPDF23_lo_as_0130_qed.tar.gz tar -xzpvf NNPDF23_lo_as_0130_qed.tar.gz @@ -201,12 +205,12 @@ jobs: echo "heptools_install_dir=/home/runner/.cache/HEPtools" >> input/mg5_configuration.txt cp Template/LO/Source/.make_opts Template/LO/Source/make_opts echo "install pythia8" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd - name: Verify pythia8 landed in the cache if: steps.cache-pythia8.outputs.cache-hit != 'true' run: | - # mg5_aMC exits 0 even when "install pythia8" fails (e.g. a network + # madgraph exits 0 even when "install pythia8" fails (e.g. a network # timeout while downloading hepmc/pythia8 from the download server), # so guard the cache here. Without Pythia.h, MG5 nullifies # pythia8_path at startup, leaving the parton shower unavailable and @@ -251,7 +255,7 @@ jobs: echo "heptools_install_dir=/home/runner/.cache/HEPtools" >> input/mg5_configuration.txt cp Template/LO/Source/.make_opts Template/LO/Source/make_opts echo "install eMELA" > cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd # delete_lhapdf_cache: # runs-on: ${{ matrix.os }} @@ -309,7 +313,7 @@ jobs: # YODA's python extension build needs Cython (no longer shipped by # default on the GitHub runner image); without it rivet aborts at # YODA, before FastJet is installed, leaving NLO builds broken. - # Install into the same interpreter mg5_aMC/YODA use (no sudo, so + # Install into the same interpreter madgraph/YODA use (no sudo, so # the system Python is left untouched for other steps). python3 -m pip install Cython mkdir -p /home/runner/.cache/HEPtools @@ -318,12 +322,12 @@ jobs: cp Template/LO/Source/.make_opts Template/LO/Source/make_opts echo "install rivet" > cmd echo "install contur" >> cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd - name: Verify rivet/fastjet landed in the cache if: steps.cache-contur.outputs.cache-hit != 'true' run: | - # mg5_aMC exits 0 even when "install rivet" fails, so guard the + # madgraph exits 0 even when "install rivet" fails, so guard the # cache here: a missing fastjet-config means NLO subprocesses cannot # compile (fastjet/ClusterSequence.hh). Fail loudly instead of # saving an incomplete heptools cache. @@ -385,7 +389,7 @@ jobs: cp Template/LO/Source/.make_opts Template/LO/Source/make_opts echo "install collier " > cmd echo "install ninja " >> cmd - ./bin/mg5_aMC cmd + ./bin/madgraph cmd heptools_cache: if: always() && (github.ref_name == 'main' || github.ref_name == 'test_ci' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') diff --git a/INSTALL b/INSTALL index 1294ef7ed0..d6192fe3fe 100644 --- a/INSTALL +++ b/INSTALL @@ -24,7 +24,7 @@ Dependencies : * MadGraph5_aMC@NLO * -- Python 3.7 (or higher) +- Python 3.12 (or higher) * MadEvent * Package for the LO cross-section computation and generation of events @@ -48,7 +48,7 @@ On Windows: In order to run MG5 you need to 1) add the Python directory to the PATH -2) run $> python ./bin/mg5_aMC +2) run $> python ./bin/madgraph Note that most of the output (including madevent/aMCatNLO) are not compatible with Windows. We do recomend to use unix subsystem. diff --git a/MadSpin/decay.py b/MadSpin/decay.py index ca9ab1edc0..299879bae1 100755 --- a/MadSpin/decay.py +++ b/MadSpin/decay.py @@ -5127,7 +5127,7 @@ def generate_all_matrix_element(self): # remove decay with 0 branching ratio. #mgcmd.remove_pointless_decay(self.banner.param_card) # - commandline = 'output standalone %s --prefix=int' % pjoin(path_me, ms_me_subdir) + commandline = 'output standalone_fortran %s --prefix=int' % pjoin(path_me, ms_me_subdir) logger.info(commandline) mgcmd.exec_cmd(commandline, precmd=True) logger.info('Done %.4g' % (time.time()-start)) diff --git a/MadSpin/madspin b/MadSpin/madspin index 088fca86b0..0c04f25c9d 100755 --- a/MadSpin/madspin +++ b/MadSpin/madspin @@ -19,8 +19,8 @@ and call immediately the command line interface scripts""" from __future__ import absolute_import import sys -if sys.version_info < (3, 7): - sys.exit('MadSpin works only with python 3.7 (or later).\n\ +if sys.version_info < (3, 12): + sys.exit('MadSpin works only with python 3.12 (or later).\n\ Please upgrade your version of python.') import os diff --git a/Template/LO/Cards/proc_card_mg5.dat b/Template/LO/Cards/proc_card_mg5.dat index 5a2158341f..975cc6fc9a 100644 --- a/Template/LO/Cards/proc_card_mg5.dat +++ b/Template/LO/Cards/proc_card_mg5.dat @@ -17,7 +17,7 @@ #* * #* Command File for MadGraph5_aMC@NLO * #* * -#* run as ./bin/mg5_aMC filename * +#* run as ./bin/madgraph filename * #* * #************************************************************ import model sm diff --git a/Template/LO/bin/generate_events b/Template/LO/bin/generate_events index 5577cc66a0..93189287ed 100755 --- a/Template/LO/bin/generate_events +++ b/Template/LO/bin/generate_events @@ -27,8 +27,8 @@ import time root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] pjoin = os.path.join -if sys.version_info < (3, 7): - sys.exit('MadEvent works with python 3.7 or higher.\n\ +if sys.version_info < (3, 12): + sys.exit('MadEvent works with python 3.12 or higher.\n\ Please upgrade your version of python.') try: diff --git a/Template/LO/bin/internal/Gridpack/gridrun b/Template/LO/bin/internal/Gridpack/gridrun index 01d4ab53f5..dfff0766c4 100755 --- a/Template/LO/bin/internal/Gridpack/gridrun +++ b/Template/LO/bin/internal/Gridpack/gridrun @@ -20,8 +20,8 @@ and call immediately the command line interface scripts""" from __future__ import absolute_import import sys -if sys.version_info < (3, 7): - sys.exit('MadGraph/MadEvent 5 works only with python 3.7 or later.\n\ +if sys.version_info < (3, 12): + sys.exit('MadGraph/MadEvent 5 works only with python 3.12 or later.\n\ Please upgrate your version of python.') try: diff --git a/Template/LO/bin/madevent b/Template/LO/bin/madevent index 6d5d59c8c2..fd4ffd6a75 100755 --- a/Template/LO/bin/madevent +++ b/Template/LO/bin/madevent @@ -19,8 +19,8 @@ and call immediately the command line interface scripts""" import sys -if sys.version_info < (3, 7): - sys.exit('MadGraph/MadEvent 5 works only with python 3.7 or later.\n\ +if sys.version_info < (3, 12): + sys.exit('MadGraph/MadEvent 5 works only with python 3.12 or later.\n\ Please upgrate your version of python.') try: diff --git a/Template/LO/bin/newprocess_mg5 b/Template/LO/bin/newprocess_mg5 deleted file mode 100755 index dba4767861..0000000000 --- a/Template/LO/bin/newprocess_mg5 +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bash -# -# First get to main level directory for this process -# - -if [[ ! -d ./bin || ! -d ./SubProcesses ]]; then - cd ../ - if [[ ! -d ./bin || ! -d ./SubProcesses ]]; then - echo "Error: newprocess_mg5 must be executed from the main, or bin directory" - exit - fi -fi -echo -e "\033[1;31m WARNING This out-dated method of using MG5 will be remove in version 2.0\033[0m" -echo -e "\033[1;31m A proc_card example is present in the main directory of MG5 \033[0m" -echo -e "\033[1;31m you can run it like ./bin/mg5 proc_card.dat \033[0m" - -if [[ -e SubProcesses/subproc.mg ]]; then - echo "Error: newprocess_mg5 can only be used in a clean copy of Template." - echo " This directory already contains a generated process, please" - echo " open the index.html file to see information about the process." - echo "If you want to generate events from this process directory, run" - echo " bin/generate_events" - echo "or" - echo " bin/madevent" - echo "and type \"help\" to get started." - exit -fi - -# Check that mg5 exists -main=`pwd` -mgdir=$main/../bin -if [[ ! -x $mgdir/mg5 ]]; then - mgdir=$main/../madgraph5/bin -fi -if [[ ! -x $mgdir/mg5 ]]; then - echo "Error no mg5 executable $mgdir/mg5 found" - exit -fi - - -dirbin=$main/bin/internal -bin=$main/bin - -# Local versions to work on the cluster -tag='' -while [[ "$1" != "" ]]; do - if [[ "$1" == "--web" ]]; then - mgdir=$MADGRAPH_BASE/MG_ME/mg5 - dirbin=$MADGRAPH_BASE/MG_ME/WebBin - bin =$MADGRAPH_BASE/MG_ME/WebBin - tag="--web" - fi - shift 1 -done - -# some external executable -gen_card=$dirbin/gen_cardhtml-pl -gen_info=$dirbin/gen_infohtml-pl - -# Check if we have to use MG4 proc_card.dat or MG5 proc_card.dat -if [[ -e ./Cards/proc_card_mg5.dat ]]; then - if [[ -e ./Cards/proc_card.dat ]]; then - if [[ $tag != '--web' ]]; then - echo "both mg4 and mg5 proc_card.dat are detected. Which one do you want to use? [4/5]" - read card_use - else - card_use='5' - fi - else - card_use='5' - fi -elif [[ -e ./Cards/proc_card.dat ]]; then - card_use='4' -else - echo "neither proc_card.dat or proc_card_mg5.dat" - echo "are present in directory Cards" - echo "Prepare a card (see examples on the web) and" - echo "copy it there, or run directly ../bin/mg5_aMC." - exit -fi - -echo $$ > generating -rm proc_log.txt >& /dev/null -echo "Started `date`" > ./proc_log.txt -echo "Running..." - -cp -p HTML/thinking.gif HTML/card.jpg -rm SubProcesses/done >& /dev/null - -$gen_card >& /dev/null - -# launch the mg5 program -if [[ $card_use == '4' ]]; then -# Run ./mg5 with stderr going to both the file proc_log.txt and to terminal -# output. See http://acs.lbl.gov/~ksb/Scratch/sh_redir_pipe.html - ((echo import proc_v4 ./Cards/proc_card.dat | $mgdir/mg5 3>&1 1>&2 2>&3) | tee /dev/tty) >> proc_log.txt 2>&1 -elif [[ $card_use == '5' ]]; then -# Run ./mg5 with stderr going to both the file proc_log.txt and to terminal -# output. See http://acs.lbl.gov/~ksb/Scratch/sh_redir_pipe.html - (($mgdir/mg5 ./Cards/proc_card_mg5.dat 3>&1 1>&2 2>&3) | tee /dev/tty) >> proc_log.txt 2>&1 -else - echo 'not recognized mode' -fi - -echo "Finished `date` " >> ./proc_log.txt -echo "`date` " >& ./CREATED -cd SubProcesses -touch done -cd .. - -if [[ $tag == "--web" ]]; then - touch Online -fi -rm generating -echo 'done' - -# Check that generation worked -if [[ ! -e SubProcesses/subproc.mg ]]; then - - cp -p HTML/stop.jpg HTML/card.jpg - echo "No diagrams for this process!" -fi - -$gen_card >& /dev/null diff --git a/Template/NLO/bin/aMCatNLO b/Template/NLO/bin/aMCatNLO index 3ba4da5765..2b7cefaedd 100755 --- a/Template/NLO/bin/aMCatNLO +++ b/Template/NLO/bin/aMCatNLO @@ -19,8 +19,8 @@ and call immediately the command line interface scripts""" import sys -if sys.version_info < (3, 7): - sys.exit('MadGraph/aMCatNLO 5 works only with python 3.7 or later .\n\ +if sys.version_info < (3, 12): + sys.exit('MadGraph/aMCatNLO 5 works only with python 3.12 or later .\n\ Please upgrate your version of python.') try: diff --git a/Template/NLO/bin/calculate_xsect b/Template/NLO/bin/calculate_xsect index 04188b0110..cdf30c2294 100755 --- a/Template/NLO/bin/calculate_xsect +++ b/Template/NLO/bin/calculate_xsect @@ -28,8 +28,8 @@ pjoin = os.path.join sys.path.append(pjoin(root_path,'bin','internal')) import amcatnlo_run_interface as run -if sys.version_info < (3, 7): - sys.exit('MadEvent works with python 3.7 or higher.\n\ +if sys.version_info < (3, 12): + sys.exit('MadEvent works with python 3.12 or higher.\n\ Please upgrade your version of python.') try: diff --git a/Template/NLO/bin/generate_events b/Template/NLO/bin/generate_events index ecf13bc537..262938fd0a 100755 --- a/Template/NLO/bin/generate_events +++ b/Template/NLO/bin/generate_events @@ -28,8 +28,8 @@ pjoin = os.path.join sys.path.append(pjoin(root_path,'bin','internal')) import amcatnlo_run_interface as run -if sys.version_info < (3, 7): - sys.exit('MadEvent works with python 3.7 or higher.\n\ +if sys.version_info < (3, 12): + sys.exit('MadEvent works with python 3.12 or higher.\n\ Please upgrade your version of python.') try: diff --git a/Template/NLO/bin/shower b/Template/NLO/bin/shower index c77f56ac0c..8d2d564da7 100755 --- a/Template/NLO/bin/shower +++ b/Template/NLO/bin/shower @@ -28,8 +28,8 @@ pjoin = os.path.join sys.path.append(pjoin(root_path,'bin','internal')) import amcatnlo_run_interface as run -if sys.version_info < (3, 7): - sys.exit('MadEvent works with python 3.7 and higher.\n\ +if sys.version_info < (3, 12): + sys.exit('MadEvent works with python 3.12 and higher.\n\ Please upgrade your version of python.') try: diff --git a/aloha/aloha_lib.py b/aloha/aloha_lib.py index cc6b7ba4fd..1fe72eba99 100755 --- a/aloha/aloha_lib.py +++ b/aloha/aloha_lib.py @@ -1061,11 +1061,16 @@ def __str__(self): return '%s' % self.name class FactoryLorentz(FactoryVar): - """ A symbolic Object for All Helas object. All Helas Object Should + """ A symbolic Object for All Helas object. All Helas Object Should derivated from this class""" - + mult_class = MultLorentz # The class for the multiplication object_class = LorentzObject # Define How to create the basic object. + # True when the arguments of the structure commute, so that writing them in + # any order denotes the same object (Metric(1,2) == Metric(2,1)). Consumers + # use it to tell a mere reordering apart from a real difference; see + # models.import_ufo.canonicalize_lorentz_structure. + is_symmetric = False def __new__(cls, *args): name = cls.get_unique_name(*args) diff --git a/aloha/aloha_object.py b/aloha/aloha_object.py index bed31d991d..dba10eedd5 100755 --- a/aloha/aloha_object.py +++ b/aloha/aloha_object.py @@ -1013,9 +1013,12 @@ def create_representation(self): self.lorentz_ind,self.spin_ind) class Metric(aloha_lib.FactoryLorentz): - + object_class = L_Metric - + # g^{mu nu} is symmetric by definition -- which is why get_unique_name + # below sorts its two indices. + is_symmetric = True + @classmethod def get_unique_name(cls,l1,l2): diff --git a/bin/create_release.py b/bin/create_release.py index 8f5f70ca59..88278f1b41 100755 --- a/bin/create_release.py +++ b/bin/create_release.py @@ -131,8 +131,8 @@ def get_first_contributions(repo_path): import sys -if sys.version_info < (3, 7): - sys.exit('MadGraph5_aMC@NLO works only with python 3.7 or later.\n\ +if sys.version_info < (3, 12): + sys.exit('MadGraph5_aMC@NLO works only with python 3.12 or later.\n\ Please upgrate your version of python.') import glob @@ -351,7 +351,7 @@ def get_first_contributions(repo_path): pass shutil.rmtree(path.join(filepath, '.git')) for data in glob.glob(path.join(filepath, 'bin', '*')): - if not data.endswith('mg5') and not data.endswith('mg5_aMC'): + if not data.endswith('mg5') and not data.endswith('madgraph'): if 'compile.py' not in data: os.remove(data) else: diff --git a/bin/mg5_aMC b/bin/madgraph similarity index 90% rename from bin/mg5_aMC rename to bin/madgraph index b424fee513..a9b3777b85 100755 --- a/bin/mg5_aMC +++ b/bin/madgraph @@ -24,11 +24,9 @@ and call immediately the command line interface scripts""" import sys import logging import logging.config -if sys.version_info < (3, 7): - sys.exit('MadGraph5_aMC@NLO works with python 3.7 or higher.\n\ +if sys.version_info < (3, 12): + sys.exit('MadGraph5_aMC@NLO works with python 3.12 or higher.\n\ Please upgrade your version of python.') -if sys.version_info[1] < 10: - logging.warning("\033[91mSupport for Python3.9 (and below) has been dropped since end of 2025. Please consider update your version of Python. Continue at your own risk \033[0m") import os @@ -114,8 +112,18 @@ else: else: state_dir = os.getenv('XDG_STATE_HOME', os.path.join(os.environ['HOME'], '.local', 'state')) - history_file = os.path.join(state_dir, "mg5history") - readline.read_history_file(history_file) + # MG7 keeps its own history file. An MG5_aMC install writes mg5history + # into this same shared state directory, so sharing the name would + # interleave the two command sets. Read mg5history as a one-time + # fallback so an existing MG5 user does not start from an empty + # history; writes always go to mg7history. + history_file = os.path.join(state_dir, "mg7history") + if os.path.exists(history_file): + readline.read_history_file(history_file) + else: + legacy_history_file = os.path.join(state_dir, "mg5history") + if os.path.exists(legacy_history_file): + readline.read_history_file(legacy_history_file) except: pass @@ -187,7 +195,7 @@ else: try: if options.file or args: if sys.platform == "darwin" and options.nosleep: - logging.getLogger('madgraph').warning("launching caffeinate to prevent idle sleep when MG5aMC is running. Run './bin/mg5_aMC -s' to prevent this.") + logging.getLogger('madgraph').warning("launching caffeinate to prevent idle sleep when MG5aMC is running. Run './bin/madgraph -s' to prevent this.") pid = os.getpid() subprocess.Popen(['caffeinate', '-i', '-w', str(pid)]) # They are an input file diff --git a/docs/gluon-quartic-plan.md b/docs/gluon-quartic-plan.md index fe59dcdd64..a0d387a542 100644 --- a/docs/gluon-quartic-plan.md +++ b/docs/gluon-quartic-plan.md @@ -399,7 +399,7 @@ bottleneck. The madevent run is unchanged, same cross section and error. Everything below is `g g > N g` with the flag off against `speed`, on the same machine. Standalone Fortran is the shipped `check` driver looping -`SMATRIX`; madmatrix is `check_sa.exe perf` built `FPTYPE=d` on `cppsse4` +`SMATRIX`; madmatrix is `check_sa.exe perf` built `FPTYPE=d` on `cpu_128b` (the default mixed precision build rounds the two to the same value and would hide any difference). Two runs each, reproducible to about 0.1%. @@ -826,7 +826,7 @@ so `auto` defers the choice to `output`. It works only because the two modes differ in nothing but the diagram order, and `slots` is `speed` reversed -- verified byte for byte: generating in the `speed` order and reversing at output time reproduces a native `slots` generation exactly, in both backends, -and a session going standalone -> standalone_mg7 -> standalone reproduces its +and a session going standalone_fortran -> standalone -> standalone_fortran reproduces its first output for the third. **The choice comes from the matrix element exporter, not the output format.** diff --git a/docs/standalone_flavor_python.md b/docs/standalone_flavor_python.md index 0c83258c5e..7f50931a43 100644 --- a/docs/standalone_flavor_python.md +++ b/docs/standalone_flavor_python.md @@ -14,9 +14,9 @@ physical flavor combinations. Every standalone entry point therefore takes a ## 1. Generate the standalone output ``` -mg5_aMC +madgraph > generate p p > j j QCD=0 -> output standalone /path/to/MYPROC --prefix=int +> output standalone_fortran /path/to/MYPROC --prefix=int ``` This writes one subprocess directory per group, e.g. @@ -134,7 +134,7 @@ name-mangling/prefix. active), instead of a timing table: ``` -mg5_aMC +madgraph > launch /path/to/MYPROC --timings=21 --nb_run=0 ``` diff --git a/input/.mg5_configuration_default.txt b/input/.mg5_configuration_default.txt index a07569cac1..3f4ceb88c1 100644 --- a/input/.mg5_configuration_default.txt +++ b/input/.mg5_configuration_default.txt @@ -19,7 +19,7 @@ # Line starting with # should be uncommented if you want to modify the default # value. # Current value for all options can seen by typing "display options" -# after either ./bin/mg5_aMC or ./bin/madevent +# after either ./bin/madgraph or ./bin/madevent # # You can place this files in ~/.mg5/mg5_configuration.txt if you have more than # one version of MG5. diff --git a/madgraph/core/drawing.py b/madgraph/core/drawing.py index 31c7f8ed77..b1dfd678c1 100755 --- a/madgraph/core/drawing.py +++ b/madgraph/core/drawing.py @@ -48,6 +48,25 @@ import madgraph.core.base_objects as base_objects import madgraph.loop.loop_base_objects as loop_objects import madgraph.various.misc as misc + +#=============================================================================== +# Display labels for the merged-flavor particles +#=============================================================================== +# The merged-flavor particles created by Model.define_merge_particle_for carry +# internal model names ('_quark', '_anti_quark', '_lepton', ...). Those names +# are what the user types on the interface (multiparticle definitions, process +# generation) and what model['name2pdg'] resolves, so they must NOT be renamed. +# In a *drawn* diagram those underscore-prefixed names are however unreadable, +# so the labels below are substituted at drawing time only. +# The sign convention follows the model: the merged '_lepton' is built from the +# electron (PDG 11, charge -1), hence the particle is 'L-' and its antiparticle +# 'L+'. The generic '_merged%d' particles (PDG 90+n) have no canonical short +# label -- their content depends on which PDGs were merged -- so they keep +# their model name. +MERGED_PARTICLE_DRAW_NAME = {81: 'Q', -81: 'Qx', + 82: 'L-', -82: 'L+', + 83: 'v', -83: 'vx'} + #=============================================================================== # FeynmanLine #=============================================================================== @@ -198,7 +217,12 @@ def get_name(self, name='name',add_pol=True): name += '_pol' return name - + # merged-flavor particles are drawn with a short readable label + # (the model name '_quark', ... stays untouched: the interface needs it) + # ('name' already means 'antiname' for a negative pid, see below) + if name == 'name' and pid in MERGED_PARTICLE_DRAW_NAME: + return MERGED_PARTICLE_DRAW_NAME[pid] + if pid > 0: return model_info.get(name) elif model_info: diff --git a/madgraph/core/helas_objects.py b/madgraph/core/helas_objects.py index b936482823..9b4742332c 100755 --- a/madgraph/core/helas_objects.py +++ b/madgraph/core/helas_objects.py @@ -1680,7 +1680,6 @@ def get_coupling_for_flavor(self, model, tag_name='flavortag'): return None pdg_out = self.get('pdg_code') - misc.sprint(pdg_out, self[tag_name], [p.get_pdg_code() for p in vertex.get('particles')]) if abs(pdg_out) in model.get('merged_particles'): pdg_vertex = [p.get_pdg_code() for p in vertex.get('particles')] index_merge, merge_pdg = [(i,pdg) for i, pdg in enumerate(pdg_vertex) if abs(pdg) in model.get('merged_particles')][0] diff --git a/madgraph/interface/amcatnlo_interface.py b/madgraph/interface/amcatnlo_interface.py index f2c6e2b8d8..f1c27ad719 100755 --- a/madgraph/interface/amcatnlo_interface.py +++ b/madgraph/interface/amcatnlo_interface.py @@ -145,7 +145,14 @@ def check_output(self, args): else: self._export_format = 'NLO' - forbidden_formats = ['madevent', 'standalone'] + # Elsewhere `standalone` names the MadMatrix (C++/CUDA) export. Here it + # is accepted as an alias for `standalone_fortran`, so that it is + # reported as a forbidden *format* below rather than being silently + # taken as the output path. + if args and args[0] == 'standalone': + args[0] = 'standalone_fortran' + + forbidden_formats = ['madevent', 'standalone_fortran'] if not hasattr(self, '_fks_multi_proc') or not self._fks_multi_proc: diff --git a/madgraph/interface/amcatnlo_run_interface.py b/madgraph/interface/amcatnlo_run_interface.py index ab2688abbd..cdea2099e9 100755 --- a/madgraph/interface/amcatnlo_run_interface.py +++ b/madgraph/interface/amcatnlo_run_interface.py @@ -6094,8 +6094,8 @@ class aMCatNLOCmdShell(aMCatNLOCmd, cmd.CmdShell): # This can ONLY run a single command !! import sys - if sys.version_info < (3, 7): - sys.exit('MadGraph5_aMc@NLO works only with python 3.7 and later.\n'+\ + if sys.version_info < (3, 12): + sys.exit('MadGraph5_aMc@NLO works only with python 3.12 and later.\n'+\ 'Please upgrade your version of python or specify a compatible version.') import os diff --git a/madgraph/interface/loop_interface.py b/madgraph/interface/loop_interface.py index f3e53c7a5d..33d78d1ac6 100755 --- a/madgraph/interface/loop_interface.py +++ b/madgraph/interface/loop_interface.py @@ -90,10 +90,19 @@ def check_add(self, args): mg_interface.MadGraphCmd.check_add(self,args) - def check_output(self, args, default='standalone'): + def check_output(self, args, default='standalone_fortran'): """ Check the arguments of the output command in the context of the Loop interface.""" - + + # Elsewhere `standalone` names the MadMatrix (C++/CUDA) export, which + # MadLoop does not support. Here it is accepted as an alias for + # `standalone_fortran`, the MadLoop standalone output, so that + # `output standalone` keeps working in the ML5 interface. Without this + # the generic check_output would not recognise it as a format and would + # silently use it as the output *path*. + if args and args[0] == 'standalone': + args[0] = 'standalone_fortran' + mg_interface.MadGraphCmd.check_output(self,args, default=default) if self._export_format not in self.supported_ML_format: @@ -389,7 +398,7 @@ def validate_model(self, loop_type='virtual',coupling_type=['QCD'], stop=True): class LoopInterface(CheckLoop, CompleteLoop, HelpLoop, CommonLoopInterface): - supported_ML_format = ['standalone', 'standalone_rw', 'matchbox'] + supported_ML_format = ['standalone_fortran', 'standalone_rw', 'matchbox'] def __init__(self, mgme_dir = '', *completekey, **stdin): """ Special init tasks for the Loop Interface """ @@ -412,7 +421,7 @@ def setup(self): self._curr_amps = diagram_generation.AmplitudeList() self._curr_matrix_elements = helas_objects.HelasMultiProcess() self._v4_export_formats = [] - self._export_formats = [ 'matrix', 'standalone' ] + self._export_formats = [ 'matrix', 'standalone_fortran' ] self._nlo_modes_for_completion = ['virt'] self.validate_model() # Set where to look for CutTools installation. @@ -502,11 +511,11 @@ def do_output(self, line): noclean, output_type=output_type, group_subprocesses=False, cmd_options=line_options) - if self._export_format in ['standalone', 'matchbox']: + if self._export_format in ['standalone_fortran', 'matchbox']: self._curr_exporter.copy_template(self._curr_model) if self._export_format == "standalone_rw": - self._export_format = "standalone" + self._export_format = "standalone_fortran" self._curr_exporter.copy_template(self._curr_model) self._export_format = "standalone_rw" diff --git a/madgraph/interface/madevent_interface.py b/madgraph/interface/madevent_interface.py index b28e345532..a2c88efb22 100755 --- a/madgraph/interface/madevent_interface.py +++ b/madgraph/interface/madevent_interface.py @@ -7933,8 +7933,8 @@ def wait_monitoring(Idle, Running, Done): # Launch the interface without any check if one code is already running. # This can ONLY run a single command !! import sys - if sys.version_info < (3, 7): - sys.exit('MadGraph/MadEvent 5 works only with python 3.7 or later).\n'+\ + if sys.version_info < (3, 12): + sys.exit('MadGraph/MadEvent 5 works only with python 3.12 or later).\n'+\ 'Please upgrate your version of python.') import os diff --git a/madgraph/interface/madgraph_interface.py b/madgraph/interface/madgraph_interface.py index e7cd08fcf0..39991da5d5 100755 --- a/madgraph/interface/madgraph_interface.py +++ b/madgraph/interface/madgraph_interface.py @@ -501,10 +501,10 @@ def help_output(self): logger.info(" it is set by default.") logger.info(" - If mode is madevent, create a MadEvent process directory.") logger.info(" - If mode is standalone, create a Standalone directory") + logger.info(" using the MadMatrix (C++/CUDA) matrix elements.") + logger.info(" - If mode is standalone_fortran, create a Fortran Standalone directory") logger.info(" - If mode is matrix, output the matrix.f files for all") logger.info(" generated processes in directory \"path\".") - logger.info(" - If mode is standalone_cpp, create a standalone C++") - logger.info(" directory in \"path\".") logger.info(" - If mode is pythia8, output all files needed to generate") logger.info(" the processes using Pythia 8. The files are written in") logger.info(" the Pythia 8 directory (default).") @@ -524,14 +524,14 @@ def help_output(self): logger.info(" -nojpeg: no jpeg diagrams will be generated.") logger.info(" --noeps=True: no jpeg and eps diagrams will be generated.") logger.info(" -name: the postfix of the main file in pythia8 mode.") - logger.info(" --jamp_optim=[True|False]: [madevent(default:True)|standalone(default:False)] allows a more efficient code computing the color-factor.") + logger.info(" --jamp_optim=[True|False]: [madevent(default:True)|standalone_fortran(default:False)] allows a more efficient code computing the color-factor.") logger.info(" --t_strategy: [madevent] allows to change ordering strategy for t-channel.") logger.info(" --hel_recycling=False: [madevent] forbids helicity recycling optimization") - logger.info(" --mask=False: [madevent|standalone] disable flavor-mask optimization for grouped/merged flavors (default:True).") - logger.info(" --prefix=int|proc: [standalone] prefix matrix-element routine names (int: M_, proc: process name); generates f2py python-linkable routines.") + logger.info(" --mask=False: [madevent|standalone_fortran] disable flavor-mask optimization for grouped/merged flavors (default:True).") + logger.info(" --prefix=int|proc: [standalone_fortran] prefix matrix-element routine names (int: M_, proc: process name); generates f2py python-linkable routines.") logger.info(" Examples:",'$MG:color:GREEN') logger.info(" output",'$MG:color:GREEN') - logger.info(" output standalone MYRUN -f",'$MG:color:GREEN') + logger.info(" output standalone_fortran MYRUN -f",'$MG:color:GREEN') logger.info(" output pythia8 ../pythia8/ -name qcdprocs",'$MG:color:GREEN') def help_check(self): @@ -1450,6 +1450,13 @@ def check_launch(self, args, options): elif self._done_export[1].startswith(mode): args.append(self._done_export[1]) args.append(self._done_export[0]) + elif mode == 'standalone_fortran' and self._done_export[1] in \ + ('standalone_msP', 'standalone_msF', 'standalone_rw'): + # find_output_type cannot tell the Fortran standalone + # variants apart on disk: they all report + # 'standalone_fortran'. Accept the recorded format. + args.append(self._done_export[1]) + args.append(self._done_export[0]) else: raise self.InvalidCmd('%s not valid directory for launch' % self._done_export[0]) return @@ -1519,7 +1526,7 @@ def find_import_type(self, path): def find_output_type(self, path): """ identify the type of output of a given directory: - valid output: madevent/standalone/standalone_cpp""" + valid output: madevent/standalone/standalone_fortran/mg7/...""" card_path = pjoin(path,'Cards') bin_path = pjoin(path,'bin') @@ -1536,19 +1543,26 @@ def find_output_type(self, path): if os.path.isfile(pjoin(bin_path,'madevent')): return 'madevent' elif os.path.isfile(pjoin(subproc_path, 'madmatrix_standalone.mk')): - # standalone_mg7 writes SubProcesses/madmatrix_standalone.mk - # (the regular mg7 export only writes madmatrix.mk). - return 'standalone_mg7' + # the `standalone` (madmatrix) export writes + # SubProcesses/madmatrix_standalone.mk (the regular mg7 export only + # writes madmatrix.mk, so testing for that would match it too). + return 'standalone' elif os.path.isfile(pjoin(card_path, 'run_card.toml')): return 'mg7' elif os.path.isdir(src_path): - return 'standalone_cpp' + # Catch-all for the C++-family standalone trees, i.e. anything + # written by a ProcessExporterCPP descendant that ships a src/ + # directory and is not one of the more specific cases above -- + # today that is `matchbox_cpp` and `mg7_v5`. This is not a + # user-facing `output` format name; it only has to start with + # 'standalone' so that do_launch routes it to the SALauncher. + return 'standalone_cpp_family' elif os.path.isdir(mw_path): return 'madweight' elif os.path.isfile(pjoin(bin_path,'aMCatNLO')): return 'aMC@NLO' elif os.path.isdir(card_path): - return 'standalone' + return 'standalone_fortran' raise self.InvalidCmd('%s : Not a valid directory' % path) @@ -1772,6 +1786,12 @@ def check_output(self, args, default='mg7'): if args and args[0] == 'pythia8': raise self.InvalidCmd('output pythia8 is no longer supported; please use a different output mode') + if args and args[0] == 'standalone_cpp': + raise self.InvalidCmd('output standalone_cpp is no longer supported; ' + 'use \'standalone\' for the MadMatrix (C++/CUDA) ' + 'standalone or \'standalone_fortran\' for the ' + 'Fortran one') + if args and args[0] in self._export_formats: self._export_format = args.pop(0) elif args: @@ -1820,8 +1840,8 @@ def check_output(self, args, default='mg7'): raise self.InvalidCmd('%s is not allowed in the output path' % char) # Check for special directory treatment if path == 'auto' and self._export_format in \ - ['madevent', 'standalone', 'standalone_cpp', 'matchbox_cpp', - 'matchbox', 'plugin', 'me7', 'mg7', 'mg7_v5', 'standalone_mg7']: + ['madevent', 'standalone_fortran', 'matchbox_cpp', + 'matchbox', 'plugin', 'me7', 'mg7', 'mg7_v5', 'standalone']: self.get_default_path() if '-noclean' not in args and os.path.exists(self._export_dir): args.append('-noclean') @@ -1944,7 +1964,7 @@ def check_compute_widths(self, args): def get_default_path(self): """Set self._export_dir to the default (\'auto\') path""" - if self._export_format in ['madevent', 'standalone']: + if self._export_format in ['madevent', 'standalone_fortran']: # Detect if this script is launched from a valid copy of the Template, # if so store this position as standard output directory if 'TemplateVersion.txt' in os.listdir('.'): @@ -1971,7 +1991,11 @@ def get_default_path(self): auto_path = lambda i: pjoin(self.writing_dir, name_dir(i)) elif self._export_format in ['mg7', 'mg7_v5']: - name_dir = lambda i: 'PROCMG7_%s_%s' % \ + # mg7 is the default output format, so it takes the plain PROC_ + # prefix. This deliberately shares a namespace with madevent + # below: auto_path() picks the first free index, so the two never + # collide on disk, they just interleave. + name_dir = lambda i: 'PROC_%s_%s' % \ (self._curr_model['name'], i) auto_path = lambda i: pjoin(self.writing_dir, name_dir(i)) @@ -1981,21 +2005,13 @@ def get_default_path(self): auto_path = lambda i: pjoin(self.writing_dir, name_dir(i)) elif self._export_format.startswith('standalone'): - if self._export_format == 'standalone_cpp': - name_dir = lambda i: 'PROC_SA_CPP_%s_%s' % \ - (self._curr_model['name'], i) - auto_path = lambda i: pjoin(self.writing_dir, - name_dir(i)) - elif self._export_format == 'standalone_mg7': - name_dir = lambda i: 'PROCMG7_SA_%s_%s' % \ - (self._curr_model['name'], i) - auto_path = lambda i: pjoin(self.writing_dir, - name_dir(i)) - else: - name_dir = lambda i: 'PROC_SA_%s_%s' % \ - (self._curr_model['name'], i) - auto_path = lambda i: pjoin(self.writing_dir, - name_dir(i)) + # The madmatrix standalone is the default standalone, so it takes + # the plain PROC_SA_ prefix and shares the auto-name namespace with + # the Fortran standalone (and its msP/msF/rw variants). + name_dir = lambda i: 'PROC_SA_%s_%s' % \ + (self._curr_model['name'], i) + auto_path = lambda i: pjoin(self.writing_dir, + name_dir(i)) elif self._export_format in ['matchbox_cpp', 'matchbox']: name_dir = lambda i: 'PROC_MATCHBOX_%s_%s' % \ (self._curr_model['name'], i) @@ -2602,8 +2618,12 @@ def complete_launch(self, text, line, begidx, endidx,formatting=True): mode = self.find_launch_mode(args) - if mode and mode.startswith('standalone') and mode != 'standalone_mg7': - # standalone outputs are run through SALauncher/MadLoopLauncher: + if mode and mode.startswith('standalone') and mode != 'standalone': + # NB: `mode != 'standalone'` deliberately EXCLUDES the plain + # `standalone` (madmatrix) output, which is launched through its own + # bin/generate_events, not through SALauncher. It is not a typo: + # every *other* standalone_* mode (standalone_fortran, _cpp, _msP, + # _msF, _rw) is run through SALauncher/MadLoopLauncher, for which # only force + the timing analysis options are relevant. opt = ['-f', '--force', '--timings=', '--nb_run='] out['Options'] = self.list_completion(text, opt, line) @@ -2723,7 +2743,7 @@ def complete_output(self, text, line, begidx, endidx, return self.aloha_complete_output(text, line, begidx, endidx) except Exception as error: print(error) - if 'standalone' in args: + if 'standalone_fortran' in args: possible_options_full = list(possible_options_full) + ['--prefix=int', '--prefix=proc', '--density='] # Directory continuation @@ -3140,11 +3160,11 @@ class MadGraphCmd(HelpToCmd, CheckValidForCmd, CompleteForCmd, CmdExtended): _install_opts.extend(_advanced_install_opts) - _v4_export_formats = ['madevent', 'standalone', 'standalone_msP','standalone_msF', + _v4_export_formats = ['madevent', 'standalone_fortran', 'standalone_msP','standalone_msF', 'matrix', 'standalone_rw'] - _export_formats = _v4_export_formats + ['standalone_cpp', 'aloha', + _export_formats = _v4_export_formats + ['aloha', 'matchbox_cpp', 'matchbox', 'mg7_v5', 'mg7', - 'standalone_mg7'] + 'standalone'] _set_options = ['group_subprocesses', 'ignore_six_quark_processes', 'stdout_level', @@ -3341,9 +3361,9 @@ def setup(self): self._curr_proc_defs = base_objects.ProcessDefinitionList() self._curr_matrix_elements = helas_objects.HelasMultiProcess() - self._v4_export_formats = ['madevent', 'standalone','standalone_msP','standalone_msF', + self._v4_export_formats = ['madevent', 'standalone_fortran','standalone_msP','standalone_msF', 'matrix', 'standalone_rw'] - self._export_formats = self._v4_export_formats + ['standalone_cpp', 'mg7_v5', 'mg7', 'standalone_mg7'] + self._export_formats = self._v4_export_formats + ['mg7_v5', 'mg7', 'standalone'] self._nlo_modes_for_completion = ['all','virt','real'] def do_quit(self, line): @@ -6677,7 +6697,7 @@ def advanced_install(self, tool_to_install, logger.warning('Default installation of Madanalys5 failed.') logger.warning("MG5aMC will now attempt to reinstall it with the options '--no_MA5_further_install --no_root_in_MA5'.") logger.warning("This will however limit MA5 applicability for hadron-level analysis.") - logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/mg5_aMC --debug'.") + logger.warning("If you would like to prevent MG5aMC to re-attempt MA5 installation, start MG5aMC with './bin/madgraph --debug'.") for option in ['--no_MA5_further_install', '--no_root_in_MA5', '--force']: if option not in add_options: add_options.append(option) @@ -7182,7 +7202,7 @@ def do_install(self, line, paths=None, additional_options=[]): import os import sys root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] -exe_path = os.path.join(root_path,'bin','mg5_aMC') +exe_path = os.path.join(root_path,'bin','madgraph') sys.argv.pop(0) os.system('%s -tt %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) '''.format(name,'' if pyvers == 2 else pyvers) @@ -7191,7 +7211,7 @@ def do_install(self, line, paths=None, additional_options=[]): import os import sys root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] -exe_path = os.path.join(root_path,'bin','mg5_aMC') +exe_path = os.path.join(root_path,'bin','madgraph') sys.argv.pop(0) os.system('%s -O -W ignore::DeprecationWarning %s %s --mode={0}' %(sys.executable, str(exe_path) , ' '.join(sys.argv) )) '''.format(name,'' if pyvers == 2 else pyvers) @@ -7926,7 +7946,7 @@ def do_launch(self, line): options = options.__dict__ # args is now MODE PATH - if args[0] == 'standalone_mg7': + if args[0] == 'standalone': class ext_program: @staticmethod def run(): @@ -9619,7 +9639,7 @@ def do_open(self, line): # Output formats whose matrix elements can run on a gpu, where the # wavefunction store is per thread. See set2_merge_quartic_vertices. - _gpu_me_formats = ['mg7', 'mg7_v5', 'standalone_mg7'] + _gpu_me_formats = ['mg7', 'mg7_v5', 'standalone'] # Diagram order currently materialised in _curr_amps, and the diagrams as # they came out of the generation. Both only used for 'auto'. _quartic_order = None @@ -9772,17 +9792,16 @@ def do_output(self, line): config = {} config['madevent'] = {'check': True, 'exporter': 'v4', 'output':'Template'} config['matrix'] = {'check': False, 'exporter': 'v4', 'output':'dir'} - config['standalone'] = {'check': True, 'exporter': 'v4', 'output':'Template'} + config['standalone_fortran'] = {'check': True, 'exporter': 'v4', 'output':'Template'} config['standalone_msF'] = {'check': False, 'exporter': 'v4', 'output':'Template'} config['standalone_msP'] = {'check': False, 'exporter': 'v4', 'output':'Template'} config['standalone_rw'] = {'check': False, 'exporter': 'v4', 'output':'Template'} - config['standalone_cpp'] = {'check': False, 'exporter': 'cpp', 'output': 'Template'} config['pythia8'] = {'check': False, 'exporter': 'cpp', 'output':'dir'} config['matchbox_cpp'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} config['matchbox'] = {'check': True, 'exporter': 'v4', 'output': 'Template'} config['mg7_v5'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} config['mg7'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} - config['standalone_mg7'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} + config['standalone'] = {'check': True, 'exporter': 'cpp', 'output': 'Template'} if self._export_format == 'plugin': options = {'check': self._export_plugin.check, 'exporter':self._export_plugin.exporter, 'output':self._export_plugin.output} @@ -10374,7 +10393,7 @@ def finalize(self, nojpeg, online = False, flaglist=[]): # into its final citations.bib. self.write_generation_citations() - if self._export_format in ['madevent', 'standalone', 'standalone_cpp', 'matchbox', 'mg7']: + if self._export_format in ['madevent', 'standalone_fortran', 'matchbox', 'mg7']: logger.info('Output to directory ' + self._export_dir + ' done.') if self._export_format in ['madevent', 'NLO']: @@ -10389,8 +10408,8 @@ def write_generation_citations(self): routines. Writes citations.log (machine-readable, collected by every run) plus a ready-to-use citations.bib and a citations.md summary. """ - runnable = ['madevent', 'standalone', 'standalone_cpp', 'NLO', - 'madweight', 'matchbox', 'mg7', 'mg7_v5', 'standalone_mg7'] + runnable = ['madevent', 'standalone_fortran', 'NLO', + 'madweight', 'matchbox', 'mg7', 'mg7_v5', 'standalone'] if self._export_format not in runnable or not self._export_dir: return try: @@ -10416,13 +10435,13 @@ def write_generation_citations(self): polarization=getattr(self, '_uses_polarization', False), taudecay=getattr(self, '_uses_taudecay', False)) - # MadSpace + MadNIS: used by the mg7 / standalone_mg7 integration engine - if self._export_format in ('mg7', 'mg7_v5', 'standalone_mg7'): + # MadSpace + MadNIS: used by the mg7 / standalone integration engine + if self._export_format in ('mg7', 'mg7_v5', 'standalone'): pairs += [('Heimel:2026hgp', 'phase-space integration with MadSpace'), ('Heimel:2023ngj', 'normalising flows for integration (MadNIS)')] - if self._export_format == 'standalone_mg7': + if self._export_format == 'standalone': pairs.append(('Hagebock:2025jyk', 'data-parallel matrix-element evaluation (MadMatrix)')) @@ -10963,7 +10982,7 @@ class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd): help="forbid to display the generate file and only generate the eps file") # LAUNCH PROGRAM _launch_usage = "launch [DIRPATH] [options]\n" + \ - "-- execute the madevent/standalone/standalone_cpp/pythia8/NLO output present in DIRPATH\n" + \ + "-- execute the madevent/standalone/standalone_fortran/pythia8/NLO output present in DIRPATH\n" + \ " By default DIRPATH is the latest created directory \n" + \ " (for pythia8, it should be the Pythia 8 main directory) \n" + \ " Example: launch PROC_sm_1 --name=run2 \n" + \ @@ -10987,9 +11006,9 @@ class MadGraphCmdWeb(CheckValidForCmdWeb, MadGraphCmd): _launch_parser.add_option("-M", "--madspin", default=False, action='store_true', help="Run the madspin package") _launch_parser.add_option("", "--timings", default=0, type='int', - help="[standalone] Number of SMATRIX calls per flavor per run for timing analysis (0=disabled)") + help="[standalone_fortran] Number of SMATRIX calls per flavor per run for timing analysis (0=disabled)") _launch_parser.add_option("", "--nb_run", default=1, type='int', - help="[standalone] Number of timing repetitions for statistics (used with --timings); 0 = good-helicity check (print matrix-element values instead of a timing table)") + help="[standalone_fortran] Number of timing repetitions for statistics (used with --timings); 0 = good-helicity check (print matrix-element values instead of a timing table)") #=============================================================================== # Interface for customize question. diff --git a/madgraph/interface/master_interface.py b/madgraph/interface/master_interface.py index 8e956efac5..1a0f505814 100755 --- a/madgraph/interface/master_interface.py +++ b/madgraph/interface/master_interface.py @@ -504,7 +504,8 @@ def do_launch(self, line, *argss, **opts): # if there is a path, find what output has been done if path: type = self.cmd.find_output_type(self, path) - if type in ['standalone', 'standalone_cpp', 'pythia8', 'madevent']: + if type in ['standalone_fortran', 'standalone_cpp_family', + 'pythia8', 'madevent']: self.change_principal_cmd('MadGraph') elif type == 'aMC@NLO': self.change_principal_cmd('aMC@NLO') diff --git a/madgraph/interface/tutorial_text.py b/madgraph/interface/tutorial_text.py index f12e7f4846..76841e51da 100755 --- a/madgraph/interface/tutorial_text.py +++ b/madgraph/interface/tutorial_text.py @@ -176,7 +176,7 @@ execute the commands in it, you can do: MG5_aMC>import command my_mg5_cmd.dat or from the shell: -./bin/mg5_aMC my_mg5_cmd.dat +./bin/madgraph my_mg5_cmd.dat It is also possible to display this file directly from MG5_aMC: MG5_aMC>open ./my_mg5_cmd.dat diff --git a/madgraph/iolibs/export_cpp.py b/madgraph/iolibs/export_cpp.py index 1b83b6f670..9cc700aecb 100755 --- a/madgraph/iolibs/export_cpp.py +++ b/madgraph/iolibs/export_cpp.py @@ -102,7 +102,6 @@ class UFOModelConverterCPP(object): def __init__(self, model, output_path, wanted_lorentz = [], wanted_couplings = [], replace_dict={}): """ initialization of the objects """ - misc.sprint('Exporting model to C++ standalone format') self.model = model self.model_name = ProcessExporterCPP.get_model_name(model['name']) @@ -217,7 +216,6 @@ def prepare_couplings(self, wanted_couplings = []): # Handle flavor couplings # strategy picke one of the actual coupling and check if this is a running one or not flavor_couplings = [c for c in wanted_couplings if isinstance(c, base_objects.FLV_Coupling)] - misc.sprint(self.coups_dep) deps = [c.name for c in self.coups_dep.values()] for one_flv in flavor_couplings: one_coupling = one_flv.get_one_coupling() @@ -349,7 +347,6 @@ def write_parameters(self, params): # For each parameter type, write out the definition string # type parameters; - misc.sprint(type_param_dict) res_strings = [] for key in type_param_dict: res_strings.append("%s %s;" % (self.type_dict[key], @@ -379,7 +376,7 @@ def write_set_parameters(self, params): def _assert_flv_couplings_supported(self, params): """Refuse, with a clear and actionable message, the merged-flavor - coupling structures the C++ (mg7/standalone_mg7) backend cannot yet + coupling structures the C++ (mg7/standalone) backend cannot yet generate correctly, instead of crashing or emitting wrong/uncompilable code. @@ -396,7 +393,7 @@ def _assert_flv_couplings_supported(self, params): * a vertex with more than two merged-flavor legs (never seen so far). - The Fortran 'madevent'/'standalone' output supports the remaining cases. + The Fortran 'madevent'/'standalone_fortran' output supports the remaining cases. See docs/mg7_merged_flavor_mssm_design.md. """ for coupl in params: @@ -405,10 +402,10 @@ def _assert_flv_couplings_supported(self, params): if nb_merged in (1, 2): continue raise InvalidCmd( - "merged-flavor C++ output (mg7/standalone_mg7) does not yet " + "merged-flavor C++ output (mg7/standalone) does not yet " "support this process: flavor coupling %s connects %d " "merged-flavor legs; only one or two are supported. Use " - "'output madevent' or 'output standalone' for this process. " + "'output madevent' or 'output standalone_fortran' for this process. " "See docs/mg7_merged_flavor_mssm_design.md for details." % (coupl.name, nb_merged)) @@ -3187,13 +3184,6 @@ class ProcessExporterMG7(ProcessExporterCPP): from_template = {'src': [s+'read_slha.h', s+'read_slha.cc', s+'mg7/api.h'], 'SubProcesses': [s+'mg7/api.cpp'], 'Cards': []} - #from_template_simd = [ - # s+"mg7/api.h", - # s+"mg7/simd/api_simd.cpp", - # s+"mg7/simd/cudacpp.mk", - # s+"mg7/simd/Makefile", - #] - #to_link_simd = ["api.h", "api_simd.cpp", "cudacpp.mk", "Makefile"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -3257,7 +3247,7 @@ def copy_template(self, model): "#! /usr/bin/env python3\n" "import sys, os\n" f"sys.path.append('{MG5DIR}')\n" - "from madgraph.iolibs.template_files.mg7.madevent import main\n" + "from madgraph.iolibs.template_files.mg7.launch import main\n" "if __name__ == '__main__':\n" " os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))\n" " try:\n" @@ -3562,8 +3552,6 @@ def ExportCPPFactory(cmd, group_subprocesses=False, cmd_options={}): if cformat == 'pythia8': return ProcessExporterPythia8(cmd._export_dir, opt) - elif cformat == 'standalone_cpp': - return ProcessExporterCPP(cmd._export_dir, opt) elif cformat == 'matchbox_cpp': return ProcessExporterMatchbox(cmd._export_dir, opt) elif cformat == 'mg7_v5': @@ -3571,7 +3559,7 @@ def ExportCPPFactory(cmd, group_subprocesses=False, cmd_options={}): elif cformat == 'mg7': from madmatrix.output import ProcessExporterMadMatrix return ProcessExporterMadMatrix(cmd._export_dir, opt) - elif cformat == 'standalone_mg7': + elif cformat == 'standalone': from madmatrix.output import ProcessExporterMadMatrixStandalone return ProcessExporterMadMatrixStandalone(cmd._export_dir, opt) else: diff --git a/madgraph/iolibs/export_v4.py b/madgraph/iolibs/export_v4.py index 459e43a1d0..d740f81693 100755 --- a/madgraph/iolibs/export_v4.py +++ b/madgraph/iolibs/export_v4.py @@ -3393,7 +3393,7 @@ def __init__(self, *args,**opts): self.format = opts['format'] del opts['format'] else: - self.format = 'standalone' + self.format = 'standalone_fortran' self.prefix_info = {} ProcessExporterFortran.__init__(self, *args, **opts) @@ -3948,7 +3948,7 @@ def color_dim_from_particle(p): fsock.close() #important to put that first - if self.format == 'standalone': + if self.format == 'standalone_fortran': filename2 = pjoin(dirpath, 'check_sa.f') self.write_check_sa(writers.FortranWriter(filename2), matrix_element, proc_prefix) @@ -4022,7 +4022,7 @@ def color_dim_from_particle(p): plot.draw() linkfiles = ['check_sa.f', 'coupl.inc'] - if self.format == 'standalone': + if self.format == 'standalone_fortran': linkfiles = ['coupl.inc'] @@ -4432,7 +4432,7 @@ def write_matrix_element_v4(self, writer, matrix_element, fortran_model, #=========================================================================== def write_check_sa(self, writer, matrix_element, proc_prefix=''): - if self.format != 'standalone': + if self.format != 'standalone_fortran': return # Density-mode defaults (overridden if 'density' is in cmd_options). @@ -8699,7 +8699,7 @@ def copy_standard_file(self): text = open(path).read() text = text.replace('madevent','aMCatNLO').replace('../vector.inc', '') open(path, 'w').writelines(text) - elif self.opt['export_format'] in ['standalone', 'standalone_msP','standalone_msF', + elif self.opt['export_format'] in ['standalone_fortran', 'standalone_msP','standalone_msF', 'madloop','madloop_optimized', 'standalone_rw', 'madweight','matchbox','madloop_matchbox', 'plugin']: cp( MG5DIR + '/models/template_files/fortran/makefile_standalone', @@ -11651,6 +11651,11 @@ def ExportV4Factory(cmd, noclean, output_type='default', group_subprocesses=True if format in ['madevent']: opt['madanalysis5'] = cmd.options['madanalysis5_path'] + # Every standalone_* format that reaches the *v4* factory is + # Fortran-family (standalone_fortran, standalone_msP/msF/rw). The plain + # `standalone` (MadMatrix) is declared with exporter 'cpp' in + # MadGraphCmd.do_output and goes to ExportCPPFactory instead, so it + # never gets here despite matching the prefix. if format == 'matrix' or format.startswith('standalone'): return ProcessExporterFortranSA(cmd._export_dir, opt, format=format) diff --git a/madgraph/iolibs/group_subprocs.py b/madgraph/iolibs/group_subprocs.py index 335dd9ada6..7fd3b8bb78 100755 --- a/madgraph/iolibs/group_subprocs.py +++ b/madgraph/iolibs/group_subprocs.py @@ -776,7 +776,11 @@ def group_amplitudes(decay_chain_amps, criteria='madevent', matrix_elements_opts assert isinstance(decay_chain_amps, diagram_generation.DecayChainAmplitudeList), \ "Argument to group_amplitudes must be DecayChainAmplitudeList" - if criteria in ['matrix', 'standalone','pythia8','standalone_cpp', False]: + # `criteria` is an exporter's grouped_mode, not an output format name: + # the only values ever passed are False, 'madevent' and 'madweight' + # ('gpu' is mapped to 'madevent' by the caller). Normalise the falsy + # case the same way SubProcessGroup.group_amplitudes does. + if not criteria: criteria = 'madevent' assert criteria in ['madevent', 'madweight'] diff --git a/madgraph/iolibs/template_files/madmatrix/cudacpp_overlay.mk b/madgraph/iolibs/template_files/madmatrix/cudacpp_overlay.mk index d54b2a03a5..4ef75c82c2 100644 --- a/madgraph/iolibs/template_files/madmatrix/cudacpp_overlay.mk +++ b/madgraph/iolibs/template_files/madmatrix/cudacpp_overlay.mk @@ -211,12 +211,12 @@ madevent_hip_link: ln -s $(CUDACPP_BUILDDIR)/$(PROG)_hip $(PROG) madevent_cpp_link: - $(MAKE) USEGTEST=0 BACKEND=cppauto $(CUDACPP_BUILDDIR)/$(PROG)_cpp + $(MAKE) USEGTEST=0 BACKEND=cpu $(CUDACPP_BUILDDIR)/$(PROG)_cpp rm -f $(PROG) ln -s $(CUDACPP_BUILDDIR)/$(PROG)_cpp $(PROG) # Variant AVX builds for cpp backend -override SUPPORTED_AVXS := cppnone cppsse4 cppavx2 cpp512y cpp512z cppauto +override SUPPORTED_AVXS := cpu_scalar cpu_128b cpu_256b cpu_512b_y cpu_512b cpu madevent_%_link: @if [ '$(words $(filter $*, $(SUPPORTED_AVXS)))' != '1' ]; then \ echo "ERROR! Invalid target '$@' (supported: $(foreach avx,$(SUPPORTED_AVXS),madevent_$(avx)_link))"; exit 1; fi @@ -257,23 +257,23 @@ bldhip: $(PROG)_fortran $(DSIG_cudacpp) bldnone: $(PROG)_fortran $(DSIG_cudacpp) @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppnone + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_scalar bldsse4: $(PROG)_fortran $(DSIG_cudacpp) @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppsse4 + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_128b bldavx2: $(PROG)_fortran $(DSIG_cudacpp) @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppavx2 + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_256b bld512y: $(PROG)_fortran $(DSIG_cudacpp) @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512y + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b_y bld512z: $(PROG)_fortran $(DSIG_cudacpp) @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512z + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b # Clean (NB: 'make clean' in Source calls 'make clean' in all P*) clean: # Clean builds: fortran in this Pn; cudacpp executables for one AVX in this Pn diff --git a/madgraph/iolibs/template_files/madmatrix/generate_events_standalone b/madgraph/iolibs/template_files/madmatrix/generate_events_standalone index f86c1d676e..7dce42351c 100644 --- a/madgraph/iolibs/template_files/madmatrix/generate_events_standalone +++ b/madgraph/iolibs/template_files/madmatrix/generate_events_standalone @@ -2,7 +2,7 @@ # Copyright (C) 2020-2026 CERN and UCLouvain. # Licensed under the GNU Lesser General Public License (version 3 or later). # Integrated with the MadGraph7 project in Feb 2026. -"""Standalone driver for the MadGraph7 standalone_mg7 mode. +"""Standalone driver for the MadGraph7 `output standalone` (madmatrix) mode. Orchestrates compilation and run of `check_sa.exe matrix` in each SubProcesses/P*/ folder. @@ -17,9 +17,9 @@ import os import subprocess import sys -BACKENDS = ['cppauto', 'cppnone', 'cppsse4', 'cppavx2', 'cpp512y', 'cpp512z', 'cuda', 'hip'] +BACKENDS = ['cpu', 'cpu_scalar', 'cpu_128b', 'cpu_256b', 'cpu_512b_y', 'cpu_512b', 'cuda', 'hip'] -DEFAULT_BACKEND = 'cppauto' +DEFAULT_BACKEND = 'cpu' def list_p_dirs(subproc): diff --git a/madgraph/iolibs/template_files/madmatrix/madmatrix.mk b/madgraph/iolibs/template_files/madmatrix/madmatrix.mk index b3a75ba12e..fb019ac2a2 100644 --- a/madgraph/iolibs/template_files/madmatrix/madmatrix.mk +++ b/madgraph/iolibs/template_files/madmatrix/madmatrix.mk @@ -9,7 +9,7 @@ # Set the default BACKEND (CUDA, HIP or C++/SIMD) choice ifeq ($(BACKEND),) - override BACKEND = cppauto + override BACKEND = cpu endif # Set the default FPTYPE (floating point type) choice @@ -33,7 +33,7 @@ endif # Check that the user-defined choices of BACKEND, FPTYPE, HELINL, HRDCOD are supported # (NB: use 'filter' and 'words' instead of 'findstring' because they properly handle whitespace-separated words) -override SUPPORTED_BACKENDS = cuda hip cppnone cppsse4 cppavx2 cpp512y cpp512z cppauto +override SUPPORTED_BACKENDS = cuda hip cpu_scalar cpu_128b cpu_256b cpu_512b_y cpu_512b cpu ifneq ($(words $(filter $(BACKEND), $(SUPPORTED_BACKENDS))),1) $(error Invalid backend BACKEND='$(BACKEND)': supported backends are $(foreach backend,$(SUPPORTED_BACKENDS),'$(backend)')) endif @@ -70,10 +70,12 @@ endif #=== Configure MADMATRIX_BUILDDIR # Build directory "full" tag (used for build lockfiles to prevent mixing builds with different options) -override DIRTAG := $(patsubst cpp%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD) +# NB: the 'cpu_' prefix of the CPU/SIMD backends is stripped, so the tag is the short backend name +# ('cpu_128b' -> '128b', 'cpu_scalar' -> 'scalar'); 'cuda' and 'hip' are left unchanged. +override DIRTAG := $(patsubst cpu_%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD) # Build directory: current directory by default, or build. if USEBUILDDIR==1 -# NB: using '=' (not ':=') ensures BACKEND is evaluated lazily after potential cppauto resolution +# NB: using '=' (not ':=') ensures BACKEND is evaluated lazily after the potential 'cpu' auto-resolution ifeq ($(USEBUILDDIR),1) override MADMATRIX_BUILDDIR = build.$(BACKEND) else @@ -118,38 +120,38 @@ $(info Building objects in BUILDDIR=$(BUILDDIR), libraries in LIBDIR=$(LIBDIR)) #------------------------------------------------------------------------------- -#=== Redefine BACKEND if the current value is 'cppauto' +#=== Redefine BACKEND if the current value is 'cpu' -# Set the default BACKEND choice corresponding to 'cppauto' (the 'best' C++ vectorization available) +# Set the default BACKEND choice corresponding to 'cpu' (the 'best' C++ vectorization available) BACKEND_ORIG := $(BACKEND) -ifeq ($(BACKEND),cppauto) +ifeq ($(BACKEND),cpu) ifeq ($(UNAME_P),ppc64le) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifneq (,$(filter $(UNAME_M),arm64 aarch64)) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifeq ($(wildcard /proc/cpuinfo),) - override BACKEND = cppnone + override BACKEND = cpu_scalar ###$(warning Using BACKEND='$(BACKEND)' because host SIMD features cannot be read from /proc/cpuinfo) else ifeq ($(shell grep -m1 -c avx512vl /proc/cpuinfo)$(shell $(CXX) --version | grep ^clang),1) - override BACKEND = cpp512y + override BACKEND = cpu_512b_y else ifeq ($(shell grep -m1 -c avx2 /proc/cpuinfo),1) - override BACKEND = cppavx2 + override BACKEND = cpu_256b ###ifneq ($(shell grep -m1 -c avx512vl /proc/cpuinfo),1) ### $(warning Using BACKEND='$(BACKEND)' because host does not support avx512vl) ###else ### $(warning Using BACKEND='$(BACKEND)' because this is faster than avx512vl for clang) ###endif else ifeq ($(shell grep -m1 -c sse4_2 /proc/cpuinfo),1) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else - override BACKEND = cppnone + override BACKEND = cpu_scalar endif - $(info BACKEND=$(BACKEND) (was cppauto)) + $(info BACKEND=$(BACKEND) (was cpu)) else $(info BACKEND='$(BACKEND)') endif -# Create file with the resolved backend in case user chooses 'cppauto' +# Create file with the resolved backend in case user chooses 'cpu' BACKEND_LOG ?= .resolved-backend ifneq ($(BACKEND_ORIG),$(BACKEND)) $(file >$(BACKEND_LOG),$(BACKEND)) @@ -367,9 +369,9 @@ else override GPUFLAGS= # Sanity check, this should never happen: if GPUCC is empty, then this is a C++ build, i.e. BACKEND is neither cuda nor hip. - # In practice, in the following, "ifeq ($(GPUCC),)" is equivalent to "ifneq ($(findstring cpp,$(BACKEND)),)". + # In practice, in the following, "ifeq ($(GPUCC),)" is equivalent to "ifneq ($(findstring cpu,$(BACKEND)),)". # Conversely, note that GPUFLAGS is non-empty also for C++ builds, but it is never used in that case. - ifeq ($(findstring cpp,$(BACKEND)),) + ifeq ($(findstring cpu,$(BACKEND)),) $(error INTERNAL ERROR! Unknown backend BACKEND='$(BACKEND)': supported backends are $(foreach backend,$(SUPPORTED_BACKENDS),'$(backend)')) endif @@ -381,7 +383,7 @@ export GPUFLAGS export GPULANGUAGE export GPUSUFFIX -# Export BACKEND (resolved from cppauto above if needed; used e.g. to name the common library) +# Export BACKEND (resolved from cpu above if needed; used e.g. to name the common library) export BACKEND #------------------------------------------------------------------------------- @@ -435,13 +437,13 @@ INCFLAGS += -I$(SRC) # PowerPC-specific CXX compiler flags (being reviewed) ifeq ($(UNAME_P),ppc64le) - CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cppnone and cppsse4 - # Throughput references without the extra flags below: cppnone=1.41-1.42E6, cppsse4=2.15-2.19E6 + CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cpu_scalar and cpu_128b + # Throughput references without the extra flags below: cpu_scalar=1.41-1.42E6, cpu_128b=2.15-2.19E6 ###CXXFLAGS+= -DNO_WARN_X86_INTRINSICS # no change ###CXXFLAGS+= -fpeel-loops # no change - ###CXXFLAGS+= -funroll-loops # gains ~1%% for cppnone, loses ~1%% for cppsse4 + ###CXXFLAGS+= -funroll-loops # gains ~1%% for cpu_scalar, loses ~1%% for cpu_128b ###CXXFLAGS+= -ftree-vectorize # no change - ###CXXFLAGS+= -flto # would increase to cppnone=4.08-4.12E6, cppsse4=4.99-5.03E6! + ###CXXFLAGS+= -flto # would increase to cpu_scalar=4.08-4.12E6, cpu_128b=4.99-5.03E6! else ###CXXFLAGS+= -flto # also on Intel this would increase throughputs by a factor 2 to 4... ######CXXFLAGS+= -fno-semantic-interposition # no benefit (neither alone, nor combined with -flto) @@ -522,66 +524,66 @@ endif $(info OMPFLAGS=$(OMPFLAGS)) CXXFLAGS += $(OMPFLAGS) -# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cppnone") +# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cpu_scalar") # [NB MGONGPU_PVW512 is needed because "-mprefer-vector-width=256" is not exposed in a macro] # [See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96476] # [Use 'g++ -E -dM - < /dev/null' to check which #define's are enabled] ifeq ($(UNAME_P),ppc64le) - ifeq ($(BACKEND),cppsse4) + ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -D__SSE4_2__ # Power9 VSX with 128 width (VSR registers) - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) endif else ifeq ($(UNAME_M),arm64) # ARM on Apple silicon - ifeq ($(BACKEND),cppnone) # this internally undefines __ARM_NEON + ifeq ($(BACKEND),cpu_scalar) # this internally undefines __ARM_NEON override AVXFLAGS = -DMGONGPU_NOARMNEON - else ifeq ($(BACKEND),cppsse4) # __ARM_NEON is always defined on Apple silicon + else ifeq ($(BACKEND),cpu_128b) # __ARM_NEON is always defined on Apple silicon override AVXFLAGS = - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) endif else ifeq ($(UNAME_M),aarch64) # ARM on Linux - ifeq ($(BACKEND),cppnone) # +nosimd ensures __ARM_NEON is absent + ifeq ($(BACKEND),cpu_scalar) # +nosimd ensures __ARM_NEON is absent override AVXFLAGS = -march=armv8-a+nosimd - else ifeq ($(BACKEND),cppsse4) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) + else ifeq ($(BACKEND),cpu_128b) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) override AVXFLAGS = -march=armv8-a+simd - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) endif else ifneq ($(shell $(CXX) --version | grep ^nvc++),) # support nvc++ #531 - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -mno-sse3 # no SIMD - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -mno-avx # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif else - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -march=x86-64 # no SIMD (see #588) - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -march=nehalem # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake-avx512 -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake-avx512 -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif endif @@ -672,7 +674,8 @@ endif #=== Configure build directories and build lockfiles === # Build lockfile "full" tag (defines full specification of object-file builds that cannot be intermixed) -override TAG = $(patsubst cpp%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD) +# NB: the 'cpu_' prefix of the CPU/SIMD backends is stripped (see DIRTAG above) +override TAG = $(patsubst cpu_%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD) # Export TAG (so that there is no need to check/define it again in src/Makefile) export TAG @@ -812,31 +815,31 @@ bldhip: bldnone: @echo - $(MAKE) $(_BLDFLAGS) BACKEND=cppnone + $(MAKE) $(_BLDFLAGS) BACKEND=cpu_scalar bldsse4: @echo - $(MAKE) $(_BLDFLAGS) BACKEND=cppsse4 + $(MAKE) $(_BLDFLAGS) BACKEND=cpu_128b bldavx2: @echo - $(MAKE) $(_BLDFLAGS) BACKEND=cppavx2 + $(MAKE) $(_BLDFLAGS) BACKEND=cpu_256b bld512y: @echo - $(MAKE) $(_BLDFLAGS) BACKEND=cpp512y + $(MAKE) $(_BLDFLAGS) BACKEND=cpu_512b_y bld512z: @echo - $(MAKE) $(_BLDFLAGS) BACKEND=cpp512z + $(MAKE) $(_BLDFLAGS) BACKEND=cpu_512b # The C++/SIMD backends that are worth building on this machine... ifeq ($(UNAME_P),ppc64le) - BLDAVXS = cppnone cppsse4 + BLDAVXS = cpu_scalar cpu_128b else ifneq (,$(filter $(UNAME_M),arm64 aarch64)) - BLDAVXS = cppnone cppsse4 + BLDAVXS = cpu_scalar cpu_128b else - BLDAVXS = cppnone cppsse4 cppavx2 cpp512y cpp512z + BLDAVXS = cpu_scalar cpu_128b cpu_256b cpu_512b_y cpu_512b endif # ...plus the GPU backends whose compiler was found. This is the single place @@ -850,9 +853,18 @@ ifneq ($(HIP_HOME),) BLDBACKENDS := hip $(BLDBACKENDS) endif -# 'bldcppsse4' etc. are named 'bldsse4' etc. (the 'cpp' prefix is dropped) -bldavxs: $(addprefix bld,$(subst cpp,,$(BLDAVXS))) -bldall: $(addprefix bld,$(subst cpp,,$(BLDBACKENDS))) +# The bld* targets keep their historical short names, which do not follow the +# backend names, so map them explicitly rather than editing the backend string. +BLDTARGET_cpu_scalar = bldnone +BLDTARGET_cpu_128b = bldsse4 +BLDTARGET_cpu_256b = bldavx2 +BLDTARGET_cpu_512b_y = bld512y +BLDTARGET_cpu_512b = bld512z +BLDTARGET_cuda = bldcuda +BLDTARGET_hip = bldhip + +bldavxs: $(foreach backend,$(BLDAVXS),$(BLDTARGET_$(backend))) +bldall: $(foreach backend,$(BLDBACKENDS),$(BLDTARGET_$(backend))) # Target: the common (src) library in all BACKEND modes. Used by the # SubProcesses dispatcher, which owns the common library during a 'bldall' @@ -901,7 +913,7 @@ cleanallcommon: #------------------------------------------------------------------------------- -# Detect backend (to be used in case of 'cppauto' to give info to the user) +# Detect backend (to be used in case of 'cpu' to give info to the user) .PHONY: detect-backend detect-backend: @echo "Resolved backend has already been written to $(BACKEND_LOG) at parse time." diff --git a/madgraph/iolibs/template_files/madmatrix/madmatrix_src.mk b/madgraph/iolibs/template_files/madmatrix/madmatrix_src.mk index 8b13f7f4e1..59337f2ad9 100644 --- a/madgraph/iolibs/template_files/madmatrix/madmatrix_src.mk +++ b/madgraph/iolibs/template_files/madmatrix/madmatrix_src.mk @@ -86,7 +86,7 @@ $(BUILDDIR)/.build.$(TAG): #------------------------------------------------------------------------------- # Generic target and build rules: objects from C++ or CUDA/HIP compilation. -# Plain .o suffix — the BUILDDIR (e.g. build.cppavx2/) provides backend separation. +# Plain .o suffix — the BUILDDIR (e.g. build.cpu_256b/) provides backend separation. # Use USEBUILDDIR=1 to build for multiple backends simultaneously without cleaning. ifeq ($(GPUCC),) $(BUILDDIR)/%%.o : %%.cc *.h $(BUILDDIR)/.build.$(TAG) diff --git a/madgraph/iolibs/template_files/madmatrix/madmatrix_standalone.mk b/madgraph/iolibs/template_files/madmatrix/madmatrix_standalone.mk index 618cb9e42a..ce7ebec20a 100644 --- a/madgraph/iolibs/template_files/madmatrix/madmatrix_standalone.mk +++ b/madgraph/iolibs/template_files/madmatrix/madmatrix_standalone.mk @@ -2,7 +2,7 @@ # Licensed under the GNU Lesser General Public License (version 3 or later). # Integrated with the MadGraph7 project in Feb 2026. # -# Standalone (standalone_mg7) Makefile. +# Standalone (`output standalone`, madmatrix) Makefile. # Extends the non-standalone (madmatrix) Makefile by including madmatrix.mk and # adding a recipe for check_sa.exe (the standalone driver). Running `make` here # will build both the process library AND the standalone executable. diff --git a/madgraph/iolibs/template_files/madmatrix/madmatrix_subprocesses.mk b/madgraph/iolibs/template_files/madmatrix/madmatrix_subprocesses.mk index 3f779624d3..4c1d4e13c3 100644 --- a/madgraph/iolibs/template_files/madmatrix/madmatrix_subprocesses.mk +++ b/madgraph/iolibs/template_files/madmatrix/madmatrix_subprocesses.mk @@ -48,7 +48,7 @@ endif # # The common library is built *through* one representative subprocess directory # rather than directly: madmatrix.mk already resolves BACKEND (including the -# 'cppauto' detection), FPTYPE, the compiler flags and the paths of src/ and +# 'cpu' detection), FPTYPE, the compiler flags and the paths of src/ and # lib/, and none of that has to be duplicated here. COMMONDIR := $(firstword $(SUBDIRS)) diff --git a/madgraph/iolibs/template_files/madmatrix/mgOnGpuConfig.h b/madgraph/iolibs/template_files/madmatrix/mgOnGpuConfig.h index 09c76a6bd5..3875d71bb4 100644 --- a/madgraph/iolibs/template_files/madmatrix/mgOnGpuConfig.h +++ b/madgraph/iolibs/template_files/madmatrix/mgOnGpuConfig.h @@ -202,7 +202,7 @@ namespace mgOnGpu using mgOnGpu::fptype; using mgOnGpu::fptype2; -// Undefine ARM_NEON (hack for cppnone on Apple silicon ARM) +// Undefine ARM_NEON (hack for cpu_scalar on Apple silicon ARM) #ifdef MGONGPU_NOARMNEON #undef __ARM_NEON #endif diff --git a/madgraph/iolibs/template_files/madmatrix/rambo.h b/madgraph/iolibs/template_files/madmatrix/rambo.h index 00679a5255..1d404629ef 100644 --- a/madgraph/iolibs/template_files/madmatrix/rambo.h +++ b/madgraph/iolibs/template_files/madmatrix/rambo.h @@ -1,7 +1,7 @@ // Copyright (C) 2020-2026 CERN and UCLouvain. // Licensed under the GNU Lesser General Public License (version 3 or later). //========================================================================== -// RAMBO phase-space generator for the standalone_mg7 driver. +// RAMBO phase-space generator for the standalone (madmatrix) driver. // Ported verbatim from the MG5aMC standalone_cpp output (rambo.cc/rambo.h), so // that check_sa generates the SAME phase-space point as the Fortran/C++ 'check' // drivers, INCLUDING the particle masses. The only changes are: diff --git a/madgraph/iolibs/template_files/mg7/generate_events b/madgraph/iolibs/template_files/mg7/generate_events deleted file mode 100755 index 57316e48a7..0000000000 --- a/madgraph/iolibs/template_files/mg7/generate_events +++ /dev/null @@ -1,10 +0,0 @@ -#! /usr/bin/env python3 -import sys, os -from internal.madevent import main - -if __name__ == '__main__': - os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) - try: - main() - except KeyboardInterrupt: - pass diff --git a/madgraph/iolibs/template_files/mg7/madevent.py b/madgraph/iolibs/template_files/mg7/launch.py similarity index 98% rename from madgraph/iolibs/template_files/mg7/madevent.py rename to madgraph/iolibs/template_files/mg7/launch.py index 94d0a6da69..882d25c584 100644 --- a/madgraph/iolibs/template_files/mg7/madevent.py +++ b/madgraph/iolibs/template_files/mg7/launch.py @@ -115,14 +115,14 @@ def resolve_verbosity(verbosity: str) -> str: return verbosity -def resolve_cppauto_backend(build_path: str) -> str: - """Ask the matrix-element Makefile to resolve ``cppauto``. +def resolve_cpu_backend(build_path: str) -> str: + """Ask the matrix-element Makefile to resolve ``cpu``. Given the produced shared library will have its name taken from the resolved backend name, we need to make sure the detection is taking place correctly and catch any possible error. """ - command = ["make", "-n", "BACKEND=cppauto", "detect-backend"] + command = ["make", "-n", "BACKEND=cpu", "detect-backend"] try: result = subprocess.run( command, @@ -133,7 +133,7 @@ def resolve_cppauto_backend(build_path: str) -> str: ) except OSError as exc: raise RuntimeError( - f"Could not run make to resolve cppauto in '{build_path}': {exc}" + f"Could not run make to resolve cpu in '{build_path}': {exc}" ) from exc except subprocess.CalledProcessError as exc: output = "\n".join( @@ -141,20 +141,20 @@ def resolve_cppauto_backend(build_path: str) -> str: ) detail = f"\nmake output:\n{output}" if output else "" raise RuntimeError( - f"Could not resolve cppauto in '{build_path}': " + f"Could not resolve cpu in '{build_path}': " f"Exit status {exc.returncode}.{detail}" ) from exc match = re.search( - r"^BACKEND=(\S+) \(was cppauto\)$", result.stdout, re.MULTILINE + r"^BACKEND=(\S+) \(was cpu\)$", result.stdout, re.MULTILINE ) - if match is None or match.group(1) == "cppauto": + if match is None or match.group(1) == "cpu": output = "\n".join( part.strip() for part in (result.stdout, result.stderr) if part.strip() ) detail = f"\nmake output:\n{output}" if output else "" raise RuntimeError( - f"Could not resolve cppauto in '{build_path}': " + f"Could not resolve cpu in '{build_path}': " f"make failed to report a backend.{detail}" ) return match.group(1) @@ -468,7 +468,7 @@ def init_subprocesses(self) -> None: def compile_matrix_elements(self) -> list[str]: """Build the matrix-element library of every subprocess, and return the - list of requested devices with 'cppauto' replaced by the backend it + list of requested devices with 'cpu' replaced by the backend it resolves to on this machine. SubProcesses/makefile is a dispatcher over the P* directories, so a @@ -485,14 +485,14 @@ def compile_matrix_elements(self) -> list[str]: first_proc_path = self.subprocess_data[0]["path"] subproc_path = os.path.dirname(first_proc_path) - # Resolve 'cppauto' once (the build rules pick the best SIMD backend + # Resolve 'cpu' once (the build rules pick the best SIMD backend # available here), so that all subprocesses agree on the library names. - cppauto_backend = None - if "cppauto" in backends: - cppauto_backend = resolve_cppauto_backend(first_proc_path) - logger.info("Device 'cppauto' resolved as '%s'", cppauto_backend) + cpu_backend = None + if "cpu" in backends: + cpu_backend = resolve_cpu_backend(first_proc_path) + logger.info("Device 'cpu' resolved as '%s'", cpu_backend) resolved = [ - cppauto_backend if backend == "cppauto" else backend + cpu_backend if backend == "cpu" else backend for backend in backends ] @@ -828,10 +828,18 @@ def generate_events(self) -> None: ) elif output_format == "lhe": self.lhe_completer = self.build_lhe_completer() + lhe_path = os.path.join(self.run_path, "events.lhe") self.event_generator.combine_to_lhe( - os.path.join(self.run_path, "events.lhe"), self.lhe_completer, + lhe_path, self.lhe_completer, self.build_lhe_meta(), ) + # Ship the LHE compressed by default. These files are large and + # very compressible, madevent has always stored its events + # gzipped, and every consumer here already accepts either form + # (see _find_event_file). misc.gzip replaces events.lhe with + # events.lhe.gz, and switches to an external multithreaded tool + # above 256 MB. + misc.gzip(lhe_path) else: raise ValueError("Unknown output format") self.save_gridpack() @@ -2011,7 +2019,7 @@ def check_open(self, args): def do_compute_widths(self, line): # The interactive card editor delegates 'auto' width computation to - # the mother interface. Reuse the runtime helper (mg5_aMC subprocess + # the mother interface. Reuse the runtime helper (madgraph subprocess # + the model stored at output time). ``line`` looks like # " --path= [--nlo]"; we only need the card path. m = re.search(r'--path=(\S+)', line or "") @@ -2506,7 +2514,7 @@ def run_lhe_postprocessing(process) -> None: def compute_auto_widths(param_card_path=os.path.join("Cards", "param_card.dat")) -> None: - """Fill any width set to ``auto`` in the param_card, using mg5_aMC and the + """Fill any width set to ``auto`` in the param_card, using madgraph and the model stored at output time (``SubProcesses/model.txt``), and write the result back into the card. A no-op when the card has no ``auto`` width. @@ -2549,9 +2557,9 @@ def compute_auto_widths(param_card_path=os.path.join("Cards", "param_card.dat")) "current model, which may be inconsistent with the matrix " "element.", model) - mg5 = str(_MG_ROOT / "bin" / "mg5_aMC") + mg5 = str(_MG_ROOT / "bin" / "madgraph") if not os.path.exists(mg5): - logger.warning("Cannot find mg5_aMC at %s; 'auto' widths not computed.", mg5) + logger.warning("Cannot find madgraph at %s; 'auto' widths not computed.", mg5) return import tempfile diff --git a/madgraph/iolibs/template_files/mg7/run_card.toml b/madgraph/iolibs/template_files/mg7/run_card.toml index 4e3d07d635..b033e964f0 100644 --- a/madgraph/iolibs/template_files/mg7/run_card.toml +++ b/madgraph/iolibs/template_files/mg7/run_card.toml @@ -1,6 +1,6 @@ [run] run_name = %(run.run_name)s -# options: cuda, hip, cpp, cppnone, cppsse4, cppavx2, cpp512y, cpp512z, cppauto +# options: cpu (auto-detected SIMD width), cpu_scalar, cpu_128b, cpu_256b, cpu_512b_y, cpu_512b, cuda, hip devices = %(run.devices)s # options: # -1 to choose automatically diff --git a/madgraph/iolibs/template_files/mg7/run_interface.py b/madgraph/iolibs/template_files/mg7/run_interface.py index 6f3007fcb4..2491c3c2c2 100644 --- a/madgraph/iolibs/template_files/mg7/run_interface.py +++ b/madgraph/iolibs/template_files/mg7/run_interface.py @@ -64,13 +64,23 @@ def __init__(self, me_dir, options, run_name, lhe_path): # ------------------------------------------------------------------ def _prepare_run_dir(self): """Provide the file names the madevent tools look for: a gzipped - ``unweighted_events.lhe.gz`` next to the mg7 ``events.lhe``.""" + ``unweighted_events.lhe.gz`` next to the mg7 event file. + + The mg7 event file may already be gzipped (``events.lhe.gz``, the + default) or plain (``events.lhe``). Compressing an already-gzipped + source would produce a doubly-gzipped file: every consumer would + decompress it once, get gzip bytes instead of LHE text, and read zero + events. So copy when the source is already compressed and only gzip a + plain source.""" run_dir = os.path.dirname(self._mg7_lhe_path) gz = pjoin(run_dir, 'unweighted_events.lhe.gz') if not os.path.exists(gz) and os.path.exists(self._mg7_lhe_path): - with open(self._mg7_lhe_path, 'rb') as fin, \ - gzip.open(gz, 'wb') as fout: - shutil.copyfileobj(fin, fout) + if self._mg7_lhe_path.endswith('.gz'): + shutil.copyfile(self._mg7_lhe_path, gz) + else: + with open(self._mg7_lhe_path, 'rb') as fin, \ + gzip.open(gz, 'wb') as fout: + shutil.copyfileobj(fin, fout) def load_results_db(self): """Fresh results database without recreating old runs from banners: the diff --git a/madgraph/iolibs/template_files/mg7/simd/Makefile b/madgraph/iolibs/template_files/mg7/simd/Makefile deleted file mode 100644 index 5daffc1a48..0000000000 --- a/madgraph/iolibs/template_files/mg7/simd/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -include config.mk - -SUBPROC_PATH=$(PROC_PATH)/SubProcesses/P$(SUBPROC_NUMBER)_$(SUBPROC_NAME) -COMMON_LIB_NAME=libmg5amc_common_cpp.so -SUBPROC_LIB_NAME=libmg5amc_$(SUBPROC_NAME)_cpp.so - -include $(PROC_PATH)/src/cudacpp_config.mk -include cudacpp.mk - -INCDIR_SP=$(SUBPROC_PATH) -INCDIR_SRC=$(PROC_PATH)/src -COMMON_LIB=$(PROC_PATH)/lib/$(COMMON_LIB_NAME) -SUBPROC_LIB=$(PROC_PATH)/lib/$(SUBPROC_LIB_NAME) -MAIN=api.so - -all: $(MAIN) - -$(COMMON_LIB_NAME): $(COMMON_LIB) - cp $(COMMON_LIB) $(COMMON_LIB_NAME) - -$(SUBPROC_LIB_NAME): $(SUBPROC_LIB) - cp $(SUBPROC_LIB) $(SUBPROC_LIB_NAME) - if [ "$(shell uname)" = "Darwin" ]; then\ - install_name_tool -id @rpath/$(SUBPROC_LIB_NAME) $(SUBPROC_LIB_NAME);\ - fi - -$(MAIN): api_simd.cpp $(COMMON_LIB_NAME) $(SUBPROC_LIB_NAME) - $(CXX) -shared $(CXXFLAGS) -I$(INCDIR_SP) -I$(INCDIR_SRC) -I. -Wl,-rpath $(shell pwd) -o $@ \ - api_simd.cpp $(COMMON_LIB_NAME) $(SUBPROC_LIB_NAME) - -.PHONY: clean -clean: - rm -f $(MAIN) $(COMMON_LIB_NAME) $(SUBPROC_LIB_NAME) diff --git a/madgraph/iolibs/template_files/mg7/simd/api_simd.cpp b/madgraph/iolibs/template_files/mg7/simd/api_simd.cpp deleted file mode 100644 index 41f3dab40e..0000000000 --- a/madgraph/iolibs/template_files/mg7/simd/api_simd.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "api.h" - -#include "CPPProcess.h" -#include "MemoryAccessMomenta.h" -#include - -using namespace mg5amcCpu; - -namespace { - -void* initialize_impl( - const fptype* momenta, - const fptype* couplings, - fptype* matrix_elements, - fptype* numerators, - fptype* denominators, - std::size_t count -) { - bool is_good_hel[CPPProcess::ncomb]; - sigmaKin_getGoodHel( - momenta, couplings, matrix_elements, numerators, denominators, is_good_hel, count - ); - sigmaKin_setGoodHel(is_good_hel); - return nullptr; -} - -void initialize( - const fptype* momenta, - const fptype* couplings, - fptype* matrix_elements, - fptype* numerators, - fptype* denominators, - std::size_t count -) { - // static local initialization is called exactly once in a thread-safe way - static void* dummy = initialize_impl( - momenta, couplings, matrix_elements, numerators, denominators, count - ); -} - -void transpose_momenta( - const double* momenta_in, fptype* momenta_out, std::size_t i_event, std::size_t stride -) { - std::size_t page_size = MemoryAccessMomentaBase::neppM; - std::size_t i_page = i_event / page_size; - std::size_t i_vector = i_event % page_size; - - for (std::size_t i_part = 0; i_part < CPPProcess::npar; ++i_part) { - for(std::size_t i_mom = 0; i_mom < 4; ++i_mom) { - momenta_out[ - i_page * CPPProcess::npar * 4 * page_size + - i_part * 4 * page_size + i_mom * page_size + i_vector - ] = momenta_in[ - stride * (CPPProcess::npar * i_mom + i_part) + i_event - ]; - } - } -} - -} - -extern "C" { - -const SubProcessInfo* subprocess_info() { - static SubProcessInfo info = { - /* on_gpu = */ false, - /* particle_count = */ CPPProcess::npar, - /* diagram_count = */ CPPProcess::ndiagrams, - /* helicity_count = */ CPPProcess::ncomb - }; - return &info; -} - -void* init_subprocess(const char* param_card_path) { - CPPProcess process; - process.initProc(param_card_path); - // We don't actually need the CPPProcess instance for anything as it initializes a - // global variable. So here we just return a boolean that is used to store whether - // the good helicities are initialized - return new bool(false); -} - -void compute_matrix_element( - void* subprocess, - size_t count, - size_t stride, - const double* momenta_in, - const int* flavor_in, - double* m2_out -) { - // need to round to round to double page size for some reason - std::size_t page_size2 = 2 * MemoryAccessMomentaBase::neppM; - std::size_t rounded_count = (count + page_size2 - 1) / page_size2 * page_size2; - - std::vector momenta(rounded_count * CPPProcess::npar * 4); - std::vector couplings( - rounded_count * mg5amcCpu::Parameters_sm_dependentCouplings::ndcoup * 2 - ); - // alpha s from the paramcard is discarded, so we just use 0.118 for now - std::vector g_s(rounded_count, 1.2177157847767195); // sqrt(4 pi alpha_s) - std::vector helicity_random(rounded_count, 0.5); - std::vector color_random(rounded_count, 0.5); - std::vector matrix_elements(rounded_count); - std::vector channel_index(rounded_count, 2); - std::vector numerators(rounded_count * CPPProcess::ndiagrams); - std::vector denominators(rounded_count); - std::vector helicity_index(rounded_count); - std::vector color_index(rounded_count); - - for (std::size_t i_event = 0; i_event < count; ++i_event) { - transpose_momenta(momenta_in, momenta.data(), i_event, stride); - } - computeDependentCouplings( - g_s.data(), couplings.data(), rounded_count - ); - - bool& is_initialized = *static_cast(subprocess); - if (!is_initialized) { - initialize( - momenta.data(), - couplings.data(), - matrix_elements.data(), - numerators.data(), - denominators.data(), - rounded_count - ); - is_initialized = true; - } - - sigmaKin( - momenta.data(), - couplings.data(), - helicity_random.data(), - color_random.data(), - matrix_elements.data(), - channel_index.data(), - numerators.data(), - denominators.data(), - color_index.data(), - helicity_index.data(), - rounded_count - ); - - std::size_t page_size = MemoryAccessMomentaBase::neppM; - for (std::size_t i_event = 0; i_event < count; ++i_event) { - std::size_t i_page = i_event / page_size; - std::size_t i_vector = i_event % page_size; - - double denominator = denominators[i_event]; - double factor = denominator / numerators[ - i_page * page_size * CPPProcess::ndiagrams + - 1 * page_size + i_vector - ]; - m2_out[i_event] = factor * matrix_elements[i_event]; - } -} - -void compute_matrix_element_multichannel( - void* subprocess, - size_t count, - size_t stride, - const double* momenta_in, - const double* alpha_s_in, - const double* random_in, - const int* flavor_in, - double* m2_out, - double* amp2_out, - int* diagram_out, - int* color_out, - int* helicity_out -) { - // need to round to round to double page size for some reason - std::size_t page_size2 = 2 * MemoryAccessMomentaBase::neppM; - std::size_t rounded_count = (count + page_size2 - 1) / page_size2 * page_size2; - - std::vector momenta(rounded_count * CPPProcess::npar * 4); - std::vector couplings( - rounded_count * mg5amcCpu::Parameters_sm_dependentCouplings::ndcoup * 2 - ); - std::vector g_s(rounded_count); - std::vector helicity_random(rounded_count); - std::vector color_random(rounded_count); - std::vector matrix_elements(rounded_count); - std::vector channel_index(rounded_count, 2); - std::vector numerators(rounded_count * CPPProcess::ndiagrams); - std::vector denominators(rounded_count); - std::vector helicity_index(rounded_count); - std::vector color_index(rounded_count); - - for (std::size_t i_event = 0; i_event < count; ++i_event) { - transpose_momenta(momenta_in, momenta.data(), i_event, stride); - helicity_random[i_event] = random_in[i_event]; - color_random[i_event] = random_in[i_event + stride]; - g_s[i_event] = sqrt(4 * M_PI * alpha_s_in[i_event]); - } - computeDependentCouplings( - g_s.data(), couplings.data(), rounded_count - ); - - bool& is_initialized = *static_cast(subprocess); - if (!is_initialized) { - initialize( - momenta.data(), - couplings.data(), - matrix_elements.data(), - numerators.data(), - denominators.data(), - rounded_count - ); - is_initialized = true; - } - - sigmaKin( - momenta.data(), - couplings.data(), - helicity_random.data(), - color_random.data(), - matrix_elements.data(), - channel_index.data(), - numerators.data(), - denominators.data(), - color_index.data(), - helicity_index.data(), - rounded_count - ); - - std::size_t page_size = MemoryAccessMomentaBase::neppM; - for (std::size_t i_event = 0; i_event < count; ++i_event) { - std::size_t i_page = i_event / page_size; - std::size_t i_vector = i_event % page_size; - - double denominator = denominators[i_event]; - double factor = denominator / numerators[ - i_page * page_size * CPPProcess::ndiagrams + - 1 * page_size + i_vector - ]; - m2_out[i_event] = factor * matrix_elements[i_event]; - for (std::size_t i_diag = 0; i_diag < CPPProcess::ndiagrams; ++i_diag) { - amp2_out[stride * i_diag + i_event] = numerators[ - i_page * page_size * CPPProcess::ndiagrams + - i_diag * page_size + i_vector - ] / denominator; - } - diagram_out[i_event] = 0; - color_out[i_event] = color_index[i_event] - 1; - helicity_out[i_event] = helicity_index[i_event] - 1; - } -} - -void free_subprocess(void* subprocess) { - delete static_cast(subprocess); -} - -} diff --git a/madgraph/iolibs/template_files/mg7/simd/cudacpp.mk b/madgraph/iolibs/template_files/mg7/simd/cudacpp.mk deleted file mode 100644 index 0fd17ab80a..0000000000 --- a/madgraph/iolibs/template_files/mg7/simd/cudacpp.mk +++ /dev/null @@ -1,658 +0,0 @@ -# Copyright (C) 2020-2024 CERN and UCLouvain. -# Licensed under the GNU Lesser General Public License (version 3 or later). -# Created by: S. Roiser (Feb 2020) for the MG5aMC CUDACPP plugin. -# Further modified by: S. Hageboeck, O. Mattelaer, S. Roiser, J. Teig, A. Valassi (2020-2024) for the MG5aMC CUDACPP plugin. - -#=== Determine the name of this makefile (https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html) -#=== NB: use ':=' to ensure that the value of CUDACPP_MAKEFILE is not modified further down after including make_opts -#=== NB: use 'override' to ensure that the value can not be modified from the outside -override CUDACPP_MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) -###$(info CUDACPP_MAKEFILE='$(CUDACPP_MAKEFILE)') - -#=== NB: different names (e.g. cudacpp.mk and cudacpp_src.mk) are used in the Subprocess and src directories -override CUDACPP_SRC_MAKEFILE = cudacpp_src.mk - -#------------------------------------------------------------------------------- - -#=== Include cudacpp_config.mk - -# Check that the user-defined choices of BACKEND, FPTYPE, HELINL, HRDCOD are supported (and configure defaults if no user-defined choices exist) -# Stop with an error if BACKEND=cuda and nvcc is missing or if BACKEND=hip and hipcc is missing. -# Determine CUDACPP_BUILDDIR from a DIRTAG based on BACKEND, FPTYPE, HELINL, HRDCOD and from the user-defined choice of USEBUILDDIR -# include ../../src/cudacpp_config.mk - -# Export CUDACPP_BUILDDIR (so that there is no need to check/define it again in cudacpp_src.mk) -export CUDACPP_BUILDDIR - -#------------------------------------------------------------------------------- - -#=== Use bash in the Makefile (https://www.gnu.org/software/make/manual/html_node/Choosing-the-Shell.html) - -SHELL := /bin/bash - -#------------------------------------------------------------------------------- - -#=== Detect O/S and architecture (assuming uname is available, https://en.wikipedia.org/wiki/Uname) - -# Detect O/S kernel (Linux, Darwin...) -UNAME_S := $(shell uname -s) -###$(info UNAME_S='$(UNAME_S)') - -# Detect architecture (x86_64, ppc64le...) -UNAME_P := $(shell uname -p) -###$(info UNAME_P='$(UNAME_P)') - -#------------------------------------------------------------------------------- - -#=== Include the common MG5aMC Makefile options - -# OM: including make_opts is crucial for MG5aMC flag consistency/documentation -# AV: disable the inclusion of make_opts if the file has not been generated (standalone cudacpp) -ifneq ($(wildcard ../../Source/make_opts),) - include ../../Source/make_opts -endif - -#------------------------------------------------------------------------------- - -#=== Redefine BACKEND if the current value is 'cppauto' - -# Set the default BACKEND choice corresponding to 'cppauto' (the 'best' C++ vectorization available: eventually use native instead?) -ifeq ($(BACKEND),cppauto) - ifeq ($(UNAME_P),ppc64le) - override BACKEND = cppsse4 - else ifeq ($(UNAME_P),arm) - override BACKEND = cppsse4 - else ifeq ($(wildcard /proc/cpuinfo),) - override BACKEND = cppnone - ###$(warning Using BACKEND='$(BACKEND)' because host SIMD features cannot be read from /proc/cpuinfo) - else ifeq ($(shell grep -m1 -c avx512vl /proc/cpuinfo)$(shell $(CXX) --version | grep ^clang),1) - override BACKEND = cpp512y - else - override BACKEND = cppavx2 - ###ifneq ($(shell grep -m1 -c avx512vl /proc/cpuinfo),1) - ### $(warning Using BACKEND='$(BACKEND)' because host does not support avx512vl) - ###else - ### $(warning Using BACKEND='$(BACKEND)' because this is faster than avx512vl for clang) - ###endif - endif - $(info BACKEND=$(BACKEND) (was cppauto)) -else - $(info BACKEND='$(BACKEND)') -endif - -#------------------------------------------------------------------------------- - -#=== Configure the C++ compiler - -CXXFLAGS = $(OPTFLAGS) -std=c++17 -Wall -Wshadow -Wextra -ifeq ($(shell $(CXX) --version | grep ^nvc++),) - CXXFLAGS += -ffast-math # see issue #117 -endif -###CXXFLAGS+= -Ofast # performance is not different from --fast-math -###CXXFLAGS+= -g # FOR DEBUGGING ONLY - -# Optionally add debug flags to display the full list of flags (eg on Darwin) -###CXXFLAGS+= -v - -# Note: AR, CXX and FC are implicitly defined if not set externally -# See https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html - -# Add -mmacosx-version-min=11.3 to avoid "ld: warning: object file was built for newer macOS version than being linked" -ifneq ($(shell $(CXX) --version | egrep '^Apple clang'),) - CXXFLAGS += -mmacosx-version-min=11.3 -endif - -# Export CXXFLAGS (so that there is no need to check/define it again in cudacpp_src.mk) -export CXXFLAGS - -#------------------------------------------------------------------------------- - -#=== Configure the GPU compiler (CUDA or HIP) -#=== (note, this is done also for C++, as NVTX and CURAND/ROCRAND are also needed by the C++ backends) - -# Set CUDA_HOME from the path to nvcc, if it exists -override CUDA_HOME = $(patsubst %/bin/nvcc,%,$(shell which nvcc 2>/dev/null)) - -# Set HIP_HOME from the path to hipcc, if it exists -override HIP_HOME = $(patsubst %/bin/hipcc,%,$(shell which hipcc 2>/dev/null)) - -# Configure CUDA_INC (for CURAND and NVTX) and NVTX if a CUDA installation exists (see #965) -ifeq ($(CUDA_HOME),) - # CUDA_HOME is empty (nvcc not found) - override CUDA_INC= -else ifeq ($(wildcard $(CUDA_HOME)/include/),) - # CUDA_HOME is defined (nvcc was found) but $(CUDA_HOME)/include/ does not exist? - override CUDA_INC= -else - CUDA_INC = -I$(CUDA_HOME)/include/ -endif -###$(info CUDA_INC=$(CUDA_INC)) - -# Configure NVTX if a CUDA include directory exists and NVTX headers exist (see #965) -ifeq ($(CUDA_INC),) - # $(CUDA_HOME)/include/ does not exist - override USE_NVTX= -else ifeq ($(wildcard $(CUDA_HOME)/include/nvtx3/nvToolsExt.h),) - # $(CUDA_HOME)/include/ exists but NVTX headers do not exist? - override USE_NVTX= -else - # $(CUDA_HOME)/include/nvtx.h exists: use NVTX - # (NB: the option to disable NVTX if 'USE_NVTX=' is defined has been removed) - override USE_NVTX=-DUSE_NVTX -endif -###$(info USE_NVTX=$(USE_NVTX)) - -# NB: NEW LOGIC FOR ENABLING AND DISABLING CUDA OR HIP BUILDS (AV Feb-Mar 2024) -# - In the old implementation, by default the C++ targets for one specific AVX were always built together with either CUDA or HIP. -# If both CUDA and HIP were installed, then CUDA took precedence over HIP, and the only way to force HIP builds was to disable -# CUDA builds by setting CUDA_HOME to an invalid value (as CUDA_HOME took precdence over PATH to find the installation of nvcc). -# Similarly, C++-only builds could be forced by setting CUDA_HOME and/or HIP_HOME to invalid values. A check for an invalid nvcc -# in CUDA_HOME or an invalid hipcc HIP_HOME was necessary to ensure this logic, and had to be performed at the very beginning. -# - In the new implementation (PR #798), separate individual builds are performed for one specific C++/AVX mode, for CUDA or -# for HIP. The choice of the type of build is taken depending on the value of the BACKEND variable (replacing the AVX variable). -# Unlike what happened in the past, nvcc and hipcc must have already been added to PATH. Using 'which nvcc' and 'which hipcc', -# their existence and their location is checked, and the variables CUDA_HOME and HIP_HOME are internally set by this makefile. -# This must be still done before backend-specific customizations, e.g. because CURAND and NVTX are also used in C++ builds. -# Note also that a preliminary check for nvcc and hipcc if BACKEND is cuda or hip is performed in cudacpp_config.mk. -# - Note also that the REQUIRE_CUDA variable (which was used in the past, e.g. for CI tests on GPU #443) is now (PR #798) no -# longer necessary, as it is now equivalent to BACKEND=cuda. Similarly, there is no need to introduce a REQUIRE_HIP variable. - -#=== Configure the CUDA or HIP compiler (only for the CUDA and HIP backends) -#=== (NB: throughout all makefiles, an empty GPUCC is used to indicate that this is a C++ build, i.e. that BACKEND is neither cuda nor hip!) - -ifeq ($(BACKEND),cuda) - - # If CXX is not a single word (example "clang++ --gcc-toolchain...") then disable CUDA builds (issue #505) - # This is because it is impossible to pass this to "GPUFLAGS += -ccbin " below - ifneq ($(words $(subst ccache ,,$(CXX))),1) # allow at most "CXX=ccache " from outside - $(error BACKEND=$(BACKEND) but CUDA builds are not supported for multi-word CXX "$(CXX)") - endif - - # Set GPUCC as $(CUDA_HOME)/bin/nvcc (it was already checked above that this exists) - GPUCC = $(CUDA_HOME)/bin/nvcc - XCOMPILERFLAG = -Xcompiler - GPULANGUAGE = cu - GPUSUFFIX = cuda - - # Optimization flags - GPUFLAGS = $(foreach opt, $(OPTFLAGS), $(XCOMPILERFLAG) $(opt)) - - # NVidia CUDA architecture flags - # See https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html - # See https://arnon.dk/matching-sm-architectures-arch-and-gencode-for-various-nvidia-cards/ - # Default: use compute capability 70 for V100 (CERN lxbatch, CERN itscrd, Juwels Cluster). - # This will embed device code for 70, and PTX for 70+. - # One may pass MADGRAPH_CUDA_ARCHITECTURE (comma-separated list) to the make command to use another value or list of values (see #533). - # Examples: use 60 for P100 (Piz Daint), 80 for A100 (Juwels Booster, NVidia raplab/Curiosity). - MADGRAPH_CUDA_ARCHITECTURE ?= 70 - ###GPUARCHFLAGS = -gencode arch=compute_$(MADGRAPH_CUDA_ARCHITECTURE),code=compute_$(MADGRAPH_CUDA_ARCHITECTURE) -gencode arch=compute_$(MADGRAPH_CUDA_ARCHITECTURE),code=sm_$(MADGRAPH_CUDA_ARCHITECTURE) # Older implementation (AV): go back to this one for multi-GPU support #533 - ###GPUARCHFLAGS = --gpu-architecture=compute_$(MADGRAPH_CUDA_ARCHITECTURE) --gpu-code=sm_$(MADGRAPH_CUDA_ARCHITECTURE),compute_$(MADGRAPH_CUDA_ARCHITECTURE) # Newer implementation (SH): cannot use this as-is for multi-GPU support #533 - comma:=, - GPUARCHFLAGS = $(foreach arch,$(subst $(comma), ,$(MADGRAPH_CUDA_ARCHITECTURE)),-gencode arch=compute_$(arch),code=compute_$(arch) -gencode arch=compute_$(arch),code=sm_$(arch)) - GPUFLAGS += $(GPUARCHFLAGS) - - # Other NVidia-specific flags - CUDA_OPTFLAGS = -lineinfo - GPUFLAGS += $(CUDA_OPTFLAGS) - - # NVCC version - ###GPUCC_VERSION = $(shell $(GPUCC) --version | grep 'Cuda compilation tools' | cut -d' ' -f5 | cut -d, -f1) - - # Fast math - GPUFLAGS += -use_fast_math - - # Extra build warnings - GPUFLAGS += $(XCOMPILERFLAG) -Wunused-parameter - ###GPUFLAGS += $(XCOMPILERFLAG) -Wall $(XCOMPILERFLAG) -Wextra $(XCOMPILERFLAG) -Wshadow - - # CUDA includes and NVTX - GPUFLAGS += $(CUDA_INC) $(USE_NVTX) - - # C++ standard - GPUFLAGS += -std=c++17 # need CUDA >= 11.2 (see #333): this is enforced in mgOnGpuConfig.h - - # For nvcc, use -maxrregcount to control the maximum number of registries (this does not exist in hipcc) - # Without -maxrregcount: baseline throughput: 6.5E8 (16384 32 12) up to 7.3E8 (65536 128 12) - ###GPUFLAGS+= --maxrregcount 160 # improves throughput: 6.9E8 (16384 32 12) up to 7.7E8 (65536 128 12) - ###GPUFLAGS+= --maxrregcount 128 # improves throughput: 7.3E8 (16384 32 12) up to 7.6E8 (65536 128 12) - ###GPUFLAGS+= --maxrregcount 96 # degrades throughput: 4.1E8 (16384 32 12) up to 4.5E8 (65536 128 12) - ###GPUFLAGS+= --maxrregcount 64 # degrades throughput: 1.7E8 (16384 32 12) flat at 1.7E8 (65536 128 12) - - # Set the host C++ compiler for nvcc via "-ccbin " - # (NB issue #505: this must be a single word, "clang++ --gcc-toolchain..." is not supported) - GPUFLAGS += -ccbin $(shell which $(subst ccache ,,$(CXX))) - - # Allow newer (unsupported) C++ compilers with older versions of CUDA if ALLOW_UNSUPPORTED_COMPILER_IN_CUDA is set (#504) - ifneq ($(origin ALLOW_UNSUPPORTED_COMPILER_IN_CUDA),undefined) - GPUFLAGS += -allow-unsupported-compiler - endif - -else ifeq ($(BACKEND),hip) - - # Set GPUCC as $(HIP_HOME)/bin/hipcc (it was already checked above that this exists) - GPUCC = $(HIP_HOME)/bin/hipcc - XCOMPILERFLAG = - GPULANGUAGE = hip - GPUSUFFIX = hip - - # Optimization flags - override OPTFLAGS = -O2 # work around "Memory access fault" in gq_ttq for HIP #806: disable hipcc -O3 optimizations - GPUFLAGS = $(foreach opt, $(OPTFLAGS), $(XCOMPILERFLAG) $(opt)) - - # DEBUG FLAGS (for #806: see https://hackmd.io/@gmarkoma/lumi_finland) - ###GPUFLAGS += -ggdb # FOR DEBUGGING ONLY - - # AMD HIP architecture flags - GPUARCHFLAGS = --offload-arch=gfx90a - GPUFLAGS += $(GPUARCHFLAGS) - - # Other AMD-specific flags - GPUFLAGS += -target x86_64-linux-gnu -DHIP_PLATFORM=amd - - # Fast math (is -DHIP_FAST_MATH equivalent to -ffast-math?) - GPUFLAGS += -DHIP_FAST_MATH - - # Extra build warnings - ###GPUFLAGS += $(XCOMPILERFLAG) -Wall $(XCOMPILERFLAG) -Wextra $(XCOMPILERFLAG) -Wshadow - - # HIP includes - HIP_INC = -I$(HIP_HOME)/include/ - GPUFLAGS += $(HIP_INC) - - # C++ standard - GPUFLAGS += -std=c++17 - -else - - # Backend is neither cuda nor hip - override GPUCC= - override GPUFLAGS= - - # Sanity check, this should never happen: if GPUCC is empty, then this is a C++ build, i.e. BACKEND is neither cuda nor hip. - # In practice, in the following, "ifeq ($(GPUCC),)" is equivalent to "ifneq ($(findstring cpp,$(BACKEND)),)". - # Conversely, note that GPUFLAGS is non-empty also for C++ builds, but it is never used in that case. - ifeq ($(findstring cpp,$(BACKEND)),) - $(error INTERNAL ERROR! Unknown backend BACKEND='$(BACKEND)': supported backends are $(foreach backend,$(SUPPORTED_BACKENDS),'$(backend)')) - endif - -endif - -# Export GPUCC, GPUFLAGS, GPULANGUAGE, GPUSUFFIX (so that there is no need to check/define them again in cudacpp_src.mk) -export GPUCC -export GPUFLAGS -export GPULANGUAGE -export GPUSUFFIX - -#------------------------------------------------------------------------------- - -#=== Configure ccache for C++ and CUDA/HIP builds - -# Enable ccache only if USECCACHE=1 -ifeq ($(USECCACHE)$(shell echo $(CXX) | grep ccache),1) - override CXX:=ccache $(CXX) -endif -#ifeq ($(USECCACHE)$(shell echo $(AR) | grep ccache),1) -# override AR:=ccache $(AR) -#endif -ifneq ($(GPUCC),) - ifeq ($(USECCACHE)$(shell echo $(GPUCC) | grep ccache),1) - override GPUCC:=ccache $(GPUCC) - endif -endif - -#------------------------------------------------------------------------------- - -#=== Configure common compiler flags for C++ and CUDA/HIP - -INCFLAGS = -I. -OPTFLAGS = -O3 # this ends up in GPUFLAGS too (should it?), cannot add -Ofast or -ffast-math here - -# Dependency on src directory -ifeq ($(GPUCC),) -MG5AMC_COMMONLIB = mg5amc_common_cpp -else -MG5AMC_COMMONLIB = mg5amc_common_$(GPUSUFFIX) -endif -LIBFLAGS = -L$(LIBDIR) -l$(MG5AMC_COMMONLIB) -INCFLAGS += -I../../src - -# Compiler-specific googletest build directory (#125 and #738) -ifneq ($(shell $(CXX) --version | grep '^Intel(R) oneAPI DPC++/C++ Compiler'),) - override CXXNAME = icpx$(shell $(CXX) --version | head -1 | cut -d' ' -f5) -else ifneq ($(shell $(CXX) --version | egrep '^clang'),) - override CXXNAME = clang$(shell $(CXX) --version | head -1 | cut -d' ' -f3) -else ifneq ($(shell $(CXX) --version | grep '^g++ (GCC)'),) - override CXXNAME = gcc$(shell $(CXX) --version | head -1 | cut -d' ' -f3) -else - override CXXNAME = unknown -endif -###$(info CXXNAME=$(CXXNAME)) -override CXXNAMESUFFIX = _$(CXXNAME) - -# Export CXXNAMESUFFIX (so that there is no need to check/define it again in cudacpp_test.mk) -export CXXNAMESUFFIX - -# Dependency on test directory -# Within the madgraph4gpu git repo: by default use a common gtest installation in /test (optionally use an external or local gtest) -# Outside the madgraph4gpu git repo: by default do not build the tests (optionally use an external or local gtest) -# Do not build the tests if USEGTEST is equal to 0 (default inside launch_plugin.py, see https://github.com/madgraph5/madgraph4gpu/issues/878) -###GTEST_ROOT = /cvmfs/sft.cern.ch/lcg/releases/gtest/1.11.0-21e8c/x86_64-centos8-gcc11-opt/# example of an external gtest installation -###LOCALGTEST = yes# comment this out (or use make LOCALGTEST=yes) to build tests using a local gtest installation -TESTDIRCOMMON = ../../../../../test -TESTDIRLOCAL = ../../test -ifeq ($(USEGTEST),0) - TESTDIR= - GTEST_ROOT= -else ifneq ($(wildcard $(GTEST_ROOT)),) - TESTDIR= -else ifneq ($(LOCALGTEST),) - TESTDIR=$(TESTDIRLOCAL) - GTEST_ROOT=$(TESTDIR)/googletest/install$(CXXNAMESUFFIX) -else ifneq ($(wildcard ../../../../../epochX/cudacpp/CODEGEN),) - TESTDIR=$(TESTDIRCOMMON) - GTEST_ROOT= $(TESTDIR)/googletest/install$(CXXNAMESUFFIX) -else - TESTDIR= -endif -ifneq ($(GTEST_ROOT),) - GTESTLIBDIR = $(GTEST_ROOT)/lib64/ - GTESTLIBS = $(GTESTLIBDIR)/libgtest.a - GTESTINC = -I$(GTEST_ROOT)/include -else - GTESTLIBDIR = - GTESTLIBS = - GTESTINC = -endif -###$(info GTEST_ROOT = $(GTEST_ROOT)) -###$(info LOCALGTEST = $(LOCALGTEST)) -###$(info TESTDIR = $(TESTDIR)) - -#------------------------------------------------------------------------------- - -#=== Configure PowerPC-specific compiler flags for C++ and CUDA/HIP - -# PowerPC-specific CXX compiler flags (being reviewed) -ifeq ($(UNAME_P),ppc64le) - CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3% both for cppnone and cppsse4 - # Throughput references without the extra flags below: cppnone=1.41-1.42E6, cppsse4=2.15-2.19E6 - ###CXXFLAGS+= -DNO_WARN_X86_INTRINSICS # no change - ###CXXFLAGS+= -fpeel-loops # no change - ###CXXFLAGS+= -funroll-loops # gains ~1% for cppnone, loses ~1% for cppsse4 - ###CXXFLAGS+= -ftree-vectorize # no change - ###CXXFLAGS+= -flto # would increase to cppnone=4.08-4.12E6, cppsse4=4.99-5.03E6! -else - ###CXXFLAGS+= -flto # also on Intel this would increase throughputs by a factor 2 to 4... - ######CXXFLAGS+= -fno-semantic-interposition # no benefit (neither alone, nor combined with -flto) -endif - -# PowerPC-specific CUDA/HIP compiler flags (to be reviewed!) -ifeq ($(UNAME_P),ppc64le) - GPUFLAGS+= $(XCOMPILERFLAG) -mno-float128 -endif - -#------------------------------------------------------------------------------- - -#=== Configure defaults for OMPFLAGS - -# Disable OpenMP by default: enable OpenMP only if USEOPENMP=1 (#758) -ifeq ($(USEOPENMP),1) - ###$(info USEOPENMP==1: will build with OpenMP if possible) - ifneq ($(findstring hipcc,$(GPUCC)),) - override OMPFLAGS = # disable OpenMP MT when using hipcc #802 - else ifneq ($(shell $(CXX) --version | egrep '^Intel'),) - override OMPFLAGS = -fopenmp - ###override OMPFLAGS = # disable OpenMP MT on Intel (was ok without GPUCC but not ok with GPUCC before #578) - else ifneq ($(shell $(CXX) --version | egrep '^clang version 16'),) - ###override OMPFLAGS = # disable OpenMP on clang16 #904 - $(error OpenMP is not supported by cudacpp on clang16 - issue #904) - else ifneq ($(shell $(CXX) --version | egrep '^clang version 17'),) - ###override OMPFLAGS = # disable OpenMP on clang17 #904 - $(error OpenMP is not supported by cudacpp on clang17 - issue #904) - else ifneq ($(shell $(CXX) --version | egrep '^(clang)'),) - override OMPFLAGS = -fopenmp - ###override OMPFLAGS = # disable OpenMP MT on clang (was not ok without or with nvcc before #578) - ###else ifneq ($(shell $(CXX) --version | egrep '^(Apple clang)'),) # AV for Mac (Apple clang compiler) - else ifeq ($(UNAME_S),Darwin) # OM for Mac (any compiler) - override OMPFLAGS = # AV disable OpenMP MT on Apple clang (builds fail in the CI #578) - ###override OMPFLAGS = -fopenmp # OM reenable OpenMP MT on Apple clang? (AV Oct 2023: this still fails in the CI) - else - override OMPFLAGS = -fopenmp # enable OpenMP MT by default on all other platforms - ###override OMPFLAGS = # disable OpenMP MT on all other platforms (default before #575) - endif -else - ###$(info USEOPENMP!=1: will build without OpenMP) - override OMPFLAGS = -endif - -#------------------------------------------------------------------------------- - -#=== Configure defaults and check if user-defined choices exist for RNDGEN (legacy!), HASCURAND, HASHIPRAND - -# If the legacy RNDGEN exists, this take precedence over any HASCURAND choice (but a warning is printed out) -###$(info RNDGEN=$(RNDGEN)) -ifneq ($(RNDGEN),) - $(warning Environment variable RNDGEN is no longer supported, please use HASCURAND instead!) - ifeq ($(RNDGEN),hasCurand) - override HASCURAND = $(RNDGEN) - else ifeq ($(RNDGEN),hasNoCurand) - override HASCURAND = $(RNDGEN) - else ifneq ($(RNDGEN),hasNoCurand) - $(error Unknown RNDGEN='$(RNDGEN)': only 'hasCurand' and 'hasNoCurand' are supported - but use HASCURAND instead!) - endif -endif - -# Set the default HASCURAND (curand random number generator) choice, if no prior choice exists for HASCURAND -# (NB: allow HASCURAND=hasCurand even if $(GPUCC) does not point to nvcc: assume CUDA_HOME was defined correctly...) -ifeq ($(HASCURAND),) - ifeq ($(GPUCC),) # CPU-only build - ifeq ($(CUDA_INC),) - # $(CUDA_HOME)/include/ does not exist (see #965) - override HASCURAND = hasNoCurand - else ifeq ($(wildcard $(CUDA_HOME)/include/curand.h),) - # $(CUDA_HOME)/include/ exists but CURAND headers do not exist? (see #965) - override HASCURAND = hasNoCurand - else - # By default, assume that curand is installed if a CUDA installation exists - override HASCURAND = hasCurand - endif - else ifeq ($(findstring nvcc,$(GPUCC)),nvcc) # Nvidia GPU build - # By default, assume that curand is installed if a CUDA build is requested - override HASCURAND = hasCurand - else # non-Nvidia GPU build - override HASCURAND = hasNoCurand - endif -endif - -# Set the default HASHIPRAND (hiprand random number generator) choice, if no prior choice exists for HASHIPRAND -# (NB: allow HASHIPRAND=hasHiprand even if $(GPUCC) does not point to hipcc: assume HIP_HOME was defined correctly...) -ifeq ($(HASHIPRAND),) - ifeq ($(GPUCC),) # CPU-only build - override HASHIPRAND = hasNoHiprand - else ifeq ($(findstring hipcc,$(GPUCC)),hipcc) # AMD GPU build - override HASHIPRAND = hasHiprand - else # non-AMD GPU build - override HASHIPRAND = hasNoHiprand - endif -endif - -#------------------------------------------------------------------------------- - -#=== Set the CUDA/HIP/C++ compiler flags appropriate to user-defined choices of AVX, FPTYPE, HELINL, HRDCOD - -# Set the build flags appropriate to OMPFLAGS -$(info OMPFLAGS=$(OMPFLAGS)) -CXXFLAGS += $(OMPFLAGS) - -# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cppnone") -# [NB MGONGPU_PVW512 is needed because "-mprefer-vector-width=256" is not exposed in a macro] -# [See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96476] -ifeq ($(UNAME_P),ppc64le) - ifeq ($(BACKEND),cppsse4) - override AVXFLAGS = -D__SSE4_2__ # Power9 VSX with 128 width (VSR registers) - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - endif -else ifeq ($(UNAME_P),arm) - ifeq ($(BACKEND),cppsse4) - override AVXFLAGS = -D__SSE4_2__ # ARM NEON with 128 width (Q/quadword registers) - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - endif -else ifneq ($(shell $(CXX) --version | grep ^nvc++),) # support nvc++ #531 - ifeq ($(BACKEND),cppnone) - override AVXFLAGS = -mno-sse3 # no SIMD - else ifeq ($(BACKEND),cppsse4) - override AVXFLAGS = -mno-avx # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) - override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) - override AVXFLAGS = -march=skylake -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) - override AVXFLAGS = -march=skylake -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) - endif -else - ifeq ($(BACKEND),cppnone) - override AVXFLAGS = -march=x86-64 # no SIMD (see #588) - else ifeq ($(BACKEND),cppsse4) - override AVXFLAGS = -march=nehalem # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) - override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) - override AVXFLAGS = -march=skylake-avx512 -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) - override AVXFLAGS = -march=skylake-avx512 -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) - endif -endif -# For the moment, use AVXFLAGS everywhere (in C++ builds): eventually, use them only in encapsulated implementations? -ifeq ($(GPUCC),) - CXXFLAGS+= $(AVXFLAGS) -endif - -# Set the build flags appropriate to each FPTYPE choice (example: "make FPTYPE=f") -$(info FPTYPE='$(FPTYPE)') -ifeq ($(FPTYPE),d) - CXXFLAGS += -DMGONGPU_FPTYPE_DOUBLE -DMGONGPU_FPTYPE2_DOUBLE - GPUFLAGS += -DMGONGPU_FPTYPE_DOUBLE -DMGONGPU_FPTYPE2_DOUBLE -else ifeq ($(FPTYPE),f) - CXXFLAGS += -DMGONGPU_FPTYPE_FLOAT -DMGONGPU_FPTYPE2_FLOAT - GPUFLAGS += -DMGONGPU_FPTYPE_FLOAT -DMGONGPU_FPTYPE2_FLOAT -else ifeq ($(FPTYPE),m) - CXXFLAGS += -DMGONGPU_FPTYPE_DOUBLE -DMGONGPU_FPTYPE2_FLOAT - GPUFLAGS += -DMGONGPU_FPTYPE_DOUBLE -DMGONGPU_FPTYPE2_FLOAT -else - $(error Unknown FPTYPE='$(FPTYPE)': only 'd', 'f' and 'm' are supported) -endif - -# Set the build flags appropriate to each HELINL choice (example: "make HELINL=1") -$(info HELINL='$(HELINL)') -ifeq ($(HELINL),1) - CXXFLAGS += -DMGONGPU_INLINE_HELAMPS - GPUFLAGS += -DMGONGPU_INLINE_HELAMPS -else ifneq ($(HELINL),0) - $(error Unknown HELINL='$(HELINL)': only '0' and '1' are supported) -endif - -# Set the build flags appropriate to each HRDCOD choice (example: "make HRDCOD=1") -$(info HRDCOD='$(HRDCOD)') -ifeq ($(HRDCOD),1) - CXXFLAGS += -DMGONGPU_HARDCODE_PARAM - GPUFLAGS += -DMGONGPU_HARDCODE_PARAM -else ifneq ($(HRDCOD),0) - $(error Unknown HRDCOD='$(HRDCOD)': only '0' and '1' are supported) -endif - -#=== Set the CUDA/HIP/C++ compiler and linker flags appropriate to user-defined choices of HASCURAND, HASHIPRAND - -$(info HASCURAND=$(HASCURAND)) -$(info HASHIPRAND=$(HASHIPRAND)) -override RNDCXXFLAGS= -override RNDLIBFLAGS= - -# Set the RNDCXXFLAGS and RNDLIBFLAGS build flags appropriate to each HASCURAND choice (example: "make HASCURAND=hasNoCurand") -ifeq ($(HASCURAND),hasNoCurand) - override RNDCXXFLAGS += -DMGONGPU_HAS_NO_CURAND -else ifeq ($(HASCURAND),hasCurand) - override RNDLIBFLAGS += -L$(CUDA_HOME)/lib64/ -lcurand # NB: -lcuda is not needed here! -else - $(error Unknown HASCURAND='$(HASCURAND)': only 'hasCurand' and 'hasNoCurand' are supported) -endif - -# Set the RNDCXXFLAGS and RNDLIBFLAGS build flags appropriate to each HASHIPRAND choice (example: "make HASHIPRAND=hasNoHiprand") -ifeq ($(HASHIPRAND),hasNoHiprand) - override RNDCXXFLAGS += -DMGONGPU_HAS_NO_HIPRAND -else ifeq ($(HASHIPRAND),hasHiprand) - override RNDLIBFLAGS += -L$(HIP_HOME)/lib/ -lhiprand -else ifneq ($(HASHIPRAND),hasHiprand) - $(error Unknown HASHIPRAND='$(HASHIPRAND)': only 'hasHiprand' and 'hasNoHiprand' are supported) -endif - -#$(info RNDCXXFLAGS=$(RNDCXXFLAGS)) -#$(info RNDLIBFLAGS=$(RNDLIBFLAGS)) - -#------------------------------------------------------------------------------- - -#=== Configure Position-Independent Code -CXXFLAGS += -fPIC -GPUFLAGS += $(XCOMPILERFLAG) -fPIC - -#------------------------------------------------------------------------------- - -#=== Configure channelid debugging -ifneq ($(MG5AMC_CHANNELID_DEBUG),) - CXXFLAGS += -DMGONGPU_CHANNELID_DEBUG - GPUFLAGS += -DMGONGPU_CHANNELID_DEBUG -endif - -#------------------------------------------------------------------------------- - -#=== Configure build directories and build lockfiles === - -# Build lockfile "full" tag (defines full specification of build options that cannot be intermixed) -# (Rationale: avoid mixing of builds with different random number generators) -override TAG = $(patsubst cpp%,%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD)_$(HASCURAND)_$(HASHIPRAND) - -# Export TAG (so that there is no need to check/define it again in cudacpp_src.mk) -export TAG - -# Build directory: current directory by default, or build.$(DIRTAG) if USEBUILDDIR==1 -override BUILDDIR = $(CUDACPP_BUILDDIR) -ifeq ($(USEBUILDDIR),1) - override LIBDIR = ../../lib/$(BUILDDIR) - override LIBDIRRPATH = '$$ORIGIN/../$(LIBDIR)' - $(info Building in BUILDDIR=$(BUILDDIR) for tag=$(TAG) (USEBUILDDIR == 1)) -else - override LIBDIR = ../../lib - override LIBDIRRPATH = '$$ORIGIN/$(LIBDIR)' - $(info Building in BUILDDIR=$(BUILDDIR) for tag=$(TAG) (USEBUILDDIR != 1)) -endif -###override INCDIR = ../../include -###$(info Building in BUILDDIR=$(BUILDDIR) for tag=$(TAG)) - -# On Linux, set rpath to LIBDIR to make it unnecessary to use LD_LIBRARY_PATH -# Use relative paths with respect to the executables or shared libraries ($ORIGIN on Linux) -# On Darwin, building libraries with absolute paths in LIBDIR makes this unnecessary -ifeq ($(UNAME_S),Darwin) - override CXXLIBFLAGSRPATH = - override GPULIBFLAGSRPATH = - override CXXLIBFLAGSRPATH2 = - override GPULIBFLAGSRPATH2 = -else - # RPATH to gpu/cpp libs when linking executables - override CXXLIBFLAGSRPATH = -Wl,-rpath=$(LIBDIRRPATH) - override GPULIBFLAGSRPATH = -Xlinker -rpath=$(LIBDIRRPATH) - # RPATH to common lib when linking gpu/cpp libs - override CXXLIBFLAGSRPATH2 = -Wl,-rpath='$$ORIGIN' - override GPULIBFLAGSRPATH2 = -Xlinker -rpath='$$ORIGIN' -endif - -# Setting LD_LIBRARY_PATH or DYLD_LIBRARY_PATH in the RUNTIME is no longer necessary (neither on Linux nor on Mac) -override RUNTIME = - diff --git a/madgraph/various/banner.py b/madgraph/various/banner.py index 5fa8336294..4779e9b1f8 100755 --- a/madgraph/various/banner.py +++ b/madgraph/various/banner.py @@ -803,7 +803,7 @@ class ProcCard(list): '#* *\n' + \ '#* Command File for MadGraph5_aMC@NLO *\n' + \ '#* *\n' + \ - '#* run as ./bin/mg5_aMC filename *\n' + \ + '#* run as ./bin/madgraph filename *\n' + \ '#* *\n' + \ '#************************************************************\n' @@ -6463,8 +6463,8 @@ def default_setup(self): # ----------------------------- [run] -------------------------- self.add_toml_param('run', 'run_name', "run", gridpack=True) - self.add_toml_param('run', 'devices', ["cppnone"], typelist=str, gridpack=True, - comment="options: cuda, hip, cpp, cppnone, cppsse4, cppavx2, cpp512y, cpp512z, cppauto") + self.add_toml_param('run', 'devices', ["cpu"], typelist=str, gridpack=True, + comment="options: cpu (auto-detected SIMD width), cpu_scalar, cpu_128b, cpu_256b, cpu_512b_y, cpu_512b, cuda, hip") self.add_toml_param('run', 'simd_vector_size', -1, comment="-1 chooses automatically; on x86: 1, 4, 8; on Apple silicon: 1, 2") self.add_toml_param('run', 'cpu_thread_pool_size', -1, gridpack=True, @@ -6486,9 +6486,18 @@ def default_setup(self): # ----------------------------- [beam] ------------------------- self.add_toml_param('beam', 'e_cm', 13000.0) self.add_toml_param('beam', 'leptonic', False) - self.add_toml_param('beam', 'pdf', "NNPDF23_lo_as_0130_qed") - self.add_toml_param('beam', 'fixed_ren_scale', True) - self.add_toml_param('beam', 'fixed_fact_scale', True) + # NNPDF4.0 LO, 5-flavour scheme, alpha_s(M_Z) = 0.118. This is the + # MC-generator-oriented variant of the NNPDF4.0 LO set: a single member + # and ~0.7 MB, versus ~54 MB for NNPDF40_lo_as_01180. NNPDF4.0 has no + # 4-flavour LO counterpart, so there is no scheme-dependent choice to + # make here: this one set is used whatever the b-quark treatment. + self.add_toml_param('beam', 'pdf', "NNPDF40MC_lo_as_01180") + # Default to the dynamical scale set by dynamical_scale_choice below + # (half_transverse_mass, i.e. HT/2) rather than to the fixed ren_scale + # / fact_scale values. Those fixed values are kept as the fallback used + # when a user turns either of these back on. + self.add_toml_param('beam', 'fixed_ren_scale', False) + self.add_toml_param('beam', 'fixed_fact_scale', False) self.add_toml_param('beam', 'ren_scale', 91.188) self.add_toml_param('beam', 'fact_scale1', 91.188) self.add_toml_param('beam', 'fact_scale2', 91.188) @@ -6662,14 +6671,18 @@ def __getitem__(self, name): 'dparameter', 'lhaid', 'iseed', 'python_seed', } - # mg7 dynamical_scale_choice name -> legacy integer code - # NOTE: mapping to confirm; only relevant for a dynamical-scale run (fixed - # scales, the mg7 default, are handled through the event scale directly). + # mg7 dynamical_scale_choice name -> legacy integer code. This is the + # inverse of _LO_DYNSCALE_MAP below and must stay consistent with it, and + # with the legacy codes documented on the LO run_card's + # dynamical_scale_choice: 1 = sum of transverse energy, 2 = HT (sum of + # transverse mass), 3 = HT/2, 4 = partonic centre-of-mass energy. + # Only consulted for a dynamical-scale run; a fixed-scale run returns -1 + # before reaching here and is handled through the event scale directly. _dyn_scale_legacy = { 'partonic_energy': 4, 'transverse_mass': 2, 'half_transverse_mass': 3, - 'transverse_energy': 3, + 'transverse_energy': 1, } def _legacy_compat(self, key): diff --git a/madgraph/various/process_checks.py b/madgraph/various/process_checks.py index 423ec5d603..87a5566ea7 100755 --- a/madgraph/various/process_checks.py +++ b/madgraph/various/process_checks.py @@ -4084,7 +4084,7 @@ def check_language(process_definition, param_card=None, options=None, cpp_compiler = (hasattr(cmd, 'options') and cmd.options.get('cpp_compiler')) or 'g++' - # MG7 (standalone_mg7 / madmatrix) availability: needs the madmatrix + # MG7 (standalone / madmatrix) availability: needs the madmatrix # package, a C++ compiler and make. Its check_sa.exe "matrix" mode # evaluates the same phase-space point as the Fortran/C++ drivers and # prints the per-flavor PDG / matrix-element lines in the same format. @@ -4277,7 +4277,7 @@ def _parse_sa_output(text, target_pdgs=None): # tuple. All individual-flavor procs share the same matrix element code. sa_f_output_cache = {} sa_cpp_output_cache = {} - # Cache of MG7 (standalone_mg7) check_sa.exe matrix-mode output text. + # Cache of MG7 (standalone / madmatrix) check_sa.exe matrix-mode output text. sa_mg7_output_cache = {} energy_str = str(energy) @@ -4314,7 +4314,7 @@ def _parse_sa_output(text, target_pdgs=None): parent_f = tempfile.mkdtemp(prefix='mg5_langcheck_f_') sa_dir_f = pjoin(parent_f, 'sa_f') try: - opt_f = {'sa_symmetry': False, 'export_format': 'standalone', + opt_f = {'sa_symmetry': False, 'export_format': 'standalone_fortran', 'mp': False, 'v5_model': True, 'output_options': {'noeps': 'True'}} exporter_f = export_v4.ProcessExporterFortranSA(sa_dir_f, opt_f) @@ -4402,7 +4402,7 @@ def _parse_sa_output(text, target_pdgs=None): out_cpp_text = sa_cpp_output_cache.get(sa_key) - # ── MG7 SA (standalone_mg7 / madmatrix) ────────────────────────────── + # ── MG7 SA (standalone / madmatrix) ───────────────────────────────── out_mg7_text = None if has_mg7: if sa_key not in sa_mg7_output_cache: @@ -4410,7 +4410,7 @@ def _parse_sa_output(text, target_pdgs=None): parent_mg7 = tempfile.mkdtemp(prefix='mg5_langcheck_mg7_') sa_dir_mg7 = pjoin(parent_mg7, 'sa_mg7') try: - opt_mg7 = {'export_format': 'standalone_mg7', + opt_mg7 = {'export_format': 'standalone', 'mp': False, 'v5_model': True, 'cpp_compiler': cpp_compiler, 'output_options': {}} @@ -4432,7 +4432,7 @@ def _parse_sa_output(text, target_pdgs=None): if p_dirs_mg7: check_dir_mg7 = pjoin(sa_dir_mg7, 'SubProcesses', p_dirs_mg7[0]) - backends = ["cppnone", "cppsse4", "cppavx2", "cpp512z", "cuda", "hip"] + backends = ["cpu_scalar", "cpu_128b", "cpu_256b", "cpu_512b", "cuda", "hip"] for backend in backends: with open(os.devnull, 'w') as devnull: ret = subprocess.call(f'make clean && make BACKEND={backend} USEBUILDDIR=1', shell=True, cwd=check_dir_mg7, diff --git a/madmatrix/MadtRex/makefiles/cudacpp_driver.mk b/madmatrix/MadtRex/makefiles/cudacpp_driver.mk index f01fc2c780..16b5eb3534 100644 --- a/madmatrix/MadtRex/makefiles/cudacpp_driver.mk +++ b/madmatrix/MadtRex/makefiles/cudacpp_driver.mk @@ -55,32 +55,32 @@ endif #------------------------------------------------------------------------------- -#=== Redefine BACKEND if the current value is 'cppauto' +#=== Redefine BACKEND if the current value is 'cpu' -# Set the default BACKEND choice corresponding to 'cppauto' (the 'best' C++ vectorization available) -ifeq ($(BACKEND),cppauto) +# Set the default BACKEND choice corresponding to 'cpu' (the 'best' C++ vectorization available) +ifeq ($(BACKEND),cpu) ifeq ($(UNAME_P),ppc64le) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifneq (,$(filter $(UNAME_M),arm64 aarch64)) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifeq ($(wildcard /proc/cpuinfo),) - override BACKEND = cppnone + override BACKEND = cpu_scalar ###$(warning Using BACKEND='$(BACKEND)' because host SIMD features cannot be read from /proc/cpuinfo) else ifeq ($(shell grep -m1 -c avx512vl /proc/cpuinfo)$(shell $(CXX) --version | grep ^clang),1) - override BACKEND = cpp512y + override BACKEND = cpu_512b_y else ifeq ($(shell grep -m1 -c avx2 /proc/cpuinfo),1) - override BACKEND = cppavx2 + override BACKEND = cpu_256b ###ifneq ($(shell grep -m1 -c avx512vl /proc/cpuinfo),1) ### $(warning Using BACKEND='$(BACKEND)' because host does not support avx512vl) ###else ### $(warning Using BACKEND='$(BACKEND)' because this is faster than avx512vl for clang) ###endif else ifeq ($(shell grep -m1 -c sse4_2 /proc/cpuinfo),1) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else - override BACKEND = cppnone + override BACKEND = cpu_scalar endif - $(info BACKEND=$(BACKEND) (was cppauto)) + $(info BACKEND=$(BACKEND) (was cpu)) else $(info BACKEND='$(BACKEND)') endif @@ -254,9 +254,9 @@ else override GPUFLAGS= # Sanity check, this should never happen: if GPUCC is empty, then this is a C++ build, i.e. BACKEND is neither cuda nor hip. - # In practice, in the following, "ifeq ($(GPUCC),)" is equivalent to "ifneq ($(findstring cpp,$(BACKEND)),)". + # In practice, in the following, "ifeq ($(GPUCC),)" is equivalent to "ifneq ($(findstring cpu,$(BACKEND)),)". # Conversely, note that GPUFLAGS is non-empty also for C++ builds, but it is never used in that case. - ifeq ($(findstring cpp,$(BACKEND)),) + ifeq ($(findstring cpu,$(BACKEND)),) $(error INTERNAL ERROR! Unknown backend BACKEND='$(BACKEND)': supported backends are $(foreach backend,$(SUPPORTED_BACKENDS),'$(backend)')) endif @@ -325,13 +325,13 @@ export CXXNAMESUFFIX # PowerPC-specific CXX compiler flags (being reviewed) ifeq ($(UNAME_P),ppc64le) - CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cppnone and cppsse4 - # Throughput references without the extra flags below: cppnone=1.41-1.42E6, cppsse4=2.15-2.19E6 + CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cpu_scalar and cpu_128b + # Throughput references without the extra flags below: cpu_scalar=1.41-1.42E6, cpu_128b=2.15-2.19E6 ###CXXFLAGS+= -DNO_WARN_X86_INTRINSICS # no change ###CXXFLAGS+= -fpeel-loops # no change - ###CXXFLAGS+= -funroll-loops # gains ~1%% for cppnone, loses ~1%% for cppsse4 + ###CXXFLAGS+= -funroll-loops # gains ~1%% for cpu_scalar, loses ~1%% for cpu_128b ###CXXFLAGS+= -ftree-vectorize # no change - ###CXXFLAGS+= -flto # would increase to cppnone=4.08-4.12E6, cppsse4=4.99-5.03E6! + ###CXXFLAGS+= -flto # would increase to cpu_scalar=4.08-4.12E6, cpu_128b=4.99-5.03E6! else ###CXXFLAGS+= -flto # also on Intel this would increase throughputs by a factor 2 to 4... ######CXXFLAGS+= -fno-semantic-interposition # no benefit (neither alone, nor combined with -flto) @@ -430,66 +430,66 @@ endif $(info OMPFLAGS=$(OMPFLAGS)) CXXFLAGS += $(OMPFLAGS) -# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cppnone") +# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cpu_scalar") # [NB MGONGPU_PVW512 is needed because "-mprefer-vector-width=256" is not exposed in a macro] # [Use 'g++ -E -dM - < /dev/null' to check which #define's are enabled] # [See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96476] ifeq ($(UNAME_P),ppc64le) - ifeq ($(BACKEND),cppsse4) + ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -D__SSE4_2__ # Power9 VSX with 128 width (VSR registers) - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) endif else ifeq ($(UNAME_M),arm64) # ARM on Apple silicon - ifeq ($(BACKEND),cppnone) # this internally undefines __ARM_NEON + ifeq ($(BACKEND),cpu_scalar) # this internally undefines __ARM_NEON override AVXFLAGS = -DMGONGPU_NOARMNEON - else ifeq ($(BACKEND),cppsse4) # __ARM_NEON is always defined on Apple silicon + else ifeq ($(BACKEND),cpu_128b) # __ARM_NEON is always defined on Apple silicon override AVXFLAGS = - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) endif else ifeq ($(UNAME_M),aarch64) # ARM on Linux - ifeq ($(BACKEND),cppnone) # +nosimd ensures __ARM_NEON is absent + ifeq ($(BACKEND),cpu_scalar) # +nosimd ensures __ARM_NEON is absent override AVXFLAGS = -march=armv8-a+nosimd - else ifeq ($(BACKEND),cppsse4) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) + else ifeq ($(BACKEND),cpu_128b) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) override AVXFLAGS = -march=armv8-a+simd - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) endif else ifneq ($(shell $(CXX) --version | grep ^nvc++),) # support nvc++ #531 - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -mno-sse3 # no SIMD - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -mno-avx # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif else - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -march=x86-64 # no SIMD (see #588) - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -march=nehalem # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake-avx512 -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake-avx512 -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif endif @@ -571,7 +571,7 @@ GPUFLAGS += $(XCOMPILERFLAG) -fPIC # Build lockfile "full" tag (defines full specification of build options that cannot be intermixed) # (Rationale: avoid mixing of builds with different random number generators) -override TAG = $(patsubst cpp%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD)_$(HASCURAND)_$(HASHIPRAND) +override TAG = $(patsubst cpu_%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD)_$(HASCURAND)_$(HASHIPRAND) # Export TAG (so that there is no need to check/define it again in cudacpp_src.mk) export TAG @@ -724,23 +724,23 @@ bldhip: bldnone: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppnone -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_scalar -f $(CUDACPP_MAKEFILE) bldsse4: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppsse4 -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_128b -f $(CUDACPP_MAKEFILE) bldavx2: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppavx2 -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_256b -f $(CUDACPP_MAKEFILE) bld512y: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512y -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b_y -f $(CUDACPP_MAKEFILE) bld512z: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512z -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b -f $(CUDACPP_MAKEFILE) ifeq ($(UNAME_P),ppc64le) ###bldavxs: $(INCDIR)/fbridge.inc bldnone bldsse4 diff --git a/madmatrix/MadtRex/makefiles/cudacpp_runner.mk b/madmatrix/MadtRex/makefiles/cudacpp_runner.mk index fed66e030f..c4b7449534 100644 --- a/madmatrix/MadtRex/makefiles/cudacpp_runner.mk +++ b/madmatrix/MadtRex/makefiles/cudacpp_runner.mk @@ -56,32 +56,32 @@ endif #------------------------------------------------------------------------------- -#=== Redefine BACKEND if the current value is 'cppauto' +#=== Redefine BACKEND if the current value is 'cpu' -# Set the default BACKEND choice corresponding to 'cppauto' (the 'best' C++ vectorization available) -ifeq ($(BACKEND),cppauto) +# Set the default BACKEND choice corresponding to 'cpu' (the 'best' C++ vectorization available) +ifeq ($(BACKEND),cpu) ifeq ($(UNAME_P),ppc64le) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifneq (,$(filter $(UNAME_M),arm64 aarch64)) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else ifeq ($(wildcard /proc/cpuinfo),) - override BACKEND = cppnone + override BACKEND = cpu_scalar ###$(warning Using BACKEND='$(BACKEND)' because host SIMD features cannot be read from /proc/cpuinfo) else ifeq ($(shell grep -m1 -c avx512vl /proc/cpuinfo)$(shell $(CXX) --version | grep ^clang),1) - override BACKEND = cpp512y + override BACKEND = cpu_512b_y else ifeq ($(shell grep -m1 -c avx2 /proc/cpuinfo),1) - override BACKEND = cppavx2 + override BACKEND = cpu_256b ###ifneq ($(shell grep -m1 -c avx512vl /proc/cpuinfo),1) ### $(warning Using BACKEND='$(BACKEND)' because host does not support avx512vl) ###else ### $(warning Using BACKEND='$(BACKEND)' because this is faster than avx512vl for clang) ###endif else ifeq ($(shell grep -m1 -c sse4_2 /proc/cpuinfo),1) - override BACKEND = cppsse4 + override BACKEND = cpu_128b else - override BACKEND = cppnone + override BACKEND = cpu_scalar endif - $(info BACKEND=$(BACKEND) (was cppauto)) + $(info BACKEND=$(BACKEND) (was cpu)) else $(info BACKEND='$(BACKEND)') endif @@ -175,8 +175,8 @@ endif # PowerPC-specific CXX compiler flags (being reviewed) ifeq ($(UNAME_P),ppc64le) - CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cppnone and cppsse4 - # Throughput references without the extra flags below: cppnone=1.41-1.42E6, cppsse4=2.15-2.19E6 + CXXFLAGS+= -mcpu=power9 -mtune=power9 # gains ~2-3%% both for cpu_scalar and cpu_128b + # Throughput references without the extra flags below: cpu_scalar=1.41-1.42E6, cpu_128b=2.15-2.19E6 else ###CXXFLAGS+= -flto # also on Intel this would increase throughputs by a factor 2 to 4... ######CXXFLAGS+= -fno-semantic-interposition # no benefit (neither alone, nor combined with -flto) @@ -275,66 +275,66 @@ endif $(info OMPFLAGS=$(OMPFLAGS)) CXXFLAGS += $(OMPFLAGS) -# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cppnone") +# Set the build flags appropriate to each BACKEND choice (example: "make BACKEND=cpu_scalar") # [NB MGONGPU_PVW512 is needed because "-mprefer-vector-width=256" is not exposed in a macro] # [Use 'g++ -E -dM - < /dev/null' to check which #define's are enabled] # [See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96476] ifeq ($(UNAME_P),ppc64le) - ifeq ($(BACKEND),cppsse4) + ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -D__SSE4_2__ # Power9 VSX with 128 width (VSR registers) - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on PowerPC for the moment) endif else ifeq ($(UNAME_M),arm64) # ARM on Apple silicon - ifeq ($(BACKEND),cppnone) # this internally undefines __ARM_NEON + ifeq ($(BACKEND),cpu_scalar) # this internally undefines __ARM_NEON override AVXFLAGS = -DMGONGPU_NOARMNEON - else ifeq ($(BACKEND),cppsse4) # __ARM_NEON is always defined on Apple silicon + else ifeq ($(BACKEND),cpu_128b) # __ARM_NEON is always defined on Apple silicon override AVXFLAGS = - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on ARM for the moment) endif else ifeq ($(UNAME_M),aarch64) # ARM on Linux - ifeq ($(BACKEND),cppnone) # +nosimd ensures __ARM_NEON is absent + ifeq ($(BACKEND),cpu_scalar) # +nosimd ensures __ARM_NEON is absent override AVXFLAGS = -march=armv8-a+nosimd - else ifeq ($(BACKEND),cppsse4) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) + else ifeq ($(BACKEND),cpu_128b) # +simd ensures __ARM_NEON is present (128 width Q/quadword registers) override AVXFLAGS = -march=armv8-a+simd - else ifeq ($(BACKEND),cppavx2) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512y) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) - else ifeq ($(BACKEND),cpp512z) - $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cppnone' and 'cppsse4' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_256b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b_y) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) + else ifeq ($(BACKEND),cpu_512b) + $(error Invalid SIMD BACKEND='$(BACKEND)': only 'cpu_scalar' and 'cpu_128b' are supported on aarch64 for the moment) endif else ifneq ($(shell $(CXX) --version | grep ^nvc++),) # support nvc++ #531 - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -mno-sse3 # no SIMD - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -mno-avx # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif else - ifeq ($(BACKEND),cppnone) + ifeq ($(BACKEND),cpu_scalar) override AVXFLAGS = -march=x86-64 # no SIMD (see #588) - else ifeq ($(BACKEND),cppsse4) + else ifeq ($(BACKEND),cpu_128b) override AVXFLAGS = -march=nehalem # SSE4.2 with 128 width (xmm registers) - else ifeq ($(BACKEND),cppavx2) + else ifeq ($(BACKEND),cpu_256b) override AVXFLAGS = -march=haswell # AVX2 with 256 width (ymm registers) [DEFAULT for clang] - else ifeq ($(BACKEND),cpp512y) + else ifeq ($(BACKEND),cpu_512b_y) override AVXFLAGS = -march=skylake-avx512 -mprefer-vector-width=256 # AVX512 with 256 width (ymm registers) [DEFAULT for gcc] - else ifeq ($(BACKEND),cpp512z) + else ifeq ($(BACKEND),cpu_512b) override AVXFLAGS = -march=skylake-avx512 -DMGONGPU_PVW512 # AVX512 with 512 width (zmm registers) endif endif @@ -416,7 +416,7 @@ GPUFLAGS += $(XCOMPILERFLAG) -fPIC # Build lockfile "full" tag (defines full specification of build options that cannot be intermixed) # (Rationale: avoid mixing of builds with different random number generators) -override TAG = $(patsubst cpp%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD)_$(HASCURAND)_$(HASHIPRAND) +override TAG = $(patsubst cpu_%%,%%,$(BACKEND))_$(FPTYPE)_inl$(HELINL)_hrd$(HRDCOD)_$(HASCURAND)_$(HASHIPRAND) # Export TAG (so that there is no need to check/define it again in cudacpp_src.mk) export TAG @@ -741,23 +741,23 @@ bldhip: bldnone: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppnone -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_scalar -f $(CUDACPP_MAKEFILE) bldsse4: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppsse4 -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_128b -f $(CUDACPP_MAKEFILE) bldavx2: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cppavx2 -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_256b -f $(CUDACPP_MAKEFILE) bld512y: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512y -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b_y -f $(CUDACPP_MAKEFILE) bld512z: @echo - $(MAKE) USEBUILDDIR=1 BACKEND=cpp512z -f $(CUDACPP_MAKEFILE) + $(MAKE) USEBUILDDIR=1 BACKEND=cpu_512b -f $(CUDACPP_MAKEFILE) ifeq ($(UNAME_P),ppc64le) ###bldavxs: $(INCDIR)/fbridge.inc bldnone bldsse4 diff --git a/madmatrix/__init__.py b/madmatrix/__init__.py index a76600e4a1..0eab42beec 100644 --- a/madmatrix/__init__.py +++ b/madmatrix/__init__.py @@ -6,10 +6,11 @@ PLUGIN_NAME = __name__ # PLUGIN_NAME can be one of PLUGIN/CUDACPP_OUTPUT or MG5aMC_PLUGIN/CUDACPP_OUTPUT -# AV - Require Python >= 3.8 to ensure that {} dictionaries preserve the order of item insertion -# (note: python3.7 would probably be enough but this plugin has only been tested using python3.8) +# Require the same Python as MadGraph itself (see bin/madgraph), so that the +# plugin never becomes the reason a supported interpreter is refused. It used +# to ask only for >= 3.8, the version that made {} preserve insertion order. import sys -minpython = (3,8) +minpython = (3,12) if sys.version_info < minpython : print('ERROR! Cannot load plugin %s: Python >= %s.%s is required' % (PLUGIN_NAME, minpython[0], minpython[1] )) @@ -40,7 +41,7 @@ new_cluster = {} # 3. Define a new interface (allows adding/modifying MG5 command). - # This can be activated via ./bin/mg5_aMC --mode=PLUGINNAME. + # This can be activated via ./bin/madgraph --mode=PLUGINNAME. # Put None if no dedicated command are required if PLUGIN_NAME.rsplit('.',1)[0] == 'MG5aMC_PLUGIN': import madgraph.interface.master_interface as interface diff --git a/madmatrix/contrib/acceptance_tests/create_acceptance_from_file.py b/madmatrix/contrib/acceptance_tests/create_acceptance_from_file.py index f012a3ca63..1373f75008 100644 --- a/madmatrix/contrib/acceptance_tests/create_acceptance_from_file.py +++ b/madmatrix/contrib/acceptance_tests/create_acceptance_from_file.py @@ -38,7 +38,7 @@ def test_%(name)s(self): open(pjoin(self.path, 'mg5_cmd'),'w').write(cmd) newenv = os.environ.copy() newenv[\"PYTHONPATH\"] = pjoin(MG5DIR, '..') - subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','mg5_aMC'),'-m','CUDACPP_OUTPUT', + subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','madgraph'),'-m','CUDACPP_OUTPUT', pjoin(self.path, 'mg5_cmd')], env=newenv, #cwd=self.path, stdout=stdout, stderr=stderr) diff --git a/madmatrix/contrib/acceptance_tests/test_simd_madevent.py b/madmatrix/contrib/acceptance_tests/test_simd_madevent.py index f93ec4ba5b..d5825a2a65 100644 --- a/madmatrix/contrib/acceptance_tests/test_simd_madevent.py +++ b/madmatrix/contrib/acceptance_tests/test_simd_madevent.py @@ -150,7 +150,7 @@ def test_simd_cpp_eemumua_float(self): open(pjoin(self.path, 'mg5_cmd'),'w').write(cmd) newenv = os.environ.copy() newenv["PYTHONPATH"] = pjoin(MG5DIR, '..') - subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','mg5_aMC'),'-m','CUDACPP_OUTPUT', + subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','madgraph'),'-m','CUDACPP_OUTPUT', pjoin(self.path, 'mg5_cmd')], env=newenv, #cwd=self.path, stdout=stdout, stderr=stderr) @@ -200,7 +200,7 @@ def test_simd_cpp_heft_ggh_double(self): open(pjoin(self.path, 'mg5_cmd'),'w').write(cmd) newenv = os.environ.copy() newenv["PYTHONPATH"] = pjoin(MG5DIR, '..') - subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','mg5_aMC'),'-m','CUDACPP_OUTPUT', + subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','madgraph'),'-m','CUDACPP_OUTPUT', pjoin(self.path, 'mg5_cmd')], env=newenv, #cwd=self.path, stdout=stdout, stderr=stderr) @@ -250,7 +250,7 @@ def test_simd_cpp_pptt_mixed(self): open(pjoin(self.path, 'mg5_cmd'),'w').write(cmd) newenv = os.environ.copy() newenv["PYTHONPATH"] = pjoin(MG5DIR, '..') - subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','mg5_aMC'),'-m','CUDACPP_OUTPUT', + subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','madgraph'),'-m','CUDACPP_OUTPUT', pjoin(self.path, 'mg5_cmd')], env=newenv, #cwd=self.path, stdout=stdout, stderr=stderr) @@ -307,7 +307,7 @@ def test_simd_cpp_vector_size(self): open(pjoin(self.path, 'mg5_cmd'),'w').write(cmd) newenv = os.environ.copy() newenv["PYTHONPATH"] = pjoin(MG5DIR, '..') - subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','mg5_aMC'),'-m','CUDACPP_OUTPUT', + subprocess.call([sys.executable, pjoin(MG5DIR, 'bin','madgraph'),'-m','CUDACPP_OUTPUT', pjoin(self.path, 'mg5_cmd')], env=newenv, #cwd=self.path, stdout=stdout, stderr=stderr) diff --git a/madmatrix/launch_plugin.py b/madmatrix/launch_plugin.py index 9554922472..5cd31b9862 100644 --- a/madmatrix/launch_plugin.py +++ b/madmatrix/launch_plugin.py @@ -25,6 +25,11 @@ import madgraph.various.banner as banner_mod import madgraph.interface.common_run_interface as common_run_interface +# The backends accepted by the 'cudacpp_backend' run_card entry. 'cpu' is the +# auto-detecting CPU backend (the makefile resolves it to the widest SIMD flavour +# available on the host); the cpu_* entries pin one explicit SIMD width. +CUDACPP_SUPPORTED_BACKENDS = [ 'fortran', 'cuda', 'hip', 'cpu_scalar', 'cpu_128b', 'cpu_256b', 'cpu_512b_y', 'cpu_512b', 'cpu' ] + class CPPMEInterface(madevent_interface.MadEventCmdShell): def compile(self, *args, **opts): """ """ @@ -36,24 +41,24 @@ def compile(self, *args, **opts): common_run_interface.CommonRunCmd.update_make_opts_full(path, {'override FPTYPE': self.run_card['floating_type'] }) misc.sprint('FPTYPE checked') - cudacpp_supported_backends = [ 'fortran', 'cuda', 'hip', 'cpp', 'cppnone', 'cppsse4', 'cppavx2', 'cpp512y', 'cpp512z', 'cppauto' ] - if args and args[0][0] == 'madevent' and hasattr(self, 'run_card'): + cudacpp_supported_backends = CUDACPP_SUPPORTED_BACKENDS + if args and args[0][0] == 'madevent' and hasattr(self, 'run_card'): cudacpp_backend = self.run_card['cudacpp_backend'].lower() # the default value is defined in launch_plugin.py - if cudacpp_backend in ['cpp', 'cppauto']: + if cudacpp_backend == 'cpu': backend_log = pjoin(opts["cwd"], ".resolved-backend") # try to remove old file if present try: os.remove(backend_log) except FileNotFoundError: pass - misc.compile(["-f", "cudacpp.mk", f"BACKEND=cppauto", f"BACKEND_LOG={backend_log}", "detect-backend"], **opts) + misc.compile(["-f", "cudacpp.mk", f"BACKEND=cpu", f"BACKEND_LOG={backend_log}", "detect-backend"], **opts) try: with open(backend_log, "r") as f: resolved_backend = f.read().strip() logger.info(f"Backend '{cudacpp_backend}' resolved as '{resolved_backend}'") cudacpp_backend = resolved_backend except FileNotFoundError: - raise RuntimeError("Could not resolve cudacpp_backend=cppauto|cpp; ensure Makefile detection runs properly.") + raise RuntimeError("Could not resolve cudacpp_backend=cpu; ensure Makefile detection runs properly.") logger.info(f"Building madevent in madevent_interface.py with '{cudacpp_backend}' matrix elements") if cudacpp_backend in cudacpp_supported_backends : args[0][0] = 'madevent_' + cudacpp_backend + '_link' @@ -68,7 +73,7 @@ def compile(self, *args, **opts): """#*********************************************************************** # SIMD/GPU configuration for the CUDACPP plugin #************************************************************************ - %(cudacpp_backend)s = cudacpp_backend ! CUDACPP backend: fortran, cuda, hip, cpp, cppnone, cppsse4, cppavx2, cpp512y, cpp512z, cppauto + %(cudacpp_backend)s = cudacpp_backend ! CUDACPP backend: fortran, cuda, hip, cpu_scalar, cpu_128b, cpu_256b, cpu_512b_y, cpu_512b, cpu """ template_off = '' @@ -77,6 +82,27 @@ def compile(self, *args, **opts): class CPPRunCard(banner_mod.RunCardLO): blocks = banner_mod.RunCardLO.blocks + [plugin_block] + def __setitem__(self, name, value, *args, **opts): + """Refuse an unsupported cudacpp_backend instead of silently falling back. + + The generic ConfigFile machinery reacts to a value outside an 'allowed' + list by logging a warning and keeping the previous value. For + cudacpp_backend that would mean building and running on a backend the + user never asked for, so make it a hard error here. This matters in + particular for run cards written before the backend renaming, which + still carry the removed 'cpp' value. + """ + if isinstance(name, str) and name.strip().lower() == 'cudacpp_backend': + allowed = getattr(self, 'allowed_value', {}).get('cudacpp_backend', []) + if allowed and str(value).strip().lower() not in [str(v).lower() for v in allowed]: + raise banner_mod.InvalidRunCard( + "Invalid cudacpp_backend='%s': supported backends are [ '%s' ]. " \ + % (str(value).strip(), "', '".join(str(v) for v in allowed)) + + "The CPU/SIMD backends were renamed: use 'cpu' (auto-detected SIMD width) " \ + "instead of 'cpp', and 'cpu_scalar'/'cpu_128b'/'cpu_256b'/'cpu_512b_y'/'cpu_512b' " \ + "instead of 'cppnone'/'cppsse4'/'cppavx2'/'cpp512y'/'cpp512z'.") + return super().__setitem__(name, value, *args, **opts) + def reset_simd(self, old_value, new_value, name): if not hasattr(self, 'path'): raise Exception('INTERNAL ERROR! CPPRunCard instance has no attribute path') # now ok after fixing #790 @@ -105,9 +131,8 @@ def default_setup(self): allowed=['m','d','f'], comment='floating point precision: f (single), d (double), m (mixed: double for amplitudes, single for colors)' ) - cudacpp_supported_backends = [ 'fortran', 'cuda', 'hip', 'cpp', 'cppnone', 'cppsse4', 'cppavx2', 'cpp512y', 'cpp512z', 'cppauto' ] - self.add_param('cudacpp_backend', 'cpp', include=False, hidden=False, - allowed=cudacpp_supported_backends) + self.add_param('cudacpp_backend', 'cpu', include=False, hidden=False, + allowed=CUDACPP_SUPPORTED_BACKENDS) self['vector_size'] = 16 # already setup in default class (just change value) self['aloha_flag'] = '--fast-math' self['matrix_flag'] = '-O3' diff --git a/madmatrix/model_handling.py b/madmatrix/model_handling.py index 88c6a5f18a..1d17370fbf 100644 --- a/madmatrix/model_handling.py +++ b/madmatrix/model_handling.py @@ -168,7 +168,6 @@ def get_header_txt(self, name=None, couplings=None,mode='', combined=False): else: type = self.type2def[format] + ' ' + self.type2def['aloha_ref'] list_arg = '' - misc.sprint(argname,self.tag) if argname.startswith('COUP'): type = self.type2def['double'] # AV from cxtype_sv to fptype array (running alphas #373) if 'M' in self.tag: @@ -2201,8 +2200,6 @@ def edit_coloramps(self): iconfig_to_diag[iconfig] = config[0] diag_to_iconfig[config[0]] = iconfig - misc.sprint(iconfig_to_diag) - misc.sprint(diag_to_iconfig) # Note that if the last diagram is/are not mapped to a channel nb_diag # will be smaller than the true number of diagram. This is fine for color diff --git a/madmatrix/output.py b/madmatrix/output.py index fd5e80e608..8b6b102df4 100644 --- a/madmatrix/output.py +++ b/madmatrix/output.py @@ -152,7 +152,6 @@ class ProcessExporterMadMatrix(export_cpp.ProcessExporterMG7): # AV (default from OM's tutorial) - add a debug printout def __init__(self, *args, **kwargs): self.in_madevent_mode = False # see MR #747 - misc.sprint('Entering ProcessExporterMadMatrix.__init__ (initialise the exporter)') args[1]["me_lib_format"] = pjoin("lib", "libmadmatrix_{process_id}_{{device}}.so") super().__init__(*args, **kwargs) # Honor the output command's --mask=True|False (flavor-mask @@ -169,7 +168,6 @@ def _parse_flavor_mask_option(self): # AV - overload the default version: create CMake directory, do not create lib directory def copy_template(self, model): - misc.sprint('Entering ProcessExporterMadMatrix.copy_template (initialise the directory)') super().copy_template(model) # Rename Makefile to makefile if self.template_src_make: @@ -191,11 +189,6 @@ def write_p_makefiles(self, model): # AV - add debug printouts (in addition to the default one from OM's tutorial) def generate_subprocess_directory(self, matrix_element, cpp_helas_call_writer, proc_number=None): - misc.sprint('Entering ProcessExporterMadMatrix.generate_subprocess_directory (create the directory)') - misc.sprint(' type(matrix_element)=%s'%type(matrix_element)) # e.g. madgraph.core.helas_objects.HelasMatrixElement - misc.sprint(' type(cpp_helas_call_writer)=%s'%type(cpp_helas_call_writer)) # e.g. madgraph.iolibs.helas_call_writers.GPUFOHelasCallWriter - misc.sprint(' type(proc_number)=%s me=%s'%(type(proc_number) if proc_number is not None else None, proc_number)) # e.g. int - misc.sprint("need to link", self.to_link_in_P) # Propagate the --mask toggle to the helas call writer that emits the # guarded wavefunction/amplitude calls. if cpp_helas_call_writer is not None: diff --git a/madmatrix/trex.py b/madmatrix/trex.py index 9809fd01cf..6bccecf1ee 100644 --- a/madmatrix/trex.py +++ b/madmatrix/trex.py @@ -312,7 +312,7 @@ def __init__(self, *args, **kwargs): self.param_card = None self.reweight_card = [] self.reweight_names = [] - self.backend = 'cppauto' # default backend for tRex reweighting + self.backend = 'cpu' # default backend for tRex reweighting self.fptype = 'm' # default floating point type for tRex reweighting self.nb_threads = 1 if self.mother: @@ -465,7 +465,7 @@ def do_change(self,line): if len(args) < 2: return super().do_change(line) if args[0].lower() in ['cudacpp_backend', 'backend']: - cudacpp_supported_backends = [ 'cuda', 'hip', 'cpp', 'cppnone', 'cppsse4', 'cppavx2', 'cpp512y', 'cpp512z', 'cppauto' ] + cudacpp_supported_backends = [ 'cuda', 'hip', 'cpu_scalar', 'cpu_128b', 'cpu_256b', 'cpu_512b_y', 'cpu_512b', 'cpu' ] if args[1].lower() in cudacpp_supported_backends: self.backend = args[1].lower() logger.info("Setting tRex reweighting backend to '%s'" % self.backend) diff --git a/models/import_ufo.py b/models/import_ufo.py index a20cce8097..d1964136fc 100755 --- a/models/import_ufo.py +++ b/models/import_ufo.py @@ -59,6 +59,41 @@ # Suffixes to employ for the various poles of CTparameters pole_dict = {-2:'2EPS',-1:'1EPS',0:'FIN'} +def is_symmetric_lorentz_structure(name): + """True when the lorentz structure *name* has commuting arguments. + + The answer belongs to the structure itself: the aloha objects carry an + is_symmetric attribute, False on FactoryLorentz and set to True by the + structures whose arguments may be written in any order (Metric).""" + + structure = getattr(aloha_object, name, None) + return bool(getattr(structure, 'is_symmetric', False)) + +def canonicalize_lorentz_structure(structure): + """Sort the arguments of the symmetric functions appearing in *structure*. + + Renumbering the indices of a vertex can reorder the arguments of a + symmetric function, so that Metric(3,2) and Metric(2,3) -- the same object + -- come out as different strings. Sorting the arguments of the functions + known to be symmetric makes the two spellings compare equal, so that only a + real disagreement between two definitions is reported. + + Only calls whose arguments are all plain (possibly negative) integer + indices are touched, so a nested expression is never rewritten.""" + + if not isinstance(structure, str): + return structure + + def sort_args(matchobj): + name = matchobj.group(1) + if not is_symmetric_lorentz_structure(name): + return matchobj.group(0) + args = [a.strip() for a in matchobj.group(2).split(',')] + return '%s(%s)' % (name, ','.join(sorted(args, key=int))) + + return re.sub(r'\b([A-Za-z_]\w*)\(\s*(-?\d+(?:\s*,\s*-?\d+)*)\s*\)', + sort_args, structure) + class UFOImportError(MadGraph5Error): """ a error class for wrong import of UFO model""" @@ -1378,7 +1413,11 @@ def get_symmetric_lorentz(self, old_lorentz, substitution, change_number=False): new_lor = self.add_lorentz(new_name, new_spins, new_expr, formfact=new_formfact) except AssertionError: prev_def = [l for l in self.model['lorentz'] if l.name==new_name][0] - if prev_def.structure != new_expr: + # compare canonicalised forms: the index renumbering above can + # reorder the arguments of a symmetric function, and that alone + # is not a redefinition (see canonicalize_lorentz_structure) + if canonicalize_lorentz_structure(prev_def.structure) != \ + canonicalize_lorentz_structure(new_expr): misc.sprint("WARNING, two different definition for one lorentz name", prev_def.structure, new_expr) new_lor = prev_def return new_lor diff --git a/tests/acceptance_tests/check_xsec_processes_reference.json b/tests/acceptance_tests/check_xsec_processes_reference.json index 30c7316e27..0f19dd0782 100644 --- a/tests/acceptance_tests/check_xsec_processes_reference.json +++ b/tests/acceptance_tests/check_xsec_processes_reference.json @@ -1,5 +1,5 @@ { - "_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.", + "_comment": "Reference cross-sections (pb) for systematic MG7 testing. Source of truth: #28. Reference runs used fixed scale (mu = 91.188 GeV, pinned by the test; the run_card.toml default is now dynamical HT/2), e_cm = 13000 GeV, NNPDF23_lo_as_0130_qed (also pinned by the test, so these values stay valid if the run_card.toml default PDF changes), 1M events.", "defines": [], "sections": { "3jets": [ diff --git a/tests/acceptance_tests/test_check_xsec_processes_mg7.py b/tests/acceptance_tests/test_check_xsec_processes_mg7.py index 3da2a80730..627a7a7de9 100644 --- a/tests/acceptance_tests/test_check_xsec_processes_mg7.py +++ b/tests/acceptance_tests/test_check_xsec_processes_mg7.py @@ -24,10 +24,12 @@ ``_anti_quark`` merged-flavor particles are used directly from the sm model), 2. ``output mg7``s it, - 3. edits ``Cards/run_card.toml`` -- fixed scale is already the template - default (mu = 91.188 GeV, e_cm = 13000 GeV, NNPDF23_lo_as_0130_qed); here - we only set the event count and, for the hadronic tt~ decays, neutralise - the jet cuts (see CLAUDE.md), + 3. edits ``Cards/run_card.toml`` -- it pins the configuration the references + were generated with: the fixed scale (mu = 91.188 GeV, e_cm = 13000 GeV), + since the template now defaults to the dynamical HT/2 scale, and the PDF + set (``NNPDF23_lo_as_0130_qed``), so the references stay valid no matter + which set the template defaults to; it also sets the event count and, for + the hadronic tt~ decays, neutralises the jet cuts (see CLAUDE.md), 4. runs ``bin/generate_events -f`` and reads the cross-section from the madspace ``Events/*/info.json`` (``process.mean`` / ``process.error``), 5. asserts the relative difference to the reference stays within a tolerance. @@ -74,6 +76,13 @@ _HERE = os.path.dirname(os.path.abspath(__file__)) _REFERENCE = pjoin(_HERE, 'check_xsec_processes_reference.json') +# PDF set the reference cross-sections were generated with. The test pins it +# into every run_card.toml (see _edit_run_card) instead of relying on the +# template default, so that changing the default PDF of the mg7 run_card does +# not silently invalidate all ~40 reference values. It is also the set +# _mg7_datadir_or_skip requires to be installed. +_REFERENCE_PDF = 'NNPDF23_lo_as_0130_qed' + # Environment-tunable knobs (see module docstring). Kept as module globals so # the dynamically generated test methods pick up the CI-provided values. _TOLERANCE = float(os.environ.get('MG7_XSEC_TOLERANCE', 0.01)) @@ -104,9 +113,9 @@ def _tail(path, n=60): def _mg7_datadir_or_skip(test): - """Return an LHAPDF data dir that contains the NNPDF23_lo_as_0130_qed set, - or ``skipTest`` (on *test*) when the mg7 runtime stack (madspace + LHAPDF + - the run_card.toml default PDF) is unavailable.""" + """Return an LHAPDF data dir that contains the ``_REFERENCE_PDF`` set, or + ``skipTest`` (on *test*) when the mg7 runtime stack (madspace + LHAPDF + + the PDF set the references were generated with) is unavailable.""" try: import madspace has_mg7 = hasattr(madspace, 'ChannelEventGenerator') @@ -126,21 +135,28 @@ def _mg7_datadir_or_skip(test): except Exception: pass for d in candidates: - if d and os.path.isdir(d) and glob.glob(pjoin(d, 'NNPDF23_lo_as_0130_qed*')): + if d and os.path.isdir(d) and glob.glob(pjoin(d, '%s*' % _REFERENCE_PDF)): return d - test.skipTest('NNPDF23_lo_as_0130_qed LHAPDF data not found ' - '(set $LHAPDF_DATA_PATH)') + test.skipTest('%s LHAPDF data not found (set $LHAPDF_DATA_PATH)' + % _REFERENCE_PDF) def _edit_run_card(toml_path, events, disable_jet_cuts): """Set the event count and (optionally) neutralise the jet cuts. - Fixed renormalisation/factorisation scales are already the template - default; we only force them back on if a template change ever flipped - them, to keep the reference configuration honest.""" + The reference cross-sections were produced with FIXED scales + (mu = 91.188 GeV) and with the NNPDF23_lo_as_0130_qed PDF set. The + run_card.toml template now defaults to the dynamical HT/2 scale instead, + and its default PDF set is free to change, so these replacements are what + pins the configuration back to the one the references were generated with. + They are load-bearing: drop them and every reference value below goes + stale. The PDF pin in particular decouples the references from the + template default -- ``_mg7_datadir_or_skip`` already guarantees the pinned + set is the one present on disk.""" t = open(toml_path).read() t = t.replace('fixed_ren_scale = false', 'fixed_ren_scale = true') t = t.replace('fixed_fact_scale = false', 'fixed_fact_scale = true') + t = re.sub(r'(?m)^pdf = ".*"$', 'pdf = "%s"' % _REFERENCE_PDF, t) t = re.sub(r'events = \d+', 'events = %d' % events, t) if disable_jet_cuts: # jet cuts must be disabled for the hadronic tt~ decay processes to diff --git a/tests/acceptance_tests/test_cmd.py b/tests/acceptance_tests/test_cmd.py index 1f6ce3ffd3..9bc9f83766 100755 --- a/tests/acceptance_tests/test_cmd.py +++ b/tests/acceptance_tests/test_cmd.py @@ -432,7 +432,7 @@ def test_output_mg7_directory(self): (madmatrix/cudacpp) directory for e+ e- > e+ e- -- the top-level layout (src/, SubProcesses/, lib/, Cards/, bin/), the mg7 cards and launcher, and that the generated subprocess compiles into the expected shared - libraries (scalar cppnone backend). + libraries (cpu_scalar backend). """ if os.path.isdir(self.out_dir): shutil.rmtree(self.out_dir) @@ -545,7 +545,7 @@ def test_output_standalone_directory(self): self.do('set group_subprocesses False') self.do('import model sm') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s' % self.out_dir) + self.do('output standalone_fortran %s' % self.out_dir) self.do('set group_subprocesses True') self.assertTrue(os.path.exists(self.out_dir)) self.assertTrue(os.path.isfile(os.path.join(self.out_dir, 'lib', 'libdhelas.a'))) @@ -564,7 +564,7 @@ def test_custom_propa(self): path = os.path.join(MG5DIR, 'tests', 'input_files', 'sm_with_custom_propa') self.do('import model %s' % path) self.do('generate g g > t t~') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) files = ['aloha_file.inc', 'aloha_functions.f','FFV1_0.f', 'FFV1_1.f', 'FFV1_2.f', 'makefile', 'VVV1PV2_1.f'] @@ -618,7 +618,7 @@ def test_ufo_aloha_merged(self): self.do('import model sm') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) # Check that the needed ALOHA subroutines are generated files = ['FFV6_3.f', 'aloha_object.mod', 'FFV2_3.f', 'aloha_file.inc', 'makefile', 'FFV6_0.f', 'FFV1P0_3.f', 'FFV2_0.f', 'FFV1_0.f', 'aloha_functions.f'] for f in files: @@ -676,7 +676,7 @@ def test_ufo_aloha(self): self.do('set apply_flavor_grouping False') self.do('import model sm') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) # Check that the needed ALOHA subroutines are generated files = ['aloha_file.inc', #'FFS1C1_2.f', 'FFS1_0.f', @@ -748,7 +748,7 @@ def test_standalone_spin2_loop_smgrav(self): model_path = pjoin(MG5DIR, 'tests', 'input_files', 'loop_smgrav') self.do('import model %s' % model_path) self.do('generate p p > w+ y') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) # Pin down whichever P*_udx_wpy directory the exporter chose # (depends on flavor-grouping defaults). @@ -799,7 +799,7 @@ def test_standalone_wwjj(self): shutil.rmtree(self.out_dir) self.do('generate p p > w+ w- j j QCD=0') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) sub_root = os.path.join(self.out_dir, 'SubProcesses') proc_candidates = [d for d in os.listdir(sub_root) @@ -876,7 +876,7 @@ def test_standalone_merged_flavor_uq_zuq(self): self.do('import model sm') self.do('define q = u d') self.do('generate u q > Z u q QCD=0') - output_cmd = 'output standalone %s' % self.out_dir + output_cmd = 'output standalone_fortran %s' % self.out_dir if mask_flag: output_cmd += ' ' + mask_flag self.do(output_cmd + ' -f') @@ -924,8 +924,10 @@ def test_standalone_flavor_mask(self): """Acceptance test for the per-flavor masking optimization. Generates p p > j j QCD=0 and, for the q q~ > q q~ subprocess, - exercises both the Fortran (standalone) and C++ (standalone_cpp) - backends. The check_sa driver is patched to also evaluate two + exercises both the Fortran (standalone_fortran) and scalar C++ + (export_cpp.ProcessExporterCPP, driven through its internal API by + _output_standalone_cpp) backends. + The check_sa driver is patched to also evaluate two non-representative flavors -- s c~ > s c~ (flavor 3 4 3 4) and s c~ > c c~ (flavor 3 4 4 4) -- and the matrix-element source is patched to print the runtime flavor mask that gates the HELAS @@ -1020,7 +1022,7 @@ def assert_backend(text, known_flavor, zero_flavor): # 'mask for %s should be all-on' % (zero_flavor,)) # ---- Fortran standalone ------------------------------------- - self.do('output standalone %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) proc_dir = find_qqx(pjoin(self.out_dir, 'SubProcesses')) check_f = pjoin(proc_dir, 'check_sa.f') @@ -1063,8 +1065,7 @@ def assert_backend(text, known_flavor, zero_flavor): assert_backend(run_check(proc_dir), (3, 4, 3, 4), (3, 4, 4, 4)) # ---- C++ standalone ----------------------------------------- - shutil.rmtree(self.out_dir) - self.do('output standalone_cpp %s -f' % self.out_dir) + self._output_standalone_cpp(self.out_dir, force=True) proc_dir = find_qqx(pjoin(self.out_dir, 'SubProcesses')) def extend_flavor_2d_array(text, name, dim_old, dim_new, extra_rows): @@ -1210,7 +1211,7 @@ def run_check(proc_dir, nb_try): if define_cmd: self.do(define_cmd) self.do('generate %s' % proc) - self.do('output standalone %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) subprocess.call(['make'], stdout=devnull, stderr=devnull, cwd=pjoin(self.out_dir, 'Source')) sub_root = pjoin(self.out_dir, 'SubProcesses') @@ -1244,19 +1245,19 @@ def run_check(proc_dir, nb_try): self.assertTrue(saw_nonzero, 'all matrix elements vanished for %s' % proc) - def test_standalone_mg7_goodhel_filter(self): - """The standalone_mg7 (cudacpp) good-helicity filter must reproduce the + def test_madmatrix_goodhel_filter(self): + """The standalone (madmatrix/cudacpp) good-helicity filter must reproduce the per-flavor matrix element of every flavor served by a merged matrix element. - standalone_mg7 computes a single global good-helicity list once, as the + the standalone (madmatrix) export computes a single global good-helicity list once, as the union over all flavor combinations (see sigmaKin_getGoodHel). A flavor-blind filter -- one that seeds the good helicities from only the flavor(s) of the first sampled events -- would drop a helicity that vanishes for the seeding flavor but contributes for another merged flavor, giving a too-small |M|^2 for that other flavor. - We compare the standalone_mg7 per-flavor values (check_sa.exe 'matrix' + We compare the standalone (madmatrix) per-flavor values (check_sa.exe 'matrix' mode) against the Fortran standalone ones, which test_standalone_goodhel_filter independently validates as filter-invariant. ``u u~ > j j QCD=0`` is a single merged matrix element @@ -1288,9 +1289,9 @@ def get_values(output_format, check_exe, build_source=False): values = [] for d in dirs: proc_dir = pjoin(proc_root, d) - # standalone uses 'make check' + ./check; standalone_mg7 ships a + # standalone_fortran uses 'make check' + ./check; standalone ships a # UMAMI check_sa.exe whose 'matrix' mode == the Fortran driver. - target = ['make', 'check'] if output_format == 'standalone' \ + target = ['make', 'check'] if output_format == 'standalone_fortran' \ else ['make'] subprocess.call(target, stdout=devnull, stderr=devnull, cwd=proc_dir) @@ -1306,24 +1307,29 @@ def get_values(output_format, check_exe, build_source=False): self.do('import model sm') self.do('generate u u~ > j j QCD=0') - mg7 = get_values('standalone_mg7', './check_sa.exe') - standalone = get_values('standalone', './check', build_source=True) + mg7 = get_values('standalone', './check_sa.exe') + standalone = get_values('standalone_fortran', './check', build_source=True) self.assertTrue(any(v != 0.0 for v in standalone), 'all matrix elements vanished for u u~ > j j') self._assert_me_lists_close(mg7, standalone, atol=1e-7) def test_standalone_cpp(self): - """test that standalone cpp is working""" + """test that the scalar C++ standalone exporter is working + + `output standalone_cpp` is no longer a user-facing format, so the C++ + arm drives export_cpp.ProcessExporterCPP through its internal API + (_output_standalone_cpp) instead of the command. + """ if os.path.isdir(self.out_dir): shutil.rmtree(self.out_dir) self.do('import model MSSM_SLHA2-full') self.do('generate g g > go go QED=2') - self.do('output standalone_cpp %s ' % self.out_dir) + self._output_standalone_cpp(self.out_dir) devnull = open(os.devnull,'w') - # Locate the subprocess directory: the merge shortened the standalone_cpp + # Locate the subprocess directory: the merge shortened the C++ # directory name (e.g. P0_Sigma_MSSM_SLHA2_full_gg_gogo -> P1_gg_gogo), # so discover it rather than hard-coding the number/prefix. proc_root = os.path.join(self.out_dir, 'SubProcesses') @@ -1352,20 +1358,45 @@ def test_standalone_cpp(self): self.assertTrue(me_groups) self.assertAlmostEqual(float(me_groups.group('value')), 6.4739191,5) - # Cross-check standalone_mg7 (madmatrix) against standalone_cpp for this - # massive BSM process. The Fortran/C++ ./check auto-bumps the CM energy + # Cross-check standalone (madmatrix) against standalone_fortran for + # this massive BSM process. The Fortran ./check auto-bumps the CM energy # to 2*total_mass for the heavy gluinos, but check_sa.exe does not, so # evaluate BOTH at the same explicit above-threshold energy. energy = '5000' - cpp_e_log = os.path.join(proc_dir, 'check_e.log') + + shutil.rmtree(self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) + subprocess.call(['make'], stdout=devnull, stderr=devnull, + cwd=os.path.join(self.out_dir, 'Source')) + f_root = os.path.join(self.out_dir, 'SubProcesses') + f_cand = [d for d in os.listdir(f_root) + if d.endswith('_gg_gogo') and + os.path.isdir(os.path.join(f_root, d))] + self.assertEqual(len(f_cand), 1, + 'expected one gg_gogo Fortran subprocess, got %s' + % f_cand) + f_dir = os.path.join(f_root, f_cand[0]) + subprocess.call(['make', 'check'], stdout=devnull, stderr=devnull, + cwd=f_dir) + # Same hard-coded reference at the auto-bumped default energy. + f_log = os.path.join(f_dir, 'check.log') + subprocess.call('./check', + stdout=open(f_log, 'w'), stderr=subprocess.STDOUT, + cwd=f_dir, shell=True) + f_default = me_re.search(open(f_log).read()) + self.assertTrue(f_default, + 'standalone_fortran produced no matrix element') + self.assertAlmostEqual(float(f_default.group('value')), 6.4739191, 5) + # Reference value at the explicit above-threshold energy. + f_e_log = os.path.join(f_dir, 'check_e.log') subprocess.call('./check %s' % energy, - stdout=open(cpp_e_log, 'w'), stderr=subprocess.STDOUT, - cwd=proc_dir, shell=True) - cpp_me = me_re.search(open(cpp_e_log).read()) - self.assertTrue(cpp_me) + stdout=open(f_e_log, 'w'), stderr=subprocess.STDOUT, + cwd=f_dir, shell=True) + f_me = me_re.search(open(f_e_log).read()) + self.assertTrue(f_me) shutil.rmtree(self.out_dir) - self.do('output standalone_mg7 %s -f' % self.out_dir) + self.do('output standalone %s -f' % self.out_dir) mg7_root = os.path.join(self.out_dir, 'SubProcesses') mg7_cand = [d for d in os.listdir(mg7_root) if d.endswith('_gg_gogo') and @@ -1379,9 +1410,9 @@ def test_standalone_cpp(self): stdout=open(mg7_log, 'w'), stderr=subprocess.STDOUT, cwd=mg7_dir, shell=True) mg7_me = me_re.search(open(mg7_log).read()) - self.assertTrue(mg7_me, 'standalone_mg7 produced no matrix element') + self.assertTrue(mg7_me, 'standalone (madmatrix) produced no matrix element') self._assert_me_lists_close([float(mg7_me.group('value'))], - [float(cpp_me.group('value'))]) + [float(f_me.group('value'))]) def test_standalone_cpp_output_consistency(self): @@ -1392,11 +1423,11 @@ def test_standalone_cpp_output_consistency(self): #step 0 cpp output self.do('generate p p > t t~, t > b mu+ vm, t~ > b~ mu- vm~') - self.do('output standalone_cpp %s ' % self.out_dir) + self._output_standalone_cpp(self.out_dir) devnull = open(os.devnull,'w') - # Discover the subprocess directories: the merge shortened the - # standalone_cpp directory names (e.g. P0_Sigma_sm_gg_bmupvmbxmumvmx -> + # Discover the subprocess directories: the merge shortened the C++ + # directory names (e.g. P0_Sigma_sm_gg_bmupvmbxmumvmx -> # P1_gg_bmupvmbxmumvmx), so list them rather than hard-coding. def get_values(): proc_root = os.path.join(self.out_dir, 'SubProcesses') @@ -1429,21 +1460,78 @@ def get_values(): original = get_values() #step 1 standalone output shutil.rmtree(self.out_dir) - self.do('output standalone %s -f' % self.out_dir) - shutil.rmtree(self.out_dir) - self.do('output standalone_cpp %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) + self._output_standalone_cpp(self.out_dir, force=True) new = get_values() for i,_ in enumerate(original): self.assertEqual(original[i], new[i]) + def _output_standalone_cpp(self, out_dir, force=False): + """Write a scalar C++ standalone output for the processes currently + held by the interface, driving export_cpp.ProcessExporterCPP through + its internal API. + + `output standalone_cpp` is no longer a user-facing format, but the + exporter class itself is very much alive: it is the base class of the + madmatrix (`standalone`) export, and `check language` drives it exactly + this way (see madgraph/various/process_checks.py and + tests/unit_tests/various/test_process_checks.py). Going through the API + keeps the scalar-C++ coverage of these tests without the command. + """ + import madgraph.iolibs.export_cpp as export_cpp + import madgraph.iolibs.helas_call_writers as helas_call_writers + import madgraph.core.helas_objects as helas_objects + + cmd = self.cmd + model = cmd._curr_model + + if force and os.path.isdir(out_dir): + shutil.rmtree(out_dir) + + opt = dict(cmd.options) + opt['output_options'] = {} + opt.update({'sa_symmetry': False, 'export_format': 'standalone_cpp', + 'mp': False, 'v5_model': True}) + exporter = export_cpp.ProcessExporterCPP(out_dir, opt) + + # Reuse the helas objects the interface already built, exactly like + # do_output does: building a second HelasMultiProcess from the same + # _curr_amps does NOT give the same matrix elements back (decay chains + # in particular are lost), so the cache is what makes repeated exports + # of one `generate` consistent. + multi_me = cmd._curr_matrix_elements + if not isinstance(multi_me, helas_objects.HelasMultiProcess) or \ + not multi_me.get_matrix_elements(): + # do_output sets this global from the exporter before building the + # helas objects; mirror it. + helas_objects.HelasMatrixElement.enumerate_all_flavors = \ + not getattr(exporter, 'use_flavor_mask', True) + multi_me = helas_objects.HelasMultiProcess(cmd._curr_amps) + for uid, me in enumerate(multi_me.get_matrix_elements()): + me.get('processes')[0].set('uid', uid + 1) + cmd._curr_matrix_elements = multi_me + matrix_elements = multi_me.get_matrix_elements() + self.assertTrue(matrix_elements, 'no matrix element to export') + + cpp_writer = helas_call_writers.CPPUFOHelasCallWriter(model) + exporter.copy_template(model) + for me_number, me in enumerate(matrix_elements): + exporter.generate_subprocess_directory(me, cpp_writer, me_number) + exporter.convert_model(model, multi_me.get_used_lorentz(), + multi_me.get_used_couplings()) + # ProcessExporterCPP.finalize() ignores its arguments and compiles src. + exporter.finalize({'matrix_elements': matrix_elements}, '', + cmd.options, ['nojpeg']) + return out_dir + def _assert_me_lists_close(self, a, b, rtol=1e-5, atol=0.0): """Assert two matrix-element value lists agree as multisets (sorted), within a combined relative/absolute tolerance (|x-y| <= atol + rtol*max(|x|,|y|)). - Backends print with different precision (standalone_cpp 7 sig figs vs - standalone_mg7 full double) and may emit the per-flavour values in a + Backends print with different precision (the scalar C++ one 7 sig figs vs + standalone (madmatrix) full double) and may emit the per-flavour values in a different order, so compare sorted rather than index-by-index / exact. `atol` lets callers treat numerically-tiny (vanishing-flavour) values as zero, where the different floating-point arithmetic of the Fortran vs @@ -1457,11 +1545,11 @@ def _assert_me_lists_close(self, a, b, rtol=1e-5, atol=0.0): 'matrix-element mismatch: %s vs %s' % (x, y)) def test_standalone_cpp_fd_output_consistency(self): - """test standalone_mg7 in FD gauge against standalone + """test the standalone (madmatrix) output in FD gauge against standalone_fortran - The standalone_mg7 (madmatrix) matrix elements must agree with the + The standalone (madmatrix) matrix elements must agree with the Fortran standalone ones, both in FD gauge and in unitary gauge (and FD - vs unitary, i.e. gauge invariance). standalone_mg7 ships a UMAMI-based + vs unitary, i.e. gauge invariance). madmatrix ships a UMAMI-based check_sa.exe whose 'matrix' mode is by design identical to the Fortran check driver; the per-flavour values are compared as sorted multisets (the backends may order flavours differently and print at different @@ -1481,18 +1569,18 @@ def get_values(output_format): proc_dir = os.path.join(self.out_dir, 'SubProcesses') directories = sorted([d for d in os.listdir(proc_dir) if d.startswith('P')]) self.assertTrue(directories) - if output_format == 'standalone': + if output_format == 'standalone_fortran': subprocess.call(['make'], stdout=devnull, stderr=devnull, cwd=os.path.join(self.out_dir, 'Source')) for oneproc in directories: logfile = os.path.join(proc_dir, oneproc, 'check.log') - # standalone uses 'make check' + ./check; standalone_mg7 ships a + # standalone_fortran uses 'make check' + ./check; standalone ships a # UMAMI check_sa.exe whose 'matrix' mode == the Fortran driver. - if output_format == 'standalone': + if output_format == 'standalone_fortran': target = ['make', 'check'] check_exe = './check %s' % energy - elif output_format == 'standalone_mg7': + elif output_format == 'standalone': target = ['make'] check_exe = './check_sa.exe %s' % energy else: @@ -1512,15 +1600,15 @@ def get_values(output_format): values.extend(float(value) for value in me_groups) return values - standalone_mg7 = get_values('standalone_mg7') + madmatrix = get_values('standalone') shutil.rmtree(self.out_dir) - standalone = get_values('standalone') + standalone = get_values('standalone_fortran') # atol: this process's matrix elements are O(1e-20), i.e. at the # floating-point noise floor, where the Fortran and cudacpp backends # differ; only require agreement above an absolute floor (the original # cpp-vs-standalone check used assertAlmostEqual, equally lenient here). - self._assert_me_lists_close(standalone_mg7, standalone, atol=1e-7) + self._assert_me_lists_close(madmatrix, standalone, atol=1e-7) self.do('set gauge unitary') self.do('generate _quark _quark > h _quark _quark _quark _anti_quark QCD=0') @@ -1528,16 +1616,16 @@ def get_values(output_format): energy = '1000' shutil.rmtree(self.out_dir) - standalone_mg7_no_fd = get_values('standalone_mg7') + madmatrix_no_fd = get_values('standalone') shutil.rmtree(self.out_dir) - standalone_no_fd = get_values('standalone') + standalone_no_fd = get_values('standalone_fortran') - self._assert_me_lists_close(standalone_mg7_no_fd, standalone_no_fd, + self._assert_me_lists_close(madmatrix_no_fd, standalone_no_fd, atol=1e-7) # gauge invariance: unitary-gauge values must also match the FD ones. - self._assert_me_lists_close(standalone_mg7_no_fd, standalone, atol=1e-7) + self._assert_me_lists_close(madmatrix_no_fd, standalone, atol=1e-7) - def test_standalone_mg7_fd_vs_fortran(self): + def test_madmatrix_fd_vs_fortran(self): """FD gauge: madmatrix and the Fortran standalone must agree on the value, not merely both produce one. @@ -1560,7 +1648,7 @@ def test_standalone_mg7_fd_vs_fortran(self): madmatrix is checked once per backend: the FD wavefunctions are written twice in helas_fd.h, once under #ifndef MGONGPU_CPPSIMD and once for the vector types, and the two have drifted apart before. Which one a plain - 'make' builds depends on the host (cppauto), so neither is exercised + 'make' builds depends on the host (cpu), so neither is exercised unless it is asked for by name. """ energy = '1000' @@ -1584,7 +1672,7 @@ def get_values(output_format, check_exe, build_source=False, values = [] for d in dirs: proc_dir = pjoin(proc_root, d) - target = ['make', 'check'] if output_format == 'standalone' \ + target = ['make', 'check'] if output_format == 'standalone_fortran' \ else ['make'] + (['BACKEND=%s' % backend] if backend else []) subprocess.call(target, stdout=devnull, stderr=devnull, cwd=proc_dir) @@ -1602,13 +1690,13 @@ def get_values(output_format, check_exe, build_source=False, self.do('set gauge FD') try: self.do('generate u u~ > w+ w-') - standalone = get_values('standalone', './check', build_source=True) - # cppnone is the scalar code path, cppsse4 the vector one (it maps + standalone = get_values('standalone_fortran', './check', build_source=True) + # cpu_scalar is the scalar code path, cpu_128b the vector one (it maps # to NEON on arm) mg7 = dict((backend, - get_values('standalone_mg7', './check_sa.exe', + get_values('standalone', './check_sa.exe', backend=backend)) - for backend in ('cppnone', 'cppsse4')) + for backend in ('cpu_scalar', 'cpu_128b')) finally: self.do('set gauge unitary') @@ -1620,7 +1708,7 @@ def get_values(output_format, check_exe, build_source=False, # -ffast-math on the C++ side puts the backends ~3e-8 apart self._assert_me_lists_close(values, standalone, rtol=1e-6) - def test_standalone_mg7_fd_simd_lanes(self): + def test_madmatrix_fd_simd_lanes(self): """FD gauge: the scalar and the vectorised madmatrix backends must compute the same thing, over many events. @@ -1646,14 +1734,14 @@ def test_standalone_mg7_fd_simd_lanes(self): self.do('set gauge FD') try: self.do('generate u u~ > w+ w-') - self.do('output standalone_mg7 %s -f' % self.out_dir) + self.do('output standalone %s -f' % self.out_dir) finally: self.do('set gauge unitary') proc_root = pjoin(self.out_dir, 'SubProcesses') dirs = sorted(d for d in os.listdir(proc_root) if d.startswith('P') and os.path.isdir(pjoin(proc_root, d))) - self.assertTrue(dirs, 'no subprocess for standalone_mg7') + self.assertTrue(dirs, 'no subprocess for standalone') def mean_me(proc_dir, backend): """mean |M|^2 over a multi-event run of the given backend""" @@ -1680,37 +1768,40 @@ def mean_me(proc_dir, backend): for d in dirs: proc_dir = pjoin(proc_root, d) - # cppnone is the scalar code path, cppsse4 the vector one (it maps + # cpu_scalar is the scalar code path, cpu_128b the vector one (it maps # to NEON on arm) - scalar = mean_me(proc_dir, 'cppnone') - self.assertTrue(scalar, 'standalone_mg7 did not build in %s' % proc_dir) + scalar = mean_me(proc_dir, 'cpu_scalar') + self.assertTrue(scalar, 'standalone did not build in %s' % proc_dir) self.assertGreater(scalar, 0., 'null mean matrix element in %s' % proc_dir) - vector = mean_me(proc_dir, 'cppsse4') + vector = mean_me(proc_dir, 'cpu_128b') if vector is None: continue # no vectorised backend here: nothing to compare self.assertLessEqual(abs(vector - scalar), 1e-5 * scalar, 'the scalar and vectorised backends disagree ' 'in %s: %s vs %s' % (d, scalar, vector)) - def test_standalone_mg7_vs_cpp(self): - """Cross-check that standalone_mg7 (madmatrix) reproduces the - standalone_cpp matrix elements for p p > e+ e- QCD=0. + def test_madmatrix_vs_fortran(self): + """Cross-check that standalone (madmatrix) reproduces the + standalone_fortran matrix elements for p p > e+ e- QCD=0. Uses a massless final state so both check drivers evaluate the same default 1000 GeV phase-space point (no energy auto-bump mismatch), and compares the per-flavour matrix elements as sorted multisets (the two backends may emit them in a different order and at different printed - precision). standalone_mg7 ships a UMAMI-based check_sa.exe whose - 'matrix' mode is by design identical to the Fortran/C++ check drivers. + precision). madmatrix ships a UMAMI-based check_sa.exe whose + 'matrix' mode is by design identical to the Fortran check driver. """ energy = '1000' devnull = open(os.devnull, 'w') - def get_values(output_format, check_exe): + def get_values(output_format, check_exe, build_source=False): if os.path.isdir(self.out_dir): shutil.rmtree(self.out_dir) self.do('output %s %s' % (output_format, self.out_dir)) + if build_source: + subprocess.call(['make'], stdout=devnull, stderr=devnull, + cwd=os.path.join(self.out_dir, 'Source')) proc_root = os.path.join(self.out_dir, 'SubProcesses') dirs = sorted(d for d in os.listdir(proc_root) if d.startswith('P') and @@ -1721,7 +1812,12 @@ def get_values(output_format, check_exe): re.IGNORECASE) for d in dirs: proc_dir = os.path.join(proc_root, d) - subprocess.call(['make'], stdout=devnull, stderr=devnull, + # standalone_fortran uses 'make check' + ./check; standalone + # ships a UMAMI check_sa.exe whose 'matrix' mode == the Fortran + # driver. + target = ['make', 'check'] \ + if output_format == 'standalone_fortran' else ['make'] + subprocess.call(target, stdout=devnull, stderr=devnull, cwd=proc_dir) log = os.path.join(proc_dir, 'check.log') subprocess.call('%s %s' % (check_exe, energy), @@ -1735,13 +1831,15 @@ def get_values(output_format, check_exe): self.do('import model sm') self.do('generate p p > e+ e- QCD=0') - cpp = get_values('standalone_cpp', './check') - mg7 = get_values('standalone_mg7', './check_sa.exe') - self._assert_me_lists_close(mg7, cpp) + fortran = get_values('standalone_fortran', './check', build_source=True) + self.assertTrue(any(v != 0.0 for v in fortran), + 'all matrix elements vanished for p p > e+ e- QCD=0') + mg7 = get_values('standalone', './check_sa.exe') + self._assert_me_lists_close(mg7, fortran) - def test_standalone_mg7_mssm_single_leg(self): + def test_madmatrix_mssm_single_leg(self): """Single-merged-leg flavored couplings must give the same per-flavor - |M|^2 in standalone_mg7 (madmatrix) as in the Fortran standalone. + |M|^2 in standalone (madmatrix) as in the Fortran standalone. p p > n1 n1 QCD=0 is a t-channel-squark process with single-merged-leg vertices (one merged light quark + an unmerged neutralino + a squark) @@ -1770,7 +1868,7 @@ def get_values(output_format, check_exe, build_source=False): values = [] for d in dirs: proc_dir = os.path.join(proc_root, d) - target = ['make', 'check'] if output_format == 'standalone' \ + target = ['make', 'check'] if output_format == 'standalone_fortran' \ else ['make'] subprocess.call(target, stdout=devnull, stderr=devnull, cwd=proc_dir) @@ -1786,15 +1884,15 @@ def get_values(output_format, check_exe, build_source=False): self.do('import model MSSM_SLHA2') self.do('generate p p > n1 n1 QCD=0') - mg7 = get_values('standalone_mg7', './check_sa.exe') - standalone = get_values('standalone', './check', build_source=True) + mg7 = get_values('standalone', './check_sa.exe') + standalone = get_values('standalone_fortran', './check', build_source=True) self.assertTrue(any(v != 0.0 for v in standalone), 'all matrix elements vanished for p p > n1 n1') self._assert_me_lists_close(mg7, standalone, rtol=1e-4) - def test_standalone_mg7_mssm_gogo(self): + def test_madmatrix_mssm_gogo(self): """Dependent (event-by-event, running-alphas) flavored couplings must - give the same per-flavor |M|^2 in standalone_mg7 (madmatrix) as in the + give the same per-flavor |M|^2 in standalone (madmatrix) as in the Fortran standalone. MSSM 'p p > go go' has single-merged-leg squark/gluino-quark vertices @@ -1804,7 +1902,7 @@ def test_standalone_mg7_mssm_gogo(self): addressable as fixed value[] pointers, so they are gathered event-by- event into cDPF_* / flvCOUPs_dep (Step 3 of docs/mg7_merged_flavor_mssm_design.md). This is the dependent-coupling - counterpart of test_standalone_mg7_mssm_single_leg (independent flavored + counterpart of test_madmatrix_mssm_single_leg (independent flavored couplings) and the consistency check matching test_madevent_mssm_gogo. The energy (sqrt(s)) is chosen above the gluino-pair threshold (Mgo ~ @@ -1831,7 +1929,7 @@ def get_values(output_format, check_exe, build_source=False): values = [] for d in dirs: proc_dir = os.path.join(proc_root, d) - target = ['make', 'check'] if output_format == 'standalone' \ + target = ['make', 'check'] if output_format == 'standalone_fortran' \ else ['make'] subprocess.call(target, stdout=devnull, stderr=devnull, cwd=proc_dir) @@ -1847,8 +1945,8 @@ def get_values(output_format, check_exe, build_source=False): self.do('import model MSSM_SLHA2') self.do('generate p p > go go') - mg7 = get_values('standalone_mg7', './check_sa.exe') - standalone = get_values('standalone', './check', build_source=True) + mg7 = get_values('standalone', './check_sa.exe') + standalone = get_values('standalone_fortran', './check', build_source=True) self.assertTrue(any(v != 0.0 for v in standalone), 'all matrix elements vanished for p p > go go') self._assert_me_lists_close(mg7, standalone, rtol=1e-4) @@ -1857,7 +1955,7 @@ def test_madevent_mssm_gogo(self): """The Fortran madevent output supports MSSM 'p p > go go' (merged-flavor squark/gluino vertices with single-merged-leg / event-by-event flavored couplings). The mg7/madmatrix C++ output now also supports it and is - checked to agree per-flavor in test_standalone_mg7_mssm_gogo; this acts + checked to agree per-flavor in test_madmatrix_mssm_gogo; this acts as the madevent counterpart. """ self.do('import model MSSM_SLHA2') @@ -1880,7 +1978,7 @@ def test_standalone_density(self): shutil.rmtree(self.out_dir) self.do('generate p p > j t t~ ') - self.do('output standalone %s --density=4,5 -f' % self.out_dir) + self.do('output standalone_fortran %s --density=4,5 -f' % self.out_dir) devnull = open(os.devnull,'w') logfile = os.path.join(self.out_dir,'SubProcesses', 'P0_gg_gttx', @@ -1929,7 +2027,7 @@ def test_standalone_density(self): ### check case with polarization vectors ######################################################################## self.do('generate u u~ > z{0} z{T} g') - self.do('output standalone %s --density=3,4,5 -f ' % self.out_dir) + self.do('output standalone_fortran %s --density=3,4,5 -f ' % self.out_dir) devnull = open(os.devnull,'w') logfile = os.path.join(self.out_dir,'SubProcesses', 'P0_uux_z0zTg', @@ -1986,7 +2084,7 @@ def test_standalone_density(self): ### check Z > t t~ case ######################################################################## self.do('generate z > b b~') - self.do('output standalone %s --density=1 -f ' % self.out_dir) + self.do('output standalone_fortran %s --density=1 -f ' % self.out_dir) devnull = open(os.devnull,'w') logfile = os.path.join(self.out_dir,'SubProcesses', 'P0_z_bbx', @@ -2038,7 +2136,7 @@ def test_standalone_density(self): ### check case with interference computation ######################################################################## self.do('generate u u~ > t t~ QCD^2==2') - self.do('output standalone %s --density=3,4 -f ' % self.out_dir) + self.do('output standalone_fortran %s --density=3,4 -f ' % self.out_dir) devnull = open(os.devnull,'w') logfile = os.path.join(self.out_dir,'SubProcesses', 'P0_uux_ttx', @@ -2096,12 +2194,12 @@ def test_standalone_density_uu(self): # testing case u u~ > z z, z > e+ e- ############################################################################ self.do('generate u u~ > z z') - self.do('output standalone %s_prod --density=3,4 -f ' % self.out_dir) + self.do('output standalone_fortran %s_prod --density=3,4 -f ' % self.out_dir) self.do('generate u u~ > z z, z > e+ e-') - self.do('output standalone %s_full -f ' % self.out_dir) + self.do('output standalone_fortran %s_full -f ' % self.out_dir) self.do('generate z > e+ e- --standalone') # --standalone allow mix 2>1 and 2>2 processes - self.do('output standalone %s_dec1 --density=1 -f ' % self.out_dir) - self.do('output standalone %s_dec2 --density=1 -f ' % self.out_dir) + self.do('output standalone_fortran %s_dec1 --density=1 -f ' % self.out_dir) + self.do('output standalone_fortran %s_dec2 --density=1 -f ' % self.out_dir) # Read a test event for u u~ > z z, z > e+ e- @@ -2236,12 +2334,12 @@ def test_standalone_density_dd(self): # testing case d d~ > z z, z > e+ e- ############################################################################ self.do('generate d d~ > z z') - self.do('output standalone %s_prod --prefix=int --density=3,4 -f ' % self.out_dir) + self.do('output standalone_fortran %s_prod --prefix=int --density=3,4 -f ' % self.out_dir) self.do('generate d d~ > z z, z > e+ e-') - self.do('output standalone %s_full -f ' % self.out_dir) + self.do('output standalone_fortran %s_full -f ' % self.out_dir) self.do('generate z > e+ e- --standalone') # --standalone allow mix 2>1 and 2>2 processes - self.do('output standalone %s_dec1 --density=1 -f ' % self.out_dir) - self.do('output standalone %s_dec2 --density=1 -f ' % self.out_dir) + self.do('output standalone_fortran %s_dec1 --density=1 -f ' % self.out_dir) + self.do('output standalone_fortran %s_dec2 --density=1 -f ' % self.out_dir) # Read a test event for u u~ > z z, z > e+ e- text_lhe = """ 8 1 +9.3182000e+00 1.00474800e+02 7.54677100e-03 1.27930100e-01 @@ -2656,12 +2754,12 @@ def test_standalone_density_f2py(self): # testing case d d~ > z z, z > e+ e- ############################################################################ self.do('generate d d~ > z z') - self.do('output standalone %s_prod --prefix=int --density=3,4 -f ' % self.out_dir) + self.do('output standalone_fortran %s_prod --prefix=int --density=3,4 -f ' % self.out_dir) self.do('generate d d~ > z z, z > e+ e-') - #self.do('output standalone %s_full -f ' % self.out_dir) + #self.do('output standalone_fortran %s_full -f ' % self.out_dir) #self.do('generate z > e+ e- --standalone') # --standalone allow mix 2>1 and 2>2 processes - #self.do('output standalone %s_dec1 --density=1 -f ' % self.out_dir) - #self.do('output standalone %s_dec2 --density=1 -f ' % self.out_dir) + #self.do('output standalone_fortran %s_dec1 --density=1 -f ' % self.out_dir) + #self.do('output standalone_fortran %s_dec2 --density=1 -f ' % self.out_dir) # Read a test event for u u~ > z z, z > e+ e- text_lhe = """ 8 1 +9.3182000e+00 1.00474800e+02 7.54677100e-03 1.27930100e-01 @@ -2815,7 +2913,7 @@ def test_density_mode_user_interface(self): command_card.write(text) command_card.close() - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), pjoin(self.out_dir+'_density0', '..', 'mg5_cmd.txt')]) lhe_path = pjoin(self.out_dir+'_density0','Events','run_01','unweighted_events.lhe.gz') @@ -2878,7 +2976,7 @@ def test_density_mode_user_interface(self): logfile = 'test_density_mode_ttbar.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -2950,7 +3048,7 @@ def test_density_mode_ttbar(self): command_card.close() logfile = 'test_density_mode_ttbar1.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), pjoin(self.tmpdir, 'mg5_cmd.txt')], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -2971,7 +3069,7 @@ def test_density_mode_ttbar(self): command_card_rwgt.close() logfile = 'test_density_mode_ttbar2.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd_rwgt.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) #The lhe file has been reweighted, now we read density_check, the density matrix to compare to the reference @@ -3027,7 +3125,7 @@ def test_density_mode_wpwm(self): logfile = 'test_density_mode_wpwm1.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd2.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -3051,7 +3149,7 @@ def test_density_mode_wpwm(self): command_card_rwgt.close() logfile = 'test_density_mode_wpwm2.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd_rwgt2.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) #The lhe file has been reweighted, now we read density_check, the density matrix to compare to the reference @@ -3128,7 +3226,7 @@ def test_density_mode_decay1(self): command_card.close() logfile = 'test_density_mode_decay11.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -3150,7 +3248,7 @@ def test_density_mode_decay1(self): command_card_rwgt.close() logfile = 'test_density_mode_decay12.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd_rwgt.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) #The lhe file has been reweighted, now we read density_check, the density matrix to compare to the reference @@ -3222,7 +3320,7 @@ def test_density_mode_decay2(self): command_card.close() logfile = 'test_density_mode_decay21.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -3244,7 +3342,7 @@ def test_density_mode_decay2(self): command_card_rwgt.close() logfile = 'test_density_mode_decay22.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd_rwgt.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) #The lhe file has been reweighted, now we read density_check, the density matrix to compare to the reference @@ -3304,7 +3402,7 @@ def test_density_mode_doublettbar(self): command_card.close() logfile = 'test_density_mode_ttbar1.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -3326,7 +3424,7 @@ def test_density_mode_doublettbar(self): command_card_rwgt.close() logfile = 'test_density_mode_ttbar2.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd_rwgt.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) @@ -3424,7 +3522,7 @@ def notest_v4_heft(self): self.do('import model heft', force=True) self.do('generate g g > h g g') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) devnull = open(os.devnull,'w') # Check that the Model and Aloha output compile @@ -3547,7 +3645,7 @@ def test_mg7_ufo_aloha(self): header: the same FFV* helicity-amplitude functions are emitted as inline ``ALOHAOBJ`` C++ routines. This mirrors test_madevent_ufo_aloha but for the mg7 backend: it checks the routines are generated, the parameters / - process sources are present, and that the subprocess compiles (cppnone + process sources are present, and that the subprocess compiles (cpu_scalar backend) into the expected shared libraries. """ @@ -3961,7 +4059,7 @@ def test_complex_mass_SA(self): self.do('import model sm --noprefix') self.do('set complex_mass_scheme') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) misc.compile(cwd=os.path.join(self.out_dir,'SubProcesses', 'P0_epem_epem')) p = subprocess.Popen(['./check'], cwd=os.path.join(self.out_dir,'SubProcesses', 'P0_epem_epem'), stdout=subprocess.PIPE) @@ -3977,7 +4075,7 @@ def test_complex_mass_SA(self): self.do('import model sm') self.do('set complex_mass_scheme') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) misc.compile(cwd=os.path.join(self.out_dir,'SubProcesses', 'P0_epem_epem')) p = subprocess.Popen(['./check'], cwd=os.path.join(self.out_dir,'SubProcesses', 'P0_epem_epem'), stdout=subprocess.PIPE) @@ -3996,7 +4094,7 @@ def test_complex_mass_SA_merged(self): self.do('import model sm --noprefix') self.do('set complex_mass_scheme') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s ' % self.out_dir) + self.do('output standalone_fortran %s ' % self.out_dir) subdir = os.path.join(self.out_dir, 'SubProcesses', 'P0_epem_epem') misc.compile(cwd=subdir) p = subprocess.Popen(['./check'], cwd=subdir, stdout=subprocess.PIPE) @@ -4011,7 +4109,7 @@ def test_complex_mass_SA_merged(self): self.do('import model sm') self.do('set complex_mass_scheme') self.do('generate e+ e- > e+ e-') - self.do('output standalone %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) subdir = os.path.join(self.out_dir, 'SubProcesses', 'P0_epem_epem') misc.compile(cwd=subdir) p = subprocess.Popen(['./check'], cwd=subdir, stdout=subprocess.PIPE) @@ -4583,7 +4681,7 @@ def run_standalone(self,commands): for command in commands: self.do(command) - self.do('output standalone %s -f' % self.out_dir) + self.do('output standalone_fortran %s -f' % self.out_dir) Pdir = None for pdir in misc.glob('P*', pjoin(self.out_dir, 'SubProcesses')): Pdir = pdir @@ -4780,7 +4878,7 @@ def test_standalone_cpp_output(self): self.do('import model sm') self.do('generate e+ e- > e+ e- @2') - self.do('output standalone_cpp %s' % self.out_dir) + self._output_standalone_cpp(self.out_dir) # Check that all needed src files are generated files = ['HelAmps_sm.h', 'HelAmps_sm.cc', 'Makefile', @@ -4798,7 +4896,7 @@ def test_standalone_cpp_output(self): self.assertTrue(os.path.exists(os.path.join(self.out_dir, 'lib', 'libmodel_sm.a'))) - # Locate the subprocess directory: the merge shortened the standalone_cpp + # Locate the subprocess directory: the merge shortened the C++ # directory name (P2_Sigma_sm_epem_epem -> P2_epem_epem), so discover it. proc_root = os.path.join(self.out_dir, 'SubProcesses') candidates = [d for d in os.listdir(proc_root) @@ -4862,7 +4960,7 @@ class IOTestFDGauge(IOTests.IOTestManager): a vector constant broadcast to the first lane only, and a gauge direction that differed between the scalar and vector branches) lived in the released templates because of it. Two of them show up as a wrong number, which - test_standalone_mg7_fd_vs_fortran and test_standalone_mg7_fd_simd_lanes now + test_madmatrix_fd_vs_fortran and test_madmatrix_fd_simd_lanes now catch; the third is a gauge choice, invisible to any matrix element, and only a reference file can hold it still. @@ -4915,4 +5013,4 @@ def testIO_FDgauge_madmatrix(self): """ # one file holds all of it for madmatrix: the generated routines and, # pasted above them, the FD helpers of helas_fd.h - self.generate_fd('standalone_mg7', pjoin(self.IOpath, 'FD_madmatrix')) + self.generate_fd('standalone', pjoin(self.IOpath, 'FD_madmatrix')) diff --git a/tests/acceptance_tests/test_cmd_amcatnlo.py b/tests/acceptance_tests/test_cmd_amcatnlo.py index 54c8344120..e8ef9ee408 100755 --- a/tests/acceptance_tests/test_cmd_amcatnlo.py +++ b/tests/acceptance_tests/test_cmd_amcatnlo.py @@ -774,7 +774,7 @@ def test_amcatnlo_from_file(self): stderr=devnull - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(_file_path, 'input_files','test_amcatnlo')], cwd=self.tmpdir, stdout=stdout,stderr=stderr) diff --git a/tests/acceptance_tests/test_cmd_madevent.py b/tests/acceptance_tests/test_cmd_madevent.py index d50b924361..d0776f17a0 100755 --- a/tests/acceptance_tests/test_cmd_madevent.py +++ b/tests/acceptance_tests/test_cmd_madevent.py @@ -96,8 +96,8 @@ def _mg7_datadir_or_skip(test): misc.sprint(datadir) if not has_mg7 or not datadir or not os.path.isdir(datadir): test.skipTest('mg7 runtime stack (madspace + LHAPDF data) unavailable') - if not glob.glob(pjoin(datadir, 'NNPDF23_lo_as_0130_qed*')): - test.skipTest('NNPDF23_lo_as_0130_qed PDF set not available') + if not glob.glob(pjoin(datadir, 'NNPDF40MC_lo_as_01180*')): + test.skipTest('NNPDF40MC_lo_as_01180 PDF set not available') return datadir @@ -208,7 +208,7 @@ def _run_mg7_postproc(test, setup_cmds, run_dir, datadir, switch_lines=None, # exec_cmd bypasses the history, so the proc_card would miss the model / # generate / output lines and MadSpin (which reads 'generate' from the # banner) would abort with "no generate line". This mirrors how a real user - # drives the output (bin/mg5_aMC command file / interactive session). + # drives the output (bin/madgraph command file / interactive session). for c in setup_cmds: mg.run_cmd(c) mg.run_cmd('output mg7 %s' % run_dir) @@ -341,7 +341,7 @@ def generate(self, process, model): #if not os.path.exists(pjoin(MG5DIR, 'MadAnalysis')): # print("install MadAnalysis") - # p = subprocess.Popen([pjoin(MG5DIR,'bin','mg5_aMC')], + # p = subprocess.Popen([pjoin(MG5DIR,'bin','madgraph')], # stdin=subprocess.PIPE, # stdout=stdout,stderr=stderr) # out = p.communicate('install MadAnalysis4'.encode()) @@ -722,8 +722,8 @@ def test_group_subprocess_mg7(self): Runs the mg7 (madspace) integrator with group_subprocesses on and off and checks the two cross-sections agree (grouping consistency). It also pins the absolute value to the mg7-native result obtained with the - run_card.toml defaults (NNPDF23_lo_as_0130_qed + dynamical HT/2 scale, - events=2000) ~ 1.277e+06 pb. + run_card.toml defaults (NNPDF40MC_lo_as_01180 + dynamical HT/2 scale, + events=2000) ~ 7.76e+05 pb. NOTE: this is NOT the madevent reference (1.31e6 pb in test_group_subprocess); but it would be if true lhapdf were used in madevent @@ -746,8 +746,8 @@ def test_group_subprocess_mg7(self): if not has_mg7 or not datadir or not os.path.isdir(datadir): self.skipTest('mg7 runtime stack (madspace + LHAPDF data) unavailable') # the mg7 run_card.toml default PDF must be present in the data dir - if not glob.glob(pjoin(datadir, 'NNPDF23_lo_as_0130_qed*')): - self.skipTest('NNPDF23_lo_as_0130_qed PDF set not available') + if not glob.glob(pjoin(datadir, 'NNPDF40MC_lo_as_01180*')): + self.skipTest('NNPDF40MC_lo_as_01180 PDF set not available') def run_mg7(group): run_dir = pjoin(self.path, 'MG7_%s' % ('grp' if group else 'ungrp')) @@ -786,9 +786,13 @@ def run_mg7(group): self.assertLess(abs(val1 - val2) / (err1 + err2 + 1e-30), 5, 'mg7 grouped (%s +- %s) vs ungrouped (%s +- %s) disagree' % (val1, err1, val2, err2)) - # NOT the madevent 1.31e6 value for internal pdf but the one for - # lhapdf NNPDF23_lo_as_0130_qed + dynamical HT/2 scale - target = 1.277e+06 + # NOT the madevent 1.31e6 value for internal pdf but the one for + # lhapdf NNPDF40MC_lo_as_01180 + dynamical HT/2 scale. Was 1.277e+06 + # with the old default NNPDF23_lo_as_0130_qed; a same-code A/B gives + # 1.272e+06 (NNPDF23) vs 7.79e+05, so the -39% is the PDF change alone: + # alpha_s^2 (-18%) times the smaller NNPDF4.0 u-quark luminosity. + # Spread over 6 runs at events=2000: 7.66e5-7.84e5, mean 7.76e5. + target = 7.76e+05 self.assertLess(abs(val2 - target) / target, 0.10, 'mg7 u u > u u cross-section %s far from mg7 reference %s' % (val2, target)) @@ -1250,7 +1254,7 @@ def test_relaunch_switch_defaults_mg7(self): mg.exec_cmd('output mg7 %s' % out_dir) launcher = importlib.import_module( - 'madgraph.iolibs.template_files.mg7.madevent') + 'madgraph.iolibs.template_files.mg7.launch') tool_cards = ('pythia8_card.dat', 'madspin_card.dat', 'delphes_card.dat', 'reweight_card.dat', 'rivet_card.dat', 'madanalysis5_parton_card.dat', @@ -1292,8 +1296,9 @@ def launch_select_nothing(): def test_madevent_merged_flavor_uq_mg7(self): """mg7 equivalent of test_madevent_merged_flavor_uq (u q > u q QCD=0, - q = u d): the merged-flavor path must reproduce the 4428 pb obtained by - running u u > u u and u d > u d as separate single-flavor processes. + q = u d): the merged-flavor path must reproduce the cross-section + obtained by running u u > u u and u d > u d as separate single-flavor + processes. This used to come out too large because the mg7 exporter mirrored the mixed u d initial flavor -- leg 1 is a fixed u, so the beam-swapped @@ -1319,8 +1324,8 @@ def test_madevent_merged_flavor_uq_mg7(self): datadir = None if not has_mg7 or not datadir or not os.path.isdir(datadir): self.skipTest('mg7 runtime stack (madspace + LHAPDF data) unavailable') - if not glob.glob(pjoin(datadir, 'NNPDF23_lo_as_0130_qed*')): - self.skipTest('NNPDF23_lo_as_0130_qed PDF set not available') + if not glob.glob(pjoin(datadir, 'NNPDF40MC_lo_as_01180*')): + self.skipTest('NNPDF40MC_lo_as_01180 PDF set not available') run_dir = pjoin(self.path, 'MG7_uq') if os.path.isdir(run_dir): @@ -1353,8 +1358,14 @@ def test_madevent_merged_flavor_uq_mg7(self): info = json.load(open(infos[-1]))['process'] cross = float(info['mean']) error = float(info.get('error') or 0.0) - # physical reference (same as the madevent test); mg7 must reproduce it - self.assertAlmostEqual(cross, 4428.0, delta=max(30.0, 5 * error)) + # mg7 reference with the default PDF NNPDF40MC_lo_as_01180. This no + # longer equals the 4428 pb of the madevent test above: that one runs on + # madevent's internal (nn23lo1) PDF while mg7 convolutes with the LHAPDF + # grid named in run_card.toml. QCD=0, so there is no alpha_s here at all + # and the -16% shift is purely the smaller NNPDF4.0 valence-quark + # luminosity; a same-code A/B gives 4380 pb (NNPDF23) vs 3688 pb. + # Spread over 7 runs at events=2000: 3675-3775, mean 3731. + self.assertAlmostEqual(cross, 3730.0, delta=max(30.0, 5 * error)) def test_flavor_grouping_consistency(self): """Check that the four combinations of 'apply_flavor_grouping' and @@ -1738,7 +1749,7 @@ def test_e_p_collision_mg7(self): generate_events run. The mg7 (madmatrix/cudacpp) integrator is far too slow for a CI cross-section run on this process, so this equivalent validates the mg7 *output* path instead: that `output mg7` generates the - e- p > e- j subprocess directories and that they compile (scalar cppnone + e- p > e- j subprocess directories and that they compile (cpu_scalar backend) into the expected shared libraries. The cross-section comparison against the madevent reference remains a TODO pending a faster mg7 integrator. @@ -2253,7 +2264,7 @@ def test_width_scan(self): stdout=devnull stderr=devnull - subprocess.call([pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], #cwd=pjoin(self.path), stdout=stdout,stderr=stdout) @@ -2489,7 +2500,7 @@ def test_add_time_of_flight(self): devnull =open(os.devnull,'w') stdout=devnull stderr=devnull - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'mg5_cmd')], #cwd=self.path, stdout=stdout, stderr=stderr) @@ -2572,7 +2583,7 @@ def test_w_production_with_ms_decay(self): launch """) fsock.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2653,7 +2664,7 @@ def test_wj_production_with_ms_decay(self): launch """) fsock.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2729,7 +2740,7 @@ def test_w_production_with_PA_decay(self): launch """) fsock.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2815,7 +2826,7 @@ def test_w_production_with_PA_decay_inline_then_offline(self): launch """) fsock.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2874,7 +2885,7 @@ def test_DY_onejet(self): """ % {'path':self.run_dir}) command.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2935,7 +2946,7 @@ def test_generation_heft(self): """ % {'path':self.run_dir}) command.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -2946,22 +2957,23 @@ def test_generation_heft(self): def test_generation_heft_mg7(self): """mg7 equivalent of test_generation_heft for g g > b b~ HIW<=1 (HEFT). - KNOWN-FAILING, intentionally NOT marked xfail: mg7 runs this HEFT process - but its cross-section comes out ~257x below the physical value (~1.6e6 pb - vs the madevent 4.117e8 pb) -- a large mg7 normalisation discrepancy for - the effective ggH coupling. The test asserts the physical reference and is - expected to fail until that is resolved; left undecorated to keep the - discrepancy visible. Self-skips where the mg7 runtime stack is unavailable. + Pins the mg7-native cross-section obtained with the run_card.toml + defaults and the dynamical HT/2 scale that _run_mg7_xsec selects. + Self-skips where the mg7 runtime stack is unavailable. """ datadir = _mg7_datadir_or_skip(self) - cross, error = _run_mg7_xsec(self, + cross, error = _run_mg7_xsec(self, ['set automatic_html_opening False --no_save', 'import model heft', 'generate g g > b b~ HIW<=1'], pjoin(self.path, 'MG7_heft'), datadir) - # physical reference (same as test_generation_heft) - target = 4.117e8 # HT/2 - target = 3.754e+08 # fixed scale MZ + # mg7 reference with the default PDF NNPDF40MC_lo_as_01180 (NNPDF4.0 LO, + # alpha_s(M_Z) = 0.118). The previous 3.754e+08 was the same run with the + # old default NNPDF23_lo_as_0130_qed: a same-code A/B on this process + # gives 3.708e+08 (NNPDF23) vs 1.820e+08 (NNPDF40MC), i.e. the -51% is + # entirely the PDF change -- gg luminosity (-25% at these x) times + # alpha_s^2 (-22% at the ~20 GeV dynamical scale). + target = 1.820e+08 self.assertLess(abs(cross - target) / target, 0.10, 'mg7 HEFT cross-section %s far from physical reference %s' % (cross, target)) @@ -3017,7 +3029,7 @@ def test_polarization_top_decay(self): """ % {'path':self.run_dir}) command.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -3047,7 +3059,7 @@ def test_polarization_top_decay(self): """ % {'path':self.run_dir}) command.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -3078,7 +3090,7 @@ def test_polarization_top_decay(self): """ % {'path':self.run_dir}) command.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'cmd')], cwd=pjoin(_file_path, os.path.pardir), stdout=stdout,stderr=stdout) @@ -3108,7 +3120,7 @@ def test_generation_from_file_1(self): fsock.write(open(pjoin(_file_path, 'input_files','test_mssm_generation')).read() % {'dir_name': self.run_dir, 'mg5_path':pjoin(_file_path, os.path.pardir)}) fsock.close() - subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([sys.executable, pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'test_mssm_generation')], #cwd=pjoin(self.path), stdout=stdout,stderr=stdout) @@ -3138,13 +3150,14 @@ def test_generation_from_file_1(self): event.check() def test_generation_from_file_1_mg7(self): - """mg7 (madspace) cross-section for MSSM p p > go go, pinned to the - madevent reference from test_generation_from_file_1. + """mg7 (madspace) cross-section for MSSM p p > go go. - standalone_mg7 reproduces the per-flavor |M|^2 for p p > go go - (test_standalone_mg7_mssm_gogo, ~1e-4) and the madspace integrator now - lands on the madevent cross-section as well, so this pins the mg7 result - to the madevent reference (run_01 of test_generation_from_file_1). + the standalone (madmatrix) export reproduces the per-flavor |M|^2 for + p p > go go (test_madmatrix_mssm_gogo, ~1e-4) and the madspace integrator + lands on the madevent cross-section as well: with NNPDF23_lo_as_0130_qed + pinned in the run_card this setup gives 5.0235, against the madevent + reference of 5.024 (run_01 of test_generation_from_file_1). The target + below is for the default PDF instead -- see the comment on it. This used to be red at random rather than for a physics reason: the assertion is at 1%, but with the old 2000-event target a single run @@ -3161,10 +3174,17 @@ def test_generation_from_file_1_mg7(self): 'import model MSSM_SLHA2', 'generate p p > go go'], pjoin(self.path, 'MG7_mssm_gogo'), datadir) - # madevent reference (run_01 in test_generation_from_file_1) - target = 5.024 # no cut madevent with lhapdf (not internal pdf) (relative error from madevent: 1e-4) + # Reference for the default PDF NNPDF40MC_lo_as_01180, measured over 6 + # runs: 3.7864 +- 0.0011 (single-run error ~0.003, i.e. ~0.08%), so the + # 1% tolerance here is a ~12 sigma check. The value shifts from the old + # NNPDF23_lo_as_0130_qed reference of 5.024 (madevent, no cuts, lhapdf) + # purely because of the PDF change: p p > go go is forced to large x by + # the ~600 GeV gluino pair, where the two sets differ a lot. With + # NNPDF23 pinned in the run_card this same setup still gives 5.0235, + # matching that madevent reference to 0.01%. + target = 3.786 self.assertLess(abs(cross - target) / target, 0.01, - 'mg7 p p > go go cross-section %s far from madevent reference %s' + 'mg7 p p > go go cross-section %s far from reference %s' % (cross, target)) def test_contur_from_file(self): @@ -3186,7 +3206,7 @@ def test_contur_from_file(self): stdout= None - subprocess.call([pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(_file_path, os.path.pardir, 'tests', 'input_files','rivet_contur_test.cmd')], cwd=pjoin(self.path), stdout=stdout,stderr=stdout) @@ -3244,7 +3264,7 @@ def test_rivet_from_file(self): devnull =open(os.devnull,'w') stdout=devnull stderr=devnull - subprocess.call([pjoin(_file_path, os.path.pardir,'bin','mg5_aMC'), + subprocess.call([pjoin(_file_path, os.path.pardir,'bin','madgraph'), pjoin(self.path, 'mg5_cmd')], #cwd=self.path, stdout=stdout, stderr=stderr) @@ -3260,7 +3280,8 @@ def test_rivet_from_file(self): # tool-selection question -> run_selected_tools -> MG7RunCmd), so that at # least one test exercises the command interface + chaining of every tool # with the new (default) output. They self-skip when the mg7 runtime stack - # (madspace + LHAPDF + NNPDF23) or the external tool is unavailable. + # (madspace + LHAPDF + the default PDF set) or the external tool is + # unavailable. #========================================================================== def test_add_time_of_flight_mg7(self): """time-of-flight LHE post-processing chained on the mg7 output. diff --git a/tests/acceptance_tests/test_cmd_madloop.py b/tests/acceptance_tests/test_cmd_madloop.py index ee46b977e8..91c8c93d50 100755 --- a/tests/acceptance_tests/test_cmd_madloop.py +++ b/tests/acceptance_tests/test_cmd_madloop.py @@ -637,7 +637,7 @@ def test_density_mode_loop_induced_standalone1(self): self.do('import model loop_sm') self.do('generate g g > h [sqrvirt=QCD]') - self.run_cmd(f'output standalone {short_path} --density=1,2 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. + self.run_cmd(f'output standalone_fortran {short_path} --density=1,2 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. self.run_cmd(f'launch {short_path} -f ') devnull = open(os.devnull,'w') @@ -695,7 +695,7 @@ def test_density_mode_loop_induced_standalone2(self): self.do('import model loop_sm') self.do('generate g g > w+ w- [sqrvirt=QCD]') - self.run_cmd(f'output standalone {short_path} --density=3,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. + self.run_cmd(f'output standalone_fortran {short_path} --density=3,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. self.run_cmd(f'launch {short_path} -f ') devnull = open(os.devnull,'w') @@ -760,7 +760,7 @@ def test_density_mode_loop_induced_standalone3(self): self.do('import model loop_sm') self.do('generate p p > h j [sqrvirt=QCD]') - self.run_cmd(f'output standalone {short_path} --density=2,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. + self.run_cmd(f'output standalone_fortran {short_path} --density=2,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. self.run_cmd(f'launch {short_path} -f ') # the result of the run is stored inside the file result.dat @@ -922,7 +922,7 @@ def test_density_mode_vs_standalone_LI1(self): command_card.close() logfile = 'test_density_vs_LI_standalone1.log' - subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), '/tmp/mg5_cmd.txt']) lhe_path = pjoin(self.out_dir, "Events/run_01/unweighted_events.lhe.gz") @@ -950,7 +950,7 @@ def test_density_mode_vs_standalone_LI1(self): # self.do('import model loop_sm') # self.do('generate g g > w+ w- [sqrvirt=QCD]') - # self.run_cmd(f'output standalone {short_path2} --density=3,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. + # self.run_cmd(f'output standalone_fortran {short_path2} --density=3,4 -f') # we need run_cmd here, else HelicityFilterLevel is not set to 1. # path_PS_card = pjoin(short_path2, "SubProcesses/P0_gg_wpwm/PS.input") # with open(path_PS_card, 'w') as psinput: # psinput.write(str(p_all[0]).strip("[],") + "\n") @@ -969,7 +969,7 @@ def test_density_mode_vs_standalone_LI1(self): # command_card_bis.close() # logfile = 'test_density_vs_LI_standalone.log' - # subprocess.call([sys.executable,pjoin(MG5DIR,'bin','mg5_aMC'), + # subprocess.call([sys.executable,pjoin(MG5DIR,'bin','madgraph'), # '/tmp/mg5_cmd_bis.txt'], stdout=open(logfile, 'w'), stderr=subprocess.STDOUT) diff --git a/tests/acceptance_tests/test_madspin.py b/tests/acceptance_tests/test_madspin.py index 6f942d5517..9a8e90ec6a 100755 --- a/tests/acceptance_tests/test_madspin.py +++ b/tests/acceptance_tests/test_madspin.py @@ -267,7 +267,7 @@ def test_madspin_mixed_flavor_decay_log_summary(self): with open(log_path, 'w') as log_file: return_code = subprocess.call( - [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'mg5_aMC'), cmd_path], + [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'madgraph'), cmd_path], cwd=pjoin(_file_path, os.path.pardir), stdout=log_file, stderr=subprocess.STDOUT) self.assertEqual(return_code, 0) @@ -373,7 +373,7 @@ def test_madspin_mixed_flavor_decay_log_summary_mg7(self): with open(log_path, 'w') as log_file: try: return_code = subprocess.call( - [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'mg5_aMC'), cmd_path], + [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'madgraph'), cmd_path], cwd=pjoin(_file_path, os.path.pardir), stdin=subprocess.DEVNULL, stdout=log_file, stderr=subprocess.STDOUT, timeout=240) @@ -385,7 +385,7 @@ def test_madspin_mixed_flavor_decay_log_summary_mg7(self): # dir CI does not upload) so the reason is visible in the CI output. if return_code != 0 or not re.search(r'MadSpin\s+unweight\s+efficiency', log): print('\n===== test_madspin_mixed_flavor_decay_log_summary_mg7: ' - 'mg5_aMC log tail (rc=%s) =====\n%s' + 'madgraph log tail (rc=%s) =====\n%s' % (return_code, '\n'.join(log.splitlines()[-150:])), file=sys.stderr, flush=True) self.assertEqual(return_code, 0) @@ -417,7 +417,7 @@ def test_madspin_wplus_all_all_flavor_balance(self): with open(log_path, 'w') as log_file: return_code = subprocess.call( - [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'mg5_aMC'), cmd_path], + [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'madgraph'), cmd_path], cwd=pjoin(_file_path, os.path.pardir), stdout=log_file, stderr=subprocess.STDOUT) self.assertEqual(return_code, 0) @@ -479,7 +479,7 @@ def test_madspin_wplus_all_all_flavor_balance_2to1(self): with open(log_path, 'w') as log_file: return_code = subprocess.call( - [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'mg5_aMC'), cmd_path], + [sys.executable, pjoin(_file_path, os.path.pardir, 'bin', 'madgraph'), cmd_path], cwd=pjoin(_file_path, os.path.pardir), stdout=log_file, stderr=subprocess.STDOUT) self.assertEqual(return_code, 0) diff --git a/tests/acceptance_tests/test_model_equivalence.py b/tests/acceptance_tests/test_model_equivalence.py index 5025b69fd9..2c28bfee14 100755 --- a/tests/acceptance_tests/test_model_equivalence.py +++ b/tests/acceptance_tests/test_model_equivalence.py @@ -346,7 +346,7 @@ def setUp(self): # model = save_load_object.load_from_file(picklefile) misc.sprint(self.output_path, os.path.exists(self.output_path)) - export_v4.UFO_model_to_mg4(model, self.output_path,opt = {'export_format': 'standalone', 'mp':False}).build() + export_v4.UFO_model_to_mg4(model, self.output_path,opt = {'export_format': 'standalone_fortran', 'mp':False}).build() # tearDown = CheckFileCreate.clean_files diff --git a/tests/acceptance_tests/test_standalone_madevent_consistency.py b/tests/acceptance_tests/test_standalone_madevent_consistency.py index 0c9dd01983..d717c1af33 100644 --- a/tests/acceptance_tests/test_standalone_madevent_consistency.py +++ b/tests/acceptance_tests/test_standalone_madevent_consistency.py @@ -73,7 +73,7 @@ def check_process(self, process, model='sm', tolerance=1e-6): self.do('import model %s' % model) self.do('generate %s' % process) generated_process = self.cmd._curr_amps[0].get('process') - self.do('output standalone %s -f' % self.standalone_dir) + self.do('output standalone_fortran %s -f' % self.standalone_dir) self.do('output madevent %s -f' % self.madevent_dir) standalone_dir = self._get_single_subprocess_dir( diff --git a/tests/input_files/mg7_run_card.toml b/tests/input_files/mg7_run_card.toml index 8a2db1fb34..eb57edf4ab 100644 --- a/tests/input_files/mg7_run_card.toml +++ b/tests/input_files/mg7_run_card.toml @@ -1,7 +1,7 @@ [run] run_name = "run" -# options: cuda, hip, cpp, cppnone, cppsse4, cppavx2, cpp512y, cpp512z, cppauto -devices = ["cppnone"] +# options: cuda, hip, cpu_scalar, cpu_128b, cpu_256b, cpu_512b_y, cpu_512b, cpu +devices = ["cpu_scalar"] # options: # -1 to choose automatically # on x86: 1, 4, 8 diff --git a/tests/parallel_tests/loop_me_comparator.py b/tests/parallel_tests/loop_me_comparator.py index 62d2d43b0b..0fd4eda927 100755 --- a/tests/parallel_tests/loop_me_comparator.py +++ b/tests/parallel_tests/loop_me_comparator.py @@ -236,7 +236,7 @@ def format_mg5_proc_card(self, proc_list, model): v5_string += 'add process ' + proc + ' ' + born_couplings + \ ' [virt=' + perturbations + '] ' + squared_couplings + \ (' @%i\n'%i) - v5_string += "output standalone %s -f\n"%\ + v5_string += "output standalone_fortran %s -f\n"%\ os.path.join(self.mg5_path, self.temp_dir_name) return v5_string @@ -448,7 +448,7 @@ def format_mg5_proc_card(self, proc_list, model): v5_string += 'add process ' + proc + ' ' + born_couplings + \ ' [virt=' + perturbations + '] ' + squared_couplings + \ (' @%i\n'%i) - v5_string += "output standalone %s -f\n"%\ + v5_string += "output standalone_fortran %s -f\n"%\ os.path.join(self.mg5_path, self.temp_dir_name) v5_string += 'set complex_mass_scheme False \n' diff --git a/tests/parallel_tests/madevent_comparator.py b/tests/parallel_tests/madevent_comparator.py index 0a660e0613..c196252ed1 100755 --- a/tests/parallel_tests/madevent_comparator.py +++ b/tests/parallel_tests/madevent_comparator.py @@ -749,8 +749,8 @@ class MG5RunnerMG7Aligned(MG5Runner): run_card.toml defaults, so its cross-section is directly comparable with :class:`MG7Runner`. - Matched settings: e_cm = 13 TeV (ebeam 6500 each), PDF NNPDF23_lo_as_0130_qed - (lhaid 247000), the dynamical HT/2 scale (dynamical_scale_choice=3, which is + Matched settings: e_cm = 13 TeV (ebeam 6500 each), PDF NNPDF40MC_lo_as_01180 + (lhaid 338500), the dynamical HT/2 scale (dynamical_scale_choice=3, which is the madevent equivalent of mg7's ``half_transverse_mass``), and the mg7 jet cuts (pt>20, |eta|<5, dR>0.4). Returns the total cross-section under the 'cross' key so the comparison is total-to-total. @@ -758,9 +758,10 @@ class MG5RunnerMG7Aligned(MG5Runner): name = 'MadGraph madevent (mg7-aligned)' type = 'v5_mg7aligned' - # lhaid for NNPDF23_lo_as_0130_qed (the mg7 run_card.toml default PDF), so - # both sides use exactly the same LHAPDF set. - lhaid = 247000 + # lhaid for NNPDF40MC_lo_as_01180 (the mg7 run_card.toml default PDF), so + # both sides use exactly the same LHAPDF set. Must be kept in sync with the + # [beam] pdf default in banner.py. + lhaid = 338500 def format_mg5_proc_card(self, proc_list, model, orders): if model != 'mssm': @@ -781,7 +782,7 @@ def format_mg5_proc_card(self, proc_list, model, orders): # --- align with the mg7 run_card.toml ------------------------------- v5_string += "set ebeam1 6500\n" v5_string += "set ebeam2 6500\n" - # Use exactly the mg7 run_card.toml PDF (NNPDF23_lo_as_0130_qed) via + # Use exactly the mg7 run_card.toml PDF (NNPDF40MC_lo_as_01180) via # LHAPDF, now that the AlphaS_FlavorScheme metadata hotfix patches the # source set in pdfsets_dir. v5_string += "set pdlabel lhapdf\n" @@ -854,10 +855,10 @@ def run(self, proc_list, model, orders={}): devnull = open(os.devnull,'w') if logging.root.level >=20: - subprocess.call([pjoin(self.mg5_path,'bin','mg5_aMC'), proc_card_location], + subprocess.call([pjoin(self.mg5_path,'bin','madgraph'), proc_card_location], stdout=devnull, stderr=devnull) else: - subprocess.call([pjoin(self.mg5_path,'bin','mg5_aMC'), proc_card_location]) + subprocess.call([pjoin(self.mg5_path,'bin','madgraph'), proc_card_location]) os.remove(proc_card_location) values = self.get_values() diff --git a/tests/parallel_tests/madspin_comparator.py b/tests/parallel_tests/madspin_comparator.py index 90552c61c9..ffeaf14350 100644 --- a/tests/parallel_tests/madspin_comparator.py +++ b/tests/parallel_tests/madspin_comparator.py @@ -271,7 +271,7 @@ def __init__(self, name, production_process, decays, self._results = {} # ------------------------------------------------------------------ - # Production: run mg5_aMC once to generate events. + # Production: run madgraph once to generate events. # ------------------------------------------------------------------ def _write_mg5_script(self, script_path): lines = ['set automatic_html_opening False --no_save', @@ -300,7 +300,7 @@ def _write_mg5_script(self, script_path): fp.write('\n'.join(lines) + '\n') def produce_events(self): - """Run mg5_aMC once; cache the LHE file path.""" + """Run madgraph once; cache the LHE file path.""" if self.events_file: return self.events_file @@ -312,15 +312,15 @@ def produce_events(self): self.name, log_path) with open(log_path, 'w') as logf: ret = subprocess.call( - [pjoin(MG5DIR, 'bin', 'mg5_aMC'), '-f', script_path], + [pjoin(MG5DIR, 'bin', 'madgraph'), '-f', script_path], stdout=logf, stderr=subprocess.STDOUT, ) if ret != 0: raise RuntimeError( - 'mg5_aMC failed for factory %s (see %s)' % (self.name, log_path) + 'madgraph failed for factory %s (see %s)' % (self.name, log_path) ) - # mg5_aMC -f sometimes returns 0 even when an intermediate command + # madgraph -f sometimes returns 0 even when an intermediate command # (e.g. ``generate``) aborts -- the wrapper just skips the rest and # exits cleanly. Check the log for the unmistakable markers it emits # in that case so we surface the failure here instead of further down @@ -332,7 +332,7 @@ def produce_events(self): 'command not executed: launch'): if marker in log_text: raise RuntimeError( - 'mg5_aMC aborted mid-script for factory %s ' + 'madgraph aborted mid-script for factory %s ' '(marker %r in %s)' % (self.name, marker, log_path) ) diff --git a/tests/parallel_tests/me_comparator.py b/tests/parallel_tests/me_comparator.py index 83411edf5c..a775a63a05 100755 --- a/tests/parallel_tests/me_comparator.py +++ b/tests/parallel_tests/me_comparator.py @@ -443,7 +443,7 @@ def format_mg5_proc_card(self, proc_list, model, orders): for i, proc in enumerate(proc_list): v5_string += 'add process ' + proc + ' ' + couplings + \ '@%i' % i + '\n' - v5_string += "output standalone %s -f\n" % \ + v5_string += "output standalone_fortran %s -f\n" % \ os.path.join(self.mg4_path, self.temp_dir_name) return v5_string @@ -466,7 +466,7 @@ def format_mg5_proc_card(self, proc_list, model, orders): for i, proc in enumerate(proc_list): v5_string += 'add process ' + proc + ' ' + couplings + \ '@%i' % i + '\n' - v5_string += "output standalone %s -f\n" % \ + v5_string += "output standalone_fortran %s -f\n" % \ os.path.join(self.mg4_path, self.temp_dir_name) misc.sprint("proc_card.dat content:\n%s" % v5_string) return v5_string @@ -496,7 +496,7 @@ def format_mg5_proc_card(self, proc_list, model, orders): for i, proc in enumerate(proc_list): v5_string += 'add process ' + proc + ' ' + couplings + \ '@%i' % i + '\n' - v5_string += "output standalone %s -f\n" % \ + v5_string += "output standalone_fortran %s -f\n" % \ os.path.join(self.mg4_path, self.temp_dir_name) v5_string += 'set complex_mass_scheme False \n' @@ -546,7 +546,7 @@ def run(self, proc_list, model, orders={}, energy=1000): v5_string = "import model %s \n" % model proc_card_file.write(v5_string) proc_card_file.write(self.pass_proc) - proc_card_file.write("\n output standalone %s -f\n" % dir_name) + proc_card_file.write("\n output standalone_fortran %s -f\n" % dir_name) proc_card_file.close() logging.info("proc_card.dat file for %i processes successfully created in %s" % \ @@ -557,10 +557,10 @@ def run(self, proc_list, model, orders={}, energy=1000): devnull = open(os.devnull,'w') if logging.root.level >=20: - subprocess.call([pjoin(self.mg5_path,'bin','mg5_aMC'), proc_card_location], + subprocess.call([pjoin(self.mg5_path,'bin','madgraph'), proc_card_location], stdout=devnull, stderr=devnull) else: - subprocess.call([pjoin(self.mg5_path,'bin','mg5_aMC'), proc_card_location]) + subprocess.call([pjoin(self.mg5_path,'bin','madgraph'), proc_card_location]) # Remove the temporary proc_card @@ -592,53 +592,12 @@ def format_mg5_proc_card(self, proc_list, model, orders): for i, proc in enumerate(proc_list): v5_string += 'add process ' + proc + ' ' + couplings + \ '@%i' % i + '\n' - v5_string += "output standalone %s -f\n" % \ + v5_string += "output standalone_fortran %s -f\n" % \ os.path.join(self.mg4_path, self.temp_dir_name) return v5_string -class MG5_CPP_Runner(MG5Runner): - """Runner object for the MG5 C++ Standalone output.""" - - mg5_path = "" - - type='cpp' - name = 'MG5-C++' - compilator ='g++' - - def format_mg5_proc_card(self, proc_list, model, orders): - """Create a proc_card.dat string following v5 conventions.""" - - v5_string = "import model %s \n" % model - v5_string += "set automatic_html_opening False\n" - couplings = MERunner.get_coupling_definitions(orders) - - for i, proc in enumerate(proc_list): - v5_string += 'add process ' + proc + ' ' + couplings + \ - '@%i' % i + '\n' - v5_string += "output standalone_cpp %s -f\n" % \ - os.path.join(self.mg4_path, self.temp_dir_name) - - return v5_string - - def fix_energy_in_check(self, dir_name, energy): - """Replace the hard coded collision energy in check_sa.cpp by the given - energy, assuming a working dir dir_name""" - - for check_sa_path in glob.glob( - os.path.join(dir_name, 'SubProcesses', '*', 'check_sa.cpp')): - - file = open(check_sa_path, 'r') - check_sa = file.read() - file.close() - - file = open(check_sa_path, 'w') - file.write(re.sub(r"double energy = [\d.]+;", - "double energy = %s;" % str(float(energy)), - check_sa)) - file.close() - class PickleRunner(MERunner): """Runner object for the stored comparison results.""" diff --git a/tests/parallel_tests/sample_script.py b/tests/parallel_tests/sample_script.py index bb038c7212..2dc89c352c 100755 --- a/tests/parallel_tests/sample_script.py +++ b/tests/parallel_tests/sample_script.py @@ -71,10 +71,6 @@ my_mg5_ufo = me_comparator.MG5_UFO_Runner() my_mg5_ufo.setup(mg5_path, mg4_path) - # Create a MERunner object for C++ - my_mg5_cpp = me_comparator.MG5_CPP_Runner() - my_mg5_cpp.setup(mg5_path, mg4_path) - # Create and setup a comparator my_comp = me_comparator.MEComparator() my_comp.set_me_runners(my_mg5, my_mg5_ufo) diff --git a/tests/test_manager.py b/tests/test_manager.py index be15cc97b2..911f13c950 100755 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -1249,7 +1249,7 @@ def bypass_for_py3(fct): pass if sys.platform == "darwin" and options.nosleep: - logging.getLogger('madgraph').warning("launching caffeinate to prevent idle sleep when MG5aMC is running. Run './bin/mg5_aMC -s' to prevent this.") + logging.getLogger('madgraph').warning("launching caffeinate to prevent idle sleep when MG5aMC is running. Run './bin/madgraph -s' to prevent this.") pid = os.getpid() subprocess.Popen(['caffeinate', '-i', '-w', str(pid)]) diff --git a/tests/unit_tests/various/test_import_ufo.py b/tests/unit_tests/various/test_import_ufo.py index 373e8f2124..33d7cf2abd 100755 --- a/tests/unit_tests/various/test_import_ufo.py +++ b/tests/unit_tests/various/test_import_ufo.py @@ -1668,3 +1668,51 @@ def test_restrict_from_a_param_card(self): found += 1 self.assertEqual(found, 1) + + +class TestLorentzStructureCanonicalisation(unittest.TestCase): + """Sorting the arguments of the symmetric lorentz structures. + + Renumbering the indices of a vertex can reorder the arguments of a + symmetric function, so that the same object is written Metric(3,2) in one + definition and Metric(2,3) in another. import_ufo compares the two + structures when a lorentz name is defined twice and warns when they + disagree; without canonicalisation that warning fires on every such + renumbering and hides the real disagreements among the noise. + """ + + def test_symmetry_is_carried_by_the_structure(self): + """is_symmetric lives on the aloha object, and defaults to False.""" + import aloha.aloha_object as aloha_object + import aloha.aloha_lib as aloha_lib + self.assertFalse(aloha_lib.FactoryLorentz.is_symmetric) + self.assertTrue(aloha_object.Metric.is_symmetric) + self.assertFalse(aloha_object.Gamma.is_symmetric) + self.assertTrue(import_ufo.is_symmetric_lorentz_structure('Metric')) + self.assertFalse(import_ufo.is_symmetric_lorentz_structure('Gamma')) + # an unknown name must not be taken for a symmetric structure + self.assertFalse(import_ufo.is_symmetric_lorentz_structure('NotAThing')) + + def test_argument_order_of_a_symmetric_function_is_ignored(self): + """The two spellings of one Metric compare equal.""" + canon = import_ufo.canonicalize_lorentz_structure + # the two cases actually met when importing the sm model + self.assertEqual(canon('Metric(3,2)'), canon('Metric(2,3)')) + self.assertEqual(canon('Metric(4,2)'), canon('Metric(2,4)')) + # summed indices are negative, and must sort numerically (not as text) + self.assertEqual(canon('Metric(-1,2)'), canon('Metric(2,-1)')) + # and inside a larger expression + self.assertEqual(canon('Metric(1,2)*Gamma(3,4,5)'), + canon('Metric(2,1)*Gamma(3,4,5)')) + + def test_real_differences_are_still_reported(self): + """Canonicalisation must not silence a genuine redefinition.""" + canon = import_ufo.canonicalize_lorentz_structure + # different indices, not a reordering + self.assertNotEqual(canon('Metric(1,2)'), canon('Metric(1,3)')) + # Gamma and ProjP are NOT symmetric: reordering them stays a difference + self.assertNotEqual(canon('Gamma(1,2,3)'), canon('Gamma(3,2,1)')) + self.assertNotEqual(canon('ProjP(1,2)'), canon('ProjP(2,1)')) + # a symmetric part that matches does not excuse an asymmetric part + self.assertNotEqual(canon('Metric(1,2)*ProjM(3,4)'), + canon('Metric(2,1)*ProjM(4,3)')) diff --git a/tests/unit_tests/various/test_process_checks.py b/tests/unit_tests/various/test_process_checks.py index 012d1350ed..a47ea0cd30 100755 --- a/tests/unit_tests/various/test_process_checks.py +++ b/tests/unit_tests/various/test_process_checks.py @@ -860,7 +860,7 @@ def test_python_vs_fortran_epem_aa(self): parent = tempfile.mkdtemp(prefix='mg5_test_f_') sa_dir = os.path.join(parent, 'sa_f') try: - opt = {'sa_symmetry': False, 'export_format': 'standalone', + opt = {'sa_symmetry': False, 'export_format': 'standalone_fortran', 'mp': False, 'v5_model': True, 'output_options': {'noeps': 'True'}} exporter = ev4.ProcessExporterFortranSA(sa_dir, opt)