pyedb 0.31.0__py3-none-any.whl → 0.34.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 -27
- pyedb/common/__init__.py +0 -0
- pyedb/common/nets.py +488 -0
- pyedb/configuration/cfg_common.py +20 -0
- pyedb/configuration/cfg_components.py +218 -57
- pyedb/configuration/cfg_data.py +6 -0
- pyedb/configuration/cfg_modeler.py +139 -0
- pyedb/configuration/cfg_operations.py +5 -4
- pyedb/configuration/cfg_padstacks.py +319 -55
- pyedb/configuration/cfg_ports_sources.py +99 -7
- pyedb/configuration/cfg_s_parameter_models.py +6 -6
- pyedb/configuration/configuration.py +31 -9
- pyedb/dotnet/clr_module.py +92 -32
- pyedb/dotnet/edb.py +54 -5
- pyedb/dotnet/edb_core/cell/hierarchy/component.py +0 -202
- pyedb/dotnet/edb_core/cell/layout.py +1 -1
- pyedb/dotnet/edb_core/cell/primitive/primitive.py +5 -27
- pyedb/dotnet/edb_core/edb_data/control_file.py +21 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +6 -1
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +16 -222
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +31 -0
- pyedb/dotnet/edb_core/hfss.py +2 -2
- pyedb/dotnet/edb_core/layout_validation.py +1 -3
- pyedb/dotnet/edb_core/materials.py +38 -38
- pyedb/dotnet/edb_core/modeler.py +4 -1
- pyedb/dotnet/edb_core/nets.py +2 -373
- pyedb/generic/filesystem.py +2 -5
- {pyedb-0.31.0.dist-info → pyedb-0.34.0.dist-info}/METADATA +12 -9
- {pyedb-0.31.0.dist-info → pyedb-0.34.0.dist-info}/RECORD +31 -28
- {pyedb-0.31.0.dist-info → pyedb-0.34.0.dist-info}/WHEEL +1 -1
- {pyedb-0.31.0.dist-info → pyedb-0.34.0.dist-info}/LICENSE +0 -0
|
@@ -106,6 +106,9 @@ class Configuration:
|
|
|
106
106
|
def run(self, **kwargs):
|
|
107
107
|
"""Apply configuration settings to the current design"""
|
|
108
108
|
|
|
109
|
+
if self.cfg_data.variables:
|
|
110
|
+
self.cfg_data.variables.apply()
|
|
111
|
+
|
|
109
112
|
if self.cfg_data.general:
|
|
110
113
|
self.cfg_data.general.apply()
|
|
111
114
|
|
|
@@ -123,9 +126,6 @@ class Configuration:
|
|
|
123
126
|
# Configure pin groups
|
|
124
127
|
self.cfg_data.pin_groups.apply()
|
|
125
128
|
|
|
126
|
-
# Configure ports
|
|
127
|
-
self.cfg_data.ports.apply()
|
|
128
|
-
|
|
129
129
|
# Configure sources
|
|
130
130
|
self.cfg_data.sources.apply()
|
|
131
131
|
|
|
@@ -161,6 +161,12 @@ class Configuration:
|
|
|
161
161
|
# Configure operations
|
|
162
162
|
self.cfg_data.operations.apply()
|
|
163
163
|
|
|
164
|
+
# Modeler
|
|
165
|
+
self.cfg_data.modeler.apply()
|
|
166
|
+
|
|
167
|
+
# Configure ports
|
|
168
|
+
self.cfg_data.ports.apply()
|
|
169
|
+
|
|
164
170
|
return True
|
|
165
171
|
|
|
166
172
|
def _load_stackup(self):
|
|
@@ -287,8 +293,16 @@ class Configuration:
|
|
|
287
293
|
data["sources"] = self.cfg_data.sources.get_data_from_db()
|
|
288
294
|
if kwargs.get("ports", False):
|
|
289
295
|
data["ports"] = self.cfg_data.ports.get_data_from_db()
|
|
290
|
-
if kwargs.get("components", False):
|
|
291
|
-
|
|
296
|
+
if kwargs.get("components", False) or kwargs.get("s_parameters", False):
|
|
297
|
+
self.cfg_data.components.retrieve_parameters_from_edb()
|
|
298
|
+
components = []
|
|
299
|
+
for i in self.cfg_data.components.components:
|
|
300
|
+
components.append(i.get_attributes())
|
|
301
|
+
|
|
302
|
+
if kwargs.get("components", False):
|
|
303
|
+
data["components"] = components
|
|
304
|
+
elif kwargs.get("s_parameters", False):
|
|
305
|
+
data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db(components)
|
|
292
306
|
if kwargs.get("nets", False):
|
|
293
307
|
data["nets"] = self.cfg_data.nets.get_data_from_db()
|
|
294
308
|
if kwargs.get("pin_groups", False):
|
|
@@ -296,9 +310,17 @@ class Configuration:
|
|
|
296
310
|
if kwargs.get("operations", False):
|
|
297
311
|
data["operations"] = self.cfg_data.operations.get_data_from_db()
|
|
298
312
|
if kwargs.get("padstacks", False):
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
313
|
+
self.cfg_data.padstacks.retrieve_parameters_from_edb()
|
|
314
|
+
definitions = []
|
|
315
|
+
for i in self.cfg_data.padstacks.definitions:
|
|
316
|
+
definitions.append(i.get_attributes())
|
|
317
|
+
instances = []
|
|
318
|
+
for i in self.cfg_data.padstacks.instances:
|
|
319
|
+
instances.append(i.get_attributes())
|
|
320
|
+
data["padstacks"] = dict()
|
|
321
|
+
data["padstacks"]["definitions"] = definitions
|
|
322
|
+
data["padstacks"]["instances"] = instances
|
|
323
|
+
|
|
302
324
|
if kwargs.get("boundaries", False):
|
|
303
325
|
data["boundaries"] = self.cfg_data.boundaries.get_data_from_db()
|
|
304
326
|
|
|
@@ -308,7 +330,7 @@ class Configuration:
|
|
|
308
330
|
self,
|
|
309
331
|
file_path,
|
|
310
332
|
stackup=True,
|
|
311
|
-
package_definitions=
|
|
333
|
+
package_definitions=False,
|
|
312
334
|
setups=True,
|
|
313
335
|
sources=True,
|
|
314
336
|
ports=True,
|
pyedb/dotnet/clr_module.py
CHANGED
|
@@ -1,68 +1,125 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
import pkgutil
|
|
4
|
+
import shutil
|
|
3
5
|
import sys
|
|
4
6
|
import warnings
|
|
5
7
|
|
|
8
|
+
import pyedb
|
|
9
|
+
|
|
10
|
+
LINUX_WARNING = (
|
|
11
|
+
"Due to compatibility issues between .NET Core and libssl on some Linux versions, "
|
|
12
|
+
"for example Ubuntu 22.04, we are going to stop depending on `dotnetcore2`."
|
|
13
|
+
"Instead of using this package which embeds .NET Core 3, users will be required to "
|
|
14
|
+
"install .NET themselves. For more information, see "
|
|
15
|
+
"https://edb.docs.pyansys.com/version/stable/build_breaking_change.html"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
existing_showwarning = warnings.showwarning
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def custom_show_warning(message, category, filename, lineno, file=None, line=None):
|
|
22
|
+
"""Custom warning used to remove <stdin>:loc: pattern."""
|
|
23
|
+
print(f"{category.__name__}: {message}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
warnings.showwarning = custom_show_warning
|
|
27
|
+
|
|
6
28
|
modules = [tup[1] for tup in pkgutil.iter_modules()]
|
|
7
29
|
cpython = "IronPython" not in sys.version and ".NETFramework" not in sys.version
|
|
8
30
|
is_linux = os.name == "posix"
|
|
9
31
|
is_windows = not is_linux
|
|
10
32
|
is_clr = False
|
|
33
|
+
pyedb_path = Path(pyedb.__file__).parent
|
|
34
|
+
sys.path.append(str(pyedb_path / "dlls" / "PDFReport"))
|
|
11
35
|
|
|
12
|
-
try:
|
|
13
|
-
import pyedb
|
|
14
36
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
37
|
+
def find_dotnet_root() -> Path:
|
|
38
|
+
"""Find dotnet root path."""
|
|
39
|
+
dotnet_path = shutil.which("dotnet")
|
|
40
|
+
if not dotnet_path:
|
|
41
|
+
raise FileNotFoundError("The 'dotnet' executable was not found in the PATH.")
|
|
20
42
|
|
|
21
|
-
|
|
43
|
+
dotnet_path = Path(dotnet_path).resolve()
|
|
44
|
+
dotnet_root = dotnet_path.parent
|
|
45
|
+
return dotnet_root
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def find_runtime_config(dotnet_root: Path) -> Path:
|
|
49
|
+
"""Find dotnet runtime configuration file path."""
|
|
50
|
+
sdk_path = dotnet_root / "sdk"
|
|
51
|
+
if not sdk_path.is_dir():
|
|
52
|
+
raise EnvironmentError(f"The 'sdk' directory could not be found in: {dotnet_root}")
|
|
53
|
+
sdk_versions = sorted(sdk_path.iterdir(), key=lambda x: x.name, reverse=True)
|
|
54
|
+
if not sdk_versions:
|
|
55
|
+
raise FileNotFoundError("No SDK versions were found.")
|
|
56
|
+
runtime_config = sdk_versions[0] / "dotnet.runtimeconfig.json"
|
|
57
|
+
if not runtime_config.is_file():
|
|
58
|
+
raise FileNotFoundError(f"The configuration file '{runtime_config}' does not exist.")
|
|
59
|
+
return runtime_config
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if is_linux: # pragma: no cover
|
|
63
|
+
from pythonnet import load
|
|
64
|
+
|
|
65
|
+
# Use system DOTNET core runtime
|
|
22
66
|
try:
|
|
67
|
+
from clr_loader import get_coreclr
|
|
68
|
+
|
|
69
|
+
runtime = get_coreclr()
|
|
70
|
+
load(runtime)
|
|
71
|
+
is_clr = True
|
|
72
|
+
# Define DOTNET root and runtime config file to load DOTNET core runtime
|
|
73
|
+
except Exception:
|
|
23
74
|
if os.environ.get("DOTNET_ROOT") is None:
|
|
24
|
-
runtime = None
|
|
25
75
|
try:
|
|
26
|
-
|
|
76
|
+
dotnet_root = find_dotnet_root()
|
|
77
|
+
runtime_config = find_runtime_config(dotnet_root)
|
|
78
|
+
except Exception:
|
|
79
|
+
warnings.warn(
|
|
80
|
+
"Unable to set DOTNET root and locate the runtime configuration file. "
|
|
81
|
+
"Falling back to using dotnetcore2."
|
|
82
|
+
)
|
|
83
|
+
warnings.warn(LINUX_WARNING)
|
|
27
84
|
|
|
28
|
-
runtime = os.path.join(os.path.dirname(dotnet.__path__))
|
|
29
|
-
except:
|
|
30
85
|
import dotnetcore2
|
|
31
86
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
87
|
+
dotnet_root = Path(dotnetcore2.__file__).parent / "bin"
|
|
88
|
+
runtime_config = pyedb_path / "misc" / "pyedb.runtimeconfig.json"
|
|
89
|
+
else:
|
|
90
|
+
dotnet_root = Path(os.environ["DOTNET_ROOT"])
|
|
91
|
+
try:
|
|
92
|
+
runtime_config = find_runtime_config(dotnet_root)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
"Configuration file could not be found from DOTNET_ROOT. "
|
|
96
|
+
"Please ensure that .NET SDK is correctly installed or "
|
|
97
|
+
"that DOTNET_ROOT is correctly set."
|
|
98
|
+
)
|
|
99
|
+
try:
|
|
100
|
+
load("coreclr", runtime_config=str(runtime_config), dotnet_root=str(dotnet_root))
|
|
42
101
|
if "mono" not in os.getenv("LD_LIBRARY_PATH", ""):
|
|
43
102
|
warnings.warn("LD_LIBRARY_PATH needs to be setup to use pyedb.")
|
|
44
|
-
warnings.warn("export
|
|
103
|
+
warnings.warn("export ANSYSEM_ROOT242=/path/to/AnsysEM/v242/Linux64")
|
|
45
104
|
msg = "export LD_LIBRARY_PATH="
|
|
46
|
-
msg += "$
|
|
105
|
+
msg += "$ANSYSEM_ROOT242/common/mono/Linux64/lib64:$LD_LIBRARY_PATH"
|
|
47
106
|
msg += (
|
|
48
|
-
"If PyEDB
|
|
107
|
+
"If PyEDB is used with AEDT<2023.2 then /path/to/AnsysEM/v2XY/Linux64/Delcross "
|
|
108
|
+
"should be added to LD_LIBRARY_PATH."
|
|
49
109
|
)
|
|
50
110
|
warnings.warn(msg)
|
|
51
111
|
is_clr = True
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
msg = "pythonnet or dotnetcore not installed. Pyedb will work only in client mode."
|
|
56
|
-
warnings.warn(msg)
|
|
112
|
+
except ImportError:
|
|
113
|
+
msg = "pythonnet or dotnetcore not installed. Pyedb will work only in client mode."
|
|
114
|
+
warnings.warn(msg)
|
|
57
115
|
else:
|
|
58
116
|
try:
|
|
59
117
|
from pythonnet import load
|
|
60
118
|
|
|
61
119
|
load("coreclr")
|
|
62
120
|
is_clr = True
|
|
63
|
-
|
|
64
121
|
except:
|
|
65
|
-
|
|
122
|
+
warnings.warn("Unable to load DOTNET core runtime")
|
|
66
123
|
|
|
67
124
|
|
|
68
125
|
try: # work around a number formatting bug in the EDB API for non-English locales
|
|
@@ -93,6 +150,7 @@ except ImportError: # pragma: no cover
|
|
|
93
150
|
Dictionary = None
|
|
94
151
|
Array = None
|
|
95
152
|
edb_initialized = False
|
|
153
|
+
|
|
96
154
|
if "win32com" in modules:
|
|
97
155
|
try:
|
|
98
156
|
import win32com.client as win32_client
|
|
@@ -101,3 +159,5 @@ if "win32com" in modules:
|
|
|
101
159
|
import win32com.client as win32_client
|
|
102
160
|
except ImportError:
|
|
103
161
|
win32_client = None
|
|
162
|
+
|
|
163
|
+
warnings.showwarning = existing_showwarning
|
pyedb/dotnet/edb.py
CHANGED
|
@@ -95,7 +95,7 @@ from pyedb.dotnet.edb_core.utilities.siwave_simulation_setup import (
|
|
|
95
95
|
SiwaveDCSimulationSetup,
|
|
96
96
|
SiwaveSimulationSetup,
|
|
97
97
|
)
|
|
98
|
-
from pyedb.generic.constants import AEDT_UNITS, SolverType
|
|
98
|
+
from pyedb.generic.constants import AEDT_UNITS, SolverType, unit_converter
|
|
99
99
|
from pyedb.generic.general_methods import (
|
|
100
100
|
generate_unique_name,
|
|
101
101
|
get_string_version,
|
|
@@ -3180,7 +3180,7 @@ class Edb(Database):
|
|
|
3180
3180
|
self.logger.info("Variable %s doesn't exists.", variable_name)
|
|
3181
3181
|
return None
|
|
3182
3182
|
|
|
3183
|
-
def add_project_variable(self, variable_name, variable_value):
|
|
3183
|
+
def add_project_variable(self, variable_name, variable_value, description=""):
|
|
3184
3184
|
"""Add a variable to edb database (project). The variable will have the prefix `$`.
|
|
3185
3185
|
|
|
3186
3186
|
..note::
|
|
@@ -3192,6 +3192,8 @@ class Edb(Database):
|
|
|
3192
3192
|
Name of the variable. Name can be provided without ``$`` prefix.
|
|
3193
3193
|
variable_value : str, float
|
|
3194
3194
|
Value of the variable with units.
|
|
3195
|
+
description : str, optional
|
|
3196
|
+
Description of the variable.
|
|
3195
3197
|
|
|
3196
3198
|
Returns
|
|
3197
3199
|
-------
|
|
@@ -3210,9 +3212,11 @@ class Edb(Database):
|
|
|
3210
3212
|
"""
|
|
3211
3213
|
if not variable_name.startswith("$"):
|
|
3212
3214
|
variable_name = "${}".format(variable_name)
|
|
3213
|
-
return self.add_design_variable(
|
|
3215
|
+
return self.add_design_variable(
|
|
3216
|
+
variable_name=variable_name, variable_value=variable_value, description=description
|
|
3217
|
+
)
|
|
3214
3218
|
|
|
3215
|
-
def add_design_variable(self, variable_name, variable_value, is_parameter=False):
|
|
3219
|
+
def add_design_variable(self, variable_name, variable_value, is_parameter=False, description=""):
|
|
3216
3220
|
"""Add a variable to edb. The variable can be a design one or a project variable (using ``$`` prefix).
|
|
3217
3221
|
|
|
3218
3222
|
..note::
|
|
@@ -3228,7 +3232,8 @@ class Edb(Database):
|
|
|
3228
3232
|
is_parameter : bool, optional
|
|
3229
3233
|
Whether to add the variable as a local variable. The default is ``False``.
|
|
3230
3234
|
When ``True``, the variable is added as a parameter default.
|
|
3231
|
-
|
|
3235
|
+
description : str, optional
|
|
3236
|
+
Description of the variable.
|
|
3232
3237
|
Returns
|
|
3233
3238
|
-------
|
|
3234
3239
|
tuple
|
|
@@ -3250,6 +3255,8 @@ class Edb(Database):
|
|
|
3250
3255
|
var_server = self.variable_exists(variable_name)
|
|
3251
3256
|
if not var_server[0]:
|
|
3252
3257
|
var_server[1].AddVariable(variable_name, self.edb_value(variable_value), is_parameter)
|
|
3258
|
+
if description:
|
|
3259
|
+
var_server[1].SetVariableDescription(variable_name, description)
|
|
3253
3260
|
return True, var_server[1]
|
|
3254
3261
|
self.logger.error("Variable %s already exists.", variable_name)
|
|
3255
3262
|
return False, var_server[1]
|
|
@@ -4598,3 +4605,45 @@ class Edb(Database):
|
|
|
4598
4605
|
def workflow(self):
|
|
4599
4606
|
"""Workflow class."""
|
|
4600
4607
|
return Workflow(self)
|
|
4608
|
+
|
|
4609
|
+
def export_gds_comp_xml(self, comps_to_export, gds_comps_unit="mm", control_path=None):
|
|
4610
|
+
"""Exports an XML file with selected components information for use in a GDS import.
|
|
4611
|
+
|
|
4612
|
+
Parameters
|
|
4613
|
+
----------
|
|
4614
|
+
comps_to_export : list
|
|
4615
|
+
List of components whose information will be exported to xml file.
|
|
4616
|
+
gds_comps_unit : str, optional
|
|
4617
|
+
GDS_COMPONENTS section units. Default is ``"mm"``.
|
|
4618
|
+
control_path : str, optional
|
|
4619
|
+
Path for outputting the XML file.
|
|
4620
|
+
|
|
4621
|
+
Returns
|
|
4622
|
+
-------
|
|
4623
|
+
bool
|
|
4624
|
+
``True`` when successful, ``False`` when failed.
|
|
4625
|
+
"""
|
|
4626
|
+
from pyedb.generic.general_methods import ET
|
|
4627
|
+
|
|
4628
|
+
components = ET.Element("GDS_COMPONENTS")
|
|
4629
|
+
components.set("LengthUnit", gds_comps_unit)
|
|
4630
|
+
if not comps_to_export:
|
|
4631
|
+
comps_to_export = self.components.components
|
|
4632
|
+
for comp in comps_to_export:
|
|
4633
|
+
ocomp = self.components.components[comp]
|
|
4634
|
+
gds_component = ET.SubElement(components, "GDS_COMPONENT")
|
|
4635
|
+
for pin_name, pin in ocomp.pins.items():
|
|
4636
|
+
pins_position_unit = unit_converter(pin.position, output_units=gds_comps_unit)
|
|
4637
|
+
gds_pin = ET.SubElement(gds_component, "GDS_PIN")
|
|
4638
|
+
gds_pin.set("Name", pin_name)
|
|
4639
|
+
gds_pin.set("x", str(pins_position_unit[0]))
|
|
4640
|
+
gds_pin.set("y", str(pins_position_unit[1]))
|
|
4641
|
+
gds_pin.set("Layer", pin.placement_layer)
|
|
4642
|
+
component = ET.SubElement(gds_component, "Component")
|
|
4643
|
+
component.set("RefDes", ocomp.refdes)
|
|
4644
|
+
component.set("PartName", ocomp.partname)
|
|
4645
|
+
component.set("PartType", ocomp.type)
|
|
4646
|
+
tree = ET.ElementTree(components)
|
|
4647
|
+
ET.indent(tree, space="\t", level=0)
|
|
4648
|
+
tree.write(control_path)
|
|
4649
|
+
return True if os.path.exists(control_path) else False
|
|
@@ -33,7 +33,6 @@ 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
|
|
37
36
|
|
|
38
37
|
try:
|
|
39
38
|
import numpy as np
|
|
@@ -1009,204 +1008,3 @@ class EDBComponent(Group):
|
|
|
1009
1008
|
)
|
|
1010
1009
|
void.is_negative = True
|
|
1011
1010
|
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().ToString())
|
|
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
|
-
ic_die_prop.SetType(getattr(self._edb.definition.DieType, snake_to_pascal(die_type)))
|
|
1127
|
-
if not die_type == "no_die":
|
|
1128
|
-
orientation = kwargs.get("orientation")
|
|
1129
|
-
if orientation:
|
|
1130
|
-
ic_die_prop.SetOrientation(
|
|
1131
|
-
getattr(self._edb.definition.DieOrientation, snake_to_pascal(orientation))
|
|
1132
|
-
)
|
|
1133
|
-
if die_type == "wire_bond":
|
|
1134
|
-
height = kwargs.get("height")
|
|
1135
|
-
if height:
|
|
1136
|
-
ic_die_prop.SetHeight(self._pedb.edb_value(height))
|
|
1137
|
-
cp.SetDieProperty(ic_die_prop)
|
|
1138
|
-
self.component_property = cp
|
|
1139
|
-
|
|
1140
|
-
@property
|
|
1141
|
-
def solder_ball_properties(self):
|
|
1142
|
-
temp = dict()
|
|
1143
|
-
cp = self.component_property
|
|
1144
|
-
c_type = self.type.lower()
|
|
1145
|
-
if c_type not in ["io", "other"]:
|
|
1146
|
-
return temp
|
|
1147
|
-
else:
|
|
1148
|
-
solder_ball_prop = cp.GetSolderBallProperty().Clone()
|
|
1149
|
-
_, diam, mid_diam = solder_ball_prop.GetDiameterValue()
|
|
1150
|
-
height = solder_ball_prop.GetHeightValue().ToString()
|
|
1151
|
-
shape = solder_ball_prop.GetShape().ToString()
|
|
1152
|
-
uses_solder_ball = solder_ball_prop.UsesSolderball()
|
|
1153
|
-
temp["uses_solder_ball"] = uses_solder_ball
|
|
1154
|
-
temp["shape"] = pascal_to_snake(shape)
|
|
1155
|
-
temp["diameter"] = diam.ToString()
|
|
1156
|
-
temp["mid_diameter"] = mid_diam.ToString()
|
|
1157
|
-
temp["height"] = height
|
|
1158
|
-
return temp
|
|
1159
|
-
|
|
1160
|
-
@solder_ball_properties.setter
|
|
1161
|
-
def solder_ball_properties(self, kwargs):
|
|
1162
|
-
cp = self.component_property
|
|
1163
|
-
solder_ball_prop = cp.GetSolderBallProperty().Clone()
|
|
1164
|
-
shape = kwargs.get("shape")
|
|
1165
|
-
if shape:
|
|
1166
|
-
solder_ball_prop.SetShape(getattr(self._edb.definition.SolderballShape, snake_to_pascal(shape)))
|
|
1167
|
-
if shape == "cylinder":
|
|
1168
|
-
diameter = kwargs["diameter"]
|
|
1169
|
-
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(diameter))
|
|
1170
|
-
elif shape == "spheroid":
|
|
1171
|
-
diameter = kwargs["diameter"]
|
|
1172
|
-
mid_diameter = kwargs["mid_diameter"]
|
|
1173
|
-
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(mid_diameter))
|
|
1174
|
-
else:
|
|
1175
|
-
return
|
|
1176
|
-
solder_ball_prop.SetHeight(self._get_edb_value(kwargs["height"]))
|
|
1177
|
-
cp.SetSolderBallProperty(solder_ball_prop)
|
|
1178
|
-
self.component_property = cp
|
|
1179
|
-
|
|
1180
|
-
@property
|
|
1181
|
-
def port_properties(self):
|
|
1182
|
-
temp = dict()
|
|
1183
|
-
cp = self.component_property
|
|
1184
|
-
c_type = self.type.lower()
|
|
1185
|
-
if c_type not in ["ic", "io", "other"]:
|
|
1186
|
-
return temp
|
|
1187
|
-
else:
|
|
1188
|
-
port_prop = cp.GetPortProperty().Clone()
|
|
1189
|
-
reference_height = port_prop.GetReferenceHeightValue().ToString()
|
|
1190
|
-
reference_size_auto = port_prop.GetReferenceSizeAuto()
|
|
1191
|
-
_, reference_size_x, reference_size_y = port_prop.GetReferenceSize()
|
|
1192
|
-
temp["reference_height"] = reference_height
|
|
1193
|
-
temp["reference_size_auto"] = reference_size_auto
|
|
1194
|
-
temp["reference_size_x"] = str(reference_size_x)
|
|
1195
|
-
temp["reference_size_y"] = str(reference_size_y)
|
|
1196
|
-
return temp
|
|
1197
|
-
|
|
1198
|
-
@port_properties.setter
|
|
1199
|
-
def port_properties(self, kwargs):
|
|
1200
|
-
cp = self.component_property
|
|
1201
|
-
port_prop = cp.GetPortProperty().Clone()
|
|
1202
|
-
height = kwargs.get("reference_height")
|
|
1203
|
-
if height:
|
|
1204
|
-
port_prop.SetReferenceHeight(self._pedb.edb_value(height))
|
|
1205
|
-
reference_size_auto = kwargs.get("reference_size_auto")
|
|
1206
|
-
if reference_size_auto:
|
|
1207
|
-
port_prop.SetReferenceSizeAuto(reference_size_auto)
|
|
1208
|
-
reference_size_x = kwargs.get("reference_size_x", 0)
|
|
1209
|
-
reference_size_y = kwargs.get("reference_size_y", 0)
|
|
1210
|
-
port_prop.SetReferenceSize(self._pedb.edb_value(reference_size_x), self._pedb.edb_value(reference_size_y))
|
|
1211
|
-
cp.SetPortProperty(port_prop)
|
|
1212
|
-
self.component_property = cp
|
|
@@ -580,17 +580,17 @@ class Primitive(Connectable):
|
|
|
580
580
|
_, name = self._edb_object.GetProductProperty(self._pedb._edb.ProductId.Designer, 1, val)
|
|
581
581
|
name = str(name).strip("'")
|
|
582
582
|
if name == "":
|
|
583
|
-
if str(self.primitive_type) == "
|
|
583
|
+
if str(self.primitive_type).lower() == "path":
|
|
584
584
|
ptype = "line"
|
|
585
|
-
elif str(self.primitive_type) == "
|
|
585
|
+
elif str(self.primitive_type).lower() == "rectangle":
|
|
586
586
|
ptype = "rect"
|
|
587
|
-
elif str(self.primitive_type) == "
|
|
587
|
+
elif str(self.primitive_type).lower() == "polygon":
|
|
588
588
|
ptype = "poly"
|
|
589
|
-
elif str(self.primitive_type) == "
|
|
589
|
+
elif str(self.primitive_type).lower() == "bondwire":
|
|
590
590
|
ptype = "bwr"
|
|
591
591
|
else:
|
|
592
592
|
ptype = str(self.primitive_type).lower()
|
|
593
|
-
name = "{}
|
|
593
|
+
name = "{}__{}".format(ptype, self.id)
|
|
594
594
|
self._edb_object.SetProductProperty(self._pedb._edb.ProductId.Designer, 1, name)
|
|
595
595
|
return name
|
|
596
596
|
|
|
@@ -603,10 +603,6 @@ class Primitive(Connectable):
|
|
|
603
603
|
""":class:`pyedb.dotnet.edb_core.dotnet.database.PolygonDataDotNet`: Outer contour of the Polygon object."""
|
|
604
604
|
return PolygonData(self._pedb, self._edb_object.GetPolygonData())
|
|
605
605
|
|
|
606
|
-
@polygon_data.setter
|
|
607
|
-
def polygon_data(self, poly):
|
|
608
|
-
self._edb_object.SetPolygonData(poly._edb_object)
|
|
609
|
-
|
|
610
606
|
def add_void(self, point_list):
|
|
611
607
|
"""Add a void to current primitive.
|
|
612
608
|
|
|
@@ -757,24 +753,6 @@ class Primitive(Connectable):
|
|
|
757
753
|
points.append(point)
|
|
758
754
|
return points
|
|
759
755
|
|
|
760
|
-
def expand(self, offset=0.001, tolerance=1e-12, round_corners=True, maximum_corner_extension=0.001):
|
|
761
|
-
"""Expand the polygon shape by an absolute value in all direction.
|
|
762
|
-
Offset can be negative for negative expansion.
|
|
763
|
-
|
|
764
|
-
Parameters
|
|
765
|
-
----------
|
|
766
|
-
offset : float, optional
|
|
767
|
-
Offset value in meters.
|
|
768
|
-
tolerance : float, optional
|
|
769
|
-
Tolerance in meters.
|
|
770
|
-
round_corners : bool, optional
|
|
771
|
-
Whether to round corners or not.
|
|
772
|
-
If True, use rounded corners in the expansion otherwise use straight edges (can be degenerate).
|
|
773
|
-
maximum_corner_extension : float, optional
|
|
774
|
-
The maximum corner extension (when round corners are not used) at which point the corner is clipped.
|
|
775
|
-
"""
|
|
776
|
-
return self.polygon_data.expand(offset, tolerance, round_corners, maximum_corner_extension)
|
|
777
|
-
|
|
778
756
|
def scale(self, factor, center=None):
|
|
779
757
|
"""Scales the polygon relative to a center point by a factor.
|
|
780
758
|
|
|
@@ -193,6 +193,19 @@ class ControlFileLayer:
|
|
|
193
193
|
content.set("Thickness", self.properties.get("Thickness", "0.001"))
|
|
194
194
|
if self.properties.get("Type"):
|
|
195
195
|
content.set("Type", self.properties.get("Type", "conductor"))
|
|
196
|
+
if self.properties.get("ConvertPolygonToCircle"):
|
|
197
|
+
content.set("ConvertPolygonToCircle", self.properties["ConvertPolygonToCircle"])
|
|
198
|
+
if self.properties.get("ConvertPolygonToCircleRatio"):
|
|
199
|
+
content.set("ConvertPolygonToCircleRatio", self.properties["ConvertPolygonToCircleRatio"])
|
|
200
|
+
if self.properties.get("ReconstructArcs"):
|
|
201
|
+
content.set("ReconstructArcs", self.properties["ReconstructArcs"])
|
|
202
|
+
if self.properties.get("ArcTolerance"):
|
|
203
|
+
content.set("ArcTolerance", self.properties["ArcTolerance"])
|
|
204
|
+
if self.properties.get("UnionPrimitives"):
|
|
205
|
+
content.set("UnionPrimitives", self.properties["UnionPrimitives"])
|
|
206
|
+
# To confirm syntax with development
|
|
207
|
+
if self.properties.get("DefeatureMinTraceWidth"):
|
|
208
|
+
content.set("DefeatureMinTraceWidth", self.properties["DefeatureMinTraceWidth"])
|
|
196
209
|
|
|
197
210
|
|
|
198
211
|
class ControlFileVia(ControlFileLayer):
|
|
@@ -226,6 +239,14 @@ class ControlFileVia(ControlFileLayer):
|
|
|
226
239
|
content.set("Thickness", self.properties.get("Thickness", "0.001"))
|
|
227
240
|
if self.properties.get("Type"):
|
|
228
241
|
content.set("Type", self.properties.get("Type", "conductor"))
|
|
242
|
+
if self.properties.get("ConvertPolygonToCircle"):
|
|
243
|
+
content.set("ConvertPolygonToCircle", self.properties["ConvertPolygonToCircle"])
|
|
244
|
+
if self.properties.get("ConvertPolygonToCircleRatio"):
|
|
245
|
+
content.set("ConvertPolygonToCircleRatio", self.properties["ConvertPolygonToCircleRatio"])
|
|
246
|
+
if self.properties.get("ReconstructArcs"):
|
|
247
|
+
content.set("ReconstructArcs", self.properties["ReconstructArcs"])
|
|
248
|
+
if self.properties.get("ArcTolerance"):
|
|
249
|
+
content.set("ArcTolerance", self.properties["ArcTolerance"])
|
|
229
250
|
if self.create_via_group:
|
|
230
251
|
viagroup = ET.SubElement(content, "CreateViaGroups")
|
|
231
252
|
viagroup.set("CheckContainment", "true" if self.check_containment else "false")
|