pyedb 0.31.0__py3-none-any.whl → 0.34.1__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.

Files changed (32) hide show
  1. pyedb/__init__.py +1 -27
  2. pyedb/common/__init__.py +0 -0
  3. pyedb/common/nets.py +488 -0
  4. pyedb/configuration/cfg_common.py +20 -0
  5. pyedb/configuration/cfg_components.py +218 -57
  6. pyedb/configuration/cfg_data.py +6 -0
  7. pyedb/configuration/cfg_modeler.py +139 -0
  8. pyedb/configuration/cfg_operations.py +5 -4
  9. pyedb/configuration/cfg_padstacks.py +319 -55
  10. pyedb/configuration/cfg_ports_sources.py +99 -7
  11. pyedb/configuration/cfg_s_parameter_models.py +6 -6
  12. pyedb/configuration/configuration.py +31 -9
  13. pyedb/dotnet/clr_module.py +92 -32
  14. pyedb/dotnet/edb.py +54 -5
  15. pyedb/dotnet/edb_core/cell/hierarchy/component.py +0 -202
  16. pyedb/dotnet/edb_core/cell/layout.py +1 -1
  17. pyedb/dotnet/edb_core/cell/primitive/primitive.py +5 -27
  18. pyedb/dotnet/edb_core/edb_data/control_file.py +21 -0
  19. pyedb/dotnet/edb_core/edb_data/layer_data.py +60 -6
  20. pyedb/dotnet/edb_core/edb_data/nets_data.py +6 -1
  21. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +16 -222
  22. pyedb/dotnet/edb_core/edb_data/primitives_data.py +31 -0
  23. pyedb/dotnet/edb_core/hfss.py +2 -2
  24. pyedb/dotnet/edb_core/layout_validation.py +1 -3
  25. pyedb/dotnet/edb_core/materials.py +38 -38
  26. pyedb/dotnet/edb_core/modeler.py +4 -1
  27. pyedb/dotnet/edb_core/nets.py +2 -373
  28. pyedb/generic/filesystem.py +2 -5
  29. {pyedb-0.31.0.dist-info → pyedb-0.34.1.dist-info}/METADATA +12 -9
  30. {pyedb-0.31.0.dist-info → pyedb-0.34.1.dist-info}/RECORD +32 -29
  31. {pyedb-0.31.0.dist-info → pyedb-0.34.1.dist-info}/WHEEL +1 -1
  32. {pyedb-0.31.0.dist-info → pyedb-0.34.1.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
- data["components"] = self.cfg_data.components.get_data_from_db()
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
- data["padstacks"] = self.cfg_data.padstacks.get_data_from_db()
300
- if kwargs.get("s_parameters", False):
301
- data["s_parameters"] = self.cfg_data.s_parameters.get_data_from_db()
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=True,
333
+ package_definitions=False,
312
334
  setups=True,
313
335
  sources=True,
314
336
  ports=True,
@@ -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
- pyedb_path = os.path.dirname(os.path.abspath(pyedb.__file__))
16
- sys.path.append(os.path.join(pyedb_path, "dlls", "PDFReport"))
17
- except ImportError:
18
- pyedb_path = None
19
- warnings.warn("Cannot import pyedb.")
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
- if is_linux and cpython: # pragma: no cover
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
- import dotnet
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
- runtime = os.path.join(os.path.dirname(dotnetcore2.__file__), "bin")
33
- finally:
34
- os.environ["DOTNET_ROOT"] = runtime
35
-
36
- from pythonnet import load
37
-
38
- if pyedb_path is not None:
39
- json_file = os.path.abspath(os.path.join(pyedb_path, "misc", "pyedb.runtimeconfig.json"))
40
- load("coreclr", runtime_config=json_file, dotnet_root=os.environ["DOTNET_ROOT"])
41
- print("DotNet Core correctly loaded.")
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 ANSYSEM_ROOT232=/path/to/AnsysEM/v232/Linux64")
103
+ warnings.warn("export ANSYSEM_ROOT242=/path/to/AnsysEM/v242/Linux64")
45
104
  msg = "export LD_LIBRARY_PATH="
46
- msg += "$ANSYSEM_ROOT232/common/mono/Linux64/lib64:$LD_LIBRARY_PATH"
105
+ msg += "$ANSYSEM_ROOT242/common/mono/Linux64/lib64:$LD_LIBRARY_PATH"
47
106
  msg += (
48
- "If PyEDB will run on AEDT<2023.2 then $ANSYSEM_ROOT222/Delcross should be added to LD_LIBRARY_PATH"
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
- else:
53
- print("DotNet Core not correctly loaded.")
54
- except ImportError:
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
- pass
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(variable_name=variable_name, variable_value=variable_value)
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
@@ -313,7 +313,7 @@ class Layout(ObjBase):
313
313
  """
314
314
  obj = self._pedb._edb.Cell.Net.FindByName(self._edb_object, value)
315
315
  if obj.IsNull():
316
- raise ValueError(f"Net {value} doesn't exist")
316
+ return None
317
317
  else:
318
318
  return EDBNetsData(obj, self._pedb)
319
319
 
@@ -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) == "Path":
583
+ if str(self.primitive_type).lower() == "path":
584
584
  ptype = "line"
585
- elif str(self.primitive_type) == "Rectangle":
585
+ elif str(self.primitive_type).lower() == "rectangle":
586
586
  ptype = "rect"
587
- elif str(self.primitive_type) == "Polygon":
587
+ elif str(self.primitive_type).lower() == "polygon":
588
588
  ptype = "poly"
589
- elif str(self.primitive_type) == "Bondwire":
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 = "{}_{}".format(ptype, self.id)
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")