pyedb 0.27.0__py3-none-any.whl → 0.29.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.
- pyedb/__init__.py +1 -1
- pyedb/configuration/cfg_boundaries.py +44 -74
- pyedb/configuration/cfg_common.py +1 -1
- pyedb/configuration/cfg_components.py +31 -105
- pyedb/configuration/cfg_data.py +4 -9
- pyedb/configuration/cfg_operations.py +19 -13
- pyedb/configuration/cfg_padstacks.py +66 -89
- pyedb/configuration/cfg_pin_groups.py +7 -8
- pyedb/configuration/cfg_ports_sources.py +4 -2
- pyedb/configuration/cfg_s_parameter_models.py +85 -29
- pyedb/configuration/configuration.py +48 -13
- pyedb/dotnet/application/Variables.py +43 -41
- pyedb/dotnet/edb.py +12 -4
- pyedb/dotnet/edb_core/cell/hierarchy/component.py +199 -0
- pyedb/dotnet/edb_core/cell/layout.py +4 -1
- pyedb/dotnet/edb_core/cell/primitive/primitive.py +2 -0
- pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py +3 -3
- pyedb/dotnet/edb_core/cell/terminal/terminal.py +4 -3
- pyedb/dotnet/edb_core/definition/component_def.py +17 -1
- pyedb/dotnet/edb_core/definition/component_model.py +0 -4
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +3 -3
- pyedb/dotnet/edb_core/edb_data/nets_data.py +10 -7
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +301 -45
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +2 -2
- pyedb/dotnet/edb_core/general.py +11 -0
- pyedb/dotnet/edb_core/layout_validation.py +3 -3
- pyedb/dotnet/edb_core/modeler.py +5 -2
- pyedb/dotnet/edb_core/nets.py +162 -181
- pyedb/edb_logger.py +1 -1
- pyedb/siwave.py +33 -7
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/METADATA +5 -5
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/RECORD +34 -34
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/LICENSE +0 -0
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/WHEEL +0 -0
|
@@ -337,13 +337,15 @@ class CfgPort(CfgCircuitElement):
|
|
|
337
337
|
return circuit_elements
|
|
338
338
|
|
|
339
339
|
def export_properties(self):
|
|
340
|
-
|
|
340
|
+
data = {
|
|
341
341
|
"name": self.name,
|
|
342
342
|
"type": self.type,
|
|
343
343
|
"reference_designator": self.reference_designator,
|
|
344
344
|
"positive_terminal": self.positive_terminal_info.export_properties(),
|
|
345
|
-
"negative_terminal": self.negative_terminal_info.export_properties(),
|
|
346
345
|
}
|
|
346
|
+
if self.negative_terminal_info:
|
|
347
|
+
data.update({"negative_terminal": self.negative_terminal_info.export_properties()})
|
|
348
|
+
return data
|
|
347
349
|
|
|
348
350
|
|
|
349
351
|
class CfgSource(CfgCircuitElement):
|
|
@@ -24,37 +24,93 @@ from pathlib import Path
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class CfgSParameterModel:
|
|
27
|
-
def __init__(self,
|
|
28
|
-
self.
|
|
27
|
+
def __init__(self, **kwargs):
|
|
28
|
+
self.name = kwargs.get("name", "")
|
|
29
|
+
self.component_definition = kwargs.get("component_definition", "")
|
|
30
|
+
self.file_path = kwargs.get("file_path", "")
|
|
31
|
+
self.apply_to_all = kwargs.get("apply_to_all", False)
|
|
32
|
+
self.components = kwargs.get("components", [])
|
|
33
|
+
self.reference_net = kwargs.get("reference_net", "")
|
|
34
|
+
self.reference_net_per_component = kwargs.get("reference_net_per_component", {})
|
|
35
|
+
self.pin_order = kwargs.get("pin_order", None)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CfgSParameters:
|
|
39
|
+
def __init__(self, pedb, data, path_lib=None):
|
|
40
|
+
self._pedb = pedb
|
|
29
41
|
self.path_libraries = path_lib
|
|
30
|
-
self.
|
|
31
|
-
self.name = self._sparam_dict.get("name", "")
|
|
32
|
-
self.component_definition = self._sparam_dict.get("component_definition", "")
|
|
33
|
-
self.file_path = self._sparam_dict.get("file_path", "")
|
|
34
|
-
self.apply_to_all = self._sparam_dict.get("apply_to_all", False)
|
|
35
|
-
self.components = self._sparam_dict.get("components", [])
|
|
36
|
-
self.reference_net = self._sparam_dict.get("reference_net", "")
|
|
37
|
-
self.reference_net_per_component = self._sparam_dict.get("reference_net_per_component", {})
|
|
42
|
+
self.s_parameters_models = [CfgSParameterModel(**i) for i in data]
|
|
38
43
|
|
|
39
44
|
def apply(self):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
for s_param in self.s_parameters_models:
|
|
46
|
+
fpath = s_param.file_path
|
|
47
|
+
if not Path(fpath).anchor:
|
|
48
|
+
fpath = str(Path(self.path_libraries) / fpath)
|
|
49
|
+
comp_def = self._pedb.definitions.component[s_param.component_definition]
|
|
50
|
+
if s_param.pin_order:
|
|
51
|
+
comp_def.set_properties(pin_order=s_param.pin_order)
|
|
52
|
+
comp_def.add_n_port_model(fpath, s_param.name)
|
|
53
|
+
comp_list = dict()
|
|
54
|
+
if s_param.apply_to_all:
|
|
55
|
+
comp_list.update(
|
|
56
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes not in s_param.components}
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
comp_list.update(
|
|
60
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes in s_param.components}
|
|
61
|
+
)
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
for refdes, comp in comp_list.items():
|
|
64
|
+
if refdes in s_param.reference_net_per_component:
|
|
65
|
+
ref_net = s_param.reference_net_per_component[refdes]
|
|
66
|
+
else:
|
|
67
|
+
ref_net = s_param.reference_net
|
|
68
|
+
comp.use_s_parameter_model(s_param.name, reference_net=ref_net)
|
|
69
|
+
|
|
70
|
+
def get_data_from_db(self):
|
|
71
|
+
db_comp_def = self._pedb.definitions.component
|
|
72
|
+
for name, compdef_obj in db_comp_def.items():
|
|
73
|
+
nport_models = compdef_obj.component_models
|
|
74
|
+
if not nport_models:
|
|
75
|
+
continue
|
|
58
76
|
else:
|
|
59
|
-
|
|
60
|
-
|
|
77
|
+
pin_order = compdef_obj.get_properties()["pin_order"]
|
|
78
|
+
temp_comps = compdef_obj.components
|
|
79
|
+
for model_name, model_obj in nport_models.items():
|
|
80
|
+
temp_comp_list = []
|
|
81
|
+
reference_net_per_component = {}
|
|
82
|
+
for i in temp_comps.values():
|
|
83
|
+
s_param_model = i.model_properties.get("s_parameter_model")
|
|
84
|
+
if s_param_model:
|
|
85
|
+
if s_param_model["model_name"] == model_name:
|
|
86
|
+
temp_comp_list.append(i.refdes)
|
|
87
|
+
reference_net_per_component[i.refdes] = s_param_model["reference_net"]
|
|
88
|
+
else:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
self.s_parameters_models.append(
|
|
92
|
+
CfgSParameterModel(
|
|
93
|
+
name=model_name,
|
|
94
|
+
component_definition=name,
|
|
95
|
+
file_path=model_obj.reference_file,
|
|
96
|
+
apply_to_all=False,
|
|
97
|
+
components=temp_comp_list,
|
|
98
|
+
reference_net_per_component=reference_net_per_component,
|
|
99
|
+
pin_order=pin_order,
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
data = []
|
|
104
|
+
for i in self.s_parameters_models:
|
|
105
|
+
data.append(
|
|
106
|
+
{
|
|
107
|
+
"name": i.name,
|
|
108
|
+
"component_definition": i.component_definition,
|
|
109
|
+
"file_path": i.file_path,
|
|
110
|
+
"apply_to_all": i.apply_to_all,
|
|
111
|
+
"components": i.components,
|
|
112
|
+
"reference_net_per_component": i.reference_net_per_component,
|
|
113
|
+
"pin_order": i.pin_order,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
return data
|
|
@@ -74,7 +74,7 @@ class Configuration:
|
|
|
74
74
|
elif config_file.endswith(".toml"):
|
|
75
75
|
data = toml.load(f)
|
|
76
76
|
else: # pragma: no cover
|
|
77
|
-
|
|
77
|
+
raise RuntimeError(f"File {config_file} does not exist.")
|
|
78
78
|
|
|
79
79
|
if not append: # pragma: no cover
|
|
80
80
|
self.data = {}
|
|
@@ -103,7 +103,7 @@ class Configuration:
|
|
|
103
103
|
self._pedb.open_edb()
|
|
104
104
|
return self.cfg_data
|
|
105
105
|
|
|
106
|
-
def run(self):
|
|
106
|
+
def run(self, **kwargs):
|
|
107
107
|
"""Apply configuration settings to the current design"""
|
|
108
108
|
|
|
109
109
|
# Configure boundary settings
|
|
@@ -117,10 +117,6 @@ class Configuration:
|
|
|
117
117
|
# Configure components
|
|
118
118
|
self.cfg_data.components.apply()
|
|
119
119
|
|
|
120
|
-
# Configure padstacks
|
|
121
|
-
if self.cfg_data.padstacks:
|
|
122
|
-
self.cfg_data.padstacks.apply()
|
|
123
|
-
|
|
124
120
|
# Configure pin groups
|
|
125
121
|
self.cfg_data.pin_groups.apply()
|
|
126
122
|
|
|
@@ -134,11 +130,23 @@ class Configuration:
|
|
|
134
130
|
self.cfg_data.setups.apply()
|
|
135
131
|
|
|
136
132
|
# Configure stackup
|
|
137
|
-
|
|
133
|
+
if kwargs.get("fix_padstack_def"):
|
|
134
|
+
pedb_defs = self._pedb.padstacks.definitions
|
|
135
|
+
temp = {}
|
|
136
|
+
for name, pdef in pedb_defs.items():
|
|
137
|
+
temp[name] = pdef.get_properties()
|
|
138
|
+
self.cfg_data.stackup.apply()
|
|
139
|
+
for name, pdef_p in temp.items():
|
|
140
|
+
pedb_defs[name].set_properties(**pdef_p)
|
|
141
|
+
else:
|
|
142
|
+
self.cfg_data.stackup.apply()
|
|
143
|
+
|
|
144
|
+
# Configure padstacks
|
|
145
|
+
if self.cfg_data.padstacks:
|
|
146
|
+
self.cfg_data.padstacks.apply()
|
|
138
147
|
|
|
139
148
|
# Configure S-parameter
|
|
140
|
-
|
|
141
|
-
s_parameter_model.apply()
|
|
149
|
+
self.cfg_data.s_parameters.apply()
|
|
142
150
|
|
|
143
151
|
# Configure SPICE models
|
|
144
152
|
for spice_model in self.cfg_data.spice_models:
|
|
@@ -282,6 +290,12 @@ class Configuration:
|
|
|
282
290
|
data["pin_groups"] = self.cfg_data.pin_groups.get_data_from_db()
|
|
283
291
|
if kwargs.get("operations", False):
|
|
284
292
|
data["operations"] = self.cfg_data.operations.get_data_from_db()
|
|
293
|
+
if kwargs.get("padstacks", False):
|
|
294
|
+
data["padstacks"] = self.cfg_data.padstacks.get_data_from_db()
|
|
295
|
+
if kwargs.get("s_parameters", False):
|
|
296
|
+
data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db()
|
|
297
|
+
if kwargs.get("boundaries", False):
|
|
298
|
+
data["boundaries"] = self.cfg_data.boundaries.get_data_from_db()
|
|
285
299
|
|
|
286
300
|
return data
|
|
287
301
|
|
|
@@ -296,6 +310,10 @@ class Configuration:
|
|
|
296
310
|
nets=True,
|
|
297
311
|
pin_groups=True,
|
|
298
312
|
operations=True,
|
|
313
|
+
components=True,
|
|
314
|
+
boundaries=True,
|
|
315
|
+
s_parameters=True,
|
|
316
|
+
padstacks=True,
|
|
299
317
|
):
|
|
300
318
|
"""Export the configuration data from layout to a file.
|
|
301
319
|
|
|
@@ -319,22 +337,39 @@ class Configuration:
|
|
|
319
337
|
Whether to export pin groups.
|
|
320
338
|
operations : bool
|
|
321
339
|
Whether to export operations.
|
|
340
|
+
components : bool
|
|
341
|
+
Whether to export component.
|
|
342
|
+
boundaries : bool
|
|
343
|
+
Whether to export boundaries.
|
|
344
|
+
s_parameters : bool
|
|
345
|
+
Whether to export s_parameters.
|
|
346
|
+
padstacks : bool
|
|
347
|
+
Whether to export padstacks.
|
|
322
348
|
Returns
|
|
323
349
|
-------
|
|
324
350
|
bool
|
|
325
351
|
"""
|
|
326
|
-
file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
327
|
-
file_path = file_path if file_path.suffix == ".json" else file_path.with_suffix(".json")
|
|
328
352
|
data = self.get_data_from_db(
|
|
329
353
|
stackup=stackup,
|
|
330
354
|
package_definitions=package_definitions,
|
|
331
|
-
setups=
|
|
355
|
+
setups=False,
|
|
332
356
|
sources=sources,
|
|
333
357
|
ports=ports,
|
|
334
358
|
nets=nets,
|
|
335
359
|
pin_groups=pin_groups,
|
|
336
360
|
operations=operations,
|
|
361
|
+
components=components,
|
|
362
|
+
boundaries=boundaries,
|
|
363
|
+
s_parameters=s_parameters,
|
|
364
|
+
padstacks=padstacks,
|
|
337
365
|
)
|
|
366
|
+
|
|
367
|
+
file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
368
|
+
file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
|
|
369
|
+
|
|
338
370
|
with open(file_path, "w") as f:
|
|
339
|
-
|
|
371
|
+
if file_path.suffix == ".json":
|
|
372
|
+
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
373
|
+
else:
|
|
374
|
+
toml.dump(data, f)
|
|
340
375
|
return True if os.path.isfile(file_path) else False
|
|
@@ -27,7 +27,7 @@ This module is used to create and edit design and project variables in the 3D to
|
|
|
27
27
|
|
|
28
28
|
Examples
|
|
29
29
|
--------
|
|
30
|
-
>>> from
|
|
30
|
+
>>> from ansys.aedt.core import Hfss
|
|
31
31
|
>>> hfss = Hfss()
|
|
32
32
|
>>> hfss["$d"] = "5mm"
|
|
33
33
|
>>> hfss["d"] = "5mm"
|
|
@@ -415,8 +415,8 @@ class VariableManager(object):
|
|
|
415
415
|
Examples
|
|
416
416
|
--------
|
|
417
417
|
|
|
418
|
-
>>> from
|
|
419
|
-
>>> from
|
|
418
|
+
>>> from ansys.aedt.core.maxwell import Maxwell3d
|
|
419
|
+
>>> from ansys.aedt.core.desktop import Desktop
|
|
420
420
|
>>> d = Desktop()
|
|
421
421
|
>>> aedtapp = Maxwell3d()
|
|
422
422
|
|
|
@@ -1765,40 +1765,42 @@ class Variable(object):
|
|
|
1765
1765
|
def __mul__(self, other): # pragma: no cover
|
|
1766
1766
|
"""Multiply the variable with a number or another variable and return a new object.
|
|
1767
1767
|
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
import
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1768
|
+
Parameters
|
|
1769
|
+
----------
|
|
1770
|
+
other : numbers.Number or variable
|
|
1771
|
+
Object to be multiplied.
|
|
1772
|
+
|
|
1773
|
+
Returns
|
|
1774
|
+
-------
|
|
1775
|
+
type
|
|
1776
|
+
Variable.
|
|
1777
|
+
|
|
1778
|
+
Examples
|
|
1779
|
+
--------
|
|
1780
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1781
|
+
|
|
1782
|
+
Multiply ``'Length1'`` by unitless ``'None'``` to obtain ``'Length'``.
|
|
1783
|
+
A numerical value is also considered to be unitless.
|
|
1784
|
+
|
|
1785
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1786
|
+
>>> v1 = Variable("10mm")
|
|
1787
|
+
>>> v2 = Variable(3)
|
|
1788
|
+
>>> result_1 = v1 * v2
|
|
1789
|
+
>>> result_2 = v1 * 3
|
|
1790
|
+
>>> assert result_1.numeric_value == 30.0
|
|
1791
|
+
>>> assert result_1.unit_system == "Length"
|
|
1792
|
+
>>> assert result_2.numeric_value == result_1.numeric_value
|
|
1793
|
+
>>> assert result_2.unit_system == "Length"
|
|
1794
|
+
|
|
1795
|
+
Multiply voltage times current to obtain power.
|
|
1796
|
+
|
|
1797
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1798
|
+
>>> v3 = Variable("3mA")
|
|
1799
|
+
>>> v4 = Variable("40V")
|
|
1800
|
+
>>> result_3 = v3 * v4
|
|
1801
|
+
>>> assert result_3.numeric_value == 0.12
|
|
1802
|
+
>>> assert result_3.units == "W"
|
|
1803
|
+
>>> assert result_3.unit_system == "Power"
|
|
1802
1804
|
|
|
1803
1805
|
"""
|
|
1804
1806
|
assert is_number(other) or isinstance(other, Variable), "Multiplier must be a scalar quantity or a variable."
|
|
@@ -1836,7 +1838,7 @@ class Variable(object):
|
|
|
1836
1838
|
Examples
|
|
1837
1839
|
--------
|
|
1838
1840
|
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1839
|
-
>>> import
|
|
1841
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1840
1842
|
>>> v1 = Variable("3mA")
|
|
1841
1843
|
>>> v2 = Variable("10A")
|
|
1842
1844
|
>>> result = v1 + v2
|
|
@@ -1876,7 +1878,7 @@ class Variable(object):
|
|
|
1876
1878
|
Examples
|
|
1877
1879
|
--------
|
|
1878
1880
|
|
|
1879
|
-
>>> import
|
|
1881
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1880
1882
|
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1881
1883
|
>>> v3 = Variable("3mA")
|
|
1882
1884
|
>>> v4 = Variable("10A")
|
|
@@ -1922,7 +1924,7 @@ class Variable(object):
|
|
|
1922
1924
|
resolve the new units to ``"A"``.
|
|
1923
1925
|
|
|
1924
1926
|
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1925
|
-
>>> import
|
|
1927
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1926
1928
|
>>> v1 = Variable("10W")
|
|
1927
1929
|
>>> v2 = Variable("40V")
|
|
1928
1930
|
>>> result = v1 / v2
|
|
@@ -1964,7 +1966,7 @@ class Variable(object):
|
|
|
1964
1966
|
Divide a number by a variable with units ``"s"`` and automatically determine that
|
|
1965
1967
|
the result is in ``"Hz"``.
|
|
1966
1968
|
|
|
1967
|
-
>>> import
|
|
1969
|
+
>>> import ansys.aedt.core.generic.constants
|
|
1968
1970
|
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1969
1971
|
>>> v = Variable("1s")
|
|
1970
1972
|
>>> result = 3.0 / v
|
pyedb/dotnet/edb.py
CHANGED
|
@@ -1630,6 +1630,14 @@ class Edb(Database):
|
|
|
1630
1630
|
)
|
|
1631
1631
|
else:
|
|
1632
1632
|
obj_data = i.Expand(expansion_size, tolerance, round_corner, round_extension)
|
|
1633
|
+
if inlcude_voids_in_extents and "PolygonData" not in str(i) and i.has_voids and obj_data:
|
|
1634
|
+
for void in i.voids:
|
|
1635
|
+
void_data = void.primitive_object.GetPolygonData().Expand(
|
|
1636
|
+
-1 * expansion_size, tolerance, round_corner, round_extension
|
|
1637
|
+
)
|
|
1638
|
+
if void_data:
|
|
1639
|
+
for v in list(void_data):
|
|
1640
|
+
obj_data[0].AddHole(v)
|
|
1633
1641
|
if obj_data:
|
|
1634
1642
|
if not inlcude_voids_in_extents:
|
|
1635
1643
|
unite_polys.extend(list(obj_data))
|
|
@@ -2209,9 +2217,9 @@ class Edb(Database):
|
|
|
2209
2217
|
pins_to_preserve.extend([i.id for i in el.pins.values()])
|
|
2210
2218
|
nets_to_preserve.extend(el.nets)
|
|
2211
2219
|
if include_pingroups:
|
|
2212
|
-
for
|
|
2213
|
-
for pin in
|
|
2214
|
-
if pin.
|
|
2220
|
+
for pingroup in self.padstacks.pingroups:
|
|
2221
|
+
for pin in pingroup.pins.values():
|
|
2222
|
+
if pin.net_name in reference_list:
|
|
2215
2223
|
pins_to_preserve.append(pin.id)
|
|
2216
2224
|
if check_terminals:
|
|
2217
2225
|
terms = [
|
|
@@ -2280,12 +2288,12 @@ class Edb(Database):
|
|
|
2280
2288
|
if extent_type in ["Conforming", self.edb_api.geometry.extent_type.Conforming, 1]:
|
|
2281
2289
|
if extent_defeature > 0:
|
|
2282
2290
|
_poly = _poly.Defeature(extent_defeature)
|
|
2283
|
-
|
|
2284
2291
|
_poly1 = _poly.CreateFromArcs(_poly.GetArcData(), True)
|
|
2285
2292
|
if inlcude_voids_in_extents:
|
|
2286
2293
|
for hole in list(_poly.Holes):
|
|
2287
2294
|
if hole.Area() >= 0.05 * _poly1.Area():
|
|
2288
2295
|
_poly1.AddHole(hole)
|
|
2296
|
+
self.logger.info(f"Number of voids included:{len(list(_poly1.Holes))}")
|
|
2289
2297
|
_poly = _poly1
|
|
2290
2298
|
if not _poly or _poly.IsNull():
|
|
2291
2299
|
self._logger.error("Failed to create Extent.")
|
|
@@ -33,6 +33,7 @@ from pyedb.dotnet.edb_core.cell.hierarchy.s_parameter_model import SparamModel
|
|
|
33
33
|
from pyedb.dotnet.edb_core.cell.hierarchy.spice_model import SpiceModel
|
|
34
34
|
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
|
|
35
35
|
from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstackInstance
|
|
36
|
+
from pyedb.dotnet.edb_core.general import pascal_to_snake, snake_to_pascal
|
|
36
37
|
|
|
37
38
|
try:
|
|
38
39
|
import numpy as np
|
|
@@ -1008,3 +1009,201 @@ class EDBComponent(Group):
|
|
|
1008
1009
|
)
|
|
1009
1010
|
void.is_negative = True
|
|
1010
1011
|
return True
|
|
1012
|
+
|
|
1013
|
+
@property
|
|
1014
|
+
def model_properties(self):
|
|
1015
|
+
pp = {}
|
|
1016
|
+
c_p = self.component_property
|
|
1017
|
+
model = c_p.GetModel().Clone()
|
|
1018
|
+
netlist_model = {}
|
|
1019
|
+
pin_pair_model = []
|
|
1020
|
+
s_parameter_model = {}
|
|
1021
|
+
spice_model = {}
|
|
1022
|
+
if model.GetModelType().ToString() == "NetlistModel":
|
|
1023
|
+
netlist_model["netlist"] = model.GetNetlist()
|
|
1024
|
+
elif model.GetModelType().ToString() == "PinPairModel":
|
|
1025
|
+
temp = {}
|
|
1026
|
+
for i in model.PinPairs:
|
|
1027
|
+
temp["first_pin"] = i.FirstPin
|
|
1028
|
+
temp["second_pin"] = i.SecondPin
|
|
1029
|
+
rlc = model.GetPinPairRlc(i)
|
|
1030
|
+
temp["is_parallel"] = rlc.IsParallel
|
|
1031
|
+
temp["resistance"] = rlc.R.ToString()
|
|
1032
|
+
temp["resistance_enabled"] = rlc.REnabled
|
|
1033
|
+
temp["inductance"] = rlc.L.ToString()
|
|
1034
|
+
temp["inductance_enabled"] = rlc.LEnabled
|
|
1035
|
+
temp["capacitance"] = rlc.C.ToString()
|
|
1036
|
+
temp["capacitance_enabled"] = rlc.CEnabled
|
|
1037
|
+
pin_pair_model.append(temp)
|
|
1038
|
+
elif model.GetModelType().ToString() == "SParameterModel":
|
|
1039
|
+
s_parameter_model["reference_net"] = model.GetReferenceNet()
|
|
1040
|
+
s_parameter_model["model_name"] = model.GetComponentModelName()
|
|
1041
|
+
elif model.GetModelType().ToString() == "SPICEModel":
|
|
1042
|
+
spice_model["model_name"] = model.GetModelName()
|
|
1043
|
+
spice_model["model_path"] = model.GetModelPath()
|
|
1044
|
+
spice_model["sub_circuit"] = model.GetSubCkt()
|
|
1045
|
+
spice_model["terminal_pairs"] = [[i, j] for i, j in dict(model.GetTerminalPinPairs()).items()]
|
|
1046
|
+
|
|
1047
|
+
if netlist_model:
|
|
1048
|
+
pp["netlist_model"] = netlist_model
|
|
1049
|
+
if pin_pair_model:
|
|
1050
|
+
pp["pin_pair_model"] = pin_pair_model
|
|
1051
|
+
if s_parameter_model:
|
|
1052
|
+
pp["s_parameter_model"] = s_parameter_model
|
|
1053
|
+
if spice_model:
|
|
1054
|
+
pp["spice_model"] = spice_model
|
|
1055
|
+
return pp
|
|
1056
|
+
|
|
1057
|
+
@model_properties.setter
|
|
1058
|
+
def model_properties(self, kwargs):
|
|
1059
|
+
netlist_model = kwargs.get("netlist_model")
|
|
1060
|
+
pin_pair_model = kwargs.get("pin_pair_model")
|
|
1061
|
+
s_parameter_model = kwargs.get("s_parameter_model")
|
|
1062
|
+
spice_model = kwargs.get("spice_model")
|
|
1063
|
+
|
|
1064
|
+
c_p = self.component_property
|
|
1065
|
+
if netlist_model:
|
|
1066
|
+
m = self._pedb._edb.Cell.Hierarchy.SParameterModel()
|
|
1067
|
+
m.SetNetlist(netlist_model["netlist"])
|
|
1068
|
+
c_p.SetModel(m)
|
|
1069
|
+
self.component_property = c_p
|
|
1070
|
+
elif pin_pair_model:
|
|
1071
|
+
m = self._pedb._edb.Cell.Hierarchy.PinPairModel()
|
|
1072
|
+
for i in pin_pair_model:
|
|
1073
|
+
p = self._pedb._edb.Utility.PinPair(str(i["first_pin"]), str(i["second_pin"]))
|
|
1074
|
+
rlc = self._pedb._edb.Utility.Rlc(
|
|
1075
|
+
self._pedb.edb_value(i["resistance"]),
|
|
1076
|
+
i["resistance_enabled"],
|
|
1077
|
+
self._pedb.edb_value(i["inductance"]),
|
|
1078
|
+
i["inductance_enabled"],
|
|
1079
|
+
self._pedb.edb_value(i["capacitance"]),
|
|
1080
|
+
i["capacitance_enabled"],
|
|
1081
|
+
i["is_parallel"],
|
|
1082
|
+
)
|
|
1083
|
+
m.SetPinPairRlc(p, rlc)
|
|
1084
|
+
c_p.SetModel(m)
|
|
1085
|
+
self.component_property = c_p
|
|
1086
|
+
elif s_parameter_model:
|
|
1087
|
+
m = self._pedb._edb.Cell.Hierarchy.SParameterModel()
|
|
1088
|
+
m.SetComponentModelName(s_parameter_model["model_name"])
|
|
1089
|
+
m.SetReferenceNet(s_parameter_model["reference_net"])
|
|
1090
|
+
c_p.SetModel(m)
|
|
1091
|
+
self.component_property = c_p
|
|
1092
|
+
elif spice_model:
|
|
1093
|
+
self.assign_spice_model(
|
|
1094
|
+
spice_model["model_path"],
|
|
1095
|
+
spice_model["model_name"],
|
|
1096
|
+
spice_model["sub_circuit"],
|
|
1097
|
+
spice_model["terminal_pairs"],
|
|
1098
|
+
)
|
|
1099
|
+
|
|
1100
|
+
@property
|
|
1101
|
+
def ic_die_properties(self):
|
|
1102
|
+
temp = dict()
|
|
1103
|
+
cp = self.component_property
|
|
1104
|
+
c_type = self.type.lower()
|
|
1105
|
+
if not c_type == "ic":
|
|
1106
|
+
return temp
|
|
1107
|
+
else:
|
|
1108
|
+
ic_die_prop = cp.GetDieProperty().Clone()
|
|
1109
|
+
die_type = pascal_to_snake(ic_die_prop.GetType().ToString())
|
|
1110
|
+
temp["type"] = die_type
|
|
1111
|
+
if not die_type == "no_die":
|
|
1112
|
+
temp["orientation"] = pascal_to_snake(ic_die_prop.GetOrientation())
|
|
1113
|
+
if die_type == "wire_bond":
|
|
1114
|
+
temp["height"] = ic_die_prop.GetHeightValue().ToString()
|
|
1115
|
+
return temp
|
|
1116
|
+
|
|
1117
|
+
@ic_die_properties.setter
|
|
1118
|
+
def ic_die_properties(self, kwargs):
|
|
1119
|
+
cp = self.component_property
|
|
1120
|
+
c_type = self.type.lower()
|
|
1121
|
+
if not c_type == "ic":
|
|
1122
|
+
return
|
|
1123
|
+
else:
|
|
1124
|
+
ic_die_prop = cp.GetDieProperty().Clone()
|
|
1125
|
+
die_type = kwargs.get("type")
|
|
1126
|
+
if not die_type == "no_die":
|
|
1127
|
+
orientation = kwargs.get("orientation")
|
|
1128
|
+
if orientation:
|
|
1129
|
+
ic_die_prop.SetOrientation(getattr(self._edb.definition.DieType, snake_to_pascal(die_type)))
|
|
1130
|
+
if die_type == "wire_bond":
|
|
1131
|
+
height = kwargs.get("height")
|
|
1132
|
+
if height:
|
|
1133
|
+
ic_die_prop.SetHeight(self._pedb.edb_value(height))
|
|
1134
|
+
cp.SetDieProperty(ic_die_prop)
|
|
1135
|
+
self.component_property = cp
|
|
1136
|
+
|
|
1137
|
+
@property
|
|
1138
|
+
def solder_ball_properties(self):
|
|
1139
|
+
temp = dict()
|
|
1140
|
+
cp = self.component_property
|
|
1141
|
+
c_type = self.type.lower()
|
|
1142
|
+
if c_type not in ["io", "other"]:
|
|
1143
|
+
return temp
|
|
1144
|
+
else:
|
|
1145
|
+
solder_ball_prop = cp.GetSolderBallProperty().Clone()
|
|
1146
|
+
_, diam, mid_diam = solder_ball_prop.GetDiameterValue()
|
|
1147
|
+
height = solder_ball_prop.GetHeightValue().ToString()
|
|
1148
|
+
shape = solder_ball_prop.GetShape().ToString()
|
|
1149
|
+
uses_solder_ball = solder_ball_prop.UsesSolderball()
|
|
1150
|
+
temp["uses_solder_ball"] = uses_solder_ball
|
|
1151
|
+
temp["shape"] = pascal_to_snake(shape)
|
|
1152
|
+
temp["diameter"] = diam.ToString()
|
|
1153
|
+
temp["mid_diameter"] = mid_diam.ToString()
|
|
1154
|
+
temp["height"] = height
|
|
1155
|
+
return temp
|
|
1156
|
+
|
|
1157
|
+
@solder_ball_properties.setter
|
|
1158
|
+
def solder_ball_properties(self, kwargs):
|
|
1159
|
+
cp = self.component_property
|
|
1160
|
+
solder_ball_prop = cp.GetSolderBallProperty().Clone()
|
|
1161
|
+
shape = kwargs.get("shape")
|
|
1162
|
+
if shape:
|
|
1163
|
+
solder_ball_prop.SetShape(getattr(self._edb.definition.SolderballShape, snake_to_pascal(shape)))
|
|
1164
|
+
if shape == "cylinder":
|
|
1165
|
+
diameter = kwargs["diameter"]
|
|
1166
|
+
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(diameter))
|
|
1167
|
+
elif shape == "spheroid":
|
|
1168
|
+
diameter = kwargs["diameter"]
|
|
1169
|
+
mid_diameter = kwargs["mid_diameter"]
|
|
1170
|
+
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(mid_diameter))
|
|
1171
|
+
else:
|
|
1172
|
+
return
|
|
1173
|
+
solder_ball_prop.SetHeight(self._get_edb_value(kwargs["height"]))
|
|
1174
|
+
cp.SetSolderBallProperty(solder_ball_prop)
|
|
1175
|
+
self.component_property = cp
|
|
1176
|
+
|
|
1177
|
+
@property
|
|
1178
|
+
def port_properties(self):
|
|
1179
|
+
temp = dict()
|
|
1180
|
+
cp = self.component_property
|
|
1181
|
+
c_type = self.type.lower()
|
|
1182
|
+
if c_type not in ["ic", "io", "other"]:
|
|
1183
|
+
return temp
|
|
1184
|
+
else:
|
|
1185
|
+
port_prop = cp.GetPortProperty().Clone()
|
|
1186
|
+
reference_height = port_prop.GetReferenceHeightValue().ToString()
|
|
1187
|
+
reference_size_auto = port_prop.GetReferenceSizeAuto()
|
|
1188
|
+
_, reference_size_x, reference_size_y = port_prop.GetReferenceSize()
|
|
1189
|
+
temp["reference_height"] = reference_height
|
|
1190
|
+
temp["reference_size_auto"] = reference_size_auto
|
|
1191
|
+
temp["reference_size_x"] = str(reference_size_x)
|
|
1192
|
+
temp["reference_size_y"] = str(reference_size_y)
|
|
1193
|
+
return temp
|
|
1194
|
+
|
|
1195
|
+
@port_properties.setter
|
|
1196
|
+
def port_properties(self, kwargs):
|
|
1197
|
+
cp = self.component_property
|
|
1198
|
+
port_prop = cp.GetPortProperty().Clone()
|
|
1199
|
+
height = kwargs.get("reference_height")
|
|
1200
|
+
if height:
|
|
1201
|
+
port_prop.SetReferenceHeight(self._pedb.edb_value(height))
|
|
1202
|
+
reference_size_auto = kwargs.get("reference_size_auto")
|
|
1203
|
+
if reference_size_auto:
|
|
1204
|
+
port_prop.SetReferenceSizeAuto(reference_size_auto)
|
|
1205
|
+
reference_size_x = kwargs.get("reference_size_x", 0)
|
|
1206
|
+
reference_size_y = kwargs.get("reference_size_y", 0)
|
|
1207
|
+
port_prop.SetReferenceSize(self._pedb.edb_value(reference_size_x), self._pedb.edb_value(reference_size_y))
|
|
1208
|
+
cp.SetPortProperty(port_prop)
|
|
1209
|
+
self.component_property = cp
|
|
@@ -323,7 +323,10 @@ class Layout(ObjBase):
|
|
|
323
323
|
|
|
324
324
|
"""
|
|
325
325
|
obj = self._pedb._edb.Cell.Net.FindByName(self._edb_object, value)
|
|
326
|
-
|
|
326
|
+
if obj.IsNull():
|
|
327
|
+
raise ValueError(f"Net {value} doesn't exist")
|
|
328
|
+
else:
|
|
329
|
+
return EDBNetsData(obj, self._pedb)
|
|
327
330
|
|
|
328
331
|
def find_component_by_name(self, value: str):
|
|
329
332
|
"""Find a component object by name. Component name is the reference designator in layout.
|