ATLAS Offline Software
Loading...
Searching...
No Matches
RunKLFitterAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7
9
12
13namespace EventReco {
14
27
29
31
32 ANA_CHECK(m_systematicsList.initialize());
33
34 // parse likelihood type
35 const auto lhIt = KLFEnums::strToLikelihood.find(m_LHType.value());
36 if (lhIt == KLFEnums::strToLikelihood.end()) {
37 ANA_MSG_ERROR("Unrecognized KLFitter likelihood: "
38 << m_LHType.value() << ". Available options: "
40 return StatusCode::FAILURE;
41 }
42 m_LHTypeEnum = lhIt->second;
43
45 ANA_MSG_ERROR("The ttbar_JetAngles likelihood is currently not supported!");
46 return StatusCode::FAILURE;
47 }
48
49 // parse lepton type
50 const auto leptonIt = KLFEnums::strToLeptonType.find(m_leptonType.value());
51 if (leptonIt == KLFEnums::strToLeptonType.end()) {
52 ANA_MSG_ERROR("Unrecognized KLFitter leptonType: "
53 << m_leptonType.value() << ". Available options: "
55 return StatusCode::FAILURE;
56 }
57 m_leptonTypeEnum = leptonIt->second;
61 "If using ttbar_AllHad likelihood, please use leptonType = "
62 "kNoLepton.");
63 return StatusCode::FAILURE;
64 }
65
66 // parse jet selection
67 const auto jetSelIt =
69 if (jetSelIt == KLFEnums::strToJetSelection.end()) {
70 ANA_MSG_ERROR("Unrecognized KLFitter JetSelectionMode: "
71 << m_jetSelectionMode.value() << ". Available options: "
73 return StatusCode::FAILURE;
74 }
75 m_jetSelectionModeEnum = jetSelIt->second;
76
78 m_useBtagPriority = true;
79 const auto njetsIt = KLFEnums::jetSelToNumber.find(m_jetSelectionModeEnum);
80 if (njetsIt == KLFEnums::jetSelToNumber.end()) {
82 "Could not parse the number of required jets from KLFitter jet "
83 "selection mode: "
84 << m_jetSelectionMode.value());
85 return StatusCode::FAILURE;
86 }
87 m_njetsRequirement = njetsIt->second;
88
89 // parse b-tagging method
90 const auto btagIt = KLFEnums::strToBtagMethod.find(m_bTaggingMethod.value());
91 if (btagIt == KLFEnums::strToBtagMethod.end()) {
92 ANA_MSG_ERROR("Unrecognized KLFitter BTaggingMethod: "
93 << m_bTaggingMethod.value() << ". Available options: "
95 return StatusCode::FAILURE;
96 }
97 m_bTaggingMethodEnum = btagIt->second;
98
99 // setup the KLFitter::Fitter instance
100 m_myFitter = std::make_unique<KLFitter::Fitter>();
101 const std::string transferFunctionAbsPath =
104 std::make_unique<KLFitter::DetectorAtlas_8TeV>(transferFunctionAbsPath);
105 if (!m_myFitter->SetDetector(m_myDetector.get())) {
107 "Failed to set KLFitter::Detector for KLFitter::Fitter instance.");
108 return StatusCode::FAILURE;
109 }
110
111 // validate the lepton type for the leptonic likelihoods
116 ANA_MSG_ERROR(" LeptonType " << m_leptonType.value()
117 << " is only defined for the "
118 "ttZTrilepton likelihood");
119 return StatusCode::FAILURE;
120 }
123 ANA_MSG_ERROR(" Please supply a valid LeptonType : kElectron or kMuon");
124 return StatusCode::FAILURE;
125 }
126 }
127
128 // create the likelihood; the settings are applied on the concrete type
129 // before handing it over as a KLFitter::LikelihoodBase
130 const bool useElectrons =
133 auto configureCommon = [this](auto &likelihood) {
134 likelihood.SetBTagging(m_bTaggingMethodEnum);
135 // set top mass
136 likelihood.PhysicsConstants()->SetMassTop(m_massTop);
137 // whether the top mass is fixed to the constant in likelihood or not
138 likelihood.SetFlagTopMassFixed(m_fixedTopMass);
139 };
140 auto makeLeptonic = [&](auto likelihood)
141 -> std::unique_ptr<KLFitter::LikelihoodBase> {
142 using LH = typename decltype(likelihood)::element_type;
143 likelihood->SetLeptonType(useElectrons ? LH::LeptonType::kElectron
144 : LH::LeptonType::kMuon);
145 configureCommon(*likelihood);
146 return likelihood;
147 };
148
149 switch (m_LHTypeEnum) {
151 m_likelihood = makeLeptonic(
152 std::make_unique<KLFitter::LikelihoodTopLeptonJets>());
153 break;
155 m_likelihood = makeLeptonic(
156 std::make_unique<KLFitter::LikelihoodTTHLeptonJets>());
157 break;
159 m_likelihood = makeLeptonic(
160 std::make_unique<KLFitter::LikelihoodTopLeptonJets_JetAngles>());
161 break;
163 m_likelihood = makeLeptonic(
164 std::make_unique<KLFitter::LikelihoodTopLeptonJets_Angular>());
165 break;
167 // For ttZ->trilepton, we can have difficult combinations of leptons in
168 // the final state (3x same flavour, or mixed case). The latter is
169 // trivial, for which we can default back to the ljets likelihood. So we
170 // distinguish here:
171 // - kTriMuon, kTriElectron: dedicated TTZ->trilepton likelihood,
172 // - kMuon, kElectron: standard ttbar->l+jets likelihood.
175 m_likelihood = makeLeptonic(
176 std::make_unique<KLFitter::LikelihoodTTZTrilepton>());
177 } else {
178 m_likelihood = makeLeptonic(
179 std::make_unique<KLFitter::LikelihoodTopLeptonJets>());
180 }
181 break;
183 m_likelihood = makeLeptonic(
184 std::make_unique<KLFitter::BoostedLikelihoodTopLeptonJets>());
185 break;
187 auto likelihood = std::make_unique<KLFitter::LikelihoodTopAllHadronic>();
188 configureCommon(*likelihood);
189 m_likelihood = std::move(likelihood);
190 break;
191 }
192 }
193 if (!m_likelihood) {
194 ANA_MSG_ERROR("Unrecognized KLFitter likelihood: " << m_LHType.value());
195 return StatusCode::FAILURE;
196 }
197
198 // configure which likelihood to use in the fitter
199 if (!m_myFitter->SetLikelihood(m_likelihood.get())) {
200 ANA_MSG_ERROR("Failed to SetLikelihood for likelihood "
201 << m_LHType.value());
202 return StatusCode::FAILURE;
203 }
204
205 if (m_bTagDecoration.value().find("Continuous") != std::string::npos) {
206 ANA_MSG_ERROR("KLFitter cannot run using Continuous b-tag working point!");
207 return StatusCode::FAILURE;
208 }
209 m_bTagDecoAcc.emplace(m_bTagDecoration.value());
210
212 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
213 ANA_CHECK(m_btagging_eff_tool.retrieve());
214 // single-jet container reused to query the b-tagging efficiencies
215 m_effJets.setStore(&m_effJetsAux);
216 m_effJet = m_effJets.push_back(std::make_unique<xAOD::Jet>());
217 }
218
219 ANA_MSG_INFO("++++++++++++++++++++++++++++++");
220 ANA_MSG_INFO("Configured KLFitter with name " << name());
221 ANA_MSG_INFO(" Using " << m_btagging_eff_tool);
222 ANA_MSG_INFO(" Using transfer functions with full path "
223 << transferFunctionAbsPath);
224 ANA_MSG_INFO(" Using Lepton \t\t" << m_leptonType.value());
225 ANA_MSG_INFO(" Using JetSelectionMode \t" << m_jetSelectionMode.value());
226 ANA_MSG_INFO(" Using BTaggingMethod \t" << m_bTaggingMethod.value());
227 ANA_MSG_INFO(" Using TopMassFixed \t" << m_fixedTopMass);
228
230 ANA_MSG_INFO(" Saving All permutations");
231 else
233 " Saving only the permutation with the highest event probability");
234 ANA_MSG_INFO("++++++++++++++++++++++++++++++");
235
236 return StatusCode::SUCCESS;
237}
238
239StatusCode RunKLFitterAlg::execute(const EventContext& ctx) {
240 for (const auto &sys : m_systematicsList.systematicsVector()) {
241 ANA_CHECK(execute_syst(sys, ctx));
242 }
243 return StatusCode::SUCCESS;
244}
245
247 const EventContext &ctx) {
248 // run KLFitter
249 // create an instance of the particles class filled with the particles to be
250 // fitted; here, you need to make sure that
251 // - the particles are in the range allowed by the transfer functions (eta and
252 // pt)
253 // - the energies and momenta are in GeV
254 // - be aware that *all* particles you're adding are considered in the fit
255 // (many particles lead to many permutations to be considered and hence a
256 // long running time and not necessarily good fitting results due to the
257 // many available permutations)
258 // the arguments taken by AddParticle() are
259 // - TLorentzVector of the physics 4-momentum
260 // - detector eta for the evaluation of the transfer functions (for muons:
261 // just use the physics eta)
262 // - type of particle
263 // - an optional name of the particle (pass empty string in case you don't
264 // want to give your particle a name)
265 // - index of the particle in your original collection (for convenience)
266 // - for jets:
267 // * bool isBtagged : mandatory only if you want to use b-tagging in the fit
268
269 // first figure out if this event even passes the selection in which we are to
270 // run this KLFitter instance
271 const xAOD::EventInfo *evtInfo = nullptr;
272 ANA_CHECK(m_eventInfoHandle.retrieve(evtInfo, sys, ctx));
273
274 if (!m_selection.getBool(*evtInfo, sys))
275 return StatusCode::SUCCESS;
276
277 const xAOD::ElectronContainer *electrons = nullptr;
278 ANA_CHECK(m_electronsHandle.retrieve(electrons, sys, ctx));
279 const xAOD::MuonContainer *muons = nullptr;
280 ANA_CHECK(m_muonsHandle.retrieve(muons, sys, ctx));
281 const xAOD::JetContainer *jets = nullptr;
282 ANA_CHECK(m_jetsHandle.retrieve(jets, sys, ctx));
283 const xAOD::MissingETContainer *met = nullptr;
284 ANA_CHECK(m_metHandle.retrieve(met, sys, ctx));
285
286 // perform selection of objects
287 auto myParticles = std::make_unique<KLFitter::Particles>();
288
289 std::vector<const xAOD::Electron *> selected_electrons;
290 std::vector<const xAOD::Muon *> selected_muons;
291 std::vector<const xAOD::Jet *> selected_jets;
292
293 // select particles
294 for (const xAOD::Electron *el : *electrons) {
295 if (m_electronSelection.getBool(*el, sys))
296 selected_electrons.push_back(el);
297 }
298
299 for (const xAOD::Muon *mu : *muons) {
300 if (m_muonSelection.getBool(*mu, sys))
301 selected_muons.push_back(mu);
302 }
303
304 for (const xAOD::Jet *jet : *jets) {
305 if (m_jetSelection.getBool(*jet, sys))
306 selected_jets.push_back(jet);
307 }
308
309 std::vector<size_t> electron_indices;
310 const std::vector<const xAOD::Electron *> selected_sorted_electrons =
311 sortPt(selected_electrons, electron_indices);
312 std::vector<size_t> muon_indices;
313 const std::vector<const xAOD::Muon *> selected_sorted_muons =
314 sortPt(selected_muons, muon_indices);
315 std::vector<size_t> jet_indices;
316 const std::vector<const xAOD::Jet *> selected_sorted_jets =
317 sortPt(selected_jets, jet_indices);
318
319 // add leptons to KLFitter particles (not for ttbar all hadronic)
321 ANA_CHECK(add_leptons(selected_sorted_electrons, selected_sorted_muons,
322 myParticles.get()));
323
324 // add jets to KLFitter particles
325 ANA_CHECK(add_jets(selected_sorted_jets, myParticles.get()));
326
327 // add the particles to the fitter itself
328 if (!m_myFitter->SetParticles(myParticles.get())) {
329 ANA_MSG_ERROR("Error adding particles to KLFitter");
330 return StatusCode::FAILURE;
331 }
332
333 // add MET
334 auto *met_finalTrk = (*met)[m_METterm.value()];
335 if (!met_finalTrk) {
336 ANA_MSG_ERROR("RunKLFitterAlg: Error retrieving MET term "
337 << m_METterm.value());
338 return StatusCode::FAILURE;
339 }
340 if (!m_myFitter->SetET_miss_XY_SumET(met_finalTrk->mpx() / 1.e3,
341 met_finalTrk->mpy() / 1.e3,
342 met_finalTrk->sumet())) {
343 ANA_MSG_ERROR("Error adding MET term to KLFitter");
344 return StatusCode::FAILURE;
345 }
346
347 ANA_CHECK(evaluatePermutations(sys, ctx, electron_indices, muon_indices,
348 jet_indices));
349
350 return StatusCode::SUCCESS;
351}
352
354 const std::vector<const xAOD::Electron *> &selected_electrons,
355 const std::vector<const xAOD::Muon *> &selected_muons,
356 KLFitter::Particles *myParticles) {
357 // likelihoods with single lepton (either l+jets or ttZ 3lepton mixed lepton
358 // flavour)
360 // for the lep+jets channel, we assume that your leading-pT lepton is the
361 // only selected lepton
362 TLorentzVector el;
363 if (selected_electrons.size() == 0) {
365 "For single-lepton kElectron KLFitter likelihoods, at least one "
366 "electron is required");
367 return StatusCode::FAILURE;
368 }
369 const xAOD::Electron *xaod_el = selected_electrons.at(0);
370 if (!xaod_el->caloCluster()) {
371 ANA_MSG_ERROR("Selected electron has no associated calo cluster");
372 return StatusCode::FAILURE;
373 }
374 el.SetPtEtaPhiE(xaod_el->pt() / 1.e3, xaod_el->eta(), xaod_el->phi(),
375 xaod_el->e() / 1.e3);
376 myParticles->AddParticle(&el, xaod_el->caloCluster()->etaBE(2),
377 KLFitter::Particles::kElectron);
379 TLorentzVector mu;
380 if (selected_muons.size() == 0) {
382 "For single-lepton kMuon KLFitter likelihoods, at least one muon is "
383 "required");
384 return StatusCode::FAILURE;
385 }
386 const xAOD::Muon *xaod_mu = selected_muons.at(0);
387 mu.SetPtEtaPhiE(xaod_mu->pt() / 1.e3, xaod_mu->eta(), xaod_mu->phi(),
388 xaod_mu->e() / 1.e3);
389 myParticles->AddParticle(&mu, mu.Eta(), KLFitter::Particles::kMuon);
390 } else if (m_leptonTypeEnum ==
392 if (selected_electrons.size() < 3) {
394 "For tri-lepton kTriElectron KLFitter likelihoods, at least 3 "
395 "electrons are required");
396 return StatusCode::FAILURE;
397 }
398 TLorentzVector el;
399 for (size_t i = 0; i < 3; ++i) {
400 const xAOD::Electron *electron = selected_electrons.at(i);
401 if (!electron->caloCluster()) {
402 ANA_MSG_ERROR("Selected electron has no associated calo cluster");
403 return StatusCode::FAILURE;
404 }
405 el.SetPtEtaPhiE(electron->pt() / 1.e3, electron->eta(), electron->phi(),
406 electron->e() / 1.e3);
407 myParticles->AddParticle(&el, electron->caloCluster()->etaBE(2),
408 KLFitter::Particles::kElectron, "", i);
409 }
410 } else if (m_leptonTypeEnum ==
411 KLFEnums::LeptonType::kTriMuon) { // ttZ trilep
412 if (selected_muons.size() < 3) {
414 "For tri-lepton kTriMuon KLFitter likelihoods, at least 3 muons are "
415 "required");
416 return StatusCode::FAILURE;
417 }
418 TLorentzVector mu;
419 for (size_t i = 0; i < 3; ++i) {
420 const xAOD::Muon *muon = selected_muons.at(i);
421 mu.SetPtEtaPhiE(muon->pt() / 1.e3, muon->eta(), muon->phi(),
422 muon->e() / 1.e3);
423 myParticles->AddParticle(&mu, mu.Eta(), KLFitter::Particles::kMuon, "",
424 i);
425 }
426 }
427 return StatusCode::SUCCESS;
428}
429
430StatusCode RunKLFitterAlg::add_jets(const std::vector<const xAOD::Jet *> &jets,
431 KLFitter::Particles *myParticles) {
432 if (m_useBtagPriority) {
434 } else {
435 ANA_CHECK(setJetskLeadingN(jets, myParticles, m_njetsRequirement));
436 }
437 return StatusCode::SUCCESS;
438}
439
441 const std::vector<const xAOD::Jet *> &jets,
442 KLFitter::Particles *inputParticles, size_t njets) {
443
444 // If container has less jets than required, raise error
446 if (jets.size() < njets) {
447 ANA_MSG_ERROR("KLFitterTool::setJetskLeadingX: You required "
448 << njets << " jets. Event has " << jets.size() << " jets!");
449 return StatusCode::FAILURE;
450 }
451 }
452
453 size_t index(0);
454
455 for (const xAOD::Jet *jet : jets) {
456 if (index >= njets)
457 break;
458
459 bool isTagged(false);
460 ANA_CHECK(getBTagDecision(*jet, isTagged));
461 ANA_CHECK(addJet(jet, index, isTagged, inputParticles));
462 ++index;
463 }
464 return StatusCode::SUCCESS;
465}
466
468 bool &isTagged) const {
469 if (!m_bTagDecoAcc->isAvailable(jet)) {
470 ANA_MSG_ERROR("RunKLFitterAlg: jet does not have "
471 << m_bTagDecoration.value() << " aux variable!");
472 return StatusCode::FAILURE;
473 }
474 isTagged = (*m_bTagDecoAcc)(jet);
475 return StatusCode::SUCCESS;
476}
477
478StatusCode RunKLFitterAlg::addJet(const xAOD::Jet *jet, const size_t index,
479 const bool isTagged,
480 KLFitter::Particles *inputParticles) {
481 TLorentzVector jet_p4;
482 jet_p4.SetPtEtaPhiE(jet->pt() / 1.e3, jet->eta(), jet->phi(),
483 jet->e() / 1.e3);
484
486 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
487 float eff(0), ineff(0);
488 ANA_CHECK(retrieveEfficiencies(jet, &eff, &ineff));
489
490 static const float minIneff = 1e-6;
491 if (ineff < minIneff) {
492 ANA_MSG_WARNING("RunKLFitterAlg: light-jet mistag inefficiency "
493 << ineff << " below minimum " << minIneff
494 << ", clamping rejection weight");
495 }
496 inputParticles->AddParticle(&jet_p4, jet_p4.Eta(),
497 KLFitter::Particles::kParton, "", index,
498 isTagged, eff, 1. / std::max(ineff, minIneff),
499 KLFitter::Particles::kNone);
500 } else {
501 inputParticles->AddParticle(&jet_p4, jet_p4.Eta(),
502 KLFitter::Particles::kParton, "", index,
503 isTagged);
504 }
505 return StatusCode::SUCCESS;
506}
507
509 float *eff, float *ineff) {
510 // need to make a copy of the jet, so that we can manipulate its flavour to
511 // get the various efficiencies
512 xAOD::Jet *jet_copy = m_effJet;
513 *jet_copy = *jet;
514 jet_copy->setJetP4(jet->jetP4());
515 // treat jet as b-tagged
516 jet_copy->setAttribute("HadronConeExclTruthLabelID", 5);
517 ANA_CHECK(m_btagging_eff_tool->getMCEfficiency(*jet_copy, *eff));
518 // treat jet as light
519 jet_copy->setAttribute("HadronConeExclTruthLabelID", 0);
520 ANA_CHECK(m_btagging_eff_tool->getMCEfficiency(*jet_copy, *ineff));
521 return StatusCode::SUCCESS;
522}
523
525 const std::vector<const xAOD::Jet *> &jets,
526 KLFitter::Particles *inputParticles, const size_t maxJets) {
527 // kBtagPriority mode first adds the b jets, then the light jets
528 // If your 6th or 7th jet is a b jet, then you probably want this option
529
530 // If container has less jets than required, raise error
532 if (jets.size() < maxJets) {
533 ANA_MSG_ERROR("KLFitterTool::setJetskBtagPriority: You required "
534 << maxJets << " jets. Event has " << jets.size()
535 << " jets!");
536 return StatusCode::FAILURE;
537 }
538 }
539
540 unsigned int totalJets(0);
541
542 // First find the b-jets
543 unsigned int index(0);
544 for (const xAOD::Jet *jet : jets) {
545 if (totalJets >= maxJets)
546 break;
547
548 bool isTagged(false);
549 ANA_CHECK(getBTagDecision(*jet, isTagged));
550 if (isTagged) {
551 ANA_CHECK(addJet(jet, index, true, inputParticles));
552 ++totalJets;
553 } // is b-tagged
554
555 ++index;
556 } // for (jet)
557
558 // Second, find the light jets
559 index = 0;
560 for (const xAOD::Jet *jet : jets) {
561 if (totalJets >= maxJets)
562 break;
563
564 bool isTagged(false);
565 ANA_CHECK(getBTagDecision(*jet, isTagged));
566 if (!isTagged) {
567 ANA_CHECK(addJet(jet, index, false, inputParticles));
568 ++totalJets;
569 } // not-btagged jet
570
571 ++index;
572 } // for (jet)
573 return StatusCode::SUCCESS;
574}
575
577 const CP::SystematicSet &sys, const EventContext &ctx,
578 const std::vector<size_t> &electron_indices,
579 const std::vector<size_t> &muon_indices,
580 const std::vector<size_t> &jet_indices) {
581 // create or retrieve (if existent) the xAOD::KLFitterResultContainer
582 auto resultAuxContainer =
583 std::make_unique<xAOD::KLFitterResultAuxContainer>();
584 auto resultContainer = std::make_unique<xAOD::KLFitterResultContainer>();
585 resultContainer->setStore(resultAuxContainer.get());
586
587 // Set name hash. This is because it seems std::string is not supported by
588 // AuxContainers...
589 const size_t selectionCode = std::hash<std::string>{}(sys.name());
590
591 // loop over all permutations
592 const int nperm = m_myFitter->Permutations()->NPermutations();
593 for (int iperm = 0; iperm < nperm; ++iperm) {
594 // Perform the fit
595 m_myFitter->Fit(iperm);
596 // create a result
597 xAOD::KLFitterResult *result =
598 resultContainer->push_back(std::make_unique<xAOD::KLFitterResult>());
599
600 result->setSelectionCode(selectionCode);
601
602 unsigned int ConvergenceStatusBitWord = m_myFitter->ConvergenceStatus();
603 bool MinuitDidNotConverge =
604 (ConvergenceStatusBitWord & m_myFitter->MinuitDidNotConvergeMask) != 0;
605 bool FitAbortedDueToNaN =
606 (ConvergenceStatusBitWord & m_myFitter->FitAbortedDueToNaNMask) != 0;
607 bool AtLeastOneFitParameterAtItsLimit =
608 (ConvergenceStatusBitWord &
609 m_myFitter->AtLeastOneFitParameterAtItsLimitMask) != 0;
610 bool InvalidTransferFunctionAtConvergence =
611 (ConvergenceStatusBitWord &
612 m_myFitter->InvalidTransferFunctionAtConvergenceMask) != 0;
613
614 result->setMinuitDidNotConverge(((MinuitDidNotConverge) ? 1 : 0));
615 result->setFitAbortedDueToNaN(((FitAbortedDueToNaN) ? 1 : 0));
616 result->setAtLeastOneFitParameterAtItsLimit(
617 ((AtLeastOneFitParameterAtItsLimit) ? 1 : 0));
618 result->setInvalidTransferFunctionAtConvergence(
619 ((InvalidTransferFunctionAtConvergence) ? 1 : 0));
620
621 result->setLogLikelihood(m_myFitter->Likelihood()->LogLikelihood(
622 m_myFitter->Likelihood()->GetBestFitParameters()));
623 result->setEventProbability(
624 std::exp(m_myFitter->Likelihood()->LogEventProbability()));
625 result->setParameters(m_myFitter->Likelihood()->GetBestFitParameters());
626 result->setParameterErrors(
627 m_myFitter->Likelihood()->GetBestFitParameterErrors());
628
629 KLFitter::Particles *myModelParticles =
630 m_myFitter->Likelihood()->ParticlesModel();
631 KLFitter::Particles **myPermutedParticles =
632 m_myFitter->Likelihood()->PParticlesPermuted();
633
640 result->setModel_bhad_pt(myModelParticles->Parton(0)->Pt());
641 result->setModel_bhad_eta(myModelParticles->Parton(0)->Eta());
642 result->setModel_bhad_phi(myModelParticles->Parton(0)->Phi());
643 result->setModel_bhad_E(myModelParticles->Parton(0)->E());
644 result->setModel_bhad_jetIndex(
645 jet_indices.at((*myPermutedParticles)->JetIndex(0)));
646
647 result->setModel_blep_pt(myModelParticles->Parton(1)->Pt());
648 result->setModel_blep_eta(myModelParticles->Parton(1)->Eta());
649 result->setModel_blep_phi(myModelParticles->Parton(1)->Phi());
650 result->setModel_blep_E(myModelParticles->Parton(1)->E());
651 result->setModel_blep_jetIndex(
652 jet_indices.at((*myPermutedParticles)->JetIndex(1)));
653
654 result->setModel_lq1_pt(myModelParticles->Parton(2)->Pt());
655 result->setModel_lq1_eta(myModelParticles->Parton(2)->Eta());
656 result->setModel_lq1_phi(myModelParticles->Parton(2)->Phi());
657 result->setModel_lq1_E(myModelParticles->Parton(2)->E());
658 result->setModel_lq1_jetIndex(
659 jet_indices.at((*myPermutedParticles)->JetIndex(2)));
660
661 // boosted likelihood has only one light jet
663 result->setModel_lq2_pt(myModelParticles->Parton(3)->Pt());
664 result->setModel_lq2_eta(myModelParticles->Parton(3)->Eta());
665 result->setModel_lq2_phi(myModelParticles->Parton(3)->Phi());
666 result->setModel_lq2_E(myModelParticles->Parton(3)->E());
667 result->setModel_lq2_jetIndex(
668 jet_indices.at((*myPermutedParticles)->JetIndex(3)));
669
671 result->setModel_Higgs_b1_pt(myModelParticles->Parton(4)->Pt());
672 result->setModel_Higgs_b1_eta(myModelParticles->Parton(4)->Eta());
673 result->setModel_Higgs_b1_phi(myModelParticles->Parton(4)->Phi());
674 result->setModel_Higgs_b1_E(myModelParticles->Parton(4)->E());
675 result->setModel_Higgs_b1_jetIndex(
676 jet_indices.at((*myPermutedParticles)->JetIndex(4)));
677
678 result->setModel_Higgs_b2_pt(myModelParticles->Parton(5)->Pt());
679 result->setModel_Higgs_b2_eta(myModelParticles->Parton(5)->Eta());
680 result->setModel_Higgs_b2_phi(myModelParticles->Parton(5)->Phi());
681 result->setModel_Higgs_b2_E(myModelParticles->Parton(5)->E());
682 result->setModel_Higgs_b2_jetIndex(
683 jet_indices.at((*myPermutedParticles)->JetIndex(5)));
684 }
685 }
686
689 result->setModel_lep_pt(myModelParticles->Electron(0)->Pt());
690 result->setModel_lep_eta(myModelParticles->Electron(0)->Eta());
691 result->setModel_lep_phi(myModelParticles->Electron(0)->Phi());
692 result->setModel_lep_E(myModelParticles->Electron(0)->E());
693
695 result->setModel_lep_index(
696 electron_indices.at((*myPermutedParticles)->ElectronIndex(0)));
697
698 result->setModel_lepZ1_pt(myModelParticles->Electron(1)->Pt());
699 result->setModel_lepZ1_eta(myModelParticles->Electron(1)->Eta());
700 result->setModel_lepZ1_phi(myModelParticles->Electron(1)->Phi());
701 result->setModel_lepZ1_E(myModelParticles->Electron(1)->E());
702 result->setModel_lepZ1_index(
703 electron_indices.at((*myPermutedParticles)->ElectronIndex(1)));
704
705 result->setModel_lepZ2_pt(myModelParticles->Electron(2)->Pt());
706 result->setModel_lepZ2_eta(myModelParticles->Electron(2)->Eta());
707 result->setModel_lepZ2_phi(myModelParticles->Electron(2)->Phi());
708 result->setModel_lepZ2_E(myModelParticles->Electron(2)->E());
709 result->setModel_lepZ2_index(
710 electron_indices.at((*myPermutedParticles)->ElectronIndex(2)));
711 }
712 }
713
716 result->setModel_lep_pt(myModelParticles->Muon(0)->Pt());
717 result->setModel_lep_eta(myModelParticles->Muon(0)->Eta());
718 result->setModel_lep_phi(myModelParticles->Muon(0)->Phi());
719 result->setModel_lep_E(myModelParticles->Muon(0)->E());
720
722 result->setModel_lep_index(
723 muon_indices.at((*myPermutedParticles)->MuonIndex(0)));
724
725 result->setModel_lepZ1_pt(myModelParticles->Muon(1)->Pt());
726 result->setModel_lepZ1_eta(myModelParticles->Muon(1)->Eta());
727 result->setModel_lepZ1_phi(myModelParticles->Muon(1)->Phi());
728 result->setModel_lepZ1_E(myModelParticles->Muon(1)->E());
729 result->setModel_lepZ1_index(
730 muon_indices.at((*myPermutedParticles)->MuonIndex(1)));
731
732 result->setModel_lepZ2_pt(myModelParticles->Muon(2)->Pt());
733 result->setModel_lepZ2_eta(myModelParticles->Muon(2)->Eta());
734 result->setModel_lepZ2_phi(myModelParticles->Muon(2)->Phi());
735 result->setModel_lepZ2_E(myModelParticles->Muon(2)->E());
736 result->setModel_lepZ2_index(
737 muon_indices.at((*myPermutedParticles)->MuonIndex(2)));
738 }
739 }
740
741 result->setModel_nu_pt(myModelParticles->Neutrino(0)->Pt());
742 result->setModel_nu_eta(myModelParticles->Neutrino(0)->Eta());
743 result->setModel_nu_phi(myModelParticles->Neutrino(0)->Phi());
744 result->setModel_nu_E(myModelParticles->Neutrino(0)->E());
746 result->setModel_b_from_top1_pt(myModelParticles->Parton(0)->Pt());
747 result->setModel_b_from_top1_eta(myModelParticles->Parton(0)->Eta());
748 result->setModel_b_from_top1_phi(myModelParticles->Parton(0)->Phi());
749 result->setModel_b_from_top1_E(myModelParticles->Parton(0)->E());
750 result->setModel_b_from_top1_jetIndex(
751 jet_indices.at((*myPermutedParticles)->JetIndex(0)));
752
753 result->setModel_b_from_top2_pt(myModelParticles->Parton(1)->Pt());
754 result->setModel_b_from_top2_eta(myModelParticles->Parton(1)->Eta());
755 result->setModel_b_from_top2_phi(myModelParticles->Parton(1)->Phi());
756 result->setModel_b_from_top2_E(myModelParticles->Parton(1)->E());
757 result->setModel_b_from_top2_jetIndex(
758 jet_indices.at((*myPermutedParticles)->JetIndex(1)));
759
760 result->setModel_lj1_from_top1_pt(myModelParticles->Parton(2)->Pt());
761 result->setModel_lj1_from_top1_eta(myModelParticles->Parton(2)->Eta());
762 result->setModel_lj1_from_top1_phi(myModelParticles->Parton(2)->Phi());
763 result->setModel_lj1_from_top1_E(myModelParticles->Parton(2)->E());
764 result->setModel_lj1_from_top1_jetIndex(
765 jet_indices.at((*myPermutedParticles)->JetIndex(2)));
766
767 result->setModel_lj2_from_top1_pt(myModelParticles->Parton(3)->Pt());
768 result->setModel_lj2_from_top1_eta(myModelParticles->Parton(3)->Eta());
769 result->setModel_lj2_from_top1_phi(myModelParticles->Parton(3)->Phi());
770 result->setModel_lj2_from_top1_E(myModelParticles->Parton(3)->E());
771 result->setModel_lj2_from_top1_jetIndex(
772 jet_indices.at((*myPermutedParticles)->JetIndex(3)));
773
774 result->setModel_lj1_from_top2_pt(myModelParticles->Parton(4)->Pt());
775 result->setModel_lj1_from_top2_eta(myModelParticles->Parton(4)->Eta());
776 result->setModel_lj1_from_top2_phi(myModelParticles->Parton(4)->Phi());
777 result->setModel_lj1_from_top2_E(myModelParticles->Parton(4)->E());
778 result->setModel_lj1_from_top2_jetIndex(
779 jet_indices.at((*myPermutedParticles)->JetIndex(4)));
780
781 result->setModel_lj2_from_top2_pt(myModelParticles->Parton(5)->Pt());
782 result->setModel_lj2_from_top2_eta(myModelParticles->Parton(5)->Eta());
783 result->setModel_lj2_from_top2_phi(myModelParticles->Parton(5)->Phi());
784 result->setModel_lj2_from_top2_E(myModelParticles->Parton(5)->E());
785 result->setModel_lj2_from_top2_jetIndex(
786 jet_indices.at((*myPermutedParticles)->JetIndex(5)));
787 }
788 } // Loop over permutations
789
790 // Normalize event probability to unity
791 // work out best permutation
792 float sumEventProbability(0.), bestEventProbability(0.);
793 std::optional<size_t> bestPermutation;
794 size_t iPerm(0);
795
796 // First loop
797 for (auto x : *resultContainer) {
798 float prob = x->eventProbability();
799 short minuitDidNotConverge = x->minuitDidNotConverge();
800 short fitAbortedDueToNaN = x->fitAbortedDueToNaN();
801 short atLeastOneFitParameterAtItsLimit =
802 x->atLeastOneFitParameterAtItsLimit();
803 short invalidTransferFunctionAtConvergence =
804 x->invalidTransferFunctionAtConvergence();
805 sumEventProbability += prob;
806 ++iPerm;
807
808 // check if the best value has the highest event probability AND converged
809 if (minuitDidNotConverge)
810 continue;
811 if (fitAbortedDueToNaN)
812 continue;
813 if (atLeastOneFitParameterAtItsLimit)
814 continue;
815 if (invalidTransferFunctionAtConvergence)
816 continue;
817
818 if (prob > bestEventProbability) {
819 bestEventProbability = prob;
820 // Using iPerm -1 because it has already been incremented before
821 bestPermutation = iPerm - 1;
822 }
823 }
824
825 if (!bestPermutation) {
826 ANA_MSG_DEBUG("No KLFitter permutation passed the convergence criteria");
827 }
828 if (!resultContainer->empty() && sumEventProbability == 0.) {
830 "Sum of KLFitter event probabilities is zero, event probabilities are "
831 "not normalized");
832 }
833
834 // Second loop
835 iPerm = 0;
836 for (auto x : *resultContainer) {
837 if (sumEventProbability != 0.)
838 x->setEventProbability(x->eventProbability() / sumEventProbability);
839 if (bestPermutation && iPerm == *bestPermutation) {
840 x->setBestPermutation(1);
841 } else {
842 x->setBestPermutation(0);
843 }
844 ++iPerm;
845 }
846
847 // Save all permutations
849 ANA_CHECK(m_outHandle.record(std::move(resultContainer),
850 std::move(resultAuxContainer), sys, ctx));
851 } else { // Save only the best permutation
852 // create or retrieve the xAOD::KLFitterResultContainer
853 auto bestContainer = std::make_unique<xAOD::KLFitterResultContainer>();
854 auto bestAuxContainer =
855 std::make_unique<xAOD::KLFitterResultAuxContainer>();
856 bestContainer->setStore(bestAuxContainer.get());
857
858 for (auto x : *resultContainer) {
859 if (x->bestPermutation() == 1) {
860 auto result = std::make_unique<xAOD::KLFitterResult>();
861 result->makePrivateStore(*x);
862 bestContainer->push_back(std::move(result));
863 }
864 }
865 ANA_CHECK(m_outHandle.record(std::move(bestContainer),
866 std::move(bestAuxContainer), sys, ctx));
867 }
868
869 return StatusCode::SUCCESS;
870}
871
872} // namespace EventReco
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
#define ANA_MSG_WARNING(xmsg,...)
Macro printing warning messages.
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
#define x
Class to wrap a set of SystematicVariations.
virtual::StatusCode execute()
execute this algorithm
std::optional< SG::ConstAccessor< char > > m_bTagDecoAcc
CP::SysWriteHandle< xAOD::KLFitterResultContainer, xAOD::KLFitterResultAuxContainer > m_outHandle
virtual StatusCode initialize() final
StatusCode retrieveEfficiencies(const xAOD::Jet *jet, float *eff, float *ineff)
StatusCode addJet(const xAOD::Jet *jet, const size_t index, const bool isTagged, KLFitter::Particles *inputParticles)
CP::SysReadHandle< xAOD::EventInfo > m_eventInfoHandle
Gaudi::Property< std::string > m_transferFunctionsPath
StatusCode setJetskLeadingN(const std::vector< const xAOD::Jet * > &jets, KLFitter::Particles *inputParticles, const size_t njets)
CP::SysListHandle m_systematicsList
std::unique_ptr< KLFitter::DetectorAtlas_8TeV > m_myDetector
CP::SysReadSelectionHandle m_muonSelection
StatusCode evaluatePermutations(const CP::SystematicSet &sys, const EventContext &ctx, const std::vector< size_t > &electron_indices, const std::vector< size_t > &muon_indices, const std::vector< size_t > &jet_indices)
CP::SysReadHandle< xAOD::ElectronContainer > m_electronsHandle
KLFEnums::JetSelectionMode m_jetSelectionModeEnum
KLFEnums::LeptonType m_leptonTypeEnum
std::vector< const T * > sortPt(const std::vector< const T * > &particles, std::vector< size_t > &indices)
Gaudi::Property< bool > m_fixedTopMass
CP::SysReadHandle< xAOD::JetContainer > m_jetsHandle
Gaudi::Property< std::string > m_leptonType
xAOD::JetContainer m_effJets
StatusCode getBTagDecision(const xAOD::Jet &jet, bool &isTagged) const
Gaudi::Property< std::string > m_bTaggingMethod
StatusCode add_leptons(const std::vector< const xAOD::Electron * > &selected_electrons, const std::vector< const xAOD::Muon * > &selected_muons, KLFitter::Particles *myParticles)
Gaudi::Property< bool > m_saveAllPermutations
Gaudi::Property< std::string > m_METterm
CP::SysReadHandle< xAOD::MissingETContainer > m_metHandle
KLFEnums::Likelihood m_LHTypeEnum
CP::SysReadSelectionHandle m_selection
KLFitter::LikelihoodBase::BtaggingMethod m_bTaggingMethodEnum
ToolHandle< IBTaggingEfficiencyTool > m_btagging_eff_tool
Gaudi::Property< std::string > m_bTagDecoration
std::unique_ptr< KLFitter::LikelihoodBase > m_likelihood
xAOD::JetAuxContainer m_effJetsAux
StatusCode setJetskBtagPriority(const std::vector< const xAOD::Jet * > &jets, KLFitter::Particles *inputParticles, const size_t maxJets)
CP::SysReadHandle< xAOD::MuonContainer > m_muonsHandle
Gaudi::Property< bool > m_failOnLessThanXJets
CP::SysReadSelectionHandle m_electronSelection
Gaudi::Property< std::string > m_jetSelectionMode
StatusCode add_jets(const std::vector< const xAOD::Jet * > &selected_jets, KLFitter::Particles *myParticles)
CP::SysReadSelectionHandle m_jetSelection
Gaudi::Property< std::string > m_LHType
StatusCode execute_syst(const CP::SystematicSet &sys, const EventContext &ctx)
std::unique_ptr< KLFitter::Fitter > m_myFitter
Gaudi::Property< float > m_massTop
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
virtual double e() const override
The total energy of the particle.
Definition Egamma_v1.cxx:86
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition Egamma_v1.cxx:71
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
Definition Egamma_v1.cxx:76
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
void setAttribute(const std::string &name, const T &v)
void setJetP4(const JetFourMom_t &p4)
Definition Jet_v1.cxx:182
KLFitterResult Auxiliary-store-backed xAOD object holding the result of one KLFitter permutation: fit...
virtual double pt() const override
The transverse momentum ( ) of the particle.
virtual double eta() const override
The pseudorapidity ( ) of the particle.
virtual double e() const override
The total energy of the particle.
Definition Muon_v1.cxx:62
virtual double phi() const override
The azimuthal angle ( ) of the particle.
std::string printEnumOptions(const std::map< std::string, T > &availOpts)
const std::map< std::string, LeptonType > strToLeptonType
const std::map< std::string, Likelihood > strToLikelihood
const std::map< std::string, JetSelectionMode > strToJetSelection
const std::map< std::string, LikelihoodBase::BtaggingMethod > strToBtagMethod
const std::map< JetSelectionMode, size_t > jetSelToNumber
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".