ATLAS Offline Software
TrigGlobEffCorrExample3e.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
8 /*
9  * The set of examples 3a - 3e illustrates the use of lepton selection tags
10  * for various scenarios:
11  *
12  * - Example 3a: trigger = 2e12_lhloose_L12EM10VH, selecting events containing
13  * >=2 loose electrons, the leading-pT electron always satisfying
14  * in addition tight PID+isolation requirements.
15  *
16  * - Example 3b: trigger = e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose
17  * || 2e12_lhloose_L12EM10VH
18  * selecting events with >=2 loose electrons where the leading-pT
19  * electron also satisfies medium PID requirements.
20  * Only the latter is allowed to fire the single-electron trigger.
21  *
22  * - Example 3c: trigger = e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose
23  * || 2e12_lhloose_L12EM10VH
24  * selecting events with >=2 loose electrons. Any electron also
25  * satisfying medium PID requirements is allowed to fire the
26  * single-electron trigger.
27  *
28  * - Example 3d: trigger = 2e17_lhvloose_nod0 || e7_lhmedium_nod0_mu24
29  * || e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0
30  * same type of selection as example 3c but with 3 PID working
31  * points, using two distinct decorations.
32  *
33  * - Example 3e: same scenario as example 3d, but using an alternative
34  * implementation that requires only one decoration.
35  *
36  */
37 /*
38  * We use a single decoration named 'PID', and rely on the decorated value to
39  * indicate whether the electron passes TightLH PID + isolation (=> value = 2)
40  * or only MediumLH PID (=> value = 1). The TrigGlob tool then forms tags
41  * by suffixing the decorated value to the decoration name, i.e. 'PID1' and
42  * 'PID2'. One must then use the latter tags in the properties 'ListOfLegsPerTag'
43  * and 'ListOfTagsPerTool'. */
44 
45 // ROOT include(s):
46 #include <TFile.h>
47 #include <TError.h>
48 
49 // Infrastructure include(s):
50 #ifdef XAOD_STANDALONE
51  #include "xAODRootAccess/Init.h"
52  #include "xAODRootAccess/TEvent.h"
53  #include "xAODRootAccess/TStore.h"
54 #else
56  #include "POOLRootAccess/TEvent.h"
57 #endif
58 
60 // EDM include(s):
61 #include "AsgTools/AnaToolHandle.h"
67 #include "xAODMuon/MuonContainer.h"
68 #include "PATCore/PATCoreEnums.h"
72 
73 // stdlib include(s):
74 #include <sstream>
75 #include <random>
76 #include <vector>
77 #include <array>
78 using std::vector;
79 using std::string;
80 
82 namespace { vector<string> split_comma_delimited(const std::string&); }
83 
84 #define MSGSOURCE "Example 3e"
85 
86 ANA_MSG_HEADER(Test)
88 using namespace Test;
89 int main(int argc, char* argv[])
90 {
91  ANA_CHECK_SET_TYPE(bool)
92  const char* filename = nullptr;
93  bool debug = false, cmdline_error = false, toys = false;
94  for(int i=1;i<argc;++i)
95  {
96  if(string(argv[i]) == "--debug") debug = true;
97  else if(string(argv[i]) == "--toys") toys = true;
98  else if(!filename && *argv[i]!='-') filename = argv[i];
99  else cmdline_error = true;
100  }
101  if(!filename || cmdline_error)
102  {
103  Error(MSGSOURCE, "No file name received!");
104  Error(MSGSOURCE, " Usage: %s [--debug] [--toys] [DxAOD file name]", argv[0]);
105  return 1;
106  }
107  #ifdef XAOD_STANDALONE
108  xAOD::Init(MSGSOURCE).ignore();
109  TFile* file = TFile::Open(filename, "READ");
110  if(!file)
111  {
112  Error(MSGSOURCE, "Unable to open file!");
113  return 2;
114  }
117  StatusCode::enableFailure();
118  #else
119  IAppMgrUI* app = POOL::Init();
121  TString file(filename);
122  #endif
123  event.readFrom(file).ignore();
124  Long64_t entries = event.getEntries();
125  Info(MSGSOURCE, "Number of events in the file: %lli", entries);
126 
127  /* ********************************************************************** */
128 
129  Info(MSGSOURCE, "Configuring the electron CP tools");
131  ToolHandleArray<IAsgElectronEfficiencyCorrectionTool> electronEffTools;
133  ToolHandleArray<IAsgElectronEfficiencyCorrectionTool> electronSFTools;
135  std::map<std::string,std::string> legsPerTool;
137  std::map<std::string,std::string> tagsPerTool;
139  std::map<std::string,std::string> legsPerTag;
141  static const SG::Decorator<char> dec_pid("PID");
143  std::bernoulli_distribution bernoulliPdf(0.9);
144 
146  vector<asg::AnaToolHandle<IAsgElectronEfficiencyCorrectionTool>> factory;
147  enum{ cLEGS, cTAG, cKEY, cPID, cISO };
148  std::vector<std::array<std::string,5> > toolConfigs = {
151  {"e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0", "PID2",
152  "2016_e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0", "Tight", "GradientLoose"},
154  {"e7_lhmedium_nod0", "PID1,PID2", "2016_e7_lhmedium_nod0", "Medium", ""},
156  {"e17_lhvloose_nod0", "*,PID1,PID2", "2016_e17_lhvloose_nod0", "LooseBLayer", ""},
157  };
158 
159  const char* mapPath = "ElectronEfficiencyCorrection/2015_2017/"
160  "rel21.2/Moriond_February2018_v2/map6.txt";
161  for(auto& cfg : toolConfigs)
162  for(int j=0;j<2;++j)
163  {
164  string name = "AsgElectronEfficiencyCorrectionTool/"
165  + ((j? "ElTrigEff_" : "ElTrigSF_")
166  + std::to_string(factory.size()/2));
167  auto t = factory.emplace(factory.end(), name);
168  t->setProperty("MapFilePath", mapPath).ignore();
169  t->setProperty("TriggerKey", string(j?"":"Eff_") + cfg[cKEY]).ignore();
170  t->setProperty("IdKey", cfg[cPID]).ignore();
171  t->setProperty("IsoKey", cfg[cISO]).ignore();
172 
173  t->setProperty("CorrelationModel", "TOTAL").ignore();
174  t->setProperty("ForceDataType", (int)PATCore::ParticleDataType::Full).ignore();
175  if(t->initialize() != StatusCode::SUCCESS)
176  {
177  Error(MSGSOURCE, "Unable to initialize the electron CP tool <%s>!",
178  t->name().c_str());
179  return 3;
180  }
181  auto& handles = (j? electronSFTools : electronEffTools);
182  handles.push_back(t->getHandle());
185  name = handles[handles.size()-1].name();
186  legsPerTool[name] = cfg[cLEGS];
187  tagsPerTool[name] = cfg[cTAG];
188  if(!j)
189  {
190  for(auto& tag : ::split_comma_delimited(cfg[cTAG]))
191  {
192  if(legsPerTag[tag]=="") legsPerTag[tag] = cfg[cLEGS];
193  else legsPerTag[tag] += "," + cfg[cLEGS];
194  }
195  }
196 
197  }
198 
199  /* ********************************************************************** */
200 
201  Info(MSGSOURCE, "Configuring the muon CP tools");
203  ToolHandleArray<CP::IMuonTriggerScaleFactors> muonTools;
204  asg::AnaToolHandle<CP::IMuonTriggerScaleFactors> muonTool("CP::MuonTriggerScaleFactors/MuonTrigEff");
205  muonTool.setProperty("MuonQuality", "Tight").ignore();
206  muonTool.setProperty("useRel207", false).ignore();
207  if(muonTool.initialize() != StatusCode::SUCCESS)
208  {
209  Error(MSGSOURCE, "Unable to initialize the muon CP tool!");
210  return 3;
211  }
212  muonTools.push_back(muonTool.getHandle());
213 
214  /* ********************************************************************** */
215 
216  Info(MSGSOURCE, "Configuring the global trigger SF tool");
217  asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool> myTool("TrigGlobalEfficiencyCorrectionTool/TrigGlobal");
218  myTool.setProperty("ElectronEfficiencyTools", electronEffTools).ignore();
219  myTool.setProperty("ElectronScaleFactorTools", electronSFTools).ignore();
220  myTool.setProperty("MuonTools", muonTools).ignore();
221  const char* triggers2016 =
222  "e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0"
223  "|| e7_lhmedium_nod0_mu24"
224  "|| 2e17_lhvloose_nod0";
225  myTool.setProperty("TriggerCombination2016", triggers2016).ignore();
228  myTool.setProperty("LeptonTagDecorations", "PID?").ignore();
229  myTool.setProperty("ListOfLegsPerTool", legsPerTool).ignore();
230  myTool.setProperty("ListOfTagsPerTool", tagsPerTool).ignore();
231  myTool.setProperty("ListOfLegsPerTag", legsPerTag).ignore();
232 
233  if(debug) myTool.setProperty("OutputLevel", MSG::DEBUG).ignore();
234  if(toys) myTool.setProperty("NumberOfToys", 1000).ignore();
235  if(myTool.initialize() != StatusCode::SUCCESS)
236  {
237  Error(MSGSOURCE, "Unable to initialize the TrigGlob tool!");
238  return 3;
239  }
240 
243  const unsigned periodRuns[] = {
245  296939, 300345, 301912, 302737, 303638, 303943, 305291, 307124,
246  305359, 309311, 310015
247  };
248  std::uniform_int_distribution<unsigned> uniformPdf(0,
249  sizeof(periodRuns)/sizeof(*periodRuns) - 1);
250  std::default_random_engine randomEngine;
251 
252  static const SG::ConstAccessor<int> truthType("truthType");
253  static const SG::ConstAccessor<int> truthOrigin("truthOrigin");
254 
255  /* ********************************************************************** */
256 
257  Info(MSGSOURCE, "Starting the event loop");
258  unsigned errors = 0;
259  double nSuitableEvents = 0., sumW = 0.;
260  static const SG::Decorator<unsigned> RandomRunNumberDec("RandomRunNumber");
261  for(Long64_t entry = 0; entry < entries; ++entry)
262  {
263  event.getEntry(entry);
264 
266  const xAOD::EventInfo* eventInfo = nullptr;
267  event.retrieve(eventInfo,"EventInfo").ignore();
268  unsigned runNumber = periodRuns[uniformPdf(randomEngine)];
269  RandomRunNumberDec(*eventInfo) = runNumber;
270 
271  unsigned nTrig_e26 = 0, nTrig_e7 = 0, nTrig_e17 = 0;
272 
273  vector<const xAOD::Electron*> myTriggeringElectrons;
274  const xAOD::ElectronContainer* electrons = nullptr;
275  event.retrieve(electrons,"Electrons").ignore();
276  for(auto electron : *electrons)
277  {
278  if(!electron->caloCluster()) continue;
279  float eta = fabs(electron->caloCluster()->etaBE(2));
280  float pt = electron->pt();
281  if(pt<10e3f || eta>=2.47) continue;
282  if(!truthType.isAvailable(*electron)) continue;
283  if(!truthOrigin.isAvailable(*electron)) continue;
284  int t = truthType(*electron), o = truthOrigin(*electron);
285  if(t!=2 || !(o==10 || (o>=12 && o<=22) || o==43)) continue;
287  if(pt < 7e3f) continue;
288  if(pt >= 18e3f) ++nTrig_e17;
289 
290  myTriggeringElectrons.push_back(electron);
291  }
292 
293  vector<const xAOD::Muon*> myTriggeringMuons;
294  const xAOD::MuonContainer* muons = nullptr;
295  event.retrieve(muons,"Muons").ignore();
296  for(auto muon : *muons)
297  {
298  if(runNumber >= 324320) break; // delete line once all SFs available for 2017
299  float pt = muon->pt();
300  if(pt<10e3f || fabs(muon->eta())>=2.5) continue;
301  auto mt = muon->muonType();
302  if(mt!=xAOD::Muon::Combined && mt!=xAOD::Muon::MuonStandAlone) continue;
303  auto& mtp = *(muon->primaryTrackParticle());
304  if(!truthType.isAvailable(mtp)) continue;
305  if(!truthOrigin.isAvailable(mtp)) continue;
306  int t = truthType(mtp), o = truthOrigin(mtp);
307  if(t!=6 || !(o==10 || (o>=12 && o<=22) || o==43)) continue;
309  if(pt < 25.2e3f) continue;
310 
311  myTriggeringMuons.push_back(muon);
312  }
313 
317  for(auto electron : myTriggeringElectrons)
318  {
319  bool medium = bernoulliPdf(randomEngine);
320  bool tight = medium && bernoulliPdf(randomEngine);
322  dec_pid(*electron) = tight? 2 : medium? 1 : 0;
323  if(medium && electron->pt()>8e3f) ++nTrig_e7;
324  if(tight && electron->pt()>27e3f) ++nTrig_e26;
325  }
326 
328  if(nTrig_e26 < 1
329  && (nTrig_e7==0 || myTriggeringMuons.size()==0)
330  && nTrig_e17 < 2)
331  {
332  continue;
333  }
334 
335 
337  double sf = 1.;
338  auto cc = myTool->getEfficiencyScaleFactor(myTriggeringElectrons,
339  myTriggeringMuons, sf);
341  {
342  nSuitableEvents += 1;
343  sumW += sf;
344  }
345  else
346  {
347  Warning(MSGSOURCE, "Scale factor evaluation failed");
348  ++errors;
349  }
350  if(errors>10)
351  {
352  Error(MSGSOURCE, "Too many errors reported!");
353  break;
354  }
355  }
356  Info(MSGSOURCE, "Average scale factor: %f (over %ld events)",
357  sumW / nSuitableEvents, long(nSuitableEvents));
358  #ifndef XAOD_STANDALONE
359  ANA_CHECK(app->finalize())
360  #endif
361  return errors? 4 : 0;
362 }
363 
365 namespace
366 {
367  inline vector<string> split_comma_delimited(const string& s)
368  {
369  std::stringstream ss(s);
370  std::vector<std::string> tokens;
371  std::string token;
372  while(std::getline(ss, token, ','))
373  {
374  if(token.length()) tokens.push_back(token);
375  }
376  return tokens;
377  }
378 }
asg::AnaToolHandle::initialize
StatusCode initialize()
initialize the tool
store
StoreGateSvc * store
Definition: fbtTestBasics.cxx:69
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:195
asg::AnaToolHandle< CP::IMuonTriggerScaleFactors >
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
PowhegControl_ttHplus_NLO.ss
ss
Definition: PowhegControl_ttHplus_NLO.py:83
MSGSOURCE
#define MSGSOURCE
Definition: TrigGlobEffCorrExample3e.cxx:84
IAsgElectronEfficiencyCorrectionTool.h
ITrigGlobalEfficiencyCorrectionTool.h
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
test_pyathena.pt
pt
Definition: test_pyathena.py:11
ANA_CHECK
#define ANA_CHECK(EXP)
check whether the given expression was successful
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:324
SG::ConstAccessor< int >
LArCellConditions.argv
argv
Definition: LArCellConditions.py:112
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
beamspotman.tokens
tokens
Definition: beamspotman.py:1284
xAOD::TEvent::kClassAccess
@ kClassAccess
Access auxiliary data using the aux containers.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:97
asg::AnaToolHandle::setProperty
StatusCode setProperty(const std::string &property, const T2 &value)
set the given property of the tool.
POOL::Init
IAppMgrUI * Init(const char *options="POOLRootAccess/basic.opts")
Bootstraps (creates and configures) the Gaudi Application with the provided options file.
Definition: PhysicsAnalysis/POOLRootAccess/src/TEvent.cxx:29
POOL::TEvent::kClassAccess
@ kClassAccess
Definition: PhysicsAnalysis/POOLRootAccess/POOLRootAccess/TEvent.h:45
ANA_MSG_HEADER
#define ANA_MSG_HEADER(NAME)
for standalone code this creates a new message category
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:113
PATCore::ParticleDataType::Full
@ Full
Definition: PATCoreEnums.h:22
DiTauMassTools::ignore
void ignore(T &&)
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:54
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
SG::Decorator< char >
ElectronContainer.h
lumiFormat.i
int i
Definition: lumiFormat.py:92
vector< string >
MessageCheck.h
macros for messaging and checking status codes
PATCoreEnums.h
TEvent.h
IMuonTriggerScaleFactors.h
file
TFile * file
Definition: tile_monitor.h:29
Init.h
DQHistogramMergeRegExp.argc
argc
Definition: DQHistogramMergeRegExp.py:20
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
AnaToolHandle.h
Trk::Combined
@ Combined
Definition: TrackSummaryTool.h:32
mergePhysValFiles.errors
list errors
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:43
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
main
int main(int argc, char *argv[])
Definition: TrigGlobEffCorrExample3e.cxx:89
ANA_MSG_SOURCE
#define ANA_MSG_SOURCE(NAME, TITLE)
the source code part of ANA_MSG_SOURCE
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:133
POOL::TEvent
Definition: PhysicsAnalysis/POOLRootAccess/POOLRootAccess/TEvent.h:39
TEvent.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
debug
const bool debug
Definition: MakeUncertaintyPlots.cxx:53
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
WriteCaloSwCorrections.cfg
cfg
Definition: WriteCaloSwCorrections.py:23
EventInfo.h
xAOD::EventInfo_v1
Class describing the basic event information.
Definition: EventInfo_v1.h:43
MuonContainer.h
AthAnalysisHelper.h
DeMoAtlasDataLoss.runNumber
string runNumber
Definition: DeMoAtlasDataLoss.py:64
CP::CorrectionCode::Ok
@ Ok
The correction was done successfully.
Definition: CorrectionCode.h:38
ITrigGlobalEfficiencyCorrectionTool::getEfficiencyScaleFactor
virtual CP::CorrectionCode getEfficiencyScaleFactor(const std::vector< const xAOD::IParticle * > &particles, double &efficiencyScaleFactor)=0
asg::AnaToolHandle::getHandle
const ToolHandle< T > & getHandle() const noexcept
the tool handle we wrap
xAOD::TStore
A relatively simple transient store for objects created in analysis.
Definition: TStore.h:44
mapkey::sf
@ sf
Definition: TElectronEfficiencyCorrectionTool.cxx:38
ANA_CHECK_SET_TYPE
#define ANA_CHECK_SET_TYPE(TYPE)
set the type for ANA_CHECK to report failures
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:314
DEBUG
#define DEBUG
Definition: page_access.h:11
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
CaloCellTimeCorrFiller.filename
filename
Definition: CaloCellTimeCorrFiller.py:24
entries
double entries
Definition: listroot.cxx:49
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
L1Topo::Error
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition: Error.h:16
CaloCondBlobAlgs_fillNoiseFromASCII.tag
string tag
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:24
ConstAccessor.h
Helper class to provide constant type-safe access to aux data.
Decorator.h
Helper class to provide type-safe access to aux data.
TStore.h
InDetDD::electrons
@ electrons
Definition: InDetDD_Defs.h:17
xAOD::TEvent
Tool for accessing xAOD files outside of Athena.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:81
AuxElement.h
Base class for elements of a container that can have aux data.
python.handimod.cc
int cc
Definition: handimod.py:523
xAOD::Init
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition: Init.cxx:31