Skip to content
Jan Mayer edited this page Aug 17, 2021 · 1 revision

Tasks in R3BRoot

Tasks in R3BRoot take event-based data, and transform it into new data or fill Histogramms. They can also read and save and parameters from parameter (par) files. Tasks can be chained, i.e., the output of one task is available in the next.

All tasks are all derived from FairTask, which in turn is derived from TTask.

Creating Tasks in R3BRoot

Creating a Task from scratch

Start with thinking more closely about what the task is supposed to do, and derive the Class and File names from this.

Remember not to pack a task too full - just because you can transform data and fill histograms at the same time doesn't always make it a good idea. A task should have a clearly defined and delimited purpose. This is well supported by the naming convention, e.g. Cal2Hit.

Here, we take some As from the Detector detector as input and create Bs, thus the name, including the R3B prefix, is R3BDetectorA2B. The detector named detector does not exist, obviously. To follow this example, use any existing detector you like.

To start: In the /detector/ directory, create R3BDetectorA2B.h:

#ifndef R3BDETECTORA2B_H
#define R3BDETECTORA2B_H

#include "FairTask.h"

class R3BDetectorA2B : public FairTask
{
  public:
    R3BDetectorA2B() = default;
    ~R3BDetectorA2B() override = default;

    ClassDefOverride(R3BDetectorA2B, 1);
};

#endif

Also create R3BDetectorA2B.cxx:

#include "R3BDetectorA2B.h"

ClassImp(R3BDetectorA2B);

Add these to the respective CMakeLists.txt and DetectorLinkDef.h files, and it should compile. (Use the compile script or your IDE!)

Make sure you have run . build/config.sh at least once in your shell, and run root -l. In ROOT, you should be able to create the task:

root [0] task = R3BDetectorA2B();
root [1] task
(R3BDetectorA2B &) Name:  Title:
root [2]

Congratulations, you have just created a task that does absolutely nothing!

Adding functionality to the Task

Now, you implement the functions you need in your Task - and only these.

There are tons of very similar functions declared in FairTask.h. I can't tell you what most of them are good for - and have never needed them. Some also effectively do the same thing and are just named differently.

You only need:

  • The Constructor (In the minimal case without any attributes = default. In particular, you do not need the useless name and verbose!)
  • The Destructor (In the minimal case = default)
  • Init(), which is called once at the beginning, mostly to establish the connection to the data source and to make histograms ready.
  • Exec(), which is executed for each event.

and optionally, if needed

  • Finish(), mostly to output aggregated data and save histograms.
  • SetParContainers(), if parameters are needed.

Note: In the past, poorly thought out and poorly implemented templates have been copied too often - by people who don't know C++ or just code it to the "barely works" state, when that should be only the first step. Remember:

  • If you don't need a function, e.g., SetParContainers(), leave it out!
  • Remove unnecessary comments! We know that Init() does the initialization. Code is self-documenting to a degree!
  • Do comment on: What is this whole task supposed to do and what is needed for the task to work? Also, comment code that uses special tricks, works only in this configuration, uses workarounds, or is otherwise hard to understand.

One of the smallest working examples is R3BNeulandClusterFinder: Here, only Init and Exec are used. Both the annoying input-output connection and the logic itself is outsourced, so the implementation gets by with few lines. A more detailed example with TClonesArrays is R3BNeulandMapped2Cal - it's not good, but not terrible either.

Committing your code and pushing it to the repository

Running git status should look like this:

On branch dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   detector/CMakeLists.txt
        modified:   detector/DetectorLinkDef.h

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        detector/R3BDetectorA2B.cxx
        detector/R3BDetectorA2B.h

no changes added to commit (use "git add" and/or "git commit -a")

Run the code formatting tool on the C++ files and then add them to the commit in a new branch:

clang-format -i detector/R3BDetectorA2B.cxx detector/R3BDetectorA2B.h
git checkout -b detectora2b
git add detector/*

git status should now show:

On branch detectora2b
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   detector/CMakeLists.txt
        modified:   detector/DetectorLinkDef.h
        new file:   detector/R3BDetectorA2B.cxx
        new file:   detector/R3BDetectorA2B.h

Now, you can commit them.

git commit -m "Add A2B for Detector"

Once you finished development, rebase to the main repo and push to your GitHub fork. Note that it is encouraged that you squash individual commits into one while rebasing.

git fetch origin
git rebase -i origin
git push mine detectora2b