Skip to content

[Common,DPG] add occupancy wrt bunch crossings (tables BcOccs, BcOccsAll) - #18689

Merged
altsybee merged 14 commits into
AliceO2Group:masterfrom
altsybee:master
Nov 12, 2026
Merged

altsybee merged 14 commits into
AliceO2Group:masterfrom
altsybee:master

Conversation

@altsybee

@altsybee altsybee commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Occupancy wrt bunch crossings: tables BcOccs and BcOccsAll

Refactored OccupancyCalculator

  • simpler interfaces for calculateForCollision() and calculateForBC()
  • no change in EvSels: the per-collision results remain bit-identical. Also, nothing changes for the users who use existing machinery.

Occupancy wrt BCs

Same estimators, time window, thresholds and median time as in EvSels, but calculated wrt a BC instead of a collision.

Two tables added to Common/DataModel/EventSelection.h, both produced by o2-analysis-event-selection-service:

  • BcOccs, joinable with aod::BCs: one row per BC of the BC table.
    • Configurables: bcoccOpts.amIneeded (-1 auto, 0 no, 1 yes) and bcoccOpts.bcsForOccupancy (0 - all BCs stored in AO2D tables, 1 - BCs with FT0, 2 - TVX, 3 - colliding; other BCs get -1).
  • BcOccsAll, not joinable: every BC of the TFs present in the DF, including BCs without an entry in aod::BCs (e.g. for UPC studies). Rows are in increasing order of global BC, with the column globalBC().
    • Configurables: bcoccAllOpts.amIneeded and bcoccAllOpts.bcsForOccupancy (0 - all BCs in TFs, also BCs not stored in AO2D, 1 - colliding BCs).
    • The table is large: one row per BC, i.e. 114048 rows per 32-orbit TF. Request it only when needed.
    • It has no rows if the occupancy inputs are not available (e.g. unanchored MC).

With the default amIneeded = -1, each table is produced only when a task subscribes to it. The BC and event selection, which provide the inputs, are then switched on automatically.

Differences from the collision-level values:

  • all collisions found in the BC are excluded (counted in numCollsInBC), while for a per-collision occupancy calculation, only the collision itself is excluded: other collisions in the same BC are included;
  • no vZ available for BCs, so the close-vZ veto in kNoCollInRofStandard is not applied (only the FT0C-multiplicity condition);
  • occupancy flags are stored in a separate 8-bit bitmap (aod::bcocc::BcOccupancyFlags; bit numbers differ from aod::evsel);
  • BCs not selected by the condition in the configurable bcsForOccupancy get occupancy -1 and all occupancy flags 0 (kUpcMode is filled for all BCs).
getter meaning
trackOccupancyInTimeRange() occupancy by ITS tracks (-1 if not available, e.g. near TF borders or BC not selected)
ft0cOccupancyInTimeRange() occupancy by FT0C amplitudes (-1 if not available)
occupancyMedianTime() median time of the occupancy
occupancyFlags_bit(bit) kNoCollInTimeRangeNarrow/Strict/Standard, kNoCollInRofStrict/Standard, kNoHighMultCollInPrevRof, kUpcMode (enum BcOccupancyFlags, one 8-bit bitmap)
occupancyFlags_bit(kUpcMode) the ITS ROF of this BC is in UPC mode (see below)
numCollsInBC() number of collisions found in this BC
numCollsInRof() number of collisions found in the ITS ROF of this BC (within the TF), including those in this BC; -1 if the ROF parameters are not available (e.g. unanchored MC)

kUpcMode (for UPC studies): tells whether the ITS ROF containing this BC was reconstructed in the UPC mode.

  • Per collision, the UPC mode of the ITS reconstruction is stored in the vertex flags: (collision.flags() & Vertex::Flags::UPCMode) != 0. A BC has no such flag, so it is taken from the collisions in its ITS ROF:
    • set if at least one collision in the ROF was reconstructed in the UPC mode;
    • also set if the ROF has no collisions (numCollsInRof() == 0): for such BCs we also artificially assign an "effective UPC mode" (useful in UPC analyses).
  • Collisions are assigned to ROFs by their found BC (same ROF definition as for numCollsInRof() and the in-ROF vetoes).
  • Filled for all BCs, also for BCs without calculated occupancy
  • N.B.: the AO2D table aod::BCFlags (bit bc::ITSUPCMode) has a similar per-BC flag, taken directly from the ITS ROF records, but only for the BCs stored in aod::BCs.

Usage

// occupancy for BCs of the BC table
void process(soa::Join<aod::BCs, aod::BcOccs> const& bcs)
{
  for (const auto& bc : bcs) {
    if (bc.trackOccupancyInTimeRange() < 0) {
      continue; // not available
    }
    bool noCollInTimeRange = bc.occupancyFlags_bit(aod::bcocc::kNoCollInTimeRangeStandard);
  }
}

