Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
miniCaloSim is a Geant4-based calorimeter simulator designed for teaching. It exposes a Python API via pybind11 so students can define calorimeter geometries, run batch simulations, and visualise results — all from a Jupyter notebook.
Build
Requires Geant4 (v11.1.2), pybind11 (submodule at lib/pybind11), and Python 3 development headers.
mkdir build && cd build
cmake ..
make -j$(nproc)
This produces two artifacts:
build/minicalo.so— the pybind11 Python modulebuild/exampleB4a— a standalone Geant4 executable (for reference only)
After building, copy the Python files to the Python path for use outside the bind/ directory (the Dockerfile shows the canonical install paths):
cp build/minicalo*.so bind/G4Calo.py bind/minicalo_tools.py bind/minipandas.py /target/python/path/
cp bind/G4Calo_exec.py /usr/local/bin/
Testing
Run the minipandas unit tests (no Geant4 required):
cd bind && python3 test_minipandas.py
Run the TempFileManager unit tests:
cd bind && python3 -m unittest minicalo_tools.TestTempFileManager
There are no automated tests for the full simulation — student usage is the primary validation path.
Architecture
C++ / Geant4 layer (src/, include/)
The simulation is a standard Geant4 application derived from example B4a. The key extension is that geometry is driven externally via GeometryDescriptor rather than hardcoded:
GeometryDescriptor(include/GeometryDescriptor.hh) — the central geometry object. Holds a list ofLayerobjects, each of which containsSensorobjects after construction. Sensors accumulate deposited energy during a run. Fully pickle-able via__getstate__/__setstate__.Layer— describes one slab: material (NIST name), thickness (cm), active/passive, and annx × nysensor grid.Sensor— stores position, size, andmutable energy(reset between events viaGeometryDescriptor::resetSensorEnergies()).DetectorConstruction(src/DetectorConstruction.cc) — readsGeometryDescriptorand builds Geant4 volumes. UsesG4PVParameterised+LayerParametrisationfor the sensor grid. Active sensors have theirG4VPhysicalVolume*assigned back into theLayer, enabling lookup inSteppingAction.SteppingAction— on each step, maps the physical volume back to aSensorviaGeometryDescriptor::getSensorByVolume()and accumulates energy.RunAction— writes a ROOT ntuple named"Hits"with per-event scalars (true_energy,total_dep_energy,N_layers, ...) and per-sensor arrays (sensor_energy,sensor_x/y/z,sensor_dx/dy/dz,sensor_layer,sensor_copy_number).G4System(include/G4System.hh) — owns the Geant4 run manager lifetime.init(GeometryDescriptor&, seed)sets everything up;run_batch(...)fires events to a ROOT file. OneG4Systemper process — instantiated inside the subprocess (G4Calo_exec.py) to avoid Geant4 singleton issues.
pybind11 bindings (bind/bindings.cpp)
Exposes Sensor, Layer, GeometryDescriptor, and G4System to Python as the minicalo module.
Python layer (bind/)
G4Calo.py— the public student API.run_batch()parallelises events across CPU cores usingThreadPoolExecutor; each worker subprocess callsG4Calo_exec.py, which instantiates a freshG4Systemto avoid Geant4 singleton issues. Results are written as temporary ROOT files in/dev/shm(fallback:/tmp), read back withuproot/awkward, and merged into aMiniFrame.display_event()runs a single event and renders a 3D Plotly figure.G4Calo_exec.py— the worker subprocess entry point. Reads a pickledGeometryDescriptor+ parameters, runs the simulation, writes a ROOT file, and returns the path. Must be on$PATHas an executable.minicalo_tools.py—TempFileManager: context manager for/dev/shm-backed pickle IPC files between the main process and worker subprocesses.minipandas.py—MiniFrame: a minimal NumPy-backed dataframe. Supports scalar columns(N,)and fixed-size vector columns(N, M). Converts topandas.DataFrameviato_pandas()and serialises withto_pickle()/read_pickle().
Subprocess isolation pattern
Geant4 uses global singletons that cannot be re-initialised within a process. Therefore, each simulation batch (even in "single-core" mode) runs in a fresh subprocess spawned by G4Calo_exec.py. Communication uses pickle files via TempFileManager; ROOT output files are used for event data.
Coordinate conventions
Geant4 internal units are mm; sensor positions stored in Sensor are in Geant4 internal units. The Plotly visualisation multiplies layer dimensions by 10 to convert from cm to mm and labels axes with [mm].
Docker
docker/Dockerfile builds a JupyterHub-based image with Geant4 v11.1.2 (multithreading disabled, GEANT4_BUILD_MULTITHREADED=OFF), the minicalo package, and ML dependencies (PyTorch, PyG). docker/Dockerfile-cpu is the CPU-only variant.