Skip to content

Fix instabilities when we have empty timeframes due low interaction rate - #15705

Open
sawenzel wants to merge 6 commits into
AliceO2Group:devfrom
sawenzel:sawenzel/colcontext-empty-tf
Open

Fix instabilities when we have empty timeframes due low interaction rate#15705
sawenzel wants to merge 6 commits into
AliceO2Group:devfrom
sawenzel:sawenzel/colcontext-empty-tf

Conversation

@sawenzel

Copy link
Copy Markdown
Collaborator

Fixes problems with empty timeframe handling in

  • collision context
  • tpc loopers
  • mch digitizer

sawenzel and others added 4 commits September 20, 2026 06:49
This fixes a problem in the timeframe index structure of the collision
context and adds a unit test.

- getTimeFrameBoundaries closed only one timeframe per collision, so a
  timeframe without collisions was left out of the index structure
  entirely and the collisions after it were assigned to the wrong
  timeframe.
- The number of extracted per-timeframe contexts was therefore the number
  of non-empty timeframes, not the number of timeframes asked for, and
  the last tf<N>/collisioncontext.root could be missing.
- The scan now closes every timeframe a collision skips over and pads the
  result to the number of timeframes the caller asks for, so entry i always
  describes orbits [start + i*orbitsPerTF, start + (i+1)*orbitsPerTF).
- applyMaxCollisionFilter keeps an empty timeframe empty when it re-indexes,
  and extractSingleTimeframe returns a valid empty context for it.
- o2-steer-colcontexttool passes the number of timeframes it asked for,
  reports timeframes that came out empty together with the mean number of
  collisions per timeframe implied by the interaction rate, and refuses to
  continue when --noEmptyTF was requested.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This fixes a problem in GenTPCLoopers::setFlatGas when the collision
context of a timeframe is empty.

- A timeframe holds no collision whenever the interaction rate is low
  enough, and the generator called exit(1) on it.
- The extent of the timeframe now comes from HBFUtils in that case, which
  is where it is defined, instead of from the last collision.
- With a single collision in the timeframe the mean interaction spacing
  was divided by zero; it is now taken from the interaction rate stored in
  the collision context.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This fixes a segmentation fault in MCHDPLDigitizerTask when the collision
context of a timeframe is empty.

- The noise-only signal range was taken from eventRecords.front() and
  eventRecords.back(), which is undefined behaviour on an empty vector.
- A timeframe holds no collision whenever the interaction rate is low.
- The range now comes from HBFUtils in that case, so the noise covers the
  timeframe that is actually being digitised.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This fixes a crash in the ITS, MFT, MCH and MID digit readers when the digit
tree of a timeframe has no entry.

- A timeframe holds no collision at all whenever the interaction rate is low
  enough, and the digitiser then writes a valid tree with zero entries.
- The ITS/MFT reader guarded this with an assert, which is compiled out of
  every production build because ENABLE_CASSERT defaults to OFF, and then
  dereferenced branch addresses that GetEntry had not filled.
- The MCH and MID readers threw on the failed TTreeReader::Next().
- All four now send empty output and end the stream.
- The two asserts in the ITS/MFT connectTree become real errors for the same
  reason.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sawenzel and others added 2 commits September 20, 2026 09:41
This replaces a disabled assert with a real check in 36 ROOT-tree reader
specs, so that a timeframe whose tree has no entry ends the stream instead
of reading past the end.

- Every one of them carried the same two lines: assert(ent <
  mTree->GetEntries()) with the comment "this should not happen", followed
  by mTree->GetEntry(ent).
- ENABLE_CASSERT defaults to OFF, so the assert is compiled out of every
  production build and the reader then publishes branch addresses that
  GetEntry never filled.
- A timeframe holds no collision whenever the interaction rate is low
  enough, which is when the trees come out empty.
- The readers now end the stream, which the consumers downstream already
  handle.
- Detectors/Upgrades/ALICE3/IOTOF is left alone: it has no ControlService.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This fixes the TPC digit writer producing a file without a tree when a
timeframe holds no collision.

- The custom close callback only called TFile::Close inside "if (entries >
  0)", and never called TFile::Write, so with nothing to write the tree
  never reached the file.
- The result was a 942 byte file with no o2sim tree, and every reader of it
  failed on a missing branch rather than on an empty tree.
- Each branch is now filled once with the empty default object it is bound
  to, so the file is an ordinary timeframe that happens to contain no digit
  and the readers downstream stay on their normal path.
- The tree is written explicitly, the way RootTreeWriter's own close does.

https://its.cern.ch/jira/browse/O2-7132

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant