GAUDI User Guide

Chapter 4
Getting started

4.1  Overview

In this chapter we walk through one of the example applications ( Histograms ) which are distributed with the framework. We look briefly at the different files and go over the steps needed to compile and execute the code. We also outline where various subjects are covered in more detail in the remainder of the document. Finally we cover briefly the other example applications which are distributed and say a few words on what each one is intended to demonstrate.

4.2  Creating a job

Traditionally, a "job" is the running of a program on a specified set of input data to produce a set of output data, usually in batch.

For the example applications supplied this is essentially a two step process. First the executable must be produced, and secondly the necessary environment variables must be set and the required job options specified, as illustrated in Figure 3

The example applications consist of a number of "source code" files which together allow you to generate an executable program. These are:

.

Figure 3 Creating a job from the Histogram example application

 

In order for the job to run as desired you must provide the correct configuration information for the executable. This is done via entries in the job options file.

4.3   The main program

An example main program is shown in Listing 1 on See The example main program. . It is constructed as follows:

Include files
These are needed for the creation of the application manager and Smart interface pointers.
Library declarations
In this release of the Gaudi framework, we have implemented the use of dynamic load libraries (DLL) on the Windows NT platform. On the Unix platforms we still use static libraries. The extern declarations on lines 11 to 13 , and the conditional code on lines 21 to 25 are required to tell the linker to load the corresponding static libraries. (On NT, the DLLs to load are specified in the job options file, see for example Listing 29 on See The Standard Include Job Option File for NT Systems ).
ApplicationManager instantiation
Line 28 instantiates an ApplicationMgr object. The application manager is essentially the job controller. It is responsible for creating and correctly initialising all of the services and algorithms required, for looping over the input data events and executing the algorithms specified in the job options file, and for terminating the job cleanly.
Retrieval of Interface pointers
The code on lines 30 and 31 retrieves the pointers to the IProperty and IAppMgrUI interfaces of the application manager.
Setting the application manager's properties
The only property which needs to be set explicitly in the main program is the name of the job options file which contains all of the other configuration information needed to run the job. This is done on line 35 .
Program execution
All of the code before line 43 is essentially for setting up the job. Once this is done, a call to ApplicationMgr::run() is all that is needed to start the job proper! The steps that occur within this method are discussed briefly in section 4.6
Note on algorithm factories:
Note that in release 3 of the Gaudi framework it is no longer necessary to declare to the application manager the abstract factories needed to instantiate algorithms. The main program has therefore become rather trivial!

4.4  Configuring the job

The application framework makes use of a job options file (or possibly a database in future) for job configuration. The job options file of the Histograms example application is shown in Listing 2 on See The job options file for the Histograms example application. .

The format of an options file is discussed fully in Chapter 11 . Options may be set both for algorithms and services and the list of available options for standard components is given in Appendix Appendix B .

For the moment we look briefly at one of the options. The option TopAlg of the application manager is a list of algorithms that will be created and controlled directly by the application manager, the so-called top-level algorithms. The syntax is a list of the form:

 

 
ApplicationMgr.TopAlg = { "Type1/Name1","Type2/Name2" };

The line above instructs the application manager to make two top level algorithms. One of type Type1 called "Name1" and one of type Type2 called "Name2". In the case where the name of the algorithm is the same as the algorithm's type (i.e. class), only the class name is necessary. Thus, in the example in Listing 2 line 12 , an instance of the class "HistoAlgorithm" will be created with name "HistoAlgorithm"

.

Listing 1 The example main program.

