Skip to content

Latest commit

 

History

History

Geometry step filtering

Stops transport of a track once it steps outside a hull wrapped around the detector, and derives that hull from the geometry.

run.sh runs the whole chain: a reference simulation with the MCStepLogger, the derivation of a hull from its geometry, a check that every recorded hit lies inside that hull, and two MCReplay runs — one without cuts, one with the hull — whose step and hit counts can be compared.

file
makeKeepStepCylinders.macro derives the hull and writes a keepStep() macro
checkKeepStepCylinders.macro verifies that no recorded hit lies outside a hull
countHits.macro hits per detector of an o2-sim output

The hull is applied through SimCutParams.stepFilteringMacro, in addition to the built-in z/R cut, so it can only remove steps. A ready-made one is installed at $O2_ROOT/share/Detectors/gconfig/KeepStepCylinders.macro; regenerate it whenever the geometry changes.

MCReplayParam.allowStopTrack=true is what lets a replay act on the StopTrack() calls the hull makes.

Measured on 10 pp minimum-bias events, Pythia8 and Geant4, with the hull generated from the geometry of the run itself:

module list steps removed hits lost
default minus ZDC about 5 % 0.18 %
default about 2 % 0.20 %

Hits exclude FT0, which draws a random number while creating hits and does not reproduce under replay.

Read the replay's step accounting with care. MCReplayParam.allowStopTrack makes a replay honour every StopTrack() of a replayed step, not only the ones the hull causes. FT0's photocathode efficiency and HMPID's Fresnel loss stop tracks on a random draw, and those draws do not repeat on replay, so a replay with allowStopTrack=true and a keepStep() that returns true already reports about 8 % of steps skipped with no cut in play; running it with --skipModules ZDC FT0 HMP reports exactly zero. Use the replay only as a difference against such a no-op macro, and expect that difference to still read a little high, because a secondary is dropped whenever its parent was skipped before it was born, which approximates rather than reproduces what Geant4 does.

The number to quote comes from a real Geant4 pair with SimCutParams.trackSeed on, summing the per-event This event/chunk did N steps. Without per-track seeding the two runs diverge into different physics and the comparison is worthless: on one sample it returned 0.19 % where the truth was 4.4 %.

Do not expect the step reduction to become a CPU reduction. Without ZDC, measured as user time over sequential runs on an idle machine with the same generator seed:

run Geant4 steps CPU
no macro 9 855 230 88.7 s
macro returning true 9 855 230 91.1 s
the hull 9 380 571 90.4 s

Two things follow. Reaching a cling-compiled keepStep() through a std::function costs about 235 ns per step on its own -- the middle row removes no steps at all -- while the cylinder scan itself is negligible next to it. And the steps the hull removes are cheap ones: the ~5 % of steps it removes are worth only about 0.7 % of the runtime, so even at zero hook overhead the gain here would be small. The macro is compiled once at start-up, not per step.

Evaluating a cylinder set natively rather than through a macro would remove the overhead; whether a geometry hull is worth it without ZDC is a separate question.

Background: A. Swain, Geometric Hyperparameter Optimisation of ALICE Monte Carlo Transport Simulations, CERN-STUDENTS-Note-2023-164, and B. Völkel, Geometry cuts in MC transport, WP12/13 meeting, 11.10.2023 (https://indico.cern.ch/event/1334852/contributions/5620122/).