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