1: // Include files
2: #include "Gaudi/Kernel/SmartIF.h"
3: #include "Gaudi/Kernel/Bootstrap.h"
4: #include "Gaudi/Interfaces/IAppMgrUI.h"
5: #include "Gaudi/Interfaces/IProperty.h"
6: #include "Gaudi/JobOptionsSvc/Property.h"
7: //---------------------------------------------------------------------
8: // Package : Gaudi Examples
9: // Description: Main Program
10: //---------------------------------------------------------------------
11: extern void GaudiParts_load();
12: extern void HbookCnv_load();
13: extern void SicbCnv_load();
14:
15: //--- Example main program
16: int main(int argc, char* argv[]) {
17:
18: StatusCode status = StatusCode::SUCCESS;
19:
20: // Force static loading by linker if dynamic loading is not used
21: #ifndef GAUDI_USE_DLL
22: GaudiParts_load();
23: HbookCnv_load();
24: SicbCnv_load();
25: #endif // GAUDI_USE_DLL
26:
27: // Create an instance of an application manager
28: IInterface* iface = Gaudi::createApplicationMgr();
29:
30: SmartIF propMgr ( IID_IProperty, iface );
31: SmartIF appMgr ( IID_IAppMgrUI, iface );
32:
33: // Set properties of algorithms and services
34: if ( propMgr == iface ) {
35: status = propMgr->setProperty( StringProperty("JobOptionsPath", "jobOptions.txt") );
36: }
37: else {
38: exit(0);
39: }
40:
41: // Run the application manager and process events
42: if ( appMgr ) {
43: status = appMgr->run();
44: }
45: else {
46: return 0;
47: }
48:
49: // All done - exit
50: return 0;
51: }
52:

 

Listing 2 The job options file for the Histograms example application.

1: //##############################################################
2: // Job options file
3: //==============================================================
4: // For Windows/NT
5: #include "../Common/Win32StandardJob.txt"
6: // For Unix
7: //#include "../Common/UnixStandardJob.txt"
8:
9: //--------------------------------------------------------------
10: // Private Application Configuration options
11: //--------------------------------------------------------------
12: ApplicationMgr.TopAlg = { "HistoAlgorithm" };
13:
14: //--------------------------------------------------------------
15: // Set output level threshold (2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL )
16: //--------------------------------------------------------------
17: MessageSvc.OutputLevel = 3;
18: HistoAlgorithm.OutputLevel = 3;
19:
20: //--------------------------------------------------------------
21: // Histogram output file
22: //--------------------------------------------------------------
23: HistogramPersistencySvc.OutputFile = "histo.hbook";
24:
25: //--------------------------------------------------------------
26: // Event related parameters
27: //--------------------------------------------------------------
28:
29: // Number of events to be processed (default is 10)
30: ApplicationMgr.EvtMax = 10;
31:
32: // Input file name
33: // For UNIX:
34: //ApplicationMgr.EvtSel = "FILE
35: /afs/cern.ch/lhcb/software/TMP/job11132.data!";
36: //ApplicationMgr.EvtSel = "FILE /afs/cern.ch/lhcb/data/mc/sicbmc.dat!";
37:
38: // For Windows/NT:
39: ApplicationMgr.EvtSel = "FILE S:\lhcb\software\class_b\sicbmc.dat";
40: //ApplicationMgr.EvtSel = "FILE F:/cern.ch/lhcb/data/mc/sicbmc.dat";
41:
42: // For both UNIX and Windows/NT:
43: //ApplicationMgr.EvtSel = "JOBID 10371";
44: //ApplicationMgr.EvtSel = "JOBID 11757";
45:
46: //--------------------------------------------------------------
47: // Algorithms Private Options
48: //--------------------------------------------------------------
49: // 0 = false = no histograms
50: HistoAlgorithm.HistogramFlag = true;
51: //==============================================================
52: // End of job options file
53: //##############################################################

4.5  Algorithms

The subject of specialising the Algorithm base class to do something useful will be covered in detail in chapter 5 . Here we will limit ourselves to looking at the class HistoAlgorithm in the example just to get an idea of the basics. For the full listing of this class, refer to the software distribution. Here we look only at those parts of the code which do something interesting and leave the technicalities for later.

4.5.1  The HistoAlgorithm header file

The HistoAlgorithm class definition is shown in Listing 3 .

Note the following:

 

Listing 3 The header file of the class: HistoAlgorithm.

