Skip to content
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

MAINT: integrate pyaedt recent PR changes #49

Merged
merged 10 commits into from
Nov 4, 2023
8 changes: 6 additions & 2 deletions .github/workflows/legacy_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ jobs:
run: |
pytest -m "legacy and unit" -n 6 -v

- name: "Executing legacy system tests"
- name: "Executing legacy system tests (distributing on multiple CPUs)"
run: |
pytest -m "legacy and system" -n 6 -v
pytest -m "legacy and system and not no_xdist" -n auto -v

- name: "Executing legacy system tests that cannot be distributed"
run: |
pytest -m "legacy and system and no_xdist" -v
98 changes: 90 additions & 8 deletions src/pyedb/legacy/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from pyedb.legacy.edb_core.edb_data.edbvalue import EdbValue
from pyedb.legacy.edb_core.edb_data.hfss_simulation_setup_data import HfssSimulationSetup
from pyedb.legacy.edb_core.edb_data.ports import BundleWavePort
from pyedb.legacy.edb_core.edb_data.ports import CircuitPort
from pyedb.legacy.edb_core.edb_data.ports import CoaxPort
from pyedb.legacy.edb_core.edb_data.ports import ExcitationProbes
from pyedb.legacy.edb_core.edb_data.ports import ExcitationSources
from pyedb.legacy.edb_core.edb_data.ports import GapPort
from pyedb.legacy.edb_core.edb_data.ports import WavePort
Expand All @@ -35,8 +35,10 @@
from pyedb.legacy.edb_core.edb_data.terminals import BundleTerminal
from pyedb.legacy.edb_core.edb_data.terminals import EdgeTerminal
from pyedb.legacy.edb_core.edb_data.terminals import PadstackInstanceTerminal
from pyedb.legacy.edb_core.edb_data.terminals import PinGroupTerminal
from pyedb.legacy.edb_core.edb_data.terminals import Terminal
from pyedb.legacy.edb_core.edb_data.variables import Variable
from pyedb.legacy.edb_core.general import BoundaryType
from pyedb.legacy.edb_core.general import LayoutObjType
from pyedb.legacy.edb_core.general import Primitives
from pyedb.legacy.edb_core.general import TerminalType
Expand Down Expand Up @@ -365,6 +367,8 @@ def terminals(self):
ter = BundleTerminal(self, i)
elif terminal_type == TerminalType.PadstackInstanceTerminal.name:
ter = PadstackInstanceTerminal(self, i)
elif terminal_type == TerminalType.PinGroupTerminal.name:
ter = PinGroupTerminal(self, i)
else:
ter = Terminal(self, i)
temp[ter.name] = ter
Expand Down Expand Up @@ -398,9 +402,12 @@ def ports(self):
ports = {}
for t in temp:
t2 = Terminal(self, t)
if t2.terminal_type == TerminalType.BundleTerminal.name:
bundle_ter = BundleWavePort(self, t)
ports[bundle_ter.name] = bundle_ter
if t2.is_circuit_port:
port = CircuitPort(self, t)
ports[port.name] = port
elif t2.terminal_type == TerminalType.BundleTerminal.name:
port = BundleWavePort(self, t)
ports[port.name] = port
elif t2.hfss_type == "Wave":
ports[t2.name] = WavePort(self, t)
elif t2.terminal_type == TerminalType.PadstackInstanceTerminal.name:
Expand All @@ -425,9 +432,13 @@ def sources(self):
@property
def probes(self):
"""Get all layout sources."""
terms = [term for term in self.layout.terminals if int(term.GetBoundaryType()) in [8]]
return {ter.GetName(): ExcitationProbes(self, ter) for ter in terms}

temp = {}
for name, val in self.terminals.items():
if val.boundary_type == BoundaryType.kVoltageProbe.name:
if not val.is_reference_terminal:
temp[name] = val
return temp

