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
pyedb/grpc/database/padstacks.py
CHANGED
|
@@ -93,8 +93,7 @@ class Padstacks(object):
|
|
|
93
93
|
|
|
94
94
|
def __init__(self, p_edb: Any) -> None:
|
|
95
95
|
self._pedb = p_edb
|
|
96
|
-
self.
|
|
97
|
-
self._definitions: Dict[str, Any] = {}
|
|
96
|
+
self.__definitions: Dict[str, Any] = {}
|
|
98
97
|
|
|
99
98
|
@property
|
|
100
99
|
def _active_layout(self) -> Any:
|
|
@@ -211,13 +210,12 @@ class Padstacks(object):
|
|
|
211
210
|
>>> for name, definition in all_definitions.items():
|
|
212
211
|
... print(f"Padstack: {name}")
|
|
213
212
|
"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
for padstack_def in self._pedb.db.padstack_defs:
|
|
213
|
+
padstack_defs = self._pedb.db.padstack_defs
|
|
214
|
+
self.__definitions = {}
|
|
215
|
+
for padstack_def in padstack_defs:
|
|
218
216
|
if len(padstack_def.data.layer_names) >= 1:
|
|
219
|
-
self.
|
|
220
|
-
return self.
|
|
217
|
+
self.__definitions[padstack_def.name] = PadstackDef(self._pedb, padstack_def)
|
|
218
|
+
return self.__definitions
|
|
221
219
|
|
|
222
220
|
@property
|
|
223
221
|
def instances(self) -> Dict[int, PadstackInstance]:
|
|
@@ -230,15 +228,11 @@ class Padstacks(object):
|
|
|
230
228
|
|
|
231
229
|
Examples
|
|
232
230
|
--------
|
|
233
|
-
>>> all_instances =
|
|
231
|
+
>>> all_instances = edb.padstacks.instances
|
|
234
232
|
>>> for id, instance in all_instances.items():
|
|
235
233
|
... print(f"Instance {id}: {instance.name}")
|
|
236
234
|
"""
|
|
237
|
-
|
|
238
|
-
if len(self._instances) == len(pad_stack_inst):
|
|
239
|
-
return self._instances
|
|
240
|
-
self._instances = {i.edb_uid: PadstackInstance(self._pedb, i) for i in pad_stack_inst}
|
|
241
|
-
return self._instances
|
|
235
|
+
return self._pedb.layout.padstack_instances
|
|
242
236
|
|
|
243
237
|
@property
|
|
244
238
|
def instances_by_name(self) -> Dict[str, PadstackInstance]:
|
|
@@ -348,6 +342,7 @@ class Padstacks(object):
|
|
|
348
342
|
@property
|
|
349
343
|
def pad_type(self) -> GrpcPadType:
|
|
350
344
|
"""Return a PadType Enumerator."""
|
|
345
|
+
return GrpcPadType
|
|
351
346
|
|
|
352
347
|
def create_circular_padstack(
|
|
353
348
|
self,
|
|
@@ -800,7 +795,7 @@ class Padstacks(object):
|
|
|
800
795
|
if net_list and not isinstance(net_list, list):
|
|
801
796
|
net_list = [net_list]
|
|
802
797
|
via_list = []
|
|
803
|
-
for inst in self._layout.padstack_instances:
|
|
798
|
+
for inst_id, inst in self._layout.padstack_instances.items():
|
|
804
799
|
pad_layers_name = inst.padstack_def.data.layer_names
|
|
805
800
|
if len(pad_layers_name) > 1:
|
|
806
801
|
if not net_list:
|
|
@@ -1150,7 +1145,7 @@ class Padstacks(object):
|
|
|
1150
1145
|
padstack_instance.is_layout_pin = is_pin
|
|
1151
1146
|
return PadstackInstance(self._pedb, padstack_instance)
|
|
1152
1147
|
else:
|
|
1153
|
-
|
|
1148
|
+
raise RuntimeError("Place padstack failed")
|
|
1154
1149
|
|
|
1155
1150
|
def remove_pads_from_padstack(self, padstack_name: str, layer_name: Optional[str] = None):
|
|
1156
1151
|
"""Remove pads from a padstack definition on specified layers.
|
|
@@ -1287,6 +1282,29 @@ class Padstacks(object):
|
|
|
1287
1282
|
self.definitions[padstack_name].data = new_padstack_def
|
|
1288
1283
|
return True
|
|
1289
1284
|
|
|
1285
|
+
def get_padstack_instance_by_net_name(self, net: str):
|
|
1286
|
+
"""Get padstack instances by net name.
|
|
1287
|
+
|
|
1288
|
+
.. deprecated:: 0.55.0
|
|
1289
|
+
Use: :func:`get_instances` with `net_name` parameter instead.
|
|
1290
|
+
|
|
1291
|
+
Parameters
|
|
1292
|
+
----------
|
|
1293
|
+
net : str
|
|
1294
|
+
Net name to filter padstack instances.
|
|
1295
|
+
|
|
1296
|
+
Returns
|
|
1297
|
+
-------
|
|
1298
|
+
list[:class:`pyedb.grpc.database.primitive.padstack_instance.PadstackInstance`]
|
|
1299
|
+
List of padstack instances associated with the specified net.
|
|
1300
|
+
"""
|
|
1301
|
+
warnings.warn(
|
|
1302
|
+
"`get_padstack_instance_by_net_name` is deprecated, use `get_instances` with `net_name` "
|
|
1303
|
+
"parameter instead.",
|
|
1304
|
+
DeprecationWarning,
|
|
1305
|
+
)
|
|
1306
|
+
return self.get_instances(net_name=net)
|
|
1307
|
+
|
|
1290
1308
|
def get_instances(
|
|
1291
1309
|
self,
|
|
1292
1310
|
name: Optional[str] = None,
|
|
@@ -1322,7 +1340,7 @@ class Padstacks(object):
|
|
|
1322
1340
|
if pid:
|
|
1323
1341
|
return instances_by_id[pid]
|
|
1324
1342
|
elif name:
|
|
1325
|
-
instances = [inst for inst in list(self.instances.values()) if inst.
|
|
1343
|
+
instances = [inst for inst in list(self.instances.values()) if inst.aedt_name == name]
|
|
1326
1344
|
if instances:
|
|
1327
1345
|
return instances
|
|
1328
1346
|
else:
|
|
@@ -1835,3 +1853,90 @@ class Padstacks(object):
|
|
|
1835
1853
|
clusters[int(label)].append(padstack_ids[i])
|
|
1836
1854
|
|
|
1837
1855
|
return dict(clusters)
|
|
1856
|
+
|
|
1857
|
+
def reduce_via_by_density(
|
|
1858
|
+
self, padstacks: List[int], cell_size_x: float = 1e-3, cell_size_y: float = 1e-3, delete: bool = False
|
|
1859
|
+
) -> tuple[List[int], List[List[List[float]]]]:
|
|
1860
|
+
"""
|
|
1861
|
+
Reduce the number of vias by density. Keep only one via which is closest to the center of the cell. The cells
|
|
1862
|
+
are automatically populated based on the input vias.
|
|
1863
|
+
|
|
1864
|
+
Parameters
|
|
1865
|
+
----------
|
|
1866
|
+
padstacks: List[int]
|
|
1867
|
+
List of padstack ids to be reduced.
|
|
1868
|
+
|
|
1869
|
+
cell_size_x : float
|
|
1870
|
+
Width of each grid cell (default is 1e-3).
|
|
1871
|
+
|
|
1872
|
+
cell_size_y : float
|
|
1873
|
+
Height of each grid cell (default is 1e-3).
|
|
1874
|
+
|
|
1875
|
+
delete: bool
|
|
1876
|
+
If True, delete vias that are not kept (default is False).
|
|
1877
|
+
|
|
1878
|
+
Returns
|
|
1879
|
+
-------
|
|
1880
|
+
List[int]
|
|
1881
|
+
IDs of vias kept after reduction.
|
|
1882
|
+
|
|
1883
|
+
List[List[float]]
|
|
1884
|
+
coordinates for grid lines (for plotting).
|
|
1885
|
+
|
|
1886
|
+
"""
|
|
1887
|
+
to_keep = set()
|
|
1888
|
+
|
|
1889
|
+
all_instances = self.instances
|
|
1890
|
+
positions = np.array([all_instances[_id].position for _id in padstacks])
|
|
1891
|
+
|
|
1892
|
+
x_coords, y_coords = positions[:, 0], positions[:, 1]
|
|
1893
|
+
x_min, x_max = np.min(x_coords), np.max(x_coords)
|
|
1894
|
+
y_min, y_max = np.min(y_coords), np.max(y_coords)
|
|
1895
|
+
|
|
1896
|
+
padstacks_array = np.array(padstacks)
|
|
1897
|
+
cell_map = {} # {(cell_x, cell_y): [(id1, [x1, y1]), (id2, [x2, y2), ...]}
|
|
1898
|
+
grid = []
|
|
1899
|
+
|
|
1900
|
+
for idx, pos in enumerate(positions):
|
|
1901
|
+
i = int((pos[0] - x_min) // cell_size_x)
|
|
1902
|
+
j = int((pos[1] - y_min) // cell_size_y)
|
|
1903
|
+
cell_key = (i, j)
|
|
1904
|
+
cell_map.setdefault(cell_key, []).append((padstacks_array[idx], pos))
|
|
1905
|
+
|
|
1906
|
+
for (i, j), items in cell_map.items():
|
|
1907
|
+
# cell center
|
|
1908
|
+
cell_x_min = x_min + i * cell_size_x
|
|
1909
|
+
cell_y_min = y_min + j * cell_size_y
|
|
1910
|
+
cell_x_mid = cell_x_min + 0.5 * cell_size_x
|
|
1911
|
+
cell_y_mid = cell_y_min + 0.5 * cell_size_y
|
|
1912
|
+
|
|
1913
|
+
grid.append(
|
|
1914
|
+
[
|
|
1915
|
+
[
|
|
1916
|
+
cell_x_min,
|
|
1917
|
+
cell_x_min + cell_size_x,
|
|
1918
|
+
cell_x_min + cell_size_x,
|
|
1919
|
+
cell_x_min,
|
|
1920
|
+
cell_x_min,
|
|
1921
|
+
],
|
|
1922
|
+
[
|
|
1923
|
+
cell_y_min,
|
|
1924
|
+
cell_y_min,
|
|
1925
|
+
cell_y_min + cell_size_y,
|
|
1926
|
+
cell_y_min + cell_size_y,
|
|
1927
|
+
cell_y_min,
|
|
1928
|
+
],
|
|
1929
|
+
]
|
|
1930
|
+
)
|
|
1931
|
+
|
|
1932
|
+
# Find closest via to cell center
|
|
1933
|
+
distances = [np.linalg.norm(pos - [cell_x_mid, cell_y_mid]) for _, pos in items]
|
|
1934
|
+
closest_idx = np.argmin(distances)
|
|
1935
|
+
to_keep.add(items[closest_idx][0])
|
|
1936
|
+
|
|
1937
|
+
if delete:
|
|
1938
|
+
to_delete = set(padstacks) - to_keep
|
|
1939
|
+
for _id in to_delete:
|
|
1940
|
+
all_instances[_id].delete()
|
|
1941
|
+
|
|
1942
|
+
return list(to_keep), grid
|
|
@@ -22,11 +22,14 @@
|
|
|
22
22
|
|
|
23
23
|
import math
|
|
24
24
|
import re
|
|
25
|
+
import warnings
|
|
25
26
|
|
|
26
27
|
from ansys.edb.core.database import ProductIdType as GrpcProductIdType
|
|
27
28
|
from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
|
|
28
29
|
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
29
30
|
from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
|
|
31
|
+
from ansys.edb.core.hierarchy.structure3d import MeshClosure as GrpcMeshClosure
|
|
32
|
+
from ansys.edb.core.hierarchy.structure3d import Structure3D as GrpcStructure3D
|
|
30
33
|
from ansys.edb.core.primitive.padstack_instance import (
|
|
31
34
|
PadstackInstance as GrpcPadstackInstance,
|
|
32
35
|
)
|
|
@@ -34,7 +37,9 @@ from ansys.edb.core.terminal.pin_group_terminal import (
|
|
|
34
37
|
PinGroupTerminal as GrpcPinGroupTerminal,
|
|
35
38
|
)
|
|
36
39
|
|
|
40
|
+
from pyedb.generic.general_methods import generate_unique_name
|
|
37
41
|
from pyedb.grpc.database.definition.padstack_def import PadstackDef
|
|
42
|
+
from pyedb.grpc.database.modeler import Circle
|
|
38
43
|
from pyedb.grpc.database.terminal.padstack_instance_terminal import (
|
|
39
44
|
PadstackInstanceTerminal,
|
|
40
45
|
)
|
|
@@ -67,6 +72,16 @@ class PadstackInstance(GrpcPadstackInstance):
|
|
|
67
72
|
self._pedb = pedb
|
|
68
73
|
self._object_instance = None
|
|
69
74
|
|
|
75
|
+
@property
|
|
76
|
+
def is_pin(self):
|
|
77
|
+
"""Property added for backward compatibility with earlier versions of pyEDB."""
|
|
78
|
+
return self.is_layout_pin
|
|
79
|
+
|
|
80
|
+
@is_pin.setter
|
|
81
|
+
def is_pin(self, value):
|
|
82
|
+
"""Property added for backward compatibility with earlier versions of pyEDB."""
|
|
83
|
+
self.is_layout_pin = value
|
|
84
|
+
|
|
70
85
|
@property
|
|
71
86
|
def definition(self) -> PadstackDef:
|
|
72
87
|
"""Padstack definition.
|
|
@@ -108,6 +123,77 @@ class PadstackInstance(GrpcPadstackInstance):
|
|
|
108
123
|
term = PadstackInstanceTerminal(self._pedb, term)
|
|
109
124
|
return term if not term.is_null else None
|
|
110
125
|
|
|
126
|
+
def set_backdrill_top(self, drill_depth, drill_diameter, offset=0.0):
|
|
127
|
+
"""Set backdrill from top.
|
|
128
|
+
|
|
129
|
+
.deprecated:: 0.55.0
|
|
130
|
+
Use :method:`set_back_drill_by_depth` instead.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
drill_depth : str
|
|
135
|
+
Name of the drill to layer.
|
|
136
|
+
drill_diameter : float, str
|
|
137
|
+
Diameter of backdrill size.
|
|
138
|
+
offset : str, optional.
|
|
139
|
+
offset with respect to the layer to drill to.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
bool
|
|
144
|
+
True if success, False otherwise.
|
|
145
|
+
"""
|
|
146
|
+
warnings.warn(
|
|
147
|
+
"`set_backdrill_top` is deprecated. Use `set_back_drill_by_depth` or " "`set_back_drill_by_layer` instead.",
|
|
148
|
+
DeprecationWarning,
|
|
149
|
+
)
|
|
150
|
+
if isinstance(drill_depth, str):
|
|
151
|
+
if drill_depth in self._pedb.stackup.layers:
|
|
152
|
+
return self.set_back_drill_by_layer(
|
|
153
|
+
drill_to_layer=self._pedb.stackup.layers[drill_depth],
|
|
154
|
+
offset=Value(offset),
|
|
155
|
+
diameter=Value(drill_diameter),
|
|
156
|
+
from_bottom=False,
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
return self.set_back_drill_by_depth(Value(drill_depth), Value(drill_diameter), from_bottom=False)
|
|
160
|
+
|
|
161
|
+
def set_backdrill_bottom(self, drill_depth, drill_diameter, offset=0.0):
|
|
162
|
+
"""Set backdrill from bottom.
|
|
163
|
+
|
|
164
|
+
.deprecated: 0.55.0
|
|
165
|
+
Use: method:`set_back_drill_by_depth` instead.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
drill_depth : str
|
|
170
|
+
Name of the drill to layer.
|
|
171
|
+
drill_diameter : float, str
|
|
172
|
+
Diameter of backdrill size.
|
|
173
|
+
offset : str, optional.
|
|
174
|
+
offset with respect to the layer to drill to.
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
bool
|
|
179
|
+
True if success, False otherwise.
|
|
180
|
+
"""
|
|
181
|
+
warnings.warn(
|
|
182
|
+
"`set_backdrill_bottom` is deprecated. Use `set_back_drill_by_depth` or "
|
|
183
|
+
"`set_back_drill_by_layer` instead.",
|
|
184
|
+
DeprecationWarning,
|
|
185
|
+
)
|
|
186
|
+
if isinstance(drill_depth, str):
|
|
187
|
+
if drill_depth in self._pedb.stackup.layers:
|
|
188
|
+
return self.set_back_drill_by_layer(
|
|
189
|
+
drill_to_layer=self._pedb.stackup.layers[drill_depth],
|
|
190
|
+
offset=Value(offset),
|
|
191
|
+
diameter=Value(drill_diameter),
|
|
192
|
+
from_bottom=True,
|
|
193
|
+
)
|
|
194
|
+
else:
|
|
195
|
+
return self.set_back_drill_by_depth(Value(drill_depth), Value(drill_diameter), from_bottom=True)
|
|
196
|
+
|
|
111
197
|
def create_terminal(self, name=None) -> PadstackInstanceTerminal:
|
|
112
198
|
"""Create a padstack instance terminal.
|
|
113
199
|
|
|
@@ -500,13 +586,16 @@ class PadstackInstance(GrpcPadstackInstance):
|
|
|
500
586
|
list
|
|
501
587
|
List of ``[x, y]`` coordinates for the padstack instance position.
|
|
502
588
|
"""
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
589
|
+
try:
|
|
590
|
+
position = self.get_position_and_rotation()
|
|
591
|
+
if self.component:
|
|
592
|
+
out2 = self.component.transform.transform_point(GrpcPointData(position[:2]))
|
|
593
|
+
self._position = [Value(out2[0]), Value(out2[1])]
|
|
594
|
+
else:
|
|
595
|
+
self._position = [Value(pt) for pt in position[:2]]
|
|
596
|
+
return self._position
|
|
597
|
+
except Exception:
|
|
598
|
+
return False
|
|
510
599
|
|
|
511
600
|
@position.setter
|
|
512
601
|
def position(self, value):
|
|
@@ -684,6 +773,85 @@ class PadstackInstance(GrpcPadstackInstance):
|
|
|
684
773
|
def side_number(self, value):
|
|
685
774
|
self._side_number = self.set_product_property(GrpcProductIdType.HFSS_3D_LAYOUT, 21, value)
|
|
686
775
|
|
|
776
|
+
def split(self) -> list:
|
|
777
|
+
"""Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
|
|
778
|
+
pdef_name = self.padstack_definition
|
|
779
|
+
position = self.position
|
|
780
|
+
net_name = self.net_name
|
|
781
|
+
name = self.name
|
|
782
|
+
stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
|
|
783
|
+
start_idx = stackup_layer_range.index(self.start_layer)
|
|
784
|
+
stop_idx = stackup_layer_range.index(self.stop_layer)
|
|
785
|
+
temp = []
|
|
786
|
+
for idx, (l1, l2) in enumerate(
|
|
787
|
+
list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
|
|
788
|
+
):
|
|
789
|
+
pd_inst = self._pedb.padstacks.place(
|
|
790
|
+
position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2
|
|
791
|
+
)
|
|
792
|
+
temp.append(pd_inst)
|
|
793
|
+
self.delete()
|
|
794
|
+
return temp
|
|
795
|
+
|
|
796
|
+
def convert_hole_to_conical_shape(self, angle=75):
|
|
797
|
+
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
|
|
798
|
+
|
|
799
|
+
Parameters
|
|
800
|
+
----------
|
|
801
|
+
angle : float, optional
|
|
802
|
+
Angle of laser penetration in degrees. The angle defines the lowest hole diameter with this formula:
|
|
803
|
+
HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
|
|
804
|
+
The default is ``75``.
|
|
805
|
+
The lowest hole is ``0.75*HoleDepth/HoleDiam``.
|
|
806
|
+
|
|
807
|
+
Returns
|
|
808
|
+
-------
|
|
809
|
+
"""
|
|
810
|
+
stackup_layers = self._pedb.stackup.stackup_layers
|
|
811
|
+
signal_layers = self._pedb.stackup.signal_layers
|
|
812
|
+
layer_idx = list(signal_layers.keys()).index(self.start_layer)
|
|
813
|
+
|
|
814
|
+
_layer_idx = list(stackup_layers.keys()).index(self.start_layer)
|
|
815
|
+
diel_layer_idx = list(stackup_layers.keys())[_layer_idx + 1]
|
|
816
|
+
diel_thickness = stackup_layers[diel_layer_idx].thickness
|
|
817
|
+
|
|
818
|
+
rad_large = self.definition.hole_diameter / 2
|
|
819
|
+
rad_small = rad_large - diel_thickness * 1 / math.tan(math.radians(angle))
|
|
820
|
+
|
|
821
|
+
if layer_idx + 1 < len(signal_layers) / 2: # upper half of stack
|
|
822
|
+
rad_u = rad_large
|
|
823
|
+
rad_l = rad_small
|
|
824
|
+
else:
|
|
825
|
+
rad_u = rad_small
|
|
826
|
+
rad_l = rad_large
|
|
827
|
+
|
|
828
|
+
layout = self._pedb.active_layout
|
|
829
|
+
cloned_circle = Circle.create(
|
|
830
|
+
layout,
|
|
831
|
+
self.start_layer,
|
|
832
|
+
self.net,
|
|
833
|
+
Value(self.position[0]),
|
|
834
|
+
Value(self.position[1]),
|
|
835
|
+
Value(rad_u),
|
|
836
|
+
)
|
|
837
|
+
cloned_circle2 = Circle.create(
|
|
838
|
+
layout,
|
|
839
|
+
self.stop_layer,
|
|
840
|
+
self.net,
|
|
841
|
+
Value(self.position[0]),
|
|
842
|
+
Value(self.position[1]),
|
|
843
|
+
Value(rad_l),
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
s3d = GrpcStructure3D.create(layout, generate_unique_name("via3d_" + self.aedt_name.replace("via_", ""), n=3))
|
|
847
|
+
s3d.add_member(cloned_circle)
|
|
848
|
+
s3d.add_member(cloned_circle2)
|
|
849
|
+
s3d.set_material(self.definition.material)
|
|
850
|
+
s3d.mesh_closure = GrpcMeshClosure.ENDS_CLOSED
|
|
851
|
+
hole_override_enabled = True
|
|
852
|
+
hole_override_diam = 0
|
|
853
|
+
self.set_hole_overrides(hole_override_enabled, Value(hole_override_diam))
|
|
854
|
+
|
|
687
855
|
def get_backdrill_type(self, from_bottom=True):
|
|
688
856
|
"""Return backdrill type
|
|
689
857
|
Parameters
|
|
@@ -271,6 +271,6 @@ class Polygon(GrpcPolygon, Primitive):
|
|
|
271
271
|
return False
|
|
272
272
|
|
|
273
273
|
def add_void(self, polygon):
|
|
274
|
-
if isinstance(polygon, list):
|
|
274
|
+
if isinstance(polygon, list) or isinstance(polygon, GrpcPolygonData):
|
|
275
275
|
polygon = self._pedb.modeler.create_polygon(points=polygon, layer_name=self.layer.name)
|
|
276
|
-
return self._edb_object.add_void(polygon
|
|
276
|
+
return self._edb_object.add_void(polygon)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from ansys.edb.core.database import ProductIdType as GrpcProductIdType
|
|
2
2
|
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
3
3
|
|
|
4
|
-
import pyedb.siwave_core.cpa.simulation_setup_data_model
|
|
5
4
|
from pyedb.siwave_core.cpa.simulation_setup_data_model import SIwaveCpaSetup, Vrm
|
|
6
5
|
from pyedb.siwave_core.product_properties import SIwaveProperties
|
|
7
6
|
|
|
@@ -190,11 +189,13 @@ class ChannelSetup:
|
|
|
190
189
|
Raises:
|
|
191
190
|
ValueError: If the input is not a list.
|
|
192
191
|
"""
|
|
192
|
+
from pyedb.siwave_core.cpa.simulation_setup_data_model import Vrm
|
|
193
|
+
|
|
193
194
|
if not isinstance(value, list):
|
|
194
195
|
raise ValueError("vrm setter must have list as input.")
|
|
195
196
|
vrm_str = ""
|
|
196
197
|
for vrm in value:
|
|
197
|
-
if isinstance(vrm,
|
|
198
|
+
if isinstance(vrm, Vrm):
|
|
198
199
|
if vrm_str:
|
|
199
200
|
vrm_str += "*"
|
|
200
201
|
vrm_str += vrm.name
|
pyedb/grpc/database/siwave.py
CHANGED
|
@@ -589,7 +589,7 @@ class Siwave(object):
|
|
|
589
589
|
f.write('ExportTouchstone "{}"\n'.format(touchstone_file_path))
|
|
590
590
|
f.write("SaveSiw\n")
|
|
591
591
|
|
|
592
|
-
return
|
|
592
|
+
return file_name
|
|
593
593
|
|
|
594
594
|
def add_cpa_analysis(self, name=None, siwave_cpa_setup_class=None):
|
|
595
595
|
if not name:
|
|
@@ -431,12 +431,10 @@ class SourceExcitation:
|
|
|
431
431
|
refdes = Component(self._pedb, refdes)
|
|
432
432
|
pins = self._get_pins_for_ports(pins, refdes)
|
|
433
433
|
if not pins:
|
|
434
|
-
|
|
435
|
-
return False
|
|
434
|
+
raise RuntimeWarning("No pins found during port creation. Port is not defined.")
|
|
436
435
|
reference_pins = self._get_pins_for_ports(reference_pins, refdes)
|
|
437
436
|
if not reference_pins:
|
|
438
|
-
|
|
439
|
-
return False
|
|
437
|
+
raise RuntimeWarning("No reference pins found during port creation. Port is not defined.")
|
|
440
438
|
if refdes and any(refdes.rlc_values):
|
|
441
439
|
return self._pedb.components.deactivate_rlc_component(component=refdes, create_circuit_port=True)
|
|
442
440
|
if not port_name:
|
|
@@ -2801,11 +2799,15 @@ class SourceExcitation:
|
|
|
2801
2799
|
self,
|
|
2802
2800
|
terminal: Union[PadstackInstanceTerminal, EdgeTerminal],
|
|
2803
2801
|
ref_terminal: Union[PadstackInstanceTerminal, EdgeTerminal],
|
|
2802
|
+
magnitude: Union[int, float] = 1,
|
|
2803
|
+
phase: Union[int, float] = 0,
|
|
2804
2804
|
) -> bool:
|
|
2805
2805
|
"""Create a voltage source.
|
|
2806
2806
|
|
|
2807
2807
|
Parameters
|
|
2808
2808
|
----------
|
|
2809
|
+
name : str, optional
|
|
2810
|
+
Voltage source name
|
|
2809
2811
|
terminal : :class:`EdgeTerminal <pyedb.grpc.database.terminals.EdgeTerminal>`,
|
|
2810
2812
|
:class:`PadstackInstanceTerminal <pyedb.grpc.database.terminals.PadstackInstanceTerminal>`,
|
|
2811
2813
|
:class:`PointTerminal <pyedb.grpc.database.terminals.PointTerminal>`,
|
|
@@ -2816,6 +2818,10 @@ class SourceExcitation:
|
|
|
2816
2818
|
:class:`PadstackInstanceTerminal <pyedb.grpc.database.terminals.PointTerminal>`,
|
|
2817
2819
|
:class:`PinGroupTerminal <pyedb.grpc.database.terminals.PinGroupTerminal>`,
|
|
2818
2820
|
Negative terminal of the source.
|
|
2821
|
+
magnitude : int, float, optional
|
|
2822
|
+
Magnitude of the source.
|
|
2823
|
+
phase : int, float, optional
|
|
2824
|
+
Phase of the source
|
|
2819
2825
|
|
|
2820
2826
|
Returns
|
|
2821
2827
|
-------
|
|
@@ -2834,7 +2840,8 @@ class SourceExcitation:
|
|
|
2834
2840
|
|
|
2835
2841
|
ref_term = Terminal(self._pedb, ref_terminal)
|
|
2836
2842
|
ref_term.boundary_type = "voltage_source"
|
|
2837
|
-
|
|
2843
|
+
term.magnitude = self._pedb.value(magnitude)
|
|
2844
|
+
term.phase = self._pedb.value(phase)
|
|
2838
2845
|
term.ref_terminal = ref_terminal
|
|
2839
2846
|
return term
|
|
2840
2847
|
|
pyedb/grpc/database/stackup.py
CHANGED
|
@@ -1355,7 +1355,7 @@ class Stackup(LayerCollection):
|
|
|
1355
1355
|
_offset_y = Value(offset_y)
|
|
1356
1356
|
|
|
1357
1357
|
if edb_cell.name not in self._pedb.cell_names:
|
|
1358
|
-
list_cells = self._pedb.copy_cells([edb_cell
|
|
1358
|
+
list_cells = self._pedb.copy_cells([edb_cell])
|
|
1359
1359
|
edb_cell = list_cells[0]
|
|
1360
1360
|
self._pedb.layout.cell.is_blackbox = True
|
|
1361
1361
|
cell_inst2 = GrpcCellInstance.create(
|
|
@@ -152,7 +152,7 @@ class BundleTerminal(GrpcBundleTerminal):
|
|
|
152
152
|
-------
|
|
153
153
|
:class:`Terminal <pyedb.grpc.database.terminal.terminal.Terminal>`
|
|
154
154
|
"""
|
|
155
|
-
return Terminal(self._pedb,
|
|
155
|
+
return Terminal(self._pedb, super().reference_terminal)
|
|
156
156
|
|
|
157
157
|
@reference_terminal.setter
|
|
158
158
|
def reference_terminal(self, value):
|
|
@@ -26,7 +26,7 @@ from ansys.edb.core.terminal.padstack_instance_terminal import (
|
|
|
26
26
|
from ansys.edb.core.terminal.terminal import BoundaryType as GrpcBoundaryType
|
|
27
27
|
|
|
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 PadstackInstanceTerminal(GrpcPadstackInstanceTerminal):
|
|
@@ -27,7 +27,7 @@ from ansys.edb.core.terminal.terminal import BoundaryType as GrpcBoundaryType
|
|
|
27
27
|
|
|
28
28
|
from pyedb.grpc.database.net.net import Net
|
|
29
29
|
from pyedb.grpc.database.utility.value import Value
|
|
30
|
-
from pyedb.misc.
|
|
30
|
+
from pyedb.misc.decorators import deprecated_property
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class PinGroupTerminal(GrpcPinGroupTerminal):
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
# SOFTWARE.
|
|
22
|
+
|
|
22
23
|
import ansys.edb.core.utility.value
|
|
23
24
|
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
24
25
|
|
|
@@ -26,8 +26,8 @@ import re
|
|
|
26
26
|
import subprocess
|
|
27
27
|
import sys
|
|
28
28
|
|
|
29
|
-
from pyedb.edb_logger import pyedb_logger
|
|
30
29
|
from pyedb.generic.general_methods import ET, env_path, env_value, is_linux
|
|
30
|
+
from pyedb.generic.settings import settings
|
|
31
31
|
from pyedb.misc.aedtlib_personalib_install import write_pretty_xml
|
|
32
32
|
from pyedb.misc.misc import list_installed_ansysem
|
|
33
33
|
|
|
@@ -56,7 +56,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
56
56
|
base_path = env_path(edbversion)
|
|
57
57
|
sys.path.append(base_path)
|
|
58
58
|
else:
|
|
59
|
-
|
|
59
|
+
settings.logger.error("No Edb installation found. Check environment variables")
|
|
60
60
|
return False
|
|
61
61
|
os.environ["HELIC_ROOT"] = os.path.join(base_path, "helic")
|
|
62
62
|
if os.getenv("ANSYSLMD_LICENCE_FILE", None) is None:
|
|
@@ -69,7 +69,7 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
69
69
|
os.environ["ANSYSLMD_LICENSE_FILE"] = line.split("=")[1]
|
|
70
70
|
break
|
|
71
71
|
else:
|
|
72
|
-
|
|
72
|
+
settings.logger.error("ANSYSLMD_LICENSE_FILE is not defined.")
|
|
73
73
|
vlc_file_name = os.path.splitext(tech_file)[0]
|
|
74
74
|
if not control_file:
|
|
75
75
|
control_file = vlc_file_name + ".xml"
|
|
@@ -103,9 +103,9 @@ def convert_technology_file(tech_file, edbversion=None, control_file=None):
|
|
|
103
103
|
p = subprocess.Popen(command, env=my_env)
|
|
104
104
|
p.wait()
|
|
105
105
|
if os.path.exists(control_file):
|
|
106
|
-
|
|
106
|
+
settings.logger.info("Xml file created.")
|
|
107
107
|
return control_file
|
|
108
|
-
|
|
108
|
+
settings.logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
109
109
|
return False
|
|
110
110
|
|
|
111
111
|
|