| #!/usr/bin/env python3 | |
| """ Tool for sanity checking rrgraph CHAN PTC's. | |
| """ | |
| import lxml.etree as ET | |
| import argparse | |
| def check_ptc(xml): | |
| """ Checks ptc values used on CHANX and CHANY rr graph nodes are valid. | |
| CHAN ptc numbers are an index per x/y coordinate and channel type (CHANX or | |
| CHANY). ptc's at a particular coordinate/type must start at 0, and fill | |
| to the max value. | |
| """ | |
| chan_ptcs = {} | |
| nodes = {} | |
| for node in xml.find('rr_nodes').iter('node'): | |
| assert node.attrib['id'] not in nodes | |
| nodes[node.attrib['id']] = node | |
| node_type = node.attrib['type'] | |
| if node_type in ['CHANX', 'CHANY']: | |
| loc_xml = node.find('loc') | |
| assert loc_xml is not None | |
| for x in range(int(loc_xml.attrib['xlow']), | |
| int(loc_xml.attrib['xhigh']) + 1): | |
| for y in range(int(loc_xml.attrib['ylow']), | |
| int(loc_xml.attrib['yhigh']) + 1): | |
| key = (node_type, x, y) | |
| if key not in chan_ptcs: | |
| chan_ptcs[key] = [] | |
| chan_ptcs[key].append( | |
| (node.attrib['id'], int(loc_xml.attrib['ptc'])) | |
| ) | |
| for (node_type, x, y), node_ptcs in chan_ptcs.items(): | |
| nodes, ptcs = zip(*node_ptcs) | |
| starts_at_zero = min(ptcs) == 0 | |
| ends_at_max_val = max(ptcs) == len(ptcs) - 1 | |
| all_values_present = len(ptcs) == len(set(ptcs)) | |
| if not all((starts_at_zero, ends_at_max_val, all_values_present)): | |
| sorted_nodes = sorted(zip(ptcs, nodes), key=lambda x: x[0]) | |
| for idx, (ptc, node) in enumerate(sorted_nodes): | |
| if idx == ptc: | |
| continue | |
| if idx > 1: | |
| raise ValueError( | |
| """\ | |
| Gap in ptc value for type = {node_type} @ ({x}, {y}) | |
| Expect PTC = {idx}, found {ptc} | |
| Current node is id = {cur_node} | |
| Previous node is id = {prev_node}""".format( | |
| x=x, | |
| y=y, | |
| node_type=node_type, | |
| idx=idx, | |
| ptc=ptc, | |
| cur_node=node, | |
| prev_node=sorted_nodes[idx - 1][1], | |
| ) | |
| ) | |
| else: | |
| raise ValueError( | |
| "Lowest ptc is {ptc} for type = {node_type} @ ({x}, {y})" | |
| .format( | |
| x=x, | |
| y=y, | |
| node_type=node_type, | |
| ptc=ptc, | |
| ) | |
| ) | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('input_xml') | |
| args = parser.parse_args() | |
| xml = ET.parse(args.input_xml, ET.XMLParser(remove_blank_text=True)) | |
| check_ptc(xml) | |
| if __name__ == "__main__": | |
| main() |