LHCb F.A.Q.

This page will be populated with Frequently Asked Questions concerning general LHCb software

Add your own Question

Did you not find the answer you were looking for? If not please submit your question here.

Current user-submitted FAQ's can be found here

Where do I find documentation on Python Job Options?

  • Tutorials:
  • Presentations:
    • Examples shown by Pere Mato on 19th September 2007
  • Papers:
    • The proposal at the Barcelona LHCb week (2005-09-15)

How to retrieve event data from the Transient Event store?

See get and getIfExists methods in http://proj-gaudi.web.cern.ch/proj-gaudi/releases/latest/doxygen/class_gaudi_common.html. These methods are available in all Algorithms and Tools. In Services you have to use directly some of the Gaudi internal methods:
  100// Locate the Event Data Service
  101SmartIF<IDataProviderSvc> evtSvc(serviceLocator()->service<IDataProviderSvc>("EventSvc"));
  102// Get the data from the service
  103SmartDataPtr<MyDataObj> myObj( evtSvc, "path/to/object");
  104if( 0 != myObj ) { 
  105    //use it 
  106} 
  107else { 
  108  // does not exist, or not of type MyDataObj
  109}

How to locate Tools and Services?

See GaudiAlgorithm reference.

The methods in the reference above are not available inside Services. In this case (and in this case only), use the following:

  100SmartIF<IToolSvc> toolSvc(serviceLocator()->service<IToolSvc>("ToolSvc"));
  101IMyTool *myTool = 0;
  102toolSvc->retrieveTool("MyToolType/Name", myTool); // public
  103toolSvc->retrieveTool("MyToolType/Name", myTool, this); // private
  104myTool->doSomething();
  105toolSvc->releaseTool(myTool);
  106myTool = 0;

Printing from Gaudi

How to print using the predefined message streams?

See GaudiAlgorithm reference

How do I set the printout format?

To change the number of characters used to print out the algorithm name, do
MessageSvc().Format = "% F%60W%S%7W%R%T %0W%M"
This will print on 60 characters:
DaVinciInit                                                 SUCCESS ==================================================================
DaVinciInit                                                 SUCCESS Requested to process 100 events
DaVinciInit                                                 SUCCESS ==================================================================
The full description of the format is to be found in the Message class doxygen.

How do I change the OutputLevel for an arbitrary MsgStream?

The following example sets to Warning the OutputLevel of the 'Rich2/Rich2Gas' MsgStream
from Configurables import MessageSvc
MessageSvc().setWarning = [ 'Rich2/Rich2Gas' ]

How to use easy and friendly histogramming in Gaudi?

Gaudi framework provides access to the histogramming facilities through their AIDA abstract interfaces. This powerful and flexible way of making the histogramming has one important disadvantage. The locality of the histogramming facilities is lost. For the typical Gaudi algorithm, one needs: 1 declare the local variables for pointers to AIDA histograms in the body of the algorithm (which is usually resides inside separate file), 1 explicitly book the histograms with the help of IHistogramSvc, ans store the pointer to the booked histogram in some data member field of the algorithm. Usually this operation is performed inside the initialize method of the {\it{algorithm}}. 1 the actual histogram filling is usually performed inside execute method of the algorithm.

Usually the modification of different files and different code fragments is necessary to deal with histograms. Thus standard Gaudi histogramming facilities become non-local.

The regular 1D-histograms

The base classes GaudiHistoAlg and GaudiHistoTool provide the easy methods for simultaneous boolking and filling the histograms:

 1000AIDA::IHistogram1D*  plot 
 1010  ( const double        value        , // the value to be added to the histogram
 1020    const std::string&  title        , // the histogram title 
 1030    const double        low          , // the low edge of the histogram
 1040    const double        high         , // the high edge of the histogram 
 1050    const unsigned long bins   = 100 , // the number of bins
 1060    const double        weight = 1.0 ) const ; // the weight 
 1070
 1080  AIDA::IHistogram1D*  plot      
 1090  ( const double        value        , // the value to be added to the histogram
 1100    const HistoID&      ID           ,  // the histogram identified (string or number) with the optional subdirectory 
 1110    const std::string&  title        , // the histogram title 
 1120    const double        low          , // the low edge 
 1130    const double        high         , // the high edge 
 1140    const unsigned long bins   = 100 , // the number of bins 
 1150    const double        weight = 1.0 ) const ; // the weight 
 1160

For usage of these method one does not need to book the histogram. Booking is performed on demand. The unique integer histogram identifier for the first method is generated automatically. For the the second method the assignment of the histigram identified is under the full user control:

 1000const double value = ... ;
 1010 
 1020// use the automatically assigned ID:
 1030plot (  value , "It is the title for the first histo" , 0 , 100 ) ;
 1040
 1050// use string ID:
 1060plot ( value , "MyHisto" ,  "It is a title for the second histo" , 0 , 100 , 10 ) ;
 1070
 1080// use integer ID
 1090plot ( value , 100         ,  "It is the title for the third histogram" , 0 , 50 , 50 ) ;
 1100
 1110// using the subdirectory:
 1120plot ( value , "subdir/MyHisto1" , "It is the title for the fourth histo" , -100 , 100 , 200 ) ;

As it was emphasized histogram will be booked automatically on-demand. But in addition one can use book method explicitely to book the histograms:

 1000// book the histo with automatically generated ID (coulbe be extracted later using the method histo 
 1010book ( "Transverse momentum in GeV/c" , 0 , 10 ) ;
 1020
 1030// book the histo with assigned integer ID:
 1040AIDA::IHistogram* h15 = book ( 15 , "Momentum of the B-candidate" , -1 , 1 ) ;
Both book and plot methods return the pointer to AIDA::IHistogram1D class which can be used for explicit manipulations with histograms.

The booked histogram, previosuly booked with book or plot method could be retrieved using the method histo:

 1000// get the histogram by the unique title:
 1010AIDA::IHistogram1D* h1 = histo( "The histiogram unique title" ) ;
 1020
 1030// get the historgam by its unique numerical ID:
 1040AIDA::IHistogram1D* h2 = histo( 15 ) 
 1050
 1060// get the histoigram by its unique literal ID:
 1070AIDA::IHistogram1D* h3 = histo ( HistoID( "iThe historam Unique ID" ) ) ; 
If no histogram with given title/ID has been booked the method histo returns zero pointer.

The existence of the histogram with the given identifier or the title could be checked using the methods exists:

 1000// check the existence of the histogram by title:
 1010const bool ok1 = histoExists ( "Some histogram title" ) ;
 1020
 1030// check the existence of the histogram by numerical ID:
 1040const bool ok2 = histoExists ( 15 ) ; 
 1050
 1060// check the existence of the histogram by literal ID:
 1070const bool ok3 = histoExists ( HistoID("Soem uinque histogram ID" ) ) ;

2D,3D-histograms and the profile histograms

In a similar way there exist methods for manipulation with 2D, 3D histograms and profile-histograms with the similar semantics:

 1000const double mass1 = ... ;
 1010const double mass2 = ... ;
 1020
 1030// fill 2D-histogram    (book-on-demand)
 1040plot2D ( mass1, mass2, "Invariant Mass2 versus Mass1" ,2.5 ,3.5, 4.5, 5.5, 100, 200 );
 1050      
 1060// fill 1D-profile histogram (book-on-demand)
 1070profile1D ( mass1, mass2, "Invariant Mass2 versus Mass1" ,2.5 ,3.5, 100 );
 1080    
 1090const double X = ... ;
 1100const double Y = ... ;
 1110const double Z = ... ;
 1120
 1130// fill 3D histogram (book-on-demand)
 1140plot3D ( X, Y, Z, "Space Points" ,2.5 ,3.5, 4.5, 5.5, 6.5, 7.5, 10, 20, 30 ) ;
 1150
 1160// fill 2D profile histogram (book-on-demand) 
 1170profile2D ( X, Y, Z, "Space Points" ,2.5 ,3.5, 4.5, 5.5, 10, 20 );
 1180 
 1190// retrieve the booked 2D-histogram (if any)
 1200AIDA::IHistohram2D* h1 = histo2D ( "Some Title" ) ;
