Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e008c6d
initial commit - merging of CJs classes
MoritzNeuberger Nov 10, 2025
c3a6ebe
Adds geometry benchmark CLI
MoritzNeuberger Nov 12, 2025
c36fd05
implemented better approach to be less suseptable for sudden spikes i…
MoritzNeuberger Dec 2, 2025
ec915f8
Adds support for benchmarking specific GDML components
MoritzNeuberger Dec 2, 2025
41f5062
Add geometry benchmarking documentation and update summary generator
MoritzNeuberger Dec 2, 2025
b2b7953
Removing histprint dependency
MoritzNeuberger Dec 2, 2025
4265481
precommit skipped with this?
MoritzNeuberger Dec 2, 2025
9be7753
Removing histprint dependency
MoritzNeuberger Dec 2, 2025
0f98dbf
Merge branch 'navigaion_benchmark_utilities' of https://github.com/Mo…
MoritzNeuberger Dec 3, 2025
5a725f5
Added tests for the python package, also removed some depricated func…
MoritzNeuberger Dec 3, 2025
0098522
Merge branch 'navigaion_benchmark_utilities' of https://github.com/Mo…
MoritzNeuberger Dec 3, 2025
f90ac28
Added suggestion
MoritzNeuberger Dec 3, 2025
d59f081
Implementing suggestions from conversation:
MoritzNeuberger Dec 9, 2025
d9369d9
Add mplhep and hist dependencies; refactor summary generator for hist…
MoritzNeuberger Dec 9, 2025
b6fe1da
gave up on the hist color bar to have a label
MoritzNeuberger Dec 9, 2025
a9611ca
Merge branch 'main' into navigaion_benchmark_utilities
MoritzNeuberger Dec 16, 2025
813eb40
Update python/remage/geombench/cli.py
MoritzNeuberger Dec 19, 2025
fd2ede2
Update python/remage/geombench/cli.py
MoritzNeuberger Dec 19, 2025
2333c46
Merge branch 'main' of https://github.com/legend-exp/remage into navi…
MoritzNeuberger Dec 19, 2025
689fe97
Merge branch 'navigaion_benchmark_utilities' of https://github.com/Mo…
MoritzNeuberger Dec 19, 2025
33a8cd1
Add license information to geombench modules
MoritzNeuberger Dec 19, 2025
7e170e3
Update .pre-commit-config.yaml
MoritzNeuberger Dec 19, 2025
8e3b235
Merge branch 'navigaion_benchmark_utilities' of https://github.com/Mo…
MoritzNeuberger Dec 19, 2025
1b96530
Refactor variable names in geombench modules for consistency: changed…
MoritzNeuberger Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions docs/manual/geombench.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
(manual-geombench)=

# Geometry benchmarking

The `remage-geombench` command-line tool helps identify performance bottlenecks
in detector geometries during the design phase. It systematically samples points
on three grids of starting positions and simulates geantinos through the volume.
It returns the median simulation time per geantino. Based on these overview
plots and statistics are generated.

:::{tip}

Use this tool during geometry development to identify components that may slow
down simulations. Complex nested structures, boolean operations, and highly
detailed volumes can significantly increase navigation time.

:::

## Overview

The geometry benchmark works by:

1. Loading a GDML geometry file
2. Creating three 2D grids in XY, XZ, and YZ direction according to grid
specifications
3. Sampling geantinos and estimating the median simulation time per grid point
4. Generating statistics and visualizations showing where navigation is slow

This information helps you optimize geometries before running full physics
simulations, potentially saving significant computation time.

## Basic usage

The simplest usage requires only a GDML file:

```console
$ remage-geombench detector.gdml
```

This will:

- Benchmark the entire geometry
- Use default settings (10M events, 1 mm grid spacing, 25% buffer)
- Save results to `detector.lh5` in the current directory
- Print summary statistics to the console and generate overview plots in the
current directory

## Command-line options

### Geometry selection

**`geometry`** (required) : Path to the GDML geometry file to benchmark.

**`--logical-volume NAME`** (optional) : Extract and benchmark only a specific
logical volume including daughters from the geometry. Useful for isolating
performance issues in complex assemblies.

Example:

```console
$ remage-geombench l1000.gdml --logical-volume V0101
```

### Grid configuration

**`--grid-increment SPACING`** (default: `1`) : Uniform spacing between grid
points in millimeters for all dimensions.

Example (coarse grid for quick tests):

```console
$ remage-geombench l1000.gdml --grid-increment 5
```

**`--grid-increments DICT`** (optional) : Specify different spacing per
dimension using a Python dictionary literal. Overrides `--grid-increment` if
provided.

Example:

```console
$ remage-geombench l1000.gdml --grid-increments "{'x': 1.0, 'y': 2.0, 'z': 0.5}"
```

### Buffer region

**`--buffer-fraction FRACTION`** (default: `0.25`) : Fractional buffer space
around the geometry. A value of 0.25 adds 12.5% extra space on each side,
creating a world volume large enough to contain the geometry with margin.

Example (tighter bounds):

```console
$ remage-geombench l1000.gdml --buffer-fraction 0.1
```

### Simulation control

**`--num-events N`** (default: `10000000`) : Number of navigation events to
simulate. Higher values give more stable statistics but take longer.

Example (quick test):

```console
$ remage-geombench l1000.gdml --num-events 1000000
```

**`--output-dir PATH`** (default: `./`) : Directory to store output files.

Example:

```console
$ remage-geombench l1000.gdml --output-dir ./benchmark_results/
```

**`--dry-run`** : Generate and display the macro file without running the
simulation. Useful for verifying configuration before long runs.

Example:

```console
$ remage-geombench l1000.gdml --dry-run
```

## Interpreting results

