From geant4-claude
Read a run's ROOT output with uproot/numpy and produce plots. Schema-aware — recipes target the example's `Hits` TTree (per-event edep, hit map, per-volume sums); adapt branch names for custom schemas. Load when writing or running anything in analysis/ or interpreting runs/<id>/*.root.
How this skill is triggered — by the user, by Claude, or both
Slash command
/geant4-claude:geant4-analysisThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The plugin's default analysis stack is **`uproot` + `numpy` +
The plugin's default analysis stack is uproot + numpy +
matplotlib on the host — no ROOT install required. Anything that
genuinely needs ROOT (TBrowser, TMVA, RooFit) runs in the container via
g4run root <macro>.
The recipes below are written against the example main's schema
(one Hits TTree). For user-written mains with different schemas,
inspect the file first (the geant4-analyze skill does this automatically) and
substitute branch names; the same uproot patterns apply.
When the user runs the example main from the geant4-example skill,
runs/<id>/hits.root contains exactly one TTree, Hits, with these
branches:
| Branch | Type | Unit | Meaning |
|---|---|---|---|
event | int32 | — | Event ID (0-indexed). |
volume | string (char[64]) | — | Logical-volume name where the hit was recorded. |
edep | float64 | MeV | Energy deposited in this step. |
x,y,z | float64 | mm | Pre-step position in global coordinates. |
t | float64 | ns | Pre-step global time. |
pdg | int32 | — | PDG code of the depositing track. |
One row per non-zero-edep step. To get per-event quantities, group by
event.
runs/<id>/config.json since v0.0.2 holds generic provenance
(run_id, executable, args, image, git_sha, started_utc,
duration_s, exit_status). Macro-derived fields (particle, energy,
event count) are not in there — derive them from data
(event.max() + 1 for the event count) or parse the macro file
yourself.
The geant4-analyze skill resolves a Python with uproot/numpy/
matplotlib automatically: host Python if it already has them, else the
plugin-managed venv at ${GEANT4_CLAUDE_VENV} (seeded once, or
repaired on demand). Never pip install --user — it pollutes the host
site-packages the rest of the plugin deliberately avoids. To ensure /
repair the venv on demand (env vars come from sourcing .g4c/env):
. .g4c/env
"${GEANT4_CLAUDE_ROOT}/scripts/ensure_venv.sh"
then run the analysis with ${GEANT4_CLAUDE_VENV}/bin/python.
A separate project venv is a fine alternative if you prefer it isolated from the plugin's managed venv:
python3 -m venv .venv && . .venv/bin/activate
pip install uproot numpy matplotlib
Always start by listing what's actually in the file. The geant4-analyze skill does this automatically; standalone:
import uproot
with uproot.open("runs/<id>/hits.root") as f:
for k, t in f.items():
if hasattr(t, "keys"):
print(f"{k}:", {b: t[b].typename for b in t.keys()})
import pathlib
import uproot, numpy as np
run_dir = pathlib.Path("runs/<id>")
with uproot.open(run_dir / "hits.root") as f:
t = f["Hits"]
arrs = t.arrays(["event", "volume", "edep", "x", "y", "z", "t", "pdg"],
library="np")
event = arrs["event"]
edep = arrs["edep"]
# arrs["volume"] is a numpy array of bytes; decode if needed:
volume = np.array([v.decode() for v in arrs["volume"]])
For large files use t.iterate(step_size="100 MB", library="np").
n_events = int(event.max() + 1) # derive from data, not config.json
per_event = np.bincount(event, weights=edep, minlength=n_events)
# per_event[i] is total MeV deposited in event i
Histogram:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.hist(per_event, bins=50)
ax.set_xlabel("Energy deposit per event [MeV]")
ax.set_ylabel("Events")
ax.set_title(f"{run_dir.name} — {n_events} events, {len(edep)} hits")
fig.savefig(run_dir / "edep_hist.png", dpi=120)
If you specifically need the gun energy / particle in the title, parse
the macro file (runs/<id>/run.mac if your driver materialized one,
else the original macros/<name>.mac) for /gun/energy and
/gun/particle lines. The provenance file no longer carries them.
import collections
n_events = int(event.max() + 1)
totals = collections.Counter()
for v, e in zip(volume, edep):
totals[v] += e
for name, mev in sorted(totals.items(), key=lambda kv: -kv[1]):
print(f"{name:30s} {mev:12.3g} MeV ({mev/n_events:.3g} MeV/event)")
fig, ax = plt.subplots()
ax.hexbin(arrs["x"], arrs["y"], C=arrs["edep"], reduce_C_function=np.sum,
gridsize=80, cmap="viridis")
ax.set_xlabel("x [mm]"); ax.set_ylabel("y [mm]")
ax.set_aspect("equal")
ax.set_title("Edep hit map (Σ over all hits)")
fig.savefig(run_dir / "xy_map.png", dpi=120)
For longitudinal showers (z vs energy), do the same with arrs["z"]
and a 1-D histogram.
TBrowser).RooFit, TMVA)..C macro that someone already wrote.g4run root 'mymacro.C("runs/<id>/hits.root")'
Even then, prefer producing the plot with matplotlib if the script will be re-run by other people who may not have ROOT.
volume is bytes, not str — fix with .decode().np.bincount to aggregate.t.array("event") (singular) vs t.arrays([...]) — both work,
the plural is faster when reading several branches.iterate
instead and accumulate per-event sums online.The plugin ships a Geant4-and-physics knowledge base under wiki/ (see wiki/index.md for the full catalog).
Use the Read tool to pull these pages into context when their topic
is load-bearing for the task at hand:
wiki/sources/geant4-code/synthesis/analysis-manager.md —
G4AnalysisManager API: histogram + ntuple booking, format
abstraction (CSV/ROOT/HDF5/XML), MT merging semantics. Read this when
the user wants to write the analysis manager output from Geant4
rather than from uproot post-hoc.wiki/sources/geant4-code/examples/g4-example-analysis-anaex01.md —
worked example: histogram booking, ntuple filling, end-of-run write.
Read this when sketching a new analysis surface inside the user's
main.cc.wiki/sources/geant4-code/examples/g4-example-analysis-anaex02.md —
direct ROOT TFile/TTree (no G4AnalysisManager), exactly the
pattern the plugin's example main uses. Read this when the user wants
to extend the Hits schema or add a sibling tree.wiki/sources/geant4-code/synthesis/scoring-styles.md — the five
scoring approaches Geant4 supports (SD, primitive scorer, scoring
mesh, stepping-action accumulators, hand-rolled in EndOfEventAction).
Read this when the user is about to write a custom SD and may not
need one.wiki/sources/geant4-code/synthesis/scoring-mesh.md —
G4ScoringManager command-based dose grids. Read this when the
question is "show me energy deposit on a 3-D voxel grid", which is
not what the example's Hits TTree gives you.wiki/sources/physics/passage-particles-matter-summary.md — PDG
Ch. 34 in summary form: dE/dx, multiple scattering, bremsstrahlung,
Cherenkov. Read this when interpreting why a deposit distribution
looks the way it does (Landau tail, Molière broadening, etc.).Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub zhaozhiwen/geant4_claude --plugin geant4-claude