All methods has their partners with the assigned unique histogram identifiers. For completeness it is worth to mention that all previously considered methods for the regular 1D-histograms are shortcuts for the full methods plot1D, book1D, histo1D, etc..

Histograms and loops

Since the method plot does have some overhead, it is not recommended to use it directly inside the primitive loops. Here one can be more CPU-efficient using the direct manipulations with underlying pointer to the histogram

 1000AIDA::IHistogram1D* h = histo ( "Transverse Momentum in GeV" ) ;
 1010for ( int i = 0 ; i < nParticles  ; ++i ) 
 1020   {
 1030     const double p = .... ;
 1040     histo->fill ( p , 1.0 ) ;   ///< fill the histogram ;
 1050   }

However the base classes GaudiAlgorithm and GaudiTool provides functionality to make the efficient implicit STL-like loops:

 1000// some container with data:
 1010std::vector<double> data = ... ;
 1020
 1030// fill the histogram using implict loop (book-on-demand)
 1040plot1D  ( sin  , // the function to be applied for all elements 
 1050         data.begin() , // the begin of the sequence 
 1060         data.end()   , // the end of the sequence 
 1070         "The sin of the all number from container" , // the title  
 1080          -1 ,  1      ) ; // the low and the high edges  
 1090
The method is templated and any sequence and function or function object could be used, e.g. one can easily reuse all LoKi functors:
 1000const std::vector<const LHCb::Particle*>& particles = ... ;
 1010       
 1020// fill the histogram through implicit loop (book-on-demand)
 1030plot ( PT/GeV  ,  // the functor 
 1040       particles.begin() , // the begin of the sequence 
 1050       particles.end() , // the end of the sequence 
 1060       "The transverse momentum in GeV" , 0 , 10 ) ; // the title and the edges 
 1070

Many STL-adapters could be used as the appropriate functors:

 1000const std::vector<const LHCb::Particle*>& particles = ... ;
 1010       
 1020// fill the histogram through implicit loop (book-on-demand)
 1030plot ( std::mem_fun(&LHCb::Particle::p) , // the functor 
 1040       particles.begin() , particles.end() , // the begin and the end of the sequence 
 1050       "The momentum" , 0 , 10 ) ; // the title and the edges 
 1060
Please note that these template methods not only very efficient but also are very compact.

Can I use all this nice histogramming in Python?

The short answer is yes, the detailed answer see here

How can I use GaudiHistoAlg and GaudiHistoTool base classes?

The simplest way to use these nice features for easy and friendly histograms is through inheritance from base classes GaudiHistoAlg or GaudiHistoTool.

The base classes GaudiHistoAlg and GaudiHistoTool are very easy to use and they implement the functionality described above through template class GaudiHistos.

Policy

To get the access to the desired functionality one needs to inherit the code from these base classes:
 1000#include "GaudiAlg/GaudiHistoAlg.h"
 1010
 1020class MyAlg : public GaudiHistoAlg 
 1030{ 
 1040   ....
 1050};
For the implementation of the basic method one needs to follow the policy for the contructor, initialization and finalization methods:
 1000// constructor:
 1010MyAlg::MyAlg ( const std::string& name , ISvcLocator* pSvc ) 
 1020  : GaudiHistoAlg ( name , pSvc )   ///< Invoke the constructor for the base class 
 1030  { ...}
 1040
 1050// initialization of the algorithm:
 1060StatusCode MyAlg::initialize ()
 1070{
 1080   // Initialize the base class:
 1090   StatusCode sc = GaudiHistoAlg::initilalize () ; ///< initialize the base class
 1100   if ( sc.isFailure() ) { return sc ; } 
 1110
 1120   .. perform the specific initialization here ...
 1130
 1140   return StatusCode::SUCCESS ;                        ///< RETURN  
 1150} 
 1160
 1170// finalization of the algorithm:
 1180StatusCode MyAlg::finalize () 
 1190{
 1200   ... perform the specific finalization here ...
 1210
 1220    // and at the end finalize the base class:
 1230    return GaudiHistoAlg::finalize () ;
 1240}

Major properties of GaudiHistoAlg and GaudiHistoTool base classes

The major properties of the base classes GaudiHistoAlg and GaudiHistoTool relevant for the histograms are:

Property Type Default Value Description
HistoProduce bool true Switches off all histogramming actions
HistoPrint bool true Switch on/off the printout of summary information about booked histograms
HistoCheckFroNaN bool true Switch on/off the checking of the values for "Not-a-Number" and "Infinity"
HistoSplitDir bool false Switch on/off the splitting of long directory names into short name (suitable for HBOOK persistency)
HistoOffSet int 0 Start value for automatically assigned histogram identifiers
HistoTopDir string "" Optional top-level subdirectory for more granular location of histograms, e.g. "Velo/"  (note the trailing ="/")
HistoDir string name Subdirectory in the output file where all histograms are put
MonitorHistorams bool true Switch on/of the automatic registration of all booked histogram for Monitoring Service

For the general properties, inherited from the base classes GaudiAlgorithm and GaudiTool see here.

Histogram summary

If the property HistoPrint is activated, some short summary on booked histograms is printed at the end of the job:


SimpleHistos      SUCCESS Booked 18 Histogram(s) : 1D=9 2D=4 3D=2 1DProf=1 2DProf=2
SimpleHistos      SUCCESS List of booked 1D histograms in directory         "SimpleHistos" :-
SimpleHistos      SUCCESS  ID=1                "Gaussian mean=0, sigma=1"             Ents/All=50000/50000<X>/sX=-0.010746/0.99822
SimpleHistos      SUCCESS  ID=6                "AutoID time test"                     Ents/All=50000/50000<X>/sX=-0.010746/0.99822
SimpleHistos      SUCCESS  ID=101              "Exponential"                          Ents/All=49643/50000<X>/sX=0.97244/0.91365
SimpleHistos      SUCCESS  ID=102              "Breit"                                Ents/All=46916/50000<X>/sX=-0.0047661/1.1982
SimpleHistos      SUCCESS  ID=1111             "Forced Numeric ID time test"          Ents/All=50000/50000<X>/sX=-0.010746/0.99822
SimpleHistos      SUCCESS  ID=poisson          "Poisson"                              Ents/All=47490/50000<X>/sX=1.8072/1.1794
SimpleHistos      SUCCESS  ID=subdir1/bino     "Binominal"                            Ents/All=48626/50000<X>/sX=1.9077/1.1167
SimpleHistos      SUCCESS  ID=subdir2/bino     "Binominal"                            Ents/All=48626/50000<X>/sX=1.9077/1.1167
SimpleHistos      SUCCESS  ID=test1            "Forced Alpha ID time test"            Ents/All=50000/50000<X>/sX=-0.010746/0.99822

IHistoTool interface

There exist cases where the usage of the inheritance sceme is not possible, e.g.

  • if one want to equip with histogram Gaudi component, different from algorithm or tool, e.g.
    • Service
    • Converter
    • Auditor
  • if one needs to equip temporary the component with histogramming abilities ony for debugging purposes and the change of the class structure is not possible, e.g. the algorithm is inherited from some other base class algorithm.

for these cases one can use "external" tool, which implement IHistoTool interface:

 1000#include "GaudiAlg/IHistoTool.h"
 1010...
 1020{
 1030  IHistoTool* t = tool<IHistoTool>( "HistoTool" , ... ) ;
 1040
 1050  // use IHistoTool::plot method:
 1060  const double value = .... ;
 1070  plot  ( value , "It is a histogram title" , -1 , 1 , 100 ) ;
 1080  ...
 1090} 
Other methods, like plot, book, histo, histoExists are also implemented.

Where can I find more examples on usage of GaudiHistoAlg and GaudiHistoTool base classes?

The package GaudiExamples contains few examples for the histograms, see here

Can I use easy and friendly histogramming in (Gaudi)Python?