1: #include "Gaudi/Algorithm/Algorithm.h" // Required for inheritance
2: class IHistogram1D;                    // Forward declaration
3:
4: class HistoAlgorithm : public Algorithm {
5: public:
6: // Constructor of this form must be provided
7: HistoAlgorithm(const std::string& name, ISvcLocator* pSvcLocator);
8:
9: // Three mandatory member functions of any algorithm
10: StatusCode initialize();
11: StatusCode execute();
12: StatusCode finalize();
13:
14: private:
15: // These data members are used in the execution of this algorithm
16: // They are set in the initialisation phase by the job options service
17: bool m_produceHistogram;
18: // Two histograms ( used if m_produceHistogram = 1 (true) )
19: IHistogram1D* m_hTrackCount;
20: IHistogram1D* m_hEnergyDist;
21: };
22:

4.5.2  The HistoAlgorithm implementation file

The implementation file contains the actual code for the constructor and for the methods: initialize(), execute() and finalize(). It also contains two lines of code for the HistoAlgorithm factory, which we will discuss in section 5.3.1

The constructor
must call the base class constructor, passing on its two arguments. As usual, member variables should be initialised. Here we set the m_produceHistogram flag to false and set the histogram pointers to zero. This is also the place to declare any member variables that you wish to be set by the job options service. This is done by making a call to the declareProperty() method.

 

1: HistoAlgorithm::HistoAlgorithm(const std::string& name,
2:                                ISvcLocator* pSvcLocator) :
3:                             Algorithm(name, pSvcLocator),
4:                             m_hTrackCount(0), m_hEnergyDist(0) {
5: // Declare the algorithm's properties
6: declareProperty( "HistogramFlag", m_produceHistogram = false ); }
Initialisation

The application manager invokes the sysInitialize() method of the algorithm base class which, in turn, invokes the initialize() method of the base class, the setProperties() method, and finally the initialize() method of the concrete algorithm class. As a consequence all of an algorithm's properties will have been set before its initialize() method is invoked, and all of the standard services such as the message service are available. This is discussed in more detail in chapter 5 .

Looking at the code in the example we see that depending on the value of the histogram flag the HistoAlgorithm class may also create two histograms at initialisation and declare them to the histogram data service (see Chapter 9 for details on the use of histograms in Gaudi):

Listing 4 Example of creation of histograms

