Learn how to associate information from distinct tables through index columns and index tables

Source: associatedExample.cxx
Executable: o2-analysistutorial-associated-derived

Index columns and index tables

Related information can be contained in different tables. And in order to associate this informations index columns and index tables are used.

ProduceEtaPhi, ProduceColExtra, and ConsumeEtaPhi

The tutorial example starts with the declaration and production of three tables, EtaPhi and CollisionsExtra, which are normal tables, and HMPIDTracksIndex, an index table.

The index table HMPIDTracksIndex contains for each row of table Tracks the row number of table HMPIDs with the related HMPID information.

DECLARE_SOA_INDEX_TABLE_USER(HMPIDTracksIndex, Tracks, "HMPIDTRKIDX", indices::TrackId, indices::HMPIDId);


In task ConsumeColExtra the basic usage of indices is demonstrated. Tracks are associated to collisions via the index column o2::aod::track::CollisionId (see the declaration of the Tracks table). Access to the collsion associated with a given track track0 is achieved with track0.collision_as<T>(), where T is a table including the Collisions table (see also tutorial [Creating Tables] (creatingTables.md#declaration-of-columns)). In the example case T is a Join of Collisions and CollisionsExtra.

struct ConsumeColExtra {
  // use collisions with > 10 tracks only
  using myCol = soa::Join<aod::Collisions, aod::CollisionsExtra>;
  expressions::Filter multfilter = aod::collision::mult > 10;

  // group tracks according to collision
  void process(soa::Filtered<myCol>::iterator const& col, aod::Tracks const& tracks)
    // get collision index and track multiplicity from the collisions ...
    LOGF(INFO, "[direct] ID: %d; %d == %d", col.globalIndex(), col.mult(), tracks.size());
    if (tracks.size() > 0) {
      // ... or through an associated track.
      auto track0 = tracks.begin();
      LOGF(INFO, "[index ] ID: %d; %d == %d", track0.collision_as<myCol>().globalIndex(), track0.collision_as<myCol>().mult(), tracks.size());


Index columns allow to easily select e.g. all tracks belonging to a given collision using the sliceBy() method (see also DECLARE_SOA_TABLE). groupedTracks contains only tracks which belong to Collision col.

auto groupedTracks = tracks.sliceBy(aod::track::collisionId, col.globalIndex());

BuildHmpidIndex and ConsumeHmpidIndex

Builds<T> is used to prepare an index column of type T. This has to be performed before the index table can be used. Note the declaration of the init() function without any content. This is needed to make the task complete (see minimum requirements for a task).

struct BuildHmpidIndex {
  // build the index table HMPIDTracksIndex
  Builds<aod::HMPIDTracksIndex> idx;
  void init(InitContext const&){};

In the following loop the index table is used to relate the information from the Tracks table with the related rows of the HMPID table. To check if a given track has related HMPID information the has_hmpid() method is applied. This returns true in case the HMPID information exists and the method hmpid() can be used to retrieve the associated row of the HMPIDs table.

for (auto& track : tracks) {
  // check weather given track has associated HMPID information
  if (track.has_hmpid()) {
    // access the HMIPD information associated with the actual track
    LOGF(INFO, "Track %d has HMPID info: %.2f", track.globalIndex(), track.hmpid().hmpidSignal());