DAS  3.0
Das Analysis System
DAS::Muon Namespace Reference

Classes

class  IDApplier
 
class  TriggerApplier
 

Enumerations

enum  Selector {
  None = 0u, CutBasedIdLoose = 1u<< 0, CutBasedIdMedium = 1u<< 1, CutBasedIdMediumPrompt = 1u<< 2,
  CutBasedIdTight = 1u<< 3, CutBasedIdGlobalHighPt = 1u<< 4, CutBasedIdTrkHighPt = 1u<< 5, PFIsoVeryLoose = 1u<< 6,
  PFIsoLoose = 1u<< 7, PFIsoMedium = 1u<< 8, PFIsoTight = 1u<< 9, PFIsoVeryTight = 1u<<10,
  TkIsoLoose = 1u<<11, TkIsoTight = 1u<<12, SoftCutBasedId = 1u<<13, SoftMvaId = 1u<<14,
  MvaLoose = 1u<<15, MvaMedium = 1u<<16, MvaTight = 1u<<17, MiniIsoLoose = 1u<<18,
  MiniIsoMedium = 1u<<19, MiniIsoTight = 1u<<20, MiniIsoVeryTight = 1u<<21
}
 

Functions

bool PassTriggerSelection (const Trigger &trg, const vector< RecMuon > &recMuons, int year)
 
