Warning, /physics_benchmarks/Snakefile is written in an unsupported language. File is not indexed.
0001 configfile: "snakemake.yml"
0002
0003 import functools
0004 import os
0005 import subprocess
0006 from snakemake.logging import logger
0007
0008
0009 ## The detector install prefix is the single source of truth: the geometry XML
0010 ## directory, the geometry library and thisepic.sh are all derived from it.
0011 ## DETECTOR_PATH is published back into the configuration so that rules can
0012 ## refer to it as config["DETECTOR_PATH"] rather than reaching for a
0013 ## module-level name, and so that a detector with a non-standard layout can
0014 ## still be pointed at directly with --config DETECTOR_PATH=...
0015 DETECTOR_PREFIX = config["DETECTOR_PREFIX"]
0016 config.setdefault("DETECTOR_PATH", f"{DETECTOR_PREFIX}/share/{config['DETECTOR']}")
0017
0018 ## ROOT mirrors the absolute source path underneath its build directory, so
0019 ## ROOT_BUILD_DIR has to be absolute for the declared outputs to match where
0020 ## ACLiC actually writes. An empty value means build in-tree.
0021 ROOT_BUILD_DIR = config.get("ROOT_BUILD_DIR") or None
0022
0023 if ROOT_BUILD_DIR is not None:
0024 ROOT_BUILD_DIR = os.path.abspath(ROOT_BUILD_DIR)
0025 ROOT_BUILD_DIR_PREFIX = f"{ROOT_BUILD_DIR}/{os.getcwd().lstrip('/')}/"
0026 else:
0027 ROOT_BUILD_DIR_PREFIX = ""
0028
0029
0030 ## Every shell: block gets the detector environment and ROOT settings from the
0031 ## configuration, so the pipeline does not depend on the CI job having set them
0032 ## up. Five things to keep in mind when editing this:
0033 ## - No stray curly braces: shell.prefix() runs its argument through
0034 ## snakemake's own format(), which would interpret them as format fields.
0035 ## That rules out ${VAR:-} style defaults, hence the ordering below.
0036 ## - "set -euo pipefail" comes last, not first. Snakemake normally prepends it
0037 ## to every shell: block, but only while no shell.prefix() is set, so we have
0038 ## to reinstate it ourselves or silently lose it. It has to come *after* the
0039 ## environment setup: thisepic.sh reads $LD_LIBRARY_PATH unguarded and the
0040 ## ROOT_INCLUDE_PATH append reads its own previous value, both of which abort
0041 ## under "set -u" when unset. The rule body still runs fully strict.
0042 ## - thisepic.sh takes the detector configuration as $1. That relies on
0043 ## "source" rather than POSIX ".", which does not give the sourced script
0044 ## its own positional parameters; snakemake runs shell: blocks under bash
0045 ## (it calls shell.executable("bash") on import), so this is fine.
0046 ## - DETECTOR_PATH is re-exported afterwards, because thisepic.sh sets it from
0047 ## its own install tree, which would otherwise disagree with
0048 ## config["DETECTOR_PATH"] for the rules that read $DETECTOR_PATH in a
0049 ## shell: block.
0050 ## - ";" and not "&&", so that the environment setup does not abort a rule
0051 ## where thisepic.sh is absent (e.g. the lager image used by dvmp:generate).
0052 shell.prefix(
0053 f"source {DETECTOR_PREFIX}/bin/thisepic.sh {config['DETECTOR_CONFIG']}; "
0054 f"export DETECTOR_PATH={config['DETECTOR_PATH']}; "
0055 f"export ROOT_MAX_THREADS={config['BENCHMARK_N_THREADS']}; "
0056 f"export ROOT_INCLUDE_PATH={os.path.abspath(workflow.basedir)}/include:$ROOT_INCLUDE_PATH; "
0057 + (f"export ROOT_BUILD_DIR={ROOT_BUILD_DIR}; " if ROOT_BUILD_DIR else "")
0058 + "set -euo pipefail; "
0059 )
0060
0061
0062 @functools.cache
0063 def get_spack_package_hash(package_name):
0064 import json
0065 try:
0066 ver_info = json.loads(subprocess.check_output(["spack", "find", "--json", package_name]))
0067 return ver_info[0]["hash"]
0068 except FileNotFoundError as e:
0069 logger.warning("Spack is not installed")
0070 return ""
0071 except subprocess.CalledProcessError as e:
0072 print(e)
0073 return ""
0074
0075
0076 @functools.cache
0077 def find_epic_libraries():
0078 import ctypes.util
0079 # if library is not found (not avaliable) we return an empty list to let DAG still evaluate
0080 libs = []
0081 lib = ctypes.util.find_library("epic")
0082 if lib is not None:
0083 libs.append(f"{DETECTOR_PREFIX}/lib/{lib}")
0084 return libs
0085
0086
0087 def epic_fetch_url(path):
0088 if not path.startswith("EPIC/"):
0089 raise ValueError(f"EPIC fetch path must start with 'EPIC/', got {path!r}")
0090 return f"root://dtn2304.jlab.org:8443//jlab-osdf-ro/eic/EPIC/volatile/{path.removeprefix('EPIC/')}"
0091
0092
0093 rule compile_analysis:
0094 input:
0095 "{path}/{filename}.cxx",
0096 output:
0097 ROOT_BUILD_DIR_PREFIX + "{path}/{filename}_cxx.d",
0098 ROOT_BUILD_DIR_PREFIX + "{path}/{filename}_cxx.so",
0099 ROOT_BUILD_DIR_PREFIX + "{path}/{filename}_cxx_ACLiC_dict_rdict.pcm",
0100 shell:
0101 """
0102 root -l -b -q -e '.L {input}+'
0103 """
0104
0105
0106 rule fetch_epic:
0107 output:
0108 filepath="EPIC/{PATH}"
0109 params:
0110 remote_path=lambda wildcards, output: epic_fetch_url(output.filepath)
0111 cache: True
0112 shell: """
0113 xrdcp {params.remote_path} {output.filepath}
0114 """
0115
0116
0117 rule warmup_run:
0118 output:
0119 "warmup/{DETECTOR_CONFIG}.edm4hep.rnt.root",
0120 message: "Ensuring that calibrations/fieldmaps are available for {wildcards.DETECTOR_CONFIG}"
0121 shell: """
0122 ddsim \
0123 --runType batch \
0124 --numberOfEvents 1 \
0125 --compactFile "$DETECTOR_PATH/{wildcards.DETECTOR_CONFIG}.xml" \
0126 --outputConfig.useRNTuple true \
0127 --outputFile "{output}" \
0128 --enableGun
0129 """
0130
0131 include: "benchmarks/Exclusive-Diffraction-Tagging/demp/Snakefile"
0132 include: "benchmarks/Exclusive-Diffraction-Tagging/diffractive_vm/Snakefile"
0133 include: "benchmarks/Exclusive-Diffraction-Tagging/dvmp/Snakefile"
0134 include: "benchmarks/Exclusive-Diffraction-Tagging/semi_coherent/Snakefile"
0135 include: "benchmarks/Jets-HF/jets/Snakefile"
0136 include: "benchmarks/Inclusive/dis/Snakefile"