pyedb 0.39.0__py3-none-any.whl → 0.40.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/common/nets.py +11 -2
- pyedb/configuration/cfg_components.py +2 -0
- pyedb/configuration/cfg_padstacks.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +63 -11
- pyedb/configuration/cfg_stackup.py +22 -1
- pyedb/dotnet/database/cell/terminal/edge_terminal.py +55 -0
- pyedb/dotnet/database/components.py +14 -12
- pyedb/dotnet/database/edb_data/ports.py +0 -55
- pyedb/dotnet/database/materials.py +40 -11
- pyedb/dotnet/database/modeler.py +11 -4
- pyedb/grpc/database/components.py +24 -72
- pyedb/grpc/database/definition/materials.py +16 -1
- pyedb/grpc/database/layout/layout.py +43 -4
- pyedb/grpc/database/layout_validation.py +164 -143
- pyedb/grpc/database/net/net.py +5 -8
- pyedb/grpc/database/padstacks.py +184 -31
- pyedb/grpc/database/primitive/padstack_instance.py +1 -1
- pyedb/grpc/database/source_excitations.py +83 -105
- pyedb/grpc/edb.py +42 -198
- {pyedb-0.39.0.dist-info → pyedb-0.40.0.dist-info}/METADATA +2 -1
- {pyedb-0.39.0.dist-info → pyedb-0.40.0.dist-info}/RECORD +24 -24
- {pyedb-0.39.0.dist-info → pyedb-0.40.0.dist-info}/LICENSE +0 -0
- {pyedb-0.39.0.dist-info → pyedb-0.40.0.dist-info}/WHEEL +0 -0
|
@@ -54,6 +54,7 @@ from pyedb.grpc.database.definition.component_pin import ComponentPin
|
|
|
54
54
|
from pyedb.grpc.database.hierarchy.component import Component
|
|
55
55
|
from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
|
|
56
56
|
from pyedb.grpc.database.hierarchy.pingroup import PinGroup
|
|
57
|
+
from pyedb.grpc.database.padstacks import Padstacks
|
|
57
58
|
from pyedb.grpc.database.utility.sources import SourceType
|
|
58
59
|
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
59
60
|
|
|
@@ -119,17 +120,10 @@ class Components(object):
|
|
|
119
120
|
|
|
120
121
|
def __init__(self, p_edb):
|
|
121
122
|
self._pedb = p_edb
|
|
122
|
-
self.
|
|
123
|
-
self._res = {}
|
|
124
|
-
self._cap = {}
|
|
125
|
-
self._ind = {}
|
|
126
|
-
self._ios = {}
|
|
127
|
-
self._ics = {}
|
|
128
|
-
self._others = {}
|
|
123
|
+
self.refresh_components()
|
|
129
124
|
self._pins = {}
|
|
130
125
|
self._comps_by_part = {}
|
|
131
|
-
self.
|
|
132
|
-
# self._padstack = Padstacks(self._pedb)
|
|
126
|
+
self._padstack = Padstacks(self._pedb)
|
|
133
127
|
# self._excitations = self._pedb.excitations
|
|
134
128
|
|
|
135
129
|
@property
|
|
@@ -137,16 +131,6 @@ class Components(object):
|
|
|
137
131
|
"""Logger."""
|
|
138
132
|
return self._pedb.logger
|
|
139
133
|
|
|
140
|
-
def _init_parts(self):
|
|
141
|
-
a = self.instances
|
|
142
|
-
a = self.resistors
|
|
143
|
-
a = self.ICs
|
|
144
|
-
a = self.Others
|
|
145
|
-
a = self.inductors
|
|
146
|
-
a = self.IOs
|
|
147
|
-
a = self.components_by_partname
|
|
148
|
-
return True
|
|
149
|
-
|
|
150
134
|
@property
|
|
151
135
|
def _active_layout(self):
|
|
152
136
|
return self._pedb.active_layout
|
|
@@ -180,8 +164,6 @@ class Components(object):
|
|
|
180
164
|
>>> edbapp.components.instances
|
|
181
165
|
|
|
182
166
|
"""
|
|
183
|
-
if not self._cmp:
|
|
184
|
-
self.refresh_components()
|
|
185
167
|
return self._cmp
|
|
186
168
|
|
|
187
169
|
@property
|
|
@@ -287,10 +269,28 @@ class Components(object):
|
|
|
287
269
|
"""Refresh the component dictionary."""
|
|
288
270
|
self._logger.info("Refreshing the Components dictionary.")
|
|
289
271
|
self._cmp = {}
|
|
272
|
+
self._res = {}
|
|
273
|
+
self._ind = {}
|
|
274
|
+
self._cap = {}
|
|
275
|
+
self._ics = {}
|
|
276
|
+
self._ios = {}
|
|
277
|
+
self._others = {}
|
|
290
278
|
for i in self._pedb.layout.groups:
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
279
|
+
self._cmp[i.name] = i
|
|
280
|
+
if i.type == "resistor":
|
|
281
|
+
self._res[i.name] = i
|
|
282
|
+
elif i.type == "capacitor":
|
|
283
|
+
self._cap[i.name] = i
|
|
284
|
+
elif i.type == "inductor":
|
|
285
|
+
self._ind[i.name] = i
|
|
286
|
+
elif i.type == "ic":
|
|
287
|
+
self._ics[i.name] = i
|
|
288
|
+
elif i.type == "io":
|
|
289
|
+
self._ios[i.name] = i
|
|
290
|
+
elif i.type == "other":
|
|
291
|
+
self._others[i.name] = i
|
|
292
|
+
else:
|
|
293
|
+
self._logger.warning(f"Unknown component type {i.name} found while refreshing components, will ignore")
|
|
294
294
|
return True
|
|
295
295
|
|
|
296
296
|
@property
|
|
@@ -309,14 +309,6 @@ class Components(object):
|
|
|
309
309
|
>>> edbapp = Edb("myaedbfolder")
|
|
310
310
|
>>> edbapp.components.resistors
|
|
311
311
|
"""
|
|
312
|
-
self._res = {}
|
|
313
|
-
for el, val in self.instances.items():
|
|
314
|
-
if not val.is_null:
|
|
315
|
-
try:
|
|
316
|
-
if val.type == "resistor":
|
|
317
|
-
self._res[el] = val
|
|
318
|
-
except:
|
|
319
|
-
pass
|
|
320
312
|
return self._res
|
|
321
313
|
|
|
322
314
|
@property
|
|
@@ -335,14 +327,6 @@ class Components(object):
|
|
|
335
327
|
>>> edbapp = Edb("myaedbfolder")
|
|
336
328
|
>>> edbapp.components.capacitors
|
|
337
329
|
"""
|
|
338
|
-
self._cap = {}
|
|
339
|
-
for el, val in self.instances.items():
|
|
340
|
-
if not val.is_null:
|
|
341
|
-
try:
|
|
342
|
-
if val.type == "capacitor":
|
|
343
|
-
self._cap[el] = val
|
|
344
|
-
except:
|
|
345
|
-
pass
|
|
346
330
|
return self._cap
|
|
347
331
|
|
|
348
332
|
@property
|
|
@@ -362,14 +346,6 @@ class Components(object):
|
|
|
362
346
|
>>> edbapp.components.inductors
|
|
363
347
|
|
|
364
348
|
"""
|
|
365
|
-
self._ind = {}
|
|
366
|
-
for el, val in self.instances.items():
|
|
367
|
-
if not val.is_null:
|
|
368
|
-
try:
|
|
369
|
-
if val.type == "inductor":
|
|
370
|
-
self._ind[el] = val
|
|
371
|
-
except:
|
|
372
|
-
pass
|
|
373
349
|
return self._ind
|
|
374
350
|
|
|
375
351
|
@property
|
|
@@ -389,14 +365,6 @@ class Components(object):
|
|
|
389
365
|
>>> edbapp.components.ICs
|
|
390
366
|
|
|
391
367
|
"""
|
|
392
|
-
self._ics = {}
|
|
393
|
-
for el, val in self.instances.items():
|
|
394
|
-
if not val.is_null:
|
|
395
|
-
try:
|
|
396
|
-
if val.type == "ic":
|
|
397
|
-
self._ics[el] = val
|
|
398
|
-
except:
|
|
399
|
-
pass
|
|
400
368
|
return self._ics
|
|
401
369
|
|
|
402
370
|
@property
|
|
@@ -416,14 +384,6 @@ class Components(object):
|
|
|
416
384
|
>>> edbapp.components.IOs
|
|
417
385
|
|
|
418
386
|
"""
|
|
419
|
-
self._ios = {}
|
|
420
|
-
for el, val in self.instances.items():
|
|
421
|
-
if not val.is_null:
|
|
422
|
-
try:
|
|
423
|
-
if val.type == "io":
|
|
424
|
-
self._ios[el] = val
|
|
425
|
-
except:
|
|
426
|
-
pass
|
|
427
387
|
return self._ios
|
|
428
388
|
|
|
429
389
|
@property
|
|
@@ -443,14 +403,6 @@ class Components(object):
|
|
|
443
403
|
>>> edbapp.components.others
|
|
444
404
|
|
|
445
405
|
"""
|
|
446
|
-
self._others = {}
|
|
447
|
-
for el, val in self.instances.items():
|
|
448
|
-
if not val.is_null:
|
|
449
|
-
try:
|
|
450
|
-
if val.type == "other":
|
|
451
|
-
self._others[el] = val
|
|
452
|
-
except:
|
|
453
|
-
pass
|
|
454
406
|
return self._others
|
|
455
407
|
|
|
456
408
|
@property
|
|
@@ -26,7 +26,7 @@ import difflib
|
|
|
26
26
|
import logging
|
|
27
27
|
import os
|
|
28
28
|
import re
|
|
29
|
-
from typing import Optional
|
|
29
|
+
from typing import Optional, Union
|
|
30
30
|
import warnings
|
|
31
31
|
|
|
32
32
|
from ansys.edb.core.definition.debye_model import DebyeModel as GrpcDebyeModel
|
|
@@ -1205,3 +1205,18 @@ class Materials(object):
|
|
|
1205
1205
|
|
|
1206
1206
|
self.__edb.logger.error(f"Material {material_name} does not exist in syslib AMAT file.")
|
|
1207
1207
|
return res
|
|
1208
|
+
|
|
1209
|
+
def update_materials_from_sys_library(self, update_all: bool = True, material_name: Union[str, list] = None):
|
|
1210
|
+
"""Update material properties from syslib AMAT file."""
|
|
1211
|
+
amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
|
|
1212
|
+
materials_dict = self.read_materials(amat_file)
|
|
1213
|
+
if update_all:
|
|
1214
|
+
for name, obj in self.materials.items():
|
|
1215
|
+
if name in materials_dict:
|
|
1216
|
+
obj.update(materials_dict[name])
|
|
1217
|
+
self.__edb.logger.info(f"Material {name} is updated from syslibrary.")
|
|
1218
|
+
else:
|
|
1219
|
+
material_names = material_name if isinstance(material_name, list) else [material_name]
|
|
1220
|
+
for name in material_names:
|
|
1221
|
+
self.materials[name].update(materials_dict[name])
|
|
1222
|
+
self.__edb.logger.info(f"Material {name} is updated from syslibrary.")
|
|
@@ -26,6 +26,7 @@ This module contains these classes: `EdbLayout` and `Shape`.
|
|
|
26
26
|
from typing import Union
|
|
27
27
|
|
|
28
28
|
from ansys.edb.core.layout.layout import Layout as GrpcLayout
|
|
29
|
+
import ansys.edb.core.primitive.primitive
|
|
29
30
|
|
|
30
31
|
from pyedb.grpc.database.hierarchy.component import Component
|
|
31
32
|
from pyedb.grpc.database.hierarchy.pingroup import PinGroup
|
|
@@ -34,7 +35,12 @@ from pyedb.grpc.database.net.differential_pair import DifferentialPair
|
|
|
34
35
|
from pyedb.grpc.database.net.extended_net import ExtendedNet
|
|
35
36
|
from pyedb.grpc.database.net.net import Net
|
|
36
37
|
from pyedb.grpc.database.net.net_class import NetClass
|
|
38
|
+
from pyedb.grpc.database.primitive.bondwire import Bondwire
|
|
39
|
+
from pyedb.grpc.database.primitive.circle import Circle
|
|
37
40
|
from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
|
|
41
|
+
from pyedb.grpc.database.primitive.path import Path
|
|
42
|
+
from pyedb.grpc.database.primitive.polygon import Polygon
|
|
43
|
+
from pyedb.grpc.database.primitive.rectangle import Rectangle
|
|
38
44
|
from pyedb.grpc.database.terminal.bundle_terminal import BundleTerminal
|
|
39
45
|
from pyedb.grpc.database.terminal.edge_terminal import EdgeTerminal
|
|
40
46
|
from pyedb.grpc.database.terminal.padstack_instance_terminal import (
|
|
@@ -59,6 +65,24 @@ class Layout(GrpcLayout):
|
|
|
59
65
|
"""
|
|
60
66
|
return self._pedb._active_cell
|
|
61
67
|
|
|
68
|
+
@property
|
|
69
|
+
def primitives(self):
|
|
70
|
+
prims = []
|
|
71
|
+
for prim in super().primitives:
|
|
72
|
+
if isinstance(prim, ansys.edb.core.primitive.primitive.Path):
|
|
73
|
+
prims.append(Path(self._pedb, prim))
|
|
74
|
+
elif isinstance(prim, ansys.edb.core.primitive.primitive.Polygon):
|
|
75
|
+
prims.append(Polygon(self._pedb, prim))
|
|
76
|
+
elif isinstance(prim, ansys.edb.core.primitive.primitive.PadstackInstance):
|
|
77
|
+
prims.append(PadstackInstance(self._pedb, prim))
|
|
78
|
+
elif isinstance(prim, ansys.edb.core.primitive.primitive.Rectangle):
|
|
79
|
+
prims.append(Rectangle(self._pedb, prim))
|
|
80
|
+
elif isinstance(prim, ansys.edb.core.primitive.primitive.Circle):
|
|
81
|
+
prims.append(Circle(self._pedb, prim))
|
|
82
|
+
elif isinstance(prim, ansys.edb.core.primitive.primitive.Bondwire):
|
|
83
|
+
prims.append(Bondwire(self._pedb, prim))
|
|
84
|
+
return prims
|
|
85
|
+
|
|
62
86
|
@property
|
|
63
87
|
def terminals(self):
|
|
64
88
|
"""Get terminals belonging to active layout.
|
|
@@ -180,17 +204,32 @@ class Layout(GrpcLayout):
|
|
|
180
204
|
"""
|
|
181
205
|
return [VoltageRegulator(self._pedb, i) for i in self._pedb.active_cell.layout.voltage_regulators]
|
|
182
206
|
|
|
183
|
-
def find_primitive(
|
|
207
|
+
def find_primitive(
|
|
208
|
+
self, layer_name: Union[str, list] = None, name: Union[str, list] = None, net_name: Union[str, list] = None
|
|
209
|
+
) -> list:
|
|
184
210
|
"""Find a primitive objects by layer name.
|
|
185
|
-
|
|
186
211
|
Parameters
|
|
187
212
|
----------
|
|
188
213
|
layer_name : str, list
|
|
214
|
+
layer_name : str, list, optional
|
|
189
215
|
Name of the layer.
|
|
216
|
+
name : str, list, optional
|
|
217
|
+
Name of the primitive
|
|
218
|
+
net_name : str, list, optional
|
|
219
|
+
Name of the primitive
|
|
190
220
|
Returns
|
|
191
221
|
-------
|
|
192
222
|
List[:class:`Primitive <pyedb.grpc.database.primitive.primitive.Primitive`].
|
|
193
223
|
List of Primitive.
|
|
194
224
|
"""
|
|
195
|
-
|
|
196
|
-
|
|
225
|
+
if layer_name:
|
|
226
|
+
layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
|
|
227
|
+
if name:
|
|
228
|
+
name = name if isinstance(name, list) else [name]
|
|
229
|
+
if net_name:
|
|
230
|
+
net_name = net_name if isinstance(net_name, list) else [net_name]
|
|
231
|
+
prims = self.primitives
|
|
232
|
+
prims = [i for i in prims if i.aedt_name in name] if name is not None else prims
|
|
233
|
+
prims = [i for i in prims if i.layer_name in layer_name] if layer_name is not None else prims
|
|
234
|
+
prims = [i for i in prims if i.net_name in net_name] if net_name is not None else prims
|
|
235
|
+
return prims
|
|
@@ -22,8 +22,11 @@
|
|
|
22
22
|
|
|
23
23
|
import re
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
from ansys.edb.core.database import ProductIdType as GrpcProductIdType
|
|
26
|
+
|
|
27
|
+
from pyedb.generic.general_methods import generate_unique_name
|
|
28
|
+
from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
|
|
29
|
+
|
|
27
30
|
# from pyedb.grpc.database.primitive.primitive import Primitive
|
|
28
31
|
|
|
29
32
|
|
|
@@ -120,146 +123,145 @@ class LayoutValidation:
|
|
|
120
123
|
i.net = self._pedb.nets.nets[temp_name]
|
|
121
124
|
return dc_shorts
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
# return new_nets
|
|
126
|
+
def disjoint_nets(
|
|
127
|
+
self,
|
|
128
|
+
net_list=None,
|
|
129
|
+
keep_only_main_net=False,
|
|
130
|
+
clean_disjoints_less_than=0.0,
|
|
131
|
+
order_by_area=False,
|
|
132
|
+
keep_disjoint_pins=False,
|
|
133
|
+
):
|
|
134
|
+
"""Find and fix disjoint nets from a given netlist.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
net_list : str, list, optional
|
|
139
|
+
List of nets on which check disjoints. If `None` is provided then the algorithm will loop on all nets.
|
|
140
|
+
keep_only_main_net : bool, optional
|
|
141
|
+
Remove all secondary nets other than principal one (the one with more objects in it). Default is `False`.
|
|
142
|
+
clean_disjoints_less_than : bool, optional
|
|
143
|
+
Clean all disjoint nets with area less than specified area in square meters. Default is `0.0` to disable it.
|
|
144
|
+
order_by_area : bool, optional
|
|
145
|
+
Whether if the naming order has to be by number of objects (fastest) or area (slowest but more accurate).
|
|
146
|
+
Default is ``False``.
|
|
147
|
+
keep_disjoint_pins : bool, optional
|
|
148
|
+
Whether if delete disjoints pins not connected to any other primitive or not. Default is ``False``.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
List
|
|
153
|
+
New nets created.
|
|
154
|
+
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
|
|
158
|
+
>>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"])
|
|
159
|
+
"""
|
|
160
|
+
timer_start = self._pedb.logger.reset_timer()
|
|
161
|
+
|
|
162
|
+
if not net_list:
|
|
163
|
+
net_list = list(self._pedb.nets.keys())
|
|
164
|
+
elif isinstance(net_list, str):
|
|
165
|
+
net_list = [net_list]
|
|
166
|
+
_objects_list = {}
|
|
167
|
+
_padstacks_list = {}
|
|
168
|
+
for prim in self._pedb.modeler.primitives:
|
|
169
|
+
if not prim.net.is_null:
|
|
170
|
+
n_name = prim.net.name
|
|
171
|
+
if n_name in _objects_list:
|
|
172
|
+
_objects_list[n_name].append(prim)
|
|
173
|
+
else:
|
|
174
|
+
_objects_list[n_name] = [prim]
|
|
175
|
+
for pad in list(self._pedb.padstacks.instances.values()):
|
|
176
|
+
if not pad.net.is_null:
|
|
177
|
+
n_name = pad.net_name
|
|
178
|
+
if n_name in _padstacks_list:
|
|
179
|
+
_padstacks_list[n_name].append(pad)
|
|
180
|
+
else:
|
|
181
|
+
_padstacks_list[n_name] = [pad]
|
|
182
|
+
new_nets = []
|
|
183
|
+
disjoints_objects = []
|
|
184
|
+
self._pedb.logger.reset_timer()
|
|
185
|
+
for net in net_list:
|
|
186
|
+
net_groups = []
|
|
187
|
+
obj_dict = {}
|
|
188
|
+
for i in _objects_list.get(net, []):
|
|
189
|
+
obj_dict[i.id] = i
|
|
190
|
+
for i in _padstacks_list.get(net, []):
|
|
191
|
+
obj_dict[i.id] = i
|
|
192
|
+
objs = list(obj_dict.values())
|
|
193
|
+
l = len(objs)
|
|
194
|
+
while l > 0:
|
|
195
|
+
l1 = self._layout_instance.get_connected_objects(objs[0].layout_object_instance, False)
|
|
196
|
+
l1.append(objs[0].id)
|
|
197
|
+
repetition = False
|
|
198
|
+
for net_list in net_groups:
|
|
199
|
+
if set(l1).intersection(net_list):
|
|
200
|
+
net_groups.append([i for i in l1 if i not in net_list])
|
|
201
|
+
repetition = True
|
|
202
|
+
if not repetition:
|
|
203
|
+
net_groups.append(l1)
|
|
204
|
+
objs = [i for i in objs if i.id not in l1]
|
|
205
|
+
l = len(objs)
|
|
206
|
+
if len(net_groups) > 1:
|
|
207
|
+
|
|
208
|
+
def area_calc(elem):
|
|
209
|
+
sum = 0
|
|
210
|
+
for el in elem:
|
|
211
|
+
try:
|
|
212
|
+
if el.layout_obj.obj_type.value == 0:
|
|
213
|
+
if not el.is_void:
|
|
214
|
+
sum += el.area()
|
|
215
|
+
except:
|
|
216
|
+
pass
|
|
217
|
+
return sum
|
|
218
|
+
|
|
219
|
+
if order_by_area:
|
|
220
|
+
areas = [area_calc(i) for i in net_groups]
|
|
221
|
+
sorted_list = [x for _, x in sorted(zip(areas, net_groups), reverse=True)]
|
|
222
|
+
else:
|
|
223
|
+
sorted_list = sorted(net_groups, key=len, reverse=True)
|
|
224
|
+
for disjoints in sorted_list[1:]:
|
|
225
|
+
if keep_only_main_net:
|
|
226
|
+
for geo in disjoints:
|
|
227
|
+
try:
|
|
228
|
+
obj_dict[geo].delete()
|
|
229
|
+
except KeyError:
|
|
230
|
+
pass
|
|
231
|
+
elif len(disjoints) == 1 and (
|
|
232
|
+
clean_disjoints_less_than
|
|
233
|
+
and "area" in dir(obj_dict[disjoints[0]])
|
|
234
|
+
and obj_dict[disjoints[0]].area() < clean_disjoints_less_than
|
|
235
|
+
):
|
|
236
|
+
try:
|
|
237
|
+
obj_dict[disjoints[0]].delete()
|
|
238
|
+
except KeyError:
|
|
239
|
+
pass
|
|
240
|
+
elif (
|
|
241
|
+
len(disjoints) == 1
|
|
242
|
+
and not keep_disjoint_pins
|
|
243
|
+
and isinstance(obj_dict[disjoints[0]], PadstackInstance)
|
|
244
|
+
):
|
|
245
|
+
try:
|
|
246
|
+
obj_dict[disjoints[0]].delete()
|
|
247
|
+
except KeyError:
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
else:
|
|
251
|
+
new_net_name = generate_unique_name(net, n=6)
|
|
252
|
+
net_obj = self._pedb.nets.find_or_create_net(new_net_name)
|
|
253
|
+
if net_obj:
|
|
254
|
+
new_nets.append(net_obj.name)
|
|
255
|
+
for geo in disjoints:
|
|
256
|
+
try:
|
|
257
|
+
obj_dict[geo].net_name = net_obj.name
|
|
258
|
+
except KeyError:
|
|
259
|
+
pass
|
|
260
|
+
disjoints_objects.extend(disjoints)
|
|
261
|
+
self._pedb._logger.info("Found {} objects in {} new nets.".format(len(disjoints_objects), len(new_nets)))
|
|
262
|
+
self._pedb._logger.info_timer("Disjoint Cleanup Completed.", timer_start)
|
|
263
|
+
|
|
264
|
+
return new_nets
|
|
263
265
|
|
|
264
266
|
def fix_self_intersections(self, net_list=None):
|
|
265
267
|
"""Find and fix self intersections from a given netlist.
|
|
@@ -274,7 +276,7 @@ class LayoutValidation:
|
|
|
274
276
|
bool
|
|
275
277
|
"""
|
|
276
278
|
if not net_list:
|
|
277
|
-
net_list = list(self._pedb.nets.keys())
|
|
279
|
+
net_list = list(self._pedb.nets.nets.keys())
|
|
278
280
|
elif isinstance(net_list, str):
|
|
279
281
|
net_list = [net_list]
|
|
280
282
|
new_prims = []
|
|
@@ -317,3 +319,22 @@ class LayoutValidation:
|
|
|
317
319
|
v.rlc_values = [0, 1, 0]
|
|
318
320
|
self._pedb._logger.info(f"Found {len(temp)} inductors have no value.")
|
|
319
321
|
return
|
|
322
|
+
|
|
323
|
+
def padstacks_no_name(self, fix=False):
|
|
324
|
+
pds = self._pedb.layout.padstack_instances
|
|
325
|
+
counts = 0
|
|
326
|
+
via_count = 1
|
|
327
|
+
for obj in pds:
|
|
328
|
+
name = obj.get_product_property(GrpcProductIdType.DESIGNER, 11)
|
|
329
|
+
name = str(name).strip("'")
|
|
330
|
+
if name == "":
|
|
331
|
+
counts += 1
|
|
332
|
+
if fix:
|
|
333
|
+
if not obj.component:
|
|
334
|
+
obj.set_product_property(GrpcProductIdType.DESIGNER, 11, f"Via{via_count}")
|
|
335
|
+
via_count = via_count + 1
|
|
336
|
+
else:
|
|
337
|
+
obj.set_product_property(
|
|
338
|
+
GrpcProductIdType.DESIGNER, 11, f"{obj.component.name}-{obj.component_pin}"
|
|
339
|
+
)
|
|
340
|
+
self._pedb._logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
|
pyedb/grpc/database/net/net.py
CHANGED
|
@@ -122,13 +122,7 @@ class Net(GrpcNet):
|
|
|
122
122
|
return self._pedb.layout_validation.dc_shorts(self.name, fix)
|
|
123
123
|
|
|
124
124
|
def plot(
|
|
125
|
-
self,
|
|
126
|
-
layers=None,
|
|
127
|
-
show_legend=True,
|
|
128
|
-
save_plot=None,
|
|
129
|
-
outline=None,
|
|
130
|
-
size=(2000, 1000),
|
|
131
|
-
show=True,
|
|
125
|
+
self, layers=None, show_legend=True, save_plot=None, outline=None, size=(2000, 1000), show=True, title=None
|
|
132
126
|
):
|
|
133
127
|
"""Plot a net to Matplotlib 2D chart.
|
|
134
128
|
|
|
@@ -147,7 +141,9 @@ class Net(GrpcNet):
|
|
|
147
141
|
size : tuple, optional
|
|
148
142
|
Image size in pixel (width, height).
|
|
149
143
|
show : bool, optional
|
|
150
|
-
Whether to show the plot or not. Default is
|
|
144
|
+
Whether to show the plot or not. Default is ``True``.
|
|
145
|
+
title : str, optional
|
|
146
|
+
Plot title. If value is ``None`` the project name is assigned by default. Default value is ``None``.
|
|
151
147
|
"""
|
|
152
148
|
|
|
153
149
|
self._pedb.nets.plot(
|
|
@@ -160,6 +156,7 @@ class Net(GrpcNet):
|
|
|
160
156
|
show=show,
|
|
161
157
|
plot_components=True,
|
|
162
158
|
plot_vias=True,
|
|
159
|
+
title=None,
|
|
163
160
|
)
|
|
164
161
|
|
|
165
162
|
def get_smallest_trace_width(self):
|