Event Mixing
Obtain mixed event tuples.
Executable: o2-analysistutorial-event-mixing
For a general introduction to combinations and event mixing, check first here.
MixedEvents
Firstly, we define slice cache and binning of collisions for block combinations:
SliceCache cache;
std::vector<double> xBins{VARIABLE_WIDTH, -0.064, -0.062, -0.060, 0.066, 0.068, 0.070, 0.072};
std::vector<double> yBins{VARIABLE_WIDTH, -0.320, -0.301, -0.300, 0.330, 0.340, 0.350, 0.360};
using BinningType = BinningPolicy<aod::collision::PosX, aod::collision::PosY>;
BinningType binningOnPositions{{xBins, yBins}, true}; // true is for 'ignore overflows' (true by default)
Then, we define the mixing structure itself:
SameKindPair<aod::Collisions, aod::Tracks, BinningType> pair{binningOnPositions, 5, -1, &cache}; // indicates that 5 events should be mixed and under/overflow (-1) to be ignored
In this case, only table types and the binning police type need to be passed, as the rest is taken from the defaults.
Then, inside your process()
function, you can directly iterate over mixed event pairs together with two separate track tables which contain tracks from the two different collision in the pair:
for (auto& [c1, tracks1, c2, tracks2] : pair) {
LOGF(info, "Mixed event collisions: (%d, %d)", c1.globalIndex(), c2.globalIndex());
}
You might want, for example, to further iterate over the track tables inside the mixing loop:
for (auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) {
LOGF(info, "Mixed event tracks pair: (%d, %d) from events (%d, %d)", t1.index(), t2.index(), c1.index(), c2.index());
}
MixedEventsInsideProcess
This is the same task as above, with the difference that binning policy and SameKindPair
are declared inside process()
. This is particularly helpful when your bins are ConfigurableAxes. The standard out-of-process declaration of binning policy and corresponding mixing structure would take only default configurable values.
Tasks with different table structures
These tasks demonstrate how mixing works with Filtered and Join.
MixedEventsDynamicColumns
This is a more realistic example with mixing of collisions binned by z-vertex and multiplicity V0M. As MultFV0M
is a dynamic column, its type is templated on the contributing column types. Therefore, the binning policy type is:
using BinningType = BinningPolicy<aod::collision::PosZ, aod::mult::MultFV0M<aod::mult::MultFV0A, aod::mult::MultFV0C>>;
The rest of the task is the same as in the basic example.
Tasks with different table kinds
These tasks demonstrate usage of Pair
, Triple
and SameKindTriple
on tracks and V0s.
MixedEventsWithHashTask
This task shows how one can use NoBinningPolicy
in case of bins predefined somewhere else.
MixedEventsPartitionedTracks
This is a bit more advanced example which shows how one can further partition the tracks from mixing. As the tracks tables are produced only at the generation of each mixed collision pair, Partitions
must be declared inside the mixing loop. Additionally, each partition must be bound to a respective table – tracks1
or tracks2
. Then, the corresponding partitioning condition is applied to the selected table.
for (auto& [c1, tracks1, c2, tracks2] : pair) {
Partition<myTracks> leftPhi1 = aod::track::phi < philow;
Partition<myTracks> leftPhi2 = aod::track::phi < philow;
Partition<myTracks> rightPhi1 = aod::track::phi >= phiup;
Partition<myTracks> rightPhi2 = aod::track::phi >= phiup;
leftPhi1.bindTable(tracks1);
leftPhi2.bindTable(tracks2);
rightPhi1.bindTable(tracks1);
rightPhi2.bindTable(tracks2);
}
MixedEventsLambdaBinning
The task demonstrates how to use FlexibleBinningPolicy if binning cannot be calculated straight from the collision columns, but is obtained from other variables in a user-defined function.
This is naturally implemented for mixing inside process()
, as the helper lambda function is usually defined inside process()
. For example:
void process(aod::Collisions& collisions, aod::Tracks& tracks) {
auto getTracksSize =
[&tracks, this](aod::Collision const& col) {
auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, col.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once
return associatedTracks.size();
};
The binning policy:
using BinningType = FlexibleBinningPolicy<std::tuple<decltype(getTracksSize)>, aod::collision::PosZ, decltype(getTracksSize)>;
BinningType binningWithLambda{{getTracksSize}, {axisVertex, axisMultiplicity}, true};
A tuple with types of all lambda functions must be first passed in the BinningType
definition, before the rest of arguments follow in the order of usage.
Similarly, in binningWithLambda
definition, one must first pass a tuple with all lambda functions before other arguments.
Note that binning with respect to z-vertex is calculated from column values as before, while the lambda is used only for the multiplicity axis. You must be careful to follow the same order of columns/lambdas in the BinningType
definition and of the corresponding axes in binning instantation.
Any combination of lambda- and column-based binning is possible.
Finally, the mixing structure is defined like in previous examples:
SameKindPair<aod::Collisions, aod::Tracks, BinningType> pair{binningWithLambda, 5, -1, collisions, tracksTuple, &cache};