CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/L1Trigger/GlobalCaloTrigger/src/L1GctMet.cc

Go to the documentation of this file.
00001 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctMet.h"
00002 
00003 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctHtMissLut.h"
00004 
00005 #include <math.h>
00006 
00007 L1GctMet::L1GctMet(const unsigned ex, const unsigned ey, const L1GctMet::metAlgoType algo) :
00008   m_exComponent(ex),
00009   m_eyComponent(ey),
00010   m_algoType(algo),
00011   m_bitShift(0),
00012   m_htMissLut(new L1GctHtMissLut())
00013 { }
00014 
00015 L1GctMet::L1GctMet(const etComponentType& ex, const etComponentType& ey, const metAlgoType algo) :
00016   m_exComponent(ex),
00017   m_eyComponent(ey),
00018   m_algoType(algo),
00019   m_bitShift(0),
00020   m_htMissLut(new L1GctHtMissLut())
00021 { }
00022 
00023 L1GctMet::~L1GctMet() {}
00024 
00025 // the Etmiss algorithm - external entry point
00026 L1GctMet::etmiss_vec
00027 L1GctMet::metVector () const
00028 {
00029   etmiss_vec      result;
00030   etmiss_internal algoResult;
00031   switch (m_algoType)
00032     {
00033     case cordicTranslate:
00034       algoResult = cordicTranslateAlgo (m_exComponent.value(), m_eyComponent.value(), (m_exComponent.overFlow() || m_eyComponent.overFlow()) );
00035       break;
00036 
00037     case useHtMissLut:
00038       algoResult = useHtMissLutAlgo    (m_exComponent.value(), m_eyComponent.value(), (m_exComponent.overFlow() || m_eyComponent.overFlow()) );
00039       break;
00040 
00041     case oldGct:
00042       algoResult = oldGctAlgo          (m_exComponent.value(), m_eyComponent.value());
00043       break;
00044 
00045     case floatingPoint:
00046       algoResult = floatingPointAlgo   (m_exComponent.value(), m_eyComponent.value());
00047       break;
00048 
00049     default:
00050       algoResult.mag = 0;
00051       algoResult.phi = 0;
00052       break;
00053     }
00054 
00055   // The parameter m_bitShift allows us to discard additional LSB
00056   // in order to change the output scale. 
00057   result.mag.setValue(algoResult.mag>>(m_bitShift));
00058   result.phi.setValue(algoResult.phi);
00059 
00060   result.mag.setOverFlow( result.mag.overFlow() || inputOverFlow() );
00061 
00062   return result;
00063 
00064 }
00065 
00066 void L1GctMet::setExComponent(const unsigned ex) {
00067   etComponentType temp(ex);
00068   setExComponent(temp);
00069 }
00070 
00071 void L1GctMet::setEyComponent(const unsigned ey) {
00072   etComponentType temp(ey);
00073   setEyComponent(temp);
00074 }
00075 
00076 // private member functions - the different algorithms:
00077 
00078 L1GctMet::etmiss_internal
00079 L1GctMet::cordicTranslateAlgo (const int ex, const int ey, const bool of) const
00080 {
00081   //---------------------------------------------------------------------------------
00082   //
00083   // This is an implementation of the CORDIC algorithm (COordinate Rotation for DIgital Computers)
00084   //
00085   // Starting from an initial two-component vector ex, ey, we perform successively smaller rotations
00086   // to transform the y component to zero. At the end of the procedure, the x component is the magnitude
00087   // of the original vector, scaled by a known constant factor. The azimuth angle phi is the sum of the
00088   // rotations applied.
00089   //
00090   // The algorithm can be used in a number of different variants for calculation of trigonometric
00091   // and hyperbolic functions as well as exponentials, logarithms and square roots. This variant
00092   // is called the "vector translation" mode in the Xilinx documentation.
00093   //
00094   // Original references:
00095   // Volder, J., "The CORDIC Trigonometric Computing Technique" IRE Trans. Electronic Computing, Vol.
00096   // EC-8, Sept. 1959, pp330-334
00097   // Walther, J.S., "A Unified Algorithm for Elementary Functions," Spring Joint computer conf., 1971,
00098   // proc., pp379-385
00099   //
00100   // Other information sources: http://www.xilinx.com/support/documentation/ip_documentation/cordic.pdf;
00101   // http://www.fpga-guru.com/files/crdcsrvy.pdf; and http://en.wikipedia.org/wiki/CORDIC
00102   //
00103   //---------------------------------------------------------------------------------
00104 
00105   etmiss_internal result;
00106 
00107   static const int of_val = 0x1FFF; // set components to 8191 (decimal) if there's an overflow on the input
00108 
00109   static const int n_iterations = 6;
00110   // The angle units here are 1/32 of a 5 degree bin.
00111   // So a 90 degree rotation is 32*18=576 or 240 hex.
00112   const int cordic_angles[n_iterations] = { 0x120, 0x0AA, 0x05A, 0x02E, 0x017, 0x00B };
00113   const int cordic_starting_angle_090 = 0x240;
00114   const int cordic_starting_angle_270 = 0x6C0;
00115   const int cordic_angle_360 = 0x900;
00116 
00117   const int cordic_scale_factor = 0x26E; // decimal 622
00118 
00119   int  x, y;
00120   int dx,dy;
00121   int  z;
00122 
00123   if (of) {
00124     x =  of_val;
00125     y = -of_val;
00126     z = cordic_starting_angle_090;
00127   } else {
00128     if (ey>=0) {
00129       x =  ey;
00130       y = -ex;
00131       z = cordic_starting_angle_090;
00132     } else {
00133       x = -ey;
00134       y =  ex;
00135       z = cordic_starting_angle_270;
00136     }
00137   }
00138 
00139   for (int i=0; i<n_iterations; i++) {
00140     dx = cordicShiftAndRoundBits (y,i);
00141     dy = cordicShiftAndRoundBits (x,i);
00142     if (y>=0) {
00143       x = x + dx;
00144       y = y - dy;
00145       z = z + cordic_angles[i];
00146     } else {
00147       x = x - dx;
00148       y = y + dy;
00149       z = z - cordic_angles[i];
00150     }
00151   }
00152 
00153   int scaled_magnitude = x * cordic_scale_factor;
00154   int adjusted_angle   = ( (z < 0) ? (z + cordic_angle_360) : z ) % cordic_angle_360;
00155   result.mag = scaled_magnitude >> 10;
00156   result.phi = adjusted_angle   >> 5;
00157   if (result.mag > (unsigned) of_val) result.mag = (unsigned) of_val;
00158   return result;
00159 }
00160 
00161 int L1GctMet::cordicShiftAndRoundBits (const int e, const unsigned nBits) const
00162 {
00163   int r;
00164   if (nBits==0) {
00165     r = e;
00166   } else {
00167     r = (((e>>(nBits-1)) + 1)>>1);
00168   }
00169   return r;
00170 }
00171 
00172 
00173 L1GctMet::etmiss_internal
00174 L1GctMet::useHtMissLutAlgo (const int ex, const int ey, const bool of) const
00175 {
00176   // The firmware discards the LSB of the input values, before forming
00177   // the address for the LUT. We do the same here.
00178   static const int maxComponent    = 1<<L1GctHtMissLut::kHxOrHyMissComponentNBits;
00179   static const int componentMask   = maxComponent-1;
00180   static const int maxPosComponent = componentMask >> 1;
00181 
00182   static const int maxInput = 1<<(L1GctHtMissLut::kHxOrHyMissComponentNBits+kExOrEyMissComponentShift-1);
00183 
00184   static const unsigned resultMagMask = (1<<L1GctHtMissLut::kHtMissMagnitudeNBits) - 1;
00185   static const unsigned resultPhiMask = (1<<L1GctHtMissLut::kHtMissAngleNBits)     - 1;
00186 
00187   etmiss_internal result;
00188 
00189   if (m_htMissLut == 0) {
00190 
00191     result.mag = 0;
00192     result.phi = 0;
00193 
00194   } else {
00195 
00196     // Extract the bit fields of the input components to be used for the LUT address
00197     int hxCompBits = (ex >> kExOrEyMissComponentShift) & componentMask;
00198     int hyCompBits = (ey >> kExOrEyMissComponentShift) & componentMask;
00199 
00200     if (of || (abs(ex) >= maxInput) || (abs(ey) >= maxInput)) {
00201       hxCompBits = maxPosComponent;
00202       hyCompBits = maxPosComponent;
00203     }
00204 
00205     // Perform the table lookup to get the missing Ht magnitude and phi
00206     uint16_t lutAddress = static_cast<uint16_t> ( (hxCompBits << L1GctHtMissLut::kHxOrHyMissComponentNBits) | hyCompBits );
00207 
00208     uint16_t lutData = m_htMissLut->lutValue(lutAddress);
00209 
00210     result.mag = static_cast<unsigned>(lutData>>L1GctHtMissLut::kHtMissAngleNBits) & resultMagMask;
00211     result.phi = static_cast<unsigned>(lutData) & resultPhiMask;
00212 
00213   }
00214 
00215   return result;
00216 }
00217 
00218 L1GctMet::etmiss_internal
00219 L1GctMet::oldGctAlgo (const int ex, const int ey) const
00220 {
00221   //---------------------------------------------------------------------------------
00222   //
00223   // Calculates magnitude and direction of missing Et, given measured Ex and Ey.
00224   //
00225   // The algorithm used is suitable for implementation in hardware, using integer
00226   // multiplication, addition and comparison and bit shifting operations.
00227   //
00228   // Proceed in two stages. The first stage gives a result that lies between
00229   // 92% and 100% of the true Et, with the direction measured in 45 degree bins.
00230   // The final precision depends on the number of factors used in corrFact.
00231   // The present version with eleven factors gives a precision of 1% on Et, and
00232   // finds the direction to the nearest 5 degrees.
00233   //
00234   //---------------------------------------------------------------------------------
00235   etmiss_internal result;
00236 
00237   unsigned eneCoarse, phiCoarse;
00238   unsigned eneCorect, phiCorect;
00239 
00240   const unsigned root2fact = 181;
00241   const unsigned corrFact[11] = {24, 39, 51, 60, 69, 77, 83, 89, 95, 101, 106};
00242   const unsigned corrDphi[11] = { 0,  1,  1,  2,  2,  3,  3,  3,  3,   4,   4};
00243 
00244   std::vector<bool> s(3);
00245   unsigned Mx, My, Mw;
00246 
00247   unsigned Dx, Dy;
00248   unsigned eFact;
00249 
00250   unsigned b,phibin;
00251   bool midphi=false;
00252 
00253   // Here's the coarse calculation, with just one multiply operation
00254   //
00255   My = static_cast<unsigned>(abs(ey));
00256   Mx = static_cast<unsigned>(abs(ex));
00257   Mw = (((Mx+My)*root2fact)+0x80)>>8;
00258 
00259   s.at(0) = (ey<0);
00260   s.at(1) = (ex<0);
00261   s.at(2) = (My>Mx);
00262 
00263   phibin = 0; b = 0;
00264   for (int i=0; i<3; i++) {
00265     if (s.at(i)) { b=1-b;} phibin = 2*phibin + b;
00266   }
00267 
00268   eneCoarse = std::max(std::max(Mx, My), Mw);
00269   phiCoarse = phibin*9;
00270 
00271   // For the fine calculation we multiply both input components
00272   // by all the factors in the corrFact list in order to find
00273   // the required corrections to the energy and angle
00274   //
00275   for (eFact=0; eFact<10; eFact++) {
00276     Dx = (Mx*corrFact[eFact])>>8;
00277     Dy = (My*corrFact[eFact])>>8;
00278     if         ((Dx>=My) || (Dy>=Mx))         {midphi=false; break;}
00279     if ((Mx+Dx)>=(My-Dy) && (My+Dy)>=(Mx-Dx)) {midphi=true;  break;}
00280   }
00281   eneCorect = (eneCoarse*(128+eFact))>>7;
00282   if (midphi ^ (b==1)) {
00283     phiCorect = phiCoarse + 8 - corrDphi[eFact];
00284   } else {
00285     phiCorect = phiCoarse + corrDphi[eFact];
00286   }
00287 
00288   // Store the result of the calculation
00289   //
00290   result.mag = eneCorect;
00291   result.phi = phiCorect;
00292 
00293   return result;
00294 }
00295 
00296 L1GctMet::etmiss_internal
00297 L1GctMet::floatingPointAlgo (const int ex, const int ey) const
00298 {
00299 
00300   etmiss_internal result;
00301 
00302   double fx = static_cast<double>(ex);
00303   double fy = static_cast<double>(ey);
00304   double fmag = sqrt(fx*fx + fy*fy);
00305   double fphi = 36.*atan2(fy, fx)/M_PI;
00306 
00307   result.mag = static_cast<unsigned>(fmag);
00308   if (fphi>=0) {
00309     result.phi = static_cast<unsigned>(fphi);
00310   } else {
00311     result.phi = static_cast<unsigned>(fphi+72.);
00312   }
00313 
00314   return result;
00315 
00316 }
00317 
00318 void L1GctMet::setEtScale(const L1CaloEtScale* const fn)
00319 {
00320   m_htMissLut->setEtScale(fn);
00321 }
00322 
00323 void L1GctMet::setEtComponentLsb(const double lsb)
00324 {
00325   m_htMissLut->setExEyLsb( lsb * static_cast<double>( 1<<kExOrEyMissComponentShift ) );
00326 }
00327 
00328 const L1CaloEtScale* L1GctMet::etScale() const
00329 { 
00330   return m_htMissLut->etScale();
00331 }
00332 
00333 const double L1GctMet::componentLsb() const
00334 { 
00335   return m_htMissLut->componentLsb();
00336 }
00337 
00340 const bool L1GctMet::inputOverFlow() const
00341 {
00342   bool result = m_exComponent.overFlow() || m_eyComponent.overFlow();
00343 
00344   if (m_algoType == useHtMissLut) {
00345     static const int maxComponentInput = ( 1 << (L1GctHtMissLut::kHxOrHyMissComponentNBits+kExOrEyMissComponentShift-1) ) - 1;
00346 
00347     // Emulate the (symmetric) overflow condition used in the firmware
00348     result |= (m_exComponent.value() > maxComponentInput) || (m_exComponent.value() < -maxComponentInput) ||
00349       (m_eyComponent.value() > maxComponentInput) || (m_eyComponent.value() < -maxComponentInput);
00350   }
00351 
00352   return result;
00353 }
00354