Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:21:10

0001 #include "L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h"
0002 #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h"
0003 
0004 #include "DataFormats/CSCDigi/interface/CSCConstants.h"
0005 #include "L1Trigger/DTUtilities/interface/DTTrigGeom.h"
0006 
0007 #include "FWCore/Framework/interface/EventSetup.h"
0008 #include "Geometry/Records/interface/MuonGeometryRecord.h"
0009 #include "Geometry/CSCGeometry/interface/CSCGeometry.h"
0010 #include "Geometry/DTGeometry/interface/DTGeometry.h"
0011 #include "Geometry/RPCGeometry/interface/RPCGeometry.h"
0012 #include "DataFormats/CSCDigi/interface/CSCCorrelatedLCTDigi.h"
0013 #include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambPhDigi.h"
0014 #include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambThContainer.h"
0015 #include "DataFormats/RPCDigi/interface/RPCDigi.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 
0018 #include <cmath>
0019 
0020 namespace {
0021   template <typename T>
0022   int sgn(T val) {
0023     return (T(0) < val) - (val < T(0));
0024   }
0025 
0026   int fixCscOffsetGeom(int offsetLoc) {
0027     // fix for CSC geo dependence from GlobalTag

0028 
0029     // dump of CSC offsets for MC global tag

0030     const std::vector<int> offCSC = {-154, -133, -17, -4,  4,   17,  133, 146, 154, 167, 283, 296, 304, 317,
0031                                      433,  446,  454, 467, 583, 596, 604, 617, 733, 746, 754, 767, 883, 904};
0032     auto gep = std::lower_bound(offCSC.begin(), offCSC.end(), offsetLoc);
0033     int fixOff = (gep != offCSC.end()) ? *gep : *(gep - 1);
0034     if (gep != offCSC.begin() && std::abs(*(gep - 1) - offsetLoc) < std::abs(fixOff - offsetLoc))
0035       fixOff = *(gep - 1);
0036     return fixOff;
0037   }
0038 
0039 }  // namespace

0040 
0041 AngleConverterBase::AngleConverterBase() : _geom_cache_id(0ULL) {}
0042 ///////////////////////////////////////

0043 ///////////////////////////////////////

0044 AngleConverterBase::~AngleConverterBase() {}
0045 ///////////////////////////////////////

0046 ///////////////////////////////////////

0047 void AngleConverterBase::checkAndUpdateGeometry(const edm::EventSetup& es,
0048                                                 const ProcConfigurationBase* config,
0049                                                 const MuonGeometryTokens& muonGeometryTokens) {
0050   if (muonGeometryRecordWatcher.check(es)) {
0051     _georpc = es.getHandle(muonGeometryTokens.rpcGeometryEsToken);
0052     _geocsc = es.getHandle(muonGeometryTokens.cscGeometryEsToken);
0053     _geodt = es.getHandle(muonGeometryTokens.dtGeometryEsToken);
0054   }
0055   this->config = config;
0056   nPhiBins = config->nPhiBins();
0057 }
0058 ///////////////////////////////////////

0059 ///////////////////////////////////////

0060 int AngleConverterBase::getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const {
0061   int dtPhiBins = 4096;
0062 
0063   double hsPhiPitch = 2 * M_PI / nPhiBins;  // width of phi Pitch, related to halfStrip at CSC station 2

0064 
0065   int sector = dtScNum + 1;  //NOTE: there is a inconsistency in DT sector numb. Thus +1 needed to get detector numb.

0066 
0067   double scale = 1. / dtPhiBins / hsPhiPitch;
0068   int scale_coeff = lround(scale * pow(2, 11));  // 216.2688

0069 
0070   int ichamber = sector - 1;
0071   if (ichamber > 6)
0072     ichamber = ichamber - 12;
0073 
0074   int offsetGlobal = (int)nPhiBins * ichamber / 12;
0075 
0076   int phiConverted = floor(dtPhi * scale_coeff / pow(2, 11)) + offsetGlobal - phiZero;
0077 
0078   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" phiZero "<<phiZero<<" phiDT "<<phiDT<<" sector "<<sector<<" ichamber "<<ichamber<<" offsetGlobal "<<offsetGlobal<<" phi "<<phi<<" foldPhi(phi) "<<omtfConfig->foldPhi(phi)<<std::endl;

0079   return config->foldPhi(phiConverted);
0080 }
0081 ///////////////////////////////////////

0082 ///////////////////////////////////////

