CMS 3D CMS Logo

L1GctMet.cc
Go to the documentation of this file.
2 
4 
5 #include <cmath>
6 
7 L1GctMet::L1GctMet(const unsigned ex, const unsigned ey, const L1GctMet::metAlgoType algo)
8  : m_exComponent(ex), m_eyComponent(ey), m_algoType(algo), m_bitShift(0), m_htMissLut(new L1GctHtMissLut()) {}
9 
11  : m_exComponent(ex), m_eyComponent(ey), m_algoType(algo), m_bitShift(0), m_htMissLut(new L1GctHtMissLut()) {}
12 
14 
15 // the Etmiss algorithm - external entry point
18  etmiss_internal algoResult;
19  switch (m_algoType) {
20  case cordicTranslate:
21  algoResult = cordicTranslateAlgo(
23  break;
24 
25  case useHtMissLut:
26  algoResult = useHtMissLutAlgo(
28  break;
29 
30  case oldGct:
32  break;
33 
34  case floatingPoint:
36  break;
37 
38  default:
39  algoResult.mag = 0;
40  algoResult.phi = 0;
41  break;
42  }
43 
44  // The parameter m_bitShift allows us to discard additional LSB
45  // in order to change the output scale.
46  result.mag.setValue(algoResult.mag >> (m_bitShift));
47  result.phi.setValue(algoResult.phi);
48 
49  result.mag.setOverFlow(result.mag.overFlow() || inputOverFlow());
50 
51  return result;
52 }
53 
54 void L1GctMet::setExComponent(const unsigned ex) {
57 }
58 
59 void L1GctMet::setEyComponent(const unsigned ey) {
62 }
63 
64 // private member functions - the different algorithms:
65 
66 L1GctMet::etmiss_internal L1GctMet::cordicTranslateAlgo(const int ex, const int ey, const bool of) const {
67  //---------------------------------------------------------------------------------
68  //
69  // This is an implementation of the CORDIC algorithm (COordinate Rotation for DIgital Computers)
70  //
71  // Starting from an initial two-component vector ex, ey, we perform successively smaller rotations
72  // to transform the y component to zero. At the end of the procedure, the x component is the magnitude
73  // of the original vector, scaled by a known constant factor. The azimuth angle phi is the sum of the
74  // rotations applied.
75  //
76  // The algorithm can be used in a number of different variants for calculation of trigonometric
77  // and hyperbolic functions as well as exponentials, logarithms and square roots. This variant
78  // is called the "vector translation" mode in the Xilinx documentation.
79  //
80  // Original references:
81  // Volder, J., "The CORDIC Trigonometric Computing Technique" IRE Trans. Electronic Computing, Vol.
82  // EC-8, Sept. 1959, pp330-334
83  // Walther, J.S., "A Unified Algorithm for Elementary Functions," Spring Joint computer conf., 1971,
84  // proc., pp379-385
85  //
86  // Other information sources: http://www.xilinx.com/support/documentation/ip_documentation/cordic.pdf;
87  // http://www.fpga-guru.com/files/crdcsrvy.pdf; and http://en.wikipedia.org/wiki/CORDIC
88  //
89  //---------------------------------------------------------------------------------
90 
92 
93  static const int of_val = 0x1FFF; // set components to 8191 (decimal) if there's an overflow on the input
94 
95  static const int n_iterations = 6;
96  // The angle units here are 1/32 of a 5 degree bin.
97  // So a 90 degree rotation is 32*18=576 or 240 hex.
98  const int cordic_angles[n_iterations] = {0x120, 0x0AA, 0x05A, 0x02E, 0x017, 0x00B};
99  const int cordic_starting_angle_090 = 0x240;
100  const int cordic_starting_angle_270 = 0x6C0;
101  const int cordic_angle_360 = 0x900;
102 
103  const int cordic_scale_factor = 0x26E; // decimal 622
104 
105  int x, y;
106  int dx, dy;
107  int z;
108 
109  if (of) {
110  x = of_val;
111  y = -of_val;
112  z = cordic_starting_angle_090;
113  } else {
114  if (ey >= 0) {
115  x = ey;
116  y = -ex;
117  z = cordic_starting_angle_090;
118  } else {
119  x = -ey;
120  y = ex;
121  z = cordic_starting_angle_270;
122  }
123  }
124 
125  for (int i = 0; i < n_iterations; i++) {
128  if (y >= 0) {
129  x = x + dx;
130  y = y - dy;
131  z = z + cordic_angles[i];
132  } else {
133  x = x - dx;
134  y = y + dy;
135  z = z - cordic_angles[i];
136  }
137  }
138 
139  int scaled_magnitude = x * cordic_scale_factor;
140  int adjusted_angle = ((z < 0) ? (z + cordic_angle_360) : z) % cordic_angle_360;
141  result.mag = scaled_magnitude >> 10;
142  result.phi = adjusted_angle >> 5;
143  if (result.mag > (unsigned)of_val)
144  result.mag = (unsigned)of_val;
145  return result;
146 }
147 
148 int L1GctMet::cordicShiftAndRoundBits(const int e, const unsigned nBits) const {
149  int r;
150  if (nBits == 0) {
151  r = e;
152  } else {
153  r = (((e >> (nBits - 1)) + 1) >> 1);
154  }
155  return r;
156 }
157 
158 L1GctMet::etmiss_internal L1GctMet::useHtMissLutAlgo(const int ex, const int ey, const bool of) const {
159  // The firmware discards the LSB of the input values, before forming
160  // the address for the LUT. We do the same here.
161  static const int maxComponent = 1 << L1GctHtMissLut::kHxOrHyMissComponentNBits;
162  static const int componentMask = maxComponent - 1;
163  static const int maxPosComponent = componentMask >> 1;
164 
165  static const int maxInput = 1 << (L1GctHtMissLut::kHxOrHyMissComponentNBits + kExOrEyMissComponentShift - 1);
166 
167  static const unsigned resultMagMask = (1 << L1GctHtMissLut::kHtMissMagnitudeNBits) - 1;
168  static const unsigned resultPhiMask = (1 << L1GctHtMissLut::kHtMissAngleNBits) - 1;
169 
171 
172  if (m_htMissLut == nullptr) {
173  result.mag = 0;
174  result.phi = 0;
175 
176  } else {
177  // Extract the bit fields of the input components to be used for the LUT address
178  int hxCompBits = (ex >> kExOrEyMissComponentShift) & componentMask;
179  int hyCompBits = (ey >> kExOrEyMissComponentShift) & componentMask;
180 
181  if (of || (abs(ex) >= maxInput) || (abs(ey) >= maxInput)) {
182  hxCompBits = maxPosComponent;
183  hyCompBits = maxPosComponent;
184  }
185 
186  // Perform the table lookup to get the missing Ht magnitude and phi
187  uint16_t lutAddress = static_cast<uint16_t>((hxCompBits << L1GctHtMissLut::kHxOrHyMissComponentNBits) | hyCompBits);
188 
189  uint16_t lutData = m_htMissLut->lutValue(lutAddress);
190 
191  result.mag = static_cast<unsigned>(lutData >> L1GctHtMissLut::kHtMissAngleNBits) & resultMagMask;
192  result.phi = static_cast<unsigned>(lutData) & resultPhiMask;
193  }
194 
195  return result;
196 }
197 
198 L1GctMet::etmiss_internal L1GctMet::oldGctAlgo(const int ex, const int ey) const {
199  //---------------------------------------------------------------------------------
200  //
201  // Calculates magnitude and direction of missing Et, given measured Ex and Ey.
202  //
203  // The algorithm used is suitable for implementation in hardware, using integer
204  // multiplication, addition and comparison and bit shifting operations.
205  //
206  // Proceed in two stages. The first stage gives a result that lies between
207  // 92% and 100% of the true Et, with the direction measured in 45 degree bins.
208  // The final precision depends on the number of factors used in corrFact.
209  // The present version with eleven factors gives a precision of 1% on Et, and
210  // finds the direction to the nearest 5 degrees.
211  //
212  //---------------------------------------------------------------------------------
214 
215  unsigned eneCoarse, phiCoarse;
216  unsigned eneCorect, phiCorect;
217 
218  const unsigned root2fact = 181;
219  const unsigned corrFact[11] = {24, 39, 51, 60, 69, 77, 83, 89, 95, 101, 106};
220  const unsigned corrDphi[11] = {0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4};
221 
222  std::vector<bool> s(3);
223  unsigned Mx, My, Mw;
224 
225  unsigned Dx, Dy;
226  unsigned eFact;
227 
228  unsigned b, phibin;
229  bool midphi = false;
230 
231  // Here's the coarse calculation, with just one multiply operation
232  //
233  My = static_cast<unsigned>(abs(ey));
234  Mx = static_cast<unsigned>(abs(ex));
235  Mw = (((Mx + My) * root2fact) + 0x80) >> 8;
236 
237  s.at(0) = (ey < 0);
238  s.at(1) = (ex < 0);
239  s.at(2) = (My > Mx);
240 
241  phibin = 0;
242  b = 0;
243  for (int i = 0; i < 3; i++) {
244  if (s.at(i)) {
245  b = 1 - b;
246  }
247  phibin = 2 * phibin + b;
248  }
249 
250  eneCoarse = std::max(std::max(Mx, My), Mw);
251  phiCoarse = phibin * 9;
252 
253  // For the fine calculation we multiply both input components
254  // by all the factors in the corrFact list in order to find
255  // the required corrections to the energy and angle
256  //
257  for (eFact = 0; eFact < 10; eFact++) {
258  Dx = (Mx * corrFact[eFact]) >> 8;
259  Dy = (My * corrFact[eFact]) >> 8;
260  if ((Dx >= My) || (Dy >= Mx)) {
261  midphi = false;
262  break;
263  }
264  if ((Mx + Dx) >= (My - Dy) && (My + Dy) >= (Mx - Dx)) {
265  midphi = true;
266  break;
267  }
268  }
269  eneCorect = (eneCoarse * (128 + eFact)) >> 7;
270  if (midphi ^ (b == 1)) {
271  phiCorect = phiCoarse + 8 - corrDphi[eFact];
272  } else {
273  phiCorect = phiCoarse + corrDphi[eFact];
274  }
275 
276  // Store the result of the calculation
277  //
278  result.mag = eneCorect;
279  result.phi = phiCorect;
280 
281  return result;
282 }
283 
284 L1GctMet::etmiss_internal L1GctMet::floatingPointAlgo(const int ex, const int ey) const {
286 
287  double fx = static_cast<double>(ex);
288  double fy = static_cast<double>(ey);
289  double fmag = sqrt(fx * fx + fy * fy);
290  double fphi = 36. * atan2(fy, fx) / M_PI;
291 
292  result.mag = static_cast<unsigned>(fmag);
293  if (fphi >= 0) {
294  result.phi = static_cast<unsigned>(fphi);
295  } else {
296  result.phi = static_cast<unsigned>(fphi + 72.);
297  }
298 
299  return result;
300 }
301 
303 
304 void L1GctMet::setEtComponentLsb(const double lsb) {
305  m_htMissLut->setExEyLsb(lsb * static_cast<double>(1 << kExOrEyMissComponentShift));
306 }
307 
308 const L1CaloEtScale* L1GctMet::etScale() const { return m_htMissLut->etScale(); }
309 
310 const double L1GctMet::componentLsb() const { return m_htMissLut->componentLsb(); }
311 
314 const bool L1GctMet::inputOverFlow() const {
316 
317  if (m_algoType == useHtMissLut) {
318  static const int maxComponentInput =
320 
321  // Emulate the (symmetric) overflow condition used in the firmware
322  result |= (m_exComponent.value() > maxComponentInput) || (m_exComponent.value() < -maxComponentInput) ||
323  (m_eyComponent.value() > maxComponentInput) || (m_eyComponent.value() < -maxComponentInput);
324  }
325 
326  return result;
327 }
etmiss_internal floatingPointAlgo(const int ex, const int ey) const
Definition: L1GctMet.cc:284
etmiss_vec metVector() const
Definition: L1GctMet.cc:16
etComponentType m_exComponent
Definition: L1GctMet.h:87
void setEtScale(const L1CaloEtScale *const fn)
Set the functions.
L1GctMet(const unsigned ex=0, const unsigned ey=0, const metAlgoType algo=cordicTranslate)
Definition: L1GctMet.cc:7
~L1GctMet()
Definition: L1GctMet.cc:13
static constexpr int kHxOrHyMissComponentNBits
static constexpr int kHtMissMagnitudeNBits
uint16_t lutValue(const uint16_t lutAddress) const
Access the look-up table contents for a given Address.
Definition: L1GctLut.h:102
const double componentLsb() const
Definition: L1GctMet.cc:310
int value() const
access value as signed int
LUT for conversion of Ht components x and y to magnitude and angle.
const bool inputOverFlow() const
Definition: L1GctMet.cc:314
void setEyComponent(const unsigned ey)
Definition: L1GctMet.cc:59
void setExComponent(const unsigned ex)
Definition: L1GctMet.cc:54
etmiss_internal cordicTranslateAlgo(const int ex, const int ey, const bool of) const
Definition: L1GctMet.cc:66
void setEtScale(const L1CaloEtScale *const fn)
Definition: L1GctMet.cc:302
T sqrt(T t)
Definition: SSEVec.h:23
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
void setExEyLsb(const double lsb)
#define M_PI
etmiss_internal oldGctAlgo(const int ex, const int ey) const
Definition: L1GctMet.cc:198
L1GctHtMissLut * m_htMissLut
Definition: L1GctMet.h:92
etComponentType m_eyComponent
Definition: L1GctMet.h:88
etmiss_internal useHtMissLutAlgo(const int ex, const int ey, const bool of) const
Definition: L1GctMet.cc:158
const L1CaloEtScale * etScale() const
Definition: L1GctMet.cc:308
static constexpr int kHtMissAngleNBits
double b
Definition: hdecay.h:120
metAlgoType
Definition: L1GctMet.h:22
const L1CaloEtScale * etScale() const
Return the Lut functions and parameters.
bool overFlow() const
access overflow
int cordicShiftAndRoundBits(const int e, const unsigned nBits) const
Definition: L1GctMet.cc:148
const double componentLsb() const
metAlgoType m_algoType
Definition: L1GctMet.h:89
unsigned short m_bitShift
Definition: L1GctMet.h:90
void setEtComponentLsb(const double lsb)
Definition: L1GctMet.cc:304