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
0081
0082
0083
0084
0085 COS_PHI_IN_WIDTH = 10
0086 COSH_ETA_IN_WIDTH = 11
0087 ISOLATION_WIDTH = 11
0088
0089
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
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
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)")