ATLAS Offline Software
Loading...
Searching...
No Matches
TrigGlobalEfficiencyAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
15
16#include <utility>
17
19 ISvcLocator *svcLoc)
20 : EL::AnaAlgorithm(name, svcLoc)
21{
22 declareProperty("matchingTool", m_trigMatchingTool, "trigger matching tool");
23}
24
25template <typename ToolInterface, typename SetToolPropertiesFn>
27 std::vector<ToolHandle<ToolInterface> >& toolsFactory,
28 ToolHandleArray<ToolInterface>& effTools,
29 ToolHandleArray<ToolInterface>& sfTools,
30 const std::map<std::string, std::string>& legsPerKey,
31 const std::string& toolNamePrefix,
32 const std::string& toolNameSuffix,
33 const SetToolPropertiesFn& setToolProperties,
34 std::map<std::string, std::string>& legsPerTool)
35{
37 int nTools = 0;
38 for (const auto &[trigKey, triggers] : legsPerKey) {
39 if (trigKey == nameForDefaultSF) { // no tool needed in this case
40 auto [itr, added] = legsPerTool.emplace(nameForDefaultSF, triggers);
41 if (!added) itr->second += "," + triggers;
42 continue;
43 }
44 nTools++;
45 for (bool isSFTool : {true, false}) { // one tool instance for efficiencies, another for scale factors
46 asg::AsgToolConfig config(toolNamePrefix + std::to_string(isSFTool) + "_" + std::to_string(nTools) + toolNameSuffix);
47 ANA_CHECK(setToolProperties(config));
48 ANA_CHECK(config.setProperty("TriggerKey", isSFTool ? trigKey : "Eff_" + trigKey ));
49 ANA_CHECK(config.setProperty("ForceDataType", PATCore::ParticleDataType::Full));
50 ANA_CHECK(config.setProperty("OutputLevel", msg().level()));
51 ToolHandle<ToolInterface>& t = toolsFactory.emplace_back();
52 std::shared_ptr<void> cleanup;
53 ANA_CHECK(config.makeTool(t, cleanup));
54 m_toolsCleanup.push_back(std::move(cleanup));
55 // now record the handle
56 auto& handles = (isSFTool? sfTools : effTools);
57 handles.push_back(t);
58 legsPerTool[handles[handles.size()-1].name()] = triggers;
59 // and add the systematics
60 ANA_CHECK(m_systematicsList.addSystematics( *handles[handles.size()-1] ));
61 }
62 }
63 return StatusCode::SUCCESS;
64}
65
67{
68
69 if (m_trigList_2015.empty() && m_trigList_2016.empty() && m_trigList_2017.empty() && m_trigList_2018.empty()
70 && m_trigList_2022.empty() && m_trigList_2023.empty() && m_trigList_2024.empty() && m_trigList_2025.empty()) {
71 ATH_MSG_ERROR("A list of triggers needs to be provided");
72 return StatusCode::FAILURE;
73 }
74
78
82
86
88
89 // retrieve the trigger matching tool
90 ANA_CHECK(m_trigMatchingTool.retrieve());
91
92 // now we can build a map of triggers per year, and extract the electron/photon legs as needed
93 const std::vector<std::pair<std::string, const std::vector<std::string>*> > trigMap {
94 {"2015", &m_trigList_2015.value()},
95 {"2016", &m_trigList_2016.value()},
96 {"2017", &m_trigList_2017.value()},
97 {"2018", &m_trigList_2018.value()},
98 {"2022", &m_trigList_2022.value()},
99 {"2023", &m_trigList_2023.value()},
100 {"2024", &m_trigList_2024.value()},
101 {"2025", &m_trigList_2025.value()}};
102
103 // combine all the trigger legs in the expected format
104 std::map<std::string, std::string> triggerCombination;
105 for (const auto &[year, triggers] : trigMap) {
106 if (triggers->empty()) continue;
107 std::string& combinedString = triggerCombination[year];
108 combinedString = triggers->front();
109 for (std::size_t i = 1; i < triggers->size(); ++i) {
110 combinedString += " || " + (*triggers)[i];
111 }
112 }
113
114 // collect the combined electron and photon trigger keys supported by Egamma
115 std::map<std::string,std::string> electronLegsPerKey, photonLegsPerKey;
116 if (!m_doMatchingOnly) {
117 if (m_isRun3Geo) {
118 ANA_CHECK(TrigGlobalEfficiencyCorrectionTool::suggestElectronMapKeys(triggerCombination, "2015_2025/rel22.2/2025_Run3_Consolidated_Recommendation_v4", electronLegsPerKey));
119 }
120 else {
121 ANA_CHECK(TrigGlobalEfficiencyCorrectionTool::suggestElectronMapKeys(triggerCombination, "2015_2018/rel21.2/Precision_Summer2020_v1", electronLegsPerKey));
122 }
123 ANA_CHECK(TrigGlobalEfficiencyCorrectionTool::suggestPhotonMapKeys(triggerCombination, "2015_2018/rel21.2/Summer2020_Rec_v1", photonLegsPerKey));
124 }
125
126 std::map<std::string, std::string> legsPerTool;
127
128 // ELECTRON TOOLS
129 ToolHandleArray<IAsgElectronEfficiencyCorrectionTool> electronEffTools, electronSFTools;
130 if (!m_electronsHandle.empty() && !m_doMatchingOnly) {
131 if (m_electronID.empty()) {
132 ATH_MSG_ERROR("Electron ID was not set for TrigGlobalEfficiencyAlg!");
133 return StatusCode::FAILURE;
134 }
135 ANA_CHECK(makeEgammaTools(m_electronToolsFactory, electronEffTools, electronSFTools, electronLegsPerKey,
136 "AsgElectronEfficiencyCorrectionTool/ElTrigEff_",
137 "_" + m_electronID.value() + "_" + m_electronIsol.value(),
138 [this](asg::AsgToolConfig& config) -> StatusCode {
139 ANA_CHECK(config.setProperty("MapFilePath", std::string("ElectronEfficiencyCorrection/2015_2025/rel22.2/") +
140 (m_isRun3Geo ? "2025_Run3_Consolidated_Recommendation_v4/map2.txt" : "2025_Run2Rel22_Recommendation_v3/map1.txt")));
141 ANA_CHECK(config.setProperty("IdKey", m_electronID.value()));
142 ANA_CHECK(config.setProperty("IsoKey", m_electronIsol.value()));
143 ANA_CHECK(config.setProperty("CorrelationModel", "TOTAL"));
144 return StatusCode::SUCCESS;
145 },
146 legsPerTool));
147 }
148
149 // PHOTON TOOLS
150 ToolHandleArray<IAsgPhotonEfficiencyCorrectionTool> photonEffTools, photonSFTools;
151 if (!m_photonsHandle.empty() && !m_doMatchingOnly) {
152 if (m_photonIsol.empty()) {
153 ATH_MSG_ERROR("Photon Isolation was not set for TrigGlobalEfficiencyAlg!");
154 return StatusCode::FAILURE;
155 }
156 ANA_CHECK(makeEgammaTools(m_photonToolsFactory, photonEffTools, photonSFTools, photonLegsPerKey,
157 "AsgPhotonEfficiencyCorrectionTool/PhTrigEff_",
158 "_" + m_photonIsol.value(),
159 [this](asg::AsgToolConfig& config) -> StatusCode {
160 if (!m_isRun3Geo) {
161 ANA_CHECK(config.setProperty("MapFilePath", "PhotonEfficiencyCorrection/2015_2018/rel21.2/Summer2020_Rec_v1/map3.txt"));
162 }
163 ANA_CHECK(config.setProperty("IsoKey", m_photonIsol.value()));
164 return StatusCode::SUCCESS;
165 },
166 legsPerTool));
167 }
168
169 // MUON TOOLS
170 ToolHandleArray<CP::IMuonTriggerScaleFactors> muonTools;
171 if (!m_muonsHandle.empty() && !m_doMatchingOnly) {
172 if (m_muonID.empty()) {
173 ATH_MSG_ERROR("Muon ID was not set for TrigGlobalEfficiencyAlg!");
174 return StatusCode::FAILURE;
175 }
176 m_muonTool = asg::AnaToolHandle<CP::IMuonTriggerScaleFactors>("CP::MuonTriggerScaleFactors/MuonTrigEff_" + m_muonID.value());
177 ANA_CHECK(m_muonTool.setProperty("MuonQuality", m_muonID.value()));
178 ANA_CHECK(m_muonTool.setProperty("AllowZeroSF", true));
179 ANA_CHECK(m_muonTool.setProperty("Campaign", m_campaign.value()));
180 ANA_CHECK(m_muonTool.initialize());
181 // now record the handle
182 muonTools.push_back(m_muonTool.getHandle());
183 // and add the efficiency systematics
184 ANA_CHECK(m_systematicsList.addSystematics( *m_muonTool ));
185 }
186
187 // create the individual trigger-matching decorators
188 for(const std::string& trig : m_separateMatchingTriggers) {
189 m_separateMatchingDecorators.emplace(trig, SysWriteDecorHandle<bool>("triggerMatch_"+sanitizeTriggerChainName(trig)+m_separateMatchingDecorSuffix+"_%SYS%", this));
190 ANA_CHECK(m_separateMatchingDecorators.at(trig).initialize(m_systematicsList, m_eventInfoHandle));
191
192 m_separateMatchingFlags[trig] = false;
193 }
194
195 // finally, set up the global trigger tool
196 m_tgecTool = asg::AnaToolHandle<ITrigGlobalEfficiencyCorrectionTool>("TrigGlobalEfficiencyCorrectionTool/TrigGlobal_" + this->name() );
197 ANA_CHECK(m_tgecTool.setProperty("ElectronEfficiencyTools", electronEffTools));
198 ANA_CHECK(m_tgecTool.setProperty("ElectronScaleFactorTools", electronSFTools));
199 ANA_CHECK(m_tgecTool.setProperty("PhotonEfficiencyTools", photonEffTools));
200 ANA_CHECK(m_tgecTool.setProperty("PhotonScaleFactorTools", photonSFTools));
201 ANA_CHECK(m_tgecTool.setProperty("MuonTools", muonTools));
202 ANA_CHECK(m_tgecTool.setProperty("ListOfLegsPerTool", legsPerTool));
203 ANA_CHECK(m_tgecTool.setProperty("TriggerCombination", triggerCombination));
204 ANA_CHECK(m_tgecTool.setProperty("TriggerMatchingTool", m_trigMatchingTool));
205 ANA_CHECK(m_tgecTool.setProperty("NumberOfToys", m_numToys));
206 ANA_CHECK(m_tgecTool.setProperty("OutputLevel", MSG::ERROR));
207 ANA_CHECK(m_tgecTool.initialize());
208
209 ANA_CHECK(m_systematicsList.initialize());
210
211 return StatusCode::SUCCESS;
212}
213
214StatusCode CP::TrigGlobalEfficiencyAlg::execute(const EventContext& ctx)
215{
216
218
219 for (const auto & syst : m_systematicsList.systematicsVector()) {
220 CP::SysFilterReporter filter (filterCombiner, syst);
221
222 // retrieve lepton collections with selections
223 const xAOD::ElectronContainer* electrons(nullptr);
224 const xAOD::PhotonContainer* photons(nullptr);
225 const xAOD::MuonContainer* muons(nullptr);
226 std::vector<const xAOD::Electron*> selectedElectrons;
227 std::vector<const xAOD::Photon*> selectedPhotons;
228 std::vector<const xAOD::Muon*> selectedMuons;
229
230 if (!m_electronsHandle.empty()) {
231 ANA_CHECK(m_electronsHandle.retrieve(electrons, syst, ctx));
232 for (const xAOD::Electron *el: *electrons) {
233 if (m_electronSelection.getBool(*el, syst)) selectedElectrons.push_back(el);
234 }
235 }
236 if (!m_photonsHandle.empty()) {
237 ANA_CHECK(m_photonsHandle.retrieve(photons, syst, ctx));
238 for (const xAOD::Photon *ph: *photons) {
239 if (m_photonSelection.getBool(*ph, syst)) selectedPhotons.push_back(ph);
240 }
241 }
242 if (!m_muonsHandle.empty()) {
243 ANA_CHECK(m_muonsHandle.retrieve(muons, syst, ctx));
244 for (const xAOD::Muon *mu: *muons) {
245 if (m_muonSelection.getBool(*mu, syst)) selectedMuons.push_back(mu);
246 }
247 }
248
249 ANA_CHECK(m_tgecTool->applySystematicVariation(syst));
250
251 // compute the scale factor
252 double sf;
253 if (selectedElectrons.empty() && selectedMuons.empty() && selectedPhotons.empty()) sf = 1.0;
254 else if (m_doMatchingOnly) sf = 1.0;
255 else {
256 sf = NAN;
257 const CP::CorrectionCode code = m_tgecTool->getEfficiencyScaleFactor(selectedElectrons, selectedMuons, selectedPhotons, sf);
258 if (code != CP::CorrectionCode::Ok) {
260 if (m_nScaleFactorFailures <= 10) {
261 ATH_MSG_WARNING("Global trigger scale factor computation failed (CorrectionCode " << code.code() << ") for systematic '" << syst.name() << "', scale factor set to " << sf
262 << (m_nScaleFactorFailures == 10 ? " (further warnings suppressed)" : ""));
263 }
264 }
265 }
266
267 // Retrieve EventInfo
268 const xAOD::EventInfo *evtInfo {nullptr};
269 ANA_CHECK(m_eventInfoHandle.retrieve(evtInfo, syst, ctx));
270
271 // Check if we have trigger matching
272 bool matched = false;
273 if (!(selectedElectrons.empty() && selectedMuons.empty() && selectedPhotons.empty())) {
274 if(m_separateMatchingTriggers.value().empty()) {
275 ANA_CHECK(m_tgecTool->checkTriggerMatching(matched, selectedElectrons, selectedMuons, selectedPhotons));
276 } else {
277 ANA_CHECK(m_tgecTool->checkTriggerMatching(m_separateMatchingFlags, selectedElectrons, selectedMuons, selectedPhotons));
278 for(const auto& [trig, flag] : m_separateMatchingFlags) {
279 if(flag) matched = true;
280 m_separateMatchingDecorators.at(trig).set(*evtInfo, flag, syst);
281 }
282 }
283 } else {
284 // no selected leptons: still write the per-trigger matching decorations
285 for (const auto& [trig, decorator] : m_separateMatchingDecorators) {
286 decorator.set(*evtInfo, false, syst);
287 }
288 }
289 if (matched) filter.setPassed(true);
290
291 // Decorate global outputs onto the EventInfo
292 m_scaleFactorDecoration.set(*evtInfo, sf, syst);
293 m_matchingDecoration.set(*evtInfo, matched, syst);
294 }
295
296 return StatusCode::SUCCESS;
297}
298
300{
301 if (m_nScaleFactorFailures > 0) {
302 ATH_MSG_WARNING("Global trigger scale factor computation failed " << m_nScaleFactorFailures << " times");
303 }
304
305 ANA_CHECK (m_filterParams.finalize());
306 return StatusCode::SUCCESS;
307}
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ANA_CHECK(EXP)
check whether the given expression was successful
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Return value from object correction CP tools.
@ Ok
The correction was done successfully.
a reporter class that combines the filter decisions for all systematics
a systematics aware filter reporter
a data handle for reading systematics varied input data
asg::AnaToolHandle< ITrigGlobalEfficiencyCorrectionTool > m_tgecTool
Trigger Global Efficiency Correction Tool handle.
Gaudi::Property< std::vector< std::string > > m_trigList_2024
SysReadHandle< xAOD::EventInfo > m_eventInfoHandle
EventInfo to decorate.
Gaudi::Property< std::vector< std::string > > m_trigList_2018
virtual StatusCode finalize() final override
Gaudi::Property< std::string > m_electronIsol
electron Isolation
Gaudi::Property< std::vector< std::string > > m_trigList_2023
std::unordered_map< std::string, SysWriteDecorHandle< bool > > m_separateMatchingDecorators
Gaudi::Property< std::vector< std::string > > m_separateMatchingTriggers
store separate trigger matching flags for each trigger
Gaudi::Property< std::string > m_electronID
electron ID
ToolHandle< Trig::IMatchingTool > m_trigMatchingTool
trigger matching tool
Gaudi::Property< std::string > m_photonIsol
photon Isolation
std::vector< std::shared_ptr< void > > m_toolsCleanup
keeps the tools created via m_electronToolsFactory/m_photonToolsFactory alive in AnalysisBase
SysWriteDecorHandle< char > m_matchingDecoration
decoration of the global trigger matching flag
SysReadSelectionHandle m_muonSelection
input muon selection
Gaudi::Property< std::vector< std::string > > m_trigList_2017
Gaudi::Property< bool > m_noFilter
whether to not apply an event filter
unsigned long long m_nScaleFactorFailures
number of events for which the global trigger scale factor computation failed
StatusCode makeEgammaTools(std::vector< ToolHandle< ToolInterface > > &toolsFactory, ToolHandleArray< ToolInterface > &effTools, ToolHandleArray< ToolInterface > &sfTools, const std::map< std::string, std::string > &legsPerKey, const std::string &toolNamePrefix, const std::string &toolNameSuffix, const SetToolPropertiesFn &setToolProperties, std::map< std::string, std::string > &legsPerTool)
create one efficiency and one scale factor tool per electron/photon trigger key
std::vector< ToolHandle< IAsgPhotonEfficiencyCorrectionTool > > m_photonToolsFactory
on-the-fly public tool creation for photons
SysReadSelectionHandle m_electronSelection
input electron selection
Gaudi::Property< std::vector< std::string > > m_trigList_2015
list of triggers or trigger chains
Gaudi::Property< bool > m_doMatchingOnly
whether to only run the global trigger matching, and not compute efficiency SFs
SysWriteDecorHandle< float > m_scaleFactorDecoration
decoration of the global trigger SF
TrigGlobalEfficiencyAlg(const std::string &name, ISvcLocator *pSvcLocator=nullptr)
Gaudi::Property< std::vector< std::string > > m_trigList_2022
virtual StatusCode initialize() final override
SysReadSelectionHandle m_photonSelection
input photon selection
Gaudi::Property< std::vector< std::string > > m_trigList_2016
std::vector< ToolHandle< IAsgElectronEfficiencyCorrectionTool > > m_electronToolsFactory
on-the-fly public tool creation for electrons
Gaudi::Property< std::vector< std::string > > m_trigList_2025
std::unordered_map< std::string, bool > m_separateMatchingFlags
SysReadHandle< xAOD::PhotonContainer > m_photonsHandle
input photon collection
SysReadHandle< xAOD::ElectronContainer > m_electronsHandle
input electron collection
SysFilterReporterParams m_filterParams
the filter reporter params
Gaudi::Property< bool > m_isRun3Geo
whether to use Run 3 settings
SysReadHandle< xAOD::MuonContainer > m_muonsHandle
input muon collection
AnaAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
constructor with parameters
virtual::StatusCode execute()
execute this algorithm
static std::string toolnameForDefaultScaleFactor()
To be used with the ListOfLegsPerTool property:
static CP::CorrectionCode suggestPhotonMapKeys(const std::map< std::string, std::string > &triggerCombination, const std::string &version, std::map< std::string, std::string > &legsPerKey)
static CP::CorrectionCode suggestElectronMapKeys(const std::map< std::string, std::string > &triggerCombination, const std::string &version, std::map< std::string, std::string > &legsPerKey)
a modified tool handle that allows its owner to configure new tools from the C++ side
an object that can create a AsgTool
std::string sanitizeTriggerChainName(std::string chain)
convert a trigger chain name into a string usable in decoration/branch names (.
This module defines the arguments passed from the BATCH driver to the BATCH worker.
PhotonContainer_v1 PhotonContainer
Definition of the current "photon container version".
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
Muon_v1 Muon
Reference the current persistent version:
Photon_v1 Photon
Definition of the current "egamma version".
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
Electron_v1 Electron
Definition of the current "egamma version".
MsgStream & msg
Definition testRead.cxx:32