Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:20:01

0001 /**
0002  * \class L1GtMuonCondition
0003  *
0004  *
0005  * Description: evaluation of a CondMuon condition.
0006  *
0007  * Implementation:
0008  *    <TODO: enter implementation details>
0009  *
0010  * \author: Vasile Mihai Ghete   - HEPHY Vienna
0011  *
0012  *
0013  */
0014 
0015 // this class header
0016 #include "L1Trigger/GlobalTrigger/interface/L1GtMuonCondition.h"
0017 
0018 // system include files
0019 #include <iomanip>
0020 #include <iostream>
0021 
0022 #include <algorithm>
0023 #include <string>
0024 #include <vector>
0025 
0026 // user include files
0027 //   base classes
0028 #include "CondFormats/L1TObjects/interface/L1GtMuonTemplate.h"
0029 #include "L1Trigger/GlobalTrigger/interface/L1GtConditionEvaluation.h"
0030 
0031 #include "DataFormats/L1GlobalTrigger/interface/L1GlobalTriggerReadoutSetupFwd.h"
0032 
0033 #include "DataFormats/L1GlobalMuonTrigger/interface/L1MuGMTCand.h"
0034 
0035 #include "L1Trigger/GlobalTrigger/interface/L1GlobalTriggerFunctions.h"
0036 #include "L1Trigger/GlobalTrigger/interface/L1GlobalTriggerGTL.h"
0037 
0038 #include "FWCore/MessageLogger/interface/MessageDrop.h"
0039 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0040 
0041 // constructors
0042 //     default
0043 L1GtMuonCondition::L1GtMuonCondition() : L1GtConditionEvaluation() {
0044   // empty
0045 }
0046 
0047 //     from base template condition (from event setup usually)
0048 L1GtMuonCondition::L1GtMuonCondition(const L1GtCondition *muonTemplate,
0049                                      const L1GlobalTriggerGTL *ptrGTL,
0050                                      const int nrL1Mu,
0051                                      const int ifMuEtaNumberBits)
0052     : L1GtConditionEvaluation(),
0053       m_gtMuonTemplate(static_cast<const L1GtMuonTemplate *>(muonTemplate)),
0054       m_gtGTL(ptrGTL),
0055       m_ifMuEtaNumberBits(ifMuEtaNumberBits) {
0056   m_corrParDeltaPhiNrBins = 0;
0057   m_condMaxNumberObjects = nrL1Mu;
0058 }
0059 
0060 // copy constructor
0061 void L1GtMuonCondition::copy(const L1GtMuonCondition &cp) {
0062   m_gtMuonTemplate = cp.gtMuonTemplate();
0063   m_gtGTL = cp.gtGTL();
0064 
0065   m_ifMuEtaNumberBits = cp.gtIfMuEtaNumberBits();
0066   m_corrParDeltaPhiNrBins = cp.m_corrParDeltaPhiNrBins;
0067 
0068   m_condMaxNumberObjects = cp.condMaxNumberObjects();
0069   m_condLastResult = cp.condLastResult();
0070   m_combinationsInCond = cp.getCombinationsInCond();
0071 
0072   m_verbosity = cp.m_verbosity;
0073 }
0074 
0075 L1GtMuonCondition::L1GtMuonCondition(const L1GtMuonCondition &cp) : L1GtConditionEvaluation() { copy(cp); }
0076 
0077 // destructor
0078 L1GtMuonCondition::~L1GtMuonCondition() {
0079   // empty
0080 }
0081 
0082 // equal operator
0083 L1GtMuonCondition &L1GtMuonCondition::operator=(const L1GtMuonCondition &cp) {
0084   copy(cp);
0085   return *this;
0086 }
0087 
0088 // methods
0089 void L1GtMuonCondition::setGtMuonTemplate(const L1GtMuonTemplate *muonTempl) { m_gtMuonTemplate = muonTempl; }
0090 
0091 ///   set the pointer to GTL
0092 void L1GtMuonCondition::setGtGTL(const L1GlobalTriggerGTL *ptrGTL) { m_gtGTL = ptrGTL; }
0093 
0094 //   set the number of bits for eta of muon objects
0095 void L1GtMuonCondition::setGtIfMuEtaNumberBits(const int &ifMuEtaNumberBitsValue) {
0096   m_ifMuEtaNumberBits = ifMuEtaNumberBitsValue;
0097 }
0098 
0099 //   set the maximum number of bins for the delta phi scales
0100 void L1GtMuonCondition::setGtCorrParDeltaPhiNrBins(const int &corrParDeltaPhiNrBins) {
0101   m_corrParDeltaPhiNrBins = corrParDeltaPhiNrBins;
0102 }
0103 
0104 // try all object permutations and check spatial correlations, if required
0105 const bool L1GtMuonCondition::evaluateCondition() const {
0106   // number of trigger objects in the condition
0107   int nObjInCond = m_gtMuonTemplate->nrObjects();
0108 
0109   // the candidates
0110   const std::vector<const L1MuGMTCand *> *candVec = m_gtGTL->getCandL1Mu();
0111 
0112   int numberObjects = candVec->size();
0113   // LogTrace("L1GlobalTrigger") << "  numberObjects: " << numberObjects
0114   //    << std::endl;
0115   if (numberObjects < nObjInCond) {
0116     return false;
0117   }
0118 
0119   std::vector<int> index(numberObjects);
0120 
0121   for (int i = 0; i < numberObjects; ++i) {
0122     index[i] = i;
0123   }
0124 
0125   int jumpIndex = 1;
0126   int jump = factorial(numberObjects - nObjInCond);
0127 
0128   // condition result condResult set to true if at least one permutation
0129   //     passes all requirements
0130   // all possible permutations are checked
0131   bool condResult = false;
0132 
0133   // store the indices of the muon objects
0134   // from the combination evaluated in the condition
0135   SingleCombInCond objectsInComb;
0136   objectsInComb.reserve(nObjInCond);
0137 
0138   // clear the m_combinationsInCond vector
0139   (combinationsInCond()).clear();
0140 
0141   do {
0142     if (--jumpIndex)
0143       continue;
0144 
0145     jumpIndex = jump;
0146 
0147     // clear the indices in the combination
0148     objectsInComb.clear();
0149 
0150     bool tmpResult = true;
0151 
0152     // check if there is a permutation that matches object-parameter
0153     // requirements
0154     for (int i = 0; i < nObjInCond; i++) {
0155       tmpResult &= checkObjectParameter(i, *(*candVec)[index[i]]);
0156       objectsInComb.push_back(index[i]);
0157     }
0158 
0159     // if permutation does not match particle conditions
0160     // skip charge correlation and spatial correlations
0161     if (!tmpResult) {
0162       continue;
0163     }
0164 
0165     // get the correlation parameters (chargeCorrelation included here also)
0166     L1GtMuonTemplate::CorrelationParameter corrPar = *(m_gtMuonTemplate->correlationParameter());
0167 
0168     // charge_correlation consists of 3 relevant bits (D2, D1, D0)
0169     unsigned int chargeCorr = corrPar.chargeCorrelation;
0170 
0171     // charge ignore bit (D0) not set?
0172     if ((chargeCorr & 1) == 0) {
0173       for (int i = 0; i < nObjInCond; i++) {
0174         // check valid charge - skip if invalid charge
0175         bool chargeValid = (*candVec)[index[i]]->charge_valid();
0176         tmpResult &= chargeValid;
0177 
0178         if (!chargeValid) {
0179           continue;
0180         }
0181       }
0182 
0183       if (!tmpResult) {
0184         continue;
0185       }
0186 
0187       if (nObjInCond == 1) {  // one object condition
0188 
0189         // D2..enable pos, D1..enable neg
0190         if (!(((chargeCorr & 4) != 0 && (*candVec)[index[0]]->charge() > 0) ||
0191               ((chargeCorr & 2) != 0 && (*candVec)[index[0]]->charge() < 0))) {
0192           continue;
0193         }
0194 
0195       } else {  // more objects condition
0196 
0197         // find out if signs are equal
0198         bool equalSigns = true;
0199         for (int i = 0; i < nObjInCond - 1; i++) {
0200           if ((*candVec)[index[i]]->charge() != (*candVec)[index[i + 1]]->charge()) {
0201             equalSigns = false;
0202             break;
0203           }
0204         }
0205 
0206         // two or three particle condition
0207         if (nObjInCond == 2 || nObjInCond == 3) {
0208           // D2..enable equal, D1..enable not equal
0209           if (!(((chargeCorr & 4) != 0 && equalSigns) || ((chargeCorr & 2) != 0 && !equalSigns))) {
0210             continue;
0211           }
0212         }
0213 
0214         // four particle condition
0215         if (nObjInCond == 4) {
0216           // counter to count positive charges to determine if there are pairs
0217           unsigned int posCount = 0;
0218 
0219           for (int i = 0; i < nObjInCond; i++) {
0220             if ((*candVec)[index[i]]->charge() > 0) {
0221               posCount++;
0222             }
0223           }
0224 
0225           // D2..enable equal, D1..enable pairs
0226           if (!(((chargeCorr & 4) != 0 && equalSigns) || ((chargeCorr & 2) != 0 && posCount == 2))) {
0227             continue;
0228           }
0229         }
0230       }
0231     }  // end signchecks
0232 
0233     if (m_gtMuonTemplate->wsc()) {
0234       // wsc requirements have always nObjInCond = 2
0235       // one can use directly index[0] and index[1] to compute
0236       // eta and phi differences
0237       const int ObjInWscComb = 2;
0238       if (nObjInCond != ObjInWscComb) {
0239         edm::LogError("L1GlobalTrigger") << "\n  Error: "
0240                                          << "number of particles in condition with spatial correlation = " << nObjInCond
0241                                          << "\n  it must be = " << ObjInWscComb << std::endl;
0242         // TODO Perhaps I should throw here an exception,
0243         // since something is really wrong if nObjInCond != ObjInWscComb (=2)
0244         continue;
0245       }
0246 
0247       unsigned int candDeltaEta;
0248       unsigned int candDeltaPhi;
0249 
0250       // check candDeltaEta
0251 
0252       // get eta index and the sign bit of the eta index (MSB is the sign)
0253       //   signedEta[i] is the signed eta index of (*candVec)[index[i]]
0254       int signedEta[ObjInWscComb];
0255       int signBit[ObjInWscComb] = {0, 0};
0256 
0257       int scaleEta = 1 << (m_ifMuEtaNumberBits - 1);
0258 
0259       for (int i = 0; i < ObjInWscComb; ++i) {
0260         signBit[i] = ((*candVec)[index[i]]->etaIndex() & scaleEta) >> (m_ifMuEtaNumberBits - 1);
0261         signedEta[i] = ((*candVec)[index[i]]->etaIndex()) % scaleEta;
0262 
0263         if (signBit[i] == 1) {
0264           signedEta[i] = (-1) * signedEta[i];
0265         }
0266       }
0267 
0268       // compute candDeltaEta - add 1 if signs are different (due to +0/-0
0269       // indices)
0270       candDeltaEta =
0271           static_cast<int>(std::abs(signedEta[1] - signedEta[0])) + static_cast<int>(signBit[1] ^ signBit[0]);
0272 
0273       if (!checkBit(corrPar.deltaEtaRange, candDeltaEta)) {
0274         continue;
0275       }
0276 
0277       // check candDeltaPhi
0278 
0279       // calculate absolute value of candDeltaPhi
0280       if ((*candVec)[index[0]]->phiIndex() > (*candVec)[index[1]]->phiIndex()) {
0281         candDeltaPhi = (*candVec)[index[0]]->phiIndex() - (*candVec)[index[1]]->phiIndex();
0282       } else {
0283         candDeltaPhi = (*candVec)[index[1]]->phiIndex() - (*candVec)[index[0]]->phiIndex();
0284       }
0285 
0286       // check if candDeltaPhi > 180 (via delta_phi_maxbits)
0287       // delta_phi contains bits for 0..180 (0 and 180 included)
0288       // protect also against infinite loop...
0289 
0290       int nMaxLoop = 10;
0291       int iLoop = 0;
0292 
0293       while (candDeltaPhi >= m_corrParDeltaPhiNrBins) {
0294         unsigned int candDeltaPhiInitial = candDeltaPhi;
0295 
0296         // candDeltaPhi > 180 ==> take 360 - candDeltaPhi
0297         candDeltaPhi = (m_corrParDeltaPhiNrBins - 1) * 2 - candDeltaPhi;
0298         if (m_verbosity) {
0299           LogTrace("L1GlobalTrigger") << "    Initial candDeltaPhi = " << candDeltaPhiInitial
0300                                       << " > m_corrParDeltaPhiNrBins = " << m_corrParDeltaPhiNrBins
0301                                       << "  ==> candDeltaPhi rescaled to: " << candDeltaPhi << " [ loop index " << iLoop
0302                                       << "; breaks after " << nMaxLoop << " loops ]\n"
0303                                       << std::endl;
0304         }
0305 
0306         iLoop++;
0307         if (iLoop > nMaxLoop) {
0308           return false;
0309         }
0310       }
0311 
0312       // delta_phi bitmask is saved in two uint64_t words
0313       if (candDeltaPhi < 64) {
0314         if (!checkBit(corrPar.deltaPhiRange0Word, candDeltaPhi)) {
0315           continue;
0316         }
0317       } else {
0318         if (!checkBit(corrPar.deltaPhiRange1Word, (candDeltaPhi - 64))) {
0319           continue;
0320         }
0321       }
0322 
0323     }  // end wsc check
0324 
0325     // if we get here all checks were successfull for this combination
0326     // set the general result for evaluateCondition to "true"
0327 
0328     condResult = true;
0329     (combinationsInCond()).push_back(objectsInComb);
0330 
0331   } while (std::next_permutation(index.begin(), index.end()));
0332   return condResult;
0333 }
0334 
0335 // load muon candidates
0336 const L1MuGMTCand *L1GtMuonCondition::getCandidate(const int indexCand) const {
0337   return (*(m_gtGTL->getCandL1Mu()))[indexCand];
0338 }
0339 
0340 /**
0341  * checkObjectParameter - Compare a single particle with a numbered condition.
0342  *
0343  * @param iCondition The number of the condition.
0344  * @param cand The candidate to compare.
0345  *
0346  * @return The result of the comparison (false if a condition does not exist).
0347  */
0348 
0349 const bool L1GtMuonCondition::checkObjectParameter(const int iCondition, const L1MuGMTCand &cand) const {
0350   // number of objects in condition
0351   int nObjInCond = m_gtMuonTemplate->nrObjects();
0352 
0353   if (iCondition >= nObjInCond || iCondition < 0) {
0354     return false;
0355   }
0356 
0357   // empty candidates can not be compared
0358   if (cand.empty()) {
0359     return false;
0360   }
0361 
0362   const L1GtMuonTemplate::ObjectParameter objPar = (*(m_gtMuonTemplate->objectParameter()))[iCondition];
0363 
0364   // using the logic table from GTL-9U-module.pdf
0365   // "Truth table for Isolation bit"
0366 
0367   // check thresholds:
0368 
0369   //   value < low pt threshold
0370   //       fail trigger
0371 
0372   //   low pt threshold <= value < high pt threshold & non-isolated muon:
0373   //       requestIso true:                    fail trigger
0374   //       requestIso false, enableIso true:   fail trigger
0375   //       requestIso false, enableIso false:  OK,  trigger
0376 
0377   //   low pt threshold <= value < high pt threshold & isolated muon:
0378   //       requestIso true:                    OK,  trigger
0379   //       requestIso false, enableIso true:   OK,  trigger
0380   //       requestIso false, enableIso false:  OK,  trigger
0381 
0382   //   value >= high pt threshold & non-isolated muon:
0383   //       requestIso true:  fail trigger
0384   //       requestIso false: OK,  trigger
0385 
0386   //   value >= high pt threshold & isolated muon:
0387   //       OK, trigger
0388 
0389   if (!checkThreshold(objPar.ptHighThreshold, cand.ptIndex(), m_gtMuonTemplate->condGEq())) {
0390     if (!checkThreshold(objPar.ptLowThreshold, cand.ptIndex(), m_gtMuonTemplate->condGEq())) {
0391       return false;
0392     } else {
0393       // check isolation
0394       if (!cand.isol()) {
0395         if (objPar.requestIso || objPar.enableIso) {
0396           return false;
0397         }
0398       }
0399     }
0400 
0401   } else {
0402     if (!cand.isol()) {
0403       if (objPar.requestIso) {
0404         return false;
0405       }
0406     }
0407   }
0408 
0409   // check eta
0410 
0411   if (!checkBit(objPar.etaRange, cand.etaIndex())) {
0412     return false;
0413   }
0414 
0415   // check phi  - in the requested range (no LUT used - LUT too big for hw chip)
0416   // for phiLow <= phiHigh takes [phiLow, phiHigh]
0417   // for phiLow >= phiHigh takes [phiLow, phiHigh] over zero angle!
0418 
0419   if (objPar.phiHigh >= objPar.phiLow) {
0420     if (!((objPar.phiLow <= cand.phiIndex()) && (cand.phiIndex() <= objPar.phiHigh))) {
0421       return false;
0422     }
0423 
0424   } else {  // go over zero angle!!
0425     if (!((objPar.phiLow <= cand.phiIndex()) || (cand.phiIndex() <= objPar.phiHigh))) {
0426       return false;
0427     }
0428   }
0429 
0430   // check quality ( bit check )
0431 
0432   // A number of values is required to trigger (at least one).
0433   // "Don’t care" means that all values are allowed.
0434   // Qual = 000 means then NO MUON (GTL module)
0435 
0436   if (cand.quality() == 0) {
0437     return false;
0438   }
0439 
0440   if (objPar.qualityRange == 0) {
0441     return false;
0442   } else {
0443     if (!checkBit(objPar.qualityRange, cand.quality())) {
0444       return false;
0445     }
0446   }
0447 
0448   // check mip
0449   if (objPar.enableMip) {
0450     if (!cand.mip()) {
0451       return false;
0452     }
0453   }
0454 
0455   // particle matches if we get here
0456   // LogTrace("L1GlobalTrigger")
0457   //    << "  checkObjectParameter: muon object OK, passes all requirements\n"
0458   //    << std::endl;
0459 
0460   return true;
0461 }
0462 
0463 void L1GtMuonCondition::print(std::ostream &myCout) const {
0464   m_gtMuonTemplate->print(myCout);
0465 
0466   myCout << "    Number of bits for eta of muon objects = " << m_ifMuEtaNumberBits << std::endl;
0467   myCout << "    Maximum number of bins for the delta phi scales = " << m_corrParDeltaPhiNrBins << "\n " << std::endl;
0468 
0469   L1GtConditionEvaluation::print(myCout);
0470 }