pyedb 0.43.0__py3-none-any.whl → 0.45.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 (68) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +21 -15
  3. pyedb/configuration/cfg_components.py +8 -8
  4. pyedb/configuration/cfg_general.py +14 -6
  5. pyedb/configuration/cfg_modeler.py +8 -0
  6. pyedb/configuration/cfg_operations.py +40 -1
  7. pyedb/configuration/cfg_package_definition.py +41 -1
  8. pyedb/configuration/cfg_padstacks.py +611 -256
  9. pyedb/configuration/cfg_pin_groups.py +1 -1
  10. pyedb/configuration/cfg_ports_sources.py +234 -66
  11. pyedb/configuration/cfg_s_parameter_models.py +81 -1
  12. pyedb/configuration/cfg_setup.py +167 -33
  13. pyedb/configuration/cfg_stackup.py +44 -0
  14. pyedb/configuration/configuration.py +13 -3
  15. pyedb/dotnet/database/cell/primitive/path.py +12 -0
  16. pyedb/dotnet/database/edb_data/design_options.py +19 -1
  17. pyedb/dotnet/database/edb_data/padstacks_data.py +9 -4
  18. pyedb/dotnet/database/geometry/point_data.py +26 -0
  19. pyedb/dotnet/database/geometry/polygon_data.py +13 -2
  20. pyedb/dotnet/database/nets.py +13 -3
  21. pyedb/dotnet/database/padstack.py +6 -2
  22. pyedb/dotnet/database/utilities/simulation_setup.py +7 -17
  23. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +30 -0
  24. pyedb/dotnet/edb.py +41 -18
  25. pyedb/grpc/database/components.py +2 -3
  26. pyedb/grpc/database/definition/component_def.py +15 -0
  27. pyedb/grpc/database/definition/component_pin.py +1 -1
  28. pyedb/grpc/database/definition/materials.py +27 -0
  29. pyedb/grpc/database/definition/package_def.py +20 -2
  30. pyedb/grpc/database/definition/padstack_def.py +5 -2
  31. pyedb/grpc/database/hfss.py +10 -1
  32. pyedb/grpc/database/hierarchy/component.py +4 -2
  33. pyedb/grpc/database/hierarchy/pingroup.py +12 -8
  34. pyedb/grpc/database/layers/layer.py +28 -0
  35. pyedb/grpc/database/layers/stackup_layer.py +281 -40
  36. pyedb/grpc/database/layout/layout.py +12 -6
  37. pyedb/grpc/database/layout_validation.py +2 -2
  38. pyedb/grpc/database/modeler.py +8 -8
  39. pyedb/grpc/database/padstacks.py +15 -9
  40. pyedb/grpc/database/ports/ports.py +3 -3
  41. pyedb/grpc/database/primitive/bondwire.py +3 -3
  42. pyedb/grpc/database/primitive/circle.py +1 -1
  43. pyedb/grpc/database/primitive/padstack_instance.py +13 -3
  44. pyedb/grpc/database/primitive/path.py +2 -2
  45. pyedb/grpc/database/primitive/polygon.py +3 -3
  46. pyedb/grpc/database/primitive/primitive.py +1 -1
  47. pyedb/grpc/database/primitive/rectangle.py +2 -2
  48. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +78 -30
  49. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +73 -30
  50. pyedb/grpc/database/simulation_setup/sweep_data.py +12 -1
  51. pyedb/grpc/database/siwave.py +10 -1
  52. pyedb/grpc/database/source_excitations.py +19 -9
  53. pyedb/grpc/database/stackup.py +26 -10
  54. pyedb/grpc/database/terminal/bundle_terminal.py +3 -3
  55. pyedb/grpc/database/terminal/edge_terminal.py +95 -2
  56. pyedb/grpc/database/terminal/padstack_instance_terminal.py +42 -2
  57. pyedb/grpc/database/terminal/pingroup_terminal.py +48 -2
  58. pyedb/grpc/database/terminal/point_terminal.py +10 -1
  59. pyedb/grpc/database/terminal/terminal.py +4 -4
  60. pyedb/grpc/database/utility/hfss_extent_info.py +14 -10
  61. pyedb/grpc/edb.py +21 -17
  62. pyedb/grpc/edb_init.py +19 -15
  63. pyedb/grpc/rpc_session.py +11 -8
  64. pyedb/misc/misc.py +13 -0
  65. {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/METADATA +6 -6
  66. {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/RECORD +68 -68
  67. {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/LICENSE +0 -0
  68. {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/WHEEL +0 -0
@@ -32,6 +32,59 @@ class CfgSetup:
32
32
  """
33
33
 
34
34
  class Common:
35
+ class Grpc:
36
+ def __init__(self, parent):
37
+ self.parent = parent
38
+
39
+ def apply_freq_sweep(self, edb_setup):
40
+ for i in self.parent.parent.freq_sweep:
41
+ f_set = []
42
+ freq_string = []
43
+ for f in i.get("frequencies", []):
44
+ if isinstance(f, dict):
45
+ increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
46
+ f_set.append([f["distribution"], f["start"], f["stop"], increment])
47
+ else:
48
+ freq_string.append(f)
49
+ discrete_sweep = True
50
+ if i["type"] == "interpolation":
51
+ discrete_sweep = False
52
+ if freq_string:
53
+ for _sweep in freq_string:
54
+ _sw = _sweep.split(" ")
55
+ edb_setup.add_sweep(
56
+ name=i["name"],
57
+ distribution=_sw[0],
58
+ start_freq=_sw[1],
59
+ stop_freq=_sw[2],
60
+ step=_sw[3],
61
+ discrete=discrete_sweep,
62
+ )
63
+ else:
64
+ edb_setup.add_sweep(i["name"], frequency_set=f_set, discrete=discrete_sweep)
65
+
66
+ class DotNet(Grpc):
67
+ def __init__(self, parent):
68
+ super().__init__(parent)
69
+
70
+ @staticmethod
71
+ def set_frequency_string(sweep, freq_string):
72
+ sweep.frequency_string = freq_string
73
+
74
+ def apply_freq_sweep(self, edb_setup):
75
+ for i in self.parent.parent.freq_sweep:
76
+ f_set = []
77
+ freq_string = []
78
+ for f in i.get("frequencies", []):
79
+ if isinstance(f, dict):
80
+ increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
81
+ f_set.append([f["distribution"], f["start"], f["stop"], increment])
82
+ else:
83
+ freq_string.append(f)
84
+ sweep = edb_setup.add_sweep(i["name"], frequency_set=f_set, sweep_type=i["type"])
85
+ if len(freq_string) > 0:
86
+ self.parent.api.set_frequency_string(sweep, freq_string)
87
+
35
88
  @property
36
89
  def pyedb_obj(self):
37
90
  return self.parent.pyedb_obj
@@ -39,24 +92,17 @@ class CfgSetup:
39
92
  def __init__(self, parent):
40
93
  self.parent = parent
41
94
  self.pedb = parent.pedb
95
+ if self.pedb.grpc:
96
+ self.api = self.Grpc(self)
97
+ else:
98
+ self.api = self.DotNet(self)
42
99
 
43
100
  def _retrieve_parameters_from_edb_common(self):
44
101
  self.parent.name = self.pyedb_obj.name
45
102
  self.parent.type = self.pyedb_obj.type
46
103
 
47
104
  def _apply_freq_sweep(self, edb_setup):
48
- for i in self.parent.freq_sweep:
49
- f_set = []
50
- freq_string = []
51
- for f in i.get("frequencies", []):
52
- if isinstance(f, dict):
53
- increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
54
- f_set.append([f["distribution"], f["start"], f["stop"], increment])
55
- else:
56
- freq_string.append(f)
57
- sweep = edb_setup.add_sweep(i["name"], frequency_set=f_set, sweep_type=i["type"])
58
- if len(freq_string) > 0:
59
- sweep.frequency_string = freq_string
105
+ self.api.apply_freq_sweep(edb_setup)
60
106
 
61
107
  class Grpc(Common):
62
108
  def __init__(self, parent):
@@ -148,9 +194,8 @@ class CfgSIwaveDCSetup(CfgSetup):
148
194
  edb_setup = self.pedb.create_siwave_dc_setup(
149
195
  name=self.parent.name, dc_slider_position=self.parent.dc_slider_position
150
196
  )
151
- edb_setup.dc_settings.dc_slider_position = self.parent.dc_slider_position
152
- dc_ir_settings = self.parent.dc_ir_settings
153
- edb_setup.dc_ir_settings.export_dc_thermal_data = dc_ir_settings["export_dc_thermal_data"]
197
+ edb_setup.settings.dc.dc_slider_pos = self.parent.dc_slider_position
198
+ edb_setup.settings.export_dc_thermal_data = self.parent.dc_ir_settings.get("export_dc_thermal_data", False)
154
199
 
155
200
  def retrieve_parameters_from_edb(self):
156
201
  self._retrieve_parameters_from_edb_common()
@@ -163,6 +208,14 @@ class CfgSIwaveDCSetup(CfgSetup):
163
208
  def __init__(self, parent):
164
209
  super().__init__(parent)
165
210
 
211
+ def set_parameters_to_edb(self):
212
+ edb_setup = self.pedb.create_siwave_dc_setup(
213
+ name=self.parent.name, dc_slider_position=self.parent.dc_slider_position
214
+ )
215
+ edb_setup.dc_settings.dc_slider_position = self.parent.dc_slider_position
216
+ dc_ir_settings = self.parent.dc_ir_settings
217
+ edb_setup.dc_ir_settings.export_dc_thermal_data = dc_ir_settings.get("export_dc_thermal_data", False)
218
+
166
219
  def __init__(self, pedb, pyedb_obj, **kwargs):
167
220
  super().__init__(pedb, pyedb_obj, **kwargs)
168
221
  self.type = "siwave_dc"
@@ -202,6 +255,57 @@ class CfgHFSSSetup(CfgSetup):
202
255
  net_layer_list=i.get("nets_layers_list", {}),
203
256
  )
204
257
 
258
+ def retrieve_parameters_from_edb(self):
259
+ self._retrieve_parameters_from_edb_common()
260
+ single_frequency_adaptive_solution = self.pyedb_obj.settings.general.single_frequency_adaptive_solution
261
+ self.parent.f_adapt = single_frequency_adaptive_solution.adaptive_frequency
262
+ self.parent.max_num_passes = single_frequency_adaptive_solution.max_passes
263
+ self.parent.max_mag_delta_s = float(single_frequency_adaptive_solution.max_delta)
264
+ self.parent.freq_sweep = []
265
+ setup_sweeps = self.sort_sweep_data(self.pyedb_obj.sweep_data)
266
+ for setup_name, sweeps in setup_sweeps.items():
267
+ sw_name = sweeps[0].name
268
+ sw_type = sweeps[0].type.name.lower().split("_")[0]
269
+ freq_strings = [f.frequency_string for f in sweeps]
270
+ self.parent.freq_sweep.append({"name": sw_name, "type": sw_type, "frequencies": freq_strings})
271
+
272
+ self.parent.mesh_operations = []
273
+ from ansys.edb.core.simulation_setup.mesh_operation import (
274
+ LengthMeshOperation as GrpcLengthMeshOperation,
275
+ )
276
+
277
+ for mesh_op in self.pyedb_obj.mesh_operations:
278
+ if isinstance(mesh_op, GrpcLengthMeshOperation):
279
+ mop_type = "length"
280
+ else:
281
+ mop_type = "skin"
282
+ self.parent.mesh_operations.append(
283
+ {
284
+ "name": mesh_op.name,
285
+ "type": mop_type,
286
+ "max_elements": mesh_op.max_elements,
287
+ "max_length": mesh_op.max_length,
288
+ "restrict_length": mesh_op.restrict_max_length,
289
+ "refine_inside": mesh_op.refine_inside,
290
+ "nets_layers_list": mesh_op.net_layer_info,
291
+ }
292
+ )
293
+
294
+ @staticmethod
295
+ def sort_sweep_data(sweep_data):
296
+ """grpc sweep data contains all sweeps for each setup, we need to sort thwm by setup"""
297
+ setups = {}
298
+ for sweep in sweep_data:
299
+ if sweep.name not in setups:
300
+ setups[sweep.name] = [sweep]
301
+ else:
302
+ setups[sweep.name].append(sweep)
303
+ return setups
304
+
305
+ class DotNet(Grpc):
306
+ def __init__(self, parent):
307
+ super().__init__(parent)
308
+
205
309
  def retrieve_parameters_from_edb(self):
206
310
  self._retrieve_parameters_from_edb_common()
207
311
  adaptive_frequency_data_list = list(self.pyedb_obj.adaptive_settings.adaptive_frequency_data_list)[0]
@@ -226,10 +330,6 @@ class CfgHFSSSetup(CfgSetup):
226
330
  }
227
331
  )
228
332
 
229
- class DotNet(Grpc):
230
- def __init__(self, parent):
231
- super().__init__(parent)
232
-
233
333
  def __init__(self, pedb, pyedb_obj, **kwargs):
234
334
  super().__init__(pedb, pyedb_obj, **kwargs)
235
335
  self.type = "hfss"
@@ -254,9 +354,56 @@ class CfgHFSSSetup(CfgSetup):
254
354
 
255
355
 
256
356
  class CfgSetups:
357
+ class Grpc:
358
+ def __init__(self, parent):
359
+ self.parent = parent
360
+ self._pedb = parent.pedb
361
+
362
+ def retrieve_parameters_from_edb(self):
363
+ self.parent.setups = []
364
+ for _, setup in self._pedb.setups.items():
365
+ if setup.type.name.lower() == "hfss":
366
+ hfss = CfgHFSSSetup(self._pedb, setup)
367
+ hfss.api.retrieve_parameters_from_edb()
368
+ self.parent.setups.append(hfss)
369
+ elif setup.type.name.lower() == "si_wave_dcir":
370
+ siwave_dc = CfgSIwaveDCSetup(self._pedb, setup)
371
+ siwave_dc.api.retrieve_parameters_from_edb()
372
+ self.parent.setups.append(siwave_dc)
373
+ elif setup.type.name.lower() == "si_wave":
374
+ siwave_ac = CfgSIwaveACSetup(self._pedb, setup)
375
+ siwave_ac.api.retrieve_parameters_from_edb()
376
+ self.parent.setups.append(siwave_ac)
377
+ elif setup.type.name.lower() == "raptor_x":
378
+ pass
379
+
380
+ class DotNet(Grpc):
381
+ def __init__(self, parent):
382
+ super().__init__(parent)
383
+
384
+ def retrieve_parameters_from_edb(self):
385
+ self.parent.setups = []
386
+ for _, setup in self._pedb.setups.items():
387
+ if setup.type == "hfss":
388
+ hfss = CfgHFSSSetup(self._pedb, setup)
389
+ hfss.api.retrieve_parameters_from_edb()
390
+ self.parent.setups.append(hfss)
391
+ elif setup.type == "siwave_dc":
392
+ siwave_dc = CfgSIwaveDCSetup(self._pedb, setup)
393
+ siwave_dc.api.retrieve_parameters_from_edb()
394
+ self.parent.setups.append(siwave_dc)
395
+ elif setup.type == "siwave_ac":
396
+ siwave_ac = CfgSIwaveACSetup(self._pedb, setup)
397
+ siwave_ac.api.retrieve_parameters_from_edb()
398
+ self.parent.setups.append(siwave_ac)
399
+
257
400
  def __init__(self, pedb, setups_data):
258
401
  self.pedb = pedb
259
402
  self.setups = []
403
+ if self.pedb.grpc:
404
+ self.api = self.Grpc(self)
405
+ else:
406
+ self.api = self.DotNet(self)
260
407
  for stp in setups_data:
261
408
  if stp["type"].lower() == "hfss":
262
409
  self.setups.append(CfgHFSSSetup(self.pedb, None, **stp))
@@ -273,17 +420,4 @@ class CfgSetups:
273
420
  return [i.to_dict() for i in self.setups]
274
421
 
275
422
  def retrieve_parameters_from_edb(self):
276
- self.setups = []
277
- for _, setup in self.pedb.setups.items():
278
- if setup.type == "hfss":
279
- hfss = CfgHFSSSetup(self.pedb, setup)
280
- hfss.api.retrieve_parameters_from_edb()
281
- self.setups.append(hfss)
282
- elif setup.type == "siwave_dc":
283
- siwave_dc = CfgSIwaveDCSetup(self.pedb, setup)
284
- siwave_dc.api.retrieve_parameters_from_edb()
285
- self.setups.append(siwave_dc)
286
- elif setup.type == "siwave_ac":
287
- siwave_ac = CfgSIwaveACSetup(self.pedb, setup)
288
- siwave_ac.api.retrieve_parameters_from_edb()
289
- self.setups.append(siwave_ac)
423
+ self.api.retrieve_parameters_from_edb()
@@ -164,6 +164,50 @@ class CfgStackup:
164
164
  def __init__(self, parent):
165
165
  super().__init__(parent)
166
166
 
167
+ def __apply_layers(self):
168
+ """Apply layer settings to the current design"""
169
+ layers = list()
170
+ layers.extend(self.parent.layers)
171
+
172
+ removal_list = []
173
+ lc_signal_layers = []
174
+ for name, obj in self._pedb.stackup.all_layers.items():
175
+ if obj.type == "dielectric":
176
+ removal_list.append(name)
177
+ elif obj.type == "signal":
178
+ lc_signal_layers.append(obj.id)
179
+ for l in removal_list:
180
+ self._pedb.stackup.remove_layer(l)
181
+
182
+ # update all signal layers
183
+ id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
184
+ signal_idx = 0
185
+ for l in layers:
186
+ if l.type == "signal":
187
+ layer_id = lc_signal_layers[signal_idx]
188
+ layer_name = id_name[layer_id]
189
+ attrs = l.get_attributes()
190
+ self._pedb.stackup.layers[layer_name].update(**attrs)
191
+ signal_idx = signal_idx + 1
192
+
193
+ # add all dielectric layers. Dielectric layers must be added last. Otherwise,
194
+ # dielectric layer will occupy signal and document layer id.
195
+ prev_layer_clone = None
196
+ l = layers.pop(0)
197
+ if l.type == "signal":
198
+ prev_layer_clone = self._pedb.stackup.layers[l.name]
199
+ else:
200
+ attrs = l.get_attributes()
201
+ prev_layer_clone = self._pedb.stackup.add_layer_top(**attrs)
202
+ for idx, l in enumerate(layers):
203
+ if l.type == "dielectric":
204
+ attrs = l.get_attributes()
205
+ prev_layer_clone = self._pedb.stackup.add_layer_below(
206
+ base_layer_name=prev_layer_clone.name, **attrs
207
+ )
208
+ elif l.type == "signal":
209
+ prev_layer_clone = self._pedb.stackup.layers[l.name]
210
+
167
211
  def __init__(self, pedb: Edb, data):
168
212
  self._pedb = pedb
169
213
  if self._pedb.grpc:
@@ -205,6 +205,8 @@ class Configuration:
205
205
  self.parent.cfg_data.components.retrieve_parameters_from_edb()
206
206
  components = []
207
207
  for i in self.parent.cfg_data.components.components:
208
+ if i.type == "io":
209
+ components.append(i.get_attributes())
208
210
  components.append(i.get_attributes())
209
211
 
210
212
  if kwargs.get("components", False):
@@ -306,6 +308,14 @@ class Configuration:
306
308
  file_path = file_path if isinstance(file_path, Path) else Path(file_path)
307
309
  file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
308
310
 
311
+ for comp in data["components"]:
312
+ for key, value in comp.items():
313
+ try:
314
+ json.dumps(value)
315
+ print(f"Key '{key}' is serializable.")
316
+ except TypeError as e:
317
+ print(f"Key '{key}' failed: {e}")
318
+
309
319
  with open(file_path, "w") as f:
310
320
  if file_path.suffix == ".json":
311
321
  json.dump(data, f, ensure_ascii=False, indent=4)
@@ -472,9 +482,6 @@ class Configuration:
472
482
  # Configure package definitions
473
483
  self.cfg_data.package_definitions.apply()
474
484
 
475
- # Configure operations
476
- self.cfg_data.operations.apply()
477
-
478
485
  # Modeler
479
486
  self.cfg_data.modeler.apply()
480
487
 
@@ -484,6 +491,9 @@ class Configuration:
484
491
  # Configure probes
485
492
  self.cfg_data.probes.apply()
486
493
 
494
+ # Configure operations
495
+ self.cfg_data.operations.apply()
496
+
487
497
  return True
488
498
 
489
499
  def _load_stackup(self):
@@ -341,6 +341,18 @@ class Path(Primitive):
341
341
  polygon_data = self._edb.geometry.polygon_data.dotnetobj(convert_py_list_to_net_list(points), False)
342
342
  self._edb_object.SetCenterLine(polygon_data)
343
343
 
344
+ def get_center_line_polygon_data(self):
345
+ """Gets center lines of the path as a PolygonData object."""
346
+ edb_object = self._edb_object.GetCenterLine()
347
+ return self._pedb.pedb_class.database.geometry.polygon_data.PolygonData(self._pedb, edb_object=edb_object)
348
+
349
+ def set_center_line_polygon_data(self, polygon_data):
350
+ """Sets center lines of the path from a PolygonData object."""
351
+ if not self._edb_object.SetCenterLine(polygon_data._edb_object):
352
+ raise ValueError
353
+ else:
354
+ return True
355
+
344
356
  @property
345
357
  def corner_style(self):
346
358
  """:class:`PathCornerType`: Path's corner style."""
@@ -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
+ import warnings
22
23
 
23
24
 
24
25
  class EdbDesignOptions:
@@ -51,8 +52,25 @@ class EdbDesignOptions:
51
52
  ``True`` if antipad is always on, ``False`` otherwise.
52
53
 
53
54
  """
54
- return self._active_cell.GetAntiPadsAlwaysOn()
55
+ warnings.warn("Use new property :func:`anti_pads_always_on` instead.", DeprecationWarning)
56
+ return self.anti_pads_always_on
55
57
 
56
58
  @antipads_always_on.setter
57
59
  def antipads_always_on(self, value):
60
+ self.anti_pads_always_on = value
61
+
62
+ @property
63
+ def anti_pads_always_on(self):
64
+ """Whether to always turn on antipad.
65
+
66
+ Returns
67
+ -------
68
+ bool
69
+ ``True`` if antipad is always on, ``False`` otherwise.
70
+
71
+ """
72
+ return self._active_cell.GetAntiPadsAlwaysOn()
73
+
74
+ @anti_pads_always_on.setter
75
+ def anti_pads_always_on(self, value):
58
76
  self._active_cell.SetAntiPadsAlwaysOn(value)
@@ -35,6 +35,7 @@ from pyedb.dotnet.database.general import (
35
35
  snake_to_pascal,
36
36
  )
37
37
  from pyedb.dotnet.database.geometry.polygon_data import PolygonData
38
+ from pyedb.generic.data_handlers import float_units
38
39
  from pyedb.generic.general_methods import generate_unique_name
39
40
  from pyedb.modeler.geometry_operators import GeometryOperators
40
41
 
@@ -1958,15 +1959,18 @@ class EDBPadstackInstance(Primitive):
1958
1959
  pad_shape = padstack_pad.geometry_type
1959
1960
  params = padstack_pad.parameters_values
1960
1961
  polygon_data = padstack_pad._polygon_data_dotnet
1962
+ pad_offset = [float_units(padstack_pad.offset_x), float_units(padstack_pad.offset_y)]
1961
1963
 
1962
1964
  def _rotate(p):
1963
1965
  x = p[0] * math.cos(rotation) - p[1] * math.sin(rotation)
1964
1966
  y = p[0] * math.sin(rotation) + p[1] * math.cos(rotation)
1965
1967
  return [x, y]
1966
1968
 
1967
- def _translate(p):
1968
- x = p[0] + padstack_center[0]
1969
- y = p[1] + padstack_center[1]
1969
+ def _translate(p, t=None):
1970
+ if t is None:
1971
+ t = padstack_center
1972
+ x = p[0] + t[0]
1973
+ y = p[1] + t[1]
1970
1974
  return [x, y]
1971
1975
 
1972
1976
  rect = None
@@ -2092,7 +2096,8 @@ class EDBPadstackInstance(Primitive):
2092
2096
 
2093
2097
  if rect is None or len(rect) != 4:
2094
2098
  return False
2095
- path = self._pedb.modeler.Shape("polygon", points=rect)
2099
+ offset_rect = [_translate(p, _rotate(pad_offset)) for p in rect]
2100
+ path = self._pedb.modeler.Shape("polygon", points=offset_rect)
2096
2101
  pdata = self._pedb.modeler.shape_to_polygon_data(path)
2097
2102
  new_rect = []
2098
2103
  for point in pdata.Points:
@@ -35,3 +35,29 @@ class PointData:
35
35
  self._pedb.edb_value(x),
36
36
  self._pedb.edb_value(y),
37
37
  )
38
+
39
+ @property
40
+ def x(self):
41
+ """X value of point."""
42
+ return self._edb_object.X.ToString()
43
+
44
+ @x.setter
45
+ def x(self, value):
46
+ self._edb_object.X = self._pedb.edb_value(value)
47
+
48
+ @property
49
+ def x_evaluated(self):
50
+ return self._edb_object.X.ToDouble()
51
+
52
+ @property
53
+ def y(self):
54
+ """Y value of point."""
55
+ return self._edb_object.Y.ToString()
56
+
57
+ @y.setter
58
+ def y(self, value):
59
+ self._edb_object.Y = self._pedb.edb_value(value)
60
+
61
+ @property
62
+ def y_evaluated(self):
63
+ return self._edb_object.Y.ToDouble()
@@ -89,8 +89,10 @@ class PolygonData:
89
89
  def create_from_points(self, points, closed=True):
90
90
  list_of_point_data = []
91
91
  for pt in points:
92
- list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1]))
93
- return self._pedb.edb_api.geometry.api_class.PolygonData(list_of_point_data, closed)
92
+ list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1])._edb_object)
93
+ return self._pedb.edb_api.geometry.api_class.PolygonData(
94
+ convert_py_list_to_net_list(list_of_point_data), closed
95
+ )
94
96
 
95
97
  def create_from_bounding_box(self, points):
96
98
  bbox = BBox(self._pedb, point_1=points[0], point_2=points[1])
@@ -133,3 +135,12 @@ class PolygonData:
133
135
  def point_in_polygon(self, x: Union[str, float], y: Union[str, float]) -> bool:
134
136
  """Determines whether a point is inside the polygon."""
135
137
  return self._edb_object.PointInPolygon(self._pedb.point_data(x, y))
138
+
139
+ def get_point(self, index):
140
+ """Gets the point at the index as a PointData object."""
141
+ edb_object = self._edb_object.GetPoint(index)
142
+ return self._pedb.pedb_class.database.geometry.point_data.PointData(self._pedb, edb_object)
143
+
144
+ def set_point(self, index, point_data):
145
+ """Sets the point at the index from a PointData object."""
146
+ self._edb_object.SetPoint(index, point_data)
@@ -308,11 +308,21 @@ class EdbNets(CommonNets):
308
308
  val_value = cmp.rlc_values
309
309
  if refdes in exception_list:
310
310
  pass
311
- elif val_type == "Inductor" and val_value[1] < inductor_below:
311
+ elif (
312
+ val_type == "Inductor"
313
+ and self._pedb.edb_value(val_value[1]).ToDouble() <= self._pedb.edb_value(inductor_below).ToDouble()
314
+ ):
312
315
  pass
313
- elif val_type == "Resistor" and val_value[0] < resistor_below:
316
+ elif (
317
+ val_type == "Resistor"
318
+ and self._pedb.edb_value(val_value[0]).ToDouble() <= self._pedb.edb_value(resistor_below).ToDouble()
319
+ ):
314
320
  pass
315
- elif val_type == "Capacitor" and val_value[2] > capacitor_above:
321
+ elif (
322
+ val_type == "Capacitor"
323
+ and self._pedb.edb_value(val_value[2]).ToDouble()
324
+ >= self._pedb.edb_value(capacitor_above).ToDouble()
325
+ ):
316
326
  pass
317
327
  else:
318
328
  continue
@@ -1153,7 +1153,7 @@ class EdbPadstacks(object):
1153
1153
  Name of the net. The default is ``""``.
1154
1154
  via_name : str, optional
1155
1155
  The default is ``""``.
1156
- rotation : float, optional
1156
+ rotation : float, str, optional
1157
1157
  Rotation of the padstack in degrees. The default
1158
1158
  is ``0``.
1159
1159
  fromlayer :
@@ -1175,7 +1175,11 @@ class EdbPadstacks(object):
1175
1175
  padstack = self.definitions[pad].edb_padstack
1176
1176
  position = self._edb.geometry.point_data(position[0], position[1])
1177
1177
  net = self._pedb.nets.find_or_create_net(net_name)
1178
- rotation = self._get_edb_value(rotation * math.pi / 180)
1178
+ rotation = (
1179
+ self._get_edb_value(rotation * math.pi / 180)
1180
+ if not isinstance(rotation, str)
1181
+ else self._get_edb_value(rotation)
1182
+ )
1179
1183
  sign_layers_values = {i: v for i, v in self._pedb.stackup.signal_layers.items()}
1180
1184
  sign_layers = list(sign_layers_values.keys())
1181
1185
  if not fromlayer:
@@ -96,8 +96,6 @@ class SimulationSetup(object):
96
96
  if self._edb_object:
97
97
  self._name = self._edb_object.GetName()
98
98
 
99
- self._sweep_list = {}
100
-
101
99
  @property
102
100
  def sim_setup_info(self):
103
101
  return SimSetupInfo(self._pedb, sim_setup=self, edb_object=self._edb_object.GetSimSetupInfo())
@@ -239,7 +237,7 @@ class SimulationSetup(object):
239
237
  """List of frequency sweeps."""
240
238
  return {i.name: i for i in self.sim_setup_info.sweep_data_list}
241
239
 
242
- def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
240
+ def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
243
241
  """Add frequency sweep.
244
242
 
245
243
  Parameters
@@ -292,15 +290,7 @@ class SimulationSetup(object):
292
290
  sweep_data: SweepData
293
291
  """
294
292
  warnings.warn("Use new property :func:`add_sweep_data` instead.", DeprecationWarning)
295
- self._sweep_list[sweep_data.name] = sweep_data
296
- edb_setup_info = self.sim_setup_info
297
-
298
- if self._setup_type in ["kSIwave", "kHFSS", "kRaptorX", "kHFSSPI"]:
299
- for _, v in self._sweep_list.items():
300
- edb_setup_info.SweepDataList.Add(v._edb_object)
301
-
302
- self._edb_object = self._set_edb_setup_info(edb_setup_info)
303
- self._update_setup()
293
+ return self.sim_setup_info.add_sweep_data(sweep_data)
304
294
 
305
295
  def delete_frequency_sweep(self, sweep_data):
306
296
  """Delete a frequency sweep.
@@ -310,17 +300,17 @@ class SimulationSetup(object):
310
300
  sweep_data : EdbFrequencySweep.
311
301
  """
312
302
  name = sweep_data.name
313
- if name in self._sweep_list:
314
- self._sweep_list.pop(name)
303
+ if name in self.sweeps:
304
+ self.sweeps.pop(name)
315
305
 
316
306
  fsweep = []
317
- if self.frequency_sweeps:
318
- fsweep = [val for key, val in self.frequency_sweeps.items() if not key == name]
307
+ if self.sweeps:
308
+ fsweep = [val for key, val in self.sweeps.items() if not key == name]
319
309
  self.sim_setup_info._edb_object.SweepDataList.Clear()
320
310
  for i in fsweep:
321
311
  self.sim_setup_info._edb_object.SweepDataList.Add(i._edb_object)
322
312
  self._update_setup()
323
- return True if name in self.frequency_sweeps else False
313
+ return False if name in self.sweeps else True
324
314
 
325
315
  def add_frequency_sweep(self, name=None, frequency_sweep=None):
326
316
  """Add frequency sweep.
@@ -95,6 +95,8 @@ class SiwaveSimulationSetup(SimulationSetup):
95
95
  self._edb_object = self._simulation_setup_builder(sim_setup_info._edb_object)
96
96
  self._update_setup()
97
97
 
98
+ self._siwave_sweeps_list = []
99
+
98
100
  def create(self, name=None):
99
101
  """Create a SIwave SYZ setup.
100
102
 
@@ -248,6 +250,34 @@ class SiwaveSimulationSetup(SimulationSetup):
248
250
  self._edb_object = self._set_edb_setup_info(edb_setup_info)
249
251
  self._update_setup()
250
252
 
253
+ def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
254
+ """Add frequency sweep.
255
+
256
+ Parameters
257
+ ----------
258
+ name : str, optional
259
+ Name of the frequency sweep. The default is ``None``.
260
+ frequency_set : list, optional
261
+ List of frequency points. The default is ``None``.
262
+ sweep_type : str, optional
263
+ Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
264
+ Returns
265
+ -------
266
+
267
+ Examples
268
+ --------
269
+ >>> setup1 = edbapp.create_siwave_syz_setup("setup1")
270
+ >>> setup1.add_sweep(name="sw1", frequency_set=["linear count", "1MHz", "100MHz", 10])
271
+ """
272
+ sweep_data = SimulationSetup.add_sweep(self, name, frequency_set, sweep_type, **kwargs)
273
+ self._siwave_sweeps_list.append(sweep_data)
274
+ return sweep_data
275
+
276
+ @property
277
+ def sweeps(self):
278
+ """List of frequency sweeps."""
279
+ return {i.name: i for i in self._siwave_sweeps_list}
280
+
251
281
 
252
282
  class SiwaveDCSimulationSetup(SimulationSetup):
253
283
  """Manages EDB methods for SIwave DC simulation setup."""