ATLAS Offline Software
Loading...
Searching...
No Matches
TrigBmumuxComboHypo.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5
6
8
9#include "xAODMuon/Muon.h"
11#include "xAODTracking/Vertex.h"
18
22
23#include "AthViews/View.h"
24#include "AthViews/ViewHelper.h"
26
27#include "Math/GenVector/VectorUtil.h"
28#include "Math/Vector2D.h"
29#include <algorithm>
30#include <numeric>
31#include <iterator>
32
37using ROOT::Math::XYVector;
38
39
40
41const std::vector<std::vector<double>> TrigBmumuxComboHypo::s_trkMass{
42 {PDG::mMuon, PDG::mMuon}, // {Psi.mu1, Psi.mu2}
43 {PDG::mMuon, PDG::mMuon, PDG::mKaon}, // {Psi.mu1, Psi.mu2, trk1}
44 {PDG::mMuon, PDG::mMuon, PDG::mKaon, PDG::mKaon}, // {Psi.mu1, Psi.mu2, trk1, trk2}
45 {PDG::mKaon, PDG::mKaon, PDG::mPion}, // {D_s+.K+, D_s+.K-, D_s+.pi+}
46 {PDG::mPion, PDG::mPion, PDG::mKaon}, // {D+.pi+, D+.pi+, D+.K-}
47 {PDG::mKaon, PDG::mPion}, // {D0.K-, D0.pi+}
48 {PDG::mMuon, PDG::mMuon, PDG::mPion}, // {Psi.mu1, Psi.mu2, D*+.pi+}
49 {PDG::mPion, PDG::mPion}, // {trk1, trk2}
50 {PDG::mMuon, PDG::mMuon, PDG::mPion} // {mu1, mu2, trk1}
51};
52
53TrigBmumuxComboHypo::TrigBmumuxComboHypo(const std::string& name, ISvcLocator* pSvcLocator)
54 : ::ComboHypo(name, pSvcLocator) {}
55
56
58 ATH_MSG_DEBUG( "TrigBmumuxComboHypo::initialize()" );
59
61
62 ATH_CHECK( m_muonContainerKey.initialize() );
66 ATH_CHECK( m_trigBphysContainerKey.initialize() );
67 ATH_CHECK( m_beamSpotKey.initialize() );
68
69 ATH_CHECK( m_vertexFitter.retrieve() );
71 ATH_CHECK( m_trackToVertexTool.retrieve() );
72
73 // allowed IDs to filter out incoming decisions at L2 level
74 for (const auto& item : triggerMultiplicityMap()) {
75 const HLT::Identifier id = HLT::Identifier(item.first);
76 m_allowedIDs.insert(id.numeric());
77 if (item.second.size() > 1) {
78 for (size_t i = 0; i < item.second.size(); i++) {
79 m_allowedIDs.insert(TrigCompositeUtils::createLegName(id, i).numeric());
80 }
81 }
82 }
83 if (msgLvl(MSG::DEBUG)) {
84 ATH_MSG_DEBUG( "Allowed decisions:" );
85 for (const DecisionID& id : m_allowedIDs) {
86 ATH_MSG_DEBUG( " +++ " << HLT::Identifier(id) );
87 }
88 }
89
90 if (!m_monTool.empty()) {
91 ATH_CHECK( m_monTool.retrieve() );
92 ATH_MSG_DEBUG( "GenericMonitoringTool name:" << m_monTool );
93 }
94 else {
95 ATH_MSG_DEBUG( "No GenericMonitoringTool configured: no monitoring histograms will be available" );
96 }
97
98 return StatusCode::SUCCESS;
99}
100
101
102StatusCode TrigBmumuxComboHypo::execute(const EventContext& context) const {
103
104 ATH_MSG_DEBUG( "TrigBmumuxComboHypo::execute() starts" );
105
106 ATH_MSG_DEBUG( "decision input key: " << decisionsInput().at(0).key() );
107 auto previousDecisionsHandle = SG::makeHandle(decisionsInput().at(0), context);
108 ATH_CHECK( previousDecisionsHandle.isValid() );
109 ATH_MSG_DEBUG( "Running with " << previousDecisionsHandle->size() << " previous decisions" );
110
112
113 auto trigBphysHandle = SG::makeHandle(m_trigBphysContainerKey, context);
114 ATH_CHECK( trigBphysHandle.record(std::make_unique<xAOD::TrigBphysContainer>(),
115 std::make_unique<xAOD::TrigBphysAuxContainer>()) );
116
118 ATH_CHECK( beamSpotHandle.isValid() );
119
120 auto state = std::make_unique<TrigBmumuxState>(context, *previousDecisionsHandle, *outputDecisionsHandle, trigBphysHandle.ptr(), *beamSpotHandle);
121
124
125 if (!state->dimuons.empty()) {
129 }
130
131 ATH_MSG_DEBUG( "TrigBmumuxComboHypo::execute() terminates with StatusCode::SUCCESS" );
132 return StatusCode::SUCCESS;
133}
134
135
137
138 auto& muons = state.muons;
139 muons.clear();
140
141 // all muons from views are already connected with previous decisions by TrigMuonEFHypoAlg
142 for (const Decision* decision : state.previousDecisions()) {
144 auto muonEL = decision->objectLink<xAOD::MuonContainer>(TrigCompositeUtils::featureString());
145 const xAOD::Muon* muon = *muonEL;
146 if (!muon->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle)) continue;
147
148 auto decisionEL = TrigCompositeUtils::decisionToElementLink(decision, state.context());
149 auto itr = std::find_if(muons.begin(), muons.end(), [this, muon](const auto& x){ return isIdenticalTracks(muon, *x.link); });
150 if (itr == muons.end()) {
151 muons.push_back({muonEL, std::vector<ElementLink<DecisionContainer>>(1, decisionEL), DecisionIDContainer()});
152 }
153 else {
154 (*itr).decisionLinks.push_back(decisionEL);
155 }
156 }
157
158 // muon->pt() is equal to muon->trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle)->pt()
159 // and the later is used by TrigMuonEFHypoTool for classification of muEFCB candidates
160 std::sort(muons.begin(), muons.end(), [](const auto& lhs, const auto& rhs){ return ((*lhs.link)->pt() > (*rhs.link)->pt()); });
161
162 // for each muon we extract DecisionIDs stored in the associated Decision objects and copy them at muon.decisionIDs
163 for (auto& item : muons) {
164 for (const ElementLink<xAOD::TrigCompositeContainer>& decisionEL : item.decisionLinks) {
165 TrigCompositeUtils::decisionIDs(*decisionEL, item.decisionIDs);
166 }
167 }
168
169 if (msgLvl(MSG::DEBUG)) {
170 ATH_MSG_DEBUG( "Dump found muons before vertex fit: " << muons.size() << " candidates" );
171 for (const auto& item : muons) {
172 const xAOD::Muon* muon = *item.link;
173 const xAOD::TrackParticle* track = muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
174 ATH_MSG_DEBUG( " -- muon InDetTrackParticle pt/eta/phi/q: " << track->pt() << " / " << track->eta() << " / " << track->phi() << " / " << track->charge() );
175 ATH_MSG_DEBUG( " muon CombinedTrackParticle pt: " << muon->pt() );
176 ATH_MSG_DEBUG( " allowed decisions:" );
177 for (const DecisionID& id : item.decisionIDs) {
178 ATH_MSG_DEBUG( " +++ " << HLT::Identifier(id) );
179 }
180 }
181 }
182
183 return StatusCode::SUCCESS;
184}
185
186
188
189 auto& tracks = state.tracks;
190 tracks.clear();
191
192 size_t viewCounter = 0;
193 for (const Decision* decision : state.previousDecisions()) {
194 auto viewLinkInfo = TrigCompositeUtils::findLink<ViewContainer>(state.context(), decision, TrigCompositeUtils::viewString(), true);
195 ATH_CHECK( viewLinkInfo.isValid() );
196 auto view = *viewLinkInfo.link;
197
199 ATH_CHECK( roiLinkInfo.isValid() );
200 const auto roi = *roiLinkInfo.link;
201
202 auto tracksHandle = ViewHelper::makeHandle(view, m_trackParticleContainerKey, state.context());
203 ATH_CHECK( tracksHandle.isValid() );
204 ATH_MSG_DEBUG( "tracks handle " << m_trackParticleContainerKey << " size: " << tracksHandle->size() );
205
206 std::vector<ElementLink<xAOD::TrackParticleContainer>> tracksFromView;
207 tracksFromView.reserve(tracksHandle->size());
208 for (size_t idx = 0; idx < tracksHandle->size(); ++idx) {
209 tracksFromView.emplace_back(ViewHelper::makeLink<xAOD::TrackParticleContainer>(view, tracksHandle, idx));
210 }
211
212 for (const auto& trackEL : tracksFromView) {
213 const xAOD::TrackParticle* track = *trackEL;
214 if (track->definingParametersCovMatrixVec().empty()) continue;
215
216 if (viewCounter == 0 ||
217 std::find_if(tracks.begin(), tracks.end(),
218 [this, track](const auto& x){ return isIdenticalTracks(track, *x); }) == tracks.end()) {
219 tracks.emplace_back(trackEL);
220 }
221 }
222 viewCounter++;
223 if (roi->composite()) {
224 state.isCompositeRoI = true;
225 break;
226 }
227 }
228 std::sort(tracks.begin(), tracks.end(), [](const auto& lhs, const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
229
230 if (msgLvl(MSG::DEBUG)) {
231 ATH_MSG_DEBUG( "Dump found tracks before vertex fit: " << tracks.size() << " candidates" );
232 for (const auto& trackEL : tracks) {
233 const xAOD::TrackParticle* track = *trackEL;
234 ATH_MSG_DEBUG( " -- track pt/eta/phi/q: " << track->pt() << " / " << track->eta() << " / " << track->phi() << " / " << track->charge() );
235 }
236 }
237 return StatusCode::SUCCESS;
238}
239
240
242
243 auto mon_nDimuon = Monitored::Scalar<int>("nDimuon", 0);
244 auto group = Monitored::Group(m_monTool, mon_nDimuon);
245
246 const auto& muons = state.muons;
247 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks(2);
248 std::vector<const DecisionIDContainer*> previousDecisionIDs(2, nullptr);
249
250 for (size_t itrk1 = 0; itrk1 < muons.size(); ++itrk1) {
251 const xAOD::Muon* mu1 = *muons[itrk1].link;
252 trackParticleLinks[0] = ::linkTrack(mu1->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
253 previousDecisionIDs[0] = &muons[itrk1].decisionIDs;
254 const xAOD::TrackParticle* trk1 = *trackParticleLinks[0];
255 auto p1 = trk1->genvecP4();
256 p1.SetM(PDG::mMuon);
257 auto charge1 = trk1->charge();
258
259 for (size_t itrk2 = itrk1 + 1; itrk2 < muons.size(); ++itrk2) {
260 const xAOD::Muon* mu2 = *muons[itrk2].link;
261 trackParticleLinks[1] = ::linkTrack(mu2->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
262 //cppcheck-suppress objectIndex
263 previousDecisionIDs[1] = &muons[itrk2].decisionIDs;
264 const xAOD::TrackParticle* trk2 = *trackParticleLinks[1];
265 auto p2 = trk2->genvecP4();
266 p2.SetM(PDG::mMuon);
267 auto charge2 = trk2->charge();
268
269 double mass = (p1 + p2).M();
270
271 ATH_MSG_DEBUG( "muon 1: " << p1.Pt()<< " / " << p1.Eta() << " / " << p1.Phi() << " / " << trk1->charge() );
272 ATH_MSG_DEBUG( "muon 2: " << p2.Pt()<< " / " << p2.Eta() << " / " << p2.Phi() << " / " << trk2->charge() );
273 ATH_MSG_DEBUG( "track pair mass: " << mass );
274
275 if (m_dimuon_rejectSameChargeTracks && charge1 * charge2 > 0.) {
276 ATH_MSG_DEBUG( "muon pair is rejected by opposite charge check" );
277 continue;
278 }
279
280 if (!passDimuonTrigger(previousDecisionIDs)) {
281 ATH_MSG_DEBUG( "muon pair did not pass passDimuonTrigger() check" );
282 continue;
283 }
284
285 if (!isInMassRange(mass, m_dimuon_massRange)) {
286 ATH_MSG_DEBUG( "muon pair is out of the requested mass range" );
287 continue;
288 }
289
290 // fit muons to the common vertex and pass this vertex to the dimuons collection which also takes the ownership of the created object
291 auto vertex = fit(state.context(), trackParticleLinks);
292 if (!vertex) continue;
293
294 // convert vertex to trigger object and add it to the output xAOD::TrigBphysContainer
295 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vertex);
296 if (!trigBphys) {
297 ATH_MSG_ERROR( "xAOD::Vertex could not be converted to xAOD::TrigBphys object: please enable MakeExtendedVertex option in vertex fitter " << m_vertexFitter->name() );
298 return StatusCode::FAILURE;
299 }
300
301 // the dimuon vertex in the xAOD::TrigBphysContainer is used as a reference for the upcoming B-candidates and to fire bBmumux_idperf chain
302 state.dimuons.push_back(vertex.release());
303 state.trigBphysMuonIndices.emplace_back(std::array<size_t, 2>{itrk1, itrk2});
304 state.trigBphysCollection().push_back(trigBphys);
305 }
306 }
307 mon_nDimuon = state.dimuons.size();
308 ATH_MSG_DEBUG( "Found " << state.dimuons.size() << " dimuon candidates" );
309
310 return StatusCode::SUCCESS;
311}
312
313
315
316 std::vector<int> nSelectedTrk;
317 auto mon_nTrk = Monitored::Scalar<int>("nTrk", 0);
318 auto mon_nSelectedTrk = Monitored::Collection("nSelectedTrk", nSelectedTrk);
319 auto mon_nBPhysObject = Monitored::Scalar<int>("nBPhysObject", 0);
320 auto group = Monitored::Group(m_monTool, mon_nTrk, mon_nSelectedTrk, mon_nBPhysObject);
321
322 for (size_t dimuonIndex = 0; dimuonIndex < state.dimuons.size(); ++dimuonIndex) {
323
324 ATH_CHECK( findBmumuxCandidates_selectTracks(state, dimuonIndex) );
325 if (state.selectedTracks.empty()) continue;
326 nSelectedTrk.push_back(state.selectedTracks.size());
327
328 ATH_CHECK( findBmumuxCandidates_fit(state, dimuonIndex, true) );
329 ATH_CHECK( findBmumuxCandidates_fastFit(state, dimuonIndex) );
330 ATH_CHECK( findBmumuxCandidates_fit(state, dimuonIndex) );
331 }
332
333 mon_nTrk = state.tracks.size();
334 mon_nBPhysObject = state.trigBphysCollection().size() - state.dimuons.size();
335
336 return StatusCode::SUCCESS;
337}
338
339
341
342 auto& selectedTracks = state.selectedTracks;
343 auto& selectedTrackZ0 = state.selectedTrackZ0;
344
345 selectedTracks.clear();
346 selectedTrackZ0.clear();
347
348 const xAOD::Vertex* dimuon = state.dimuons.get(dimuonIndex);
349
350 std::vector<const xAOD::Muon*> muons(2, nullptr);
351 const auto& muonIndices = state.trigBphysMuonIndices.at(dimuonIndex);
352 for (size_t i = 0; i < 2; ++i) {
353 const auto& muon = state.muons.at(muonIndices[i]);
354 muons[i] = *muon.link;
355 }
356
357 const xAOD::TrackParticle* mu1 = dimuon->trackParticle(0);
358 const xAOD::TrackParticle* mu2 = dimuon->trackParticle(1);
359
360 // check impact parameter of the track with respect to the fitted dimuon vertex
361 // we can safely omit tracks with large z0
362 state.selectedTracks.reserve(state.tracks.size());
363 for (const auto& trackEL : state.tracks) {
364 if (state.isCompositeRoI && !isInSameRoI(muons[0], *trackEL) && !isInSameRoI(muons[1], *trackEL)) continue;
365 if (m_trkZ0 > 0.) {
366 std::unique_ptr<const Trk::Perigee> perigee(m_trackToVertexTool->perigeeAtVertex(state.context(), **trackEL, dimuon->position()));
367 if (perigee && std::abs(perigee->parameters()[Trk::z0]) < m_trkZ0) {
368 selectedTracks.push_back(trackEL);
369 selectedTrackZ0[*trackEL] = perigee->parameters()[Trk::z0];
370 }
371 }
372 else {
373 selectedTracks.push_back(trackEL);
374 selectedTrackZ0[*trackEL] = -1000.;
375 }
376 }
377
378 // remove muon duplicates
379 if (selectedTracks.size() < 2) {
380 ATH_MSG_DEBUG( "Found no tracks consistent with dimuon vertex " << dimuonIndex );
381 selectedTracks.clear();
382 selectedTrackZ0.clear();
383 return StatusCode::SUCCESS;
384 }
385 std::sort(selectedTracks.begin(), selectedTracks.end(), [p_mu=mu1->genvecP4()](const auto& lhs, const auto& rhs){ return ROOT::Math::VectorUtil::DeltaR(p_mu, (*lhs)->genvecP4()) > ROOT::Math::VectorUtil::DeltaR(p_mu, (*rhs)->genvecP4()); });
386 if (isIdenticalTracks(mu1, *selectedTracks.back())) selectedTracks.pop_back();
387 std::sort(selectedTracks.begin(), selectedTracks.end(), [p_mu=mu2->genvecP4()](const auto& lhs, const auto& rhs){ return ROOT::Math::VectorUtil::DeltaR(p_mu, (*lhs)->genvecP4()) > ROOT::Math::VectorUtil::DeltaR(p_mu, (*rhs)->genvecP4()); });
388 if (isIdenticalTracks(mu2, *selectedTracks.back())) selectedTracks.pop_back();
389 std::sort(selectedTracks.begin(), selectedTracks.end(), [](const auto& lhs, const auto& rhs){ return ((*lhs)->pt() > (*rhs)->pt()); });
390
391 ATH_MSG_DEBUG( "Found " << selectedTracks.size() << " tracks consistent with dimuon vertex " << dimuonIndex );
392
393 return StatusCode::SUCCESS;
394}
395
396
397StatusCode TrigBmumuxComboHypo::findBmumuxCandidates_fit(TrigBmumuxState& state, size_t dimuonIndex, bool makeCombinations) const {
398
399 const auto& selectedTracks = state.selectedTracks;
400 if (makeCombinations) state.trackCombinations.clear();
401
402 const xAOD::Vertex* dimuon = state.dimuons.get(dimuonIndex);
403 auto dimuonTriggerObjectEL = ElementLink<xAOD::TrigBphysContainer>(state.trigBphysCollection(), dimuonIndex);
404 ATH_CHECK( dimuonTriggerObjectEL.isValid() );
405
406 // vtx1 = {mu1, mu2, trk1}
407 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_vtx1(dimuon->trackParticleLinks());
408 trackParticleLinks_vtx1.emplace_back();
409
410 // vtx2 = {mu1, mu2, trk1, trk2}
411 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_vtx2(trackParticleLinks_vtx1);
412 trackParticleLinks_vtx2.emplace_back();
413
414 // vtx3 = {trk1, trk2, trk3}
415 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_vtx3(3);
416
417 const xAOD::TrackParticle* mu1 = *trackParticleLinks_vtx1[0];
418 const xAOD::TrackParticle* mu2 = *trackParticleLinks_vtx1[1];
419 auto p_dimuon = mu1->genvecP4().SetM(PDG::mMuon) + mu2->genvecP4().SetM(PDG::mMuon);
420
421 size_t iterations = 0;
422 size_t nTrigBphysObjects = state.trigBphysCollection().size();
423 bool isOverWarningThreshold = false;
424 // dimuon + 1 track
425 for (size_t itrk1 = 0; itrk1 < selectedTracks.size(); ++itrk1) {
426 const xAOD::TrackParticle* trk1 = *selectedTracks[itrk1];
427
428 trackParticleLinks_vtx1[2] = selectedTracks[itrk1];
429 auto p_trk1 = trk1->genvecP4();
430 auto charge1 = trk1->charge();
431
432 std::unique_ptr<xAOD::Vertex> vtx1;
433 bool makeFit_vtx1 = !makeCombinations;
434 bool passFastFit_vtx1 = (!makeCombinations && !state.isBadCombination(itrk1));
435
436 // B+ -> mu+ mu- K+
437 if (m_BplusToMuMuKaon &&
438 p_trk1.Pt() > m_BplusToMuMuKaon_minKaonPt &&
439 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mKaon)).M(), m_BplusToMuMuKaon_massRange)) {
440
441 if (makeCombinations && m_BplusToMuMuKaon_useFastFit) state.addTrackCombination(itrk1);
442 if (!vtx1 && makeFit_vtx1 && (passFastFit_vtx1 || !m_BplusToMuMuKaon_useFastFit)) {
443 vtx1 = fit(state.context(), trackParticleLinks_vtx1, kB_2mu1trk, dimuon);
444 makeFit_vtx1 = false;
445 ++iterations;
446 }
447 if (vtx1 && vtx1->chiSquared() < m_BplusToMuMuKaon_chi2) {
448 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx1, xAOD::TrigBphys::BKMUMU, {PDG::mMuon, PDG::mMuon, PDG::mKaon}, dimuonTriggerObjectEL);
449 ATH_CHECK( state.addTriggerObject(trigBphys) );
450 }
451 }
452
453 // B_c+ -> J/psi(-> mu+ mu-) pi+
454 if (m_BcToMuMuPion &&
455 p_trk1.Pt() > m_BcToMuMuPion_minPionPt &&
457 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mPion)).M() - p_dimuon.M() + PDG::mJpsi, m_BcToMuMuPion_massRange)) {
458
459 if (makeCombinations && m_BcToMuMuPion_useFastFit) state.addTrackCombination(itrk1);
460 if (!vtx1 && makeFit_vtx1 && (passFastFit_vtx1 || !m_BcToMuMuPion_useFastFit)) {
461 vtx1 = fit(state.context(), trackParticleLinks_vtx1, kB_2mu1trk, dimuon);
462 makeFit_vtx1 = false;
463 ++iterations;
464 }
465 if (vtx1 && vtx1->chiSquared() < m_BcToMuMuPion_chi2) {
466 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx1, xAOD::TrigBphys::BCPIMUMU, {PDG::mMuon, PDG::mMuon, PDG::mPion}, dimuonTriggerObjectEL);
467 ATH_CHECK( state.addTriggerObject(trigBphys) );
468 }
469 }
470 vtx1.reset();
471
472 // dimuon + 2 tracks
473 for (size_t itrk2 = itrk1 + 1; itrk2 < selectedTracks.size(); ++itrk2) {
474 const xAOD::TrackParticle* trk2 = *selectedTracks[itrk2];
475
476 trackParticleLinks_vtx2[2] = selectedTracks[itrk1];
477 trackParticleLinks_vtx2[3] = selectedTracks[itrk2];
478 auto p_trk2 = trk2->genvecP4();
479 auto charge2 = trk2->charge();
480
481 std::unique_ptr<xAOD::Vertex> vtx2;
482 bool makeFit_vtx2 = !makeCombinations;
483 bool passFastFit_vtx2 = (!makeCombinations && !state.isBadCombination(itrk1) && !state.isBadCombination(itrk2));
484
485 // B_s0 -> mu+ mu- phi(-> K+ K-)
486 if (m_BsToMuMuPhi1020 &&
487 (!m_BsToMuMuPhi1020_rejectSameChargeTracks || charge1 * charge2 < 0.) &&
488 p_trk1.Pt() > m_BsToMuMuPhi1020_minKaonPt &&
489 p_trk2.Pt() > m_BsToMuMuPhi1020_minKaonPt &&
490 isInMassRange((p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mKaon)).M(), m_BsToMuMuPhi1020_phiMassRange) &&
491 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mKaon)).M(), m_BsToMuMuPhi1020_massRange)) {
492
493 if (makeCombinations && m_BsToMuMuPhi1020_useFastFit) {
494 state.addTrackCombination(itrk1);
495 state.addTrackCombination(itrk2);
496 }
497 if (!vtx2 && makeFit_vtx2 && (passFastFit_vtx2 || !m_BsToMuMuPhi1020_useFastFit)) {
498 vtx2 = fit(state.context(), trackParticleLinks_vtx2, kB_2mu2trk, dimuon);
499 makeFit_vtx2 = false;
500 ++iterations;
501 }
502 if (vtx2 && vtx2->chiSquared() < m_BsToMuMuPhi1020_chi2) {
503 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx2, xAOD::TrigBphys::BSPHIMUMU, {PDG::mMuon, PDG::mMuon, PDG::mKaon, PDG::mKaon}, dimuonTriggerObjectEL);
504 ATH_CHECK( state.addTriggerObject(trigBphys) );
505 }
506 }
507
508 // B0 -> mu+ mu- K*0(-> K+ pi-)
509 if (m_BdToMuMuKstar0 &&
510 (!m_BdToMuMuKstar0_rejectSameChargeTracks || charge1 * charge2 < 0.) &&
511 p_trk1.Pt() > m_BdToMuMuKstar0_minKaonPt &&
512 p_trk2.Pt() > m_BdToMuMuKstar0_minPionPt &&
513 isInMassRange((p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mPion)).M(), m_BdToMuMuKstar0_KstarMassRange) &&
514 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mPion)).M(), m_BdToMuMuKstar0_massRange)) {
515
516 if (makeCombinations && m_BdToMuMuKstar0_useFastFit) {
517 state.addTrackCombination(itrk1);
518 state.addTrackCombination(itrk2);
519 }
520 if (!vtx2 && makeFit_vtx2 && (passFastFit_vtx2 || !m_BdToMuMuKstar0_useFastFit)) {
521 vtx2 = fit(state.context(), trackParticleLinks_vtx2, kB_2mu2trk, dimuon);
522 makeFit_vtx2 = false;
523 ++iterations;
524 }
525 if (vtx2 && vtx2->chiSquared() < m_BdToMuMuKstar0_chi2) {
526 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx2, xAOD::TrigBphys::BDKSTMUMU, {PDG::mMuon, PDG::mMuon, PDG::mKaon, PDG::mPion}, dimuonTriggerObjectEL);
527 ATH_CHECK( state.addTriggerObject(trigBphys) );
528 }
529 }
530 // anti-B0 -> mu+ mu- anti-K*0(-> K- pi+)
531 if (m_BdToMuMuKstar0 &&
532 (!m_BdToMuMuKstar0_rejectSameChargeTracks || charge1 * charge2 < 0.) &&
533 p_trk1.Pt() > m_BdToMuMuKstar0_minPionPt &&
534 p_trk2.Pt() > m_BdToMuMuKstar0_minKaonPt &&
535 isInMassRange((p_trk1.SetM(PDG::mPion) + p_trk2.SetM(PDG::mKaon)).M(), m_BdToMuMuKstar0_KstarMassRange) &&
536 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mPion) + p_trk2.SetM(PDG::mKaon)).M(), m_BdToMuMuKstar0_massRange)) {
537
538 if (makeCombinations && m_BdToMuMuKstar0_useFastFit) {
539 state.addTrackCombination(itrk1);
540 state.addTrackCombination(itrk2);
541 }
542 if (!vtx2 && makeFit_vtx2 && (passFastFit_vtx2 || !m_BdToMuMuKstar0_useFastFit)) {
543 vtx2 = fit(state.context(), trackParticleLinks_vtx2, kB_2mu2trk, dimuon);
544 makeFit_vtx2 = false;
545 ++iterations;
546 }
547 if (vtx2 && vtx2->chiSquared() < m_BdToMuMuKstar0_chi2) {
548 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx2, xAOD::TrigBphys::BDKSTMUMU, {PDG::mMuon, PDG::mMuon, PDG::mPion, PDG::mKaon}, dimuonTriggerObjectEL);
549 ATH_CHECK( state.addTriggerObject(trigBphys) );
550 }
551 }
552
553 // Lambda_b0 -> J/psi(-> mu+ mu-) p K-
557 (p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mPion)).M() > m_LambdaBToMuMuProtonKaon_minKstarMass &&
558 (p_trk1.SetM(PDG::mPion) + p_trk2.SetM(PDG::mKaon)).M() > m_LambdaBToMuMuProtonKaon_minKstarMass &&
560 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mProton) + p_trk2.SetM(PDG::mKaon)).M() - p_dimuon.M() + PDG::mJpsi, m_LambdaBToMuMuProtonKaon_massRange)) {
561
562 if (makeCombinations && m_LambdaBToMuMuProtonKaon_useFastFit) {
563 state.addTrackCombination(itrk1);
564 state.addTrackCombination(itrk2);
565 }
566 if (!vtx2 && makeFit_vtx2 && (passFastFit_vtx2 || !m_LambdaBToMuMuProtonKaon_useFastFit)) {
567 vtx2 = fit(state.context(), trackParticleLinks_vtx2, kB_2mu2trk, dimuon);
568 makeFit_vtx2 = false;
569 ++iterations;
570 }
571 if (vtx2 && vtx2->chiSquared() < m_LambdaBToMuMuProtonKaon_chi2 && Lxy(state.beamSpotPosition(), *vtx2) > 0.) {
572 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx2, xAOD::TrigBphys::LBPQMUMU, {PDG::mMuon, PDG::mMuon, PDG::mProton, PDG::mKaon}, dimuonTriggerObjectEL);
573 ATH_CHECK( state.addTriggerObject(trigBphys) );
574 }
575 }
576 // anti-Lambda_b0 -> J/psi(-> mu+ mu-) anti-p K+
580 (p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mPion)).M() > m_LambdaBToMuMuProtonKaon_minKstarMass &&
581 (p_trk1.SetM(PDG::mPion) + p_trk2.SetM(PDG::mKaon)).M() > m_LambdaBToMuMuProtonKaon_minKstarMass &&
583 isInMassRange((p_dimuon + p_trk1.SetM(PDG::mKaon) + p_trk2.SetM(PDG::mProton)).M() - p_dimuon.M() + PDG::mJpsi, m_LambdaBToMuMuProtonKaon_massRange)) {
584
585 if (makeCombinations && m_LambdaBToMuMuProtonKaon_useFastFit) {
586 state.addTrackCombination(itrk1);
587 state.addTrackCombination(itrk2);
588 }
589 if (!vtx2 && makeFit_vtx2 && (passFastFit_vtx2 || !m_LambdaBToMuMuProtonKaon_useFastFit)) {
590 vtx2 = fit(state.context(), trackParticleLinks_vtx2, kB_2mu2trk, dimuon);
591 makeFit_vtx2 = false;
592 ++iterations;
593 }
594 if (vtx2 && vtx2->chiSquared() < m_LambdaBToMuMuProtonKaon_chi2 && Lxy(state.beamSpotPosition(), *vtx2) > 0.) {
595 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx2, xAOD::TrigBphys::LBPQMUMU, {PDG::mMuon, PDG::mMuon, PDG::mKaon, PDG::mProton}, dimuonTriggerObjectEL);
596 ATH_CHECK( state.addTriggerObject(trigBphys) );
597 }
598 }
599 vtx2.reset();
600
601 for (size_t itrk3 = 0; itrk3 < selectedTracks.size(); ++itrk3) {
602 const xAOD::TrackParticle* trk3 = *selectedTracks[itrk3];
603 if (itrk3 == itrk1 || itrk3 == itrk2) continue;
604
605 trackParticleLinks_vtx3[0] = selectedTracks[itrk1];
606 trackParticleLinks_vtx3[1] = selectedTracks[itrk2];
607 trackParticleLinks_vtx3[2] = selectedTracks[itrk3];
608 auto p_trk3 = trk3->genvecP4();
609 auto charge3 = trk3->charge();
610
611 std::unique_ptr<xAOD::Vertex> vtx3;
612 bool makeFit_vtx3 = !makeCombinations;
613 bool passFastFit_vtx3 = (!makeCombinations && !state.isBadCombination(itrk1, itrk2, itrk3));
614
615 // B_c+ -> J/psi(-> mu+ mu-) D_s+(->phi(-> K+ K-) pi+)
616 p_trk1.SetM(PDG::mKaon); // D_s+.phi.K+
617 p_trk2.SetM(PDG::mKaon); // D_s+.phi.K-
618 p_trk3.SetM(PDG::mPion); // D_s+.pi+
619 if (m_BcToDsMuMu &&
620 charge1 * charge2 < 0. &&
621 p_trk1.Pt() > m_BcToDsMuMu_minKaonPt &&
622 p_trk2.Pt() > m_BcToDsMuMu_minKaonPt &&
623 p_trk3.Pt() > m_BcToDsMuMu_minPionPt &&
625 isInMassRange((p_trk1 + p_trk2).M(), m_BcToDsMuMu_phiMassRange) &&
626 isInMassRange((p_trk1 + p_trk2 + p_trk3).M(), m_BcToDsMuMu_DsMassRange) &&
627 isInMassRange((p_dimuon + p_trk1 + p_trk2 + p_trk3).M() - p_dimuon.M() + PDG::mJpsi, m_BcToDsMuMu_massRange)) {
628
629 if (makeCombinations && m_BcToDsMuMu_useFastFit) state.addTrackCombination(itrk1, itrk2, itrk3);
630 if (!vtx3 && makeFit_vtx3 && (passFastFit_vtx3 || !m_BcToDsMuMu_useFastFit)) {
631 vtx3 = fit(state.context(), trackParticleLinks_vtx3, kDs, dimuon);
632 makeFit_vtx3 = false;
633 ++iterations;
634 }
635 if (vtx3 && vtx3->chiSquared() < m_BcToDsMuMu_chi2) {
636 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx3, xAOD::TrigBphys::BCDSMUMU, {PDG::mKaon, PDG::mKaon, PDG::mPion}, dimuonTriggerObjectEL);
637 ATH_CHECK( state.addTriggerObject(trigBphys) );
638 }
639 }
640
641 // B_c+ -> J/psi(-> mu+ mu-) D+(-> K- pi+ pi+)
642 p_trk1.SetM(PDG::mPion); // D+.pi+
643 p_trk2.SetM(PDG::mPion); // D+.pi+
644 p_trk3.SetM(PDG::mKaon); // D+.K-
645 if (m_BcToDplusMuMu &&
646 charge1 * charge2 > 0. && charge1 * charge3 < 0. &&
647 p_trk1.Pt() > m_BcToDplusMuMu_minPionPt &&
648 p_trk2.Pt() > m_BcToDplusMuMu_minPionPt &&
649 p_trk3.Pt() > m_BcToDplusMuMu_minKaonPt &&
651 isInMassRange((p_trk1 + p_trk2 + p_trk3).M(), m_BcToDplusMuMu_DplusMassRange) &&
652 isInMassRange((p_dimuon + p_trk1 + p_trk2 + p_trk3).M() - p_dimuon.M() + PDG::mJpsi, m_BcToDplusMuMu_massRange)) {
653
654 if (makeCombinations && m_BcToDplusMuMu_useFastFit) state.addTrackCombination(itrk1, itrk2, itrk3);
655 if (!vtx3 && makeFit_vtx3 && (passFastFit_vtx3 || !m_BcToDplusMuMu_useFastFit)) {
656 vtx3 = fit(state.context(), trackParticleLinks_vtx3, kDplus, dimuon);
657 makeFit_vtx3 = false;
658 ++iterations;
659 }
660 if (vtx3 && vtx3->chiSquared() < m_BcToDplusMuMu_chi2 && Lxy(dimuon->position(), *vtx3) > 0.) {
661 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *vtx3, xAOD::TrigBphys::BCDPMUMU, {PDG::mPion, PDG::mPion, PDG::mKaon}, dimuonTriggerObjectEL);
662 ATH_CHECK( state.addTriggerObject(trigBphys) );
663 }
664 }
665 vtx3.reset();
666
667 }
668 }
669
670 if (iterations > m_fitAttemptsWarningThreshold && !isOverWarningThreshold) {
671 ATH_MSG_WARNING( "Dimuon + tracks: " << state.trigBphysCollection().size() - nTrigBphysObjects << " vertices created after " << iterations << " vertex fitter calls" );
672 isOverWarningThreshold = true;
673 }
674 if (iterations > m_fitAttemptsBreakThreshold) {
675 ATH_MSG_WARNING( "Dimuon + tracks: the number of fit attempts has exceeded the limit; breaking the loop at this point" );
676 break;
677 }
678 }
679 ATH_MSG_DEBUG( "Dimuon + tracks: " << state.trigBphysCollection().size() - nTrigBphysObjects << " vertices created after " << iterations << " vertex fitter calls" );
680
681 iterations = 0;
682 nTrigBphysObjects = state.trigBphysCollection().size();
683 isOverWarningThreshold = false;
684 // B_c+ -> J/psi(-> mu+ mu-) D*+(-> D0(-> K- pi+) pi+)
685 if (!makeCombinations && m_BcToDstarMuMu && isInMassRange(p_dimuon.M(), m_BcToDstarMuMu_dimuonMassRange)) {
686 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_D0(2); // {K-, pi+}
687
688 for (size_t itrk1 = 0; itrk1 < selectedTracks.size(); ++itrk1) {
689 const xAOD::TrackParticle* trk1 = *selectedTracks[itrk1];
690
691 trackParticleLinks_D0[0] = selectedTracks[itrk1];
692 auto p_trk1 = trk1->genvecP4();
693 p_trk1.SetM(PDG::mKaon);
694 auto charge1 = trk1->charge();
695
696 for (size_t itrk2 = 0; itrk2 < selectedTracks.size(); ++itrk2) {
697 if (itrk2 == itrk1) continue;
698 const xAOD::TrackParticle* trk2 = *selectedTracks[itrk2];
699
700 trackParticleLinks_D0[1] = selectedTracks[itrk2];
701 auto p_trk2 = trk2->genvecP4();
702 p_trk2.SetM(PDG::mPion);
703 auto charge2 = trk2->charge();
704
705 std::unique_ptr<xAOD::Vertex> D0;
706 if (charge1 * charge2 < 0. &&
707 p_trk1.Pt() > m_BcToDstarMuMu_minD0KaonPt &&
708 p_trk2.Pt() > m_BcToDstarMuMu_minD0PionPt &&
709 isInMassRange((p_trk1 + p_trk2).M(), m_BcToDstarMuMu_D0MassRange) &&
710 isInMassRange((p_dimuon + p_trk1 + p_trk2).M() - p_dimuon.M() + PDG::mJpsi, m_BcToDstarMuMu_massRange)) {
711 D0 = fit(state.context(), trackParticleLinks_D0, kD0, dimuon);
712 ++iterations;
713 }
714 bool isValidD0 = false;
715 if (D0 && D0->chiSquared() < m_BcToDstarMuMu_chi2 && Lxy(dimuon->position(), *D0) > 0.) {
716 isValidD0 = true;
717 ATH_MSG_DEBUG( "Partially reconstructed B_c+(-> mu+ mu- D0 X) candidate has been created" );
718 xAOD::TrigBphys* trigBphys = makeTriggerObject(state, *D0, xAOD::TrigBphys::DZKPI, s_trkMass[kD0], dimuonTriggerObjectEL);
719 ATH_CHECK( state.addTriggerObject(trigBphys) );
720 }
721
722 if (m_BcToDstarMuMu_makeDstar && isValidD0) { // full B_c+ reconstruction
724
725 for (size_t itrk3 = 0; itrk3 < selectedTracks.size(); ++itrk3) {
726 const xAOD::TrackParticle* trk3 = *selectedTracks[itrk3];
727 if (itrk3 == itrk1 || itrk3 == itrk2) continue;
728
729 // J/psi + pion from D*+
730 trackParticleLinks_vtx1[2] = selectedTracks[itrk3];
731 auto p_trk3 = trk3->genvecP4();
732 p_trk3.SetM(PDG::mPion);
733
734 if (p_trk3.Pt() > m_BcToDstarMuMu_minDstarPionPt &&
736 isInMassRange((p_D0 + p_trk3).M() - p_D0.M() + PDG::mD0, m_BcToDstarMuMu_DstarMassRange)) {
737 auto Bc_vtx1 = fit(state.context(), trackParticleLinks_vtx1, kB_PsiPi);
738 ++iterations;
739
740 if (Bc_vtx1 && Bc_vtx1->chiSquared() < m_BcToDstarMuMu_chi2) {
741 ATH_MSG_DEBUG( "Decay vertex(mu+ mu- D*+.pi+) for B_c+ candidate has been created" );
742 xAOD::TrigBphys* triggerObject_vtx1 = makeTriggerObject(state, *Bc_vtx1, xAOD::TrigBphys::DSTDZPI, s_trkMass[kB_PsiPi], dimuonTriggerObjectEL);
743 auto triggerObjectEL_vtx1 = ElementLink<xAOD::TrigBphysContainer>(state.trigBphysCollection(), state.trigBphysCollection().size());
744 ATH_CHECK( state.addTriggerObject(triggerObject_vtx1) );
745 ATH_CHECK( triggerObjectEL_vtx1.isValid() );
746
747 // refit D0 vertex
748 auto Bc_vtx2 = fit(state.context(), trackParticleLinks_D0, kD0, Bc_vtx1.get());
749 ++iterations;
750 if (Bc_vtx2 && Bc_vtx2->chiSquared() < m_BcToDstarMuMu_chi2) {
751 ATH_MSG_DEBUG( "Fully reconstructed B_c+(-> mu+ mu- D*+) candidate has been created" );
752 xAOD::TrigBphys* triggerObject_vtx2 = makeTriggerObject(state, *Bc_vtx2, xAOD::TrigBphys::BCDSTMUMU, s_trkMass[kD0], triggerObjectEL_vtx1);
753 ATH_CHECK( state.addTriggerObject(triggerObject_vtx2) );
754 }
755 }
756 }
757 }
758 } // end of full B_c+ reconstruction
759
760 }
761
762 if (iterations > m_fitAttemptsWarningThreshold && !isOverWarningThreshold) {
763 ATH_MSG_WARNING( "B_c+ -> mu+ mu- D*+: " << state.trigBphysCollection().size() - nTrigBphysObjects << " vertices created after " << iterations << " vertex fitter calls" );
764 isOverWarningThreshold = true;
765 }
766 if (iterations > m_fitAttemptsBreakThreshold) {
767 ATH_MSG_WARNING( "B_c+ -> mu+ mu- D*+: the number of fit attempts has exceeded the limit; breaking the loop at this point" );
768 break;
769 }
770 }
771 ATH_MSG_DEBUG( "B_c+ -> mu+ mu- D*+: " << state.trigBphysCollection().size() - nTrigBphysObjects << " vertices created after " << iterations << " vertex fitter calls" );
772
773 } // end of B_c+ -> J/psi D*+ topology
774
775 return StatusCode::SUCCESS;
776}
777
778
779StatusCode TrigBmumuxComboHypo::findBmumuxCandidates_fastFit(TrigBmumuxState& state, size_t dimuonIndex) const {
780
781 state.badTrackCombinations.clear();
782
783 const xAOD::Vertex* dimuon = state.dimuons.get(dimuonIndex);
784
785 // {mu1, mu2, trk1}
786 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_2mu1trk(dimuon->trackParticleLinks());
787 trackParticleLinks_2mu1trk.emplace_back();
788
789 // {trk1, trk2}
790 std::vector<ElementLink<xAOD::TrackParticleContainer>> trackParticleLinks_2trk(2);
791
792 size_t n = state.selectedTracks.size();
793 size_t iterations = 0;
794 for (const auto& item : state.trackCombinations) {
795 if (item.second < 5) continue;
796
797 size_t key = item.first;
798 if (key < n) { // dimuon + track
799 trackParticleLinks_2mu1trk[2] = state.selectedTracks[key];
800 auto vertex = fit(state.context(), trackParticleLinks_2mu1trk, kFastFit_2mu1trk, dimuon);
801 iterations++;
802 if (!vertex || vertex->chiSquared() > m_fastFit_2mu1trk_chi2) state.badTrackCombinations.push_back(key);
803 }
804 else { // track + track
805 trackParticleLinks_2trk[0] = state.selectedTracks[key % n];
806 trackParticleLinks_2trk[1] = state.selectedTracks[key / n];
807 auto vertex = fit(state.context(), trackParticleLinks_2trk, kFastFit_2trk);
808 iterations++;
809 if (!vertex || vertex->chiSquared() > m_fastFit_2trk_chi2) state.badTrackCombinations.push_back(key);
810 }
811 }
812 std::sort(state.badTrackCombinations.begin(), state.badTrackCombinations.end());
813 ATH_MSG_DEBUG( "Fast fit found " << state.badTrackCombinations.size() << " bad combinations after " << iterations << " iterations" );
814
815 return StatusCode::SUCCESS;
816}
817
818
820
821 for (const xAOD::TrigBphys* triggerObject : state.trigBphysCollection()) {
822 // skip the first vertex of the cascade decay B_c+(-> mu+ mu- D*+), it is already linked to the xAOD::TrigBphys::BCDSTMUMU trigger object via lowerChainLink()
823 if (triggerObject->particleType() == xAOD::TrigBphys::DSTDZPI) continue;
824
825 ATH_MSG_DEBUG( "Found xAOD::TrigBphys object: mass = " << triggerObject->mass() );
826
827 auto triggerObjectEL = ElementLink<xAOD::TrigBphysContainer>(state.trigBphysCollection(), triggerObject->index());
828 ATH_CHECK( triggerObjectEL.isValid() );
829
830 const xAOD::TrigBphys* dimuonTriggerObject = (triggerObject->particleType() == xAOD::TrigBphys::MULTIMU ? triggerObject : triggerObject->lowerChain());
831 if (triggerObject->particleType() == xAOD::TrigBphys::BCDSTMUMU && dimuonTriggerObject) dimuonTriggerObject = dimuonTriggerObject->lowerChain();
832 if (!dimuonTriggerObject) {
833 ATH_MSG_ERROR( "Failed to found a valid link for preceding dimuon trigger object" );
834 return StatusCode::FAILURE;
835 }
836
837 // need to get the references to the original muon objects used to build the dimuon vertex
838 // the position of this vertex in state.dimuons container is the same as for dimuonTriggerObject in trigBphysCollection
839 // dimuon vertex has already been decorated with muon indices
840 auto dimuonIndex = dimuonTriggerObject->index();
841 const xAOD::Vertex* dimuon = state.dimuons.get(dimuonIndex);
842 if ( !dimuon || dimuonIndex >= state.trigBphysMuonIndices.size() ) {
843 ATH_MSG_ERROR( "Failed to find original muons the dimuon vertex had been built from" );
844 return StatusCode::FAILURE;
845 }
846
847 // create a new output Decision object, backed by the 'decisions' container.
849
850 std::vector<const DecisionIDContainer*> previousDecisionIDs;
851 for (const size_t& i : state.trigBphysMuonIndices.at(dimuonIndex)) {
852 const auto& muon = state.muons.at(i);
853 // attach all previous decisions: if the same previous decision is called twice, that's fine - internally takes care of that
854 // we already have an array of links to the previous decisions, so there is no need to use TrigCompositeUtils::linkToPrevious()
855 decision->addObjectCollectionLinks(TrigCompositeUtils::seedString(), muon.decisionLinks);
856 previousDecisionIDs.push_back(&muon.decisionIDs);
857 }
858
859 // set mandatory link to the trigger object
861
862 for (const auto& tool : hypoTools()) {
863 ATH_MSG_DEBUG( "Go to " << tool );
864 ATH_CHECK( tool->decideOnSingleObject(decision, previousDecisionIDs) );
865 }
866 }
867
868 return StatusCode::SUCCESS;
869}
870
871
872std::unique_ptr<xAOD::Vertex> TrigBmumuxComboHypo::fit(
873 const EventContext& context,
874 const std::vector<ElementLink<xAOD::TrackParticleContainer>>& trackParticleLinks,
875 Decay decay,
876 const xAOD::Vertex* dimuon) const {
877
878 ATH_MSG_VERBOSE( "Perform vertex fit" );
879
880 if (trackParticleLinks.size() < 2) {
881 ATH_MSG_WARNING( "At least two tracks should be given to the vertex fitter" );
882 return nullptr;
883 }
884
885 std::vector<const xAOD::TrackParticle*> tracklist(trackParticleLinks.size(), nullptr);
886 std::transform(trackParticleLinks.begin(), trackParticleLinks.end(), tracklist.begin(),
887 [](const ElementLink<xAOD::TrackParticleContainer>& link){ return *link; });
888
889 Amg::Vector3D startingPoint = Amg::Vector3D::Zero(3);
890 if (dimuon) {
891 startingPoint = Amg::Vector3D(dimuon->x(), dimuon->y(), dimuon->z());
892 }
893 else {
894 if (decay != Decay::kPsi_2mu && decay != Decay::kB_PsiPi && decay != Decay::kFastFit_2trk) {
895 ATH_MSG_WARNING( "Already fitted dimuon vertex should be provided for B -> mu1 mu2 trk1 .. trkN decay as a starting point for fitter" );
896 }
897 int flag = 0;
898 int errorcode = 0;
899 const Trk::Perigee& perigee1 = tracklist[0]->perigeeParameters();
900 const Trk::Perigee& perigee2 = tracklist[1]->perigeeParameters();
901 startingPoint = m_vertexPointEstimator->getCirclesIntersectionPoint(&perigee1, &perigee2, flag, errorcode);
902 if (errorcode != 0) startingPoint = Amg::Vector3D::Zero(3);
903 }
904 ATH_MSG_VERBOSE( "Starting point: (" << startingPoint(0) << ", " << startingPoint(1) << ", " << startingPoint(2) << ")" );
905
906 auto fitterState = m_vertexFitter->makeState(context);
907 m_vertexFitter->setMassInputParticles(s_trkMass[static_cast<size_t>(decay)], *fitterState);
908
909 // the combined momentum of D+/D_s+ candidate is constrained to point to the dimuon vertex
910 if (dimuon && (decay == Decay::kDs || decay == Decay::kDplus || decay == Decay::kD0)) {
911 m_vertexFitter->setVertexForConstraint(*dimuon, *fitterState);
912 m_vertexFitter->setCnstType(8, *fitterState);
913 }
914
915 std::unique_ptr<xAOD::Vertex> vertex(m_vertexFitter->fit(tracklist, startingPoint, *fitterState));
916 if (!vertex) {
917 ATH_MSG_VERBOSE( "Vertex fit fails" );
918 return vertex;
919 }
920 if (vertex->chiSquared() > 150. || (decay == Decay::kPsi_2mu && vertex->chiSquared() > m_dimuon_chi2)) {
921 ATH_MSG_VERBOSE( "Fit is successful, but vertex chi2 is too high, we are not going to save it (chi2 = " << vertex->chiSquared() << ")" );
922 vertex.reset();
923 return vertex;
924 }
925 ATH_MSG_VERBOSE( "Fit is successful" );
926
927 // update trackParticleLinks()
928 vertex->clearTracks();
929 vertex->setTrackParticleLinks(trackParticleLinks);
930
931 return vertex;
932}
933
934
936 TrigBmumuxState& state,
937 const xAOD::Vertex& vertex,
939 const std::vector<double>& trkMass,
940 const ElementLink<xAOD::TrigBphysContainer>& dimuonLink) const {
941
942 const xAOD::TrigBphys* dimuon = (type != xAOD::TrigBphys::MULTIMU ? *dimuonLink : nullptr);
944
945 // refitted track momentum as a 4-vector for mass hypothesis defined by the given decay value
947 std::vector<xAOD::TrackParticle::GenVecFourMom_t> momenta;
948 if (!vertex.vxTrackAtVertexAvailable()) return nullptr;
949 for (size_t i = 0; i < vertex.vxTrackAtVertex().size(); ++i) {
950 const Trk::TrackParameters* perigee = vertex.vxTrackAtVertex()[i].perigeeAtVertex();
951 if (!perigee) return nullptr;
952 const Amg::Vector3D& p = perigee->momentum();
953 momenta.emplace_back(p.x(), p.y(), p.z(), trkMass[i]);
954 momentum += momenta.back();
955 }
956 if (isCascadeDecay) {
957 momentum += ROOT::Math::PtEtaPhiMVector(dimuon->pt(), dimuon->eta(), dimuon->phi(), dimuon->mass());
958 }
959
960 auto result = new xAOD::TrigBphys();
961 result->makePrivateStore();
962
963 float mass = momentum.M();
965 mass += PDG::mD0 - (momenta[0] + momenta[1]).M();
966 }
967 else if (type != xAOD::TrigBphys::MULTIMU) {
968 mass += PDG::mJpsi - (isCascadeDecay ? dimuon->mass() : (momenta[0] + momenta[1]).M());
969 }
970
971 result->initialise(0, momentum.Eta(), momentum.Phi(), momentum.Pt(), type, mass, xAOD::TrigBphys::EF);
972
973 result->setFitmass(momentum.M());
974 result->setFitx(vertex.x());
975 result->setFity(vertex.y());
976 result->setFitz(vertex.z());
977 result->setFitchi2(vertex.chiSquared());
978 result->setFitndof(vertex.numberDoF());
979
980 Amg::Vector3D productionVertex = (isCascadeDecay ? Amg::Vector3D(dimuon->fitx(), dimuon->fity(), dimuon->fitz()) : state.beamSpotPosition());
981 result->setLxy(Lxy(productionVertex, vertex));
982
983 // set all the particles associated with the decay
984 result->setTrackParticleLinks(vertex.trackParticleLinks());
985
986 // use lowerChainLink() as a link to the preceding dimuon trigger object
988 result->setLowerChainLink(dimuonLink);
989 }
990
992 "TrigBphys object:\n\t " <<
993 "roiId: " << result->roiId() << "\n\t " <<
994 "particleType: " << result->particleType() << "\n\t " <<
995 "level: " << result->level() << "\n\t " <<
996 "eta: " << result->eta() << "\n\t " <<
997 "phi: " << result->phi() << "\n\t " <<
998 "mass: " << result->mass() << "\n\t " <<
999 "fitmass: " << result->fitmass() << "\n\t " <<
1000 "chi2/NDF: " << result->fitchi2() << " / " << result->fitndof() << "\n\t " <<
1001 "vertex: (" << result->fitx() << ", " << result->fity() << ", " << result->fitz() << ")" << "\n\t " <<
1002 "Lxy: " << result->lxy() );
1003
1004 return result;
1005}
1006
1007
1009
1010 if (lhs->charge() * rhs->charge() < 0.) return false;
1011 return (ROOT::Math::VectorUtil::DeltaR(lhs->genvecP4(), rhs->genvecP4()) < m_deltaR);
1012}
1013
1014
1015bool TrigBmumuxComboHypo::isIdenticalTracks(const xAOD::Muon* lhs, const xAOD::Muon* rhs) const {
1016
1017 return isIdenticalTracks(lhs->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle),
1018 rhs->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
1019}
1020
1021
1023
1024 auto p_mu = muon->genvecP4();
1025 auto p_trk = track->genvecP4();
1026 return (ROOT::Math::VectorUtil::DeltaPhi(p_mu, p_trk) < m_roiPhiWidth && std::abs(p_mu.eta() - p_trk.eta()) < m_roiEtaWidth);
1027}
1028
1029
1030double TrigBmumuxComboHypo::Lxy(const Amg::Vector3D& productionVertex, const xAOD::Vertex& decayVertex) const {
1031
1032 XYVector R(decayVertex.x() - productionVertex.x(), decayVertex.y() - productionVertex.y());
1033 XYVector pT;
1034
1035 if (!decayVertex.vxTrackAtVertexAvailable()) return -100.;
1036 const auto& tracks = decayVertex.vxTrackAtVertex();
1037 for (const auto& track : tracks) {
1038 const Trk::TrackParameters* perigee = track.perigeeAtVertex();
1039 if (!perigee) return -100.;
1040 const Amg::Vector3D& momentum = perigee->momentum();
1041 pT += XYVector(momentum.x(), momentum.y());
1042 }
1043 return R.Dot(pT.unit());
1044}
1045
1046
1047xAOD::TrackParticle::GenVecFourMom_t TrigBmumuxComboHypo::momentum(const xAOD::Vertex& vertex, const std::vector<double>& trkMass) const {
1048
1050 for (size_t i = 0; i < vertex.vxTrackAtVertex().size(); ++i) {
1051 const Trk::TrackParameters* perigee = vertex.vxTrackAtVertex()[i].perigeeAtVertex();
1052 const Amg::Vector3D& p = perigee->momentum();
1053 momentum += xAOD::TrackParticle::GenVecFourMom_t(p.x(), p.y(), p.z(), trkMass[i]);
1054 }
1055 return momentum;
1056}
1057
1058
1059bool TrigBmumuxComboHypo::passDimuonTrigger(const std::vector<const DecisionIDContainer*>& previousDecisionIDs) const {
1060
1061 if (previousDecisionIDs.size() != 2) {
1062 ATH_MSG_WARNING( "TrigBmumuxComboHypo::passDimuonTrigger() expects exactly two containers with previous decision IDs" );
1063 return false;
1064 }
1065
1066 for (const auto& tool : hypoTools()) {
1067 const std::vector<HLT::Identifier>& legDecisionIDs = tool->legDecisionIds();
1068 if (legDecisionIDs.size() == 1 && tool->legMultiplicity().at(0) >= 2) {
1069 // trigger with symmetric legs like HLT_2mu4_bBmumux_BsmumuPhi_L12MU4
1070 const DecisionID id = legDecisionIDs[0].numeric();
1071 if (TrigCompositeUtils::passed(id, *previousDecisionIDs[0]) && TrigCompositeUtils::passed(id, *previousDecisionIDs[1])) return true;
1072 }
1073 else if (legDecisionIDs.size() == 2) {
1074 // trigger with asymmetric legs like HLT_mu6_mu4_bBmumux_BsmumuPhi_L1MU6_2MU4
1075 bool direct = true;
1076 bool inverse = true;
1077 for (size_t i = 0; i < 2; ++i) {
1078 if (direct && !TrigCompositeUtils::passed(legDecisionIDs[i].numeric(), *previousDecisionIDs[i])) direct = false;
1079 if (inverse && !TrigCompositeUtils::passed(legDecisionIDs[i].numeric(), *previousDecisionIDs[1-i])) inverse = false;
1080 }
1081 if (direct || inverse) return true;
1082 }
1083 else {
1084 ATH_MSG_WARNING( "TrigBmumuxComboHypo can not check decisions for " << tool->name() );
1085 }
1086 }
1087 return false;
1088}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
int charge3(const T &p)
Definition AtlasPID.h:1001
Base class for elements of a container that can have aux data.
ElementLink< xAOD::TrackParticleContainer > linkTrack(const xAOD::TrackParticle *trk)
size_t size() const
Number of registered mappings.
#define x
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)
bool msgLvl(const MSG::Level lvl) const
ComboHypo(const std::string &name, ISvcLocator *pSvcLocator)
Definition ComboHypo.cxx:13
const SG::WriteHandleKeyArray< TrigCompositeUtils::DecisionContainer > & decisionsOutput() const
Definition ComboHypo.h:42
const Combo::MultiplicityReqMap & triggerMultiplicityMap() const
Definition ComboHypo.h:43
ToolHandleArray< ComboHypoToolBase > & hypoTools()
Definition ComboHypo.h:45
const SG::ReadHandleKeyArray< TrigCompositeUtils::DecisionContainer > & decisionsInput() const
Definition ComboHypo.h:41
virtual StatusCode initialize() override
Definition ComboHypo.cxx:22
const T * get(size_type n) const
Access an element, as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
TrigCompositeUtils::DecisionContainer & decisions()
const TrigCompositeUtils::DecisionContainer & previousDecisions() const
xAOD::TrigBphysContainer & trigBphysCollection()
Amg::Vector3D beamSpotPosition() const
const EventContext & context() const
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
pointer_type ptr()
Dereference the pointer.
Gaudi::Property< bool > m_dimuon_rejectSameChargeTracks
Gaudi::Property< bool > m_BcToDplusMuMu_useFastFit
StatusCode findBmumuxCandidates_fit(TrigBmumuxState &, size_t dimuonIndex, bool makeCombinations=false) const
Perform fit of B decays for the topologies described above if makeCombinations = false.
Gaudi::Property< std::pair< double, double > > m_BcToMuMuPion_massRange
Gaudi::Property< float > m_BdToMuMuKstar0_chi2
ToolHandle< Trk::TrkVKalVrtFitter > m_vertexFitter
Gaudi::Property< bool > m_BdToMuMuKstar0_rejectSameChargeTracks
Gaudi::Property< bool > m_BdToMuMuKstar0_useFastFit
Gaudi::Property< double > m_BdToMuMuKstar0_minPionPt
Gaudi::Property< std::pair< double, double > > m_BcToDplusMuMu_massRange
std::unique_ptr< xAOD::Vertex > fit(const EventContext &context, const std::vector< ElementLink< xAOD::TrackParticleContainer > > &trackParticleLinks, Decay decay=kPsi_2mu, const xAOD::Vertex *dimuon=nullptr) const
Perform a vertex fit on selected tracks.
Gaudi::Property< std::pair< double, double > > m_BcToDsMuMu_phiMassRange
Gaudi::Property< std::pair< double, double > > m_BcToDstarMuMu_D0MassRange
Gaudi::Property< std::pair< double, double > > m_BcToDplusMuMu_DplusMassRange
Gaudi::Property< bool > m_BcToDsMuMu
Gaudi::Property< double > m_fastFit_2mu1trk_chi2
Gaudi::Property< bool > m_BcToMuMuPion
Gaudi::Property< double > m_BplusToMuMuKaon_minKaonPt
Gaudi::Property< std::pair< double, double > > m_BsToMuMuPhi1020_massRange
Gaudi::Property< double > m_BcToDsMuMu_minPionPt
Gaudi::Property< std::pair< double, double > > m_BdToMuMuKstar0_massRange
TrigCompositeUtils::DecisionIDContainer m_allowedIDs
SG::ReadCondHandleKey< InDet::BeamSpotData > m_beamSpotKey
Gaudi::Property< bool > m_LambdaBToMuMuProtonKaon
Gaudi::Property< double > m_roiPhiWidth
Gaudi::Property< double > m_BcToMuMuPion_minPionPt
SG::WriteHandleKey< xAOD::TrigBphysContainer > m_trigBphysContainerKey
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackParticleContainerKey
Gaudi::Property< double > m_dimuon_chi2
Gaudi::Property< float > m_BsToMuMuPhi1020_chi2
Gaudi::Property< bool > m_BcToDsMuMu_useFastFit
Gaudi::Property< double > m_BsToMuMuPhi1020_minKaonPt
ToolHandle< InDet::VertexPointEstimator > m_vertexPointEstimator
bool passDimuonTrigger(const std::vector< const TrigCompositeUtils::DecisionIDContainer * > &previousDecisionIDs) const
Gaudi::Property< std::pair< double, double > > m_BsToMuMuPhi1020_phiMassRange
Gaudi::Property< float > m_BcToDsMuMu_chi2
Gaudi::Property< std::pair< double, double > > m_BplusToMuMuKaon_massRange
Gaudi::Property< std::pair< double, double > > m_BcToDsMuMu_DsMassRange
Gaudi::Property< float > m_BcToMuMuPion_chi2
Gaudi::Property< double > m_BcToDstarMuMu_minD0KaonPt
Gaudi::Property< double > m_BdToMuMuKstar0_minKaonPt
double Lxy(const Amg::Vector3D &productionVertex, const xAOD::Vertex &decayVertex) const
Calculate the Lxy (~distance between vertices) It is defined as the transverse distance between the p...
Gaudi::Property< bool > m_LambdaBToMuMuProtonKaon_useFastFit
ToolHandle< Reco::ITrackToVertex > m_trackToVertexTool
Gaudi::Property< std::pair< double, double > > m_LambdaBToMuMuProtonKaon_massRange
StatusCode findBmumuxCandidates(TrigBmumuxState &) const
Find B decays by appling next three subprocedures to each found dimuon candidate.
Gaudi::Property< std::pair< double, double > > m_dimuon_massRange
StatusCode mergeMuonsFromDecisions(TrigBmumuxState &) const
Go through state.previousDecisions(), fetch xAOD::Muons objects attached to decisions and save links ...
Gaudi::Property< float > m_BplusToMuMuKaon_chi2
Gaudi::Property< bool > m_BsToMuMuPhi1020
Gaudi::Property< double > m_LambdaBToMuMuProtonKaon_minKaonPt
Gaudi::Property< bool > m_BplusToMuMuKaon
Gaudi::Property< bool > m_BdToMuMuKstar0
Gaudi::Property< double > m_BcToDstarMuMu_minD0PionPt
StatusCode findBmumuxCandidates_selectTracks(TrigBmumuxState &, size_t dimuonIndex) const
Select tracks in vicinity of given dimuon vertex.
StatusCode findBmumuxCandidates_fastFit(TrigBmumuxState &, size_t dimuonIndex) const
Go through (dimuon+track) and (track+track) combinations found by findBmumuxCandidates_fit(makeCombin...
Gaudi::Property< std::pair< double, double > > m_BcToDstarMuMu_DstarMassRange
xAOD::TrigBphys * makeTriggerObject(TrigBmumuxState &state, const xAOD::Vertex &vertex, xAOD::TrigBphys::pType type=xAOD::TrigBphys::MULTIMU, const std::vector< double > &trkMass={PDG::mMuon, PDG::mMuon}, const ElementLink< xAOD::TrigBphysContainer > &dimuonLink=ElementLink< xAOD::TrigBphysContainer >()) const
Construct the trigger object that may be stored for debugging or matching.
Gaudi::Property< double > m_BcToDstarMuMu_minDstarPionPt
Gaudi::Property< std::pair< double, double > > m_LambdaBToMuMuProtonKaon_dimuonMassRange
Gaudi::Property< bool > m_BplusToMuMuKaon_useFastFit
Gaudi::Property< bool > m_BsToMuMuPhi1020_useFastFit
bool isInSameRoI(const xAOD::Muon *, const xAOD::TrackParticle *) const
Attempts to identify if the track is in the same RoI as the muon by comparing the angle with the RoI ...
Gaudi::Property< std::pair< double, double > > m_BcToDplusMuMu_dimuonMassRange
TrigBmumuxComboHypo()=delete
virtual StatusCode initialize() override
Gaudi::Property< double > m_roiEtaWidth
Gaudi::Property< std::pair< double, double > > m_BcToDsMuMu_massRange
Gaudi::Property< double > m_BcToDplusMuMu_minPionPt
Gaudi::Property< bool > m_BcToDstarMuMu
Gaudi::Property< std::pair< double, double > > m_BdToMuMuKstar0_KstarMassRange
static const std::vector< std::vector< double > > s_trkMass
Gaudi::Property< bool > m_BcToDstarMuMu_makeDstar
Gaudi::Property< std::pair< double, double > > m_BcToDstarMuMu_massRange
SG::ReadHandleKey< xAOD::MuonContainer > m_muonContainerKey
ToolHandle< GenericMonitoringTool > m_monTool
Gaudi::Property< double > m_BcToDstarMuMu_maxDstarPionZ0
Gaudi::Property< bool > m_BcToDplusMuMu
Gaudi::Property< double > m_LambdaBToMuMuProtonKaon_minProtonPt
Gaudi::Property< bool > m_BcToMuMuPion_useFastFit
Gaudi::Property< size_t > m_fitAttemptsBreakThreshold
Gaudi::Property< std::pair< double, double > > m_BcToDsMuMu_dimuonMassRange
Gaudi::Property< float > m_BcToDstarMuMu_chi2
Gaudi::Property< double > m_deltaR
Gaudi::Property< size_t > m_fitAttemptsWarningThreshold
Gaudi::Property< float > m_LambdaBToMuMuProtonKaon_chi2
Gaudi::Property< std::pair< double, double > > m_BcToMuMuPion_dimuonMassRange
Gaudi::Property< double > m_fastFit_2trk_chi2
StatusCode mergeTracksFromViews(TrigBmumuxState &) const
Go through state.previousDecisions() and fetch xAOD::TrackParticle objects associated with the neares...
virtual StatusCode execute(const EventContext &context) const override
Gaudi::Property< bool > m_BsToMuMuPhi1020_rejectSameChargeTracks
StatusCode createDecisionObjects(TrigBmumuxState &) const
Create a decision for each xAOD::TrigBphys object from state.trigBphysCollection() and save it to sta...
Gaudi::Property< float > m_BcToDplusMuMu_chi2
StatusCode findDimuonCandidates(TrigBmumuxState &) const
Make all possible dimuon combinations from state.muons(), fit muon InDet tracks to the common vertex,...
bool isInMassRange(double mass, const std::pair< double, double > &range) const
Checks that the given mass value falls into the specified range.
bool isIdenticalTracks(const xAOD::TrackParticle *lhs, const xAOD::TrackParticle *rhs) const
Attempts to identify identical tracks by selection on DeltaR.
Gaudi::Property< double > m_trkZ0
Gaudi::Property< double > m_BcToDplusMuMu_minKaonPt
Gaudi::Property< double > m_LambdaBToMuMuProtonKaon_minKstarMass
Gaudi::Property< std::pair< double, double > > m_BcToDstarMuMu_dimuonMassRange
Gaudi::Property< double > m_BcToDsMuMu_minKaonPt
xAOD::TrackParticle::GenVecFourMom_t momentum(const xAOD::Vertex &vertex, const std::vector< double > &trkMass) const
Calculate 4-momentum of the fitted vertex particle assuming the given masses.
State class for TrigBmumuxComboHypo algorithm.
std::vector< Muon > muons
std::map< const xAOD::TrackParticle *, double > selectedTrackZ0
void addTrackCombination(size_t i1)
bool isBadCombination(size_t i1) const
std::vector< ElementLink< xAOD::TrackParticleContainer > > selectedTracks
std::map< size_t, size_t > trackCombinations
StatusCode addTriggerObject(xAOD::TrigBphys *triggerObject)
std::vector< size_t > badTrackCombinations
xAOD::VertexContainer dimuons
std::vector< ElementLink< xAOD::TrackParticleContainer > > tracks
std::vector< std::array< size_t, 2 > > trigBphysMuonIndices
const Amg::Vector3D & momentum() const
Access method for the momentum.
const TrackParticle * trackParticle(TrackParticleType type) const
Returns a pointer (which can be a nullptr) to the TrackParticle used in identification of this muon.
Definition Muon_v1.cxx:422
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzM4D< double > > GenVecFourMom_t
Base 4 Momentum type for TrackParticle.
GenVecFourMom_t genvecP4() const
The full 4-momentum of the particle : GenVector form.
float charge() const
Returns the charge.
float pt() const
accessor method: pt
float eta() const
accessor method: eta
float phi() const
accessor method: phi
const TrigBphys_v1 * lowerChain() const
accessor method: lowerChain decay particle
float fitx() const
accessor method: x position of vertex
float fitz() const
accessor method: z position of vertex
float mass() const
accessor method: mass
pType
enum for different particle types
float fity() const
accessor method: y position of vertex
bool setObjectLink(const std::string &name, const ElementLink< CONTAINER > &link)
Set the link to an object.
bool addObjectCollectionLinks(const std::string &collectionName, const std::vector< ElementLink< CONTAINER > > &links)
Add links to multiple objects within a collection. Performs de-duplication.
float z() const
Returns the z position.
const TrackParticleLinks_t & trackParticleLinks() const
Get all the particles associated with the vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
float y() const
Returns the y position.
bool vxTrackAtVertexAvailable() const
Check if VxTrackAtVertices are attached to the object.
std::vector< Trk::VxTrackAtVertex > & vxTrackAtVertex()
Non-const access to the VxTrackAtVertex vector.
const Amg::Vector3D & position() const
Returns the 3-pos.
float x() const
Returns the x position.
Eigen::Matrix< double, 3, 1 > Vector3D
ValuesCollection< T > Collection(std::string name, const T &collection)
Declare a monitored (double-convertible) collection.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
unsigned int DecisionID
const std::string & viewString()
xAOD::TrigComposite Decision
const std::string & roiString()
Decision * newDecisionIn(DecisionContainer *dc, const std::string &name)
Helper method to create a Decision object, place it in the container and return a pointer to it.
const std::string & featureString()
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
const std::string & comboHypoAlgNodeName()
std::set< DecisionID > DecisionIDContainer
SG::WriteHandle< DecisionContainer > createAndStore(const SG::WriteHandleKey< DecisionContainer > &key, const EventContext &ctx)
Creates and right away records the DecisionContainer with the key.
LinkInfo< T > findLink(const EventContext &ctx, const Decision *start, const std::string &linkName, const bool suppressMultipleLinksWarning=false)
Perform a recursive search for ElementLinks of type T and name 'linkName', starting from Decision obj...
const std::string & seedString()
xAOD::TrigCompositeContainer DecisionContainer
void decisionIDs(const Decision *d, DecisionIDContainer &destination)
Extracts DecisionIDs stored in the Decision object.
ElementLink< DecisionContainer > decisionToElementLink(const Decision *d, const EventContext &ctx)
Takes a raw pointer to a Decision and returns an ElementLink to the Decision.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ z0
Definition ParamDefs.h:64
ParametersBase< TrackParametersDim, Charged > TrackParameters
ElementLink< T > makeLink(const SG::View *view, const SG::ReadHandle< T > &handle, size_t index)
Create EL to a collection in view.
Definition ViewHelper.h:309
auto makeHandle(const SG::View *view, const KEY &key, const EventContext &ctx)
Create a view handle from a handle key.
Definition ViewHelper.h:273
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrigBphys_v1 TrigBphys
Definition TrigBphys.h:18
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
Muon_v1 Muon
Reference the current persistent version:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
TrigBphysContainer_v1 TrigBphysContainer