Repository navigation
rootana create module
This will take you through the steps to get a working module. It should highlight some of the basic concepts of the module framework and how the modules are made to be configurable.
I'll assume you've got rootana compiled and have sourced thisdaq.sh in the AlcapDAQ directory.
I'll use the variable ROOTANA_HOME to point to the rootana directory where you run make. This is equivalent to $DAQDir/analyzer/rootana.
Creating a new module or generator from scratch is most easily achieved by using the CreateModule.sh script, located in $DAQDir/analzyer/rootana/scripts/, (although it should be executable from any location).
Usage for the CreateModule.sh script can be obtained by running the script with no arguments:
./CreateModule.sh
> Usage: ./CreateModule.sh Name [Type] [TargetDirectory]
> Script to create a set of skeleton files to implement a new module or generator
> ModuleName = The name of the new component.
> Type (optional) = Make a special type of component.
> Must be one of: module TAP_generator TDP_generator TME_generator
> Default is 'module'.
> TargetDirectory = Specify a target directory to place the new files.
> (optional) Default is src or one of the *_generators directories if 'type==*generator'
To create a new module, only 1 argument is necessary, the name of the new module. To make a module called MyFirstModule do:
cd $ROOTANA_HOME
./scripts/CreateModule MyFirstModuleNow look in the src directory, and you should see, amongst the other code directories, a new header and implementation file:
ls src/*.*
> files.make LibraryLinkDef.h main.cpp
> MyFirstModule.cpp MyFirstModule.h testModule.txtThe files.make and LibraryLinkDef.h files are there to help build rootana, and we don't need them yet. main.cpp is the code used to build the actual rootana executable. testModule.txt is an example modules file which we'll use shortly.
For now though, let's try running make from ROOTANA_HOME and test the new module.
cd $ROOTANA_HOME
makeAssuming that completes without a problem (the final line should read: Building Rootana) we're good to try running.
Now we need to go back to the testModule.txt file. This file is an example of what we're calling a MODULES file and tells rootana how to run. It tells rootana which modules to run with and how to configure each one.
To use your new module, open this file in a text editor.
Tip: If you're working with vim, run
:set syn=cfgwhich will highlight this file nicely. If you're not working with vim, try switching to vim!
It's worth reading through the comments in this file as they explain a lot of how the file works. Actually, I'm not going to copy this here (so I only need to maintain one area), so that's the best place right now to understand the file. I'll wait a while for you to read it.....
Once you're satisfied with reading things, go to the part of the file which says: [MODULES]. You should see (without the comments):
[ MODULES ]
analyse_pulses = MakeAnalysedPulses
detector_pulses = MakeDetectorPulses
muon_events = MakeMuonEvents
draw_pulses = ExportPulseTo use our new module, add it's name to this list, ideally just above ExportPulse. Let's also give it an alias so we can use a later section of the file to give the module options. The alias is the part to the left of the equals sign.
The MODULES section should now look something like:
[ MODULES ]
analyse_pulses = MakeAnalysedPulses
detector_pulses = MakeDetectorPulses
muon_events = MakeMuonEvents
my_first_module = MyFirstModule
draw_pulses = ExportPulseAt this point, you can close the modules file and run rootana with it. You need an input file (one of alcapana's output tree files) to be able to run rootana. If this file is called input.root, run rootana with:
./rootana -m src/testModule.txt -i input.root -o output.root -r 10The -r 10 option means we only process up to 10 events, useful for debugging. See the rootana mainpage for more details of the command line options.
You should see some output from the new module, something like:
-----MyFirstModule::BeforeFirstEntry(): I'm debugging!
-----MyFirstModule::BeforeFirstEntry(): x_max is: 100
...
...
-----MyFirstModule::AfterLastEntry(): I'm debugging!
If you don't, make sure your module file has the debug=all option set near the top of the file, before any of the section headers.
Now I'll look at how modules get options from a MODULES file. Open up the implementation file of the new module, and find the constructor, somewhere near the top.
The code there should look something like:
MyFirstModule::MyFirstModule(modules::options* opts):
FillHistBase("MyFirstModule",opts){
fXMax=opts->GetDouble("x_max",100);
}The key points to notice:
- The constructor of a module always receives a pointer to modules::options. This is passed on to base class which means we can set common options for all modules quite easily.
Tip: Options at the top of the Modules file (before any section header) are used as global options. For example, give
debug=allbefore a section header and every module will be passed thedebugoption. The modules base class then uses this to set theDebug()method to returntrueorfalsefor debug mode.
- You can obtain different types of variables from the module's options. As well as
GetDoubleyou can call:GetInt,GetStringandGetBool. Each returns the type you would expect and takes as the first argument the name of the option (the part to the left of the equals sign in the modules file). You can also specify a default value to return if the option wasn't provided by using the second argument. Look at the header file for modules::options for more possible getters (TODO: link to the doxygen version when it's ready).
All this mechanism allows us to send controls into a module without having to recompile. If you followed the steps above, we gave an alias for the new module when we asked to run with it in the MODULES section:
my_first_module = MyFirstModuleNow we can use that alias to create a section in the modules file and pass in options to that module. To show this, open the testModule.txt file again and scroll to the last section (probably named draw_pulses). Create a new section using the alias from above and give the x_max option some value. The new section should look like:
[my_first_module]
x_max=283Now run rootana again. The output should now show a different value for x_max.
There is one other way to get options to a module, which is to treat the Module name in the list of Modules like a constructor. Any number of arguments can be given this way, but for them to be meaningful we need to name them.
To see how we do this, open the implementation file of the new module and go to the bottom, to the line looking something like:
ALCAP_REGISTER_MODULE(MyFirstModule,x_max);The primary reason for this line is to tell rootana that this module exists. This is the purpose of the first argument. Every subsequent argument is then used to name the possible arguments that this module might get. Because this skeleton modules file has already named an argument x_max, if we go back to the modules file and replace the line:
my_first_module = MyFirstModulewith:
MyFirstModule(213)when we run again, we will now see the value of x_max is changed from the default 100 to 213.
Notes:
- We didn't need to remove the alias. However, if we had not done this, the section later on would over-ride the value of x_max. This way, the later section is silently ignored.
- If you do give argument names to
ALCAP_REGISTER_MODULE, this doesn't force to use the constructor-style approach in the modules file, it just gives you the option to do this. I suspect that most options will be given using aliased sections, but some very simple modules, that make a single plot for instance may be happier using the constructor-style approach.
Todo:
- Event navigator, access to data object and storing them
- Have to wait for Phill to finish interface
- Saving plots
- Drawing pulses with ExportPulse
- Probably put elsewhere
- General tips, requests, ideas etc
These generators use a very similar interface to the one described above for modules.
You can also use the CreateModule.sh script to produce a template by giving a second argument of the type of generator you want, for example:
cd $ROOTANA_HOME
./scripts/CreateModule MyFirstAPGenerator TAP_generatorThe key differences between generators and modules:
- At this time, generators don't use the modules file in the same way, it depends on the calling module (such as MakeAnalysedPulses for TAP generators) as to how options from the file get passed through to the generator.
- All generators must end with {AP,DP,ME}Generator. This is used so that in the Register macro, the name of the class should drop the ..Generator part. The same is true in the modules file, where this part of the name is not needed.
- APGenerator for Analysed pulse generators
- DPGenerator for Detector pulse generators
- MEGenerator for Muon event generators
- The preprocessor macro to register a generator is
ALCAP_TAP_GENERATOR,ALCAP_TDP_GENERATORandALCAP_TME_GENERATORfor the corresponding pulse types. The arguments that this macro takes are equivalent to those for registering a module, except for the naming convention mentioned above. - Generators have different base methods to implement. Look at the base classes (TV...Generator) for what they are.