0083 int AngleConverterBase::getProcessorPhi(
0084     int phiZero, l1t::tftype part, const CSCDetId& csc, const CSCCorrelatedLCTDigi& digi, unsigned int iInput) const {
0085   const double hsPhiPitch = 2 * M_PI / nPhiBins;
0086   //

0087   // get offset for each chamber.

0088   // FIXME: These parameters depends on processor and chamber only so may be precomputed and put in map

0089   //

0090 
0091   int halfStrip = digi.getStrip();  // returns halfStrip 0..159

0092 
0093   const CSCChamber* chamber = _geocsc->chamber(csc);
0094 
0095   //in the PhaseIITDRSpring19DR dataset (generated with CMSSW_10_6_1_patch2?), in case of the ME1/1 ring 4 (higher eta) the detId in the CSCCorrelatedLCTDigiCollection is ME1/1 ring 1 (instead ME1/1/4 as it was before),

0096   //and the digi.getStrip() is increased by 2*64 (i.e. number of half strips in the chamber roll)

0097   if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) {
0098     CSCDetId cscME11 = CSCDetId(csc.endcap(), csc.station(), 4, csc.chamber());  //changing ring  to 4

0099     chamber = _geocsc->chamber(cscME11);
0100   }
0101 
0102   const CSCChamberSpecs* cspec = chamber->specs();
0103   const CSCLayer* layer = chamber->layer(3);
0104   int order = (layer->centerOfStrip(2).phi() - layer->centerOfStrip(1).phi() > 0) ? 1 : -1;
0105   double stripPhiPitch = cspec->stripPhiPitch();
0106   double scale = std::abs(stripPhiPitch / hsPhiPitch / 2.);
0107   if (std::abs(scale - 1.) < 0.0002)
0108     scale = 1.;
0109 
0110   double phiHalfStrip0 = layer->centerOfStrip(1).phi() - order * stripPhiPitch / 4.;
0111 
0112   int offsetLoc = lround((phiHalfStrip0) / hsPhiPitch - phiZero);
0113   offsetLoc = config->foldPhi(offsetLoc);
0114 
0115   if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) {  //ME1/1/

0116                                                                    /*    if(cspec->nStrips() != 64)

0117       edm::LogImportant("l1tOmtfEventPrint") <<__FUNCTION__<<":"<<__LINE__<<" cspec->nStrips() != 64 in case of the ME1/1, phi of the muon stub will be not correct. chamber "

0118       <<csc<<" cspec->nStrips() "<<cspec->nStrips()<<std::endl;

0119       this checks has no sense - the ME1/1/ ring 4 has cspec->nStrips() = 48. but the offset of 128 half strips in the digi.getStrip() looks to be good*/
0120     halfStrip -= 128;
0121   }
0122 
0123   //FIXME: to be checked (only important for ME1/3) keep more bits for offset, truncate at the end

0124 
0125   int fixOff = offsetLoc;
0126   // a quick fix for towards geometry changes due to global tag.

0127   // in case of MC tag fixOff should be identical to offsetLoc

0128 
0129   if (config->getFixCscGeometryOffset()) {
0130     if (config->nProcessors() == 6)          //phase1

0131       fixOff = fixCscOffsetGeom(offsetLoc);  //TODO does not work in when phiZero is always 0. Fix this

0132     else if (config->nProcessors() == 3) {   //phase2

0133       //TODO fix this bricolage!!!!!!!!!!!!!!

0134       if (iInput >= 14)
0135         fixOff = fixCscOffsetGeom(offsetLoc - 900) + 900;
0136       else
0137         fixOff = fixCscOffsetGeom(offsetLoc);
0138     }
0139   }
0140   int phi = fixOff + order * scale * halfStrip;
0141   //the phi conversion is done like above - and not simply converting the layer->centerOfStrip(halfStrip/2 +1).phi() - to mimic this what is done by the firmware,

0142   //where phi of the stub is calculated with use of the offset and scale provided by an register

