pyedb 0.54.0__py3-none-any.whl → 0.56.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +1 -8
- pyedb/configuration/cfg_boundaries.py +69 -151
- pyedb/configuration/cfg_components.py +201 -460
- pyedb/configuration/cfg_data.py +4 -2
- pyedb/configuration/cfg_general.py +13 -36
- pyedb/configuration/cfg_modeler.py +2 -1
- pyedb/configuration/cfg_nets.py +21 -35
- pyedb/configuration/cfg_operations.py +22 -151
- pyedb/configuration/cfg_package_definition.py +56 -112
- pyedb/configuration/cfg_padstacks.py +292 -688
- pyedb/configuration/cfg_pin_groups.py +32 -79
- pyedb/configuration/cfg_ports_sources.py +19 -6
- pyedb/configuration/cfg_s_parameter_models.py +67 -172
- pyedb/configuration/cfg_setup.py +102 -295
- pyedb/configuration/configuration.py +64 -5
- pyedb/dotnet/database/Variables.py +26 -19
- pyedb/dotnet/database/cell/connectable.py +38 -9
- pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
- pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/database/cell/layout.py +63 -2
- pyedb/dotnet/database/cell/layout_obj.py +2 -2
- pyedb/dotnet/database/cell/primitive/path.py +6 -8
- pyedb/dotnet/database/cell/primitive/primitive.py +3 -24
- pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
- pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/terminal.py +24 -24
- pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
- pyedb/dotnet/database/components.py +137 -124
- pyedb/dotnet/database/definition/component_def.py +4 -4
- pyedb/dotnet/database/definition/component_model.py +1 -1
- pyedb/dotnet/database/definition/package_def.py +2 -3
- pyedb/dotnet/database/dotnet/database.py +3 -199
- pyedb/dotnet/database/dotnet/primitive.py +3 -3
- pyedb/dotnet/database/edb_data/control_file.py +5 -5
- pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
- pyedb/dotnet/database/edb_data/layer_data.py +23 -23
- pyedb/dotnet/database/edb_data/padstacks_data.py +63 -88
- pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
- pyedb/dotnet/database/edb_data/sources.py +6 -6
- pyedb/dotnet/database/edb_data/variables.py +1 -1
- pyedb/dotnet/database/geometry/point_data.py +14 -10
- pyedb/dotnet/database/geometry/polygon_data.py +3 -3
- pyedb/dotnet/database/hfss.py +46 -48
- pyedb/dotnet/database/layout_validation.py +14 -11
- pyedb/dotnet/database/materials.py +10 -11
- pyedb/dotnet/database/modeler.py +97 -91
- pyedb/dotnet/database/nets.py +19 -22
- pyedb/dotnet/database/padstack.py +171 -83
- pyedb/dotnet/database/siwave.py +42 -42
- pyedb/dotnet/database/stackup.py +140 -72
- pyedb/dotnet/database/utilities/heatsink.py +4 -4
- pyedb/dotnet/database/utilities/obj_base.py +2 -2
- pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
- pyedb/dotnet/database/utilities/value.py +16 -16
- pyedb/dotnet/edb.py +230 -152
- pyedb/edb_logger.py +12 -27
- pyedb/extensions/create_cell_array.py +394 -0
- pyedb/extensions/via_design_backend.py +6 -3
- pyedb/generic/data_handlers.py +6 -7
- pyedb/generic/design_types.py +81 -30
- pyedb/generic/filesystem.py +5 -2
- pyedb/generic/general_methods.py +2 -122
- pyedb/generic/process.py +44 -108
- pyedb/generic/settings.py +79 -19
- pyedb/grpc/database/components.py +26 -4
- pyedb/grpc/database/control_file.py +5 -5
- pyedb/grpc/database/definition/materials.py +1 -1
- pyedb/grpc/database/definition/package_def.py +3 -3
- pyedb/grpc/database/definition/padstack_def.py +53 -0
- pyedb/grpc/database/geometry/polygon_data.py +1 -1
- pyedb/grpc/database/layout/layout.py +81 -5
- pyedb/grpc/database/layout_validation.py +5 -5
- pyedb/grpc/database/modeler.py +24 -16
- pyedb/grpc/database/net/net.py +15 -14
- pyedb/grpc/database/nets.py +70 -0
- pyedb/grpc/database/padstacks.py +122 -17
- pyedb/grpc/database/primitive/padstack_instance.py +175 -7
- pyedb/grpc/database/primitive/polygon.py +2 -2
- pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +3 -2
- pyedb/grpc/database/siwave.py +1 -1
- pyedb/grpc/database/source_excitations.py +12 -5
- pyedb/grpc/database/stackup.py +1 -1
- pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
- pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
- pyedb/grpc/database/utility/value.py +1 -0
- pyedb/grpc/database/utility/xml_control_file.py +5 -5
- pyedb/grpc/edb.py +80 -30
- pyedb/grpc/edb_init.py +3 -3
- pyedb/grpc/rpc_session.py +14 -13
- pyedb/libraries/common.py +366 -0
- pyedb/libraries/rf_libraries/base_functions.py +1358 -0
- pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
- pyedb/misc/decorators.py +61 -0
- pyedb/misc/misc.py +0 -13
- pyedb/modeler/geometry_operators.py +6 -6
- pyedb/siwave.py +6 -8
- pyedb/siwave_core/__init__.py +0 -0
- pyedb/siwave_core/cpa/__init__.py +0 -0
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/METADATA +1 -2
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/RECORD +105 -98
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/WHEEL +0 -0
- {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -57,6 +57,7 @@ from pyedb.grpc.database.hierarchy.pingroup import PinGroup
|
|
|
57
57
|
from pyedb.grpc.database.padstacks import Padstacks
|
|
58
58
|
from pyedb.grpc.database.utility.sources import SourceType
|
|
59
59
|
from pyedb.grpc.database.utility.value import Value
|
|
60
|
+
from pyedb.misc.decorators import deprecate_argument_name
|
|
60
61
|
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
61
62
|
|
|
62
63
|
|
|
@@ -500,6 +501,7 @@ class Components(object):
|
|
|
500
501
|
"""
|
|
501
502
|
return self.instances[name]
|
|
502
503
|
|
|
504
|
+
@deprecate_argument_name({"pinName": "pin_name"})
|
|
503
505
|
def get_pin_from_component(
|
|
504
506
|
self,
|
|
505
507
|
component: Union[str, Component],
|
|
@@ -1063,6 +1065,9 @@ class Components(object):
|
|
|
1063
1065
|
ComponentGroup as GrpcComponentGroup,
|
|
1064
1066
|
)
|
|
1065
1067
|
|
|
1068
|
+
if not pins:
|
|
1069
|
+
raise ValueError("Pins must be a list of PadstackInstance objects.")
|
|
1070
|
+
|
|
1066
1071
|
if not component_name:
|
|
1067
1072
|
component_name = generate_unique_name("Comp_")
|
|
1068
1073
|
if component_part_name:
|
|
@@ -1072,7 +1077,10 @@ class Components(object):
|
|
|
1072
1077
|
if not compdef:
|
|
1073
1078
|
return False
|
|
1074
1079
|
new_cmp = GrpcComponentGroup.create(self._active_layout, component_name, compdef.name)
|
|
1075
|
-
|
|
1080
|
+
if hasattr(pins[0], "component") and pins[0].component:
|
|
1081
|
+
hosting_component_location = pins[0].component.transform
|
|
1082
|
+
else:
|
|
1083
|
+
hosting_component_location = None
|
|
1076
1084
|
if not len(pins) == len(compdef.component_pins):
|
|
1077
1085
|
self._pedb.logger.error(
|
|
1078
1086
|
f"Number on pins {len(pins)} does not match component definition number "
|
|
@@ -1090,7 +1098,18 @@ class Components(object):
|
|
|
1090
1098
|
if new_cmp_layer_name in self._pedb.stackup.signal_layers:
|
|
1091
1099
|
new_cmp_placement_layer = self._pedb.stackup.signal_layers[new_cmp_layer_name]
|
|
1092
1100
|
new_cmp.placement_layer = new_cmp_placement_layer
|
|
1093
|
-
|
|
1101
|
+
if r_value:
|
|
1102
|
+
new_cmp.component_type = GrpcComponentType.RESISTOR
|
|
1103
|
+
is_rlc = True
|
|
1104
|
+
elif c_value:
|
|
1105
|
+
new_cmp.component_type = GrpcComponentType.CAPACITOR
|
|
1106
|
+
is_rlc = True
|
|
1107
|
+
elif l_value:
|
|
1108
|
+
new_cmp.component_type = GrpcComponentType.INDUCTOR
|
|
1109
|
+
is_rlc = True
|
|
1110
|
+
else:
|
|
1111
|
+
new_cmp.component_type = GrpcComponentType.OTHER
|
|
1112
|
+
is_rlc = False
|
|
1094
1113
|
if is_rlc and len(pins) == 2:
|
|
1095
1114
|
rlc = GrpcRlc()
|
|
1096
1115
|
rlc.is_parallel = is_parallel
|
|
@@ -1123,7 +1142,8 @@ class Components(object):
|
|
|
1123
1142
|
component_property = new_cmp.component_property
|
|
1124
1143
|
component_property.model = rlc_model
|
|
1125
1144
|
new_cmp.component_property = component_property
|
|
1126
|
-
|
|
1145
|
+
if hosting_component_location:
|
|
1146
|
+
new_cmp.transform = hosting_component_location
|
|
1127
1147
|
new_edb_comp = Component(self._pedb, new_cmp)
|
|
1128
1148
|
self._cmp[new_cmp.name] = new_edb_comp
|
|
1129
1149
|
return new_edb_comp
|
|
@@ -1664,7 +1684,9 @@ class Components(object):
|
|
|
1664
1684
|
if comp.partname == part_name:
|
|
1665
1685
|
pass
|
|
1666
1686
|
else:
|
|
1667
|
-
pinlist = self.
|
|
1687
|
+
pinlist = list(self.instances[refdes].pins.values())
|
|
1688
|
+
if not pinlist:
|
|
1689
|
+
continue
|
|
1668
1690
|
if not part_name in self.definitions:
|
|
1669
1691
|
comp_def = ComponentDef.create(self._db, part_name, None)
|
|
1670
1692
|
# for pin in range(len(pinlist)):
|
|
@@ -27,8 +27,8 @@ import subprocess
|
|
|
27
27
|
import sys
|
|
28
28
|
from typing import Any, Dict, List, Optional, Union
|
|
29
29
|
|
|
30
|
-
from pyedb.edb_logger import pyedb_logger
|
|
31
30
|
from pyedb.generic.general_methods import ET, env_path, env_value, is_linux
|
|
31
|
+
from pyedb.generic.settings import settings
|
|
32
32
|
from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
|
|
33
33
|
from pyedb.misc.misc import list_installed_ansysem
|
|
34
34
|
|
|
@@ -194,7 +194,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
194
194
|
base_path = env_path(edbversion)
|
|
195
195
|
sys.path.append(base_path)
|
|
196
196
|
else:
|
|
197
|
-
|
|
197
|
+
settings.logger.error("No EDB installation found. Check environment variables")
|
|
198
198
|
return False
|
|
199
199
|
os.environ["HELIC_ROOT"] = os.path.join(base_path, "helic")
|
|
200
200
|
if os.getenv("ANSYSLMD_LICENCE_FILE", None) is None:
|
|
@@ -207,7 +207,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
207
207
|
os.environ["ANSYSLMD_LICENSE_FILE"] = line.split("=")[1]
|
|
208
208
|
break
|
|
209
209
|
else:
|
|
210
|
-
|
|
210
|
+
settings.logger.error("ANSYSLMD_LICENSE_FILE is not defined.")
|
|
211
211
|
vlc_file_name = os.path.splitext(tech_file)[0]
|
|
212
212
|
if not control_file:
|
|
213
213
|
control_file = vlc_file_name + ".xml"
|
|
@@ -241,9 +241,9 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
241
241
|
p = subprocess.Popen(command, env=my_env)
|
|
242
242
|
p.wait()
|
|
243
243
|
if os.path.exists(control_file):
|
|
244
|
-
|
|
244
|
+
settings.logger.info("XML file created.")
|
|
245
245
|
return control_file
|
|
246
|
-
|
|
246
|
+
settings.logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
247
247
|
return False
|
|
248
248
|
|
|
249
249
|
|
|
@@ -378,7 +378,7 @@ class Material(GrpcMaterialDef):
|
|
|
378
378
|
"Use property dielectric_loss_tangent instead.",
|
|
379
379
|
DeprecationWarning,
|
|
380
380
|
)
|
|
381
|
-
self.dielectric_loss_tangent
|
|
381
|
+
self.dielectric_loss_tangent = value
|
|
382
382
|
|
|
383
383
|
@dielectric_loss_tangent.setter
|
|
384
384
|
def dielectric_loss_tangent(self, value):
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
from ansys.edb.core.definition.package_def import PackageDef as GrpcPackageDef
|
|
24
24
|
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
25
25
|
|
|
26
|
-
from pyedb.
|
|
26
|
+
from pyedb.generic.settings import settings
|
|
27
27
|
from pyedb.grpc.database.utility.heat_sink import HeatSink
|
|
28
28
|
from pyedb.grpc.database.utility.value import Value
|
|
29
|
-
from pyedb.misc.
|
|
29
|
+
from pyedb.misc.decorators import deprecated_property
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class PackageDef(GrpcPackageDef):
|
|
@@ -82,7 +82,7 @@ class PackageDef(GrpcPackageDef):
|
|
|
82
82
|
else:
|
|
83
83
|
bbox = extent_bounding_box
|
|
84
84
|
if bbox is None:
|
|
85
|
-
|
|
85
|
+
settings.logger.warning(
|
|
86
86
|
"Package creation uses bounding box but it cannot be inferred. "
|
|
87
87
|
"Please set argument 'component_part_name' or 'extent_bounding_box'."
|
|
88
88
|
)
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
|
|
23
23
|
import math
|
|
24
|
+
import warnings
|
|
24
25
|
|
|
25
26
|
from ansys.edb.core.definition.padstack_def import PadstackDef as GrpcPadstackDef
|
|
26
27
|
from ansys.edb.core.definition.padstack_def_data import (
|
|
@@ -109,6 +110,26 @@ class PadProperties:
|
|
|
109
110
|
"""
|
|
110
111
|
return self._pad_parameter_value[0].name.split("_")[-1].lower()
|
|
111
112
|
|
|
113
|
+
@shape.setter
|
|
114
|
+
def shape(self, value: str):
|
|
115
|
+
"""Set pad shape.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
value : str
|
|
120
|
+
Pad shape.
|
|
121
|
+
"""
|
|
122
|
+
if value.lower() == "circle":
|
|
123
|
+
self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE)
|
|
124
|
+
elif value.lower() == "rectangle":
|
|
125
|
+
self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_RECTANGLE)
|
|
126
|
+
elif value.lower() == "polygon":
|
|
127
|
+
self._update_pad_parameters_parameters(geom_type=GrpcPadGeometryType.PADGEOMTYPE_POLYGON)
|
|
128
|
+
else:
|
|
129
|
+
raise ValueError(
|
|
130
|
+
f"Unsupported pad shape: {value}. Supported shapes are 'circle', " f"'rectangle', and 'polygon'."
|
|
131
|
+
)
|
|
132
|
+
|
|
112
133
|
@property
|
|
113
134
|
def parameters_values(self):
|
|
114
135
|
"""Parameters.
|
|
@@ -300,6 +321,22 @@ class PadstackDef(GrpcPadstackDef):
|
|
|
300
321
|
"""
|
|
301
322
|
return self.layers[0]
|
|
302
323
|
|
|
324
|
+
@property
|
|
325
|
+
def via_start_layer(self):
|
|
326
|
+
"""Via starting layer.
|
|
327
|
+
|
|
328
|
+
.deprecated
|
|
329
|
+
Use: :method:`start_layer <pyedb.grpc.database.definition.padstack_def.PadstackDef.start_layer>`
|
|
330
|
+
instead.
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
str
|
|
335
|
+
Name of the via starting layer.
|
|
336
|
+
"""
|
|
337
|
+
warnings.warn("via_start_layer is deprecated. Use start_layer instead.", DeprecationWarning)
|
|
338
|
+
return self.start_layer
|
|
339
|
+
|
|
303
340
|
@property
|
|
304
341
|
def stop_layer(self):
|
|
305
342
|
"""Stopping layer.
|
|
@@ -311,6 +348,22 @@ class PadstackDef(GrpcPadstackDef):
|
|
|
311
348
|
"""
|
|
312
349
|
return self.layers[-1]
|
|
313
350
|
|
|
351
|
+
@property
|
|
352
|
+
def via_stop_layer(self):
|
|
353
|
+
"""Via stop layer.
|
|
354
|
+
|
|
355
|
+
.deprecated
|
|
356
|
+
Use :method:`stop_layer <pyedb.grpc.database.definition.padstack_def.PadstackDef.stop_layer>`
|
|
357
|
+
instead.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
str
|
|
362
|
+
Name of the via stop layer.
|
|
363
|
+
"""
|
|
364
|
+
warnings.warn("via_stop_layer is deprecated. Use stop_layer instead.", DeprecationWarning)
|
|
365
|
+
return self.stop_layer
|
|
366
|
+
|
|
314
367
|
@property
|
|
315
368
|
def hole_diameter(self) -> float:
|
|
316
369
|
"""Hole diameter.
|
|
@@ -127,7 +127,7 @@ class PolygonData(GrpcPolygonData):
|
|
|
127
127
|
bool
|
|
128
128
|
|
|
129
129
|
"""
|
|
130
|
-
new_poly =
|
|
130
|
+
new_poly = super().expand(offset, tolerance, round_corners, maximum_corner_extension)
|
|
131
131
|
if not new_poly[0].points:
|
|
132
132
|
return False
|
|
133
133
|
self._edb_object = new_poly[0]
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"""
|
|
24
24
|
This module contains these classes: `EdbLayout` and `Shape`.
|
|
25
25
|
"""
|
|
26
|
-
from typing import Union
|
|
26
|
+
from typing import Dict, List, Union
|
|
27
27
|
|
|
28
28
|
from ansys.edb.core.layout.layout import Layout as GrpcLayout
|
|
29
29
|
import ansys.edb.core.primitive.bondwire
|
|
@@ -63,6 +63,7 @@ class Layout(GrpcLayout):
|
|
|
63
63
|
super().__init__(pedb.active_cell._Cell__stub.GetLayout(pedb.active_cell.msg))
|
|
64
64
|
self._pedb = pedb
|
|
65
65
|
self.__primitives = []
|
|
66
|
+
self.__padstack_instances = {}
|
|
66
67
|
|
|
67
68
|
@property
|
|
68
69
|
def cell(self):
|
|
@@ -74,8 +75,9 @@ class Layout(GrpcLayout):
|
|
|
74
75
|
|
|
75
76
|
@property
|
|
76
77
|
def primitives(self) -> list[any]:
|
|
78
|
+
primitives = super().primitives
|
|
77
79
|
self.__primitives = []
|
|
78
|
-
for prim in
|
|
80
|
+
for prim in primitives:
|
|
79
81
|
if isinstance(prim, ansys.edb.core.primitive.path.Path):
|
|
80
82
|
self.__primitives.append(Path(self._pedb, prim))
|
|
81
83
|
elif isinstance(prim, ansys.edb.core.primitive.polygon.Polygon):
|
|
@@ -196,11 +198,12 @@ class Layout(GrpcLayout):
|
|
|
196
198
|
return [DifferentialPair(self._pedb, i) for i in self._pedb.active_cell.layout.differential_pairs]
|
|
197
199
|
|
|
198
200
|
@property
|
|
199
|
-
def padstack_instances(self) ->
|
|
201
|
+
def padstack_instances(self) -> Dict[int, PadstackInstance]:
|
|
200
202
|
"""Get all padstack instances in a list."""
|
|
201
|
-
|
|
203
|
+
pad_stack_inst = super().padstack_instances
|
|
204
|
+
self.__padstack_instances = {i.edb_uid: PadstackInstance(self._pedb, i) for i in pad_stack_inst}
|
|
205
|
+
return self.__padstack_instances
|
|
202
206
|
|
|
203
|
-
#
|
|
204
207
|
@property
|
|
205
208
|
def voltage_regulators(self) -> list[VoltageRegulator]:
|
|
206
209
|
"""Voltage regulators.
|
|
@@ -240,3 +243,76 @@ class Layout(GrpcLayout):
|
|
|
240
243
|
prims = [i for i in prims if i.layer_name in layer_name] if layer_name is not None else prims
|
|
241
244
|
prims = [i for i in prims if i.net_name in net_name] if net_name is not None else prims
|
|
242
245
|
return prims
|
|
246
|
+
|
|
247
|
+
def find_padstack_instances(
|
|
248
|
+
self,
|
|
249
|
+
aedt_name: Union[str, List[str]] = None,
|
|
250
|
+
component_name: Union[str, List[str]] = None,
|
|
251
|
+
component_pin_name: Union[str, List[str]] = None,
|
|
252
|
+
net_name: Union[str, List[str]] = None,
|
|
253
|
+
instance_id: Union[int, List[int]] = None,
|
|
254
|
+
) -> List:
|
|
255
|
+
"""
|
|
256
|
+
Finds padstack instances matching the specified criteria.
|
|
257
|
+
|
|
258
|
+
This method filters the available padstack instances based on specified attributes such as
|
|
259
|
+
`aedt_name`, `component_name`, `component_pin_name`, `net_name`, or `instance_id`. Criteria
|
|
260
|
+
can be passed as individual values or as a list of values. If no padstack instances match
|
|
261
|
+
the criteria, an error is raised.
|
|
262
|
+
|
|
263
|
+
Parameters
|
|
264
|
+
----------
|
|
265
|
+
aedt_name : Union[str, List[str]], optional
|
|
266
|
+
Name(s) of the AEDT padstack instance(s) to filter.
|
|
267
|
+
component_name : Union[str, List[str]], optional
|
|
268
|
+
Name(s) of the component(s) to filter padstack instances by.
|
|
269
|
+
component_pin_name : Union[str, List[str]], optional
|
|
270
|
+
Name(s) of the component pin(s) to filter padstack instances by.
|
|
271
|
+
net_name : Union[str, List[str]], optional
|
|
272
|
+
Name(s) of the net(s) to filter padstack instances by.
|
|
273
|
+
instance_id : Union[int, List[int]], optional
|
|
274
|
+
ID(s) of the padstack instance(s) to filter.
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
List
|
|
279
|
+
A list of padstack instances matching the specified criteria.
|
|
280
|
+
"""
|
|
281
|
+
padstacks = self.padstack_instances
|
|
282
|
+
instances_found = []
|
|
283
|
+
if instance_id is not None:
|
|
284
|
+
instance_ids = instance_id if isinstance(instance_id, list) else [instance_id]
|
|
285
|
+
if instance_id in instance_ids:
|
|
286
|
+
instances_found.append(padstacks[instance_id])
|
|
287
|
+
|
|
288
|
+
if aedt_name is not None:
|
|
289
|
+
name = aedt_name if isinstance(aedt_name, list) else [aedt_name]
|
|
290
|
+
[instances_found.append(i) for i in list(padstacks.values()) if i.aedt_name in name]
|
|
291
|
+
|
|
292
|
+
if component_name is not None:
|
|
293
|
+
value = component_name if isinstance(component_name, list) else [component_name]
|
|
294
|
+
for inst in padstacks.values():
|
|
295
|
+
if inst.component:
|
|
296
|
+
if inst.component.name in value:
|
|
297
|
+
instances_found.append(inst)
|
|
298
|
+
|
|
299
|
+
if net_name is not None:
|
|
300
|
+
value = net_name if isinstance(net_name, list) else [net_name]
|
|
301
|
+
for inst in padstacks.values():
|
|
302
|
+
if inst.net:
|
|
303
|
+
if inst.net.name in value:
|
|
304
|
+
instances_found.append(inst)
|
|
305
|
+
|
|
306
|
+
if component_pin_name is not None:
|
|
307
|
+
value = component_pin_name if isinstance(component_name, list) else [component_pin_name]
|
|
308
|
+
for inst in padstacks.values():
|
|
309
|
+
if inst.component:
|
|
310
|
+
if hasattr(inst, "name"):
|
|
311
|
+
if inst.name in value:
|
|
312
|
+
instances_found.append(inst)
|
|
313
|
+
if not instances_found: # pragma: no cover
|
|
314
|
+
raise ValueError(
|
|
315
|
+
f"Failed to find padstack instances with aedt_name={aedt_name}, component_name={component_name}, "
|
|
316
|
+
f"net_name={net_name}, component_pin_name={component_pin_name}"
|
|
317
|
+
)
|
|
318
|
+
return instances_found
|
|
@@ -334,7 +334,7 @@ class LayoutValidation:
|
|
|
334
334
|
new_name = re.sub(pattern, "_", net)
|
|
335
335
|
val.name = new_name
|
|
336
336
|
|
|
337
|
-
self._pedb.
|
|
337
|
+
self._pedb.logger.info("Found {} illegal net names.".format(len(renamed_nets)))
|
|
338
338
|
return
|
|
339
339
|
|
|
340
340
|
def illegal_rlc_values(self, fix: bool = False) -> List[str]:
|
|
@@ -354,11 +354,11 @@ class LayoutValidation:
|
|
|
354
354
|
temp = []
|
|
355
355
|
for k, v in inductors.items():
|
|
356
356
|
model = v.component_property.model
|
|
357
|
-
if not len(model.pin_pairs): # pragma: no cover
|
|
357
|
+
if not len(model.pin_pairs()): # pragma: no cover
|
|
358
358
|
temp.append(k)
|
|
359
359
|
if fix:
|
|
360
360
|
v.rlc_values = [0, 1, 0]
|
|
361
|
-
self._pedb.
|
|
361
|
+
self._pedb.logger.info(f"Found {len(temp)} inductors have no value.")
|
|
362
362
|
return temp
|
|
363
363
|
|
|
364
364
|
def padstacks_no_name(self, fix: bool = False) -> None:
|
|
@@ -373,7 +373,7 @@ class LayoutValidation:
|
|
|
373
373
|
>>> # Automatically assign names to unnamed padstacks
|
|
374
374
|
>>> edb.layout_validation.padstacks_no_name(fix=True)
|
|
375
375
|
"""
|
|
376
|
-
pds = self._pedb.layout.padstack_instances
|
|
376
|
+
pds = list(self._pedb.layout.padstack_instances.values())
|
|
377
377
|
counts = 0
|
|
378
378
|
via_count = 1
|
|
379
379
|
for obj in pds:
|
|
@@ -389,4 +389,4 @@ class LayoutValidation:
|
|
|
389
389
|
obj.set_product_property(
|
|
390
390
|
GrpcProductIdType.DESIGNER, 11, f"{obj.component.name}-{obj.component_pin}"
|
|
391
391
|
)
|
|
392
|
-
self._pedb.
|
|
392
|
+
self._pedb.logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
|
pyedb/grpc/database/modeler.py
CHANGED
|
@@ -92,7 +92,8 @@ class Modeler(object):
|
|
|
92
92
|
def __init__(self, p_edb) -> None:
|
|
93
93
|
"""Initialize Modeler instance."""
|
|
94
94
|
self._pedb = p_edb
|
|
95
|
-
self.
|
|
95
|
+
self.__primitives = []
|
|
96
|
+
self.__primitives_by_layer = {}
|
|
96
97
|
|
|
97
98
|
@property
|
|
98
99
|
def _edb(self) -> Any:
|
|
@@ -267,7 +268,7 @@ class Modeler(object):
|
|
|
267
268
|
try:
|
|
268
269
|
lay = i.layer.name
|
|
269
270
|
if lay in _primitives_by_layer:
|
|
270
|
-
_primitives_by_layer[lay].append(
|
|
271
|
+
_primitives_by_layer[lay].append(i)
|
|
271
272
|
except (InvalidArgumentException, AttributeError):
|
|
272
273
|
pass
|
|
273
274
|
return _primitives_by_layer
|
|
@@ -602,17 +603,20 @@ class Modeler(object):
|
|
|
602
603
|
else:
|
|
603
604
|
corner_style = GrpcPathCornerType.MITER
|
|
604
605
|
_points = []
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
coord
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
606
|
+
if isinstance(points, list):
|
|
607
|
+
for pt in points:
|
|
608
|
+
_pt = []
|
|
609
|
+
for coord in pt:
|
|
610
|
+
coord = Value(coord, self._pedb.active_cell)
|
|
611
|
+
_pt.append(coord)
|
|
612
|
+
_points.append(_pt)
|
|
613
|
+
points = _points
|
|
614
|
+
width = Value(width, self._pedb.active_cell)
|
|
615
|
+
polygon_data = GrpcPolygonData(points)
|
|
616
|
+
elif isinstance(points, GrpcPolygonData):
|
|
617
|
+
polygon_data = points
|
|
618
|
+
else:
|
|
619
|
+
raise TypeError("Points must be a list of points or a PolygonData object.")
|
|
616
620
|
path = Path.create(
|
|
617
621
|
layout=self._active_layout,
|
|
618
622
|
layer=layer_name,
|
|
@@ -630,7 +634,7 @@ class Modeler(object):
|
|
|
630
634
|
|
|
631
635
|
def create_trace(
|
|
632
636
|
self,
|
|
633
|
-
path_list: List[List[float]],
|
|
637
|
+
path_list: Union[List[List[float]], GrpcPolygonData],
|
|
634
638
|
layer_name: str,
|
|
635
639
|
width: float = 1,
|
|
636
640
|
net_name: str = "",
|
|
@@ -1114,7 +1118,7 @@ class Modeler(object):
|
|
|
1114
1118
|
# return None
|
|
1115
1119
|
# pointA = GrpcPointData(pointA[0]), self._get_edb_value(shape.pointA[1])
|
|
1116
1120
|
# )
|
|
1117
|
-
# pointB = self._edb.
|
|
1121
|
+
# pointB = self._edb.Geometry.PointData(
|
|
1118
1122
|
# self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
|
|
1119
1123
|
# )
|
|
1120
1124
|
# return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
|
|
@@ -1475,7 +1479,11 @@ class Modeler(object):
|
|
|
1475
1479
|
if isinstance(pins_by_name, str):
|
|
1476
1480
|
pins_by_name = [pins_by_name]
|
|
1477
1481
|
p_inst = self._pedb.layout.padstack_instances
|
|
1478
|
-
_pins = {
|
|
1482
|
+
_pins = {
|
|
1483
|
+
pin_id: pin
|
|
1484
|
+
for pin_id, pin in p_inst.items()
|
|
1485
|
+
if pin.aedt_name in pins_by_aedt_name or pin.name in pins_by_name
|
|
1486
|
+
}
|
|
1479
1487
|
if not pins:
|
|
1480
1488
|
pins = _pins
|
|
1481
1489
|
else:
|
pyedb/grpc/database/net/net.py
CHANGED
|
@@ -60,7 +60,7 @@ class Net(GrpcNet):
|
|
|
60
60
|
self._pedb = pedb
|
|
61
61
|
self._core_components = pedb.components
|
|
62
62
|
self._core_primitive = pedb.modeler
|
|
63
|
-
self.
|
|
63
|
+
self.__primitives = []
|
|
64
64
|
|
|
65
65
|
@property
|
|
66
66
|
def primitives(self) -> list[Union[Path, Polygon, Circle, Rectangle, Bondwire]]:
|
|
@@ -76,19 +76,20 @@ class Net(GrpcNet):
|
|
|
76
76
|
- :class:`Rectangle <pyedb.grpc.database.primitive.rectangle.Rectangle>`
|
|
77
77
|
- :class:`Bondwire <pyedb.grpc.database.primitive.bondwire.Bondwire>`
|
|
78
78
|
"""
|
|
79
|
-
primitives =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
79
|
+
primitives = super().primitives
|
|
80
|
+
if not len(self.__primitives) == len(primitives):
|
|
81
|
+
for primitive in primitives:
|
|
82
|
+
if primitive.primitive_type == GrpcPrimitiveType.PATH:
|
|
83
|
+
self.__primitives.append(Path(self._pedb, primitive))
|
|
84
|
+
elif primitive.primitive_type == GrpcPrimitiveType.POLYGON:
|
|
85
|
+
self.__primitives.append(Polygon(self._pedb, primitive))
|
|
86
|
+
elif primitive.primitive_type == GrpcPrimitiveType.CIRCLE:
|
|
87
|
+
self.__primitives.append(Circle(self._pedb, primitive))
|
|
88
|
+
elif primitive.primitive_type == GrpcPrimitiveType.RECTANGLE:
|
|
89
|
+
self.__primitives.append(Rectangle(self._pedb, primitive))
|
|
90
|
+
elif primitive.primitive_type == GrpcPrimitiveType.BONDWIRE:
|
|
91
|
+
self.__primitives.append(Bondwire(self._pedb, primitive))
|
|
92
|
+
return self.__primitives
|
|
92
93
|
|
|
93
94
|
@property
|
|
94
95
|
def padstack_instances(self) -> list[PadstackInstance]:
|
pyedb/grpc/database/nets.py
CHANGED
|
@@ -25,9 +25,12 @@ from __future__ import absolute_import # noreorder
|
|
|
25
25
|
from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
|
26
26
|
import warnings
|
|
27
27
|
|
|
28
|
+
from ansys.edb.core.net.net_class import NetClass as GrpcNetClass
|
|
29
|
+
|
|
28
30
|
from pyedb.common.nets import CommonNets
|
|
29
31
|
from pyedb.generic.general_methods import generate_unique_name
|
|
30
32
|
from pyedb.grpc.database.net.net import Net
|
|
33
|
+
from pyedb.grpc.database.net.net_class import NetClass
|
|
31
34
|
from pyedb.grpc.database.primitive.bondwire import Bondwire
|
|
32
35
|
from pyedb.grpc.database.primitive.path import Path
|
|
33
36
|
from pyedb.grpc.database.primitive.polygon import Polygon
|
|
@@ -888,3 +891,70 @@ class Nets(CommonNets):
|
|
|
888
891
|
if isinstance(net_names_list, str):
|
|
889
892
|
net_names_list = [net_names_list]
|
|
890
893
|
return self._pedb.modeler.unite_polygons_on_layer(net_names_list=net_names_list)
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
class NetClasses:
|
|
897
|
+
"""Net classes management.
|
|
898
|
+
|
|
899
|
+
This class provides access to net classes in the EDB layout.
|
|
900
|
+
It allows for operations like retrieving nets, adding/removing nets,
|
|
901
|
+
and checking if a net is part of a net class.
|
|
902
|
+
|
|
903
|
+
Examples
|
|
904
|
+
--------
|
|
905
|
+
>>> from pyedb import Edb
|
|
906
|
+
>>> edb = Edb(myedb, edbversion="2025.1")
|
|
907
|
+
>>> net_classes = edb.net_classes
|
|
908
|
+
"""
|
|
909
|
+
|
|
910
|
+
def __init__(self, pedb):
|
|
911
|
+
self._pedb = pedb
|
|
912
|
+
self._net_classes = pedb.active_layout.net_classes
|
|
913
|
+
|
|
914
|
+
def __getitem__(self, name: str) -> NetClass:
|
|
915
|
+
"""Get a net by name.
|
|
916
|
+
|
|
917
|
+
Parameters
|
|
918
|
+
----------
|
|
919
|
+
name : str
|
|
920
|
+
Name of the net to retrieve.
|
|
921
|
+
|
|
922
|
+
"""
|
|
923
|
+
return self.items[name]
|
|
924
|
+
|
|
925
|
+
@property
|
|
926
|
+
def items(self) -> Dict[str, NetClass]:
|
|
927
|
+
"""Extended nets.
|
|
928
|
+
|
|
929
|
+
Returns
|
|
930
|
+
-------
|
|
931
|
+
Dict[str, :class:`pyedb.grpc.database.nets.nets_class.NetClass`]
|
|
932
|
+
Dictionary of extended nets.
|
|
933
|
+
"""
|
|
934
|
+
return {i.name: i for i in self._pedb.layout.net_classes}
|
|
935
|
+
|
|
936
|
+
def create(self, name, net) -> Union[bool, NetClass]:
|
|
937
|
+
"""Create a new net class.
|
|
938
|
+
|
|
939
|
+
Parameters
|
|
940
|
+
----------
|
|
941
|
+
name : str
|
|
942
|
+
Name of the net class.
|
|
943
|
+
net : str, list
|
|
944
|
+
Name of the nets to be added into this net class.
|
|
945
|
+
|
|
946
|
+
Returns
|
|
947
|
+
-------
|
|
948
|
+
:class:`pyedb.dotnet.database.edb_data.nets_data.EDBNetClassData` `False` if net name already exists.
|
|
949
|
+
"""
|
|
950
|
+
if name in self.items:
|
|
951
|
+
self._pedb.logger.error("{} already exists.".format(name))
|
|
952
|
+
return False
|
|
953
|
+
grpc_net_class = GrpcNetClass.create(self._pedb.active_layout, name)
|
|
954
|
+
if isinstance(net, str):
|
|
955
|
+
net = [net]
|
|
956
|
+
for i in net:
|
|
957
|
+
grpc_net_class.add_net(self._pedb.nets[i])
|
|
958
|
+
net_class = NetClass(self._pedb, grpc_net_class)
|
|
959
|
+
self.items[name] = net_class
|
|
960
|
+
return net_class
|