// occupancy for any BC of the TFs in the DF: O(1) lookup by global BC, no search and no CCDB needed
void process(aod::BCs const& bcs, aod::BcOccsAll const& bcOccsAll)
{
  aod::bcocc::BcOccAllIndex bcOccAllIndexed(bcOccsAll); // built once per DF
  for (const auto& bc : bcs) {
    if (!bcOccAllIndexed.contains(bc.globalBC())) {
      continue; // operator[] is fatal for a BC that is not in the table
    }
    auto occ = bcOccAllIndexed[bc.globalBC()]; // iterator of aod::BcOccsAll
    int occByTracks = occ.trackOccupancyInTimeRange();
    bool isUpcModeRof = bc.occupancyFlags_bit(aod::bcocc::kUpcMode);
  }
}

QA:

  • A macro DPG/Tasks/AOTEvent/bcOccupancyQa.cxx (o2-analysis-bc-occupancy-qa)
  • Three process functions (all on by default; they switch on the subscribed tables in the event selection service: o2-analysis-event-selection-service | o2-analysis-bc-occupancy-qa):
    • processBcOccsAll: QA of BcOccsAll, with the cross-check of BcOccAllIndex;
    • processBcOccs: QA of BcOccs (joined with aod::BCs);
    • processBcOccsVsBcOccsAll: for the BCs of aod::BCs, BcOccs is compared with the BcOccsAll entry of the same BC (found with BcOccAllIndex): the values should be identical.
  • Macro DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C reads AnalysisResults.root, prints a summary and writes a multi-page PDF and to a .root file:
    root -l -b -q 'plotBcOccupancyQa.C("AnalysisResults.root")'

Example QA:

image image

@github-actions github-actions Bot changed the title add occupancy wrt bunch crossings (tables BcOccs, BcOccsAll) [Common,DPG] add occupancy wrt bunch crossings (tables BcOccs, BcOccsAll) Nov 11, 2026
@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

O2 linter results: ❌ 0 errors, ⚠️ 9 warnings, 🔕 68 disabled

@alibuild

Copy link
Copy Markdown
Collaborator

Error while checking build/O2Physics/code-check for 4abc96e at 2026-11-11 15:00:

