ATLAS Offline Software
Loading...
Searching...
No Matches
RunKLFitterAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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 try {
37 } catch (std::out_of_range &) {
38 ANA_MSG_ERROR("Unrecognized KLFitter likelihood: "
39 << m_LHType.value() << ". Available options: "
41 return StatusCode::FAILURE;
42 }
43
45 ANA_MSG_ERROR("The ttbar_JetAngles likelihood is currently not supported!");
46 return StatusCode::FAILURE;
47 }
48
49 // parse lepton type
50 try {
55 "If using ttbar_AllHad likelihood, please use leptonType = "
56 "kNoLepton.");
57 return StatusCode::FAILURE;
58 }
59 } catch (std::out_of_range &) {
60 ANA_MSG_ERROR("Unrecognized KLFitter leptonType: "
61 << m_leptonType.value() << ". Available options: "
63 return StatusCode::FAILURE;
64 }
65
66 // parse jet selection
67 try {
70 } catch (std::out_of_range &) {
71 ANA_MSG_ERROR("Unrecognized KLFitter JetSelectionMode: "
72 << m_jetSelectionMode.value() << ". Available options: "
74 return StatusCode::FAILURE;
75 }
76
78 m_useBtagPriority = true;
79 try {
81 } catch (std::out_of_range &) {
83 "Could not parse the number of required jets from KLFitter jet "
84 "selection mode: "
85 << m_jetSelectionMode.value());
86 return StatusCode::FAILURE;
87 }
88
89 // parse b-tagging method
90 try {
93 } catch (std::out_of_range &) {
94 ANA_MSG_ERROR("Unrecognized KLFitter BTaggingMethod: "
95 << m_bTaggingMethod.value() << ". Available options: "
97 return StatusCode::FAILURE;
98 }
99
100 // setup the KLFitter::Fitter instance
101 m_myFitter = std::make_unique<KLFitter::Fitter>();
102 const std::string transferFunctionAbsPath =
105 std::make_unique<KLFitter::DetectorAtlas_8TeV>(transferFunctionAbsPath);
106 if (!m_myFitter->SetDetector(m_myDetector.get())) {
108 "Failed to set KLFitter::Detector for KLFitter::Fitter instance.");
109 return StatusCode::FAILURE;
110 }
111
112 // create the likelihoods
113 m_myLikelihood = std::make_unique<KLFitter::LikelihoodTopLeptonJets>();
114 m_myLikelihood_TTH = std::make_unique<KLFitter::LikelihoodTTHLeptonJets>();
116 std::make_unique<KLFitter::LikelihoodTopLeptonJets_JetAngles>();
118 std::make_unique<KLFitter::LikelihoodTopLeptonJets_Angular>();
119 m_myLikelihood_TTZ = std::make_unique<KLFitter::LikelihoodTTZTrilepton>();
121 std::make_unique<KLFitter::LikelihoodTopAllHadronic>();
123 std::make_unique<KLFitter::BoostedLikelihoodTopLeptonJets>();
124
125 // SetleptonType
129 KLFitter::LikelihoodTopLeptonJets::LeptonType::kElectron;
131 KLFitter::LikelihoodTTHLeptonJets::LeptonType::kElectron;
133 KLFitter::LikelihoodTopLeptonJets_JetAngles::LeptonType::kElectron;
135 KLFitter::LikelihoodTopLeptonJets_Angular::LeptonType::kElectron;
137 KLFitter::LikelihoodTTZTrilepton::LeptonType::kElectron;
139 KLFitter::BoostedLikelihoodTopLeptonJets::LeptonType::kElectron;
142 KLFitter::LikelihoodTopLeptonJets::LeptonType::kMuon;
144 KLFitter::LikelihoodTTHLeptonJets::LeptonType::kMuon;
146 KLFitter::LikelihoodTopLeptonJets_JetAngles::LeptonType::kMuon;
148 KLFitter::LikelihoodTopLeptonJets_Angular::LeptonType::kMuon;
150 KLFitter::LikelihoodTTZTrilepton::LeptonType::kMuon;
152 KLFitter::BoostedLikelihoodTopLeptonJets::LeptonType::kMuon;
156 " LeptonType kTriElectron is only defined for the ttZTrilepton "
157 "likelihood");
158 return StatusCode::FAILURE;
159 }
161 KLFitter::LikelihoodTopLeptonJets::LeptonType::kElectron;
163 KLFitter::LikelihoodTTHLeptonJets::LeptonType::kElectron;
165 KLFitter::LikelihoodTopLeptonJets_JetAngles::LeptonType::kElectron;
167 KLFitter::LikelihoodTTZTrilepton::LeptonType::kElectron;
169 KLFitter::BoostedLikelihoodTopLeptonJets::LeptonType::kElectron;
173 " LeptonType kTriMuon is only defined for the ttZTrilepton "
174 "likelihood");
175 return StatusCode::FAILURE;
176 }
178 KLFitter::LikelihoodTopLeptonJets::LeptonType::kMuon;
180 KLFitter::LikelihoodTTHLeptonJets::LeptonType::kMuon;
182 KLFitter::LikelihoodTopLeptonJets_JetAngles::LeptonType::kMuon;
184 KLFitter::LikelihoodTTZTrilepton::LeptonType::kMuon;
186 KLFitter::BoostedLikelihoodTopLeptonJets::LeptonType::kMuon;
187 } else {
188 ANA_MSG_ERROR(" Please supply a valid LeptonType : kElectron or kMuon");
189 return StatusCode::FAILURE;
190 }
191
197 m_myLikelihood_BoostedLJets->SetLeptonType(
199 }
200
208 // set top mass
209 m_myLikelihood->PhysicsConstants()->SetMassTop(m_massTop);
210 m_myLikelihood_TTH->PhysicsConstants()->SetMassTop(m_massTop);
211 m_myLikelihood_JetAngles->PhysicsConstants()->SetMassTop(m_massTop);
212 m_myLikelihood_Angular->PhysicsConstants()->SetMassTop(m_massTop);
213 m_myLikelihood_TTZ->PhysicsConstants()->SetMassTop(m_massTop);
214 m_myLikelihood_AllHadronic->PhysicsConstants()->SetMassTop(m_massTop);
215 m_myLikelihood_BoostedLJets->PhysicsConstants()->SetMassTop(m_massTop);
216
217 // whether the top mass is fixed to the constant in likelihood or not
218 m_myLikelihood->SetFlagTopMassFixed(m_fixedTopMass);
219 m_myLikelihood_TTH->SetFlagTopMassFixed(m_fixedTopMass);
220 m_myLikelihood_JetAngles->SetFlagTopMassFixed(m_fixedTopMass);
221 m_myLikelihood_Angular->SetFlagTopMassFixed(m_fixedTopMass);
222 m_myLikelihood_TTZ->SetFlagTopMassFixed(m_fixedTopMass);
223 m_myLikelihood_AllHadronic->SetFlagTopMassFixed(m_fixedTopMass);
224 m_myLikelihood_BoostedLJets->SetFlagTopMassFixed(m_fixedTopMass);
225
226 // configure which likelihood to use in the fitter
227 int klfitter_returncode = 0;
229 klfitter_returncode = m_myFitter->SetLikelihood(m_myLikelihood.get());
231 klfitter_returncode = m_myFitter->SetLikelihood(m_myLikelihood_TTH.get());
233 klfitter_returncode =
234 m_myFitter->SetLikelihood(m_myLikelihood_JetAngles.get());
236 klfitter_returncode =
237 m_myFitter->SetLikelihood(m_myLikelihood_Angular.get());
241 // For ttZ->trilepton, we can have difficult combinations of leptons in the
242 // final state (3x same flavour, or mixed case). The latter is trivial, for
243 // which we can default back to the ljets likelihood. So we distinguish
244 // here:
245 // - kTriMuon, kTriElectron: dedicated TTZ->trilepton likelihood,
246 // - kMuon, kElectron: standard ttbar->l+jets likelihood.
247 klfitter_returncode = m_myFitter->SetLikelihood(m_myLikelihood_TTZ.get());
249 klfitter_returncode = m_myFitter->SetLikelihood(m_myLikelihood.get());
251 klfitter_returncode =
252 m_myFitter->SetLikelihood(m_myLikelihood_AllHadronic.get());
254 klfitter_returncode =
255 m_myFitter->SetLikelihood(m_myLikelihood_BoostedLJets.get());
256 } else {
257 ANA_MSG_ERROR("Unrecognized KLFitter likelihood: " << m_LHType.value());
258 return StatusCode::FAILURE;
259 }
260
261 if (!klfitter_returncode) {
262 ANA_MSG_ERROR("Failed to SetLikelihood for likelihood "
263 << m_LHType.value());
264 return StatusCode::FAILURE;
265 }
266
267 if (m_bTagDecoration.value().find("Continuous") != std::string::npos) {
268 ANA_MSG_ERROR("KLFitter cannot run using Continuous b-tag working point!");
269 return StatusCode::FAILURE;
270 }
271 m_bTagDecoAcc = std::make_unique<SG::ConstAccessor<char>>(
272 m_bTagDecoration.value());
273
275 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
276 ANA_CHECK(m_btagging_eff_tool.retrieve());
277 }
278
279 ANA_MSG_INFO("++++++++++++++++++++++++++++++");
280 ANA_MSG_INFO("Configured KLFitter with name " << name());
281 ANA_MSG_INFO(" Using " << m_btagging_eff_tool);
282 ANA_MSG_INFO(" Using transfer functions with full path "
283 << transferFunctionAbsPath);
284 ANA_MSG_INFO(" Using Lepton \t\t" << m_leptonType.value());
285 ANA_MSG_INFO(" Using JetSelectionMode \t" << m_jetSelectionMode.value());
286 ANA_MSG_INFO(" Using BTaggingMethod \t" << m_bTaggingMethod.value());
287 ANA_MSG_INFO(" Using TopMassFixed \t" << m_fixedTopMass);
288
290 ANA_MSG_INFO(" Saving All permutations");
291 else
293 " Saving only the permutation with the highest event probability");
294 ANA_MSG_INFO("++++++++++++++++++++++++++++++");
295
296 return StatusCode::SUCCESS;
297}
298
300 for (const auto &sys : m_systematicsList.systematicsVector()) {
302 }
303 return StatusCode::SUCCESS;
304}
305
307 // run KLFitter
308 // create an instance of the particles class filled with the particles to be
309 // fitted; here, you need to make sure that
310 // - the particles are in the range allowed by the transfer functions (eta and
311 // pt)
312 // - the energies and momenta are in GeV
313 // - be aware that *all* particles you're adding are considered in the fit
314 // (many particles lead to many permutations to be considered and hence a
315 // long running time and not necessarily good fitting results due to the
316 // many available permutations)
317 // the arguments taken py AddParticle() are
318 // - TLorentzVector of the physics 4-momentum
319 // - detector eta for the evaluation of the transfer functions (for muons:
320 // just use the physics eta)
321 // - type of particle
322 // - an optional name of the particle (pass empty string in case you don't
323 // want to give your particle a name)
324 // - index of the particle in your original collection (for convenience)
325 // - for jets:
326 // * bool isBtagged : mandatory only if you want to use b-tagging in the fit
327
328 // first figure out if this event even passes the selection in which we are to
329 // run this KLFitter instance
330 const xAOD::EventInfo *evtInfo = nullptr;
331 ANA_CHECK(m_eventInfoHandle.retrieve(evtInfo, sys));
332
333 if (!m_selection.getBool(*evtInfo, sys))
334 return StatusCode::SUCCESS;
335
336 const xAOD::ElectronContainer *electrons = nullptr;
337 ANA_CHECK(m_electronsHandle.retrieve(electrons, sys));
338 const xAOD::MuonContainer *muons = nullptr;
339 ANA_CHECK(m_muonsHandle.retrieve(muons, sys));
340 const xAOD::JetContainer *jets = nullptr;
341 ANA_CHECK(m_jetsHandle.retrieve(jets, sys));
342 const xAOD::MissingETContainer *met = nullptr;
343 ANA_CHECK(m_metHandle.retrieve(met, sys));
344
345 // perform selection of objects
346 KLFitter::Particles *myParticles = new KLFitter::Particles{};
347
348 std::vector<const xAOD::Electron *> selected_electrons;
349 std::vector<const xAOD::Muon *> selected_muons;
350 std::vector<const xAOD::Jet *> selected_jets;
351
352 // select particles
353 for (const xAOD::Electron *el : *electrons) {
354 if (m_electronSelection.getBool(*el, sys))
355 selected_electrons.push_back(el);
356 }
357
358 for (const xAOD::Muon *mu : *muons) {
359 if (m_muonSelection.getBool(*mu, sys))
360 selected_muons.push_back(mu);
361 }
362
363 for (const xAOD::Jet *jet : *jets) {
364 if (m_jetSelection.getBool(*jet, sys))
365 selected_jets.push_back(jet);
366 }
367
368 std::vector<size_t> electron_indices;
369 const std::vector<const xAOD::Electron *> selected_sorted_electrons =
370 sortPt(selected_electrons, electron_indices);
371 std::vector<size_t> muon_indices;
372 const std::vector<const xAOD::Muon *> selected_sorted_muons =
373 sortPt(selected_muons, muon_indices);
374 std::vector<size_t> jet_indices;
375 const std::vector<const xAOD::Jet *> selected_sorted_jets =
376 sortPt(selected_jets, jet_indices);
377
378 // add leptons to KLFitter particles (not for ttbar all hadronic)
380 ANA_CHECK(add_leptons(selected_sorted_electrons, selected_sorted_muons,
381 myParticles));
382
383 // add jets to KLFitter particles
384 ANA_CHECK(add_jets(selected_sorted_jets, myParticles));
385
386 // add the particles to the fitter itself
387 if (!m_myFitter->SetParticles(myParticles)) {
388 ANA_MSG_ERROR("Error adding particles to KLFitter");
389 return StatusCode::FAILURE;
390 }
391
392 // add MET
393 auto *met_finalTrk = (*met)[m_METterm.value()];
394 if (!met_finalTrk) {
395 ANA_MSG_ERROR("RunKLFitterAlg: Error retrieving MET term "
396 << m_METterm.value());
397 return StatusCode::FAILURE;
398 }
399 if (!m_myFitter->SetET_miss_XY_SumET(met_finalTrk->mpx() / 1.e3,
400 met_finalTrk->mpy() / 1.e3,
401 met_finalTrk->sumet())) {
402 ANA_MSG_ERROR("Error adding MET term to KLFitter");
403 return StatusCode::FAILURE;
404 }
405
406 ANA_CHECK(
407 evaluatePermutations(sys, electron_indices, muon_indices, jet_indices));
408
409 delete myParticles;
410
411 return StatusCode::SUCCESS;
412}
413
415 const std::vector<const xAOD::Electron *> &selected_electrons,
416 const std::vector<const xAOD::Muon *> &selected_muons,
417 KLFitter::Particles *myParticles) {
418 // likelihoods with single lepton (either l+jets or ttZ 3lepton mixed lepton
419 // flavour)
421 // for the lep+jets channel, we assume that your leading-pT lepton is the
422 // only selected lepton
423 TLorentzVector el;
424 if (selected_electrons.size() == 0) {
426 "For single-lepton kElectron KLFitter likelihoods, at least one "
427 "electron is required");
428 return StatusCode::FAILURE;
429 }
430 const xAOD::Electron *xaod_el = selected_electrons.at(0);
431 el.SetPtEtaPhiE(xaod_el->pt() / 1.e3, xaod_el->eta(), xaod_el->phi(),
432 xaod_el->e() / 1.e3);
433 myParticles->AddParticle(&el, xaod_el->caloCluster()->etaBE(2),
434 KLFitter::Particles::kElectron);
436 TLorentzVector mu;
437 if (selected_muons.size() == 0) {
439 "For single-lepton kMuon KLFitter likelihoods, at least one muon is "
440 "required");
441 return StatusCode::FAILURE;
442 }
443 const xAOD::Muon *xaod_mu = selected_muons.at(0);
444 mu.SetPtEtaPhiE(xaod_mu->pt() / 1.e3, xaod_mu->eta(), xaod_mu->phi(),
445 xaod_mu->e() / 1.e3);
446 myParticles->AddParticle(&mu, mu.Eta(), KLFitter::Particles::kMuon);
447 } else if (m_leptonTypeEnum ==
449 if (selected_electrons.size() < 3) {
451 "For tri-lepton kTriElectron KLFitter likelihoods, at least 3 "
452 "electrons are required");
453 return StatusCode::FAILURE;
454 }
455 TLorentzVector el;
456 for (size_t i = 0; i < 3; ++i) {
457 const xAOD::Electron *electron = selected_electrons.at(i);
458 el.SetPtEtaPhiE(electron->pt() / 1.e3, electron->eta(), electron->phi(),
459 electron->e() / 1.e3);
460 myParticles->AddParticle(&el, electron->caloCluster()->etaBE(2),
461 KLFitter::Particles::kElectron, "", i);
462 }
463 } else if (m_leptonTypeEnum ==
464 KLFEnums::LeptonType::kTriMuon) { // ttZ trilep
465 if (selected_muons.size() < 3) {
467 "For tr-lepton kTriMuons KLFitter likelihoods, at least 3 muons are "
468 "required");
469 return StatusCode::FAILURE;
470 }
471 TLorentzVector mu;
472 for (size_t i = 0; i < 3; ++i) {
473 const xAOD::Muon *muon = selected_muons.at(i);
474 mu.SetPtEtaPhiE(muon->pt() / 1.e3, muon->eta(), muon->phi(),
475 muon->e() / 1.e3);
476 myParticles->AddParticle(&mu, mu.Eta(), KLFitter::Particles::kMuon, "",
477 i);
478 }
479 }
480 return StatusCode::SUCCESS;
481}
482
483StatusCode RunKLFitterAlg::add_jets(const std::vector<const xAOD::Jet *> &jets,
484 KLFitter::Particles *myParticles) {
485 if (m_useBtagPriority) {
487 } else {
488 ANA_CHECK(setJetskLeadingN(jets, myParticles, m_njetsRequirement));
489 }
490 return StatusCode::SUCCESS;
491}
492
494 const std::vector<const xAOD::Jet *> &jets,
495 KLFitter::Particles *inputParticles, size_t njets) {
496
497 // If container has less jets than required, raise error
499 if (jets.size() < njets) {
500 ANA_MSG_ERROR("KLFitterTool::setJetskLeadingX: You required "
501 << njets << " jets. Event has " << jets.size() << " jets!");
502 return StatusCode::FAILURE;
503 }
504 }
505
506 size_t index(0);
507
508 for (const xAOD::Jet *jet : jets) {
509 if (index > njets - 1)
510 break;
511
512 TLorentzVector jet_p4;
513 jet_p4.SetPtEtaPhiE(jet->pt() / 1.e3, jet->eta(), jet->phi(),
514 jet->e() / 1.e3);
515
516 float eff(0), ineff(0);
517
518 if (!m_bTagDecoAcc->isAvailable(*jet)) {
519 ANA_MSG_ERROR("RunKLFitterAlg::setJetskLeadingX: jet does not have "
520 << m_bTagDecoration.value() << " aux variable!");
521 return StatusCode::FAILURE;
522 }
523
524 const bool isTagged = (*m_bTagDecoAcc)(*jet);
525
527 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
528 ANA_CHECK(retrieveEfficiencies(jet, &eff, &ineff))
529
530 inputParticles->AddParticle(
531 &jet_p4, jet_p4.Eta(), KLFitter::Particles::kParton, "", index,
532 isTagged, eff, 1. / ineff, KLFitter::Particles::kNone);
533 } else {
534 inputParticles->AddParticle(&jet_p4, jet_p4.Eta(),
535 KLFitter::Particles::kParton, "", index,
536 isTagged);
537 }
538 ++index;
539 }
540 return StatusCode::SUCCESS;
541}
542
544 float *eff, float *ineff) {
545 // need to make a copy of the jet, so that we can manipulate its flavour to
546 // get the various efficiencies
548 xAOD::JetAuxContainer jetsAux;
549 jets.setStore(&jetsAux);
550 xAOD::Jet *jet_copy = new xAOD::Jet();
551 jets.push_back(jet_copy);
552 *jet_copy = *jet;
553 jet_copy->setJetP4(jet->jetP4());
554 // treat jet as b-tagged
555 jet_copy->setAttribute("HadronConeExclTruthLabelID", 5);
556 ANA_CHECK(m_btagging_eff_tool->getMCEfficiency(*jet_copy, *eff));
557 // treat jet as light
558 jet_copy->setAttribute("HadronConeExclTruthLabelID", 0);
559 ANA_CHECK(m_btagging_eff_tool->getMCEfficiency(*jet_copy, *ineff));
560 return StatusCode::SUCCESS;
561}
562
564 const std::vector<const xAOD::Jet *> &jets,
565 KLFitter::Particles *inputParticles, const size_t maxJets) {
566 // kBtagPriority mode first adds the b jets, then the light jets
567 // If your 6th or 7th jet is a b jet, then you probably want this option
568
569 // If container has less jets than required, raise error
571 if (jets.size() < maxJets) {
572 ANA_MSG_ERROR("KLFitterTool::setJetskBtagPriority: You required "
573 << maxJets << " jets. Event has " << jets.size()
574 << " jets!");
575 return StatusCode::FAILURE;
576 }
577 }
578
579 unsigned int totalJets(0);
580
581 // First find the b-jets
582 unsigned int index(0);
583 for (const xAOD::Jet *jet : jets) {
584 if (totalJets >= maxJets)
585 break;
586
587 if (!m_bTagDecoAcc->isAvailable(*jet)) {
588 ANA_MSG_ERROR("RunKLFitterAlg::setJetskLeadingX: jet does not have "
589 << m_bTagDecoration.value() << " aux variable!");
590 return StatusCode::FAILURE;
591 }
592
593 if ((*m_bTagDecoAcc)(*jet)) {
594 TLorentzVector jet_p4;
595 jet_p4.SetPtEtaPhiE(jet->pt() / 1.e3, jet->eta(), jet->phi(),
596 jet->e() / 1.e3);
597
599 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
600 float eff(0), ineff(0);
601 ANA_CHECK(retrieveEfficiencies(jet, &eff, &ineff));
602
603 inputParticles->AddParticle(
604 &jet_p4, jet_p4.Eta(), KLFitter::Particles::kParton, "", index,
605 true, eff, 1. / ineff, KLFitter::Particles::kNone);
606 } else {
607 inputParticles->AddParticle(&jet_p4, jet_p4.Eta(),
608 KLFitter::Particles::kParton, "", index,
609 true);
610 }
611 ++totalJets;
612 } // is b-tagged
613
614 ++index;
615 } // for (jet)
616
617 // Second, find the light jets
618 index = 0;
619 for (const xAOD::Jet *jet : jets) {
620 if (totalJets >= maxJets)
621 break;
622 if (!(*m_bTagDecoAcc)(*jet)) {
623 TLorentzVector jet_p4;
624 jet_p4.SetPtEtaPhiE(jet->pt() / 1.e3, jet->eta(), jet->phi(),
625 jet->e() / 1.e3);
626
628 KLFitter::LikelihoodBase::BtaggingMethod::kWorkingPoint) {
629 float eff(0), ineff(0);
630 ANA_CHECK(retrieveEfficiencies(jet, &eff, &ineff));
631
632 inputParticles->AddParticle(
633 &jet_p4, jet_p4.Eta(), KLFitter::Particles::kParton, "", index,
634 false, eff, 1. / ineff, KLFitter::Particles::kNone);
635 } else {
636 inputParticles->AddParticle(&jet_p4, jet_p4.Eta(),
637 KLFitter::Particles::kParton, "", index,
638 false);
639 }
640 ++totalJets;
641 } // not-btagged jet
642
643 ++index;
644 } // for (jet)
645 return StatusCode::SUCCESS;
646}
647
649 const CP::SystematicSet &sys, const std::vector<size_t> &electron_indices,
650 const std::vector<size_t> &muon_indices,
651 const std::vector<size_t> &jet_indices) {
652 // create or retrieve (if existent) the xAOD::KLFitterResultContainer
653 auto resultAuxContainer =
654 std::make_unique<xAOD::KLFitterResultAuxContainer>();
655 auto resultContainer = std::make_unique<xAOD::KLFitterResultContainer>();
656 resultContainer->setStore(resultAuxContainer.get());
657
658 // loop over all permutations
659 const int nperm = m_myFitter->Permutations()->NPermutations();
660 for (int iperm = 0; iperm < nperm; ++iperm) {
661 // Perform the fit
662 m_myFitter->Fit(iperm);
663 // create a result
665 resultContainer->push_back(result);
666
667 // Set name hash. This is because it seems std::string is not supported by
668 // AuxContainers...
669 std::hash<std::string> hash_string;
670 result->setSelectionCode(hash_string(sys.name()));
671
672 unsigned int ConvergenceStatusBitWord = m_myFitter->ConvergenceStatus();
673 bool MinuitDidNotConverge =
674 (ConvergenceStatusBitWord & m_myFitter->MinuitDidNotConvergeMask) != 0;
675 bool FitAbortedDueToNaN =
676 (ConvergenceStatusBitWord & m_myFitter->FitAbortedDueToNaNMask) != 0;
677 bool AtLeastOneFitParameterAtItsLimit =
678 (ConvergenceStatusBitWord &
679 m_myFitter->AtLeastOneFitParameterAtItsLimitMask) != 0;
680 bool InvalidTransferFunctionAtConvergence =
681 (ConvergenceStatusBitWord &
682 m_myFitter->InvalidTransferFunctionAtConvergenceMask) != 0;
683
684 result->setMinuitDidNotConverge(((MinuitDidNotConverge) ? 1 : 0));
685 result->setFitAbortedDueToNaN(((FitAbortedDueToNaN) ? 1 : 0));
686 result->setAtLeastOneFitParameterAtItsLimit(
687 ((AtLeastOneFitParameterAtItsLimit) ? 1 : 0));
688 result->setInvalidTransferFunctionAtConvergence(
689 ((InvalidTransferFunctionAtConvergence) ? 1 : 0));
690
691 result->setLogLikelihood(m_myFitter->Likelihood()->LogLikelihood(
692 m_myFitter->Likelihood()->GetBestFitParameters()));
693 result->setEventProbability(
694 std::exp(m_myFitter->Likelihood()->LogEventProbability()));
695 result->setParameters(m_myFitter->Likelihood()->GetBestFitParameters());
696 result->setParameterErrors(
697 m_myFitter->Likelihood()->GetBestFitParameterErrors());
698
699 KLFitter::Particles *myModelParticles =
700 m_myFitter->Likelihood()->ParticlesModel();
701 KLFitter::Particles **myPermutedParticles =
702 m_myFitter->Likelihood()->PParticlesPermuted();
703
710 result->setModel_bhad_pt(myModelParticles->Parton(0)->Pt());
711 result->setModel_bhad_eta(myModelParticles->Parton(0)->Eta());
712 result->setModel_bhad_phi(myModelParticles->Parton(0)->Phi());
713 result->setModel_bhad_E(myModelParticles->Parton(0)->E());
714 result->setModel_bhad_jetIndex(
715 jet_indices.at((*myPermutedParticles)->JetIndex(0)));
716
717 result->setModel_blep_pt(myModelParticles->Parton(1)->Pt());
718 result->setModel_blep_eta(myModelParticles->Parton(1)->Eta());
719 result->setModel_blep_phi(myModelParticles->Parton(1)->Phi());
720 result->setModel_blep_E(myModelParticles->Parton(1)->E());
721 result->setModel_blep_jetIndex(
722 jet_indices.at((*myPermutedParticles)->JetIndex(1)));
723
724 result->setModel_lq1_pt(myModelParticles->Parton(2)->Pt());
725 result->setModel_lq1_eta(myModelParticles->Parton(2)->Eta());
726 result->setModel_lq1_phi(myModelParticles->Parton(2)->Phi());
727 result->setModel_lq1_E(myModelParticles->Parton(2)->E());
728 result->setModel_lq1_jetIndex(
729 jet_indices.at((*myPermutedParticles)->JetIndex(2)));
730
731 // boosted likelihood has only one light jet
733 result->setModel_lq2_pt(myModelParticles->Parton(3)->Pt());
734 result->setModel_lq2_eta(myModelParticles->Parton(3)->Eta());
735 result->setModel_lq2_phi(myModelParticles->Parton(3)->Phi());
736 result->setModel_lq2_E(myModelParticles->Parton(3)->E());
737 result->setModel_lq2_jetIndex(
738 jet_indices.at((*myPermutedParticles)->JetIndex(3)));
739
741 result->setModel_Higgs_b1_pt(myModelParticles->Parton(4)->Pt());
742 result->setModel_Higgs_b1_eta(myModelParticles->Parton(4)->Eta());
743 result->setModel_Higgs_b1_phi(myModelParticles->Parton(4)->Phi());
744 result->setModel_Higgs_b1_E(myModelParticles->Parton(4)->E());
745 result->setModel_Higgs_b1_jetIndex(
746 jet_indices.at((*myPermutedParticles)->JetIndex(4)));
747
748 result->setModel_Higgs_b2_pt(myModelParticles->Parton(5)->Pt());
749 result->setModel_Higgs_b2_eta(myModelParticles->Parton(5)->Eta());
750 result->setModel_Higgs_b2_phi(myModelParticles->Parton(5)->Phi());
751 result->setModel_Higgs_b2_E(myModelParticles->Parton(5)->E());
752 result->setModel_Higgs_b2_jetIndex(
753 jet_indices.at((*myPermutedParticles)->JetIndex(5)));
754 }
755 }
756
759 result->setModel_lep_pt(myModelParticles->Electron(0)->Pt());
760 result->setModel_lep_eta(myModelParticles->Electron(0)->Eta());
761 result->setModel_lep_phi(myModelParticles->Electron(0)->Phi());
762 result->setModel_lep_E(myModelParticles->Electron(0)->E());
763
765 result->setModel_lep_index(
766 electron_indices.at((*myPermutedParticles)->ElectronIndex(0)));
767
768 result->setModel_lepZ1_pt(myModelParticles->Electron(1)->Pt());
769 result->setModel_lepZ1_eta(myModelParticles->Electron(1)->Eta());
770 result->setModel_lepZ1_phi(myModelParticles->Electron(1)->Phi());
771 result->setModel_lepZ1_E(myModelParticles->Electron(1)->E());
772 result->setModel_lepZ1_index(
773 electron_indices.at((*myPermutedParticles)->ElectronIndex(1)));
774
775 result->setModel_lepZ2_pt(myModelParticles->Electron(2)->Pt());
776 result->setModel_lepZ2_eta(myModelParticles->Electron(2)->Eta());
777 result->setModel_lepZ2_phi(myModelParticles->Electron(2)->Phi());
778 result->setModel_lepZ2_E(myModelParticles->Electron(2)->E());
779 result->setModel_lepZ2_index(
780 electron_indices.at((*myPermutedParticles)->ElectronIndex(2)));
781 }
782 }
783
786 result->setModel_lep_pt(myModelParticles->Muon(0)->Pt());
787 result->setModel_lep_eta(myModelParticles->Muon(0)->Eta());
788 result->setModel_lep_phi(myModelParticles->Muon(0)->Phi());
789 result->setModel_lep_E(myModelParticles->Muon(0)->E());
790
792 result->setModel_lep_index(
793 muon_indices.at((*myPermutedParticles)->MuonIndex(0)));
794
795 result->setModel_lepZ1_pt(myModelParticles->Muon(1)->Pt());
796 result->setModel_lepZ1_eta(myModelParticles->Muon(1)->Eta());
797 result->setModel_lepZ1_phi(myModelParticles->Muon(1)->Phi());
798 result->setModel_lepZ1_E(myModelParticles->Muon(1)->E());
799 result->setModel_lepZ1_index(
800 muon_indices.at((*myPermutedParticles)->MuonIndex(1)));
801
802 result->setModel_lepZ2_pt(myModelParticles->Muon(2)->Pt());
803 result->setModel_lepZ2_eta(myModelParticles->Muon(2)->Eta());
804 result->setModel_lepZ2_phi(myModelParticles->Muon(2)->Phi());
805 result->setModel_lepZ2_E(myModelParticles->Muon(2)->E());
806 result->setModel_lepZ2_index(
807 muon_indices.at((*myPermutedParticles)->MuonIndex(2)));
808 }
809 }
810
811 result->setModel_nu_pt(myModelParticles->Neutrino(0)->Pt());
812 result->setModel_nu_eta(myModelParticles->Neutrino(0)->Eta());
813 result->setModel_nu_phi(myModelParticles->Neutrino(0)->Phi());
814 result->setModel_nu_E(myModelParticles->Neutrino(0)->E());
816 result->setModel_b_from_top1_pt(myModelParticles->Parton(0)->Pt());
817 result->setModel_b_from_top1_eta(myModelParticles->Parton(0)->Eta());
818 result->setModel_b_from_top1_phi(myModelParticles->Parton(0)->Phi());
819 result->setModel_b_from_top1_E(myModelParticles->Parton(0)->E());
820 result->setModel_b_from_top1_jetIndex(
821 jet_indices.at((*myPermutedParticles)->JetIndex(0)));
822
823 result->setModel_b_from_top2_pt(myModelParticles->Parton(1)->Pt());
824 result->setModel_b_from_top2_eta(myModelParticles->Parton(1)->Eta());
825 result->setModel_b_from_top2_phi(myModelParticles->Parton(1)->Phi());
826 result->setModel_b_from_top2_E(myModelParticles->Parton(1)->E());
827 result->setModel_b_from_top2_jetIndex(
828 jet_indices.at((*myPermutedParticles)->JetIndex(1)));
829
830 result->setModel_lj1_from_top1_pt(myModelParticles->Parton(2)->Pt());
831 result->setModel_lj1_from_top1_eta(myModelParticles->Parton(2)->Eta());
832 result->setModel_lj1_from_top1_phi(myModelParticles->Parton(2)->Phi());
833 result->setModel_lj1_from_top1_E(myModelParticles->Parton(2)->E());
834 result->setModel_lj1_from_top1_jetIndex(
835 jet_indices.at((*myPermutedParticles)->JetIndex(2)));
836
837 result->setModel_lj2_from_top1_pt(myModelParticles->Parton(3)->Pt());
838 result->setModel_lj2_from_top1_eta(myModelParticles->Parton(3)->Eta());
839 result->setModel_lj2_from_top1_phi(myModelParticles->Parton(3)->Phi());
840 result->setModel_lj2_from_top1_E(myModelParticles->Parton(3)->E());
841 result->setModel_lj2_from_top1_jetIndex(
842 jet_indices.at((*myPermutedParticles)->JetIndex(3)));
843
844 result->setModel_lj1_from_top2_pt(myModelParticles->Parton(4)->Pt());
845 result->setModel_lj1_from_top2_eta(myModelParticles->Parton(4)->Eta());
846 result->setModel_lj1_from_top2_phi(myModelParticles->Parton(4)->Phi());
847 result->setModel_lj1_from_top2_E(myModelParticles->Parton(4)->E());
848 result->setModel_lj1_from_top2_jetIndex(
849 jet_indices.at((*myPermutedParticles)->JetIndex(4)));
850
851 result->setModel_lj2_from_top2_pt(myModelParticles->Parton(5)->Pt());
852 result->setModel_lj2_from_top2_eta(myModelParticles->Parton(5)->Eta());
853 result->setModel_lj2_from_top2_phi(myModelParticles->Parton(5)->Phi());
854 result->setModel_lj2_from_top2_E(myModelParticles->Parton(5)->E());
855 result->setModel_lj2_from_top2_jetIndex(
856 jet_indices.at((*myPermutedParticles)->JetIndex(5)));
857 }
858 } // Loop over permutations
859
860 // Normalize event probability to unity
861 // work out best permutation
862 float sumEventProbability(0.), bestEventProbability(0.);
863 size_t bestPermutation(999), iPerm(0);
864
865 // First loop
866 for (auto x : *resultContainer) {
867 float prob = x->eventProbability();
868 short minuitDidNotConverge = x->minuitDidNotConverge();
869 short fitAbortedDueToNaN = x->fitAbortedDueToNaN();
870 short atLeastOneFitParameterAtItsLimit =
871 x->atLeastOneFitParameterAtItsLimit();
872 short invalidTransferFunctionAtConvergence =
873 x->invalidTransferFunctionAtConvergence();
874 sumEventProbability += prob;
875 ++iPerm;
876
877 // check if the best value has the highest event probability AND converged
878 if (minuitDidNotConverge)
879 continue;
880 if (fitAbortedDueToNaN)
881 continue;
882 if (atLeastOneFitParameterAtItsLimit)
883 continue;
884 if (invalidTransferFunctionAtConvergence)
885 continue;
886
887 if (prob > bestEventProbability) {
888 bestEventProbability = prob;
889 // Using iPerm -1 because it has already been incremented before
890 bestPermutation = iPerm - 1;
891 }
892 }
893
894 // Second loop
895 iPerm = 0;
896 for (auto x : *resultContainer) {
897 x->setEventProbability(x->eventProbability() / sumEventProbability);
898 if (iPerm == bestPermutation) {
899 x->setBestPermutation(1);
900 } else {
901 x->setBestPermutation(0);
902 }
903 ++iPerm;
904 }
905
906 // Save all permutations
908 ANA_CHECK(m_outHandle.record(std::move(resultContainer),
909 std::move(resultAuxContainer), sys));
910 } else { // Save only the best permutation
911 // create or retrieve the xAOD::KLFitterResultContainer
912 auto bestContainer = std::make_unique<xAOD::KLFitterResultContainer>();
913 auto bestAuxContainer =
914 std::make_unique<xAOD::KLFitterResultAuxContainer>();
915 bestContainer->setStore(bestAuxContainer.get());
916
917 for (auto x : *resultContainer) {
918 if (x->bestPermutation() == 1) {
920 result->makePrivateStore(*x);
921 bestContainer->push_back(result);
922 }
923 }
924 ANA_CHECK(m_outHandle.record(std::move(bestContainer),
925 std::move(bestAuxContainer), sys));
926 }
927
928 return StatusCode::SUCCESS;
929}
930
931} // namespace EventReco
DataVector adapter that acts like it holds const pointers.
#define ANA_MSG_INFO(xmsg)
Macro printing info messages.
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
#define x
Class to wrap a set of SystematicVariations.
StatusCode evaluatePermutations(const CP::SystematicSet &sys, const std::vector< size_t > &electron_indices, const std::vector< size_t > &muon_indices, const std::vector< size_t > &jet_indices)
CP::SysWriteHandle< xAOD::KLFitterResultContainer, xAOD::KLFitterResultAuxContainer > m_outHandle
KLFitter::LikelihoodTTZTrilepton::LeptonType m_leptonTypeKLFitterEnum_TTZ
virtual StatusCode initialize() final
StatusCode retrieveEfficiencies(const xAOD::Jet *jet, float *eff, float *ineff)
std::unique_ptr< KLFitter::LikelihoodTopLeptonJets_JetAngles > m_myLikelihood_JetAngles
CP::SysReadHandle< xAOD::EventInfo > m_eventInfoHandle
std::unique_ptr< KLFitter::LikelihoodTTHLeptonJets > m_myLikelihood_TTH
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< SG::ConstAccessor< char > > m_bTagDecoAcc
std::unique_ptr< KLFitter::DetectorAtlas_8TeV > m_myDetector
CP::SysReadSelectionHandle m_muonSelection
StatusCode execute_syst(const CP::SystematicSet &sys)
CP::SysReadHandle< xAOD::ElectronContainer > m_electronsHandle
KLFEnums::JetSelectionMode m_jetSelectionModeEnum
std::unique_ptr< KLFitter::LikelihoodTTZTrilepton > m_myLikelihood_TTZ
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
std::unique_ptr< KLFitter::LikelihoodTopLeptonJets > m_myLikelihood
Gaudi::Property< std::string > m_leptonType
KLFitter::BoostedLikelihoodTopLeptonJets::LeptonType m_leptonTypeKLFitterEnum_BoostedLJets
KLFitter::LikelihoodTopLeptonJets_Angular::LeptonType m_leptonTypeKLFitterEnum_Angular
std::unique_ptr< KLFitter::BoostedLikelihoodTopLeptonJets > m_myLikelihood_BoostedLJets
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
KLFitter::LikelihoodTopLeptonJets_JetAngles::LeptonType m_leptonTypeKLFitterEnum_JetAngles
StatusCode setJetskBtagPriority(const std::vector< const xAOD::Jet * > &jets, KLFitter::Particles *inputParticles, const size_t maxJets)
CP::SysReadHandle< xAOD::MuonContainer > m_muonsHandle
std::unique_ptr< KLFitter::LikelihoodTopLeptonJets_Angular > m_myLikelihood_Angular
KLFitter::LikelihoodTTHLeptonJets::LeptonType m_leptonTypeKLFitterEnum_TTH
Gaudi::Property< bool > m_failOnLessThanXJets
CP::SysReadSelectionHandle m_electronSelection
virtual StatusCode execute() final
Gaudi::Property< std::string > m_jetSelectionMode
KLFitter::LikelihoodTopLeptonJets::LeptonType m_leptonTypeKLFitterEnum
StatusCode add_jets(const std::vector< const xAOD::Jet * > &selected_jets, KLFitter::Particles *myParticles)
CP::SysReadSelectionHandle m_jetSelection
Gaudi::Property< std::string > m_LHType
std::unique_ptr< KLFitter::Fitter > m_myFitter
Gaudi::Property< float > m_massTop
std::unique_ptr< KLFitter::LikelihoodTopAllHadronic > m_myLikelihood_AllHadronic
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:171
KLFitterResult A simple xAOD class which we can persist into a mini-xAOD The xAOD EDM is way too comp...
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
virtual double e() const
The total energy of the particle.
Definition Muon_v1.cxx:49
virtual double pt() const
The transverse momentum ( ) of the particle.
std::string printEnumOptions(const std::map< std::string, T > &availOpts)
static const std::map< std::string, LeptonType > strToLeptonType
static const std::map< std::string, Likelihood > strToLikelihood
static const std::map< std::string, JetSelectionMode > strToJetSelection
static const std::map< std::string, LikelihoodBase::BtaggingMethod > strToBtagMethod
static 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.
JetAuxContainer_v1 JetAuxContainer
Definition of the current jet auxiliary container.
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".