The tool generates an LH5 output file containing spatial navigation performance
data and prints summary statistics:

```
Geometry Benchmark Analysis Results:
mean_navigation_time: 2.45 ns
median_navigation_time: 1.89 ns
std_navigation_time: 1.23 ns
max_navigation_time: 45.67 ns
min_navigation_time: 0.34 ns
Comment on lines +131 to +136
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the actual output?

```

In addition, the visualization of the data can help identify hotspots.

### Key metrics

**Mean navigation time** : Average time spent navigating to each point. Lower is
better.

**Max navigation time** : Slowest navigation time encountered. High values
indicate geometry hotspots.

**Standard deviation** : Variability in navigation time. High values suggest
non-uniform complexity.
Comment on lines +141 to +150
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be removed.


:::{warning}

Navigation times are relative and depend on the hardware. Focus on identifying
spatial patterns and relative differences between geometric components rather
than absolute timing values.

In addition, these statistics also depend on the ratio of empty space to actual
material. If one is not interested in potential slowdowns far away from the
object, one should choose a small enough buffer to reduce the impact of the
empty space.

:::

## Workflow examples

### Full detector benchmark

Benchmark an entire detector assembly with default settings:

```console
$ remage-geombench l1000.gdml --output-dir benchmarks/
```

### Component isolation

Test a specific problematic component:

```console
$ remage-geombench l1000.gdml --logical-volume V0101 \
--grid-increment 0.5 --output-dir component_tests/
```

This generates a `part_{logical-volume}.lh5` and
`part_{logical-volume}_[...].pdf` files in the output directory.

### Anisotropic sampling

For elongated geometries, use different grid spacing per dimension:

```console
$ remage-geombench l1000.gdml \
--grid-increments "{'x': 0.5, 'y': 0.5, 'z': 2.0}"
```

## Performance optimization tips

Based on benchmark results, consider these optimization strategies:

1. **Simplify boolean operations**: Multiple nested unions/subtractions are
expensive. Consider alternative representations.

2. **Reduce tessellated solid complexity**: Decrease facet count where possible
without losing essential features.

3. **Material boundaries**: Excessive material changes force more boundary
checks. Consolidate materials where physics allows.

4. **Envelope optimization**: Proper envelope volumes can accelerate navigation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you don't explain well what you mean here

in complex assemblies.

## Technical details

The benchmark uses the `GeomBench` generator, which systematically steps through
three 2D grids and measures median simulation time per grid point. The geometry
is automatically wrapped in a world volume sized to contain it with the
specified buffer fraction.

When extracting a specific logical volume, the tool:

1. Identifies the volume in the GDML registry
2. Copies all dependent resources (materials, solids, daughter volumes)
3. Creates a minimal world volume containing only the extracted component
4. Applies the buffer and generates a temporary GDML file for benchmarking

This allows testing individual components without the overhead of the full
geometry.

## See also

- {ref}`manual-geometry` – General geometry setup
- {ref}`manual-running` – Running simulations
- {ref}`manual-output` – Output data formats
1 change: 1 addition & 0 deletions docs/manual/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ install.md
containers.md
running.md
geometry.md
geombench.md
physicslist.md
confinement.md
generators.md
Expand Down
7 changes: 6 additions & 1 deletion docs/rmg-commands.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions include/RMGGeomBench.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (C) 2025 Moritz Neuberger <https://orcid.org/0009-0001-8471-9076>
#ifndef _RMG_GEOMBENCH_HH_
#define _RMG_GEOMBENCH_HH_

#include <chrono>
#include <memory>
#include <string>
#include <vector>

#include "CLHEP/Units/SystemOfUnits.h"
#include "G4AnalysisManager.hh"
#include "G4GenericMessenger.hh"
#include "G4LogicalVolume.hh"
#include "G4ParticleGun.hh"
#include "G4VPhysicalVolume.hh"

#include "RMGGeomBenchOutputScheme.hh"
#include "RMGVGenerator.hh"

namespace u = CLHEP;

class RMGGeomBench : public RMGVGenerator {

public:

RMGGeomBench();
~RMGGeomBench();

RMGGeomBench(RMGGeomBench const&) = delete;
RMGGeomBench& operator=(RMGGeomBench const&) = delete;
RMGGeomBench(RMGGeomBench&&) = delete;
RMGGeomBench& operator=(RMGGeomBench&&) = delete;

void GeneratePrimaries(G4Event* event) override;
void SetParticlePosition(G4ThreeVector) override{};
void RecordBatchTime(size_t pixel_idx, double batch_time);
void SaveAllPixels();

void BeginOfRunAction(const G4Run* r) override;
void EndOfRunAction(const G4Run* r) override;

private:

// Helper to find the benchmark output scheme if it's active
RMGGeomBenchOutputScheme* GetBenchmarkOutputScheme();

std::unique_ptr<G4ParticleGun> fGun = nullptr;

std::unique_ptr<G4GenericMessenger> fMessenger = nullptr;
void DefineCommands();

long totalnevents;
size_t totalnpixels;
int npixelsperrow;
int neventsperpixel;
double cubesize;

// Configurable sampling parameters (user-specified increments)
G4ThreeVector user_increment;
G4ThreeVector sampling_width;

// Calculated number of pixels based on increments and widths
size_t npixels_x;
size_t npixels_y;
size_t npixels_z;
size_t ID;

double starttime;
double currenttime;
double bunchstarttime;

// For tracking batches and calculating median
std::vector<std::vector<double>> pixel_batch_times; // One vector of batch times per pixel
int events_per_bunch;
int total_batch_rounds;
int current_batch_event;
int current_pixel_index;
int current_batch_round;

G4ThreeVector origin;
G4ThreeVector limit;
G4ThreeVector increment;
};

#endif
Loading
Loading