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.
Files changed (34) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +44 -74
  3. pyedb/configuration/cfg_common.py +1 -1
  4. pyedb/configuration/cfg_components.py +31 -105
  5. pyedb/configuration/cfg_data.py +4 -9
  6. pyedb/configuration/cfg_operations.py +19 -13
  7. pyedb/configuration/cfg_padstacks.py +66 -89
  8. pyedb/configuration/cfg_pin_groups.py +7 -8
  9. pyedb/configuration/cfg_ports_sources.py +4 -2
  10. pyedb/configuration/cfg_s_parameter_models.py +85 -29
  11. pyedb/configuration/configuration.py +48 -13
  12. pyedb/dotnet/application/Variables.py +43 -41
  13. pyedb/dotnet/edb.py +12 -4
  14. pyedb/dotnet/edb_core/cell/hierarchy/component.py +199 -0
  15. pyedb/dotnet/edb_core/cell/layout.py +4 -1
  16. pyedb/dotnet/edb_core/cell/primitive/primitive.py +2 -0
  17. pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py +3 -3
  18. pyedb/dotnet/edb_core/cell/terminal/terminal.py +4 -3
  19. pyedb/dotnet/edb_core/definition/component_def.py +17 -1
  20. pyedb/dotnet/edb_core/definition/component_model.py +0 -4
  21. pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +3 -3
  22. pyedb/dotnet/edb_core/edb_data/nets_data.py +10 -7
  23. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +301 -45
  24. pyedb/dotnet/edb_core/edb_data/primitives_data.py +2 -2
  25. pyedb/dotnet/edb_core/general.py +11 -0
  26. pyedb/dotnet/edb_core/layout_validation.py +3 -3
  27. pyedb/dotnet/edb_core/modeler.py +5 -2
  28. pyedb/dotnet/edb_core/nets.py +162 -181
  29. pyedb/edb_logger.py +1 -1
  30. pyedb/siwave.py +33 -7
  31. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/METADATA +5 -5
  32. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/RECORD +34 -34
  33. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/LICENSE +0 -0
  34. {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
- return {
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, pdata, path_lib, sparam_dict):
28
- self._pedb = pdata._pedb
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._sparam_dict = sparam_dict
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
- fpath = self.file_path
41
- if not Path(fpath).anchor:
42
- fpath = str(Path(self.path_libraries) / fpath)
43
- comp_def = self._pedb.definitions.component[self.component_definition]
44
- comp_def.add_n_port_model(fpath, self.name)
45
- comp_list = dict()
46
- if self.apply_to_all:
47
- comp_list.update(
48
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in self.components}
49
- )
50
- else:
51
- comp_list.update(
52
- {refdes: comp for refdes, comp in comp_def.components.items() if refdes in self.components}
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
- for refdes, comp in comp_list.items():
56
- if refdes in self.reference_net_per_component:
57
- ref_net = self.reference_net_per_component[refdes]
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
- ref_net = self.reference_net
60
- comp.use_s_parameter_model(self.name, reference_net=ref_net)
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
- return False
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
- self.cfg_data.stackup.apply()
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
- for s_parameter_model in self.cfg_data.s_parameters:
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=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
- json.dump(data, f, ensure_ascii=False, indent=4)
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 pyaedt import Hfss
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 pyaedt.maxwell import Maxwell3d
419
- >>> from pyaedt.desktop import Desktop
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
- 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 pyaedt.generic.constants >>> v1 = Variable("10mm")
1786
- >>> v2 = Variable(3)
1787
- >>> result_1 = v1 * v2
1788
- >>> result_2 = v1 * 3
1789
- >>> assert result_1.numeric_value == 30.0
1790
- >>> assert result_1.unit_system == "Length"
1791
- >>> assert result_2.numeric_value == result_1.numeric_value
1792
- >>> assert result_2.unit_system == "Length"
1793
-
1794
- Multiply voltage times current to obtain power.
1795
-
1796
- import pyaedt.generic.constants >>> v3 = Variable("3mA")
1797
- >>> v4 = Variable("40V")
1798
- >>> result_3 = v3 * v4
1799
- >>> assert result_3.numeric_value == 0.12
1800
- >>> assert result_3.units == "W"
1801
- >>> assert result_3.unit_system == "Power"
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 pyaedt.generic.constants
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 pyaedt.generic.constants
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 pyaedt.generic.constants
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 pyaedt.generic.constants
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 reference in reference_list:
2213
- for pin in self.nets.nets[reference].padstack_instances:
2214
- if pin.pingroups:
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
- return EDBNetsData(obj, self._pedb) if obj is not None else None
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.
@@ -160,6 +160,8 @@ class Primitive(Connectable):
160
160
  -------
161
161
  float
162
162
  """
163
+ if "GetPolygonData" not in dir(self._edb_object):
164
+ return 0
163
165
  area = self._edb_object.GetPolygonData().Area()
164
166
  if include_voids:
165
167
  for el in self._edb_object.Voids: