38 #include "Math/GenVector/VectorUtil.h"
39 #include "Math/Vector2D.h"
46 using ROOT::Math::XYVector;
57 bool prev_perm (std::vector<char>&
v)
59 return std::ranges::prev_permutation(
v).found;;
79 ATH_MSG_INFO(
"totalCharge value is not specified, no charge selection for track combinations will be used" );
84 ATH_MSG_INFO(
"trackMasses value is not specified, muon/electron mass will be used" );
90 ATH_MSG_INFO(
"trackPtThresholds value is not specified" );
92 m_trkPt.value().emplace_back(std::vector<double>(
n, -100.));
103 for (
size_t i = 0;
i <
m_nTrk.size(); ++
i) {
115 for (
size_t i = 0;
i <
m_nTrk.size(); ++
i) {
117 for (
size_t j = 0; j <
m_nTrk[
i]; ++j) {
129 ATH_MSG_DEBUG(
"Configured to run in a streamer mode: no trigger objects will be created" );
132 ATH_MSG_ERROR(
"Could not create trigger objects from tracks or L2 CB muons, use the streamer mode for L2 step" );
133 return StatusCode::FAILURE;
147 return StatusCode::FAILURE;
161 if (
item.second.size() > 1) {
162 for (
size_t i = 0;
i <
item.second.size();
i++) {
176 bool isMergedElectronChain =
false;
179 isMergedElectronChain =
true;
202 ATH_MSG_DEBUG(
"No GenericMonitoringTool configured: no monitoring histograms will be available" );
205 return StatusCode::SUCCESS;
215 CHECK( previousDecisionsHandle.isValid() );
216 ATH_MSG_DEBUG(
"Running with "<< previousDecisionsHandle->size() <<
" previous decisions" );
224 beamSpotData = *beamSpotHandle;
227 std::unique_ptr<TrigMultiTrkState<xAOD::MuonContainer>> muonState;
228 std::unique_ptr<TrigMultiTrkState<xAOD::ElectronContainer>> electronState;
231 electronState = std::make_unique<TrigMultiTrkState<xAOD::ElectronContainer>>(context, *previousDecisionsHandle, *outputDecisionsHandle,
nullptr, beamSpotData);
232 commonState = electronState.get();
235 muonState = std::make_unique<TrigMultiTrkState<xAOD::MuonContainer>>(context, *previousDecisionsHandle, *outputDecisionsHandle,
nullptr, beamSpotData);
236 commonState = muonState.get();
244 ATH_CHECK( mergeTracksFromDecisions<xAOD::L2CombinedMuonContainer>(*commonState) );
247 ATH_CHECK( (
m_doElectrons ? mergeTracksFromDecisions<xAOD::ElectronContainer>(*commonState) : mergeTracksFromDecisions<xAOD::MuonContainer>(*commonState)) );
254 ATH_CHECK( trigBphysHandle.record(std::make_unique<xAOD::TrigBphysContainer>(),
255 std::make_unique<xAOD::TrigBphysAuxContainer>()) );
273 ATH_MSG_DEBUG(
"TrigMultiTrkHypo::execute() terminates with StatusCode::SUCCESS" );
274 return StatusCode::SUCCESS;
281 auto& leptons = state.
leptons();
285 std::map<const Decision*, int> decisionToInputCollectionIndexMap;
286 for (
const auto& decision : previousDecisions) decisionToInputCollectionIndexMap.emplace(decision, 0);
290 CHECK( previousDecisionsHandle.isValid() );
292 for (
const Decision* decision : *previousDecisionsHandle) {
293 previousDecisions.push_back(decision);
294 decisionToInputCollectionIndexMap.emplace(decision,
static_cast<int>(
k));
300 for (
const Decision* decision : previousDecisions) {
310 leptonEL = leptonLinkInfo.link;
313 const auto lepton = *leptonEL;
315 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
316 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
319 if (!lepton->trackParticle())
continue;
322 ATH_MSG_ERROR(
"mergeLeptonsFromDecisions(): no scenario for the provided CONTAINER is specified" );
323 return StatusCode::FAILURE;
327 auto itr = leptons.end();
329 itr = std::find_if(leptons.begin(), leptons.end(),
330 [
this, lepton = lepton](
const auto&
x){ return this->isIdenticalTracks(lepton, *x.link); });
332 if (itr == leptons.end()) {
333 leptons.push_back({leptonEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
DecisionIDContainer()});
336 (*itr).decisionLinks.push_back(decisionEL);
342 std::sort(leptons.begin(), leptons.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs.link)->pt() > (*rhs.link)->pt()); });
346 for (
auto&
item : leptons) {
349 auto decisionIndex = decisionToInputCollectionIndexMap[*decisionEL];
354 if (legToInputCollectionIndexMap.at(
chain).at(legIndex) == decisionIndex)
item.decisionIDs.insert(
id);
364 ATH_MSG_DEBUG(
"Dump found leptons before vertex fit: " << leptons.size() <<
" candidates" );
365 for (
const auto&
item : leptons) {
366 const auto lepton = *
item.link;
369 track = lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
372 track = lepton->trackParticle();
375 ATH_MSG_DEBUG(
" lepton pt (muon: CombinedTrackParticle): " << lepton->pt() <<
" / " << lepton->eta() <<
" / " << lepton->phi() <<
" / " << lepton->charge() );
383 return StatusCode::SUCCESS;
389 auto& tracks = state.
tracks();
392 std::set<const SG::View*> views;
399 if (views.find(
view) != views.end())
continue;
405 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracksFromView;
406 tracksFromView.reserve(tracksHandle->size());
407 for (
size_t idx = 0;
idx < tracksHandle->size(); ++
idx) {
408 tracksFromView.emplace_back(ViewHelper::makeLink<xAOD::TrackParticleContainer>(
view, tracksHandle,
idx));
411 for (
const auto& trackEL : tracksFromView) {
416 std::find_if(tracks.begin(), tracks.end(),
417 [
this,
track](
const auto&
x){ return isIdenticalTracks(track, *x); }) == tracks.end()) {
418 tracks.emplace_back(trackEL);
423 std::sort(tracks.begin(), tracks.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
426 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: " << tracks.size() <<
" candidates" );
427 for (
const auto& trackEL : tracks) {
433 return StatusCode::SUCCESS;
437 template<
typename CONTAINER>
440 auto& tracks = state.
tracks();
449 const auto lepton = *leptonEL;
453 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
454 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
455 trackEL = lepton->inDetTrackParticleLink();
458 if (!lepton->idTrack())
continue;
459 trackEL = lepton->idTrackLink();
462 if (!lepton->trackParticle())
continue;
463 trackEL = lepton->trackParticleLink();
466 ATH_MSG_ERROR(
"mergeTracksFromDecisions(): no scenario for the provided CONTAINER is specified" );
467 return StatusCode::FAILURE;
470 if (!trackEL.
isValid())
continue;
472 std::find_if(tracks.begin(), tracks.end(),
473 [
this,
track = *trackEL](
const auto&
x){ return this->isIdenticalTracks(track, *x); }) == tracks.end()) {
474 tracks.emplace_back(trackEL);
477 std::sort(tracks.begin(), tracks.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
480 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: " << tracks.size() <<
" candidates" );
481 for (
const auto& trackEL : tracks) {
487 return StatusCode::SUCCESS;
493 const auto& tracks = state.
tracks();
503 mon_nAcceptedTrk, mon_nVertexFitterCalls, mon_isEventAccepted,
506 for (
size_t iTrk = 0; iTrk <
m_nTrk.size(); ++iTrk) {
508 size_t nTrk =
m_nTrk[iTrk];
510 if (tracks.size() < nTrk) {
511 ATH_MSG_DEBUG(
"Could not build a subset of " << nTrk <<
" tracks from collection which contains only " << tracks.size() <<
" objects" );
514 ATH_MSG_DEBUG(
"Consider combinations of " << nTrk <<
" tracks from collection which contains " << tracks.size() <<
" objects until find a good one" );
516 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(nTrk);
517 std::vector<xAOD::TrackParticle::GenVecFourMom_t>
p(nTrk);
521 std::vector<char>
idx(tracks.size(), 0);
525 bool isValidCombination =
true;
528 for (
size_t i = 0;
i <
idx.size(); ++
i) {
529 if (!
idx[
i])
continue;
530 const auto& trackEL = tracks[
i];
531 tracklist[j] = trackEL;
532 const auto track = *trackEL;
535 totalCharge +=
static_cast<int>(
track->charge());
537 isValidCombination =
false;
545 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: pT / eta / phi / charge" );
546 for (
size_t i = 0;
i < tracklist.size(); ++
i) {
547 const auto track = *tracklist[
i];
559 ++mon_nVertexFitterCalls;
562 ATH_MSG_DEBUG(
"Filter found a subset of tracks which passed the rough selection: stop looking for other combinations" );
566 }
while (prev_perm(
idx));
570 ATH_MSG_DEBUG(
"Filter could not find a good subset of tracks" );
575 return StatusCode::SUCCESS;
583 const auto& leptons = state.
leptons();
591 std::vector<float> trkMassBeforeFit;
592 std::vector<float> bphysMass;
593 std::vector<float> d0track1, d0track2;
594 std::vector<float> pttrack1, pttrack2;
595 std::vector<float> etatrack1, etatrack2;
596 std::vector<int> bphysCharge;
613 mon_nAcceptedTrk, mon_nCombination, mon_nCombinationBeforeFit, mon_nBPhysObject,
614 mon_trkMassBeforeFit, mon_bphysChi2, mon_bphysLxy, mon_bphysFitMass, mon_bphysMass, mon_bphysCharge, mon_d0track1, mon_d0track2,
615 mon_timer, mon_pttrack1, mon_pttrack2, mon_etatrack1, mon_etatrack2);
617 for (
size_t iTrk = 0; iTrk <
m_nTrk.size(); ++iTrk) {
618 size_t nTrk =
m_nTrk[iTrk];
620 if (leptons.size() < nTrk) {
621 ATH_MSG_DEBUG(
"Could not build a subset of " << nTrk <<
" legs from collection which contains only " << leptons.size() <<
" objects" );
624 ATH_MSG_DEBUG(
"Consider all combinations of " << nTrk <<
" legs from collection which contains " << leptons.size() <<
" objects" );
626 std::vector<size_t> leptonIndices(nTrk);
627 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(nTrk);
628 std::vector<xAOD::TrackParticle::GenVecFourMom_t>
p(nTrk);
630 std::vector<char> combination(leptons.size(), 0);
631 std::fill(combination.begin(), combination.begin() + nTrk, 1);
634 bool isValidCombination =
true;
637 for (
size_t i = 0;
i < combination.size(); ++
i) {
638 if (!combination[
i])
continue;
639 leptonIndices[j] =
i;
640 auto leg = *leptons[
i].link;
641 charge +=
static_cast<int>(lround(
leg->charge()));
644 trackEL =
leg->inDetTrackParticleLink();
647 trackEL =
leg->trackParticleLink();
649 tracklist[j] = trackEL;
651 p[j] =
leg->genvecP4();
655 p[j] = (*trackEL)->genvecP4();
659 isValidCombination =
false;
667 ATH_MSG_DEBUG(
"Dump found leptons before vertex fit: pT / eta / phi / charge" );
668 for (
size_t i = 0;
i < tracklist.size(); ++
i) {
669 const auto track = *tracklist[
i];
678 trkMassBeforeFit.push_back(
mass * 0.001);
681 mon_nCombinationBeforeFit++;
690 bphysMass.push_back(
mass * 0.001);
691 bphysCharge.push_back(
charge);
692 d0track1.push_back((*tracklist[0])->
d0());
693 d0track2.push_back((*tracklist[1])->
d0());
694 pttrack1.push_back((*tracklist[0])->
pt() * 0.001);
695 pttrack2.push_back((*tracklist[1])->
pt() * 0.001);
696 etatrack1.push_back((*tracklist[0])->
eta());
697 etatrack2.push_back((*tracklist[1])->
eta());
699 }
while (prev_perm(combination));
701 return StatusCode::SUCCESS;
707 ATH_MSG_DEBUG(
"Try to find electrons originating from the same EM cluster" );
710 auto& leptons = state.
leptons();
713 ATH_MSG_DEBUG(
"no chains similar to BPH-0DR3-EM7J15 have been requested, should not look for close-by electrons" );
714 return StatusCode::SUCCESS;
726 if (!
electron->trackParticle())
continue;
735 leptons.push_back({electronEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
decisionIDs});
740 auto initialRoI = *roiInfo.link;
743 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(2);
744 tracklist[0] =
electron->trackParticleLink();
747 if (electronFromView ==
electron)
continue;
748 if (!electronFromView->trackParticle())
continue;
750 tracklist[1] = electronFromView->trackParticleLink();
753 auto vertex =
fit(tracklist, particleMasses, *fitterState);
756 trigBphys->
setRoiId(initialRoI->roiWord());
761 return StatusCode::SUCCESS;
767 ATH_MSG_DEBUG(
"Try to find muon + track combinations from the same SG::View" );
772 const std::vector<double> particleMasses(2,
PDG::mMuon);
780 const auto muon = *muonEL;
781 if (!
muon->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
782 if (!
muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
783 const auto muonInDetTrack =
muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
784 auto muonMomentum = muonInDetTrack->genvecP4();
790 muons.push_back({muonEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
decisionIDs});
792 ATH_MSG_DEBUG(
"Found muon (CombinedTrackParticle): " <<
muon->pt() <<
" / " <<
muon->eta() <<
" / " <<
muon->phi() <<
" / " <<
muon->charge() );
796 auto view = *viewLinkInfo.link;
803 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(2);
804 tracklist[0] =
muon->inDetTrackParticleLink();
805 for (
size_t idx = 0;
idx < tracksHandle->size(); ++
idx) {
812 if (
m_nTrkCharge[0] >= 0 && muonInDetTrack->charge() *
track->charge() > 0.)
continue;
814 tracklist[1] = ViewHelper::makeLink<xAOD::TrackParticleContainer>(
view, tracksHandle,
idx);
816 ATH_MSG_DEBUG(
"Dump found muon+track pair before vertex fit: pT / eta / phi / charge" <<
endmsg <<
817 " muon: " << muonMomentum.Pt() <<
" / " << muonMomentum.Eta() <<
" / " << muonMomentum.Phi() <<
" / " <<
muon->charge() <<
endmsg <<
821 auto vertex =
fit(tracklist, particleMasses, *fitterState);
829 return StatusCode::SUCCESS;
854 return StatusCode::SUCCESS;
862 ATH_MSG_DEBUG(
"Found xAOD::TrigBphys: mass / chi2 = " << triggerObject->mass() <<
" / " << triggerObject->fitchi2() );
870 std::vector<const DecisionIDContainer*> previousDecisionIDs;
881 decision->setDetail<int32_t>(
"noCombo", 1);
893 return StatusCode::SUCCESS;
904 CHECK( previousDecisionsHandle.isValid() );
905 ATH_MSG_DEBUG(
"Running with "<< previousDecisionsHandle->size() <<
" previous decisions" );
907 for (
const Decision* previousDecision : *previousDecisionsHandle) {
922 return StatusCode::SUCCESS;
928 const std::vector<double>& particleMasses,
932 std::vector<const xAOD::TrackParticle*> tracklist(
trackParticleLinks.size(),
nullptr);
936 const Trk::Perigee& perigee1 = tracklist[0]->perigeeParameters();
937 const Trk::Perigee& perigee2 = tracklist[1]->perigeeParameters();
942 ATH_MSG_DEBUG(
"Starting point: (" << startingPoint(0) <<
", " << startingPoint(1) <<
", " << startingPoint(2) <<
")" );
944 m_vertexFitter->setMassInputParticles(particleMasses, fitterState);
945 std::unique_ptr<xAOD::Vertex>
vertex(
m_vertexFitter->fit(tracklist, startingPoint, fitterState));
951 ATH_MSG_DEBUG(
"Fit is successful, but vertex chi2 is too high, we are not going to save it (chi2 = " <<
vertex->chiSquared() <<
" > " <<
m_chi2.value() <<
")" );
964 const std::vector<double>& particleMasses,
968 double invariantMass = 0.;
969 double invariantMassError = 0.;
970 if (!
m_vertexFitter->VKalGetMassError(invariantMass, invariantMassError, fitterState).isSuccess()) {
971 ATH_MSG_DEBUG(
"Warning from TrkVKalVrtFitter: can not calculate uncertainties" );
972 invariantMass = -9999.;
976 for (
size_t i = 0;
i <
vertex.nTrackParticles(); ++
i) {
977 auto p =
vertex.trackParticle(
i)->genvecP4();
978 p.SetM(particleMasses[
i]);
983 result->makePrivateStore();
987 result->setFitmass(invariantMass);
993 result->setTrackParticleLinks(
vertex.trackParticleLinks());
998 "TrigBphys objects:\n\t " <<
999 "roiId: " <<
result->roiId() <<
"\n\t " <<
1000 "particleType: " <<
result->particleType() <<
"\n\t " <<
1001 "level: " <<
result->level() <<
"\n\t " <<
1002 "eta: " <<
result->eta() <<
"\n\t " <<
1003 "phi: " <<
result->phi() <<
"\n\t " <<
1004 "mass: " <<
result->mass() <<
"\n\t " <<
1005 "fitmass: " <<
result->fitmass() <<
"\n\t " <<
1006 "chi2/NDF: " <<
result->fitchi2() <<
" / " <<
result->fitndof() <<
"\n\t " <<
1007 "vertex: (" <<
result->fitx() <<
", " <<
result->fity() <<
", " <<
result->fitz() <<
")\n\t " <<
1008 "Lxy/LxyError: " <<
result->lxy() <<
" / " <<
result->lxyError() );
1044 for (
size_t i = 0;
i <
p.size(); ++
i) {
1045 for (
size_t j =
i + 1; j <
p.size(); ++j) {