Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ p_ME_*
tests/status
input/default_run_card_lo.dat
input/default_run_card_nlo.dat
input/default_run_card_mg7.toml
input/mg5_configuration.txt
TEST_MW_*
.vscode/
Expand Down Expand Up @@ -62,6 +63,7 @@ additional_command
input/mg5_configuration.txt
input/default_run_card_lo.dat
input/default_run_card_nlo.dat
input/default_run_card_mg7.toml
models/*/*.pkl
py.py
vendor/CutTools/includects/
Expand Down
21 changes: 21 additions & 0 deletions input/.default_run_card_mg7.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# *********************************************************************
# MadGraph5_aMC@NLO
#
# run_card.toml (mg7 / madnis)
#
# This file allows to overwrite the default values written in
# Cards/run_card.toml when it is generated for a dedicated process
# (i.e. when the "output" command is used).
# When you run the code, the value in Cards/run_card.toml is always used.
#
# It must be valid TOML: uncomment a "[section]" header together with
# the entries you want to change.
# *********************************************************************
#
# Example (uncomment to apply):
#
# [generation]
# events = 50000
#
# [phasespace]
# sde_strategy = "denominators"
33 changes: 27 additions & 6 deletions madgraph/interface/common_run_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -5325,15 +5325,15 @@ def get_path(self, name, cards):
if isinstance(cards, list):
if name in cards:
return True
elif '%s_card.dat' % name in cards:
elif '%s_card.dat' % name in cards or '%s_card.toml' % name in cards:
return True
elif name in self.paths and self.paths[name] in cards:
return True
else:
cardnames = [os.path.basename(p) for p in cards]
if '%s_card.dat' % name in cardnames:
if '%s_card.dat' % name in cardnames or '%s_card.toml' % name in cardnames:
return True
else:
else:
return False

elif isinstance(cards, dict) and name in cards:
Expand Down Expand Up @@ -6321,6 +6321,21 @@ def do_set(self, line):
return

#### RUN CARD
# For mg7 TOML run cards, resolve bare keys (e.g. 'events' -> 'generation.events')
# before the membership check below.
if card in ('', 'run_card') and hasattr(self.run_card, 'toml_sections') \
and '.' not in args[start]:
matches = ['%s.%s' % (sec, args[start])
for sec, keys in self.run_card.toml_sections.items()
if args[start] in keys]
if len(matches) == 1:
args[start] = matches[0]
elif len(matches) > 1:
logger.warning(
"Ambiguous key %r — use the full section.key form, e.g.: %s",
args[start], ' or '.join(matches))
return

if args[start] in [l.lower() for l in self.run_card.keys()] and card in ['', 'run_card']:

if args[start] not in self.run_set:
Expand Down Expand Up @@ -7231,7 +7246,10 @@ def handle_alarm(signum, frame):
else:
log_level=20

if run_card and (run_card['lpp1'] !=0 or run_card['lpp2'] !=0):
if run_card and 'lpp1' in run_card and (run_card['lpp1'] !=0 or run_card['lpp2'] !=0):
# The beam-dependent alpha_s/PDF reset only applies to the LO/NLO
# run_card (which defines lpp1/lpp2). Other run_card flavours (e.g.
# the TOML run_card of the mg7 mode) skip this block.
# They are likely case like lpp=+-3, where alpas not need reset
# but those have dedicated name of pdf avoid the reset
as_for_pdf = {'cteq6_m': 0.118,
Expand Down Expand Up @@ -8067,8 +8085,11 @@ def open_file(self, answer):

if answer in self.modified_card:
self.write_card(answer)
elif os.path.basename(answer.replace('_card.dat','')) in self.modified_card:
self.write_card(os.path.basename(answer.replace('_card.dat','')))
else:
short = os.path.basename(
answer.replace('_card.dat', '').replace('_card.toml', ''))
if short in self.modified_card:
self.write_card(short)

start = time.time()
try:
Expand Down
65 changes: 63 additions & 2 deletions madgraph/interface/madgraph_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7672,6 +7672,7 @@ def set_configuration(self, config_path=None, final=True):
if not os.path.exists(pjoin(MG5DIR,'input','default_run_card_lo.dat')) and madgraph.ReadWrite:
files.cp(pjoin(MG5DIR,'input','.default_run_card_lo.dat'), pjoin(MG5DIR,'input','default_run_card_lo.dat'))
files.cp(pjoin(MG5DIR,'input','.default_run_card_nlo.dat'), pjoin(MG5DIR,'input','default_run_card_nlo.dat'))
files.cp(pjoin(MG5DIR,'input','.default_run_card_mg7.toml'), pjoin(MG5DIR,'input','default_run_card_mg7.toml'))

config_file = open(config_path)

Expand Down Expand Up @@ -7962,12 +7963,72 @@ def run():
shell = isinstance(self, cmd.CmdShell),
options=self.options,**options)
elif args[0] == 'mg7':
me_dir = args[1]
# When MG5 runs non-interactively (a command file / piped input),
# drive bin/generate_events from the card-editing commands that
# follow `launch` in the script. Feeding them on stdin also makes
# the subprocess non-interactive, so the one-off madspace install
# runs with defaults instead of blocking on a prompt.
scripted = not self.use_rawinput
feed_lines = []
if scripted and self.inputfile is not None:
stop_prefixes = ('generate', 'add process', 'define', 'output',
'launch', 'import', 'quit', 'exit')
while True:
try:
nxt = next(self.inputfile)
except (StopIteration, TypeError):
break
stripped = nxt.replace('\n', '').strip()
if not stripped:
continue
if stripped.lower().startswith(stop_prefixes):
self.store_line(nxt) # belongs to MG5, hand it back
break
feed_lines.append(stripped)
if stripped.lower() in ('done', '0'):
break

# Expose the configured HEPTools location so that the one-off
# madspace build can pick up a cmake installed there via MG5's
# 'install cmake' (heptools_install_dir may point outside MG5DIR).
gen_env = os.environ.copy()
heptools_dir = self.options.get('heptools_install_dir')
if heptools_dir:
if not os.path.isabs(heptools_dir):
heptools_dir = os.path.join(MG5DIR, heptools_dir)
gen_env['MADGRAPH_HEPTOOLS_DIR'] = os.path.abspath(heptools_dir)

# Point the run at the configured LHAPDF data directory (e.g. a
# lhapdf6 installed via 'install lhapdf6') so it can find the PDF
# sets without the user having to set LHAPDF_DATA_PATH by hand.
if 'LHAPDF_DATA_PATH' not in gen_env:
for _opt in ('lhapdf', 'lhapdf_py3'):
_val = self.options.get(_opt)
if not _val:
continue
_exe = _val.split()[0] # strip any '--python=' suffix
try:
_datadir = subprocess.check_output(
[_exe, '--datadir'], text=True,
stderr=subprocess.DEVNULL).strip()
except Exception:
continue
if _datadir and os.path.isdir(_datadir):
gen_env['LHAPDF_DATA_PATH'] = _datadir
break

class ext_program:
@staticmethod
def run():
os.chdir(args[1])
os.chdir(me_dir)
gen = os.path.join("bin", "generate_events")
try:
subprocess.run(os.path.join("bin", "generate_events"))
if scripted:
stdin_text = "\n".join(feed_lines + ["done"]) + "\n"
subprocess.run([gen], input=stdin_text, text=True, env=gen_env)
else:
subprocess.run(gen, env=gen_env)
except KeyboardInterrupt:
pass

Expand Down
43 changes: 41 additions & 2 deletions madgraph/iolibs/export_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import madgraph.core.base_objects as base_objects
import madgraph.core.color_algebra as color
import madgraph.core.helas_objects as helas_objects
import madgraph.iolibs.group_subprocs as group_subprocs
import madgraph.iolibs.drawing_eps as draw
import madgraph.iolibs.drawing_svg as draw_svg
import madgraph.iolibs.files as files
Expand Down Expand Up @@ -3139,9 +3140,12 @@ class ProcessExporterMG7(ProcessExporterCPP):
# 'check' driver)
template_Sub_make = pjoin(_file_path, 'iolibs', 'template_files',
'Makefile_sa_cpp_sp_api')
# NB: Cards/run_card.toml is NOT copied verbatim here; it is generated in
# finalize() from the run_card.toml template via banner.RunCardMG7, so that
# process-dependent defaults are filled in (see create_run_card).
from_template = {'src': [s+'read_slha.h', s+'read_slha.cc', s+'mg7/api.h'],
'SubProcesses': [s+'mg7/api.cpp'],
'Cards': [s+'mg7/run_card.toml']}
'Cards': []}
#from_template_simd = [
# s+"mg7/api.h",
# s+"mg7/simd/api_simd.cpp",
Expand Down Expand Up @@ -3213,15 +3217,50 @@ def copy_template(self, model):
)
os.chmod(madnis_bin, 0o755)

def finalize(self, *args, **kwargs):
def finalize(self, matrix_elements=None, history='', *args, **kwargs):
file_name = os.path.normpath(os.path.join(
self.dir_path, "SubProcesses", "subprocesses.json"
))
with open(file_name, 'w') as f:
json.dump(self.process_info, f)

# Generate Cards/run_card.toml from the template, filling in
# process-dependent defaults (mirrors the LO run_card.dat logic).
self.create_run_card(matrix_elements, history)

# we don't call super().finalize() since it would call ProcessExporterCPP.finalize()
# which would compile the model in src/, and we don't want that

def create_run_card(self, matrix_elements, history):
"""Write Cards/run_card.toml from the run_card.toml template via
banner.RunCardMG7, applying process-dependent defaults."""

run_card = banner_mod.RunCardMG7()

processes = None
try:
if isinstance(matrix_elements, group_subprocs.SubProcessGroupList):
processes = [me.get('processes') for megroup in matrix_elements
for me in megroup['matrix_elements']]
elif matrix_elements:
processes = [me.get('processes')
for me in matrix_elements['matrix_elements']]
except (KeyError, TypeError):
processes = None

if processes:
run_card.create_default_for_process(self.proc_characteristic,
history, processes)

template = pjoin(_file_path, 'iolibs', 'template_files',
'mg7', 'run_card.toml')
run_card.write(pjoin(self.dir_path, 'Cards', 'run_card.toml'),
template=template)
# Also write a concrete default card so the interactive card editor
# can offer "set <param> default" (mirrors run_card_default.dat at LO).
run_card.write(pjoin(self.dir_path, 'Cards', 'run_card_default.toml'),
template=template)

def ExportCPPFactory(cmd, group_subprocesses=False, cmd_options={}):
""" Determine which Export class is required. cmd is the command
interface containing all potential usefull information.
Expand Down
13 changes: 10 additions & 3 deletions madgraph/iolibs/template_files/mg7/gridpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@
import argparse

def main() -> None:
# load run card and metadata
with open(os.path.join("Cards", "run_card.toml"), "rb") as f:
run_card = tomllib.load(f)
# load run card and metadata. Use the RunCardMG7 representation when the
# madgraph package is importable; gridpacks are meant to be portable, so
# fall back to a plain tomllib parse otherwise (the card is the same TOML).
run_card_path = os.path.join("Cards", "grid_run_card.toml")
try:
from madgraph.various.banner import RunCardMG7
run_card = RunCardMG7(run_card_path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This never happens because madgraph is not added to the path. Do we want to keep it or just always use the tomllib one to be completely independent of the main MG code?

except ImportError:
with open(run_card_path, "rb") as f:
run_card = tomllib.load(f)
run_args = run_card["run"]
gen_args = run_card["generation"]
param_card_path = os.path.join("Cards", "param_card.dat")
Expand Down
Loading
Loading