DAS  3.0
Das Analysis System
DAS::Normalisation Namespace Reference

Classes

struct  Efficiency
 
struct  Functor
 
struct  LumiUnc
 
class  Strategy
 
struct  TriggerEff
 
struct  TriggerLumi
 

Enumerations

enum  { WEIGHT = 0b001, SIGN = 0b010, CUTOFF = 0b100 }
 

Functions

void getHLTJetResponse (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
template<typename T = TH3D>
std::unique_ptr< T > makeRespHist (TString name, std::vector< double > pt_edges=DAS::JetEnergy::pt_JERC_edges, TString title=";p_{T}^{gen};|#eta^{rec}|;#frac{p_{T}^{rec}}{p_{T}^{gen}}")
 
void applyDataNormalisation (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void reset (Weights &wgts, const double v=0)
 
float GetNormFactor (const int steering, const vector< fs::path > &sumWgts, const float xsec)
 
void applyMClumi (const vector< fs::path > &inputs, const vector< fs::path > &sumWgts, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void applyNormFactor (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void getSumWeights (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
std::vector< DAS::RecJet >::iterator phaseSel (std::vector< DAS::RecJet > &recjets)
 
std::ostream & operator<< (std::ostream &Stream, const TriggerLumi &tr_lu)
 
void loopOverDirs (TDirectory *dIn, TDirectory *dOut, const int steering, const DT::Slice slice)
 
void getHistoEfficiencyCurves (const fs::path &input, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
float getPrescale (Trigger *trigger, size_t indx)
 
void getTriggerCurves (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void getTriggerEfficiencyEmulation (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void getTriggerTurnons (const fs::path &input, const fs::path &outputRoot, const fs::path &outputTxt, const pt::ptree &config, const int steering)
 
vector< double > extractBinning (const unique_ptr< TH1 > &h3D, const TString &axis)
 
unique_ptr< TH1F > makeTriggerEffHist (const unique_ptr< TEfficiency > &t_eff, int iHLT, int iEta)
 
DAS::FourVector match (const DAS::FourVector &jet, const std::vector< DAS::FourVector > *hltJets)
 
float GetX (TF1 *f)
 
template<typename STREAM >
TF1 * FitTriggerEfficiency (int trigger, TH1 *h, STREAM &Stream, int from, const char *options="NQERS")
 
template<typename STREAM >
float GetTriggerEfficiency (int trigger, TH1 *h, STREAM &Stream, float from, float minEff)
 

Variables

vector< double > thresholds
 
int nThresholds
 
const float threshold = 0.995
 

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
WEIGHT 

use the weights

SIGN 

use the sign

CUTOFF 

apply a selection on the weight

27  {
28  WEIGHT = 0b001,
29  SIGN = 0b010,
30  CUTOFF = 0b100
31 };

Function Documentation

◆ applyDataNormalisation()

void DAS::Normalisation::applyDataNormalisation ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Apply the the kinematic selection, ensuring that events in the dataset have fired a trigger and correcting the weight of the events with the associated trigger prescales, trigger efficiency, and total luminosity. The weight $\frac{ \text{Prescale} * \mathcal{L}^{-1} }{ \epsilon_\text{trigger} } $ is applied by event. The argument 'strategy' defines the selection criterion of the events and the calculation of the weight (see functor in applyDataNormalisation.h).

Todo:
add lumi unc variations
Todo:
revisit the logic (having inputs modified + a return object may be confusing)
Todo:
reimplement the logic to avoid a selection on the weight
Parameters
inputsinput ROOT files (n-tuple)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::Options`
steeringparameters obtained from explicit options
slicenumber and index of slice
48  {1,0}
49  )
50 {
51  cout << __func__ << ' ' << slice << " start" << endl;
52 
53  DT::Flow flow(steering, inputs);
54  auto tIn = flow.GetInputTree(slice);
55  auto [fOut, tOut] = flow.GetOutput(output);
56 
57  DT::MetaInfo metainfo(tOut);
58  metainfo.Check(config);
59  auto isMC = metainfo.Get<bool>("flags", "isMC");
60  if (isMC)
61  BOOST_THROW_EXCEPTION( DE::BadInput("Only real data may be used as input.", metainfo) );
62 
63  // event information
64  auto recEvt = flow.GetBranchReadWrite<RecEvent>("recEvent");
65  auto trigger = flow.GetBranchReadOnly<Trigger>("jetTrigger");
66 
67  // physics object information
68  auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
69  auto hltJets = flow.GetBranchReadOnly<vector<FourVector>>("hltJets");
70 
71  int year = metainfo.Get<int>("flags", "year");
72 
73  // defining functor to apply data prescales
74  auto lumi_file = config.get<fs::path>("corrections.normalisation.luminosities" ),
75  unc_file = config.get<fs::path>("corrections.normalisation.uncertainties"),
76  turnon_file = config.get<fs::path>("corrections.normalisation.turnons" ),
77  efficiencies = config.get<fs::path>("corrections.normalisation.efficiencies" );
78  auto strategy = config.get<string>("corrections.normalisation.strategy"),
79  method = config.get<string>("corrections.normalisation.method" );
80  Functor normalisation(lumi_file, turnon_file, efficiencies, strategy, method, year);
81  LumiUnc lumi_unc(unc_file, year);
82  fOut->cd();
83 
84  bool applySyst = steering & DT::syst;
85  if (applySyst)
86  for (string source: lumi_unc.sources)
87  metainfo.Set<string>("variations", RecEvent::WeightVar, source);
88 
89  // a few control plots
90  ControlPlots::isMC = false;
91  ControlPlots corrNoTrigEff("corrNoTrigEff");
92 
93  vector<ControlPlots> corr { ControlPlots("nominal") };
94  TList * ev_wgts = metainfo.List("variations", RecEvent::WeightVar);
95  for (TObject * obj: *ev_wgts) {
96  auto name = dynamic_cast<TObjString*>(obj)->GetString();
97  corr.push_back(ControlPlots(name));
98  }
99  //if (applySyst)
101 
102  for (DT::Looper looper(tIn); looper(); ++looper) {
103  [[ maybe_unused ]]
104  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
105 
106  if (applySyst)
107  lumi_unc(recEvt);
108 
109  if (recJets->size() == 0) continue;
110 
111  RecJet leadingJet = normalisation(*recEvt, *recJets, *hltJets, *trigger);
112  cout << "leadingJet: " << leadingJet << endl;
113  // the normalisation itself is done in `Normalisation::Functor`
115 
117  if (recEvt->weights.front() <= 0) continue;
118  if (steering & DT::fill) tOut->Fill();
119 
120  float evtWgts = recEvt->weights.front();
121  float efficiency = normalisation.eff(leadingJet);
122 
123  cout << "evtWgts = " << evtWgts << '\n'
124  << "efficiency = " << efficiency << endl;
125  if (efficiency <= 0) continue;
126 
127  corrNoTrigEff(*recJets, evtWgts*efficiency); // compensate
128  for (size_t i = 0; i < corr.size(); ++i)
129  corr.at(i)(*recJets, recEvt->weights.at(i));
130 
131  // Exclusive curves are filled (i.e. one event can populate only a trigger curve).
132  // The ibit value is determined by
133  // the leading jet but also the other jets of the event can populate the trigger curve.
134  for (auto& jet: *recJets) {
135  float y = jet.AbsRap();
136  float w = recEvt->weights.front();
137  normalisation.eff.contribs.at(normalisation.ibit)->Fill(jet.CorrPt(), y, w);
138  }
139  }
140 
141  fOut->cd();
142  corrNoTrigEff.Write(fOut);
143  for (size_t i = 0; i < corr.size(); ++i)
144  corr.at(i).Write(fOut);
145  TDirectory * controlplots = fOut->mkdir("controlplots");
146  controlplots->cd();
147  for (TH2 * h: normalisation.eff.contribs) {
148  h->SetDirectory(controlplots);
149  h->Write();
150  }
151 
152  metainfo.Set<bool>("git", "complete", true);
153 
154  cout << __func__ << ' ' << slice << " stop" << endl;
155 }

◆ applyMClumi()

void DAS::Normalisation::applyMClumi ( const vector< fs::path > &  inputs,
const vector< fs::path > &  sumWgts,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Normalise with sum of weights (to be computed) and cross section (given)

Note
A cut-off for events with hard scale above 5 TeV is applied, since these events are not realistic
Parameters
inputsinput ROOT files (n-tuple)
sumWgtsinput ROOT files (histogram)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::Options`
steeringparameters obtained from explicit options
slicenumber and index of slice
65  {1,0}
66  )
67 {
68  cout << __func__ << ' ' << slice << " start" << endl;
69 
70  DT::Flow flow(steering, inputs);
71  auto tIn = flow.GetInputTree(slice);
72  auto [fOut, tOut] = flow.GetOutput(output);
73 
74  DT::MetaInfo metainfo(tOut);
75  metainfo.Check(config);
76  auto isMC = metainfo.Get<bool>("flags", "isMC");
77  if (!isMC) BOOST_THROW_EXCEPTION( DE::BadInput("Only MC may be used as input.",
78  make_unique<TFile>(inputs.front().c_str() )) );
79 
80  // normalisation factor
81  auto xsection = config.get<float>("corrections.MCnormalisation.xsection");
82  float factor = GetNormFactor(steering, sumWgts, xsection);
83  metainfo.Set<float>("corrections", "MCnormalisation", "xsection", xsection);
84 
85  // declaring branches
86  auto genEvt = flow.GetBranchReadWrite<GenEvent>("genEvent");
87  auto recEvt = flow.GetBranchReadOnly<RecEvent>("recEvent");
88  auto genJets = flow.GetBranchReadOnly<vector<GenJet>>("genJets", DT::facultative);
89  auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets", DT::facultative);
90 
91  // control plot
92  ControlPlots::isMC = true;
93  ControlPlots plots("controlplots");
94 
95  for (DT::Looper looper(tIn); looper(); ++looper) {
96  [[ maybe_unused ]]
97  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
98 
99  // sanity check
100  if (recJets != nullptr && recJets->size() > 0 && recJets->front().scales.size() > 1)
101  BOOST_THROW_EXCEPTION( DE::AnomalousEvent("Unexpected jet energy scale variations", tIn) );
102 
103  // renormalisation
104  genEvt->weights.front() *= factor;
105  if (steering & DT::fill) tOut->Fill();
106 
107  // control plot
108  if (genJets != nullptr)
109  plots(*genJets, genEvt->weights.front() );
110  if (recJets != nullptr)
111  plots(*recJets, genEvt->weights.front() * recEvt->weights.front());
112  }
113 
114  metainfo.Set<bool>("git", "complete", true);
115 
116  plots.Write(fOut);
117 
118  cout << __func__ << ' ' << slice << " stop" << endl;
119 }

◆ applyNormFactor()

void DAS::Normalisation::applyNormFactor ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Multiplies the gen weight of every event by a factor provided on the command line.

Parameters
inputsinput ROOT files (n-tuple)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::Options`
steeringparameters obtained from explicit options
slicenumber and index of slice
41  {1,0}
42  )
43 {
44  cout << __func__ << ' ' << slice << " start" << endl;
45 
46  DT::Flow flow(steering, inputs);
47  auto tIn = flow.GetInputTree(slice);
48  auto tOut = flow.GetOutputTree(output);
49 
50  DT::MetaInfo metainfo(tOut);
51  metainfo.Check(config);
52  auto isMC = metainfo.Get<bool>("flags", "isMC");
53  if (!isMC) BOOST_THROW_EXCEPTION( DE::BadInput("Only MC may be used as input.",
54  make_unique<TFile>(inputs.front().c_str() )) );
55 
56  const float factor = config.get<float>("corrections.normFactor");
57  metainfo.Set<float>("corrections", "normFactor", factor);
58 
59  // declaring branches
60  auto evnt = flow.GetBranchReadOnly<GenEvent>("genEvent");
61 
62  for (DT::Looper looper(tIn); looper(); ++looper) {
63  [[ maybe_unused ]]
64  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
65 
66  // sanity check
67  if (evnt->weights.size() != 1)
68  BOOST_THROW_EXCEPTION( DE::AnomalousEvent("Unexpected event weights", tIn) );
69 
70  // normalise
71  for (auto& weight: evnt->weights)
72  weight *= factor;
73 
74  if (steering & DT::fill) tOut->Fill();
75  }
76 
77  metainfo.Set<bool>("git", "complete", true);
78 
79  cout << __func__ << ' ' << slice << " stop" << endl;
80 }

◆ extractBinning()

vector<double> DAS::Normalisation::extractBinning ( const unique_ptr< TH1 > &  h3D,
const TString &  axis 
)

Extract the axis binning from a TH1 obgect and return it in a vector.

19 {
20  const TAxis *naxis = nullptr;
21  if (axis == "X") naxis = h3D->GetXaxis();
22  else if (axis == "Y") naxis = h3D->GetYaxis();
23  else if (axis == "Z") naxis = h3D->GetZaxis();
24 
25  int ndiv = naxis->GetNbins();
26  vector<double> binning(ndiv+1);
27  naxis->GetLowEdge(&binning[0]);
28  binning[ndiv] = naxis->GetBinUpEdge(ndiv);
29 
30  return binning;
31 }

◆ FitTriggerEfficiency()

TF1* DAS::Normalisation::FitTriggerEfficiency ( int  trigger,
TH1 *  h,
STREAM &  Stream,
int  from,
const char *  options = "NQERS" 
)

Fit the trigger efficiency with sigmoid function in [trigger, 3* trigger], where trigger is the HLT pt threshold.

The sigmoid function is defined as follows:

\epsilon (p_T) = a + 0.5 \times (1-a) \times \left( 1 + \erf \left( \frac{p_T - \mu}{\sigma} \right) \right)

where a, $\mu$ and $\sigma$ are the three parameters.

NOTE:

  • the output is very sensitive to the fit range
  • unclear if/how JES uncertainties should be taken into account
Parameters
triggertrigger HLT threshold
hefficiency histogram
Stream`cout` or file
fromlast turnon, to know from where the ref is efficient
optionsfit options for TF1 function
54 {
55  assert(from > 0);
56  int mbin = h->GetXaxis()->FindBin( from),
57  Mbin = h->GetXaxis()->FindBin(3*from);
58  float m = h->GetBinLowEdge(mbin+1), M = h->GetBinLowEdge(Mbin);
59  for (int bin = 0; bin <= mbin; ++bin) {
60  h->SetBinContent(bin, 0);
61  h->SetBinError (bin, 0);
62  }
63  for (int bin = Mbin+1; bin <= h->GetNbinsX()+1; ++bin) {
64  h->SetBinContent(bin, 0);
65  h->SetBinError (bin, 0);
66  }
67 
68  cout << "Fitting trigger " << trigger << " from " << m << " to " << M << endl;
69 
70  // function
71  TF1 * f = new TF1(Form("sigmoid%d", trigger),
72  "[0]+0.5*(1-[0])*(1+erf((x-[1])/[2]))",
73  m, M);
74 
75  f->SetParNames("a", "#mu", "#sigma");
76 
77  //f->FixParameter(0,0);
78  f->SetParameter(0,0.1);
79  f->SetParLimits(0,0,0.9);
80 
81  f->SetParameter(1,1.1*trigger);
82  f->SetParLimits(1,m,M);
83 
84  f->SetParameter(2,10);
85  f->SetParLimits(2,1,150);
86 
87  // fit
88  h->Fit(f, options, "", m, M);
89 
90  float turnon = GetX(f);
91 
92  Stream << trigger << '\t' << turnon << '\n';
93 
94  return f;
95 }

◆ getHistoEfficiencyCurves()

void DAS::Normalisation::getHistoEfficiencyCurves ( const fs::path &  input,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Extract trigger efficiency distributions from getTriggerEfficiency*Method*

Parameters
inputinput ROOT file (output of getTriggerEfficiency*Method*)
outputname of output ROOT file (histograms)
configconfig file from `DTOptions`
steeringsteering parameters from `DTOptions`
sliceslices for running
119  {1,0}
120  )
121 {
122  cout << __func__ << " start" << endl;
123 
124  auto fIn = make_unique<TFile>(input .c_str(), "READ"),
125  fOut = make_unique<TFile>(output.c_str(), "RECREATE");
126  Normalisation::loopOverDirs(fIn.get(), fOut.get(), steering, slice);
127 
128  cout << __func__ << ' ' << slice << " stop" << endl;
129 } // end of void

◆ getHLTJetResponse()

void DAS::Normalisation::getHLTJetResponse ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Get HLT single-jet response in bins of kinematics in real data. The output can be used as input to fitJetResponse to determine and understand the deviations from the Gaussian expectations, which prevent from fitting the trigger efficiency with the error function.

Parameters
inputsinput ROOT files (n-tuples)
outputname of output ROOT file (histograms)
configconfig file from `DTOptions`
steeringsteering parameters from `DTOptions`
sliceslices for running
46  {1,0}
47  )
48 {
49  cout << __func__ << ' ' << slice << " start" << endl;
50 
51  DT::Flow flow(steering, inputs);
52  auto tIn = flow.GetInputTree(slice);
53  auto [fOut, tOut] = flow.GetOutput(output);
54 
55  DT::MetaInfo metainfo(tOut);
56  metainfo.Check(config);
57  auto isMC = metainfo.Get<bool>("flags", "isMC");
58  if (isMC)
59  BOOST_THROW_EXCEPTION( DE::BadInput("Only DATA may be used as input.", metainfo) );
60 
61  auto rEv = flow.GetBranchReadOnly<RecEvent>("recEvent");
62  auto recjets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
63  auto hltjets = flow.GetBranchReadOnly<vector<FourVector>>("hltJets");
64 
65  unique_ptr<TH3> inclResp = makeRespHist("inclusive"); // Inclusive response
66 
67  for (DT::Looper looper(tIn); looper(); ++looper) {
68  [[ maybe_unused ]]
69  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
70 
71  auto recWgt = rEv->weights.front();
72  // Matching & Fill response
73  for (const RecJet& recjet: *recjets) {
74  FourVector hltjet = match(recjet.p4, hltjets);
75  auto ptrec = recjet.CorrPt();
76  auto pthlt = hltjet.Pt();
77 
78  int pthltbin = inclResp->GetXaxis()->FindBin(pthlt);
79  double hlt_lowedge = inclResp->GetXaxis()->GetBinLowEdge(pthltbin);
80 
81  // Fill response
82  auto response = ptrec/hlt_lowedge;
83  auto etarec = abs(recjet.p4.Eta());
84 
85  inclResp->Fill(pthlt, etarec, response, recWgt);
86 
87  } // End of recjets' loop
88  } // End of event loop
89 
90  // Creating directory hierarchy and saving histograms
91  inclResp->SetDirectory(fOut);
92  inclResp->SetTitle("Response");
93  inclResp->Write("Response");
94 
95  metainfo.Set<bool>("git", "complete", true);
96 
97  cout << __func__ << ' ' << slice << " end" << endl;
98 }

◆ GetNormFactor()

float DAS::Normalisation::GetNormFactor ( const int  steering,
const vector< fs::path > &  sumWgts,
const float  xsec 
)

Retrieve the sum of the weights obtained with getSumWeights and combines it with the input cross section to calculate the normalisation factor.

Parameters
sumWgtsfile containing the hist
xseccross section value
40 {
41  auto h = DT::Flow(steering, sumWgts).GetInputHist<TH2>("hSumWgt");
42  auto sumw = h->Integral(0, -1, // duplicates in overflow cancel overweighted entries
43  1, 2); // both positive and negative weights
44  if (sumw <= 0)
45  BOOST_THROW_EXCEPTION( DE::BadInput("Negative sum of weights.", h) );
46  if (xsec <= 0)
47  BOOST_THROW_EXCEPTION( invalid_argument("Negative cross section.") );
48  auto factor = xsec/sumw;
49  if (steering & DT::verbose)
50  cout << xsec << '/' << sumw << '=' << factor << endl;
51  return factor;
52 }

◆ getPrescale()

float DAS::Normalisation::getPrescale ( Trigger trigger,
size_t  indx 
)
95 {
96  float preHLT = trigger->PreHLT[indx];
97  float preL1min = trigger->PreL1min[indx];
98  float preL1max = trigger->PreL1max[indx];
99  assert(preL1min == preL1max);
100  float prescale = preHLT * preL1min;
101  return prescale;
102 }

◆ getSumWeights()

void DAS::Normalisation::getSumWeights ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Sum the weights from ROOT n-tuple. Mostly useful for MC to estimate the effective number of events, which is necessary to normalise.

The histogram is filled in a way so that it can be used for two purposes:

  • provide a distribution of the weights and choose a max weight,
  • extract the normalisation factor by takaing its integral.
Note
The values beyond maxAbsValue are filled a 2nd time in the overflow with the opposite weight. The truncated sum of the weights is then obtained from the integral by including the overflow.
Parameters
inputsinput ROOT files (n-tuple)
outputoutput ROOT file (histograms)
configconfig handled with `Darwin::Tools::Options`
steeringparameters obtained from explicit options
slicenumber and index of slice
45  {1,0}
46  )
47 {
48  cout << __func__ << ' ' << slice << " start" << endl;
49 
50  DT::Flow flow(steering, inputs);
51  auto tIn = flow.GetInputTree(slice);
52  auto tOut = flow.GetOutputTree(output);
53 
54  DT::MetaInfo metainfo(tOut);
55  metainfo.Check(config);
56  auto isMC = metainfo.Get<bool>("flags", "isMC");
57  if (!isMC) BOOST_THROW_EXCEPTION( DE::BadInput("Only MC may be used as input.",
58  make_unique<TFile>(inputs.front().c_str() )) );
59 
60  const auto maxAbsValue = config.get<float>("corrections.weights.maxAbsValue");
61  const auto mode = config.get<string>("corrections.weights.mode");
62 
63  cout << "maxAbsValue = " << maxAbsValue << endl;
64 
65  auto evnt = flow.GetBranchReadOnly<GenEvent>("genEvent");
66 
67  TString title = ";log_{10}(w);sign;#sum_{i=1}^{events} w_{i}";
68  if (maxAbsValue > 0) title = Form("w < %f", maxAbsValue);
69  auto h = make_unique<TH2D>("hSumWgt", title, 100, 3, 40,
70  2, -1, 1);
71  const double overflow = h->GetXaxis()->GetXmax()+1.;
72 
73  uint32_t wm = 0;
74  if (mode == "weight" ) wm = WEIGHT | SIGN;
75  else if (mode == "signOnly") wm = SIGN;
76  else if (mode != "count" )
77  BOOST_THROW_EXCEPTION( invalid_argument(mode + " is unknown") );
78 
79  if (maxAbsValue > 0) wm |= CUTOFF;
80 
81  cout << "wm = " << bitset<8>(wm) << endl;
82 
83  if (steering & DT::verbose)
84  cout << setw(20) << "w"
85  << setw(20) << "absw"
86  << setw(20) << "x [log10(abs(w))]"
87  << setw(20) << "y [sign]"
88  << setw(20) << "z [eff. weight]" << endl;
89 
90  for (DT::Looper looper(tIn); looper(); ++looper) {
91  [[ maybe_unused ]]
92  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
93 
94  const double w = evnt->weights.front();
95  if (w == 0.) continue;
96 
97  if (!isfinite(w))
98  BOOST_THROW_EXCEPTION( runtime_error("Infinite or NaN weight:"s + w) );
99 
100  // the weight is used twice:
101  // - once for the bin to fill, which should always be [log(abs(w)),+/-1]
102  // - once for the actual weight in the histogram, which depends on the options
103 
104  const double absw = std::abs(w),
105  x = log10(absw),
106  y = copysign(0.5,w); // bin center
107  double z = wm & WEIGHT ? absw : 1;
108  if (wm & SIGN) z = copysign(z,w);
109 
110  cout << setw(20) << w
111  << setw(20) << absw
112  << setw(20) << x
113  << setw(20) << (2*y) // we want the sign only (bin center is irrelevant)
114  << setw(20) << z << endl;
115 
116  h->Fill(x, y, z);
117 
118  if (x >= overflow)
119  cerr << orange << "Warning: a good weight is being filled in the overflow.\n" << def;
120 
124  if ((wm & CUTOFF) && absw >= maxAbsValue)
125  h->Fill(overflow, y, -z);
126  }
127 
128  metainfo.Set<bool>("git", "complete", true);
129 
130  h->Write();
131 
132  cout << __func__ << ' ' << slice << " end" << endl;
133 }

◆ getTriggerCurves()

void DAS::Normalisation::getTriggerCurves ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Get trigger curves from the data n-tuples.

Todo:
fix error
Todo:
fix error
Parameters
inputsinput ROOT file (n-tuple)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::options`
steeringparameters obtained from explicit options
slicenumber and index of slice
111  {1,0}
112  )
113 {
114  //cout << __func__ << ' ' << slice << " start" << endl;
116 
117  DT::Flow flow(steering, inputs);
118  auto tIn = flow.GetInputTree(slice);
119  auto [fOut, tOut] = flow.GetOutput(output);
120 
121  DT::MetaInfo metainfo(tOut);
122  metainfo.Check(config);
123 
124  const auto usePrescales = config.get<bool>("corrections.normalisation.use_prescales");
125  metainfo.Set<bool>("corrections", "normalisation", "use_prescales", usePrescales);
126 
127  auto lumi_file = config.get<fs::path>("corrections.normalisation.luminosities");
128  pt::ptree triggers_lumi;
129  pt::read_info(lumi_file.string(), triggers_lumi);
130  for (auto const& trigger_lumi: triggers_lumi)
131  thresholds.push_back(stoi(trigger_lumi.first));
132  nThresholds = thresholds.size()-1;
133  metainfo.Set<fs::path>("corrections", "normalisation", "luminosities", lumi_file);
134 
135  auto trigger = flow.GetBranchReadOnly<Trigger>("jetTrigger");
136  auto recjets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
137  auto hltjets = flow.GetBranchReadOnly<vector<FourVector>>("hltJets");
138 
139  map<TString, size_t> methods { // methods[name] = shift (first trigger for which the method is used)
140  {"emulation", 1}, // default method
141  {"emulationShift", 2}, // emulation but with a lower-threshold reference trigger (e.g. trig 40 as reference for trig 80 as test)
142  {"TnP", 0} // tag-and-probe method (used in any case of the lowest reference trigger(s)
143  };
144 
145  TH2 * pt_correlation = new TH2F("ptCorr","; p_{T}^{PF,corr}; p_{T}^{hlt}",nPtBins,pt_edges.data(),nPtBins,pt_edges.data());
146  TH1 * Deta = new TH1F("deta","; #Delta #eta; nevt", 200, -5, 5);
147  TH1 * Dphi = new TH1F("dphi","; #Delta #phi; nevt", 200, -M_PI, M_PI);
148  TH1 * dR = new TH1F("dR" ,"; #Delta R; nevt" , 200, 0, 10);
149 
150  map<TString, map<int, Efficiency>> curves;
151  for (auto method: methods)
152  for (size_t i = method.second; i < thresholds.size(); ++i) {
153  int t = thresholds.at(i);
154  cout << method.first << '\t' << t << '\n';
155  curves[method.first].insert( {t, Efficiency(method.first, t)} );
156  }
157  cout << flush;
158 
159  for (DT::Looper looper(tIn); looper(); ++looper) {
160  [[ maybe_unused ]]
161  static auto& cout = (steering & DT::verbose) == DT::verbose ? ::cout : DT::dev_null;
162 
163  // sanity check
164  size_t nbits = trigger->Bit.size();
165  if (nbits < thresholds.size())
166  BOOST_THROW_EXCEPTION( DE::AnomalousEvent( Form("nbits = %ld < thresholds.size() = %ld",
167  nbits, thresholds.size()), tIn) );
168 
169  // avoid empty events
170  if (recjets->size() == 0) continue;
171 
172  for (const RecJet& pfjet: *recjets){
173  FourVector hltjet = match(pfjet.p4, hltjets);
174  if ( hltjet == FourVector()) continue;
175 
176  Deta->Fill(pfjet.p4.Eta() - hltjet.Eta(), pfjet.weights.front());
177  Dphi->Fill(DeltaPhi(pfjet.p4,hltjet), pfjet.weights.front());
178  dR->Fill(DeltaR(pfjet.p4, hltjet), pfjet.weights.front());
179  pt_correlation->Fill(pfjet.CorrPt(), hltjet.Pt(), pfjet.weights.front());
180  }
181 
182  // NOTE: from now on, only the leading jet is considered
183 
184  auto leadingInTk = phaseSel(*recjets); // iterator
185 
186  if (leadingInTk == recjets->end()) continue;
187 
188  FourVector pfjet0 = leadingInTk->p4;
189  pfjet0 *= leadingInTk->scales.front();
190 
191  FourVector hltjet0 = match(pfjet0, hltjets);
192  if ( hltjet0 == FourVector()) continue;
193 
194  /*** using emulation method(s) ***/
195  for (auto method: methods) {
196 
197  if (method.first.Contains("TnP")) continue;
198  size_t shift = method.second;
199 
200  for (size_t i = shift; i < thresholds.size(); ++i) {
201 
202  int t = thresholds[i];
203  auto& eff = curves.at(method.first).at(t);
204 
205  eff.hAll->Fill(pfjet0.Pt(), hltjet0.Pt());
206 
207  // test if previous trigger has fired
208  if (!trigger->Bit[i-shift]) continue;
209  eff.hFired->Fill(pfjet0.Pt(), hltjet0.Pt());
210 
211  if (hltjet0.Pt() < thresholds.at(i-shift)) continue;
212  eff.hFiredThreshold->Fill(pfjet0.Pt(), hltjet0.Pt());
213 
214  float wgt = usePrescales ? getPrescale(trigger, i-shift) : 1;
215  bool fired = hltjet0.Pt() > t;
216  eff.Fill(pfjet0, fired, wgt*recjets->front().weights.front());
217 
218  eff.hHLTmap->Fill( pfjet0.Phi(),pfjet0.Eta(),wgt*recjets->front().weights.front() );
219  }
220  } // end of loop on methods
221 
222  /*** using tag & probe method ***/
223  for (size_t i = 0; i < thresholds.size(); ++i) {
224 
225  int t = thresholds[i];
226  auto& eff = curves.at("TnP").at(t);
227 
228  eff.hAll->Fill(pfjet0.Pt(), hltjet0.Pt());
229 
230  // first, it needs to have fired
231  if (!trigger->Bit[i])
232  continue;
233  eff.hFired->Fill(pfjet0.Pt(), hltjet0.Pt());
234 
235  // then we need dijet configurations at PF level:
236  // -> 1) at least 2 jets
237  if (recjets->size() == 1)
238  continue;
239  // -> 2) back-to-back jets
240  if (DeltaPhi(recjets->at(0).p4, recjets->at(1).p4) < 2.4) continue;
241  // -> 3) a possible 3rd jet should not be significant
242  if (recjets->size() > 2) {
243  const double pt0 = recjets->at(0).CorrPt(),
244  pt1 = recjets->at(1).CorrPt(),
245  pt2 = recjets->at(2).CorrPt();
246  if (pt2 > 0.15*(pt0 + pt1))
247  continue;
248  }
249 
250  // we take the probe and the tag randomly
251  static TRandom3 Rand(/* seed = */ metainfo.Seed<10989678>(slice));
252  double r = Rand.Uniform();
253  int itag = (r<0.5),
254  iprobe = (r>=0.5);
255 
256  FourVector pftag = recjets->at(itag ).p4,
257  pfprobe = recjets->at(iprobe).p4;
258 
259  float pfprobe_wgt = recjets->at(iprobe).weights.front();
260  float pftag_wgt = recjets->at(itag).weights.front();
261 
262  pftag *= recjets->at(itag ).scales.front();
263  pfprobe *= recjets->at(iprobe).scales.front();
264 
265  // -> 4) selection on the rapidity of the system
266  if (std::abs(recjets->at(itag).p4.Eta()) > 1.3) continue;
267 
268  // match PF at HLT
269  // 1) test if tag can be matched
270  // - if not, continue
271  // 2) then test if the probe can be match
272 
273  const FourVector& hlttag = match(pftag, hltjets);
274  const FourVector& hltprobe = match(pfprobe, hltjets);
275  if ( hlttag == FourVector() || hltprobe == FourVector()) continue;
276 
277  if (hlttag.Pt() > t) {
278  eff.hFiredThreshold->Fill(pfjet0.Pt(), hltjet0.Pt());
279 
280  const FourVector& hltprobe = match(pfprobe, hltjets);
281  bool fired = hltprobe.Pt() > t;
282 
283  float wgt = usePrescales ? getPrescale(trigger, i) : 1;
284  eff.Fill(pfprobe, fired, wgt * pftag_wgt * pfprobe_wgt);
285  eff.hHLTmap->Fill( pfjet0.Phi(),pfjet0.Eta(),wgt*recjets->front().weights.front() );
286  }
287  }
288  }
289 
290  cout << "Writing to file" << endl;
291  for (auto& method: curves) {
292  fOut->cd();
293  auto d = fOut->mkdir(method.first);
294  for (auto& curve: method.second)
295  curve.second.Write(d);
296  }
297  fOut->cd();
298  dR->Write();
299  Deta->Write();
300  Dphi->Write();
301  pt_correlation->Write();
302 
303  metainfo.Set<bool>("git", "complete", true);
304 
305  //cout << __func__ << ' ' << slice << " end" << endl;
307 }

◆ GetTriggerEfficiency()

float DAS::Normalisation::GetTriggerEfficiency ( int  trigger,
TH1 *  h,
STREAM &  Stream,
float  from,
float  minEff 
)

DON'T fit the trigger efficiency but just find the first bin above threshold

Todo:
Where does the factor 6 come from?
Parameters
triggertrigger HLT threshold
hefficiency histogram
Stream`cout` or file
fromlast turnon, to know from where the ref is efficient
minEffmin efficiency (e.g. different for barrel and forward region)
106 {
107  int mbin = h->GetXaxis()->FindBin( from),
108  Mbin = h->GetXaxis()->FindBin(6*from);
109  for (int bin = 0; bin < mbin; ++bin) {
110  h->SetBinContent(bin, 0);
111  h->SetBinError (bin, 0);
112  }
113  for (int bin = Mbin+1; bin <= h->GetNbinsX()+1; ++bin) {
114  h->SetBinContent(bin, 0);
115  h->SetBinError (bin, 0);
116  }
117  for (int bin = mbin; bin <= Mbin; ++bin) {
118  float content = h->GetBinContent(bin);
119  if (content < minEff) continue;
120  float turnon = h->GetBinLowEdge(bin);
121  Stream << trigger << '\t' << turnon << '\n';
122  return turnon;
123  }
124  return -1;
125 }

◆ getTriggerEfficiencyEmulation()

void DAS::Normalisation::getTriggerEfficiencyEmulation ( const vector< fs::path > &  inputs,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Get the efficiency in 3D TEfficiency objects from data n-tuples using different selection criteria for the matching.

Todo:
: what if there are HLT jets but no rec jets? -> global inefficiency?
Parameters
inputsinput ROOT files (n-tuples)
outputname of output ROOT file (histograms)
configconfig file from `DTOptions`
steeringsteering parameters from `DTOptions`
sliceslices for running
131  {1,0}
132  )
133 {
134  cout << __func__ << " start" << endl;
135 
136  DT::Flow flow(steering, inputs);
137  auto tIn = flow.GetInputTree(slice);
138  auto [fOut, tOut] = flow.GetOutput(output);
139 
140  pt::ptree triggers_lumi;
141  auto lumi_file = config.get<fs::path>("corrections.normalisation.luminosities");
142  pt::read_info(lumi_file.c_str(), triggers_lumi);
143  vector<double> thresholds;
144  for (auto [trigger, _]: triggers_lumi)
145  thresholds.push_back(stoi(trigger));
146  if (thresholds.size() == 0)
147  BOOST_THROW_EXCEPTION(invalid_argument("Empty list of triggers"));
148  thresholds.push_back(3*thresholds.back()); // Added one more boundary to have an upper HLT limit
149 
150  DT::MetaInfo metainfo(tOut);
151  metainfo.Check(config);
152  const auto R = metainfo.Get<int>("flags", "R");
153 
154  auto rEv = flow.GetBranchReadOnly<RecEvent>("recEvent");
155  auto trigger = flow.GetBranchReadOnly<Trigger>("jetTrigger");
156  auto recjets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
157  auto hltjets = flow.GetBranchReadOnly<vector<FourVector>>("hltJets");
158 
159  using Matching = JMEmatching<vector<FourVector>, vector<RecJet>>;
160  Matching::maxDR = R/10./2.;
161  cout << "Radius for matching: " << Matching::maxDR << endl;
162 
163  Strategy leading_pt ("leading_pt" , thresholds),
164  best_match ("best_match" , thresholds),
165  most_central ("most_central" , thresholds),
166  isolated_jets("isolated_jets", thresholds);
167 
168  for (DT::Looper looper(tIn); looper(); ++looper) {
169  [[ maybe_unused ]]
170  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
171 
172  // sanity check
173  size_t nbits = trigger->Bit.size();
174  if (nbits < thresholds.size()-1) // manually added an extra HLT boundary, -1 to satisfy the condition
175  BOOST_THROW_EXCEPTION( DE::AnomalousEvent( Form("nbits = %ld < thresholds.size() = %ld",
176  nbits, thresholds.size()), tIn) );
177 
179  if (recjets->empty()) continue;
180 
181  cout << "Running matching" << endl;
182  Matching matching(*hltjets, *recjets);
183 
184  auto ev_w = rEv->Weight();
185 
186  auto get_hlt_match = [&matching,&hltjets](const RecJet& recjet) {
187  // match_it = { hlt jet iterator, rec jet iterator }
188  auto criterion = [&recjet](const auto& match_it) {
189  return *(match_it.second) == recjet;
190  };
191  auto it = ranges::find_if(matching.match_its, criterion);
192  return (it == matching.match_its.end()) ? hltjets->end() : it->first;
193  };
194 
195  // leading pt
196  {
197  cout << "Leading pt" << endl;
198  const auto& recjet = recjets->front();
199  const auto hltjet_it = get_hlt_match(recjet);
200  if (hltjet_it != hltjets->end())
201  leading_pt.Fill(recjet, *hltjet_it, trigger->Bit, ev_w);
202  }
203 
204  // most central
205  {
206  cout << "Most central" << endl;
207  auto criterion = [](const RecJet& jet1, const RecJet& jet2) {
208  return jet1.AbsRap() < jet2.AbsRap();
209  };
210  auto recjet_it = ranges::min_element(*recjets, criterion);
211  const auto hltjet_it = get_hlt_match(*recjet_it);
212  if (hltjet_it != hltjets->end())
213  most_central.Fill(*recjet_it, *hltjet_it, trigger->Bit, ev_w);
214  }
215 
216  // best match
217  if (matching.match_its.size() > 0) {
218  cout << "Best match" << endl;
219  const auto& [hltjet_it, recjet_it] = matching.match_its.front();
220  best_match.Fill(*recjet_it, *hltjet_it, trigger->Bit, ev_w);
221  }
222 
223  // all isolated jets
224  {
225  cout << "All isolated jets" << endl;
226  for (auto ref_it = recjets->begin(); ref_it != recjets->end(); ++ref_it) {
227  const auto hltjet_it = get_hlt_match(*ref_it);
228 
229  auto is_neighbor = [ref_it, R](const RecJet& test_jet) {
230  return &test_jet != &(*ref_it) && DeltaR(ref_it->p4, test_jet.p4) < R / 10.; // Avoid comparing jet to itself and check proximity.
231  };
232  // Look for the first neighboring jet. If one is found, continue (not isolated).
233  if (any_of(recjets->begin(), recjets->end(), is_neighbor)) continue;
234  isolated_jets.Fill(*ref_it, *hltjet_it, trigger->Bit, ev_w);
235  }
236  }
237  }
238 
239  leading_pt .Write(fOut);
240  most_central .Write(fOut);
241  best_match .Write(fOut);
242  isolated_jets.Write(fOut);
243 
244  cout << __func__ << " stop" << endl;
245 }

◆ getTriggerTurnons()

void DAS::Normalisation::getTriggerTurnons ( const fs::path &  input,
const fs::path &  outputRoot,
const fs::path &  outputTxt,
const pt::ptree &  config,
const int  steering 
)

Get the trigger turn-on points from the trigger curves.

Todo:
Use metainfo
Todo:
Get year from metainfo?
Todo:
Get lumis from metainfo?
Todo:
implement a more general logic to use only rapidity <3 turnons to determine the overall turnon
Parameters
inputinput ROOT file (n-tuple)
outputRootoutput ROOT file with efficiency
outputTxtoutput text file with turn-ons
configconfig handled with `Darwin::Tools::options`
steeringparameters obtained from explicit options
45 {
46  cout << __func__ << " start" << endl;
47 
48  auto fOut = DT::GetOutputFile(outputRoot);
49 
51  //DT::MetaInfo metainfo(tOut);
52  //metainfo.Check(config);
53  int year = config.get<int>("flags.year");
54 
55  cout << setw(10) << "trigger";
56  for (auto yBin: yBins) cout << setw(18) << yBin;
57  cout << endl;
58 
59  pt::ptree triggers_lumi;
60  auto lumi_file = config.get<fs::path>("corrections.normalisation.luminosities");
61  pt::read_info(lumi_file.c_str(), triggers_lumi);
62  vector<int> triggerThresholds;
63  for (auto trigger_lumi: triggers_lumi)
64  triggerThresholds.push_back(stoi(trigger_lumi.first));
65 
66  auto fIn = make_unique<TFile>(input.c_str(), "READ");
67  map<int, int> turnonsFinal;
68  TIter Next(fIn->GetListOfKeys()) ;
69  TKey* key = nullptr;
70  TString defMethod = "TnP"; // only for the first trigger(s)
71  while ( (key = dynamic_cast<TKey*>(Next())) ) { // looping over methods
72  if (TString(key->ReadObj()->ClassName()) != TString("TDirectoryFile"))
73  continue;
74 
75  fIn->cd();
76  auto dIn = dynamic_cast<TDirectory*>(key->ReadObj());
77 
78  int lastturnon = triggerThresholds.front();
79  cout << dIn << endl;
80 
81  TString method = dIn->GetName();
82  cout << method << endl;
83 
84  fOut->cd();
85  auto dOut = fOut->mkdir(method);
86 
87  TIter Next2(dIn->GetListOfKeys()) ;
88  while ( (key = dynamic_cast<TKey*>(Next2())) ) { // looping of triggers
89  if (TString(key->ReadObj()->ClassName()) != TString("TDirectoryFile"))
90  continue;
91 
92  dIn->cd();
93  auto ddIn = dynamic_cast<TDirectory*>(key->ReadObj());
94 
95  TString trigName = ddIn->GetName();
96  assert(trigName.Contains("HLT"));
97 
98  dOut->cd();
99  auto ddOut = dOut->mkdir(trigName);
100 
101  trigName.ReplaceAll("HLT","");
102  int trigger = trigName.Atoi();
103  if (method == "TnP" && trigger < triggerThresholds.at(0)) continue;
104  if (method == "emulation" && trigger < triggerThresholds.at(1)) continue;
105  if (method == "emulationShift" && trigger < triggerThresholds.at(2)) continue;
106  cout << setw(10) << trigger;
107 
108  auto h2 = unique_ptr<TH2>(ddIn->Get<TH2>("test"));
109  {
110  auto den = unique_ptr<TH2>(ddIn->Get<TH2>("ref"));
111  h2->Divide(h2.get(), den.get(), 1, 1, "B");
112  }
113 
114  ddOut->cd();
115 
116  h2->SetDirectory(ddOut);
117  h2->SetName("efficiency");
118 
119  vector<int> turnonsNow;
120  for (int y = 1; y <= h2->GetNbinsY(); ++y) {
121 
122  // efficiency curve
123  auto h1 = unique_ptr<TH1>(h2->ProjectionX(Form("efficiency_ybin%d", y), y, y));
124  //cout << y << '\t';
125  static ostream bitBucket(0); // printing to nowhere
126  double threshold = 0.995;
127  switch (year) {
128  case 2017:
129  if (y > 5) threshold = 0.99;
130  break;
131  case 2018:
132  if (y > 3) threshold = 0.99;
133  break;
134  case 2016:
135  default:
136  if (y > 5) threshold = 0.99; //2016 Pre
137  //if (y > 5) threshold = 0.99; 2016 Post
138  }
139  float from = h1->GetBinLowEdge(h1->FindBin(lastturnon)+1);
140  int turnon = Normalisation::GetTriggerEfficiency(trigger, h1.get(), bitBucket, from, threshold);
141  h1->SetTitle(Form("%d (%.3f)", turnon, threshold));
142  h1->SetDirectory(dOut);
143  h1->Write();
144  turnonsNow.push_back(turnon);
145  }
146 
149  auto maxturnon = max_element(turnonsNow.begin(), turnonsNow.begin()+6);
150  h2->SetTitle(Form("%d", *maxturnon));
151  h2->Write();
152  for (auto turnon: turnonsNow) {
153  if (turnon == *maxturnon) cout << "\x1B[32m\e[1m";
154  if (turnon < 0) cout << "\x1B[31m\e[1m";
155  cout << setw(18) << turnon;
156  cout << "\x1B[30m\e[0m";
157  }
158  cout << endl;
159 
160  // final choice
161  if (method == defMethod)
162  turnonsFinal[trigger] = *maxturnon;
163 
164  defMethod = "emulation";
165  lastturnon = *maxturnon;
166 
167  if (lastturnon == -1) {
168  cerr << "Didn't find any turnon for trigger " << trigger << '\n';
169  lastturnon = trigger;
170  }
171  } // end of loop over triggers
172  } // end of loop over method
173 
174  pt::ptree turnon_file;
175  for (auto& turnon: turnonsFinal)
176  turnon_file.put<int>(to_string(turnon.first), turnon.second);
177  pt::write_info(outputTxt.string(), turnon_file);
178 
179  cout << __func__ << " end" << endl;
180 }

◆ GetX()

float DAS::Normalisation::GetX ( TF1 *  f)

Replaces TF1::GetX() which does not return the same value when run after compilation or in interactive mode...

Principle: just scan the pt axis with step = 1 until eff > 0.995

21 {
22  double m = 0, M = 7000;
23  f->GetRange(m,M);
24 
25  for (float pt = m; pt < M; ++pt)
26  if (f->Eval(pt) > threshold)
27  return pt;
28 
29  cerr << "No threshold was found from " << m << " to " << M << ".\nAborting.\n";
30  exit(EXIT_FAILURE);
31 }

◆ loopOverDirs()

void DAS::Normalisation::loopOverDirs ( TDirectory *  dIn,
TDirectory *  dOut,
const int  steering,
const DT::Slice  slice 
)

Considering the possible strategies to determine the trigger efficiency of jets systems stored in 3D ROOT::TEfficiency objects, they need to be extarcted to other more convenient ROOT objects used in plotting and fitting:

  • TH1
  • TGraphAsymmErrors Based on whether the errors are symmetrical or not, the appropriate class should be used. In this case, the errors are symmetrical, so the TH1 class will be used.

This class includes the extraction of the corresponding histograms that are filled with the efficiency, for all HLT and |eta| bins.

55 {
56  for (const auto&& obj: *(dIn->GetListOfKeys())) {
57 if (!obj->InheritsFrom("TKey")) continue;
58  auto const key = dynamic_cast<TKey*>(obj);
59  //dIn->cd(); // redundant?
60  auto ddIn = dynamic_cast<TDirectory*>( key->ReadObj() );
61  if (ddIn == nullptr) continue;
62  ddIn->cd();
63  cout << ddIn << endl;
64 
65  TString match = ddIn->GetName();
66  cout << "Matching method: " << match << endl;
67  cout << endl;
68 
69  dOut->cd();
70  auto ddOut = dOut->mkdir(match); // Create a folder for each matching method
71  ddOut->cd();
72 
73  auto t_eff = unique_ptr<TEfficiency>( dynamic_cast<TEfficiency*>( ddIn->Get("efficiency") ) ); // ROOT::TEfficiency from input
74  if (t_eff == nullptr) continue;
75 
76  auto h3D = t_eff->GetTotalHistogram(); // used only to extract HLT thresholds
77 
78  // Extracting HLT bins (thresholds)
79  auto h_HLTBins = unique_ptr<TH1>( dynamic_cast<TH1*>(h3D->Clone("h_HLTBins")) );
80  vector<double> HLTBins = extractBinning(h_HLTBins, "X");
81  const int nHLTBins = HLTBins.size()-1;
82 
83  // Extracting Eta bins
84  auto h_EtaBins = unique_ptr<TH1>( dynamic_cast<TH1*>(h3D->Clone("h_EtaBins")) );
85  vector<double> EtaBins = extractBinning(h_EtaBins, "Y");
86  const int nEtaBins = EtaBins.size()-1;
87 
88  for (int iHLT = 1; iHLT <= nHLTBins; ++iHLT){
89  if (t_eff->GetDimension() != 3) continue; // works only for 3D TEfficiency plots
90 
91  auto dddOut = ddOut->mkdir(Form("HLT%.0f", HLTBins[iHLT-1])); // Create a sub-folder for each HLT threshold
92  dddOut->cd();
93 
94  vector<unique_ptr<TH1>> h1D_eff;
95  for (int iEta = 1; iEta <= nEtaBins; ++iEta){
96  auto ddddOut = dddOut->mkdir(Form("etabin%d", iEta)); // Create a sub-sub-folder for each Eta bin
97  ddddOut->cd();
98 
99  cout << "HLT" << HLTBins[iHLT-1] << std::setw(10) << EtaBins[iEta-1] << "<|#eta|<" << EtaBins[iEta] << endl;
100 
101  // Fill 1D histogram with efficiency for each HLT and Eta bin
102  h1D_eff.push_back(makeTriggerEffHist(t_eff, iHLT, iEta));
103  h1D_eff.at(iEta-1)->SetDirectory(0);
104 
105  h1D_eff.at(iEta-1)->SetDirectory(ddddOut);
106  h1D_eff.at(iEta-1)->Write();
107  } // end of eta loop
108  } // end of HLT loop
109  } // end of list-of-keys loop
110 }

◆ makeRespHist()

std::unique_ptr<T> DAS::Normalisation::makeRespHist ( TString  name,
std::vector< double >  pt_edges = DAS::JetEnergy::pt_JERC_edges,
TString  title = ";p_{T}^{gen};|#eta^{rec}|;#frac{p_{T}^{rec}}{p_{T}^{gen}}" 
)

Create a TH3 histogram for the Jet response and HLT jet response or trigger efficiency curve.

23  {T}^{gen};|#eta^{rec}|;#frac{p_{T}^{rec}}{p_{T}^{gen}}")
24 {
25  using namespace std;
26  using namespace DAS::JetEnergy;
27 
28  static int nResBins = 200;
29  static auto resBins = getBinning(nResBins, 0, 2);
30  int nPtBins = pt_edges.size()-1;
31  unique_ptr<T> h = make_unique<T>(name, title,
32  nPtBins, pt_edges.data(),
33  nAbsEtaBins, abseta_edges.data(),
34  nResBins, resBins.data());
35 
36  h->SetDirectory(nullptr);
37  return h;
38 }

◆ makeTriggerEffHist()

unique_ptr<TH1F> DAS::Normalisation::makeTriggerEffHist ( const unique_ptr< TEfficiency > &  t_eff,
int  iHLT,
int  iEta 
)

Extract the HLT efficiency curves in 1D histograms from TEfficiency objects.

22 {
23  auto h3D = t_eff->GetTotalHistogram(); // used only to extract binning
24 
25  // Extracting HLT bins (thresholds)
26  auto h3D_HLT = unique_ptr<TH1>( dynamic_cast<TH1*>(h3D->Clone("h3D_HLT")) ); // create one clone for HLT bins
27  vector<double> HLTBins = extractBinning(h3D_HLT, "X");
28 
29  // Extracting resolution bins
30  auto h3D_res = unique_ptr<TH1>( dynamic_cast<TH1*>(h3D->Clone("h3D_res")) ); // a separate clone for Res bins
31  vector<double> ResBins = extractBinning(h3D_res, "Z");
32  const int nResBins = ResBins.size()-1;
33 
34  TString name = "efficiency";
35  TString title = Form("HLT%.0f_eta%d", HLTBins[iHLT-1], iEta+1);
36  unique_ptr<TH1F> h = make_unique<TH1F>(name, title, nResBins, 0, 2*HLTBins[iHLT-1]);
37  for (int ipt = 1; ipt <= nResBins; ++ipt){ // loop over pt bins (z axis of TEfficiency)
38  h->SetBinContent( ipt, t_eff->GetEfficiency (t_eff->GetGlobalBin(iHLT, iEta, ipt)) );
39  h->SetBinError ( ipt, t_eff->GetEfficiencyErrorUp(t_eff->GetGlobalBin(iHLT, iEta, ipt)) );
40  } // end of pt loop
41 
42  h->SetDirectory(nullptr);
43  return h;
44 }

◆ match()

DAS::FourVector DAS::Normalisation::match ( const DAS::FourVector jet,
const std::vector< DAS::FourVector > *  hltJets 
)
7  {
8  for (const auto& hltjet: *hltJets){
9  using ROOT::Math::VectorUtil::DeltaR;
10  if (DeltaR(hltjet, jet) < 0.3)
11  return hltjet;
12  }
13  return DAS::FourVector();
14 }

◆ operator<<()

std::ostream& DAS::Normalisation::operator<< ( std::ostream &  Stream,
const TriggerLumi tr_lu 
)
24 {
25  Stream << tr_lu.pt << '\t' << tr_lu.turnon << '\t' << tr_lu.weight << '\t' << 1./tr_lu.weight;
26  return Stream;
27 }

◆ phaseSel()

std::vector<DAS::RecJet>::iterator DAS::Normalisation::phaseSel ( std::vector< DAS::RecJet > &  recjets)
9  {
10  auto leadingInTk = recjets.begin();
11  while (leadingInTk != recjets.end()
12  && std::abs(leadingInTk->Rapidity()) >= 3.0)
13  ++leadingInTk;
14 
15  return leadingInTk;
16 }

◆ reset()

void DAS::Normalisation::reset ( Weights wgts,
const double  v = 0 
)
inline
28 { std::fill(wgts.begin(), wgts.end(), Weight{v,0}); }

Variable Documentation

◆ nThresholds

int nThresholds

◆ threshold

const float threshold = 0.995

◆ thresholds

vector<double> thresholds
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.name
name
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:48
DAS::Normalisation::phaseSel
std::vector< DAS::RecJet >::iterator phaseSel(std::vector< DAS::RecJet > &recjets)
Definition: PhaseSelection.h:9
method
method
Definition: Core-gitclone-lastrun.txt:5
Ntupliser_cfg.cerr
cerr
Definition: Ntupliser_cfg.py:105
DAS::Normalisation::SIGN
@ SIGN
use the sign
Definition: getSumWeights.cc:29
Darwin::Tools::fill
@ fill
activate -f to fill the tree
Definition: Options.h:27
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.options
options
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:41
jmarExample.pt
pt
Definition: jmarExample.py:19
Darwin::Tools::Flow
User-friendly handling of input and output n-tuples.
Definition: Flow.h:78
Step::verbose
static bool verbose
Definition: Step.h:40
DAS::Normalisation::thresholds
vector< double > thresholds
Definition: getTriggerCurves.cc:41
Step::def
static const char * def
Definition: Step.h:36
DAS::PhysicsObject::p4
FourVector p4
raw four-momentum directly after reconstruction
Definition: PhysicsObject.h:50
DAS::Normalisation::nThresholds
int nThresholds
Definition: getTriggerCurves.cc:42
Ntupliser_cfg.year
int year
Definition: Ntupliser_cfg.py:67
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.source
source
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:39
Darwin::Tools::Looper
Facility to loop over a n-tuple, including parallelisation and printing.
Definition: Looper.h:22
DAS::pt_edges
static const std::vector< double > pt_edges
Definition: binnings.h:33
Ntupliser_cfg.f
f
Definition: Ntupliser_cfg.py:322
Darwin::Tools::syst
@ syst
activate -s to systematic uncertainties
Definition: Options.h:29
jercExample.key
string key
Definition: jercExample.py:109
DAS::JetEnergy::w
static const float w
Definition: common.h:53
Darwin::Tools::MetaInfo
Generic meta-information for n-tuple (including speficities to Darwin).
Definition: MetaInfo.h:68
Strategy
Strategy
Definition: fjcore.hh:1017
Darwin::Tools::GetOutputFile
std::shared_ptr< TFile > GetOutputFile(const std::filesystem::path &, const std::source_location=std::source_location::current())
Shortcut to create a reproducible output file (see ROOT Doxygen for details)
Definition: FileUtils.cc:141
recjet
DAS::RecJet recjet
Definition: classes.h:15
weight
DAS::Weight weight
Definition: classes.h:11
DAS::Normalisation::makeTriggerEffHist
unique_ptr< TH1F > makeTriggerEffHist(const unique_ptr< TEfficiency > &t_eff, int iHLT, int iEta)
Extract the HLT efficiency curves in 1D histograms from TEfficiency objects.
Definition: MakeEfficiencyHistos.h:21
Ntupliser_cfg.config
config
Definition: Ntupliser_cfg.py:330
gitlab_post_comment.response
response
Definition: gitlab_post_comment.py:23
orange
static const char * orange
Definition: colours.h:6
DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.input
input
Definition: DYToLL_M-50_13TeV_pythia8_cff_GEN_SIM_RECOBEFMIX_DIGI_L1_DIGI2RAW_L1Reco_RECO.py:35
DAS::PhysicsObject::CorrPt
float CorrPt(size_t i) const
corrected transverse momentum
Definition: PhysicsObject.h:55
Ntupliser_cfg.recjets
recjets
Definition: Ntupliser_cfg.py:342
DAS::Normalisation::extractBinning
vector< double > extractBinning(const unique_ptr< TH1 > &h3D, const TString &axis)
Extract the axis binning from a TH1 obgect and return it in a vector.
Definition: ExtractBinning.h:18
DAS::Normalisation::makeRespHist
std::unique_ptr< T > makeRespHist(TString name, std::vector< double > pt_edges=DAS::JetEnergy::pt_JERC_edges, TString title=";p_{T}^{gen};|#eta^{rec}|;#frac{p_{T}^{rec}}{p_{T}^{gen}}")
Definition: MakeResponseHistos.h:22
DAS::nPtBins
static const int nPtBins
Definition: binnings.h:39
DAS::Normalisation::WEIGHT
@ WEIGHT
use the weights
Definition: getSumWeights.cc:28
Ntupliser_cfg.isMC
dictionary isMC
Definition: Ntupliser_cfg.py:62
DAS::TPS::RemovalStrategy::DeltaR
@ DeltaR
DAS::Normalisation::threshold
const float threshold
Definition: sigmoid.h:14
DAS::Normalisation::GetNormFactor
float GetNormFactor(const int steering, const vector< fs::path > &sumWgts, const float xsec)
Definition: applyMClumi.cc:37
jercExample.inputs
def inputs
Definition: jercExample.py:118
DAS::Normalisation::match
DAS::FourVector match(const DAS::FourVector &jet, const std::vector< DAS::FourVector > *hltJets)
Definition: match.h:7
Darwin::Exceptions::AnomalousEvent
Generic exception for problematic event (during event loop).
Definition: exceptions.h:63
DAS::FourVector
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< float > > FourVector
Definition: PhysicsObject.h:15
Darwin::Tools::dev_null
static std::ostream dev_null(nullptr)
to redirect output stream to nowhere
DAS::Normalisation::GetTriggerEfficiency
float GetTriggerEfficiency(int trigger, TH1 *h, STREAM &Stream, float from, float minEff)
Definition: sigmoid.h:101
Darwin::Tools::Flow::GetInputHist
std::unique_ptr< THX > GetInputHist(const std::string &name)
Load a single ROOT histogram from a list of files.
Definition: Flow.h:210
DAS::Normalisation::getPrescale
float getPrescale(Trigger *trigger, size_t indx)
Definition: getTriggerCurves.cc:94
Darwin::Exceptions::BadInput
Generic exception for ill-defined input (before the event loop).
Definition: exceptions.h:83
jmarExample.eta
eta
DeepAK8/ParticleNet tagging.
Definition: jmarExample.py:19
Darwin::Tools::facultative
@ facultative
mounting branch is facultative
Definition: Flow.h:31
DAS::Normalisation::loopOverDirs
void loopOverDirs(TDirectory *dIn, TDirectory *dOut, const int steering, const DT::Slice slice)
Definition: getHistoEfficiencyCurves.cc:51
DAS::Normalisation::GetX
float GetX(TF1 *f)
Definition: sigmoid.h:20
DAS::yBins
static const std::vector< TString > yBins
Definition: binnings.h:44
DAS::Normalisation::CUTOFF
@ CUTOFF
apply a selection on the weight
Definition: getSumWeights.cc:30