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