From 4ffb2f78b8f8ad1fb09778102a13372212932ce1 Mon Sep 17 00:00:00 2001 From: Lars Bogner Date: Mon, 8 Jun 2026 16:07:17 +0200 Subject: [PATCH] extend Steps ntuple and switch Docker to Geant4 submodule source Add 15 new columns to the Steps ntuple: edep, step_length, parent_id, process name, layer_id, material, pre-step momentum direction, and B/E field components (in T and V/m) at the pre-step point. Replace wget Geant4 tarball download in all three Dockerfiles with ADD of the lib/geant4 submodule source; narrow submodule init to lib/pybind11 only so builds no longer require network access for Geant4. Co-Authored-By: Claude Sonnet 4.6 --- docker/Dockerfile | 34 ++++++++++++----------- docker/Dockerfile-cpu | 35 +++++++++++++----------- docker/Dockerfile-mini | 22 +++++++-------- src/RunAction.cc | 17 +++++++++++- src/SteppingAction.cc | 61 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 45 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 843f2fe..d9eace4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -50,22 +50,24 @@ RUN mkdir dawn-source \ && make clean && make guiclean && make && make install \ && cd - && rm -rf "dawn-source" -## main package +## main package — build Geant4 from submodule source +ADD minicalosim/lib/geant4 /tmp/geant4-src -RUN cd && wget -q https://gitlab.cern.ch/geant4/geant4/-/archive/v11.1.2/geant4-v11.1.2.tar.gz && \ - tar -xzf geant4-v11.1.2.tar.gz -C /tmp && \ - mkdir /tmp/geant4-v11.1.2-build && \ - cd /tmp/geant4-v11.1.2-build && \ - cmake -DCMAKE_INSTALL_PREFIX=/opt/geant4-v11.1.2 -DCMAKE_RULE_MESSAGES=OFF -DGEANT4_INSTALL_DATA=ON \ - -DGEANT4_USE_GDML=ON -DGEANT4_USE_OPENGL_X11=ON \ - -DGEANT4_BUILD_MULTITHREADED=OFF \ - -DGEANT4_BUILD_TLS_MODEL=global-dynamic \ - -DGEANT4_USE_RAYTRACER_X11=ON /tmp/geant4-v11.1.2 >/dev/null && \ - make -j24 >/dev/null && \ - make install >/dev/null - -RUN rm -rf /tmp/geant4-v11.1.2 && \ - rm -rf /tmp/geant4-v11.1.2-build +RUN cmake \ + -S /tmp/geant4-src \ + -B /tmp/geant4-build \ + -DCMAKE_INSTALL_PREFIX=/opt/geant4-v11.1.2 \ + -DCMAKE_RULE_MESSAGES=OFF \ + -DGEANT4_INSTALL_DATA=ON \ + -DGEANT4_USE_GDML=ON \ + -DGEANT4_USE_OPENGL_X11=ON \ + -DGEANT4_BUILD_MULTITHREADED=OFF \ + -DGEANT4_BUILD_TLS_MODEL=global-dynamic \ + -DGEANT4_USE_RAYTRACER_X11=ON \ + >/dev/null && \ + cmake --build /tmp/geant4-build --parallel $(nproc) >/dev/null && \ + cmake --install /tmp/geant4-build >/dev/null && \ + rm -rf /tmp/geant4-src /tmp/geant4-build RUN python3 -m pip install geant4-pybind @@ -94,7 +96,7 @@ ARG USER ADD minicalosim /root/minicalosim RUN cd /root/minicalosim && git checkout $COMMIT && \ - git submodule update --init && \ + git submodule update --init lib/pybind11 && \ mkdir -p build && cd build && rm -rf * && cmake ../ && make -j4 diff --git a/docker/Dockerfile-cpu b/docker/Dockerfile-cpu index 62c7f4b..b6d00ed 100644 --- a/docker/Dockerfile-cpu +++ b/docker/Dockerfile-cpu @@ -50,22 +50,24 @@ RUN mkdir dawn-source \ && make clean && make guiclean && make && make install \ && cd - && rm -rf "dawn-source" -## main package +## main package — build Geant4 from submodule source +ADD minicalosim/lib/geant4 /tmp/geant4-src -RUN cd && wget -q https://gitlab.cern.ch/geant4/geant4/-/archive/v11.1.2/geant4-v11.1.2.tar.gz && \ - tar -xzf geant4-v11.1.2.tar.gz -C /tmp && \ - mkdir /tmp/geant4-v11.1.2-build && \ - cd /tmp/geant4-v11.1.2-build && \ - cmake -DCMAKE_INSTALL_PREFIX=/opt/geant4-v11.1.2 -DCMAKE_RULE_MESSAGES=OFF -DGEANT4_INSTALL_DATA=ON \ - -DGEANT4_USE_GDML=ON -DGEANT4_USE_OPENGL_X11=ON \ - -DGEANT4_BUILD_MULTITHREADED=ON \ - -DGEANT4_BUILD_TLS_MODEL=global-dynamic \ - -DGEANT4_USE_RAYTRACER_X11=ON /tmp/geant4-v11.1.2 >/dev/null && \ - make -j4 >/dev/null && \ - make install >/dev/null - -RUN rm -rf /tmp/geant4-v11.1.2 && \ - rm -rf /tmp/geant4-v11.1.2-build +RUN cmake \ + -S /tmp/geant4-src \ + -B /tmp/geant4-build \ + -DCMAKE_INSTALL_PREFIX=/opt/geant4-v11.1.2 \ + -DCMAKE_RULE_MESSAGES=OFF \ + -DGEANT4_INSTALL_DATA=ON \ + -DGEANT4_USE_GDML=ON \ + -DGEANT4_USE_OPENGL_X11=ON \ + -DGEANT4_BUILD_MULTITHREADED=ON \ + -DGEANT4_BUILD_TLS_MODEL=global-dynamic \ + -DGEANT4_USE_RAYTRACER_X11=ON \ + >/dev/null && \ + cmake --build /tmp/geant4-build --parallel $(nproc) >/dev/null && \ + cmake --install /tmp/geant4-build >/dev/null && \ + rm -rf /tmp/geant4-src /tmp/geant4-build RUN python3 -m pip install geant4-pybind @@ -94,7 +96,8 @@ ARG USER ADD minicalosim /root/minicalosim RUN cd /root/minicalosim && git checkout $COMMIT && \ - mkdir -p build && cd build && rm -rf * && cmake ../ && make -j4 &&\ + git submodule update --init lib/pybind11 && \ + mkdir -p build && cd build && rm -rf * && cmake ../ && make -j$(nproc) &&\ cp minicalo* ../bind/G4Calo.py /usr/local/lib/python3.8/dist-packages/ diff --git a/docker/Dockerfile-mini b/docker/Dockerfile-mini index f795d3c..941e968 100644 --- a/docker/Dockerfile-mini +++ b/docker/Dockerfile-mini @@ -16,23 +16,21 @@ RUN python3 -m pip install --upgrade pip && \ python3 -m pip install numpy pandas uproot awkward plotly ipython && \ ln -sf /usr/bin/python3 /usr/bin/python -# Geant4 v11.1.2 — batch mode only (no visualization, no multithreading) -RUN wget -q https://gitlab.cern.ch/geant4/geant4/-/archive/v11.1.2/geant4-v11.1.2.tar.gz && \ - tar -xzf geant4-v11.1.2.tar.gz -C /tmp && \ - rm geant4-v11.1.2.tar.gz && \ - mkdir /tmp/geant4-v11.1.2-build && \ - cmake \ - -S /tmp/geant4-v11.1.2 \ - -B /tmp/geant4-v11.1.2-build \ +# Geant4 — build from submodule source (batch mode only, no visualization, no multithreading) +ADD minicalosim/lib/geant4 /tmp/geant4-src + +RUN cmake \ + -S /tmp/geant4-src \ + -B /tmp/geant4-build \ -DCMAKE_INSTALL_PREFIX=/opt/geant4-v11.1.2 \ -DCMAKE_RULE_MESSAGES=OFF \ -DGEANT4_INSTALL_DATA=ON \ -DGEANT4_BUILD_MULTITHREADED=OFF \ -DGEANT4_BUILD_TLS_MODEL=global-dynamic \ > /dev/null && \ - cmake --build /tmp/geant4-v11.1.2-build --parallel $(nproc) > /dev/null && \ - cmake --install /tmp/geant4-v11.1.2-build > /dev/null && \ - rm -rf /tmp/geant4-v11.1.2 /tmp/geant4-v11.1.2-build + cmake --build /tmp/geant4-build --parallel $(nproc) > /dev/null && \ + cmake --install /tmp/geant4-build > /dev/null && \ + rm -rf /tmp/geant4-src /tmp/geant4-build ENV LD_LIBRARY_PATH="/opt/geant4-v11.1.2/lib" @@ -45,7 +43,7 @@ LABEL org.label-schema.build-date=$BUILD_DATE ADD minicalosim /root/minicalosim RUN cd /root/minicalosim && git checkout $COMMIT && \ - git submodule update --init && \ + git submodule update --init lib/pybind11 && \ cmake \ -S . -B build \ -DWITH_GEANT4_UIVIS=OFF \ diff --git a/src/RunAction.cc b/src/RunAction.cc index b19eed9..c14ef49 100644 --- a/src/RunAction.cc +++ b/src/RunAction.cc @@ -95,7 +95,22 @@ RunAction::RunAction() analysisManager->CreateNtupleDColumn("post_x"); // col 8 analysisManager->CreateNtupleDColumn("post_y"); // col 9 analysisManager->CreateNtupleDColumn("post_z"); // col 10 - analysisManager->CreateNtupleDColumn("post_E"); // col 11 + analysisManager->CreateNtupleDColumn("post_E"); // col 11 + analysisManager->CreateNtupleDColumn("edep"); // col 12 [MeV] + analysisManager->CreateNtupleDColumn("step_length"); // col 13 [mm] + analysisManager->CreateNtupleIColumn("parent_id"); // col 14 + analysisManager->CreateNtupleSColumn("process"); // col 15 + analysisManager->CreateNtupleIColumn("layer_id"); // col 16 (-1 = outside all layers) + analysisManager->CreateNtupleSColumn("material"); // col 17 + analysisManager->CreateNtupleDColumn("pre_dx"); // col 18 + analysisManager->CreateNtupleDColumn("pre_dy"); // col 19 + analysisManager->CreateNtupleDColumn("pre_dz"); // col 20 + analysisManager->CreateNtupleDColumn("Bx"); // col 21 [T] + analysisManager->CreateNtupleDColumn("By"); // col 22 [T] + analysisManager->CreateNtupleDColumn("Bz"); // col 23 [T] + analysisManager->CreateNtupleDColumn("Ex"); // col 24 [V/m] + analysisManager->CreateNtupleDColumn("Ey"); // col 25 [V/m] + analysisManager->CreateNtupleDColumn("Ez"); // col 26 [V/m] analysisManager->FinishNtuple(); } diff --git a/src/SteppingAction.cc b/src/SteppingAction.cc index 1f84d52..964c28c 100644 --- a/src/SteppingAction.cc +++ b/src/SteppingAction.cc @@ -36,6 +36,10 @@ #include "G4AnalysisManager.hh" #include "G4Track.hh" #include "G4ParticleDefinition.hh" +#include "G4TransportationManager.hh" +#include "G4FieldManager.hh" +#include "G4Field.hh" +#include "G4SystemOfUnits.hh" using namespace B4; @@ -95,6 +99,63 @@ void SteppingAction::UserSteppingAction(const G4Step* step) analysisManager->FillNtupleDColumn(1, 9, post->GetPosition().y()); analysisManager->FillNtupleDColumn(1, 10, post->GetPosition().z()); analysisManager->FillNtupleDColumn(1, 11, post->GetKineticEnergy()); + + // A: energy deposited in medium at this step (≠ pre_E - post_E when secondaries are created) + analysisManager->FillNtupleDColumn(1, 12, edep); + + // B: geometric step length + analysisManager->FillNtupleDColumn(1, 13, step->GetStepLength()); + + // C: parent track ID (0 for primary) + analysisManager->FillNtupleIColumn(1, 14, track->GetParentID()); + + // D: process that ended this step + G4String processName = ""; + const auto* postProc = post->GetProcessDefinedStep(); + if (postProc) processName = postProc->GetProcessName(); + analysisManager->FillNtupleSColumn(1, 15, processName); + + // E: layer index (-1 if outside all layers) and material name at pre-step point + int layerId = -1; + const auto& layers = cw->getLayers(); + for (int i = 0; i < (int)layers.size(); i++) { + if (layers[i].physicalVolume == volume) { layerId = i; break; } + } + G4String materialName = pre->GetMaterial() ? pre->GetMaterial()->GetName() : ""; + analysisManager->FillNtupleIColumn(1, 16, layerId); + analysisManager->FillNtupleSColumn(1, 17, materialName); + + // F: pre-step momentum direction (unit vector) + const auto dir = pre->GetMomentumDirection(); + analysisManager->FillNtupleDColumn(1, 18, dir.x()); + analysisManager->FillNtupleDColumn(1, 19, dir.y()); + analysisManager->FillNtupleDColumn(1, 20, dir.z()); + + // Field: B [T] and E [V/m] at pre-step position; zero if no field is registered + G4double Bx=0, By=0, Bz=0, Ex=0, Ey=0, Ez=0; + const auto* fm = G4TransportationManager::GetTransportationManager()->GetFieldManager(); + if (fm && fm->DoesFieldExist()) { + const G4Field* field = fm->GetDetectorField(); + if (field) { + const G4double point[4] = {pre->GetPosition().x(), pre->GetPosition().y(), + pre->GetPosition().z(), pre->GetGlobalTime()}; + G4double fieldVal[6] = {0,0,0,0,0,0}; + field->GetFieldValue(point, fieldVal); + Bx = fieldVal[0] / tesla; + By = fieldVal[1] / tesla; + Bz = fieldVal[2] / tesla; + Ex = fieldVal[3] / (volt/m); + Ey = fieldVal[4] / (volt/m); + Ez = fieldVal[5] / (volt/m); + } + } + analysisManager->FillNtupleDColumn(1, 21, Bx); + analysisManager->FillNtupleDColumn(1, 22, By); + analysisManager->FillNtupleDColumn(1, 23, Bz); + analysisManager->FillNtupleDColumn(1, 24, Ex); + analysisManager->FillNtupleDColumn(1, 25, Ey); + analysisManager->FillNtupleDColumn(1, 26, Ez); + analysisManager->AddNtupleRow(1); }