0143 
0144   /*//debug

0145   auto localPoint = layer->toLocal(layer->centerOfStrip(halfStrip));

0146   LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 147 << " csc: " <<csc.rawId()<<" "<< csc<<" layer "<<layer->id()<<" "<<layer->id().rawId()

0147       << " halfStrip "<<halfStrip<<" phiGlobal " << layer->centerOfStrip(halfStrip).phi()<<" local phi "<<localPoint.phi()<<" x "<<localPoint.x()<<" y "<<localPoint.y() <<std::endl;

0148     */
0149 
0150   /*//debug

0151   auto radToDeg = [](double rad) { return (180. / M_PI * rad); };

0152   LogTrace("l1tOmtfEventPrint") <<__FUNCTION__<<":"<<__LINE__<<" "<<std::setw(16)<<csc<<" phiZero "<<phiZero<<" hs: "<<std::setw(3)<< halfStrip <<" phiHalfStrip0 "<<std::setw(10)<<radToDeg(phiHalfStrip0)<<" offset: " << offsetLoc

0153       <<" oder*scale: "<<std::setw(10)<< order*scale

0154        <<" phi: " <<phi<<" foldPhi(phi) "<<config->foldPhi(phi)<<" ("<<offsetLoc + order*scale*halfStrip<<")"<<" centerOfStrip "<<std::setw(10)<< radToDeg( layer->centerOfStrip(halfStrip/2 +1).phi() )

0155        <<" centerOfStrip/hsPhiPitch "<< ( (layer->centerOfStrip(halfStrip/2 + 1).phi() )/hsPhiPitch)<<"  hsPhiPitch "<<hsPhiPitch

0156        //<<" phiSpan.f "<<layer->geometry()->phiSpan().first<<" phiSpan.s "<<layer->geometry()->phiSpan().second

0157        <<" nStrips "<<cspec->nStrips()

0158        //<<" strip 1 "<<radToDeg( layer->centerOfStrip(1).phi() )<<" strip last "<<radToDeg( layer->centerOfStrip(cspec->nStrips()).phi() )

0159        << std::endl;*/
0160 
0161   return config->foldPhi(phi);
0162 }
0163 
0164 ///////////////////////////////////////

0165 ///////////////////////////////////////

0166 int AngleConverterBase::getProcessorPhi(
0167     int phiZero, l1t::tftype part, const RPCDetId& rollId, const unsigned int& digi1, const unsigned int& digi2) const {
0168   const double hsPhiPitch = 2 * M_PI / nPhiBins;
0169   const int dummy = nPhiBins;
0170   const RPCRoll* roll = _georpc->roll(rollId);
0171   if (!roll)
0172     return dummy;
0173 
0174   double stripPhi1 = (roll->toGlobal(roll->centreOfStrip((int)digi1))).phi();  // note [-pi,pi]

0175   double stripPhi2 = (roll->toGlobal(roll->centreOfStrip((int)digi2))).phi();  // note [-pi,pi]

0176 
0177   // the case when the two strips are on different sides of phi = pi

0178   if (std::signbit(stripPhi1) != std::signbit(stripPhi2) && std::abs(stripPhi1) > M_PI / 2.) {
0179     if (std::signbit(stripPhi1)) {  //stripPhi1 is negative

0180       stripPhi1 += 2 * M_PI;
0181     } else  //stripPhi2 is negative

0182       stripPhi2 += 2 * M_PI;
0183   }
0184   int halfStrip = lround(((stripPhi1 + stripPhi2) / 2.) / hsPhiPitch);
0185   halfStrip = config->foldPhi(halfStrip);  //only for the case when the two strips are on different sides of phi = pi

0186 
0187   LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 185 << " roll " << rollId.rawId() << " " << rollId
0188                                 << " cluster: firstStrip " << digi1 << " stripPhi1Global " << stripPhi1
0189                                 << " stripPhi1LocalPhi " << roll->centreOfStrip((int)digi1).x() << " y "
0190                                 << roll->centreOfStrip((int)digi1).y() << " lastStrip " << digi2 << " stripPhi2Global "
0191                                 << stripPhi2 << " stripPhi2LocalPhi x " << roll->centreOfStrip((int)digi2).x() << " y "
0192                                 << roll->centreOfStrip((int)digi2).y() << " halfStrip " << halfStrip << std::endl;
0193 
0194   return config->foldPhi(halfStrip - phiZero);
0195 }
0196 
0197 int AngleConverterBase::getProcessorPhi(unsigned int iProcessor,
0198                                         l1t::tftype part,
0199                                         const RPCDetId& rollId,
0200                                         const unsigned int& digi) const {
0201   const double hsPhiPitch = 2 * M_PI / nPhiBins;
0202   const int dummy = nPhiBins;
0203   int processor = iProcessor + 1;
0204   const RPCRoll* roll = _georpc->roll(rollId);
0205   if (!roll)
0206     return dummy;
0207 
0208   double phi15deg = M_PI / 3. * (processor - 1) + M_PI / 12.;
0209   // "0" is 15degree moved cyclically to each processor, note [0,2pi]

0210 
0211   double stripPhi = (roll->toGlobal(roll->centreOfStrip((int)digi))).phi();  // note [-pi,pi]

0212 
0213   // adjust [0,2pi] and [-pi,pi] to get deltaPhi difference properly

0214   switch (processor) {
0215     case 1:
0216       break;
0217     case 6: {
0218       phi15deg -= 2 * M_PI;
0219       break;
0220     }
0221     default: {
0222       if (stripPhi < 0)
0223         stripPhi += 2 * M_PI;
0224       break;
0225     }
0226   }
0227 
0228   // local angle in CSC halfStrip usnits

0229   int halfStrip = lround((stripPhi - phi15deg) / hsPhiPitch);
0230 
0231   return halfStrip;
0232 }
0233 ///////////////////////////////////////

