Files
2026-06-08 11:20:31 +02:00

5.1 KiB
Raw Permalink Blame History

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 module
  • build/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 of Layer objects, each of which contains Sensor objects 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 an nx × ny sensor grid.
  • Sensor — stores position, size, and mutable energy (reset between events via GeometryDescriptor::resetSensorEnergies()).
  • DetectorConstruction (src/DetectorConstruction.cc) — reads GeometryDescriptor and builds Geant4 volumes. Uses G4PVParameterised + LayerParametrisation for the sensor grid. Active sensors have their G4VPhysicalVolume* assigned back into the Layer, enabling lookup in SteppingAction.
  • SteppingAction — on each step, maps the physical volume back to a Sensor via GeometryDescriptor::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. One G4System per 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 using ThreadPoolExecutor; each worker subprocess calls G4Calo_exec.py, which instantiates a fresh G4System to avoid Geant4 singleton issues. Results are written as temporary ROOT files in /dev/shm (fallback: /tmp), read back with uproot/awkward, and merged into a MiniFrame. display_event() runs a single event and renders a 3D Plotly figure.
  • G4Calo_exec.py — the worker subprocess entry point. Reads a pickled GeometryDescriptor + parameters, runs the simulation, writes a ROOT file, and returns the path. Must be on $PATH as an executable.
  • minicalo_tools.pyTempFileManager: context manager for /dev/shm-backed pickle IPC files between the main process and worker subprocesses.
  • minipandas.pyMiniFrame: a minimal NumPy-backed dataframe. Supports scalar columns (N,) and fixed-size vector columns (N, M). Converts to pandas.DataFrame via to_pandas() and serialises with to_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.