Declaration and production of tables
Learn how to declare and produce new tables.
Executable: o2-analysistutorial-new-collections
Before we come to discussing the tutorial code a few general words about creating tables.
Declaration of tables
The first step in creating a table in O2 is to declare it, hence specify its name, some additional parameters, and it's basic components, the columns.
The O2 framework provides a few methods to declare tables in analysis tasks. See the list below. Click on the titles to display information about the arguments and the resulting tables.
All methods have a Name
and Description
argument. The argument Name is used to define the type of the table which is o2::aod::Name
. The Description argument is a string which is used within the framework to identify the table. It has a maximum length of 16 characters. Origin has to be set to "AOD".
Method | Type | |
---|---|---|
asArrowTable( ) | std::shared_ptr<arrow::Table> | Type erased arrow table. Allows to apply the full functionality of Apache arrow tables. |
getId<T> ( ) | ||
size ( ) or tableSize ( ) | int64_t | The number of rows the table contains. |
begin ( ) | First row. | |
iteratorAt ( uint64_t i) | ith row. | |
end ( ) | Last row. | |
select (framework::expressions::Filter&& f) | Rows of table for which filter f returns true. | |
scliceBy<T>(colId, int value) | Rows of table for which (colId == value) is true. colId is an index column. | |
Declaration of columns
Tables are basically collections of columns. The O2 framework provides the methods to declare columns, which are listed below. Click on the titles to display information about the arguments and the resulting columns.
Name
and Getter
are the common arguments of all methods. Name is used to
define the type of the column which is namespace::Name
where namespace is the
namespace the column is declared in. Getter is the method which allows to access
a column (tab.pt() e.g. gives access to an element of the column which was declared with a Getter value of pt).
Method | Type | |
---|---|---|
`Getter`( ) | `Type` | Column element. |
Method | Type | |
---|---|---|
`Getter`( ) | `Type` | Column element. |
Projector( ) | o2::framework::expressions::Projector | `Expression`. |
Method | Type | |
---|---|---|
`Getter`Id( ) | `Type` | Column element. |
has_`Getter`( ) | bool | True if the binding table is not a NULL pointer. |
`Getter`_as <T>( ) | auto | Respective row of (T*)binding table. T must include `Tables`s, hence can be e.g. a join including `Tables`s. |
`Getter`( ) | auto | Respective row of table `Tables`s. |
setCurrent <T>(T* t) | bool | Replace `Table`s by t as binding table. |
getCurrent( ) | `Table`s* | Binding table. |
Method | Type | |
---|---|---|
`Name`Callback | functor | The column lambda. |
`Getter`<T...>(T... t) | according to functor | Dynamic column element computed with input columns t. |
This tutorial demonstrates the creation and filling of normal tables. The usage of index tables is explained in tutorial Index Tables.
ProduceEtaPhi
In order to avoid naming conflicts between different tasks it is advisable to declare new columns in subspaces of the namespace o2::aod and the new tables in namespace o2::aod.
// declare columns in a sub-namespace of o2::aod
// and tables in namespace o2::aod
namespace o2::aod
{
namespace etaphi
{
DECLARE_SOA_COLUMN(Eta, eta, float);
DECLARE_SOA_COLUMN(Phi, phi, float);
} // namespace etaphi
DECLARE_SOA_TABLE(EtaPhi, "AOD", "ETAPHI",
etaphi::Eta, etaphi::Phi);
} // namespace o2::aod
Now that the table is declared we can use it to create a corresponding table object. This happens with the Produces class. Produces is a templated class and takes the type of the table to create as template argument. The table type in this case is aod::EtaPhi and the actual table object is etaphi.
The filling of the table etaphi is done with the method (… ) which takes as many arguments as columns are available.
struct ProduceEtaPhi {
// declare production of table etaphi
Produces<aod::EtaPhi> etaphi;
void process(aod::Tracks const& tracks)
{
for (auto& track : tracks) {
float phi = asin(track.snp()) + track.alpha() + static_cast<float>(M_PI);
float eta = log(tan(0.25f * static_cast<float>(M_PI) - 0.5f * atan(track.tgl())));
// update the table etaphi
etaphi(phi, eta);
}
}
};
ConsumeEtaPhi and LoopEtaPhi
Within all tasks of a workflow the such created and filled table is available and hence can be use for further calculations. This is demonstrated with the tasks ConsumeEtaPhi and LoopEtaPhi of this tutorial.