0234 ///////////////////////////////////////

0235 EtaValue AngleConverterBase::getGlobalEtaDt(const DTChamberId& detId) const {
0236   Local2DPoint chamberMiddleLP(0, 0);
0237   GlobalPoint chamberMiddleGP = _geodt->chamber(detId)->toGlobal(chamberMiddleLP);
0238 
0239   const DTChamberId baseidNeigh(detId.wheel() + (detId.wheel() >= 0 ? -1 : +1), detId.station(), detId.sector());
0240   GlobalPoint chambNeighMiddleGP = _geodt->chamber(baseidNeigh)->toGlobal(chamberMiddleLP);
0241 
0242   EtaValue etaValue = {
0243       config->etaToHwEta(chamberMiddleGP.eta()),
0244       config->etaToHwEta(std::abs(chamberMiddleGP.eta() - chambNeighMiddleGP.eta())) / 2,
0245       0,  //quality

0246       0,  //bx

0247       0   //timin

0248   };
0249 
0250   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rawid "<<detId.rawId()<<" baseid "<<detId<<" chamberMiddleGP.eta() "<<chamberMiddleGP.eta()<<" eta "<<etaValue.eta<<" etaSigma "<<etaValue.etaSigma<<std::endl;

0251   return etaValue;
0252 }
0253 
0254 ///////////////////////////////////////

0255 ///////////////////////////////////////

0256 void AngleConverterBase::getGlobalEta(const L1MuDTChambThDigi& thetaDigi, std::vector<EtaValue>& etaSegments) const {
0257   const DTChamberId baseid(thetaDigi.whNum(), thetaDigi.stNum(), thetaDigi.scNum() + 1);
0258   DTTrigGeom trig_geom(_geodt->chamber(baseid), false);
0259 
0260   // super layer 2 is the theta superlayer in a DT chamber

0261   // station 4 does not have a theta super layer

0262   // the BTI index from the theta trigger is an OR of some BTI outputs

0263   // so, we choose the BTI that's in the middle of the group

0264   // as the BTI that we get theta from

0265   // TODO:::::>>> need to make sure this ordering doesn't flip under wheel sign

0266   const int NBTI_theta = trig_geom.nCell(2);
0267   for (unsigned int btiGroup = 0; btiGroup < 7; ++btiGroup) {
0268     if (thetaDigi.position(btiGroup)) {
0269       unsigned btiActual = btiGroup * NBTI_theta / 7 + NBTI_theta / 14 + 1;
0270       DTBtiId thetaBTI = DTBtiId(baseid, 2, btiActual);
0271       GlobalPoint theta_gp = trig_geom.CMSPosition(thetaBTI);
0272 
0273       EtaValue etaValue = {
0274           config->etaToHwEta(theta_gp.eta()),
0275           0,
0276           thetaDigi.quality(btiGroup),
0277           thetaDigi.bxNum(),
0278           0  //TODO what about sub-bx timing???

0279       };
0280       etaSegments.emplace_back(etaValue);
0281 
0282       //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" bx "<<thetaDigi.bxNum()<<" baseid "<<baseid<<" btiGroup "<<btiGroup<<" quality "<<thetaDigi.quality(btiGroup)<<" theta_gp.eta() "<<theta_gp.eta()<<" eta "<<etaValue.eta<<" etaSigma "<<etaValue.etaSigma<<std::endl;

0283     }
0284   }
0285 }
0286 
0287 std::vector<EtaValue> AngleConverterBase::getGlobalEta(const L1MuDTChambThContainer* dtThDigis,
0288                                                        int bxFrom,
0289                                                        int bxTo) const {
0290   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" dtThDigis size "<<dtThDigis->getContainer()->size()<<std::endl;

0291 
0292   std::vector<EtaValue> etaSegments;
0293 
0294   for (auto& thetaDigi : (*(dtThDigis->getContainer()))) {
0295     if (thetaDigi.bxNum() >= bxFrom && thetaDigi.bxNum() <= bxTo) {
0296       getGlobalEta(thetaDigi, etaSegments);
0297     }
0298   }
0299   return etaSegments;
0300 }
0301 
0302 //just read from the drawing

