ATLAS Offline Software
Loading...
Searching...
No Matches
TrigMufastHypoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "GaudiKernel/SystemOfUnits.h"
10
12
13#include <cmath>
14
15using namespace TrigCompositeUtils;
16// --------------------------------------------------------------------------------
17// --------------------------------------------------------------------------------
18
20 const std::string & name,
21 const IInterface* parent )
22 : AthAlgTool( type, name, parent ),
23 m_decisionId( HLT::Identifier::fromToolName( name ) )
24{
25}
26
29
30// --------------------------------------------------------------------------------
31// --------------------------------------------------------------------------------
32
34{
35 ATH_MSG_DEBUG("Initializing " << name());
36
37 if(m_acceptAll) {
38 ATH_MSG_DEBUG("AcceptAll = True");
39 ATH_MSG_DEBUG("Accepting all the events!");
40 }
41 else if(m_doCalib){
42 ATH_MSG_DEBUG("This is a muon calibration chain.");
43 }
44 else {
45 ATH_MSG_DEBUG("AcceptAll = False");
46 m_bins.resize (m_ptBins.size());
47 for ( size_t j=0; j<m_ptBins.size(); ++j) {
48 m_bins[j] = m_ptBins[j].size() - 1;
49 if (m_bins[j] != m_ptThresholds[j].size()) {
50 ATH_MSG_DEBUG("bad thresholds setup .... exiting!");
51 return StatusCode::SUCCESS;
52 }
53
54 for (std::vector<float>::size_type i=0; i<m_bins[j];++i) {
55 char buf1[256];
56 char buf2[256];
57 sprintf(buf1,"%f5.2",m_ptBins[j][i]);
58 sprintf(buf2,"%f5.2",m_ptBins[j][i+1]);
59 ATH_MSG_DEBUG("EtaBin[" << j << "] " << buf1 << " - " << buf2
60 << ": with Pt Threshold of " << (m_ptThresholds[j][i])/Gaudi::Units::GeV
61 << " GeV");
62 }
63
64 ATH_MSG_DEBUG("Endcap WeakBField A[" << j << "]: pT threshold of " << m_ptThresholdForECWeakBRegionA[j] / Gaudi::Units::GeV << " GeV");
65 ATH_MSG_DEBUG("Endcap WeakBField B[" << j << "]: pT threshold of " << m_ptThresholdForECWeakBRegionB[j] / Gaudi::Units::GeV << " GeV");
66 }
67 }
68
69 ATH_MSG_DEBUG( "Tool configured for chain/id: " << m_decisionId );
70
71 if ( not m_monTool.name().empty() ) {
72 ATH_CHECK( m_monTool.retrieve() );
73 ATH_MSG_DEBUG("MonTool name: " << m_monTool);
74 }
75
76
77 // Overlap Removal
78 if( m_applyOR ) {
79 ATH_MSG_DEBUG( "--- overlap removal as: ---" );
80 if( m_requireDR ) {
81 ATH_MSG_DEBUG( "+ dR cut:" );
82 if( (m_etaBinsEC.size()-1) != m_dRThresEC.size() ) {
83 ATH_MSG_ERROR( "bad thresholds setup .... exiting!" );
84 return StatusCode::FAILURE;
85 }
86 ATH_MSG_DEBUG( " B-B : dR < " << m_dRThresBB );
87 ATH_MSG_DEBUG( " B-E : dR < " << m_dRThresBE );
88 ATH_MSG_DEBUG( " E-E : " );
89 for(unsigned int i=0; i<m_dRThresEC.size(); i++) {
90 ATH_MSG_DEBUG( " EtaBin " << m_etaBinsEC[i] << " - " << m_etaBinsEC[i+1]
91 << " : dR < " << m_dRThresEC[i] );
92 }
93 }
94 if( m_requireMass ) {
95 ATH_MSG_DEBUG( "+ Mass cut:" );
96 if( (m_etaBinsEC.size()-1) != m_massThresEC.size() ) {
97 ATH_MSG_ERROR( "bad thresholds setup .... exiting!" );
98 return StatusCode::FAILURE;
99 }
100 ATH_MSG_DEBUG( " B-B : Mass < " << m_massThresBB );
101 ATH_MSG_DEBUG( " B-E : Mass < " << m_massThresBE );
102 ATH_MSG_DEBUG( " E-E : " );
103 for(unsigned int i=0; i<m_massThresEC.size(); i++) {
104 ATH_MSG_DEBUG( " EtaBin " << m_etaBinsEC[i] << " - " << m_etaBinsEC[i+1]
105 << " : Mass < " << m_massThresEC[i] );
106 }
107 }
108 if( m_requireSameSign ) ATH_MSG_DEBUG( "+ Same charge sign" );
109 }
110
111
112 ATH_MSG_DEBUG("Initialization completed successfully");
113
114 return StatusCode::SUCCESS;
115}
116
117// --------------------------------------------------------------------------------
118// --------------------------------------------------------------------------------
119
121{
122
123 auto fexPt = Monitored::Scalar("Pt", -9999.);
124 auto fexEta = Monitored::Scalar("Eta", -9999.);
125 auto fexPhi = Monitored::Scalar("Phi", -9999.);
126 auto fexPtFL = Monitored::Scalar("PtFL", -9999.);
127 auto xatStation = Monitored::Scalar("XatSt", -9999.);
128 auto yatStation = Monitored::Scalar("YatSt", -9999.);
129 auto zatStation = Monitored::Scalar("ZatSt", -9999.);
130 auto xatBeam = Monitored::Scalar("XatBe", -9999.);
131 auto zatBeam = Monitored::Scalar("ZatBe", -9999.);
132
133 auto monitorIt = Monitored::Group(m_monTool, fexPt, fexEta, fexPhi, fexPtFL,
134 xatStation, yatStation, zatStation,
135 xatBeam, zatBeam);
136
137 ATH_MSG_VERBOSE( "Cut index " << cutIndex );
138
139 auto roiDescriptor = input.roi;
140 ATH_MSG_DEBUG("RoI ID = " << roiDescriptor->roiId()
141 << ", Eta = " << roiDescriptor->eta()
142 << ", Phi = " << roiDescriptor->phi());
143
144 bool result = false;
145 // if accept All flag is on, just pass it
146 if(m_acceptAll) {
147 result = true;
148 ATH_MSG_DEBUG("Accept property is set: taking all the events");
149 return result;
150 } else {
151 result = false;
152 ATH_MSG_DEBUG("Accept property not set: applying selection!");
153 }
154
155 // Get xAOD::L2StandAloneMuon:
156 auto pMuon = input.muFast;
157
158 if(!pMuon){
159 result = false;
160 ATH_MSG_ERROR("Retrieval of L2StandAloneMuon from vector failed");
161 return result;
162 }
163
164 // fill Monitoring histos
165 fexPt = (pMuon->pt())? pMuon->pt() : -9999.;
166 fexEta = (pMuon->etaMS())? pMuon->etaMS() : -9999.;
167 fexPhi = (pMuon->etaMS())? pMuon->phiMS() : -9999.;
168 fexPtFL = (pMuon->pt())? pMuon->pt() : -9999.;
169
170 if( pMuon->etaMS() ) {
171 float localPhi = getLocalPhi(pMuon->etaMS(),pMuon->phiMS(),pMuon->rMS());
172 float radius = pMuon->rMS()/cos(fabs(localPhi));
173 float DirZ = (pMuon->dirZMS())? pMuon->dirZMS() : .000001;
174 float DirF = (pMuon->dirPhiMS())? pMuon->dirPhiMS() : .000001;
175 xatStation = radius * cos(pMuon->phiMS());
176 yatStation = radius * sin(pMuon->phiMS());
177 zatStation = pMuon->zMS();
178 float xb = xatStation - yatStation/DirF;
179 float de = xatStation - xb;
180 float ds = sqrt(yatStation*yatStation+de*de);
181 xatBeam = xb;
182 zatBeam = zatStation - ds*DirZ;
183 } else {
184 xatStation = -9999.;
185 yatStation = -9999.;
186 zatStation = -9999.;
187 xatBeam = -9999.;
188 zatBeam = -9999.;
189 }
190
191 if(m_doCalib && !m_acceptAll){
192 result = false;
193 ATH_MSG_DEBUG("This muoncalib chain is only monitored.");
194 return result;
195 }
196
197 //Get the Pt cut for that eta bin
198 double threshold = 0;
199 float absEta = fabs(fexEta);
200 for (std::vector<float>::size_type i=0; i<m_bins[0]; ++i)
201 if ( absEta > m_ptBins[cutIndex][i] && absEta < m_ptBins[cutIndex][i+1] ) threshold = m_ptThresholds[cutIndex][i];
202
203 // if in the weak Bfield regions at endcap, set special threshold
204
207 ATH_MSG_DEBUG("threshold is set for EC WeakBField A");
209 }
210
212 ATH_MSG_DEBUG("threshold is set for EC WeakBField B");
214 }
215
216 ATH_MSG_DEBUG("threshold value is set as: " << threshold/Gaudi::Units::GeV << " GeV");
217
218 // Check pt threshold for hypothesis,
219 // convert units since Muonfeature is in GeV
220 if ( std::abs(pMuon->pt()) > (threshold/Gaudi::Units::GeV)){
221 // selects only tracks coming from a region around PV
222 if( m_selectPV ){
223 if((fabs(xatBeam)<m_RPV) && (fabs(zatBeam)<m_ZPV))
224 result = true;
225 } else {
226 result = true;
227 }
228 }
229
230 if ( result ) fexPtFL = -9999.;
231
232 ATH_MSG_DEBUG("REGTEST: Muon pt is " << pMuon->pt() << " GeV"
233 << " and threshold cut is " << threshold/Gaudi::Units::GeV << " GeV"
234 << " so hypothesis is " << (result?"true":"false"));
235
236 return result;
237}
238
239// --------------------------------------------------------------------------------
240// --------------------------------------------------------------------------------
241
242float TrigMufastHypoTool::getLocalPhi(float eta, float phi, float rad) const
243{
244 if(phi<0.) phi += 2*3.14159265;
245 float step = 0.78539816;
246 float offs = 0.39269908;
247 if(fabs(eta) <= 1.1)
248 {
249 float Dphi = 999999.;
250 float sign = 0.;
251 const float ZEROLIMIT = 1e-6;
252 if(rad < 800.)
253 {
254 for(int i=0;i<8;++i) if(fabs(i*step-phi)<=Dphi)
255 {
256 Dphi=fabs(i*step-phi);
257 sign = (fabs(Dphi) > ZEROLIMIT) ? (i*step-phi)/fabs(i*step-phi) : 0;
258 }
259 return sign*Dphi;
260 }else
261 {
262 for(int i=1;i<8;++i) if(fabs(i*step+offs-phi)<=Dphi)
263 {
264 Dphi=fabs(i*step+offs-phi);
265 sign = (fabs(Dphi) > ZEROLIMIT) ? (i*step+offs-phi)/fabs(i*step+offs-phi) : 0;
266 }
267 return sign*Dphi;
268 }
269 }else
270 {
271 return 0.;
272 }
273}
274
275// --------------------------------------------------------------------------------
276// --------------------------------------------------------------------------------
277
278StatusCode TrigMufastHypoTool::decide(std::vector<MuonClusterInfo>& toolInput) const {
279
280 size_t numTrigger = m_ptBins.size();
281 size_t numMuon = toolInput.size();
282 ATH_MSG_DEBUG("Retrieved from TrigMufastHypoAlg and Running TrigMufastHypoTool for selections.");
283
284 if ( numTrigger == 1 ) { // in case of HLT_mu4, HLT_mu6 and so on.
285 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
286 ATH_MSG_DEBUG("Applying selection of single << " << m_decisionId );
287 return inclusiveSelection(toolInput);
288 } else { // in case of HLT_2mu6 and so on.
289 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
290 ATH_MSG_DEBUG("Applying selection of multiplicity << " << m_decisionId );
291
292 if(m_applyOR)
293 ATH_CHECK(applyOverlapRemoval(toolInput));
294
295 return multiplicitySelection(toolInput);
296 }
297
298 return StatusCode::SUCCESS;
299}
300
301
302StatusCode TrigMufastHypoTool::inclusiveSelection(std::vector<TrigMufastHypoTool::MuonClusterInfo>& toolInput) const{
303
304 for ( auto& i: toolInput ) {
305 // If muon event has difference DecisionID, it shouldn't apply.
306 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs ) ) {
307 if ( decideOnSingleObject( i, 0 )==true ) {
308 ATH_MSG_DEBUG("Pass through selection " << m_decisionId );
310 } else {
311 ATH_MSG_DEBUG("Not pass through selection " << m_decisionId );
312 }
313 } else {
314 ATH_MSG_DEBUG("Not match DecisionID:" << m_decisionId );
315 }
316 }
317
318 return StatusCode::SUCCESS;
319}
320
321
322StatusCode TrigMufastHypoTool::multiplicitySelection(std::vector<TrigMufastHypoTool::MuonClusterInfo>& toolInput) const{
323
324 HLT::Index2DVec passingSelection( m_ptBins.size() );
325
326 for ( size_t cutIndex=0; cutIndex < m_ptBins.size(); ++cutIndex ) {
327 size_t elementIndex{ 0 };
328 for ( auto& i: toolInput ) {
329
330 if(!m_acceptAll && m_applyOR && (i.isOR.find(m_decisionId.numeric()) != i.isOR.end())) {
331 ATH_MSG_DEBUG("skip due to overap, DecisionID " << m_decisionId );
332 elementIndex++;
333 continue;
334 }
335
336 // If muon event has difference DecisionID, it shouldn't apply.
337 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs ) ) {
338 if ( decideOnSingleObject( i, cutIndex ) == true ) {
339 ATH_MSG_DEBUG("Pass through selection " << m_decisionId << " : Event[" << elementIndex << "]" );
340 passingSelection[cutIndex].push_back( elementIndex );
341 } else {
342 ATH_MSG_DEBUG("Not pass through selection " << m_decisionId << " : Event[" << elementIndex << "]" );
343 }
344 } else {
345 ATH_MSG_DEBUG("Not match DecisionID " << m_decisionId );
346 }
347 elementIndex++;
348 }
349
350 // If no object passes the selection, multipul selection should stop.
351 if ( passingSelection[cutIndex].empty() ) {
352 ATH_MSG_DEBUG( "No object passed selection " << cutIndex << " rejecting" );
353 return StatusCode::SUCCESS;
354 }
355 }
356
357 std::set<size_t> passingIndices;
358 if ( m_decisionPerCluster==true ) {
359 auto notFromSameRoI = [&]( const HLT::Index1DVec& comb ) {
360 std::set<const xAOD::L2StandAloneMuon*> setOfClusters;
361 for ( auto index: comb ) {
362 setOfClusters.insert( toolInput[index].muFast );
363 }
364 return setOfClusters.size() == comb.size();
365 };
366
367 HLT::elementsInUniqueCombinations( passingSelection, passingIndices, std::move(notFromSameRoI) );
368
369 } else {
370 HLT::elementsInUniqueCombinations( passingSelection, passingIndices );
371 }
372
373 if ( passingIndices.empty() ) {
374 ATH_MSG_DEBUG("No muon event passed through selection " << m_decisionId );
375 return StatusCode::SUCCESS;
376 }
377
378 for ( auto idx: passingIndices ) {
379 ATH_MSG_DEBUG("Muon event[" << idx << "] passes through Chain/ID " << m_decisionId
380 << " with pT = " << toolInput[idx].muFast->pt() << "GeV" );
381 TrigCompositeUtils::addDecisionID( m_decisionId.numeric(), toolInput[idx].decision );
382 }
383
384 return StatusCode::SUCCESS;
385}
386
387// --------------------------------------------------------------------------------
388// --------------------------------------------------------------------------------
389
390StatusCode TrigMufastHypoTool::applyOverlapRemoval(std::vector<TrigMufastHypoTool::MuonClusterInfo>& toolInput) const{
391
392 ATH_MSG_DEBUG("Running Overlap Removal for muFast");
393
394 std::vector<TrigMufastHypoTool::MuonClusterInfo*> input;
395
396 for ( auto& i: toolInput ) {
397 // If muon event has difference DecisionID, it shouldn't apply.
398 if ( TrigCompositeUtils::passed( m_decisionId.numeric(), i.previousDecisionIDs ) ) {
399 input.emplace_back(&i);
400 }
401 }
402
403 size_t numMuon = input.size();
404
405 auto mufastNrAllEVs = Monitored::Scalar("NrAllEVs", -9999.);
406 auto mufastNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
407 auto monitorIt = Monitored::Group(m_monTool, mufastNrAllEVs, mufastNrActiveEVs);
408 if ( numMuon == 0) {
409 ATH_MSG_DEBUG( "No positive previous hypo decision. Not need overlap removal." );
410 mufastNrActiveEVs = numMuon;
411 mufastNrAllEVs = numMuon;
412 return StatusCode::SUCCESS;
413 }
414 else if ( numMuon == 1 ) {
415 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
416 ATH_MSG_DEBUG("no overlap Removal necessary. exitting with all EventViews active." );
417 mufastNrActiveEVs = numMuon;
418 mufastNrAllEVs = numMuon;
419 return StatusCode::SUCCESS;
420 } else {
421 ATH_MSG_DEBUG("Number of muon event = " << numMuon );
422 mufastNrAllEVs = numMuon;
423 ATH_CHECK(checkOverlap(input));
424 return StatusCode::SUCCESS;
425 }
426
427
428 return StatusCode::SUCCESS;
429}
430
431// --------------------------------------------------------------------------------
432// --------------------------------------------------------------------------------
433
434StatusCode TrigMufastHypoTool::checkOverlap(std::vector<TrigMufastHypoTool::MuonClusterInfo*>& input) const {
435
436 size_t numMuon = input.size();
437 unsigned int i,j;
438 std::vector<unsigned int> mufastResult;
439
440 bool errorWhenIdentifyingOverlap = false;
441
442 for(i=0; i<numMuon; i++) {mufastResult.emplace_back(i); }
443 for(i=0; i<numMuon-1; i++){
444 for(j=i+1; j<numMuon; j++){
445 ATH_MSG_DEBUG("++ i=" << i << " vs j=" << j);
446 bool overlapped = isOverlap((*input[i]).muFast, (*input[j]).muFast);
447 if( ! overlapped ){ // judged as different
448 ATH_MSG_DEBUG(" judged as: different objects");
449 if( mufastResult[i] == mufastResult[j] ) { // but marked as same by someone
450 ATH_MSG_DEBUG( "inconsistentency in muFast overlap removal for more than two objects" );
451 ATH_MSG_DEBUG( "two objects are judged as different but both were already marked as identical by someone else as: " );
452 ATH_MSG_DEBUG( "i/j/result[i]/result[j]=" << i << " / " << j << " / " << mufastResult[i] << " / " << mufastResult[j] );
453 auto mufastError = Monitored::Scalar("MufastError", -9999.);
454 auto monitorIt = Monitored::Group(m_monTool, mufastError);
456 errorWhenIdentifyingOverlap = true;
457 }
458 }
459 else{ // judged as overlap
460 if( (mufastResult[j] != j && mufastResult[i] != mufastResult[j]) || (mufastResult[j] == j && mufastResult[i] != i) ){
461 ATH_MSG_DEBUG( "inconsistentency in muFast overlap removal for more than two objects" );
462 ATH_MSG_DEBUG( "two objects are judged as overlap but only either was already marked as overlap to someone else: " );
463 ATH_MSG_DEBUG( "i/j/result[i]/result[j]=" << i << " / " << j << " / " << mufastResult[i] << " / " << mufastResult[j] );
464 auto mufastError = Monitored::Scalar("MufastError", -9999.);
465 auto monitorIt = Monitored::Group(m_monTool, mufastError);
467 errorWhenIdentifyingOverlap = true;
468 }
469 ATH_MSG_DEBUG(" judged as: overlapped objects");
470 if( mufastResult[i] == i ) {
471 ATH_MSG_DEBUG( " i is not yet marked as overlap. so, it is a newly found overlap" );
472 ATH_MSG_DEBUG( " -> marking mufastResult[j] as i..." );
473 mufastResult[j] = i;
474 } else {
475 ATH_MSG_DEBUG( " both i/j already marked as overlap by: mufastResult[i]=" << mufastResult[i] );
476 ATH_MSG_DEBUG( " -> do nothing..." );
477 }
478 }
479 }
480 }
481
482 if( errorWhenIdentifyingOverlap ) {
483 ATH_MSG_WARNING( "error when resolving overlap. exitting with all EVs active..." );
484 auto mufastNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
485 auto monitorIt = Monitored::Group(m_monTool, mufastNrActiveEVs);
486 mufastNrActiveEVs = numMuon;
487 // for(i=0; i<numMuon; i++) TrigCompositeUtils::addDecisionID( m_decisionId, toolInput[i].decision );
488 return StatusCode::SUCCESS;
489 }
490
491 unsigned int n_uniqueMuon = 0;
492 for(i=0; i<numMuon; i++) {
493 ATH_MSG_DEBUG( "muFast results: i=" << i << ": ");
494 if( mufastResult[i] != i ) { ATH_MSG_DEBUG( " overlap to j=" << mufastResult[i] ); }
495 else {
496 n_uniqueMuon++;
497 ATH_MSG_DEBUG( " unique" );
498 }
499 }
500
501 ATH_MSG_DEBUG( "nr of unique Muons after muFast overlap removal=" << n_uniqueMuon );
502
503 if( numMuon != n_uniqueMuon ){
504 ATH_CHECK(chooseBestMuon(input, mufastResult));
505 } else {
506 ATH_MSG_DEBUG( "no overlap identified. exitting with all EventViews active" );
507 auto mufastNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
508 auto monitorIt = Monitored::Group(m_monTool, mufastNrActiveEVs);
509 mufastNrActiveEVs = n_uniqueMuon;
510 }
511
512 return StatusCode::SUCCESS;
513}
514
515// --------------------------------------------------------------------------------
516// --------------------------------------------------------------------------------
517
519 const xAOD::L2StandAloneMuon *mf2) const
520{
521
522 auto mufastDR = Monitored::Scalar("DR", -9999.);
523 auto mufastMass = Monitored::Scalar("Mass", -9999.);
524 auto mufastDRLog10 = Monitored::Scalar("DRLog10", -9999.);
525 auto mufastMassLog10 = Monitored::Scalar("MassLog10", -9999.);
526
527 auto monitorIt = Monitored::Group(m_monTool, mufastDR, mufastMass, mufastDRLog10, mufastMassLog10);
528
529 ATH_MSG_DEBUG( " ...mF1: pt/eta/phi=" << mf1->pt() << " / " << mf1->etaMS() << " / " << mf1->phiMS() );
530 ATH_MSG_DEBUG( " ...mF2: pt/eta/phi=" << mf2->pt() << " / " << mf2->etaMS() << " / " << mf2->phiMS() );
531
532 // if dR or invMass is necessary but (eta,phi) info is not avaiable
533 // (i.e. eta,phi=0,0; rec failed)
534 const double ZERO_LIMIT_FOR_ETAPHI = 1e-4;
535 if( (fabs(mf1->etaMS()) <ZERO_LIMIT_FOR_ETAPHI && fabs(mf1->phiMS()) < ZERO_LIMIT_FOR_ETAPHI) ||
536 (fabs(mf2->etaMS()) <ZERO_LIMIT_FOR_ETAPHI && fabs(mf2->phiMS()) < ZERO_LIMIT_FOR_ETAPHI) ) {
537 ATH_MSG_DEBUG( " ...-> (eta,phi) info not available (rec at (eta,phi)=(0,0))" );
538 ATH_MSG_DEBUG( " ...-> but dR of invMass check is required. cannot judge overlap -> return with false" );
539 return false;
540 }
541
542 // if charge or invMass is necessary but charge(=pT) info is not avaiable
543 const double ZERO_LIMIT_FOR_PT = 1e-4;
544 if( (fabs(mf1->pt()) <ZERO_LIMIT_FOR_PT) || (fabs(mf2->pt()) < ZERO_LIMIT_FOR_PT) ) {
545 ATH_MSG_DEBUG( " ...-> pT info not available (rec at pT=0)" );
546 ATH_MSG_DEBUG( " ...-> but same sign or invMass check is required. cannot judge overlap -> return with false" );
547 return false;
548 }
549
550
551 // determine dR, mass threshold separately for: BB, BE, EE
552 double dRThres = 9999;
553 double massThres = 9999;
554
555 const int SADDRESS_EC = -1;
556 bool isBarrel1 = (mf1->sAddress() != SADDRESS_EC ) ? true : false;
557 bool isBarrel2 = (mf2->sAddress() != SADDRESS_EC ) ? true : false;
558
559 if( isBarrel1 && isBarrel2 ) { // BB
560 ATH_MSG_DEBUG( " ...B-B" );
561 dRThres =m_dRThresBB;
562 massThres=m_massThresBB;
563 }
564 else if( (isBarrel1 && ! isBarrel2) || (!isBarrel1 && isBarrel2) ) { // BE
565 ATH_MSG_DEBUG( " ...B-E" );
566 dRThres =m_dRThresBE;
567 massThres=m_massThresBE;
568 }
569 else { // EE
570 ATH_MSG_DEBUG( " ...E-E" );
571 double absEta = (fabs(mf1->pt()) > fabs(mf2->pt())) ? fabs(mf1->etaMS()) : fabs(mf2->etaMS());
572 unsigned int iThres=0;
573 for(unsigned int i=0; i<(m_etaBinsEC.size()-1); i++) {
574 if ( m_etaBinsEC[i] <= absEta && absEta < m_etaBinsEC[i+1] ) iThres = i;
575 }
576 ATH_MSG_DEBUG( " ...iThres=" << iThres );
577 dRThres = m_dRThresEC[iThres];
578 massThres = m_massThresEC[iThres];
579 }
580 ATH_MSG_DEBUG( " ...dR threshold=" << dRThres );
581 ATH_MSG_DEBUG( " ...mass threshold=" << massThres );
582
583
584 // same sign cut
585 bool sameSign = false;
586 if( m_requireSameSign ) {
587 sameSign = ((mf1->pt()*mf2->pt()) > 0) ? true : false;
588 ATH_MSG_DEBUG( " ...-> sameSign=" << sameSign );
589 }
590
591 // dR cut
592 bool dRisClose = false;
593 double dr = dR(mf1->etaMS(),mf1->phiMS(),mf2->etaMS(),mf2->phiMS());
594
595 // for monitoring
596 mufastDR = dr;
597 const double monitor_limit = 1e-4;
598 double dr_mon = (dr>=monitor_limit) ? dr : monitor_limit;
599 mufastDRLog10 = log10(dr_mon);
600
601 if( m_requireDR ) {
602 if( dr < dRThres ) dRisClose = true;
603 ATH_MSG_DEBUG( " ...-> dR=" << dr << " : dRisClose=" << dRisClose );
604 }
605
606 // mass cut
607 const double TRACK_MASS = 0; // just assume zero mass
608 bool massIsClose = false;
609 double mass = invMass(TRACK_MASS,mf1->pt(),mf1->etaMS(),mf1->phiMS(),TRACK_MASS,mf2->pt(),mf2->etaMS(),mf2->phiMS());
610
611 // for monitoring
612 mufastMass = mass;
613 double mass_mon = (mass>=monitor_limit) ? mass : monitor_limit;
614 mufastMassLog10 = log10(mass_mon);
615
616 if( m_requireMass ) {
617 if( mass < massThres ) massIsClose = true;
618 ATH_MSG_DEBUG( " ...-> mass=" << mass << " : massIsClose=" << massIsClose );
619 }
620
621 // total judge
622 bool overlap = false;
623 if( ((m_requireSameSign && sameSign) || (! m_requireSameSign)) &&
624 ((m_requireDR && dRisClose) || (! m_requireDR)) &&
625 ((m_requireMass && massIsClose) || (! m_requireMass)) ) {
626 overlap = true;
627 }
628
629 ATH_MSG_DEBUG( " ...=> isOverlap=" << overlap );
630
631 return overlap;
632
633}
634
635// --------------------------------------------------------------------------------
636// --------------------------------------------------------------------------------
637
638double TrigMufastHypoTool::dR(double eta1, double phi1, double eta2, double phi2) const
639{
640 const double deta = eta1 - eta2;
641 const double dphi = CxxUtils::deltaPhi(phi1, phi2);
642 return std::sqrt(deta*deta + dphi*dphi);
643}
644
645// --------------------------------------------------------------------------------
646// --------------------------------------------------------------------------------
647
648double TrigMufastHypoTool::invMass(double m1, double pt1, double eta1, double phi1,
649 double m2, double pt2, double eta2, double phi2) const
650{
651 const double ZERO_LIMIT = 1e-12;
652
653 double theta1 = 2*atan2((double)exp(-eta1),1.);
654 double theta2 = 2*atan2((double)exp(-eta2),1.);
655
656 double fpt1 = fabs(pt1);
657 double fpt2 = fabs(pt2);
658
659 double px1 = fpt1*cos(phi1);
660 double py1 = fpt1*sin(phi1);
661 double pz1 = fpt1/tan(theta1);
662 double e1 = sqrt(px1*px1+py1*py1+pz1*pz1+m1*m1);
663
664 double px2 = fpt2*cos(phi2);
665 double py2 = fpt2*sin(phi2);
666 double pz2 = fpt2/tan(theta2);
667 double e2 = sqrt(px2*px2+py2*py2+pz2*pz2+m2*m2);
668
669 double pxsum = px1 + px2;
670 double pysum = py1 + py2;
671 double pzsum = pz1 + pz2;
672 double esum = e1 + e2;
673
674 double mass = 0;
675 double mass2 = esum*esum - pxsum*pxsum - pysum*pysum - pzsum*pzsum;
676 if( mass2 > ZERO_LIMIT ) mass = sqrt(mass2);
677
678 return mass;
679}
680
681// --------------------------------------------------------------------------------
682// --------------------------------------------------------------------------------
683
684StatusCode TrigMufastHypoTool::chooseBestMuon(std::vector<TrigMufastHypoTool::MuonClusterInfo*>& input, const std::vector<unsigned int>& mufastResult) const
685{
686 size_t numMuon = input.size();
687 unsigned int i,j,k;
688
689 auto mufastNrActiveEVs = Monitored::Scalar("NrActiveEVs", -9999.);
690 auto mufastNrOverlapped = Monitored::Scalar("NrOverlapped", 0);
691 auto mufastOverlappedEta = Monitored::Scalar("OverlappedEta", -9999.);
692 auto mufastOverlappedPhi = Monitored::Scalar("OverlappedPhi", -9999.);
693 auto mufastOverlappedPt = Monitored::Scalar("OverlappedPt", -9999.);
694
695 auto monitorIt = Monitored::Group(m_monTool, mufastNrActiveEVs, mufastNrOverlapped,
696 mufastOverlappedPt, mufastOverlappedEta, mufastOverlappedPhi);
697
698 ATH_MSG_DEBUG( "--- choose best among overlaps & disable EVs (muFast based) ---" );
699 for(i=0; i<numMuon; i++) {
700 ATH_MSG_DEBUG( "++ i=" << i << ": result=" << mufastResult[i] );
701 if( mufastResult[i] != i ) {
702 ATH_MSG_DEBUG( " overlap to some one. already the best one was chosen. skip." );
703 continue;
704 }
705 std::vector<unsigned int> others;
706 for(j=0; j<numMuon; j++) {
707 if( mufastResult[j] == mufastResult[i] ) others.emplace_back(j);
708 }
709 if( others.size() == 1 ) {
710 ATH_MSG_DEBUG( " unique object. keep it active." );
711 continue;
712 }
713 else {
714 // must choose one best
715 ATH_MSG_DEBUG( " overlapped objects among: " << others );
716 unsigned int best_ev = 0;
717 float maxPtMf = 0;
718 float maxPtRoI = 0;
719 for(k=0; k<others.size(); k++) {
720 j=others[k];
721 // const LVL1::RecMuonRoI* muonRoI = input[j].RecRoI;
722 // float ptRoI = muonRoI->getThresholdValue();
723 const xAOD::L2StandAloneMuon* mf = (*input[j]).muFast;
724 float ptMf = fabs(mf->pt());
725 float ptRoI = mf->roiThreshold();
726 ATH_MSG_DEBUG(" ev/PtRoI/ptMf="<< j << "/" << ptRoI << "/" << ptMf);
727 if( (ptRoI-maxPtRoI) > 0.1 ) {
728 maxPtRoI = ptRoI;
729 maxPtMf = ptMf;
730 best_ev = j;
731 }
732 else if( fabs(ptRoI-maxPtRoI) < 0.1 ) {
733 if( ptMf > maxPtMf ) {
734 maxPtRoI = ptRoI;
735 maxPtMf = ptMf;
736 best_ev = j;
737 }
738 }
739 }
740 ATH_MSG_DEBUG( " best is: best_ev/maxPtRoI/maxPtMf=" << best_ev << " / " << maxPtRoI << " / " << maxPtMf );
741
742 for(k=0; k<others.size(); k++) {
743 j=others[k];
744 if( j != best_ev ) {
745 ATH_MSG_DEBUG( " EventView( j=" << j << " ) is not active" );
746
747 (*input[j]).isOR.insert(m_decisionId.numeric());
748
749 // monitoring
750 const xAOD::L2StandAloneMuon* mf = (*input[j]).muFast;
751 ++mufastNrOverlapped;
752 mufastOverlappedPt = mf->pt();
753 mufastOverlappedEta = mf->etaMS();
754 mufastOverlappedPhi = mf->phiMS();
755 }
756 if( j == best_ev ){
757 ATH_MSG_DEBUG( " EventView( j=" << j << " ) is best one" );
758 }
759 }
760 }
761 }
762 mufastNrActiveEVs = numMuon - mufastNrOverlapped;
763
764 return StatusCode::SUCCESS;
765}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#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.
int sign(int a)
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< double > > m_ptThresholdForECWeakBRegionB
Gaudi::Property< std::vector< float > > m_dRThresEC
virtual StatusCode initialize() override
TrigMufastHypoTool(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< bool > m_acceptAll
Gaudi::Property< float > m_ZPV
float getLocalPhi(float, float, float) const
Gaudi::Property< bool > m_applyOR
Gaudi::Property< float > m_massThresBB
Gaudi::Property< std::vector< float > > m_massThresEC
Gaudi::Property< bool > m_doCalib
StatusCode chooseBestMuon(std::vector< TrigMufastHypoTool::MuonClusterInfo * > &input, const std::vector< unsigned int > &mufastResult) const
virtual StatusCode decide(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
double invMass(double m1, double pt1, double eta1, double phi1, double m2, double pt2, double eta2, double phi2) const
Gaudi::Property< std::vector< std::vector< double > > > m_ptBins
Gaudi::Property< bool > m_decisionPerCluster
std::vector< size_t > m_bins
StatusCode checkOverlap(std::vector< TrigMufastHypoTool::MuonClusterInfo * > &input) const
StatusCode applyOverlapRemoval(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
StatusCode inclusiveSelection(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Gaudi::Property< bool > m_requireDR
HLT::Identifier m_decisionId
bool decideOnSingleObject(TrigMufastHypoTool::MuonClusterInfo &input, size_t cutIndex) const
Gaudi::Property< float > m_massThresBE
StatusCode multiplicitySelection(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Gaudi::Property< float > m_dRThresBB
Gaudi::Property< bool > m_selectPV
bool isOverlap(const xAOD::L2StandAloneMuon *mf1, const xAOD::L2StandAloneMuon *mf2) const
Gaudi::Property< std::vector< std::vector< double > > > m_ptThresholds
Gaudi::Property< float > m_RPV
Gaudi::Property< std::vector< double > > m_ptThresholdForECWeakBRegionA
Gaudi::Property< bool > m_requireSameSign
Gaudi::Property< bool > m_requireMass
Gaudi::Property< std::vector< float > > m_etaBinsEC
Gaudi::Property< float > m_dRThresBE
double dR(double eta1, double phi1, double eta2, double phi2) const
ToolHandle< GenericMonitoringTool > m_monTool
int sAddress() const
Get the station address of the muon.
float etaMS() const
Get the eta at muon spectrometer.
float phiMS() const
Get the phi at muon spectrometer.
virtual double pt() const
The transverse momentum ( ) of the particle.
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
ECRegions whichECRegion(const float eta, const float phi)
L2StandAloneMuon_v2 L2StandAloneMuon
Define the latest version of the muon SA class.
Helper for azimuthal angle calculations.