DAS  3.0
Das Analysis System
DAS::TPS Namespace Reference

Classes

struct  has_p4
 
struct  has_p4< T, std::void_t< decltype(std::declval< T >().p4.Eta())> >
 
struct  Hist
 
struct  MultiJets
 

Enumerations

enum  RemovalStrategy { DeltaR, AntikT, None }
 

Functions

void CheckConsistency (DT::MetaInfo &metainfo1, TTree *tIn1, DT::MetaInfo &metainfo2, TTree *tIn2)
 
RemovalStrategy parseStrategy (const string &strategyStr, TTree *tree)
 
template<class Jet >
vector< fjcore::PseudoJet > cluster (const vector< Jet > &jets, const double R)
 
template<class Jet >
bool overlappingJets (const vector< Jet > &jets)
 
map< Long64_t, vector< Long64_t > > buildRunToEntriesMap (TTree *tree, RecEvent *recEvent)
 
void applyEventMixing (const vector< fs::path > &inputs1, const vector< fs::path > &inputs2, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
void applyNjetSkim (const vector< fs::path > &inputs, const fs::path &output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 
template<class Jet >
std::vector< Jet > PhaseSpaceSelection (const std::vector< Jet > &jets, float minpt)
 
void getTPSobservables (const vector< fs::path > inputs, const fs::path output, const pt::ptree &config, const int steering, const DT::Slice slice={1, 0})
 

Enumeration Type Documentation

◆ RemovalStrategy

enum RemovalStrategy
strong
Enumerator
DeltaR 
AntikT 
None 
37 { DeltaR, AntikT, None };

Function Documentation

◆ applyEventMixing()

void DAS::TPS::applyEventMixing ( const vector< fs::path > &  inputs1,
const vector< fs::path > &  inputs2,
const fs::path &  output,
const pt::ptree &  config,
const int  steering,
const DT::Slice  slice = {1,0} 
)

Mix the jets from second input to first input to simulate DPS or TPS events. Overlapping jets are properly treated. Only events with matching run numbers are mixed. The input must be taken from applyNjetSkim and must have the same isMC flag and pTcut.

Todo:
fix output logic
Todo:
Merge metainfos
Parameters
inputs1input ROOT files (n-tuples)
inputs2input 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
140  {1,0}
141  )
142 {
143  cout << __func__ << ' ' << slice << " start" << endl;
144 
145  DT::Flow flow1(steering, inputs1);
146  DT::Flow flow2(steering, inputs2);
147  auto tIn1 = flow1.GetInputTree(slice);
148  auto tIn2 = flow2.GetInputTree(slice);
149  auto tOut2 = flow2.GetOutputTree(output);
150  auto tOut1 = flow1.GetOutputTree(output);
151 
152  DT::MetaInfo metainfo1(tOut1);
153  DT::MetaInfo metainfo2(tOut2);
155  metainfo1.Check(config);
156  metainfo2.Check(config);
157  auto isMC = metainfo1.Get<bool>("flags", "isMC");
158  auto minpt = metainfo1.Get<float>("skims","jets","minpt");
159  auto R = metainfo1.Get<int>("flags","R");
160 
161  CheckConsistency(metainfo1, tIn1, metainfo2, tIn2);
162 
163  auto recEvent1 = flow1.GetBranchReadWrite<RecEvent>("recEvent");
164  auto recEvent2 = flow2.GetBranchReadOnly <RecEvent>("recEvent");
165  auto genEvent1 = isMC ? flow1.GetBranchReadWrite<GenEvent>("genEvent") : nullptr;
166  auto genEvent2 = isMC ? flow2.GetBranchReadOnly <GenEvent>("genEvent") : nullptr;
167  auto recJets1 = flow1.GetBranchReadWrite<vector<RecJet>>("recJets");
168  auto recJets2 = flow2.GetBranchReadOnly <vector<RecJet>>("recJets");
169  auto genJets1 = isMC ? flow1.GetBranchReadWrite<vector<GenJet>>("genJets") : nullptr;
170  auto genJets2 = isMC ? flow2.GetBranchReadOnly <vector<GenJet>>("genJets") : nullptr;
171 
172  const auto strategyStr = config.get<string>("corrections.event_mixing.overlap");
173  const auto strategy = parseStrategy(strategyStr, tIn1);
174 
175  // Build the map from run numbers to entry indices and track the last used index for each run in the 2nd tree
176  map<Long64_t, vector<Long64_t>> runToEntries = buildRunToEntriesMap(tIn2, recEvent2);
177  map<Long64_t, size_t> lastUsedIndex;
178 
179  Long64_t matchedEvents = 0;
180 
181  for (DT::Looper looper(tIn1); looper(); ++looper) {
182  [[maybe_unused]]
183  static auto& cout = (steering & DT::verbose) ? ::cout : DT::dev_null;
184 
185  int run1 = recEvent1->runNo;
186  // Skip if no matching run number
187  if (runToEntries.find(run1) == runToEntries.end())
188  continue;
189 
190  // Get all entries with matching run number
191  const auto& matchingEntries = runToEntries[run1];
192  // Get the next event to use in the 2nd tree
193  size_t currentIndex = lastUsedIndex[run1];
194  Long64_t entry2 = matchingEntries[currentIndex];
195  tIn2->GetEntry(entry2);
196 
197  // sanity check
198  if (recEvent1->runNo != recEvent2->runNo)
199  BOOST_THROW_EXCEPTION(DE::BadInput(("Run number mismatch: " + to_string(recEvent1->runNo) + " != " + to_string(recEvent2->runNo)).c_str(), tIn1));
200 
201  // Update index, wrap around if we reach the end
202  lastUsedIndex[run1] = (currentIndex + 1) % matchingEntries.size();
203 
204  if (recJets1 && recJets2) {
205  // Merge input2's jets into input1's jets
206  recJets1->insert(recJets1->end(), recJets2->begin(), recJets2->end());
207  recEvent1->weights.front() *= recEvent2->weights.front();
208 
209  sort(recJets1->begin(), recJets1->end(), pt_sort); // sort again the jets by pt
210 
211  switch (strategy) {
212  case RemovalStrategy::DeltaR:
213  if (overlappingJets(*recJets1)) continue;
214  break;
215  case RemovalStrategy::AntikT:{
216  // reclustering the jets with anti-kt algorithm
217  vector<fjcore::PseudoJet> inclusive_recJets = cluster(*recJets1, R/10.0);
218  // Jet multiplicity may vary due to the reclustering.
219  // We only leave the event with unchanged jet multiplicity.
220  int nJets1 = PhaseSpaceSelection(*recJets1, minpt).size();
221  int nJets2 = PhaseSpaceSelection(inclusive_recJets, minpt).size();
222  if (nJets1 != nJets2) {
223  cout << "Jet multiplicity changed: " << nJets1 << " -> " << nJets2 << endl;
224  cout << "recJets: ";
225  for (const auto& jet : *recJets1) cout << jet.CorrPt() << " ";
226  cout << "\nAnti-kT: ";
227  for (const auto& jet : inclusive_recJets) cout << jet.pt() << " ";
228  cout << endl;
229  continue;
230  }
231  break;
232  }
233  case RemovalStrategy::None:;
234  }
235  }
236  if (isMC && genJets1 && genJets2) {
237  // Merge input2's jets into input1's jets
238  genJets1->insert(genJets1->end(), genJets2->begin(), genJets2->end());
239  genEvent1->weights.front() *= genEvent2->weights.front();
240 
241  sort(genJets1->begin(), genJets1->end(), pt_sort); // sort again the jets by pt
242 
243  switch (strategy) {
244  case RemovalStrategy::DeltaR:
245  if (overlappingJets(*genJets1)) continue;
246  break;
247  case RemovalStrategy::AntikT:{
248  // reclustering the jets with anti-kt algorithm
249  vector<fjcore::PseudoJet> inclusive_genJets = cluster(*genJets1, R/10.0);
250  // Jet multiplicity may vary due to the reclustering.
251  // We only leave the event with unchanged jet multiplicity.
252  int nJets1 = PhaseSpaceSelection(*genJets1, minpt).size();
253  int nJets2 = PhaseSpaceSelection(inclusive_genJets, minpt).size();
254  if (nJets1 != nJets2) {
255  cout << "Jet multiplicity changed: " << nJets1 << " -> " << nJets2 << endl;
256  cout << "genJets: ";
257  for (const auto& jet : *genJets1) cout << jet.CorrPt() << " ";
258  cout << "\nAnti-kT: ";
259  for (const auto& jet : inclusive_genJets) cout << jet.pt() << " ";
260  cout << endl;
261  continue;
262  }
263  break;
264  }
265  case RemovalStrategy::None:;
266  }
267  }
268  ++matchedEvents;
269  if (steering & DT::fill) tOut1->Fill();
270  }
271 
272  // Calculate final match rate
273  cout << "Processed " << tIn1->GetEntries() << " events, matched " << matchedEvents << " events ("
274  << fixed << setprecision(2) << matchedEvents * 100.0 / tIn1->GetEntries() << "%)." << endl;
275 
276  metainfo1.Set<bool>("git", "complete", true);
277  cout << __func__ << ' ' << slice << " stop" << endl;
278 }

◆ applyNjetSkim()

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

Skims the input tree to keep only events with different jet multiplicity, with configurable pT thresholds for leading Njets.

Note
Drop the selection for genJets, as it will tighter the selection on rec level in MC samples than data. In case we only interested in the rec level in this stage, we can drop the gen level selection.
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
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 [fOut, tOut] = flow.GetOutput(output);
49 
50  DT::MetaInfo metainfo(tOut);
51  metainfo.Check(config);
52  auto isMC = metainfo.Get<bool>("flags", "isMC");
53 
54  const auto minpt = config.get<float>("skims.jets.minpt");
55  metainfo.Set<float>("skims", "jets", "minpt", minpt);
56 
57  const auto Njets = config.get<int>("skims.jets.N");
58  metainfo.Set<int>("skims", "jets", "N", Njets);
59  cout << "Skimming events: Njets = " << Njets << "\t minpt > " << minpt << endl;
60 
61  auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
62  auto genJets = isMC ? flow.GetBranchReadOnly<vector<GenJet>>("genJets") : nullptr;
63  auto pileup = flow.GetBranchReadOnly<PileUp>("pileup");
64 
65  for (DT::Looper looper(tIn); looper(); ++looper) {
66  [[ maybe_unused ]]
67  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
68 
69  if (pileup->nVtx > 1) continue; // skip events with more than one vertex
70 
71  bool passRec = recJets && PhaseSpaceSelection(*recJets, minpt).size() == Njets;
72  bool passGen = genJets && PhaseSpaceSelection(*genJets, minpt).size() == Njets;
73 
74  if ((steering & DT::fill) && passRec) tOut->Fill();
77  }
78 
79  metainfo.Set<bool>("git", "complete", true);
80  cout << __func__ << ' ' << slice << " stop" << endl;
81 }

◆ buildRunToEntriesMap()

map<Long64_t, vector<Long64_t> > DAS::TPS::buildRunToEntriesMap ( TTree *  tree,
RecEvent recEvent 
)

Build a map that groups event entries by run number.

119  {
120  map<Long64_t, vector<Long64_t>> runToEntries;
121  cout << "Creating run-to-entries map..." << endl;
122  for (DT::Looper looper(tree); looper(); ++looper) {
123  runToEntries[recEvent->runNo].push_back(*looper);
124  }
125  cout << "Found " << runToEntries.size() << " unique run numbers in tree" << endl;
126  return runToEntries;
127 }

◆ CheckConsistency()

void DAS::TPS::CheckConsistency ( DT::MetaInfo metainfo1,
TTree *  tIn1,
DT::MetaInfo metainfo2,
TTree *  tIn2 
)

Check the consistency between two inputs make sure they have the same isMC flag and pTcut. The number of entries in the two input files doesn't have to be the same, but the number of entries in the output file will be affected by the smaller one.

43  {
44  struct Dataset {
45  string name;
46  bool isMC;
47  int Njets;
48  float minpt;
49  long long entries;
50  } datasets[] = {
51  {"Input1", metainfo1.Get<bool>("flags", "isMC"), metainfo1.Get<int>("skims", "jets", "N"), metainfo1.Get<float>("skims", "jets", "minpt"), tIn1 ? tIn1->GetEntries() : 0},
52  {"Input2", metainfo2.Get<bool>("flags", "isMC"), metainfo2.Get<int>("skims", "jets", "N"), metainfo2.Get<float>("skims", "jets", "minpt"), tIn2 ? tIn2->GetEntries() : 0}
53  };
54  int minIndex = (datasets[0].entries < datasets[1].entries) ? 0 : 1;
55  cout << "+---------+------+-------+-------+-------------+\n"
56  << "| Dataset | isMC | Njets | pTcut | Entries |\n"
57  << "+---------+------+-------+-------+-------------+\n";
58  for (int i = 0; i < 2; i++) {
59  cout << "| " << setw(7) << left << datasets[i].name
60  << " | " << setw(4) << left << (datasets[i].isMC ? "Yes" : "No")
61  << " | " << setw(5) << left << datasets[i].Njets
62  << " | " << setw(5) << left << datasets[i].minpt
63  << " | " << setw(11 + (i == minIndex ? 9 : 0)) << right
64  << (i == minIndex ? orange + to_string(datasets[i].entries) + def : to_string(datasets[i].entries))
65  << " |\n";
66  }
67  cout << "+---------+------+-------+-------+-------------+\n" << flush;
68 
69  if (datasets[0].isMC != datasets[1].isMC)
70  BOOST_THROW_EXCEPTION( DE::BadInput("The isMC flag is inconsistent between inputs!", tIn1) );
71  if (datasets[0].minpt != datasets[1].minpt)
72  BOOST_THROW_EXCEPTION( DE::BadInput("The pTcut is inconsistent between inputs!", tIn1) );
73 }

◆ cluster()

vector<fjcore::PseudoJet> DAS::TPS::cluster ( const vector< Jet > &  jets,
const double  R 
)

Anti-kt clustering algorithm to recluster the jets. The jets are sorted by pT and the reclustered jets are returned.

90  {
91  vector<fjcore::PseudoJet> input_jets;
92  input_jets.reserve(jets.size()+1);
93  for (const auto& jet: jets) {
94  const auto& p4 = jet.CorrP4();
95  input_jets.push_back(fjcore::PseudoJet(p4.px(),p4.py(),p4.pz(),p4.E()));
96  }
97  fjcore::JetDefinition jet_def(fjcore::antikt_algorithm, R);
98  fjcore::ClusterSequence clust_seq(input_jets, jet_def);
99  vector<fjcore::PseudoJet> inclusive_jets = sorted_by_pt(clust_seq.inclusive_jets(0.0));
100  return inclusive_jets;
101 }

◆ getTPSobservables()

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

Calculate the observables that can be used to caracterise 6 jets events.

Parameters
inputsinput ROOT files (n-tuples)
outputname of output root file containing the histograms
configconfig file from `DTOptions`
steeringsteering parameters from `DTOptions`
sliceslices for running
121  {1,0}
122  )
123 {
124  cout << __func__ << ' ' << slice << " start" << endl;
125 
126  DT::Flow flow(steering, inputs);
127  auto tIn = flow.GetInputTree(slice);
128  auto [fOut, tOut] = flow.GetOutput(output);
129 
130  DT::MetaInfo metainfo(tOut);
131  metainfo.Check(config);
132  auto isMC = metainfo.Get<bool>("flags", "isMC");
133 
134  const auto minpt = config.get<float>("skims.jets.minpt");
135  metainfo.Set<float>("skims", "jets", "minpt", minpt);
136 
137  auto rEv = flow.GetBranchReadOnly<RecEvent>("recEvent");
138  auto recJets = flow.GetBranchReadOnly<vector<RecJet>>("recJets");
139  auto gEv = isMC ? flow.GetBranchReadOnly<GenEvent>("genEvent") : nullptr;
140  auto genJets = isMC ? flow.GetBranchReadOnly<vector<GenJet>>("genJets") : nullptr;
141 
142  Hist genHist("gen"),
143  recHist("rec");
144 
145  for (DT::Looper looper(tIn); looper(); ++looper) {
146  [[ maybe_unused ]]
147  static auto& cout = steering & DT::verbose ? ::cout : DT::dev_null;
148 
149  MultiJets recMultijets(*recJets, minpt);
150  if (recMultijets) {
151  double evweight = rEv->weights.front();
152  if (isMC) evweight *= gEv->weights.front();
153  recHist.Fill(recMultijets, evweight);
154  }
155 
156  if (!isMC) continue;
157  MultiJets genMultijets(*genJets, minpt);
158  if (genMultijets) {
159  double evweight = gEv->weights.front();
160  genHist.Fill(genMultijets, evweight);
161  }
162  }
163 
164  recHist.Write(fOut);
165  if (isMC)
166  genHist.Write(fOut);
167  metainfo.Set<bool>("git", "complete", true);
168 
169  cout << __func__ << ' ' << slice << " end" << endl;
170 }

◆ overlappingJets()

bool DAS::TPS::overlappingJets ( const vector< Jet > &  jets)

Loop all possible jets combinations checking azimuthal difference to avioding overlapping jets.

107  {
108  for (size_t i = 0; i < jets.size(); ++i) {
109  for (size_t j = i + 1; j < jets.size(); ++j) {
110  if (DeltaR(jets[i].p4, jets[j].p4) < 0.4)
111  return true;
112  }
113  }
114  return false;
115 }

◆ parseStrategy()

RemovalStrategy DAS::TPS::parseStrategy ( const string &  strategyStr,
TTree *  tree 
)

Define the strategy to remove overlapping jets.

77  {
78  cout << "Removal strategy = " << strategyStr << endl;
79  if (strategyStr == "DeltaR") return RemovalStrategy::DeltaR;
80  else if (strategyStr == "antikt") return RemovalStrategy::AntikT;
81  else if (strategyStr == "none") return RemovalStrategy::None;
82 
83  BOOST_THROW_EXCEPTION(DE::BadInput(("Unrecognized strategy: " + strategyStr).c_str(), tree));
84 }

◆ PhaseSpaceSelection()

std::vector<Jet> DAS::TPS::PhaseSpaceSelection ( const std::vector< Jet > &  jets,
float  minpt 
)
24  {
25  std::vector<Jet> tempjets;
26  for (const auto& jet : jets) {
27  double eta;
28  if constexpr(has_p4<Jet>::value) {
29  eta = jet.p4.Eta();
30  } else {
31  eta = jet.eta();
32  }
33  if (jet.CorrPt() > minpt && eta < 5.0)
34  tempjets.push_back(jet);
35  }
36  return tempjets;
37 }
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
Darwin::Tools::fill
@ fill
activate -f to fill the tree
Definition: Options.h:27
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
Step::def
static const char * def
Definition: Step.h:36
Darwin::Tools::UserInfo::Get
T Get(TList *mother, const char *key) const
Definition: UserInfo.h:75
DAS::TPS::parseStrategy
RemovalStrategy parseStrategy(const string &strategyStr, TTree *tree)
Define the strategy to remove overlapping jets.
Definition: applyEventMixing.cc:77
Darwin::Tools::Looper
Facility to loop over a n-tuple, including parallelisation and printing.
Definition: Looper.h:22
DAS::PileUp::nVtx
int nVtx
number of vertices in the event
Definition: Event.h:103
Darwin::Tools::MetaInfo
Generic meta-information for n-tuple (including speficities to Darwin).
Definition: MetaInfo.h:68
DAS::TPS::cluster
vector< fjcore::PseudoJet > cluster(const vector< Jet > &jets, const double R)
Definition: applyEventMixing.cc:90
DAS::pt_sort
bool pt_sort(const PhysicsObject &j1, const PhysicsObject &j2)
Definition: toolbox.h:18
DAS::MN::minpt
static const double minpt
Definition: getMNobservables.cc:39
sorted_by_pt
std::vector< PseudoJet > sorted_by_pt(const std::vector< PseudoJet > &jets)
Definition: fjcore.cc:4063
Ntupliser_cfg.jets
string jets
Definition: Ntupliser_cfg.py:41
antikt_algorithm
@ antikt_algorithm
Definition: fjcore.hh:1040
Ntupliser_cfg.config
config
Definition: Ntupliser_cfg.py:326
DAS::TPS::overlappingJets
bool overlappingJets(const vector< Jet > &jets)
Definition: applyEventMixing.cc:107
orange
static const char * orange
Definition: colours.h:6
DAS::TPS::RemovalStrategy::AntikT
@ AntikT
pileup
DAS::PileUp pileup
Definition: classes.h:27
DAS::TPS::PhaseSpaceSelection
std::vector< Jet > PhaseSpaceSelection(const std::vector< Jet > &jets, float minpt)
Definition: common.h:24
Step::None
@ None
iterate until max value is reached
Definition: Step.h:431
Ntupliser_cfg.isMC
dictionary isMC
Definition: Ntupliser_cfg.py:61
DAS::TPS::RemovalStrategy::DeltaR
@ DeltaR
DAS::TPS::CheckConsistency
void CheckConsistency(DT::MetaInfo &metainfo1, TTree *tIn1, DT::MetaInfo &metainfo2, TTree *tIn2)
Definition: applyEventMixing.cc:43
jercExample.inputs
def inputs
Definition: jercExample.py:118
Darwin::Tools::dev_null
static std::ostream dev_null(nullptr)
to redirect output stream to nowhere
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
DAS::TPS::buildRunToEntriesMap
map< Long64_t, vector< Long64_t > > buildRunToEntriesMap(TTree *tree, RecEvent *recEvent)
Build a map that groups event entries by run number.
Definition: applyEventMixing.cc:119