pyedb 0.42.0__py3-none-any.whl → 0.44.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 (58) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +155 -72
  3. pyedb/configuration/cfg_components.py +1 -1
  4. pyedb/configuration/cfg_general.py +34 -16
  5. pyedb/configuration/cfg_modeler.py +162 -67
  6. pyedb/configuration/cfg_nets.py +33 -17
  7. pyedb/configuration/cfg_operations.py +63 -31
  8. pyedb/configuration/cfg_package_definition.py +113 -52
  9. pyedb/configuration/cfg_padstacks.py +611 -256
  10. pyedb/configuration/cfg_pin_groups.py +75 -33
  11. pyedb/configuration/cfg_ports_sources.py +75 -15
  12. pyedb/configuration/cfg_s_parameter_models.py +125 -70
  13. pyedb/configuration/cfg_setup.py +301 -257
  14. pyedb/configuration/cfg_stackup.py +166 -90
  15. pyedb/configuration/configuration.py +342 -209
  16. pyedb/dotnet/database/edb_data/design_options.py +19 -1
  17. pyedb/dotnet/database/edb_data/padstacks_data.py +16 -6
  18. pyedb/dotnet/database/geometry/polygon_data.py +4 -2
  19. pyedb/dotnet/database/padstack.py +6 -2
  20. pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +63 -10
  21. pyedb/dotnet/database/utilities/simulation_setup.py +14 -30
  22. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +30 -0
  23. pyedb/dotnet/edb.py +75 -105
  24. pyedb/grpc/database/components.py +1 -1
  25. pyedb/grpc/database/definition/component_def.py +15 -0
  26. pyedb/grpc/database/definition/component_pin.py +1 -1
  27. pyedb/grpc/database/definition/materials.py +27 -0
  28. pyedb/grpc/database/definition/package_def.py +20 -2
  29. pyedb/grpc/database/definition/padstack_def.py +5 -2
  30. pyedb/grpc/database/hierarchy/component.py +4 -2
  31. pyedb/grpc/database/hierarchy/pingroup.py +12 -8
  32. pyedb/grpc/database/layers/layer.py +28 -0
  33. pyedb/grpc/database/layers/stackup_layer.py +281 -40
  34. pyedb/grpc/database/layout/layout.py +12 -6
  35. pyedb/grpc/database/modeler.py +8 -8
  36. pyedb/grpc/database/primitive/bondwire.py +3 -3
  37. pyedb/grpc/database/primitive/circle.py +1 -1
  38. pyedb/grpc/database/primitive/padstack_instance.py +13 -3
  39. pyedb/grpc/database/primitive/path.py +2 -2
  40. pyedb/grpc/database/primitive/polygon.py +3 -3
  41. pyedb/grpc/database/primitive/primitive.py +1 -1
  42. pyedb/grpc/database/primitive/rectangle.py +2 -2
  43. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +73 -30
  44. pyedb/grpc/database/source_excitations.py +7 -7
  45. pyedb/grpc/database/stackup.py +14 -6
  46. pyedb/grpc/database/terminal/bundle_terminal.py +3 -3
  47. pyedb/grpc/database/terminal/edge_terminal.py +2 -2
  48. pyedb/grpc/database/terminal/padstack_instance_terminal.py +42 -2
  49. pyedb/grpc/database/terminal/pingroup_terminal.py +35 -2
  50. pyedb/grpc/database/terminal/point_terminal.py +10 -1
  51. pyedb/grpc/database/terminal/terminal.py +4 -4
  52. pyedb/grpc/database/utility/hfss_extent_info.py +14 -10
  53. pyedb/grpc/edb.py +8 -8
  54. pyedb/misc/misc.py +13 -0
  55. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/METADATA +1 -1
  56. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/RECORD +58 -58
  57. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/LICENSE +0 -0
  58. {pyedb-0.42.0.dist-info → pyedb-0.44.0.dist-info}/WHEEL +0 -0
@@ -33,8 +33,331 @@ from pyedb.dotnet.database.definition.package_def import PackageDef
33
33
  class Configuration:
34
34
  """Enables export and import of a JSON configuration file that can be applied to a new or existing design."""
35
35
 
36
+ class Grpc:
37
+ def __init__(self, parent):
38
+ self.parent = parent
39
+ self._pedb = parent._pedb
40
+
41
+ def configuration_stackup(self, kwargs):
42
+ if kwargs.get("fix_padstack_def"):
43
+ from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
44
+
45
+ pedb_defs = self._pedb.padstacks.definitions
46
+ temp = []
47
+ for _, pdef in pedb_defs.items():
48
+ cfg_def = CfgPadstackDefinition(self._pedb, pdef)
49
+ cfg_def.api.retrieve_parameters_from_edb()
50
+ temp.append(cfg_def)
51
+ self.parent.cfg_data.stackup.apply()
52
+ for cfg_pdef in temp:
53
+ cfg_pdef.api.set_parameters_to_edb()
54
+ else:
55
+ temp_pdef_data = {}
56
+ from ansys.edb.core.definition.padstack_def_data import (
57
+ PadType as GrpcPadType,
58
+ )
59
+
60
+ for pdef_name, pdef in self._pedb.padstacks.definitions.items():
61
+ for layer in pdef.data.layer_names:
62
+ result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
63
+ if len(result) == 4:
64
+ # polygon based
65
+ temp_pdef_data[pdef_name] = pdef.data
66
+ break
67
+ self.parent.cfg_data.stackup.apply()
68
+ for pdef_name, pdef_data in temp_pdef_data.items():
69
+ pdef = self._pedb.padstacks.definitions[pdef_name]
70
+ pdef._padstack_def_data = pdef_data
71
+
72
+ def _load_stackup(self):
73
+ """Imports stackup information from json."""
74
+ data = self.data["stackup"]
75
+ materials = data.get("materials")
76
+
77
+ if materials:
78
+ edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
79
+ for mat in materials:
80
+ name = mat["name"].lower()
81
+ if name in edb_materials:
82
+ self._pedb.materials.delete_material(edb_materials[name])
83
+ for mat in materials:
84
+ self._pedb.materials.add_material(**mat)
85
+
86
+ layers = data.get("layers")
87
+
88
+ if layers:
89
+ input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
90
+ if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
91
+ self._pedb.logger.error("Input signal layer count do not match.")
92
+ return False
93
+
94
+ removal_list = []
95
+ lc_signal_layers = []
96
+ for name, obj in self._pedb.stackup.all_layers.items():
97
+ if obj.type == "dielectric":
98
+ removal_list.append(name)
99
+ elif obj.type == "signal":
100
+ lc_signal_layers.append(obj.id)
101
+ for l in removal_list:
102
+ self._pedb.stackup.remove_layer(l)
103
+
104
+ # update all signal layers
105
+ id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
106
+ signal_idx = 0
107
+ for l in layers:
108
+ if l["type"] == "signal":
109
+ layer_id = lc_signal_layers[signal_idx]
110
+ layer_name = id_name[layer_id]
111
+ self._pedb.stackup.layers[layer_name].update(**l)
112
+ signal_idx = signal_idx + 1
113
+
114
+ # add all dielectric layers. Dielectric layers must be added last. Otherwise,
115
+ # dielectric layer will occupy signal and document layer id.
116
+ prev_layer_clone = None
117
+ l = layers.pop(0)
118
+ if l["type"] == "signal":
119
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
120
+ else:
121
+ prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
122
+ for idx, l in enumerate(layers):
123
+ if l["type"] == "dielectric":
124
+ prev_layer_clone = self._pedb.stackup.add_layer_below(
125
+ base_layer_name=prev_layer_clone.name, **l
126
+ )
127
+ elif l["type"] == "signal":
128
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
129
+
130
+ def _load_package_def(self):
131
+ """Imports package definition information from JSON."""
132
+ comps = self._pedb.components.instances
133
+ for pkgd in self.parent.data["package_definitions"]:
134
+ name = pkgd["name"]
135
+ if name in self._pedb.definitions.package:
136
+ self._pedb.definitions.package[name].delete()
137
+ extent_bounding_box = pkgd.get("extent_bounding_box", None)
138
+ if extent_bounding_box:
139
+ package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
140
+ else:
141
+ package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
142
+ package_def.maximum_power = pkgd["maximum_power"]
143
+ package_def.therm_cond = pkgd["therm_cond"]
144
+ package_def.theta_jb = pkgd["theta_jb"]
145
+ package_def.theta_jc = pkgd["theta_jc"]
146
+ package_def.height = pkgd["height"]
147
+
148
+ heatsink = pkgd.get("heatsink", None)
149
+ if heatsink:
150
+ package_def.set_heatsink(
151
+ heatsink["fin_base_height"],
152
+ heatsink["fin_height"],
153
+ heatsink["fin_orientation"],
154
+ heatsink["fin_spacing"],
155
+ heatsink["fin_thickness"],
156
+ )
157
+
158
+ comp_def_name = pkgd["component_definition"]
159
+ comp_def = self._pedb.definitions.component[comp_def_name]
160
+
161
+ comp_list = dict()
162
+ if pkgd["apply_to_all"]:
163
+ comp_list.update(
164
+ {
165
+ refdes: comp
166
+ for refdes, comp in comp_def.components.items()
167
+ if refdes not in pkgd["components"]
168
+ }
169
+ )
170
+ else:
171
+ comp_list.update(
172
+ {refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
173
+ )
174
+ for _, i in comp_list.items():
175
+ i.package_def = name
176
+
177
+ def get_data_from_db(self, **kwargs):
178
+ """Get configuration data from layout.
179
+
180
+ Parameters
181
+ ----------
182
+ stackup
183
+
184
+ Returns
185
+ -------
186
+
187
+ """
188
+ self._pedb.logger.info("Getting data from layout database.")
189
+ data = {}
190
+ if kwargs.get("general", False):
191
+ data["general"] = self.parent.cfg_data.general.get_data_from_db()
192
+ if kwargs.get("stackup", False):
193
+ data["stackup"] = self.parent.cfg_data.stackup.get_data_from_db()
194
+ if kwargs.get("package_definitions", False):
195
+ data["package_definitions"] = self.parent.cfg_data.package_definitions.get_data_from_db()
196
+ if kwargs.get("setups", False):
197
+ setups = self.parent.cfg_data.setups
198
+ setups.retrieve_parameters_from_edb()
199
+ data["setups"] = setups.to_dict()
200
+ if kwargs.get("sources", False):
201
+ data["sources"] = self.parent.cfg_data.sources.get_data_from_db()
202
+ if kwargs.get("ports", False):
203
+ data["ports"] = self.parent.cfg_data.ports.get_data_from_db()
204
+ if kwargs.get("components", False) or kwargs.get("s_parameters", False):
205
+ self.parent.cfg_data.components.retrieve_parameters_from_edb()
206
+ components = []
207
+ for i in self.parent.cfg_data.components.components:
208
+ components.append(i.get_attributes())
209
+
210
+ if kwargs.get("components", False):
211
+ data["components"] = components
212
+ elif kwargs.get("s_parameters", False):
213
+ data["s_parameters"] = self.parent.cfg_data.s_parameters.get_data_from_db(components)
214
+ if kwargs.get("nets", False):
215
+ data["nets"] = self.parent.cfg_data.nets.get_data_from_db()
216
+ if kwargs.get("pin_groups", False):
217
+ data["pin_groups"] = self.parent.cfg_data.pin_groups.get_data_from_db()
218
+ if kwargs.get("operations", False):
219
+ data["operations"] = self.parent.cfg_data.operations.get_data_from_db()
220
+ if kwargs.get("padstacks", False):
221
+ self.parent.cfg_data.padstacks.retrieve_parameters_from_edb()
222
+ definitions = []
223
+ for i in self.parent.cfg_data.padstacks.definitions:
224
+ definitions.append(i.get_attributes())
225
+ instances = []
226
+ for i in self.parent.cfg_data.padstacks.instances:
227
+ instances.append(i.get_attributes())
228
+ data["padstacks"] = dict()
229
+ data["padstacks"]["definitions"] = definitions
230
+ data["padstacks"]["instances"] = instances
231
+
232
+ if kwargs.get("boundaries", False):
233
+ data["boundaries"] = self.parent.cfg_data.boundaries.get_data_from_db()
234
+
235
+ return data
236
+
237
+ def export(
238
+ self,
239
+ file_path,
240
+ stackup=True,
241
+ package_definitions=False,
242
+ setups=True,
243
+ sources=True,
244
+ ports=True,
245
+ nets=True,
246
+ pin_groups=True,
247
+ operations=True,
248
+ components=True,
249
+ boundaries=True,
250
+ s_parameters=True,
251
+ padstacks=True,
252
+ general=True,
253
+ ):
254
+ """Export the configuration data from layout to a file.
255
+
256
+ Parameters
257
+ ----------
258
+ file_path : str, Path
259
+ File path to export the configuration data.
260
+ stackup : bool
261
+ Whether to export stackup or not.
262
+ package_definitions : bool
263
+ Whether to export package definitions or not.
264
+ setups : bool
265
+ Whether to export setups or not.
266
+ sources : bool
267
+ Whether to export sources or not.
268
+ ports : bool
269
+ Whether to export ports or not.
270
+ nets : bool
271
+ Whether to export nets.
272
+ pin_groups : bool
273
+ Whether to export pin groups.
274
+ operations : bool
275
+ Whether to export operations.
276
+ components : bool
277
+ Whether to export component.
278
+ boundaries : bool
279
+ Whether to export boundaries.
280
+ s_parameters : bool
281
+ Whether to export s_parameters.
282
+ padstacks : bool
283
+ Whether to export padstacks.
284
+ general : bool
285
+ Whether to export general information.
286
+ Returns
287
+ -------
288
+ bool
289
+ """
290
+ data = self.get_data_from_db(
291
+ stackup=stackup,
292
+ package_definitions=package_definitions,
293
+ setups=setups,
294
+ sources=sources,
295
+ ports=ports,
296
+ nets=nets,
297
+ pin_groups=pin_groups,
298
+ operations=operations,
299
+ components=components,
300
+ boundaries=boundaries,
301
+ s_parameters=s_parameters,
302
+ padstacks=padstacks,
303
+ general=general,
304
+ )
305
+
306
+ file_path = file_path if isinstance(file_path, Path) else Path(file_path)
307
+ file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
308
+
309
+ with open(file_path, "w") as f:
310
+ if file_path.suffix == ".json":
311
+ json.dump(data, f, ensure_ascii=False, indent=4)
312
+ else:
313
+ toml.dump(data, f)
314
+ return True if os.path.isfile(file_path) else False
315
+
316
+ class DotNet(Grpc):
317
+ def __init__(self, parent):
318
+ super().__init__(parent)
319
+
320
+ def configuration_stackup(self, kwargs):
321
+ if kwargs.get("fix_padstack_def"):
322
+ from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
323
+
324
+ pedb_defs = self._pedb.padstacks.definitions
325
+ temp = []
326
+ for _, pdef in pedb_defs.items():
327
+ cfg_def = CfgPadstackDefinition(self._pedb, pdef)
328
+ cfg_def.api.retrieve_parameters_from_edb()
329
+ temp.append(cfg_def)
330
+ self.parent.cfg_data.stackup.apply()
331
+ for cfg_pdef in temp:
332
+ cfg_pdef.api.set_parameters_to_edb()
333
+ else:
334
+ temp_pdef_data = {}
335
+ for pdef_name, pdef in self._pedb.padstacks.definitions.items():
336
+ pdef_data = pdef._padstack_def_data
337
+ for lyr_name in list(pdef_data.GetLayerNames()):
338
+ result = pdef_data.GetPadParametersValue(
339
+ lyr_name, self._pedb._edb.Definition.PadType.RegularPad
340
+ )
341
+ flag, pad_shape, params, offset_x, offset_y, rotation = result
342
+ if flag is False:
343
+ result = pdef_data.GetPolygonalPadParameters(
344
+ lyr_name, self._pedb._edb.Definition.PadType.RegularPad
345
+ )
346
+ flag, polygon_data, offset_x, offset_y, rotation = result
347
+ if flag:
348
+ temp_pdef_data[pdef_name] = pdef_data
349
+ break
350
+ self.parent.cfg_data.stackup.apply()
351
+ for pdef_name, pdef_data in temp_pdef_data.items():
352
+ pdef = self._pedb.padstacks.definitions[pdef_name]
353
+ pdef._padstack_def_data = pdef_data
354
+
36
355
  def __init__(self, pedb):
37
356
  self._pedb = pedb
357
+ if self._pedb.grpc:
358
+ self.api = self.Grpc(self)
359
+ else:
360
+ self.api = self.DotNet(self)
38
361
  self._components = self._pedb.components.instances
39
362
  self.data = {}
40
363
  self._s_parameter_library = ""
@@ -133,52 +456,7 @@ class Configuration:
133
456
  self.cfg_data.setups.apply()
134
457
 
135
458
  # Configure stackup
136
- if kwargs.get("fix_padstack_def"):
137
- from pyedb.configuration.cfg_padstacks import CfgPadstackDefinition
138
-
139
- pedb_defs = self._pedb.padstacks.definitions
140
- temp = []
141
- for _, pdef in pedb_defs.items():
142
- cfg_def = CfgPadstackDefinition(self._pedb, pdef)
143
- cfg_def.api.retrieve_parameters_from_edb()
144
- temp.append(cfg_def)
145
- self.cfg_data.stackup.apply()
146
- for cfg_pdef in temp:
147
- cfg_pdef.api.set_parameters_to_edb()
148
- else:
149
- temp_pdef_data = {}
150
- if self._pedb.grpc:
151
- from ansys.edb.core.definition.padstack_def_data import (
152
- PadType as GrpcPadType,
153
- )
154
-
155
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
156
- for layer in pdef.data.layer_names:
157
- result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
158
- if len(result) == 4:
159
- # polygon based
160
- temp_pdef_data[pdef_name] = pdef.data
161
- break
162
- else:
163
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
164
- pdef_data = pdef._padstack_def_data
165
- for lyr_name in list(pdef_data.GetLayerNames()):
166
- result = pdef_data.GetPadParametersValue(
167
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
168
- )
169
- flag, pad_shape, params, offset_x, offset_y, rotation = result
170
- if flag is False:
171
- result = pdef_data.GetPolygonalPadParameters(
172
- lyr_name, self._pedb._edb.Definition.PadType.RegularPad
173
- )
174
- flag, polygon_data, offset_x, offset_y, rotation = result
175
- if flag:
176
- temp_pdef_data[pdef_name] = pdef_data
177
- break
178
- self.cfg_data.stackup.apply()
179
- for pdef_name, pdef_data in temp_pdef_data.items():
180
- pdef = self._pedb.padstacks.definitions[pdef_name]
181
- pdef._padstack_def_data = pdef_data
459
+ self.api.configuration_stackup(kwargs)
182
460
 
183
461
  # Configure padstacks
184
462
  if self.cfg_data.padstacks:
@@ -210,102 +488,11 @@ class Configuration:
210
488
 
211
489
  def _load_stackup(self):
212
490
  """Imports stackup information from json."""
213
- data = self.data["stackup"]
214
- materials = data.get("materials")
215
-
216
- if materials:
217
- edb_materials = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
218
- for mat in materials:
219
- name = mat["name"].lower()
220
- if name in edb_materials:
221
- self._pedb.materials.delete_material(edb_materials[name])
222
- for mat in materials:
223
- self._pedb.materials.add_material(**mat)
224
-
225
- layers = data.get("layers")
226
-
227
- if layers:
228
- input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
229
- if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
230
- self._pedb.logger.error("Input signal layer count do not match.")
231
- return False
232
-
233
- removal_list = []
234
- lc_signal_layers = []
235
- for name, obj in self._pedb.stackup.all_layers.items():
236
- if obj.type == "dielectric":
237
- removal_list.append(name)
238
- elif obj.type == "signal":
239
- lc_signal_layers.append(obj.id)
240
- for l in removal_list:
241
- self._pedb.stackup.remove_layer(l)
242
-
243
- # update all signal layers
244
- id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
245
- signal_idx = 0
246
- for l in layers:
247
- if l["type"] == "signal":
248
- layer_id = lc_signal_layers[signal_idx]
249
- layer_name = id_name[layer_id]
250
- self._pedb.stackup.layers[layer_name].update(**l)
251
- signal_idx = signal_idx + 1
252
-
253
- # add all dielectric layers. Dielectric layers must be added last. Otherwise,
254
- # dielectric layer will occupy signal and document layer id.
255
- prev_layer_clone = None
256
- l = layers.pop(0)
257
- if l["type"] == "signal":
258
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
259
- else:
260
- prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
261
- for idx, l in enumerate(layers):
262
- if l["type"] == "dielectric":
263
- prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
264
- elif l["type"] == "signal":
265
- prev_layer_clone = self._pedb.stackup.layers[l["name"]]
491
+ self.api._load_stackup()
266
492
 
267
493
  def _load_package_def(self):
268
494
  """Imports package definition information from JSON."""
269
- comps = self._pedb.components.instances
270
- for pkgd in self.data["package_definitions"]:
271
- name = pkgd["name"]
272
- if name in self._pedb.definitions.package:
273
- self._pedb.definitions.package[name].delete()
274
- extent_bounding_box = pkgd.get("extent_bounding_box", None)
275
- if extent_bounding_box:
276
- package_def = PackageDef(self._pedb, name=name, extent_bounding_box=extent_bounding_box)
277
- else:
278
- package_def = PackageDef(self._pedb, name=name, component_part_name=pkgd["component_definition"])
279
- package_def.maximum_power = pkgd["maximum_power"]
280
- package_def.therm_cond = pkgd["therm_cond"]
281
- package_def.theta_jb = pkgd["theta_jb"]
282
- package_def.theta_jc = pkgd["theta_jc"]
283
- package_def.height = pkgd["height"]
284
-
285
- heatsink = pkgd.get("heatsink", None)
286
- if heatsink:
287
- package_def.set_heatsink(
288
- heatsink["fin_base_height"],
289
- heatsink["fin_height"],
290
- heatsink["fin_orientation"],
291
- heatsink["fin_spacing"],
292
- heatsink["fin_thickness"],
293
- )
294
-
295
- comp_def_name = pkgd["component_definition"]
296
- comp_def = self._pedb.definitions.component[comp_def_name]
297
-
298
- comp_list = dict()
299
- if pkgd["apply_to_all"]:
300
- comp_list.update(
301
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in pkgd["components"]}
302
- )
303
- else:
304
- comp_list.update(
305
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes in pkgd["components"]}
306
- )
307
- for _, i in comp_list.items():
308
- i.package_def = name
495
+ self.api._load_package_def()
309
496
 
