This is an example of unfolding a two-dimensional distribution also using an auxiliary measurement to constrain some background
 
#include <iostream>
#include <map>
#include <cmath>
 
using namespace std;
 
 
class ToyEvent {
public:
   void GenerateDataEvent(
TRandom *rnd);
 
   void GenerateSignalEvent(
TRandom *rnd);
 
   void GenerateBgrEvent(
TRandom *rnd);
 
   
   inline Double_t GetPtRec(
void)
 const { 
return fPtRec; }
 
   inline Double_t GetEtaRec(
void)
 const { 
return fEtaRec; }
 
   inline Double_t GetDiscriminator(
void)
 const {
return fDiscriminator; }
 
   inline Bool_t IsTriggered(
void)
 const { 
return fIsTriggered; }
 
 
   
      if(IsSignal()) return fPtGen;
      else return -1.0;
   }
       if(IsSignal()) return fEtaGen;
       else return 999.0;
   }
   inline Bool_t IsSignal(
void)
 const { 
return fIsSignal; }
 
protected:
 
 
   
   
 
 
};
 
void testUnfold5a()
{
  
 
  
  const Int_t neventData         =  20000;
 
 
  Float_t etaRec,ptRec,discr,etaGen,ptGen;
 
  Int_t istriggered,issignal;
 
 
  
  
 
  TFile *dataFile=
new TFile(
"testUnfold5_data.root",
"recreate");
 
 
  dataTree->
Branch(
"etarec",&etaRec,
"etarec/F");
 
  dataTree->
Branch(
"ptrec",&ptRec,
"ptrec/F");
 
  dataTree->
Branch(
"discr",&discr,
"discr/F");
 
 
  
  dataTree->
Branch(
"istriggered",&istriggered,
"istriggered/I");
 
  
  dataTree->
Branch(
"etagen",&etaGen,
"etagen/F");
 
  dataTree->
Branch(
"ptgen",&ptGen,
"ptgen/F");
 
  dataTree->
Branch(
"issignal",&issignal,
"issignal/I");
 
 
  cout<<"fill data tree\n";
 
  Int_t nEvent=0,nTriggered=0;
 
  while(nTriggered<neventData) {
     event.GenerateDataEvent(g_rnd);
 
     etaRec=event.GetEtaRec();
     ptRec=event.GetPtRec();
     discr=event.GetDiscriminator();
     istriggered=event.IsTriggered() ? 1 : 0;
     etaGen=event.GetEtaGen();
     ptGen=event.GetPtGen();
     issignal=event.IsSignal() ? 1 : 0;
 
 
     if(!(nEvent%100000)) cout<<"   data event "<<nEvent<<"\n";
 
     if(istriggered) nTriggered++;
     nEvent++;
 
  }
 
  delete dataTree;
  delete dataFile;
 
  
  
 
  TFile *signalFile=
new TFile(
"testUnfold5_signal.root",
"recreate");
 
 
  signalTree->
Branch(
"etarec",&etaRec,
"etarec/F");
 
  signalTree->
Branch(
"ptrec",&ptRec,
"ptrec/F");
 
  signalTree->
Branch(
"discr",&discr,
"discr/F");
 
  signalTree->
Branch(
"istriggered",&istriggered,
"istriggered/I");
 
  signalTree->
Branch(
"etagen",&etaGen,
"etagen/F");
 
  signalTree->
Branch(
"ptgen",&ptGen,
"ptgen/F");
 
 
  cout<<"fill signal tree\n";
 
  for(int ievent=0;ievent<neventSignalMC;ievent++) {
     event.GenerateSignalEvent(g_rnd);
 
     etaRec=event.GetEtaRec();
     ptRec=event.GetPtRec();
     discr=event.GetDiscriminator();
     istriggered=event.IsTriggered() ? 1 : 0;
     etaGen=event.GetEtaGen();
     ptGen=event.GetPtGen();
 
     if(!(ievent%100000)) cout<<"   signal event "<<ievent<<"\n";
 
  }
 
  delete signalTree;
  delete signalFile;
 
  
  
 
  TFile *bgrFile=
new TFile(
"testUnfold5_background.root",
"recreate");
 
 
  bgrTree->
Branch(
"etarec",&etaRec,
"etarec/F");
 
  bgrTree->
Branch(
"ptrec",&ptRec,
"ptrec/F");
 
  bgrTree->
Branch(
"discr",&discr,
"discr/F");
 
  bgrTree->
Branch(
"istriggered",&istriggered,
"istriggered/I");
 
 
  cout<<"fill background tree\n";
 
  for(int ievent=0;ievent<neventBgrMC;ievent++) {
     event.GenerateBgrEvent(g_rnd);
     etaRec=event.GetEtaRec();
     ptRec=event.GetPtRec();
     discr=event.GetDiscriminator();
     istriggered=event.IsTriggered() ? 1 : 0;
 
     if(!(ievent%100000)) cout<<"   background event "<<ievent<<"\n";
 
  }
 
  delete bgrTree;
  delete bgrFile;
}
 
Double_t ToyEvent::kDataSignalFraction=0.8;
 
 
void ToyEvent::GenerateDataEvent(
TRandom *rnd) {
 
   fIsSignal=rnd->
Uniform()<kDataSignalFraction;
 
   if(IsSignal()) {
      GenerateSignalKinematics(rnd,
kTRUE);
 
   } else {
      GenerateBgrKinematics(rnd,
kTRUE);
 
   }
   GenerateReco(rnd);
}
 
void ToyEvent::GenerateSignalEvent(
TRandom *rnd) {
 
   fIsSignal=1;
   GenerateSignalKinematics(rnd,
kFALSE);
 
   GenerateReco(rnd);
}
 
void ToyEvent::GenerateBgrEvent(
TRandom *rnd) {
 
   fIsSignal=0;
   GenerateBgrKinematics(rnd,
kFALSE);
 
   GenerateReco(rnd);
}
 
void ToyEvent::GenerateSignalKinematics(
TRandom *rnd,
Bool_t isData) {
 
   if(isData) {
      e_T0=0.6;
      e_n=2.5;
      e_T0_eta=0.05;
      e_n_eta=-0.05;
      eta_p2=1.5;
   }
   if(eta_p2>0.0) {
      if(rnd->
Uniform()>=0.5) fEtaGen= -fEtaGen;
 
   } else {
      fEtaGen=rnd->
Uniform(-etaMax,etaMax);
 
   }
   
}
 
void ToyEvent::GenerateBgrKinematics(
TRandom *rnd,
Bool_t isData) {
 
   fPtGen=0.0;
   fEtaGen=0.0;
   fPtRec=rnd->
Exp(isData ? 2.5 : 2.5);
 
}
 
void ToyEvent::GenerateReco(
TRandom *rnd) {
 
   if(fIsSignal) {
      Double_t eGen=fPtGen*(expEta+1./expEta);
 
         *eGen;
      do {
         eRec=rnd->
Gaus(eGen,sigmaE);
 
      } while(eRec<=0.0);
      fEtaRec=rnd->
Gaus(fEtaGen,sigmaEta);
 
      fPtRec=eRec/(expEta+1./expEta);
      do {
         Double_t tauDiscr=0.08-0.04/(1.+fPtRec/10.0);
 
         fDiscriminator=1.0-rnd->
Exp(tauDiscr)+rnd->
Gaus(0.,sigmaDiscr);
 
      } while((fDiscriminator<=0.)||(fDiscriminator>=1.));
      
   } else {
      do {
         Double_t tauDiscr=0.15-0.05/(1.+fPtRec/5.0)+0.1*fEtaRec;
 
         fDiscriminator=rnd->
Exp(tauDiscr)+rnd->
Gaus(0.,sigmaDiscr);
 
      } while((fDiscriminator<=0.)||(fDiscriminator>=1.));
   }
}
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
 
Random number generator class based on M.
 
This is the base class for the ROOT Random number generators.
 
virtual Double_t Gaus(Double_t mean=0, Double_t sigma=1)
Samples a random number from the standard Normal (Gaussian) Distribution with the given mean and sigm...
 
virtual Double_t Exp(Double_t tau)
Returns an exponential deviate.
 
virtual Double_t Uniform(Double_t x1=1)
Returns a uniform deviate on the interval (0, x1).
 
A TTree represents a columnar dataset.
 
virtual Int_t Fill()
Fill all branches.
 
TBranch * Branch(const char *name, T *obj, Int_t bufsize=32000, Int_t splitlevel=99)
Add a new branch, and infer the data type from the type of obj being passed.
 
Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override
Write this object to the current directory.
 
T etaMax()
Function providing the maximum possible value of pseudorapidity for a non-zero rho,...
 
Double_t Exp(Double_t x)
Returns the base-e exponential function of x, which is e raised to the power x.
 
Double_t Sqrt(Double_t x)
Returns the square root of x.
 
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
 
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.