pyedb 0.42.0__py3-none-any.whl → 0.43.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 -1
- pyedb/configuration/cfg_boundaries.py +148 -71
- pyedb/configuration/cfg_general.py +30 -14
- pyedb/configuration/cfg_modeler.py +161 -67
- pyedb/configuration/cfg_nets.py +33 -17
- pyedb/configuration/cfg_operations.py +63 -31
- pyedb/configuration/cfg_package_definition.py +72 -51
- pyedb/configuration/cfg_pin_groups.py +75 -33
- pyedb/configuration/cfg_s_parameter_models.py +95 -70
- pyedb/configuration/cfg_setup.py +229 -258
- pyedb/configuration/cfg_stackup.py +122 -90
- pyedb/configuration/configuration.py +342 -209
- pyedb/dotnet/database/edb_data/padstacks_data.py +7 -2
- pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +63 -10
- pyedb/dotnet/database/utilities/simulation_setup.py +7 -13
- pyedb/dotnet/edb.py +75 -105
- {pyedb-0.42.0.dist-info → pyedb-0.43.0.dist-info}/METADATA +1 -1
- {pyedb-0.42.0.dist-info → pyedb-0.43.0.dist-info}/RECORD +20 -20
- {pyedb-0.42.0.dist-info → pyedb-0.43.0.dist-info}/LICENSE +0 -0
- {pyedb-0.42.0.dist-info → pyedb-0.43.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
|
@@ -2142,7 +2142,7 @@ class EDBPadstackInstance(Primitive):
|
|
|
2142
2142
|
component_only=component_only,
|
|
2143
2143
|
)
|
|
2144
2144
|
|
|
2145
|
-
def split(self):
|
|
2145
|
+
def split(self) -> list:
|
|
2146
2146
|
"""Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
|
|
2147
2147
|
pdef_name = self.padstack_definition
|
|
2148
2148
|
position = self.position
|
|
@@ -2151,11 +2151,16 @@ class EDBPadstackInstance(Primitive):
|
|
|
2151
2151
|
stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
|
|
2152
2152
|
start_idx = stackup_layer_range.index(self.start_layer)
|
|
2153
2153
|
stop_idx = stackup_layer_range.index(self.stop_layer)
|
|
2154
|
+
temp = []
|
|
2154
2155
|
for idx, (l1, l2) in enumerate(
|
|
2155
2156
|
list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
|
|
2156
2157
|
):
|
|
2157
|
-
self._pedb.padstacks.place(
|
|
2158
|
+
pd_inst = self._pedb.padstacks.place(
|
|
2159
|
+
position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2
|
|
2160
|
+
)
|
|
2161
|
+
temp.append(pd_inst)
|
|
2158
2162
|
self.delete()
|
|
2163
|
+
return temp
|
|
2159
2164
|
|
|
2160
2165
|
def convert_hole_to_conical_shape(self, angle=75):
|
|
2161
2166
|
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
|