@@ -82,6 +82,7 @@ void GateDigitizerPileupActor::BeginOfRunActionMasterThread(int run_id) {
8282 outputIter.TrackAttribute (" PreStepUniqueVolumeID" , &fTimeSorterOutputVolID );
8383
8484 fVolumePileupWindows .clear ();
85+ fWindowExpiry = std::queue<volumeWindowExpiry>();
8586}
8687
8788void GateDigitizerPileupActor::SetGroupVolumeDepth (const int depth) {
@@ -111,8 +112,12 @@ void GateDigitizerPileupActor::EndOfRunAction(const G4Run *) {
111112 [this ]() { fOutputDigiCollection ->FillToRootIfNeeded (true ); },
112113 [this ]() {
113114 ProcessTimeSortedDigis ();
114- for (auto &[_vol_hash, window] : fVolumePileupWindows ) {
115+ // Process all pile-up windows which still have an expiry item.
116+ while (fWindowExpiry .size () > 0 ) {
117+ auto &window =
118+ fVolumePileupWindows .at (fWindowExpiry .front ().volumeHash );
115119 ProcessPileupWindow (window);
120+ fWindowExpiry .pop ();
116121 }
117122 });
118123}
@@ -134,6 +139,7 @@ GateDigitizerPileupActor::GetPileupWindowForCurrentVolume(
134139 } else {
135140 // A PileupWindow object does not yet exist for this volume: create one.
136141 PileupWindow window;
142+ window.hash = vol_hash;
137143 const auto vol_id = volume->get ()->GetIdUpToDepth (fGroupVolumeDepth );
138144 // Create a GateDigiCollection for this volume, as a temporary storage for
139145 // digis that belong to the same time window (the name must be unique).
@@ -179,31 +185,40 @@ void GateDigitizerPileupActor::ProcessTimeSortedDigis() {
179185
180186 const auto current_time = *fTimeSorterOutputTime ;
181187 const auto current_edep = *fTimeSorterOutputEdep ;
188+
189+ // The GlobalTime of digis provided by the time sorter are guaranteed to be
190+ // monotonically increasing. As a consequence, all pile-up windows that have
191+ // expired by the time of the most recently arrived digi can be handled.
192+ ProcessPileupWindows (current_time);
193+
182194 if (window.digis ->GetSize () == 0 ) {
183- // The window has no digis yet: make the window start at the time of the
184- // current digi and remember the current edep as highest.
185- window.startTime = current_time;
186- window.highestEdep = current_edep;
187- } else if (current_time - window.startTime > fTimeWindow ) {
188- // The current digi is beyond the time window: process the digis that are
189- // currently in the window, then make the window start at the time of the
190- // current digi and remember the current edep as highest.
191- ProcessPileupWindow (window);
195+ // The window was empty: the newly arrived digi will open it.
192196 window.startTime = current_time;
197+ fWindowExpiry .push ({window.hash , window.startTime + fTimeWindow });
193198 window.highestEdep = current_edep;
194- }
195-
196- if (fTimeWindowPolicy == TimeWindowPolicy::Paralyzable) {
197- // In Paralyzable mode, extend the time window to start at the time of
198- // the current digi.
199- window.startTime = current_time;
200- } else if (fTimeWindowPolicy == TimeWindowPolicy::EnergyWinnerParalyzable) {
201- // In EnergyWinnerParalyzable mode, extend the time window only if
202- // the current digi has higher energy than the highest-energy
203- // digi so far.
204- if (current_edep > window.highestEdep ) {
199+ } else {
200+ // The window was already opened: update the window depending on the
201+ // policy.
202+ switch (fTimeWindowPolicy ) {
203+ case TimeWindowPolicy::NonParalyzable:
204+ // window start time remains the same.
205+ break ;
206+ case TimeWindowPolicy::Paralyzable:
207+ // The current digi moves the start time forward.
205208 window.startTime = current_time;
206- window.highestEdep = current_edep;
209+ fWindowExpiry .push ({window.hash , window.startTime + fTimeWindow });
210+ break ;
211+ case TimeWindowPolicy::EnergyWinnerParalyzable:
212+ // The current digi moves the start time forward if its energy is higher
213+ // than previous energies.
214+ if (current_edep > window.highestEdep ) {
215+ window.startTime = current_time;
216+ fWindowExpiry .push ({window.hash , window.startTime + fTimeWindow });
217+ window.highestEdep = current_edep;
218+ }
219+ break ;
220+ default :
221+ Fatal (" Unknown time window policy" );
207222 }
208223 }
209224
@@ -226,6 +241,10 @@ void GateDigitizerPileupActor::ProcessPileupWindow(PileupWindow &window) {
226241 G4ThreeVector weighted_position;
227242 G4ThreeVector highest_edep_position;
228243
244+ if (window.digis ->GetSize () == 0 ) {
245+ return ;
246+ }
247+
229248 // Iterate over all digis in the window from the beginning.
230249 auto &iter = window.digiIter ;
231250 iter.GoToBegin ();
@@ -286,3 +305,18 @@ void GateDigitizerPileupActor::ProcessPileupWindow(PileupWindow &window) {
286305 // Remove all processed digis from the window.
287306 window.digis ->Clear ();
288307}
308+
309+ void GateDigitizerPileupActor::ProcessPileupWindows (double currentTime) {
310+
311+ // Process the expiry items for which the expiry time is before currentTime.
312+ while (fWindowExpiry .size () > 0 &&
313+ currentTime > fWindowExpiry .front ().expiryTime ) {
314+ auto &window = fVolumePileupWindows .at (fWindowExpiry .front ().volumeHash );
315+ // Check again whether the window is actually expired, because its expiry
316+ // time may have been updated in a later expiry item.
317+ if (currentTime > window.startTime + fTimeWindow ) {
318+ ProcessPileupWindow (window);
319+ }
320+ fWindowExpiry .pop ();
321+ }
322+ }
0 commit comments