Tool Creation and Management

Last update: 30 May 2019 [History] [Edit]

Tools are possibly the most common way we distribute software components in ATLAS. In many respects it acts like a regular C++ object, but it fits in with the ATLAS component model and is configured alongside other components, though we are not going to discuss the component model here.

As an example, let’s add the GoodRunsLists tool to our analysis. This tool will check whether a given data event can be used or was in a Luminosity blocks with “problems” in it. The exact details are not that important here, we mostly use it because it makes for a simple example. The general outline will be the same for all tools.

If this example seems rather complicated for something that ought to be rather simple, it’s because it is. This mechanism is meant for much more complicated scenarios, and for something so simple you could come up with a simpler mechanism. We tried that and the problem is that the simpler mechanisms can cause you various problems further down the road when your code gets more complicated. So we concluded it is better for you to start out with the “proper” way of using tools, and save yourself some headache in the future. And after you used this 2-3 times it will probably come quite natural to you.

The ToolHandle Class

One important thing about using tools is that you don’t create (or destroy) them directly inside your algorithm class. Instead the user/framework creates and configures the tools for you and then makes them available to your algorithm. For that to work properly your algorithm needs to refer to the tool using a ToolHandle. In many respects a ToolHandle works just like a (smart) pointer to the tool, except for some extra features related to configuration.

To use this tool we need the tool interface class IGoodRunsListSelectionTool and the xAOD::EventInfo class that holds the data we operate on. For that add AsgAnalysisInterfaces and xAODEventInfo to the LINK_LIBRARIES fields in your CMakeLists.txt file.

To use the tools with a ToolHandle you have to add the proper includes to the header file (MyxAODAnalysis.h near the top):

// GRL
#include <AsgAnalysisInterfaces/IGoodRunsListSelectionTool.h>
#include <AsgTools/ToolHandle.h>

warning You should not try to forward declare the tool interface, but always include the proper header file. While forward declarations will work in EventLoop, they will create a compilation error in Athena.

And then add the ToolHandle inside the class itself:

  ToolHandle<IGoodRunsListSelectionTool> m_grl;

Inside the constructor you then have to setup the ToolHandle so that the framework can find and configure it:

MyxAODAnalysis :: MyxAODAnalysis (const std::string& name,
                                  ISvcLocator *pSvcLocator)
  : EL::AnaAlgorithm (name, pSvcLocator),
    m_grl ("GoodRunsListSelectionTool/grl", this)
{
  // declare the tool handle as a property on the algorithm
  declareProperty ("grlTool", m_grl, "the GRL tool");

The ToolHandle constructor takes two arguments: The first is the type and the name of the tool to be created, separated by a /. If you omit the / the assumption is that you want both of them to be the same. The second argument is a pointer to the parent, which indicates that you want to crate a private tool, i.e. a tool that is only owned/known by the parent. By and large you should make all your tool private tools (with some noteable exceptions). If you omit the last parameter your tool becomes a public tool, meaning it is shared by all tool handles that specify the same name.

The declareProperty call declares the ToolHandle as a property on the algorithm, which allows to configure it from python. It work pretty much the same as regular property declaration, though the configuration works somewhat differently (see below).

Within the initialize method you should then retrieve the tool, which is not strictly necessary, but it is recommended to make sure the tool is actually there before the job starts:

  ANA_CHECK (m_grl.retrieve());

warning Most tools will also have declared an initialize method. It is important that you do not call this method yourself. It will already have been called and some tools can break if it gets called twice. Unfortunately there are essentially no checks against you doing that, so you just have to make sure not to do that.

Using the Tool Itself

Next let’s actually use the tool. This part is very specific to the tool itself, whereas the above is essentially just boiler-plate code that will look more or less the same for all tools.

In the execute() method, let’s retrieve the `EventInfo object, check if the event is in fact a data event, and if it is, then check the GRL for this event:

  //----------------------------
  // Event information
  //--------------------------- 
  const xAOD::EventInfo* eventInfo = 0;
  ANA_CHECK(evtStore()->retrieve( eventInfo, "EventInfo"));  
  
  // check if the event is data or MC
  // (many tools are applied either to data or MC)
  bool isMC = false;
  // check if the event is MC
  if (eventInfo->eventType (xAOD::EventInfo::IS_SIMULATION)) {
    isMC = true; // can do something with this later
  }

  // if data check if event passes GRL
  if (!isMC) { // it's data!
    if (!m_grl->passRunLB(*eventInfo)) {
      ANA_MSG_INFO ("drop event: GRL");
      return StatusCode::SUCCESS; // go to next event
    }
  } // end if not MC

  ANA_MSG_INFO ("keep event: GRL");

The message statement is mostly so that we can see what is happening. For actual analysis you would either remove that statement or set it to DEBUG or even VERBOSE message level.

tip You may notice that sometimes we say m_grl. and sometimes m_grl->. The rule is that until the tool is initialized we are talking to the tool handle and use m_grl. after the tool is initialized we mostly talk to the tool itself and use m_grl-> instead.

You can now compile your code to make sure you didn’t make any mistakes in the code itself, but it won’t run (correctly) yet as the tool needs to be configured.

Configuring the Tool

As noted above, your tool actually gets configured inside the python configuration file and then EventLoop/Athena will create it for you. Let’s do that now. There are actually multiple ways of doing this, we prefer the way below because it works the same for Athena and EventLoop.

Just add the following to your configuration file after you create your algorithm and before you add it to the sequence/job (if you add multiple tools, you only need the import statement once):

from AnaAlgorithm.DualUseConfig import addPrivateTool

# add the GRL tool to the algorithm
addPrivateTool( alg, 'grlTool', 'GoodRunsListSelectionTool' )

# configure the properties of the GRL tool
fullGRLFilePath = os.getenv ("ALRB_TutorialData") + "/data16_13TeV.periodAllYear_DetStatus-v89-pro21-01_DQDefects-00-02-04_PHYS_StandardGRL_All_Good_25ns.xml"
alg.grlTool.GoodRunsListVec = [ fullGRLFilePath ]
alg.grlTool.PassThrough = 0 # if true (default) will ignore result of GRL and will just pass all events

We won’t discuss the actual property values here, but a couple of words on the addPrivateTool call: This takes three arguments, the algorithm the tool belongs to, and the name of the tool class. If you have keen eyes you may have noticed that this is different from the class you used in the C++ section. Essentially (almost) every tool has two classes, an interface class (usually starting with I) and an implementation class (usually the same name without the I in the beginning). In your C++ code you should only be using the interface class which contains all the functions the user can call and nothing else. In the configuration you will however have to specify the actual implementation class which contains the actual tool code.

Now compile and run your code and see if it does what you expect.