Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-04 04:35:15

0001 #include "L1Trigger/DTTriggerPhase2/interface/GlobalCoordsObtainer.h"
0002 
0003 using namespace edm;
0004 using namespace cmsdt;
0005 using namespace std;
0006 
0007 // ============================================================================
0008 // Constructors and destructor
0009 // ============================================================================
0010 GlobalCoordsObtainer::GlobalCoordsObtainer(const ParameterSet& pset) {
0011   global_coords_filename_ = pset.getParameter<edm::FileInPath>("global_coords_filename");
0012   std::ifstream ifin3(global_coords_filename_.fullPath());
0013 
0014   if (ifin3.fail()) {
0015     throw cms::Exception("Missing Input File")
0016         << "GlobalCoordsObtainer::GlobalCoordsObtainer() -  Cannot find " << global_coords_filename_.fullPath();
0017   }
0018 
0019   int wh, st, se, sl;
0020   double perp, x_phi0;
0021   std::string line;
0022 
0023   global_constant_per_sl sl1_constants;
0024   global_constant_per_sl sl3_constants;
0025 
0026   while (ifin3.good()) {
0027     ifin3 >> wh >> st >> se >> sl >> perp >> x_phi0;
0028 
0029     if (sl == 1) {
0030       sl1_constants.perp = perp;
0031       sl1_constants.x_phi0 = x_phi0;
0032     } else {
0033       sl3_constants.perp = perp;
0034       sl3_constants.x_phi0 = x_phi0;
0035 
0036       DTChamberId ChId(wh, st, se);
0037       global_constants.push_back({ChId.rawId(), sl1_constants, sl3_constants});
0038     }
0039   }
0040 
0041   int maxdrift;
0042   maxdrift_filename_ = pset.getParameter<edm::FileInPath>("maxdrift_filename");
0043   std::ifstream ifind(maxdrift_filename_.fullPath());
0044   if (ifind.fail()) {
0045     throw cms::Exception("Missing Input File")
0046         << "MPSLFilter::MPSLFilter() -  Cannot find " << maxdrift_filename_.fullPath();
0047   }
0048   while (ifind.good()) {
0049     ifind >> wh >> st >> se >> maxdrift;
0050     maxdriftinfo_[wh][st][se] = maxdrift;
0051   }
0052 }
0053 
0054 GlobalCoordsObtainer::~GlobalCoordsObtainer() {}
0055 
0056 void GlobalCoordsObtainer::generate_luts() {
0057   for (auto& global_constant : global_constants) {
0058     int sgn = 1;
0059     DTChamberId ChId(global_constant.chid);
0060     // typical hasPosRF function
0061     if (ChId.wheel() > 0 || (ChId.wheel() == 0 && ChId.sector() % 4 > 1)) {
0062       sgn = -1;
0063     }
0064 
0065     max_drift_tdc = maxdriftinfo_[ChId.wheel() + 2][ChId.station() - 1][ChId.sector() - 1];
0066     int SEMICELL_IN_TDC_COUNTS = max_drift_tdc;  //495 en un mundo peor y mas oscuro
0067     int SL1_SEMICELL_OFFSET = 96;
0068 
0069     //Read atan function from LUTs
0070     auto phi =
0071         calc_atan_lut(11,
0072                       6,
0073                       21. / SEMICELL_IN_TDC_COUNTS / ((global_constant.sl1.perp + global_constant.sl3.perp) / .2),
0074                       (global_constant.sl1.x_phi0 - 2.1 * SL1_SEMICELL_OFFSET) /
0075                           ((global_constant.sl1.perp + global_constant.sl3.perp) / 2),
0076                       1. / std::pow(2, 17),
0077                       9,
0078                       4,
0079                       11,
0080                       21,
0081                       sgn);
0082 
0083     auto phib =
0084         calc_atan_lut(9, 5, 21. / SEMICELL_IN_TDC_COUNTS / (6.5 * 16), 0., 4. / std::pow(2, 13), 9, 3, 10, 16, sgn);
0085 
0086     luts[global_constant.chid] = {phi, phib};
0087   }
0088 }
0089 
0090 std::map<int, lut_value> GlobalCoordsObtainer::calc_atan_lut(int msb_num,
0091                                                              int lsb_num,
0092                                                              double in_res,
0093                                                              double abscissa_0,
0094                                                              double out_res,
0095                                                              int a_extra_bits,
0096                                                              int b_extra_bits,
0097                                                              int a_size,
0098                                                              int b_size,
0099                                                              int sgn) {
0100   // Calculates the coefficients needed to calculate the arc-tan function in fw
0101   // by doing a piece-wise linear approximation.
0102   // In fw, input (x) and output (y) are integers, these conversions are needed
0103   //   t = x*in_res - abscissa_0
0104   //   phi = arctan(t)
0105   //   y = phi/out_res
0106   //   => y = arctan(x*in_res - abcissa_0)/out_res
0107   // The linear function is approximated as
0108   //   y = a*x_lsb + b
0109   // Where a, b = func(x_msb) are the coefficients stored in the lut
0110 
0111   // a is stored as unsigned, b as signed, with their respective sizes a_size, b_size,
0112   // previously shifted left by a_extra_bits and b_extra_bits, respectively
0113 
0114   long int a_min = -std::pow(2, (a_size - 1));
0115   long int a_max = std::pow(2, (a_size - 1)) - 1;
0116   long int b_min = -std::pow(2, (b_size - 1));
0117   long int b_max = std::pow(2, (b_size - 1)) - 1;
0118 
0119   std::map<int, lut_value> lut;
0120 
0121   for (long int x_msb = -(long int)std::pow(2, msb_num - 1); x_msb < (long int)std::pow(2, msb_num - 1); x_msb++) {
0122     int x1 = ((x_msb) << lsb_num);
0123     int x2 = ((x_msb + 1) << lsb_num) - 1;
0124 
0125     double t1 = x1 * in_res - abscissa_0;
0126     double t2 = x2 * in_res - abscissa_0;
0127 
0128     double phi1 = sgn * atan(t1);
0129     double phi2 = sgn * atan(t2);
0130 
0131     double y1 = phi1 / out_res;
0132     double y2 = phi2 / out_res;
0133 
0134     // we want to find a, b so that the error in the extremes is the same as the error in the center
0135     // so the error in the extremes will be the same, so the "a" is determined by those points
0136     double a = (y2 - y1) / (x2 - x1);
0137 
0138     // by derivating the error function and equaling to 0, you get this is the point
0139     // towards the interval center with the highest error
0140     // err_f = y - (a*x+b) = sgn*arctan(x*in_res - abcissa_0)/out_res - (a*x+b)
0141     // d(err_f)/dx = sgn*(1/(1+(x*in_res - abcissa_0)^2))*in_res/out_res - a
0142     // d(err_f)/dx = 0 => x_max_err = (sqrt(in_res/out_res/a-1) + abscissa_0)/in_res
0143     // There is sign ambiguity in the sqrt operation. The sqrt has units of t (adimensional).
0144     // It is resolved by setting the sqrt to have the same sign as (t1+t2)/2
0145 
0146     double t_max_err = sqrt(sgn * in_res / out_res / a - 1);
0147     if ((t1 + t2) < 0) {
0148       t_max_err *= -1;
0149     }
0150 
0151     double x_max_err = (t_max_err + abscissa_0) / in_res;
0152     double phi_max_err = sgn * atan(t_max_err);
0153     double y_max_err = phi_max_err / out_res;
0154 
0155     // once you have the point of max error, the "b" parameter is chosen as the average between
0156     // those two numbers, which makes the error at the center be equal in absolute value
0157     // to the error in the extremes
0158     // units: rad
0159 
0160     double b = (y1 + y_max_err - a * (x_max_err - x1)) / 2;
0161 
0162     // increase b in 1/2 of y_lsb, so that fw truncate operation on the of the result
0163     // is equivalent to a round function instead of a floor function
0164     b += 0.5;
0165 
0166     // shift left and round
0167     long int a_int = (long int)(round(a * (pow(2, a_extra_bits))));
0168     long int b_int = (long int)(round(b * (pow(2, b_extra_bits))));
0169 
0170     // tuck a, b constants into the bit size of the output (un)signed integer
0171     std::vector<long int> as = {a_min, a_int, a_max};
0172     std::vector<long int> bs = {b_min, b_int, b_max};
0173 
0174     std::sort(as.begin(), as.end());
0175     std::sort(bs.begin(), bs.end());
0176 
0177     a_int = as.at(1);
0178     b_int = bs.at(1);
0179 
0180     // // convert a, b to two's complement
0181     // auto a_signed = a_int % (long int) (pow(2, a_size));
0182     // auto b_signed = b_int % (long int) (pow(2, b_size));
0183 
0184     // convert x_msb to two's complement signed
0185     int index = to_two_comp(x_msb, msb_num);
0186     lut[index] = {a_int, b_int};
0187   }
0188   return lut;
0189 }
0190 
0191 std::vector<double> GlobalCoordsObtainer::get_global_coordinates(uint32_t chid, int sl, int x, int tanpsi) {
0192   // Depending on the type of primitive (SL1, SL3 or correlated), choose the
0193   // appropriate input data (x, tanpsi) from the input primitive data structure
0194   // and the corresponding phi-lut from the 3 available options
0195 
0196   auto phi_lut = &luts[chid].phi;  //One parameter to rule them all
0197   auto phib_lut = &luts[chid].phib;
0198 
0199   // x and slope are given in two's complement in fw
0200   x = to_two_comp(x, X_SIZE);
0201   tanpsi = to_two_comp(tanpsi, TANPSI_SIZE);
0202 
0203   // Slice x and tanpsi
0204   // Both x and tanpsi are represented in vhdl as signed, this means their values
0205   // are stored as two's complement.
0206 
0207   // The MSB part is going to be used to index the luts and obtain a and b parameters
0208   // Converting the upper part of the signed to an integer (with sign).
0209 
0210   int x_msb = x >> (X_SIZE - PHI_LUT_ADDR_WIDTH);
0211   x_msb = from_two_comp(x_msb, PHI_LUT_ADDR_WIDTH);
0212 
0213   int tanpsi_msb = tanpsi >> (TANPSI_SIZE - PHIB_LUT_ADDR_WIDTH);
0214   tanpsi_msb = from_two_comp(tanpsi_msb, PHIB_LUT_ADDR_WIDTH);
0215 
0216   // The LSB part can be sliced right away because it must yield a positive integer
0217   int x_lsb = x & (int)(std::pow(2, (X_SIZE - PHI_LUT_ADDR_WIDTH)) - 1);
0218   int tanpsi_lsb = tanpsi & (int)(std::pow(2, (TANPSI_SIZE - PHIB_LUT_ADDR_WIDTH)) - 1);
0219 
0220   // Index the luts wiht the MSB parts already calculated
0221   auto phi_lut_q = phi_lut->at(to_two_comp(x_msb, PHI_LUT_ADDR_WIDTH));
0222   auto phib_lut_q = phib_lut->at(to_two_comp(tanpsi_msb, PHIB_LUT_ADDR_WIDTH));
0223 
0224   // Separate this data into the coefficients a and b
0225   auto phi_lut_a = phi_lut_q.a;
0226   auto phi_lut_b = phi_lut_q.b;
0227   auto phib_lut_a = phib_lut_q.a;
0228   auto phib_lut_b = phib_lut_q.b;
0229 
0230   // Do the linear piece-wise operations
0231   // At this point all variables that can be negative have already been converted
0232   // so will yield negative values when necessary
0233   int phi_uncut = (phi_lut_b << PHI_B_SHL_BITS) + x_lsb * phi_lut_a;
0234   int psi_uncut = (phib_lut_b << PHIB_B_SHL_BITS) + tanpsi_lsb * phib_lut_a;
0235 
0236   // Trim phi to its final size
0237   int phi = (phi_uncut >> PHI_MULT_SHR_BITS);
0238 
0239   // Calculate phi_bending from the uncut version of phi and psi, and the trim it to size
0240   int phib_uncut = psi_uncut - (phi_uncut >> (PHI_PHIB_RES_DIFF_BITS + PHI_MULT_SHR_BITS - PHIB_MULT_SHR_BITS));
0241   int phib = (phib_uncut >> PHIB_MULT_SHR_BITS);
0242 
0243   double phi_f = (double)phi * PHI_SIZE;
0244   double phib_f = (double)phib * PHIB_SIZE;
0245 
0246   return std::vector({phi_f, phib_f});
0247 }