From 2950d123950cf4380d2bf1826b5563c61bc480d7 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Wed, 9 Oct 2024 22:53:54 +0200 Subject: [PATCH 01/14] FEAT: hole override --- src/pyedb/configuration/cfg_padstacks.py | 15 +++++--- .../edb_core/edb_data/padstacks_data.py | 37 ++++++++++++++----- .../system/test_edb_configuration_2p0.py | 3 ++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/pyedb/configuration/cfg_padstacks.py b/src/pyedb/configuration/cfg_padstacks.py index eeca365f17..b66aca7383 100644 --- a/src/pyedb/configuration/cfg_padstacks.py +++ b/src/pyedb/configuration/cfg_padstacks.py @@ -47,12 +47,11 @@ def apply(self): instances_layout = self._pedb.padstacks.instances_by_name for inst in self.instances: inst_layout = instances_layout[inst.name] - if inst.definition: - # inst_layout.padstack_definition = inst.definition - # Not supported by EDB API - pass - if inst.backdrill_parameters: - inst_layout.backdrill_parameters = inst.backdrill_parameters + data = dict() + data['backdrill_parameters'] = inst.backdrill_parameters + data["hole_override_enabled"] = inst.hole_override_enabled + data["hole_override_diameter"] = inst.hole_override_diameter + inst_layout.properties = data def get_data_from_db(self): self.definitions = [] @@ -83,6 +82,8 @@ def get_data_from_db(self): id=temp["id"], position=temp["position"], rotation=temp["rotation"], + hole_override_enabled=temp["hole_override_enabled"], + hole_override_diameter=temp["hole_override_diameter"] ) ) instances = [] @@ -114,3 +115,5 @@ def __init__(self, **kwargs): self.id = kwargs.get("id", None) self.position = kwargs.get("position", []) self.rotation = kwargs.get("rotation", None) + self.hole_override_enabled = kwargs.get("hole_override_enabled", None) + self.hole_override_diameter = kwargs.get("hole_override_diameter", None) diff --git a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py index dd427ff4e8..8111812937 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py @@ -330,14 +330,14 @@ def int_to_geometry_type(self, val=0): return self._pedbpadstack._ppadstack.int_to_geometry_type(val) def _update_pad_parameters_parameters( - self, - layer_name=None, - pad_type=None, - geom_type=None, - params=None, - offsetx=None, - offsety=None, - rotation=None, + self, + layer_name=None, + pad_type=None, + geom_type=None, + params=None, + offsetx=None, + offsety=None, + rotation=None, ): """Update padstack parameters. @@ -1932,8 +1932,8 @@ def metal_volume(self): if hole_diam: # pragma no cover hole_finished_size = padstack_def.hole_finished_size via_length = ( - self._pedb.stackup.signal_layers[start_layer].upper_elevation - - self._pedb.stackup.signal_layers[stop_layer].lower_elevation + self._pedb.stackup.signal_layers[start_layer].upper_elevation + - self._pedb.stackup.signal_layers[stop_layer].lower_elevation ) volume = (math.pi * (hole_diam / 2) ** 2 - math.pi * (hole_finished_size / 2) ** 2) * via_length return volume @@ -2335,4 +2335,21 @@ def properties(self): data["position"] = [position.X.ToString(), position.Y.ToString()] data["rotation"] = [rotation.ToString()] data["id"] = self.id + hole_override_enabled, hole_override_diam = self._edb_object.GetHoleOverrideValue() + data["hole_override_enabled"] = hole_override_enabled + data["hole_override_diameter"] = hole_override_diam.ToString() return data + + @properties.setter + def properties(self, params): + name = params.get("name", None) + if name: + self.aedt_name = name + backdrill_parameters = params.get("backdrill_parameters", None) + if backdrill_parameters: + self.backdrill_parameters = backdrill_parameters + h_o_enabled = params.get("hole_override_enabled", None) + h_o_enabled = h_o_enabled if h_o_enabled else self.properties["hole_override_enabled"] + h_o_diameter = params.get("hole_override_diameter") + h_o_diameter = h_o_diameter if h_o_diameter else self.properties["hole_override_diameter"] + self._edb_object.SetHoleOverride(h_o_enabled, self._pedb.edb_value(h_o_diameter)) diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index 105521910f..b036a31e63 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -568,7 +568,10 @@ def test_09_padstack_instance(self, edb_examples): "diameter": "0.5mm", "stub_length": "0.2mm", }, + }, + "hole_override_enabled": True, + "hole_override_diameter":"0.5mm" } ], } From 802e2a5cbc65444e3dfc61bc3a9f620713f60be7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:56:50 +0000 Subject: [PATCH 02/14] MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --- src/pyedb/configuration/cfg_padstacks.py | 4 ++-- .../edb_core/edb_data/padstacks_data.py | 20 +++++++++---------- .../system/test_edb_configuration_2p0.py | 3 +-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pyedb/configuration/cfg_padstacks.py b/src/pyedb/configuration/cfg_padstacks.py index b66aca7383..3b692b9ccd 100644 --- a/src/pyedb/configuration/cfg_padstacks.py +++ b/src/pyedb/configuration/cfg_padstacks.py @@ -48,7 +48,7 @@ def apply(self): for inst in self.instances: inst_layout = instances_layout[inst.name] data = dict() - data['backdrill_parameters'] = inst.backdrill_parameters + data["backdrill_parameters"] = inst.backdrill_parameters data["hole_override_enabled"] = inst.hole_override_enabled data["hole_override_diameter"] = inst.hole_override_diameter inst_layout.properties = data @@ -83,7 +83,7 @@ def get_data_from_db(self): position=temp["position"], rotation=temp["rotation"], hole_override_enabled=temp["hole_override_enabled"], - hole_override_diameter=temp["hole_override_diameter"] + hole_override_diameter=temp["hole_override_diameter"], ) ) instances = [] diff --git a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py index 8111812937..015796c5c6 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py @@ -330,14 +330,14 @@ def int_to_geometry_type(self, val=0): return self._pedbpadstack._ppadstack.int_to_geometry_type(val) def _update_pad_parameters_parameters( - self, - layer_name=None, - pad_type=None, - geom_type=None, - params=None, - offsetx=None, - offsety=None, - rotation=None, + self, + layer_name=None, + pad_type=None, + geom_type=None, + params=None, + offsetx=None, + offsety=None, + rotation=None, ): """Update padstack parameters. @@ -1932,8 +1932,8 @@ def metal_volume(self): if hole_diam: # pragma no cover hole_finished_size = padstack_def.hole_finished_size via_length = ( - self._pedb.stackup.signal_layers[start_layer].upper_elevation - - self._pedb.stackup.signal_layers[stop_layer].lower_elevation + self._pedb.stackup.signal_layers[start_layer].upper_elevation + - self._pedb.stackup.signal_layers[stop_layer].lower_elevation ) volume = (math.pi * (hole_diam / 2) ** 2 - math.pi * (hole_finished_size / 2) ** 2) * via_length return volume diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index b036a31e63..7bd24bf858 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -568,10 +568,9 @@ def test_09_padstack_instance(self, edb_examples): "diameter": "0.5mm", "stub_length": "0.2mm", }, - }, "hole_override_enabled": True, - "hole_override_diameter":"0.5mm" + "hole_override_diameter": "0.5mm", } ], } From e5aed102c2ae4cf2b17b6675550bcd9190872fb7 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Sat, 12 Oct 2024 08:56:58 +0200 Subject: [PATCH 03/14] draft --- src/pyedb/configuration/cfg_data.py | 3 + src/pyedb/configuration/cfg_modeler.py | 68 +++++++++++++++++++ src/pyedb/configuration/configuration.py | 3 + .../edb_core/edb_data/padstacks_data.py | 38 ++++++++--- .../system/test_edb_configuration_2p0.py | 44 +++++++++++- 5 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 src/pyedb/configuration/cfg_modeler.py diff --git a/src/pyedb/configuration/cfg_data.py b/src/pyedb/configuration/cfg_data.py index a694474420..6af0f23ef9 100644 --- a/src/pyedb/configuration/cfg_data.py +++ b/src/pyedb/configuration/cfg_data.py @@ -24,6 +24,7 @@ from pyedb.configuration.cfg_boundaries import CfgBoundaries from pyedb.configuration.cfg_components import CfgComponents from pyedb.configuration.cfg_general import CfgGeneral +from pyedb.configuration.cfg_modeler import CfgModeler from pyedb.configuration.cfg_nets import CfgNets from pyedb.configuration.cfg_operations import CfgOperations from pyedb.configuration.cfg_package_definition import CfgPackageDefinitions @@ -72,3 +73,5 @@ def __init__(self, pedb, **kwargs): self.package_definitions = CfgPackageDefinitions(self._pedb, data=kwargs.get("package_definitions", [])) self.operations = CfgOperations(self._pedb, data=kwargs.get("operations", [])) + + self.modeler = CfgModeler(self._pedb, data=kwargs.get("modeler", {})) diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py new file mode 100644 index 0000000000..947f3f2bc2 --- /dev/null +++ b/src/pyedb/configuration/cfg_modeler.py @@ -0,0 +1,68 @@ +# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from pyedb.dotnet.edb_core.edb_data.padstacks_data import ( + EDBPadstack, + EDBPadstackInstance, +) + + +class CfgTrace: + def __init__(self, **kwargs): + self.name = kwargs.get("name", "") + self.layer = kwargs["layer"] + self.path = kwargs["path"] + self.width = kwargs["width"] + self.net_name = kwargs.get("net_name", "") + self.start_cap_style = kwargs.get("start_cap_style", "flat") + self.end_cap_style = kwargs.get("end_cap_style", "flat") + self.corner_style = kwargs.get("corner_style", "sharp") + + +class CfgModeler: + """Manage configuration general settings.""" + + def __init__(self, pedb, data): + self._pedb = pedb + self.traces = [CfgTrace(**i) for i in data.get("traces", [])] + self.padstack_defs = data.get("padstack_definitions", []) + self.planes = data.get("planes", []) + + def apply(self): + if self.traces: + for t in self.traces: + self._pedb.modeler.create_trace( + path_list=t.path, + layer_name=t.layer, + width=t.width, + start_cap_style=t.start_cap_style, + end_cap_style=t.end_cap_style, + corner_style=t.corner_style, + ) + + if self.padstack_defs: + for p in self.padstack_defs: + pdata = self._pedb._edb.Definition.PadstackDefData.Create() + pdef = self._pedb._edb.Definition.PadstackDef.Create(self._pedb.active_db, p["name"]) + pdef.SetData(pdata) + pdef = EDBPadstack(pdef, self._pedb.padstacks) + pdef.properties = p diff --git a/src/pyedb/configuration/configuration.py b/src/pyedb/configuration/configuration.py index 41a53caaa5..235f71ac58 100644 --- a/src/pyedb/configuration/configuration.py +++ b/src/pyedb/configuration/configuration.py @@ -161,6 +161,9 @@ def run(self, **kwargs): # Configure operations self.cfg_data.operations.apply() + # Modeler + self.cfg_data.modeler.apply() + return True def _load_stackup(self): diff --git a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py index dd427ff4e8..82222672ba 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py @@ -1323,16 +1323,38 @@ def _update_layer_names(self, old_name, updated_name): return True def set_properties(self, **kwargs): - for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]: - value = kwargs.get(k, False) - if value: - setattr(self, k, value) + self.properties = kwargs def get_properties(self): - kwargs = {} - for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]: - kwargs[k] = getattr(self, k) - return kwargs + return self.properties + + @property + def properties(self): + data = dict() + data["hole_parameters"] = self.hole_parameters + data["hole_plating_thickness"] = self.hole_plating_thickness + data["material"] = self.material + data["hole_range"] = self.hole_range + data["pad_parameters"] = self.pad_parameters + return data + + @properties.setter + def properties(self, params): + hole_parameters = params.get("hole_parameters") + if hole_parameters: + self.hole_parameters = hole_parameters + hole_plating_thickness = params.get("hole_plating_thickness") + if hole_plating_thickness: + self.hole_plating_thickness = hole_plating_thickness + material = params.get("material") + if material: + self.material = material + hole_range = params.get("hole_range") + if hole_range: + self.hole_range = hole_range + pad_parameters = params.get("pad_parameters") + if pad_parameters: + self.pad_parameters = pad_parameters class EDBPadstackInstance(Primitive): diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index 105521910f..7ee8abca93 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -32,7 +32,6 @@ pytestmark = [pytest.mark.unit, pytest.mark.legacy] - U8_IC_DIE_PROPERTIES = { "components": [ { @@ -1025,3 +1024,46 @@ def test_17_ic_die_properties(self, edb_examples): _assert_initial_ic_die_properties(component) db.configuration.load(U8_IC_DIE_PROPERTIES, apply_file=True) _assert_final_ic_die_properties(component) + + def test_18_modeler(self, edb_examples): + data = { + "modeler": { + "traces": [ + {"name": "trace_1", "layer": "TOP", "width": "0.1mm", "path": [[0, 0], [0, "10mm"]], + "net_name": "SIG", + "start_cap_style": "flat", "end_cap_style": "flat", "corner_style": "round"} + ], + "padstack_definitions": [ + { + "name": "via_1", + "hole_plating_thickness": "0.025mm", + "material": "copper", + "pad_parameters": { + 'regular_pad': [ + {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0.1mm', 'offset_y': '0', + 'rotation': '0', + 'diameter': '0.5mm'} + ], + 'anti_pad': [ + {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', + 'rotation': '0', + 'diameter': '1mm'} + ], + }, + "hole_range": "through", + "hole_parameters": { + "shape": "circle", + "diameter": "0.25mm", + } + } + ], + "padstack_instances": [ + + ] + } + } + edbapp = edb_examples.create_empty_edb() + edbapp.stackup.create_symmetric_stackup(2) + edbapp.configuration.load(data, apply_file=True) + #edbapp.nets.plot() + edbapp.close() From 2087f1a7c606429fb90ad438168a5cd8948a451e Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Sat, 12 Oct 2024 11:23:27 +0200 Subject: [PATCH 04/14] draft --- src/pyedb/configuration/cfg_modeler.py | 10 +++ src/pyedb/dotnet/edb_core/cell/layout.py | 2 +- .../edb_core/edb_data/padstacks_data.py | 77 +++++++++++++++---- .../system/test_edb_configuration_2p0.py | 20 +++-- 4 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index 947f3f2bc2..c91e742440 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -45,6 +45,7 @@ def __init__(self, pedb, data): self._pedb = pedb self.traces = [CfgTrace(**i) for i in data.get("traces", [])] self.padstack_defs = data.get("padstack_definitions", []) + self.padstack_instances = data.get("padstack_instances", []) self.planes = data.get("planes", []) def apply(self): @@ -53,6 +54,7 @@ def apply(self): self._pedb.modeler.create_trace( path_list=t.path, layer_name=t.layer, + net_name=t.net_name, width=t.width, start_cap_style=t.start_cap_style, end_cap_style=t.end_cap_style, @@ -66,3 +68,11 @@ def apply(self): pdef.SetData(pdata) pdef = EDBPadstack(pdef, self._pedb.padstacks) pdef.properties = p + + if self.padstack_instances: + for p in self.padstack_instances: + p_inst = self._pedb.padstacks.place( + position=p["position"], + definition_name=p["definition"], + ) + p_inst.properties = p diff --git a/src/pyedb/dotnet/edb_core/cell/layout.py b/src/pyedb/dotnet/edb_core/cell/layout.py index 1c298f5af9..cee9e7fb54 100644 --- a/src/pyedb/dotnet/edb_core/cell/layout.py +++ b/src/pyedb/dotnet/edb_core/cell/layout.py @@ -313,7 +313,7 @@ def find_net_by_name(self, value: str): """ obj = self._pedb._edb.Cell.Net.FindByName(self._edb_object, value) if obj.IsNull(): - raise ValueError(f"Net {value} doesn't exist") + return None else: return EDBNetsData(obj, self._pedb) diff --git a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py index 1eaf0d5ea5..0f58d11e93 100644 --- a/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py +++ b/src/pyedb/dotnet/edb_core/edb_data/padstacks_data.py @@ -330,14 +330,14 @@ def int_to_geometry_type(self, val=0): return self._pedbpadstack._ppadstack.int_to_geometry_type(val) def _update_pad_parameters_parameters( - self, - layer_name=None, - pad_type=None, - geom_type=None, - params=None, - offsetx=None, - offsety=None, - rotation=None, + self, + layer_name=None, + pad_type=None, + geom_type=None, + params=None, + offsetx=None, + offsety=None, + rotation=None, ): """Update padstack parameters. @@ -1954,8 +1954,8 @@ def metal_volume(self): if hole_diam: # pragma no cover hole_finished_size = padstack_def.hole_finished_size via_length = ( - self._pedb.stackup.signal_layers[start_layer].upper_elevation - - self._pedb.stackup.signal_layers[stop_layer].lower_elevation + self._pedb.stackup.signal_layers[start_layer].upper_elevation + - self._pedb.stackup.signal_layers[stop_layer].lower_elevation ) volume = (math.pi * (hole_diam / 2) ** 2 - math.pi * (hole_finished_size / 2) ** 2) * via_length return volume @@ -1997,6 +1997,10 @@ def aedt_name(self): name = str(name).strip("'") return name + @aedt_name.setter + def aedt_name(self, value): + self._edb_object.SetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, value) + def parametrize_position(self, prefix=None): """Parametrize the instance position. @@ -2350,13 +2354,22 @@ def get_reference_pins(self, reference_net="GND", search_radius=5e-3, max_limit= @property def properties(self): data = {} + data["id"] = self.id data["name"] = self.aedt_name + net = self._edb_object.GetNet() + data["net_name"] = net.GetName() if not net.IsNull() else "" data["definition"] = self.padstack_definition - data["backdrill_parameters"] = self.backdrill_parameters + data["is_pin"] = self.is_pin + + _, start_layer, stop_layer = self._edb_object.GetLayerRange() + data["layer_range"] = [start_layer.GetName(), stop_layer.GetName()] + _, position, rotation = self._edb_object.GetPositionAndRotationValue() data["position"] = [position.X.ToString(), position.Y.ToString()] - data["rotation"] = [rotation.ToString()] - data["id"] = self.id + data["rotation"] = rotation.ToString() + + data["backdrill_parameters"] = self.backdrill_parameters + hole_override_enabled, hole_override_diam = self._edb_object.GetHoleOverrideValue() data["hole_override_enabled"] = hole_override_enabled data["hole_override_diameter"] = hole_override_diam.ToString() @@ -2367,11 +2380,49 @@ def properties(self, params): name = params.get("name", None) if name: self.aedt_name = name + + net_name = params.get("net_name", None) + if net_name: + net = self._pedb.layout.find_net_by_name(net_name) + if net: + net = net._edb_object + else: + net = self._pedb._edb.Cell.Net.Create(self._pedb.active_layout, net_name) + self._edb_object.SetNet(net) + is_pin = params.get("is_pin", None) + if is_pin is not None: + self.is_pin = is_pin + + layer_range = params.get("layer_range", None) + if layer_range: + start_layer = self._pedb.stackup[layer_range[0]]._edb_object + stop_layer = self._pedb.stackup[layer_range[1]]._edb_object + self._edb_object.SetLayerRange(start_layer, stop_layer) + + position = params.get("position", None) + if position: + point_data = self._pedb._edb.Geometry.PointData( + self._pedb.edb_value(position[0]), + self._pedb.edb_value(position[1])) + self._edb_object.SetPositionAndRotation( + point_data, + self._pedb.edb_value(self.properties["rotation"]) + ) + rotation = params.get("rotation", None) + if rotation is not None: + _, point_data, _ = self._edb_object.GetPositionAndRotationValue() + self._edb_object.SetPositionAndRotation( + point_data, + self._pedb.edb_value(rotation) + ) + backdrill_parameters = params.get("backdrill_parameters", None) if backdrill_parameters: self.backdrill_parameters = backdrill_parameters + h_o_enabled = params.get("hole_override_enabled", None) h_o_enabled = h_o_enabled if h_o_enabled else self.properties["hole_override_enabled"] + h_o_diameter = params.get("hole_override_diameter") h_o_diameter = h_o_diameter if h_o_diameter else self.properties["hole_override_diameter"] self._edb_object.SetHoleOverride(h_o_enabled, self._pedb.edb_value(h_o_diameter)) diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index 145e5aa04c..cb7cb983f8 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -1037,17 +1037,23 @@ def test_18_modeler(self, edb_examples): ], "padstack_definitions": [ { - "name": "via_1", + "name": "via", "hole_plating_thickness": "0.025mm", "material": "copper", "pad_parameters": { 'regular_pad': [ - {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0.1mm', 'offset_y': '0', + {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0mm', 'offset_y': '0', + 'rotation': '0', + 'diameter': '0.5mm'}, + {'layer_name': 'BOT', 'shape': 'circle', 'offset_x': '0mm', 'offset_y': '0', 'rotation': '0', 'diameter': '0.5mm'} ], 'anti_pad': [ {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', + 'rotation': '0', + 'diameter': '1mm'}, + {'layer_name': 'BOT', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0', 'diameter': '1mm'} ], @@ -1060,12 +1066,16 @@ def test_18_modeler(self, edb_examples): } ], "padstack_instances": [ - - ] + {"name": "via_1", + "definition": "via", + "layer_range": ["TOP", "BOT"], + "position": [0, 0], + "net_name": "SIG" + } + ], } } edbapp = edb_examples.create_empty_edb() edbapp.stackup.create_symmetric_stackup(2) edbapp.configuration.load(data, apply_file=True) - #edbapp.nets.plot() edbapp.close() From ed5ec5afb9d61b3d372cd0e0085b85cc794127cc Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Mon, 14 Oct 2024 13:38:08 +0200 Subject: [PATCH 05/14] draft --- src/pyedb/configuration/cfg_common.py | 21 +++++++++++++++++++ src/pyedb/configuration/cfg_data.py | 3 +++ src/pyedb/configuration/cfg_modeler.py | 8 ++++--- src/pyedb/configuration/configuration.py | 3 +++ .../system/test_edb_configuration_2p0.py | 12 +++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/pyedb/configuration/cfg_common.py b/src/pyedb/configuration/cfg_common.py index bc08ccac42..ee71067cf8 100644 --- a/src/pyedb/configuration/cfg_common.py +++ b/src/pyedb/configuration/cfg_common.py @@ -1,3 +1,4 @@ + # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # @@ -39,3 +40,23 @@ def set_attributes(self, pedb_object): if attr not in dir(pedb_object): raise AttributeError(f"Invalid attribute '{attr}' in '{pedb_object}'") setattr(pedb_object, attr, value) + + +class CfgVar: + def __init__(self, **kwargs): + self.name = kwargs["name"] + self.value = kwargs["value"] + self.description = kwargs.get("description", "") + + +class CfgVariables: + def __init__(self, pedb, data): + self._pedb = pedb + self.variables = [CfgVar(**i) for i in data] + + def apply(self): + for i in self.variables: + if i.name.startswith("$"): + self._pedb.add_project_variable(i.name, i.value) + else: + self._pedb.add_design_variable(i.name, i.value) diff --git a/src/pyedb/configuration/cfg_data.py b/src/pyedb/configuration/cfg_data.py index 6af0f23ef9..0c3e630b98 100644 --- a/src/pyedb/configuration/cfg_data.py +++ b/src/pyedb/configuration/cfg_data.py @@ -22,6 +22,7 @@ from pyedb.configuration.cfg_boundaries import CfgBoundaries +from pyedb.configuration.cfg_common import CfgVariables from pyedb.configuration.cfg_components import CfgComponents from pyedb.configuration.cfg_general import CfgGeneral from pyedb.configuration.cfg_modeler import CfgModeler @@ -75,3 +76,5 @@ def __init__(self, pedb, **kwargs): self.operations = CfgOperations(self._pedb, data=kwargs.get("operations", [])) self.modeler = CfgModeler(self._pedb, data=kwargs.get("modeler", {})) + + self.variables = CfgVariables(self._pedb, data=kwargs.get("variables", [])) diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index c91e742440..53f5f5c1a3 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -33,8 +33,8 @@ def __init__(self, **kwargs): self.path = kwargs["path"] self.width = kwargs["width"] self.net_name = kwargs.get("net_name", "") - self.start_cap_style = kwargs.get("start_cap_style", "flat") - self.end_cap_style = kwargs.get("end_cap_style", "flat") + self.start_cap_style = kwargs.get("start_cap_style", "round") + self.end_cap_style = kwargs.get("end_cap_style", "round") self.corner_style = kwargs.get("corner_style", "sharp") @@ -51,7 +51,7 @@ def __init__(self, pedb, data): def apply(self): if self.traces: for t in self.traces: - self._pedb.modeler.create_trace( + obj = self._pedb.modeler.create_trace( path_list=t.path, layer_name=t.layer, net_name=t.net_name, @@ -60,6 +60,7 @@ def apply(self): end_cap_style=t.end_cap_style, corner_style=t.corner_style, ) + obj.aedt_name = t.name if self.padstack_defs: for p in self.padstack_defs: @@ -72,6 +73,7 @@ def apply(self): if self.padstack_instances: for p in self.padstack_instances: p_inst = self._pedb.padstacks.place( + via_name=p["name"], position=p["position"], definition_name=p["definition"], ) diff --git a/src/pyedb/configuration/configuration.py b/src/pyedb/configuration/configuration.py index 235f71ac58..4e30035fe7 100644 --- a/src/pyedb/configuration/configuration.py +++ b/src/pyedb/configuration/configuration.py @@ -106,6 +106,9 @@ def load(self, config_file, append=True, apply_file=False, output_file=None, ope def run(self, **kwargs): """Apply configuration settings to the current design""" + if self.cfg_data.variables: + self.cfg_data.variables.apply() + if self.cfg_data.general: self.cfg_data.general.apply() diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index cb7cb983f8..642af43797 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -1079,3 +1079,15 @@ def test_18_modeler(self, edb_examples): edbapp.stackup.create_symmetric_stackup(2) edbapp.configuration.load(data, apply_file=True) edbapp.close() + + def test_19_variables(self, edb_examples): + data = { + "variables": [ + {"name": "var_1", "value": "1mm", "description": "No description"}, + {"name": "$var_2", "value": "1mm", "description": "No description"} + ] + } + edbapp = edb_examples.create_empty_edb() + edbapp.stackup.create_symmetric_stackup(2) + edbapp.configuration.load(data, apply_file=True) + edbapp.close() From 7b8c904ed38edebf17957019f2ff67708d25bb43 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Mon, 14 Oct 2024 15:22:23 +0200 Subject: [PATCH 06/14] draft --- src/pyedb/configuration/cfg_modeler.py | 32 ++++++++++++++++++- .../system/test_edb_configuration_2p0.py | 10 +++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index 53f5f5c1a3..e2f2e12734 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -38,6 +38,19 @@ def __init__(self, **kwargs): self.corner_style = kwargs.get("corner_style", "sharp") +class CfgPlane: + def __init__(self, **kwargs): + self.name = kwargs.get("name", "") + self.layer = kwargs["layer"] + self.net_name = kwargs.get("net_name", "") + self.type = kwargs.get("type", "rectangle") + self.lower_left_point = kwargs["lower_left_point"] + self.upper_right_point = kwargs["upper_right_point"] + self.corner_radius = kwargs.get("corner_radius", 0) + self.rotation = kwargs.get("rotation", 0) + self.voids = kwargs.get("voids", []) + + class CfgModeler: """Manage configuration general settings.""" @@ -46,7 +59,7 @@ def __init__(self, pedb, data): self.traces = [CfgTrace(**i) for i in data.get("traces", [])] self.padstack_defs = data.get("padstack_definitions", []) self.padstack_instances = data.get("padstack_instances", []) - self.planes = data.get("planes", []) + self.planes = [CfgPlane(**i) for i in data.get("planes", [])] def apply(self): if self.traces: @@ -78,3 +91,20 @@ def apply(self): definition_name=p["definition"], ) p_inst.properties = p + + if self.planes: + for p in self.planes: + if p.type == "rectangle": + obj = self._pedb.modeler.create_rectangle( + layer_name=p.layer, + net_name=p.net_name, + lower_left_point=p.lower_left_point, + upper_right_point=p.upper_right_point, + corner_radius=p.corner_radius, + rotation=p.rotation, + ) + obj.aedt_name = p.name + for v in p.voids: + for i in self._pedb.layout.primitives: + if i.aedt_name == v: + self._pedb.modeler.add_void(obj, i) diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index 642af43797..28ef10d41d 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -1033,7 +1033,8 @@ def test_18_modeler(self, edb_examples): "traces": [ {"name": "trace_1", "layer": "TOP", "width": "0.1mm", "path": [[0, 0], [0, "10mm"]], "net_name": "SIG", - "start_cap_style": "flat", "end_cap_style": "flat", "corner_style": "round"} + "start_cap_style": "flat", "end_cap_style": "flat", "corner_style": "round"}, + {"name": "trace_1_void", "layer": "TOP", "width": "0.3mm", "path": [[0, 0], [0, "10mm"]]} ], "padstack_definitions": [ { @@ -1073,11 +1074,18 @@ def test_18_modeler(self, edb_examples): "net_name": "SIG" } ], + "planes": [ + {"name": "GND_TOP", "layer": "TOP", "net_name": "GND", "lower_left_point": [0, 0], + "upper_right_point": [0, "12mm"], "voids": ["trace_1_void"]}, + ] } } edbapp = edb_examples.create_empty_edb() edbapp.stackup.create_symmetric_stackup(2) edbapp.configuration.load(data, apply_file=True) + assert [i for i in edbapp.layout.primitives if i.aedt_name == "trace_1"] + plane = [i for i in edbapp.layout.primitives if i.aedt_name == "GND_TOP"][0] + assert plane.voids edbapp.close() def test_19_variables(self, edb_examples): From a200276e01c29fbbb05231800bbd38fee4ce46d0 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 15 Oct 2024 15:36:52 +0200 Subject: [PATCH 07/14] draft --- src/pyedb/configuration/cfg_components.py | 3 +++ src/pyedb/configuration/cfg_modeler.py | 13 ++++++++++ src/pyedb/configuration/cfg_padstacks.py | 3 +++ .../system/test_edb_configuration_2p0.py | 24 +++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/src/pyedb/configuration/cfg_components.py b/src/pyedb/configuration/cfg_components.py index 8e169e6ad4..b9219ddc94 100644 --- a/src/pyedb/configuration/cfg_components.py +++ b/src/pyedb/configuration/cfg_components.py @@ -45,6 +45,7 @@ def __init__(self, **kwargs): self.pin_pair_model = kwargs.get("pin_pair_model", None) self.spice_model = kwargs.get("spice_model", None) self.s_parameter_model = kwargs.get("s_parameter_model", None) + self.placement_layer = kwargs.get("placement_layer", None) class CfgComponents: @@ -72,6 +73,8 @@ def apply(self): c_db.model_properties = {"spice_model": comp.spice_model} if comp.s_parameter_model: c_db.model_properties = {"s_parameter_model": comp.s_parameter_model} + if comp.placement_layer: + c_db.placement_layer = comp.placement_layer def _load_data_from_db(self): self.components = [] diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index e2f2e12734..12ebc6545e 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -60,6 +60,7 @@ def __init__(self, pedb, data): self.padstack_defs = data.get("padstack_definitions", []) self.padstack_instances = data.get("padstack_instances", []) self.planes = [CfgPlane(**i) for i in data.get("planes", [])] + self.components = data.get("components", []) def apply(self): if self.traces: @@ -108,3 +109,15 @@ def apply(self): for i in self._pedb.layout.primitives: if i.aedt_name == v: self._pedb.modeler.add_void(obj, i) + + if self.components: + pedb_p_inst = self._pedb.padstacks.instances_by_name + for c in self.components: + obj = self._pedb.components.create( + [pedb_p_inst[i] for i in c["pins"]], + component_name=c["reference_designator"], + placement_layer=c["placement_layer"], + component_part_name=c["definition"], + ) + obj.solder_ball_properties = c["solder_ball_properties"] + obj.port_properties = c["port_properties"] diff --git a/src/pyedb/configuration/cfg_padstacks.py b/src/pyedb/configuration/cfg_padstacks.py index 3b692b9ccd..a73a08ece5 100644 --- a/src/pyedb/configuration/cfg_padstacks.py +++ b/src/pyedb/configuration/cfg_padstacks.py @@ -51,6 +51,7 @@ def apply(self): data["backdrill_parameters"] = inst.backdrill_parameters data["hole_override_enabled"] = inst.hole_override_enabled data["hole_override_diameter"] = inst.hole_override_diameter + data["is_pin"] = inst.is_pin inst_layout.properties = data def get_data_from_db(self): @@ -84,6 +85,7 @@ def get_data_from_db(self): rotation=temp["rotation"], hole_override_enabled=temp["hole_override_enabled"], hole_override_diameter=temp["hole_override_diameter"], + is_pin=temp["is_pin"], ) ) instances = [] @@ -117,3 +119,4 @@ def __init__(self, **kwargs): self.rotation = kwargs.get("rotation", None) self.hole_override_enabled = kwargs.get("hole_override_enabled", None) self.hole_override_diameter = kwargs.get("hole_override_diameter", None) + self.is_pin = kwargs.get("is_pin", None) diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index 28ef10d41d..bc4845f567 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -1072,11 +1072,34 @@ def test_18_modeler(self, edb_examples): "layer_range": ["TOP", "BOT"], "position": [0, 0], "net_name": "SIG" + }, + {"name": "pin_1", + "definition": "via", + "layer_range": ["TOP", "TOP"], + "position": [0, "1mm"], + "net_name": "SIG", + "is_pin": True } ], "planes": [ {"name": "GND_TOP", "layer": "TOP", "net_name": "GND", "lower_left_point": [0, 0], "upper_right_point": [0, "12mm"], "voids": ["trace_1_void"]}, + ], + "components": [ + { + "reference_designator": "U1", + "pins": ["pin_1"], + "part_type": "io", + "definition": "BGA", + "placement_layer": "TOP", + "solder_ball_properties": {"shape": "cylinder", "diameter": "244um", "height": "406um"}, + "port_properties": { + "reference_offset": "0.1mm", + "reference_size_auto": True, + "reference_size_x": 0, + "reference_size_y": 0, + }, + }, ] } } @@ -1086,6 +1109,7 @@ def test_18_modeler(self, edb_examples): assert [i for i in edbapp.layout.primitives if i.aedt_name == "trace_1"] plane = [i for i in edbapp.layout.primitives if i.aedt_name == "GND_TOP"][0] assert plane.voids + assert edbapp.components["U1"] edbapp.close() def test_19_variables(self, edb_examples): From 012edd2781c442d0eb1670e7c1630b904d75f2e7 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 09:48:35 +0100 Subject: [PATCH 08/14] FEAT: edb cfg wave port --- src/pyedb/configuration/cfg_ports_sources.py | 98 +++++++++++++++++-- .../system/test_edb_configuration_2p0.py | 55 +++++++++++ 2 files changed, 147 insertions(+), 6 deletions(-) diff --git a/src/pyedb/configuration/cfg_ports_sources.py b/src/pyedb/configuration/cfg_ports_sources.py index feb549a94c..d26cc097ab 100644 --- a/src/pyedb/configuration/cfg_ports_sources.py +++ b/src/pyedb/configuration/cfg_ports_sources.py @@ -20,7 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list from pyedb.configuration.cfg_common import CfgBase +from pyedb.dotnet.edb_core.edb_data.ports import WavePort +from pyedb.dotnet.edb_core.geometry.point_data import PointData class CfgTerminalInfo(CfgBase): @@ -114,11 +117,28 @@ def export_properties(self): class CfgPorts: def __init__(self, pedb, ports_data): self._pedb = pedb - self.ports = [CfgPort(self._pedb, **p) for p in ports_data] + + self.ports = [] + for p in ports_data: + if p["type"] == "wave_port": + self.ports.append(CfgWavePort(self._pedb, **p)) + elif p["type"] == "diff_wave_port": + self.ports.append(CfgDiffWavePort(self._pedb, **p)) + elif p["type"] in ["coax", "circuit"]: + self.ports.append(CfgPort(self._pedb, **p)) + else: + raise ValueError("Unknown port type") def apply(self): + edb_primitives = {} + for i in self._pedb.layout.primitives: + if i.aedt_name: + edb_primitives[i.aedt_name] = i for p in self.ports: - p.create() + if p.type not in ["wave_port", "diff_wave_port"]: + p.set_parameters_to_edb() + else: + p.set_parameters_to_edb(edb_primitives) def get_data_from_db(self): self.ports = [] @@ -188,8 +208,8 @@ def export_properties(self): class CfgCircuitElement(CfgBase): def __init__(self, pedb, **kwargs): self._pedb = pedb - self.name = kwargs.get("name", None) - self.type = kwargs.get("type", None) + self.name = kwargs["name"] + self.type = kwargs["type"] self.reference_designator = kwargs.get("reference_designator", None) self.distributed = kwargs.get("distributed", False) @@ -321,7 +341,7 @@ class CfgPort(CfgCircuitElement): def __init__(self, pedb, **kwargs): super().__init__(pedb, **kwargs) - def create(self): + def set_parameters_to_edb(self): """Create port.""" self._create_terminals() is_circuit_port = True if self.type == "circuit" else False @@ -356,7 +376,7 @@ def __init__(self, pedb, **kwargs): self.magnitude = kwargs.get("magnitude", 0.001) - def create(self): + def set_parameters_to_edb(self): """Create sources.""" self._create_terminals() # is_circuit_port = True if self.type == "circuit" else False @@ -385,3 +405,69 @@ def export_properties(self): "positive_terminal": self.positive_terminal_info.export_properties(), "negative_terminal": self.negative_terminal_info.export_properties(), } + + +class CfgWavePort: + def __init__(self, pedb, **kwargs): + self._pedb = pedb + self.name = kwargs["name"] + self.type = kwargs["type"] + self.primitive_name = kwargs["primitive_name"] + self.point_on_edge = kwargs["point_on_edge"] + self.horizontal_extent_factor = kwargs.get("horizontal_extent_factor", 5) + self.vertical_extent_factor = kwargs.get("vertical_extent_factor", 3) + self.pec_launch_width = kwargs.get("pec_launch_width", "0.01mm") + + def set_parameters_to_edb(self, edb_primitives): + point_on_edge = PointData(self._pedb, x=self.point_on_edge[0], y=self.point_on_edge[1]) + primitive = edb_primitives[self.primitive_name] + pos_edge = self._pedb.edb_api.cell.terminal.PrimitiveEdge.Create(primitive._edb_object, + point_on_edge._edb_object) + pos_edge = convert_py_list_to_net_list(pos_edge, self._pedb.edb_api.cell.terminal.Edge) + edge_term = self._pedb.edb_api.cell.terminal.EdgeTerminal.Create( + primitive._edb_object.GetLayout(), primitive._edb_object.GetNet(), self.name, pos_edge, isRef=False + ) + edge_term.SetImpedance(self._pedb.edb_value(50)) + wave_port = WavePort(self._pedb, edge_term) + wave_port.horizontal_extent_factor = self.horizontal_extent_factor + wave_port.vertical_extent_factor = self.vertical_extent_factor + wave_port.pec_launch_width = self.pec_launch_width + wave_port.hfss_type = "Wave" + wave_port.do_renormalize = True + return wave_port + + +class CfgDiffWavePort: + def __init__(self, pedb, **kwargs): + self._pedb = pedb + self.name = kwargs["name"] + self.type = kwargs["type"] + self.horizontal_extent_factor = kwargs.get("horizontal_extent_factor", 5) + self.vertical_extent_factor = kwargs.get("vertical_extent_factor", 3) + self.pec_launch_width = kwargs.get("pec_launch_width", "0.01mm") + self.positive_port = CfgWavePort(self._pedb, + name=self.name + ":T1", + type=self.type, + horizontal_extent_factor=self.horizontal_extent_factor, + vertical_extent_factor=self.vertical_extent_factor, + pec_launch_width=self.pec_launch_width, + **kwargs["positive_terminal"]) + self.negative_port = CfgWavePort(self._pedb, + name=self.name + ":T2", + type=self.type, + horizontal_extent_factor=self.horizontal_extent_factor, + vertical_extent_factor=self.vertical_extent_factor, + pec_launch_width=self.pec_launch_width, + **kwargs["negative_terminal"]) + + def set_parameters_to_edb(self, edb_primitives): + pos_term = self.positive_port.set_parameters_to_edb(edb_primitives) + neg_term = self.negative_port.set_parameters_to_edb(edb_primitives) + edb_list = convert_py_list_to_net_list( + [pos_term._edb_object, neg_term._edb_object], self._pedb.edb_api.cell.terminal.Terminal + ) + _edb_boundle_terminal = self._pedb.edb_api.cell.terminal.BundleTerminal.Create(edb_list) + _edb_boundle_terminal.SetName(self.name) + pos, neg = list(_edb_boundle_terminal.GetTerminals()) + pos.SetName(self.name + ":T1") + neg.SetName(self.name + ":T2") diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index bc4845f567..aeeeb9b58f 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -385,6 +385,7 @@ def test_05f_ports_between_two_points(self, edb_examples): "ports": [ { "name": "x_y_port", + "type": "circuit", "positive_terminal": { "coordinates": {"layer": "1_Top", "point": ["104mm", "37mm"], "net": "AVCC_1V3"} }, @@ -401,6 +402,60 @@ def test_05f_ports_between_two_points(self, edb_examples): assert data_from_db["ports"][0]["positive_terminal"]["coordinates"]["net"] == "AVCC_1V3" edbapp.close() + def test_05g_wave_port(self, edb_examples): + edbapp = edb_examples.create_empty_edb() + edbapp.stackup.create_symmetric_stackup(2) + edbapp.modeler.create_rectangle(layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], + upper_right_point=["2mm", "2mm"]) + prim_1 = edbapp.modeler.create_trace(path_list=([0, 0], [0, "1mm"]), layer_name="TOP", net_name="SIG", + width="0.1mm", + start_cap_style="Flat", end_cap_style="Flat") + prim_1.aedt_name = "path_1" + data = {"ports": [ + { + "name": "wport_1", + "type": "wave_port", + "primitive_name": prim_1.aedt_name, + "point_on_edge": [0, "1mm"], + "horizontal_extent_factor": 6, + "vertical_extent_factor": 4, + "pec_launch_width": "0,2mm" + } + ]} + edbapp.configuration.load(data, apply_file=True) + assert edbapp.ports["wport_1"].horizontal_extent_factor == 6 + edbapp.close() + + def test_05h_diff_wave_port(self, edb_examples): + edbapp = edb_examples.create_empty_edb() + edbapp.stackup.create_symmetric_stackup(2) + edbapp.modeler.create_rectangle(layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], + upper_right_point=["2mm", "2mm"]) + prim_1 = edbapp.modeler.create_trace(path_list=([0, 0], [0, "1mm"]), layer_name="TOP", net_name="SIG", + width="0.1mm", + start_cap_style="Flat", end_cap_style="Flat") + prim_1.aedt_name = "path_1" + prim_2 = edbapp.modeler.create_trace(path_list=(["1mm", 0], ["1mm", "1mm"]), layer_name="TOP", net_name="SIG", + width="0.1mm", + start_cap_style="Flat", end_cap_style="Flat") + prim_2.aedt_name = "path_2" + data = {"ports": [ + { + "name": "diff_wave_1", + "type": "diff_wave_port", + "positive_terminal": {"primitive_name": prim_1.aedt_name, + "point_on_edge": [0, "1mm"]}, + "negative_terminal": {"primitive_name": prim_2.aedt_name, + "point_on_edge": ["1mm", "1mm"]}, + "horizontal_extent_factor": 6, + "vertical_extent_factor": 4, + "pec_launch_width": "0,2mm" + } + ]} + edbapp.configuration.load(data, apply_file=True) + assert edbapp.ports["diff_wave_1"].horizontal_extent_factor == 6 + edbapp.close() + def test_06_s_parameters(self, edb_examples): data = { "general": {"s_parameter_library": self.local_input_folder}, From 8b153cfe8305afca47917d774c044cc3df019620 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 10:27:30 +0100 Subject: [PATCH 09/14] minor fix --- src/pyedb/configuration/cfg_ports_sources.py | 9 +++++---- src/pyedb/configuration/configuration.py | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/pyedb/configuration/cfg_ports_sources.py b/src/pyedb/configuration/cfg_ports_sources.py index d26cc097ab..d9b59b0846 100644 --- a/src/pyedb/configuration/cfg_ports_sources.py +++ b/src/pyedb/configuration/cfg_ports_sources.py @@ -445,16 +445,17 @@ def __init__(self, pedb, **kwargs): self.horizontal_extent_factor = kwargs.get("horizontal_extent_factor", 5) self.vertical_extent_factor = kwargs.get("vertical_extent_factor", 3) self.pec_launch_width = kwargs.get("pec_launch_width", "0.01mm") + + kwargs["positive_terminal"]["type"] = "wave_port" + kwargs["positive_terminal"]["name"] = self.name + ":T1" self.positive_port = CfgWavePort(self._pedb, - name=self.name + ":T1", - type=self.type, horizontal_extent_factor=self.horizontal_extent_factor, vertical_extent_factor=self.vertical_extent_factor, pec_launch_width=self.pec_launch_width, **kwargs["positive_terminal"]) + kwargs["negative_terminal"]["type"] = "wave_port" + kwargs["negative_terminal"]["name"] = self.name + ":T2" self.negative_port = CfgWavePort(self._pedb, - name=self.name + ":T2", - type=self.type, horizontal_extent_factor=self.horizontal_extent_factor, vertical_extent_factor=self.vertical_extent_factor, pec_launch_width=self.pec_launch_width, diff --git a/src/pyedb/configuration/configuration.py b/src/pyedb/configuration/configuration.py index 4e30035fe7..8fda17288c 100644 --- a/src/pyedb/configuration/configuration.py +++ b/src/pyedb/configuration/configuration.py @@ -126,9 +126,6 @@ def run(self, **kwargs): # Configure pin groups self.cfg_data.pin_groups.apply() - # Configure ports - self.cfg_data.ports.apply() - # Configure sources self.cfg_data.sources.apply() @@ -167,6 +164,9 @@ def run(self, **kwargs): # Modeler self.cfg_data.modeler.apply() + # Configure ports + self.cfg_data.ports.apply() + return True def _load_stackup(self): From 103724196b032d1e8feca7a536647bcc8badcb97 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 11:08:38 +0100 Subject: [PATCH 10/14] minor fix --- src/pyedb/configuration/cfg_ports_sources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyedb/configuration/cfg_ports_sources.py b/src/pyedb/configuration/cfg_ports_sources.py index d9b59b0846..a93edc8a83 100644 --- a/src/pyedb/configuration/cfg_ports_sources.py +++ b/src/pyedb/configuration/cfg_ports_sources.py @@ -68,7 +68,7 @@ def __init__(self, pedb, sources_data): def apply(self): for src in self.sources: - src.create() + src.set_parameters_to_edb() def get_data_from_db(self): self.sources = [] From 31e1a9fc65b46754d35488dc0049ea0c0174336d Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 12:42:41 +0100 Subject: [PATCH 11/14] minor fix --- src/pyedb/configuration/cfg_components.py | 3 ++ src/pyedb/configuration/cfg_modeler.py | 38 +++++++++++-------- src/pyedb/configuration/cfg_padstacks.py | 28 +++++++++----- src/pyedb/configuration/cfg_ports_sources.py | 6 +-- .../system/test_edb_configuration_2p0.py | 22 +++++------ 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/pyedb/configuration/cfg_components.py b/src/pyedb/configuration/cfg_components.py index b85b5f116a..5ad57d38c1 100644 --- a/src/pyedb/configuration/cfg_components.py +++ b/src/pyedb/configuration/cfg_components.py @@ -33,6 +33,9 @@ def __init__(self, pedb, pedb_object, **kwargs): self.reference_designator = kwargs.get("reference_designator", None) self.definition = kwargs.get("definition", None) self.type = kwargs["part_type"].lower() if kwargs.get("part_type") else None + self.placement_layer = kwargs["placement_layer"] + self.pins = kwargs.get("pins", []) + self.port_properties = kwargs.get("port_properties", {}) self.solder_ball_properties = kwargs.get("solder_ball_properties", {}) self.ic_die_properties = kwargs.get("ic_die_properties", {}) diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index 12ebc6545e..6d4db2e355 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -22,8 +22,10 @@ from pyedb.dotnet.edb_core.edb_data.padstacks_data import ( EDBPadstack, - EDBPadstackInstance, ) +from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition +from pyedb.configuration.cfg_padstacks import CfgPadstackInstance +from pyedb.configuration.cfg_components import CfgComponent class CfgTrace: @@ -57,10 +59,12 @@ class CfgModeler: def __init__(self, pedb, data): self._pedb = pedb self.traces = [CfgTrace(**i) for i in data.get("traces", [])] - self.padstack_defs = data.get("padstack_definitions", []) - self.padstack_instances = data.get("padstack_instances", []) + self.padstack_defs = [CfgPadstackDefinition(self._pedb, None, **i) for i in + data.get("padstack_definitions", [])] + self.padstack_instances = [CfgPadstackInstance(self._pedb, None, **i) for i in + data.get("padstack_instances", [])] self.planes = [CfgPlane(**i) for i in data.get("planes", [])] - self.components = data.get("components", []) + self.components = [CfgComponent(self._pedb, None, **i) for i in data.get("components", [])] def apply(self): if self.traces: @@ -79,19 +83,21 @@ def apply(self): if self.padstack_defs: for p in self.padstack_defs: pdata = self._pedb._edb.Definition.PadstackDefData.Create() - pdef = self._pedb._edb.Definition.PadstackDef.Create(self._pedb.active_db, p["name"]) + pdef = self._pedb._edb.Definition.PadstackDef.Create(self._pedb.active_db, p.name) pdef.SetData(pdata) pdef = EDBPadstack(pdef, self._pedb.padstacks) - pdef.properties = p + p._pyedb_obj = pdef + p.set_parameters_to_edb() if self.padstack_instances: for p in self.padstack_instances: p_inst = self._pedb.padstacks.place( - via_name=p["name"], - position=p["position"], - definition_name=p["definition"], + via_name=p.name, + position=p.position, + definition_name=p.definition, ) - p_inst.properties = p + p._pyedb_obj = p_inst + p.set_parameters_to_edb() if self.planes: for p in self.planes: @@ -114,10 +120,10 @@ def apply(self): pedb_p_inst = self._pedb.padstacks.instances_by_name for c in self.components: obj = self._pedb.components.create( - [pedb_p_inst[i] for i in c["pins"]], - component_name=c["reference_designator"], - placement_layer=c["placement_layer"], - component_part_name=c["definition"], + [pedb_p_inst[i] for i in c.pins], + component_name=c.reference_designator, + placement_layer=c.placement_layer, + component_part_name=c.definition, ) - obj.solder_ball_properties = c["solder_ball_properties"] - obj.port_properties = c["port_properties"] + c._pyedb_obj = obj + c.set_parameters_to_edb() diff --git a/src/pyedb/configuration/cfg_padstacks.py b/src/pyedb/configuration/cfg_padstacks.py index 910209239b..96cbda4684 100644 --- a/src/pyedb/configuration/cfg_padstacks.py +++ b/src/pyedb/configuration/cfg_padstacks.py @@ -40,12 +40,12 @@ def __init__(self, pedb, padstack_dict=None): padstack_defs_layout = self._pedb.padstacks.definitions for pdef in padstack_dict.get("definitions", []): obj = padstack_defs_layout[pdef["name"]] - self.definitions.append(Definition(self._pedb, obj, **pdef)) + self.definitions.append(CfgPadstackDefinition(self._pedb, obj, **pdef)) inst_from_layout = self._pedb.padstacks.instances_by_name for inst in padstack_dict.get("instances", []): obj = inst_from_layout[inst["name"]] - self.instances.append(Instance(self._pedb, obj, **inst)) + self.instances.append(CfgPadstackInstance(self._pedb, obj, **inst)) def clean(self): self.definitions = [] @@ -63,17 +63,17 @@ def apply(self): def retrieve_parameters_from_edb(self): self.clean() for _, obj in self._pedb.padstacks.definitions.items(): - pdef = Definition(self._pedb, obj) + pdef = CfgPadstackDefinition(self._pedb, obj) pdef.retrieve_parameters_from_edb() self.definitions.append(pdef) for obj in self._pedb.layout.padstack_instances: - inst = Instance(self._pedb, obj) + inst = CfgPadstackInstance(self._pedb, obj) inst.retrieve_parameters_from_edb() self.instances.append(inst) -class Definition(CfgBase): +class CfgPadstackDefinition(CfgBase): """Padstack definition data class.""" PAD_SHAPE_PARAMETERS = { @@ -98,16 +98,16 @@ def __init__(self, pedb, pedb_object, **kwargs): self.hole_parameters = kwargs.get("hole_parameters", None) def set_parameters_to_edb(self): + if self.hole_parameters: + self._set_hole_parameters_to_edb(self.hole_parameters) + if self.hole_range: + self._pyedb_obj.hole_range = self.hole_range if self.hole_plating_thickness: self._pyedb_obj.hole_plating_thickness = self.hole_plating_thickness if self.material: self._pyedb_obj.material = self.material - if self.hole_range: - self._pyedb_obj.hole_range = self.hole_range if self.pad_parameters: self._set_pad_parameters_to_edb(self.pad_parameters) - if self.hole_parameters: - self._set_hole_parameters_to_edb(self.hole_parameters) def retrieve_parameters_from_edb(self): self.name = self._pyedb_obj.name @@ -282,13 +282,15 @@ def _set_hole_parameters_to_edb(self, params): self._pyedb_obj._padstack_def_data = pdef_data -class Instance(CfgBase): +class CfgPadstackInstance(CfgBase): """Instance data class.""" def __init__(self, pedb, pyedb_obj, **kwargs): self._pedb = pedb self._pyedb_obj = pyedb_obj self.name = kwargs.get("name", None) + self.net_name = kwargs.get("net_name", "") + self.layer_range = kwargs.get("layer_range", [None, None]) self.definition = kwargs.get("definition", None) self.backdrill_parameters = kwargs.get("backdrill_parameters", None) self._id = kwargs.get("id", None) @@ -300,6 +302,12 @@ def __init__(self, pedb, pyedb_obj, **kwargs): def set_parameters_to_edb(self): if self.name is not None: self._pyedb_obj.aedt_name = self.name + if self.net_name is not None: + self._pyedb_obj.net_name = self._pedb.nets.find_or_create_net(self.net_name).name + if self.layer_range[0] is not None: + self._pyedb_obj.start_layer = self.layer_range[0] + if self.layer_range[1] is not None: + self._pyedb_obj.stop_layer = self.layer_range[1] if self.backdrill_parameters: self._pyedb_obj.backdrill_parameters = self.backdrill_parameters diff --git a/src/pyedb/configuration/cfg_ports_sources.py b/src/pyedb/configuration/cfg_ports_sources.py index a93edc8a83..486a3a4cc9 100644 --- a/src/pyedb/configuration/cfg_ports_sources.py +++ b/src/pyedb/configuration/cfg_ports_sources.py @@ -135,10 +135,10 @@ def apply(self): if i.aedt_name: edb_primitives[i.aedt_name] = i for p in self.ports: - if p.type not in ["wave_port", "diff_wave_port"]: - p.set_parameters_to_edb() - else: + if p.type in ["wave_port", "diff_wave_port"]: p.set_parameters_to_edb(edb_primitives) + else: + p.set_parameters_to_edb() def get_data_from_db(self): self.ports = [] diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index abfd87f011..f4168d1e37 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -40,6 +40,17 @@ } +def _assert_initial_ic_die_properties(component: dict): + assert component["ic_die_properties"]["type"] == "no_die" + assert "orientation" not in component["ic_die_properties"] + assert "height" not in component["ic_die_properties"] + + +def _assert_final_ic_die_properties(component: dict): + assert component["ic_die_properties"]["type"] == "flip_chip" + assert component["ic_die_properties"]["orientation"] == "chip_down" + + class TestClass: @pytest.fixture(autouse=True) def init(self, local_scratch): @@ -1059,17 +1070,6 @@ def test_17_ic_die_properties(self, edb_examples): component = [i for i in comps_edb if i["reference_designator"] == "U8"][0] _assert_final_ic_die_properties(component) - -def _assert_initial_ic_die_properties(component: dict): - assert component["ic_die_properties"]["type"] == "no_die" - assert "orientation" not in component["ic_die_properties"] - assert "height" not in component["ic_die_properties"] - - -def _assert_final_ic_die_properties(component: dict): - assert component["ic_die_properties"]["type"] == "flip_chip" - assert component["ic_die_properties"]["orientation"] == "chip_down" - def test_18_modeler(self, edb_examples): data = { "modeler": { From dfe32ca2236aa587094dab16c4344a5e3c35029f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:43:33 +0000 Subject: [PATCH 12/14] MISC: Auto fixes from pre-commit.com hooks For more information, see https://pre-commit.ci --- src/pyedb/configuration/cfg_common.py | 1 - src/pyedb/configuration/cfg_modeler.py | 17 +- src/pyedb/configuration/cfg_ports_sources.py | 31 +-- .../system/test_edb_configuration_2p0.py | 202 +++++++++++------- 4 files changed, 154 insertions(+), 97 deletions(-) diff --git a/src/pyedb/configuration/cfg_common.py b/src/pyedb/configuration/cfg_common.py index ee71067cf8..4d7b55d262 100644 --- a/src/pyedb/configuration/cfg_common.py +++ b/src/pyedb/configuration/cfg_common.py @@ -1,4 +1,3 @@ - # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # diff --git a/src/pyedb/configuration/cfg_modeler.py b/src/pyedb/configuration/cfg_modeler.py index 6d4db2e355..4e961f6e4a 100644 --- a/src/pyedb/configuration/cfg_modeler.py +++ b/src/pyedb/configuration/cfg_modeler.py @@ -20,12 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from pyedb.dotnet.edb_core.edb_data.padstacks_data import ( - EDBPadstack, -) -from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition -from pyedb.configuration.cfg_padstacks import CfgPadstackInstance from pyedb.configuration.cfg_components import CfgComponent +from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition, CfgPadstackInstance +from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstack class CfgTrace: @@ -59,10 +56,12 @@ class CfgModeler: def __init__(self, pedb, data): self._pedb = pedb self.traces = [CfgTrace(**i) for i in data.get("traces", [])] - self.padstack_defs = [CfgPadstackDefinition(self._pedb, None, **i) for i in - data.get("padstack_definitions", [])] - self.padstack_instances = [CfgPadstackInstance(self._pedb, None, **i) for i in - data.get("padstack_instances", [])] + self.padstack_defs = [ + CfgPadstackDefinition(self._pedb, None, **i) for i in data.get("padstack_definitions", []) + ] + self.padstack_instances = [ + CfgPadstackInstance(self._pedb, None, **i) for i in data.get("padstack_instances", []) + ] self.planes = [CfgPlane(**i) for i in data.get("planes", [])] self.components = [CfgComponent(self._pedb, None, **i) for i in data.get("components", [])] diff --git a/src/pyedb/configuration/cfg_ports_sources.py b/src/pyedb/configuration/cfg_ports_sources.py index 486a3a4cc9..60e2572ec8 100644 --- a/src/pyedb/configuration/cfg_ports_sources.py +++ b/src/pyedb/configuration/cfg_ports_sources.py @@ -20,9 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list from pyedb.configuration.cfg_common import CfgBase from pyedb.dotnet.edb_core.edb_data.ports import WavePort +from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list from pyedb.dotnet.edb_core.geometry.point_data import PointData @@ -421,8 +421,9 @@ def __init__(self, pedb, **kwargs): def set_parameters_to_edb(self, edb_primitives): point_on_edge = PointData(self._pedb, x=self.point_on_edge[0], y=self.point_on_edge[1]) primitive = edb_primitives[self.primitive_name] - pos_edge = self._pedb.edb_api.cell.terminal.PrimitiveEdge.Create(primitive._edb_object, - point_on_edge._edb_object) + pos_edge = self._pedb.edb_api.cell.terminal.PrimitiveEdge.Create( + primitive._edb_object, point_on_edge._edb_object + ) pos_edge = convert_py_list_to_net_list(pos_edge, self._pedb.edb_api.cell.terminal.Edge) edge_term = self._pedb.edb_api.cell.terminal.EdgeTerminal.Create( primitive._edb_object.GetLayout(), primitive._edb_object.GetNet(), self.name, pos_edge, isRef=False @@ -448,18 +449,22 @@ def __init__(self, pedb, **kwargs): kwargs["positive_terminal"]["type"] = "wave_port" kwargs["positive_terminal"]["name"] = self.name + ":T1" - self.positive_port = CfgWavePort(self._pedb, - horizontal_extent_factor=self.horizontal_extent_factor, - vertical_extent_factor=self.vertical_extent_factor, - pec_launch_width=self.pec_launch_width, - **kwargs["positive_terminal"]) + self.positive_port = CfgWavePort( + self._pedb, + horizontal_extent_factor=self.horizontal_extent_factor, + vertical_extent_factor=self.vertical_extent_factor, + pec_launch_width=self.pec_launch_width, + **kwargs["positive_terminal"], + ) kwargs["negative_terminal"]["type"] = "wave_port" kwargs["negative_terminal"]["name"] = self.name + ":T2" - self.negative_port = CfgWavePort(self._pedb, - horizontal_extent_factor=self.horizontal_extent_factor, - vertical_extent_factor=self.vertical_extent_factor, - pec_launch_width=self.pec_launch_width, - **kwargs["negative_terminal"]) + self.negative_port = CfgWavePort( + self._pedb, + horizontal_extent_factor=self.horizontal_extent_factor, + vertical_extent_factor=self.vertical_extent_factor, + pec_launch_width=self.pec_launch_width, + **kwargs["negative_terminal"], + ) def set_parameters_to_edb(self, edb_primitives): pos_term = self.positive_port.set_parameters_to_edb(edb_primitives) diff --git a/tests/legacy/system/test_edb_configuration_2p0.py b/tests/legacy/system/test_edb_configuration_2p0.py index f4168d1e37..94bd0e0eb4 100644 --- a/tests/legacy/system/test_edb_configuration_2p0.py +++ b/tests/legacy/system/test_edb_configuration_2p0.py @@ -412,23 +412,31 @@ def test_05f_ports_between_two_points(self, edb_examples): def test_05g_wave_port(self, edb_examples): edbapp = edb_examples.create_empty_edb() edbapp.stackup.create_symmetric_stackup(2) - edbapp.modeler.create_rectangle(layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], - upper_right_point=["2mm", "2mm"]) - prim_1 = edbapp.modeler.create_trace(path_list=([0, 0], [0, "1mm"]), layer_name="TOP", net_name="SIG", - width="0.1mm", - start_cap_style="Flat", end_cap_style="Flat") + edbapp.modeler.create_rectangle( + layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], upper_right_point=["2mm", "2mm"] + ) + prim_1 = edbapp.modeler.create_trace( + path_list=([0, 0], [0, "1mm"]), + layer_name="TOP", + net_name="SIG", + width="0.1mm", + start_cap_style="Flat", + end_cap_style="Flat", + ) prim_1.aedt_name = "path_1" - data = {"ports": [ - { - "name": "wport_1", - "type": "wave_port", - "primitive_name": prim_1.aedt_name, - "point_on_edge": [0, "1mm"], - "horizontal_extent_factor": 6, - "vertical_extent_factor": 4, - "pec_launch_width": "0,2mm" - } - ]} + data = { + "ports": [ + { + "name": "wport_1", + "type": "wave_port", + "primitive_name": prim_1.aedt_name, + "point_on_edge": [0, "1mm"], + "horizontal_extent_factor": 6, + "vertical_extent_factor": 4, + "pec_launch_width": "0,2mm", + } + ] + } edbapp.configuration.load(data, apply_file=True) assert edbapp.ports["wport_1"].horizontal_extent_factor == 6 edbapp.close() @@ -436,31 +444,42 @@ def test_05g_wave_port(self, edb_examples): def test_05h_diff_wave_port(self, edb_examples): edbapp = edb_examples.create_empty_edb() edbapp.stackup.create_symmetric_stackup(2) - edbapp.modeler.create_rectangle(layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], - upper_right_point=["2mm", "2mm"]) - prim_1 = edbapp.modeler.create_trace(path_list=([0, 0], [0, "1mm"]), layer_name="TOP", net_name="SIG", - width="0.1mm", - start_cap_style="Flat", end_cap_style="Flat") + edbapp.modeler.create_rectangle( + layer_name="BOT", net_name="GND", lower_left_point=["-2mm", "-2mm"], upper_right_point=["2mm", "2mm"] + ) + prim_1 = edbapp.modeler.create_trace( + path_list=([0, 0], [0, "1mm"]), + layer_name="TOP", + net_name="SIG", + width="0.1mm", + start_cap_style="Flat", + end_cap_style="Flat", + ) prim_1.aedt_name = "path_1" - prim_2 = edbapp.modeler.create_trace(path_list=(["1mm", 0], ["1mm", "1mm"]), layer_name="TOP", net_name="SIG", - width="0.1mm", - start_cap_style="Flat", end_cap_style="Flat") + prim_2 = edbapp.modeler.create_trace( + path_list=(["1mm", 0], ["1mm", "1mm"]), + layer_name="TOP", + net_name="SIG", + width="0.1mm", + start_cap_style="Flat", + end_cap_style="Flat", + ) prim_2.aedt_name = "path_2" - data = {"ports": [ - { - "name": "diff_wave_1", - "type": "diff_wave_port", - "positive_terminal": {"primitive_name": prim_1.aedt_name, - "point_on_edge": [0, "1mm"]}, - "negative_terminal": {"primitive_name": prim_2.aedt_name, - "point_on_edge": ["1mm", "1mm"]}, - "horizontal_extent_factor": 6, - "vertical_extent_factor": 4, - "pec_launch_width": "0,2mm" - } - ]} + data = { + "ports": [ + { + "name": "diff_wave_1", + "type": "diff_wave_port", + "positive_terminal": {"primitive_name": prim_1.aedt_name, "point_on_edge": [0, "1mm"]}, + "negative_terminal": {"primitive_name": prim_2.aedt_name, "point_on_edge": ["1mm", "1mm"]}, + "horizontal_extent_factor": 6, + "vertical_extent_factor": 4, + "pec_launch_width": "0,2mm", + } + ] + } edbapp.configuration.load(data, apply_file=True) - assert edbapp.ports["diff_wave_1"].horizontal_extent_factor == 6 + assert edbapp.ports["diff_wave_1"].horizontal_extent_factor == 6 edbapp.close() def test_06_s_parameters(self, edb_examples): @@ -1074,10 +1093,17 @@ def test_18_modeler(self, edb_examples): data = { "modeler": { "traces": [ - {"name": "trace_1", "layer": "TOP", "width": "0.1mm", "path": [[0, 0], [0, "10mm"]], - "net_name": "SIG", - "start_cap_style": "flat", "end_cap_style": "flat", "corner_style": "round"}, - {"name": "trace_1_void", "layer": "TOP", "width": "0.3mm", "path": [[0, 0], [0, "10mm"]]} + { + "name": "trace_1", + "layer": "TOP", + "width": "0.1mm", + "path": [[0, 0], [0, "10mm"]], + "net_name": "SIG", + "start_cap_style": "flat", + "end_cap_style": "flat", + "corner_style": "round", + }, + {"name": "trace_1_void", "layer": "TOP", "width": "0.3mm", "path": [[0, 0], [0, "10mm"]]}, ], "padstack_definitions": [ { @@ -1085,48 +1111,76 @@ def test_18_modeler(self, edb_examples): "hole_plating_thickness": "0.025mm", "material": "copper", "pad_parameters": { - 'regular_pad': [ - {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0mm', 'offset_y': '0', - 'rotation': '0', - 'diameter': '0.5mm'}, - {'layer_name': 'BOT', 'shape': 'circle', 'offset_x': '0mm', 'offset_y': '0', - 'rotation': '0', - 'diameter': '0.5mm'} + "regular_pad": [ + { + "layer_name": "TOP", + "shape": "circle", + "offset_x": "0mm", + "offset_y": "0", + "rotation": "0", + "diameter": "0.5mm", + }, + { + "layer_name": "BOT", + "shape": "circle", + "offset_x": "0mm", + "offset_y": "0", + "rotation": "0", + "diameter": "0.5mm", + }, ], - 'anti_pad': [ - {'layer_name': 'TOP', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', - 'rotation': '0', - 'diameter': '1mm'}, - {'layer_name': 'BOT', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', - 'rotation': '0', - 'diameter': '1mm'} + "anti_pad": [ + { + "layer_name": "TOP", + "shape": "circle", + "offset_x": "0", + "offset_y": "0", + "rotation": "0", + "diameter": "1mm", + }, + { + "layer_name": "BOT", + "shape": "circle", + "offset_x": "0", + "offset_y": "0", + "rotation": "0", + "diameter": "1mm", + }, ], }, "hole_range": "through", "hole_parameters": { "shape": "circle", "diameter": "0.25mm", - } + }, } ], "padstack_instances": [ - {"name": "via_1", - "definition": "via", - "layer_range": ["TOP", "BOT"], - "position": [0, 0], - "net_name": "SIG" - }, - {"name": "pin_1", - "definition": "via", - "layer_range": ["TOP", "TOP"], - "position": [0, "1mm"], - "net_name": "SIG", - "is_pin": True - } + { + "name": "via_1", + "definition": "via", + "layer_range": ["TOP", "BOT"], + "position": [0, 0], + "net_name": "SIG", + }, + { + "name": "pin_1", + "definition": "via", + "layer_range": ["TOP", "TOP"], + "position": [0, "1mm"], + "net_name": "SIG", + "is_pin": True, + }, ], "planes": [ - {"name": "GND_TOP", "layer": "TOP", "net_name": "GND", "lower_left_point": [0, 0], - "upper_right_point": [0, "12mm"], "voids": ["trace_1_void"]}, + { + "name": "GND_TOP", + "layer": "TOP", + "net_name": "GND", + "lower_left_point": [0, 0], + "upper_right_point": [0, "12mm"], + "voids": ["trace_1_void"], + }, ], "components": [ { @@ -1143,7 +1197,7 @@ def test_18_modeler(self, edb_examples): "reference_size_y": 0, }, }, - ] + ], } } edbapp = edb_examples.create_empty_edb() @@ -1159,7 +1213,7 @@ def test_19_variables(self, edb_examples): data = { "variables": [ {"name": "var_1", "value": "1mm", "description": "No description"}, - {"name": "$var_2", "value": "1mm", "description": "No description"} + {"name": "$var_2", "value": "1mm", "description": "No description"}, ] } edbapp = edb_examples.create_empty_edb() From ae702a225513f0337bf8a1746c9ff591e16e5862 Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 13:32:29 +0100 Subject: [PATCH 13/14] minor fix --- src/pyedb/configuration/cfg_components.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyedb/configuration/cfg_components.py b/src/pyedb/configuration/cfg_components.py index 5ad57d38c1..af69d24f47 100644 --- a/src/pyedb/configuration/cfg_components.py +++ b/src/pyedb/configuration/cfg_components.py @@ -33,7 +33,7 @@ def __init__(self, pedb, pedb_object, **kwargs): self.reference_designator = kwargs.get("reference_designator", None) self.definition = kwargs.get("definition", None) self.type = kwargs["part_type"].lower() if kwargs.get("part_type") else None - self.placement_layer = kwargs["placement_layer"] + self.placement_layer = kwargs.get("placement_layer", None) self.pins = kwargs.get("pins", []) self.port_properties = kwargs.get("port_properties", {}) From 31f4fe68c809237093517f6baae905421530ce3c Mon Sep 17 00:00:00 2001 From: ring630 <@gmail.com> Date: Tue, 29 Oct 2024 15:28:01 +0100 Subject: [PATCH 14/14] fix example --- examples/use_configuration/import_ports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/use_configuration/import_ports.py b/examples/use_configuration/import_ports.py index 9bcf7f8697..748faf3a2e 100644 --- a/examples/use_configuration/import_ports.py +++ b/examples/use_configuration/import_ports.py @@ -94,6 +94,7 @@ port_4 = { "name": "port_4", + "type": "circuit", "positive_terminal": {"coordinates": {"layer": "1_Top", "point": ["104mm", "37mm"], "net": "AVCC_1V3"}}, "negative_terminal": {"coordinates": {"layer": "Inner6(GND2)", "point": ["104mm", "37mm"], "net": "GND"}}, }