3. Analysis in a Task

In order to run all the stuff from above as a compiled !FairTask instead of an interpreted ROOT macro some preparations have to be done. But it’s actually easier than you might think! The necessary steps to convert your analysis code to a compilable task are:

  • Create a class inheriting from FairTask containing the analysis code

  • Add/modify local files CMakeLists.txt and tutrhoLinkDef.h

  • Modify CMakeLists.txt in root directory (e.g. trunk/CMakeLists.txt) in order to build the library

  • Create a macro, which loads the library and adds your analysis task to FairRunAna

  • Run the macro

Since most of this is not analysis specific but more related to !FairRoot please also take a look to the FairRoot website (http://fairroot.gsi.de/) for further information.

3.1 Create the class PndTutAnaTask

In principle the code from our macro tut_ana.C can by copied to the task code almost like it is, but we have to split it up appropriately to the header file PndTutAnaTask.h and the source file PndTutAnaTask.cxx of our class definition. To understand what goes where, let’s first take a look to the structure of a FairTask. The three most important methods of this class are:

  • Init() - Initialization of the task. Here the members of the class can be initialized, histograms are create, etc

  • Exec() - This is the actual event loop. Here your analysis code is located.

  • Finish() - At the end of the analysis, histograms etc are stored.

In order to access variables and objects across the class methods, they have to be declared in the private section of the class definition in the header file PndTutAnaTask.h like it is shown below:

...
class PndTutAnaTask : public FairTask
{
    public:
    PndTutAnaTask();                   // ** Default constructor
    ~PndTutAnaTask();                  // ** Destructor
    ...

    private:
    // *** the method from macro
    int SelectTruePid(PndAnalysis *ana, RhoCandList &l);

    int fEvtCount;                         // *** event counter
    RhoMassParticleSelector *fJpsiMassSel; // *** mass selector for the J/psi

    // *** declare some histograms
    TH1F *hjpsim_all;
    TH1F *hpsim_all;
    TH1F *hjpsim_lpid;
    ...
    TLorentzVector fIni;                // *** the initial 4-vector
    PndAnalysis *fAnalysis;             // *** the PndAnalysis object
    ...
};
...

In particular it is important to declare an object of class PndAnalysis, which works in the task in the same way as in the macro. After creating the header file, the members like fAnalysis, fIni, the histograms etc have to be setup in the Init() method in the source file PndTutAnaTask.cxx:

InitStatus PndTutAnaTask::Init()
{
    fAnalysis = new PndAnalysis();  // *** initialize analysis object
    fEvtCount = 0;                  // *** reset the event counter

    // *** Mass selector for the jpsi cands
    fJpsiMassSel=new RhoMassParticleSelector("jpsi",3.096,1.0);

    // *** create the histograms
    hjpsim_all = new TH1F("hjpsim_all","J/#psi mass (all)",200,0,4.5);
    hpsim_all  = new TH1F("hpsim_all","#psi(2S) mass (all)",200,0,5);
    ...

    // *** the lorentz vector of the initial psi(2S)
    fIni.SetXYZT(0, 0, 6.231552, 7.240065);

    return kSUCCESS;
}

The main part now is to implement the analysis code in the Exec() method. There we copy everything from within the event loop from the macro after putting an fAnalysis->GetEventInTask() (instead of fAnalysis->GetEvent() used in the macro!) just at the beginning of the method. This looks like this:

void PndTutAnaTask::Exec(Option_t* opt)
{
    // necessary to read the next event
    fAnalysis->GetEventInTask();  // instead of GetEvent() in macro

    // ---> from now on everything is exactly the same
    // ---> as in tut_ana.C, except adaptations of some variable names
    // ---> like fIni, fAnalysis,...

    // *** RhoCandLists for the analysis
    RhoCandList muplus, muminus, piplus, piminus, jpsi, psi2s;

    // *** Select with no PID info ('All'); type and mass are set
    fAnalysis->FillList(muplus,  "MuonAllPlus");
    fAnalysis->FillList(muminus, "MuonAllMinus");
    fAnalysis->FillList(piplus,  "PionAllPlus");
    fAnalysis->FillList(piminus, "PionAllMinus");

    // *** combinatorics for J/psi -> mu+ mu-
    jpsi.Combine(muplus, muminus);
...
}

Finally in the Finish() method, all the histograms are stored in the output file. Since the IO is handled by FairRootManager, we don’t have to care about opening files etc. The corresponding code looks like this:

void PndTutAnaTask::Finish()
{
    // *** Store all the histograms
    hjpsim_all->Write();
    hpsim_all->Write();
    hjpsim_lpid->Write();
...
}

3.2 Compile the class and build a library

The code of our new task now is ready, we just need to tell PandaROOT to compile it and build a corresponding library which we can use in a macro. Therefore we basically need two local files: CMakeLists.txt and tutrhoLinkDef.h. The first one is a configuration file for cmake containing all dependencies of your class (i.e. from which other !PandaROOT directories it needs to include stuff), the name and location of source and header files and the name of the library to be built. The most important part here is to add your source and header files (in this example the library will be named libtutrhotask.so) in CMakeLists.txt:

set(tutrhotask_SRCS
...
PndTutAnaTask.cxx
)

set(tutrhotask_HEADERS
...
PndTutAnaTask.h

In addition you need to add a line in the tutrhoLinkDef.h file like this:

#pragma link C++ class  PndTutAnaTask+;

Last but not least, you have to modify the CMakeLists.txt in your $VMCWORKDIR (e.g. trunk/) by adding a line:

add_subdirectory(tutorials/rho)

somewhere close to the place, where all the other add_subdirectory commands are.

Now you are able to compile your code and build the library by just executing make in your build directory.

3.3 Loading library and running the macro

For running the analysis we still need a macro, but in contrast to tut_ana.C it will look fairly simple and is completely independent of the actual analysis code. It starts like every standard PandaROOT macro, where you initialize some things and define your input and output files. You then just need to add your task to the FairRunAna and start the event loop. The full macro looks like this:

void tut_ana_task(int nevts = 0, TString prefix = "signal")
{
    TString OutFile=prefix+"_ana_task.root";

    // *** the files coming from the simulation
    TString inPidFile  = prefix+"_pid.root";    // PndPidCandidates and McTruth
    TString inParFile  = prefix+"_par.root";

    // *** PID table with selection thresholds; can be modified by the user
    TString pidParFile = TString(gSystem->Getenv("VMCWORKDIR"))+"/macro/params/all.par";

    // *** initialization
    FairLogger::GetLogger()->SetLogToFile(kFALSE);
    FairRunAna* fRun = new FairRunAna();
    FairRuntimeDb* rtdb = fRun->GetRuntimeDb();
    fRun->SetSource(new FairFileSource(inPidFile));

    // *** setup parameter database
    FairParRootFileIo* parIO = new FairParRootFileIo();
    parIO->open(inParFile);
    FairParAsciiFileIo* parIOPid = new FairParAsciiFileIo();
    parIOPid->open(pidParFile.Data(),"in");

    rtdb->setFirstInput(parIO);
    rtdb->setSecondInput(parIOPid);
    rtdb->setOutput(parIO);

    fRun->SetOutputFile(OutFile);

    // *** HERE OUR TASK GOES!
    PndTutAnaTask *anaTask = new PndTutAnaTask();
    fRun->AddTask(anaTask);

    // *** and run analysis
    fRun->Init();
    fRun->Run(0,nevts);
}

Now you can run your macro with root -l -b -q tut_ana_task.C, and the analysis should just run like with tut_ana.C.