Skip to content

feat: optimization of the electron stacking#627

Merged
MoritzNeuberger merged 30 commits intolegend-exp:mainfrom
MoritzNeuberger:stack-volume
Apr 14, 2026
Merged

feat: optimization of the electron stacking#627
MoritzNeuberger merged 30 commits intolegend-exp:mainfrom
MoritzNeuberger:stack-volume

Conversation

@MoritzNeuberger
Copy link
Copy Markdown
Contributor

@MoritzNeuberger MoritzNeuberger commented Feb 18, 2026

This pull request introduces optimizations to the recently added stacking scheme for electron tracks in the bulk of volumes. It optimizes safety calculations using caching and bounding spheres, and allows filtering to only consider Germanium detectors for certain checks.

Updates to the User Commands

  • The /RMG/Output/VolumeStacker/ command group was adjusted. Instead of activating the filter for only a single volume, the user can add multiple volumes via the name AddVolumeName (register multiple volumes). In addition, the safety calculation can be adjusted to only consider the distances to HPGe detectors via DistanceCheckGermaniumOnly (limit checks to Germanium detectors).

Performance Improvements: Safety Calculation

  • Added an efficient is_within_surface_safety function that quickly determines if any surface is within a safety distance, with early exits and bounding sphere optimizations.
  • Introduced a caching mechanism (volume_cache and VolumeCache struct) for volume geometry data.
  • Introduced a simple precondition for the safety calculation via bounding spheres for daughter volumes, to speed up repeated distance checks.
  • Introduced option to only check safety distances to HPGe detectors (see update to user commands).
  • In case the safety is set to 0, the safety calculation is skipped, and all electrons in the volume are directly put on the waiting stack.

These changes were presented in an internal presentation on 26.01.2026 [link]. Since then, some more tests have been performed. The previous tests were run with the multithreading option, which turned out to distort the mean time per event, and systematic differences were introduced due to differences depending on when the simulations were run. Now the simulations are all run single-threaded and at the same time. The plot below shows the mean time per event for a Tl208 simulation in L1000 for different E_low thresholds and different configurations of safety compared to the optical photon stacking implementation and w/o optical physics.

image

A slight increase in the mean time per event for larger safeties is visible, but they are all still significantly smaller than with the only optical photon stacking.

EDIT: I realize that I probably should rebase the branch to the main repo. Will do that in a bit.

Copilot AI review requested due to automatic review settings February 18, 2026 08:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the electron/positron “bulk” stacking logic by replacing repeated full distance-to-surface calculations with a cached, early-exit safety-threshold check, and updates the /RMG/Output/VolumeStacker/ UI to support multiple volumes and optional Germanium-only distance checks.

Changes:

  • Add RMGOutputTools geometry caching (VolumeCache) and a new is_within_surface_safety() fast threshold check with bounding-sphere prechecks.
  • Update RMGVolumeDistanceStacker to support registering multiple volume names and to use the new safety-threshold API (with a safety==0 fast-path).
  • Register/document the new VolumeStacker commands in doc-dump and docs/rmg-commands.md.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/remage-doc-dump.cc Registers RMGVolumeDistanceStacker so its commands appear in generated command docs.
src/RMGVolumeDistanceStacker.cc Switches to multi-volume configuration and uses is_within_surface_safety() for faster stacking decisions.
src/RMGOutputTools.cc Implements global cache, cache builder, optimized distance checking, and Germanium-only filtering toggle.
include/RMGVolumeDistanceStacker.hh Updates stacker configuration API (multi-volume + Germanium-only toggle).
include/RMGOutputTools.hh Adds new APIs and exposes cache structs/config in the public header.
docs/rmg-commands.md Documents the new /RMG/Output/VolumeStacker/ command group and updated command names/options.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/RMGOutputTools.cc Outdated
Comment thread src/RMGOutputTools.cc
Comment thread include/RMGOutputTools.hh Outdated
Comment thread src/RMGOutputTools.cc Outdated
Comment thread include/RMGOutputTools.hh Outdated
@tdixon97
Copy link
Copy Markdown
Contributor

Very nice work Moritz, I will look in more detail later

Comment thread src/RMGOutputTools.cc
Comment thread src/RMGOutputTools.cc
@ManuelHu
Copy link
Copy Markdown
Contributor

I am not sure what is going on here, but the docs building cannot handle the G4ThreadLocals. I tried to push a fix for these.