The package GaudiPython offers such functionality. One needs to inherit Python algorithm from the Python base class GaudiAlgs.HistoAlgo:

 1000from   GaudiAlgs   import HistoAlgo
 1010
 1020class HistoEx(HistoAlgo) :
 1030    """ The simple algorithm which book&fill the histograms """
 1040    def execute( self ) :
 1050        """ The major method 'execute', it is invoked for each event """
 1060        # fill the histogram (book-on-demand)
 1070        for i in range(0,10) : self.plot1D ( i , ' 1D histo ' , 0 , 20 , 20 )
 1080        return SUCCESS
See the examples HistoEx.py and HistoEx1.py in the directory $GAUDIEXAMPLESROOT/scripts.

Also see the Gaudi Python pages for more examples.

How can I access the underlying ROOT objects for AIDA histograms?

The package GaudiUtils contains the useful utility Gaudi::Utils::Aida2ROOT:aida2root which allows to extract from AIDA pointer the underlying ROOT object:

 1000#include "GaudiUtils/Aida2ROOT.h"
 1010
 1020...
 1030// histograms:
 1040AIDA::IHistogram1D* ai1D = ... ;
 1050AIDA::IHistogram2D* ai2D = ... ;
 1060AIDA::IHistogram3D* ai2D = ... ;
 1070// profiles:
 1080AIDA::IProfile1D*       ap1D = ... ;
 1090AIDA::IProfile2D*       ap2D = ... ;
 1100
 1110// get the underlying ROOT objects:
 1120TH1D*       rh1D = Gaudi::Utils::Aida2ROOT::aida2root  ( ai1D ) ;
 1130TH2D*       rh2D = Gaudi::Utils::Aida2ROOT::aida2root  ( ai2D ) ;
 1140TH3D*       rh3D = Gaudi::Utils::Aida2ROOT::aida2root  ( ai3D ) ;
 1150TProfile*   rp1D = Gaudi::Utils::Aida2ROOT::aida2root  ( ap1D ) ;
 1160TProfile2D* rp2D = Gaudi::Utils::Aida2ROOT::aida2root  ( ap2D ) ;

Where can I find my histograms in the output file?

The actual location of the histograms inside the output histogram files are under the control of two properties of GaudiHistoAlg and GaudiHistoTool base classes

  • "HistoTopDir" with default value "" (empty string)
  • "HistoDir" with the default value, equal to the full name of the component (algorithm or tool)

For more details see here.

How can I specify the histogram parameters through job-options?

Starting from Gaudi v19r5, one can specify the parameters of 1D-histogram through job-options. Histogram parameters include:

  • Histogram title,
  • Number of bins,
  • Lowee edge
  • Upper edges.

Clearly only the equidistant histograms could be specified through job-options. The 1D-histogram parameters are specified either directly through the class Gaudi::Histo1DDef or through Histo1DProperty :

 1000class MyAlg: public ...
 1010{
 1020... 
 1030 private:
 1040  Gaudi::Histo1DDef m_histo1 ;
 1050  Histo1DProperty    m_histo2 ;
 1060} ;
 1070
 1080MyAlg::MyAlg ( .... ) 
 1090  : ....
 1100{
 1110   declareProperty ( "Histo1" , m_histo1 , "Parameters of the first histogram" ) ;
 1120   declareProperty ( "Histo2" , m_histo2 , "Parameters of the second histogram" ) ;
 1130} 

The helper class Gaudi::Histo1DDef could be unpacked directly:

 1000// get the title:
 1010const std::string title = m_histo1.title() ;
 1020
 1030// get number of bins:
 1040const int nBins = m_histo1.bins()  ;
 1050
 1060// get lower edge 
 1070const double low = m_histo1.lowEdge() ;
 1080
 1090// get high edge 
 1100const double high = m_histo1.highEdge() ;

Alternatively one can use the methods GaudiHistos::book and GaudiHistos::plot directly, without unpacking of the helper structure:

 1000const double value1 = ... ;
 1010
 1020// fill (book-on-demand) the histogram:
 1030plot ( value1 , m_histo1 ) ;
 1040
 1050const double value2 = ... ; 
 1060
 1070// fill (book-on-demand) the histogram with forced (numerical) ID 
 1080plot ( value2 , 15 , m_histo2 ) ;

Possible representation of the 1D-historgam parametrs via job-options:

 1000// title, low& high edges, #bins:
 1010MyAlg.Histo1 = ('it is a title', 0.0, 1.0 , 100 ) ;
 1020
 1030// title, low& high edges:
 1040MyAlg.Histo1 = ("it is a title", 0.0, 1.0 ) ;
 1050
 1060//  low& high edges, title , #bins:
 1070MyAlg.Histo1 = (0.0, 1.0 , " it is a title" , 100 ) ;
 1080
 1090//  low& high edges, title :
 1100MyAlg.Histo1 = (0.0, 1.0 , " it is a title" ) ;
 1110
 1120//  low& high edges, #bins:
 1130MyAlg.Histo1 = (0.0, 1.0 , 100 ) ;
 1140
 1150//  low& high edges:
 1160MyAlg.Histo1 = (0.0, 1.0) ;

The unspecified title is set to be empty, and the default number of bins is 100. Please note that the parsing function (coded by Sascha Mazurov) check two mandatory conditions:

  • low edge is less that high edge
  • number of bins is positive integer number

Since the representation of class Gaudi::Histo1DDef ( or Histo1DProperty or SimpleProperty<Gaudi::Histo1DDef> or SimplePropertyRef<Gaudi::Histo1DDef> ) consides with semantic of native Python tuple, it is very easy to use this functionality in python:

 1000#get the component
 1010myalg = ...
 1020
 1030#set the property form the native python tuple
 1040myalg.Histo1 = ("title",0.0,1.0,100) 

How can I overwrite the 1D-histogram parameters from job-options?

From Gaudi v19r5 there is possibility to overwrite the parameters of 1D-histogram (the tile, number of bins and low&high edges) through job-options without recompilation of the executable. This functionality could be very useful for monitoring purposes and indeed has been discussed in the context of "histogram sets". The parameters of the histogram could be redefined through the direct configuration of =HistogramDataSvc" via its property "Predefined1DHistos". This property defined the mapping between histogram unique location in Histogram Transient Store and new parameters of the histogram. Booking the histogram the service ignores the parameters which are passed through direct C++ call and uses new parameters, defined through the property Predefined1DHistos. The format of the histogram parameters is described here.

 1000// configure the histogram service:
 1010HistogramDataSvc.Predefined1DHistos += 
 1020{
 1030   '/stat/MyHistos/1' ,  ("new title",-1.0,1.0,200) ,
 1040   '/stat/MyHistos/2' ,  ('title',-10.,10.)  ,
 1050   "MyHistos/3"        ,  (-100.,100.) 
 1060};

Can I use HBOOK as a persistency for my histograms?

Yes, it is still possible for 32-bit versions of applications. To use HBOOK as persistency please make sure that you do have CMT-dependency on the package HbookCnv. It could be achieved b the presence of the following line in cmt/requirements file of your package or application:

 1000# use HBOOK for the histogram persistency:
 1010use HbookCnv v* 
In addition one needs to specify the persistency type through the configuration file:
 1000// define HBOOK as the persistency type:
 1010ApplicationMgr.HistogramPersistency = "HBOOK" ;

Please note:

  1. HBOOK persistency is not available for 64-bit platforms.
  2. Some advanced features (like 3D-histograms, or 2D-profiles) are not available for HBOOK persistency

How can I use easy and friendly N-Tuples in Gaudi?

Simple (scalar) columns

The simple columns are booked and filled using the method column and they are applicable for the numerical scalar type, including bool:
 1000// retrieve N-Tuple (book-on-demand)
 1010Tuple tuple = nTuple( "My simple N-Tuple") ;
 1020 
 1030const double x = ... ;
 1040const float  y = ... ;
 1050const int     ia = ... ;
 1060const int     ib = ... ;
 1070
 1080// fill double/float data
 1090tuple -> column ( "x" , x ) ;
 1100tuple -> column ( "y" , y ) ;
 1110
 1120// fill with the integer data:
 1130tuple -> column ( "a" , a ) ;
 1140
 1150// fill with the integer data with low/high limits:
 1160tuple -> column ( "b" , b , 0 , 127 ) ;
 1170
 1180// fill with the boolean data:
 1190tuple -> column ( "good" , x > 0 ) ; 

