ATLAS Offline Software
Loading...
Searching...
No Matches
TrigBphysMonitorAlgorithm.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "GaudiKernel/SystemOfUnits.h"
8
13
14using namespace Gaudi::Units;
15
16TrigBphysMonitorAlgorithm::TrigBphysMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
17 : AthMonitorAlgorithm(name,pSvcLocator)
18{}
19
20
22
23
25
26 ATH_CHECK( m_TrigBphysContainerKeys.initialize() );
29 ATH_CHECK( m_offlinePvCollectionKey.initialize() );
30
32
33 return StatusCode::SUCCESS;
34
35}
36
37
38StatusCode TrigBphysMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
39
40 // fill the container hists
41 ATH_MSG_DEBUG ("fill... Containers");
42 if (fillContainers(ctx).isFailure()) {ATH_MSG_ERROR("Problems filling Container histograms");}
43
44 // fill the chain hists
45 ATH_MSG_DEBUG ("fill... Chains");
46 if (fillChains(ctx).isFailure()) {ATH_MSG_ERROR("Problems filling Chain histograms");}
47
48 // build offline dimuons and fill offline histograms
49 std::vector<std::unique_ptr<xAOD::Vertex>> offlineDimuons;
50 if (buildDimuons(ctx, offlineDimuons).isFailure()) {
51 ATH_MSG_ERROR("Problems building offline dimuons, won't fill corresponding histograms");
52 }
53 else {
54 if (fillOfflineDimuons(ctx, offlineDimuons).isFailure()) {ATH_MSG_ERROR("Problems filling Offline dimuon histograms");}
55 }
56
57 return StatusCode::SUCCESS;
58}
59
60StatusCode TrigBphysMonitorAlgorithm::fillContainers(const EventContext& ctx) const {
61
63 ATH_MSG_DEBUG("Process container " << monitoredContainerKey.key().c_str());
64 if(fillContainerHists(ctx, monitoredContainerKey).isFailure()) {
65 ATH_MSG_ERROR(Form("Problems filling %s container histograms", monitoredContainerKey.key().c_str()));
66 }
67 }
68
69 return StatusCode::SUCCESS;
70}
71
72StatusCode TrigBphysMonitorAlgorithm::fillContainerHists(const EventContext& ctx, const SG::ReadHandleKey<xAOD::TrigBphysContainer>& trigBphysContainerKey) const {
73 SG::ReadHandle<xAOD::TrigBphysContainer> trigBphysContainer(trigBphysContainerKey, ctx);
74 if( !trigBphysContainer.isValid() ) {
75 ATH_MSG_WARNING("No valid TrigBphysContainer with tag: " << trigBphysContainerKey);
76 }
77 else {
78 // Fill container-wise histograms
79 std::string monGroupName = std::string("Container_")+trigBphysContainerKey.key();
80 auto monGroup = getGroup(monGroupName);
81
82 auto ncandidates = Monitored::Scalar<int>("ncandidates",-999);
83 ncandidates = trigBphysContainer->size();
84
85 auto bphys_mass = Monitored::Collection("bphys_mass", (*trigBphysContainer), [](const xAOD::TrigBphys* bphys){ return bphys->fitmass() / GeV;});
86
87 fill(monGroup, ncandidates, bphys_mass);
88
89 }
90 return StatusCode::SUCCESS;
91}
92
93
94StatusCode TrigBphysMonitorAlgorithm::fillChains(const EventContext& ctx) const {
95
96 for(const auto& monitoredChain : m_ChainNames_MuMu) {
97 ATH_MSG_DEBUG("Process chain " << monitoredChain);
98 if( !isChainPassed(monitoredChain) ) {
99 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
100 continue;
101 }
102 if(fillDimuonChainHists(ctx, monitoredChain).isFailure()) {
103 ATH_MSG_ERROR(Form("Problems filling %s chain histograms", monitoredChain.c_str()));
104 }
105 }
106
107 for(const auto& monitoredChain : m_ChainNames_MuMuX) {
108 ATH_MSG_DEBUG("Process chain " << monitoredChain);
109 if( !isChainPassed(monitoredChain) ) {
110 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
111 continue;
112 }
113 if(fillBmumuxChainHists(ctx, monitoredChain).isFailure()) {
114 ATH_MSG_ERROR(Form("Problems filling %s chain histograms", monitoredChain.c_str()));
115 }
116 }
117
118 for(const auto& monitoredChain : m_ChainNames_ElEl) {
119 ATH_MSG_DEBUG("Process chain " << monitoredChain);
120 if( !isChainPassed(monitoredChain) ) {
121 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
122 continue;
123 }
124 if(fillDielectronChainHists(ctx, monitoredChain).isFailure()) {
125 ATH_MSG_ERROR(Form("Problems filling %s chain histograms", monitoredChain.c_str()));
126 }
127 }
128
129 return StatusCode::SUCCESS;
130}
131
132StatusCode TrigBphysMonitorAlgorithm::fillDimuonChainHists(const EventContext& ctx, const std::string& chainName) const {
133 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
134
135 std::string monGroupName = std::string("Chain_")+chainName;
136 auto monGroup = getGroup(monGroupName);
137
138 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
139 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
140 }
141
142 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
143 for (const auto& featLinkInfo: chainFeatureContainer){
144 ATH_CHECK(featLinkInfo.isValid());
145 const auto featLink = featLinkInfo.link;
146 if (fillBphysObjectHists(monGroup, featLink, "dimu").isFailure()) {
147 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
148 }
149 if (fillTrigLeptonHists(monGroup, featLink, "mu").isFailure()) {
150 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
151 }
152 }
153 return StatusCode::SUCCESS;
154}
155
156
157StatusCode TrigBphysMonitorAlgorithm::fillBmumuxChainHists(const EventContext& ctx, const std::string& chainName) const {
158 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
159
160 std::string monGroupName = std::string("Chain_")+chainName;
161 auto monGroup = getGroup(monGroupName);
162
163 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
164 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
165 }
166
167 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
168 for (const auto& featLinkInfo: chainFeatureContainer){
169 ATH_CHECK(featLinkInfo.isValid());
170 const auto featLink = featLinkInfo.link;
171 if (fillBphysObjectHists(monGroup, featLink, "B").isFailure()) {
172 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
173 }
174 if (fillTrigBmumuxTrkHists(monGroup, featLink).isFailure()) {
175 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
176 }
177
178 auto dimuonLink = (*featLink)->lowerChainLink();
179 ATH_CHECK(dimuonLink.isValid());
180 if (fillBphysObjectHists(monGroup, dimuonLink, "dimu").isFailure()) {
181 ATH_MSG_ERROR(Form("Problems filling dimuon object histograms for %s chain",chainName.c_str()));
182 }
183 if (fillTrigLeptonHists(monGroup, dimuonLink, "mu").isFailure()) {
184 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
185 }
186 }
187
188 return StatusCode::SUCCESS;
189}
190
191StatusCode TrigBphysMonitorAlgorithm::fillDielectronChainHists(const EventContext& ctx, const std::string& chainName) const {
192 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
193
194 std::string monGroupName = std::string("Chain_")+chainName;
195 auto monGroup = getGroup(monGroupName);
196
197 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
198 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
199 }
200
201 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
202 for (const auto& featLinkInfo: chainFeatureContainer){
203 ATH_CHECK(featLinkInfo.isValid());
204 const auto featLink = featLinkInfo.link;
205 if (fillBphysObjectHists(monGroup, featLink, "diel").isFailure()) {
206 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
207 }
208 if (fillTrigLeptonHists(monGroup, featLink, "el").isFailure()) {
209 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
210 }
211 }
212 return StatusCode::SUCCESS;
213}
214
215
216// Function to fill general per-chain hists, independent on the type of chains
217StatusCode TrigBphysMonitorAlgorithm::fillChainGenericHists(const EventContext& /*ctx*/, const ToolHandle<GenericMonitoringTool>& currentMonGroup, const std::string& chainName) const {
218
219 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
220 auto ncandidates = Monitored::Scalar<int>("ncandidates",-999);
221 ncandidates = chainFeatureContainer.size();
222
223 fill(currentMonGroup, ncandidates);
224
225 return StatusCode::SUCCESS;
226}
227
228
229// Function to fill per-object hists (e.g. for dimuon, B from Bmumux, or X from Bmumux)
230StatusCode TrigBphysMonitorAlgorithm::fillBphysObjectHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, const std::string& objStr) const {
231
232 auto dimu_mass = Monitored::Scalar<float>(objStr+"_mass",-999.);
233 auto dimu_fitmass = Monitored::Scalar<float>(objStr+"_fitmass",-999.);
234 auto dimu_pt = Monitored::Scalar<float>(objStr+"_pt",-999.);
235 auto dimu_y = Monitored::Scalar<float>(objStr+"_y",-999.);
236 auto dimu_chi2 = Monitored::Scalar<float>(objStr+"_chi2",-999.);
237
238 dimu_mass = (*bphysLink)->mass() / GeV;
239 dimu_fitmass = (*bphysLink)->fitmass() / GeV;
240 dimu_pt = (*bphysLink)->pt() / GeV;
241 dimu_chi2 = (*bphysLink)->fitchi2();
242 dimu_y = (*bphysLink)->eta();
243
244 fill(currentMonGroup, dimu_mass, dimu_fitmass, dimu_pt, dimu_y, dimu_chi2);
245
246 return StatusCode::SUCCESS;
247}
248
249
250// Function to fill per-muon hists, assuming that the passed object is a dimuon
251StatusCode TrigBphysMonitorAlgorithm::fillTrigLeptonHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, const std::string& name_prefix) const {
252
253 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
254 ATH_MSG_DEBUG("fillTrigLeptonHists: number of lepton tracks: " << trackVector.size());
255 if( fillTracksHists(currentMonGroup, trackVector, name_prefix, true).isFailure() ) {
256 ATH_MSG_ERROR(Form("Problems filling muon histograms for a chain"));
257 return StatusCode::FAILURE;
258 }
259 if( fillDiTracksHists(currentMonGroup, trackVector, std::string("di")+name_prefix).isFailure() ) {
260 ATH_MSG_ERROR(Form("Problems filling two-muon histograms for a chain"));
261 return StatusCode::FAILURE;
262 }
263
264 return StatusCode::SUCCESS;
265}
266
267// Function to fill per-track hists for Bmumux candidates
268StatusCode TrigBphysMonitorAlgorithm::fillTrigBmumuxTrkHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, UInt_t tracksStartFrom) const {
269
270 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
271 if (trackVector.size() < tracksStartFrom) {
272 ATH_MSG_WARNING("Unexpected number of tracks: "<< trackVector.size() << " found, while expected at least " << tracksStartFrom);
273 return StatusCode::SUCCESS;
274 }
275
276 if (fillTracksHists(currentMonGroup, trackVector, "trk", false, tracksStartFrom).isFailure()) {
277 ATH_MSG_ERROR(Form("Problems filling track histograms for a BMuMuX chain"));
278 return StatusCode::FAILURE;
279 }
280
281 return StatusCode::SUCCESS;
282}
283
284StatusCode TrigBphysMonitorAlgorithm::fillTracksHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup,
285 const std::vector<ElementLink<xAOD::TrackParticleContainer> >& tpLinkVector,
286 const std::string& prefix,
287 bool separateHists,
288 UInt_t offsetIndex) const {
289 for(UInt_t i = offsetIndex; i < tpLinkVector.size(); ++i) {
290 ATH_CHECK(tpLinkVector.at(i).isValid());
291 std::string curPrefix = prefix;
292 if(separateHists)
293 curPrefix += std::to_string(i+1);
294 if (fillTrkHists(currentMonGroup, *tpLinkVector.at(i), curPrefix).isFailure()) {
295 ATH_MSG_ERROR(Form("Problems filling track histograms"));
296 return StatusCode::FAILURE;
297 }
298 }
299 return StatusCode::SUCCESS;
300}
301
302StatusCode TrigBphysMonitorAlgorithm::fillDiTracksHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup,
303 const std::vector<ElementLink<xAOD::TrackParticleContainer> >& tpLinkVector,
304 const std::string& name_prefix) const {
305 // Use first two tracks
306 if (tpLinkVector.size() <2) {
307 ATH_MSG_ERROR("Unexpected number of tracks in a dimuon: " << tpLinkVector.size());
308 return StatusCode::FAILURE;
309 }
310 ATH_CHECK(tpLinkVector.at(0).isValid());
311 ATH_CHECK(tpLinkVector.at(1).isValid());
312 const xAOD::TrackParticle* trk1 = *tpLinkVector.at(0);
313 const xAOD::TrackParticle* trk2 = *tpLinkVector.at(1);
314
315 auto ditrk_dR = Monitored::Scalar<float>(name_prefix+"_dR",-999.);
316 auto ditrk_deta = Monitored::Scalar<float>(name_prefix+"_deta",-999.);
317 auto ditrk_dphi = Monitored::Scalar<float>(name_prefix+"_dphi",-999.);
318
319 ditrk_dR = xAOD::P4Helpers::deltaR(*trk1, *trk2, false); // false for pseudo, not true rapidity
320 ditrk_deta = std::abs(trk1->eta()-trk2->eta());
321 ditrk_dphi = std::abs(xAOD::P4Helpers::deltaPhi(*trk1, *trk2));
322
323 fill(currentMonGroup, ditrk_dR, ditrk_deta, ditrk_dphi);
324
325 return StatusCode::SUCCESS;
326}
327
328// Generic function to fill track hists
329StatusCode TrigBphysMonitorAlgorithm::fillTrkHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const xAOD::TrackParticle* trk, const std::string& name_prefix) const {
330 if (!trk) {
331 ATH_MSG_ERROR("Null pointer for a track");
332 return StatusCode::FAILURE;
333 }
334 auto trk_pt = Monitored::Scalar<float>(name_prefix+"_pt",-999.);
335 auto trk_eta = Monitored::Scalar<float>(name_prefix+"_eta",-999.);
336 auto trk_d0 = Monitored::Scalar<float>(name_prefix+"_d0",-999.);
337
338 trk_pt = trk->pt() / GeV;
339 trk_eta = trk->eta();
340 trk_d0 = trk->d0();
341
342 fill(currentMonGroup, trk_pt, trk_eta, trk_d0);
343
344 return StatusCode::SUCCESS;
345}
346
347StatusCode TrigBphysMonitorAlgorithm::fillOfflineDimuons(const EventContext& ctx, const std::vector<std::unique_ptr<xAOD::Vertex>>& dimuonContainer) const {
348
349 std::vector<std::string> dimuonMonGroupNames = {"Any"};
350 dimuonMonGroupNames.insert( dimuonMonGroupNames.end(), m_ChainNames_MuMu.begin(), m_ChainNames_MuMu.end() );
351 dimuonMonGroupNames.insert( dimuonMonGroupNames.end(), m_ChainNames_MuMuX.begin(), m_ChainNames_MuMuX.end() );
352
353 for(const auto& dimuonMonGroupName : dimuonMonGroupNames) {
354 ATH_MSG_DEBUG("Process dimuons for " << dimuonMonGroupName);
355 if(dimuonMonGroupName != "Any") {
356 auto& monitoredChain = dimuonMonGroupName;
357 if( !(dimuonMonGroupName == "Any") && !isChainPassed(monitoredChain) ) {
358 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
359 continue;
360 }
361 }
362 if(fillOfflineDimuonHists(ctx, dimuonMonGroupName, dimuonContainer).isFailure()) {
363 ATH_MSG_ERROR(Form("Problems filling offline dimuon histograms for %s", dimuonMonGroupName.c_str()));
364 }
365 }
366
367 return StatusCode::SUCCESS;
368}
369
370StatusCode TrigBphysMonitorAlgorithm::fillOfflineDimuonHists(const EventContext& /*ctx*/, const std::string& dimuonMonGroupName, const std::vector<std::unique_ptr<xAOD::Vertex>>& dimuonContainer) const {
371 ATH_MSG_DEBUG("Filling " << dimuonMonGroupName << " offline dimuons histograms");
372
373 // Do matching
374 std::vector<const xAOD::Vertex*> matchedDimuons;
375 for(auto& offlineDimuon : dimuonContainer) {
376 if( dimuonMonGroupName == "Any" || matchDimuon(offlineDimuon.get(), dimuonMonGroupName) )
377 matchedDimuons.push_back(offlineDimuon.get());
378 }
379
380 std::string monGroupName = std::string("OfflineDimu_")+dimuonMonGroupName;
381 auto monGroup = getGroup(monGroupName);
382
383 auto ncandidates = Monitored::Scalar<int>("ncandidates",-999);
384 ncandidates = matchedDimuons.size();
385
386 fill(monGroup, ncandidates);
387
388 for(auto matchedDimuon : matchedDimuons) {
389 if (fillVertexHists(monGroup, matchedDimuon, "dimu").isFailure()) {
390 ATH_MSG_ERROR(Form("Problems filling histogram for an offline dimuon vertex in %s", dimuonMonGroupName.c_str()));
391 }
392 if (fillTracksHists(monGroup, matchedDimuon->trackParticleLinks(), "mu", true).isFailure()) {
393 ATH_MSG_ERROR(Form("Problems filling histogram for offline dimuon muons in %s", dimuonMonGroupName.c_str()));
394 }
395 if (fillDiTracksHists(monGroup, matchedDimuon->trackParticleLinks(), "dimu").isFailure()) {
396 ATH_MSG_ERROR(Form("Problems filling histogram for offline dimuon muon pairs in %s", dimuonMonGroupName.c_str()));
397 }
398 }
399
400 return StatusCode::SUCCESS;
401
402}
403
404StatusCode TrigBphysMonitorAlgorithm::fillVertexHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const xAOD::Vertex* vertex, const std::string& objStr) const {
405
406 xAOD::BPhysHelper dimuonVertexHelper(vertex);
407 if(dimuonVertexHelper.nRefTrks() != 2) {
408 ATH_MSG_WARNING("Unexpected number of refitted tracks at vertex is " << dimuonVertexHelper.nRefTrks());
409 return StatusCode::SUCCESS;
410 }
411
412 using namespace TrigVtx;
413 TLorentzVector dimuonMom = dimuonVertexHelper.totalP(std::array<double,2>{TrigParticleMasses().mass[TrigParticleName::muon], TrigParticleMasses().mass[TrigParticleName::muon]});
414
415 auto dimu_mass = Monitored::Scalar<float>(objStr+"_mass",-999.);
416 auto dimu_pt = Monitored::Scalar<float>(objStr+"_pt",-999.);
417 auto dimu_y = Monitored::Scalar<float>(objStr+"_y",-999.);
418 auto dimu_chi2 = Monitored::Scalar<float>(objStr+"_chi2",-999.);
419 auto dimu_Lxy = Monitored::Scalar<float>(objStr+"_Lxy",-999.);
420 auto dimu_LxySig = Monitored::Scalar<float>(objStr+"_LxySig",-999.);
421
422 dimu_mass = dimuonMom.M() / GeV;
423 dimu_pt = dimuonMom.Pt() / GeV;
424 dimu_chi2 = vertex->chiSquared();
425 dimu_y = dimuonMom.Rapidity();
426 dimu_Lxy = dimuonVertexHelper.lxy(xAOD::BPhysHelper::PV_MIN_A0);
427 dimu_LxySig = dimuonVertexHelper.lxy(xAOD::BPhysHelper::PV_MIN_A0)/dimuonVertexHelper.lxyErr(xAOD::BPhysHelper::PV_MIN_A0);
428
429 fill(currentMonGroup, dimu_mass, dimu_pt, dimu_y, dimu_chi2, dimu_Lxy, dimu_LxySig);
430
431 return StatusCode::SUCCESS;
432}
433
434bool TrigBphysMonitorAlgorithm::isChainPassed(const std::string& chain) const {
435 // Check if a chain is passed after prescale, accounting for Express Stream prescales if necessary
437 return getTrigDecisionTool()->isPassed(chain);
438 }
439 else {
440 const unsigned int passBits = getTrigDecisionTool()->isPassedBits(chain);
441 return passBits & TrigDefs::Express_passed;
442 }
443}
444
445StatusCode TrigBphysMonitorAlgorithm::buildDimuons(const EventContext& ctx, std::vector<std::unique_ptr<xAOD::Vertex>>& vxContainer) const {
446 ATH_MSG_DEBUG( "TrigBphysMonitorAlgorithm::buildDimuons" );
447
448 // Get the muons
450 ATH_CHECK(muonHandle.isValid());
451 const xAOD::MuonContainer* muonContainer = muonHandle.cptr();
452 ATH_MSG_DEBUG("Muon container size " << muonContainer->size());
453
454 // Muon preselection
455 std::vector<const xAOD::Muon*> selectedMuons;
456 for (const auto mu : *muonContainer) {
457 if ( mu == nullptr ) continue;
458 if ( mu->muonType() != xAOD::Muon::Combined ) continue; // require combined muons
459 if (!mu->inDetTrackParticleLink()) continue; // No muons without ID tracks
460 if (!mu->inDetTrackParticleLink().isValid()) continue; // No muons without ID tracks
461 selectedMuons.push_back(mu);
462 }
463 if(selectedMuons.size() < 2) {
464 ATH_MSG_DEBUG("Only " << selectedMuons.size() << "muons pass preselection");
465 return StatusCode::SUCCESS;
466 }
467 std::sort(selectedMuons.begin(), selectedMuons.end(), [](const auto mu1, const auto mu2){ return mu1->pt() > mu2->pt(); });
468
469 // Build dimuons
470 for(auto outerItr=selectedMuons.begin(); outerItr<selectedMuons.end(); ++outerItr){
471 for(auto innerItr=(outerItr+1); innerItr!=selectedMuons.end(); ++innerItr){
472 const auto muon1 = *outerItr;
473 const auto muon2 = *innerItr;
474 const auto trackParticle1 = muon1->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
475 const auto trackParticle2 = muon2->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
476 // Charge selection
477 if(trackParticle1->qOverP() * trackParticle2->qOverP() > 0.)
478 continue;
479 // Mass selection
480 double dimu_momentum_prefit = dimuonMass(trackParticle1, trackParticle2);
481 if( !(dimu_momentum_prefit > m_dimuMassLower_prefit && dimu_momentum_prefit < m_dimuMassUpper_prefit) )
482 continue;
483 // Fit
484 std::unique_ptr<xAOD::Vertex> dimuon = dimuonFit(trackParticle1, trackParticle2);
485 if(!dimuon) continue;
486 if(dimuon->chiSquared() > m_dimuChi2Cut) continue;
487 vxContainer.push_back(std::move(dimuon));
488 }
489 }
490 ATH_MSG_DEBUG("Found " << vxContainer.size() << " good dimuons");
491
492 // Augment the dimuon vertices
493 if( !vxContainer.empty() ) {
495 ATH_CHECK(pvHandle.isValid());
496 const xAOD::VertexContainer* pvContainer = pvHandle.cptr();
497 std::vector<const xAOD::Vertex*> goodPVs = GetGoodPVs(pvContainer);
498 ATH_MSG_DEBUG("Found " << goodPVs.size() << " good PVs");
499 for(auto& dimuon : vxContainer) {
500 xAOD::BPhysHelper jpsiHelper(dimuon.get());
501 jpsiHelper.setRefTrks();
502 const xAOD::Vertex* lowestA0Pv = getPvForDimuon_lowestA0(dimuon.get(), goodPVs);
503 if(lowestA0Pv) {
504 jpsiHelper.setLxy ( m_v0Tools->lxy ( dimuon.get(),lowestA0Pv ), xAOD::BPhysHelper::PV_MIN_A0 );
505 jpsiHelper.setLxyErr( m_v0Tools->lxyError( dimuon.get(),lowestA0Pv ), xAOD::BPhysHelper::PV_MIN_A0 );
506 ATH_MSG_VERBOSE("Lxy = " << m_v0Tools->lxy ( dimuon.get(),lowestA0Pv ));
507 ATH_MSG_VERBOSE("LxyErr = " << m_v0Tools->lxyError( dimuon.get(),lowestA0Pv ));
508 }
509 }
510 }
511
512 return StatusCode::SUCCESS;
513}
514
515std::unique_ptr<xAOD::Vertex> TrigBphysMonitorAlgorithm::dimuonFit(const xAOD::TrackParticle* mu1, const xAOD::TrackParticle* mu2) const {
516
517 const Trk::Perigee& mu1Perigee = mu1->perigeeParameters();
518 const Trk::Perigee& mu2Perigee = mu2->perigeeParameters();
519 int sflag = 0; int errorcode = 0;
520 Amg::Vector3D startingPoint = m_vertexPointEstimator->getCirclesIntersectionPoint(&mu1Perigee,&mu2Perigee,sflag,errorcode);
521 if (errorcode != 0) {startingPoint(0) = 0.0; startingPoint(1) = 0.0; startingPoint(2) = 0.0;}
522 const std::vector<const xAOD::TrackParticle*> trackPair = {mu1, mu2};
523 std::unique_ptr<xAOD::Vertex> myVxCandidate(m_vertexFitter->fit(trackPair, startingPoint));
524
525 return myVxCandidate;
526}
527
528bool TrigBphysMonitorAlgorithm::matchDimuon(const xAOD::Vertex* dimuonVertex, const std::string& chainName) const {
529 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
530 for (const auto& featLinkInfo: chainFeatureContainer){
531 if(!featLinkInfo.isValid())
532 return false;
533 const auto featLink = featLinkInfo.link;
534 if( matchDimuon(dimuonVertex, featLink) )
535 return true;
536 }
537 return false;
538}
539
541 auto offlineTrk1 = dimuonVertex->trackParticle(0);
542 auto offlineTrk2 = dimuonVertex->trackParticle(1);
543 if(!offlineTrk1 || !offlineTrk2) {
544 ATH_MSG_DEBUG("TrackParticle from dimuon is null, won't match");
545 return false;
546 }
547
548 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
549 if (trackVector.size() < 2) {
550 ATH_MSG_ERROR("Unexpected number of tracks in a dimuon: " << trackVector.size() << ", won't match");
551 return false;
552 }
553
554 const xAOD::TrackParticle *hltTrk1(nullptr),*hltTrk2(nullptr);
555 // Assume the first two tracks are always muons'
556 if( !trackVector.at(0).isValid() || !trackVector.at(1).isValid() )
557 return false;
558 hltTrk1 = *trackVector.at(0);
559 hltTrk2 = *trackVector.at(1);
560 if (!hltTrk1 || !hltTrk2) {
561 ATH_MSG_ERROR("Null pointer for track in a dimuon!");
562 return false;
563 }
564 if( ( matchTrackParticles(offlineTrk1, hltTrk1) && matchTrackParticles(offlineTrk2, hltTrk2) ) ||
565 ( matchTrackParticles(offlineTrk1, hltTrk2) && matchTrackParticles(offlineTrk2, hltTrk1) ) )
566 return true;
567 else
568 return false;
569}
570
572 double deltaR = xAOD::P4Helpers::deltaR(*trk1, *trk2);
574 return true;
575 else
576 return false;
577}
578
580 using namespace TrigVtx;
585 xAOD::TrackParticle::GenVecFourMom_t dimu_mom = mom1 + mom2;
586 return dimu_mom.M();
587}
588
589std::vector<const xAOD::Vertex*> TrigBphysMonitorAlgorithm::GetGoodPVs(const xAOD::VertexContainer* pvContainer) const {
590 std::vector<const xAOD::Vertex*> goodPrimaryVertices;
591 goodPrimaryVertices.reserve(pvContainer->size());
592 for (auto pv : *pvContainer) {
593 xAOD::VxType::VertexType pvType = pv->vertexType();
594 if ( pvType == xAOD::VxType::PriVtx || pvType == xAOD::VxType::PileUp ) {
595 goodPrimaryVertices.push_back(pv);
596 }
597 }
598 return goodPrimaryVertices;
599}
600
601const xAOD::Vertex* TrigBphysMonitorAlgorithm::getPvForDimuon_lowestA0(const xAOD::Vertex* vtx, const std::vector<const xAOD::Vertex*>& PVs) const {
602 std::vector<const xAOD::Vertex*>::const_iterator pv = std::min_element(PVs.begin(), PVs.end(),
603 [&, vtx](const xAOD::Vertex* pv1, const xAOD::Vertex* pv2)
604 { return (std::abs(m_v0Tools->a0(vtx, pv1)) < std::abs(m_v0Tools->a0(vtx, pv2)));}
605 );
606 if(pv == PVs.end()) {
607 return nullptr;
608 }
609 ATH_MSG_VERBOSE("Min-a0 PV has index " << std::distance(PVs.begin(), pv) << ", a0 = " << m_v0Tools->a0(vtx, *pv));
610 return *pv;
611}
Scalar deltaR(const MatrixBase< Derived > &vec) const
#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)
: B-physics xAOD helpers.
xAOD::MuonContainer * muonContainer
const ToolHandle< GenericMonitoringTool > & getGroup(const std::string &name) const
Get a specific monitoring tool from the tool handle array.
virtual StatusCode initialize() override
initialize
const ToolHandle< Trig::TrigDecisionTool > & getTrigDecisionTool() const
Get the trigger decision tool member.
AthMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
size_type size() const noexcept
Returns the number of elements in the collection.
Declare a monitored scalar variable.
Property holding a SG store/key/clid from which a ReadHandle is made.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
const std::string & key() const
Return the StoreGate ID for the referenced object.
StatusCode fillChains(const EventContext &ctx) const
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
Gaudi::Property< double > m_deltaRMatchingThreshold
bool matchTrackParticles(const xAOD::TrackParticle *trk1, const xAOD::TrackParticle *trk2) const
SG::ReadHandleKey< xAOD::MuonContainer > m_offlineMuonCollectionKey
Gaudi::Property< double > m_dimuMassLower_prefit
bool matchDimuon(const xAOD::Vertex *dimuonVertex, const std::string &chainName) const
Gaudi::Property< std::vector< std::string > > m_ChainNames_MuMu
ToolHandle< Trk::V0Tools > m_v0Tools
StatusCode fillVertexHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const xAOD::Vertex *vertex, const std::string &objStr) const
Gaudi::Property< double > m_dimuMassUpper_prefit
StatusCode fillChainGenericHists(const EventContext &, const ToolHandle< GenericMonitoringTool > &currentMonGroup, const std::string &chainName) const
StatusCode fillDiTracksHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const std::vector< ElementLink< xAOD::TrackParticleContainer > > &tpLinkVector, const std::string &name_prefix) const
StatusCode fillDimuonChainHists(const EventContext &ctx, const std::string &chainName) const
StatusCode fillBphysObjectHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const ElementLink< xAOD::TrigBphysContainer > &bphysLink, const std::string &objStr) const
virtual StatusCode initialize() override
initialize
StatusCode fillTrigBmumuxTrkHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const ElementLink< xAOD::TrigBphysContainer > &bphysLink, UInt_t tracksStartFrom=2) const
Gaudi::Property< double > m_dimuChi2Cut
StatusCode fillBmumuxChainHists(const EventContext &ctx, const std::string &chainName) const
SG::ReadHandleKey< xAOD::VertexContainer > m_offlinePvCollectionKey
bool isChainPassed(const std::string &chain) const
StatusCode fillContainerHists(const EventContext &ctx, const SG::ReadHandleKey< xAOD::TrigBphysContainer > &trigBphysContainerKey) const
Gaudi::Property< std::vector< std::string > > m_ChainNames_MuMuX
ToolHandle< InDet::VertexPointEstimator > m_vertexPointEstimator
std::vector< const xAOD::Vertex * > GetGoodPVs(const xAOD::VertexContainer *pvContainer) const
StatusCode fillOfflineDimuonHists(const EventContext &, const std::string &dimuonMonGroupName, const std::vector< std::unique_ptr< xAOD::Vertex > > &dimuonContainer) const
StatusCode fillContainers(const EventContext &ctx) const
For lxy etc.
StatusCode fillOfflineDimuons(const EventContext &ctx, const std::vector< std::unique_ptr< xAOD::Vertex > > &dimuonContainer) const
StatusCode fillTrigLeptonHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const ElementLink< xAOD::TrigBphysContainer > &bphysLink, const std::string &name_prefix) const
StatusCode fillTracksHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const std::vector< ElementLink< xAOD::TrackParticleContainer > > &tpLinkVector, const std::string &prefix, bool separateHists=false, UInt_t offsetIndex=0) const
const xAOD::Vertex * getPvForDimuon_lowestA0(const xAOD::Vertex *vtx, const std::vector< const xAOD::Vertex * > &PVs) const
StatusCode fillTrkHists(const ToolHandle< GenericMonitoringTool > &currentMonGroup, const xAOD::TrackParticle *trk, const std::string &name_prefix) const
std::unique_ptr< xAOD::Vertex > dimuonFit(const xAOD::TrackParticle *mu1, const xAOD::TrackParticle *mu2) const
Gaudi::Property< bool > m_requireExplicitESDecision
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_offlineIDTrackCollectionKey
SG::ReadHandleKeyArray< xAOD::TrigBphysContainer > m_TrigBphysContainerKeys
StatusCode fillDielectronChainHists(const EventContext &ctx, const std::string &chainName) const
TrigBphysMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode buildDimuons(const EventContext &ctx, std::vector< std::unique_ptr< xAOD::Vertex > > &vxContainer) const
Gaudi::Property< std::vector< std::string > > m_ChainNames_ElEl
double dimuonMass(const xAOD::TrackParticle *mu1, const xAOD::TrackParticle *mu2) const
ToolHandle< Trk::TrkVKalVrtFitter > m_vertexFitter
bool setLxyErr(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
its error
bool setLxy(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the transverse decay distance and its error measured between the refitted primary vertex of type ...
float lxy(const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Get the transverse decay distance and its error measured between the refitted primary vertex of type ...
bool setRefTrks(std::vector< float > px, std::vector< float > py, std::vector< float > pz)
Sets refitted track momenta.
int nRefTrks()
Returns number of stored refitted track momenta.
TVector3 totalP()
: Returns total 3-momentum calculated from the refitted tracks
float lxyErr(const pv_type vertexType=BPhysHelper::PV_MIN_A0)
its error
ROOT::Math::LorentzVector< ROOT::Math::PxPyPzM4D< double > > GenVecFourMom_t
Base 4 Momentum type for TrackParticle.
const Trk::Perigee & perigeeParameters() const
Returns the Trk::MeasuredPerigee track parameters.
float d0() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
GenVecFourMom_t genvecP4() const
The full 4-momentum of the particle : GenVector form.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float fitmass() const
accessor method: mass from vertex fit
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
Eigen::Matrix< double, 3, 1 > Vector3D
ValuesCollection< T > Collection(std::string name, const T &collection)
Declare a monitored (double-convertible) collection.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
double deltaR(double rapidity1, double phi1, double rapidity2, double phi2)
from bare bare rapidity,phi
VertexType
Vertex types.
@ PileUp
Pile-up vertex.
@ PriVtx
Primary vertex.
TrigBphys_v1 TrigBphys
Definition TrigBphys.h:18
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
TrigBphysContainer_v1 TrigBphysContainer
std::array< double, 6 > mass
void fill(H5::Group &out_file, size_t iterations)