Skip to content

Integrate recent PRS from pyaedt #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 108 additions & 48 deletions src/pyedb/legacy/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,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 @@ -1440,7 +1441,7 @@ def _create_extent(
expansion_size,
smart_cut,
reference_list,
include_pingroups,
pins_to_preserve,
)
else:
_poly = self.layout.expanded_extent(
Expand All @@ -1465,7 +1466,7 @@ def _create_extent(
expansion_size,
smart_cut,
reference_list,
include_pingroups,
pins_to_preserve,
)
else:
_poly = self.layout.expanded_extent(
Expand All @@ -1490,65 +1491,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))]

@pyedb_function_handler()
def _smart_cut(self, net_signals, reference_list=[], include_pingroups=True):
def _smart_cut(self, reference_list=[], expansion_size=1e-12):
from pyedb.legacy.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

@pyedb_function_handler()
Expand All @@ -1561,17 +1570,27 @@ 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 @@ -2045,6 +2064,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 @@ -2095,6 +2125,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 Expand Up @@ -3079,7 +3110,7 @@ def build_simulation_project(self, simulation_setup):

if not simulation_setup.signal_nets and simulation_setup.components:
nets_to_include = []
pnets = list(self.nets.power_nets.keys())[:]
pnets = list(self.nets.power.keys())[:]
for el in simulation_setup.components:
nets_to_include.append([i for i in self.components[el].nets if i not in pnets])
simulation_setup.signal_nets = [
Expand Down Expand Up @@ -3142,13 +3173,33 @@ def build_simulation_project(self, simulation_setup):
if not simulation_setup.generate_solder_balls:
source_type = SourceType.CircPort
for cmp in simulation_setup.components:
self.components.create_port_on_component(
cmp,
net_list=simulation_setup.signal_nets,
do_pingroup=False,
reference_net=simulation_setup.power_nets,
port_type=source_type,
)
if isinstance(cmp, str): # keep legacy component
self.components.create_port_on_component(
cmp,
net_list=simulation_setup.signal_nets,
do_pingroup=False,
reference_net=simulation_setup.power_nets,
port_type=source_type,
)
elif isinstance(cmp, dict):
if "refdes" in cmp:
if not "solder_balls_height" in cmp: # pragma no cover
cmp["solder_balls_height"] = None
if not "solder_balls_size" in cmp: # pragma no cover
cmp["solder_balls_size"] = None
cmp["solder_balls_mid_size"] = None
if not "solder_balls_mid_size" in cmp: # pragma no cover
cmp["solder_balls_mid_size"] = None
self.components.create_port_on_component(
cmp["refdes"],
net_list=simulation_setup.signal_nets,
do_pingroup=False,
reference_net=simulation_setup.power_nets,
port_type=source_type,
solder_balls_height=cmp["solder_balls_height"],
solder_balls_size=cmp["solder_balls_size"],
solder_balls_mid_size=cmp["solder_balls_mid_size"],
)
if simulation_setup.generate_solder_balls and not self.hfss.set_coax_port_attributes(
simulation_setup
): # pragma: no cover
Expand All @@ -3170,17 +3221,26 @@ def build_simulation_project(self, simulation_setup):
if simulation_setup.solver_type == SolverType.SiwaveSYZ:
if simulation_setup.generate_excitations:
for cmp in simulation_setup.components:
self.components.create_port_on_component(
cmp,
net_list=simulation_setup.signal_nets,
do_pingroup=simulation_setup.do_pingroup,
reference_net=simulation_setup.power_nets,
port_type=SourceType.CircPort,
)
if isinstance(cmp, str): # keep legacy
self.components.create_port_on_component(
cmp,
net_list=simulation_setup.signal_nets,
do_pingroup=simulation_setup.do_pingroup,
reference_net=simulation_setup.power_nets,
port_type=SourceType.CircPort,
)
elif isinstance(cmp, dict):
if "refdes" in cmp: # pragma no cover
self.components.create_port_on_component(
cmp["refdes"],
net_list=simulation_setup.signal_nets,
do_pingroup=simulation_setup.do_pingroup,
reference_net=simulation_setup.power_nets,
port_type=SourceType.CircPort,
)
self.logger.info("Configuring analysis setup.")
if not self.siwave.configure_siw_analysis_setup(simulation_setup): # pragma: no cover
self.logger.error("Failed to configure Siwave simulation setup.")

if simulation_setup.solver_type == SolverType.SiwaveDC:
if simulation_setup.generate_excitations:
self.components.create_source_on_component(simulation_setup.sources)
Expand Down
58 changes: 50 additions & 8 deletions src/pyedb/legacy/edb_core/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,16 @@ def create_port_on_pins(self, refdes, pins, reference_pins, impedance=50.0, port

@pyedb_function_handler()
def create_port_on_component(
self, component, net_list, port_type=SourceType.CoaxPort, do_pingroup=True, reference_net="gnd", port_name=None
self,
component,
net_list,
port_type=SourceType.CoaxPort,
do_pingroup=True,
reference_net="gnd",
port_name=None,
solder_balls_height=None,
solder_balls_size=None,
solder_balls_mid_size=None,
):
"""Create ports on a component.

Expand All @@ -832,6 +841,14 @@ def create_port_on_component(
If a port with the specified name already exists, the
default naming convention is used so that port creation does
not fail.
solder_balls_height : float, optional
Solder balls height used for the component. When provided default value is overwritten and must be
provided in meter.
solder_balls_size : float, optional
Solder balls diameter. When provided auto evaluation based on padstack size will be disabled.
solder_balls_mid_size : float, optional
Solder balls mid diameter. When provided if value is different than solder balls size, spheroid shape will
be switched.

Returns
-------
Expand Down Expand Up @@ -877,13 +894,36 @@ def create_port_on_component(
if port_type == SourceType.CoaxPort:
pad_params = self._padstack.get_pad_parameters(pin=cmp_pins[0], layername=pin_layers[0], pad_type=0)
if not pad_params[0] == 7:
sball_diam = min([self._pedb.edb_value(val).ToDouble() for val in pad_params[1]])
solder_ball_height = 2 * sball_diam / 3
else:
bbox = pad_params[1]
sball_diam = min([abs(bbox[2] - bbox[0]), abs(bbox[3] - bbox[1])]) * 0.8
solder_ball_height = 2 * sball_diam / 3
self.set_solder_ball(component, solder_ball_height, sball_diam)
if not solder_balls_size: # pragma no cover
sball_diam = min([self._pedb.edb_value(val).ToDouble() for val in pad_params[1]])
sball_mid_diam = sball_diam
else: # pragma no cover
sball_diam = solder_balls_size
if solder_balls_mid_size:
sball_mid_diam = solder_balls_mid_size
else:
sball_mid_diam = solder_balls_size
if not solder_balls_height: # pragma no cover
solder_balls_height = 2 * sball_diam / 3
else: # pragma no cover
if not solder_balls_size:
bbox = pad_params[1]
sball_diam = min([abs(bbox[2] - bbox[0]), abs(bbox[3] - bbox[1])]) * 0.8
else:
if not solder_balls_mid_size:
sball_mid_diam = solder_balls_size
if not solder_balls_height:
solder_balls_height = 2 * sball_diam / 3
sball_shape = "Cylinder"
if not sball_diam == sball_mid_diam:
sball_shape = "Spheroid"
self.set_solder_ball(
component=component,
sball_height=solder_balls_height,
sball_diam=sball_diam,
sball_mid_diam=sball_mid_diam,
shape=sball_shape,
)
for pin in cmp_pins:
self._padstack.create_coax_port(padstackinstance=pin, name=port_name)

Expand Down Expand Up @@ -1663,6 +1703,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 @@ -1690,6 +1731,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
2 changes: 1 addition & 1 deletion src/pyedb/legacy/edb_core/edb_data/nets_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def serial_rlc(self):
{
i: v
for i, v in self._app._nets[net].components.items()
if list(set(v.nets).intersection(nets)) != [net]
if list(set(v.nets).intersection(nets)) != [net] and v.type in ["Resistor", "Inductor", "Capacitor"]
}
)
return comps_common
Expand Down
5 changes: 4 additions & 1 deletion src/pyedb/legacy/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):
"""Type of the edb object."""
return self._edb_object.GetType()
try:
return self._edb_object.GetType()
except AttributeError: # pragma: no cover
return None
Loading