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:
-
HBOOK
persistency is not available for 64-bit platforms.
- 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:
-
HBOOK
persistency is not available for 64-bit platforms.
- Gaudi
requires the same persistency for histograms and N-Tuples
- 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:
- Local counters through
GaudiAlgorithm
and GaudiTool
base classes
- Counter form Statistical Service
IStatSvc
- 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:
- The files
$GAUDIEXAMPLESROOT/src/CounterAlg.cpp
and $GAUDIEXAMPLESROOT/options/CounterEx.opts
illustrate the usage of the local generic statistical counters
- The file
$GAUDIEXAMPLESROOT/python/CounterEx.py
illustrate the usage of the statistical counters in Python
- The files
$GAUDIEXAMPLESROOT/src/StatSvcAlg.cpp
and $GAUDIEXAMPLESROOT/options/StatSvcAlg.opts
illustrate the usage of the statistical counters and IStatSvc
- 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
-
bool
-
char
, unsigned char
, signed char
-
short
, unsigned short
-
int
, unsigned int
-
long
, unsigned long
-
long long
, unsigned long long
-
float
, double
, long double
-
std::string
For each basic scalar type, the corresponding
std::vector<TYPE>
is also supported.
Other types:
-
std::pair<double,double>
-
std::vector<std::pair>double,double> >
-
std::pair<int,int>
-
std::vector<std::vector<std::string> >
-
std::vector<std::vector<double> >
Associative properties:
-
std::map<int,double>
-
std::map<std::string,std::string>
-
std::map<std::string,int>
-
std::map<std::string,double>
-
std::map<std::string,std::vector<std::string> >
-
std::map<std::string,std::vector<int> >
-
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?
- You can add an
InputCopyStream
or MDFWriter
to your existing options
- 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