How to fill several columns of type double in one go?

Several columns of type double could be filled in one go using the method fill:
 1000// retrieve the  N-tuple with assigned numerical ID (book-on-demand)
 1010Tuple tuple = nTuple( 15 , "Some Title" ) ;
 1020
 1030const double x = ... ;
 1040const double y = ... ;
 1050const double z = ... ;
 1060
 1070// fill ARBITRARY number of columns in one go, using comma or blank separated list of column names:
 1080tuple -> fill ( "x,y,z" , x , y , z ) ;
Please note that here all columns MUST be of type double, and number of items in the blank or comma separated list must match the actual number of arguments

Advanced columns

While the simple scalar columns could be used both with Row-wise N-Tuples and Column-wise N-tuples, the advanced columns could be used only with Column-wise N-tuples.

Fixed size arrays

Fixed-size arrays could be filled using the method array and begin/end iterators for the sequence of objects, convertible to double:
 1000// retrieve N-Tuple with the assigned literal ID (book-on-demand)
 1010Tuple tuple = nTuple( "MyID" , "Some Title" ) ; 
 1020
 1030// use STL vectors:
 1040const std::vector<float>& data1 = ... ;
 1050     
 1060tuple -> array 
 1070   ( "data1"         , ///< column name
 1080     data1.begin () ,  ///< begin of the sequence
 1090     data1.end   () ) ; ///< end of the sequence
 1100
 1110// use the regular C-arrays:
 1120double data2[4] = { 0.0 , 1.0 , 2.0 , 3.0 } ;
 1130tuple ->  array ( "data2" , data2 , data2 + 4 ) ;
 1140 
 1150// use ROOT::Math::SVector:
 1160const ROOT::Math::SVector<double,15>& vct = ... ;
 1170tuple -> array ( "data3" , vct.begin() , vct.end() ) ; 
For any object which supports begin/end iterators (as. e.g. std::vector, std::list, std::set, std::deque, ROOT::Math::SVector, LoKi::Range_) one can use the shortcuts:
 1000Tuple tuple = ... ; 
 1010
 1020// use STL list:     
 1030const std::list<float>& data1 =      ;
 1040tuple -> array ( "data1" , data1 ) ; 
 1050
 1060// use ROOT::Math::SVector:
 1070const ROOT::Math::SVector<double,25>& data2 = ... ;
 1080tuple -> array ( "data2" , data2 ) ;

Alternatively, if the pseudo-array supports the indexing operator, [], (e.g. std::vector, CLHEP::HepVector, ROOT::Math::SVector, LoKi::Range_, C-arrays etc..) the alternative semantics could be used:

 1000Tuple tuple = ... ; 
 1010  
 1020// use STL vector:    
 1030const std::vector<double>& data1 = ... ;
 1040tuple -> array 
 1050   ( "data1"         , ///< column name
 1060     data1 ,  ///< the object which supports "operator[]"
 1070     data1.size() ) ;  ///< the length (FIXED!)
 1080 
 1090// use SVector:
 1100const ROOT::Math::SVector<float,24>& data2 = ... ;
 1110tuple -> array ( "data2" , data2 , data2.Dim() ) ;
 1120
 1130// use the regular C-arrays:
 1140double data3[4] = { 0.0 , 1.0 , 2.0 , 3.0 } ;
 1150tuple ->  array ( "data3" , data3 , 4 ) ;
 1160 
 1170// use CLHEP
 1180const CLHEP::HepVector& data4 = ... ;
 1190tuple ->  array ( "data3" , data4 , data4.num_row() ) ;
In addition for the class ROOT::Math::SVector there exist the special shortcut:
 1000Tuple tuple = ... ; 
 1010
 1020// use SVector:
 1030const ROOT::Math::SVector<float,24>& data = ... ;
 1040tuple -> array ( "data" , data ) ;

Fixed size matrices

Any fixed size matrix object which supports the indexing in the form of a[n][m], e.g. std:vector<std::vector >, CLHEP::HepMatrix, CLHEP::GenMatrix, or plain C-"array-of-ararys" could be put into N-Tuple using the method matrix:

 1000Tuple tuple = ... ;
 1010
 1020// use STL pseudo-matrix:
 1030const std::vector<std::vector<double> >& data1 = ... ;
 1040const size_t num_row = ... ;
 1050const size_t num_col  = ... ;
 1060tuple -> matrix ( "data1" , data1 , num_row , num_col ) ;
 1070
 1080// use CLHEP
 1090const CLHEP::HepMatrix& data2 = ... ;
 1100tuple -> matrix ( "data2" , data2 , data2.num_row()  , data2.num_col() ) ;
 1110
 1120const CLHEP::GenMatrix& data3 = ... ;
 1130tuple -> matrix ( "data3" , data3 , data3.num_row() , data3.num_col() ) ;
 1140      
 1150// use the plain C++ pseudo-matrix (array of arrays) ;
 1160double** data4 = ...;
 1170tuple -> matrix ( "data4" , data4 , 15 , 23 ) ;
There exist the special method for the class ROOT::Math::SMatrix:
 1000Tuple tuple = ... ; 
 1010  
 1020// use SMatrix:
 1030const Gaudi::Matrix3x4& data = ... ;
 1040tuple -> matrix ( "data" , data ) ;

Variable sized arrays

The indexed array of the variable size could be put into N-Tuple using the method farray:
 1000Tuple tuple = ... ;
 1010
 1020// STL vector:
 1030const std::vector<double>& data1 = ... ;
 1040tuple -> farray 
 1050   ( "data1"       ,     ///< the name of the column 
 1060     data1.begin () ,    ///< the begin of the data sequence
 1070     data2.end   () ,    ///< the end of the data sequence 
 1080     "Len1"         ,     ///< the name of "the length" column
 1090     100             ) ; ///< the maximum length 
 1100
If the object implements begin/end methods, the shortcut could be used:
 1000Tuple tuple = ... ;
 1010
 1020// STL vector:
 1030const std::vector<double>& data1 = ... ;
 1040tuple -> farray ( "data1" ,  data1 , "Len1" , 100 ) ; 
It is not uncommon to put into N-Tuple the indexed array of result of some functional computation:
 1000Tuple tuple = ... ;
 1010
 1020// STL vector:
 1030const std::vector<double>& data1 = ... ;
 1040tuple -> farray 
 1050   ( "sinf"       ,     ///< the name of the column 
 1060     std::fun_ptr ( sin )  ,   ///< the function to be applied
 1070     data1.begin () ,    ///< the begin of the data sequence
 1080     data1.end   () ,    ///< the end of the data sequence 
 1090     "Len1"         ,     ///< the name of "the length" column
 1100     100             ) ; ///< the maximum length 
 1110
Such approach is especially convenient with the various data continers, e.g. one can put into N-Tuple the transverse momenta of all particles:
 1000Tuple tuple = ... ;
 1010
 1020// some data
 1030const std::vector<const LHCb::Particle*>& particles = ... ;
 1040tuple -> farray 
 1050   ( "pt"       ,     ///< the name of the column 
 1060     std::mem_fun(&LHCb::Particle::pt)  ,   ///< the function to be applied
 1070     particles.begin () ,    ///< the begin of the data sequence
 1080     particles.end   () ,    ///< the end of the data sequence 
 1090     "Num"         ,     ///< the name of "the length" column
 1100     100             ) ; ///< the maximum length 
 1110
Up to 4 functions could be evaluated simultaneously:
 1000Tuple tuple = ...;
 1010
 1020// array with data
 1030const std::vector<const LHCb:Particle*>& particles = ... ;
 1040tuple -> farray 
 1050   ( "pt" , std::mem_fun(&LHCb::Particle::pt) , 
 1060     "p"  , std::mem_fun(&LHCb::Particle::p) , 
 1070     "m"  , std::mem_fun(&LHCb::Particle::m), 
 1080     particles.begin() , particles.end() , 
 1090     "Num" , 100 ) ;