0303 float AngleConverterBase::cscChamberEtaSize(const CSCDetId& detId) const {
0304   if (detId.station() == 1) {
0305     if (detId.ring() == 1)
0306       return (2.5 - 1.6) / 2.;
0307     ///ME1/1 lower eta (b?, eta < ~2.1), L1TkMuonBayes eta bins 6-11 - but getGlobalEtaCsc(const CSCDetId& detId) gives the midle of the full chamber, so here we put the size of the full chamber

0308     if (detId.ring() == 2)
0309       return (1.7 - 1.2) / 2.;
0310     if (detId.ring() == 3)
0311       return (1.12 - 0.9) / 2.;
0312     if (detId.ring() == 4)
0313       return (2.5 - 1.6) / 2.;  ///ME1/1 higher eta (a?, eta > ~2.1), L1TkMuonBayes eta bins 10-15

0314   } else if (detId.station() == 2) {
0315     if (detId.ring() == 1)
0316       return (2.5 - 1.6) / 2.;
0317     if (detId.ring() == 2)
0318       return (1.6 - 1.0) / 2.;
0319   } else if (detId.station() == 3) {
0320     if (detId.ring() == 1)
0321       return (2.5 - 1.7) / 2.;
0322     if (detId.ring() == 2)
0323       return (1.7 - 1.1) / 2.;
0324   } else if (detId.station() == 4) {
0325     if (detId.ring() == 1)
0326       return (2.45 - 1.8) / 2.;
0327     if (detId.ring() == 2)
0328       return (1.8 - 1.2) / 2.;
0329   }
0330   return 0;
0331 }
0332 
0333 EtaValue AngleConverterBase::getGlobalEta(const CSCDetId& detId, const CSCCorrelatedLCTDigi& aDigi) const {
0334   ///Code taken from GeometryTranslator.

0335   ///Will be replaced by direct CSC phi local to global scale

0336   ///transformation as used in FPGA implementation

0337 
0338   // alot of this is transcription and consolidation of the CSC

0339   // global phi calculation code

0340   // this works directly with the geometry

0341   // rather than using the old phi luts

0342 
0343   auto chamb = _geocsc->chamber(detId);
0344   auto layer_geom = chamb->layer(CSCConstants::KEY_ALCT_LAYER)->geometry();
0345   auto layer = chamb->layer(CSCConstants::KEY_ALCT_LAYER);
0346 
0347   const uint16_t keyWG = aDigi.getKeyWG();
0348 
0349   const LocalPoint lpWg = layer_geom->localCenterOfWireGroup(keyWG);
0350   const GlobalPoint gpWg = layer->surface().toGlobal(lpWg);
0351 
0352   EtaValue etaSegment = {
0353       config->etaToHwEta(gpWg.eta()),
0354       0,  //config->etaToHwEta(cscChamberEtaSize(id) ),

0355       0,
0356       aDigi.getBX(),
0357       0  //tming???

0358   };
0359 
0360   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" csc "<<detId<<" eta "<<gpWg.eta()<<" etaHw "<<etaSegment.eta<<" etaSigma "<<etaSegment.etaSigma<<std::endl;

0361   return etaSegment;
0362 }
0363 
0364 //TODO the CSC ME1/1 has strips divided in two parts: a and b, so this function in principle can include that,

0365 //then it should also receive the roll number as parameter, off course implementation should be different then