@pyedb_function_handler()
def open_edb(self):
"""Open EDB.
Expand Down Expand Up @@ -1584,6 +1595,7 @@ def cutout(
maximum_iterations=10,
preserve_components_with_model=False,
simple_pad_check=True,
keep_lines_as_path=False,
):
"""Create a cutout using an approach entirely based on PyAEDT.
This method replaces all legacy cutout methods in PyAEDT.
Expand Down Expand Up @@ -1655,6 +1667,11 @@ def cutout(
Whether to use the center of the pad to find the intersection with extent or use the bounding box.
Second method is much slower and requires to disable multithread on padstack removal.
Default is `True`.
keep_lines_as_path : bool, optional
Whether to keep the lines as Path after they are cutout or convert them to PolygonData.
This feature works only in Electronics Desktop (3D Layout).
If the flag is set to ``True`` it can cause issues in SiWave once the Edb is imported.
Default is ``False`` to generate PolygonData of cut lines.

Returns
-------
Expand Down Expand Up @@ -1744,6 +1761,7 @@ def cutout(
preserve_components_with_model=preserve_components_with_model,
include_partial=include_partial_instances,
simple_pad_check=simple_pad_check,
keep_lines_as_path=keep_lines_as_path,
)
if self.are_port_reference_terminals_connected():
if output_aedb_path:
Expand Down Expand Up @@ -1783,6 +1801,7 @@ def cutout(
preserve_components_with_model=preserve_components_with_model,
include_partial=include_partial_instances,
simple_pad_check=simple_pad_check,
keep_lines_as_path=keep_lines_as_path,
)
if result and not open_cutout_at_end and self.edbpath != legacy_path:
self.save_edb()
Expand Down Expand Up @@ -1988,6 +2007,7 @@ def _create_cutout_multithread(
preserve_components_with_model=False,
include_partial=False,
simple_pad_check=True,
keep_lines_as_path=False,
):
if is_ironpython: # pragma: no cover
self.logger.error("Method working only in Cpython")
Expand Down Expand Up @@ -2025,6 +2045,7 @@ def _create_cutout_multithread(
i.net_object.Delete()
reference_pinsts = []
reference_prims = []
reference_paths = []
for i in self.padstacks.instances.values():
net_name = i.net_name
id = i.id
Expand All @@ -2038,7 +2059,10 @@ def _create_cutout_multithread(
if net_name not in all_list:
i.delete()
elif net_name in reference_list and not i.is_void:
reference_prims.append(i)
if keep_lines_as_path and i.type == "Path":
reference_paths.append(i)
else:
reference_prims.append(i)
self.logger.info_timer("Net clean up")
self.logger.reset_timer()

Expand Down Expand Up @@ -2086,6 +2110,17 @@ def intersect(poly1, poly2):
def subtract(poly, voids):
return poly.Subtract(convert_py_list_to_net_list(poly), convert_py_list_to_net_list(voids))

def clip_path(path):
pdata = path.polygon_data.edb_api
int_data = _poly.GetIntersectionType(pdata)
if int_data == 0:
prims_to_delete.append(path)
return
result = path._edb_object.SetClipInfo(_poly, True)
if not result:
self.logger.info("Failed to clip path {}. Clipping as polygon.".format(path.id))
reference_prims.append(path)

def clean_prim(prim_1): # pragma: no cover
pdata = prim_1.polygon_data.edb_api
int_data = _poly.GetIntersectionType(pdata)
Expand Down Expand Up @@ -2131,6 +2166,11 @@ def pins_clean(pinst):
self.logger.info_timer("Padstack Instances removal completed")
self.logger.reset_timer()

# with ThreadPoolExecutor(number_of_threads) as pool:
# pool.map(lambda item: clip_path(item), reference_paths)

for item in reference_paths:
clip_path(item)
with ThreadPoolExecutor(number_of_threads) as pool:
pool.map(lambda item: clean_prim(item), reference_prims)

Expand All @@ -2139,6 +2179,7 @@ def pins_clean(pinst):

for prim in prims_to_delete:
prim.delete()

self.logger.info_timer("Primitives cleanup completed")
self.logger.reset_timer()

Expand Down Expand Up @@ -2174,6 +2215,7 @@ def create_cutout_multithread(
remove_single_pin_components=False,
use_pyaedt_extent_computing=False,
extent_defeature=0,
keep_lines_as_path=False,
):
"""Create a cutout using an approach entirely based on legacy.
It does in sequence:
Expand Down Expand Up @@ -2214,6 +2256,11 @@ def create_cutout_multithread(
extent_defeature : float, optional
Defeature the cutout before applying it to produce simpler geometry for mesh (Experimental).
It applies only to Conforming bounding box. Default value is ``0`` which disable it.
keep_lines_as_path : bool, optional
Whether to keep the lines as Path after they are cutout or convert them to PolygonData.
This feature works only in Electronics Desktop (3D Layout).
If the flag is set to True it can cause issues in SiWave once the Edb is imported.
Default is ``False`` to generate PolygonData of cut lines.

Returns
-------
Expand Down Expand Up @@ -2253,6 +2300,7 @@ def create_cutout_multithread(
remove_single_pin_components=remove_single_pin_components,
use_pyaedt_extent_computing=use_pyaedt_extent_computing,
extent_defeature=extent_defeature,
keep_lines_as_path=keep_lines_as_path,
)

@pyedb_function_handler()
Expand Down Expand Up @@ -3366,6 +3414,8 @@ def create_siwave_syz_setup(self, name=None):
if name in self.setups:
return False
setup = SiwaveSYZSimulationSetup(self, name)
setup.si_slider_postion = 1
setup.pi_slider_postion = 1
self._setups[name] = setup
return setup

Expand Down Expand Up @@ -3592,3 +3642,35 @@ def _get_connected_ports_from_multizone_cutout(self, terminal_info_dict):
):
connected_ports_list.append((port1_connexion, port2_connexion))
return connected_ports_list

@pyedb_function_handler
def create_port(self, terminal, ref_terminal=None, is_circuit_port=False):
"""Create a port between two terminals.
Parameters
----------
terminal : class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`,
Positive terminal of the port.
ref_terminal : class:`pyaedt.edb_core.edb_data.terminals.EdgeTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PadstackInstanceTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PointTerminal`,
class:`pyaedt.edb_core.edb_data.terminals.PinGroupTerminal`,
optional
Negative terminal of the port.
is_circuit_port : bool, optional
Whether it is a circuit port. The default is ``False``.
Returns
-------
"""
if not ref_terminal:
port = CoaxPort(self, terminal._edb_object)
else:
if is_circuit_port:
port = CircuitPort(self, terminal._edb_object)
else:
port = GapPort(self, terminal._edb_object)
port.ref_terminal = ref_terminal
port.is_circuit_port = is_circuit_port
return port
99 changes: 57 additions & 42 deletions src/pyedb/legacy/edb_core/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -1777,11 +1777,15 @@ def disable_rlc_component(self, component_name):
def set_solder_ball(
self,
component="",
sball_diam="100um",
sball_height="150um",
sball_diam=None,
sball_height=None,
shape="Cylinder",
sball_mid_diam=None,
chip_orientation="chip_down",
auto_reference_size=True,
reference_size_x=0,
reference_size_y=0,
reference_height=0,
):
"""Set cylindrical solder balls on a given component.

Expand All @@ -1801,6 +1805,14 @@ def set_solder_ball(
chip_orientation : str, optional
Give the chip orientation, ``"chip_down"`` or ``"chip_up"``. Default is ``"chip_down"``. Only applicable on
IC model.
auto_reference_size : bool, optional
Whether to automatically set reference size.
reference_size_x : int, str, float, optional
X size of the reference. Applicable when auto_reference_size is False.
reference_size_y : int, str, float, optional
Y size of the reference. Applicable when auto_reference_size is False.
reference_height : int, str, float, optional
Height of the reference. Applicable when auto_reference_size is False.

Returns
-------
Expand All @@ -1818,52 +1830,55 @@ def set_solder_ball(
if not isinstance(component, self._pedb.edb_api.cell.hierarchy.component):
edb_cmp = self.get_component_by_name(component)
cmp = self.instances[component]
else:
else: # pragma: no cover
edb_cmp = component
cmp = self.instances[edb_cmp.GetName()]
if edb_cmp:
cmp_type = edb_cmp.GetComponentType()
if not sball_diam:
pin1 = list(cmp.pins.values())[0].pin
pin_layers = pin1.GetPadstackDef().GetData().GetLayerNames()
pad_params = self._padstack.get_pad_parameters(pin=pin1, layername=pin_layers[0], pad_type=0)
_sb_diam = min([self._get_edb_value(val).ToDouble() for val in pad_params[1]])
sball_diam = _sb_diam
sball_height = round(self._edb.utility.Value(sball_diam).ToDouble(), 9) / 2
if not sball_mid_diam:
sball_mid_diam = sball_diam

if shape == "Cylinder":
sball_shape = self._edb.definition.SolderballShape.Cylinder
else:
sball_shape = self._edb.definition.SolderballShape.Spheroid

cmp_property = edb_cmp.GetComponentProperty().Clone()
if cmp_type == self._edb.definition.ComponentType.IC:
ic_die_prop = cmp_property.GetDieProperty().Clone()
ic_die_prop.SetType(self._edb.definition.DieType.FlipChip)
if chip_orientation.lower() == "chip_down":
ic_die_prop.SetOrientation(self._edb.definition.DieOrientation.ChipDown)
if chip_orientation.lower() == "chip_up":
ic_die_prop.SetOrientation(self._edb.definition.DieOrientation.ChipUp)
else:
ic_die_prop.SetOrientation(self._edb.definition.DieOrientation.ChipDown)
cmp_property.SetDieProperty(ic_die_prop)

solder_ball_prop = cmp_property.GetSolderBallProperty().Clone()
solder_ball_prop.SetDiameter(self._get_edb_value(sball_diam), self._get_edb_value(sball_mid_diam))
solder_ball_prop.SetHeight(self._get_edb_value(sball_height))
cmp_type = edb_cmp.GetComponentType()
if not sball_diam:
pin1 = list(cmp.pins.values())[0].pin
pin_layers = pin1.GetPadstackDef().GetData().GetLayerNames()
pad_params = self._padstack.get_pad_parameters(pin=pin1, layername=pin_layers[0], pad_type=0)
_sb_diam = min([self._get_edb_value(val).ToDouble() for val in pad_params[1]])
sball_diam = _sb_diam
if sball_height:
sball_height = round(self._edb.utility.Value(sball_height).ToDouble(), 9)
else:
sball_height = round(self._edb.utility.Value(sball_diam).ToDouble(), 9) / 2

solder_ball_prop.SetShape(sball_shape)
cmp_property.SetSolderBallProperty(solder_ball_prop)
if not sball_mid_diam:
sball_mid_diam = sball_diam

port_prop = cmp_property.GetPortProperty().Clone()
port_prop.SetReferenceSizeAuto(True)
cmp_property.SetPortProperty(port_prop)
edb_cmp.SetComponentProperty(cmp_property)
return True
if shape == "Cylinder":
sball_shape = self._edb.definition.SolderballShape.Cylinder
else:
return False
sball_shape = self._edb.definition.SolderballShape.Spheroid

cmp_property = edb_cmp.GetComponentProperty().Clone()
if cmp_type == self._edb.definition.ComponentType.IC:
ic_die_prop = cmp_property.GetDieProperty().Clone()
ic_die_prop.SetType(self._edb.definition.DieType.FlipChip)
if chip_orientation.lower() == "chip_up":
ic_die_prop.SetOrientation(self._edb.definition.DieOrientation.ChipUp)
else:
ic_die_prop.SetOrientation(self._edb.definition.DieOrientation.ChipDown)
cmp_property.SetDieProperty(ic_die_prop)

solder_ball_prop = cmp_property.GetSolderBallProperty().Clone()
solder_ball_prop.SetDiameter(self._get_edb_value(sball_diam), self._get_edb_value(sball_mid_diam))
solder_ball_prop.SetHeight(self._get_edb_value(sball_height))

solder_ball_prop.SetShape(sball_shape)
cmp_property.SetSolderBallProperty(solder_ball_prop)

port_prop = cmp_property.GetPortProperty().Clone()
port_prop.SetReferenceHeight(self._pedb.edb_value(reference_height))
port_prop.SetReferenceSizeAuto(auto_reference_size)
if not auto_reference_size:
port_prop.SetReferenceSize(self._pedb.edb_value(reference_size_x), self._pedb.edb_value(reference_size_y))
cmp_property.SetPortProperty(port_prop)
edb_cmp.SetComponentProperty(cmp_property)
return True

@pyedb_function_handler()
def set_component_rlc(
Expand Down
Loading
Loading