File indexing completed on 2026-04-10 07:49:37
0001 import argparse
0002 import subprocess
0003 import re
0004 import os
0005 from pathlib import Path
0006
0007 run_mac_template = """
0008 /run/numberOfThreads {threads}
0009 /run/verbose 1
0010 /process/optical/cerenkov/setStackPhotons {flag}
0011 /run/initialize
0012 /run/beamOn 500
0013 """
0014
0015 os.environ["OPTICKS_EVENT_MODE"] = "Minimal"
0016
0017 def get_opticks_home():
0018 """Get OPTICKS_HOME from environment, warn if not set."""
0019 opticks_home = os.environ.get("OPTICKS_HOME")
0020 if opticks_home is None:
0021 print("Warning: $OPTICKS_HOME is not defined, so this script should be called from the eic-opticks directory.")
0022 return Path(".")
0023 return Path(opticks_home)
0024
0025 def parse_real_time(time_str):
0026
0027 match = re.search(r'real\s+(\d+)m([\d.]+)s', time_str)
0028 if match:
0029 minutes = int(match.group(1))
0030 seconds = float(match.group(2))
0031 return minutes * 60 + seconds
0032 return None
0033
0034 def parse_sim_time(output):
0035 match = re.search(r"Simulation time:\s*([\d.]+)\s*seconds", output)
0036 if match:
0037 return float(match.group(1))
0038 return None
0039
0040 def main():
0041 opticks_home = get_opticks_home()
0042
0043 parser = argparse.ArgumentParser()
0044 parser.add_argument('-g', '--gdml', type=Path, default=None, help="Path to a custom GDML geometry file (relative to current directory)")
0045 parser.add_argument('-o', '--outpath', type=Path, default=Path('./'), help="Path where the output file will be saved")
0046 args = parser.parse_args()
0047
0048
0049 if args.gdml is None:
0050 gdml_path = opticks_home / 'tests/geom/opticks_raindrop.gdml'
0051 else:
0052
0053 gdml_path = args.gdml
0054
0055
0056 run_mac_path = opticks_home / "run.mac"
0057
0058 geant_file = args.outpath / "timing_geant.txt"
0059 optix_file = args.outpath / "timing_optix.txt"
0060 log_file = args.outpath / "g4logs.txt"
0061
0062 with open(geant_file, "w") as gfile, open(optix_file, "w") as ofile, open(log_file, "w") as logfile:
0063 for threads in range(50, 0, -1):
0064 times = {}
0065 sim_time_true = None
0066 for flag in ['true', 'false']:
0067
0068 with open(run_mac_path, "w") as rm:
0069 rm.write(run_mac_template.format(threads=threads, flag=flag))
0070
0071
0072 cmd = f"time GPUCerenkov -g {gdml_path} -m {run_mac_path}"
0073 print(f"Running {threads} threads: {cmd}")
0074 result = subprocess.run(
0075 ["bash", "-c", cmd],
0076 capture_output=True, text=True
0077 )
0078 stdout = result.stdout
0079 stderr = result.stderr
0080
0081 logfile.write(f"\n{'='*60}\n")
0082 logfile.write(f"Threads: {threads}, StackPhotons: {flag}\n")
0083 logfile.write(f"{'='*60}\n")
0084 logfile.write(f"--- STDOUT ---\n{stdout}\n")
0085 logfile.write(f"--- STDERR ---\n{stderr}\n")
0086 logfile.flush()
0087
0088
0089 if flag == 'true':
0090 sim_time_true = parse_sim_time(stdout + stderr)
0091 if sim_time_true is not None:
0092 ofile.write(f"{threads} {sim_time_true}\n")
0093 ofile.flush()
0094
0095
0096 real_match = re.search(r"real\s+\d+m[\d.]+s", stderr)
0097 if real_match:
0098 real_sec = parse_real_time(real_match.group())
0099 times[flag] = real_sec
0100 else:
0101 print(f"[!] Could not find 'real' time for threads={threads} flag={flag}")
0102
0103
0104 if 'true' in times and 'false' in times:
0105 diff = times['true'] - times['false']
0106 gfile.write(f"{threads} {diff}\n")
0107 gfile.flush()
0108 else:
0109 print(f"[!] Missing times for threads={threads}")
0110
0111 print("Done.")
0112
0113 if __name__ == '__main__':
0114 main()