CMS 3D CMS Logo

AngleConverter.cc
Go to the documentation of this file.
3 
6 
10 
14 
19 
20 #include <cmath>
21 
22 namespace {
23 template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
24 
25 std::vector<float> bounds = { 1.24, 1.14353, 1.09844, 1.05168, 1.00313, 0.952728, 0.90037, 0.8};
26 // 0.8 -> 73
27 // 0.85 -> 78
28 // 0.9265 -> 85
29 // 0.9779 -> 89.9 -> 90
30 // 1.0274 -> 94.4 -> 94
31 // 1.07506 -> 98.9 -> 99
32 // 1.121 -> 103
33 // 1.2 -> 110
34 // 1.25 -> 115
35 //
36 // other (1.033) -> 1.033 -> 95
37 
38 int etaVal2Bit(float eta) { return bounds.rend() - std::lower_bound (bounds.rbegin(), bounds.rend(), fabs(eta) ); }
39 
40 int etaBit2Code( unsigned int bit) {
41  int code = 73;
42  switch (bit) {
43  case 0 : {code = 115; break;}
44  case 1 : {code = 110; break; }
45  case 2 : {code = 103; break; }
46  case 3 : {code = 99; break; }
47  case 4 : {code = 94; break; }
48  case 5 : {code = 90; break; }
49  case 6 : {code = 85; break; }
50  case 7 : {code = 78; break; }
51  case 8 : {code = 73; break; }
52  default: {code = 95; break; }
53  }
54  return code;
55 }
56 
57 int etaVal2Code( double etaVal) {
58  int sign = sgn(etaVal);
59  int bit = etaVal2Bit( fabs(etaVal) );
60  int code = etaBit2Code(bit);
61  return sign*code;
62 }
63 
64 int etaKeyWG2Code(const CSCDetId& detId, uint16_t keyWG) {
65  signed int etaCode = 121;
66  if (detId.station()==1 && detId.ring()==2) {
67  if (keyWG < 49) etaCode = 121;
68  else if (keyWG <=57) etaCode = etaBit2Code(0);
69  else if (keyWG <=63) etaCode = etaBit2Code(1);
70  }
71  else if (detId.station()==1 && detId.ring()==3) {
72  if (keyWG <= 2) etaCode = etaBit2Code(2);
73  else if (keyWG <= 8) etaCode = etaBit2Code(3);
74  else if (keyWG <= 15) etaCode = etaBit2Code(4);
75  else if (keyWG <= 23) etaCode = etaBit2Code(5);
76  else if (keyWG <= 31) etaCode = etaBit2Code(6);
77  }
78  else if ( (detId.station()==2 || detId.station()==3) && detId.ring()==2) {
79  if (keyWG < 24) etaCode = 121;
80  else if (keyWG <= 29) etaCode = etaBit2Code(0);
81  else if (keyWG <= 43) etaCode = etaBit2Code(1);
82  else if (keyWG <= 49) etaCode = etaBit2Code(2);
83  else if (keyWG <= 56) etaCode = etaBit2Code(3);
84  else if (keyWG <= 63) etaCode = etaBit2Code(4);
85  }
86 
87  if (detId.endcap()==2) etaCode *= -1;
88  return etaCode;
89 }
90 
91 
92 int fixCscOffsetGeom(int offsetLoc) {
93  // fix for CSC feo dependance from GlobalTag
94 
95  // dump of CSC offsets for MC global tag
96  const std::vector<int> offCSC = { -154, -133, -17, -4, 4, 17, 133, 146, 154, 167,
97  283, 296, 304, 317, 433, 446, 454, 467,
98  583, 596, 604, 617, 733, 746, 754, 767, 883, 904};
99  auto gep = std::lower_bound(offCSC.begin(), offCSC.end(), offsetLoc);
100  int fixOff = (gep != offCSC.end()) ? *gep : *(gep-1);
101  if (gep != offCSC.begin() && std::abs(*(gep-1)-offsetLoc) < std::abs(fixOff-offsetLoc) ) fixOff= *(gep-1);
102  return fixOff;
103 }
104 
105 }
106 
107 
108 AngleConverter::AngleConverter(): _geom_cache_id(0ULL) { }
114 void AngleConverter::checkAndUpdateGeometry(const edm::EventSetup& es, unsigned int phiBins) {
116  unsigned long long geomid = geom.cacheIdentifier();
117  if( _geom_cache_id != geomid ) {
118  geom.get(_georpc);
119  geom.get(_geocsc);
120  geom.get(_geodt);
121  _geom_cache_id = geomid;
122  }
123 
124  nPhiBins = phiBins;
125 
126 }
129 int AngleConverter::getProcessorPhi(unsigned int iProcessor, l1t::tftype part, const L1MuDTChambPhDigi &digi) const
130 {
131 
132  double hsPhiPitch = 2*M_PI/nPhiBins; // width of phi Pitch, related to halfStrip at CSC station 2
133  const int dummy = nPhiBins;
134  int processor= iProcessor+1; // FIXME: get from OMTF name when available
135  int posneg = (part==l1t::tftype::omtf_pos) ? 1 : -1; // FIXME: get from OMTF name
136 
137  int sector = digi.scNum()+1; //NOTE: there is a inconsistency in DT sector numb. Thus +1 needed to get detector numb.
138  int wheel = digi.whNum();
139  int station = digi.stNum();
140  int phiDT = digi.phi();
141 
142  if (posneg*2 != wheel) return dummy;
143  if (station > 3 ) return dummy;
144 
145  //FIXME: update the following two lines with proper method when Connections introduced
146  if (processor !=6 && !(sector >= processor*2-1 && sector <= processor*2+1) ) return dummy;
147  if (processor ==6 && !(sector >= 11 || sector==1) ) return dummy;
148 
149  // ichamber is consecutive chamber connected to processor, starting from 0 (overlaping one)
150  int ichamber = sector-1-2*(processor-1);
151  if (ichamber < 0) ichamber += 12;
152 
153  int offsetLoc = lround( ((ichamber-1)*M_PI/6+M_PI/12.)/hsPhiPitch );
154  double scale = 1./4096/hsPhiPitch;
155  int scale_coeff = lround(scale* pow(2,11));
156 // int phi = static_cast<int>(phiDT*scale) + offsetLoc;
157  int phi = floor(phiDT*scale_coeff/pow(2,11)) + offsetLoc;
158 
159  return phi;
160 }
163 int AngleConverter::getProcessorPhi(unsigned int iProcessor, l1t::tftype part, const CSCDetId & csc, const CSCCorrelatedLCTDigi &digi) const
164 {
165 
166  const double hsPhiPitch = 2*M_PI/nPhiBins;
167  const int dummy = nPhiBins;
168  int processor= iProcessor+1; // FIXME: get from OMTF name when available
169  int posneg = (part==l1t::tftype::omtf_pos) ? 1 : -1; // FIXME: get from OMTF name
170 
171 
172 
173  // filter out chambers not connected to OMTF board
174  // FIXME: temporary - use Connections or relay that filtering done before.
175  if (posneg != csc.zendcap()) return dummy;
176  if ( csc.ring() != 3 && !(csc.ring()==2 && (csc.station()==2 || csc.station()==3 || csc.station()==1)) ) return dummy;
177  if (processor !=6) {
178  if (csc.chamber() < (processor-1)*6 + 2) return dummy;
179  if (csc.chamber() > (processor-1)*6 + 8) return dummy;
180  } else {
181  if (csc.chamber() > 2 && csc.chamber() < 32) return dummy;
182  }
183 
184  //
185  // assign number 0..6, consecutive processor for a processor
186  //
187  //int ichamber = (csc.chamber()-2-6*(processor-1));
188  //if (ichamber < 0) ichamber += 36;
189 
190  //
191  // get offset for each chamber.
192  // FIXME: These parameters depends on processor and chamber only so may be precomputed and put in map
193  //
194  const CSCChamber* chamber = _geocsc->chamber(csc);
195  const CSCChamberSpecs* cspec = chamber->specs();
196  const CSCLayer* layer = chamber->layer(3);
197  int order = ( layer->centerOfStrip(2).phi() - layer->centerOfStrip(1).phi()> 0) ? 1 : -1;
198  double stripPhiPitch = cspec->stripPhiPitch();
199  double scale = fabs(stripPhiPitch/hsPhiPitch/2.); if ( fabs(scale-1.) < 0.0002) scale=1.;
200  double phi15deg = M_PI/3.*(processor-1)+M_PI/12.;
201  double phiHalfStrip0 = layer->centerOfStrip(10).phi() - order*9*stripPhiPitch - order*stripPhiPitch/4.;
202  if ( processor==6 || phiHalfStrip0<0) phiHalfStrip0 += 2*M_PI;
203  int offsetLoc = lround( (phiHalfStrip0-phi15deg)/hsPhiPitch );
204 
205  int halfStrip = digi.getStrip(); // returns halfStrip 0..159
206  //FIXME: to be checked (only important for ME1/3) keep more bits for offset, truncate at the end
207 
208  // a quick fix for towards geometry changes due to global tag.
209  // in case of MC tag fixOff shold be identical to offsetLoc
210  int fixOff = fixCscOffsetGeom(offsetLoc);
211 
212  int phi = fixOff + order*scale*halfStrip;
213 
214 // std::cout <<" hs: "<< halfStrip <<" offset: " << offsetLoc <<" oder*scale: "<< order*scale
215 // <<" phi: " <<phi<<" ("<<offsetLoc + order*scale*halfStrip<<")"<< std::endl;
216 
217  return phi;
218 }
219 
222 int AngleConverter::getProcessorPhi(unsigned int iProcessor, l1t::tftype part, const RPCDetId & rollId, const unsigned int &digi1, const unsigned int &digi2) const
223 {
224 
225  const double hsPhiPitch = 2*M_PI/nPhiBins;
226  const int dummy = nPhiBins;
227  int processor = iProcessor+1;
228  const RPCRoll* roll = _georpc->roll(rollId);
229  if (!roll) return dummy;
230 
231  double phi15deg = M_PI/3.*(processor-1)+M_PI/12.; // "0" is 15degree moved cyclicaly to each processor, note [0,2pi]
232  double stripPhi1 = (roll->toGlobal(roll->centreOfStrip((int)digi1))).phi(); // note [-pi,pi]
233  double stripPhi2 = (roll->toGlobal(roll->centreOfStrip((int)digi2))).phi(); // note [-pi,pi]
234 
235  // stripPhi from geometry is given in [-pi,pi] range.
236  // Keep like that for OMTFp1 [15-10deg,75deg] and OMTFp6 [-45-10deg,15deg].
237  // For OMTFp2..OMTFp5 move to [0,2pi] range
238  switch (processor) {
239  case 1: break;
240  case 6: {phi15deg -= 2*M_PI; break; }
241  default : { if (stripPhi1 < 0) stripPhi1 += 2*M_PI; if(stripPhi2 < 0 ) stripPhi2 += 2*M_PI; break; }
242  }
243 
244  // local angle in CSC halfStrip usnits
245  int halfStrip = lround ( ( (stripPhi1+stripPhi2)/2.-phi15deg)/hsPhiPitch );
246 
247  return halfStrip;
248 }
249 
250 int AngleConverter::getProcessorPhi(unsigned int iProcessor, l1t::tftype part, const RPCDetId & rollId, const unsigned int &digi) const
251 {
252 
253  const double hsPhiPitch = 2*M_PI/nPhiBins;
254  const int dummy = nPhiBins;
255  int processor = iProcessor+1;
256  const RPCRoll* roll = _georpc->roll(rollId);
257  if (!roll) return dummy;
258 
259  double phi15deg = M_PI/3.*(processor-1)+M_PI/12.; // "0" is 15degree moved cyclicaly to each processor, note [0,2pi]
260  double stripPhi = (roll->toGlobal(roll->centreOfStrip((int)digi))).phi(); // note [-pi,pi]
261 
262  // adjust [0,2pi] and [-pi,pi] to get deltaPhi difference properly
263  switch (processor) {
264  case 1: break;
265  case 6: {phi15deg -= 2*M_PI; break; }
266  default : {if (stripPhi < 0) stripPhi += 2*M_PI; break; }
267  }
268 
269  // local angle in CSC halfStrip usnits
270  int halfStrip = lround ( (stripPhi-phi15deg)/hsPhiPitch );
271 
272  return halfStrip;
273 }
276 int AngleConverter::getGlobalEta(unsigned int rawid,
277  const L1MuDTChambPhDigi &aDigi,
278  const L1MuDTChambThContainer *dtThDigis){
279 
280 
281  const DTChamberId baseid(aDigi.whNum(),aDigi.stNum(),aDigi.scNum()+1);
282 
283  // do not use this pointer for anything other than creating a trig geom
284  std::unique_ptr<DTChamber> chamb(const_cast<DTChamber*>(_geodt->chamber(baseid)));
285 
286  std::unique_ptr<DTTrigGeom> trig_geom( new DTTrigGeom(chamb.get(),false) );
287  chamb.release(); // release it here so no one gets funny ideas
288  // super layer one is the theta superlayer in a DT chamber
289  // station 4 does not have a theta super layer
290  // the BTI index from the theta trigger is an OR of some BTI outputs
291  // so, we choose the BTI that's in the middle of the group
292  // as the BTI that we get theta from
293  // TODO:::::>>> need to make sure this ordering doesn't flip under wheel sign
294  const int NBTI_theta = ( (baseid.station() != 4) ? trig_geom->nCell(2) : trig_geom->nCell(3) );
295 
296 // const int bti_group = findBTIgroup(aDigi,dtThDigis);
297 // const unsigned bti_actual = bti_group*NBTI_theta/7 + NBTI_theta/14 + 1;
298 // DTBtiId thetaBTI;
299 // if ( baseid.station() != 4 && bti_group != -1) {
300 // thetaBTI = DTBtiId(baseid,2,bti_actual);
301 // } else {
302 // // since this is phi oriented it'll give us theta in the middle
303 // // of the chamber
304 // thetaBTI = DTBtiId(baseid,3,1);
305 // }
306 // const GlobalPoint theta_gp = trig_geom->CMSPosition(thetaBTI);
307 // int iEta = theta_gp.eta()/2.61*240;
308 // return iEta;
309 
310  const L1MuDTChambThDigi *theta_segm = dtThDigis->chThetaSegm(aDigi.whNum(), aDigi.stNum(), aDigi.scNum(), aDigi.bxNum());
311  int bti_group = -1;
312  if (theta_segm) {
313  for(unsigned int i = 0; i < 7; ++i ) if(theta_segm->position(i) && bti_group<0) bti_group = i;
314  else if(theta_segm->position(i) && bti_group>-1) bti_group = 511;
315  }
316 
317  int iEta = 0;
318  if (bti_group == 511) iEta = 95;
319  else if ( bti_group == -1 && aDigi.stNum() == 1) iEta = 92;
320  else if ( bti_group == -1 && aDigi.stNum() == 2) iEta = 79;
321  else if ( bti_group == -1 && aDigi.stNum() == 3) iEta = 75;
322  else if (baseid.station() != 4 && bti_group >= 0) {
323 // bti_group = 6-bti_group;
324  unsigned bti_actual = bti_group*NBTI_theta/7 + NBTI_theta/14 + 1;
325  DTBtiId thetaBTI = DTBtiId(baseid,2,bti_actual);
326  GlobalPoint theta_gp = trig_geom->CMSPosition(thetaBTI);
327  iEta = etaVal2Code( fabs(theta_gp.eta()) );
328  }
329  int signEta = sgn(aDigi.whNum());
330  iEta *= signEta;
331  return iEta;
332 }
333 
336 int AngleConverter::getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTDigi &aDigi){
337 
341 
342 
343  // alot of this is transcription and consolidation of the CSC
344  // global phi calculation code
345  // this works directly with the geometry
346  // rather than using the old phi luts
347  const CSCDetId id(rawid);
348  // we should change this to weak_ptrs at some point
349  // requires introducing std::shared_ptrs to geometry
350  std::unique_ptr<const CSCChamber> chamb(_geocsc->chamber(id));
351  std::unique_ptr<const CSCLayerGeometry> layer_geom(
352  chamb->layer(CSCConstants::KEY_ALCT_LAYER)->geometry()
353  );
354  std::unique_ptr<const CSCLayer> layer(
355  chamb->layer(CSCConstants::KEY_ALCT_LAYER)
356  );
357 
358  const uint16_t halfstrip = aDigi.getStrip();
359  const uint16_t pattern = aDigi.getPattern();
360  const uint16_t keyWG = aDigi.getKeyWG();
361  //const unsigned maxStrips = layer_geom->numberOfStrips();
362 
363  // so we can extend this later
364  // assume TMB2007 half-strips only as baseline
365  double offset = 0.0;
366  switch(1) {
367  case 1:
368  offset = CSCPatternLUT::get2007Position(pattern);
369  }
370  const unsigned halfstrip_offs = unsigned(0.5 + halfstrip + offset);
371  const unsigned strip = halfstrip_offs/2 + 1; // geom starts from 1
372 
373  // the rough location of the hit at the ALCT key layer
374  // we will refine this using the half strip information
375  const LocalPoint coarse_lp =
376  layer_geom->stripWireGroupIntersection(strip,keyWG);
377  const GlobalPoint coarse_gp = layer->surface().toGlobal(coarse_lp);
378 
379  // the strip width/4.0 gives the offset of the half-strip
380  // center with respect to the strip center
381  const double hs_offset = layer_geom->stripPhiPitch()/4.0;
382 
383  // determine handedness of the chamber
384  const bool ccw = isCSCCounterClockwise(layer);
385  // we need to subtract the offset of even half strips and add the odd ones
386  const double phi_offset = ( ( halfstrip_offs%2 ? 1 : -1)*
387  ( ccw ? -hs_offset : hs_offset ) );
388 
389  // the global eta calculation uses the middle of the strip
390  // so no need to increment it
391  const GlobalPoint final_gp( GlobalPoint::Polar( coarse_gp.theta(),
392  (coarse_gp.phi().value() +
393  phi_offset),
394  coarse_gp.mag() ) );
395  // release ownership of the pointers
396  chamb.release();
397  layer_geom.release();
398  layer.release();
399 
400 // std::cout <<id<<" st: " << id.station()<< "ri: "<<id.ring()<<" eta: " << final_gp.eta()
401 // <<" etaCode_simple: " << etaVal2Code( final_gp.eta() )<< " KW: "<<keyWG <<" etaKeyWG2Code: "<<etaKeyWG2Code(id,keyWG)<< std::endl;
402 // int station = (id.endcap()==1) ? id.station() : -id.station();
403 // std::cout <<"ETA_CSC: " << station <<" "<<id.ring()<<" "<< final_gp.eta()<<" "<<keyWG <<" "<< etaKeyWG2Code(id,keyWG) << std::endl;
404 
405  return etaKeyWG2Code(id,keyWG);
406 
407 // return etaVal2Code( final_gp.eta() );
408 // int iEta = final_gp.eta()/2.61*240;
409 // return iEta;
410 }
413 int AngleConverter::getGlobalEta(unsigned int rawid, const unsigned int &strip){
414 
415  const RPCDetId id(rawid);
416  std::unique_ptr<const RPCRoll> roll(_georpc->roll(id));
417  const LocalPoint lp = roll->centreOfStrip((int)strip);
418  const GlobalPoint gp = roll->toGlobal(lp);
419  roll.release();
420 
421  return etaVal2Code(gp.eta());
422 // float iEta = gp.eta()/2.61*240;
423 // return iEta;
424 
425 }
428 bool AngleConverter::
429 isCSCCounterClockwise(const std::unique_ptr<const CSCLayer>& layer) const {
430  const int nStrips = layer->geometry()->numberOfStrips();
431  const double phi1 = layer->centerOfStrip(1).phi();
432  const double phiN = layer->centerOfStrip(nStrips).phi();
433  return ( (std::abs(phi1 - phiN) < M_PI && phi1 >= phiN) ||
434  (std::abs(phi1 - phiN) >= M_PI && phi1 < phiN) );
435 }
439  const L1MuDTChambThContainer *dtThDigis){
440 
441  int bti_group = -1;
442 
443  const L1MuDTChambThDigi *theta_segm = dtThDigis->chThetaSegm(aDigi.whNum(),
444  aDigi.stNum(),
445  aDigi.scNum(),
446  aDigi.bxNum());
447  if(!theta_segm) return bti_group;
448 
449  for(unsigned int i = 0; i < 7; ++i ){
450  if(theta_segm->position(i) && bti_group<0) bti_group = i;
454  else if(theta_segm->position(i) && bti_group>-1) return -1;
455  }
456 
457  return bti_group;
458 }
int chamber() const
Definition: CSCDetId.h:68
int getStrip() const
return the key halfstrip from 0,159
unsigned long long cacheIdentifier() const
LocalPoint centreOfStrip(int strip) const
Definition: RPCRoll.cc:52
const DTChamber * chamber(const DTChamberId &id) const
Return a DTChamber given its id.
Definition: DTGeometry.cc:117
float sgn(float val)
Definition: FWPFMaths.cc:9
GlobalPoint toGlobal(const Local2DPoint &lp) const
Conversion to the global R.F. from the R.F. of the GeomDet.
Definition: GeomDet.h:54
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
int getGlobalEta(unsigned int rawid, const L1MuDTChambPhDigi &aDigi, const L1MuDTChambThContainer *dtThDigis)
Convert local eta coordinate to global digital microGMT scale.
unsigned long long _geom_cache_id
int position(const int i) const
Geom::Theta< T > theta() const
Definition: PV3DBase.h:75
int endcap() const
Definition: CSCDetId.h:93
int getProcessorPhi(unsigned int iProcessor, l1t::tftype part, const L1MuDTChambPhDigi &digi) const
float stripPhiPitch() const
T mag() const
Definition: PV3DBase.h:67
ProductT const & get(ESGetToken< ProductT, DepRecordT > const &iToken) const
const CSCChamberSpecs * specs() const
Definition: CSCChamber.h:42
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const CSCLayer * layer(CSCDetId id) const
Return the layer corresponding to the given id.
Definition: CSCChamber.cc:39
const int findBTIgroup(const L1MuDTChambPhDigi &aDigi, const L1MuDTChambThContainer *dtThDigis)
Find BTI group.
bool isCSCCounterClockwise(const std::unique_ptr< const CSCLayer > &layer) const
Check orientation of strips in given CSC chamber.
Definition: L1Track.h:19
#define M_PI
unsigned int nPhiBins
Number of phi bins along 2Pi.
int ring() const
Definition: CSCDetId.h:75
short int zendcap() const
Definition: CSCDetId.h:100
GlobalPoint centerOfStrip(int strip) const
Definition: CSCLayer.cc:4
static double get2007Position(int pattern)
part
Definition: HCALResponse.h:20
const CSCChamber * chamber(CSCDetId id) const
Return the chamber corresponding to given DetId.
Definition: CSCGeometry.cc:133
L1MuDTChambThDigi const * chThetaSegm(int wheel, int stat, int sect, int bx) const
T eta() const
Definition: PV3DBase.h:76
int getPattern() const
return pattern
T get() const
Definition: EventSetup.h:71
edm::ESHandle< CSCGeometry > _geocsc
void checkAndUpdateGeometry(const edm::EventSetup &, unsigned int)
Update the Geometry with current Event Setup.
int station() const
Definition: CSCDetId.h:86
edm::ESHandle< RPCGeometry > _georpc
long double T
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
int getKeyWG() const
return the key wire group. counts from 0.
const RPCRoll * roll(RPCDetId id) const
Return a roll given its id.
Definition: RPCGeometry.cc:75
edm::ESHandle< DTGeometry > _geodt