## sw/BUILD/O2Physics-code-check-latest/log
--
========== List of issues found ==========
++ echo 'To reproduce the results below locally, run: '\''aliBuild build O2Physics-code-check -e ALIBUILD_BASE_HASH=upstream/master'\''.'
To reproduce the results below locally, run: 'aliBuild build O2Physics-code-check -e ALIBUILD_BASE_HASH=upstream/master'.
++ echo 'To apply all automatic fixes, add the '\''-e O2PHYSICS_CHECKER_FIX=1'\'' option.'
To apply all automatic fixes, add the '-e O2PHYSICS_CHECKER_FIX=1' option.
++ echo 'See the documentation for more details at: <https://aliceo2group.github.io/analysis-framework/docs/tools/#running-with-o2physics-code-check>.'
See the documentation for more details at: <https://aliceo2group.github.io/analysis-framework/docs/tools/#running-with-o2physics-code-check>.
++ echo 'Found 14 errors and 105 warnings.'
Found 14 errors and 105 warnings.
++ [[ 14 -gt 0 ]]
++ cat /sw/BUILD/5e7da1300e694c5285ad7fb08fc85d5c9d4c03eb/O2Physics-code-check/errors.txt
DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:132:33: error: redundant explicit casting to the same type 'int64_t' (aka 'long') as the sub-expression, remove this casting [readability-redundant-casting,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:36:1: error: included header string is not used directly [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:50:49: error: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:71:13: error: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:95:21: error: no header providing "kFALSE" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:97:22: error: no header providing "kViridis" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:220:24: error: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:27: error: no header providing "kRed" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:37: error: no header providing "kOrange" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:50: error: no header providing "kGreen" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:62: error: no header providing "kAzure" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:74: error: no header providing "kBlue" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:85: error: no header providing "kMagenta" is directly included [misc-include-cleaner,-warnings-as-errors]
DPG/Tasks/AOTEvent/macros/plotBcOccupancyQa.C:234:99: error: no header providing "kBlack" is directly included [misc-include-cleaner,-warnings-as-errors]
++ [[ 105 -gt 0 ]]
++ cat /sw/BUILD/5e7da1300e694c5285ad7fb08fc85d5c9d4c03eb/O2Physics-code-check/warnings.txt
Common/DataModel/EventSelection.h:148:11: warning: use auto when initializing with a cast to avoid duplicating the type name [modernize-use-auto]
Common/DataModel/EventSelection.h:169:3: warning: function 'contains' should be marked [[nodiscard]] [modernize-use-nodiscard]
Common/DataModel/EventSelection.h:173:3: warning: function 'rowOf' should be marked [[nodiscard]] [modernize-use-nodiscard]
Common/TableProducer/eventSelectionService.cxx:40:34: warning: variable 'metadataInfo' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]
Common/TableProducer/eventSelectionService.cxx:47:8: warning: constructor does not initialize these fields: ccdb [cppcoreguidelines-pro-type-member-init]
Common/TableProducer/eventSelectionService.cxx:106:8: warning: constructor does not initialize these fields: ccdb [cppcoreguidelines-pro-type-member-init]
Common/TableProducer/eventSelectionService.cxx:184:55: warning: redundant boolean literal supplied to boolean operator [readability-simplify-boolean-expr]
Common/TableProducer/eventSelectionService.cxx:197:5: warning: do not use 'else' after 'return' [readability-else-after-return]
Common/TableProducer/eventSelectionService.cxx:201:7: warning: do not use 'else' after 'return' [readability-else-after-return]
Common/Tools/EventSelectionModule.h:61:9: warning: function-like macro 'BITCHECK' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
Common/Tools/EventSelectionModule.h:62:9: warning: function-like macro 'BITCHECK64' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
Common/Tools/EventSelectionModule.h:67:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
Common/Tools/EventSelectionModule.h:153:3: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
Common/Tools/EventSelectionModule.h:174:15: warning: redundant string initialization [readability-redundant-string-init]
Common/Tools/EventSelectionModule.h:175:15: warning: redundant string initialization [readability-redundant-string-init]
Common/Tools/EventSelectionModule.h:374:20: warning: boolean expression can be simplified by DeMorgan's theorem [readability-simplify-boolean-expr]
Common/Tools/EventSelectionModule.h:375:20: warning: boolean expression can be simplified by DeMorgan's theorem [readability-simplify-boolean-expr]
Common/Tools/EventSelectionModule.h:376:20: warning: boolean expression can be simplified by DeMorgan's theorem [readability-simplify-boolean-expr]
Common/Tools/EventSelectionModule.h:377:20: warning: boolean expression can be simplified by DeMorgan's theorem [readability-simplify-boolean-expr]
Common/Tools/EventSelectionModule.h:382:20: warning: boolean expression can be simplified by DeMorgan's theorem [readability-simplify-boolean-expr]
[0 more errors; see full log]

Full log here.

@alibuild

Copy link
Copy Markdown
Collaborator

Error while checking build/O2Physics/o2 for 2c46716 at 2026-11-11 16:52:

## sw/BUILD/O2Physics-latest/log
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:76: error: 'const struct o2::soa::Table<o2::aod::Hash<519320931>, o2::aod::Hash<1837103245>, o2::aod::Hash<519320931>, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Join<o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:103: error: 'const struct o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
ninja: build stopped: subcommand failed.

Full log here.

@alibuild

Copy link
Copy Markdown
Collaborator

Error while checking build/O2Physics/code-check for 2c46716 at 2026-11-11 16:54:

## sw/BUILD/O2Physics-latest/log
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:76: error: 'const struct o2::soa::Table<o2::aod::Hash<519320931>, o2::aod::Hash<1837103245>, o2::aod::Hash<519320931>, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Join<o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:103: error: 'const struct o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
ninja: build stopped: subcommand failed.

Full log here.

@alibuild

Copy link
Copy Markdown
Collaborator

Error while checking build/O2Physics/staging for 2c46716 at 2026-11-11 17:08:

## sw/BUILD/O2Physics-latest/log
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:76: error: 'const struct o2::soa::Table<o2::aod::Hash<519320931>, o2::aod::Hash<1837103245>, o2::aod::Hash<519320931>, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Join<o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >, o2::soa::Table<o2::aod::Hash<1088132446>, o2::aod::Hash<558318692>, o2::aod::Hash<2286545062> >, o2::soa::Table<o2::aod::Hash<603595433>, o2::aod::Hash<3526344959>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
/sw/SOURCES/O2Physics/slc9_x86-64-slc9_x86-64/0/DPG/Tasks/AOTEvent/bcOccupancyQa.cxx:270:103: error: 'const struct o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> >::TableIteratorBase<o2::soa::DefaultIndexPolicy, o2::soa::Table<o2::aod::Hash<791022803>, o2::aod::Hash<1801235799>, o2::aod::Hash<2286545062> > >' has no member named 'occupancyFlags'; did you mean 'OccupancyFlags'?
ninja: build stopped: subcommand failed.

Full log here.

@vkucera vkucera closed this Nov 12, 2026
@vkucera vkucera reopened this Nov 12, 2026
@altsybee
altsybee enabled auto-merge (squash) November 12, 2026 12:31

@alibuild alibuild left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Auto-approving on behalf of @altsybee.

@altsybee
altsybee merged commit d037a9e into AliceO2Group:master Nov 12, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

4 participants