Such functionality could be easily reused e.g. with LoKi functors:
 1000Tuple tuple = ...;
 1010
 1020// array with data
 1030const std::vector<const LHCb:Particle*>& particles = ... ;
 1040tuple -> farray ( "pt" , PT , "p" , "P" , "id" , ID , "e" , E , particles.begin() , particles.end() , "Num" , 100 ) ;

Variable sized matrices

Only one dimension of the matrix is allowe to be variables. Number of columns must is fixed. The matrix object is required to support the indexing operator [], the expression mtrx[i][j] should be valid C++ expression. To put such matrix into N-tuple one needs to use the method fmatrix:

 1000Tuple tuple = ...;
 1010
 1020// STL pseudo-matrix: 
 1030const std::vector<std::vector<double> >& data = ... ;
 1040tuple -> fmatrix 
 1050   ( "data1" , ///< the  column name  
 1060     mtrx , ///< the matrix object
 1070     num_row , ///< the number of rows (variable) 
 1080     num_col , ///< the number of columns (fixed!)
 1090     "Rows"  , ///< the name of "the length" column
 1100     25   ) ; /// the maximal number of rows
 1110
 1120// CLHEP:
 1130const CLHEP::HepMatric& data2 = ... ;
 1140tuple -> fmatrix ( "data2" , data2 , data2.num_row() , data2.num_col() , "Rows2" , 10 ) ;

The special columns

There exist a set of useful shortcuts to put some special objects into N-tuple in one go:

Gaudi::LorentzVector and ROOT::Math::LorentzVector
 1000Tuple tuple  = ... ;
 1010
 1020const Gaudi::LorentzVector& vct = ... ;
 1030tuple -> column 
 1040   ( "p" , ///< common prefix 
 1050     vct ) ; ///< data 
 1060
The method creates and fills the four simple scalar columns with the names "pE", "pX", "pY" and "pZ".

Gaudi::Vector3D and ROOT::Math::DisplacementVector3D
 1000Tuple tuple  = ... ;
 1010
 1020const Gaudi::Vector3D& vct = ... ;
 1030tuple -> column 
 1040   ( "v" , ///< common prefix 
 1050     vct ) ; ///< data 
 1060
The method creates and fills the three simple scalar columns with the names "vX", "vY" and "vZ".

ROOT::Math::PositionVector3D and Gaudi::Point3D
 1000Tuple tuple  = ... ;
 1010
 1020const Gaudi::Point3D& vct = ... ;
 1030tuple -> column 
 1040   ( "vertex" , ///< common prefix 
 1050     vct ) ; ///< data 
 1060
The method creates and fills the three simple scalar columns with the names "vertexX", "vertexY" and "vertexZ".

Can I use all this nice functionality in Python?

The short answer is yes, the detailed answer see here

Can I use HBOOK as persistency for my N-Tuples?

Yes, it is still possible for 32-bit versions of applications. To use HBOOK as persistency please make sure that you do have CMT-dependency on the package HbookCnv. It could be achieved by the presence of the following line in cmt/requirements file of your package or application:

 1000# use HBOOK for the histogram persistency:
 1010use HbookCnv v* 
In addition one needs to specify the persistency type through the configuration file:
 1000// define HBOOK as the persistency type:
 1010ApplicationMgr.HistogramPersistency = "HBOOK" ;
Yes, it is not a typo: one does need to specify HistogramPersistency, the persistency type, specified through NTupleSvc.OutputFile is just ignored.

Please note:

  1. HBOOK persistency is not available for 64-bit platforms.
  2. Gaudi requires the same persistency for histograms and N-Tuples
  3. see also notes here

Selecting events: Event Tag Collections

Documentation on event tag collections can be found in section 10.3 of the Gaudi User Guide.

Can I use HBOOK as persistency for my Event Tag Collections?

No

Can I select a subset of events without using an event tag collection?

Event tag collections are the most efficient way of selecting a subset of events from an data file. However, for quick tests, you can also use the FilterByRunEvent algorithm, which should be added to the beginning of the top level sequence of the application.

How can I use GaudiTupleAlg and GaudiTupleTool base classes?

The simplest way to use these nice features for easy and friendly N-Tuples & Event Tag Collections is through the inheritance from the base classes GaudiTupleAlg or GaudiTupleTool.

Policy

To get the access to the desired functionality one needs to inherit the code from these base classes:
 1000#include "GaudiAlg/GaudiTupleAlg.h"
 1010...
 1020class MyAlg : public GaudiTupleAlg ///< inheritance from base class 
 1030{ 
 1040   ....
 1050};
For the implementation of the basic method one needs to follow the policy for the contructor, initialization and finalization methods:
 1000// constructor:
 1010MyAlg::MyAlg ( const std::string& name , ISvcLocator* pSvc ) 
 1020  : GaudiTupleAlg ( name , pSvc )   ///< Invoke the constructor for the base class 
 1030  { ...}
 1040
 1050// initialization of the algorithm:
 1060StatusCode MyAlg::initialize ()
 1070{
 1080   // Initialize the base class:
 1090   StatusCode sc = GaudiTupleAlg::initilalize () ; ///< initialize the base class
 1100   if ( sc.isFailure() ) { return sc ; } 
 1110
 1120   .. perform the specific initialization here ...
 1130
 1140   return StatusCode::SUCCESS ;                        ///< RETURN  
 1150} 
 1160
 1170// finalization of the algorithm:
 1180StatusCode MyAlg::finalize () 
 1190{
 1200   ... perform the specific finalization here ...
 1210
 1220    // and at the end finalize the base class:
 1230    return GaudiTupleAlg::finalize () ;
 1240}

The major properties of GaudiTupleAlg and GaudiTupleTool base classes

The major properties of the base classes GaudiTupleAlg and GaudiTupleTool relevant for the N-Tuples and Ent Tag Collections are:

Property Type Default Value Description
NTupleProduce bool true Switches off all N-Tuple-related actions
NTupleLUN string "FILE1" The string which defined the logical file unit
NTuplePrint bool true Switch on/off the printout of summary information about N-Tuples
NTupleSplitDir bool false Switch on/off the splitting of long directory names into short name (suitable for HBOOK persistency)
NTupleOffSet int 0 Start value for automatically assigned N-tuple identifiers
NTupleTopDir string "" Optional top-level subdirectory for more granular location of N-Tuples, e.g. "Velo/" (note the trailing "/")
NTupleDir string name Subdirectory in the output file where all N-Tuples are put
       
EvtColsProduce bool false Switches off all ETC-related actions
EvtColsLUN string "EVTCOL" The string which defined the logical file unit
EvtColsPrint bool true Switch on/off the printout of summary information about ETCs
EvtColsSplitDir bool false Switch on/off the splitting of long directory names into short name
EvtColsOffSet int 0 Start value for automatically assigned ETCs identifiers
EvtColsTopDir string "" Optional top-level subdirectory for more granular location of ETCs, e.g. "Velo/" (note th etrailing "/")
EvtColsDir string name Subdirectory in the output file where all ETCs are put

For the histogram-related properties, inherited from their corresponding base classes GaudiHistoAlg and GaudiHistoTool see here. For the general properties, inherited from the base classes GaudiAlgorithm and GaudiTool see here.

N-Tuples summary

If the property NTuplesPrint is activated, some short summary on booked N-Tuples is printed at the end of the job:


TupleEx1          SUCCESS Booked 3 N-Tuples and 0 Event Tag Collections
TupleEx1          SUCCESS List of booked N-Tuples in directory "MYLUN/TupleEx1"
TupleEx1          SUCCESS  ID=1             Title="Trivial Row-Wise Tuple"                  #items=7  {gauss,flat,expo,breit,poiss,binom,poisb}
TupleEx1          SUCCESS  ID=2             Title="Trivial Column-Wise Tuple"               #items=7  {gauss,flat,expo,breit,poiss,binom,poisb}
TupleEx1          SUCCESS  ID=3             Title="Fixed-size arrays/vectors"               #items=4  {arflat[1],arexpo[1],argau[1],argau2[1]}

