From 5653f90604150710b444c6242b0f951b10ee7ce7 Mon Sep 17 00:00:00 2001 From: Hui Zhou Date: Wed, 4 Oct 2023 14:49:48 +0200 Subject: [PATCH] layout validation (#3686) * fix * fix * fix * fix * fix * fix * fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix * fix * fix * Update pyaedt/edb.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update pyaedt/edb_core/edb_data/connectable.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update pyaedt/edb_core/edb_data/nets_data.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update pyaedt/edb_core/layout_validation.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: ring630 <@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- _unittest/test_00_EDB.py | 6 +- pyaedt/edb.py | 54 ++++- pyaedt/edb_core/edb_data/connectable.py | 28 ++- pyaedt/edb_core/edb_data/nets_data.py | 16 ++ pyaedt/edb_core/edb_data/padstacks_data.py | 6 - pyaedt/edb_core/edb_data/primitives_data.py | 21 +- pyaedt/edb_core/edb_data/terminals.py | 7 +- pyaedt/edb_core/general.py | 33 +++ pyaedt/edb_core/layout_validation.py | 213 ++++++++++++++++++++ pyaedt/edb_core/nets.py | 161 +-------------- 10 files changed, 367 insertions(+), 178 deletions(-) create mode 100644 pyaedt/edb_core/layout_validation.py diff --git a/_unittest/test_00_EDB.py b/_unittest/test_00_EDB.py index 9dd2373bb0f..6e77e4ef0ca 100644 --- a/_unittest/test_00_EDB.py +++ b/_unittest/test_00_EDB.py @@ -118,6 +118,7 @@ def test_003_create_coax_port_on_component(self): assert self.edbapp.components["U6"].pins["R3"].id assert self.edbapp.terminals assert self.edbapp.ports + assert self.edbapp.components["U6"].pins["R3"].get_connected_objects() def test_004_get_properties(self): assert len(self.edbapp.components.components) > 0 @@ -2892,10 +2893,13 @@ def test_147_find_dc_shorts(self): target_path = os.path.join(self.local_scratch.path, "test_dc_shorts", "ANSYS-HSD_V1_dc_shorts.aedb") self.local_scratch.copyfolder(source_path, target_path) edbapp = Edb(target_path, edbversion=desktop_version) - dc_shorts = edbapp.nets.find_dc_shorts() + dc_shorts = edbapp.layout_validation.dc_shorts() assert dc_shorts # assert len(dc_shorts) == 20 assert ["LVDS_CH09_N", "GND"] in dc_shorts assert ["LVDS_CH09_N", "DDR4_DM3"] in dc_shorts assert ["DDR4_DM3", "LVDS_CH07_N"] in dc_shorts + assert len(edbapp.nets["DDR4_DM3"].find_dc_short()) > 0 + edbapp.nets["DDR4_DM3"].find_dc_short(True) + assert len(edbapp.nets["DDR4_DM3"].find_dc_short()) == 0 edbapp.close() diff --git a/pyaedt/edb.py b/pyaedt/edb.py index ec2cc3ddd01..ee9a5b13c4b 100644 --- a/pyaedt/edb.py +++ b/pyaedt/edb.py @@ -37,11 +37,14 @@ from pyaedt.edb_core.edb_data.terminals import PadstackInstanceTerminal from pyaedt.edb_core.edb_data.terminals import Terminal from pyaedt.edb_core.edb_data.variables import Variable +from pyaedt.edb_core.general import LayoutObjType +from pyaedt.edb_core.general import Primitives from pyaedt.edb_core.general import TerminalType from pyaedt.edb_core.general import convert_py_list_to_net_list from pyaedt.edb_core.hfss import EdbHfss from pyaedt.edb_core.ipc2581.ipc2581 import Ipc2581 from pyaedt.edb_core.layout import EdbLayout +from pyaedt.edb_core.layout_validation import LayoutValidation from pyaedt.edb_core.materials import Materials from pyaedt.edb_core.net_class import EdbDifferentialPairs from pyaedt.edb_core.net_class import EdbExtendedNets @@ -328,6 +331,11 @@ def project_variables(self): p_var[i] = Variable(self, i) return p_var + @property + def layout_validation(self): + """:class:`pyaedt.edb_core.edb_data.layout_validation.LayoutValidation`.""" + return LayoutValidation(self) + @property def variables(self): """Get all Edb variables. @@ -1032,9 +1040,53 @@ def layout_instance(self): """Edb Layout Instance.""" return self.layout.layout_instance + @pyaedt_function_handler + def get_connected_objects(self, layout_object_instance): + """Get connected objects. + + Returns + ------- + list + """ + temp = [] + for i in list( + [ + loi.GetLayoutObj() + for loi in self.layout_instance.GetConnectedObjects(layout_object_instance._edb_object).Items + ] + ): + obj_type = i.GetObjType().ToString() + if obj_type == LayoutObjType.PadstackInstance.name: + from pyaedt.edb_core.edb_data.padstacks_data import EDBPadstackInstance + + temp.append(EDBPadstackInstance(i, self)) + elif obj_type == LayoutObjType.Primitive.name: + prim_type = i.GetPrimitiveType().ToString() + if prim_type == Primitives.Path.name: + from pyaedt.edb_core.edb_data.primitives_data import EdbPath + + temp.append(EdbPath(i, self)) + elif prim_type == Primitives.Rectangle.name: + from pyaedt.edb_core.edb_data.primitives_data import EdbRectangle + + temp.append(EdbRectangle(i, self)) + elif prim_type == Primitives.Circle.name: + from pyaedt.edb_core.edb_data.primitives_data import EdbCircle + + temp.append(EdbCircle(i, self)) + elif prim_type == Primitives.Polygon.name: + from pyaedt.edb_core.edb_data.primitives_data import EdbPolygon + + temp.append(EdbPolygon(i, self)) + else: + continue + else: + continue + return temp + @property def pins(self): - """EDBPadstackInstance of Component. + """EDB padstack instance of the component. .. deprecated:: 0.6.62 Use new method :func:`edb.padstacks.pins` instead. diff --git a/pyaedt/edb_core/edb_data/connectable.py b/pyaedt/edb_core/edb_data/connectable.py index 3eda3bd5dbb..d6f19e0916f 100644 --- a/pyaedt/edb_core/edb_data/connectable.py +++ b/pyaedt/edb_core/edb_data/connectable.py @@ -1,6 +1,14 @@ from pyaedt import pyaedt_function_handler +class LayoutObjInstance: + """Manages EDB functionalities for the layout object instance.""" + + def __init__(self, pedb, edb_object): + self._pedb = pedb + self._edb_object = edb_object + + class LayoutObj(object): """Manages EDB functionalities for the layout object.""" @@ -28,9 +36,10 @@ def _edb(self): return self._pedb.edb_api @property - def _layout(self): - """Return Ansys.Ansoft.Edb.Cell.Layout object.""" - return self._pedb.active_layout + def _layout_obj_instance(self): + """Returns :class:`pyaedt.edb_core.edb_data.connectable.LayoutObjInstance`.""" + obj = self._pedb.layout_instance.GetLayoutObjInstance(self._edb_object, None) + return LayoutObjInstance(self._pedb, obj) @property def _edb_properties(self): @@ -41,9 +50,14 @@ def _edb_properties(self): def _edb_properties(self, value): self._edb_object.SetProductSolverOption(self._edb.edb_api.ProductId.Designer, "HFSS", value) + @property + def _obj_type(self): + """Returns LayoutObjType.""" + return self._edb_object.GetObjType().ToString() + @property def is_null(self): - """Determine if this object is null.""" + """Flag indicating if this object is null.""" return self._edb_object.IsNull() @property @@ -81,6 +95,12 @@ def net(self): return EDBNetsData(self._edb_object.GetNet(), self._pedb) + @net.setter + def net(self, value): + """Set net.""" + net = self._pedb.nets[value] + self._edb_object.SetNet(net.net_object) + @property def component(self): """Component connected to this object. diff --git a/pyaedt/edb_core/edb_data/nets_data.py b/pyaedt/edb_core/edb_data/nets_data.py index b16c572c4fd..0574e17b7f8 100644 --- a/pyaedt/edb_core/edb_data/nets_data.py +++ b/pyaedt/edb_core/edb_data/nets_data.py @@ -74,6 +74,22 @@ def components(self): comps[comp.refdes] = comp return comps + @pyaedt_function_handler + def find_dc_short(self, fix=False): + """Find DC-shorted nets. + + Parameters + ---------- + fix : bool, optional + If `True`, rename all the nets. (default) + If `False`, only report dc shorts. + Returns + ------- + List[List[str, str]] + [[net name, net name]]. + """ + return self._app.layout_validation.dc_shorts(self.name, fix) + @pyaedt_function_handler() def plot( self, diff --git a/pyaedt/edb_core/edb_data/padstacks_data.py b/pyaedt/edb_core/edb_data/padstacks_data.py index 2c381ab0e3d..a37d2b2987a 100644 --- a/pyaedt/edb_core/edb_data/padstacks_data.py +++ b/pyaedt/edb_core/edb_data/padstacks_data.py @@ -1869,12 +1869,6 @@ def get_connected_object_id_set(self): layoutObjInst = self.object_instance return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items] - @pyaedt_function_handler() - def _get_connected_object_obj_set(self): - layoutInst = self._edb_padstackinstance.GetLayout().GetLayoutInstance() - layoutObjInst = self.object_instance - return list([loi.GetLayoutObj() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]) - @pyaedt_function_handler() def get_reference_pins(self, reference_net="GND", search_radius=5e-3, max_limit=0, component_only=True): """Search for reference pins using given criteria. diff --git a/pyaedt/edb_core/edb_data/primitives_data.py b/pyaedt/edb_core/edb_data/primitives_data.py index 514b0d279ae..7351d7ac7f3 100644 --- a/pyaedt/edb_core/edb_data/primitives_data.py +++ b/pyaedt/edb_core/edb_data/primitives_data.py @@ -81,11 +81,7 @@ def type(self): ------- str """ - types = ["Circle", "Path", "Polygon", "Rectangle", "Bondwire"] - str_type = self.primitive_type.ToString().split(".") - if str_type[-1] in types: - return str_type[-1] - return None + return self._edb_object.GetPrimitiveType().ToString() @property def net_name(self): @@ -149,6 +145,15 @@ def is_void(self): """ return self._edb_object.IsVoid() + def get_connected_objects(self): + """Get connected objects. + + Returns + ------- + list + """ + return self._pedb.get_connected_objects(self._layout_obj_instance) + class EDBPrimitives(EDBPrimitivesMain): """Manages EDB functionalities for a primitives. @@ -349,12 +354,6 @@ def get_connected_object_id_set(self): layoutObjInst = layoutInst.GetLayoutObjInstance(self.primitive_object, None) # 2nd arg was [] return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items] - @pyaedt_function_handler() - def _get_connected_object_obj_set(self): - layoutInst = self.primitive_object.GetLayout().GetLayoutInstance() - layoutObjInst = layoutInst.GetLayoutObjInstance(self.primitive_object, None) - return list([loi.GetLayoutObj() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]) - @pyaedt_function_handler() def convert_to_polygon(self): """Convert path to polygon. diff --git a/pyaedt/edb_core/edb_data/terminals.py b/pyaedt/edb_core/edb_data/terminals.py index 48e0f349476..30e551e241e 100644 --- a/pyaedt/edb_core/edb_data/terminals.py +++ b/pyaedt/edb_core/edb_data/terminals.py @@ -442,7 +442,12 @@ def create(self, padstack_instance, name=None, layer=None, is_ref=False): layer_obj = self._pedb.stackup.signal_layers[layer] terminal = self._edb.cell.terminal.PadstackInstanceTerminal.Create( - self._layout, self.net.net_object, name, padstack_instance._edb_object, layer_obj._edb_layer, isRef=is_ref + self._pedb.active_layout, + self.net.net_object, + name, + padstack_instance._edb_object, + layer_obj._edb_layer, + isRef=is_ref, ) terminal = PadstackInstanceTerminal(self._pedb, terminal) diff --git a/pyaedt/edb_core/general.py b/pyaedt/edb_core/general.py index 951c252d1f1..6be4a4b417d 100644 --- a/pyaedt/edb_core/general.py +++ b/pyaedt/edb_core/general.py @@ -172,3 +172,36 @@ class TerminalType(Enum): PadstackInstanceTerminal = 3 BundleTerminal = 4 PinGroupTerminal = 5 + + +class Primitives(Enum): + Rectangle = 0 + Circle = 1 + Polygon = 2 + Path = 3 + Bondwire = 4 + PrimitivePlugin = 5 + Text = 6 + Path3D = 7 + BoardBendDef = 8 + InValidType = 9 + + +class LayoutObjType(Enum): + InvalidLayoutObj = -1 + Primitive = 0 + PadstackInstance = 1 + Terminal = 2 + TerminalInstance = 3 + CellInstance = 4 + Layer = 5 + Net = 6 + Padstack = 7 + Group = 8 + NetClass = 9 + Cell = 10 + DifferentialPair = 11 + PinGroup = 12 + VoltageRegulator = 13 + ExtendedNet = 14 + LayoutObjTypeCount = 15 diff --git a/pyaedt/edb_core/layout_validation.py b/pyaedt/edb_core/layout_validation.py new file mode 100644 index 00000000000..6acd7bd3a24 --- /dev/null +++ b/pyaedt/edb_core/layout_validation.py @@ -0,0 +1,213 @@ +from pyaedt.edb_core.edb_data.padstacks_data import EDBPadstackInstance +from pyaedt.edb_core.edb_data.primitives_data import EDBPrimitives +from pyaedt.generic.general_methods import generate_unique_name +from pyaedt.generic.general_methods import pyaedt_function_handler + + +class LayoutValidation: + """Manages all layout validation capabilities""" + + def __init__(self, pedb): + self._pedb = pedb + + @pyaedt_function_handler() + def dc_shorts(self, net_list=None, fix=False): + """Find DC shorts on layout. + + Parameters + ---------- + net_list : str or list[str], optional + List of nets. + fix : bool, optional + If `True`, rename all the nets. (default) + If `False`, only report dc shorts. + + Returns + ------- + List[List[str, str]] + [[net name, net name]]. + + Examples + -------- + + >>> edb = Edb("edb_file") + >>> dc_shorts = edb.layout_validation.dc_shorts() + + """ + if not net_list: + net_list = list(self._pedb.nets.nets.keys()) + elif isinstance(net_list, str): + net_list = [net_list] + _objects_list = {} + _padstacks_list = {} + for prim in self._pedb.modeler.primitives: + n_name = prim.net_name + if n_name in _objects_list: + _objects_list[n_name].append(prim) + else: + _objects_list[n_name] = [prim] + for pad in list(self._pedb.padstacks.instances.values()): + n_name = pad.net_name + if n_name in _padstacks_list: + _padstacks_list[n_name].append(pad) + else: + _padstacks_list[n_name] = [pad] + dc_shorts = [] + for net in net_list: + objs = [] + for i in _objects_list.get(net, []): + objs.append(i) + for i in _padstacks_list.get(net, []): + objs.append(i) + if not len(objs): + self._pedb.nets[net].delete() + continue + + connected_objs = objs[0].get_connected_objects() + connected_objs.append(objs[0]) + net_dc_shorts = [obj for obj in connected_objs] + if net_dc_shorts: + dc_nets = list(set([obj.net.name for obj in net_dc_shorts if not obj.net.name == net])) + for dc in dc_nets: + if dc: + dc_shorts.append([net, dc]) + if fix: + temp = [] + for i in net_dc_shorts: + temp.append(i.net.name) + temp_key = set(temp) + temp_count = {temp.count(i): i for i in temp_key} + temp_count = dict(sorted(temp_count.items())) + while True: + temp_name = list(temp_count.values()).pop() + if not temp_name.lower().startswith("unnamed"): + break + elif temp_name.lower(): + break + elif len(temp) == 0: + break + for i in net_dc_shorts: + if not i.net.name == temp_name: + i.net = temp_name + return dc_shorts + + @pyaedt_function_handler() + def disjoint_nets( + self, net_list=None, keep_only_main_net=False, clean_disjoints_less_than=0.0, order_by_area=False + ): + """Find and fix disjoint nets from a given netlist. + + Parameters + ---------- + net_list : str, list, optional + List of nets on which check disjoints. If `None` is provided then the algorithm will loop on all nets. + keep_only_main_net : bool, optional + Remove all secondary nets other than principal one (the one with more objects in it). Default is `False`. + clean_disjoints_less_than : bool, optional + Clean all disjoint nets with area less than specified area in square meters. Default is `0.0` to disable it. + order_by_area : bool, optional + Whether if the naming order has to be by number of objects (fastest) or area (slowest but more accurate). + Default is ``False``. + Returns + ------- + List + New nets created. + + Examples + -------- + + >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"]) + """ + timer_start = self._pedb._logger.reset_timer() + + if not net_list: + net_list = list(self._pedb.nets.keys()) + elif isinstance(net_list, str): + net_list = [net_list] + _objects_list = {} + _padstacks_list = {} + for prim in self._pedb.modeler.primitives: + n_name = prim.net_name + if n_name in _objects_list: + _objects_list[n_name].append(prim) + else: + _objects_list[n_name] = [prim] + for pad in list(self._pedb.padstacks.instances.values()): + n_name = pad.net_name + if n_name in _padstacks_list: + _padstacks_list[n_name].append(pad) + else: + _padstacks_list[n_name] = [pad] + new_nets = [] + disjoints_objects = [] + self._pedb._logger.reset_timer() + for net in net_list: + net_groups = [] + obj_dict = {} + for i in _objects_list.get(net, []): + obj_dict[i.id] = i + for i in _padstacks_list.get(net, []): + obj_dict[i.id] = i + objs = list(obj_dict.values()) + l = len(objs) + while l > 0: + l1 = objs[0].get_connected_object_id_set() + l1.append(objs[0].id) + repetition = False + for net_list in net_groups: + if set(l1).intersection(net_list): + net_groups.append([i for i in l1 if i not in net_list]) + repetition = True + if not repetition: + net_groups.append(l1) + objs = [i for i in objs if i.id not in l1] + l = len(objs) + if len(net_groups) > 1: + + def area_calc(elem): + sum = 0 + for el in elem: + try: + if isinstance(obj_dict[el], EDBPrimitives): + if not obj_dict[el].is_void: + sum += obj_dict[el].area() + except: + pass + return sum + + if order_by_area: + areas = [area_calc(i) for i in net_groups] + sorted_list = [x for _, x in sorted(zip(areas, net_groups), reverse=True)] + else: + sorted_list = sorted(net_groups, key=len, reverse=True) + for disjoints in sorted_list[1:]: + if keep_only_main_net: + for geo in disjoints: + try: + obj_dict[geo].delete() + except KeyError: + pass + elif len(disjoints) == 1 and ( + isinstance(obj_dict[disjoints[0]], EDBPadstackInstance) + or clean_disjoints_less_than + and obj_dict[disjoints[0]].area() < clean_disjoints_less_than + ): + try: + obj_dict[disjoints[0]].delete() + except KeyError: + pass + else: + new_net_name = generate_unique_name(net, n=6) + net_obj = self._pedb.nets.find_or_create_net(new_net_name) + if net_obj: + new_nets.append(net_obj.GetName()) + for geo in disjoints: + try: + obj_dict[geo].net_name = net_obj + except KeyError: + pass + disjoints_objects.extend(disjoints) + self._pedb._logger.info("Found {} objects in {} new nets.".format(len(disjoints_objects), len(new_nets))) + self._pedb._logger.info_timer("Disjoint Cleanup Completed.", timer_start) + + return new_nets diff --git a/pyaedt/edb_core/nets.py b/pyaedt/edb_core/nets.py index 30ae3591510..6a46a1cccdc 100644 --- a/pyaedt/edb_core/nets.py +++ b/pyaedt/edb_core/nets.py @@ -6,8 +6,6 @@ import warnings from pyaedt.edb_core.edb_data.nets_data import EDBNetsData -from pyaedt.edb_core.edb_data.padstacks_data import EDBPadstackInstance -from pyaedt.edb_core.edb_data.primitives_data import EDBPrimitives from pyaedt.edb_core.general import convert_py_list_to_net_list from pyaedt.generic.constants import CSS4_COLORS from pyaedt.generic.general_methods import generate_unique_name @@ -1149,6 +1147,9 @@ def find_and_fix_disjoint_nets( ): """Find and fix disjoint nets from a given netlist. + .. deprecated:: + Use new property :func:`edb.layout_validation.disjoint_nets` instead. + Parameters ---------- net_list : str, list, optional @@ -1170,158 +1171,10 @@ def find_and_fix_disjoint_nets( >>> renamed_nets = edb_core.nets.find_and_fix_disjoint_nets(["GND","Net2"]) """ - timer_start = self._logger.reset_timer() - - if not net_list: - net_list = list(self.nets.keys()) - elif isinstance(net_list, str): - net_list = [net_list] - _objects_list = {} - _padstacks_list = {} - for prim in self._pedb.modeler.primitives: - n_name = prim.net_name - if n_name in _objects_list: - _objects_list[n_name].append(prim) - else: - _objects_list[n_name] = [prim] - for pad in list(self._pedb.padstacks.instances.values()): - n_name = pad.net_name - if n_name in _padstacks_list: - _padstacks_list[n_name].append(pad) - else: - _padstacks_list[n_name] = [pad] - new_nets = [] - disjoints_objects = [] - self._logger.reset_timer() - for net in net_list: - net_groups = [] - obj_dict = {} - for i in _objects_list.get(net, []): - obj_dict[i.id] = i - for i in _padstacks_list.get(net, []): - obj_dict[i.id] = i - objs = list(obj_dict.values()) - l = len(objs) - while l > 0: - l1 = objs[0].get_connected_object_id_set() - l1.append(objs[0].id) - repetition = False - for net_list in net_groups: - if set(l1).intersection(net_list): - net_groups.append([i for i in l1 if i not in net_list]) - repetition = True - if not repetition: - net_groups.append(l1) - objs = [i for i in objs if i.id not in l1] - l = len(objs) - if len(net_groups) > 1: - - def area_calc(elem): - sum = 0 - for el in elem: - try: - if isinstance(obj_dict[el], EDBPrimitives): - if not obj_dict[el].is_void: - sum += obj_dict[el].area() - except: - pass - return sum - - if order_by_area: - areas = [area_calc(i) for i in net_groups] - sorted_list = [x for _, x in sorted(zip(areas, net_groups), reverse=True)] - else: - sorted_list = sorted(net_groups, key=len, reverse=True) - for disjoints in sorted_list[1:]: - if keep_only_main_net: - for geo in disjoints: - try: - obj_dict[geo].delete() - except KeyError: - pass - elif len(disjoints) == 1 and ( - isinstance(obj_dict[disjoints[0]], EDBPadstackInstance) - or clean_disjoints_less_than - and obj_dict[disjoints[0]].area() < clean_disjoints_less_than - ): - try: - obj_dict[disjoints[0]].delete() - except KeyError: - pass - else: - new_net_name = generate_unique_name(net, n=6) - net_obj = self.find_or_create_net(new_net_name) - if net_obj: - new_nets.append(net_obj.GetName()) - for geo in disjoints: - try: - obj_dict[geo].net_name = net_obj - except KeyError: - pass - disjoints_objects.extend(disjoints) - self._logger.info("Found {} objects in {} new nets.".format(len(disjoints_objects), len(new_nets))) - self._logger.info_timer("Disjoint Cleanup Completed.", timer_start) - - return new_nets - - @pyaedt_function_handler() - def find_dc_shorts(self, net_list=None): - """Find DC shorts on layout. - - Parameters - ---------- - net_list : str or list[str] - Optional - - Returns - ------- - List[List[str, str]] - [[net name, net name]]. - - Examples - -------- - - >>> edb = Edb("edb_file") - >>> dc_shorts = edb.nets.find_dc_shorts() - - """ - if not net_list: - net_list = list(self.nets.keys()) - elif isinstance(net_list, str): - net_list = [net_list] - _objects_list = {} - _padstacks_list = {} - for prim in self._pedb.modeler.primitives: - n_name = prim.net_name - if n_name in _objects_list: - _objects_list[n_name].append(prim) - else: - _objects_list[n_name] = [prim] - for pad in list(self._pedb.padstacks.instances.values()): - n_name = pad.net_name - if n_name in _padstacks_list: - _padstacks_list[n_name].append(pad) - else: - _padstacks_list[n_name] = [pad] - dc_shorts = [] - for net in net_list: - objs = [] - for i in _objects_list.get(net, []): - objs.append(i) - for i in _padstacks_list.get(net, []): - objs.append(i) - try: - connected_objs = objs[0]._get_connected_object_obj_set() - connected_objs.append(objs[0].api_object) - net_dc_shorts = [obj for obj in connected_objs if not obj.GetNet().GetName() == net] - if net_dc_shorts: - dc_nets = list(set([obj.GetNet().GetName() for obj in net_dc_shorts])) - for dc in dc_nets: - if dc: - dc_shorts.append([net, dc]) - except: - pass - return dc_shorts + warnings.warn("Use new function :func:`edb.layout_validation.disjoint_nets` instead.", DeprecationWarning) + return self._pedb.layout_validation.disjoint_nets( + net_list, keep_only_main_net, clean_disjoints_less_than, order_by_area + ) @pyaedt_function_handler() def merge_nets_polygons(self, net_list):