ATLAS Offline Software
TrigMufastHypoTool.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"
8 #include "TrigMufastHypoTool.h"
9 #include "CxxUtils/phihelper.h"
10 
12 
13 #include <cmath>
14 
15 using 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 
28 }
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 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){
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 
242 float 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 
278 StatusCode 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 
302 StatusCode 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 
322 StatusCode 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 
390 StatusCode 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;
424  return StatusCode::SUCCESS;
425  }
426 
427 
428  return StatusCode::SUCCESS;
429 }
430 
431 // --------------------------------------------------------------------------------
432 // --------------------------------------------------------------------------------
433 
434 StatusCode 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 
638 double 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 
648 double 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 
684 StatusCode 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 }
TrigMufastHypoTool::decide
virtual StatusCode decide(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Definition: TrigMufastHypoTool.cxx:278
xAOD::L2MuonParameters::ECRegions
ECRegions
Definition: TrigMuonDefs.h:36
checkxAOD.ds
ds
Definition: Tools/PyUtils/bin/checkxAOD.py:257
TrigDefs::Group
Group
Properties of a chain group.
Definition: GroupProperties.h:13
get_generator_info.result
result
Definition: get_generator_info.py:21
python.SystemOfUnits.m2
int m2
Definition: SystemOfUnits.py:92
ParticleGun_SamplingFraction.eta2
eta2
Definition: ParticleGun_SamplingFraction.py:96
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
TrigMufastHypoTool::MuonClusterInfo
Definition: TrigMufastHypoTool.h:43
xAOD::L2StandAloneMuon_v2::etaMS
float etaMS() const
Get the eta at muon spectrometer.
TrigCompositeUtils::passed
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
Definition: TrigCompositeUtilsRoot.cxx:117
HLT::Identifier::numeric
TrigCompositeUtils::DecisionID numeric() const
numeric ID
Definition: TrigCompositeUtils/TrigCompositeUtils/HLTIdentifier.h:47
TrigMufastHypoTool::m_ptThresholdForECWeakBRegionA
Gaudi::Property< std::vector< double > > m_ptThresholdForECWeakBRegionA
Definition: TrigMufastHypoTool.h:107
egammaEnergyPositionAllSamples::e1
double e1(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 1st sampling
xAOD::L2StandAloneMuon_v2
Class describing standalone muons reconstructed in the LVL2 trigger.
Definition: L2StandAloneMuon_v2.h:36
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
index
Definition: index.py:1
TrigMufastHypoTool::m_etaBinsEC
Gaudi::Property< std::vector< float > > m_etaBinsEC
Definition: TrigMufastHypoTool.h:144
TrigMufastHypoTool::m_decisionId
HLT::Identifier m_decisionId
Definition: TrigMufastHypoTool.h:68
TrigCompositeUtils::addDecisionID
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
Definition: TrigCompositeUtilsRoot.cxx:61
TrigMufastHypoTool::m_doCalib
Gaudi::Property< bool > m_doCalib
Definition: TrigMufastHypoTool.h:116
TrigMufastHypoTool::m_acceptAll
Gaudi::Property< bool > m_acceptAll
Definition: TrigMufastHypoTool.h:95
xAOD::eta1
setEt setPhi setE277 setWeta2 eta1
Definition: TrigEMCluster_v1.cxx:41
TrigMufastHypoTool::chooseBestMuon
StatusCode chooseBestMuon(std::vector< TrigMufastHypoTool::MuonClusterInfo * > &input, const std::vector< unsigned int > &mufastResult) const
Definition: TrigMufastHypoTool.cxx:684
xAOD::L2StandAloneMuon_v2::phiMS
float phiMS() const
Get the phi at muon spectrometer.
python.TurnDataReader.dr
dr
Definition: TurnDataReader.py:112
TrigMufastHypoTool::checkOverlap
StatusCode checkOverlap(std::vector< TrigMufastHypoTool::MuonClusterInfo * > &input) const
Definition: TrigMufastHypoTool.cxx:434
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
TrigMufastHypoTool::m_bins
std::vector< size_t > m_bins
Definition: TrigMufastHypoTool.h:155
TrigMufastHypoTool.h
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
TrigMufastHypoTool::invMass
double invMass(double m1, double pt1, double eta1, double phi1, double m2, double pt2, double eta2, double phi2) const
Definition: TrigMufastHypoTool.cxx:648
empty
bool empty(TH1 *h)
Definition: computils.cxx:294
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
DQPostProcessTest.mf
mf
Definition: DQPostProcessTest.py:19
TrigMufastHypoTool::m_ptThresholdForECWeakBRegionB
Gaudi::Property< std::vector< double > > m_ptThresholdForECWeakBRegionB
Definition: TrigMufastHypoTool.h:110
TrigMufastHypoTool::m_massThresBE
Gaudi::Property< float > m_massThresBE
Definition: TrigMufastHypoTool.h:141
HLT::Index1DVec
std::vector< size_t > Index1DVec
Unique combinations for case when one can not repeat the index (i.e.
Definition: TrigCompositeUtils/TrigCompositeUtils/Combinators.h:139
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
TrigMufastHypoTool::decideOnSingleObject
bool decideOnSingleObject(TrigMufastHypoTool::MuonClusterInfo &input, size_t cutIndex) const
Definition: TrigMufastHypoTool.cxx:120
TrigMufastHypoTool::m_massThresEC
Gaudi::Property< std::vector< float > > m_massThresEC
Definition: TrigMufastHypoTool.h:150
TrigMufastHypoTool::TrigMufastHypoTool
TrigMufastHypoTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: TrigMufastHypoTool.cxx:19
TrigMufastHypoTool::applyOverlapRemoval
StatusCode applyOverlapRemoval(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Definition: TrigMufastHypoTool.cxx:390
python.changerun.m1
m1
Definition: changerun.py:32
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
HLT
It used to be useful piece of code for replacing actual SG with other store of similar functionality ...
Definition: HLTResultReader.h:26
xAOD::L2StandAloneMuon_v2::sAddress
int sAddress() const
Get the station address of the muon.
lumiFormat.i
int i
Definition: lumiFormat.py:92
TrigMufastHypoTool::m_selectPV
Gaudi::Property< bool > m_selectPV
Definition: TrigMufastHypoTool.h:98
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
PlotPulseshapeFromCool.input
input
Definition: PlotPulseshapeFromCool.py:106
TrigMufastHypoTool::dR
double dR(double eta1, double phi1, double eta2, double phi2) const
Definition: TrigMufastHypoTool.cxx:638
WeakBFieldA
@ WeakBFieldA
Definition: MuFastSteering.h:42
test_pyathena.parent
parent
Definition: test_pyathena.py:15
sign
int sign(int a)
Definition: TRT_StrawNeighbourSvc.h:127
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
TrigMufastHypoTool::m_decisionPerCluster
Gaudi::Property< bool > m_decisionPerCluster
Definition: TrigMufastHypoTool.h:113
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
TrigMufastHypoTool::m_dRThresBB
Gaudi::Property< float > m_dRThresBB
Definition: TrigMufastHypoTool.h:132
TrigMufastHypoTool::m_applyOR
Gaudi::Property< bool > m_applyOR
Definition: TrigMufastHypoTool.h:120
TrigMufastHypoTool::m_massThresBB
Gaudi::Property< float > m_massThresBB
Definition: TrigMufastHypoTool.h:135
TrigMufastHypoTool::m_monTool
ToolHandle< GenericMonitoringTool > m_monTool
Definition: TrigMufastHypoTool.h:157
Monitored.h
Header file to be included by clients of the Monitored infrastructure.
TrigMufastHypoTool::m_dRThresEC
Gaudi::Property< std::vector< float > > m_dRThresEC
Definition: TrigMufastHypoTool.h:147
HLT::elementsInUniqueCombinations
void elementsInUniqueCombinations(const Index2DVec &indices, std::set< size_t > &participants, std::function< bool(const Index1DVec &)> &&filter)
Definition: Combinators.cxx:154
ZERO_LIMIT
const float ZERO_LIMIT
Definition: VP1TriggerHandleL2.cxx:37
TrigMufastHypoTool::m_ZPV
Gaudi::Property< float > m_ZPV
Definition: TrigMufastHypoTool.h:101
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
TrigMufastHypoToolConsts::errorCode_inconsistent_overlap1
const int errorCode_inconsistent_overlap1
Definition: TrigMufastHypoTool.h:25
threshold
Definition: chainparser.cxx:74
CxxUtils::deltaPhi
T deltaPhi(T phiA, T phiB)
Return difference phiA - phiB in range [-pi, pi].
Definition: phihelper.h:42
phihelper.h
Helper for azimuthal angle calculations.
TrigMufastHypoTool::inclusiveSelection
StatusCode inclusiveSelection(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Definition: TrigMufastHypoTool.cxx:302
TrigMufastHypoTool::multiplicitySelection
StatusCode multiplicitySelection(std::vector< TrigMufastHypoTool::MuonClusterInfo > &toolInput) const
Definition: TrigMufastHypoTool.cxx:322
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
DataModelTestDataCommonDict::xb
DMTest::CView::Pers_t xb
Definition: DataModelTestDataCommonDict.h:44
TrigMuonDefs.h
TrigMufastHypoTool::m_ptBins
Gaudi::Property< std::vector< std::vector< double > > > m_ptBins
Definition: TrigMufastHypoTool.h:89
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
Combinators.h
TrigMufastHypoToolConsts::errorCode_inconsistent_overlap2
const int errorCode_inconsistent_overlap2
Definition: TrigMufastHypoTool.h:26
egammaEnergyPositionAllSamples::e2
double e2(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 2nd sampling
TrigMufastHypoTool::getLocalPhi
float getLocalPhi(float, float, float) const
Definition: TrigMufastHypoTool.cxx:242
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
TrigMufastHypoTool::m_requireDR
Gaudi::Property< bool > m_requireDR
Definition: TrigMufastHypoTool.h:123
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
TauGNNUtils::Variables::absEta
bool absEta(const xAOD::TauJet &tau, double &out)
Definition: TauGNNUtils.cxx:232
TrigMufastHypoTool::~TrigMufastHypoTool
virtual ~TrigMufastHypoTool()
Definition: TrigMufastHypoTool.cxx:27
LArCellBinning.step
step
Definition: LArCellBinning.py:158
TrigCompositeUtils
Definition: Event/xAOD/xAODTrigger/xAODTrigger/TrigComposite.h:19
xAOD::L2StandAloneMuon_v2::pt
virtual double pt() const
The transverse momentum ( ) of the particle.
HLT::Index2DVec
std::vector< Index1DVec > Index2DVec
Definition: TrigCompositeUtils/TrigCompositeUtils/Combinators.h:140
TrigMufastHypoTool::m_requireSameSign
Gaudi::Property< bool > m_requireSameSign
Definition: TrigMufastHypoTool.h:129
TrigMufastHypoTool::m_RPV
Gaudi::Property< float > m_RPV
Definition: TrigMufastHypoTool.h:104
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
Monitored::Scalar
Declare a monitored scalar variable.
Definition: MonitoredScalar.h:34
AthAlgTool
Definition: AthAlgTool.h:26
TrigMufastHypoTool::m_requireMass
Gaudi::Property< bool > m_requireMass
Definition: TrigMufastHypoTool.h:126
GeV
#define GeV
Definition: CaloTransverseBalanceVecMon.cxx:30
TrigMufastHypoTool::m_dRThresBE
Gaudi::Property< float > m_dRThresBE
Definition: TrigMufastHypoTool.h:138
TrigMufastHypoTool::initialize
virtual StatusCode initialize() override
Definition: TrigMufastHypoTool.cxx:33
python.SystemOfUnits.rad
int rad
Definition: SystemOfUnits.py:111
TrigMufastHypoTool::isOverlap
bool isOverlap(const xAOD::L2StandAloneMuon *mf1, const xAOD::L2StandAloneMuon *mf2) const
Definition: TrigMufastHypoTool.cxx:518
TrigMufastHypoTool::m_ptThresholds
Gaudi::Property< std::vector< std::vector< double > > > m_ptThresholds
Definition: TrigMufastHypoTool.h:92
fitman.k
k
Definition: fitman.py:528
xAOD::L2MuonParameters::whichECRegion
ECRegions whichECRegion(const float eta, const float phi)
Definition: TrigMuonDefs.cxx:16