ITupleTool interface

There exist cases where the usage of the inheritance sceme is not possible, e.g.

  • if one want to equip with N-Tuples Gaudi component, different from algorithm or tool, e.g.
    • Service
    • Converter
    • Auditor
  • if one needs to equip temporary the component with N-Tuples/ETC abilities only
for debugging purposes and the change of the class structure is not possible, e.g. the algorithm is inherited from some other base class algorithm.

for these cases one can use "external" tool, which implement ITupleTool interface:

 1000#include "GaudiAlg/ITupleTool.h"
 1010...
 1020{
 1030   ITupleTool* t = tool<ITupleTool>( "TupleTool" , ... ) ;
 1040
 1050   // use ITupleTool::nTuple method:
 1060   Tuples::Tuple tuple = t -> nTuple ("My N-Tuple") ; 
 1070   ...
 1080} 
Other methods, like evtCol are also implemented

Where can I find more examples on usage of GaudiTupleAlg and GaudiTupleTool base classes?

The package GaudiExamples contains many examples for the N-tuples and Event Tag Collections, e.g. see $GAUDIEXAMPLESROOT/src/TupleEx and $GAUDIEXAMPLESROOT/src/EvtColEx directories.

Where can I find my N-Tuples in the output file?

The actual location of the N-Tuples inside the output files are under the control of two properties of GaudiTupleAlg and GaudiTupleTool base classes

  • "NTupleTopDir" with default value "" (empty string)
  • "NTupleDir" with the default value, equal to the full name of the component (algorithm or tool)

For more details see here.

How can I use in Python easy and friendly N-Tuples and Event Tag Collections?

The package GaudiPython offers such functionality. One needs to inherit Python algorithm from the Python base class GaudiAlgs.TupleAlgo:

 1000from   GaudiAlgs   import TupleAlgo
 1010
 1020class TupleEx(TupleAlgo) :
 1030    """ Simple algorithm which book&fill N-Tuples """
 1040
 1050    def execute( self ) :
 1060        """ The major method 'execute', it is invoked for each event """
 1070
 1080        gauss = Rndm.Numbers( self.randSvc() , Rndm.Gauss( 0.0 , 1.0 ) )
 1090
 1100        tup = self.nTuple('My trivial N-tuple')
 1110        for i in range(0,100) :
 1120            tup.column( 'a' , math.sin(i) )
 1130            tup.column( 'b' , math.cos(i) )
 1140            tup.column( 'c' , math.tan(i) )
 1150            tup.column( 'g' , gauss()     )
 1160            tup.write()
 1170
 1180        return SUCCESS
See the examples TupleEx.py, TupleEx1.py, TupleEx2.py, TupleEx3.py, EvtColWrite.py and EvtColRead.py in the directory $GAUDIEXAMPLESROOT/python.

How to use the Statistical Counters ?

There are three ways for usage of the statistical counters in Gaudi framework:

  1. Local counters through GaudiAlgorithm and GaudiTool base classes
  2. Counter form Statistical Service IStatSvc
  3. Counters from Counter Service ICounterSvc

All three approaches deal with the same objects = the generic counters of the C+ type StatEntity and have the different application range. The first approach is suitable for local counters, used withing the same algorithm or tool. The counters are naturally grouped by components. The second approach allows global counters, e.g. one can modify the same counter from different components. The third approach is essentially the same as the second approach, but in addition it allows some flexible grouping of the counters. It is worth to note that the second and the third approaches unavoidably have some CPU overhead with respect to the first approach.

The generic counters in GaudiAlgorithm and GaudiTool base classes

See GaudiAlgorithm reference

How can I use IStatSvc for counters?

For the global counters, the approach with the usage of IStatSvc is more preferrable, however here since the generic counter is owned by the service, the special wrapper class Stat is suitable to preserve the object/instance semantic instead the pointer semantic:

 1000IStatSvc* statSvc = ... ;
 1010
 1020// get the counter form the service ("book on-demand") 
 1030Stat stat ( statSvc, "Total Energy" );
 1040
 1050// increment it:
 1060stat += eTotal ;
 1070 
 1080// check the underlying generic counter (optional) 
 1090const StatEntity* counter = stat->counter() ;
 1100
 1110// increment the counter in the service (in one go)  ("book-on-demand")
 1120Stat nTr ( statSvc , "#Tracks" , nTracks ) ;
The table of ll counters will be printed at the end of the job, if the property "StatPrintOutTable" activated:
******Stat******     INFO ****************************************************************************************************
******Stat******     INFO  The Final stat Table (ordered)
******Stat******     INFO ****************************************************************************************************
******Stat******     INFO      Counter     |     #     |    sum     | mean/eff^* | rms/err^*  |     min     |     max     |
******Stat******     INFO  "counter1"      |     20000 |   2000.452 |    0.10002 |2.2600e-005 |     0.10000 |     0.10005 |
******Stat******     INFO *"eff"           |     20000 |      10000 |( 50.00000 +- 0.3535534)%|   -------   |   -------   |
******Stat******     INFO  "counter3"      |     20000 |      13000 |    0.65000 |    0.35000 |     0.30000 |      1.0000 |
******Stat******     INFO  "counter2"      | 100020000 |    9993260 |   0.099913 |   0.010999 |     -1.0000 |     0.10005 |
******Stat******     INFO ****************************************************************************************************

The format of the table is under the control of properties.

How can I use ICounterSvc for counters?

The usage of counters with ICounterSvc is very similar to the previous case, but in addition it allows to define the group:

 1000ICounterSvc* svc = ... ;
 1010
 1020// get the counter from the service using "group" and "name"
 1030Stat stat ( svc , "VELO" , "#Hits" ) ;
 1040
 1050// increment the counter:
 1060stat += nHits ;
The printout of counters is performed at the end of the job:

CounterSvc        SUCCESS Number of counters : 4
CounterSvc        SUCCESS        Counter :: Group         |     #     |    sum     | mean/eff^* | rms/err^*  |     min     |     max     |
CounterSvc        SUCCESS *         "Eff1::CounterTest"   |     10000 |       5000 |( 50.00000 +- 0.5000000)%|   -------   |   -------   |
CounterSvc        SUCCESS *         "Eff2::CounterTest"   |     10000 |       3333 |( 33.33000 +- 0.4713927)%|   -------   |   -------   |
CounterSvc        SUCCESS            "Sum::CounterTest"   |     10000 |5.0005e+007 |     5000.5 |     2886.8 |      1.0000 |      10000. |
CounterSvc        SUCCESS     "TotalCount::CounterTest"   |     10000 |      10000 |     1.0000 |    0.00000 |      1.0000 |      1.0000 |

The format of the table is under the control of properties.

How can I use my counters for monitoring?

The work here is in progress, please contact Eric van Herwijnen for the details. The overall idea is to let Monitoring Service know about the generic counter StatEntity and to allow the automatic registration of all booked counters for Monitoring Service. Some work has been done by Ulrich Kerzel and Chris Jones. Recently a bit more generic approach has been proposed by Claus Buszello.

Where can I find code examples for the generic counters?

The package GaudiExaples provides three C++ examples:
  1. The files $GAUDIEXAMPLESROOT/src/CounterAlg.cpp and $GAUDIEXAMPLESROOT/options/CounterEx.opts illustrate the usage of the local generic statistical counters
  2. The file $GAUDIEXAMPLESROOT/python/CounterEx.py illustrate the usage of the statistical counters in Python
  3. The files $GAUDIEXAMPLESROOT/src/StatSvcAlg.cpp and $GAUDIEXAMPLESROOT/options/StatSvcAlg.opts illustrate the usage of the statistical counters and IStatSvc
  4. The files $GAUDIEXAMPLESROOT/src/CounterSvcAlg.cpp and $GAUDIEXAMPLESROOT/options/CounterSvcAlg.opts illustrate the usage of the statistical counters and ICounterSvc

