simple/source/MainSimple.cpp

A simple TMVA based analysis

The analysis class

#pragma once
// include the Analysis base class
namespace simple
{
// all Analyses inherit from the boca::Analysis base class
// the base class expects an Tagger class as template parameter
template<typename Tagger_>
class Analysis : public boca::Analysis<Tagger_>
{
public:
// override some functions of the base class
// Set Files used in the analysis
void SetFiles(boca::Phase const& phase) override
{
switch (phase.Tag()) {
// add a signal file by passing its file and process name
this->AddSignal("hh_14TeV-500GeV", "h");
break;
// add a background file by passing its file and process name
this->AddBackground("bb_14TeV-500GeV", "bb");
break;
}
}
// define how many events are supposed to beeing used
long TrainNumberMax() const override
{
return 1000;
}
// define the analysis name
std::string Name() const override
{
return "SimpleAnalysis";
}
};
}

The Tagger class

#pragma once
// include the Tagger base class
// include the simple Observable definition
// include the simple Branch used by TMVA
#include "simple/Branch.hh"
namespace simple
{
// each Tagger class must inherit from the boca::Tagger base class
// the Base class expect a set of Observables and a root Branch definition as template paramter
class Tagger : public boca::Tagger<Observables, Branch>
{
public:
// The first phase during a multivariant analysis is called Training phase
int Train(boca::Event const &event, boca::PreCuts const &pre_cuts, boca::Tag tag) override;
// During the second Reading phase we retrieve objects of the Observable set
std::vector<Observables> Multiplets(boca::Event const &event, boca::PreCuts const &pre_cuts, TMVA::Reader const &reader) override;
// Name of the Tagger
std::string Name() const override;
};
}

The Tagger definition

#include "simple/Tagger.hh"
namespace simple
{
int Tagger::Train(boca::Event const &event, boca::PreCuts const &, boca::Tag tag)
{
// Create one object of the the Observables and pass it the full event information
Observables observables(event);
// save also weather the Tag is signal or background
observables.SetTag(tag);
// Save the observables to the root file and return the number of saved objects (in this case always one)
return SaveEntries({observables});
}
std::vector<Observables> Tagger::Multiplets(boca::Event const &event, boca::PreCuts const &, TMVA::Reader const &reader)
{
// Create one object of the the Observables and pass it the full event information
Observables observables(event);
// save also the BDT response to this object
observables.SetBdt(Bdt(observables, reader));
// return all objects (in this case only one)
return {observables};
}
std::string Tagger::Name() const
{
return "Simple";
}
}

The Observable class

#pragma once
// include the Identification base class
// include the Event class
namespace simple
{
// use members of boca::units without prefix
using namespace boca::units;
// Each Observable is calculated by a function of this class
// Additionally the Tag and the BDT response has to be saved, which is done in the Identification base class
class Observables : public boca::Identification
{
public:
// The constructor takes the complete event
Observables(boca::Event const &event);
// The number of leptons
int LeptonNumber() const;
// The number of jets
int JetNumber() const;
// The number of bottom jets
int BottomNumber() const;
// The sclar sum of the transvers momenta
Momentum ScalarHt() const;
// The transverse momentum of the n'th jet
Momentum JetPt(unsigned number) const;
// The transverse momentum of the n'th lepton
Momentum LeptonPt(unsigned number) const;
// The missing transvser energy
Energy MissingEt() const;
private:
// storage for the jets
std::vector<boca::Jet> jets_;
// storage for the leptons
std::vector<boca::Lepton> leptons_;
// storage for the scalar ht
Momentum scalar_ht_;
// storage for the missing et
Energy missing_et_;
};
}

The Observable definition

namespace simple
{
// Get the basic objects from the event
{
// store the jets sorted by pt
jets_ = boca::SortedByPt(event.Jets());
// store the leptons sorted by pt
leptons_ = boca::SortedByPt(event.Leptons());
// store the scalar ht
scalar_ht_ = event.ScalarHt();
// store the missing et
missing_et_ = event.MissingEt().Pt();
}
{
// return the number of leptons
return leptons_.size();
}
{
// return the number of jets
return jets_.size();
}
{
// return the number of jets with Delphes b-tag
return boca::CountIfBottom(jets_);
}
{
// return scalar_ht
return scalar_ht_;
}
{
// return missing et
return missing_et_;
}
Momentum Observables::JetPt(unsigned number) const
{
// return pt of jet at number
return jets_.size() > number ? jets_.at(number).Pt() : at_rest;
}
Momentum Observables::LeptonPt(unsigned number) const
{
// return pt of lepton at number
return leptons_.size() > number ? leptons_.at(number).Pt() : at_rest;
}
}

The Branch class

#pragma once
// include the Units header
// include Branch base
// include Observables
namespace simple
{
// use the namespace for units
using namespace boca::units;
// define the branch for saving the root file
// inherits from the BDT branch base class
class Branch : public boca::branch::Bdt
{
public:
// Constructor
Branch();
// All observables must be saved as floats
float jet_number;
float bottom_number;
float missing_et;
float scalar_ht;
float jet_1_pt;
float jet_2_pt;
float jet_3_pt;
float jet_4_pt;
// define how the branches are going to be filled from the Observables
template<typename Multiplet_>
void Fill(Multiplet_ const &multiplet)
{
// store the BDT value in the BDT member
// store the other multiplet in their fields
jet_number = multiplet.JetNumber();
bottom_number = multiplet.BottomNumber();
// note that the Branch only takes plain numbers
missing_et = multiplet.MissingEt() / GeV;
scalar_ht = multiplet.ScalarHt() / GeV;
jet_1_pt = multiplet.JetPt(0) / GeV;
jet_2_pt = multiplet.JetPt(1) / GeV;
jet_3_pt = multiplet.JetPt(2) / GeV;
jet_4_pt = multiplet.JetPt(3) / GeV;
}
// return the Variables for TMVA
boca::Observables Variables() override;
private:
ClassDef(Branch, 1)
};
}

The Branch definition

// include the Branch header
#include "simple/Branch.hh"
// include macros to create Observables
namespace simple
{
// initiatialize all observables with an unphysical value
// note that only integer variables must be initiatialized as integer
{
jet_number = static_cast<int>(InitialValue());
bottom_number = static_cast<int>(InitialValue());
}
{
// return a list of observables by passing all class members with their description to the OBSERVABLE macro
OBSERVABLE(missing_et, "E_{T}^{miss}") +
OBSERVABLE(scalar_ht, "H_{T}^{scalar}") +
OBSERVABLE(jet_1_pt, "p_{T}(j_{1})") +
OBSERVABLE(jet_2_pt, "p_{T}(j_{2})") +
OBSERVABLE(jet_3_pt, "p_{T}(j_{3})") +
OBSERVABLE(jet_4_pt, "p_{T}(j_{4})");
}
}

The root LinkDef necessary for the root file creation

#ifdef __MAKECINT__
#pragma link C++ defined_in "../../../../examples/simple/simple/Branch.hh";
#endif

The main file

#include "simple/Tagger.hh"
int main()
{
// Create an object of the simple Analysis and pass it the simple Tagger
// Run the simple analysis and create efficiency plots
}