Skip to content

Commit

Permalink
Fix bug in disjoint_nets method due to a regression in the net_name s…
Browse files Browse the repository at this point in the history
…etter (#3897)

* Fix bug in disjoint_nets method due to a regression in the net_name setter

* Fix bug in disjoint_nets method due to a regression in the net_name setter

* Fix bug in disjoint_nets method due to a regression in the net_name setter

* Improved cutout method and fix_disjoint nets method

* Improved cutout method and fix_disjoint nets method

* Minor improvements

---------

Co-authored-by: maxcapodi78 <Shark78>
  • Loading branch information
maxcapodi78 authored Nov 23, 2023
1 parent d028e5f commit 3de28eb
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 52 deletions.
7 changes: 2 additions & 5 deletions _unittest/test_00_EDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,10 @@ def test_009_vias_creation(self):
assert self.edbapp.padstacks.definitions["myVia"].hole_range == "through"
self.edbapp.padstacks.create(padstackname="myVia_bullet", antipad_shape="Bullet")
assert "myVia_bullet" in list(self.edbapp.padstacks.definitions.keys())

self.edbapp.add_design_variable("via_x", 5e-3)
self.edbapp["via_y"] = "1mm"
assert self.edbapp["via_y"].value == 1e-3
assert self.edbapp["via_y"].value_string == "1mm"

assert self.edbapp.padstacks.place(["via_x", "via_x+via_y"], "myVia", via_name="via_test1")
assert self.edbapp.padstacks.place(["via_x", "via_x+via_y*2"], "myVia_bullet")
self.edbapp.padstacks["via_test1"].net_name = "GND"
Expand Down Expand Up @@ -2921,9 +2919,8 @@ def test_147_find_dc_shorts(self):
edbapp.layout_validation.illegal_rlc_values(True)

# 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 ["SFPA_Tx_Fault", "PCIe_Gen4_CLKREQ_L"] in dc_shorts
assert ["VDD_DDR", "GND"] 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
Expand Down
96 changes: 64 additions & 32 deletions pyaedt/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,7 @@ def _create_extent(
smart_cut=False,
reference_list=[],
include_pingroups=True,
pins_to_preserve=None,
):
if extent_type in ["Conforming", self.edb_api.geometry.extent_type.Conforming, 1]:
if use_pyaedt_extent:
Expand All @@ -1423,7 +1424,7 @@ def _create_extent(
expansion_size,
smart_cut,
reference_list,
include_pingroups,
pins_to_preserve,
)
else:
_poly = self.layout.expanded_extent(
Expand All @@ -1448,7 +1449,7 @@ def _create_extent(
expansion_size,
smart_cut,
reference_list,
include_pingroups,
pins_to_preserve,
)
else:
_poly = self.layout.expanded_extent(
Expand All @@ -1473,65 +1474,73 @@ def _create_conformal(
round_extension,
smart_cutout=False,
reference_list=[],
include_pingroups=True,
pins_to_preserve=None,
):
names = []
_polys = []
for net in net_signals:
names.append(net.GetName())
if pins_to_preserve:
insts = self.padstacks.instances
for i in pins_to_preserve:
p = insts[i].position
pos_1 = [i - expansion_size for i in p]
pos_2 = [i + expansion_size for i in p]
plane = self.modeler.Shape("rectangle", pointA=pos_1, pointB=pos_2)
rectangle_data = self.modeler.shape_to_polygon_data(plane)
_polys.append(rectangle_data)

for prim in self.modeler.primitives:
if prim is not None and prim.net_name in names:
obj_data = prim.primitive_object.GetPolygonData().Expand(
expansion_size, tolerance, round_corner, round_extension
)
if obj_data:
_polys.extend(list(obj_data))
_polys.append(prim.primitive_object.GetPolygonData())
if smart_cutout:
_polys.extend(self._smart_cut(net_signals, reference_list, include_pingroups))
_poly_unite = self.edb_api.geometry.polygon_data.unite(_polys)
objs_data = self._smart_cut(reference_list, expansion_size)
_polys.extend(objs_data)
k = 0
delta = expansion_size / 5
while k < 10:
unite_polys = []
for i in _polys:
obj_data = i.Expand(expansion_size, tolerance, round_corner, round_extension)
if obj_data:
unite_polys.extend(list(obj_data))
_poly_unite = self.edb_api.geometry.polygon_data.unite(unite_polys)
if len(_poly_unite) == 1:
self.logger.info("Correctly computed Extension at first iteration.")
return _poly_unite[0]
k += 1
expansion_size += delta
if len(_poly_unite) == 1:
self.logger.info("Correctly computed Extension in {} iterations.".format(k))
return _poly_unite[0]
else:
self.logger.info("Failed to Correctly computed Extension.")
areas = [i.Area() for i in _poly_unite]
return _poly_unite[areas.index(max(areas))]

@pyaedt_function_handler()
def _smart_cut(self, net_signals, reference_list=[], include_pingroups=True):
def _smart_cut(self, reference_list=[], expansion_size=1e-12):
from pyaedt.generic.clr_module import Tuple

_polys = []
terms = [term for term in self.layout.terminals if int(term.GetBoundaryType()) in [0, 3, 4, 7, 8]]
locations = []
for term in terms:
if term.GetTerminalType().ToString() == "PadstackInstanceTerminal":
if term.GetParameters()[1].GetNet().GetName() in reference_list:
locations.append(self.padstacks.instances[term.GetParameters()[1].GetId()].position)
elif term.GetTerminalType().ToString() == "PointTerminal" and term.GetNet().GetName() in reference_list:
if term.GetTerminalType().ToString() == "PointTerminal" and term.GetNet().GetName() in reference_list:
pd = term.GetParameters()[1]
locations.append([pd.X.ToDouble(), pd.Y.ToDouble()])
if include_pingroups:
for reference in reference_list:
for pin in self.nets.nets[reference].padstack_instances:
if pin.pingroups:
locations.append(pin.position)
for point in locations:
pointA = self.edb_api.geometry.point_data(
self.edb_value(point[0] - 1e-12), self.edb_value(point[1] - 1e-12)
self.edb_value(point[0] - expansion_size), self.edb_value(point[1] - expansion_size)
)
pointB = self.edb_api.geometry.point_data(
self.edb_value(point[0] + 1e-12), self.edb_value(point[1] + 1e-12)
self.edb_value(point[0] + expansion_size), self.edb_value(point[1] + expansion_size)
)

points = Tuple[self.edb_api.geometry.geometry.PointData, self.edb_api.geometry.geometry.PointData](
pointA, pointB
)
_polys.append(self.edb_api.geometry.polygon_data.create_from_bbox(points))
for cname, c in self.components.instances.items():
if (
set(net_signals).intersection(c.nets)
and c.is_enabled
and c.model_type in ["SParameterModel", "SpiceModel", "NetlistModel"]
):
for pin in c.pins:
locations.append(pin.position)
return _polys

@pyaedt_function_handler()
Expand All @@ -1544,17 +1553,28 @@ def _create_convex_hull(
round_extension,
smart_cut=False,
reference_list=[],
include_pingroups=True,
pins_to_preserve=None,
):
names = []
_polys = []
for net in net_signals:
names.append(net.GetName())
if pins_to_preserve:
insts = self.padstacks.instances
for i in pins_to_preserve:
p = insts[i].position
pos_1 = [i - 1e-12 for i in p]
pos_2 = [i + 1e-12 for i in p]
plane = self.modeler.Shape("rectangle", pointA=pos_1, pointB=pos_2)
rectangle_data = self.modeler.shape_to_polygon_data(plane)
_polys.append(rectangle_data)
for prim in self.modeler.primitives:
if prim is not None and prim.net_name in names:
_polys.append(prim.primitive_object.GetPolygonData())
if smart_cut:
_polys.extend(self._smart_cut(net_signals, reference_list, include_pingroups))
objs_data = self._smart_cut(reference_list, expansion_size)
_polys.extend(objs_data)

_poly = self.edb_api.geometry.polygon_data.get_convex_hull_of_polygons(convert_py_list_to_net_list(_polys))
_poly = _poly.Expand(expansion_size, tolerance, round_corner, round_extension)[0]
return _poly
Expand Down Expand Up @@ -2027,6 +2047,17 @@ def _create_cutout_multithread(
):
pins_to_preserve.extend([i.id for i in el.pins.values()])
nets_to_preserve.extend(el.nets)
if include_pingroups:
for reference in reference_list:
for pin in self.nets.nets[reference].padstack_instances:
if pin.pingroups:
pins_to_preserve.append(pin.id)
if check_terminals:
terms = [term for term in self.layout.terminals if int(term.GetBoundaryType()) in [0, 3, 4, 7, 8]]
for term in terms:
if term.GetTerminalType().ToString() == "PadstackInstanceTerminal":
if term.GetParameters()[1].GetNet().GetName() in reference_list:
pins_to_preserve.append(term.GetParameters()[1].GetId())

for i in self.nets.nets.values():
name = i.name
Expand Down Expand Up @@ -2077,6 +2108,7 @@ def _create_cutout_multithread(
smart_cut=check_terminals,
reference_list=reference_list,
include_pingroups=include_pingroups,
pins_to_preserve=pins_to_preserve,
)
if extent_type in ["Conforming", self.edb_api.geometry.extent_type.Conforming, 1] and extent_defeature > 0:
_poly = _poly.Defeature(extent_defeature)
Expand Down
2 changes: 2 additions & 0 deletions pyaedt/edb_core/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -1661,6 +1661,7 @@ def create_pingroup_from_pins(self, pins, group_name=None):
def delete_single_pin_rlc(self, deactivate_only=False):
# type: (bool) -> list
"""Delete all RLC components with a single pin.
Single pin component model type will be reverted to ``"RLC"``.
Parameters
----------
Expand Down Expand Up @@ -1688,6 +1689,7 @@ def delete_single_pin_rlc(self, deactivate_only=False):
if val.numpins < 2 and val.type in ["Resistor", "Capacitor", "Inductor"]:
if deactivate_only:
val.is_enabled = False
val.model_type = "RLC"
else:
val.edbcomponent.Delete()
deleted_comps.append(comp)
Expand Down
5 changes: 4 additions & 1 deletion pyaedt/edb_core/edb_data/obj_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ def is_null(self):
@property
def type(self):
"""Get type."""
return self._edb_object.GetType()
try:
return self._edb_object.GetType()
except AttributeError: # pragma: no cover
return None
10 changes: 8 additions & 2 deletions pyaedt/edb_core/edb_data/padstacks_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,10 @@ def lower_elevation(self):
float
Lower elavation of the placement layer.
"""
return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetLowerElevation()
try:
return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetLowerElevation()
except AttributeError: # pragma: no cover
return None

@property
def upper_elevation(self):
Expand All @@ -1680,7 +1683,10 @@ def upper_elevation(self):
float
Upper elevation of the placement layer.
"""
return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetUpperElevation()
try:
return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetUpperElevation()
except AttributeError: # pragma: no cover
return None

@property
def top_bottom_association(self):
Expand Down
28 changes: 22 additions & 6 deletions pyaedt/edb_core/edb_data/primitives_data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import math

from pyaedt.edb_core.dotnet.database import NetDotNet
from pyaedt.edb_core.dotnet.primitive import BondwireDotNet
from pyaedt.edb_core.dotnet.primitive import CircleDotNet
from pyaedt.edb_core.dotnet.primitive import PathDotNet
Expand Down Expand Up @@ -82,7 +83,10 @@ def type(self):
-------
str
"""
return self._edb_object.GetPrimitiveType().ToString()
try:
return self._edb_object.GetPrimitiveType().ToString()
except AttributeError: # pragma: no cover
return ""

@property
def net_name(self):
Expand All @@ -101,14 +105,20 @@ def net_name(self, name):
self.primitive_object.SetNet(net)
else:
try:
self.net = name
except:
if isinstance(name, str):
self.net = name
elif isinstance(name, NetDotNet):
self.net = name.name
except: # pragma: no cover
self._app.logger.error("Failed to set net name.")

@property
def layer(self):
"""Get the primitive edb layer object."""
return self.primitive_object.GetLayer()
try:
return self.primitive_object.GetLayer()
except AttributeError: # pragma: no cover
return None

@property
def layer_name(self):
Expand All @@ -118,7 +128,10 @@ def layer_name(self):
-------
str
"""
return self.layer.GetName()
try:
return self.layer.GetName()
except AttributeError: # pragma: no cover
return None

@layer_name.setter
def layer_name(self, val):
Expand All @@ -144,7 +157,10 @@ def is_void(self):
-------
bool
"""
return self._edb_object.IsVoid()
try:
return self._edb_object.IsVoid()
except AttributeError: # pragma: no cover
return None

def get_connected_objects(self):
"""Get connected objects.
Expand Down
Loading

0 comments on commit 3de28eb

Please sign in to comment.