MAMbo: Modular Analysis Made in Bologna



MAMbo: Modular Analysis Made in Bologna is an analysis framework that decouples the input part (ntuple reading) from the actual analysis part (cutflows and histogramming). In this way the same code can be applied to different data format. For instance, the definition of an ntuple can change over time. You don't need to manually rewrite everything as with a plain vanilla ROOT MakeClass (). For the advanced users, this can be achieved using the Factory programming pattern.

Getting Started

Download the trunk version from the ATLAS SVN repository:

svn co svn+ssh:// MAMbo 

In principle, all you have to do is

make release 

Did it work? Now, try this out:

cd MAMbo
source bin/
cd run
cp /afs/ .
(modify control/file_list/TTbarResolved/example_ttbar.txt according to your directory structure)
runMAMbo -p control/analysis_params.xml -f control/file_list/TTbarResolved/example_ttbar.txt -o test.histograms.root
root test.histograms.root

In addition, try to submit a job on your LSF batch system ( bsub):

./ -p control/analysis_params.xml -f control/file_list/TTbarResolved/example_ttbar.txt -o example_ttbar.histograms.root -j MAMbo-test

NB: If you don't remember MAMbo's parameters, you can use the autocompletion feature. If you press TAB after the dash:

runMAMbo -[press TAB]

You should see this:

-f          -n          -o          -p          
--filelist  --nevents   --output    --params   


You probably need to setup FastJet v3.X.Y and other packages (some MAMbo helper functions make use of fastjet). If FastJet is not installed, then FASTJETLOCATION is not set and MAMbo will not compile HEPTopTagger and the routine to reconstruct jets from clusters. If FASTJETLOCATION is present, then make will define a new symbol called __USE_FASTJET__ that you can use in your code to switch on/off pieces of code that depends on FastJet:

#ifdef __USE_FASTJET__

You can set up gcc and other sw from .bashrc this way:

function setup_root_afs_gcc46
  export PATH="/afs/$PATH"
  . /afs/${gccv}/x86_64-slc5/

  . /afs/${rootversion}/x86_64-slc5-gcc46-opt/root/bin/

  export FASTJET=/afs/
  export PATH=${PATH}:${FASTJET}/bin

After login, just launch:


How to Run MAMbo

In general, the command line executable requires the following parameters:

runMAMbo -p params.xml -f input_file_list.txt -o output_histograms.root


  • input_file_list.txt is a txt file containing the path of the input files, one for each line. If the path starts with "/" it is interpreted as absolute. Otherwise, if the environment variable MAMBONTUPLEDIR is set, it is prepended to the path. If this variable is not set, then the path is interpreted as relative to the directory in which runMAMbo is executed (maybe you created a symlink?).
  • output_histograms.root is the output file containing your histograms (if any) as defined in histograms.xml (see below)
  • params.xml is a xml file describing your analysis. As an example:
<analysis name="My Fancy Analysis">
    <param name="pTmin" value="20." />
    <param name="etaMax" value="2.5" />
    <param name="control_region" value="1" />

We are telling MAMbo to load the MyAnalysis cutflow (see below how to create it) to read MyNtuple ntuples (see below how to create a wrapper). To speed up the reading part it is better to specify in branch_list.txt which branches have to be switched on. Finally, you can define your histograms in histograms.xml. Some examples:

        <TH1F name="cutflow"      title="CutFlow" nbins="6" xmin="-0.5" xmax="5.5" />
        <TH1F name="el_n"          title="No. of electrons" nbins="6" xmin="-0.5" xmax="5.5" /> 
        <TH1F name="el_pt"         title="Electron p_{T} [GeV]" nbins="200" xmin="0." xmax="1000." />
        <TH1F name="ttbar_pt"    title="ttbar system p_{T} [GeV] nbins="4" edges="0, 40, 100, 250, 1000" />
        <TH2F name="my2Dh"     title="My 2D histogram" nbinsx="10" xmin="0" xmax="10" nbinsy="20" ymin="-5" ymax="5" />
        <TH2F name="my2Dh"     title="My 2D histogram" nbinsx="4" xedges="0,10,20,50,100" nbinsy="5" yedges="-2.5,-1.5,0,1.5,2.5" />

You will fill these histograms in the Cutflow::Apply function. See some examples in:

  • CutFlows/CutFlowTTHTo2LeptonsSS.cxx
  • CutFlows/CutFlowBoostedSL.cxx
  • CutFlows /CutFlowFakeRateZjet.cxx

What do you get (if everything is correct)

This is a typical output:

INFO: parameter pTmin values = 20
INFO: parameter etaMax values = 2.5
INFO: parameter isMCSignal values = 0
DEBUG: Looking for plugins in directory /home/ATLAS/disipio/development/MAMbo/run
DEBUG: Looking for plugins in directory /home/ATLAS/disipio/development/MAMbo/lib/
INFO: Found 2 cutflows
INFO: loading plugin /home/ATLAS/disipio/development/MAMbo/lib//
INFO: Loaded plugin: /home/ATLAS/disipio/development/MAMbo/lib//
INFO: loading plugin /home/ATLAS/disipio/development/MAMbo/lib//
INFO: Loaded plugin: /home/ATLAS/disipio/development/MAMbo/lib//
DEBUG: Looking for plugins in directory /home/ATLAS/disipio/development/MAMbo/run
DEBUG: Looking for plugins in directory /home/ATLAS/disipio/development/MAMbo/lib/
INFO: Found 2 ntuple wrappers
INFO: loading plugin /home/ATLAS/disipio/development/MAMbo/lib//
INFO: Loaded plugin: /home/ATLAS/disipio/development/MAMbo/lib//
INFO: loading plugin /home/ATLAS/disipio/development/MAMbo/lib//
INFO: Loaded plugin: /home/ATLAS/disipio/development/MAMbo/lib//
INFO: Registered cut flows:
* TTHTo2LeptonsSS
* TTbarResolved

INFO: Registered ntuples:
* HWWtth
* TopMini
INFO: Input file: /home/ATLAS/disipio/LOCAL_DISK/minituples/TTbarResolved8TeV/mc12_8TeV.117050.PowhegPythia_P2011C_ttbar.merge.NTUP_COMMON.e1728_s1581_s1586_r3658_r3549_p1562/run0/el.root
DEBUG: list of active branches from control/branch_list_TopMini.txt
DEBUG: No. of active branches = 1
INFO: HistogramManager: output file created: test.root
DEBUG: Created histogram response/h_4j2b_pseudotop_response_lep_pt
DEBUG: Created histogram response/h_4j2b_pseudotop_response_lep_eta
DEBUG: Created histogram response/h_4j2b_pseudotop_response_lep_phi
DEBUG: Created histogram response/h_4j2b_pseudotop_response_lep_E
DEBUG: Created histogram response/h_4j2b_pseudotop_response_lep_absrap
DEBUG: Created histogram response/h_4j2b_pseudotop_response_had_pt
DEBUG: Created histogram response/h_4j2b_pseudotop_response_had_eta
DEBUG: Created histogram response/h_4j2b_pseudotop_response_had_phi
DEBUG: Created histogram response/h_4j2b_pseudotop_response_had_E
DEBUG: Created histogram response/h_4j2b_pseudotop_response_had_absrap
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_pt
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_eta
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_phi
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_E
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_m
DEBUG: Created histogram response/h_4j2b_pseudottbar_response_absrap
INFO: No. of events found in ntuple: 908
INFO: MAMbo will loop on 908 (unweighted) events
INFO: Added analysis channel ALL
INFO: Channel ALL | added counter weighted
INFO: Channel ALL | added counter unweight
INFO: Event 90        (en = 1281644    rn = 195847     )       ( 10 %)
INFO: Event 180       (en = 1646041    rn = 195847     )       ( 20 %)
INFO: Event 270       (en = 1491787    rn = 195847     )       ( 30 %)
INFO: Event 360       (en = 1095565    rn = 195847     )       ( 40 %)
INFO: Event 450       (en = 1822762    rn = 195847     )       ( 50 %)
INFO: Event 540       (en = 1297913    rn = 195847     )       ( 59 %)
INFO: Event 630       (en = 57866      rn = 195847     )       ( 69 %)
INFO: Event 720       (en = 405032     rn = 195847     )       ( 79 %)
INFO: Event 810       (en = 1037941    rn = 195847     )       ( 89 %)
INFO: Event 900       (en = 285659     rn = 195847     )       ( 99 %)
 * Cut flow: Cutflow ALL weighted

 0) All Events                  908
 1) Trigger                     908
 2) Prim. Vtx                   908
 3) SingleLepton                908
 4) ETmiss > 30 GeV             856
 5) mTW > 35 GeV                705
 6) NJets >= 2                  705
 7) NJets >= 4                  703
 8) Nbtags >= 1                 703
 9) Nbtags >= 2                 368
 * Cut flow: Cutflow ALL unweight

 0) All Events                  908
 1) Trigger                     908
 2) Prim. Vtx                   908
 3) SingleLepton                908
 4) ETmiss > 30 GeV             856
 5) mTW > 35 GeV                705
 6) NJets >= 2                  705
 7) NJets >= 4                  703
 8) Nbtags >= 1                 703
 9) Nbtags >= 2                 368