0366 EtaValue AngleConverterBase::getGlobalEtaCsc(const CSCDetId& detId) const {
0367   auto chamb = _geocsc->chamber(detId);
0368 
0369   Local2DPoint chamberMiddleLP(0, 0);
0370   GlobalPoint chamberMiddleGP = chamb->toGlobal(chamberMiddleLP);
0371 
0372   EtaValue etaValue = {
0373       config->etaToHwEta(chamberMiddleGP.eta()),
0374       config->etaToHwEta(cscChamberEtaSize(detId)),
0375       0,
0376       0,  //bx

0377       0   //timnig

0378   };
0379 
0380   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rawid "<<detId.rawId()<<" detId "<<detId<<" chamberMiddleGP.eta() "<<chamberMiddleGP.eta()<<" eta "<<etaValue.eta<<" etaSigma "<<etaValue.etaSigma<<std::endl;

0381   return etaValue;
0382 }
0383 
0384 ///////////////////////////////////////

0385 ///////////////////////////////////////

0386 EtaValue AngleConverterBase::getGlobalEta(unsigned int rawid, const unsigned int& strip) const {
0387   const RPCDetId id(rawid);
0388 
0389   auto roll = _georpc->roll(id);
0390   const LocalPoint lp = roll->centreOfStrip((int)strip);
0391   const GlobalPoint gp = roll->toGlobal(lp);
0392 
0393   int neighbRoll = 1;  //neighbor roll in eta

0394   //roll->chamber()->nrolls() does not work

0395   if (id.region() == 0) {  //barel

0396     if (id.station() == 2 && ((std::abs(id.ring()) == 2 && id.layer() == 2) ||
0397                               (std::abs(id.ring()) != 2 && id.layer() == 1))) {  //three-roll chamber

0398       if (id.roll() == 2)
0399         neighbRoll = 1;
0400       else {
0401         neighbRoll = 2;
0402       }
0403     } else  //two-roll chamber

0404       neighbRoll = (id.roll() == 1 ? 3 : 1);
0405   } else {  //endcap

0406     neighbRoll = id.roll() + (id.roll() == 1 ? +1 : -1);
0407   }
0408 
0409   const RPCDetId idNeigh =
0410       RPCDetId(id.region(), id.ring(), id.station(), id.sector(), id.layer(), id.subsector(), neighbRoll);
0411   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rpc "<<id<<std::endl;

0412   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rpc "<<idNeigh<<std::endl;

0413 
0414   auto rollNeigh = _georpc->roll(idNeigh);
0415   const LocalPoint lpNeigh = rollNeigh->centreOfStrip((int)strip);
0416   const GlobalPoint gpNeigh = rollNeigh->toGlobal(lpNeigh);
0417 
0418   EtaValue etaValue = {config->etaToHwEta(gp.eta()),
0419                        config->etaToHwEta(std::abs(gp.eta() - gpNeigh.eta())) /
0420                            2,  //half of the size of the strip in eta - not precise, but OK

0421                        0};
0422 
0423   //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rpc "<<id<<" eta "<<gp.eta()<<" etaHw "<<etaValue.eta<<" etaSigma "<<etaValue.etaSigma<<std::endl;

0424   return etaValue;
0425 }
0426 ///////////////////////////////////////

0427 ///////////////////////////////////////

0428 bool AngleConverterBase::isCSCCounterClockwise(const CSCLayer* layer) const {
0429   const int nStrips = layer->geometry()->numberOfStrips();
0430   const double phi1 = layer->centerOfStrip(1).phi();
0431   const double phiN = layer->centerOfStrip(nStrips).phi();
0432   return ((std::abs(phi1 - phiN) < M_PI && phi1 >= phiN) || (std::abs(phi1 - phiN) >= M_PI && phi1 < phiN));
0433 }
0434 ///////////////////////////////////////

0435 ///////////////////////////////////////

0436 const int AngleConverterBase::findBTIgroup(const L1MuDTChambPhDigi& aDigi, const L1MuDTChambThContainer* dtThDigis) {
0437   int bti_group = -1;
0438 
0439   const L1MuDTChambThDigi* theta_segm =
0440       dtThDigis->chThetaSegm(aDigi.whNum(), aDigi.stNum(), aDigi.scNum(), aDigi.bxNum());
0441   if (!theta_segm)
0442     return bti_group;
0443 
0444   for (unsigned int i = 0; i < 7; ++i) {
0445     if (theta_segm->position(i) && bti_group < 0)
0446       bti_group = i;
0447     ///If there are more than one theta digi we do not take is

0448     ///due to unresolved ambiguity. In this case we take eta of the

0449     ///middle of the chamber.

0450     else if (theta_segm->position(i) && bti_group > -1)
0451       return -1;
0452   }
0453 
0454   return bti_group;
0455 }
0456 ///////////////////////////////////////

0457 ///////////////////////////////////////