CMS 3D CMS Logo

L1GctMet.cc

Go to the documentation of this file.
00001 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctMet.h"
00002 
00003 #include <math.h>
00004 
00005 L1GctMet::L1GctMet(const unsigned ex, const unsigned ey, const L1GctMet::metAlgoType algo) :
00006   m_exComponent(ex),
00007   m_eyComponent(ey),
00008   m_algoType(algo),
00009   m_bitShift(0)
00010 { }
00011 
00012 L1GctMet::L1GctMet(const etComponentType& ex, const etComponentType& ey, const metAlgoType algo) :
00013   m_exComponent(ex),
00014   m_eyComponent(ey),
00015   m_algoType(algo),
00016   m_bitShift(0)
00017 { }
00018 
00019 L1GctMet::~L1GctMet() {}
00020 
00021 // the Etmiss algorithm - external entry point
00022 L1GctMet::etmiss_vec
00023 L1GctMet::metVector () const
00024 {
00025   etmiss_vec      result;
00026   etmiss_internal algoResult;
00027   switch (m_algoType)
00028     {
00029     case cordicTranslate:
00030       algoResult = cordicTranslateAlgo (m_exComponent.value(), m_eyComponent.value());
00031       break;
00032 
00033     case oldGct:
00034       algoResult = oldGctAlgo          (m_exComponent.value(), m_eyComponent.value());
00035       break;
00036 
00037     case floatingPoint:
00038       algoResult = floatingPointAlgo   (m_exComponent.value(), m_eyComponent.value());
00039       break;
00040 
00041     default:
00042       break;
00043     }
00044 
00045   // Discard the least significant bits of the result
00046   // NB One extra LSB is added during the conversion of strip sums
00047   // to x and y components (in the JetLeafCard).
00048   // The parameter m_bitShift allows us to discard additional LSB
00049   // in order to change the output scale. 
00050   result.mag.setValue(algoResult.mag>>(1+m_bitShift));
00051   result.phi.setValue(algoResult.phi);
00052 
00053   result.mag.setOverFlow( result.mag.overFlow() || m_exComponent.overFlow() || m_eyComponent.overFlow() );
00054 
00055   return result;
00056 
00057 }
00058 
00059 void L1GctMet::setExComponent(const unsigned ex) {
00060   etComponentType temp(ex);
00061   setExComponent(temp);
00062 }
00063 
00064 void L1GctMet::setEyComponent(const unsigned ey) {
00065   etComponentType temp(ey);
00066   setEyComponent(temp);
00067 }
00068 
00069 // private member functions - the different algorithms:
00070 
00071 L1GctMet::etmiss_internal
00072 L1GctMet::cordicTranslateAlgo (const int ex, const int ey) const
00073 {
00074   //---------------------------------------------------------------------------------
00075   //
00076   // This is an implementation of the CORDIC algorithm (COordinate Rotation for DIgital Computers)
00077   //
00078   // Starting from an initial two-component vector ex, ey, we perform successively smaller rotations
00079   // to transform the y component to zero. At the end of the procedure, the x component is the magnitude
00080   // of the original vector, scaled by a known constant factor. The azimuth angle phi is the sum of the
00081   // rotations applied.
00082   //
00083   // The algorithm can be used in a number of different variants for calculation of trigonometric
00084   // and hyperbolic functions as well as exponentials, logarithms and square roots. This variant
00085   // is called the "vector translation" mode in the Xilinx documentation.
00086   //
00087   // Original references:
00088   // Volder, J., "The CORDIC Trigonometric Computing Technique" IRE Trans. Electronic Computing, Vol.
00089   // EC-8, Sept. 1959, pp330-334
00090   // Walther, J.S., "A Unified Algorithm for Elementary Functions," Spring Joint computer conf., 1971,
00091   // proc., pp379-385
00092   //
00093   // Other information sources: https://www.xilinx.com/support/documentation/ip_documentation/cordic.pdf;
00094   // https://www.fpga-guru.com/files/crdcsrvy.pdf; and https://en.wikipedia.org/wiki/CORDIC
00095   //
00096   //---------------------------------------------------------------------------------
00097 
00098   etmiss_internal result;
00099 
00100   static const int n_iterations = 6;
00101   // The angle units here are 1/32 of a 5 degree bin.
00102   // So a 90 degree rotation is 32*18=576 or 240 hex.
00103   const int cordic_angles[n_iterations] = { 0x120, 0x0AA, 0x05A, 0x02E, 0x017, 0x00B };
00104   const int cordic_starting_angle_090 = 0x240;
00105   const int cordic_starting_angle_270 = 0x6C0;
00106   const int cordic_angle_360 = 0x900;
00107 
00108   const int cordic_scale_factor = 0x26E; // decimal 622
00109 
00110   int  x, y;
00111   int dx,dy;
00112   int  z;
00113 
00114   if (ey>=0) {
00115     x =  ey;
00116     y = -ex;
00117     z = cordic_starting_angle_090;
00118   } else {
00119     x = -ey;
00120     y =  ex;
00121     z = cordic_starting_angle_270;
00122   }
00123 
00124   for (int i=0; i<n_iterations; i++) {
00125     dx = cordicShiftAndRoundBits (y,i);
00126     dy = cordicShiftAndRoundBits (x,i);
00127     if (y>=0) {
00128       x = x + dx;
00129       y = y - dy;
00130       z = z + cordic_angles[i];
00131     } else {
00132       x = x - dx;
00133       y = y + dy;
00134       z = z - cordic_angles[i];
00135     }
00136   }
00137 
00138   int scaled_magnitude = x * cordic_scale_factor;
00139   int adjusted_angle   = ( (z < 0) ? (z + cordic_angle_360) : z ) % cordic_angle_360;
00140   result.mag = scaled_magnitude >> 10;
00141   result.phi = adjusted_angle   >> 5;
00142   return result;
00143 }
00144 
00145 int L1GctMet::cordicShiftAndRoundBits (const int e, const unsigned nBits) const
00146 {
00147   int r;
00148   if (nBits==0) {
00149     r = e;
00150   } else {
00151     r = (((e>>(nBits-1)) + 1)>>1);
00152   }
00153   return r;
00154 }
00155 
00156 
00157 L1GctMet::etmiss_internal
00158 L1GctMet::oldGctAlgo (const int ex, const int ey) const
00159 {
00160   //---------------------------------------------------------------------------------
00161   //
00162   // Calculates magnitude and direction of missing Et, given measured Ex and Ey.
00163   //
00164   // The algorithm used is suitable for implementation in hardware, using integer
00165   // multiplication, addition and comparison and bit shifting operations.
00166   //
00167   // Proceed in two stages. The first stage gives a result that lies between
00168   // 92% and 100% of the true Et, with the direction measured in 45 degree bins.
00169   // The final precision depends on the number of factors used in corrFact.
00170   // The present version with eleven factors gives a precision of 1% on Et, and
00171   // finds the direction to the nearest 5 degrees.
00172   //
00173   //---------------------------------------------------------------------------------
00174   etmiss_internal result;
00175 
00176   unsigned eneCoarse, phiCoarse;
00177   unsigned eneCorect, phiCorect;
00178 
00179   const unsigned root2fact = 181;
00180   const unsigned corrFact[11] = {24, 39, 51, 60, 69, 77, 83, 89, 95, 101, 106};
00181   const unsigned corrDphi[11] = { 0,  1,  1,  2,  2,  3,  3,  3,  3,   4,   4};
00182 
00183   std::vector<bool> s(3);
00184   unsigned Mx, My, Mw;
00185 
00186   unsigned Dx, Dy;
00187   unsigned eFact;
00188 
00189   unsigned b,phibin;
00190   bool midphi=false;
00191 
00192   // Here's the coarse calculation, with just one multiply operation
00193   //
00194   My = static_cast<unsigned>(abs(ey));
00195   Mx = static_cast<unsigned>(abs(ex));
00196   Mw = (((Mx+My)*root2fact)+0x80)>>8;
00197 
00198   s.at(0) = (ey<0);
00199   s.at(1) = (ex<0);
00200   s.at(2) = (My>Mx);
00201 
00202   phibin = 0; b = 0;
00203   for (int i=0; i<3; i++) {
00204     if (s.at(i)) { b=1-b;} phibin = 2*phibin + b;
00205   }
00206 
00207   eneCoarse = std::max(std::max(Mx, My), Mw);
00208   phiCoarse = phibin*9;
00209 
00210   // For the fine calculation we multiply both input components
00211   // by all the factors in the corrFact list in order to find
00212   // the required corrections to the energy and angle
00213   //
00214   for (eFact=0; eFact<10; eFact++) {
00215     Dx = (Mx*corrFact[eFact])>>8;
00216     Dy = (My*corrFact[eFact])>>8;
00217     if         ((Dx>=My) || (Dy>=Mx))         {midphi=false; break;}
00218     if ((Mx+Dx)>=(My-Dy) && (My+Dy)>=(Mx-Dx)) {midphi=true;  break;}
00219   }
00220   eneCorect = (eneCoarse*(128+eFact))>>7;
00221   if (midphi ^ (b==1)) {
00222     phiCorect = phiCoarse + 8 - corrDphi[eFact];
00223   } else {
00224     phiCorect = phiCoarse + corrDphi[eFact];
00225   }
00226 
00227   // Store the result of the calculation
00228   //
00229   result.mag = eneCorect;
00230   result.phi = phiCorect;
00231 
00232   return result;
00233 }
00234 
00235 L1GctMet::etmiss_internal
00236 L1GctMet::floatingPointAlgo (const int ex, const int ey) const
00237 {
00238 
00239   etmiss_internal result;
00240 
00241   double fx = static_cast<double>(ex);
00242   double fy = static_cast<double>(ey);
00243   double fmag = sqrt(fx*fx + fy*fy);
00244   double fphi = 36.*atan2(fy, fx)/M_PI;
00245 
00246   result.mag = static_cast<unsigned>(fmag);
00247   if (fphi>=0) {
00248     result.phi = static_cast<unsigned>(fphi);
00249   } else {
00250     result.phi = static_cast<unsigned>(fphi+72.);
00251   }
00252 
00253   return result;
00254 
00255 }
00256 

Generated on Tue Jun 9 17:40:11 2009 for CMSSW by  doxygen 1.5.4