How to Create a Standalone Analysis

We provide a script for your convenience to create a package to run an analysis in a separate directory. The syntax is simple: TestAnalysis AnalysisChannel1,AnalysisChannel2 TreeWrapper,TreeName

The script prints out some basic information about how to proceed.

How to Create a Ntuple Wrapper

First you have to define how your ntuple looks like. You can write it by yourself, but in the case you are reading ROOT trees, there is a script for you:

bin/ -t MyTree -w MyNtuple template.root

In this case we want to create a ntuple of type "MyNtuple" (up to you to decide) from a file called template.root that contains a tree called MyTree. As output, you will get four files:

  • MyTree.h
  • MyTree.cxx
  • NtupleWrapperMyNtuple.h
  • NtupleWrapperMyNtuple.cxx
The first two are generate by calling ROOT MakeClass() function. Please note that you have to manually add using namespace std; if your tree has branches defined as STL classes, like stl::vector<double>.

The wrapper files expose public functions that have to be overloaded according to your needs, e.g. MakeEventInfo(), MakeElectrons(), MakeJets(). There are few C++ preprocessor macros to simplify the matter:

  • GET_VALUE(branch_name)
  • GET_VALUE_ARRAY(array, pos)
  • GET_VALUE_VECTOR( vec, pos )
  • CHECK_TRIGGER(triggername)
You can add your ntuple by putting the files in Ntuples/, then either modify the Ntuples/Makefile like this:

NTUPLES = HWWtth MyNtuple

or simply run the compiler this way:

NTUPLES=MyNtuple make release

How to Create a Cutflow

There is a script for you: bin/ MyAnalysis

The wizard will create two files:

  • CutFlowMyAnalysis.h
  • CutFlowMyAnalysis.cxx
You can add your cutflow by putting the files in CutFlows/, then either modify the CutFlows/Makefile like this:

CUTFLOWS = TTHTo2LeptonsSS MyAnalysis

or simply run the compiler this way:

CUTFLOWS= MyAnalysis make release

Typically, what you have to do is to overload the Apply() function:

virtual bool Apply( EventData * ed, int * lastCutPassed = NULL );

See for example:


For Developers

MAMbo was designed taking into account some design patterns such as the factory, the interface and the singleton.

As written in the twiki page, thanks to these programming techniques MAMbo decouples the input part (ntuple reading) from the actual analysis part (cutflows and histogramming), so in principle we can run the same analysis on multiple input formats, provided that you write a wrapper. A wrapper is a piece of code that maps what is in the ntuple to the event data (src/EventData.h).


To do so, the trick is to create a templated class (e.g. Ntuples/NtupleWrapperTopMini.h) that “wraps” your ntuple, which in turn is created using the TTree::MakeClass() function.

Relevant files:

src/INtupleWrapper.h Declares the external interface of a wrapped ntuple ( NextEvent(), SetActiveBranches(), etc..) and some pure virtual functions to be overloaded that are supposed to take care of filling the event data ( MakeElectrons(), MakeJets(), etc..)

src/NtupleWrapper.h Actual implementation of the ntuple wrapper. It appears as a header because the class is templated.

You can create your own ntuple wrapper with the script called bin/

Event data

The second “core concept” is that event information is stored in the EventData structure. It is designed as a structure-of-arrays (collection of arrays of pT, eta, phi, E, etc..) instead of an array-of-structures (e.g. vector of TLorentzVector ).

See the file: src/EventData.h

This is because AoS are better handled in memory, but at the price of less flexibility and redundancy. For example, in src/PhysicsHelperFunctions.h you can find a number of functions to map four-momenta from the PtEtaPhiE to the PxPyPzE representation.

Cut flow

Another “core concept” is the definition of a cut flow. See the file src/ICutFlow.h . The end-user has to use this base class to derive a specialized class that actually defines the function Apply( EventData * ed ), pure virtual in the base-class.

See for instance: CutFlows/CutFlowFakeRateZfjet.h and CutFlows/CutFlowFakeRateZfjet.cxx

During the cut flow, you can access (read or modify) the EventData object (ed), for example: ed-> ed->MET.mwt

In order to let end-user to code their own cut flow, I set up a machinery based on the so-called “factory design pattern" borrowed from Rivet ( to load the cutflow at runtime as plugins. You’ll find some definitions like this in the headers:

