pyedb 0.40.0__py3-none-any.whl → 0.42.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 +12 -3
- pyedb/configuration/cfg_components.py +333 -97
- pyedb/configuration/cfg_general.py +6 -4
- pyedb/configuration/cfg_pin_groups.py +18 -8
- pyedb/configuration/cfg_setup.py +139 -65
- pyedb/configuration/configuration.py +26 -11
- pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +5 -0
- pyedb/dotnet/database/cell/terminal/point_terminal.py +12 -0
- pyedb/dotnet/database/cell/terminal/terminal.py +0 -14
- pyedb/dotnet/database/dotnet/database.py +2 -0
- pyedb/dotnet/database/edb_data/padstacks_data.py +80 -3
- pyedb/dotnet/database/siwave.py +4 -1
- pyedb/dotnet/database/utilities/simulation_setup.py +8 -3
- pyedb/dotnet/edb.py +20 -5
- pyedb/grpc/database/components.py +1 -2
- pyedb/grpc/database/hierarchy/component.py +9 -1
- pyedb/grpc/database/hierarchy/s_parameter_model.py +2 -2
- pyedb/grpc/database/hierarchy/spice_model.py +4 -0
- pyedb/grpc/database/utility/hfss_extent_info.py +31 -20
- pyedb/grpc/edb.py +18 -0
- {pyedb-0.40.0.dist-info → pyedb-0.42.0.dist-info}/METADATA +1 -1
- {pyedb-0.40.0.dist-info → pyedb-0.42.0.dist-info}/RECORD +25 -25
- {pyedb-0.40.0.dist-info → pyedb-0.42.0.dist-info}/LICENSE +0 -0
- {pyedb-0.40.0.dist-info → pyedb-0.42.0.dist-info}/WHEEL +0 -0
pyedb/configuration/cfg_setup.py
CHANGED
|
@@ -53,14 +53,9 @@ class CfgSetup(CfgBase):
|
|
|
53
53
|
def _apply_freq_sweep(self, edb_setup):
|
|
54
54
|
for i in self.freq_sweep:
|
|
55
55
|
f_set = []
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for f in i.frequencies:
|
|
60
|
-
f_set.append([f.distribution, f.start, f.stop, f.increment])
|
|
61
|
-
else:
|
|
62
|
-
kw[attr] = getattr(i, attr)
|
|
63
|
-
edb_setup.add_sweep(i.name, frequency_set=f_set, **kw)
|
|
56
|
+
for f in i.frequencies:
|
|
57
|
+
f_set.append([f.distribution, f.start, f.stop, f.increment])
|
|
58
|
+
edb_setup.add_sweep(i.name, frequency_set=f_set, sweep_type=i.type)
|
|
64
59
|
|
|
65
60
|
|
|
66
61
|
class CfgSIwaveACSetup(CfgSetup):
|
|
@@ -183,62 +178,141 @@ class CfgSetups:
|
|
|
183
178
|
continue
|
|
184
179
|
|
|
185
180
|
stp = {}
|
|
186
|
-
if
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
181
|
+
if self._pedb.grpc:
|
|
182
|
+
from ansys.edb.core.simulation_setup.mesh_operation import (
|
|
183
|
+
LengthMeshOperation as GrpcLengthMeshOperation,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
s_type = s.type.name.lower()
|
|
187
|
+
if s_type == "hfss":
|
|
188
|
+
for p_name in CfgHFSSSetup(self._pedb).__dict__:
|
|
189
|
+
if p_name.startswith("_"):
|
|
190
|
+
continue
|
|
191
|
+
elif p_name == "type":
|
|
192
|
+
stp[p_name] = s.type.name.lower()
|
|
193
|
+
elif p_name == "f_adapt":
|
|
194
|
+
stp[p_name] = s.settings.general.single_frequency_adaptive_solution.adaptive_frequency
|
|
195
|
+
elif p_name == "max_num_passes":
|
|
196
|
+
stp[p_name] = s.settings.general.single_frequency_adaptive_solution.max_passes
|
|
197
|
+
elif p_name == "max_mag_delta_s":
|
|
198
|
+
stp[p_name] = s.settings.general.single_frequency_adaptive_solution.max_delta
|
|
199
|
+
elif p_name == "freq_sweep":
|
|
200
|
+
f_sweep = []
|
|
201
|
+
for sw in s.sweep_data:
|
|
202
|
+
sweep_data = {}
|
|
203
|
+
for sw_p_name in CfgSweepData().__dict__:
|
|
204
|
+
if sw_p_name == "frequencies":
|
|
205
|
+
pass # Frequencies cannot be read from EDB
|
|
206
|
+
else:
|
|
207
|
+
sweep_data[sw_p_name] = getattr(sw, sw_p_name)
|
|
208
|
+
f_sweep.append(sweep_data)
|
|
209
|
+
stp["freq_sweep"] = f_sweep
|
|
210
|
+
elif p_name == "mesh_operations":
|
|
211
|
+
mops = []
|
|
212
|
+
for i in s.mesh_operations:
|
|
213
|
+
mop = {}
|
|
214
|
+
for mop_p_name in CfgLengthMeshOperation().__dict__:
|
|
215
|
+
if mop_p_name == "type":
|
|
216
|
+
if isinstance(i, GrpcLengthMeshOperation):
|
|
217
|
+
mop[mop_p_name] = "length"
|
|
218
|
+
elif mop_p_name == "nets_layers_list":
|
|
219
|
+
mop[mop_p_name] = i.__dict__["_net_layer_info"]
|
|
220
|
+
elif mop_p_name == "restrict_length":
|
|
221
|
+
mop[mop_p_name] = i.__dict__["_restrict_max_length"]
|
|
222
|
+
else:
|
|
223
|
+
mop[mop_p_name] = i.__dict__[f"_{mop_p_name}"]
|
|
224
|
+
mops.append(mop)
|
|
225
|
+
stp["mesh_operations"] = mops
|
|
226
|
+
else:
|
|
227
|
+
stp[p_name] = getattr(s, p_name)
|
|
228
|
+
|
|
229
|
+
elif s_type == "siwave_ac":
|
|
230
|
+
for p_name in CfgSIwaveACSetup(self._pedb).__dict__:
|
|
231
|
+
if p_name.startswith("_"):
|
|
232
|
+
continue
|
|
233
|
+
elif p_name == "freq_sweep":
|
|
234
|
+
pass # Bug in EDB API
|
|
235
|
+
else:
|
|
236
|
+
stp[p_name] = getattr(s, p_name)
|
|
237
|
+
elif s_type == "siwave_dc":
|
|
238
|
+
for p_name in CfgSIwaveDCSetup(self._pedb).__dict__:
|
|
239
|
+
if p_name.startswith("_"):
|
|
240
|
+
continue
|
|
241
|
+
elif p_name == "freq_sweep":
|
|
242
|
+
pass
|
|
243
|
+
elif p_name == "dc_ir_settings":
|
|
244
|
+
dc_ir_s = {}
|
|
245
|
+
for dcir_p_name in CfgDcIrSettings().__dict__:
|
|
246
|
+
dc_ir_s[dcir_p_name] = getattr(s.dc_ir_settings, dcir_p_name)
|
|
247
|
+
stp["dc_ir_settings"] = dc_ir_s
|
|
248
|
+
elif p_name == "dc_slider_position":
|
|
249
|
+
stp[p_name] = getattr(s.dc_settings, p_name)
|
|
250
|
+
else:
|
|
251
|
+
stp[p_name] = getattr(s, p_name)
|
|
252
|
+
else:
|
|
253
|
+
for _, s in self._pedb.setups.items():
|
|
254
|
+
if float(self._pedb.edbversion) < 2025.1:
|
|
255
|
+
if not s.type == "hfss":
|
|
256
|
+
self._pedb.logger.warning("Only HFSS setups are exported in 2024 R2 and earlier version.")
|
|
257
|
+
continue
|
|
258
|
+
if s.type == "hfss":
|
|
259
|
+
for p_name in CfgHFSSSetup(self._pedb).__dict__:
|
|
260
|
+
if p_name.startswith("_"):
|
|
261
|
+
continue
|
|
262
|
+
elif p_name == "type":
|
|
263
|
+
stp[p_name] = s.type
|
|
264
|
+
elif p_name == "f_adapt":
|
|
265
|
+
stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[
|
|
266
|
+
0
|
|
267
|
+
].adaptive_frequency
|
|
268
|
+
elif p_name == "max_num_passes":
|
|
269
|
+
stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_passes
|
|
270
|
+
elif p_name == "max_mag_delta_s":
|
|
271
|
+
stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_delta
|
|
272
|
+
elif p_name == "freq_sweep":
|
|
273
|
+
f_sweep = []
|
|
274
|
+
for sw in s.sweeps.items():
|
|
275
|
+
sweep_data = {}
|
|
276
|
+
for sw_p_name in CfgSweepData().__dict__:
|
|
277
|
+
if sw_p_name == "frequencies":
|
|
278
|
+
pass # Frequencies cannot be read from EDB
|
|
279
|
+
else:
|
|
280
|
+
sweep_data[sw_p_name] = getattr(sw[1], sw_p_name)
|
|
281
|
+
f_sweep.append(sweep_data)
|
|
282
|
+
stp["freq_sweep"] = f_sweep
|
|
283
|
+
elif p_name == "mesh_operations":
|
|
284
|
+
mops = []
|
|
285
|
+
for _, i in s.mesh_operations.items():
|
|
286
|
+
mop = {}
|
|
287
|
+
for mop_p_name in CfgLengthMeshOperation().__dict__:
|
|
288
|
+
mop[mop_p_name] = getattr(i, mop_p_name)
|
|
289
|
+
mops.append(mop)
|
|
290
|
+
stp["mesh_operations"] = mops
|
|
291
|
+
else:
|
|
292
|
+
stp[p_name] = getattr(s, p_name)
|
|
293
|
+
|
|
294
|
+
elif s.type == "siwave_ac":
|
|
295
|
+
for p_name in CfgSIwaveACSetup(self._pedb).__dict__:
|
|
296
|
+
if p_name.startswith("_"):
|
|
297
|
+
continue
|
|
298
|
+
elif p_name == "freq_sweep":
|
|
299
|
+
pass # Bug in EDB API
|
|
300
|
+
else:
|
|
301
|
+
stp[p_name] = getattr(s, p_name)
|
|
302
|
+
elif s.type == "siwave_dc":
|
|
303
|
+
for p_name in CfgSIwaveDCSetup(self._pedb).__dict__:
|
|
304
|
+
if p_name.startswith("_"):
|
|
305
|
+
continue
|
|
306
|
+
elif p_name == "freq_sweep":
|
|
307
|
+
pass
|
|
308
|
+
elif p_name == "dc_ir_settings":
|
|
309
|
+
dc_ir_s = {}
|
|
310
|
+
for dcir_p_name in CfgDcIrSettings().__dict__:
|
|
311
|
+
dc_ir_s[dcir_p_name] = getattr(s.dc_ir_settings, dcir_p_name)
|
|
312
|
+
stp["dc_ir_settings"] = dc_ir_s
|
|
313
|
+
elif p_name == "dc_slider_position":
|
|
314
|
+
stp[p_name] = getattr(s.dc_settings, p_name)
|
|
315
|
+
else:
|
|
316
|
+
stp[p_name] = getattr(s, p_name)
|
|
243
317
|
setups.append(stp)
|
|
244
318
|
return setups
|
|
@@ -147,19 +147,34 @@ class Configuration:
|
|
|
147
147
|
cfg_pdef.api.set_parameters_to_edb()
|
|
148
148
|
else:
|
|
149
149
|
temp_pdef_data = {}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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(
|
|
157
167
|
lyr_name, self._pedb._edb.Definition.PadType.RegularPad
|
|
158
168
|
)
|
|
159
|
-
flag,
|
|
160
|
-
if flag:
|
|
161
|
-
|
|
162
|
-
|
|
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
|
|
163
178
|
self.cfg_data.stackup.apply()
|
|
164
179
|
for pdef_name, pdef_data in temp_pdef_data.items():
|
|
165
180
|
pdef = self._pedb.padstacks.definitions[pdef_name]
|
|
@@ -43,6 +43,11 @@ class PadstackInstanceTerminal(Terminal):
|
|
|
43
43
|
return EDBPadstackInstance(edb_padstack_instance[1], self._pedb).position
|
|
44
44
|
return False
|
|
45
45
|
|
|
46
|
+
@property
|
|
47
|
+
def location(self):
|
|
48
|
+
"""Location of the padstack instance."""
|
|
49
|
+
return self.position
|
|
50
|
+
|
|
46
51
|
def create(self, padstack_instance, name=None, layer=None, is_ref=False):
|
|
47
52
|
"""Create an edge terminal.
|
|
48
53
|
|
|
@@ -78,3 +78,15 @@ class PointTerminal(Terminal):
|
|
|
78
78
|
layer = self._pedb.stackup.layers[value]._edb_layer
|
|
79
79
|
point_data = self._pedb.point_data(*self.location)
|
|
80
80
|
self._edb_object.SetParameters(point_data, layer)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def location(self):
|
|
84
|
+
"""Location of the terminal."""
|
|
85
|
+
|
|
86
|
+
_, point_data, _ = self._edb_object.GetParameters()
|
|
87
|
+
return [point_data.X.ToDouble(), point_data.Y.ToDouble()]
|
|
88
|
+
|
|
89
|
+
@location.setter
|
|
90
|
+
def location(self, value):
|
|
91
|
+
layer = self.layer
|
|
92
|
+
self._edb_object.SetParameters(self._pedb.point_data(*value), layer._edb_object)
|
|
@@ -107,20 +107,6 @@ class Terminal(Connectable):
|
|
|
107
107
|
"""Get layer of the terminal."""
|
|
108
108
|
return self._pedb.logger.error("Cannot determine terminal layer")
|
|
109
109
|
|
|
110
|
-
@property
|
|
111
|
-
def location(self):
|
|
112
|
-
"""Location of the terminal."""
|
|
113
|
-
try:
|
|
114
|
-
_, point_data, _ = self._edb_object.GetParameters()
|
|
115
|
-
return [point_data.X.ToDouble(), point_data.Y.ToDouble()]
|
|
116
|
-
except:
|
|
117
|
-
self._pedb.logger.error("Cannot determine terminal location")
|
|
118
|
-
|
|
119
|
-
@location.setter
|
|
120
|
-
def location(self, value):
|
|
121
|
-
layer = self.layer
|
|
122
|
-
self._edb_object.SetParameters(self._pedb.point_data(*value), layer._edb_object)
|
|
123
|
-
|
|
124
110
|
@property
|
|
125
111
|
def is_circuit_port(self):
|
|
126
112
|
"""Whether it is a circuit port."""
|
|
@@ -510,7 +510,7 @@ class EDBPadstack(object):
|
|
|
510
510
|
list
|
|
511
511
|
List of layers.
|
|
512
512
|
"""
|
|
513
|
-
return self._padstack_def_data.GetLayerNames()
|
|
513
|
+
return list(self._padstack_def_data.GetLayerNames())
|
|
514
514
|
|
|
515
515
|
@property
|
|
516
516
|
def via_start_layer(self):
|
|
@@ -521,7 +521,7 @@ class EDBPadstack(object):
|
|
|
521
521
|
str
|
|
522
522
|
Name of the starting layer.
|
|
523
523
|
"""
|
|
524
|
-
return
|
|
524
|
+
return self.via_layers[0]
|
|
525
525
|
|
|
526
526
|
@property
|
|
527
527
|
def via_stop_layer(self):
|
|
@@ -532,7 +532,7 @@ class EDBPadstack(object):
|
|
|
532
532
|
str
|
|
533
533
|
Name of the stopping layer.
|
|
534
534
|
"""
|
|
535
|
-
return
|
|
535
|
+
return self.via_layers[-1]
|
|
536
536
|
|
|
537
537
|
@property
|
|
538
538
|
def hole_params(self):
|
|
@@ -2141,3 +2141,80 @@ class EDBPadstackInstance(Primitive):
|
|
|
2141
2141
|
max_limit=max_limit,
|
|
2142
2142
|
component_only=component_only,
|
|
2143
2143
|
)
|
|
2144
|
+
|
|
2145
|
+
def split(self):
|
|
2146
|
+
"""Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
|
|
2147
|
+
pdef_name = self.padstack_definition
|
|
2148
|
+
position = self.position
|
|
2149
|
+
net_name = self.net_name
|
|
2150
|
+
name = self.name
|
|
2151
|
+
stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
|
|
2152
|
+
start_idx = stackup_layer_range.index(self.start_layer)
|
|
2153
|
+
stop_idx = stackup_layer_range.index(self.stop_layer)
|
|
2154
|
+
for idx, (l1, l2) in enumerate(
|
|
2155
|
+
list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
|
|
2156
|
+
):
|
|
2157
|
+
self._pedb.padstacks.place(position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2)
|
|
2158
|
+
self.delete()
|
|
2159
|
+
|
|
2160
|
+
def convert_hole_to_conical_shape(self, angle=75):
|
|
2161
|
+
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
|
|
2162
|
+
|
|
2163
|
+
Parameters
|
|
2164
|
+
----------
|
|
2165
|
+
angle : float, optional
|
|
2166
|
+
Angle of laser penetration in degrees. The angle defines the lowest hole diameter with this formula:
|
|
2167
|
+
HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
|
|
2168
|
+
The default is ``75``.
|
|
2169
|
+
The lowest hole is ``0.75*HoleDepth/HoleDiam``.
|
|
2170
|
+
|
|
2171
|
+
Returns
|
|
2172
|
+
-------
|
|
2173
|
+
"""
|
|
2174
|
+
pos = self.position
|
|
2175
|
+
stackup_layers = self._pedb.stackup.stackup_layers
|
|
2176
|
+
signal_layers = self._pedb.stackup.signal_layers
|
|
2177
|
+
layer_idx = list(signal_layers.keys()).index(self.start_layer)
|
|
2178
|
+
|
|
2179
|
+
_layer_idx = list(stackup_layers.keys()).index(self.start_layer)
|
|
2180
|
+
diel_layer_idx = list(stackup_layers.keys())[_layer_idx + 1]
|
|
2181
|
+
diel_thickness = stackup_layers[diel_layer_idx].thickness
|
|
2182
|
+
|
|
2183
|
+
rad_large = self.definition.hole_diameter / 2
|
|
2184
|
+
rad_small = rad_large - diel_thickness * 1 / math.tan(math.radians(angle))
|
|
2185
|
+
|
|
2186
|
+
if layer_idx + 1 < len(signal_layers) / 2: # upper half of stack
|
|
2187
|
+
rad_u = rad_large
|
|
2188
|
+
rad_l = rad_small
|
|
2189
|
+
else:
|
|
2190
|
+
rad_u = rad_small
|
|
2191
|
+
rad_l = rad_large
|
|
2192
|
+
|
|
2193
|
+
layout = self._pedb.active_layout
|
|
2194
|
+
cloned_circle = self._edb.cell.primitive.circle.create(
|
|
2195
|
+
layout,
|
|
2196
|
+
self.start_layer,
|
|
2197
|
+
self._edb_padstackinstance.GetNet(),
|
|
2198
|
+
self._pedb.edb_value(pos[0]),
|
|
2199
|
+
self._pedb.edb_value(pos[1]),
|
|
2200
|
+
self._pedb.edb_value(rad_u),
|
|
2201
|
+
)
|
|
2202
|
+
cloned_circle2 = self._edb.cell.primitive.circle.create(
|
|
2203
|
+
layout,
|
|
2204
|
+
self.stop_layer,
|
|
2205
|
+
self._edb_padstackinstance.GetNet(),
|
|
2206
|
+
self._pedb.edb_value(pos[0]),
|
|
2207
|
+
self._pedb.edb_value(pos[1]),
|
|
2208
|
+
self._pedb.edb_value(rad_l),
|
|
2209
|
+
)
|
|
2210
|
+
s3d = self._pedb._edb.Cell.Hierarchy.Structure3D.Create(
|
|
2211
|
+
layout, generate_unique_name("via3d_" + self.aedt_name.replace("via_", ""), n=3)
|
|
2212
|
+
)
|
|
2213
|
+
s3d.AddMember(cloned_circle.prim_obj)
|
|
2214
|
+
s3d.AddMember(cloned_circle2.prim_obj)
|
|
2215
|
+
s3d.SetMaterial(self.definition.material)
|
|
2216
|
+
s3d.SetMeshClosureProp(self._pedb._edb.Cell.Hierarchy.Structure3D.TClosure.EndsClosed)
|
|
2217
|
+
|
|
2218
|
+
hole_override_enabled = True
|
|
2219
|
+
hole_override_diam = 0
|
|
2220
|
+
self._edb_object.SetHoleOverride(hole_override_enabled, self._pedb.edb_value(hole_override_diam))
|
pyedb/dotnet/database/siwave.py
CHANGED
|
@@ -811,6 +811,7 @@ class EdbSiwave(object):
|
|
|
811
811
|
|
|
812
812
|
def add_siwave_syz_analysis(
|
|
813
813
|
self,
|
|
814
|
+
name=None,
|
|
814
815
|
accuracy_level=1,
|
|
815
816
|
decade_count=10,
|
|
816
817
|
sweeptype=1,
|
|
@@ -823,6 +824,8 @@ class EdbSiwave(object):
|
|
|
823
824
|
|
|
824
825
|
Parameters
|
|
825
826
|
----------
|
|
827
|
+
name : str optional
|
|
828
|
+
Setup name.
|
|
826
829
|
accuracy_level : int, optional
|
|
827
830
|
Level of accuracy of SI slider. The default is ``1``.
|
|
828
831
|
decade_count : int
|
|
@@ -849,7 +852,7 @@ class EdbSiwave(object):
|
|
|
849
852
|
:class:`pyedb.dotnet.database.edb_data.siwave_simulation_setup_data.SiwaveSYZSimulationSetup`
|
|
850
853
|
Setup object class.
|
|
851
854
|
"""
|
|
852
|
-
setup = self._pedb.create_siwave_syz_setup()
|
|
855
|
+
setup = self._pedb.create_siwave_syz_setup(name=name)
|
|
853
856
|
sweep = "linear count"
|
|
854
857
|
if sweeptype == 2:
|
|
855
858
|
sweep = "log scale"
|
|
@@ -239,7 +239,7 @@ class SimulationSetup(object):
|
|
|
239
239
|
"""List of frequency sweeps."""
|
|
240
240
|
return {i.name: i for i in self.sim_setup_info.sweep_data_list}
|
|
241
241
|
|
|
242
|
-
def add_sweep(self, name, frequency_set: list = None, **kwargs):
|
|
242
|
+
def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
243
243
|
"""Add frequency sweep.
|
|
244
244
|
|
|
245
245
|
Parameters
|
|
@@ -248,7 +248,8 @@ class SimulationSetup(object):
|
|
|
248
248
|
Name of the frequency sweep. The default is ``None``.
|
|
249
249
|
frequency_set : list, optional
|
|
250
250
|
List of frequency points. The default is ``None``.
|
|
251
|
-
|
|
251
|
+
sweep_type : str, optional
|
|
252
|
+
Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
|
|
252
253
|
Returns
|
|
253
254
|
-------
|
|
254
255
|
|
|
@@ -265,7 +266,7 @@ class SimulationSetup(object):
|
|
|
265
266
|
for k, v in kwargs.items():
|
|
266
267
|
if k in dir(sweep_data):
|
|
267
268
|
setattr(sweep_data, k, v)
|
|
268
|
-
sweep_data.
|
|
269
|
+
sweep_data.type = sweep_type
|
|
269
270
|
|
|
270
271
|
if frequency_set is None:
|
|
271
272
|
sweep_type = "linear_scale"
|
|
@@ -285,6 +286,10 @@ class SimulationSetup(object):
|
|
|
285
286
|
self._update_setup()
|
|
286
287
|
return sweep_data
|
|
287
288
|
|
|
289
|
+
def delete(self):
|
|
290
|
+
"""Delete current simulation setup."""
|
|
291
|
+
self._pedb.layout.cell.DeleteSimulationSetup(self.name)
|
|
292
|
+
|
|
288
293
|
def _add_frequency_sweep(self, sweep_data):
|
|
289
294
|
"""Add a frequency sweep.
|
|
290
295
|
|
pyedb/dotnet/edb.py
CHANGED
|
@@ -46,6 +46,7 @@ from pyedb.dotnet.database.Variables import decompose_variable_value
|
|
|
46
46
|
from pyedb.dotnet.database.cell.layout import Layout
|
|
47
47
|
from pyedb.dotnet.database.cell.terminal.terminal import Terminal
|
|
48
48
|
from pyedb.dotnet.database.components import Components
|
|
49
|
+
import pyedb.dotnet.database.dotnet.database
|
|
49
50
|
from pyedb.dotnet.database.dotnet.database import Database
|
|
50
51
|
from pyedb.dotnet.database.edb_data.control_file import (
|
|
51
52
|
ControlFile,
|
|
@@ -277,7 +278,7 @@ class Edb(Database):
|
|
|
277
278
|
if self.active_cell:
|
|
278
279
|
self.logger.info("EDB initialized.")
|
|
279
280
|
else:
|
|
280
|
-
|
|
281
|
+
raise AttributeError("Failed to initialize DLLs.")
|
|
281
282
|
|
|
282
283
|
def __enter__(self):
|
|
283
284
|
return self
|
|
@@ -548,10 +549,7 @@ class Edb(Database):
|
|
|
548
549
|
self.run_as_standalone(self.standalone)
|
|
549
550
|
|
|
550
551
|
# self.logger.info("EDB Standalone %s", self.standalone)
|
|
551
|
-
|
|
552
|
-
self.open(self.edbpath, self.isreadonly)
|
|
553
|
-
except Exception as e:
|
|
554
|
-
self.logger.error("Builder is not Initialized.")
|
|
552
|
+
self.open(self.edbpath, self.isreadonly)
|
|
555
553
|
if not self.active_db:
|
|
556
554
|
self.logger.warning("Error Opening db")
|
|
557
555
|
self._active_cell = None
|
|
@@ -761,6 +759,23 @@ class Edb(Database):
|
|
|
761
759
|
"""Active cell."""
|
|
762
760
|
return self._active_cell
|
|
763
761
|
|
|
762
|
+
@active_cell.setter
|
|
763
|
+
def active_cell(self, value):
|
|
764
|
+
if isinstance(value, str):
|
|
765
|
+
_cell = [cell for cell in self.circuit_cells if cell.GetName() == value]
|
|
766
|
+
if _cell:
|
|
767
|
+
self._active_cell = _cell[0]
|
|
768
|
+
self._init_objects()
|
|
769
|
+
self.logger.info(f"Cell {value} set as active")
|
|
770
|
+
else:
|
|
771
|
+
raise f"Design {value} not found in database."
|
|
772
|
+
elif isinstance(value, pyedb.dotnet.database.dotnet.database.CellClassDotNet):
|
|
773
|
+
self._active_cell = value
|
|
774
|
+
self._init_objects()
|
|
775
|
+
self.logger.info(f"Cell {value.GetName()} set as active")
|
|
776
|
+
else:
|
|
777
|
+
raise "No valid design."
|
|
778
|
+
|
|
764
779
|
@property
|
|
765
780
|
def core_components(self): # pragma: no cover
|
|
766
781
|
"""Edb Components methods and properties.
|
|
@@ -2274,8 +2274,7 @@ class Components(object):
|
|
|
2274
2274
|
pingroup = PinGroup.create(self._active_layout, group_name, pins)
|
|
2275
2275
|
|
|
2276
2276
|
if pingroup.is_null: # pragma: no cover
|
|
2277
|
-
|
|
2278
|
-
return False
|
|
2277
|
+
raise RuntimeError(f"Failed to create pin group {group_name}.")
|
|
2279
2278
|
else:
|
|
2280
2279
|
for pin in pins:
|
|
2281
2280
|
if not pin.net.is_null:
|
|
@@ -41,6 +41,7 @@ from ansys.edb.core.hierarchy.pin_pair_model import PinPairModel as GrpcPinPairM
|
|
|
41
41
|
from ansys.edb.core.hierarchy.sparameter_model import (
|
|
42
42
|
SParameterModel as GrpcSParameterModel,
|
|
43
43
|
)
|
|
44
|
+
from ansys.edb.core.hierarchy.spice_model import SPICEModel as GrpcSPICEModel
|
|
44
45
|
from ansys.edb.core.primitive.primitive import PadstackInstance as GrpcPadstackInstance
|
|
45
46
|
from ansys.edb.core.terminal.terminals import (
|
|
46
47
|
PadstackInstanceTerminal as GrpcPadstackInstanceTerminal,
|
|
@@ -49,6 +50,7 @@ from ansys.edb.core.utility.rlc import Rlc as GrpcRlc
|
|
|
49
50
|
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
50
51
|
|
|
51
52
|
from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
|
|
53
|
+
from pyedb.grpc.database.hierarchy.s_parameter_model import SparamModel
|
|
52
54
|
from pyedb.grpc.database.hierarchy.spice_model import SpiceModel
|
|
53
55
|
from pyedb.grpc.database.layers.stackup_layer import StackupLayer
|
|
54
56
|
from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
|
|
@@ -204,7 +206,13 @@ class Component(GrpcComponentGroup):
|
|
|
204
206
|
:class:`Model <ansys.edb.core.hierarchy.model.Model>`
|
|
205
207
|
|
|
206
208
|
"""
|
|
207
|
-
|
|
209
|
+
|
|
210
|
+
if isinstance(self.component_property.model, GrpcSPICEModel):
|
|
211
|
+
return SpiceModel(edb_object=self.component_property.model.msg)
|
|
212
|
+
elif isinstance(self.component_property.model, GrpcSParameterModel):
|
|
213
|
+
return SparamModel(edb_object=self.component_property.model.msg)
|
|
214
|
+
else:
|
|
215
|
+
return self.component_property.model
|
|
208
216
|
|
|
209
217
|
@model.setter
|
|
210
218
|
def model(self, value):
|
|
@@ -28,6 +28,6 @@ from ansys.edb.core.hierarchy.sparameter_model import (
|
|
|
28
28
|
class SparamModel(GrpcSParameterModel): # pragma: no cover
|
|
29
29
|
"""Manage :class:`SParameterModel <ansys.edb.core.hierarchy.sparameter_model.SParameterModel>`"""
|
|
30
30
|
|
|
31
|
-
def __init__(self,
|
|
31
|
+
def __init__(self, edb_object):
|
|
32
32
|
super().__init__(self.msg)
|
|
33
|
-
self._edb_model =
|
|
33
|
+
self._edb_model = edb_object
|