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