Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:55:52

0001 """
0002 This computes the most optimal COS_PHI_LUT and COSH_ETA_LUT. Call
0003 :func:`~l1tGTSingleInOutLUT.SingleInOutLUT.export` to export the
0004 generated LUT.
0005 """
0006 
0007 import FWCore.ParameterSet.Config as cms
0008 from L1Trigger.Phase2L1GT.l1tGTScales import scale_parameter
0009 from statistics import mean, median, stdev
0010 import math
0011 
0012 
0013 class SingleInOutLUT:
0014 
0015     def __init__(self, width_in, unused_lsbs, lsb, output_scale_factor, operation, start_value=0, label=""):
0016         self.debug_txt = ""
0017         input_scale_factor = 2**unused_lsbs * lsb
0018         self.unused_lsbs = unused_lsbs
0019         self.lsb = lsb
0020         signed_output = min([operation(input_scale_factor * (i + 0.5) + start_value)
0021                             for i in range(2**width_in)]) < 0
0022 
0023         self.width_out = math.ceil(math.log2(output_scale_factor *
0024                                              max([abs(operation(input_scale_factor * (i + 0.5) + start_value)) for i in range(2**width_in - 1)] + 
0025                                              [abs(operation(input_scale_factor * (2**width_in - 1) + start_value))])))
0026 
0027         if signed_output:
0028             self.width_out += 1
0029 
0030         self.debug_info(
0031             "***************************** {} LUT {} *****************************".format(operation.__name__, label))
0032         self.debug_info("Depth: {} x {} (addr x data)".format(width_in, self.width_out))
0033         self.debug_info("Scale: {}".format(output_scale_factor))
0034 
0035         self.width_in = width_in
0036         self.output_scale_factor = output_scale_factor
0037         self.input_scale_factor = input_scale_factor
0038         self.operation = operation
0039         self.start_value = start_value
0040         self.lut = cms.vint32(
0041             * ([round(output_scale_factor * operation(input_scale_factor * (i + 0.5) + start_value)) for i in range(2**width_in - 1)]
0042                + [round(output_scale_factor * operation(input_scale_factor * (2 ** width_in - 1) + start_value))]))
0043 
0044         self.print_error()
0045 
0046     def debug_info(self, msg):
0047         self.debug_txt += msg + "\n"
0048 
0049     def config(self):
0050         return cms.PSet(
0051             output_scale_factor=cms.double(self.output_scale_factor),
0052             unused_lsbs=cms.uint32(self.unused_lsbs),
0053             lut=self.lut,
0054             max_error=cms.double(self.max_error)
0055         )
0056 
0057     def export(self, filename: str):
0058         print(self.debug_txt)
0059         with open(filename, "w") as file:
0060             for value in self.lut:
0061                 file.write("{:X}".format(int(value) & ((1 << self.width_out) - 1)
0062                                          ).rjust(math.ceil(self.width_out/4), '0') + "\n")
0063 
0064     @ staticmethod
0065     def optimal_scale_factor(width_in, max_width_out, unused_lsbs, lsb, operation, start_value=0):
0066         input_scale_factor = 2**unused_lsbs * lsb
0067         scale_factor = (2**max_width_out - 1) / max([abs(operation(input_scale_factor * (i + 0.5) + start_value))
0068                                                      for i in range(2**width_in)])
0069         return scale_factor
0070 
0071     def print_error(self):
0072         errors = [abs(self.lut[int(i/(2**self.unused_lsbs))]/self.output_scale_factor -
0073                       self.operation(i * self.lsb + self.start_value)) for i in range(2**(self.width_in + self.unused_lsbs))]
0074 
0075         self.max_error = max(errors)
0076 
0077         self.debug_info("Error: {:.5f} +/- {:.5f}, max: {:.5f}, total: {:.5f}, median: {:.5f}".format(
0078             mean(errors), stdev(errors), self.max_error, sum(errors), median(errors)))
0079 
0080         # mass_errors = [errors[i]/(2*self.operation(i * self.lsb + self.start_value)) for i in range(2**(self.width_in + self.unused_lsbs)) ]
0081         # self.debug_info("inv mass error: {:.5f} +/- {:.5f}, max: {:.5f}, total: {:.5f}, median: {:.5f}".format(
0082         #       mean(mass_errors), stdev(mass_errors), max(mass_errors), sum(mass_errors), median(mass_errors)))
0083 
0084 
0085 COS_PHI_IN_WIDTH = 10   # not using 2 lsb and 1 msb (cos(x + pi) = -cos(x), x in [0, pi))
0086 COSH_ETA_IN_WIDTH = 11  # not using 2 lsb and 1 msb (splitted LUT)
0087 ISOLATION_WIDTH = 11
0088 
0089 # Since we calculate cosh(dEta) - cos(dPhi); both must be on the same scale the difference should fit into 17 bits for the DSP
0090 optimal_scale_factor = math.floor(
0091     (2**17 - 1) / (math.cosh((2**(COSH_ETA_IN_WIDTH + 2) - 1)*scale_parameter.eta_lsb.value()) + 1))
0092 
0093 COS_PHI_LUT = SingleInOutLUT(
0094     COS_PHI_IN_WIDTH, 2, scale_parameter.phi_lsb.value(), optimal_scale_factor, math.cos)
0095 
0096 # eta in [0, 2pi)
0097 COSH_ETA_LUT = SingleInOutLUT(
0098     COSH_ETA_IN_WIDTH, 2, scale_parameter.eta_lsb.value(), optimal_scale_factor, math.cosh, 0, "[0, 2pi)")
0099 
0100 # eta in [2pi, 4pi)
0101 COSH_ETA_LUT_2 = SingleInOutLUT(
0102     COSH_ETA_IN_WIDTH, 2, scale_parameter.eta_lsb.value(),
0103     SingleInOutLUT.optimal_scale_factor(
0104         COSH_ETA_IN_WIDTH, 17, 2, scale_parameter.eta_lsb.value(), math.cosh, 2**13 * scale_parameter.eta_lsb.value()),
0105     math.cosh, 2**13 * scale_parameter.eta_lsb.value(), "[2pi, 4pi)")