Can I use this functionality in Python?

The package GaudiPython offers such functionality. One needs to inherit Python algorithm from the Python base class GaudiAlgs.GaudiAlgo ( or GaudiAlgs.HistoAlgo or GaudiAlgs.Algo) :

 1000from   GaudiAlgs   import GaudiAlgo
 1010
 1020class Counter(GaudiAlgo) :
 1030    """ Simple algorithm which manipulates with counters """
 1040        
 1050    def execute( self ) :
 1060        """ The major method 'execute', it is invoked for each event """
 1070
 1080        executed = self.counter('executed')
 1090        executed += 1. 
 1100
 1110        gauss   = Numbers( self.randSvc() , Rndm.Gauss   ( 0.0 ,1.0 ) )
 1120
 1130        # 'gauss'
 1140        value = gauss.shoot() 
 1150
 1160        g1 = self.counter('gauss')
 1170        g2 = self.counter('g2')
 1180        
 1190        g1 += value
 1200        g2 += value * value
 1210
 1220        return SUCCESS
For more examples see $GAUDIEXAMPLESROOT/python/CounterEx.py from GaudiExamples package.

How can I inspect/retrieve/modify the properties for the given Gaudi component?

It is easy to check if the given component has a property with the given name using the method Gaudi::Utils::hasProperty:

 1000IMyComponent* component = ...;
 1010  
 1020// check the presence of property
 1030const bool OK = Gaudi::Utils::hasProperty ( component ,  "SomeProperty" ) ; 
Also one can extract the given property by name:
 1000IMyComponent* component = ... ;
 1010  
 1020// get the property by name (return NULL pointer for non-existing properties)
 1030Property* property = Gaudi::Utils::getProperty ( component , "SomeProperty" ) ;

The modification of the existing properties is also possible:

 1000IMyComponent* component = ... ;
 1010
 1020// change the output level:
 1030StatusCode sc = Gaudi::Utils::setProperty( component , "OutputLevel" , 2 ) ;

How can I inspect/retrieve/modify the properties for the given Gaudi component in (Gaudi)Python ?

In (Gaudi)Python one can inspect the properties interactively:
 1000# get the component by name
 1010component = gaudi.algorithm('AlgName') 
 1020
 1030# get the dictionary of all properties:
 1040props = component.properties() 
 1050
 1060# loop over all properties and print them:
 1070for p in properties : 
 1080    value = properties[p].value() 
 1090    print "Property  Name/Value:   '%s'/%s " % ( p, value ) 
 1100
 1110# modify the property:
 1120component.OutputLevel = 2 

What C++ types could be used as component's properties in Gaudi ?

Currently Gaudi supports following basic scalar types for properties
  1. bool
  2. char, unsigned char, signed char
  3. short, unsigned short
  4. int, unsigned int
  5. long, unsigned long
  6. long long, unsigned long long
  7. float, double, long double
  8. std::string
For each basic scalar type, the corresponding std::vector<TYPE> is also supported. Other types:
  1. std::pair<double,double>
  2. std::vector<std::pair>double,double> >
  3. std::pair<int,int>
  4. std::vector<std::vector<std::string> >
  5. std::vector<std::vector<double> >
Associative properties:
  1. std::map<int,double>
  2. std::map<std::string,std::string>
  3. std::map<std::string,int>
  4. std::map<std::string,double>
  5. std::map<std::string,std::vector<std::string> >
  6. std::map<std::string,std::vector<int> >
  7. std::map<std::string,std::vector<double> >

Essentially each type, with the implemented functions

  • StatusCode Gaudi::Parsers::parse(  TYPE& result, const std::string& input )
  • std::ostream& Gaudi::Utils::toStream( const TYPE& object , std::ostream& stream)
could be used as the base for properties. For all types, listed above, the corresponding parse functions have been implemented by Sascha Mazurov using Spirit & Phoenix libraries from Boost project. The great flexibility and functionality of these libraries make the extension of properties for other classes to be rather simple.

For the special case of histogram properties see here.

How can I specify the extended properties in the options-file?

The canonical representation of each property type, listed above is defined by its representation through Gaudi::Utils::toStream function, and corresponds to the native python representation of the object using the mapping:

  • std::vector is mapped to Python's list
  • std::map is mapped to Python's dict
  • std::pair is mapped to Python's tuple
  • histogram proprty is mapped to Python's tuple with the special structure, see here.
The boolean value could be specified in three ways:
  • like Python's True or False
  • like C++ true or false
  • as 1 or 0
The string are specified using single '...' or double "..." quotes. The curly braces {...} could be substituted by the rectangular brackets [...] and vice versa. The examples are available in GaudiExamples package in the file $GAUDIEXAMPLESROOT/options/ExtendedProperties.opts, the corresponding C++ code is $GAUDIEXAMPLESROOT/src/ExtendedProperties/ExtendedProperties.cpp

When and why should I update the version numbers of an InterfaceID?

Each Interface in Gaudi has a unique Interface Identifier (InterfaceID) which is versioned (see section 16.3 of the Gaudi User Guide). The purpose of the version number is to check compatibility between clients of an Interface (e.g. an algorithm requesting a tool) and the component implementing the Interface (e.g. the tool) - if the two components have been compiled against different incompatible versions of the Interface, then this will result in a core dump when the Interface is accessed.

Gaudi provides a mechanism to avoid these core dumps. When you call the templated tool or svc methods to locate a tool or service, behind the scenes these methods call the queryInterface() method of the tool or service, which checks (using the InterfaceID::versionMatch() method) that the version number used in the requesting code is compatible with that used in the implementating code. Of course this only works if the implementer of the interface remembers to increment the version numbers of the interface when a change is made.

The major version number should be incremented whenever the interface is changed in a run-time incompatible way. If the change is run-time compatible, the minor version should be incremented. Note that very few changes are run-time compatible (e.g. change the constness of an argument in one of the methods, change the default value of one of the arguments, add new enum items, etc.). Even adding a method at the end of the Interface definition is not guaranteed to be run-time compatible on all platforms. If in doubt, increase the major version.

How do I check for untested StatusCode?

Add the following option to your application.
ApplicationMgr.StatusCodeCheck = true;

N.B., the checking is very slow if there are lots of untested StatusCode, so you better also have something like:

ApplicationMgr.EvtMax = 5;

How do I dump the contents of a POOL data (or ETC) file?

This can be done inside ROOT using the dumpFile macro:
root [1] .L $GAUDIPOOLDBROOT/scripts/dumpFile.C
root [2] dumpFile("theFileName")

How do I modify the entries of the ParticleTable.txt used by the LHCb::ParticlePropertySvc?

This can be done by using the OtherFiles and Particles properties of the LHCb::ParticlePropertySvc

How can I use new Particle Property Service ( LHCb::ParticlePropertySvc)?

Actually the usage of new particle property service LHCb::ParticlePropertySvc= is fairly trivial and explained in detail here.

The major items:

  • the abstract interface for the service has a name LHCb::IParticlePropertySvc, (doxygen)
  • the major object which carry particle properties is named LHCb::ParticleProperty, (doxygen)
  • GaudiPython provides set of useful "decorators" for using particle properties functionality in python, namely python class iParticlePropertySvc=, (doxygen) and various utilities, see
  • all classes and utilities reside in the package Kernel/PartProp

How to locate new service?

If one uses the base classes GaudiAlgorithm or GaudiTool, the location of the service is trivial:

 1000#include "PartProp/IParticlePropertySvc.h"
 1010... 
 1020// assuming  GaudiAlgorithm base class... 
 1030...
 1040const LHCb::IParticlePropertySvc* ppsvc = 
 1050   svc<LHCb::IParticlePropertySvc>( "LHCb::ParticlePropertySvc" ) ;
 1060

Please note that the base class DVAlgorithm has already the accessor to the new service:

 1000// assuming DAVlgorithm base class .. 
 1010...
 1020const LHCb::IParticlePropertySvc* ppsvc = ppSvc() ;

For usage in python it is recommended to "import" the helper module PartProp.Service:

 1000import PartProp.Service 

