37 #include "Math/GenVector/VectorUtil.h"
38 #include "Math/Vector2D.h"
45 using ROOT::Math::XYVector;
63 ATH_MSG_INFO(
"totalCharge value is not specified, no charge selection for track combinations will be used" );
68 ATH_MSG_INFO(
"trackMasses value is not specified, muon/electron mass will be used" );
74 ATH_MSG_INFO(
"trackPtThresholds value is not specified" );
76 m_trkPt.value().emplace_back(std::vector<double>(
n, -100.));
87 for (
size_t i = 0;
i <
m_nTrk.size(); ++
i) {
99 for (
size_t i = 0;
i <
m_nTrk.size(); ++
i) {
101 for (
size_t j = 0; j <
m_nTrk[
i]; ++j) {
113 ATH_MSG_DEBUG(
"Configured to run in a streamer mode: no trigger objects will be created" );
116 ATH_MSG_ERROR(
"Could not create trigger objects from tracks or L2 CB muons, use the streamer mode for L2 step" );
117 return StatusCode::FAILURE;
131 return StatusCode::FAILURE;
145 if (
item.second.size() > 1) {
146 for (
size_t i = 0;
i <
item.second.size();
i++) {
160 bool isMergedElectronChain =
false;
163 isMergedElectronChain =
true;
186 ATH_MSG_DEBUG(
"No GenericMonitoringTool configured: no monitoring histograms will be available" );
189 return StatusCode::SUCCESS;
199 CHECK( previousDecisionsHandle.isValid() );
200 ATH_MSG_DEBUG(
"Running with "<< previousDecisionsHandle->size() <<
" previous decisions" );
208 beamSpotData = *beamSpotHandle;
211 std::unique_ptr<TrigMultiTrkState<xAOD::MuonContainer>> muonState;
212 std::unique_ptr<TrigMultiTrkState<xAOD::ElectronContainer>> electronState;
215 electronState = std::make_unique<TrigMultiTrkState<xAOD::ElectronContainer>>(context, *previousDecisionsHandle, *outputDecisionsHandle,
nullptr, beamSpotData);
216 commonState = electronState.get();
219 muonState = std::make_unique<TrigMultiTrkState<xAOD::MuonContainer>>(context, *previousDecisionsHandle, *outputDecisionsHandle,
nullptr, beamSpotData);
220 commonState = muonState.get();
228 ATH_CHECK( mergeTracksFromDecisions<xAOD::L2CombinedMuonContainer>(*commonState) );
231 ATH_CHECK( (
m_doElectrons ? mergeTracksFromDecisions<xAOD::ElectronContainer>(*commonState) : mergeTracksFromDecisions<xAOD::MuonContainer>(*commonState)) );
238 ATH_CHECK( trigBphysHandle.record(std::make_unique<xAOD::TrigBphysContainer>(),
239 std::make_unique<xAOD::TrigBphysAuxContainer>()) );
257 ATH_MSG_DEBUG(
"TrigMultiTrkHypo::execute() terminates with StatusCode::SUCCESS" );
258 return StatusCode::SUCCESS;
265 auto& leptons = state.
leptons();
269 std::map<const Decision*, int> decisionToInputCollectionIndexMap;
270 for (
const auto& decision : previousDecisions) decisionToInputCollectionIndexMap.emplace(decision, 0);
274 CHECK( previousDecisionsHandle.isValid() );
276 for (
const Decision* decision : *previousDecisionsHandle) {
277 previousDecisions.push_back(decision);
278 decisionToInputCollectionIndexMap.emplace(decision,
static_cast<int>(
k));
284 for (
const Decision* decision : previousDecisions) {
294 leptonEL = leptonLinkInfo.link;
297 const auto lepton = *leptonEL;
299 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
300 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
303 if (!lepton->trackParticle())
continue;
306 ATH_MSG_ERROR(
"mergeLeptonsFromDecisions(): no scenario for the provided CONTAINER is specified" );
307 return StatusCode::FAILURE;
311 auto itr = leptons.end();
313 itr = std::find_if(leptons.begin(), leptons.end(),
314 [
this, lepton = lepton](
const auto&
x){ return this->isIdenticalTracks(lepton, *x.link); });
316 if (itr == leptons.end()) {
317 leptons.push_back({leptonEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
DecisionIDContainer()});
320 (*itr).decisionLinks.push_back(decisionEL);
326 std::sort(leptons.begin(), leptons.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs.link)->pt() > (*rhs.link)->pt()); });
330 for (
auto&
item : leptons) {
333 auto decisionIndex = decisionToInputCollectionIndexMap[*decisionEL];
338 if (legToInputCollectionIndexMap.at(
chain).at(legIndex) == decisionIndex)
item.decisionIDs.insert(
id);
348 ATH_MSG_DEBUG(
"Dump found leptons before vertex fit: " << leptons.size() <<
" candidates" );
349 for (
const auto&
item : leptons) {
350 const auto lepton = *
item.link;
353 track = lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
356 track = lepton->trackParticle();
359 ATH_MSG_DEBUG(
" lepton pt (muon: CombinedTrackParticle): " << lepton->pt() <<
" / " << lepton->eta() <<
" / " << lepton->phi() <<
" / " << lepton->charge() );
367 return StatusCode::SUCCESS;
373 auto& tracks = state.
tracks();
376 std::set<const SG::View*> views;
383 if (views.find(
view) != views.end())
continue;
389 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracksFromView;
390 tracksFromView.reserve(tracksHandle->size());
391 for (
size_t idx = 0;
idx < tracksHandle->size(); ++
idx) {
392 tracksFromView.emplace_back(ViewHelper::makeLink<xAOD::TrackParticleContainer>(
view, tracksHandle,
idx));
395 for (
const auto& trackEL : tracksFromView) {
400 std::find_if(tracks.begin(), tracks.end(),
401 [
this,
track](
const auto&
x){ return isIdenticalTracks(track, *x); }) == tracks.end()) {
402 tracks.emplace_back(trackEL);
407 std::sort(tracks.begin(), tracks.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
410 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: " << tracks.size() <<
" candidates" );
411 for (
const auto& trackEL : tracks) {
417 return StatusCode::SUCCESS;
421 template<
typename CONTAINER>
424 auto& tracks = state.
tracks();
433 const auto lepton = *leptonEL;
437 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
438 if (!lepton->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
439 trackEL = lepton->inDetTrackParticleLink();
442 if (!lepton->idTrack())
continue;
443 trackEL = lepton->idTrackLink();
446 if (!lepton->trackParticle())
continue;
447 trackEL = lepton->trackParticleLink();
450 ATH_MSG_ERROR(
"mergeTracksFromDecisions(): no scenario for the provided CONTAINER is specified" );
451 return StatusCode::FAILURE;
454 if (!trackEL.
isValid())
continue;
456 std::find_if(tracks.begin(), tracks.end(),
457 [
this,
track = *trackEL](
const auto&
x){ return this->isIdenticalTracks(track, *x); }) == tracks.end()) {
458 tracks.emplace_back(trackEL);
461 std::sort(tracks.begin(), tracks.end(), [](
const auto& lhs,
const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
464 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: " << tracks.size() <<
" candidates" );
465 for (
const auto& trackEL : tracks) {
471 return StatusCode::SUCCESS;
477 const auto& tracks = state.
tracks();
487 mon_nAcceptedTrk, mon_nVertexFitterCalls, mon_isEventAccepted,
490 for (
size_t iTrk = 0; iTrk <
m_nTrk.size(); ++iTrk) {
492 size_t nTrk =
m_nTrk[iTrk];
494 if (tracks.size() < nTrk) {
495 ATH_MSG_DEBUG(
"Could not build a subset of " << nTrk <<
" tracks from collection which contains only " << tracks.size() <<
" objects" );
498 ATH_MSG_DEBUG(
"Consider combinations of " << nTrk <<
" tracks from collection which contains " << tracks.size() <<
" objects until find a good one" );
500 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(nTrk);
501 std::vector<xAOD::TrackParticle::GenVecFourMom_t>
p(nTrk);
505 std::vector<char>
idx(tracks.size(), 0);
509 bool isValidCombination =
true;
512 for (
size_t i = 0;
i <
idx.size(); ++
i) {
513 if (!
idx[
i])
continue;
514 const auto& trackEL = tracks[
i];
515 tracklist[j] = trackEL;
516 const auto track = *trackEL;
519 totalCharge +=
static_cast<int>(
track->charge());
521 isValidCombination =
false;
529 ATH_MSG_DEBUG(
"Dump found tracks before vertex fit: pT / eta / phi / charge" );
530 for (
size_t i = 0;
i < tracklist.size(); ++
i) {
531 const auto track = *tracklist[
i];
543 ++mon_nVertexFitterCalls;
546 ATH_MSG_DEBUG(
"Filter found a subset of tracks which passed the rough selection: stop looking for other combinations" );
550 }
while (std::prev_permutation(
idx.begin(),
idx.end()));
554 ATH_MSG_DEBUG(
"Filter could not find a good subset of tracks" );
559 return StatusCode::SUCCESS;
567 const auto& leptons = state.
leptons();
575 std::vector<float> trkMassBeforeFit;
576 std::vector<float> bphysMass;
577 std::vector<float> d0track1, d0track2;
578 std::vector<float> pttrack1, pttrack2;
579 std::vector<float> etatrack1, etatrack2;
580 std::vector<int> bphysCharge;
597 mon_nAcceptedTrk, mon_nCombination, mon_nCombinationBeforeFit, mon_nBPhysObject,
598 mon_trkMassBeforeFit, mon_bphysChi2, mon_bphysLxy, mon_bphysFitMass, mon_bphysMass, mon_bphysCharge, mon_d0track1, mon_d0track2,
599 mon_timer, mon_pttrack1, mon_pttrack2, mon_etatrack1, mon_etatrack2);
601 for (
size_t iTrk = 0; iTrk <
m_nTrk.size(); ++iTrk) {
602 size_t nTrk =
m_nTrk[iTrk];
604 if (leptons.size() < nTrk) {
605 ATH_MSG_DEBUG(
"Could not build a subset of " << nTrk <<
" legs from collection which contains only " << leptons.size() <<
" objects" );
608 ATH_MSG_DEBUG(
"Consider all combinations of " << nTrk <<
" legs from collection which contains " << leptons.size() <<
" objects" );
610 std::vector<size_t> leptonIndices(nTrk);
611 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(nTrk);
612 std::vector<xAOD::TrackParticle::GenVecFourMom_t>
p(nTrk);
614 std::vector<char> combination(leptons.size(), 0);
615 std::fill(combination.begin(), combination.begin() + nTrk, 1);
618 bool isValidCombination =
true;
621 for (
size_t i = 0;
i < combination.size(); ++
i) {
622 if (!combination[
i])
continue;
623 leptonIndices[j] =
i;
624 auto leg = *leptons[
i].link;
625 charge +=
static_cast<int>(lround(
leg->charge()));
628 trackEL =
leg->inDetTrackParticleLink();
631 trackEL =
leg->trackParticleLink();
633 tracklist[j] = trackEL;
635 p[j] =
leg->genvecP4();
639 p[j] = (*trackEL)->genvecP4();
643 isValidCombination =
false;
651 ATH_MSG_DEBUG(
"Dump found leptons before vertex fit: pT / eta / phi / charge" );
652 for (
size_t i = 0;
i < tracklist.size(); ++
i) {
653 const auto track = *tracklist[
i];
662 trkMassBeforeFit.push_back(
mass * 0.001);
665 mon_nCombinationBeforeFit++;
674 bphysMass.push_back(
mass * 0.001);
675 bphysCharge.push_back(
charge);
676 d0track1.push_back((*tracklist[0])->
d0());
677 d0track2.push_back((*tracklist[1])->
d0());
678 pttrack1.push_back((*tracklist[0])->
pt() * 0.001);
679 pttrack2.push_back((*tracklist[1])->
pt() * 0.001);
680 etatrack1.push_back((*tracklist[0])->
eta());
681 etatrack2.push_back((*tracklist[1])->
eta());
683 }
while (std::prev_permutation(combination.begin(), combination.end()));
685 return StatusCode::SUCCESS;
691 ATH_MSG_DEBUG(
"Try to find electrons originating from the same EM cluster" );
694 auto& leptons = state.
leptons();
697 ATH_MSG_DEBUG(
"no chains similar to BPH-0DR3-EM7J15 have been requested, should not look for close-by electrons" );
698 return StatusCode::SUCCESS;
710 if (!
electron->trackParticle())
continue;
719 leptons.push_back({electronEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
decisionIDs});
724 auto initialRoI = *roiInfo.link;
727 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(2);
728 tracklist[0] =
electron->trackParticleLink();
731 if (electronFromView ==
electron)
continue;
732 if (!electronFromView->trackParticle())
continue;
734 tracklist[1] = electronFromView->trackParticleLink();
737 auto vertex =
fit(tracklist, particleMasses, *fitterState);
740 trigBphys->
setRoiId(initialRoI->roiWord());
745 return StatusCode::SUCCESS;
751 ATH_MSG_DEBUG(
"Try to find muon + track combinations from the same SG::View" );
756 const std::vector<double> particleMasses(2,
PDG::mMuon);
764 const auto muon = *muonEL;
765 if (!
muon->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle))
continue;
766 if (!
muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
continue;
767 const auto muonInDetTrack =
muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
768 auto muonMomentum = muonInDetTrack->genvecP4();
774 muons.push_back({muonEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL),
decisionIDs});
776 ATH_MSG_DEBUG(
"Found muon (CombinedTrackParticle): " <<
muon->pt() <<
" / " <<
muon->eta() <<
" / " <<
muon->phi() <<
" / " <<
muon->charge() );
780 auto view = *viewLinkInfo.link;
787 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracklist(2);
788 tracklist[0] =
muon->inDetTrackParticleLink();
789 for (
size_t idx = 0;
idx < tracksHandle->size(); ++
idx) {
796 if (
m_nTrkCharge[0] >= 0 && muonInDetTrack->charge() *
track->charge() > 0.)
continue;
798 tracklist[1] = ViewHelper::makeLink<xAOD::TrackParticleContainer>(
view, tracksHandle,
idx);
800 ATH_MSG_DEBUG(
"Dump found muon+track pair before vertex fit: pT / eta / phi / charge" <<
endmsg <<
801 " muon: " << muonMomentum.Pt() <<
" / " << muonMomentum.Eta() <<
" / " << muonMomentum.Phi() <<
" / " <<
muon->charge() <<
endmsg <<
805 auto vertex =
fit(tracklist, particleMasses, *fitterState);
813 return StatusCode::SUCCESS;
838 return StatusCode::SUCCESS;
846 ATH_MSG_DEBUG(
"Found xAOD::TrigBphys: mass / chi2 = " << triggerObject->mass() <<
" / " << triggerObject->fitchi2() );
854 std::vector<const DecisionIDContainer*> previousDecisionIDs;
865 decision->setDetail<int32_t>(
"noCombo", 1);
877 return StatusCode::SUCCESS;
888 CHECK( previousDecisionsHandle.isValid() );
889 ATH_MSG_DEBUG(
"Running with "<< previousDecisionsHandle->size() <<
" previous decisions" );
891 for (
const Decision* previousDecision : *previousDecisionsHandle) {
906 return StatusCode::SUCCESS;
912 const std::vector<double>& particleMasses,
916 std::vector<const xAOD::TrackParticle*> tracklist(
trackParticleLinks.size(),
nullptr);
920 const Trk::Perigee& perigee1 = tracklist[0]->perigeeParameters();
921 const Trk::Perigee& perigee2 = tracklist[1]->perigeeParameters();
926 ATH_MSG_DEBUG(
"Starting point: (" << startingPoint(0) <<
", " << startingPoint(1) <<
", " << startingPoint(2) <<
")" );
928 m_vertexFitter->setMassInputParticles(particleMasses, fitterState);
929 std::unique_ptr<xAOD::Vertex>
vertex(
m_vertexFitter->fit(tracklist, startingPoint, fitterState));
935 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() <<
")" );
948 const std::vector<double>& particleMasses,
953 double invariantMassError = 0.;
955 ATH_MSG_DEBUG(
"Warning from TrkVKalVrtFitter: can not calculate uncertainties" );
960 for (
size_t i = 0;
i <
vertex.nTrackParticles(); ++
i) {
961 auto p =
vertex.trackParticle(
i)->genvecP4();
962 p.SetM(particleMasses[
i]);
967 result->makePrivateStore();
977 result->setTrackParticleLinks(
vertex.trackParticleLinks());
982 "TrigBphys objects:\n\t " <<
983 "roiId: " <<
result->roiId() <<
"\n\t " <<
984 "particleType: " <<
result->particleType() <<
"\n\t " <<
985 "level: " <<
result->level() <<
"\n\t " <<
986 "eta: " <<
result->eta() <<
"\n\t " <<
987 "phi: " <<
result->phi() <<
"\n\t " <<
988 "mass: " <<
result->mass() <<
"\n\t " <<
989 "fitmass: " <<
result->fitmass() <<
"\n\t " <<
990 "chi2/NDF: " <<
result->fitchi2() <<
" / " <<
result->fitndof() <<
"\n\t " <<
991 "vertex: (" <<
result->fitx() <<
", " <<
result->fity() <<
", " <<
result->fitz() <<
")\n\t " <<
992 "Lxy/LxyError: " <<
result->lxy() <<
" / " <<
result->lxyError() );
1028 for (
size_t i = 0;
i <
p.size(); ++
i) {
1029 for (
size_t j =
i + 1; j <
p.size(); ++j) {