From 6d23864d83b51d62672f5da3a6f2cf3ca3f86836 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 14 Oct 2025 16:05:36 +0200 Subject: [PATCH 01/14] Add Zenny's material for MadTrex tests --- .github/workflows/run_madtrex.py | 185 ++++++++++++++++++ .../test/MadtRex_ref/ee_mumu_rwgt.csv | 10 + .../test/MadtRex_ref/gg_tt01g_rwgt.csv | 10 + .../test/MadtRex_ref/gg_tt_rwgt.csv | 10 + .../test/MadtRex_ref/gg_ttg_rwgt.csv | 10 + .../test/MadtRex_ref/gg_ttgg_rwgt.csv | 10 + .../test/MadtRex_ref/gg_ttggg_rwgt.csv | 10 + .../test/MadtRex_ref/gq_ttq_rwgt.csv | 10 + .../test/MadtRex_ref/heft_gg_bb_rwgt.csv | 10 + .../test/MadtRex_ref/nobm_pp_ttW_rwgt.csv | 10 + .../test/MadtRex_ref/pp_tt012j_rwgt.csv | 10 + .../test/MadtRex_ref/smeft_gg_tttt_rwgt.csv | 10 + .../test/MadtRex_ref/susy_gg_t1t1_rwgt.csv | 10 + .../test/MadtRex_ref/susy_gg_tt_rwgt.csv | 10 + 14 files changed, 315 insertions(+) create mode 100644 .github/workflows/run_madtrex.py create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv create mode 100644 epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py new file mode 100644 index 0000000000..5614670d0c --- /dev/null +++ b/.github/workflows/run_madtrex.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +import argparse +import os +import sys +import shutil +import subprocess +from pathlib import Path +import csv +ALLOWED_PROCESS_DICTIONARY = { + "ee_mumu": {"model": "sm", "process": "e+ e- > mu+ mu-"}, + "gg_tt": {"model": "sm", "process": "g g > t t~"}, + "gg_tt01g": {"model": "sm", "process": "g g > t t~\nadd process g g > t t~ g"}, + "gg_ttg": {"model": "sm", "process": "g g > t t~ g"}, + "gg_ttgg": {"model": "sm", "process": "g g > t t~ g g"}, + "gg_ttggg": {"model": "sm", "process": "g g > t t~ g g g"}, + "gq_ttq": {"model": "sm", "process": "g q > t t~ q"}, + "heft_gg_bb": {"model": "heft", "process": "g g > b b~"}, + "nobm_pp_ttW": {"model": "sm-no_b_mass", "process": "p p > t t~ w+"}, + "pp_tt012j": {"model": "sm", "process": "p p > t t~\nadd process p p > t t~ j\nadd process p p > t t~ j j"}, + "smeft_gg_tttt": {"model": "SMEFTsim_topU3l_MwScheme_UFO-massless", "process": "g g > t t~ t t~"}, + "susy_gg_t1t1": {"model": "MSSM_SLHA2", "process": "g g > t1 t1~"}, + "susy_gg_tt": {"model": "MSSM_SLHA2", "process": "g g > t t~"}, +} + + +def generate_dat_content(process: str, rwgt_card_path: Path) -> str: + if not process in ALLOWED_PROCESS_DICTIONARY: + raise ValueError(f"Process '{process}' is not in the allowed processes.") + proc_info = ALLOWED_PROCESS_DICTIONARY[process] + proc = proc_info.get("process", "unknown_process") + model = proc_info.get("model", "unknown_model") + if proc == "unknown_process" or model == "unknown_model": + raise ValueError(f"Process '{process}' is not properly defined in the dictionary.") + run_card = f"import model {model}\n" + run_card += "define q = u c d s u~ c~ d~ s~\n" + run_card += f"generate {proc}\n" + run_card += f"output {process}.rw\n" + run_card += "launch\n" + run_card += "reweight=madtrex\n" + run_card += "0\n" + run_card += "set nevents 10000\n" + run_card += "set iseed 489\n" + run_card += f"{rwgt_card_path}\n" + run_card += "0\n" + return run_card + +def is_executable(path: Path) -> bool: + return path.is_file() and os.access(path, os.X_OK) + +def write_rwgt_card(path: Path) -> None: + if path.exists(): + return + content = """launch\nset sminputs 1 scan:[j for j in range(100,200,10)]\n""" + path.write_text(content, encoding="utf-8") + + +def load_csv(path): + with open(path, newline="") as f: + reader = csv.DictReader(f) + for row in reader: + yield float(row["VALUE"]), float(row["ERROR"]) + +def main() -> int: + parser = argparse.ArgumentParser( + description="Run mg5_aMC for a validated PROCESS and move reweighting results." + ) + parser.add_argument( + "mg5_rel_path", + help="Relative path (from current working directory HOME) to the mg5_aMC executable, e.g. SOMETHING/SOMETHING/bin/mg5_aMC", + ) + parser.add_argument( + "process", + help="Label for the process (must be in the allowed list)." + ) + args = parser.parse_args() + + # Treat current working directory as HOME + HOME = Path.cwd() + + # Resolve mg5 executable path from HOME + mg5_path = (HOME / args.mg5_rel_path).resolve() + if not mg5_path.exists(): + print(f"ERROR: mg5_aMC not found at: {mg5_path}", file=sys.stderr) + return 1 + if not is_executable(mg5_path): + print(f"ERROR: Not executable: {mg5_path}", file=sys.stderr) + return 1 + + process = args.process.strip() + if process not in ALLOWED_PROCESS_DICTIONARY: + print( + f"ERROR: PROCESS '{process}' is not in the allowed list.\n" + f"Allowed: {sorted(ALLOWED_PROCESS_DICTIONARY.keys())}", + file=sys.stderr, + ) + return 1 + + # Check that baseline rwgt.csv exists + baseline_csv = HOME / "baseline" / f"{process}_rwgt.csv" + if not baseline_csv.exists(): + print( + f"ERROR: Baseline rwgt.csv not found at:\n {baseline_csv}\n" + f"Ensure the baseline file exists before running.", + file=sys.stderr, + ) + return 1 + + # Write rwgt_card.dat if not exists + rwgt_card_path = HOME / "rwgt_card.dat" + try: + write_rwgt_card(rwgt_card_path) + except Exception as e: + print(f"ERROR: Failed to write rwgt_card.dat: {e}", file=sys.stderr) + return 1 + + # Write PROCESS.dat to HOME + dat_path = HOME / f"{process}.dat" + try: + dat_content = generate_dat_content(process, rwgt_card_path) + dat_path.write_text(dat_content, encoding="utf-8") + except Exception as e: + print(f"ERROR: Failed to write {dat_path}: {e}", file=sys.stderr) + return 1 + + # Run mg5_aMC with PROCESS.dat as argument, wait for completion + LOGS = HOME / "logs" + LOGS.mkdir(exist_ok=True) + stdout_log = LOGS / f"mg5_{process}.stdout.log" + stderr_log = LOGS / f"mg5_{process}.stderr.log" + print(f"Launching: {mg5_path} {dat_path}") + try: + with stdout_log.open("wb") as out, stderr_log.open("wb") as err: + result = subprocess.run( + [str(mg5_path), str(dat_path)], + cwd=str(HOME), + stdout=out, + stderr=err, + check=False, + ) + if result.returncode != 0: + print( + f"ERROR: mg5_aMC exited with code {result.returncode}. " + f"See logs:\n stdout: {stdout_log}\n stderr: {stderr_log}", + file=sys.stderr, + ) + return result.returncode + else: + print(f"mg5_aMC finished. Logs:\n stdout: {stdout_log}\n stderr: {stderr_log}") + except FileNotFoundError: + print(f"ERROR: Failed to launch mg5_aMC at {mg5_path}", file=sys.stderr) + return 1 + except Exception as e: + print(f"ERROR: mg5_aMC run failed: {e}", file=sys.stderr) + return 1 + + # Remove process.dat + dat_path.unlink(missing_ok=True) + + # Move rwgt_results.csv → HOME/baseline/PROCESS_rwgt.csv + madtrex_csv = HOME / f"{process}.rw" / "rw_me" / "SubProcesses" / "rwgt_results.csv" + if not madtrex_csv.exists(): + print( + f"ERROR: Expected results not found at:\n {madtrex_csv}\n" + f"Ensure the run produced rwgt_results.csv.", + file=sys.stderr, + ) + return 1 + + for i, ((v_base, e_base), (v_mad, e_mad)) in enumerate(zip(load_csv(baseline_csv), load_csv(madtrex_csv)), start=1): + diff = abs(v_base - v_mad) + tol = min(e_base, e_mad) + + if diff >= tol: + print(f"Error: Row {i}: |{v_base} - {v_mad}| = {diff} >= {tol}") + all_ok = False + + if not all_ok: + print(f"Some checks failed for process {process}.", file=sys.stderr) + sys.exit(1) + print(f"All checks passed for process {process}.") + + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv new file mode 100644 index 0000000000..63e5f1e81e --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 0.192061, 0.000424581 +rwgt_2, 0.147728, 0.000254344 +rwgt_3, 0.123323, 0.000160641 +rwgt_4, 0.107587, 0.000100209 +rwgt_5, 0.0966111, 0.000105217 +rwgt_6, 0.0885644, 0.000122552 +rwgt_7, 0.0824521, 0.000135735 +rwgt_8, 0.0776822, 0.000146035 +rwgt_9, 0.0738789, 0.000154259 +rwgt_10, 0.0707923, 0.000160943 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv new file mode 100644 index 0000000000..230b86d51a --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 844.049, 1.99731 +rwgt_2, 844.049, 1.99731 +rwgt_3, 844.049, 1.99731 +rwgt_4, 844.049, 1.99731 +rwgt_5, 844.049, 1.99731 +rwgt_6, 844.049, 1.99731 +rwgt_7, 844.049, 1.99731 +rwgt_8, 844.049, 1.99731 +rwgt_9, 844.049, 1.99731 +rwgt_10, 844.049, 1.99731 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv new file mode 100644 index 0000000000..bc050ce42c --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 440.654, 0.474357 +rwgt_2, 440.654, 0.474357 +rwgt_3, 440.654, 0.474357 +rwgt_4, 440.654, 0.474357 +rwgt_5, 440.654, 0.474357 +rwgt_6, 440.654, 0.474357 +rwgt_7, 440.654, 0.474357 +rwgt_8, 440.654, 0.474357 +rwgt_9, 440.654, 0.474357 +rwgt_10, 440.654, 0.474357 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv new file mode 100644 index 0000000000..3df3c25ba8 --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 412.337, 1.27291 +rwgt_2, 412.337, 1.27291 +rwgt_3, 412.337, 1.27291 +rwgt_4, 412.337, 1.27291 +rwgt_5, 412.337, 1.27291 +rwgt_6, 412.337, 1.27291 +rwgt_7, 412.337, 1.27291 +rwgt_8, 412.337, 1.27291 +rwgt_9, 412.337, 1.27291 +rwgt_10, 412.337, 1.27291 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv new file mode 100644 index 0000000000..bc8050963c --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 250.25, 0.762839 +rwgt_2, 250.25, 0.762839 +rwgt_3, 250.25, 0.762839 +rwgt_4, 250.25, 0.762839 +rwgt_5, 250.25, 0.762839 +rwgt_6, 250.25, 0.762839 +rwgt_7, 250.25, 0.762839 +rwgt_8, 250.25, 0.762839 +rwgt_9, 250.25, 0.762839 +rwgt_10, 250.25, 0.762839 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv new file mode 100644 index 0000000000..bf99308b40 --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 123.712, 0.386311 +rwgt_2, 123.712, 0.386311 +rwgt_3, 123.712, 0.386311 +rwgt_4, 123.712, 0.386311 +rwgt_5, 123.712, 0.386311 +rwgt_6, 123.712, 0.386311 +rwgt_7, 123.712, 0.386311 +rwgt_8, 123.712, 0.386311 +rwgt_9, 123.712, 0.386311 +rwgt_10, 123.712, 0.386311 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv new file mode 100644 index 0000000000..fdf617316c --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 70.1922, 0.241705 +rwgt_2, 70.1922, 0.241705 +rwgt_3, 70.1922, 0.241705 +rwgt_4, 70.1922, 0.241705 +rwgt_5, 70.1922, 0.241705 +rwgt_6, 70.1922, 0.241705 +rwgt_7, 70.1922, 0.241705 +rwgt_8, 70.1922, 0.241705 +rwgt_9, 70.1922, 0.241705 +rwgt_10, 70.1922, 0.241705 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv new file mode 100644 index 0000000000..9ad4db4aae --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 4.11321e+08, 551469 +rwgt_2, 4.11321e+08, 551469 +rwgt_3, 4.11321e+08, 551469 +rwgt_4, 4.11321e+08, 551469 +rwgt_5, 4.11321e+08, 551469 +rwgt_6, 4.11321e+08, 551469 +rwgt_7, 4.11321e+08, 551469 +rwgt_8, 4.11321e+08, 551469 +rwgt_9, 4.11321e+08, 551469 +rwgt_10, 4.11321e+08, 551469 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv new file mode 100644 index 0000000000..0083deb686 --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 0.206845, 0.000526606 +rwgt_2, 0.219457, 0.000502079 +rwgt_3, 0.227656, 0.000486133 +rwgt_4, 0.233687, 0.000474403 +rwgt_5, 0.238392, 0.000492311 +rwgt_6, 0.2422, 0.000515007 +rwgt_7, 0.245359, 0.000533843 +rwgt_8, 0.248031, 0.000549775 +rwgt_9, 0.250326, 0.000563454 +rwgt_10, 0.25232, 0.000575344 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv new file mode 100644 index 0000000000..79916aba3d --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 1456.15, 3.06487 +rwgt_2, 1456.15, 3.06487 +rwgt_3, 1456.15, 3.06487 +rwgt_4, 1456.15, 3.06487 +rwgt_5, 1456.15, 3.06487 +rwgt_6, 1456.15, 3.06487 +rwgt_7, 1456.15, 3.06487 +rwgt_8, 1456.15, 3.06487 +rwgt_9, 1456.15, 3.06487 +rwgt_10, 1456.15, 3.06487 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv new file mode 100644 index 0000000000..79c342abf6 --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 0.00843189, 2.3805e-05 +rwgt_2, 0.00843189, 2.3805e-05 +rwgt_3, 0.00843189, 2.3805e-05 +rwgt_4, 0.00843189, 2.3805e-05 +rwgt_5, 0.00843189, 2.3805e-05 +rwgt_6, 0.00843189, 2.3805e-05 +rwgt_7, 0.00843189, 2.3805e-05 +rwgt_8, 0.00843189, 2.3805e-05 +rwgt_9, 0.00843189, 2.3805e-05 +rwgt_10, 0.00843189, 2.3805e-05 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv new file mode 100644 index 0000000000..e0e1dcd12a --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 1.09753, 0.00201894 +rwgt_2, 1.09753, 0.00201894 +rwgt_3, 1.09753, 0.00201894 +rwgt_4, 1.09753, 0.00201894 +rwgt_5, 1.09753, 0.00201894 +rwgt_6, 1.09753, 0.00201894 +rwgt_7, 1.09753, 0.00201894 +rwgt_8, 1.09753, 0.00201894 +rwgt_9, 1.09753, 0.00201894 +rwgt_10, 1.09753, 0.00201894 diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv new file mode 100644 index 0000000000..d98d3779d2 --- /dev/null +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv @@ -0,0 +1,10 @@ +rwgt_1, 417.165, 0.454138 +rwgt_2, 417.165, 0.454138 +rwgt_3, 417.165, 0.454138 +rwgt_4, 417.165, 0.454138 +rwgt_5, 417.165, 0.454138 +rwgt_6, 417.165, 0.454138 +rwgt_7, 417.165, 0.454138 +rwgt_8, 417.165, 0.454138 +rwgt_9, 417.165, 0.454138 +rwgt_10, 417.165, 0.454138 From 758a111b21e01b6727f5f727cc4e374fab5dc9bc Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 13:29:29 +0200 Subject: [PATCH 02/14] Rename folder to baseline --- .../test/{MadtRex_ref => MadtRex_baseline}/ee_mumu_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gg_tt01g_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gg_tt_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gg_ttg_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gg_ttgg_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gg_ttggg_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/gq_ttq_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/heft_gg_bb_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/nobm_pp_ttW_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/pp_tt012j_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/smeft_gg_tttt_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/susy_gg_t1t1_rwgt.csv | 0 .../test/{MadtRex_ref => MadtRex_baseline}/susy_gg_tt_rwgt.csv | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/ee_mumu_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gg_tt01g_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gg_tt_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gg_ttg_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gg_ttgg_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gg_ttggg_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/gq_ttq_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/heft_gg_bb_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/nobm_pp_ttW_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/pp_tt012j_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/smeft_gg_tttt_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/susy_gg_t1t1_rwgt.csv (100%) rename epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/{MadtRex_ref => MadtRex_baseline}/susy_gg_tt_rwgt.csv (100%) diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/ee_mumu_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/ee_mumu_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/ee_mumu_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_tt01g_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt01g_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_tt01g_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_tt_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_tt_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_tt_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttg_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttg_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttg_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttgg_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttgg_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttgg_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttggg_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gg_ttggg_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gg_ttggg_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gq_ttq_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/gq_ttq_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/gq_ttq_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/heft_gg_bb_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/heft_gg_bb_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/heft_gg_bb_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/nobm_pp_ttW_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/pp_tt012j_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/pp_tt012j_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/pp_tt012j_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/smeft_gg_tttt_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/smeft_gg_tttt_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/smeft_gg_tttt_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/susy_gg_t1t1_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_t1t1_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/susy_gg_t1t1_rwgt.csv diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/susy_gg_tt_rwgt.csv similarity index 100% rename from epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_ref/susy_gg_tt_rwgt.csv rename to epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/susy_gg_tt_rwgt.csv From 03f1c292efba424f21bbb3440ee1a304bed68f47 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 13:30:17 +0200 Subject: [PATCH 03/14] Modify the entrypoint for MadtRex tests for better inclusion in the CI --- .github/workflows/run_madtrex.py | 77 +++++++++----------------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 5614670d0c..8e1dbdf2cd 100644 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -1,42 +1,14 @@ #!/usr/bin/env python3 -import argparse import os import sys -import shutil import subprocess from pathlib import Path import csv -ALLOWED_PROCESS_DICTIONARY = { - "ee_mumu": {"model": "sm", "process": "e+ e- > mu+ mu-"}, - "gg_tt": {"model": "sm", "process": "g g > t t~"}, - "gg_tt01g": {"model": "sm", "process": "g g > t t~\nadd process g g > t t~ g"}, - "gg_ttg": {"model": "sm", "process": "g g > t t~ g"}, - "gg_ttgg": {"model": "sm", "process": "g g > t t~ g g"}, - "gg_ttggg": {"model": "sm", "process": "g g > t t~ g g g"}, - "gq_ttq": {"model": "sm", "process": "g q > t t~ q"}, - "heft_gg_bb": {"model": "heft", "process": "g g > b b~"}, - "nobm_pp_ttW": {"model": "sm-no_b_mass", "process": "p p > t t~ w+"}, - "pp_tt012j": {"model": "sm", "process": "p p > t t~\nadd process p p > t t~ j\nadd process p p > t t~ j j"}, - "smeft_gg_tttt": {"model": "SMEFTsim_topU3l_MwScheme_UFO-massless", "process": "g g > t t~ t t~"}, - "susy_gg_t1t1": {"model": "MSSM_SLHA2", "process": "g g > t1 t1~"}, - "susy_gg_tt": {"model": "MSSM_SLHA2", "process": "g g > t t~"}, -} +ALLOWED_PROCESSES = [ "ee_mumu", "gg_tt", "gg_tt01g", "gg_ttg", "gg_ttgg", "gg_ttggg", "gq_ttq", "heft_gg_bb", "nobm_pp_ttW", "pp_tt012j", "smeft_gg_tttt", "susy_gg_t1t1", "susy_gg_tt" ] def generate_dat_content(process: str, rwgt_card_path: Path) -> str: - if not process in ALLOWED_PROCESS_DICTIONARY: - raise ValueError(f"Process '{process}' is not in the allowed processes.") - proc_info = ALLOWED_PROCESS_DICTIONARY[process] - proc = proc_info.get("process", "unknown_process") - model = proc_info.get("model", "unknown_model") - if proc == "unknown_process" or model == "unknown_model": - raise ValueError(f"Process '{process}' is not properly defined in the dictionary.") - run_card = f"import model {model}\n" - run_card += "define q = u c d s u~ c~ d~ s~\n" - run_card += f"generate {proc}\n" - run_card += f"output {process}.rw\n" - run_card += "launch\n" - run_card += "reweight=madtrex\n" + run_card = "reweight=madtrex\n" run_card += "0\n" run_card += "set nevents 10000\n" run_card += "set iseed 489\n" @@ -61,42 +33,34 @@ def load_csv(path): yield float(row["VALUE"]), float(row["ERROR"]) def main() -> int: - parser = argparse.ArgumentParser( - description="Run mg5_aMC for a validated PROCESS and move reweighting results." - ) - parser.add_argument( - "mg5_rel_path", - help="Relative path (from current working directory HOME) to the mg5_aMC executable, e.g. SOMETHING/SOMETHING/bin/mg5_aMC", - ) - parser.add_argument( - "process", - help="Label for the process (must be in the allowed list)." - ) - args = parser.parse_args() + # Name of the directory of the process to test + process_dir = sys.argv[1] + # Label for the process (must be in the allowed list) + process = process_dir.replace(".mad", "") # Treat current working directory as HOME HOME = Path.cwd() - # Resolve mg5 executable path from HOME - mg5_path = (HOME / args.mg5_rel_path).resolve() - if not mg5_path.exists(): - print(f"ERROR: mg5_aMC not found at: {mg5_path}", file=sys.stderr) + # Resolve generate_events executable path from HOME + process_path = (HOME / process_dir).resolve() + generate_events = (process_dir / "bin" / "generate_events").resolve() + if not process_path.exists(): + print(f"ERROR: Process {process} not found at: {process_path}", file=sys.stderr) return 1 - if not is_executable(mg5_path): - print(f"ERROR: Not executable: {mg5_path}", file=sys.stderr) + if not is_executable(generate_events): + print(f"ERROR: Not executable: {generate_events}", file=sys.stderr) return 1 - process = args.process.strip() - if process not in ALLOWED_PROCESS_DICTIONARY: + if process not in ALLOWED_PROCESSES: print( f"ERROR: PROCESS '{process}' is not in the allowed list.\n" - f"Allowed: {sorted(ALLOWED_PROCESS_DICTIONARY.keys())}", + f"Allowed: {sorted(ALLOWED_PROCESSES)}", file=sys.stderr, ) return 1 # Check that baseline rwgt.csv exists - baseline_csv = HOME / "baseline" / f"{process}_rwgt.csv" + baseline_csv = HOME / "epochX" / "cudacpp" / "CODEGEN" / "PLUGIN" / "CUDACPP_SA_OUTPUT" / "test" / "MadtRex_baseline" / f"{process}_rwgt.csv" if not baseline_csv.exists(): print( f"ERROR: Baseline rwgt.csv not found at:\n {baseline_csv}\n" @@ -127,11 +91,11 @@ def main() -> int: LOGS.mkdir(exist_ok=True) stdout_log = LOGS / f"mg5_{process}.stdout.log" stderr_log = LOGS / f"mg5_{process}.stderr.log" - print(f"Launching: {mg5_path} {dat_path}") + print(f"Launching: {generate_events} {dat_path}") try: with stdout_log.open("wb") as out, stderr_log.open("wb") as err: result = subprocess.run( - [str(mg5_path), str(dat_path)], + [str(generate_events), str(dat_path)], cwd=str(HOME), stdout=out, stderr=err, @@ -147,7 +111,7 @@ def main() -> int: else: print(f"mg5_aMC finished. Logs:\n stdout: {stdout_log}\n stderr: {stderr_log}") except FileNotFoundError: - print(f"ERROR: Failed to launch mg5_aMC at {mg5_path}", file=sys.stderr) + print(f"ERROR: Failed to launch {generate_events}", file=sys.stderr) return 1 except Exception as e: print(f"ERROR: mg5_aMC run failed: {e}", file=sys.stderr) @@ -157,7 +121,7 @@ def main() -> int: dat_path.unlink(missing_ok=True) # Move rwgt_results.csv → HOME/baseline/PROCESS_rwgt.csv - madtrex_csv = HOME / f"{process}.rw" / "rw_me" / "SubProcesses" / "rwgt_results.csv" + madtrex_csv = process_path / "rw_me" / "SubProcesses" / "rwgt_results.csv" if not madtrex_csv.exists(): print( f"ERROR: Expected results not found at:\n {madtrex_csv}\n" @@ -166,6 +130,7 @@ def main() -> int: ) return 1 + all_ok = True for i, ((v_base, e_base), (v_mad, e_mad)) in enumerate(zip(load_csv(baseline_csv), load_csv(madtrex_csv)), start=1): diff = abs(v_base - v_mad) tol = min(e_base, e_mad) From dfeee4ce4e23fb9d45399c49ebddba2bf6c64b58 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 18:43:16 +0200 Subject: [PATCH 04/14] Go back using MadGraph CLI for run_madtrex.py --- .github/workflows/run_madtrex.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 8e1dbdf2cd..0bd4c153cd 100644 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -6,9 +6,11 @@ import csv ALLOWED_PROCESSES = [ "ee_mumu", "gg_tt", "gg_tt01g", "gg_ttg", "gg_ttgg", "gg_ttggg", "gq_ttq", "heft_gg_bb", "nobm_pp_ttW", "pp_tt012j", "smeft_gg_tttt", "susy_gg_t1t1", "susy_gg_tt" ] +MADGRAPH_CLI = Path.cwd() / ".." / ".." / "MG5aMC" / "mg5amcnlo" / "bin" / "mg5_aMC" -def generate_dat_content(process: str, rwgt_card_path: Path) -> str: - run_card = "reweight=madtrex\n" +def generate_dat_content(process_dir: str, rwgt_card_path: Path) -> str: + run_card = f"launch {process_dir}\n" + run_card += "reweight=madtrex\n" run_card += "0\n" run_card += "set nevents 10000\n" run_card += "set iseed 489\n" @@ -43,13 +45,9 @@ def main() -> int: # Resolve generate_events executable path from HOME process_path = (HOME / process_dir).resolve() - generate_events = (process_dir / "bin" / "generate_events").resolve() if not process_path.exists(): print(f"ERROR: Process {process} not found at: {process_path}", file=sys.stderr) return 1 - if not is_executable(generate_events): - print(f"ERROR: Not executable: {generate_events}", file=sys.stderr) - return 1 if process not in ALLOWED_PROCESSES: print( @@ -60,7 +58,7 @@ def main() -> int: return 1 # Check that baseline rwgt.csv exists - baseline_csv = HOME / "epochX" / "cudacpp" / "CODEGEN" / "PLUGIN" / "CUDACPP_SA_OUTPUT" / "test" / "MadtRex_baseline" / f"{process}_rwgt.csv" + baseline_csv = HOME / "CODEGEN" / "PLUGIN" / "CUDACPP_SA_OUTPUT" / "test" / "MadtRex_baseline" / f"{process}_rwgt.csv" if not baseline_csv.exists(): print( f"ERROR: Baseline rwgt.csv not found at:\n {baseline_csv}\n" @@ -80,7 +78,7 @@ def main() -> int: # Write PROCESS.dat to HOME dat_path = HOME / f"{process}.dat" try: - dat_content = generate_dat_content(process, rwgt_card_path) + dat_content = generate_dat_content(process_dir, rwgt_card_path) dat_path.write_text(dat_content, encoding="utf-8") except Exception as e: print(f"ERROR: Failed to write {dat_path}: {e}", file=sys.stderr) @@ -91,11 +89,11 @@ def main() -> int: LOGS.mkdir(exist_ok=True) stdout_log = LOGS / f"mg5_{process}.stdout.log" stderr_log = LOGS / f"mg5_{process}.stderr.log" - print(f"Launching: {generate_events} {dat_path}") + print(f"Launching: {MADGRAPH_CLI} {dat_path}") try: with stdout_log.open("wb") as out, stderr_log.open("wb") as err: result = subprocess.run( - [str(generate_events), str(dat_path)], + [str(MADGRAPH_CLI), str(dat_path)], cwd=str(HOME), stdout=out, stderr=err, @@ -111,7 +109,7 @@ def main() -> int: else: print(f"mg5_aMC finished. Logs:\n stdout: {stdout_log}\n stderr: {stderr_log}") except FileNotFoundError: - print(f"ERROR: Failed to launch {generate_events}", file=sys.stderr) + print(f"ERROR: Failed to launch {MADGRAPH_CLI}", file=sys.stderr) return 1 except Exception as e: print(f"ERROR: mg5_aMC run failed: {e}", file=sys.stderr) From de912b8d2059dc61a2b6c4fcf718ec37418aa951 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 18:44:21 +0200 Subject: [PATCH 05/14] Fix csv reading in run_madtrex.py --- .github/workflows/run_madtrex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 0bd4c153cd..e3ef2f5ce2 100644 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -30,7 +30,7 @@ def write_rwgt_card(path: Path) -> None: def load_csv(path): with open(path, newline="") as f: - reader = csv.DictReader(f) + reader = csv.DictReader(f, fieldnames=["RWGT", "VALUE", "ERROR"]) for row in reader: yield float(row["VALUE"]), float(row["ERROR"]) From cc93e0cc4cedfc2f3a31eed471eb4390596d1443 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 18:44:57 +0200 Subject: [PATCH 06/14] Make run_madtrex an executable --- .github/workflows/run_madtrex.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .github/workflows/run_madtrex.py diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py old mode 100644 new mode 100755 From 38cf34448dbb14829318933b9d90e768e9b1822c Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Wed, 15 Oct 2025 18:50:10 +0200 Subject: [PATCH 07/14] Add new job for MadtRex tests to the CI --- .github/workflows/testsuite_oneprocess.yml | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/.github/workflows/testsuite_oneprocess.yml b/.github/workflows/testsuite_oneprocess.yml index a43fe7939a..b82586dfdf 100644 --- a/.github/workflows/testsuite_oneprocess.yml +++ b/.github/workflows/testsuite_oneprocess.yml @@ -280,4 +280,83 @@ jobs: env: GH_TOKEN: ${{ github.token }} + madtrex: + runs-on: ubuntu-latest + needs: codegen + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + + - name: split_prnum + # See https://stackoverflow.com/a/73467112 + id: split + run: echo "prnum=PR${GITHUB_REF_NAME%%/*}" >> $GITHUB_OUTPUT + + - name: HELLO_MADTREX + run: | + echo "HELLO_MADTREX ${{ inputs.process }} $(date)" + echo "Workflow run_id is ${{ github.run_id }}" + echo "Workflow ref_name is ${{ github.ref_name }}" + echo "Workflow PR number is ${{ steps.split.outputs.prnum }}" + echo "Current directory is $(pwd)" + echo "Current git commit is $(git log --oneline -n1 | cut -d' ' -f1)" + gh extension install actions/gh-actions-cache + REPO=${{ github.repository }} + echo "List codegencache keys for this run_id (start)" + gh actions-cache list -R $REPO --sort created-at --order asc --key codegencache-${{ runner.os }}-${{ inputs.process }}-${{ github.run_id }} + echo "List codegencache keys for this run_id (end)" + env: + GH_TOKEN: ${{ github.token }} + + - name: restore_codegen_cache + id: codegen-cache-restore + uses: actions/cache/restore@v4 + with: + path: | + epochX/cudacpp/${{ inputs.process }} + key: codegencache-${{ runner.os }}-${{ inputs.process }}-${{ github.run_id }} + restore-keys: | + codegencache-${{ runner.os }}-${{ inputs.process }}-${{ github.run_id }} + + - name: check_f2py + run: | + # check if f2py is installed, if not, install it + if command -v f2py >/dev/null 2>&1; then + echo "f2py is installed" + else + echo "f2py not found, it will be installed" + sudo apt update && sudo apt install -y python3-numpy + fi + + # check if it has been installed correctly + if ! command -v f2py >/dev/null 2>&1; then + echo "f2py not found, cannot run reweighting!" + exit 1 + fi + + - name: madtrex_test + run: | + if [ "${proc##*.}" == "mad" ]; then + cd epochX/cudacpp + ../../.github/workflows/run_madtrex.py ${{ inputs.process }} + else + echo "Skipping MadTrex tests since it is not madevent" + fi + + - name: GOODBYE_MADTREX + run: | + echo "GOODBYE_MADTREX ${{ inputs.process }} $(date)" + echo "Workflow run_id is ${{ github.run_id }}" + echo "Workflow ref_name is ${{ github.ref_name }}" + echo "Workflow PR number is ${{ steps.split.outputs.prnum }}" + echo "Current directory is $(pwd)" + echo "Current git commit is $(git log --oneline -n1 | cut -d' ' -f1)" + REPO=${{ github.repository }} + echo "List codegencache keys for this run_id (start)" + gh actions-cache list -R $REPO --sort created-at --order asc --key codegencache-${{ runner.os }}-${{ inputs.process }}-${{ github.run_id }} + echo "List codegencache keys for this run_id (end)" + env: + GH_TOKEN: ${{ github.token }} #---------------------------------------------------------------------------------------------------------------------------------- From 14625135d05963389d7c684c6df9c7a9586558d5 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Fri, 17 Oct 2025 13:47:06 +0200 Subject: [PATCH 08/14] Modify threshold for MadtRex tests Make it 2% of the cross section. --- .github/workflows/run_madtrex.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index e3ef2f5ce2..3ca577a1ac 100755 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -43,7 +43,6 @@ def main() -> int: # Treat current working directory as HOME HOME = Path.cwd() - # Resolve generate_events executable path from HOME process_path = (HOME / process_dir).resolve() if not process_path.exists(): print(f"ERROR: Process {process} not found at: {process_path}", file=sys.stderr) @@ -129,9 +128,9 @@ def main() -> int: return 1 all_ok = True - for i, ((v_base, e_base), (v_mad, e_mad)) in enumerate(zip(load_csv(baseline_csv), load_csv(madtrex_csv)), start=1): + for i, ((v_base, _), (v_mad, _)) in enumerate(zip(load_csv(baseline_csv), load_csv(madtrex_csv)), start=1): diff = abs(v_base - v_mad) - tol = min(e_base, e_mad) + tol = 0.02 * v_mad if diff >= tol: print(f"Error: Row {i}: |{v_base} - {v_mad}| = {diff} >= {tol}") From 245ac557a57657134c50c5e2aff1799e3d696f1a Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Fri, 17 Oct 2025 13:48:22 +0200 Subject: [PATCH 09/14] Add dependencies checks on MadtRex tests (f2py and Python < 3.12) --- .github/workflows/testsuite_oneprocess.yml | 42 +++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/.github/workflows/testsuite_oneprocess.yml b/.github/workflows/testsuite_oneprocess.yml index b82586dfdf..e98e68658b 100644 --- a/.github/workflows/testsuite_oneprocess.yml +++ b/.github/workflows/testsuite_oneprocess.yml @@ -1,7 +1,7 @@ -# Copyright (C) 2020-2024 CERN and UCLouvain. +# Copyright (C) 2020-2025 CERN and UCLouvain. # Licensed under the GNU Lesser General Public License (version 3 or later). # Created by: A. Valassi (Oct 2023) for the MG5aMC CUDACPP plugin. -# Further modified by: A. Valassi (2023-2024) for the MG5aMC CUDACPP plugin. +# Further modified by: A. Valassi, D. Massaro (2023-2025) for the MG5aMC CUDACPP plugin. #---------------------------------------------------------------------------------------------------------------------------------- @@ -281,7 +281,8 @@ jobs: GH_TOKEN: ${{ github.token }} madtrex: - runs-on: ubuntu-latest + if: ${{ endsWith(inputs.process, '.mad') }} # Reweighting test to do only in case of madevent + runs-on: ubuntu-22.04 # Python 3.12 not yet supported for reweighting needs: codegen steps: @@ -320,30 +321,45 @@ jobs: restore-keys: | codegencache-${{ runner.os }}-${{ inputs.process }}-${{ github.run_id }} + - name: symlink_plugin + run: | + cd MG5aMC/mg5amcnlo/PLUGIN + ln -s ../../MG5aMC_PLUGIN/CUDACPP_OUTPUT ./ + - name: check_f2py run: | # check if f2py is installed, if not, install it - if command -v f2py >/dev/null 2>&1; then + if type -P "f2py" &>/dev/null; then echo "f2py is installed" else - echo "f2py not found, it will be installed" - sudo apt update && sudo apt install -y python3-numpy + echo "f2py not found" + echo "check if numpy.f2py is present" + if python3 -m numpy.f2py -v &>/dev/null; then + echo "numpy.f2py is installed correctly, creating wrapper" + else + echo "numpy.f2py not found, it will be installed" + sudo apt update && sudo apt install -y python3-numpy + echo "Installation done, now create wrapper" + fi + mkdir -p "$HOME/.local/bin" + echo '#!/usr/bin/env bash' > "$HOME/.local/bin/f2py" + echo 'exec python3 -m numpy.f2py "$@"' >> "$HOME/.local/bin/f2py" + chmod +x "$HOME/.local/bin/f2py" + echo "$HOME/.local/bin" >> "$GITHUB_PATH" # this updates path for the subsequent steps + export PATH="$HOME/.local/bin:$PATH" # this for the current step fi - # check if it has been installed correctly - if ! command -v f2py >/dev/null 2>&1; then - echo "f2py not found, cannot run reweighting!" + # Validate that "f2py" actually executes (not just resolves) + if ! f2py -v &>/dev/null; then + echo "f2py resolves but does not execute correctly." + echo "Cannot run reweighting!" exit 1 fi - name: madtrex_test run: | - if [ "${proc##*.}" == "mad" ]; then cd epochX/cudacpp ../../.github/workflows/run_madtrex.py ${{ inputs.process }} - else - echo "Skipping MadTrex tests since it is not madevent" - fi - name: GOODBYE_MADTREX run: | From d6a610d29e23f194119f458999c603444a0d4ea6 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 21 Oct 2025 09:57:30 +0200 Subject: [PATCH 10/14] Fix reference file for nobm_pp_ttW process The process run originally in the ref was different from the one included in the repository. --- .../MadtRex_baseline/nobm_pp_ttW_rwgt.csv | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv index 0083deb686..4ac3fad2b6 100644 --- a/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv +++ b/epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT/test/MadtRex_baseline/nobm_pp_ttW_rwgt.csv @@ -1,10 +1,10 @@ -rwgt_1, 0.206845, 0.000526606 -rwgt_2, 0.219457, 0.000502079 -rwgt_3, 0.227656, 0.000486133 -rwgt_4, 0.233687, 0.000474403 -rwgt_5, 0.238392, 0.000492311 -rwgt_6, 0.2422, 0.000515007 -rwgt_7, 0.245359, 0.000533843 -rwgt_8, 0.248031, 0.000549775 -rwgt_9, 0.250326, 0.000563454 -rwgt_10, 0.25232, 0.000575344 +rwgt_1, 0.639355, 0.000526606 +rwgt_2, 0.67942, 0.000502079 +rwgt_3, 0.705468, 0.000486133 +rwgt_4, 0.724627, 0.000474403 +rwgt_5, 0.739576, 0.000492311 +rwgt_6, 0.751671, 0.000515007 +rwgt_7, 0.761708, 0.000533843 +rwgt_8, 0.770198, 0.000549775 +rwgt_9, 0.777488, 0.000563454 +rwgt_10, 0.783824, 0.000575344 From 680786e59ba9faaa02a9c4f4764dc36e1324c384 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 21 Oct 2025 10:01:59 +0200 Subject: [PATCH 11/14] Raise samples difference threshold to 5% Reference samples have been generated using MadtRex on top of vanilla MadGraph and not on top of CUDACPP, so there is a slightly larger uncertainty when comparing those ref samples with the reweighted samples that start from CUDACPP-generated events. We are not interested to check theat they are digit-by-digit correct, but that they are almost correct with each other. --- .github/workflows/run_madtrex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 3ca577a1ac..63088cc43d 100755 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -130,7 +130,7 @@ def main() -> int: all_ok = True for i, ((v_base, _), (v_mad, _)) in enumerate(zip(load_csv(baseline_csv), load_csv(madtrex_csv)), start=1): diff = abs(v_base - v_mad) - tol = 0.02 * v_mad + tol = 0.05 * v_mad if diff >= tol: print(f"Error: Row {i}: |{v_base} - {v_mad}| = {diff} >= {tol}") From b6d9dbd76f4ec72b41e7216d77a23a7589e16377 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 21 Oct 2025 12:06:22 +0200 Subject: [PATCH 12/14] Dump run logs if generation fails or output is not produced --- .github/workflows/run_madtrex.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 63088cc43d..c8d03f683c 100755 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -34,6 +34,16 @@ def load_csv(path): for row in reader: yield float(row["VALUE"]), float(row["ERROR"]) +def dump_logs(stdout_log, stderr_log): + print("Dumping run logs...") + print("==== STDOUT ====") + with open(stdout_log, "r") as file: + print(file.read()) + print("\n\n==== STDERR ====") + with open(stderr_log, "r") as file: + print(file.read()) + print("================") + def main() -> int: # Name of the directory of the process to test process_dir = sys.argv[1] @@ -104,6 +114,7 @@ def main() -> int: f"See logs:\n stdout: {stdout_log}\n stderr: {stderr_log}", file=sys.stderr, ) + dump_logs(stdout_log, stderr_log) return result.returncode else: print(f"mg5_aMC finished. Logs:\n stdout: {stdout_log}\n stderr: {stderr_log}") @@ -125,6 +136,7 @@ def main() -> int: f"Ensure the run produced rwgt_results.csv.", file=sys.stderr, ) + dump_logs(stdout_log, stderr_log) return 1 all_ok = True From 1f6f1c0ea5b8a56b96e71488d341f4f1e836b6fd Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 21 Oct 2025 13:40:13 +0200 Subject: [PATCH 13/14] Update launch commands to convert model automatically --- .github/workflows/run_madtrex.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index c8d03f683c..2ceaf6b9d9 100755 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -9,13 +9,12 @@ MADGRAPH_CLI = Path.cwd() / ".." / ".." / "MG5aMC" / "mg5amcnlo" / "bin" / "mg5_aMC" def generate_dat_content(process_dir: str, rwgt_card_path: Path) -> str: - run_card = f"launch {process_dir}\n" + run_card = "set auto_convert_model True\n" + run_card += f"launch {process_dir}\n" run_card += "reweight=madtrex\n" - run_card += "0\n" run_card += "set nevents 10000\n" run_card += "set iseed 489\n" run_card += f"{rwgt_card_path}\n" - run_card += "0\n" return run_card def is_executable(path: Path) -> bool: From f49296d25ae161f94053ebd1c0949b05749ef3f7 Mon Sep 17 00:00:00 2001 From: Daniele Massaro Date: Tue, 21 Oct 2025 14:17:24 +0200 Subject: [PATCH 14/14] Preventively import model so that autoconversion triggers if not trivial In some cases, the imported model during reweighting is still Python 2, so we need to setup autoconversion at the beginning of the launch card if the model is not trivial and it is not the Standard Model --- .github/workflows/run_madtrex.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/run_madtrex.py b/.github/workflows/run_madtrex.py index 2ceaf6b9d9..6c5d8a1b45 100755 --- a/.github/workflows/run_madtrex.py +++ b/.github/workflows/run_madtrex.py @@ -8,13 +8,25 @@ ALLOWED_PROCESSES = [ "ee_mumu", "gg_tt", "gg_tt01g", "gg_ttg", "gg_ttgg", "gg_ttggg", "gq_ttq", "heft_gg_bb", "nobm_pp_ttW", "pp_tt012j", "smeft_gg_tttt", "susy_gg_t1t1", "susy_gg_tt" ] MADGRAPH_CLI = Path.cwd() / ".." / ".." / "MG5aMC" / "mg5amcnlo" / "bin" / "mg5_aMC" -def generate_dat_content(process_dir: str, rwgt_card_path: Path) -> str: - run_card = "set auto_convert_model True\n" - run_card += f"launch {process_dir}\n" +PROCESSES_NON_TRIVIAL_MODELS = { + "heft_gg_bb": "heft", + "smeft_gg_tttt": "SMEFTsim_topU3l_MwScheme_UFO-massless", + "susy_gg_t1t1": "MSSM_SLHA2", + "susy_gg_tt": "MSSM_SLHA2", +} + +def generate_dat_content(process_dir: Path, rwgt_card_path: Path, process_name: str) -> str: + run_card = f"launch {process_dir}\n" run_card += "reweight=madtrex\n" run_card += "set nevents 10000\n" run_card += "set iseed 489\n" run_card += f"{rwgt_card_path}\n" + # if the model of this process is not trivial, import it preventively + # so that if it is still Python 2, it will be converted before the + # reweighting procedure takes place + if process_name in PROCESSES_NON_TRIVIAL_MODELS: + model = PROCESSES_NON_TRIVIAL_MODELS[process_name] + run_card = f"set auto_convert_model True\nimport model {model}\n" + run_card return run_card def is_executable(path: Path) -> bool: @@ -45,9 +57,9 @@ def dump_logs(stdout_log, stderr_log): def main() -> int: # Name of the directory of the process to test - process_dir = sys.argv[1] + process_dir = Path(sys.argv[1]) # Label for the process (must be in the allowed list) - process = process_dir.replace(".mad", "") + process = process_dir.name.replace(".mad", "") # Treat current working directory as HOME HOME = Path.cwd() @@ -86,7 +98,7 @@ def main() -> int: # Write PROCESS.dat to HOME dat_path = HOME / f"{process}.dat" try: - dat_content = generate_dat_content(process_dir, rwgt_card_path) + dat_content = generate_dat_content(process_dir, rwgt_card_path, process) dat_path.write_text(dat_content, encoding="utf-8") except Exception as e: print(f"ERROR: Failed to write {dat_path}: {e}", file=sys.stderr)