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.).npx claudepluginhub zhaozhiwen/geant4_claude --plugin geant4-claudeCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.