typedef CutFlowPluginFactory< CutFlowFakeRateZfjet > CutFlowPluginFactory_FakeRateZfjet;

extern "C" {
  CutFlowPluginFactory_FakeRateZfjet * MakeCutFlowPlugin();

The idea is that MAMbo scans the working directories looking for files called for instance This means that the library exports a function called MakeCutFlowPlugin() that returns an object of class CutFlowPluginFactory_FakeRateZfjet. This is in turn a typedef (see: src/CutFlowFactory.hpp). The sub-string “FakeRateZfjet” is used to index uniquely the cut flow.

You can create your own cut flow with the script bin/ .

Histogram Fillers

Different cut flows may share the same procedure to fill similar histograms. MAMbo provides a base-class and a plugin facility to solve this problem. You have create derived class from IHistogramFiller, which must implement the following functions:

virtual void Configure( const HistogramFillerParams_t& params );
virtual void Fill( const EventData& ed );

See for example HistogramFillers/HFFinalStateObjects.cxx.

You can create your own histogram filler with the script bin/ .

To compile, simply run the compiler this way:

HFILLERS=MyHistogramFiller make release

Developing MAMbo with Netbeans

Download NetBeans IDE from this link.

  • Checkout using Team->Subversion->Checkout
  • Use existing makefile. Use gcc tools by default.
  • Create a script (e.g. $HOME/ to define ROOT, GCC and FastJet as described above
  • Modify the project's options:
    • Build Command: sh -c "source $HOME/; cd MamboBaseFolder; ${MAKE} -f Makefile"
    • Working Directory: MamboBaseFolder
    • Clean Command: ${MAKE} -f Makefile clean
    • Build Result: MamboBaseFolder/bin/runMAMbo
    • Run Command: "${OUTPUT_PATH}" -p control/analysis_params.xml -f control/file_list/TTbarResolved/example_ttbar.txt -o test.histograms.root

Then you still have to add MAMbo to PATH and LD_LIBRARY_PATH. We still don't have a clue about how to do it in Netbeans (in principle it should source the script).

Finally, push the "hammer" button to compile. If everything is ok you should be able to run MAMbo in your shell.

MoMA: Modules of MAMbo for ATLAS

MoMA provides a bridge between MAMbo and ATLAS AnalysisTop. It is an additional package that can be compiled if needed. If the USE_ANALYSISTOP environment variable is set, MAMbo recognizes the presence of this package and links against the libraries listed in MoMA/ .

To compile MoMA, just do:

cd MoMA
make release # or make debug

If all is ok, you should see a final output like this:

ATLAS RootCore installed in /cvmfs/ 
MAMbo installed in /home/ATLAS/disipio/development/MAMbo installed in /home/ATLAS/disipio/development/MAMbo/lib

When you try to compile MAMbo with AnalysisTop set up, you'll see that a preprocessor symbol is defined: __MOMA__. You can use this symbol in your code to switch on/off some parts of your code that depends on the presence of ATLAS-specific classes. For example, to include MoMA 's header:

#ifdef __MOMA__
#include "MoMA/MoMA.h"

To call the ATLAS routines that have been implemented (not many at the moment), you have to get a handle to the MoMA tool:

#ifdef __MOMA__
MoMATool * m_moma = MoMATool::GetHandle();
cout << "INFO: ATLAS ROOTCORE detected. MoMA tool initialized." << endl;
qcd_weight = m_moma->GetFakesWeight( rc_channel, rc_event, rc_lepton, tight );

See also CutFlows/CutFlowTTbarResolved.h and CutFlows/CutFlowTTbarResolved.cxx for a real-life usage.

Bootstrap functionality (work in progress)

The implementation of the Bootstrap functionality is currently work in progress in the branch svn+ssh://, and is documented in the JIRA issue

The Bootstrap package can be integrated in your AnalysisTop installation:

svn+ssh:// BootstrapGenerator
rc find_packages
rc compile

The BootstrapGenerator package is accessed via MoMA. In order to enable in MAMbo the link to Bootstrap, the MAMBO_USE_BOOTSTRAP env variable must be set:


Bootstrap-specific pieces of code need to be wrapped in the #ifdef BOOTSTRAP_MAMBO directive, for example:

#pragma message("INFO: adding bootstrap support")
#include "BootstrapGenerator/BootstrapGenerator.h"
#include "BootstrapGenerator/TH1DBootstrap.h"


A special ntuple format will be the default one for the Run2 analyses. MAMbo has a limited support for xAOD (and derivations) which will grow in due time. To read xAODs, an additional ntuple wrapper must be compiled. However, since it heavily depends on the class xAODRootAccess, it only works if RootCore is set up. To compile:

cd my_rootcore_dir
#export MAMBO_USE_XAOD=1
MAMBO_USE_XAOD=1 make release # or make debug

In you analysis params file you have to specify:


Contact the core developers if you intend to do a non-trivial usage of this format now.

Producing the Plots

MAMbo provides a series of python programs to blend (=weighted sum) the histograms and produce the final plots. Here's a description of the workflow:

  1. Produce the ROOT histogram files: if you are running on a LSF cluster, can do it for you. Its syntax is the same as runMAMbo, but you can also specify the job name: -p param_file.xml -f file_list.txt -o outfilename.root -j jobname
  2. Blend the histograms: You probably need to merge various subsamples by weighting each one by its cross-section. You can do it using this script: -c config_file.xml -o output_file.root

The XML configuration file is structured as follows:

<?xml version="1.0" encoding="UTF-8"?>
  <histogram hpath="reco/reco_4j2b_jet_pt" />
  <sample name="singletop_tchannel_top"     dsid="110090" xsec="17.520" kfact="1.0500" genevt="4994481" generator="PowhegPythia_P2011C" simulation="Full" />
  <sample name="singletop_tchannel_antitop" dsid="110091" xsec="9.3932" kfact="1.0616" genevt="4999879" generator="PowhegPythia_P2011C" simulation="Full" />
  <file sample="singletop_tchannel_top"     path="/home/ATLAS/disipio/development/MAMbo/run/output/tt_diffxs_8TeV.110090.singletop.el.histograms.root" />
  <file sample="singletop_tchannel_antitop" path="/home/ATLAS/disipio/development/MAMbo/run/output/tt_diffxs_8TeV.110091.singletop.el.histograms.root" />

For a complete example you can take a look at the file share/control/merge_subsamples_singletop_el.xml

  1. Calculate the uncertainty bands: Once you have all your histograms in place, you can calculate the uncertainty band. The script will sum all the histograms defined in the configuration file, and will output a ROOT file containing TGraph objects you can later use to produce the final plots. -c config_file.xml -o outputfile.root

The syntax of the configuration file is similar to what is used to blend the plots. For example:

<?xml version="1.0" encoding="UTF-8"?>
  <histogram hpath="reco/reco_4j2b_jet_pt" />
  <histogram hpath="reco/reco_4j2b_fjet_pt" />
  <sample name="ttbar"     file="/home/ATLAS/disipio/development/MAMbo/run/output/" />
  <sample name="singletop" file="/home/ATLAS/disipio/development/MAMbo/run/output/" />       

See for instance share/control/merge_subsamples_uncertainty_el.xml.

  1. Make the plots: Finally, you have put all the pieces together. To make the actual plots, launch: config_file.xml 

The syntax of the configuration file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
  <plot hpath="reco/reco_4j2b_jet_pt"                   xtitle="AntiKt4 jet transverse momentum [GeV]"         ytitle="Events / GeV"  scale="log" />
  <plot hpath="reco/reco_4j2b_fjet_pt"               xtitle="Fat jet transverse momentum [GeV]"             ytitle="Events / GeV"  scale="log" />
  <sample name="data"        type="data"        description="Data"                color="1"     fillstyle="0"    linewidth="0" />
  <sample name="ttbar_ljets" type="signal"      description="t#bar{t} (l+jets)"   color="32"    fillstyle="1001" linewidth="2" />
  <sample name="singletop"   type="background"  description="Single top"          color="4"     fillstyle="1001" linewidth="2" />        
  <sample name="uncertainty" type="uncertainty" description="Stat + sys. uncert." color="1"     fillstyle="3004" linewidth="2" />  -->
  <file sample="data"         path="/home/ATLAS/disipio/development/MAMbo/run/output/" />
  <file sample="ttbar_ljets"  path="/home/ATLAS/disipio/development/MAMbo/run/output/" />
  <file sample="singletop"    path="/home/ATLAS/disipio/development/MAMbo/run/output/" />
  <file sample="uncertainty"  path="/home/ATLAS/disipio/development/MAMbo/run/output/" />

A complete example can be found in share/control/basic_plots.xml.

Edit | Attach | Watch | Print version | History: r24 < r23 < r22 < r21 < r20 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r24 - 2017-03-06 - MarinoRomano
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    Main All webs login

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