void applyDimuonTriggerStrategy (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void applyMuonSelection (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void applyRochesterCorr (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
vector< float > GetMassEdges (int nbins=100, double M=3000, double m=30)
 
void getDimuonSpectrum (const vector< fs::path > &inputs, const fs::path &output, const int steering, const DT::Slice slice={1, 0})
 
void getZmmgControlPlots (const vector< fs::path > &inputs, const fs::path &output, const int steering, const DT::Slice slice={1, 0})
 
std::tuple< std::filesystem::path, std::string > getLocation (const std::string &location)
 

Enumeration Type Documentation

◆ Selector

enum Selector

Adapted from CMSSW

Enumerator
None 
CutBasedIdLoose 
CutBasedIdMedium 
CutBasedIdMediumPrompt 
CutBasedIdTight 
CutBasedIdGlobalHighPt 
CutBasedIdTrkHighPt 
PFIsoVeryLoose 
PFIsoLoose 
PFIsoMedium 
PFIsoTight 
PFIsoVeryTight 
TkIsoLoose 
TkIsoTight 
SoftCutBasedId 
SoftMvaId 
MvaLoose 
MvaMedium 
MvaTight 
MiniIsoLoose 
MiniIsoMedium 
MiniIsoTight 
MiniIsoVeryTight 
39  {
40  None = 0u, // added
41  CutBasedIdLoose = 1u<< 0,
42  CutBasedIdMedium = 1u<< 1,
43  CutBasedIdMediumPrompt = 1u<< 2, // medium with IP cuts
44  CutBasedIdTight = 1u<< 3,
45  CutBasedIdGlobalHighPt = 1u<< 4, // high pt muon for Z',W' (better momentum resolution)
46  CutBasedIdTrkHighPt = 1u<< 5, // high pt muon for boosted Z (better efficiency)
47  PFIsoVeryLoose = 1u<< 6, // reliso<0.40
48  PFIsoLoose = 1u<< 7, // reliso<0.25
49  PFIsoMedium = 1u<< 8, // reliso<0.20
50  PFIsoTight = 1u<< 9, // reliso<0.15
51  PFIsoVeryTight = 1u<<10, // reliso<0.10
52  TkIsoLoose = 1u<<11, // reliso<0.10
53  TkIsoTight = 1u<<12, // reliso<0.05
54  SoftCutBasedId = 1u<<13,
55  SoftMvaId = 1u<<14,
56  MvaLoose = 1u<<15,
57  MvaMedium = 1u<<16,
58  MvaTight = 1u<<17,
59  MiniIsoLoose = 1u<<18, // reliso<0.40
60  MiniIsoMedium = 1u<<19, // reliso<0.20
61  MiniIsoTight = 1u<<20, // reliso<0.10
62  MiniIsoVeryTight = 1u<<21 // reliso<0.05
63 };

Function Documentation

◆ applyDimuonTriggerStrategy()

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

Code to apply the Double Muon trigger SFs documented at the following link: https://indico.cern.ch/event/1106050/contributions/4653418/ Expecting one the following triggers:

  • HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass8_v <– expected from n-tupliser
  • HLT_Mu19_TrkIsoVVL_Mu9_TrkIsoVVL_DZ_Mass8_v
  • HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_Mass3p8_v <– expected from n-tupliser
  • HLT_Mu19_TrkIsoVVL_Mu9_TrkIsoVVL_DZ_Mass3p8_v

The code was written assuming the calibration files found in /eos/cms/store/group/phys_muon/jmijusko/DoubleMuonTrigger_SF_UL/ which contains the following TH2Ds with axes corresponding to the respective muon pseudorapidities and bin content to the efficiency.

  • ScaleFactor[WP]_UL[year]
  • ScaleFactor[WP]_UL[year]_stat
  • ScaleFactor[WP]_UL[year]_syst
  • ScaleFactor[WP]_UL[year]_alt (except for 2018)
  • ScaleFactor[WP]_UL[year]_massBin (except for 2018)
  • ScaleFactor[WP]_UL[year]_massRange (except for 2018) where [WP] = Tight or Medium (for both ID and ISO) [year] = 2016_HIPM, 2016, 2017, or 2018
Parameters
inputsinput ROOT files (n-tuples)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::options`
steeringparameters obtained from explicit options
slicenumber and index of slice
128  {1,0}
129  )
130 {
131  cout << __func__ << ' ' << slice << " start" << endl;
132 
133  DT::Flow flow(steering);
134  auto tIn = flow.GetInputTree(inputs, slice);
135  auto tOut = flow.GetOutputTree(output);
136 
137  DT::MetaInfo metainfo(tOut);
138  metainfo.Check(config);
139  auto isMC = metainfo.Get<bool>("flags", "isMC");
140  auto year = metainfo.Get<int>("flags", "year");
141 
142  auto efficiency = config.get<string>("corrections.muons.trigger_eff");
143  auto [filename, histname] = getLocation(efficiency);
144 
145  TriggerApplier applier(filename, histname, year,
146  isMC && filename != "/dev/null", steering & DT::syst);
147  metainfo.Set<string>("corrections", "muons", "trigger_eff", efficiency);
148  for (const auto& name: applier.weightNames())
149  metainfo.Set<string>("variations", RecEvent::WeightVar, name);
150 
151  auto trg = flow.GetBranchReadOnly<Trigger>("muonTrigger");
152  auto recEvent = flow.GetBranchReadWrite<RecEvent>("recEvent");
153  auto recMuons = flow.GetBranchReadOnly<vector<RecMuon>>("recMuons");
154 
155  for (DT::Looper looper(tIn); looper(); ++looper) {
156  [[ maybe_unused]]
157  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
158 
159  applier(*recEvent, *trg, *recMuons);
160 
161  if (steering & DT::fill) tOut->Fill();
162  }
163 
164  metainfo.Set<bool>("git", "complete", true);
165 
166  cout << __func__ << ' ' << slice << " stop" << endl;
167 }

◆ applyMuonSelection()

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

Generic executable for all types of muon efficiency corrections. The command should be called once for each table.

TWiki Tables

==== RECO NUM = TrackerMuons DEN = genTracks

  • binning: abseta_pt
  • uncertainties: – (?)

==== Muon ID NUM = HighPtID LooseID MediumID MediumPromptID SoftID TightID TrkHighPtID DEN = TrackerMuons

  • binning: abseta_pt
  • uncertainties: stat, syst

==== Muon ISO DEN \ NUM LooseRelIso LooseRelTkIso TightRelIso TightRelTkIso LooseID x MediumID x x MediumPromptID x x TightID & IPCut x x HighPtID & IPCut x x TrkHighPtID & IPCut x x

  • binning: abseta_pt
  • uncertainties: stat, syst

==== trigger DEN \ NUM IsoMu24 IsoMu24_or_Mu50 Mu50_or_OldMu100_or_TkMu100 IdMedium & PFIsoMedium x x IdTight & PFIsoTight x x IdGlobalHighPt & TkIsoLoose x

  • binning: abseta_pt, charge_abseta_pt, charge_eta_pt, eta_pt
  • uncertainties: stat, syst

==== tracking Quoting the TWiki:

Official tracking POG SFs, where the probe is a standalone muon and it is required to be matched to a generalTrack in its vicinity, are independent of momentum. The SFs are found to be above 0.99, and are considered equivalent to unity. You can find the detailed plots per eta and pT bins in this TWiki. The recommendation are to not apply them, unless you target a precison analysis.

Todo:
ControlPlots
Parameters
inputsinput ROOT files (n-tuples)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::options`
steeringparameters obtained from explicit options
slicenumber and index of slice
217  {1,0}
218  )
219 {
220  cout << __func__ << ' ' << slice << " start" << endl;
221 
222  DT::Flow flow(steering);
223  auto tIn = flow.GetInputTree(inputs, slice);
224  auto tOut = flow.GetOutputTree(output);
225 
226  DT::MetaInfo metainfo(tOut);
227  metainfo.Check(config);
228 
229  auto recMuons = flow.GetBranchReadWrite<vector<RecMuon>>("recMuons");
230 
231  auto efficiency = config.get<string>("corrections.muons.efficiency");
232  if (efficiency == "") {
233  auto& efficiencies = config.get_child("corrections.muons.efficiency");
234  if (efficiencies.size() == 0)
235  BOOST_THROW_EXCEPTION( invalid_argument("Missing efficiency") );
236  auto it = efficiencies.begin();
237  while (metainfo.Find("corrections", "muons", "efficiency", it->first))
238  ++it;
239  efficiency = it->first;
240  }
241  auto [filename, histname] = getLocation(efficiency);
242  cout << filename << ' ' << histname << endl;
243 
244  IDApplier applier(filename, histname, filename != "/dev/null", steering & DT::syst);
245  if (metainfo.Find("corrections", "muons", "efficiency")) {
246  // 0 = previous, former
247  auto efficiency0 = metainfo.Get<string>("corrections", "muons", "efficiency");
248  auto [filename0, histname0] = getLocation(efficiency0);
249  if (filename == filename0 && filename != "/dev/null")
250  cerr << orange << "The same file has been used twice in a row, "
251  "which is unexpected: `" << filename << "`. "
252  "Proceed at your own risks.\n" << def;
253  IDApplier applier0(filename0, histname0, false, false);
254  if (applier.DEN != applier0.NUM)
255  cerr << orange << "The former and present muon efficiency corrections are "
256  "unexpected combinations: `" << applier0.name << "` and `"
257  << applier.name <<"`. Proceed at your own risks.\n" << def;
258  }
259  metainfo.Set<string>("corrections", "muons", "efficiency", efficiency);
260 
261  for (const auto& name: applier.weightNames())
262  metainfo.Set<string>("variations", RecMuon::WeightVar, name);
263 
265 
266  for (DT::Looper looper(tIn); looper(); ++looper) {
267  [[ maybe_unused]]
268  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
269 
270  applier(*recMuons);
271 
272  if (steering & DT::fill) tOut->Fill();
273  }
274 
275  metainfo.Set<bool>("git", "complete", true);
276 
277  cout << __func__ << ' ' << slice << " stop" << endl;
278 }

◆ applyRochesterCorr()

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

TWiki

 set   nmembers  comment

Default 0 1 default, reference based on madgraph sample, with adhoc ewk (sw2eff and Z width) and Z pt (to match data) weights. Stat 1 100 pre-generated stat. replicas; Zpt 2 1 derived without reweighting reference pt to data. Ewk 3 1 derived without applying ad-hoc ewk weights deltaM 4 1 one representative set for alternative profile deltaM mass window

Ewk2 5 1 reweight the reference from constant to s-dependent Z width

For statistical replicas, std. dev. gives uncertainty. For the rest, difference wrt the cental is assigned as syst. error. Total uncertainty is calculated as a quadrature sum of all components.

Todo:
Implement alternative nominal correction
Todo:
Zpt: rather provide as alternative? (issue #76)
Todo:
Ewk2: understand 3rd remark from MUON POG
Todo:
clear scales?
Todo:
should we force up (down) in the first (second) place?
Parameters
inputsinput ROOT files (n-tuples)
outputoutput ROOT file (n-tuple)
configconfig handled with `Darwin::Tools::options`
steeringparameters obtained from explicit options
slicenumber and index of slice
57  {1,0}
58  )
59 {
60  cout << __func__ << ' ' << slice << " start" << endl;
61 
62  DT::Flow flow(steering);
63  auto tIn = flow.GetInputTree(inputs, slice);
64  auto tOut = flow.GetOutputTree(output);
65 
66  DT::MetaInfo metainfo(tOut);
67  metainfo.Check(config);
68  auto isMC = metainfo.Get<bool>("flags", "isMC");
69 
70  auto recMuons = flow.GetBranchReadWrite<vector<RecMuon>>("recMuons");
71  auto genMuons = isMC ? flow.GetBranchReadWrite<vector<GenMuon>>("genMuons") : nullptr;
72 
73  auto tables = config.get<fs::path>("corrections.muons.rochester.tables");
74  if (!fs::exists(tables))
75  BOOST_THROW_EXCEPTION( fs::filesystem_error("Tables can't be found.",
76  tables, make_error_code(errc::no_such_file_or_directory)));
77  metainfo.Set<fs::path>("corrections", "muons", "rochester", "tables", tables);
78  RoccoR rc(tables.c_str());
79 
80  auto alternative = config.get<bool>("corrections.muons.rochester.alternative");
82  if (alternative)
83  BOOST_THROW_EXCEPTION( logic_error("Alternative nominal correction not yet implemented") );
84  metainfo.Set<bool>("corrections", "muons", "rochester", "alternative", alternative);
85 
86  const bool applySyst = steering & DT::syst;
87  if (applySyst) {
90  for (const string& syst: {"stat", "Zpt", "Ewk", "deltaM", "Ewk2"}) {
91  metainfo.Set<string>("variations", RecMuon::WeightVar, syst + SysUp);
92  metainfo.Set<string>("variations", RecMuon::WeightVar, syst + SysDown);
93  }
94  }
95 
96  vector<GenMuon> mcands; // matching candidates
97  for (DT::Looper looper(tIn); looper(); ++looper) {
98  [[ maybe_unused]]
99  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
100 
101  if (isMC) mcands = *genMuons; // copy to avoid modifying the event
102 
103  for (auto& recMuon: *recMuons) {
104 
105  float pt = recMuon.p4.Pt(),
106  eta = recMuon.p4.Eta(),
107  phi = recMuon.p4.Phi();
108  int Q = recMuon.Q;
109  cout << Q << '\t' << pt << '\t' << eta << '\t' << phi << endl;
110 
111  auto& nl = recMuon.nTkHits;
112 
113  // 1) get scale factor (lambda)
114  function<double(int /* unc set */,int /* member */)> SF;
115  if (isMC) {
116  // find the closest gen muon within DR <= 0.1
117  auto DR = [&recMuon](const GenMuon& m) { return DeltaR(m.p4, recMuon.p4) < 0.1; };
118  auto getClosest = [&DR](const GenMuon& m1, const GenMuon& m2) { return DR(m1) < DR(m2); };
119  auto closestGenMuon_it = min_element(genMuons->begin(), genMuons->end(), getClosest);
120 
121  if (closestGenMuon_it != mcands.end() && DR(*closestGenMuon_it))
122  SF = [&](int s, int m) {
123  float genpt = closestGenMuon_it->p4.Pt();
124  return rc.kSpreadMC(Q, pt, eta, phi, genpt, s, m);
125  };
126  else {
127  static TRandom3 r(metainfo.Seed<897532>(slice));
128  const auto u = r.Rndm();
129  SF = [&](int s, int m) { return rc.kSmearMC(Q, pt, eta, phi, nl, u, s, m); };
130  }
131  }
132  else
133  SF = [&](int s, int m) { return rc.kScaleDT(Q, pt, eta, phi, s, m); };
134 
135  // 2) store it in scale
136  recMuon.scales.clear();
137  auto nom = SF(0,0);
138  recMuon.scales.push_back(nom);
139 
140  // 3) variations
141 
142  if (!applySyst) continue;
143 
144  static const int nvars = 5;
145  recMuon.scales.reserve(1+2*nvars);
146  auto push_back = [&recMuon,&nom](float unc) {
147  recMuon.scales.push_back(unc);
148  unc -= nom; unc *= -1; unc += nom;
149  recMuon.scales.push_back(unc);
151  };
152 
153  // 3a) first stat unc (from replicas)
154  float sum1 = 0, sum2 = 0;
155  for (int m = 0; m < 100; ++m) {
156  float sf = SF(1, m);
157  sum1 += sf;
158  sum2 += sf*sf;
159  }
160  double unc = sqrt(sum1*sum1 - sum2) / 100;
161 
162  push_back(unc);
163 
164  // 3b) then the syst unc
165  for (int s = 2; s <= nvars; ++s) {
166  unc = SF(s,0);
167  push_back(unc);
168  }
169  }
170  if (steering & DT::fill) tOut->Fill();
171  }
172 
173  metainfo.Set<bool>("git", "complete", true);
174 
175  cout << __func__ << ' ' << slice << " stop" << endl;
176 }

◆ getDimuonSpectrum()

void DAS::Muon::getDimuonSpectrum ( const vector< fs::path > &  inputs,
const fs::path &  output,
const int  steering,
const DT::Slice  slice = {1, 0} 
)

Obtain dimuon spectrum.

Parameters
inputsinput ROOT files (n-tuples)
outputoutput ROOT file (n-tuple)
steeringparameters obtained from explicit options
slicenumber and index of slice
50  {1, 0}
51 ) {
52  cout << __func__ << ' ' << slice << " start" << endl;
53 
54  DT::Flow flow(steering);
55  auto tIn = flow.GetInputTree(inputs, slice);
56  auto [fOut, tOut] = flow.GetOutput(output);
57 
58  DT::MetaInfo metainfo(tOut);
59  auto isMC = metainfo.Get<bool>("flags", "isMC");
60 
61  auto recEvt = flow.GetBranchReadOnly<RecEvent>("recEvent");
62  auto genEvt = isMC ? flow.GetBranchReadOnly<GenEvent>("genEvent") : nullptr;
63 
64  auto recMuons = flow.GetBranchReadOnly<vector<RecMuon>>("recMuons");
65  auto recPhotons = flow.GetBranchReadOnly<vector<RecPhoton>>("recPhotons", DT::facultative);
66  auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets", DT::facultative);
67 
68  vector<float> mass_edges = GetMassEdges();
69  unique_ptr<TH1F> h_dimuon = make_unique<TH1F>("dimuon", "", mass_edges.size() - 1, mass_edges.data());
70  unique_ptr<TH1F> h_mmg = make_unique<TH1F>("mumugamma", "", mass_edges.size() - 1, mass_edges.data());
71 
72  unique_ptr<TH1F> h_dimuon_peak = make_unique<TH1F>("dimuon_peak", "", 60, 71, 121);
73  unique_ptr<TH1F> h_mmg_peak = make_unique<TH1F>("mumugamma_peak", "", 60, 71, 121);
74 
75  unique_ptr<TH2F> h_dimuon_mmg = make_unique<TH2F>("dimuon_mmg", "", mass_edges.size() - 1, mass_edges.data(),
76  mass_edges.size() - 1, mass_edges.data());
77  unique_ptr<TH2F> h_dimuon_mmg_peak = make_unique<TH2F>("dimuon_mmg_peak", "", 60, 71, 121,
78  60, 71, 121);
79 
80  vector<double> pt_edges = {25., 30., 35., 40., 50., 60., 70., 80., 90., 100., 110., 130., 150., 170., 190., 220., 250., 400., 1000.};
81  unique_ptr<TH3D> h_Zjet = make_unique<TH3D>("Zjet", "", (int)pt_edges.size() - 1, pt_edges.data(),
82  (int)y_edges.size() - 1, y_edges.data(),
83  (int)y_edges.size() - 1, y_edges.data());
84 
85  for (DT::Looper looper(tIn); looper(); ++looper) {
86  [[ maybe_unused]]
87  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
88 
89  if (recMuons->size() < 2) continue;
90  if (recMuons->at(0).CorrPt() < 20) continue;
91  if (recMuons->at(1).CorrPt() < 15) continue;
92 
93  FourVector m0 = recMuons->at(0).CorrP4(),
94  m1 = recMuons->at(1).CorrP4();
95  FourVector diMuon = m0 + m1;
96  float w_Z = recEvt->weights.front()
97  * recMuons->at(0).weights.front()
98  * recMuons->at(1).weights.front();
99  if (isMC)
100  w_Z *= genEvt->weights.front();
101  h_dimuon->Fill(diMuon.M(), w_Z);
102  h_dimuon_peak->Fill(diMuon.M(), w_Z);
103 
104  if (recJets != nullptr && !recJets->empty() && // at least one jet
105  abs(diMuon.M() - 91.2) < 20 && diMuon.Pt() > 25) {
106  const auto& jet = recJets->front().CorrP4();
107  if (jet.Pt() > 20 && abs(jet.Rapidity()) < 2.4 && // jet selection
108  min(m0.Pt(), m1.Pt()) > 29 && max(abs(m0.Eta()), abs(m1.Eta())) < 2.4 && // muon selection
109  DeltaR(jet, m0) > 0.4 && DeltaR(jet, m1) > 0.4) { // opening angle
110  float w_j = recJets->front().weights.front(),
111  y_b = 0.5 * (diMuon.Rapidity() + recJets->front().Rapidity()),
112  y_s = 0.5 * (diMuon.Rapidity() - recJets->front().Rapidity());
113  h_Zjet->Fill(diMuon.Pt(), y_b, y_s, w_Z * w_j);
114  }
115  }
116 
117  if (diMuon.M() >= 76) continue;
118  if (recPhotons != nullptr && !recPhotons->empty()) {
119  FourVector ph = recPhotons->front().CorrP4();
120  if (ph.Pt() < 20) continue;
121  FourVector mumugamma = diMuon + ph;
122  float w_ph = recPhotons->front().weights.front();
123 
124  h_mmg->Fill(mumugamma.M(), w_Z * w_ph);
125  h_mmg_peak->Fill(mumugamma.M(), w_Z * w_ph);
126 
127  h_dimuon_mmg->Fill(diMuon.M(), mumugamma.M(), w_Z * w_ph);
128  h_dimuon_mmg_peak->Fill(diMuon.M(), mumugamma.M(), w_Z * w_ph);
129  }
130  }
131 
132  metainfo.Set<bool>("git", "complete", true);
133 
134  h_dimuon->SetDirectory(fOut);
135  h_dimuon_peak->SetDirectory(fOut);
136  h_mmg->SetDirectory(fOut);
137  h_mmg_peak->SetDirectory(fOut);
138  h_Zjet->SetDirectory(fOut);
139 
140  h_dimuon->Write();
141  h_dimuon_peak->Write();
142  h_mmg->Write();
143  h_mmg_peak->Write();
144  h_Zjet->Write();
145 
146  h_dimuon_mmg->SetDirectory(fOut);
147  h_dimuon_mmg_peak->SetDirectory(fOut);
148  h_dimuon_mmg->Write();
149  h_dimuon_mmg_peak->Write();
150 
151  cout << __func__ << ' ' << slice << " stop" << endl;
152 }

◆ getLocation()

std::tuple<std::filesystem::path, std::string> DAS::Muon::getLocation ( const std::string &  location)
13 {
14  using namespace std;
15  namespace al = boost::algorithm;
16  namespace fs = filesystem;
17 
18  vector<string> words;
19  al::split(words, location, al::is_any_of(":"), al::token_compress_on);
20  if (words.size() != 2)
21  BOOST_THROW_EXCEPTION( invalid_argument("Expecting `/path/to/file.ext:histname`") );
22  fs::path filename = words.front();
23  string histname = words.back();
24  return {filename, histname};
25 }

◆ GetMassEdges()

vector<float> DAS::Muon::GetMassEdges ( int  nbins = 100,
double  M = 3000,
double  m = 30 
)
35  {
36  float R = pow(M / m, 1. / nbins);
37  vector<float> edges;
38  edges.reserve(nbins + 1);
39  for (float edge = m; edge <= M; edge *= R)
40  edges.push_back(edge);
41  return edges;
42 }

◆ getZmmgControlPlots()

void DAS::Muon::getZmmgControlPlots ( const vector< fs::path > &  inputs,
const fs::path &  output,
const int  steering,
const DT::Slice  slice = {1, 0} 
)

Obtain angular separation plots and fake/miss rates of photons/muons.

Parameters
inputsinput ROOT files (n-tuples)
outputoutput ROOT file (n-tuple)
steeringparameters obtained from explicit options
slicenumber and index of slice
40  {1, 0}
41 )
42 {
43  cout << __func__ << ' ' << slice << " start" << endl;
44 
45  DT::Flow flow(steering);
46  auto tIn = flow.GetInputTree(inputs, slice);
47  auto [fOut,tOut] = flow.GetOutput(output);
48 
49  DT::MetaInfo metainfo(tOut);
50  auto isMC = metainfo.Get<bool>("flags", "isMC");
51 
52  auto recEvt = flow.GetBranchReadOnly<RecEvent>("recEvent");
53  auto genEvt = isMC ? flow.GetBranchReadOnly<GenEvent>("genEvent") : nullptr;
54 
55  auto recMuons = flow.GetBranchReadOnly<vector<RecMuon>>("recMuons");
56  auto genMuons = isMC ? flow.GetBranchReadOnly<vector<GenMuon>>("genMuons") : nullptr;
57  auto recPhotons = flow.GetBranchReadOnly<vector<RecPhoton>>("recPhotons");
58  auto genPhotons = isMC ? flow.GetBranchReadOnly<vector<GenPhoton>>("genPhotons") : nullptr;
59 
60  array h_deltaR {
61  make_unique<TH1F>("deltaR0", "", 100, 0, 5.0),
62  make_unique<TH1F>("deltaR1", "", 100, 0, 5.0)
63  };
64  auto h_deltaRmin = make_unique<TH1F>("deltaRmin", "", 100, 0, 5.0);
65 
66  auto h_fake_mu = make_unique<TH1F>("fake_mu", "", 2, -0.5, 1.5);
67  auto h_miss_mu = make_unique<TH1F>("miss_mu", "", 2, -0.5, 1.5);
68  auto h_fake_ph = make_unique<TH1F>("fake_ph", "", 2, -0.5, 1.5);
69  auto h_miss_ph = make_unique<TH1F>("miss_ph", "", 2, -0.5, 1.5);
70  auto h_fake_mmg = make_unique<TH1F>("diff_fake_mmg", "", 50, 0, 100);
71  auto h_miss_mmg = make_unique<TH1F>("diff_miss_mmg", "", 100, 0, 200);
72 
73  array h_gen_reco_mu_dR {
74  make_unique<TH1F>("gen_reco_mu0_dR", "", 50, 0, 0.5),
75  make_unique<TH1F>("gen_reco_mu1_dR", "", 50, 0, 0.5)
76  };
77  auto h_gen_reco_ph_dR = make_unique<TH1F>("gen_reco_ph_dR", "", 50, 0, 0.5);
78 
79  for (DT::Looper looper(tIn); looper(); ++looper) {
80  [[maybe_unused]]
81  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
82 
83  // muon selection
84  if (recMuons->size() < 2) continue;
85  if (recMuons->at(0).CorrPt() < 20) continue;
86  if (recMuons->at(1).CorrPt() < 15) continue;
87 
88  // photon selection
89  if (recPhotons->empty()) continue;
90  auto rph = recPhotons->front().CorrP4();
91  if (rph.Pt() < 20) continue;
92 
93  // \todo Use Di<RecMuon,RecMuon>
94  // \todo Move phase space selection here
95  auto recdimuon = recMuons->at(0) + recMuons->at(1);
96  if (recdimuon.CorrP4().M() >= 76) continue;
97 
98  double w_Z = recEvt->weights.front() * recdimuon.Weight();
99  if (isMC)
100  w_Z *= genEvt->weights.front();
101 
102  bool match_mmg = true; // will use logical ands to check the matching to individual objects
103  if (isMC) {
104  const float maxDr = 0.1;
105 
106  if (genMuons->size() > 1) {
107  for (size_t irec = 0; irec < 2; irec++) {
108  // the leading and subleading muons may swap due to resolution effects
109  float dR0 = DeltaR(recMuons->at(irec).CorrP4(), genMuons->at(0).CorrP4()),
110  dR1 = DeltaR(recMuons->at(irec).CorrP4(), genMuons->at(1).CorrP4());
111  size_t igen = dR0 < dR1 ? 0 : 1;
112  float dR = min(dR0, dR1);
113 
114  bool match_mu = dR < maxDr;
115  double rW = recMuons->at(irec).weights.front(),
116  gW = genMuons->at(igen).weights.front();
117  h_fake_mu->Fill(match_mu, rW);
118  h_miss_mu->Fill(match_mu, gW);
119  match_mmg &= match_mu;
120 
121  if (match_mu)
122  h_gen_reco_mu_dR[igen]->Fill(dR, gW*rW);
123  }
124  }
125  else match_mmg = false;
126 
127  // \todo Is the leading photon the right photon? (or should we look for the photon closest to one of the two leading muons?)
128  if (recPhotons->size() > 0) {
129  bool match_ph = DeltaR(recPhotons->front().CorrP4(), genPhotons->front().CorrP4()) < maxDr;
130  h_fake_ph->Fill(match_ph, recPhotons->front().weights.front());
131  h_miss_ph->Fill(match_ph, genPhotons->front().weights.front());
132  match_mmg &= match_ph;
133  }
134  else match_mmg = false;
135  }
136 
137  // \todo Use Di<Di<RecMuon,RecMuon>, RecPhoton>
138  double w_ph = recPhotons->front().weights.front();
139 
140  float dR0 = DeltaR(rph, recMuons->at(0).CorrP4()),
141  dR1 = DeltaR(rph, recMuons->at(1).CorrP4());
142  h_deltaR[0]->Fill(dR0, w_Z * w_ph);
143  h_deltaR[1]->Fill(dR1, w_Z * w_ph);
144  h_deltaRmin->Fill(min(dR0, dR1), w_Z * w_ph);
145 
146  if (isMC) {
147 
148  if (match_mmg) {
149  FourVector gph = genPhotons->front().CorrP4();
150  h_gen_reco_ph_dR->Fill(DeltaR(gph, rph), w_Z * w_ph);
151  }
152  else {
153  auto mumugamma = recdimuon.CorrP4() + rph;
154  h_fake_mmg->Fill(mumugamma.M(), w_Z * w_ph);
155  h_miss_mmg->Fill(mumugamma.M(), w_Z * w_ph);
156  }
157  }
158  }
159 
160  metainfo.Set<bool>("git", "complete", true);
161 
162  h_deltaRmin->SetDirectory(fOut);
163  h_deltaRmin->Write();
164  for (auto& h: h_deltaR) {
165  h->SetDirectory(fOut);
166  h->Write();
167  }
168 
169  h_fake_mu->SetDirectory(fOut);
170  h_miss_mu->SetDirectory(fOut);
171  h_fake_ph->SetDirectory(fOut);
172  h_miss_ph->SetDirectory(fOut);
173  h_fake_mmg->SetDirectory(fOut);
174  h_miss_mmg->SetDirectory(fOut);
175  h_gen_reco_ph_dR->SetDirectory(fOut);
176  h_fake_mu->Write();
177  h_miss_mu->Write();
178  h_fake_ph->Write();
179  h_miss_ph->Write();
180  h_fake_mmg->Write();
181  h_miss_mmg->Write();
182  h_gen_reco_ph_dR->Write();
183  for (auto& h: h_gen_reco_mu_dR) {
184  h->SetDirectory(fOut);
185  h->Write();
186  }
187 
188  cout << __func__ << ' ' << slice << " stop" << endl;
189 }

◆ PassTriggerSelection()

bool DAS::Muon::PassTriggerSelection ( const Trigger trg,
const vector< RecMuon > &  recMuons,
int  year 
)
37 {
38  if (recMuons.size() < 2) return false;
39 
40  if (recMuons.at(0).CorrPt() < 19) return false;
41  if (recMuons.at(1).CorrPt() < 9) return false;
42 
43  auto dimuon = recMuons.at(0).p4 + recMuons.at(1).p4;
44  float m = dimuon.M();
45  bool pass = false;
46  switch (year) {
47  case 2017:
48  pass |= (m > 3.8 && trg.Bit.at(1));
49  [[fallthrough]];
50  case 2018:
51  pass |= (m > 8 && trg.Bit.at(0));
52  break;
53  default:
54  BOOST_THROW_EXCEPTION( std::runtime_error(to_string(year) + " has not been implemented yet"s) );
55  }
56 
57  return pass;
58 }
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
Ntupliser_cfg.cerr
cerr
Definition: Ntupliser_cfg.py:93
DAS::y_edges
static const std::vector< double > y_edges
Definition: binnings.h:36
DAS::Muon::MiniIsoLoose
@ MiniIsoLoose
Definition: applyMuonSelection.cc:59
DAS::Di::Weight
double Weight(const Uncertainties::Variation &v=Uncertainties::nominal) const override
Definition: Di.h:73
Darwin::Tools::fill
@ fill
activate -f to fill the tree
Definition: Options.h:27
jmarExample.pt
pt
Definition: jmarExample.py:19
DAS::Muon::TkIsoLoose
@ TkIsoLoose
Definition: applyMuonSelection.cc:52
DAS::Muon::PFIsoVeryTight
@ PFIsoVeryTight
Definition: applyMuonSelection.cc:51
Darwin::Tools::Flow
User-friendly handling of input and output n-tuples.
Definition: Flow.h:69
Step::verbose
static bool verbose
Definition: Step.h:40
Step::def
static const char * def
Definition: Step.h:36
DAS::Muon::PFIsoTight
@ PFIsoTight
Definition: applyMuonSelection.cc:50
DAS::SysUp
const std::string SysUp
Suffix used for "up" uncertainties. Follows the Combine convention.
Definition: Format.h:8
Ntupliser_cfg.year
int year
Definition: Ntupliser_cfg.py:63
Darwin::Tools::split
@ split
activate -k and -j to define slice
Definition: Options.h:26
Darwin::Tools::Looper
Facility to loop over a n-tuple, including parallelisation and printing.
Definition: Looper.h:32
DAS::pt_edges
static const std::vector< double > pt_edges
Definition: binnings.h:33
DAS::Muon::CutBasedIdMedium
@ CutBasedIdMedium
Definition: applyMuonSelection.cc:42
Darwin::Tools::syst
@ syst
activate -s to systematic uncertainties
Definition: Options.h:29
Darwin::Tools::MetaInfo
Generic meta-information for n-tuple (including speficities to Darwin).
Definition: MetaInfo.h:68
DAS::Muon::MvaLoose
@ MvaLoose
Definition: applyMuonSelection.cc:56
DAS::Muon::getLocation
std::tuple< std::filesystem::path, std::string > getLocation(const std::string &location)
Definition: toolbox.h:12
DAS::Muon::MiniIsoVeryTight
@ MiniIsoVeryTight
Definition: applyMuonSelection.cc:62
jercExample.unc
string unc
Definition: jercExample.py:70
DAS::Muon::MvaTight
@ MvaTight
Definition: applyMuonSelection.cc:58
recdimuon
DAS::RecDimuon recdimuon
Definition: classes.h:35
DAS::Muon::PFIsoLoose
@ PFIsoLoose
Definition: applyMuonSelection.cc:48
Ntupliser_cfg.config
config
Definition: Ntupliser_cfg.py:264
DAS::Muon::CutBasedIdTrkHighPt
@ CutBasedIdTrkHighPt
Definition: applyMuonSelection.cc:46
DAS::Muon::MiniIsoTight
@ MiniIsoTight
Definition: applyMuonSelection.cc:61
RoccoR
Definition: RoccoR.h:122
orange
static const char * orange
Definition: colours.h:6
DAS::Muon::CutBasedIdTight
@ CutBasedIdTight
Definition: applyMuonSelection.cc:44
DAS::Muon::CutBasedIdMediumPrompt
@ CutBasedIdMediumPrompt
Definition: applyMuonSelection.cc:43
DAS::Muon::PFIsoVeryLoose
@ PFIsoVeryLoose
Definition: applyMuonSelection.cc:47
DAS::Muon::CutBasedIdLoose
@ CutBasedIdLoose
Definition: applyMuonSelection.cc:41
DAS::SysDown
const std::string SysDown
Suffix used for "down" uncertainties. Follows the Combine convention.
Definition: Format.h:10
DAS::Muon::GetMassEdges
vector< float > GetMassEdges(int nbins=100, double M=3000, double m=30)
Definition: getDimuonSpectrum.cc:35
DAS::Muon::SoftCutBasedId
@ SoftCutBasedId
Definition: applyMuonSelection.cc:54
Ntupliser_cfg.isMC
string isMC
Definition: Ntupliser_cfg.py:59
DAS::Muon::CutBasedIdGlobalHighPt
@ CutBasedIdGlobalHighPt
Definition: applyMuonSelection.cc:45
DAS::Muon::TkIsoTight
@ TkIsoTight
Definition: applyMuonSelection.cc:53
jercExample.sf
sf
Definition: jercExample.py:112
jercExample.inputs
def inputs
Definition: jercExample.py:118
DAS::Muon::None
@ None
Definition: applyMuonSelection.cc:40
DAS::Di::CorrP4
FourVector CorrP4(const Uncertainties::Variation &v=Uncertainties::nominal) const override
Definition: Di.h:46
DAS::FourVector
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< float > > FourVector
Definition: PhysicsObject.h:15
DAS::Muon::MiniIsoMedium
@ MiniIsoMedium
Definition: applyMuonSelection.cc:60
Darwin::Tools::dev_null
static std::ostream dev_null(nullptr)
to redirect output stream to nowhere
DAS::Muon::MvaMedium
@ MvaMedium
Definition: applyMuonSelection.cc:57
DAS::Muon::PFIsoMedium
@ PFIsoMedium
Definition: applyMuonSelection.cc:49
jmarExample.eta
eta
DeepAK8/ParticleNet tagging.
Definition: jmarExample.py:19
Darwin::Tools::facultative
@ facultative
mounting branch is facultative
Definition: Flow.h:31
DAS::Muon::SoftMvaId
@ SoftMvaId
Definition: applyMuonSelection.cc:55