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.
AbsParmDouble AbsParmGeneral<T> AbsParmFilename AbsParmString AbsParmBool AbsParmIfdStrKey AbsParmVector<T> AbsParmNamedObject<T> AbsParmNamedValue<T> AbsParmPairsIn 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!
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.
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:
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.0then 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:
ana31> gmake clean ana31> rm all.log ana31> 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:
ana31/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 > ana31/workdir>
Now take a look at your new histogram in ROOT:
ana31/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!