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 for(const auto& monitoredChain : m_ChainNames_Bhh) {
130 ATH_MSG_DEBUG("Process chain " << monitoredChain);
131 if( !isChainPassed(monitoredChain) ) {
132 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
133 continue;
134 }
135 if(fillBhhChainHists(ctx, monitoredChain).isFailure()) {
136 ATH_MSG_ERROR(Form("Problems filling %s chain histograms", monitoredChain.c_str()));
137 }
138 }
139
140 return StatusCode::SUCCESS;
141}
142
143StatusCode TrigBphysMonitorAlgorithm::fillDimuonChainHists(const EventContext& ctx, const std::string& chainName) const {
144 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
145
146 std::string monGroupName = std::string("Chain_")+chainName;
147 auto monGroup = getGroup(monGroupName);
148
149 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
150 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
151 }
152
153 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
154 for (const auto& featLinkInfo: chainFeatureContainer){
155 ATH_CHECK(featLinkInfo.isValid());
156 const auto featLink = featLinkInfo.link;
157 if (fillBphysObjectHists(monGroup, featLink, "dimu").isFailure()) {
158 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
159 }
160 if (fillTrigLeptonHists(monGroup, featLink, "mu").isFailure()) {
161 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
162 }
163 }
164 return StatusCode::SUCCESS;
165}
166
167
168StatusCode TrigBphysMonitorAlgorithm::fillBmumuxChainHists(const EventContext& ctx, const std::string& chainName) const {
169 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
170
171 std::string monGroupName = std::string("Chain_")+chainName;
172 auto monGroup = getGroup(monGroupName);
173
174 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
175 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
176 }
177
178 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
179 for (const auto& featLinkInfo: chainFeatureContainer){
180 ATH_CHECK(featLinkInfo.isValid());
181 const auto featLink = featLinkInfo.link;
182 if (fillBphysObjectHists(monGroup, featLink, "B").isFailure()) {
183 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
184 }
185 if (fillTrigBmumuxTrkHists(monGroup, featLink).isFailure()) {
186 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
187 }
188
189 auto dimuonLink = (*featLink)->lowerChainLink();
190 ATH_CHECK(dimuonLink.isValid());
191 if (fillBphysObjectHists(monGroup, dimuonLink, "dimu").isFailure()) {
192 ATH_MSG_ERROR(Form("Problems filling dimuon object histograms for %s chain",chainName.c_str()));
193 }
194 if (fillTrigLeptonHists(monGroup, dimuonLink, "mu").isFailure()) {
195 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
196 }
197 }
198
199 return StatusCode::SUCCESS;
200}
201
202StatusCode TrigBphysMonitorAlgorithm::fillDielectronChainHists(const EventContext& ctx, const std::string& chainName) const {
203 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
204
205 std::string monGroupName = std::string("Chain_")+chainName;
206 auto monGroup = getGroup(monGroupName);
207
208 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
209 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
210 }
211
212 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
213 for (const auto& featLinkInfo: chainFeatureContainer){
214 ATH_CHECK(featLinkInfo.isValid());
215 const auto featLink = featLinkInfo.link;
216 if (fillBphysObjectHists(monGroup, featLink, "diel").isFailure()) {
217 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
218 }
219 if (fillTrigLeptonHists(monGroup, featLink, "el").isFailure()) {
220 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
221 }
222 }
223 return StatusCode::SUCCESS;
224}
225
226StatusCode TrigBphysMonitorAlgorithm::fillBhhChainHists(const EventContext& ctx, const std::string& chainName) const {
227 ATH_MSG_DEBUG("Filling " << chainName << " chain histograms");
228
229 std::string monGroupName = std::string("Chain_")+chainName;
230 auto monGroup = getGroup(monGroupName);
231
232 if (fillChainGenericHists(ctx, monGroup, chainName).isFailure()) {
233 ATH_MSG_ERROR(Form("Problems filling generic histograms for %s chain",chainName.c_str()));
234 }
235
236 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
237 for (const auto& featLinkInfo: chainFeatureContainer){
238 ATH_CHECK(featLinkInfo.isValid());
239 const auto featLink = featLinkInfo.link;
240 if (fillBphysObjectHists(monGroup, featLink, "B").isFailure()) {
241 ATH_MSG_ERROR(Form("Problems filling bphys object histograms for %s chain",chainName.c_str()));
242 }
243 if (fillTrigBmumuxTrkHists(monGroup, featLink, 0).isFailure()) { // same logic as for Bmumux, but start from 1st track - there are no muons
244 ATH_MSG_ERROR(Form("Problems filling muon histograms for %s chain",chainName.c_str()));
245 }
246 }
247
248 return StatusCode::SUCCESS;
249}
250
251
252// Function to fill general per-chain hists, independent on the type of chains
253StatusCode TrigBphysMonitorAlgorithm::fillChainGenericHists(const EventContext& /*ctx*/, const ToolHandle<GenericMonitoringTool>& currentMonGroup, const std::string& chainName) const {
254
255 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
256 auto ncandidates = Monitored::Scalar<int>("ncandidates",-999);
257 ncandidates = chainFeatureContainer.size();
258
259 fill(currentMonGroup, ncandidates);
260
261 return StatusCode::SUCCESS;
262}
263
264
265// Function to fill per-object hists (e.g. for dimuon, B from Bmumux, or X from Bmumux)
266StatusCode TrigBphysMonitorAlgorithm::fillBphysObjectHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, const std::string& objStr) const {
267
268 auto dimu_mass = Monitored::Scalar<float>(objStr+"_mass",-999.);
269 auto dimu_fitmass = Monitored::Scalar<float>(objStr+"_fitmass",-999.);
270 auto dimu_pt = Monitored::Scalar<float>(objStr+"_pt",-999.);
271 auto dimu_y = Monitored::Scalar<float>(objStr+"_y",-999.);
272 auto dimu_chi2 = Monitored::Scalar<float>(objStr+"_chi2",-999.);
273
274 dimu_mass = (*bphysLink)->mass() / GeV;
275 dimu_fitmass = (*bphysLink)->fitmass() / GeV;
276 dimu_pt = (*bphysLink)->pt() / GeV;
277 dimu_chi2 = (*bphysLink)->fitchi2();
278 dimu_y = (*bphysLink)->eta();
279
280 fill(currentMonGroup, dimu_mass, dimu_fitmass, dimu_pt, dimu_y, dimu_chi2);
281
282 return StatusCode::SUCCESS;
283}
284
285
286// Function to fill per-muon hists, assuming that the passed object is a dimuon
287StatusCode TrigBphysMonitorAlgorithm::fillTrigLeptonHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, const std::string& name_prefix) const {
288
289 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
290 ATH_MSG_DEBUG("fillTrigLeptonHists: number of lepton tracks: " << trackVector.size());
291 if( fillTracksHists(currentMonGroup, trackVector, name_prefix, true).isFailure() ) {
292 ATH_MSG_ERROR(Form("Problems filling muon histograms for a chain"));
293 return StatusCode::FAILURE;
294 }
295 if( fillDiTracksHists(currentMonGroup, trackVector, std::string("di")+name_prefix).isFailure() ) {
296 ATH_MSG_ERROR(Form("Problems filling two-muon histograms for a chain"));
297 return StatusCode::FAILURE;
298 }
299
300 return StatusCode::SUCCESS;
301}
302
303// Function to fill per-track hists for Bmumux candidates
304StatusCode TrigBphysMonitorAlgorithm::fillTrigBmumuxTrkHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const ElementLink<xAOD::TrigBphysContainer>& bphysLink, UInt_t tracksStartFrom) const {
305
306 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
307 if (trackVector.size() < tracksStartFrom) {
308 ATH_MSG_WARNING("Unexpected number of tracks: "<< trackVector.size() << " found, while expected at least " << tracksStartFrom);
309 return StatusCode::SUCCESS;
310 }
311
312 if (fillTracksHists(currentMonGroup, trackVector, "trk", false, tracksStartFrom).isFailure()) {
313 ATH_MSG_ERROR(Form("Problems filling track histograms for a BMuMuX chain"));
314 return StatusCode::FAILURE;
315 }
316
317 return StatusCode::SUCCESS;
318}
319
320StatusCode TrigBphysMonitorAlgorithm::fillTracksHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup,
321 const std::vector<ElementLink<xAOD::TrackParticleContainer> >& tpLinkVector,
322 const std::string& prefix,
323 bool separateHists,
324 UInt_t offsetIndex) const {
325 for(UInt_t i = offsetIndex; i < tpLinkVector.size(); ++i) {
326 ATH_CHECK(tpLinkVector.at(i).isValid());
327 std::string curPrefix = prefix;
328 if(separateHists)
329 curPrefix += std::to_string(i+1);
330 if (fillTrkHists(currentMonGroup, *tpLinkVector.at(i), curPrefix).isFailure()) {
331 ATH_MSG_ERROR(Form("Problems filling track histograms"));
332 return StatusCode::FAILURE;
333 }
334 }
335 return StatusCode::SUCCESS;
336}
337
338StatusCode TrigBphysMonitorAlgorithm::fillDiTracksHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup,
339 const std::vector<ElementLink<xAOD::TrackParticleContainer> >& tpLinkVector,
340 const std::string& name_prefix) const {
341 // Use first two tracks
342 if (tpLinkVector.size() <2) {
343 ATH_MSG_ERROR("Unexpected number of tracks in a dimuon: " << tpLinkVector.size());
344 return StatusCode::FAILURE;
345 }
346 ATH_CHECK(tpLinkVector.at(0).isValid());
347 ATH_CHECK(tpLinkVector.at(1).isValid());
348 const xAOD::TrackParticle* trk1 = *tpLinkVector.at(0);
349 const xAOD::TrackParticle* trk2 = *tpLinkVector.at(1);
350
351 auto ditrk_dR = Monitored::Scalar<float>(name_prefix+"_dR",-999.);
352 auto ditrk_deta = Monitored::Scalar<float>(name_prefix+"_deta",-999.);
353 auto ditrk_dphi = Monitored::Scalar<float>(name_prefix+"_dphi",-999.);
354
355 ditrk_dR = xAOD::P4Helpers::deltaR(*trk1, *trk2, false); // false for pseudo, not true rapidity
356 ditrk_deta = std::abs(trk1->eta()-trk2->eta());
357 ditrk_dphi = std::abs(xAOD::P4Helpers::deltaPhi(*trk1, *trk2));
358
359 fill(currentMonGroup, ditrk_dR, ditrk_deta, ditrk_dphi);
360
361 return StatusCode::SUCCESS;
362}
363
364// Generic function to fill track hists
365StatusCode TrigBphysMonitorAlgorithm::fillTrkHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const xAOD::TrackParticle* trk, const std::string& name_prefix) const {
366 if (!trk) {
367 ATH_MSG_ERROR("Null pointer for a track");
368 return StatusCode::FAILURE;
369 }
370 auto trk_pt = Monitored::Scalar<float>(name_prefix+"_pt",-999.);
371 auto trk_eta = Monitored::Scalar<float>(name_prefix+"_eta",-999.);
372 auto trk_d0 = Monitored::Scalar<float>(name_prefix+"_d0",-999.);
373
374 trk_pt = trk->pt() / GeV;
375 trk_eta = trk->eta();
376 trk_d0 = trk->d0();
377
378 fill(currentMonGroup, trk_pt, trk_eta, trk_d0);
379
380 return StatusCode::SUCCESS;
381}
382
383StatusCode TrigBphysMonitorAlgorithm::fillOfflineDimuons(const EventContext& ctx, const std::vector<std::unique_ptr<xAOD::Vertex>>& dimuonContainer) const {
384
385 std::vector<std::string> dimuonMonGroupNames = {"Any"};
386 dimuonMonGroupNames.insert( dimuonMonGroupNames.end(), m_ChainNames_MuMu.begin(), m_ChainNames_MuMu.end() );
387 dimuonMonGroupNames.insert( dimuonMonGroupNames.end(), m_ChainNames_MuMuX.begin(), m_ChainNames_MuMuX.end() );
388
389 for(const auto& dimuonMonGroupName : dimuonMonGroupNames) {
390 ATH_MSG_DEBUG("Process dimuons for " << dimuonMonGroupName);
391 if(dimuonMonGroupName != "Any") {
392 auto& monitoredChain = dimuonMonGroupName;
393 if( !(dimuonMonGroupName == "Any") && !isChainPassed(monitoredChain) ) {
394 ATH_MSG_DEBUG("Chain " << monitoredChain << " is not passed");
395 continue;
396 }
397 }
398 if(fillOfflineDimuonHists(ctx, dimuonMonGroupName, dimuonContainer).isFailure()) {
399 ATH_MSG_ERROR(Form("Problems filling offline dimuon histograms for %s", dimuonMonGroupName.c_str()));
400 }
401 }
402
403 return StatusCode::SUCCESS;
404}
405
406StatusCode TrigBphysMonitorAlgorithm::fillOfflineDimuonHists(const EventContext& /*ctx*/, const std::string& dimuonMonGroupName, const std::vector<std::unique_ptr<xAOD::Vertex>>& dimuonContainer) const {
407 ATH_MSG_DEBUG("Filling " << dimuonMonGroupName << " offline dimuons histograms");
408
409 // Do matching
410 std::vector<const xAOD::Vertex*> matchedDimuons;
411 for(auto& offlineDimuon : dimuonContainer) {
412 if( dimuonMonGroupName == "Any" || matchDimuon(offlineDimuon.get(), dimuonMonGroupName) )
413 matchedDimuons.push_back(offlineDimuon.get());
414 }
415
416 std::string monGroupName = std::string("OfflineDimu_")+dimuonMonGroupName;
417 auto monGroup = getGroup(monGroupName);
418
419 auto ncandidates = Monitored::Scalar<int>("ncandidates",-999);
420 ncandidates = matchedDimuons.size();
421
422 fill(monGroup, ncandidates);
423
424 for(auto matchedDimuon : matchedDimuons) {
425 if (fillVertexHists(monGroup, matchedDimuon, "dimu").isFailure()) {
426 ATH_MSG_ERROR(Form("Problems filling histogram for an offline dimuon vertex in %s", dimuonMonGroupName.c_str()));
427 }
428 if (fillTracksHists(monGroup, matchedDimuon->trackParticleLinks(), "mu", true).isFailure()) {
429 ATH_MSG_ERROR(Form("Problems filling histogram for offline dimuon muons in %s", dimuonMonGroupName.c_str()));
430 }
431 if (fillDiTracksHists(monGroup, matchedDimuon->trackParticleLinks(), "dimu").isFailure()) {
432 ATH_MSG_ERROR(Form("Problems filling histogram for offline dimuon muon pairs in %s", dimuonMonGroupName.c_str()));
433 }
434 }
435
436 return StatusCode::SUCCESS;
437
438}
439
440StatusCode TrigBphysMonitorAlgorithm::fillVertexHists(const ToolHandle<GenericMonitoringTool>& currentMonGroup, const xAOD::Vertex* vertex, const std::string& objStr) const {
441
442 xAOD::BPhysHelper dimuonVertexHelper(vertex);
443 if(dimuonVertexHelper.nRefTrks() != 2) {
444 ATH_MSG_WARNING("Unexpected number of refitted tracks at vertex is " << dimuonVertexHelper.nRefTrks());
445 return StatusCode::SUCCESS;
446 }
447
448 using namespace TrigVtx;
449 TLorentzVector dimuonMom = dimuonVertexHelper.totalP(std::array<double,2>{TrigParticleMasses().mass[TrigParticleName::muon], TrigParticleMasses().mass[TrigParticleName::muon]});
450
451 auto dimu_mass = Monitored::Scalar<float>(objStr+"_mass",-999.);
452 auto dimu_pt = Monitored::Scalar<float>(objStr+"_pt",-999.);
453 auto dimu_y = Monitored::Scalar<float>(objStr+"_y",-999.);
454 auto dimu_chi2 = Monitored::Scalar<float>(objStr+"_chi2",-999.);
455 auto dimu_Lxy = Monitored::Scalar<float>(objStr+"_Lxy",-999.);
456 auto dimu_LxySig = Monitored::Scalar<float>(objStr+"_LxySig",-999.);
457
458 dimu_mass = dimuonMom.M() / GeV;
459 dimu_pt = dimuonMom.Pt() / GeV;
460 dimu_chi2 = vertex->chiSquared();
461 dimu_y = dimuonMom.Rapidity();
462 dimu_Lxy = dimuonVertexHelper.lxy(xAOD::BPhysHelper::PV_MIN_A0);
463 dimu_LxySig = dimuonVertexHelper.lxy(xAOD::BPhysHelper::PV_MIN_A0)/dimuonVertexHelper.lxyErr(xAOD::BPhysHelper::PV_MIN_A0);
464
465 fill(currentMonGroup, dimu_mass, dimu_pt, dimu_y, dimu_chi2, dimu_Lxy, dimu_LxySig);
466
467 return StatusCode::SUCCESS;
468}
469
470bool TrigBphysMonitorAlgorithm::isChainPassed(const std::string& chain) const {
471 // Check if a chain is passed after prescale, accounting for Express Stream prescales if necessary
473 return getTrigDecisionTool()->isPassed(chain);
474 }
475 else {
476 const unsigned int passBits = getTrigDecisionTool()->isPassedBits(chain);
477 return passBits & TrigDefs::Express_passed;
478 }
479}
480
481StatusCode TrigBphysMonitorAlgorithm::buildDimuons(const EventContext& ctx, std::vector<std::unique_ptr<xAOD::Vertex>>& vxContainer) const {
482 ATH_MSG_DEBUG( "TrigBphysMonitorAlgorithm::buildDimuons" );
483
484 // Get the muons
486 ATH_CHECK(muonHandle.isValid());
487 const xAOD::MuonContainer* muonContainer = muonHandle.cptr();
488 ATH_MSG_DEBUG("Muon container size " << muonContainer->size());
489
490 // Muon preselection
491 std::vector<const xAOD::Muon*> selectedMuons;
492 for (const auto mu : *muonContainer) {
493 if ( mu == nullptr ) continue;
494 if ( mu->muonType() != xAOD::Muon::Combined ) continue; // require combined muons
495 if (!mu->inDetTrackParticleLink()) continue; // No muons without ID tracks
496 if (!mu->inDetTrackParticleLink().isValid()) continue; // No muons without ID tracks
497 selectedMuons.push_back(mu);
498 }
499 if(selectedMuons.size() < 2) {
500 ATH_MSG_DEBUG("Only " << selectedMuons.size() << "muons pass preselection");
501 return StatusCode::SUCCESS;
502 }
503 std::sort(selectedMuons.begin(), selectedMuons.end(), [](const auto mu1, const auto mu2){ return mu1->pt() > mu2->pt(); });
504
505 // Build dimuons
506 for(auto outerItr=selectedMuons.begin(); outerItr<selectedMuons.end(); ++outerItr){
507 for(auto innerItr=(outerItr+1); innerItr!=selectedMuons.end(); ++innerItr){
508 const auto muon1 = *outerItr;
509 const auto muon2 = *innerItr;
510 const auto trackParticle1 = muon1->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
511 const auto trackParticle2 = muon2->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
512 // Charge selection
513 if(trackParticle1->qOverP() * trackParticle2->qOverP() > 0.)
514 continue;
515 // Mass selection
516 double dimu_momentum_prefit = dimuonMass(trackParticle1, trackParticle2);
517 if( !(dimu_momentum_prefit > m_dimuMassLower_prefit && dimu_momentum_prefit < m_dimuMassUpper_prefit) )
518 continue;
519 // Fit
520 std::unique_ptr<xAOD::Vertex> dimuon = dimuonFit(trackParticle1, trackParticle2);
521 if(!dimuon) continue;
522 if(dimuon->chiSquared() > m_dimuChi2Cut) continue;
523 vxContainer.push_back(std::move(dimuon));
524 }
525 }
526 ATH_MSG_DEBUG("Found " << vxContainer.size() << " good dimuons");
527
528 // Augment the dimuon vertices
529 if( !vxContainer.empty() ) {
531 ATH_CHECK(pvHandle.isValid());
532 const xAOD::VertexContainer* pvContainer = pvHandle.cptr();
533 std::vector<const xAOD::Vertex*> goodPVs = GetGoodPVs(pvContainer);
534 ATH_MSG_DEBUG("Found " << goodPVs.size() << " good PVs");
535 for(auto& dimuon : vxContainer) {
536 xAOD::BPhysHelper jpsiHelper(dimuon.get());
537 jpsiHelper.setRefTrks();
538 const xAOD::Vertex* lowestA0Pv = getPvForDimuon_lowestA0(dimuon.get(), goodPVs);
539 if(lowestA0Pv) {
540 jpsiHelper.setLxy ( m_v0Tools->lxy ( dimuon.get(),lowestA0Pv ), xAOD::BPhysHelper::PV_MIN_A0 );
541 jpsiHelper.setLxyErr( m_v0Tools->lxyError( dimuon.get(),lowestA0Pv ), xAOD::BPhysHelper::PV_MIN_A0 );
542 ATH_MSG_VERBOSE("Lxy = " << m_v0Tools->lxy ( dimuon.get(),lowestA0Pv ));
543 ATH_MSG_VERBOSE("LxyErr = " << m_v0Tools->lxyError( dimuon.get(),lowestA0Pv ));
544 }
545 }
546 }
547
548 return StatusCode::SUCCESS;
549}
550
551std::unique_ptr<xAOD::Vertex> TrigBphysMonitorAlgorithm::dimuonFit(const xAOD::TrackParticle* mu1, const xAOD::TrackParticle* mu2) const {
552
553 const Trk::Perigee& mu1Perigee = mu1->perigeeParameters();
554 const Trk::Perigee& mu2Perigee = mu2->perigeeParameters();
555 int sflag = 0; int errorcode = 0;
556 Amg::Vector3D startingPoint = m_vertexPointEstimator->getCirclesIntersectionPoint(&mu1Perigee,&mu2Perigee,sflag,errorcode);
557 if (errorcode != 0) {startingPoint(0) = 0.0; startingPoint(1) = 0.0; startingPoint(2) = 0.0;}
558 const std::vector<const xAOD::TrackParticle*> trackPair = {mu1, mu2};
559 std::unique_ptr<xAOD::Vertex> myVxCandidate(m_vertexFitter->fit(trackPair, startingPoint));
560
561 return myVxCandidate;
562}
563
564bool TrigBphysMonitorAlgorithm::matchDimuon(const xAOD::Vertex* dimuonVertex, const std::string& chainName) const {
565 std::vector< TrigCompositeUtils::LinkInfo<xAOD::TrigBphysContainer> > chainFeatureContainer = getTrigDecisionTool()->features<xAOD::TrigBphysContainer>(chainName, TrigDefs::Physics);
566 for (const auto& featLinkInfo: chainFeatureContainer){
567 if(!featLinkInfo.isValid())
568 return false;
569 const auto featLink = featLinkInfo.link;
570 if( matchDimuon(dimuonVertex, featLink) )
571 return true;
572 }
573 return false;
574}
575
577 auto offlineTrk1 = dimuonVertex->trackParticle(0);
578 auto offlineTrk2 = dimuonVertex->trackParticle(1);
579 if(!offlineTrk1 || !offlineTrk2) {
580 ATH_MSG_DEBUG("TrackParticle from dimuon is null, won't match");
581 return false;
582 }
583
584 const std::vector<ElementLink<xAOD::TrackParticleContainer> > trackVector = (*bphysLink)->trackParticleLinks();
585 if (trackVector.size() < 2) {
586 ATH_MSG_ERROR("Unexpected number of tracks in a dimuon: " << trackVector.size() << ", won't match");
587 return false;
588 }
589
590 const xAOD::TrackParticle *hltTrk1(nullptr),*hltTrk2(nullptr);
591 // Assume the first two tracks are always muons'
592 if( !trackVector.at(0).isValid() || !trackVector.at(1).isValid() )
593 return false;
594 hltTrk1 = *trackVector.at(0);
595 hltTrk2 = *trackVector.at(1);
596 if (!hltTrk1 || !hltTrk2) {
597 ATH_MSG_ERROR("Null pointer for track in a dimuon!");
598 return false;
599 }
600 if( ( matchTrackParticles(offlineTrk1, hltTrk1) && matchTrackParticles(offlineTrk2, hltTrk2) ) ||
601 ( matchTrackParticles(offlineTrk1, hltTrk2) && matchTrackParticles(offlineTrk2, hltTrk1) ) )
602 return true;
603 else
604 return false;
605}
606
608 double deltaR = xAOD::P4Helpers::deltaR(*trk1, *trk2);
610 return true;
611 else
612 return false;
613}
614
616 using namespace TrigVtx;
621 xAOD::TrackParticle::GenVecFourMom_t dimu_mom = mom1 + mom2;
622 return dimu_mom.M();
623}
624
625std::vector<const xAOD::Vertex*> TrigBphysMonitorAlgorithm::GetGoodPVs(const xAOD::VertexContainer* pvContainer) const {
626 std::vector<const xAOD::Vertex*> goodPrimaryVertices;
627 goodPrimaryVertices.reserve(pvContainer->size());
628 for (auto pv : *pvContainer) {
629 xAOD::VxType::VertexType pvType = pv->vertexType();
630 if ( pvType == xAOD::VxType::PriVtx || pvType == xAOD::VxType::PileUp ) {
631 goodPrimaryVertices.push_back(pv);
632 }
633 }
634 return goodPrimaryVertices;
635}
636
637const xAOD::Vertex* TrigBphysMonitorAlgorithm::getPvForDimuon_lowestA0(const xAOD::Vertex* vtx, const std::vector<const xAOD::Vertex*>& PVs) const {
638 std::vector<const xAOD::Vertex*>::const_iterator pv = std::min_element(PVs.begin(), PVs.end(),
639 [&, vtx](const xAOD::Vertex* pv1, const xAOD::Vertex* pv2)
640 { return (std::abs(m_v0Tools->a0(vtx, pv1)) < std::abs(m_v0Tools->a0(vtx, pv2)));}
641 );
642 if(pv == PVs.end()) {
643 return nullptr;
644 }
645 ATH_MSG_VERBOSE("Min-a0 PV has index " << std::distance(PVs.begin(), pv) << ", a0 = " << m_v0Tools->a0(vtx, *pv));
646 return *pv;
647}
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
StatusCode fillBhhChainHists(const EventContext &ctx, const std::string &chainName) const
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
Gaudi::Property< std::vector< std::string > > m_ChainNames_Bhh
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)