Comment thread include/RMGOutputTools.hh Outdated
Comment thread include/RMGOutputTools.hh Outdated
ManuelHu and others added 3 commits February 18, 2026 20:16
…ed. This is to asure high energy electrons in showers to still produce expected results. Inspired by Eric.
@MoritzNeuberger
Copy link
Copy Markdown
Contributor Author

MoritzNeuberger commented Feb 19, 2026

Taking inspiration from Eric's implementation in his muon simulation, I added an energy threshold below which electrons are stacked. This ensures that high-energy electrons in showers still contribute. The default setting stacks all electrons, though one should test to see at what threshold it no longer influences muon showers and set it to that value.

EDIT: for that I added a new macro command of which I will update the docs momentarily.

@ManuelHu
Copy link
Copy Markdown
Contributor

something to keep in mind when somebody tests this in MT mode: I guess that the performance will be much lower (than single-threaded) because of the still existing MultiUnions in the L200 geometry. The global lock really is not that great. (the better option is however to get rid of the MultiUnions...)

@gipert gipert requested a review from tdixon97 March 16, 2026 13:46
@gipert
Copy link
Copy Markdown
Member

gipert commented Mar 16, 2026

how should we proceed with this? i admit the issue got quite complex and i personally lost track of what is going on. i would like to understand how much this is improving the situation, the thing i want to avoid is to have to maintain complex code that does not significantly help in the end

@tdixon97
Copy link
Copy Markdown
Contributor

My understanding is that this helps alot

@MoritzNeuberger
Copy link
Copy Markdown
Contributor Author

IMO, the PR is final. I wanted to test how useful it is for muon sims. @EricMEsch, since you implemented it in your simulations before, please have a look if anything is missing, and maybe also check if it has the speedup you expected in your simulations.

@gipert
Copy link
Copy Markdown
Member

gipert commented Mar 19, 2026

I'm happy to allocate some time during the next call to summarize and review the situation, if you'd like

Comment thread include/RMGEventAction.hh Outdated
Comment thread src/RMGOutputTools.cc Outdated
Comment thread src/RMGStackingAction.cc Outdated
@MoritzNeuberger
Copy link
Copy Markdown
Contributor Author

There was a presentation on 13.4.2026 for a status update on this PR [link].

A point of interest discussed was that the differences in the 511 keV line are likely due to positron stacking. I removed the functionality, and the agreement is now again better than before (see figures at the end of the post).

Plan for the PR:

  • refactor the implementation to clean up clutter accumulated over the long development time (including the above points)
  • implement tests to cover functionality and expectation in optimization / physics
  • write documentation detailing intended usage

A question I had was whether we should also do a "light refactor" of the staging condition logic. At the moment, it is necessary to set /RMG/Output/Germanium/DiscardPhotonsIfNoGermaniumEdep true so that electrons are also stacked. This is not straightforward nomenclature. Maybe use a consistent naming scheme, including /RMG/Output/IsotopeFilter/DiscardPhotonsIfIsotopeNotProduced? Maybe something like RegisterStagingCondition?

Before:
image

After:
image

@gipert
Copy link
Copy Markdown
Member

gipert commented Apr 14, 2026

I agree with changing command name but RegisterStagingCondition sounds too generic

I also think it's a good idea to ask the AI to simplify!

- Updated RMGGermaniumOutputScheme and RMGIsotopeFilterScheme to eliminate optical photon handling, delegating to RMGStagingScheme.
- Introduced RMGStagingScheme to manage staging of optical photons and electrons, allowing for deferred processing based on energy thresholds and volume safety.
- Removed RMGVolumeDistanceStacker and integrated its functionality into RMGStagingScheme.
- Updated tests to reflect changes in output schemes and ensure proper staging behavior for electrons and optical photons.
@MoritzNeuberger MoritzNeuberger merged commit 43dfcc0 into legend-exp:main Apr 14, 2026
4 of 7 checks passed
@MoritzNeuberger
Copy link
Copy Markdown
Contributor Author

MoritzNeuberger commented Apr 14, 2026

shit, didnt want to merge yet

EDIT: yes, I am aware that I pressed auto-merge ... I was convinced it was about rebasing to main ...

@MoritzNeuberger
Copy link
Copy Markdown
Contributor Author

Reverted the changes in main. I guess I have to make a new PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants