DAS  3.0
Das Analysis System
applyDataNormalisation.h
Go to the documentation of this file.
1 #include <cstdlib>
2 #include <cassert>
3 #include <iostream>
4 #include <vector>
5 #include <map>
6 #include <filesystem>
7 
10 
12 
13 #include <TFile.h>
14 #include <TChain.h>
15 #include <TH2.h>
16 #include <TString.h>
17 
18 #include "Math/VectorUtil.h"
19 
23 
24 namespace fs = std::filesystem;
25 
26 namespace DAS::Normalisation {
27 
28 inline void reset (Weights& wgts, const double v = 0) { std::fill(wgts.begin(), wgts.end(), Weight{v,0}); }
29 
66 struct Functor {
67  const std::map<int, TriggerLumi> triggers_lumi;
69  const size_t ntriggers;
70  const double inv_total_lumi;
71  const float minpt;
72  size_t ibit;
73  std::map<int, TriggerLumi>::const_reverse_iterator it;
74 
75 private:
83  const RecJet& (Functor::* NormalisationPtr)(RecEvent&, std::vector<RecJet>&, std::vector<FourVector>&, Trigger&);
85 
86 public:
89  Functor (fs::path lumi_file, // !< path to the a two column file containg trigger lumis
90  fs::path turnon_file, // !< file containing turnons output of `getTriggerTurnons`
91  fs::path trigger_curves, // !< .root trigger curves, output of `getTriggerTurnons`
92  const std::string& strategy, // !< strategy 'pt' or 'eta'
93  const std::string& method, // !< method 'presc' or 'lumi'
94  const int year) : // !< year of the dataset (201?)
95  triggers_lumi(GetLumiFromFiles(lumi_file, turnon_file)),
96  eff(trigger_curves, triggers_lumi, year),
97  ntriggers(triggers_lumi.size()),
98  inv_total_lumi((prev(triggers_lumi.end())->second).weight),
99  minpt(triggers_lumi.begin()->second.turnon)
100  {
101  using namespace std;
102 
103  cout << "ntriggers = " << ntriggers << '\n'
104  << "tot lumi = " << 1./inv_total_lumi << '\n'
105  << "minpt = " << minpt << endl;
106 
107  if (method == "prescales")
109  else if (method == "lumi")
111  else {
112  cerr << "method ('" << method << "') is not defined, aborting\n";
113  exit(EXIT_FAILURE);
114  }
115 
116  if (strategy == "pt")
118  else if (strategy == "eta")
120  else {
121  cerr << "strategy of selection and normalisation ('" << strategy << "') is not defined, aborting\n";
122  exit(EXIT_FAILURE);
123  }
124  }
125 
134  const RecJet& operator() (RecEvent & evnt,
135  std::vector<RecJet>& recJets,
136  std::vector<FourVector>& hltJets,
137  Trigger& trigger)
138  {
139  return (this->*NormalisationPtr)(evnt, recJets, hltJets, trigger);
140  }
141 
142 private:
149  const RecJet& leadingJet,
150  const Trigger& trigger)
151  {
152  using namespace std;
153 
154  // get prescale
155  double preHLT = trigger.PreHLT[ibit];
156  double preL1min = trigger.PreL1min[ibit];
157  double preL1max = trigger.PreL1max[ibit];
158  if (preL1min != preL1max)
159  cerr << "\x1B[31m\e[1m" << preL1min << ' ' << preL1max << "\x1B[30m\e[0m\n";
160 
161  double prescale = preHLT * preL1min;
162  // sanity checks:
164  // 1) we assume that the same prescale is indeed constant for a given LS
165  {
166  static vector<map<pair<int,int>,int>> prescales(ntriggers);
167  pair<int,int> runlum = {evnt.runNo, evnt.lumi};
168  if (prescales.at(ibit).count(runlum))
169  assert(prescales.at(ibit).at(runlum) == prescale);
170  else
171  prescales.at(ibit)[runlum] = prescale;
172  }
173 
174  // setting the inverse of the eff lumi to the event including correction of for the trigger efficiency
175  double efficiency = eff(leadingJet);
176  //cout << __LINE__ << ' ' << efficiency << endl; /// \todo verbose option
177  if (efficiency <= 0)
178  reset(evnt.weights);
179  else {
180  double norm = prescale * inv_total_lumi / efficiency;
181  //cout << __LINE__ << ' ' << norm << endl; /// \todo verbose option
182  evnt.weights *= norm;
183  }
184  return leadingJet;
185  }
186 
195  const RecJet& leadingJet,
196  const Trigger& trigger)
197  {
198  // retrieve the efficiency and the effective luminosity
199  double efficiency = eff(leadingJet);
200  double inv_eff_lumi = (it->second).weight;
201 
202 
203  if (efficiency <= 0)
204  reset(evnt.weights);
205  else {
206  double norm = inv_eff_lumi / efficiency;
207  evnt.weights *= norm;
208  }
209  return leadingJet;
210  }
211 
220  std::vector<RecJet>& recJets,
221  std::vector<FourVector>& hltJets,
222  Trigger& trigger)
223  {
224  using namespace std;
225 
226  // we find the leading jet in tracker acceptance
227  auto leadingInTk = phaseSel(recJets);
228 
229  // remove empty events
230  if (leadingInTk == recJets.end()) {
231  reset(evnt.weights);
232  return recJets.front();
233  }
234  // we assume that JES corrections have been stored in DAS::RecJet::scales
235  auto leading_pt = leadingInTk->CorrPt();
236  // remove events if it does not contain any jets with pt > first threshold
237  if (leading_pt < minpt) {
238  reset(evnt.weights);
239  return recJets.front();
240  }
241  // note: we want to keep jets with pt < minpt if at least the leading jets has >= 64
242  // (but other jets are allowed to have a arbitrarily low pt)
243 
244  it = triggers_lumi.rbegin();
245  ibit = ntriggers-1;
246  // find the range by looping over triggers (from top to bottom)
247  while (it != triggers_lumi.rend()) {
248  if (leading_pt >= it->second.turnon) break;
249  ++it; --ibit;
250  }
251 
252  //cout << __LINE__ << ' ' << ibit << endl; /// \todo verbose option
253 
254  // if the leading pt was "too low"
255  // (i.e. smaller than the lowest-pt turn-on),
256  // then the event is discarded
257 
258  if (it == triggers_lumi.rend()) {
259  cerr << "\x1B[31m\e[1mProblem with `trigger_lumi` iterator (leading_pt = " << leading_pt << ")\x1B[30m\e[0m\n";
260  reset(evnt.weights);
261  return recJets.front();
262  }
263  if (ibit >= ntriggers+1) {
264  cerr << "\x1B[31m\e[1mProblem with `ibit` (leading_pt = " << leading_pt << ")\x1B[30m\e[0m\n";
265  reset(evnt.weights);
266  return recJets.front();
267  }
268 
269  // check if the trigger has fired
270  if (!trigger.Bit.at(ibit)) {
271  reset(evnt.weights);
272  return recJets.front();
273  }
274  return (this->*NormalisationCommonPtr)(evnt, *leadingInTk, trigger);
275  }
276 
291  std::vector<RecJet>& recJets,
292  std::vector<FourVector>& hltJets,
293  Trigger & trigger)
294  {
295  using namespace std;
296 
297  // sorte the jets in decreasing order of rapidity
298  auto mnorder = [] (const RecJet& recJet1, const RecJet& recJet2) {
299  return (recJet1.p4.Eta() > recJet2.p4.Eta());
300  };
301  sort(recJets.begin(), recJets.end(), mnorder);
302 
303  // take the most forward and most backward jets
304  auto leadingJet = recJets.begin();
305  auto subleadingJet = prev(recJets.end());
306  FourVector leadingHltTk = match(leadingJet->p4, &hltJets);
307  FourVector subleadingHltTk = match(subleadingJet->p4, &hltJets);
308 
309  if (leadingHltTk == FourVector() && subleadingHltTk == FourVector()) {
310  reset(evnt.weights);
311  return recJets.front();
312  }
313 
314  // we assume that JES corrections have been stored in DAS::RecJet::scales
315  float leading_pt = leadingJet->CorrPt();
316  float subleading_pt = subleadingJet->CorrPt();
317  // remove events if it does not contained any jet with pt > pt of the first threshold
318  if (leading_pt < minpt && subleading_pt < minpt) {
319  reset(evnt.weights);
320  return recJets.front();
321  }
322 
323  // note: we want to keep jets with pt < minpt if at least the leading jets has > 64
324  // (but other jets are allowed to have a arbitrarily low pt)
325 
326  float leadingHlt_pt = leadingHltTk.Pt();
327  float subleadingHlt_pt = subleadingHltTk.Pt();
328 
329  it = triggers_lumi.rbegin();
330  ibit = ntriggers-1;
331 
332  // Find the range by looping over triggers (from top to bottom)
333  while (it != triggers_lumi.rend()) {
334  int recturnon = it->second.turnon;
335  float hltthreshold = it->first;
336  if ( (leading_pt >= recturnon) && (leadingHlt_pt >= hltthreshold)
337  && (subleading_pt >= recturnon) && (subleadingHlt_pt >= hltthreshold) ) {
338  if ( std::abs(subleadingJet->p4.Eta()) > std::abs(leadingJet->p4.Eta()) ) {
339  swap(leadingJet, subleadingJet);
340  swap(leading_pt, subleading_pt);
341  swap(leadingHlt_pt, subleadingHlt_pt);
342  }
343  break;
344  }
345  if (leading_pt >= recturnon && leadingHlt_pt >= hltthreshold) break;
346  if (subleading_pt >= recturnon && subleadingHlt_pt >= hltthreshold) {
347  swap(leadingJet, subleadingJet);
348  swap(leading_pt, subleading_pt);
349  swap(leadingHlt_pt, subleadingHlt_pt);
350  break;
351  }
352  ++it; --ibit;
353  }
354 
355  // if the leading pt was "too low"
356  // (i.e. smaller than the lowest-pt turn-on),
357  // then the event is discarded
358  if (it == triggers_lumi.rend()) {
359  reset(evnt.weights);
360  return recJets.front();
361  }
362 
363  if (ibit >= ntriggers+1) {
364  cerr << "\x1B[31m\e[1mProblem with `ibit` (leading_pt = " << leading_pt << ")\x1B[30m\e[0m\n";
365  reset(evnt.weights);
366  return recJets.front();
367  }
368 
369  //check if the trigger has fired
370  if (!trigger.Bit.at(ibit)) {
371  reset(evnt.weights);
372  return recJets.front();
373  }
374  return (this->*NormalisationCommonPtr)(evnt, *leadingJet, trigger);
375  }
376 };
377 
378 } // end of DAS::Normalisation namespace
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
DAS::Weights
std::vector< Weight > Weights
Definition: Weight.h:41
Ntupliser_cfg.cerr
cerr
Definition: Ntupliser_cfg.py:93
DAS::Normalisation::Functor::NormalisationStd
const RecJet & NormalisationStd(RecEvent &evnt, std::vector< RecJet > &recJets, std::vector< FourVector > &hltJets, Trigger &trigger)
Definition: applyDataNormalisation.h:219
Darwin::Tools::fill
@ fill
activate -f to fill the tree
Definition: Options.h:27
DAS::PhysicsObject::p4
FourVector p4
raw four-momentum directly after reconstruction
Definition: PhysicsObject.h:50
DAS::Normalisation::Functor::operator()
const RecJet & operator()(RecEvent &evnt, std::vector< RecJet > &recJets, std::vector< FourVector > &hltJets, Trigger &trigger)
Definition: applyDataNormalisation.h:134
DAS::Normalisation::Functor::eff
TriggerEff eff
Definition: applyDataNormalisation.h:68
Ntupliser_cfg.year
int year
Definition: Ntupliser_cfg.py:63
DAS::Normalisation::Functor::NormalisationFwd
const RecJet & NormalisationFwd(RecEvent &evnt, std::vector< RecJet > &recJets, std::vector< FourVector > &hltJets, Trigger &trigger)
Definition: applyDataNormalisation.h:290
DAS::Trigger
Definition: Event.h:71
DAS::Trigger::Bit
std::vector< bool > Bit
indicates which trigger has fired
Definition: Event.h:72
DAS::Normalisation::Functor::NormalisationCommonLumi
const RecJet & NormalisationCommonLumi(RecEvent &evnt, const RecJet &leadingJet, const Trigger &trigger)
Definition: applyDataNormalisation.h:194
TriggerLumi.h
DAS::RecEvent
Definition: Event.h:52
Event.h
DAS::RecJet
Definition: Jet.h:37
DAS::Normalisation::reset
void reset(Weights &wgts, const double v=0)
Definition: applyDataNormalisation.h:28
DAS::AbstractEvent::weights
Weights weights
e.g. cross section normalisation
Definition: Event.h:23
Jet.h
DAS::RecEvent::runNo
int runNo
6-digit run number
Definition: Event.h:55
DAS::Normalisation::Functor::it
std::map< int, TriggerLumi >::const_reverse_iterator it
Definition: applyDataNormalisation.h:73
DAS::Normalisation::Functor::ntriggers
const size_t ntriggers
Definition: applyDataNormalisation.h:69
DAS::Normalisation::Functor::NormalisationPtr
const RecJet &(Functor::* NormalisationPtr)(RecEvent &, std::vector< RecJet > &, std::vector< FourVector > &, Trigger &)
Definition: applyDataNormalisation.h:83
DAS::Trigger::PreL1max
std::vector< int > PreL1max
L1 max pre-scale.
Definition: Event.h:75
weight
DAS::Weight weight
Definition: classes.h:11
DAS::Normalisation::Functor
Definition: applyDataNormalisation.h:66
DAS::Normalisation::Functor::minpt
const float minpt
Definition: applyDataNormalisation.h:71
DAS::RecEvent::lumi
int lumi
lumi section
Definition: Event.h:56
TriggerEff.h
DAS::Normalisation::Functor::ibit
size_t ibit
Definition: applyDataNormalisation.h:72
DAS::Trigger::PreL1min
std::vector< int > PreL1min
L1 min pre-scale.
Definition: Event.h:74
DAS::GetLumiFromFiles
std::map< int, TriggerLumi > GetLumiFromFiles(const std::filesystem::path &lumi_file, const std::filesystem::path &turnon_file)
path to text file with turn-on points
DAS::Normalisation::Functor::inv_total_lumi
const double inv_total_lumi
Definition: applyDataNormalisation.h:70
toolbox.h
DAS::Weight
Definition: Weight.h:16
DAS::Normalisation::Functor::Functor
Functor(fs::path lumi_file, fs::path turnon_file, fs::path trigger_curves, const std::string &strategy, const std::string &method, const int year)
Definition: applyDataNormalisation.h:89
DAS::Normalisation
Definition: getHLTJetResponse.cc:34
DAS::Normalisation::TriggerEff
Functor to return the efficiency of a given trigger for a given (leading) jet.
Definition: TriggerEff.h:27
DAS::Normalisation::Functor::triggers_lumi
const std::map< int, TriggerLumi > triggers_lumi
Definition: applyDataNormalisation.h:67
DAS::Normalisation::match
DAS::FourVector match(const DAS::FourVector &jet, const std::vector< DAS::FourVector > *hltJets)
Definition: match.h:7
DAS::Normalisation::Functor::NormalisationCommonPresc
const RecJet & NormalisationCommonPresc(RecEvent &evnt, const RecJet &leadingJet, const Trigger &trigger)
Definition: applyDataNormalisation.h:148
DAS::Trigger::PreHLT
std::vector< int > PreHLT
HLT prescale.
Definition: Event.h:73
PhaseSelection.h
DAS::FourVector
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< float > > FourVector
Definition: PhysicsObject.h:15
DAS::Normalisation::Functor::NormalisationCommonPtr
const RecJet &(Functor::* NormalisationCommonPtr)(RecEvent &, const RecJet &, const Trigger &)
Definition: applyDataNormalisation.h:84