Skip to content

Commit ceddd03

Browse files
committed
Merge branch 'examples/geant4' into 296-ensure-all-examples-are-up-to-date-and-verified
2 parents 1cea109 + e9c5455 commit ceddd03

File tree

5 files changed

+155
-1
lines changed

5 files changed

+155
-1
lines changed

.github/workflows/examples.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Simvue Examples
22

33
on:
44
push:
5-
branches: [ "main", "dev", "hotfix/update-ci", "296-*" ]
5+
branches: [ "main", "dev", "hotfix/update-ci", "296-*", "examples/*" ]
66
pull_request:
77
branches: [ "main", "dev", "hotfix/update-ci" ]
88

@@ -153,3 +153,29 @@ jobs:
153153
export SIMVUE_URL=${{ secrets.SIMVUE_URL }}
154154
export SIMVUE_TOKEN=${{ secrets.SIMVUE_TOKEN }}
155155
python3.11 ./examples/Tensorflow/dynamic_rnn.py --ci
156+
157+
GEANT4:
158+
runs-on: ubuntu-latest
159+
container:
160+
image: artemisbeta/geant4:11.2.1
161+
steps:
162+
- uses: actions/checkout@v4
163+
with:
164+
submodules: recursive
165+
- name: Setup Python
166+
uses: actions/setup-python@v5
167+
with:
168+
python-version: "3.11"
169+
- name: Install Simvue
170+
run: python3 -m pip install .
171+
- name: Install Dependencies
172+
run: python3 -m pip install -r examples/Geant4/requirements.txt
173+
- name: Build Example
174+
run: |
175+
cmake -DCMAKE_PREFIX_PATH=/usr/local/share/geant4/install/4.11.2/ -Bbuild examples/Geant4/FixedTarget/
176+
cmake --build build
177+
- name: Run Example
178+
run: |
179+
export SIMVUE_URL=${{ secrets.SIMVUE_URL }}
180+
export SIMVUE_TOKEN=${{ secrets.SIMVUE_TOKEN }}
181+
python examples/Geant4/geant4_simvue.py build/MaterialTesting --ci --events 10

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "examples/Geant4/FixedTarget"]
2+
path = examples/Geant4/FixedTarget
3+
url = https://github.com/artemis-beta/Geant4-Example.git

examples/Geant4/FixedTarget

Submodule FixedTarget added at 4113c4c

examples/Geant4/geant4_simvue.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
Geant4 Simvue
3+
=============
4+
5+
Example of repeating simulation of a proton fired at a target of beryllium
6+
monitoring the yield of key particles of interest
7+
"""
8+
9+
import multiparser
10+
import multiparser.parsing.file as mp_file_parse
11+
import simvue
12+
import uproot
13+
import multiprocessing
14+
import typing
15+
import click
16+
import pathlib
17+
import os
18+
import tempfile
19+
20+
from particle import Particle
21+
22+
23+
@click.command
24+
@click.argument("g4_binary", type=click.Path(exists=True))
25+
@click.option("--config", type=click.Path(exists=True), default=None)
26+
@click.option("--ci", is_flag=True, default=False)
27+
@click.option("--momentum", type=float, default=10)
28+
@click.option("--events", type=int, default=100)
29+
def geant4_simvue_example(
30+
g4_binary: str, config: typing.Optional[str], ci: bool, momentum: float, events: int
31+
) -> None:
32+
@mp_file_parse.file_parser
33+
def root_file_parser(
34+
file_name: str, *_, **__
35+
) -> tuple[dict[str, typing.Any], dict[str, typing.Any]]:
36+
with uproot.open(file_name) as root_data:
37+
hit_data: dict[str, uproot.TBranch]
38+
if not (hit_data := root_data.get("Hits")):
39+
raise RuntimeError("Expected key 'Hits' in ROOT file")
40+
41+
particles_of_interest = [2212, 211, 11, 22, 2112]
42+
43+
all_particles = hit_data["fID"].array(library="np").tolist()
44+
45+
out_data = {
46+
Particle.from_pdgid(abs(identifier)).name: [
47+
abs(i) for i in all_particles
48+
].count(abs(identifier))
49+
for identifier in particles_of_interest
50+
}
51+
52+
return {}, out_data
53+
54+
termination_trigger = multiprocessing.Event()
55+
56+
with simvue.Run() as run:
57+
run.init(
58+
"Geant4_simvue_demo",
59+
folder="/simvue_client_demos",
60+
tags=[
61+
"Geant4",
62+
],
63+
description="Geant4 fixed target scenario",
64+
retention_period="1 hour" if ci else None,
65+
)
66+
67+
kwargs: dict[str, typing.Any] = {}
68+
69+
if config:
70+
kwargs["script"] = config
71+
with tempfile.TemporaryDirectory() as tempd:
72+
with multiparser.FileMonitor(
73+
per_thread_callback=lambda metrics, *_: run.log_metrics(metrics),
74+
exception_callback=run.log_event,
75+
terminate_all_on_fail=False,
76+
plain_logging=True,
77+
flatten_data=True,
78+
termination_trigger=termination_trigger,
79+
) as monitor:
80+
monitor.track(
81+
path_glob_exprs=[f'{pathlib.Path(tempd).joinpath("*")}'],
82+
parser_func=root_file_parser,
83+
static=True,
84+
)
85+
monitor.run()
86+
87+
for i in range(events):
88+
if i % 10 == 0:
89+
click.secho(
90+
f"Running {i+1}/{events} with momentum {momentum} GeV",
91+
bold=True,
92+
fg="cyan",
93+
)
94+
running_simulation = multiprocessing.Event()
95+
run.add_process(
96+
identifier=f"Geant4_simulation_{momentum}GeV_{i}",
97+
executable=g4_binary,
98+
momentum=momentum,
99+
batch=True,
100+
output=pathlib.Path(tempd).joinpath(
101+
f"output_{momentum}GeV_{i+1}.root"
102+
),
103+
completion_trigger=running_simulation
104+
if i == events - 1
105+
else None,
106+
**kwargs,
107+
)
108+
109+
termination_trigger.set()
110+
111+
for file in pathlib.Path().cwd().glob("Geant4*.err"):
112+
os.remove(file)
113+
114+
for file in pathlib.Path().cwd().glob("Geant4*.out"):
115+
os.remove(file)
116+
117+
118+
if __name__ in "__main__":
119+
geant4_simvue_example()

examples/Geant4/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
simvue
2+
uproot
3+
ukaea-multiparser
4+
click
5+
particle

0 commit comments

Comments
 (0)