Run-Time Parameters
One of the major advantages of BaBar's Framework/module code structure
is that it gives the user run-time
control of an analysis job. The user can enable or disable a module in
the execution path, or use the module talk command to change a module's
run-time parameters while running the analysis. All of these changes
can be implemented without having to recompile or relink the code.
In the Framework section, you
learned how to talk to modules and reset their run-time parameters.
But you found that the Workbook's example module, QExample, does not
yet have any run-time parameters. In this section, you will upgrade
some of QExample's parameters to run-time parameters.
BaBar's C++ class for run-time parameters is called AbsParm.
There are many different types of AbsParm, including:
AbsParmDouble
AbsParmGeneral<T>
AbsParmFilename
AbsParmString
AbsParmBool
AbsParmIfdStrKey
AbsParmVector<T>
AbsParmNamedObject<T>
AbsParmNamedValue<T>
AbsParmPairs
In particular, two important AbsParmGeneral<T> types are:
AbsParmGeneral<double>
AbsParmGeneral<int>
the AbsParm classes for double and integer run-time parameters.
Note that some of the header files for members of the AbsParm family
are stored the Framework package, while others are stored in the
the AbsParm package. When you #include your AbsParm header
file, make sure you get the package right!
Creating run-time parameters
To turn a parameter into a run-time parameter, the first step
is to declare it as an AbsParm of the same type. For example, suppose you want to define a maximum lepton momentum, _pMaxLep, as a run-time parameter. In the module's header file, #include the AbsParm header file:
#include "Framework/AbsParmGeneral.hh"
and declare the parameter:
private:
AbsParmGeneral<double> _pMaxLep;
The next step is to initialize the parameter.
The place to do this is in the module's constructor
(in the module's .cc file):
MyModule::MyModule( const char* const name,
const char* const description )
: AppModule( name, description ),
_pMaxLep("plmax", this, 1.5)
{
Note the syntax: the initialization goes after
"AppModule( name, description)," and before the first
curly bracket "{".
When you declare/initialize an AbsParm, it is passed three arguments.
- the command name; a string in double quotes,
- a module (the parameter's target): use the "this" pointer,
- a value (of the appropriate parameter type).
AbsParm parameters make sense only in the context of module classes. The
command name ("plmax") is the name used from the Framework (when
talking to the module) to access the parameter. The value (1.5)
is the (default) value of the run-time parameter. This value is what the
user can change from within the Framework.
Declaring a module data member of an AbsParm type is not enough
to make it accessible to/from the Framework. It needs to be a member of the
module's commands list. This is accomplished by the following append command:
commands()->append(& name);
This command also goes in the module's constructor, but it is
placed after the curly bracket:
MyModule::MyModule( const char* const name,
const char* const description )
: AppModule( name, description ),
_pMaxLep("plmax", this, 1.5)
{
commands->append( & _pMaxLep);
}
Now _pMaxLep is a run-time parameter. To use it
in your code (ie, in the event or beginJob functions),
you use one of AbsParm's public member functions:
- value( ) : returns the value of the parameter.
- set( ) : sets the value of the parameter.
For example, to use _pMaxLep in your code:
MyModule::event(AbsEvent* anEvent) {
...
if (pLepton > _pMaxLep.value() ) nFast++;
This has the same effect as:
if (pLepton > 1.5 ) nFast++;
But now _pMaxLep is a run-time parameter. So if it
is reset to 2.0 in a mod talk session,
> mod talk MyModule
MyModule> plmax set 2.0
then the effective statement becomes:
if (pLepton > 2.0 ) nFast++;
(It's Example 4 because the last example in the Editing Code section was Example 3.)
Now let's put this together and modify the QExample module to take advantage
of the Framework's interactive capabilities. This example assumes
that you have followed the instructions in Example 2 of the Workbook's editing
code section, and modified QExample to include a momentum histogram.
If not, then you can copy the modified QExample module from:
$BFROOT/www/doc/workboook/examples/ex2/
This time, instead of modifying QExample, you will create a new
module based on QExample. To begin, copy your QExample.cc
and .hh files into ones named ParmExample.cc and .hh respectively. You will
need to uniformly change all instances of QExample to ParmExample.
In the ParmExample header file add the following private data
members to the class definition/declaration:
AbsParmGeneral<int> _nbins;
AbsParmGeneral<double> _pMin;
AbsParmGeneral<double> _pMax;
AbsParmIfdStrKey _trackList;
The first three AbsParm variables will be used for the momentum histogram
parameters (number of bins, and the x-axis low and high limits).
The fourth AbsParm variable will be used for the name of the
BtaCandidate list (for example, "ChargedTracks"). At first
glance this looks like a string, so you might think that
this should be an AbsParmString. But in fact, BtaCandidate list
names are not strings. Their class is "IfdStrKey".
So the correct AbsParm type is AbsParmIfdStrKey.
To use these new data type you will need to #include the appropriate header
files in ParmExample.hh:
#include "Framework/AbsParmGeneral.hh"
#include "AbsParm/AbsParmIfdStrKey.hh"
(As mentioned above, for some reason, some AbsParm header files
are stored in Framework, and some in AbsParm.)
Now, in the .cc file, initialize the variables in the constructor
declaration (before "{"), and add the parameters to the command list in the
constructor (after "{"):
ParmExample::ParmExample( const char* const name,
const char* const description )
: AppModule( name, description ),
_nbins("nbins",this,25),
_pMin("pMin",this, 0.),
_pMax("pMax",this, 1.0),
_trackList("trackList", this, "ChargedTracks")
{
commands()->append( & _nbins );
commands()->append( & _pMin );
commands()->append( & _pMax );
commands()->append( & _trackList );
}
In this example the command names are the same (aside
from the "_") as the AbsParm names, but that is not required.
The commas can be tricky, so be careful: Notice that all the parameter
initializations have commas after them, except the last one.
AppModule( name, description ) also gets a comma (unless there
are no run-time parameters, making it the last item on the list).
The final step is to use these parameters in the context of the module code.
When you booked the momentum histogram you explicitly passed values for the
number of bins, low- and high-range values. Now you want the code for your
histogram to use these interactive parameters. Recall each AbsParm type of
parameter has an accessor function named value().
Use this function to pass the histogram manager each parameter's value.
_pHisto = manager->histogram("pTrack", _nbins.value() , _pMin.value(), _pMax.value() );
Now changes to these parameter values will be reflected in changes to the
different aspects of the histogram.
You may have noticed that I changed the name of the histogram
from "Momentum" to "pTrack." I did this so that it would not
overwrite QExample's Momentum histogram. For the same reason, let's
change the name of the number-of-tracks histogram as well:
_numTrkHisto = manager->histogram("nTrack", 20, 0., 20. );
(You could choose to make _numTrkHisto's settings into run-time
parameters as well, but we will not do that in this example.)
Similarly, you can replace the explicit call to "ChargedTracks" with the
run-time parameter as follows:
HepAList<BtaCandidate>* trkList =
Ifd<HepAList< BtaCandidate > >::get(anEvent, _trackList.value());
After making these changes you will need to add ParmExample
to the Framework by modifying the AppUserBuildBase.cc file.
Instead of replacing QExample, let's append ParmExample to the same path.
That way you can compare the two modules from within the
Framework. Add the following lines to AppUserBuildBase.cc, just after the
equivalent lines for QExample:
#include "BetaMiniUser/ParmExample.hh"
and
theBuild->add(new ParmExample("ParmExample", "Run-time parameter example module"));
The last step is to modify MyMiniAnalysis.tcl to add your new module
to the path. Again after the equivalent line for QExample, put:
path append Everything ParmExample
A working example of the ParmExample module (and the associated
AppUserBuildBase.cc and MyMiniAnalysis.tcl files) is provided in:
$BFROOT/www/doc/workboook/examples/ex4/
Because you changed C++ code (.cc and .hh files), you will have
to recompile and relink for your new module to be added to the framework:
ana42> gmake clean
ana42> rm all.log
ana42> bsub -q bldrecoq -o all.log gmake all
For more information about compiling and linking, refer
back to the Compile and Link section.
Run the executable and investigate the two modules by looking
at the module talk options. Then analyse a few events, change some
parameters, and analyse further events. Here is a sample dialog of
such an investigation:
ParmExample Investigation
ana42/workdir> BetaMiniApp snippet.tcl
(Lots and lots of output...)
> echo The echo command prints whatever I say.
The echo command prints whatever I say.
> mod talk QExample
QExample> help
Command(s) available in the "QExample" module:
echo Send text argument to stdout (useful in scripts).
exit Leave the current menu, module, or process
help Bring up help text for the current context.
show Display the value of any parameters or statistics.
sourceFoundFile Source file in $BFDEFAULTSEARCHPATH or $BFSEARCHPATH.
verbose bool parameter: set or list.
production bool parameter: set or list.
enableFrames bool parameter: set or list.
QExample> echo Nothing interesting to do in QExample. I'm getting out of here.
Nothing interesting to do in QExample. I'm getting out of here.
QExample> exit
> mod talk ParmExample
ParmExample> show
Current value of item(s) in the "ParmExample" module:
Value of verbose for module ParmExample: f
Value of production for module ParmExample: f
Value of enableFrames for module ParmExample: f
Value of nbins for module ParmExample is 50
Value of pMax for module ParmExample is 2
Value of pMin for module ParmExample is 0
Value of trackList for module ParmExample: IfdStrKey(ChargedTracks)
ParmExample> echo Look - there are the new parameters I created!
Look - there are the new parameters I created!
ParmExample> echo I wonder if I can change their values.
I wonder if I can change their values.
ParmExample> help
Command(s) available in the "ParmExample" module:
echo Send text argument to stdout (useful in scripts).
exit Leave the current menu, module, or process
help Bring up help text for the current context.
show Display the value of any parameters or statistics.
sourceFoundFile Source file in $BFDEFAULTSEARCHPATH or $BFSEARCHPATH.
verbose bool parameter: set or list.
production bool parameter: set or list.
enableFrames bool parameter: set or list.
nbins general parameter: set or list.
pMax general parameter: set or list.
pMin general parameter: set or list.
trackList string key parameter: set or list.
ParmExample> pMin set -1.5
ParmExample> pMax set 1.5
ParmExample> nbins set 100
ParmExample> trackList set GoodTracksLoose
ParmExample> show
Current value of item(s) in the "ParmExample" module:
Value of verbose for module ParmExample: f
Value of production for module ParmExample: f
Value of enableFrames for module ParmExample: f
Value of nbins for module ParmExample is 100
Value of pMax for module ParmExample is 1.5
Value of pMin for module ParmExample is -1.5
Value of trackList for module ParmExample: IfdStrKey(GoodTracksLoose)
ParmExample> echo Parameters successfully changed.
Parameters successfully changed.
ParmExample> exit
> mod talk KanEventInput
KanEventInput> input add /store/SP/R14/001237/200309/14.3.1c/SP_001237_000533
KanEventInput> input list
Files:
/store/SP/R14/001237/200309/14.3.1c/SP_001237_000533
Components:
hdr
tag
aod
cnd
KanEventInput> exit
> echo Okay, I guess I've done enough. Now run the job.
Okay, I guess I've done enough. Now run the job.
> ev beg -nev 40
(Lots and lots of output...)
> exit
> ana42/workdir>
Now take a look at your new histogram in ROOT:
ana42/workdir> bbrroot
root[] TFile f("myHistogram.root");
root[] f.ls();
TFile** myHistogram.root Created for you by RooTupleManager
TFile* myHistogram.root Created for you by RooTupleManager
KEY: TH1F h1d1;1 MC reco abs mtm difference
KEY: TH1F h1d2;1 Reco track momentum
KEY: TH1F h1d3;1 Tracks per Event
KEY: TH1F h1d4;1 Momentum
KEY: TH1F h1d5;1 nTrack
KEY: TH1F h1d6;1 pTrack
KEY: TH1F h1d7;1 TagInspector Status
Now your ROOT file contains both the old histograms from QExample,
and the new histograms from ParmExample.
Take a look a the number-of-track histograms:
root[] h1d3->Draw();
root[] h1d5->Draw();
and the momentum histograms:
root[] h1d4->Draw();
root[] h1d6->Draw();
The default settings for ParmExample are the same as the
settings for QExample. So if you had not modified the
run-time parameters in your Framework session, then the
histograms would have been identical.
However, you can see that your changes did indeed have
an effect. Now the momentum histogram limits are from -1.5 to 1.5 -
not a very useful setting, since there are no tracks with
negative momentum! Instead of 25 bins, now there are 100.
And because you switched to the GoodTracksLoose list,
there are 314 entries instead of 459, and the momentum
distribution itself is different.
As for the number-of-tracks
histograms, they are also different due to the use of GoodTracksLoose
instead of ChargedTracks.
Fortunately, now that your parameters are run-time parameters,
you can easily change the number of bins and the axes limits
to reasonable values, and investigate many different
particle candidate lists - all without having to recompile
or relink your code!
Page maintained by Adam Edwards
Last modified: January 2008
|