File indexing completed on 2024-07-03 04:18:04
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="", width_out_force=0):
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 if width_out_force == 0:
0024 self.width_out = math.ceil(math.log2(output_scale_factor *
0025 max([abs(operation(input_scale_factor * (i + 0.5) + start_value)) for i in range(2**width_in - 1)] +
0026 [abs(operation(input_scale_factor * (2**width_in - 1) + start_value))])))
0027 if signed_output:
0028 self.width_out += 1
0029 else:
0030 self.width_out = width_out_force
0031
0032 self.debug_info(
0033 "***************************** {} LUT {} *****************************".format(operation.__name__, label))
0034 self.debug_info("Depth: {} x {} (addr x data)".format(width_in, self.width_out))
0035 self.debug_info("Scale: {}".format(output_scale_factor))
0036
0037 self.width_in = width_in
0038 self.output_scale_factor = output_scale_factor
0039 self.input_scale_factor = input_scale_factor
0040 self.operation = operation
0041 self.start_value = start_value
0042 self.lut = cms.vint32(
0043 * ([min(round(output_scale_factor * operation(input_scale_factor * (i + 0.5) + start_value)), 2**self.width_out - 1) for i in range(2**width_in - 1)]
0044 + [min(round(output_scale_factor * operation(input_scale_factor * (2 ** width_in - 1) + start_value)), 2**self.width_out - 1)]))
0045
0046 self.print_error()
0047
0048 def debug_info(self, msg):
0049 self.debug_txt += msg + "\n"
0050
0051 def config(self):
0052 return cms.PSet(
0053 output_scale_factor=cms.double(self.output_scale_factor),
0054 unused_lsbs=cms.uint32(self.unused_lsbs),
0055 lut=self.lut,
0056 max_error=cms.double(self.max_error)
0057 )
0058
0059 def export(self, filename: str):
0060 print(self.debug_txt)
0061 with open(filename, "w") as file:
0062 for value in self.lut:
0063 file.write("{:X}".format(int(value) & ((1 << self.width_out) - 1)
0064 ).rjust(math.ceil(self.width_out/4), '0') + "\n")
0065
0066 @ staticmethod
0067 def optimal_scale_factor(width_in, max_width_out, unused_lsbs, lsb, operation, start_value=0):
0068 input_scale_factor = 2**unused_lsbs * lsb
0069 scale_factor = (2**max_width_out - 1) / max([abs(operation(input_scale_factor * (i + 0.5) + start_value))
0070 for i in range(2**width_in)])
0071 return scale_factor
0072
0073 def print_error(self):
0074 errors = [abs(self.lut[int(i/(2**self.unused_lsbs))]/self.output_scale_factor -
0075 self.operation(i * self.lsb + self.start_value)) for i in range(2**(self.width_in + self.unused_lsbs))]
0076
0077 self.max_error = max(errors)
0078
0079 self.debug_info("Error: {:.5f} +/- {:.5f}, max: {:.5f}, total: {:.5f}, median: {:.5f}".format(
0080 mean(errors), stdev(errors), self.max_error, sum(errors), median(errors)))
0081
0082
0083
0084
0085
0086
0087 COS_PHI_IN_WIDTH = 10
0088 COSH_ETA_IN_WIDTH = 11
0089 ISOLATION_WIDTH = 11
0090
0091
0092 optimal_scale_factor_lower = math.floor(
0093 (2**17 - 1) / (math.cosh((2**(COSH_ETA_IN_WIDTH + 2) - 1)*scale_parameter.eta_lsb.value()) + 1))
0094
0095 COS_PHI_LUT = SingleInOutLUT(
0096 COS_PHI_IN_WIDTH, 2, scale_parameter.phi_lsb.value(), optimal_scale_factor_lower, math.cos)
0097
0098
0099 COSH_ETA_LUT = SingleInOutLUT(
0100 COSH_ETA_IN_WIDTH, 2, scale_parameter.eta_lsb.value(), optimal_scale_factor_lower, math.cosh, 0, "[0, 2pi)")
0101
0102 optimal_scale_factor_upper = SingleInOutLUT.optimal_scale_factor(
0103 COSH_ETA_IN_WIDTH, 17, 2, scale_parameter.eta_lsb.value(), math.cosh, 2**13 * scale_parameter.eta_lsb.value())
0104
0105
0106
0107
0108 optimal_scale_factor_upper = optimal_scale_factor_lower / \
0109 math.pow(2, math.floor(math.log2(optimal_scale_factor_lower / optimal_scale_factor_upper)))
0110
0111
0112 COSH_ETA_LUT_2 = SingleInOutLUT(
0113 COSH_ETA_IN_WIDTH, 2, scale_parameter.eta_lsb.value(), optimal_scale_factor_upper, math.cosh, 2**13 * scale_parameter.eta_lsb.value(), "[2pi, 4pi)", 17)