1: if( m_produceHistogram ) {
2: log << MSG::INFO << "Histograms will be produced" << endreq;
3:
4: m_hTrackCount = new H1D( "TrackCount", "Number of MC Kinematic tracks", "1", 100, 0, 3000);
5: m_hEnergyDist = new H1D( "EnergyDist", "Energy distribution", "2", 20, 0, 50);
6:
7: // Register histogram under his number
8: StatusCode status = histogramDataService()->
9:     registerObject("/stat/simple/"+m_hTrackCount->number(),m_hTrackCount);
10: if( status.isFailure() ) {
11:   log << MSG::ERROR << "Cannot register histogram TrackCount" << endreq;
12: }
13: // Register histogram under his name
14: status = histogramDataService()-> registerObject( "/stat/simple/"+m_hEnergyDist->name_string(), m_hEnergyDist );
15: if( status.isFailure() ) {
16:   log << MSG::ERROR << "Cannot register histogram EnergyDist" << endreq;}
execution
The execute method is where most of the real action takes place. This method is called by the application manager once for every event. The HistoAlgorithm class accesses the event data store to retrieve a container of track objects (line 2 ). It then fills one of the two previously created histograms with the number of particles (line 15 ).

In order to use the objects within the container an iterator is defined (line 20 ) and the second histogram is filled with the energy of the tracks (line 24 ).

1: // MCParticle
2: SmartDataPtr particles( eventDataService(),
3:                                           EventModel::MC::Particles );
4:
5: if( !particles ) {
6:   log << MSG::ERROR << "Unable to retrieve MCParticles" << endreq;
7:   return 0;
8: }
9: log << MSG::INFO << "+++++ MCParticles retrieved +++++" << endreq;
10:
11: // Histograms
12: if( m_produceHistogram ) {
13:
14:   // Fill the track count histogram
15:    m_hTrackCount->fill(particles->size(), 1.);
16:
17:   // Fast fill the energy distribution histogram
18:   // Iterate over all tracks in the track container
19:   H1D* castedEnergyDist = dynamic_cast(m_hEnergyDist);
20:   MCParticleVector::iterator iterP = 0;
21:   for( iterP = particles->begin(); iterP != particles->end(); iterP++ ) {
22:     // Get the energy of the track and histogram it
23:     double energy = (*iterP)->fourMomentum().e();
24:     castedEnergyDist->fastFill( energy, 1. );
25:   }
26: }

The details of the event data store and how data is accessed are discussed in Chapter 6 .

Finalisation
The HistoAlgorithm class does nothing at finalisation apart from print out a message.
MsgStream
The HistoAlgorithm class makes use of the message service and the MsgStream utility class in order to print out some progress information, for example:
 
MsgStream          log( messageService(), name() ); 
	log << MSG::INFO << "finalize" << endreq;

The first line creates a local MsgStream object, which uses the Algorithm's standard message service via the messageService() accessor, and the algorithm's name via the name() accessor. The use of these is discussed in more detail in Chapter 11 .

4.6   Job execution

From the main program and the makefile or project file we can make an executable. This executable together with the file of job options form a job which may be submitted for batch or run interactively. Figure 4 shows a trace of an example program execution. The diagram is not intended to be complete, merely to illustrate a few of the points mentioned earlier in the chapter.

Figure 4 A sequence diagram showing a part of the execution of the example program.

 

  1. The application manager instantiates the required services and initialises them. The message service is done first to allow the other services to use it, and the job options service is second so that the other services may be configured at run time.
  2. The algorithms which have been declared to the application manager within the job options (via the TopAlg option) are created. We denote these algorithms "top-level" as they are the only ones controlled directly by the application manager. For illustration purposes we instantiate also an EmptyAlgorithm as well as the HistoAlgorithm of the example
  3. The top-level algorithms are initialised. They may request that their properties (if they have any) are set and may make use of the message service. If any algorithm fails to initialise the job is aborted.
  4. The application manager now starts to loop over events. After each event is read, it executes each of the top level algorithms in order. The order of execution of the algorithms is the order in which they appear in the TopAlg option. This will continue until the required number of events has been processed. If a particular algorithm returns a FAILURE status code many times, the application manager may decide that this algorithm is badly configured and jump to the finalisation stage before all events have been processed.
  5. After the required data sample has been read the application manager finalises each top level algorithm.
  6. Services are finalised.
  7. All objects are deleted and resources freed. The program terminates.

4.7  Other examples distributed with Gaudi

A number of examples is included in the current release of the framework. The intention is that each example exercises and shows to an end-user how to make use of some part of the functionality of the framework. The following table shows the list of available examples.

Table 3 List of available examples in current release

Example Name
Target Functionality

Common

Actually not a complete example: contains main program used by many examples (DDexample, DumpEvent, Histograms, ParticleProperties) and system specific Job Options include files common to all examples (reproduced in Listings 29 and 30 on See The Standard Include Job Option File for NT Systems )

DDexample

Illustrating the use of the detector description

DumpEvent

Navigation of the LHCb transient event data model

FieldGeom

Making available existing Sicb magnetic field and geometry data to Gaudi algorithms. Example of nested algorithms

FortranAlgorithm

Wrapping Fortran code in Gaudi

Histograms

Basic functionality of the framework to execute a simple algorithm, access event data and fill histograms.

MCPrimaryVertex

Retrieve data using SmartDataPtr

Ntuples

Two examples, reading and writing Ntuples

OpenScientist

Example of use of OpenScientist with Gaudi (works only on Unix at CERN)

ParticleProperties

Access the Particle Properties service to retrieve Particle Properties

Rio.Example1

Two examples, reading and writing persistent data with ROOT RIO

SimpleAnalysis

A realistic example of using the framework for a physics analysis, including access to Monte Carlo data, creation of reconstructed data and filling an n-tuple