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.

Files changed (105) hide show
  1. pyedb/__init__.py +1 -8
  2. pyedb/configuration/cfg_boundaries.py +69 -151
  3. pyedb/configuration/cfg_components.py +201 -460
  4. pyedb/configuration/cfg_data.py +4 -2
  5. pyedb/configuration/cfg_general.py +13 -36
  6. pyedb/configuration/cfg_modeler.py +2 -1
  7. pyedb/configuration/cfg_nets.py +21 -35
  8. pyedb/configuration/cfg_operations.py +22 -151
  9. pyedb/configuration/cfg_package_definition.py +56 -112
  10. pyedb/configuration/cfg_padstacks.py +292 -688
  11. pyedb/configuration/cfg_pin_groups.py +32 -79
  12. pyedb/configuration/cfg_ports_sources.py +19 -6
  13. pyedb/configuration/cfg_s_parameter_models.py +67 -172
  14. pyedb/configuration/cfg_setup.py +102 -295
  15. pyedb/configuration/configuration.py +64 -5
  16. pyedb/dotnet/database/Variables.py +26 -19
  17. pyedb/dotnet/database/cell/connectable.py +38 -9
  18. pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
  19. pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
  20. pyedb/dotnet/database/cell/layout.py +63 -2
  21. pyedb/dotnet/database/cell/layout_obj.py +2 -2
  22. pyedb/dotnet/database/cell/primitive/path.py +6 -8
  23. pyedb/dotnet/database/cell/primitive/primitive.py +3 -24
  24. pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
  25. pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
  26. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  27. pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
  28. pyedb/dotnet/database/cell/terminal/terminal.py +24 -24
  29. pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
  30. pyedb/dotnet/database/components.py +137 -124
  31. pyedb/dotnet/database/definition/component_def.py +4 -4
  32. pyedb/dotnet/database/definition/component_model.py +1 -1
  33. pyedb/dotnet/database/definition/package_def.py +2 -3
  34. pyedb/dotnet/database/dotnet/database.py +3 -199
  35. pyedb/dotnet/database/dotnet/primitive.py +3 -3
  36. pyedb/dotnet/database/edb_data/control_file.py +5 -5
  37. pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
  38. pyedb/dotnet/database/edb_data/layer_data.py +23 -23
  39. pyedb/dotnet/database/edb_data/padstacks_data.py +63 -88
  40. pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
  41. pyedb/dotnet/database/edb_data/sources.py +6 -6
  42. pyedb/dotnet/database/edb_data/variables.py +1 -1
  43. pyedb/dotnet/database/geometry/point_data.py +14 -10
  44. pyedb/dotnet/database/geometry/polygon_data.py +3 -3
  45. pyedb/dotnet/database/hfss.py +46 -48
  46. pyedb/dotnet/database/layout_validation.py +14 -11
  47. pyedb/dotnet/database/materials.py +10 -11
  48. pyedb/dotnet/database/modeler.py +97 -91
  49. pyedb/dotnet/database/nets.py +19 -22
  50. pyedb/dotnet/database/padstack.py +171 -83
  51. pyedb/dotnet/database/siwave.py +42 -42
  52. pyedb/dotnet/database/stackup.py +140 -72
  53. pyedb/dotnet/database/utilities/heatsink.py +4 -4
  54. pyedb/dotnet/database/utilities/obj_base.py +2 -2
  55. pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
  56. pyedb/dotnet/database/utilities/value.py +16 -16
  57. pyedb/dotnet/edb.py +230 -152
  58. pyedb/edb_logger.py +12 -27
  59. pyedb/extensions/create_cell_array.py +394 -0
  60. pyedb/extensions/via_design_backend.py +6 -3
  61. pyedb/generic/data_handlers.py +6 -7
  62. pyedb/generic/design_types.py +81 -30
  63. pyedb/generic/filesystem.py +5 -2
  64. pyedb/generic/general_methods.py +2 -122
  65. pyedb/generic/process.py +44 -108
  66. pyedb/generic/settings.py +79 -19
  67. pyedb/grpc/database/components.py +26 -4
  68. pyedb/grpc/database/control_file.py +5 -5
  69. pyedb/grpc/database/definition/materials.py +1 -1
  70. pyedb/grpc/database/definition/package_def.py +3 -3
  71. pyedb/grpc/database/definition/padstack_def.py +53 -0
  72. pyedb/grpc/database/geometry/polygon_data.py +1 -1
  73. pyedb/grpc/database/layout/layout.py +81 -5
  74. pyedb/grpc/database/layout_validation.py +5 -5
  75. pyedb/grpc/database/modeler.py +24 -16
  76. pyedb/grpc/database/net/net.py +15 -14
  77. pyedb/grpc/database/nets.py +70 -0
  78. pyedb/grpc/database/padstacks.py +122 -17
  79. pyedb/grpc/database/primitive/padstack_instance.py +175 -7
  80. pyedb/grpc/database/primitive/polygon.py +2 -2
  81. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +3 -2
  82. pyedb/grpc/database/siwave.py +1 -1
  83. pyedb/grpc/database/source_excitations.py +12 -5
  84. pyedb/grpc/database/stackup.py +1 -1
  85. pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
  86. pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
  87. pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
  88. pyedb/grpc/database/utility/value.py +1 -0
  89. pyedb/grpc/database/utility/xml_control_file.py +5 -5
  90. pyedb/grpc/edb.py +80 -30
  91. pyedb/grpc/edb_init.py +3 -3
  92. pyedb/grpc/rpc_session.py +14 -13
  93. pyedb/libraries/common.py +366 -0
  94. pyedb/libraries/rf_libraries/base_functions.py +1358 -0
  95. pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
  96. pyedb/misc/decorators.py +61 -0
  97. pyedb/misc/misc.py +0 -13
  98. pyedb/modeler/geometry_operators.py +6 -6
  99. pyedb/siwave.py +6 -8
  100. pyedb/siwave_core/__init__.py +0 -0
  101. pyedb/siwave_core/cpa/__init__.py +0 -0
  102. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/METADATA +1 -2
  103. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/RECORD +105 -98
  104. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/WHEEL +0 -0
  105. {pyedb-0.54.0.dist-info → pyedb-0.56.0.dist-info}/licenses/LICENSE +0 -0
