Creating your AnaAlgorithm

Last update: 09 Jul 2020 [History] [Edit]

As a first step for writing your analysis code you need to create an algorithm class. An algorithm is the basic unit of code EventLoop or Athena knows about. At least as a beginner you will typically just have a single algorithm in your job that will hold your analysis code. (As an advanced user you may want to create multiple algorithms, and maybe also tools and services.)

We will create an empty algorithm now and call it MyxAODAnalysis. You can really name it anything you want, but if you give it a different name you will have to update any paths and code referring to it in the rest of the tutorial accordingly (so for the first time it is probably best to stick with this name).

Going into your source/ directory, create the file MyAnalysis/MyAnalysis/MyxAODAnalysis.h with this content:

#ifndef MyAnalysis_MyxAODAnalysis_H
#define MyAnalysis_MyxAODAnalysis_H

#include <AnaAlgorithm/AnaAlgorithm.h>

class MyxAODAnalysis : public EL::AnaAlgorithm
{
public:
  // this is a standard algorithm constructor
  MyxAODAnalysis (const std::string& name, ISvcLocator* pSvcLocator);

  // these are the functions inherited from Algorithm
  virtual StatusCode initialize () override;
  virtual StatusCode execute () override;
  virtual StatusCode finalize () override;

private:
  // Configuration, and any other types of variables go here.
  //float m_cutValue;
  //TTree *m_myTree;
  //TH1 *m_myHist;
};

#endif

Create the file MyAnalysis/Root/MyxAODAnalysis.cxx with this content:

#include <AsgTools/MessageCheck.h>
#include <MyAnalysis/MyxAODAnalysis.h>



MyxAODAnalysis :: MyxAODAnalysis (const std::string& name,
                                  ISvcLocator *pSvcLocator)
    : EL::AnaAlgorithm (name, pSvcLocator)
{
  // Here you put any code for the base initialization of variables,
  // e.g. initialize all pointers to 0.  This is also where you
  // declare all properties for your algorithm.  Note that things like
  // resetting statistics variables or booking histograms should
  // rather go into the initialize() function.
}



StatusCode MyxAODAnalysis :: initialize ()
{
  // Here you do everything that needs to be done at the very
  // beginning on each worker node, e.g. create histograms and output
  // trees.  This method gets called before any input files are
  // connected.
  return StatusCode::SUCCESS;
}



StatusCode MyxAODAnalysis :: execute ()
{
  // Here you do everything that needs to be done on every single
  // events, e.g. read input variables, apply cuts, and fill
  // histograms and trees.  This is where most of your actual analysis
  // code will go.
  return StatusCode::SUCCESS;
}



StatusCode MyxAODAnalysis :: finalize ()
{
  // This method is the mirror image of initialize(), meaning it gets
  // called after the last event has been processed on the worker node
  // and allows you to finish up any objects you created in
  // initialize() before they are written to disk.  This is actually
  // fairly rare, since this happens separately for each worker node.
  // Most of the time you want to do your post-processing on the
  // submission node after all your histogram outputs have been
  // merged.
  return StatusCode::SUCCESS;
}

Separate Setup for AnalysisBase or AthAnalysis

This section describes the setup required specifically for working with AnalysisBase or AthAnalysis. The tutorial can be run using either but when running with AnalysisBase (working with EventLoop) you need to set up a dictionary for the algorithm, whereas when working with AthAnalysis (Athena) you are required to set up a factory for the algorithm.

Both methods are described below but please take care to implement the relevant section depending on which release you setup.

Setting Up A Dictionary For The Algorithm (for EventLoop)

tip This is strictly speaking only needed when working in EventLoop (AnalysisBase). You can create it when working with Athena (AthAnalysis), if you want, but it will give you compilation overhead, so you can skip this if you want.

Create the file MyAnalysis/MyAnalysis/MyAnalysisDict.h with this content:

#ifndef MYANALYSIS_MYANALYSIS_DICT_H
#define MYANALYSIS_MYANALYSIS_DICT_H

// This file includes all the header files that you need to create
// dictionaries for.

#include <MyAnalysis/MyxAODAnalysis.h>

#endif

Create the file MyAnalysis/MyAnalysis/selection.xml with this content:

<lcgdict>

  <!-- This file contains a list of all classes for which a dictionary
       should be created. -->

  <class name="MyxAODAnalysis" />
   
</lcgdict>

Setting Up A Factory For The Algorithm (for Athena)

tip This is only needed when working with Athena (AthAnalysis), inside EventLoop (AnalysisBase) this will not be used. As such if you know that you will never work in Athena you can leave this out (or add it later).

Create the file MyAnalysis/src/components/MyAnalysis_entries.cxx with this content:

#include <GaudiKernel/DeclareFactoryEntries.h>

#include <MyAnalysis/MyxAODAnalysis.h>

DECLARE_ALGORITHM_FACTORY (MyxAODAnalysis)

Create the file MyAnalysis/src/components/MyAnalysis_load.cxx with this content:

#include <GaudiKernel/LoadFactoryEntries.h>

LOAD_FACTORY_ENTRIES (MyAnalysis)

Update your CMakeLists.txt file

Now you need to add the compilation of these files to your MyAnalysis/CMakeLists.txt file. Note that you only have to do this once per package, and not for subsequent algorithms in the same package. The first two lines should already be there, the remainder of lines ought to be new:

# The name of the package:
atlas_subdir (MyAnalysis)

# Add the shared library:
atlas_add_library (MyAnalysisLib
  MyAnalysis/*.h Root/*.cxx
  PUBLIC_HEADERS MyAnalysis
  LINK_LIBRARIES AnaAlgorithmLib)

if (XAOD_STANDALONE)
 # Add the dictionary (for AnalysisBase only):
 atlas_add_dictionary (MyAnalysisDict
  MyAnalysis/MyAnalysisDict.h
  MyAnalysis/selection.xml
  LINK_LIBRARIES MyAnalysisLib)
endif ()

if (NOT XAOD_STANDALONE)
  # Add a component library for AthAnalysis only:
  atlas_add_component (MyAnalysis
    src/components/*.cxx
    LINK_LIBRARIES MyAnalysisLib)
endif ()

# Install files from the package:
atlas_install_joboptions( share/*_jobOptions.py )
atlas_install_scripts( share/*_eljob.py )

Note that the if (XAOD_STANDALONE) and if (NOT XAOD_STANDALONE) blocks are ways for you to control what is actually built

Now we should be able to build our package with our empty algorithm:

cd ../build/
cmake ../source/
make

Note that strictly speaking we didn’t need to call cmake ourselves this time, as make will realize that we modified CMakeLists.txt and call cmake for us, but I prefer calling cmake manually whenever I add or remove a file, just to make sure that the new file gets picked up.

Basic notes about algorithms:

  • We have created a new algorithm here, with a source file MyAnalysis/Root/MyxAODAnalysis.cxx and a header file MyAnalysis/MyAnalysis/MyxAODAnalysis.h
  • In each algorithm you will have (among others) the following functions:
    • initialize(): called once, before the first event is executed
    • execute(): called once per event
    • finalize(): called once, after the final event has completed
  • You may notice there is a return code for each algorithm function, to let the framework know how successful (or not) the function ended