CMS 3D CMS Logo

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