@@ -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._instances: Dict[int, PadstackInstance] = {}
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
- if len(self._definitions) == len(self.db.padstack_defs):
215
- return self._definitions
216
- self._definitions = {}
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._definitions[padstack_def.name] = PadstackDef(self._pedb, padstack_def)
220
- return self._definitions
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 = edb_padstacks.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
- pad_stack_inst = self._pedb.layout.padstack_instances
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
- return False
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.name == name]
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
- position = self.get_position_and_rotation()
504
- if self.component:
505
- out2 = self.component.transform.transform_point(GrpcPointData(position[:2]))
506
- self._position = [Value(out2[0]), Value(out2[1])]
507
- else:
508
- self._position = [Value(pt) for pt in position[:2]]
509
- return self._position
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._edb_object)
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, pyedb.siwave_core.cpa.simulation_setup_data_model.Vrm):
198
+ if isinstance(vrm, Vrm):
198
199
  if vrm_str:
199
200
  vrm_str += "*"
200
201
  vrm_str += vrm.name
@@ -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 True if os.path.exists(file_name) else False
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
- self._logger.error("No pins found during port creation. Port is not defined.")
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
- self._logger.error("No reference pins found during port creation. Port is not defined.")
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
 
@@ -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.api_object])
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, self.reference_terminal)
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.misc import deprecated_property
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.misc import deprecated_property
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
- pyedb_logger.error("No Edb installation found. Check environment variables")
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
- pyedb_logger.error("ANSYSLMD_LICENSE_FILE is not defined.")
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
- pyedb_logger.info("Xml file created.")
106
+ settings.logger.info("Xml file created.")
107
107
  return control_file
108
- pyedb_logger.error("Technology files are supported only in Linux. Use control file instead.")
108
+ settings.logger.error("Technology files are supported only in Linux. Use control file instead.")
109
109
  return False
110
110
 
111
111