310
497
  def get_data_from_db(self, **kwargs):
311
498
  """Get configuration data from layout.
@@ -318,52 +505,7 @@ class Configuration:
318
505
  -------
319
506
 
320
507
  """
321
- self._pedb.logger.info("Getting data from layout database.")
322
- data = {}
323
- if kwargs.get("general", False):
324
- data["general"] = self.cfg_data.general.get_data_from_db()
325
- if kwargs.get("stackup", False):
326
- data["stackup"] = self.cfg_data.stackup.get_data_from_db()
327
- if kwargs.get("package_definitions", False):
328
- data["package_definitions"] = self.cfg_data.package_definitions.get_data_from_db()
329
- if kwargs.get("setups", False):
330
- data["setups"] = self.cfg_data.setups.get_data_from_db()
331
- if kwargs.get("sources", False):
332
- data["sources"] = self.cfg_data.sources.get_data_from_db()
333
- if kwargs.get("ports", False):
334
- data["ports"] = self.cfg_data.ports.get_data_from_db()
335
- if kwargs.get("components", False) or kwargs.get("s_parameters", False):
336
- self.cfg_data.components.retrieve_parameters_from_edb()
337
- components = []
338
- for i in self.cfg_data.components.components:
339
- components.append(i.get_attributes())
340
-
341
- if kwargs.get("components", False):
342
- data["components"] = components
343
- elif kwargs.get("s_parameters", False):
344
- data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db(components)
345
- if kwargs.get("nets", False):
346
- data["nets"] = self.cfg_data.nets.get_data_from_db()
347
- if kwargs.get("pin_groups", False):
348
- data["pin_groups"] = self.cfg_data.pin_groups.get_data_from_db()
349
- if kwargs.get("operations", False):
350
- data["operations"] = self.cfg_data.operations.get_data_from_db()
351
- if kwargs.get("padstacks", False):
352
- self.cfg_data.padstacks.retrieve_parameters_from_edb()
353
- definitions = []
354
- for i in self.cfg_data.padstacks.definitions:
355
- definitions.append(i.get_attributes())
356
- instances = []
357
- for i in self.cfg_data.padstacks.instances:
358
- instances.append(i.get_attributes())
359
- data["padstacks"] = dict()
360
- data["padstacks"]["definitions"] = definitions
361
- data["padstacks"]["instances"] = instances
362
-
363
- if kwargs.get("boundaries", False):
364
- data["boundaries"] = self.cfg_data.boundaries.get_data_from_db()
365
-
366
- return data
508
+ return self.api.get_data_from_db(**kwargs)
367
509
 