This helper module provides the class AppMgr with helper accessor to the particle property service:

 1000import PartProp.Service 
 1010from GaudiPython.Bindings import AppMgr
 1020... 
 1030gaudi = AppMgr()        # instantiate the Application Manager 
 1040...
 1050ppsvc = gaudi.ppSvc()  # get the service from Gaudi 
 1060

How to configure the new service?

The configuration of new service is done through the corresponding Configurables:

 1000from Gaudi.Configuration import * 
 1010
 1020from Configurables import LHCb__ParticlePropertySvc 
 1030
 1040LHCb__ParticlePropertySvc ( 
 1050  ParticlePropertiesFile = 'the file name' , # the name of the major file with particle properties
 1060  OtherFiles = [] ,                                 # the list of additional files 
 1070  Particles    = [] ,                                  # the list of special additional particle properties
 1080  Dump       = True    # dump the particle properties in  table format 
 1090  )

Please note that for real LHCb applictaion we pick up the particle properties table from database, and the corresponding lines are placed in LHCbApp :

 1000from Gaudi.Configuration import * 
 1010
 1020from Configurables import LHCbApp
 1030
 1040LHCbApp ( 
 1050   ... ,
 1060  DDDBtag = 'default' ,  # specify the correct DDDB tag  
 1070   ... 
 1080   )

How to use the new service?

 1000// 1) get service: 
 1010const LHCb::IParticlePropertySvc* ppsvc = ... ;
 1020
 1030// 2) look up the particle property by name:
 1040const LHCb::ParticleProperty* p1 = ppsvc->find ( "B0" ) ;
 1050if ( 0 == p1 ) { ... unknown particle name ... ; } 
 1060
 1070// 3) look up the particle property using ParticleID :
 1080const LHCb::ParticleID& pid = ... ;
 1090const LHCb::ParticleProperty* p2 = ppsvc->find ( pid ) ;
 1100if ( 0 == p2 ) { ... unknown PID here ... ; }

The same stuff in Python looks as:

 1000ppsvc =    # get the service 
 1010
 1020# find particle property by name:
 1030p1 = ppsvc.find( 'B0' ) 
 1040
 1050# find particle property by PID
 1060pid = LHCb.ParticleID( 511 )
 1070p2  = ppsvc.find ( pid ) 

One also can get few particle properties which satisfy some criteria, e.g. get all leptons:

 1000#include "boost/lambda/lambda.hpp"
 1010#include "boost/lambda/bind.hpp"
 1020...
 1030using namespace boost::lambda ;
 1040...
 1050const LHCb::IParticlePropertySvc* svc = ... ;  
 1060
 1070typedef LHCb::IParticlePropertySvc::ParticleProperties Vector ; 
 1080      
 1090// create the output vector:
 1100Vector leptons ;
 1110     
 1120// use the service 
 1130svc -> get 
 1140         ( bind ( &LHCb::ParticleID::isLepton , 
 1150                  bind ( &LHCb::ParticleProperty::particleID , _1 ) ) ,
 1160           std::back_inserter ( lepton ) ) ; // output 
 1170     

In python it is even easier:

 1000ppsvc =    # get the service 
 1010
 1020# find all leptons
 1030leptons = ppsvc.get ( lambda x : x.isLepton() ) 

Manipulations with particle properties and PIDs becomes very transapren if one uses the concept of "decay nodes":

 1000# import all decay nodes: 
 1010from PartProp.Nodes import *
 1020    
 1030ppsvc = ...   # get the service 
 1040
 1050# find all leptons
 1060leptons = ppsvc.get ( Lepton ) 
 1070
 1080# find positive leptons:
 1090ellplus = ppsvc.get ( EllPlus ) 
 1100
 1110
 1120# find all tensor hadrons:
 1130tensors = ppsvc.get ( Hadron & Tensor ) 
 1140
 1150# find all baryons with spin 3/2
 1160pp = ppsvc.get ( Baryon & ThreeHalfs )
 1170 

How to get all known particles?

E.g. in DaVinci it can be done suing following script:

 1000from Gaudi.Configuration import * 
 1010
 1020from Configurables import DaVinci 
 1030
 1040import PartProp.Service 
 1050
 1060# configure DaVinci: 
 1070
 1080DaVinci (  
 1090   DataType = 'MC09' 
 1100  ) 
 1110
 1120# get application manager:
 1130
 1140from GaudiKernel.Bindings import AppMgr 
 1150gaudi = AppMgr() 
 1160
 1170# get the service 
 1180ppSvc = gaudi.ppSvc() 
 1190
 1200print ppSvc.all()       ## print as table: 
 1210
 1220 
If one runs the script using python -i ./Script.py one gets the table of all particle properties

Alternatively, one can also

SetupProject LHCb
CondDBBrowser DDDB

and look for 'ParticleTable.txt' under the folder 'param'.

My job re-opens the same file instead of going to the next one

This is likely because the 2 files have the same GUID (that's some hexadecimal file identifier). For every file you generate Gaudi will assign a GUID that's supposedly unique. This GUID is written in the output file and in the file catalogue. When you write out a file, Gaudi will generate a catalogue, or update the one you already have in the local directory. Look for files called *.xml. When reading the files back it will assume that 2 files with the same guid are the same file. It is thus impossible to read 2 files with the same GUID in the same job: Gaudi will just start re-reading the first one.

Now, how can 2 files have the same GUID? If you run a job that produces file.dst, gaudi will wirite the GUID in the file and add the pair (file.dst, GUID) in catalog.xml, or so. Then when you move this file away and run another job creating another file called file.dst gaudi will read back the pair from catalog.xml and not create a new GUID. The second file will get the same GUID as the previous one.

To avoid that never generate a file with gaudi using a temporary name file.dst, move it to castor (or elsewhere) or rename it and then restart gaudi generating a new file file.dst. The safest is to always set in the job the final name of the output file.

How can I merge two files together, or copy a few events from a file?

  1. You can add an InputCopyStream or MDFWriter to your existing options
  2. OR you can use the new FileMerger application from within the Noether project (see FileMerger).

How can I run only one algorithm or sequencer from within a complicated Gaudi job?

  • See GaudiExcise, a wrapper around gaudirun.py to do exactly that.

What's the difference between Python, GaudiPython, and Gaudi?

  • Python: an advanced interpreter language implemented in C++.
  • Gaudi: a C++ and python framework for event-wise data processing.
  • gaudirun.py: a python wrapper around Gaudi's excecutable, which feeds the Gaudi executable with "options". The options may start out as python files which adjust attributes of so-called "configurables", finally these options are flattened and handed to a C++ service which uses factories to configure the required algorithms tools and services.
  • GaudiPython: a pure python layer on top of Gaudi, a python module, with access to all of the options-file handling of Gaudi, but where the control of the event loop stays in the hands of python, allowing logical python-based algorithms, tools and services.

  • gaudirun.py someoptions.py: interprets your options, invokes your configuration options, passes the result to the job options service and passes control to the Application Manager and gaudi state machine in C++.
  • python someoptions.py: interprets your options, does nothing.
  • python someoptions.py somegaudipythonoptions.py interprets your options, then depending on what you say in your gaudipython part this may invoke your options, and then may run some custom main application loop.

What's the difference between these two jobs? Is there some intelligent way to get the differences (diff) two gaudi jobs?

  • See GaudiDiff, a wrapper around gaudirun.py to do exactly that.

Can I record all the interesting features of a gaudi job locally?

  • Running within Ganga makes for a very simple, reproducable local job, including the xmlsummary.
  • However sometimes you'll be deep into some development needing to run outside of Ganga, in this case See GaudiDiff, a wrapper around gaudirun.py to do exactly that.


-- MarcoCattaneo - 10-Oct-2012

-- PatrickSKoppenburg - 23-Dec-2010

-- Vanya Belyaev - 26 Feb 2009

Edit | Attach | Watch | Print version | History: r38 < r37 < r36 < r35 < r34 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r38 - 2014-04-15 - RobLambert
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    LHCb/FAQ All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback