ATLAS Offline Software
Loading...
Searching...
No Matches
RunHyPERAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4#include <Math/Vector4D.h>
5#include <math.h>
6
7#include <vector>
8
10
11// HyPER includes
21
22namespace EventReco {
23
24namespace {
25
26PtEtaPhiMVector toPtEtaPhiM(const ROOT::Math::PtEtaPhiEVector& vec) {
27 return PtEtaPhiMVector(vec.Pt(), vec.Eta(), vec.Phi(), vec.M());
28}
29
30ROOT::Math::PtEtaPhiEVector buildRecoP4(double pt, double eta, double phi,
31 double e) {
32 ROOT::Math::PtEtaPhiEVector vec;
33 vec.SetCoordinates(pt, eta, phi, e);
34 return vec;
35}
36
37} // namespace
38
40 ANA_MSG_INFO("Initializing RunHyPER " << name());
41 ANA_MSG_INFO(" --> topology: " << m_topology.value());
42 ANA_MSG_INFO(" --> btagger: " << m_btagger.value());
43 ANA_MSG_INFO(" --> debug level: " << static_cast<int>(this->msg().level()));
44 ANA_MSG_INFO(" --> full log event number: " << m_fullLogEventNumber.value());
45
46 // Retrieve the ONNX inference tools, one per cross-validation fold
49
50 // Load the b-tagging decoration
51 m_btagDecorName = "ftag_quantile_" + m_btagger.value();
52 m_bTagDecoAcc = std::make_unique<SG::ConstAccessor<int>>(m_btagDecorName);
53
54 // Parse topology
55 HyPERTopology hyperTopology = strToHyPERTopology(m_topology.value());
56 if (hyperTopology == EventReco::HyPERTopology::NotSelected) {
57 ANA_MSG_ERROR("Unrecognized HyPER topology: " << m_topology.value());
58 return StatusCode::FAILURE;
59 }
60 m_hyperTopology = hyperTopology;
61 m_ljetsUseBTag = (m_topology.value() == "TtbarLJets");
62
63 // Initialise object containers
75 // Intialise pre-selection
78
79 // Decorations (topology dependent)
80 if (hyperTopology == EventReco::HyPERTopology::TtbarAllHadronic) {
109 }
110 if (hyperTopology == EventReco::HyPERTopology::TtbarLJets) {
143 }
144 if (hyperTopology == EventReco::HyPERTopology::TtbarDiLepton) {
169 }
170
171 // Initialise systematics
172 ANA_CHECK(m_systematicsList.initialize());
173
174 // Initialise the correct HyPER model
175 if (hyperTopology == EventReco::HyPERTopology::TtbarLJets) {
176 ANA_MSG_INFO("Loading HyPER model.");
177 m_hyperModel = std::make_unique<EventReco::HyPERTtbarLJetsModel>(
179 ANA_MSG_INFO("Loaded TtbarLJets HyPER model!");
180
181 ANA_MSG_DEBUG("Initialising HyPERParser");
182 m_hyperParser = std::make_unique<EventReco::HyPERTtbarLJetsParser>();
183 ANA_MSG_DEBUG("Initialised HyPERParserTtbarLJets Parser");
184
185 } else if (hyperTopology == EventReco::HyPERTopology::TtbarAllHadronic) {
186 ANA_MSG_INFO("Loading HyPER model.");
187 m_hyperModel = std::make_unique<EventReco::HyPERTtbarAllHadronicModel>(
189 ANA_MSG_INFO("Loaded TtbarAllHadronic HyPER model!");
190
191 ANA_MSG_DEBUG("Initialising HyPERParser");
192 m_hyperParser = std::make_unique<EventReco::HyPERTtbarAllHadronicParser>();
193 ANA_MSG_DEBUG("Initialised HyPERParserTtbarAllHadronic Parser");
194 } else if (hyperTopology == EventReco::HyPERTopology::TtbarDiLepton) {
195 ANA_MSG_INFO("Loading HyPER model.");
196 m_hyperModel = std::make_unique<EventReco::HyPERTtbarDiLeptonModel>(
198 ANA_MSG_INFO("Loaded TtbarDiLepton HyPER model!");
199
200 ANA_MSG_DEBUG("Initialising HyPERParser");
201 m_hyperParser = std::make_unique<EventReco::HyPERTtbarDiLeptonParser>();
202 ANA_MSG_DEBUG("Initialised HyPERTtbarDiLepton Parser");
203 }
204
205 // Resolve the ONNX node names of the selected topology
206 ANA_CHECK(m_hyperModel->initialize());
207
208 // Initialisation of the HyPERGraph
209 ANA_MSG_DEBUG("Initialising HyPERGraph");
210 m_hyperGraph = std::make_unique<EventReco::HyPERGraph>();
211 ANA_MSG_DEBUG("Initialised HyPERGraph");
212
213 return StatusCode::SUCCESS;
214}
215
217 const std::vector<int>& ids,
218 PtEtaPhiMVector& bJetP4,
219 PtEtaPhiMVector& leptonP4,
220 float& analyserCharge) const {
221 const int jetID = static_cast<int>(HyPERParticleID::jet);
222 const int electronID = static_cast<int>(HyPERParticleID::e);
223 const int muonID = static_cast<int>(HyPERParticleID::mu);
224
225 if (indices.size() != 2 || ids.size() != 2)
226 return false;
227
228 int jetPosition = -1;
229 int leptonPosition = -1;
230 for (std::size_t i = 0; i < ids.size(); ++i) {
231 if (ids.at(i) == jetID)
232 jetPosition = static_cast<int>(i);
233 if (ids.at(i) == electronID || ids.at(i) == muonID)
234 leptonPosition = static_cast<int>(i);
235 }
236
237 if (jetPosition < 0 || leptonPosition < 0)
238 return false;
239
240 const int jetIndex = indices.at(jetPosition);
241 const int leptonIndex = indices.at(leptonPosition);
242 if (jetIndex < 0 || jetIndex >= static_cast<int>(m_hyperInputs.m_jets.size()))
243 return false;
244
245 const xAOD::Jet* jet = m_hyperInputs.m_jets.at(jetIndex);
246 ROOT::Math::PtEtaPhiEVector jetP4 =
247 buildRecoP4(jet->pt(), jet->eta(), jet->phi(), jet->e());
248
249 ROOT::Math::PtEtaPhiEVector localLeptonP4;
250 if (ids.at(leptonPosition) == electronID) {
251 if (leptonIndex < 0 ||
252 leptonIndex >= static_cast<int>(m_hyperInputs.m_electrons.size()))
253 return false;
254 const xAOD::Electron* electron = m_hyperInputs.m_electrons.at(leptonIndex);
255 localLeptonP4 = buildRecoP4(electron->pt(), electron->eta(),
256 electron->phi(), electron->e());
257 analyserCharge = electron->charge();
258 } else {
259 if (leptonIndex < 0 ||
260 leptonIndex >= static_cast<int>(m_hyperInputs.m_muons.size()))
261 return false;
262 const xAOD::Muon* muon = m_hyperInputs.m_muons.at(leptonIndex);
263 localLeptonP4 =
264 buildRecoP4(muon->pt(), muon->eta(), muon->phi(), muon->e());
265 analyserCharge = muon->charge();
266 }
267
268 bJetP4 = toPtEtaPhiM(jetP4);
269 leptonP4 = toPtEtaPhiM(localLeptonP4);
270 return true;
271}
272
273void RunHyPERAlg::buildTopP4TtbarAllHadronic(const std::vector<int>& topIndices,
274 const std::vector<int>& wIndices,
275 PtEtaPhiMVector& top_b_p4,
276 PtEtaPhiMVector& top_W_decay0_p4,
277 PtEtaPhiMVector& top_W_decay1_p4) {
278 // Check we have enough indices
279 if (topIndices.size() != 3 || wIndices.size() != 2) {
280 top_b_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
281 top_W_decay0_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
282 top_W_decay1_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
283 return;
284 }
285
286 // Check that W indices are within the top indices
287 if (std::find(topIndices.begin(), topIndices.end(), wIndices[0]) ==
288 topIndices.end() ||
289 std::find(topIndices.begin(), topIndices.end(), wIndices[1]) ==
290 topIndices.end()) {
291 top_b_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
292 top_W_decay0_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
293 top_W_decay1_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
294 return;
295 }
296
297 const xAOD::Jet* leadWJet = nullptr;
298 const xAOD::Jet* subleadWJet = nullptr;
299
300 // Filter good W indices (-1 is bad)
301 std::vector<int> goodWIndices;
302 for (const auto idx : wIndices) {
303 if (idx != -1) {
304 goodWIndices.push_back(idx);
305 }
306 }
307 // If we only have one good W index, by definition is the leading W decay
308 if (goodWIndices.size() == 1) {
309 int leadingWIndex = goodWIndices[0];
310 leadWJet = m_hyperInputs.m_jets.at(leadingWIndex);
311 }
312 // If there are two good W indices, we need to determine which is leading and
313 // subleading
314 else if (goodWIndices.size() == 2) {
315 int leadingWIndex = goodWIndices[0];
316 int subleadingWIndex = goodWIndices[1];
317 const xAOD::Jet* jet1 = m_hyperInputs.m_jets.at(leadingWIndex);
318 const xAOD::Jet* jet2 = m_hyperInputs.m_jets.at(subleadingWIndex);
319 if (jet1->pt() >= jet2->pt()) {
320 leadWJet = jet1;
321 subleadWJet = jet2;
322 } else {
323 leadWJet = jet2;
324 subleadWJet = jet1;
325 }
326 }
327 // Take out the b-jet index as the one not in the W indices
328 int bJetIndex = -1;
329 for (const auto idx : topIndices) {
330 if (std::find(wIndices.begin(), wIndices.end(), idx) == wIndices.end()) {
331 bJetIndex = idx;
332 break;
333 }
334 }
335 const xAOD::Jet* bJet =
336 (bJetIndex != -1) ? m_hyperInputs.m_jets.at(bJetIndex) : nullptr;
337
338 // Build the 4-vectors
339 top_b_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
340 top_W_decay0_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
341 top_W_decay1_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
342
343 if (bJet) {
344 ROOT::Math::PtEtaPhiEVector bJetP4 =
345 buildRecoP4(bJet->pt(), bJet->eta(), bJet->phi(), bJet->e());
346 top_b_p4 = toPtEtaPhiM(bJetP4);
347 }
348 if (leadWJet) {
349 ROOT::Math::PtEtaPhiEVector leadWJetP4 = buildRecoP4(
350 leadWJet->pt(), leadWJet->eta(), leadWJet->phi(), leadWJet->e());
351 top_W_decay0_p4 = toPtEtaPhiM(leadWJetP4);
352 }
353 if (subleadWJet) {
354 ROOT::Math::PtEtaPhiEVector subleadWJetP4 =
355 buildRecoP4(subleadWJet->pt(), subleadWJet->eta(), subleadWJet->phi(),
356 subleadWJet->e());
357 top_W_decay1_p4 = toPtEtaPhiM(subleadWJetP4);
358 }
359}
360
362 const std::vector<int>& topHadIndices, const std::vector<int>& wHadIndices,
363 const std::vector<int>& topLepIndices, const std::vector<int>& topLepIDs,
364 PtEtaPhiMVector& tophad_b_p4, PtEtaPhiMVector& tophad_w_decay0_p4,
365 PtEtaPhiMVector& tophad_w_decay1_p4, PtEtaPhiMVector& toplep_b_p4,
366 PtEtaPhiMVector& toplep_lep_p4) {
367 tophad_b_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
368 tophad_w_decay0_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
369 tophad_w_decay1_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
370 toplep_b_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
371 toplep_lep_p4.SetCoordinates(0.0, 0.0, 0.0, 0.0);
372
373 // Hadronic top 4-vectors
374 buildTopP4TtbarAllHadronic(topHadIndices, wHadIndices, tophad_b_p4,
375 tophad_w_decay0_p4, tophad_w_decay1_p4);
376
377 // Leptonic top 4-vectors
378 if (topLepIndices.size() == 3 && topLepIDs.size() == 3) {
379 const int jetID = static_cast<int>(HyPERParticleID::jet);
380 const int electronID = static_cast<int>(HyPERParticleID::e);
381 const int muonID = static_cast<int>(HyPERParticleID::mu);
382
383 for (std::size_t i = 0; i < 3; ++i) {
384 int idx = topLepIndices[i];
385 int id = topLepIDs[i];
386 if (idx < 0)
387 continue;
388
389 if (id == jetID) {
390 if (idx < static_cast<int>(m_hyperInputs.m_jets.size())) {
391 const xAOD::Jet* jet = m_hyperInputs.m_jets.at(idx);
392 toplep_b_p4 = toPtEtaPhiM(
393 buildRecoP4(jet->pt(), jet->eta(), jet->phi(), jet->e()));
394 }
395 } else if (id == electronID) {
396 if (idx < static_cast<int>(m_hyperInputs.m_electrons.size())) {
397 const xAOD::Electron* el = m_hyperInputs.m_electrons.at(idx);
398 toplep_lep_p4 =
399 toPtEtaPhiM(buildRecoP4(el->pt(), el->eta(), el->phi(), el->e()));
400 }
401 } else if (id == muonID) {
402 if (idx < static_cast<int>(m_hyperInputs.m_muons.size())) {
403 const xAOD::Muon* mu = m_hyperInputs.m_muons.at(idx);
404 toplep_lep_p4 =
405 toPtEtaPhiM(buildRecoP4(mu->pt(), mu->eta(), mu->phi(), mu->e()));
406 }
407 }
408 }
409 }
410}
411
412StatusCode RunHyPERAlg::execute(const EventContext& ctx) {
413 auto invalidRecoParton = []() {
414 PtEtaPhiMVector vec;
415 vec.SetCoordinates(0.0, 0.0, 0.0, 0.0);
416 return vec;
417 };
418 // Loop over systematics
419 for (const auto& sys : m_systematicsList.systematicsVector()) {
420 // Check the event selection
421 const xAOD::EventInfo* evtInfo = nullptr;
422 ANA_CHECK(m_eventInfoHandle.retrieve(evtInfo, sys, ctx));
423
424 // If user sets DEBUG the idea is the user will see general things about the
425 // code running for all events. If user sets VERBOSE the idea is the user
426 // will see very detailed information for one specific event.
427 if (m_fullLogEventNumber.value() != 0) { // User wants to log a particular event.
428 if (evtInfo->eventNumber() == m_fullLogEventNumber.value()) {
429 this->msg().setLevel(MSG::VERBOSE);
430 g_hyper_msg_level = MSG::VERBOSE;
431 } else { // We don't want other events to pollute the log.
432 this->msg().setLevel(MSG::INFO);
433 g_hyper_msg_level = MSG::INFO;
434 }
435 }
436
437 ANA_MSG_DEBUG("Event number.... : " << evtInfo->eventNumber());
438
439 // Every CP::SysWriteDecorHandle must be locked before the output stream
440 // flushes, otherwise copyAuxStoreThinned warns about unlocked decorations.
441 // Invoked on every path that leaves this systematic iteration.
442 auto lockAllDecorations = [&]() {
444 m_hyper_TtbarAllHadronic_Top1_Indices.lock(*evtInfo, sys);
445 m_hyper_TtbarAllHadronic_Top1_Score.lock(*evtInfo, sys);
446 m_hyper_TtbarAllHadronic_Top2_Indices.lock(*evtInfo, sys);
447 m_hyper_TtbarAllHadronic_Top2_Score.lock(*evtInfo, sys);
448 m_hyper_TtbarAllHadronic_W1_Indices.lock(*evtInfo, sys);
449 m_hyper_TtbarAllHadronic_W1_Score.lock(*evtInfo, sys);
450 m_hyper_TtbarAllHadronic_W2_Indices.lock(*evtInfo, sys);
451 m_hyper_TtbarAllHadronic_W2_Score.lock(*evtInfo, sys);
452 if (!m_top_b_p4.empty()) m_top_b_p4.lock(*evtInfo, sys);
453 if (!m_topbar_bbar_p4.empty()) m_topbar_bbar_p4.lock(*evtInfo, sys);
454 if (!m_top_Wplus_decay0_p4.empty()) m_top_Wplus_decay0_p4.lock(*evtInfo, sys);
455 if (!m_top_Wplus_decay1_p4.empty()) m_top_Wplus_decay1_p4.lock(*evtInfo, sys);
456 if (!m_topbar_Wminus_decay0_p4.empty()) m_topbar_Wminus_decay0_p4.lock(*evtInfo, sys);
457 if (!m_topbar_Wminus_decay1_p4.empty()) m_topbar_Wminus_decay1_p4.lock(*evtInfo, sys);
458 }
460 m_hyper_TtbarLJets_Classification_Score.lock(*evtInfo, sys);
461 m_hyper_TtbarLJets_TopHad_Indices.lock(*evtInfo, sys);
462 m_hyper_TtbarLJets_TopLep_Indices.lock(*evtInfo, sys);
463 m_hyper_TtbarLJets_WHad_Indices.lock(*evtInfo, sys);
464 m_hyper_TtbarLJets_WLep_Indices.lock(*evtInfo, sys);
465 m_hyper_TtbarLJets_TopHad_Score.lock(*evtInfo, sys);
466 m_hyper_TtbarLJets_TopLep_Score.lock(*evtInfo, sys);
467 m_hyper_TtbarLJets_WHad_Score.lock(*evtInfo, sys);
468 m_hyper_TtbarLJets_WLep_Score.lock(*evtInfo, sys);
469 m_hyper_TtbarLJets_TopHad_IDs.lock(*evtInfo, sys);
470 m_hyper_TtbarLJets_TopLep_IDs.lock(*evtInfo, sys);
471 if (!m_toplep_b_p4.empty()) m_toplep_b_p4.lock(*evtInfo, sys);
472 if (!m_toplep_lep_p4.empty()) m_toplep_lep_p4.lock(*evtInfo, sys);
473 if (!m_tophad_b_p4.empty()) m_tophad_b_p4.lock(*evtInfo, sys);
474 if (!m_tophad_w_decay0_p4.empty()) m_tophad_w_decay0_p4.lock(*evtInfo, sys);
475 if (!m_tophad_w_decay1_p4.empty()) m_tophad_w_decay1_p4.lock(*evtInfo, sys);
476 }
479 m_hyper_TtbarDiLepton_Top1_Indices.lock(*evtInfo, sys);
480 m_hyper_TtbarDiLepton_Top2_Indices.lock(*evtInfo, sys);
481 m_hyper_TtbarDiLepton_Top1_Score.lock(*evtInfo, sys);
482 m_hyper_TtbarDiLepton_Top2_Score.lock(*evtInfo, sys);
483 m_hyper_TtbarDiLepton_Top1_IDs.lock(*evtInfo, sys);
484 m_hyper_TtbarDiLepton_Top2_IDs.lock(*evtInfo, sys);
485 m_hyper_TtbarDiLepton_HE_Score.lock(*evtInfo, sys);
486 if (!m_top_b_p4.empty()) m_top_b_p4.lock(*evtInfo, sys);
487 if (!m_topbar_bbar_p4.empty()) m_topbar_bbar_p4.lock(*evtInfo, sys);
488 if (!m_top_lep_p4.empty()) m_top_lep_p4.lock(*evtInfo, sys);
489 if (!m_topbar_lepbar_p4.empty()) m_topbar_lepbar_p4.lock(*evtInfo, sys);
490 }
491 };
492
493
494 // Default decoration values (topology dependent)
495 const HyPERTopology hyperTopology = m_hyperTopology;
496 if (hyperTopology == EventReco::HyPERTopology::TtbarAllHadronic) {
498 *evtInfo, std::vector<int>{-1, -1, -1}, sys);
499 m_hyper_TtbarAllHadronic_Top1_Score.set(*evtInfo, -1, sys);
501 *evtInfo, std::vector<int>{-1, -1, -1}, sys);
502 m_hyper_TtbarAllHadronic_Top2_Score.set(*evtInfo, -1, sys);
504 *evtInfo, std::vector<int>{-1, -1, -1}, sys);
505 m_hyper_TtbarAllHadronic_W1_Score.set(*evtInfo, -1, sys);
507 *evtInfo, std::vector<int>{-1, -1, -1}, sys);
508 m_hyper_TtbarAllHadronic_W2_Score.set(*evtInfo, -1, sys);
509 if (!m_top_b_p4.empty())
510 m_top_b_p4.set(*evtInfo, invalidRecoParton(), sys);
511 if (!m_topbar_bbar_p4.empty())
512 m_topbar_bbar_p4.set(*evtInfo, invalidRecoParton(), sys);
513 if (!m_top_Wplus_decay0_p4.empty())
514 m_top_Wplus_decay0_p4.set(*evtInfo, invalidRecoParton(), sys);
515 if (!m_top_Wplus_decay1_p4.empty())
516 m_top_Wplus_decay1_p4.set(*evtInfo, invalidRecoParton(), sys);
517 if (!m_topbar_Wminus_decay0_p4.empty())
518 m_topbar_Wminus_decay0_p4.set(*evtInfo, invalidRecoParton(), sys);
519 if (!m_topbar_Wminus_decay1_p4.empty())
520 m_topbar_Wminus_decay1_p4.set(*evtInfo, invalidRecoParton(), sys);
521 }
522 if (hyperTopology == EventReco::HyPERTopology::TtbarLJets) {
523 m_hyper_TtbarLJets_Classification_Score.set(*evtInfo, -1, sys);
525 std::vector<int>{-1, -1, -1}, sys);
527 std::vector<int>{-1, -1, -1}, sys);
528 m_hyper_TtbarLJets_WHad_Indices.set(*evtInfo, std::vector<int>{-1, -1},
529 sys);
530 m_hyper_TtbarLJets_WLep_Indices.set(*evtInfo, std::vector<int>{-1, -1},
531 sys);
532 m_hyper_TtbarLJets_TopHad_Score.set(*evtInfo, -1, sys);
533 m_hyper_TtbarLJets_TopLep_Score.set(*evtInfo, -1, sys);
534 m_hyper_TtbarLJets_WHad_Score.set(*evtInfo, -1, sys);
535 m_hyper_TtbarLJets_WLep_Score.set(*evtInfo, -1, sys);
536 m_hyper_TtbarLJets_TopHad_IDs.set(*evtInfo, std::vector<int>{-1, -1, -1},
537 sys);
538 m_hyper_TtbarLJets_TopLep_IDs.set(*evtInfo, std::vector<int>{-1, -1, -1},
539 sys);
540 if (!m_toplep_b_p4.empty())
541 m_toplep_b_p4.set(*evtInfo, invalidRecoParton(), sys);
542 if (!m_toplep_lep_p4.empty())
543 m_toplep_lep_p4.set(*evtInfo, invalidRecoParton(), sys);
544 if (!m_tophad_b_p4.empty())
545 m_tophad_b_p4.set(*evtInfo, invalidRecoParton(), sys);
546 if (!m_tophad_w_decay0_p4.empty())
547 m_tophad_w_decay0_p4.set(*evtInfo, invalidRecoParton(), sys);
548 if (!m_tophad_w_decay1_p4.empty())
549 m_tophad_w_decay1_p4.set(*evtInfo, invalidRecoParton(), sys);
550 }
551 if (hyperTopology == EventReco::HyPERTopology::TtbarDiLepton) {
552 m_hyper_TtbarDiLepton_Classification_Score.set(*evtInfo, -1, sys);
553 m_hyper_TtbarDiLepton_Top1_Indices.set(*evtInfo, std::vector<int>{-1, -1},
554 sys);
555 m_hyper_TtbarDiLepton_Top2_Indices.set(*evtInfo, std::vector<int>{-1, -1},
556 sys);
557 m_hyper_TtbarDiLepton_Top1_Score.set(*evtInfo, -1, sys);
558 m_hyper_TtbarDiLepton_Top2_Score.set(*evtInfo, -1, sys);
559 m_hyper_TtbarDiLepton_Top1_IDs.set(*evtInfo, std::vector<int>{-1, -1},
560 sys);
561 m_hyper_TtbarDiLepton_Top2_IDs.set(*evtInfo, std::vector<int>{-1, -1},
562 sys);
563 m_hyper_TtbarDiLepton_HE_Score.set(*evtInfo, -1, sys);
564 if (!m_top_b_p4.empty())
565 m_top_b_p4.set(*evtInfo, invalidRecoParton(), sys);
566 if (!m_topbar_bbar_p4.empty())
567 m_topbar_bbar_p4.set(*evtInfo, invalidRecoParton(), sys);
568 if (!m_top_lep_p4.empty())
569 m_top_lep_p4.set(*evtInfo, invalidRecoParton(), sys);
570 if (!m_topbar_lepbar_p4.empty())
571 m_topbar_lepbar_p4.set(*evtInfo, invalidRecoParton(), sys);
572 }
573
574 if (m_selection && !m_selection.getBool(*evtInfo, sys)) {
575 lockAllDecorations();
576 continue;
577 }
578
579 // Read the containers
580 const xAOD::ElectronContainer* electrons = nullptr;
581 ANA_CHECK(m_electronsHandle.retrieve(electrons, sys, ctx));
582 const xAOD::MuonContainer* muons = nullptr;
583 ANA_CHECK(m_muonsHandle.retrieve(muons, sys, ctx));
584 const xAOD::JetContainer* jets = nullptr;
585 ANA_CHECK(m_jetsHandle.retrieve(jets, sys, ctx));
586 const xAOD::MissingETContainer* met = nullptr;
587 ANA_CHECK(m_metHandle.retrieve(met, sys, ctx));
588
589 // Apply object-wise selection
594 std::vector<int> selected_jets_btag;
595
596 ANA_MSG_DEBUG("Building particle containers.");
597
598 ANA_MSG_DEBUG("Building electrons container.");
599 for (const xAOD::Electron* el : *electrons) {
600 if (m_electronSelection.getBool(*el, sys))
601 selected_electrons.push_back(el);
602 }
603
604 ANA_MSG_DEBUG("Building muons container.");
605 for (const xAOD::Muon* mu : *muons) {
606 if (m_muonSelection.getBool(*mu, sys))
607 selected_muons.push_back(mu);
608 }
609
610 ANA_MSG_DEBUG("Building jets container.");
611 for (const xAOD::Jet* jet : *jets) {
612 if (m_jetSelection.getBool(*jet, sys))
613 selected_jets.push_back(jet);
614 }
615
616 // Build the HyPER graph
617 m_hyperInputs.m_electrons = std::move(selected_electrons);
618 m_hyperInputs.m_muons = std::move(selected_muons);
619 m_hyperInputs.m_jets = std::move(selected_jets);
620 m_hyperInputs.m_met = met;
621 ANA_MSG_DEBUG("Building graph.");
622 ANA_CHECK(this->buildGraph());
623 ANA_MSG_DEBUG("Graph building successful.");
624
625 if (this->msg().level() == MSG::VERBOSE) {
626 ANA_MSG_INFO("Printing the graph...");
627 m_hyperGraph->printGraph();
628 }
629
630 // Parse the inputs to the HyPER algorithm
631 ANA_MSG_DEBUG("Building the ONNX inputs.");
632 m_hyperParser->buildONNXInputs(*m_hyperGraph, *m_hyperModel);
633 ANA_MSG_DEBUG("ONNX inputs building successful.");
634
635 // Run the HyPER algorithm
636 ANA_MSG_DEBUG("Evaluating model.");
637 unsigned int modelToUse;
638 // The model TRAINED on even should always be at position [0] in the
639 // m_session vector so, m_session[1] should be used for even events
640 modelToUse = evtInfo->eventNumber() % 2 == 0 ? 1 : 0;
641
642 ANA_MSG_DEBUG("Using model: " << modelToUse);
643 ANA_CHECK(m_hyperModel->evaluate(modelToUse));
644 ANA_MSG_DEBUG("Model evaluation successful.");
645
646 if (this->msg().level() == MSG::VERBOSE) {
647 ANA_MSG_INFO("Printing the ONNX inputs:");
648 m_hyperModel->printInputInfo(true);
649 ANA_MSG_INFO("Printing the ONNX outputs:");
650 m_hyperModel->printOutputInfo(true);
651 }
652
653 // Process the outputs
654 ANA_MSG_DEBUG("Extracting outputs from model.");
655 m_hyperParser->getONNXOutputs(*m_hyperModel);
656 ANA_MSG_DEBUG("Outputs extraction successful.");
657
658 ANA_MSG_DEBUG("Performing output reconstruction.");
659 m_hyperParser->reconstructOutputs(*m_hyperGraph);
660 ANA_MSG_DEBUG("Output reconstruction successful.");
661
662 // Print the inputs/outputs for PyTorch/TCT validation
663 if (m_fullLogEventNumber.value() != 0 &&
664 evtInfo->eventNumber() == m_fullLogEventNumber.value()) {
665 m_hyperGraph->printGraphInputsForValidation();
666 m_hyperParser->printOutputsForValidation();
667 }
668
669 // Write the outputs
670 ANA_MSG_DEBUG("Writing the outputs.");
671
672 if (hyperTopology == EventReco::HyPERTopology::TtbarAllHadronic) {
673 std::vector<std::string> recoLabels = m_hyperParser->getLabels();
674 std::vector<std::vector<int>> recoIndices = m_hyperParser->getIndices();
675 std::vector<float> recoScores = m_hyperParser->getScores();
676 // HyPER_Reco_Top1
677 std::size_t index = getIndexFromLabel(recoLabels, "HyPER_Reco_Top1");
678 std::vector<int> top1Indices(recoIndices[index]);
679 m_hyper_TtbarAllHadronic_Top1_Indices.set(*evtInfo, top1Indices, sys);
680 m_hyper_TtbarAllHadronic_Top1_Score.set(*evtInfo, recoScores[index], sys);
681 // HyPER_Reco_Top2
682 index = getIndexFromLabel(recoLabels, "HyPER_Reco_Top2");
683 std::vector<int> top2Indices(recoIndices[index]);
684 m_hyper_TtbarAllHadronic_Top2_Indices.set(*evtInfo, top2Indices, sys);
685 m_hyper_TtbarAllHadronic_Top2_Score.set(*evtInfo, recoScores[index], sys);
686 // HyPER_Reco_W1
687 index = getIndexFromLabel(recoLabels, "HyPER_Reco_W1");
688 std::vector<int> w1Indices(recoIndices[index]);
689 m_hyper_TtbarAllHadronic_W1_Indices.set(*evtInfo, w1Indices, sys);
690 m_hyper_TtbarAllHadronic_W1_Score.set(*evtInfo, recoScores[index], sys);
691 // HyPER_Reco_W2
692 index = getIndexFromLabel(recoLabels, "HyPER_Reco_W2");
693 std::vector<int> w2Indices(recoIndices[index]);
694 m_hyper_TtbarAllHadronic_W2_Indices.set(*evtInfo, w2Indices, sys);
695 m_hyper_TtbarAllHadronic_W2_Score.set(*evtInfo, recoScores[index], sys);
696 // Build the top 4-vectors
697 // Top1
698 PtEtaPhiMVector top_b_p4 = invalidRecoParton();
699 PtEtaPhiMVector top_Wplus_decay0_p4 = invalidRecoParton();
700 PtEtaPhiMVector top_Wplus_decay1_p4 = invalidRecoParton();
701 if (!m_top_b_p4.empty() && !m_top_Wplus_decay0_p4.empty() &&
702 !m_top_Wplus_decay1_p4.empty()) {
703 buildTopP4TtbarAllHadronic(top1Indices, w1Indices, top_b_p4,
704 top_Wplus_decay0_p4, top_Wplus_decay1_p4);
705 m_top_b_p4.set(*evtInfo, top_b_p4, sys);
706 m_top_Wplus_decay0_p4.set(*evtInfo, top_Wplus_decay0_p4, sys);
707 m_top_Wplus_decay1_p4.set(*evtInfo, top_Wplus_decay1_p4, sys);
708 }
709 // Top2
710 PtEtaPhiMVector topbar_bbar_p4 = invalidRecoParton();
711 PtEtaPhiMVector topbar_Wminus_decay0_p4 = invalidRecoParton();
712 PtEtaPhiMVector topbar_Wminus_decay1_p4 = invalidRecoParton();
713 if (!m_topbar_bbar_p4.empty() && !m_topbar_Wminus_decay0_p4.empty() &&
714 !m_topbar_Wminus_decay1_p4.empty()) {
715 buildTopP4TtbarAllHadronic(top2Indices, w2Indices, topbar_bbar_p4,
716 topbar_Wminus_decay0_p4,
717 topbar_Wminus_decay1_p4);
718 m_topbar_bbar_p4.set(*evtInfo, topbar_bbar_p4, sys);
719 m_topbar_Wminus_decay0_p4.set(*evtInfo, topbar_Wminus_decay0_p4, sys);
720 m_topbar_Wminus_decay1_p4.set(*evtInfo, topbar_Wminus_decay1_p4, sys);
721 }
722 }
723 if (hyperTopology == EventReco::HyPERTopology::TtbarLJets) {
724 std::vector<std::string> recoLabels = m_hyperParser->getLabels();
725 std::vector<std::vector<int>> recoIndices = m_hyperParser->getIndices();
726 std::vector<float> recoScores = m_hyperParser->getScores();
727 std::vector<std::vector<int>> recoIDs = m_hyperParser->getIds();
728 float class_score = m_hyperParser->getClassificationScore();
729 // Classification score
730 m_hyper_TtbarLJets_Classification_Score.set(*evtInfo, class_score, sys);
731 // HyPER_Reco_TopHad
732 std::size_t indexTopHad =
733 getIndexFromLabel(recoLabels, "HyPER_Reco_TopHad");
734 ANA_MSG_DEBUG("Index of HyPER_Reco_TopHad: " << indexTopHad);
735 std::vector<int> topHadIndices = recoIndices[indexTopHad];
736 m_hyper_TtbarLJets_TopHad_Indices.set(*evtInfo, topHadIndices, sys);
737 m_hyper_TtbarLJets_TopHad_Score.set(*evtInfo, recoScores[indexTopHad],
738 sys);
739 m_hyper_TtbarLJets_TopHad_IDs.set(*evtInfo, recoIDs[indexTopHad], sys);
740 // HyPER_Reco_TopLep
741 std::size_t indexTopLep =
742 getIndexFromLabel(recoLabels, "HyPER_Reco_TopLep");
743 ANA_MSG_DEBUG("Index of HyPER_Reco_TopLep: " << indexTopLep);
744 std::vector<int> topLepIndices = recoIndices[indexTopLep];
745 std::vector<int> topLepIDs = recoIDs[indexTopLep];
746 m_hyper_TtbarLJets_TopLep_Indices.set(*evtInfo, topLepIndices, sys);
747 m_hyper_TtbarLJets_TopLep_Score.set(*evtInfo, recoScores[indexTopLep],
748 sys);
749 m_hyper_TtbarLJets_TopLep_IDs.set(*evtInfo, topLepIDs, sys);
750 // HyPER_Reco_WHad
751 std::size_t indexWHad = getIndexFromLabel(recoLabels, "HyPER_Reco_WHad");
752 ANA_MSG_DEBUG("Index of HyPER_Reco_WHad: " << indexWHad);
753 std::vector<int> wHadIndices = recoIndices[indexWHad];
754 m_hyper_TtbarLJets_WHad_Indices.set(*evtInfo, wHadIndices, sys);
755 m_hyper_TtbarLJets_WHad_Score.set(*evtInfo, recoScores[indexWHad], sys);
756 // HyPER_Reco_WLep
757 std::size_t indexWLep = getIndexFromLabel(recoLabels, "HyPER_Reco_WLep");
758 ANA_MSG_DEBUG("Index of HyPER_Reco_WLep: " << indexWLep);
759 m_hyper_TtbarLJets_WLep_Indices.set(*evtInfo, recoIndices[indexWLep],
760 sys);
761 m_hyper_TtbarLJets_WLep_Score.set(*evtInfo, recoScores[indexWLep], sys);
762
763 // Build 4-vectors for TtbarLJets
764 PtEtaPhiMVector tophad_b_p4 = invalidRecoParton();
765 PtEtaPhiMVector tophad_w_decay0_p4 = invalidRecoParton();
766 PtEtaPhiMVector tophad_w_decay1_p4 = invalidRecoParton();
767 PtEtaPhiMVector toplep_b_p4 = invalidRecoParton();
768 PtEtaPhiMVector toplep_lep_p4 = invalidRecoParton();
769
770 buildTopP4TtbarLJets(topHadIndices, wHadIndices, topLepIndices, topLepIDs,
771 tophad_b_p4, tophad_w_decay0_p4, tophad_w_decay1_p4,
772 toplep_b_p4, toplep_lep_p4);
773
774 if (!m_tophad_b_p4.empty())
775 m_tophad_b_p4.set(*evtInfo, tophad_b_p4, sys);
776 if (!m_tophad_w_decay0_p4.empty())
777 m_tophad_w_decay0_p4.set(*evtInfo, tophad_w_decay0_p4, sys);
778 if (!m_tophad_w_decay1_p4.empty())
779 m_tophad_w_decay1_p4.set(*evtInfo, tophad_w_decay1_p4, sys);
780 if (!m_toplep_b_p4.empty())
781 m_toplep_b_p4.set(*evtInfo, toplep_b_p4, sys);
782 if (!m_toplep_lep_p4.empty())
783 m_toplep_lep_p4.set(*evtInfo, toplep_lep_p4, sys);
784 }
785 if (hyperTopology == EventReco::HyPERTopology::TtbarDiLepton) {
786 std::vector<std::string> recoLabels = m_hyperParser->getLabels();
787 std::vector<std::vector<int>> recoIndices = m_hyperParser->getIndices();
788 std::vector<float> recoScores = m_hyperParser->getScores();
789 std::vector<std::vector<int>> recoIDs = m_hyperParser->getIds();
790 float class_score = m_hyperParser->getClassificationScore();
791 PtEtaPhiMVector topBP4 = invalidRecoParton();
792 PtEtaPhiMVector topbarBbarP4 = invalidRecoParton();
793 PtEtaPhiMVector topLepP4 = invalidRecoParton();
794 PtEtaPhiMVector topbarLepbarP4 = invalidRecoParton();
795 // Classification score
796 m_hyper_TtbarDiLepton_Classification_Score.set(*evtInfo, class_score,
797 sys);
798 // HyPER_Reco_Top1
799 std::size_t index = getIndexFromLabel(recoLabels, "HyPER_Reco_Top1");
800 m_hyper_TtbarDiLepton_Top1_Indices.set(*evtInfo, recoIndices[index], sys);
801 m_hyper_TtbarDiLepton_Top1_Score.set(*evtInfo, recoScores[index], sys);
802 m_hyper_TtbarDiLepton_Top1_IDs.set(*evtInfo, recoIDs[index], sys);
803
804 PtEtaPhiMVector candidateBJetP4 = invalidRecoParton();
805 PtEtaPhiMVector candidateLeptonP4 = invalidRecoParton();
806 float analyserCharge = 0.;
807 if (buildDileptonPartialCandidate(recoIndices[index], recoIDs[index],
808 candidateBJetP4, candidateLeptonP4,
809 analyserCharge)) {
810 if (analyserCharge > 0.) {
811 topBP4 = candidateBJetP4;
812 topLepP4 = candidateLeptonP4;
813 } else if (analyserCharge < 0.) {
814 topbarBbarP4 = candidateBJetP4;
815 topbarLepbarP4 = candidateLeptonP4;
816 }
817 }
818
819 // HyPER_Reco_Top2
820 index = getIndexFromLabel(recoLabels, "HyPER_Reco_Top2");
821 m_hyper_TtbarDiLepton_Top2_Indices.set(*evtInfo, recoIndices[index], sys);
822 m_hyper_TtbarDiLepton_Top2_Score.set(*evtInfo, recoScores[index], sys);
823 m_hyper_TtbarDiLepton_Top2_IDs.set(*evtInfo, recoIDs[index], sys);
824
825 candidateBJetP4 = invalidRecoParton();
826 candidateLeptonP4 = invalidRecoParton();
827 analyserCharge = 0.;
828 if (buildDileptonPartialCandidate(recoIndices[index], recoIDs[index],
829 candidateBJetP4, candidateLeptonP4,
830 analyserCharge)) {
831 if (analyserCharge > 0.) {
832 topBP4 = candidateBJetP4;
833 topLepP4 = candidateLeptonP4;
834 } else if (analyserCharge < 0.) {
835 topbarBbarP4 = candidateBJetP4;
836 topbarLepbarP4 = candidateLeptonP4;
837 }
838 }
839
840 // HyPER_HE_Score
841 index = getIndexFromLabel(recoLabels, "HyPER_Reco_HE");
842 m_hyper_TtbarDiLepton_HE_Score.set(*evtInfo, recoScores[index], sys);
843
844 if (!m_top_b_p4.empty())
845 m_top_b_p4.set(*evtInfo, topBP4, sys);
846 if (!m_topbar_bbar_p4.empty())
847 m_topbar_bbar_p4.set(*evtInfo, topbarBbarP4, sys);
848 if (!m_top_lep_p4.empty())
849 m_top_lep_p4.set(*evtInfo, topLepP4, sys);
850 if (!m_topbar_lepbar_p4.empty())
851 m_topbar_lepbar_p4.set(*evtInfo, topbarLepbarP4, sys);
852 }
853
854 // Clear the graph and other relevant objects for the next event
855 ANA_MSG_DEBUG("Cleaning HyPER objects for next event.");
856 m_hyperGraph->clearGraph();
857 m_hyperModel->clearInputs();
858 m_hyperModel->clearOutputs();
859 m_hyperParser->clear();
860 m_hyperInputs.clear();
861 ANA_MSG_DEBUG("Clean successful.");
862
863 lockAllDecorations();
864 }
865 return StatusCode::SUCCESS;
866}
867
869 HyPERTopology topology = m_hyperModel->getTopology();
871 ANA_MSG_ERROR("Bad topology while building HyPER graph");
872 return StatusCode::FAILURE;
873 }
874
875 using Features = std::vector<float>;
876
877 // Remember... For HyPER we use the following particle IDs -> jet=1 e=2 mu=3
878 // met=4 tau=5 Also... VERY important! The order of filling the particles for
879 // the graph is important! We use this later for the reconstruction. The order
880 // is: jets -> electrons -> muons -> met -> taus
881 // TODO: Write a checker function for the ordering.
882
884 return this->buildTtbarLJetsGraph();
886 return this->buildTtbarAllHadronicGraph();
887 else if (topology == EventReco::HyPERTopology::TtbarDiLepton)
888 return this->buildTtbarDiLeptonGraph();
889 return StatusCode::FAILURE; // No topology selected, this is bad behaviour.
890}
891
893 // For this topology we use jets, electrons and muons:
894 // [E, eta, phi, pT, charge, particleID]
895 // And Edges with the following features:
896 // [dEta, dPhi, dR, m(i,j)]
897 // And, the following globals:
898 // [nJets, nBTagJets]
899
900 // Build particles
901 std::vector<Features> particles;
902 float nBJets90 =
903 0; // Store number of bjets per-quantile for the global features.
904 float nBJets85 = 0;
905 float nBJets77 = 0;
906 float nBJets70 = 0;
907 float nBJets65 = 0;
908 float nJets = 0; // Store number of jets for the global features.
909 for (const xAOD::Jet* jet : m_hyperInputs.m_jets) {
910 nJets += 1.0f;
911 Features feats;
912 if (m_ljetsUseBTag) {
913 // Get b-tagging decision.
914 if (!m_bTagDecoAcc->isAvailable(*jet)) {
915 ANA_MSG_ERROR("HyPERAlg:: the jets do not have " << m_btagDecorName
916 << " aux variable!");
917 return StatusCode::FAILURE;
918 }
919 int bTagQuantile = (*m_bTagDecoAcc)(*jet);
920 if (bTagQuantile >= 2)
921 nBJets90 += 1;
922 if (bTagQuantile >= 3)
923 nBJets85 += 1;
924 if (bTagQuantile >= 4)
925 nBJets77 += 1;
926 if (bTagQuantile >= 5)
927 nBJets70 += 1;
928 if (bTagQuantile >= 6)
929 nBJets65 += 1;
930 feats = {float(jet->e() / 1000),
931 float(jet->eta()),
932 float(jet->phi()),
933 float(jet->pt() / 1000),
934 float(bTagQuantile),
935 0.f,
937 1.f}; // TODO: This is needed because the training was
938 // done with new HyPER dataset.
939 } else {
940 feats = {float(jet->e() / 1000),
941 float(jet->eta()),
942 float(jet->phi()),
943 float(jet->pt() / 1000),
944 0.f,
946 1.f}; // TODO: This is needed because the training was
947 // done with new HyPER dataset.
948 }
949 particles.push_back(std::move(feats));
950 }
951 for (const xAOD::Electron* el : m_hyperInputs.m_electrons) {
952 Features feats;
953 if (m_ljetsUseBTag) {
954 feats = {float(el->e() / 1000),
955 float(el->eta()),
956 float(el->phi()),
957 float(el->pt() / 1000),
958 0.f,
959 float(el->charge()),
961 2.f};
962 } else {
963 feats = {float(el->e() / 1000),
964 float(el->eta()),
965 float(el->phi()),
966 float(el->pt() / 1000),
967 float(el->charge()),
969 2.f}; // TODO: This is needed because the training was
970 // done with new HyPER dataset.
971 }
972 particles.push_back(std::move(feats));
973 }
974 for (const xAOD::Muon* mu : m_hyperInputs.m_muons) {
975 Features feats;
976 if (m_ljetsUseBTag) {
977 feats = {float(mu->e() / 1000),
978 float(mu->eta()),
979 float(mu->phi()),
980 float(mu->pt() / 1000),
981 0.f,
982 float(mu->charge()),
984 2.f};
985 } else {
986 feats = {float(mu->e() / 1000),
987 float(mu->eta()),
988 float(mu->phi()),
989 float(mu->pt() / 1000),
990 float(mu->charge()),
992 2.f}; // TODO: This is needed because the training was
993 // done with new HyPER dataset.
994 }
995 particles.push_back(std::move(feats));
996 }
997 Features metFeats;
998 if (m_ljetsUseBTag) {
999 metFeats = {float((*m_hyperInputs.m_met)["Final"]->met() / 1000),
1000 0.f,
1001 float((*m_hyperInputs.m_met)["Final"]->phi()),
1002 float((*m_hyperInputs.m_met)["Final"]->met() / 1000),
1003 0.f,
1004 0.f,
1006 3.f};
1007 } else {
1008 metFeats = {float((*m_hyperInputs.m_met)["Final"]->met() / 1000),
1009 0.f,
1010 float((*m_hyperInputs.m_met)["Final"]->phi()),
1011 float((*m_hyperInputs.m_met)["Final"]->met() / 1000),
1012 0.f,
1014 3.f};
1015 }
1016 particles.push_back(std::move(metFeats));
1017
1018 // Add the nodes
1019 for (std::size_t i = 0; i < particles.size(); i++) {
1020 m_hyperGraph->addNode(particles[i]);
1021 }
1022
1023 // Add the globals, scaling already applied here.
1024 Features globalFeats;
1025 if (m_ljetsUseBTag)
1026 globalFeats = {nJets / 6.0f, nBJets90 / 2.0f, nBJets85 / 2.0f,
1027 nBJets77 / 2.0f, nBJets70 / 2.0f, nBJets65 / 2.0f};
1028 else
1029 globalFeats = {nJets / 6.0f};
1030 m_hyperGraph->addGlobal(globalFeats);
1031
1032 // Build graph edges and hyperedges
1033 m_hyperGraph->buildEdgeIndices();
1034 m_hyperGraph->buildHyperEdges(3);
1035
1036 // Add the edges
1037 // Loop over the edge indices
1038 for (const auto& edge : m_hyperGraph->getEdgeIndicesVector()) {
1039 // Get the source and target nodes
1040 int64_t source = edge.first;
1041 int64_t target = edge.second;
1042 // Get the features
1043 Features firstNodeFeats = m_hyperGraph->getNodeFeats(source);
1044 Features secondNodeFeats = m_hyperGraph->getNodeFeats(target);
1045
1046 // Calculate the edge features
1047 float dEta = secondNodeFeats[1] - firstNodeFeats[1];
1048 float dPhi = deltaPhi(secondNodeFeats[2], firstNodeFeats[2]);
1049 float dR = sqrt(dEta * dEta + dPhi * dPhi);
1050 ROOT::Math::PtEtaPhiEVector particle1;
1051 ROOT::Math::PtEtaPhiEVector particle2;
1052 particle1.SetCoordinates(firstNodeFeats[3], firstNodeFeats[1],
1053 firstNodeFeats[2], firstNodeFeats[0]);
1054 particle2.SetCoordinates(secondNodeFeats[3], secondNodeFeats[1],
1055 secondNodeFeats[2], secondNodeFeats[0]);
1056 float m = (particle1 + particle2).M();
1057
1058 Features edgeFeats = {dEta, dPhi, dR, log(m)};
1059 m_hyperGraph->addEdge(source, target, edgeFeats);
1060 }
1061
1062 // Scaling the node inputs
1063 for (std::size_t i{0}; i < static_cast<std::size_t>(m_hyperGraph->nNodes());
1064 i++) {
1065 Features& nodeFeats = m_hyperGraph->getNodeFeats(i);
1066 nodeFeats.at(0) = log(nodeFeats.at(0));
1067 nodeFeats.at(3) = log(nodeFeats.at(3));
1068 }
1069 return StatusCode::SUCCESS;
1070}
1071
1073 // For this topology we only use jets:
1074 // [E, eta, phi, pT, bTag, particleID = 1]
1075 // And Edges with the following features:
1076 // [dEta, dPhi, dR, m(i,j)]
1077 // And, the following globals:
1078 // [nJets, nBTagJets]
1079
1080 // Build particles
1081 std::vector<Features> particles;
1082 float nBJets90 =
1083 0; // Store number of bjets per-quantile for the global features.
1084 float nBJets85 = 0;
1085 float nBJets77 = 0;
1086 float nBJets70 = 0;
1087 float nBJets65 = 0;
1088 float nJets = 0; // Store number of jets for the global features.
1089 for (const xAOD::Jet* jet : m_hyperInputs.m_jets) {
1090 nJets += 1.0f;
1091 // Get b-tagging decision
1092 if (!m_bTagDecoAcc->isAvailable(*jet)) {
1093 ANA_MSG_ERROR("HyPERAlg:: the jets do not have " << m_btagDecorName
1094 << " aux variable!");
1095 return StatusCode::FAILURE;
1096 }
1097
1098 int bTagQuantile = (*m_bTagDecoAcc)(*jet);
1099 if (bTagQuantile >= 2)
1100 nBJets90 += 1;
1101 if (bTagQuantile >= 3)
1102 nBJets85 += 1;
1103 if (bTagQuantile >= 4)
1104 nBJets77 += 1;
1105 if (bTagQuantile >= 5)
1106 nBJets70 += 1;
1107 if (bTagQuantile >= 6)
1108 nBJets65 += 1;
1109 Features feats = {float(jet->e() / 1000), float(jet->eta()),
1110 float(jet->phi()), float(jet->pt() / 1000),
1111 float(bTagQuantile), float(EventReco::HyPERParticleID::jet)};
1112 particles.push_back(std::move(feats));
1113 }
1114
1115 // Add the nodes
1116 for (std::size_t i = 0; i < particles.size(); i++) {
1117 m_hyperGraph->addNode(particles[i]);
1118 }
1119
1120 // Add the globals, scaling already applied here.
1121 Features globalFeats = {nJets / 6.0f, nBJets90 / 2.0f, nBJets85 / 2.0f,
1122 nBJets77 / 2.0f, nBJets70 / 2.0f, nBJets65 / 2.0f};
1123 m_hyperGraph->addGlobal(globalFeats);
1124
1125 // Build graph edges and hyperedges
1126 m_hyperGraph->buildEdgeIndices();
1127 m_hyperGraph->buildHyperEdges(3);
1128
1129 // Add the edges
1130 // Loop over the edge indices
1131 for (const auto& edge : m_hyperGraph->getEdgeIndicesVector()) {
1132 // Get the source and target nodes
1133 int64_t source = edge.first;
1134 int64_t target = edge.second;
1135 // Get the features
1136 Features firstNodeFeats = m_hyperGraph->getNodeFeats(source);
1137 Features secondNodeFeats = m_hyperGraph->getNodeFeats(target);
1138
1139 // Calculate the edge features
1140 float dEta = secondNodeFeats[1] - firstNodeFeats[1];
1141 float dPhi = deltaPhi(secondNodeFeats[2], firstNodeFeats[2]);
1142 float dR = sqrt(dEta * dEta + dPhi * dPhi);
1143 ROOT::Math::PtEtaPhiEVector particle1;
1144 ROOT::Math::PtEtaPhiEVector particle2;
1145 particle1.SetCoordinates(firstNodeFeats[3], firstNodeFeats[1],
1146 firstNodeFeats[2], firstNodeFeats[0]);
1147 particle2.SetCoordinates(secondNodeFeats[3], secondNodeFeats[1],
1148 secondNodeFeats[2], secondNodeFeats[0]);
1149 float m = (particle1 + particle2).M();
1150
1151 Features edgeFeats = {dEta, dPhi, dR, log(m)};
1152 m_hyperGraph->addEdge(source, target, edgeFeats);
1153 }
1154
1155 // Scaling the node inputs
1156 for (std::size_t i{0}; i < static_cast<std::size_t>(m_hyperGraph->nNodes());
1157 i++) {
1158 Features& nodeFeats = m_hyperGraph->getNodeFeats(i);
1159 nodeFeats.at(0) = log(nodeFeats.at(0));
1160 nodeFeats.at(3) = log(nodeFeats.at(3));
1161 }
1162 return StatusCode::SUCCESS;
1163}
1164
1166 // For this topology we use jets, electrons and muons:
1167 // [Log(E), eta, phi, Log(pT), bTagQuantile/6, charge, particleID/2]
1168 // And Edges with the following features:
1169 // [dEta, dPhi, dR, m(i,j)]
1170 // And, the following globals:
1171 // [nJets/6, Log(met_pT), met_phi, nBTagJets90/2, nBTagJets85/2,
1172 // nBTagJets77/2, nBTagJets70/2, nBTagJets65/2]
1173
1174 // Build particles
1175 std::vector<Features> particles;
1176 float nBJets90 =
1177 0; // Store number of bjets per-quantile for the global features.
1178 float nBJets85 = 0;
1179 float nBJets77 = 0;
1180 float nBJets70 = 0;
1181 float nBJets65 = 0;
1182 float nJets = 0; // Store number of jets for the global features.
1183 for (const xAOD::Jet* jet : m_hyperInputs.m_jets) {
1184
1185 nJets += 1.0f;
1186 // Get b-tagging decision.
1187 if (!m_bTagDecoAcc->isAvailable(*jet)) {
1188 ANA_MSG_ERROR("HyPERAlg:: the jets do not have " << m_btagDecorName
1189 << " aux variable!");
1190 return StatusCode::FAILURE;
1191 }
1192 int bTagQuantile = (*m_bTagDecoAcc)(*jet);
1193 if (bTagQuantile >= 2)
1194 nBJets90 += 1;
1195 if (bTagQuantile >= 3)
1196 nBJets85 += 1;
1197 if (bTagQuantile >= 4)
1198 nBJets77 += 1;
1199 if (bTagQuantile >= 5)
1200 nBJets70 += 1;
1201 if (bTagQuantile >= 6)
1202 nBJets65 += 1;
1203 Features feats = {float(jet->e() / 1000),
1204 float(jet->eta()),
1205 float(jet->phi()),
1206 float(jet->pt() / 1000),
1207 float(bTagQuantile),
1208 0.f,
1210 1.f}; // TODO: This is needed because the training was
1211 // done with new HyPER dataset.
1212 particles.push_back(std::move(feats));
1213 }
1214
1215 for (const xAOD::Electron* el : m_hyperInputs.m_electrons) {
1216
1217 Features feats = {float(el->e() / 1000),
1218 float(el->eta()),
1219 float(el->phi()),
1220 float(el->pt() / 1000),
1221 0.f,
1222 float(el->charge()),
1224 2.f};
1225 particles.push_back(std::move(feats));
1226 }
1227
1228 for (const xAOD::Muon* mu : m_hyperInputs.m_muons) {
1229
1230 Features feats = {float(mu->e() / 1000),
1231 float(mu->eta()),
1232 float(mu->phi()),
1233 float(mu->pt() / 1000),
1234 0.f,
1235 float(mu->charge()),
1237 2.f}; // TODO: This is needed because the
1238 // training was done with new HyPER
1239 // dataset.
1240 particles.push_back(std::move(feats));
1241 }
1242
1243 // MET features
1244 float met_pt = (*m_hyperInputs.m_met)["Final"]->met() / 1000;
1245 float met_phi = (*m_hyperInputs.m_met)["Final"]->phi();
1246
1247 Features metFeats = {
1248 met_pt, 0.f, met_phi, met_pt, 0.f, 0.f, float(EventReco::HyPERParticleID::met),
1249 3.f}; // TODO: This is needed because the training was
1250 // done with new HyPER dataset.
1251 particles.push_back(std::move(metFeats));
1252
1253 // Add the nodes
1254 for (std::size_t i = 0; i < particles.size(); i++) {
1255 m_hyperGraph->addNode(particles[i]);
1256 }
1257
1258 // Add the globals, scaling already applied here.
1259 Features globalFeats;
1260
1261 globalFeats = {nJets / 6.0f, log(met_pt), met_phi,
1262 nBJets90 / 2.0f, nBJets85 / 2.0f, nBJets77 / 2.0f,
1263 nBJets70 / 2.0f, nBJets65 / 2.0f};
1264 m_hyperGraph->addGlobal(globalFeats);
1265
1266 // Build graph edges and hyperedges
1267 m_hyperGraph->buildEdgeIndices();
1268 m_hyperGraph->buildHyperEdges(4);
1269
1270 // Add the edges
1271 // Loop over the edge indices
1272 for (const auto& edge : m_hyperGraph->getEdgeIndicesVector()) {
1273 // Get the source and target nodes
1274 int64_t source = edge.first;
1275 int64_t target = edge.second;
1276 // Get the features
1277 Features firstNodeFeats = m_hyperGraph->getNodeFeats(source);
1278 Features secondNodeFeats = m_hyperGraph->getNodeFeats(target);
1279
1280 // Calculate the edge features
1281 float dEta = secondNodeFeats[1] - firstNodeFeats[1];
1282 float dPhi = deltaPhi(secondNodeFeats[2], firstNodeFeats[2]);
1283 float dR = sqrt(dEta * dEta + dPhi * dPhi);
1284 ROOT::Math::PtEtaPhiEVector particle1;
1285 ROOT::Math::PtEtaPhiEVector particle2;
1286 particle1.SetCoordinates(firstNodeFeats[3], firstNodeFeats[1],
1287 firstNodeFeats[2], firstNodeFeats[0]);
1288 particle2.SetCoordinates(secondNodeFeats[3], secondNodeFeats[1],
1289 secondNodeFeats[2], secondNodeFeats[0]);
1290 float m = (particle1 + particle2).M();
1291
1292 Features edgeFeats = {dEta, dPhi, dR, log(m)};
1293 m_hyperGraph->addEdge(source, target, edgeFeats);
1294 }
1295
1296 // Scaling the node inputs
1297 for (std::size_t i{0}; i < static_cast<std::size_t>(m_hyperGraph->nNodes());
1298 i++) {
1299 Features& nodeFeats = m_hyperGraph->getNodeFeats(i);
1300 nodeFeats.at(0) = log(nodeFeats.at(0));
1301 nodeFeats.at(3) = log(nodeFeats.at(3));
1302 nodeFeats.at(4) = nodeFeats.at(4) / 6.0f;
1303 nodeFeats.at(6) = nodeFeats.at(6) / 2.0f;
1304 }
1305 return StatusCode::SUCCESS;
1306}
1307
1309 ANA_MSG_INFO("Finalizing RunHyPER");
1310 return StatusCode::SUCCESS;
1311}
1312
1313} // namespace EventReco
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
std::vector< size_t > vec
DataVector adapter that acts like it holds const pointers.
#define ANA_MSG_ERROR(xmsg,...)
Macro printing error messages.
#define ANA_MSG_DEBUG(xmsg,...)
Macro printing debug messages.
#define ANA_MSG_INFO(xmsg,...)
Macro printing info messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
std::vector< std::vector< int64_t > > indices
DataVector adapter that acts like it holds const pointers.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
virtual::StatusCode execute()
execute this algorithm
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_top_b_p4
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_top_lep_p4
CP::SysWriteDecorHandle< float > m_hyper_TtbarLJets_WHad_Score
std::unique_ptr< SG::ConstAccessor< int > > m_bTagDecoAcc
StatusCode buildTtbarLJetsGraph()
StatusCode buildTtbarDiLeptonGraph()
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_topbar_lepbar_p4
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarAllHadronic_Top2_Indices
CP::SysWriteDecorHandle< float > m_hyper_TtbarLJets_TopLep_Score
StatusCode buildTtbarAllHadronicGraph()
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarDiLepton_Top1_IDs
void buildTopP4TtbarAllHadronic(const std::vector< int > &topIndices, const std::vector< int > &wIndices, PtEtaPhiMVector &top_b_p4, PtEtaPhiMVector &top_W_decay0_p4, PtEtaPhiMVector &top_W_decay1_p4)
CP::SysWriteDecorHandle< float > m_hyper_TtbarDiLepton_Top2_Score
CP::SysReadSelectionHandle m_jetSelection
CP::SysReadSelectionHandle m_electronSelection
void buildTopP4TtbarLJets(const std::vector< int > &topHadIndices, const std::vector< int > &wHadIndices, const std::vector< int > &topLepIndices, const std::vector< int > &topLepIDs, PtEtaPhiMVector &tophad_b_p4, PtEtaPhiMVector &tophad_w_decay0_p4, PtEtaPhiMVector &tophad_w_decay1_p4, PtEtaPhiMVector &toplep_b_p4, PtEtaPhiMVector &toplep_lep_p4)
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_WHad_Indices
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_top_Wplus_decay1_p4
CP::SysReadHandle< xAOD::JetContainer > m_jetsHandle
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarAllHadronic_Top1_Indices
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_TopHad_IDs
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_TopHad_Indices
CP::SysWriteDecorHandle< float > m_hyper_TtbarLJets_TopHad_Score
CP::SysWriteDecorHandle< float > m_hyper_TtbarLJets_WLep_Score
CP::SysListHandle m_systematicsList
CP::SysWriteDecorHandle< float > m_hyper_TtbarAllHadronic_W2_Score
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_WLep_Indices
CP::SysReadHandle< xAOD::EventInfo > m_eventInfoHandle
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_tophad_w_decay1_p4
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarDiLepton_Top1_Indices
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_toplep_lep_p4
std::string m_btagDecorName
HyPERTopology m_hyperTopology
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarDiLepton_Top2_IDs
CP::SysReadHandle< xAOD::MuonContainer > m_muonsHandle
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_TopLep_IDs
CP::SysReadHandle< xAOD::ElectronContainer > m_electronsHandle
CP::SysWriteDecorHandle< float > m_hyper_TtbarDiLepton_Top1_Score
std::unique_ptr< HyPERModel > m_hyperModel
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarDiLepton_Top2_Indices
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_topbar_Wminus_decay0_p4
CP::SysReadHandle< xAOD::MissingETContainer > m_metHandle
CP::SysReadSelectionHandle m_muonSelection
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarLJets_TopLep_Indices
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_toplep_b_p4
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarAllHadronic_W2_Indices
CP::SysWriteDecorHandle< std::vector< int > > m_hyper_TtbarAllHadronic_W1_Indices
Gaudi::Property< long unsigned int > m_fullLogEventNumber
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_onnxToolTrainedOnEven
Gaudi::Property< std::string > m_btagger
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_topbar_bbar_p4
CP::SysWriteDecorHandle< float > m_hyper_TtbarAllHadronic_Top2_Score
CP::SysWriteDecorHandle< float > m_hyper_TtbarAllHadronic_Top1_Score
CP::SysWriteDecorHandle< float > m_hyper_TtbarDiLepton_Classification_Score
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_tophad_w_decay0_p4
CP::SysWriteDecorHandle< float > m_hyper_TtbarDiLepton_HE_Score
Gaudi::Property< std::string > m_topology
CP::SysWriteDecorHandle< float > m_hyper_TtbarLJets_Classification_Score
std::unique_ptr< HyPERGraph > m_hyperGraph
std::unique_ptr< HyPERParser > m_hyperParser
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_tophad_b_p4
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_topbar_Wminus_decay1_p4
virtual StatusCode initialize() override
CP::SysWriteDecorHandle< PtEtaPhiMVector > m_top_Wplus_decay0_p4
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_onnxToolTrainedOnOdd
CP::SysReadSelectionHandle m_selection
CP::SysWriteDecorHandle< float > m_hyper_TtbarAllHadronic_W1_Score
StatusCode buildGraph()
These methods build the HyPER graph based on the user-input topology.
bool buildDileptonPartialCandidate(const std::vector< int > &indices, const std::vector< int > &ids, PtEtaPhiMVector &bJetP4, PtEtaPhiMVector &leptonP4, float &analyserCharge) const
virtual StatusCode finalize() override
uint64_t eventNumber() const
The current event's event number.
virtual double phi() const
The azimuthal angle ( ) of the particle.
Definition Jet_v1.cxx:54
virtual double pt() const
The transverse momentum ( ) of the particle.
Definition Jet_v1.cxx:44
virtual double eta() const
The pseudorapidity ( ) of the particle.
Definition Jet_v1.cxx:49
virtual double e() const
The total energy of the particle.
Definition Jet_v1.cxx:63
HyPERTopology strToHyPERTopology(const std::string &str)
std::size_t getIndexFromLabel(const std::vector< std::string > &vec, const std::string &label)
std::vector< float > Features
Definition GraphBase.h:16
MSG::Level g_hyper_msg_level
float deltaPhi(float phi1, float phi2)
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Definition index.py:1
Jet_v1 Jet
Definition of the current "jet 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:
JetContainer_v1 JetContainer
Definition of the current "jet container 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