ATLAS Offline Software
Loading...
Searching...
No Matches
TrigmuCombHypoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "GaudiKernel/SystemOfUnits.h"
10#include "CxxUtils/phihelper.h"
11
12#include <cmath>
13
14using namespace TrigCompositeUtils;
15// --------------------------------------------------------------------------------
16// --------------------------------------------------------------------------------
17
19 const std::string & name,
20 const IInterface* parent )
21 : AthAlgTool( type, name, parent ),
22 m_decisionId( HLT::Identifier::fromToolName( name ) )
23{
24}
25
28
29// --------------------------------------------------------------------------------
30// --------------------------------------------------------------------------------
31
33{
34 ATH_MSG_DEBUG( "Tool configured for chain/id: " << m_decisionId );
35
36 if (m_acceptAll) {
37 ATH_MSG_DEBUG("Accepting all the events!");
38 } else {
39 ATH_MSG_DEBUG("AcceptAll = False");
40 m_bins.resize (m_ptBins.size());
41 for ( size_t j=0; j<m_ptBins.size(); ++j) {
42 m_bins[j] = m_ptBins[j].size() - 1;
43 if (m_bins[j] != m_ptThresholds[j].size()) {
44 ATH_MSG_ERROR("bad thresholds setup .... exiting!");
45 return StatusCode::FAILURE;
46 }
47
48 for (std::vector<float>::size_type i = 0; i < m_bins[j]; ++i) {
49
50 ATH_MSG_DEBUG("bin[" << j << "] " << m_ptBins[j][i] << " - " << m_ptBins[j][i + 1]
51 << " with Pt Threshold of " << (m_ptThresholds[j][i]) / Gaudi::Units::GeV << " GeV");
52 }
53 }
54 }
55
56 if ( not m_monTool.name().empty() ) {
57 ATH_CHECK( m_monTool.retrieve() );
58 ATH_MSG_DEBUG("MonTool name: " << m_monTool);
59 }
60
61 // Overlap Removal
62 if( m_applyOR ) {
63 ATH_MSG_DEBUG( "--- overlap removal as: ---" );
64 if( m_requireDR ) {
65 ATH_MSG_DEBUG( "+ dR cut:" );
66 if( (m_etaBins.size()-1) != m_dRThres.size() ) {
67 ATH_MSG_ERROR( "bad thresholds setup .... exiting!" );
68 return StatusCode::FAILURE;
69 }
70 for(unsigned int i=0; i<m_dRThres.size(); i++) {
71 ATH_MSG_DEBUG( " EtaBin " << m_etaBins[i] << " - " << m_etaBins[i+1]
72 << " : dR < " << m_dRThres[i] );
73 }
74 }
75 if( m_requireMufastDR ) {
76 ATH_MSG_DEBUG( "+ dr(by mF) cut:" );
77 if( (m_etaBins.size()-1) != m_mufastDRThres.size() ) {
78 ATH_MSG_ERROR( "bad thresholds setup .... exiting!" );
79 return StatusCode::FAILURE;
80 }
81 for(unsigned int i=0; i<m_mufastDRThres.size(); i++) {
82 ATH_MSG_DEBUG( " EtaBin " << m_etaBins[i] << " - " << m_etaBins[i+1]
83 << " : dR(mF) < " << m_mufastDRThres[i] );
84 }
85 }
86 if( m_requireMass ) {
87 ATH_MSG_DEBUG( "+ Mass cut:" );
88 if( (m_etaBins.size()-1) != m_massThres.size() ) {
89 ATH_MSG_ERROR( "bad thresholds setup .... exiting!" );
90 return StatusCode::FAILURE;
91 }
92 for(unsigned int i=0; i<m_massThres.size(); i++) {
93 ATH_MSG_DEBUG( " EtaBin " << m_etaBins[i] << " - " << m_etaBins[i+1]
94 << " : Mass < " << m_massThres[i] );
95 }
96 }
97 if( m_requireSameSign ) ATH_MSG_DEBUG( "+ Same charge sign" );
98 }
99 // minimum d0 cut for displaced muon triggers
100 if (m_d0min>0.) ATH_MSG_DEBUG( " Rejecting muons with abs(d0) < "<<m_d0min<<" mm");
101
102 return StatusCode::SUCCESS;
103}
104
106{
107
108 // defined Monitoring variables
109 auto fexPt = Monitored::Scalar("Pt", -9999.);
110 auto ptFL = Monitored::Scalar("PtFL", -9999.);
111 auto Strategy = Monitored::Scalar("StrategyFlag", 0);
112 auto idEta = Monitored::Scalar("Eta", -9999.);
113 auto idPhi = Monitored::Scalar("Phi", -9999.);
114 auto idZ0 = Monitored::Scalar("Z0", -9999.);
115 auto idA0 = Monitored::Scalar("A0", -9999.);
116
117 auto monitorIt = Monitored::Group(m_monTool, fexPt, ptFL, Strategy,
118 idEta, idPhi, idZ0, idA0);
119
120 ATH_MSG_VERBOSE( "Cut index " << cutIndex );
121
122 // flag to pass or not
123 bool result = false;
124
125 if(m_acceptAll) {
126 result = true;
127 ATH_MSG_DEBUG("Accept property is set: taking all the events");
128 return result;
129 } else {
130 result = false;
131 ATH_MSG_DEBUG("Accept property not set: applying selection!");
132 }
133
134 //Retrieve combined muon
135 //xAOD::L2CombinedMuon
136 auto pMuon = input.muComb;
137 if (!pMuon) {
138 result = false;
139 ATH_MSG_ERROR("Retrieval of xAOD::L2CombinedMuon from vector failed");
140 return result;
141 }
142
143 auto ptValue = pMuon->pt() * pMuon->charge() / Gaudi::Units::GeV;
144
145
146 if (pMuon->pt() == 0) {
147 ATH_MSG_DEBUG("L2CombinedMuon pt == 0, empty container -> rejected");
148 result = false;
149 return result;
150 }
151
152 fexPt = ptValue;
153 ptFL = ptValue;
154 idEta = pMuon->eta();
155 idPhi = pMuon->phi();
156 int usealgo = pMuon->strategy();
157 float ptresComb = pMuon->sigmaPt() / Gaudi::Units::GeV;
158 Strategy = usealgo;
159 ATH_MSG_DEBUG("combined muon pt (GeV)/ sigma_pt (GeV)/ eta / phi / usedalgo: "
160 << fexPt << " (GeV) / " << ptresComb << " (GeV) / " << idEta << " / " << idPhi
161 << " / " << usealgo);
162
163 // check the pointers to the L2StandAloneMuon
164 if (!pMuon->muSATrack()) {
165 ATH_MSG_DEBUG("L2CombinedMuon has no valid xaOD::L2StandaloneMuon -> rejected");
166 result = false;
167 return result;
168 }
169
170 // check the pointer to the ID track
171 if (!pMuon->idTrack()) {
172 ATH_MSG_DEBUG("L2CombinedMuon has no valid xAOD:TrackParticle IDtrack -> rejected");
173 result = false;
174 return result;
175 }
176
177 idA0 = pMuon->idTrack()->d0();
178 idZ0 = pMuon->idTrack()->z0();
179
180 //Get the Pt cut for that eta bin
181 float threshold = (idEta != -9999) ? 0 : 999999;
182 float absEta = fabs(idEta);
183 for (std::vector<float>::size_type i = 0; i < m_bins[cutIndex]; ++i) {
184 if (absEta > m_ptBins[cutIndex][i] && absEta < m_ptBins[cutIndex][i + 1]) threshold = m_ptThresholds[cutIndex][i];
185 }
186
187 // Check pt threshold for hypothesis and pi/k rejection cuts,
188 // convert units since Muonfeature is in GeV
189
190 //Kpi rejection
191 bool pikCut = true;
192 if (m_pikCuts && (std::abs(fexPt) < m_maxPtToApplyPik)) {
193 if (pMuon->idTrack()->chiSquared() > m_chi2MaxID) pikCut = false;
194 }
195
196 //Std Pt cut
197 bool stdCut = true;
198 if (std::abs(fexPt) <= (threshold / Gaudi::Units::GeV)) stdCut = false;
199 ATH_MSG_DEBUG("REGTEST muon pt is " << fexPt
200 << " GeV and threshold cut is " << threshold / Gaudi::Units::GeV
201 << " GeV and pik_cut is " << (pikCut ? "true" : "false"));
202
203 //Strategy dependent Pt cuts
204 bool sdpCut = true;
205 if (m_strategydependent && usealgo > 0) {
206 if (usealgo >= 1 && usealgo <= 4) {
207 double tmpcut = m_strategyDependentPtCuts.value()[usealgo - 1];
208 if (std::abs(fexPt) <= std::abs(tmpcut)) sdpCut = false;
209 if (tmpcut < 0) stdCut = true; //Do not apply std Pt cut
210 ATH_MSG_DEBUG("REGTEST muon pt is " << fexPt << " GeV"
211 << " and threshold for strategy dependent cut is " << tmpcut
212 << " GeV and strategy dependent / std cuts are " << (sdpCut ? "true" : "false") << " / " << (stdCut ? "true" : "false"));
213 } else {
214 ATH_MSG_DEBUG("usealgo out of range, is: " << usealgo << " while should be in [1, 4]");
215 }
216 }
217
218
219 //d0 cut
220 bool d0Cut = true;
221 if (m_d0min>0. && std::abs(idA0)<m_d0min) d0Cut = false;
222
223 result = stdCut && pikCut && sdpCut && d0Cut;
224
225 if (result) ptFL = -9999.;
226
227 if (m_d0min>0.) {
228 ATH_MSG_DEBUG("REGTEST: Muon passed pt threshold: " << (stdCut ? "true" : "false")
229 << " and pik_cut is " << (pikCut ? "true" : "false")
230 << " and strategy dependent cuts is " << (sdpCut ? "true" : "false")
231 << " and result of d0min cut is "<< (d0Cut ? "true" : "false")
232 << " so hypothesis is " << (result ? "true" : "false"));
233 } else {
234 ATH_MSG_DEBUG("REGTEST: Muon passed pt threshold: " << (stdCut ? "true" : "false")
235 << " and pik_cut is " << (pikCut ? "true" : "false")
236 << " and strategy dependent cuts is " << (sdpCut ? "true" : "false")
237 << " so hypothesis is " << (result ? "true" : "false"));
238 }
239 return result;
240}
241
242// --------------------------------------------------------------------------------
243// --------------------------------------------------------------------------------
244
245// from TrigmuCombHypoAlg
246StatusCode TrigmuCombHypoTool::decide(std::vector<TrigmuCombHypoTool::CombinedMuonInfo>& toolInput) const
247{
248 size_t numTrigger = m_ptBins.size();
249 size_t numMuon = toolInput.size();
250 ATH_MSG_DEBUG("Retrieved from TrigmuCombHypoAlg and Running TrigmuCombHypoTool for selections.");
251
252 if ( numTrigger == 1 ) { // in case of HLT_mu4, HLT_mu6 and so on.
253 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
254 ATH_MSG_DEBUG("Applying selection of single << " << m_decisionId );
255 return inclusiveSelection(toolInput);
256 } else { // in case of HLT_2mu6 and so on.
257 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
258 ATH_MSG_DEBUG("Applying selection of multiplicity << " << m_decisionId );
259
260 if(m_applyOR)
261 ATH_CHECK(applyOverlapRemoval(toolInput));
262
263 return multiplicitySelection(toolInput);
264 }
265
266 return StatusCode::SUCCESS;
267}
268
269
270StatusCode TrigmuCombHypoTool::inclusiveSelection(std::vector<TrigmuCombHypoTool::CombinedMuonInfo>& input) const
271{
272 for ( auto& i: input) {
273 // If muon event has difference DecisionID, it shouldn't apply.
274 if (TrigCompositeUtils::passed(m_decisionId.numeric(), i.previousDecisionIDs)) {
275 if ( decideOnSingleObject(i, 0)==true ) {
276 ATH_MSG_DEBUG("Pass through selection " << m_decisionId );
278 } else {
279 ATH_MSG_DEBUG("Not pass through selection " << m_decisionId );
280 }
281 } else {
282 ATH_MSG_DEBUG("Not match DecisionID:" << m_decisionId );
283 }
284 }
285
286 return StatusCode::SUCCESS;
287}
288
289
290StatusCode TrigmuCombHypoTool::multiplicitySelection(std::vector<TrigmuCombHypoTool::CombinedMuonInfo>& input) const
291{
292 HLT::Index2DVec passingSelection( m_ptBins.size() );
293
294 for ( size_t cutIndex=0; cutIndex < m_ptBins.size(); ++cutIndex ) {
295 size_t elementIndex{ 0 };
296 for ( auto& i: input ) {
297
298 if(!m_acceptAll && m_applyOR && (i.isOR.find(m_decisionId.numeric()) != i.isOR.end())) {
299 ATH_MSG_DEBUG("skip due to overap, DecisionID " << m_decisionId );
300 elementIndex++;
301 continue;
302 }
303
304 // If muon event has difference DecisionID, it shouldn't apply.
305 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs ) ) {
306 if ( decideOnSingleObject( i, cutIndex ) == true ) {
307 ATH_MSG_DEBUG("Pass through selection " << m_decisionId << " : Event[" << elementIndex << "]" );
308 passingSelection[cutIndex].push_back( elementIndex );
309 } else {
310 ATH_MSG_DEBUG("Not pass through selection " << m_decisionId << " : Event[" << elementIndex << "]" );
311 }
312 } else {
313 ATH_MSG_DEBUG("Not match DecisionID " << m_decisionId );
314 }
315 elementIndex++;
316 }
317
318 // If no object passes the selection, multipul selection should stop.
319 if ( passingSelection[cutIndex].empty() ) {
320 ATH_MSG_DEBUG( "No object passed selection " << cutIndex << " rejecting" );
321 return StatusCode::SUCCESS;
322 }
323 }
324
325 std::set<size_t> passingIndices;
326 if ( m_decisionPerCluster==true ) {
327 auto notFromSameRoI = [&]( const HLT::Index1DVec& comb ) {
328 std::set<const xAOD::L2CombinedMuon*> setOfClusters;
329 for ( auto index: comb ) {
330 setOfClusters.insert( input[index].muComb );
331 }
332 return setOfClusters.size() == comb.size();
333 };
334
335 HLT::elementsInUniqueCombinations( passingSelection, passingIndices, std::move(notFromSameRoI) );
336
337 } else {
338 HLT::elementsInUniqueCombinations( passingSelection, passingIndices );
339 }
340
341 if ( passingIndices.empty() ) {
342 ATH_MSG_DEBUG("No muon event passed through selection " << m_decisionId );
343 return StatusCode::SUCCESS;
344 }
345
346 for ( auto idx: passingIndices ) {
347 ATH_MSG_DEBUG("Muon event[" << idx << "] passes through Chain/ID " << m_decisionId
348 << " with pT = " << input[idx].muComb->pt() << "GeV" );
349 TrigCompositeUtils::addDecisionID( m_decisionId.numeric(), input[idx].decision );
350 }
351
352 return StatusCode::SUCCESS;
353}
354
355
356// --------------------------------------------------------------------------------
357// --------------------------------------------------------------------------------
358
359StatusCode TrigmuCombHypoTool::applyOverlapRemoval(std::vector<TrigmuCombHypoTool::CombinedMuonInfo>& toolInput) const {
360
361 ATH_MSG_DEBUG("Running Overlap Removal for muComb");
362
363 std::vector<TrigmuCombHypoTool::CombinedMuonInfo*> input;
364
365 // set pT threshold for events where so many muons
366 // in such events, muons are removed if pT < pTthreshold
367 // pT threshold is set to the pT value of m_numMuonThreshold-th leading muon
368 float pTthreshold = 0;
369 std::vector<float> pTvec;
370 for ( auto& i: toolInput ) {
371 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs) &&
372 i.muComb!=nullptr ){
373 pTvec.emplace_back(i.muComb->pt());
374 }
375 }
376 if(pTvec.size() > m_numMuonThreshold) {
377 std::sort(pTvec.begin(),pTvec.end(), std::greater<float>{});
378 pTthreshold = pTvec.at(m_numMuonThreshold);
379 }
380
381 for ( auto& i: toolInput ) {
382 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs) &&
383 i.muComb!=nullptr ){
384 if(i.muComb->pt() > pTthreshold)
385 input.emplace_back(&i);
386 else // set isOR for removed muons
387 i.isOR.insert(m_decisionId.numeric());
388 }
389 }
390
391 size_t numMuon = input.size();
392
393 auto mucombNrAllEVs = Monitored::Scalar("NrAllEVs", -9999.);
394 auto mucombNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
395 auto monitorIt = Monitored::Group(m_monTool, mucombNrAllEVs, mucombNrActiveEVs);
396 if ( numMuon == 0) {
397 ATH_MSG_DEBUG( "No positive previous hypo decision. Not need overlap removal." );
398 mucombNrActiveEVs = numMuon;
399 mucombNrAllEVs = numMuon;
400 return StatusCode::SUCCESS;
401 }
402 else if ( numMuon == 1 ) {
403 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
404 ATH_MSG_DEBUG("no overlap Removal necessary. exitting with all EventViews active." );
405 mucombNrActiveEVs = numMuon;
406 mucombNrAllEVs = numMuon;
407 return StatusCode::SUCCESS;
408 } else {
409 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
410 mucombNrAllEVs = numMuon;
411 ATH_CHECK(checkOverlap(input));
412 return StatusCode::SUCCESS;
413 }
414
415 return StatusCode::SUCCESS;
416}
417
418// --------------------------------------------------------------------------------
419// --------------------------------------------------------------------------------
420
421StatusCode TrigmuCombHypoTool::checkOverlap(std::vector<TrigmuCombHypoTool::CombinedMuonInfo*>& input) const {
422
423 size_t numMuon = input.size();
424 unsigned int i,j;
425 std::vector<unsigned int> mucombResult;
426
427 bool errorWhenIdentifyingOverlap = false;
428
429 for(i=0; i<numMuon; i++) {mucombResult.emplace_back(i); }
430 for(i=0; i<numMuon-1; i++){
431 for(j=i+1; j<numMuon; j++){
432 ATH_MSG_DEBUG("++ i=" << i << " vs j=" << j);
433 bool overlapped = isOverlap((*input[i]).muComb, (*input[j]).muComb);
434 if( ! overlapped ){ // judged as different
435 ATH_MSG_DEBUG(" judged as: differenr objects");
436 if( mucombResult[i] == mucombResult[j] ) { // but marked as same by someone
437 ATH_MSG_DEBUG( "inconsistentency in muComb overlap removal for more than two objects" );
438 ATH_MSG_DEBUG( "two objects are judged as different but both were already marked as identical by someone else as: " );
439 ATH_MSG_DEBUG( "i/j/result[i]/result[j]=" << i << " / " << j << " / " << mucombResult[i] << " / " << mucombResult[j] );
440 auto mucombError = Monitored::Scalar("MucombError", -9999.);
441 auto monitorIt = Monitored::Group(m_monTool, mucombError);
443 errorWhenIdentifyingOverlap = true;
444 }
445 }
446 else{ // judged as overlap
447 if( (mucombResult[j] != j && mucombResult[i] != mucombResult[j]) || (mucombResult[j] == j && mucombResult[i] != i) ){
448 ATH_MSG_DEBUG( "inconsistentency in muComb based overlap removal for more than two objects" );
449 ATH_MSG_DEBUG( "two objects are judged as overlap but only either was already marked as overlap to someone else: " );
450 ATH_MSG_DEBUG( "i/j/result[i]/result[j]=" << i << " / " << j << " / " << mucombResult[i] << " / " << mucombResult[j] );
451 auto mucombError = Monitored::Scalar("MucombError", -9999.);
452 auto monitorIt = Monitored::Group(m_monTool, mucombError);
454 errorWhenIdentifyingOverlap = true;
455 }
456 ATH_MSG_DEBUG(" judged as: overlapped objects");
457 if( mucombResult[i] == i ) {
458 ATH_MSG_DEBUG( " i is not yet marked as overlap. so, it is a newly found overlap" );
459 ATH_MSG_DEBUG( " -> marking mucombResult[j] as i..." );
460 mucombResult[j] = i;
461 } else {
462 ATH_MSG_DEBUG( " both i/j already marked as overlap by: mucombResult[i]=" << mucombResult[i] );
463 ATH_MSG_DEBUG( " -> do nothing..." );
464 }
465 }
466 }
467 }
468
469 if( errorWhenIdentifyingOverlap ) {
470 ATH_MSG_WARNING( "error when resolving overlap. exitting with all EVs active..." );
471 auto mucombNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
472 auto monitorIt = Monitored::Group(m_monTool, mucombNrActiveEVs);
473 mucombNrActiveEVs = numMuon;
474 // for(i=0; i<numMuon; i++) TrigCompositeUtils::addDecisionID( m_decisionId, toolInput[i].decision );
475 return StatusCode::SUCCESS;
476 }
477
478 unsigned int n_uniqueMuon = 0;
479 for(i=0; i<numMuon; i++) {
480 ATH_MSG_DEBUG( "muComb based results: i=" << i << ": ");
481 if( mucombResult[i] != i ) { ATH_MSG_DEBUG( " overlap to j=" << mucombResult[i] ); }
482 else {
483 n_uniqueMuon++;
484 ATH_MSG_DEBUG( " unique" );
485 }
486 }
487
488 ATH_MSG_DEBUG( "nr of unique Muons after muComb-based removal=" << n_uniqueMuon );
489
490 if( numMuon != n_uniqueMuon ){
491 ATH_CHECK(chooseBestMuon(input, mucombResult));
492 } else {
493 ATH_MSG_DEBUG( "no overlap identified. exitting with all EventViews active" );
494 auto mucombNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
495 auto monitorIt = Monitored::Group(m_monTool, mucombNrActiveEVs);
496 mucombNrActiveEVs = n_uniqueMuon;
497 }
498
499 return StatusCode::SUCCESS;
500}
501
502// --------------------------------------------------------------------------------
503// --------------------------------------------------------------------------------
504
506 const xAOD::L2CombinedMuon *combMf2) const
507{
508
509 auto mucombDR = Monitored::Scalar("DR", -9999.);
510 auto mucombMass = Monitored::Scalar("Mass", -9999.);
511 auto mucombDRLog10 = Monitored::Scalar("DRLog10", -9999.);
512 auto mucombMassLog10 = Monitored::Scalar("MassLog10", -9999.);
513
514 auto monitorIt = Monitored::Group(m_monTool, mucombDR, mucombMass, mucombDRLog10, mucombMassLog10);
515
516
517 ATH_MSG_DEBUG( " ...mF1: pt/eta/phi=" << combMf1->pt()/Gaudi::Units::GeV << " / " << combMf1->eta() << " / " << combMf1->phi() );
518 ATH_MSG_DEBUG( " ...mF2: pt/eta/phi=" << combMf2->pt()/Gaudi::Units::GeV << " / " << combMf2->eta() << " / " << combMf2->phi() );
519
520 // if dR or invMass is necessary but (eta,phi) info is not avaiable
521 // (i.e. eta,phi=0,0; rec failed)
522 const double ZERO_LIMIT_FOR_ETAPHI = 1e-4;
523 if( (fabs(combMf1->eta()) <ZERO_LIMIT_FOR_ETAPHI && fabs(combMf1->phi()) < ZERO_LIMIT_FOR_ETAPHI) ||
524 (fabs(combMf2->eta()) <ZERO_LIMIT_FOR_ETAPHI && fabs(combMf2->phi()) < ZERO_LIMIT_FOR_ETAPHI) ) {
525 ATH_MSG_DEBUG( " ...-> (eta,phi) info not available (rec at (eta,phi)=(0,0))" );
526 if( m_requireDR || m_requireMass ) {
527 ATH_MSG_DEBUG( " ...-> but dR of invMass check is required. cannot judge overlap -> return with false" );
528 return false;
529 }
530 }
531
532 // if charge or invMass is necessary but charge(=pT) info is not avaiable
533 const double ZERO_LIMIT_FOR_PT = 1e-4;
534 if( (fabs(combMf1->pt()) <ZERO_LIMIT_FOR_PT) || (fabs(combMf2->pt()) < ZERO_LIMIT_FOR_PT) ) {
535 ATH_MSG_DEBUG( " ...-> pT info not available (rec at pT=0)" );
537 ATH_MSG_DEBUG( " ...-> but same sign or invMass check is required. cannot judge overlap -> return with false" );
538 return false;
539 }
540 }
541
542 // determine etabin and thresholds
543 double absEta = (fabs(combMf1->pt()) > fabs(combMf2->pt())) ? fabs(combMf1->eta()) : fabs(combMf2->eta());
544 unsigned int iThres = 0;
545 for(unsigned int i=0; i<(m_etaBins.size()-1); i++) {
546 if ( m_etaBins[i] <= absEta && absEta < m_etaBins[i+1] ) iThres = i;
547 }
548 double dRThres = m_requireDR ? m_dRThres[iThres] : 0.;
549 double dRbyMFThres = m_requireMufastDR ? m_mufastDRThres[iThres] : 0.;
550 double massThres = m_requireMass ? m_massThres[iThres] : 0.;
551 ATH_MSG_DEBUG( " ...iThres=" << iThres );
552 if(m_requireDR) ATH_MSG_DEBUG( " ...dR threshold=" << dRThres );
553 if(m_requireMufastDR) ATH_MSG_DEBUG( " ...dR(byMF) threshold=" << dRbyMFThres );
554 if(m_requireMass) ATH_MSG_DEBUG( " ...mass threshold=" << massThres );
555
556 // same sign cut
557 bool sameSign = false;
558 if( m_requireSameSign ) {
559 sameSign = ((combMf1->pt()*combMf2->pt()) > 0) ? true : false;
560 ATH_MSG_DEBUG( " ...-> sameSign=" << sameSign );
561 }
562
563 // dR cut
564 bool dRisClose = false;
565 double dr = dR(combMf1->eta(),combMf1->phi(),combMf2->eta(),combMf2->phi());
566
567 mucombDR = dr;
568 const double monitor_limit = 1e-4;
569 double dr_mon = (dr>=monitor_limit) ? dr : monitor_limit;
570 mucombDRLog10 = log10(dr_mon);
571
572 if( m_requireDR ) {
573 if( dr < dRThres ) dRisClose = true;
574 ATH_MSG_DEBUG( " ...-> dR=" << dr << " : dRisClose=" << dRisClose );
575 }
576
577 // dR(by MF) cut
578 bool dRbyMFisClose = false;
579 if( m_requireMufastDR ) {
580 const xAOD::L2StandAloneMuon* mf1 = combMf1->muSATrack();
581 const xAOD::L2StandAloneMuon* mf2 = combMf2->muSATrack();
582 if( mf1 == 0 || mf2 == 0 ) {
583 ATH_MSG_DEBUG( "mF link from combinedMF broken" );
584 ATH_MSG_DEBUG( " ...-> mF dR is required but mF link broken. cannot judge overlap -> return with false" );
585 return false;
586 }
587 else {
588 // here, we do not check (eta,phi) of mF is not (0,0)
589 // (i.e. we apply muComb based cut even if muFast rec is failed)
590 double dRByMF = dR(mf1->etaMS(),mf1->phiMS(),mf2->etaMS(),mf2->phiMS());
591 if( dRByMF < dRbyMFThres ) dRbyMFisClose = true;
592 ATH_MSG_DEBUG( " ...-> dR(by MF)=" << dRByMF << " : dRbyMFisClose=" << dRbyMFisClose );
593 }
594 }
595
596 // mass cut
597 const double TRACK_MASS = 0; // just assume zero mass
598 bool massIsClose = false;
599 double mass = invMass(TRACK_MASS,combMf1->pt()/Gaudi::Units::GeV,combMf1->eta(),combMf1->phi(),TRACK_MASS,combMf2->pt()/Gaudi::Units::GeV,combMf2->eta(),combMf2->phi());
600
601 mucombMass = mass;
602 double mass_mon = (mass>=monitor_limit) ? mass : monitor_limit;
603 mucombMassLog10 = log10(mass_mon);
604
605 if( m_requireMass ) {
606 if( mass < massThres ) massIsClose = true;
607 ATH_MSG_DEBUG( " ...-> mass=" << mass << " : massIsClose=" << massIsClose );
608 }
609
610 // total judge
611 bool overlap = false;
612 if( ((m_requireSameSign && sameSign) || (! m_requireSameSign)) &&
613 ((m_requireDR && dRisClose) || (! m_requireDR)) &&
614 ((m_requireMufastDR && dRbyMFisClose) || (! m_requireMufastDR)) &&
615 ((m_requireMass && massIsClose) || (! m_requireMass)) ) {
616 overlap = true;
617 }
618
619 ATH_MSG_DEBUG( " ...=> isOverlap=" << overlap );
620
621 return overlap;
622
623}
624
625// --------------------------------------------------------------------------------
626// --------------------------------------------------------------------------------
627
628double TrigmuCombHypoTool::dR(double eta1, double phi1, double eta2, double phi2) const
629{
630 const double deta = eta1 - eta2;
631 const double dphi = CxxUtils::deltaPhi(phi1, phi2);
632 return std::sqrt(deta*deta + dphi*dphi);
633}
634
635// --------------------------------------------------------------------------------
636// --------------------------------------------------------------------------------
637
638double TrigmuCombHypoTool::invMass(double m1, double pt1, double eta1, double phi1,
639 double m2, double pt2, double eta2, double phi2) const
640{
641 const double ZERO_LIMIT = 1e-12;
642
643 double theta1 = 2*atan2((double)exp(-eta1),1.);
644 double theta2 = 2*atan2((double)exp(-eta2),1.);
645
646 double fpt1 = fabs(pt1);
647 double fpt2 = fabs(pt2);
648
649 double px1 = fpt1*cos(phi1);
650 double py1 = fpt1*sin(phi1);
651 double pz1 = fpt1/tan(theta1);
652 double e1 = sqrt(px1*px1+py1*py1+pz1*pz1+m1*m1);
653
654 double px2 = fpt2*cos(phi2);
655 double py2 = fpt2*sin(phi2);
656 double pz2 = fpt2/tan(theta2);
657 double e2 = sqrt(px2*px2+py2*py2+pz2*pz2+m2*m2);
658
659 double pxsum = px1 + px2;
660 double pysum = py1 + py2;
661 double pzsum = pz1 + pz2;
662 double esum = e1 + e2;
663
664 double mass = 0;
665 double mass2 = esum*esum - pxsum*pxsum - pysum*pysum - pzsum*pzsum;
666 if( mass2 > ZERO_LIMIT ) mass = sqrt(mass2);
667
668 return mass;
669}
670
671// --------------------------------------------------------------------------------
672// --------------------------------------------------------------------------------
673
674StatusCode TrigmuCombHypoTool::chooseBestMuon(std::vector<TrigmuCombHypoTool::CombinedMuonInfo*>& input, const std::vector<unsigned int>& mucombResult) const
675{
676 const double ZERO_LIMIT = 1e-4;
677 size_t numMuon = input.size();
678 unsigned int i,j,k;
679
680 auto mucombNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
681 auto mucombNrOverlapped = Monitored::Scalar("NrOverlapped", 0);
682 auto mucombOverlappedEta = Monitored::Scalar("OverlappedEta", -9999.);
683 auto mucombOverlappedPhi = Monitored::Scalar("OverlappedPhi", -9999.);
684 auto mucombOverlappedPt = Monitored::Scalar("OverlappedPt", -9999.);
685
686 auto monitorIt = Monitored::Group(m_monTool, mucombNrActiveEVs, mucombNrOverlapped,
687 mucombOverlappedPt, mucombOverlappedEta, mucombOverlappedPhi);
688
689 ATH_MSG_DEBUG( "--- choose best among overlaps & disable EVs (muComb based) ---" );
690 for(i=0; i<numMuon; i++) {
691 ATH_MSG_DEBUG( "++ i=" << i << ": result=" << mucombResult[i] );
692 if( mucombResult[i] != i ) {
693 ATH_MSG_DEBUG( " overlap to some one. already the best one was chosen. skip." );
694 continue;
695 }
696 std::vector<unsigned int> others;
697 for(j=0; j<numMuon; j++) {
698 if( mucombResult[j] == mucombResult[i] ) others.emplace_back(j);
699 }
700 if( others.size() == 1 ) {
701 ATH_MSG_DEBUG( " unique object. keep it active." );
702 continue;
703 }
704 else {// must choose one best
705 ATH_MSG_DEBUG( " overlapped objects among: " << others );
706 unsigned int best_ev = 0;
707 float maxPtCombMf = 0;
708 float mindRRoadRoI = 999;
709 for(k=0; k<others.size(); k++) {
710 j=others[k];
711
712 float ptCombMf = 0.;
713 const xAOD::L2CombinedMuon* combMf = (*input[j]).muComb;
714 ptCombMf = fabs(combMf->pt()/Gaudi::Units::GeV);
715
716 const xAOD::L2StandAloneMuon* mf = (*input[j]).muComb->muSATrack();
717 const float roadPhiP = atan2(mf->dirPhiMS(),1.);
718 const float roadPhiM = atan2(-1*mf->dirPhiMS(),-1.);
719 const float roadPhi = (std::abs(CxxUtils::deltaPhi(roadPhiP, mf->roiPhi())) < std::abs(CxxUtils::deltaPhi(roadPhiM, mf->roiPhi())))? roadPhiP : roadPhiM;
720 float roadAw = 0;
721 if(std::abs(mf->roiEta()) < 1.05) { // barrel
722 if( std::abs(mf->roadAw(1,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(1,0);
723 else if( std::abs(mf->roadAw(2,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(2,0);
724 else if( std::abs(mf->roadAw(0,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(0,0);
725 }
726 else { // endcap
727 if( std::abs(mf->roadAw(4,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(4,0);
728 else if( std::abs(mf->roadAw(5,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(5,0);
729 else if( std::abs(mf->roadAw(3,0)) > ZERO_LIMIT ) roadAw = mf->roadAw(3,0);
730 }
731 float roadEta = 999;
732 if(std::abs(roadAw) > ZERO_LIMIT)
733 roadEta = -std::log(std::tan(0.5*std::atan(std::abs(roadAw))));
734 if(roadAw < 0) roadEta *= -1.;
735 const double dRRoadRoI = dR(roadEta, roadPhi, mf->roiEta(), mf->roiPhi());
736 ATH_MSG_DEBUG(" j="<< j << " , ptCombMf=" << ptCombMf << ", dRRoadRoI=" << dRRoadRoI);
737
738 if( (ptCombMf > maxPtCombMf) ||
739 (std::abs(ptCombMf - maxPtCombMf) < ZERO_LIMIT &&
740 dRRoadRoI < mindRRoadRoI) ) {
741 maxPtCombMf = ptCombMf;
742 mindRRoadRoI = dRRoadRoI;
743 best_ev = j;
744 }
745 }
746 ATH_MSG_DEBUG( " best is: best_ev/maxPtCombMf=" << best_ev << " / " << maxPtCombMf );
747
748 for(k=0; k<others.size(); k++) {
749 j=others[k];
750 if( j != best_ev ) {
751 ATH_MSG_DEBUG( " EventView( j=" << j << " ) is not active" );
752
753 (*input[j]).isOR.insert(m_decisionId.numeric());
754
755 // monitoring
756 const xAOD::L2CombinedMuon* CombMf = (*input[j]).muComb;
757 ++mucombNrOverlapped;
758 mucombOverlappedPt = CombMf->pt()* CombMf->charge() /Gaudi::Units::GeV;
759 mucombOverlappedEta = CombMf->eta();
760 mucombOverlappedPhi = CombMf->phi();
761 }
762 if( j == best_ev ){
763 ATH_MSG_DEBUG( " EventView( j=" << j << " ) is best one" );
764 }
765 }
766 }
767 }
768 mucombNrActiveEVs = numMuon - mucombNrOverlapped;
769
770 return StatusCode::SUCCESS;
771}
#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)
Header file to be included by clients of the Monitored infrastructure.
const float ZERO_LIMIT
static const Attributes_t empty
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
Gaudi::Property< std::vector< std::vector< double > > > m_ptThresholds
virtual StatusCode decide(std::vector< TrigmuCombHypoTool::CombinedMuonInfo > &toolInput) const
Gaudi::Property< std::vector< float > > m_massThres
StatusCode applyOverlapRemoval(std::vector< TrigmuCombHypoTool::CombinedMuonInfo > &toolInput) const
Gaudi::Property< bool > m_acceptAll
Gaudi::Property< bool > m_strategydependent
Gaudi::Property< bool > m_decisionPerCluster
bool decideOnSingleObject(TrigmuCombHypoTool::CombinedMuonInfo &input, size_t cutIndex) const
Gaudi::Property< bool > m_pikCuts
StatusCode checkOverlap(std::vector< TrigmuCombHypoTool::CombinedMuonInfo * > &input) const
StatusCode multiplicitySelection(std::vector< TrigmuCombHypoTool::CombinedMuonInfo > &input) const
Gaudi::Property< float > m_d0min
bool isOverlap(const xAOD::L2CombinedMuon *mf1, const xAOD::L2CombinedMuon *mf2) const
Gaudi::Property< bool > m_applyOR
Gaudi::Property< bool > m_requireMufastDR
StatusCode inclusiveSelection(std::vector< TrigmuCombHypoTool::CombinedMuonInfo > &input) const
std::vector< size_t > m_bins
double dR(double eta1, double phi1, double eta2, double phi2) const
Gaudi::Property< std::vector< double > > m_strategyDependentPtCuts
Gaudi::Property< std::vector< float > > m_etaBins
Gaudi::Property< bool > m_requireDR
TrigmuCombHypoTool(const std::string &type, const std::string &name, const IInterface *parent)
virtual StatusCode initialize() override
double invMass(double m1, double pt1, double eta1, double phi1, double m2, double pt2, double eta2, double phi2) const
Gaudi::Property< size_t > m_numMuonThreshold
Gaudi::Property< std::vector< float > > m_mufastDRThres
ToolHandle< GenericMonitoringTool > m_monTool
Gaudi::Property< double > m_chi2MaxID
HLT::Identifier m_decisionId
Gaudi::Property< bool > m_requireSameSign
Gaudi::Property< std::vector< float > > m_dRThres
StatusCode chooseBestMuon(std::vector< TrigmuCombHypoTool::CombinedMuonInfo * > &input, const std::vector< unsigned int > &mucombResult) const
Gaudi::Property< bool > m_requireMass
Gaudi::Property< double > m_maxPtToApplyPik
Gaudi::Property< std::vector< std::vector< double > > > m_ptBins
Main LVL2 Algorithm.
Definition muComb.h:54
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
float charge() const
get seeding muon charge
virtual double pt() const
The transverse momentum ( ) of the particle.
const xAOD::L2StandAloneMuon * muSATrack() const
Get the SA muon as a bare pointer.
float etaMS() const
Get the eta at muon spectrometer.
float phiMS() const
Get the phi at muon spectrometer.
T deltaPhi(T phiA, T phiB)
Return difference phiA - phiB in range [-pi, pi].
Definition phihelper.h:42
It used to be useful piece of code for replacing actual SG with other store of similar functionality ...
void elementsInUniqueCombinations(const Index2DVec &indices, std::set< size_t > &participants, const std::function< bool(const Index1DVec &)> &filter)
std::vector< Index1DVec > Index2DVec
std::vector< size_t > Index1DVec
Unique combinations for case when one can not repeat the index (i.e.
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
L2CombinedMuon_v1 L2CombinedMuon
Define the latest version of the muon CB class.
L2StandAloneMuon_v2 L2StandAloneMuon
Define the latest version of the muon SA class.
Helper for azimuthal angle calculations.