368
510
  def export(
369
511
  self,
@@ -418,28 +560,19 @@ class Configuration:
418
560
  -------
419
561
  bool
420
562
  """
421
- data = self.get_data_from_db(
422
- stackup=stackup,
423
- package_definitions=package_definitions,
424
- setups=setups,
425
- sources=sources,
426
- ports=ports,
427
- nets=nets,
428
- pin_groups=pin_groups,
429
- operations=operations,
430
- components=components,
431
- boundaries=boundaries,
432
- s_parameters=s_parameters,
433
- padstacks=padstacks,
434
- general=general,
563
+ return self.api.export(
564
+ file_path,
565
+ stackup=True,
566
+ package_definitions=False,
567
+ setups=True,
568
+ sources=True,
569
+ ports=True,
570
+ nets=True,
571
+ pin_groups=True,
572
+ operations=True,
573
+ components=True,
574
+ boundaries=True,
575
+ s_parameters=True,
576
+ padstacks=True,
577
+ general=True,
435
578
  )
436
-
437
- file_path = file_path if isinstance(file_path, Path) else Path(file_path)
438
- file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
439
-
440
- with open(file_path, "w") as f:
441
- if file_path.suffix == ".json":
442
- json.dump(data, f, ensure_ascii=False, indent=4)
443
- else:
444
- toml.dump(data, f)
445
- return True if os.path.isfile(file_path) else False
@@ -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:
@@ -2142,7 +2147,7 @@ class EDBPadstackInstance(Primitive):
2142
2147
  component_only=component_only,
2143
2148
  )
2144
2149
 
2145
- def split(self):
2150
+ def split(self) -> list:
2146
2151
  """Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
2147
2152
  pdef_name = self.padstack_definition
2148
2153
  position = self.position
@@ -2151,11 +2156,16 @@ class EDBPadstackInstance(Primitive):
2151
2156
  stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
2152
2157
  start_idx = stackup_layer_range.index(self.start_layer)
2153
2158
  stop_idx = stackup_layer_range.index(self.stop_layer)
2159
+ temp = []
2154
2160
  for idx, (l1, l2) in enumerate(
2155
2161
  list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
2156
2162
  ):
2157
- self._pedb.padstacks.place(position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2)
2163
+ pd_inst = self._pedb.padstacks.place(
2164
+ position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2
2165
+ )
2166
+ temp.append(pd_inst)
2158
2167
  self.delete()
2168
+ return temp
2159
2169
 
2160
2170
  def convert_hole_to_conical_shape(self, angle=75):
2161
2171
  """Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.