Getting Started with GAUDI

LHCb's GAUDI page  architecture design document    user's guide  Package Configuration

First steps:  Report from August Workshop  Report from Aug 31st teleconference  

Current activities:      

Creating new services: flux service 

talk to Toby and see section 11.8 in the Gaudi User's Guide

Using the Transient Event Store

In a nutshell, the Transient Event Store is a tree that stores all data pertinent to a particular execution of the code.  This store only exists while a program is executing - data is saved for later use via the Persistency Service...but that's another story.  For more detailed information, see Chapter 6 in the User's Guide and Chapter 9 in the Architecture Design Document.

We are currently involved in migrating our current simulation from Gismo to use Geant 4 and Gaudi.  One of the first steps in the process is to make use of the Transient Event Store, to make the detector data from Glastsim available.  See the instrument package - this defines all of the GLAST specific detector classes, all of which derive from GlastDetector.  A call to GlastDetector::accept(DetectorConverter) causes all of the accept methods for all detectors to be called, thereby calling their forward methods that allows one to read out their data.  The ResponseFile class is an example of a class that derives from DetectorConverter and causes our IRF (instrument response file) to be generated or read back into the simulation.  A similar mechanism can be used to make the Glastsim data available to Gaudi.  See the Instrument class within the instrument package.

So...How does data get into the Transient Event Store?

There are 2 main ways...either data is created within an algorithm, and is stored in the Transient Event Store via some call to registerObject() or an some piece of code makes a request for some data.  The request is performed by a call to findObject() or retrieveObject() - or through the use of a SmartPointer.  When a request is made, first the Transient Event Store is checked to see if the data is already available - if so that's great and it passed to the requestor.  If the data is not available...then the Persistency Service is called and an appropriate Converter is used to retrieve the data from a persistent store, probably some file somewhere.  There is some magic going on in the background - usage of OpaqueAddresses so that proper converter is called....we'll ignore that for now.  The converter's createObj() method is called which allocates the necessary space, and then a call to updateObj() retrieves the data and stores it in some object derived from Gaudi's DataObject class - only objects derived from a DataObject (or one of Gaudi's ObjectContainers, see section 6.4 in the user's guide) can be stored in the Transient Event Store.

We do have an example to work from, since Gaudi was developed for use by the LHCb group.  There are two interesting packages, LhcbEvent and SicbCnv.  LhcbEvent contains the definition of the DataObjects for Lhcb.  SicbCnv contains the converters that do the job of reading their Zebra files (via Fortran code!) and filling the appropriate DataObjects.  

The Lhcb defined a structure for their Transient Event Store, see Chapter 7 of the User's Guide.  While the SicbEventCnvSvc is being initialized, via the initialize() method...you'll notice the following code fragment:

ICnvManager::CnvIterator i, stop;
for ( i = cnvManager()->cnvBegin(), stop = cnvManager()->cnvEnd(); i != stop; i++ ) {
    if ( repSvcType() == (*i)->repSvcType() ) {
    StatusCode iret = addConverter( *(*i) );
    if ( !iret.isSuccess() ) {
    status = iret;
    }
}
The calls to addConverter() cause the constructor of the various converters to be called.  Within each converter constructor, there is a call to declareObject(), the first parameter defines the path for this object within the Transient Event Store.

We have strongly modeled out implementation on the SicbCnv & LhcbEvent packages.  We have added two new packages:  GlastEvent and GlastSvc.  NOTE:  the code is not as organized as it should be...especially within GlastSvc...i.e. there should probably be folder for the converters, organizational things like that.  But more on that soon...first let's consider what happens when we start up a run with Gaudi...

Gaudi Execution

Each run uses a jobsOptions file to define the services, algorithm, and various parameters for that particular run.  At the beginning of program execution, this jobsOptions file is ingested.  There are many "core" services that Gaudi sets up automatically (like the Message Service) and then there are those that a user may request via the jobsOptions file (ex. our GlastDetSvc)

Take a quick look at GaudiSvc\src\ApplicationMgr.cpp - this is where all of the setup for a run that uses the Gaudi framework takes place.  All of the services are loaded and initialized.  nextEvent() is the routine that is called for each event.  Note the usage of the EventSelector (see Chapter 8 in the Architecture Design Doc)

Note the following comment from Markus Frank (9/00): "The event selector is supposed to filter out events at a very early stage based on the collection properties in case the event will immediately thrown away. This is currently not implemented."

See these interesting messages from real Gaudi developers!  1 2

After the data for the current event is loaded,  ApplicationMgr::nextEvent() causes all of the requested algorithms to call their execute() method.   

Where are we currently?

It is the EventSelector that is used within ApplicationMgr::nextEvent() to load the data for the upcoming event....see GlastSvc/src/EventSelector/EventSelector.cpp.  The EventSelector's purpose in life is to allow event cuts...this is not currrently implemented. 

The GlastDetSvc is used to load the data from our existing IRF file - through the Instrument class (available in the instrument package).  Upon each call to ApplicationMgr::nextEvent, the EventSelector::next(IEvtSelector::Iterator& it) method is called, which in turn executes:  StatusCode sc = m_detSvc->readIRF();  Basically this causes the GlastDetSvc to read the IRF file and load the Glastsim GlastDetector objects with data for that event.

We have a testing algorithm called CreateEvent.  This code is located within GlastSvc\src\test.  Within CreateEvent::execute(), we request access to data from the ACD via the call:   eventSvc()->retrieveObject("/Event/ACDTile", pObject);

This call to retrieveObject() causes the Transient Event Store to be checked to see if the requested data is already available within the store.  If not, the PersistencyService is used to call the appropriate converter to retrieve the data from some persistent store.

Our EventCnvSvc is modeled after SicbEventCnvSvc (SicbCnv/SicbCnv/TopLevel), a CnvSvc implements the IConversionSvc interface - handles the registration of the various converters during initialization and causes the appropriate converter to be called when necessary. 

Just as SicbCnv does, our converters are derived from a class called BaseCnv.  The BaseCnv implements the IEvenCnvSvc (modeled after ISicbEventCnvSvc) - which provides access to the tree structure we define for the Transient Event Store.  Note that the EventCnvSvc::updateServiceState() loops over the leaves and creates RegistryEntry objects (this is a Gaudi class...see Gaudi/Gaudi/DataSvc/RegistryEntry.h).  See this code fragment from EventCnvSvc.cpp.

Currently, there is only one implemented converter (ACDhitCnv) and DataObject representation of the ACD data (GlastEvent/src/Hits/ACDhit - stored in an object container ACDhitVector).  The updateObj() method calls GlastDetSvc::accept(), which causes the data stored in the GlastDetectors (these detectors were loaded with data back in the EventSelector), to be read into an ACDhitVector.  This vector is then put into the Transient Event Store, and provided to whoever requested the data in the first place.  See this code fragment.

Within the jobOptions file (see GlastSvc\src\test\jobOptions.txt) we define:  

GlastDetSvc.IRFFile = "src/test/muontest.irf";  // this is the IRF file that the GlastDetSvc will read

EventPersistencySvc.CnvServices = {"EventCnvSvc"};  // our converter service

Here is the output when the test application is run.

 

TO DO

Use the debugger...it's a great way to follow the code around and see what's going on.

Activity:  Within GlastSvc there is a testing algorithm called CreateEvent.  All algorithms within Gaudi implement 3 methods:  intialize(), execute(), finalize().  Take a look at the code, and then compile it. 

Cleanup...make sure classes and member variables and functions are named nicely.  And that the packages are organized appropriately...no care has been taken thus far - at least on my part!  GlastSvc and GlastEvent both contain classes that are no longer in use...perhaps they should be removed.

Consider the structure of our transient event store - this would be a good thing to pin down now!

Once a structure has been chosen, create / modify the converters to make it happen, ACD, TKR, CAL, MCTruth

Currently, when conversion of data from the IRF file is required, each converter calls the GlastDetSvc::accept method, causing all GlastDetectors to be visited.  This is probably not as efficient as since all detectors are visited.

Create new test algorithm(s) - perhaps one for each subsystem - that reads out the data from the Transient Event Store...to demonstrate that all data in being read in correctly.

Construct a Root converter to write out our data to Root files...this involves a few steps:  a.) Define the tree structure of the Root files b.) Test that Root v2.25 I/O works with Gaudi.  c.) Define the converters.  d.) Test, Test, Test

Interesting Gaudi terminology

Algorithm -"...make use of framework services to perform their work."  each algorithm is called once per event.  Implements the IAlgorithm interface, all algorithms used within Gaudi must implement the following three methods:  intialize(), execute(), and finalize().

OpaqueAddress - using the interface IOpaqueAddress, addresses may be passed between services.  The persistency service uses the OpaqueAddress to determine which converter to call.

Service - the glue that allows all the pieces of Gaudi to communicate....nothing useful would get done without the services!  Gaudi Examples: Message Service, Event Data Service, Tools Service,

Converter - a specific class that handles the actual conversion of data from its persistent storage representation into an object from a class that is somehow derived from DataObject, so that it may be stored in the Transient Event Store....or converts data from the Store into the appropriate representation so that it can be saved to a persistent store.

Tools - special type of algorithm that may be called multiple times per event.