pyedb 0.24.0__py3-none-any.whl → 0.26.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 CHANGED
@@ -44,7 +44,7 @@ deprecation_warning()
44
44
  #
45
45
 
46
46
  pyedb_path = os.path.dirname(__file__)
47
- __version__ = "0.24.0"
47
+ __version__ = "0.26.0"
48
48
  version = __version__
49
49
 
50
50
  #
@@ -33,16 +33,62 @@ class ComponentPart:
33
33
  self.nb_freq = 0
34
34
  self.ref_impedance = 50.0
35
35
  self._s_parameters = None
36
+ self.type = ""
36
37
 
37
38
  @property
38
39
  def s_parameters(self):
39
- """Return skrf.network.Network object
40
- See `scikit-rf documentation <https://scikit-rf.readthedocs.io/en/latest/api/network.html#network-class>`
40
+ """Return a skrf.network.Network object.
41
+
42
+ See `scikit-rf documentation <https://scikit-rf.readthedocs.io/en/latest/api/network.html#network-class>`_.
41
43
  """
42
44
  if not self._s_parameters:
43
45
  self._extract_impedance()
44
46
  return self._s_parameters
45
47
 
48
+ @property
49
+ def esr(self):
50
+ """Return the equivalent serial resistor for capacitor only."""
51
+ if self.type == "Capacitor":
52
+ z11 = 1 / self.s_parameters.y[:, 0, 0]
53
+ return np.abs(abs(np.abs(np.real((z11.min()))) - 50))
54
+ else:
55
+ return 0.0
56
+
57
+ @property
58
+ def f0(self):
59
+ """Return the capacitor self resonant frequency in Hz."""
60
+ if self.type == "Capacitor":
61
+ z11 = 1 / self.s_parameters.y[:, 0, 0]
62
+ fo_index = np.where(np.abs(z11) == np.min(np.abs(z11)))[0][0]
63
+ return self.s_parameters.f[fo_index]
64
+ else:
65
+ return None
66
+
67
+ @property
68
+ def esl(self):
69
+ """Return the equivalent serial inductor for capacitor only."""
70
+ if self.type == "Capacitor":
71
+ omega_r = 2 * np.pi * self.f0
72
+ return 1 / (np.power(omega_r, 2) * self.cap_value)
73
+ else:
74
+ return 0.0
75
+
76
+ @property
77
+ def cap_value(self):
78
+ """Returns the capacitance value."""
79
+ if self.type == "Capacitor":
80
+ return round(np.imag(self.s_parameters.y[0, 0, 0]) / (2 * np.pi * self._s_parameters.f[0]), 15)
81
+ else:
82
+ return 0.0
83
+
84
+ @property
85
+ def ind_value(self):
86
+ """Return the inductance value."""
87
+ if self.type == "Inductor":
88
+ return round(np.imag(1 / self.s_parameters.y[0, 0, 0]) / (2 * np.pi * self._s_parameters.f[0]), 15)
89
+ else:
90
+ return 0.0
91
+
46
92
  def _extract_impedance(self):
47
93
  with open(self._sbin_file, mode="rb") as file:
48
94
  file_content = file.read()
@@ -24,7 +24,9 @@ from pyedb.configuration.cfg_common import CfgBase
24
24
 
25
25
 
26
26
  class CfgCutout(CfgBase):
27
- def __init__(self, **kwargs):
27
+ def __init__(self, pedb, **kwargs):
28
+ self._pedb = pedb
29
+
28
30
  self.signal_list = kwargs.get("signal_list")
29
31
  self.reference_list = kwargs.get("reference_list")
30
32
  self.extent_type = kwargs.get("extent_type")
@@ -38,7 +40,7 @@ class CfgCutout(CfgBase):
38
40
  self.extent_defeature = kwargs.get("extent_defeature")
39
41
  self.remove_single_pin_components = kwargs.get("remove_single_pin_components")
40
42
  self.custom_extent = kwargs.get("custom_extent")
41
- self.custom_extent_units = kwargs.get("custom_extent_units")
43
+ self.custom_extent_units = kwargs.get("custom_extent_units", "meter")
42
44
  self.include_partial_instances = kwargs.get("include_partial_instances")
43
45
  self.keep_voids = kwargs.get("keep_voids")
44
46
  self.check_terminals = kwargs.get("check_terminals")
@@ -49,13 +51,45 @@ class CfgCutout(CfgBase):
49
51
  self.simple_pad_check = kwargs.get("simple_pad_check")
50
52
  self.keep_lines_as_path = kwargs.get("keep_lines_as_path")
51
53
 
54
+ def get_data_from_db(self):
55
+ if "pyedb_cutout" in self._pedb.stackup.all_layers:
56
+ poly = self._pedb.layout.find_primitive(layer_name="pyedb_cutout")[0]
57
+ self.custom_extent = poly.polygon_data.points
58
+
59
+ net_names = []
60
+ for name, obj in self._pedb.nets.nets.items():
61
+ if obj.primitives[0].layer.name == "pyedb_cutout":
62
+ continue
63
+ if len(obj.primitives) > 0:
64
+ net_names.append(name)
65
+
66
+ self.reference_list = []
67
+ self.signal_list = net_names
68
+ return self.export_properties()
69
+
70
+ def export_properties(self):
71
+ return {
72
+ "signal_list": self.signal_list,
73
+ "reference_list": self.reference_list,
74
+ "custom_extent": self.custom_extent,
75
+ }
76
+
52
77
 
53
78
  class CfgOperations(CfgBase):
54
79
  def __init__(self, pedb, data):
55
80
  self._pedb = pedb
56
- self.op_cutout = CfgCutout(**data["cutout"]) if "cutout" in data else None
81
+ self.op_cutout = CfgCutout(pedb, **data["cutout"]) if "cutout" in data else None
57
82
 
58
83
  def apply(self):
59
84
  """Imports operation information from JSON."""
60
85
  if self.op_cutout:
61
- self._pedb.cutout(**self.op_cutout.get_attributes())
86
+ polygon_points = self._pedb.cutout(**self.op_cutout.get_attributes())
87
+ if not "pyedb_cutout" in self._pedb.stackup.all_layers:
88
+ self._pedb.stackup.add_document_layer(name="pyedb_cutout")
89
+ self._pedb.modeler.create_polygon(polygon_points, layer_name="pyedb_cutout", net_name="pyedb_cutout")
90
+
91
+ # create a polygon on pyedb layer
92
+
93
+ def get_data_from_db(self):
94
+ self.op_cutout = CfgCutout(self._pedb)
95
+ return {"cutout": self.op_cutout.get_data_from_db()}
@@ -45,7 +45,7 @@ class CfgCoordianteTerminalInfo(CfgTerminalInfo):
45
45
  self.net = self.value["net"]
46
46
 
47
47
  def export_properties(self):
48
- return {"layer": self.layer, "point_x": self.point_x, "point_y": self.point_y, "net": self.net}
48
+ return {"coordinates": {"layer": self.layer, "point": [self.point_x, self.point_y], "net": self.net}}
49
49
 
50
50
 
51
51
  class CfgNearestPinTerminalInfo(CfgTerminalInfo):
@@ -126,7 +126,10 @@ class CfgPorts:
126
126
  ports = {name: t for name, t in ports.items() if t.is_port}
127
127
 
128
128
  for _, p in ports.items():
129
- port_type = "circuit" if p.is_circuit_port else "coax"
129
+ if not p.ref_terminal:
130
+ port_type = "coax"
131
+ else:
132
+ port_type = "circuit"
130
133
 
131
134
  if p.terminal_type == "PinGroupTerminal":
132
135
  refdes = ""
@@ -135,6 +138,9 @@ class CfgPorts:
135
138
  elif p.terminal_type == "PadstackInstanceTerminal":
136
139
  refdes = p.component.refdes if p.component else ""
137
140
  pos_term_info = {"pin": p.padstack_instance.component_pin}
141
+ elif p.terminal_type == "PointTerminal":
142
+ refdes = ""
143
+ pos_term_info = {"coordinates": {"layer": p.layer.name, "point": p.location, "net": p.net.name}}
138
144
 
139
145
  if port_type == "circuit":
140
146
  neg_term = self._pedb.terminals[p.ref_terminal.name]
@@ -143,6 +149,14 @@ class CfgPorts:
143
149
  neg_term_info = {"pin_group": pg.name}
144
150
  elif neg_term.terminal_type == "PadstackInstanceTerminal":
145
151
  neg_term_info = {"pin": neg_term.padstack_instance.component_pin}
152
+ elif neg_term.terminal_type == "PointTerminal":
153
+ neg_term_info = {
154
+ "coordinates": {
155
+ "layer": neg_term.layer.name,
156
+ "point": neg_term.location,
157
+ "net": neg_term.net.name,
158
+ }
159
+ }
146
160
 
147
161
  cfg_port = CfgPort(
148
162
  self._pedb,
@@ -280,6 +280,8 @@ class Configuration:
280
280
  data["nets"] = self.cfg_data.nets.get_data_from_db()
281
281
  if kwargs.get("pin_groups", False):
282
282
  data["pin_groups"] = self.cfg_data.pin_groups.get_data_from_db()
283
+ if kwargs.get("operations", False):
284
+ data["operations"] = self.cfg_data.operations.get_data_from_db()
283
285
 
284
286
  return data
285
287
 
@@ -293,6 +295,7 @@ class Configuration:
293
295
  ports=True,
294
296
  nets=True,
295
297
  pin_groups=True,
298
+ operations=True,
296
299
  ):
297
300
  """Export the configuration data from layout to a file.
298
301
 
@@ -312,6 +315,10 @@ class Configuration:
312
315
  Whether to export ports or not.
313
316
  nets : bool
314
317
  Whether to export nets.
318
+ pin_groups : bool
319
+ Whether to export pin groups.
320
+ operations : bool
321
+ Whether to export operations.
315
322
  Returns
316
323
  -------
317
324
  bool
@@ -326,6 +333,7 @@ class Configuration:
326
333
  ports=ports,
327
334
  nets=nets,
328
335
  pin_groups=pin_groups,
336
+ operations=operations,
329
337
  )
330
338
  with open(file_path, "w") as f:
331
339
  json.dump(data, f, ensure_ascii=False, indent=4)
pyedb/dotnet/edb.py CHANGED
@@ -1602,7 +1602,7 @@ class Edb(Database):
1602
1602
  names = []
1603
1603
  _polys = []
1604
1604
  for net in net_signals:
1605
- names.append(net.GetName())
1605
+ names.append(net.name)
1606
1606
  if pins_to_preserve:
1607
1607
  insts = self.padstacks.instances
1608
1608
  for i in pins_to_preserve:
@@ -1706,7 +1706,7 @@ class Edb(Database):
1706
1706
  names = []
1707
1707
  _polys = []
1708
1708
  for net in net_signals:
1709
- names.append(net.GetName())
1709
+ names.append(net.name)
1710
1710
  if pins_to_preserve:
1711
1711
  insts = self.padstacks.instances
1712
1712
  for i in pins_to_preserve:
@@ -1994,7 +1994,7 @@ class Edb(Database):
1994
1994
  expansion_size = self.edb_value(expansion_size).ToDouble()
1995
1995
 
1996
1996
  # validate nets in layout
1997
- net_signals = [net.api_object for net in self.layout.nets if net.name in signal_list]
1997
+ net_signals = [net for net in self.layout.nets if net.name in signal_list]
1998
1998
 
1999
1999
  # validate references in layout
2000
2000
  _netsClip = convert_py_list_to_net_list(
@@ -2264,7 +2264,7 @@ class Edb(Database):
2264
2264
  elif custom_extent:
2265
2265
  _poly = custom_extent
2266
2266
  else:
2267
- net_signals = [net.api_object for net in self.layout.nets if net.name in signal_list]
2267
+ net_signals = [net for net in self.layout.nets if net.name in signal_list]
2268
2268
  _poly = self._create_extent(
2269
2269
  net_signals,
2270
2270
  extent_type,
@@ -23,6 +23,8 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
+ from typing import Union
27
+
26
28
  from pyedb.dotnet.edb_core.cell.hierarchy.component import EDBComponent
27
29
  from pyedb.dotnet.edb_core.cell.primitive.bondwire import Bondwire
28
30
  from pyedb.dotnet.edb_core.cell.primitive.path import Path
@@ -107,6 +109,7 @@ class Layout(ObjBase):
107
109
  -----
108
110
  Method returns the expansion of the contour, so any voids within expanded objects are ignored.
109
111
  """
112
+ nets = [i._edb_object for i in nets]
110
113
  return self._edb_object.GetExpandedExtentFromNets(
111
114
  convert_py_list_to_net_list(nets),
112
115
  extent,
@@ -331,3 +334,17 @@ class Layout(ObjBase):
331
334
  """
332
335
  obj = self._pedb._edb.Cell.Hierarchy.Component.FindByName(self._edb_object, value)
333
336
  return EDBComponent(self._pedb, obj) if obj is not None else None
337
+
338
+ def find_primitive(self, layer_name: Union[str, list]) -> list:
339
+ """Find a primitive objects by layer name.
340
+
341
+ Parameters
342
+ ----------
343
+ layer_name : str, list
344
+ Name of the layer.
345
+ Returns
346
+ -------
347
+ list
348
+ """
349
+ layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
350
+ return [i for i in self.primitives if i.layer_name in layer_name]
@@ -113,8 +113,11 @@ class Primitive(Connectable):
113
113
  @property
114
114
  def layer(self):
115
115
  """Get the primitive edb layer object."""
116
- layer_name = self._edb_object.GetLayer().GetName()
117
- return self._pedb.stackup.all_layers[layer_name]
116
+ obj = self._edb_object.GetLayer()
117
+ if obj.IsNull():
118
+ return None
119
+ else:
120
+ return self._pedb.stackup.find_layer_by_name(obj.GetName())
118
121
 
119
122
  @property
120
123
  def layer_name(self):
@@ -84,8 +84,13 @@ class PadstackInstanceTerminal(Terminal):
84
84
  isRef=is_ref,
85
85
  )
86
86
  terminal = PadstackInstanceTerminal(self._pedb, terminal)
87
-
88
- return terminal if not terminal.is_null else False
87
+ if terminal.is_null:
88
+ msg = f"Failed to create terminal. "
89
+ if name in self._pedb.terminals:
90
+ msg += f"Terminal {name} already exists."
91
+ raise Exception(msg)
92
+ else:
93
+ return terminal
89
94
 
90
95
  def _get_parameters(self):
91
96
  """Gets the parameters of the padstack instance terminal."""
@@ -56,7 +56,13 @@ class PinGroupTerminal(Terminal):
56
56
  is_ref,
57
57
  )
58
58
  term = PinGroupTerminal(self._pedb, term)
59
- return term if not term.is_null else False
59
+ if term.is_null:
60
+ msg = f"Failed to create terminal. "
61
+ if name in self._pedb.terminals:
62
+ msg += f"Terminal {name} already exists."
63
+ raise Exception(msg)
64
+ else:
65
+ return term
60
66
 
61
67
  def pin_group(self):
62
68
  """Gets the pin group the terminal refers to."""
@@ -59,4 +59,10 @@ class PointTerminal(Terminal):
59
59
  is_ref,
60
60
  )
61
61
  terminal = PointTerminal(self._pedb, terminal)
62
- return terminal if not terminal.is_null else False
62
+ if terminal.is_null:
63
+ msg = f"Failed to create terminal. "
64
+ if name in self._pedb.terminals:
65
+ msg += f"Terminal {name} already exists."
66
+ raise Exception(msg)
67
+ else:
68
+ return terminal
@@ -108,7 +108,7 @@ class Terminal(Connectable):
108
108
  point_data = self._pedb.point_data(0, 0)
109
109
  layer = list(self._pedb.stackup.layers.values())[0]._edb_layer
110
110
  if self._edb_object.GetParameters(point_data, layer):
111
- return layer
111
+ return self._pedb.stackup.all_layers[layer.GetName()]
112
112
  else:
113
113
  self._pedb.logger.warning(f"No pad parameters found for terminal {self.name}")
114
114
 
@@ -128,7 +128,7 @@ class Terminal(Connectable):
128
128
  @location.setter
129
129
  def location(self, value):
130
130
  layer = self.layer
131
- self._edb_object.SetParameters(self._pedb.point_data(*value), layer)
131
+ self._edb_object.SetParameters(self._pedb.point_data(*value), layer._edb_object)
132
132
 
133
133
  @property
134
134
  def is_circuit_port(self):
@@ -651,9 +651,8 @@ class Components(object):
651
651
 
652
652
  Returns
653
653
  -------
654
- pyedb.component_libraries.ansys_components import ComponentLib object. ComponentLib object contains nested
655
- dictionaries to navigate through [component tpe][vendors][series]
656
- [class: `pyedb.component_libraries.ansys_components.ComponentPart`]
654
+ ComponentLib object contains nested dictionaries to navigate through [component type][vendors][series]
655
+ :class: `pyedb.component_libraries.ansys_components.ComponentPart`
657
656
 
658
657
  Examples
659
658
  --------
@@ -681,6 +680,7 @@ class Components(object):
681
680
  for line in f.readlines():
682
681
  part_name, index = line.split()
683
682
  _serie[part_name] = ComponentPart(part_name, int(index), sbin_file)
683
+ _serie[part_name].type = cmp_type[:-1]
684
684
  f.close()
685
685
  series[serie_name] = _serie
686
686
  vendors[vendor] = series
@@ -770,7 +770,16 @@ class Components(object):
770
770
  )
771
771
  return True
772
772
 
773
- def create_port_on_pins(self, refdes, pins, reference_pins, impedance=50.0, port_name=None, pec_boundary=False):
773
+ def create_port_on_pins(
774
+ self,
775
+ refdes,
776
+ pins,
777
+ reference_pins,
778
+ impedance=50.0,
779
+ port_name=None,
780
+ pec_boundary=False,
781
+ pingroup_on_single_pin=False,
782
+ ):
774
783
  """Create circuit port between pins and reference ones.
775
784
 
776
785
  Parameters
@@ -796,6 +805,9 @@ class Components(object):
796
805
  a perfect short is created between the pin and impedance is ignored. This
797
806
  parameter is only supported on a port created between two pins, such as
798
807
  when there is no pin group.
808
+ pingroup_on_single_pin : bool
809
+ If ``True`` force using pingroup definition on single pin to have the port created at the pad center. If
810
+ ``False`` the port is created at the pad edge. Default value is ``False``.
799
811
 
800
812
  Returns
801
813
  -------
@@ -817,6 +829,9 @@ class Components(object):
817
829
  pins = [pins]
818
830
  elif isinstance(pins, EDBPadstackInstance):
819
831
  pins = [pins.name]
832
+ if not reference_pins:
833
+ self._logger.error("No reference pin provided.")
834
+ return False
820
835
  if isinstance(reference_pins, str):
821
836
  reference_pins = [reference_pins]
822
837
  if isinstance(reference_pins, list):
@@ -848,17 +863,19 @@ class Components(object):
848
863
  if len([pin for pin in pins if isinstance(pin, str)]) == len(pins):
849
864
  cmp_pins = []
850
865
  for pin_name in pins:
851
- cmp_pin = [pin for pin in list(refdes_pins.values()) if pin_name == pin.name]
852
- if not cmp_pin:
853
- cmp_pin = [pin for pin in list(refdes_pins.values()) if pin_name == pin.name.split("-")[1]]
854
- if cmp_pin:
855
- cmp_pins.append(cmp_pin[0])
866
+ cmp_pins = [pin for pin in list(refdes_pins.values()) if pin_name == pin.name]
867
+ if not cmp_pins:
868
+ for pin in list(refdes_pins.values()):
869
+ if pin.name and "-" in pin.name:
870
+ if pin_name == pin.name.split("-")[1]:
871
+ cmp_pins.append(pin)
856
872
  if not cmp_pins:
873
+ self._logger.warning("No pin found during port creation. Port is not defined.")
857
874
  return
858
875
  pins = cmp_pins
859
876
  if not len([pin for pin in pins if isinstance(pin, EDBPadstackInstance)]) == len(pins):
860
877
  self._logger.error("Pin list must contain only pins instances")
861
- return
878
+ return False
862
879
  if not port_name:
863
880
  port_name = "Port_{}_{}".format(pins[0].net_name, pins[0].name)
864
881
  if len([pin for pin in reference_pins if isinstance(pin, str)]) == len(reference_pins):
@@ -866,15 +883,14 @@ class Components(object):
866
883
  for ref_pin_name in reference_pins:
867
884
  if ref_pin_name in refdes_pins:
868
885
  ref_cmp_pins.append(refdes_pins[ref_pin_name])
869
- elif "-" in ref_pin_name and ref_pin_name.split("-")[1] in refdes_pins:
870
- ref_cmp_pins.append(refdes_pins[ref_pin_name.split("-")[1]])
886
+ elif "-" in ref_pin_name:
887
+ if ref_pin_name.split("-")[1] in refdes_pins:
888
+ ref_cmp_pins.append(refdes_pins[ref_pin_name.split("-")[1]])
871
889
  if not ref_cmp_pins:
872
- return
890
+ self._logger.error("No reference pins found.")
891
+ return False
873
892
  reference_pins = ref_cmp_pins
874
- if not reference_pins:
875
- self._logger.error("No reference pins found.")
876
- return
877
- if len(pins) > 1:
893
+ if len(pins) > 1 or pingroup_on_single_pin:
878
894
  pec_boundary = False
879
895
  self._logger.info(
880
896
  "Disabling PEC boundary creation, this feature is supported on single pin "
@@ -887,7 +903,7 @@ class Components(object):
887
903
  else:
888
904
  term = self._create_terminal(pins[0].primitive_object, term_name=port_name)
889
905
  term.SetIsCircuitPort(True)
890
- if len(reference_pins) > 1:
906
+ if len(reference_pins) > 1 or pingroup_on_single_pin:
891
907
  pec_boundary = False
892
908
  self._logger.info(
893
909
  "Disabling PEC boundary creation. This feature is supported on single pin"
@@ -2068,8 +2084,8 @@ class Components(object):
2068
2084
  pin1 = list(cmp.pins.values())[0].pin
2069
2085
  pin_layers = pin1.GetPadstackDef().GetData().GetLayerNames()
2070
2086
  pad_params = self._padstack.get_pad_parameters(pin=pin1, layername=pin_layers[0], pad_type=0)
2071
- _sb_diam = min([self._get_edb_value(val).ToDouble() for val in pad_params[1]])
2072
- sball_diam = _sb_diam
2087
+ _sb_diam = min([abs(self._get_edb_value(val).ToDouble()) for val in pad_params[1]])
2088
+ sball_diam = 0.8 * _sb_diam
2073
2089
  if sball_height:
2074
2090
  sball_height = round(self._edb.utility.Value(sball_height).ToDouble(), 9)
2075
2091
  else:
@@ -23,6 +23,13 @@
23
23
  from __future__ import absolute_import
24
24
 
25
25
 
26
+ def layer_cast(pedb, edb_object):
27
+ if edb_object.IsStackupLayer():
28
+ return StackupLayerEdbClass(pedb, edb_object.Clone(), name=edb_object.GetName())
29
+ else:
30
+ return LayerEdbClass(pedb, edb_object.Clone(), name=edb_object.GetName())
31
+
32
+
26
33
  class LayerEdbClass(object):
27
34
  """Manages Edb Layers. Replaces EDBLayer."""
28
35
 
@@ -36,6 +36,7 @@ import warnings
36
36
  from pyedb.dotnet.edb_core.edb_data.layer_data import (
37
37
  LayerEdbClass,
38
38
  StackupLayerEdbClass,
39
+ layer_cast,
39
40
  )
40
41
  from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
41
42
  from pyedb.generic.general_methods import ET, generate_unique_name
@@ -284,10 +285,7 @@ class LayerCollection(object):
284
285
  layer_list = list(self._edb_object.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
285
286
  temp = dict()
286
287
  for i in layer_list:
287
- if i.IsStackupLayer():
288
- obj = StackupLayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
289
- else:
290
- obj = LayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
288
+ obj = layer_cast(self._pedb, i)
291
289
  temp[obj.name] = obj
292
290
  return temp
293
291
 
@@ -306,12 +304,20 @@ class LayerCollection(object):
306
304
  """
307
305
  return {name: obj for name, obj in self.all_layers.items() if obj.is_stackup_layer}
308
306
 
307
+ def find_layer_by_name(self, name: str):
308
+ """Finds a layer with the given name."""
309
+ obj = self._pedb.edb_api.cell._cell.Layer.FindByName(self._edb_object, name)
310
+ if obj.IsNull():
311
+ raise ValueError("Layer with name '{}' was not found.".format(name))
312
+ else:
313
+ return layer_cast(self._pedb, obj.Clone())
314
+
309
315
 
310
316
  class Stackup(LayerCollection):
311
317
  """Manages EDB methods for stackup accessible from `Edb.stackup` property."""
312
318
 
313
319
  def __getitem__(self, item):
314
- return self.all_layers[item]
320
+ return self.find_layer_by_name(item)
315
321
 
316
322
  def __init__(self, pedb, edb_object=None):
317
323
  super().__init__(pedb, edb_object)
@@ -1800,7 +1806,7 @@ class Stackup(LayerCollection):
1800
1806
  temp_data = {name: 0 for name, _ in self.signal_layers.items()}
1801
1807
  outline_area = 0
1802
1808
  for i in self._pedb.modeler.primitives:
1803
- layer_name = i.layer.name
1809
+ layer_name = i._edb_object.GetLayer().GetName()
1804
1810
  if layer_name.lower() == "outline":
1805
1811
  if i.area() > outline_area:
1806
1812
  outline_area = i.area()
pyedb/siwave.py CHANGED
@@ -266,6 +266,16 @@ class Siwave(object): # pragma no cover
266
266
  else:
267
267
  return False
268
268
 
269
+ @property
270
+ def file_dir(self) -> str:
271
+ """Directory path of the open project."""
272
+ return self.oproject.GetFileDir()
273
+
274
+ @property
275
+ def file_path(self) -> str:
276
+ """Path of the open project file."""
277
+ return self.oproject.GetFilePath()
278
+
269
279
  def save_project(self, projectpath=None, projectName=None):
270
280
  """Save the project.
271
281
 
@@ -283,7 +293,9 @@ class Siwave(object): # pragma no cover
283
293
 
284
294
  """
285
295
  if projectName and projectpath:
286
- self.oproject.ScrSaveProjectAs(os.path.join(projectpath, projectName + ".siw"))
296
+ if not projectName.endswith(".siw"):
297
+ projectName = projectName + ".siw"
298
+ self.oproject.ScrSaveProjectAs(os.path.join(projectpath, projectName))
287
299
  else:
288
300
  self.oproject.Save()
289
301
  return True
@@ -476,6 +488,7 @@ class Siwave(object): # pragma no cover
476
488
  if isinstance(file_path, Path):
477
489
  file_path = str(file_path)
478
490
  flag = self.oproject.ScrImportEDB(file_path)
491
+ # self.save_project(self.di)
479
492
  if flag == 0:
480
493
  self._logger.info(f"Importing EDB to {file_path}.")
481
494
  return True
@@ -493,11 +506,12 @@ class Siwave(object): # pragma no cover
493
506
  if isinstance(file_path, Path):
494
507
  file_path = str(file_path)
495
508
 
496
- temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
497
- temp_edb = os.path.join(temp_folder.name, "temp.aedb")
509
+ # temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
510
+ # temp_edb = os.path.join(temp_folder.name, "temp.aedb")
511
+
512
+ temp_edb = os.path.join(self.file_dir, "temp.aedb")
498
513
 
499
514
  self.export_edb(temp_edb)
500
- self.save_project()
501
515
  self.oproject.ScrCloseProject()
502
516
  edbapp = Edb(temp_edb, edbversion=self.current_version)
503
517
  edbapp.configuration.load(file_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyedb
3
- Version: 0.24.0
3
+ Version: 0.26.0
4
4
  Summary: Higher-Level Pythonic Ansys Electronics Data Base
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: PyEDB developers <simon.vandenbrouck@ansys.com>
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.8
15
15
  Classifier: Programming Language :: Python :: 3.9
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
- Requires-Dist: cffi>=1.16.0,<1.17; platform_system=='Linux'
18
+ Requires-Dist: cffi>=1.16.0,<1.18; platform_system=='Linux'
19
19
  Requires-Dist: pywin32 >= 303;platform_system=='Windows'
20
20
  Requires-Dist: ansys-pythonnet >= 3.1.0rc3
21
21
  Requires-Dist: dotnetcore2 ==3.1.23;platform_system=='Linux'
@@ -25,18 +25,18 @@ Requires-Dist: pydantic>=2.6.4,<2.9
25
25
  Requires-Dist: Rtree >= 1.2.0
26
26
  Requires-Dist: toml == 0.10.2
27
27
  Requires-Dist: scikit-rf
28
- Requires-Dist: ansys-sphinx-theme>=0.10.0,<0.17 ; extra == "doc"
29
- Requires-Dist: imageio>=2.30.0,<2.35 ; extra == "doc"
28
+ Requires-Dist: ansys-sphinx-theme>=0.10.0,<1.1 ; extra == "doc"
29
+ Requires-Dist: imageio>=2.30.0,<2.36 ; extra == "doc"
30
30
  Requires-Dist: ipython>=8.13.0,<8.27 ; extra == "doc"
31
31
  Requires-Dist: jupyterlab>=4.0.0,<4.3 ; extra == "doc"
32
32
  Requires-Dist: jupytext>=1.16.0,<1.17 ; extra == "doc"
33
33
  Requires-Dist: matplotlib>=3.5.0,<3.10 ; extra == "doc"
34
34
  Requires-Dist: nbsphinx>=0.9.0,<0.10 ; extra == "doc"
35
35
  Requires-Dist: nbconvert < 7.17 ; extra == "doc"
36
- Requires-Dist: numpydoc>=1.5.0,<1.8 ; extra == "doc"
36
+ Requires-Dist: numpydoc>=1.5.0,<1.9 ; extra == "doc"
37
37
  Requires-Dist: pypandoc>=1.10.0,<1.14 ; extra == "doc"
38
38
  Requires-Dist: recommonmark ; extra == "doc"
39
- Requires-Dist: Sphinx>=7.1.0,<7.4 ; extra == "doc"
39
+ Requires-Dist: Sphinx>=7.1.0,<8.1 ; extra == "doc"
40
40
  Requires-Dist: sphinx-autobuild==2024.2.4 ; extra == "doc" and ( python_version == '3.8')
41
41
  Requires-Dist: sphinx-autobuild==2024.2.4 ; extra == "doc" and ( python_version > '3.8')
42
42
  Requires-Dist: sphinx-copybutton>=0.5.0,<0.6 ; extra == "doc"
@@ -1,9 +1,9 @@
1
- pyedb/__init__.py,sha256=Chvf1Pw0bR7i5T4tBFP8S_KsnyyrNNlKEd5zobtcK48,1521
1
+ pyedb/__init__.py,sha256=LPbrtRXIz0vH59E8iYey-OmAoq8r4GQp4vPaU_f2o3w,1521
2
2
  pyedb/edb_logger.py,sha256=yNkXnoL2me7ubLT6O6r6ElVnkZ1g8fmfFYC_2XJZ1Sw,14950
3
3
  pyedb/exceptions.py,sha256=n94xluzUks6BA24vd_L6HkrvoP_H_l6__hQmqzdCyPo,111
4
- pyedb/siwave.py,sha256=Mo-8ETIwTbPNbqfaDJkbl_G3Dp8mdtYFl54Ms9sGAZo,16004
4
+ pyedb/siwave.py,sha256=mH3wJ2e-lvAgNjAFRIkLTZ7mUjz7Gp_jm4z-QN66M88,16442
5
5
  pyedb/workflow.py,sha256=Y0ya4FUHwlSmoLP45zjdYLsSpyKduHUSpT9GGK9MGd8,814
6
- pyedb/component_libraries/ansys_components.py,sha256=afelGEPmQzbFOIkHnvnWosSs3CqDT5j_kr_1bhrdfnI,3336
6
+ pyedb/component_libraries/ansys_components.py,sha256=O3ypt832IHY9zG2AD_yrRrbH2KH9P1yFaoi1EO6Zllw,4830
7
7
  pyedb/configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  pyedb/configuration/cfg_boundaries.py,sha256=ckb-OfaObItwy-xc0LqkHJyeCfKC5vg668olPjZbaKo,6647
9
9
  pyedb/configuration/cfg_common.py,sha256=5ne78TTA0wHpbi804nsUd9SPxNKZvut_X_Miu-xDRgk,1982
@@ -11,23 +11,23 @@ pyedb/configuration/cfg_components.py,sha256=XGWvttmVpz7zHh9fpKFjsMiMy6KTP_GGsR3
11
11
  pyedb/configuration/cfg_data.py,sha256=eSwdJ7ECP85oNGmmn3_1dK3lRQp4fS_uSYXD5TlNees,3631
12
12
  pyedb/configuration/cfg_general.py,sha256=0dtd-rkQt2aYR3EOL0c3sNuDuJs7htRos1OWck3rxaI,1626
13
13
  pyedb/configuration/cfg_nets.py,sha256=18NezeNh0ZOwk2ehz3zWJF_xYR7IYCqGlpDfDt7Ilho,2349
14
- pyedb/configuration/cfg_operations.py,sha256=OzktdjLgHUm6_kCbMeuZ2mhUXfOIP6gXslmbkB7nZOM,3130
14
+ pyedb/configuration/cfg_operations.py,sha256=-Lliu2j7FrD1HI0exV2gg6ebNGYsSZLCP6N3idRWhcM,4472
15
15
  pyedb/configuration/cfg_package_definition.py,sha256=f_RRT9R-3H5kHBlc4QSpjq9uQgYbaKQ78XXXrc_r3kg,5296
16
16
  pyedb/configuration/cfg_padstacks.py,sha256=5t799x_mfwLjCAic-B13v3I6FgDswysXdcKmeOxz4Uo,5571
17
17
  pyedb/configuration/cfg_pin_groups.py,sha256=Aq5rlUU2z9iNMv5cBBwHHTlSglw5Upm8EA4g7CQwD5o,3823
18
- pyedb/configuration/cfg_ports_sources.py,sha256=EhiWNeVZDsB2vMdxUgNSCJpcEK7dZPrKbRtaaYR67v4,15738
18
+ pyedb/configuration/cfg_ports_sources.py,sha256=G2mX057QB3H3JUxAL0wDMDaHgabKFnht3iIyhTJvJU4,16356
19
19
  pyedb/configuration/cfg_s_parameter_models.py,sha256=NzS3eBjBSnd7ZDk_TsX04dqRcRXompjx1DxCe1UzWMw,2855
20
20
  pyedb/configuration/cfg_setup.py,sha256=SPpNRLJusB-Cz2fDQkc6gkdilUqIlbNngoxF3zySt6g,10115
21
21
  pyedb/configuration/cfg_spice_models.py,sha256=tBY3okFiEffMGvBkpmZQrCrovpt-d62k51_WkkV4jqo,2435
22
22
  pyedb/configuration/cfg_stackup.py,sha256=CX7uNN5QRoYW_MOObknP8003YchTS7PH9Oee7FG0VKU,6589
23
- pyedb/configuration/configuration.py,sha256=ss0Jqj0pp4Up-4Hm-jBQGSAmF4uQjaELfyhxqPE2z4o,12627
23
+ pyedb/configuration/configuration.py,sha256=fWYRDI0G4O8cyR1pk0_2RNqBOjKVL0oYRevIVjlV8fo,12944
24
24
  pyedb/dotnet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  pyedb/dotnet/clr_module.py,sha256=Mo13Of3DVSA5HR-5xZEXOiHApIKy52CUxtJ2gPkEu1A,3406
26
- pyedb/dotnet/edb.py,sha256=7sNO4RxRPb3q_g5FYEiYfFS6jcNeqj8EW19JFk7dMxI,181348
26
+ pyedb/dotnet/edb.py,sha256=uyYtlbirX3S62eKdy2fWBgG6fWLmib5PqH8UDxOvPIM,181316
27
27
  pyedb/dotnet/application/Variables.py,sha256=v_fxFJ6xjyyhk4uaMzWAbP-1FhXGuKsVNuyV1huaPME,77867
28
28
  pyedb/dotnet/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  pyedb/dotnet/edb_core/__init__.py,sha256=nIRLJ8VZLcMAp12zmGsnZ5x2BEEl7q_Kj_KAOXxVjpQ,52
30
- pyedb/dotnet/edb_core/components.py,sha256=Hi07An_cDV8CPlMV11BNQMFm823oz8-nfWXpbqYPKoQ,110543
30
+ pyedb/dotnet/edb_core/components.py,sha256=Cw_z1xfUkuwtGEqWuQrHY7N0YZA0kUYUqJJooTBtj6o,111194
31
31
  pyedb/dotnet/edb_core/general.py,sha256=1g2bUekyUbu8p8zCinT4eI7uqRGIK8tY8mfuFePGRGg,4415
32
32
  pyedb/dotnet/edb_core/hfss.py,sha256=C6-to6YKoruQjRWedLY7agkTVQv4Hb2U2qX-iPzHOI0,68655
33
33
  pyedb/dotnet/edb_core/layout_obj_instance.py,sha256=Pd8rfdO3b6HLFGwXBMw-tfE4LPIcW_9_X5KEdFaiito,1407
@@ -38,10 +38,10 @@ pyedb/dotnet/edb_core/net_class.py,sha256=4U6Cc1Gn7ZJ_ub9uKmtrsoz5wD1XS42afci3Y3
38
38
  pyedb/dotnet/edb_core/nets.py,sha256=JZvrlPOKiRjbHAX6GkrYKvaXujHS3lz-rucS0Ib8ezk,43213
39
39
  pyedb/dotnet/edb_core/padstack.py,sha256=al5cXfnJXyaM6-KCAd8D8-TZzcIXHwco8grD44U7gNY,63588
40
40
  pyedb/dotnet/edb_core/siwave.py,sha256=4duoAsFCuPMNLxtMTEEVJCUaHKNkdbLDmtTXiD93VrM,64311
41
- pyedb/dotnet/edb_core/stackup.py,sha256=_jvmLHpo5_4CM8V_xnB81WQrqJGsEHs3eECS8Y-buaQ,119804
41
+ pyedb/dotnet/edb_core/stackup.py,sha256=b56leXg7X7dEVPP2DUD9n8LZIakWcjIsjiqqkIWsyZU,120035
42
42
  pyedb/dotnet/edb_core/cell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  pyedb/dotnet/edb_core/cell/connectable.py,sha256=rKWPATg0GCHi4d1ftu2V7WWhkDONjloCSPujssie5a8,2310
44
- pyedb/dotnet/edb_core/cell/layout.py,sha256=wDJI5Urhif5QCKqkrqhN2eDviLCsiRf-hu1L59dbLAg,12114
44
+ pyedb/dotnet/edb_core/cell/layout.py,sha256=u3HEdKc7rls3gkm7m31-XGi6l3pfoHEAswTVCz4FSmY,12619
45
45
  pyedb/dotnet/edb_core/cell/layout_obj.py,sha256=S42rdiI6gVqO77DV3ikc4YxTNufTuqW_X1G-2zkWArA,2765
46
46
  pyedb/dotnet/edb_core/cell/voltage_regulator.py,sha256=-uAzuyERV6ca0bFRzdH4SllcpGY2D9JEdpS7RYaQt6c,5387
47
47
  pyedb/dotnet/edb_core/cell/hierarchy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -55,14 +55,14 @@ pyedb/dotnet/edb_core/cell/hierarchy/spice_model.py,sha256=SGiUcan2l0n8DGk3GtwCs
55
55
  pyedb/dotnet/edb_core/cell/primitive/__init__.py,sha256=8jByHkoaowAYQTCww-zRrTQmN061fLz_OHjTLSrzQQY,58
56
56
  pyedb/dotnet/edb_core/cell/primitive/bondwire.py,sha256=fqIMdv0bNvk591DG6De5c--w9Rpkl5AOeo_qgzoPE6M,7322
57
57
  pyedb/dotnet/edb_core/cell/primitive/path.py,sha256=XVN7dOVpccoBP28M8l5iMzK5QSQdHqpKqC4jK76UTis,12543
58
- pyedb/dotnet/edb_core/cell/primitive/primitive.py,sha256=IMGIaPCY8wpq3uInizwc1ObmdsTn5kg9YEqk9uztRuU,29764
58
+ pyedb/dotnet/edb_core/cell/primitive/primitive.py,sha256=L9MNMc1OD8g_ghN2fhtdxa8v6jv6FY8D7oj7fF2A4vw,29825
59
59
  pyedb/dotnet/edb_core/cell/terminal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  pyedb/dotnet/edb_core/cell/terminal/bundle_terminal.py,sha256=qM0wEXkZ-DpoJ6vlVa560Ce8IgOdp4vyIJPedvoa3O0,1977
61
61
  pyedb/dotnet/edb_core/cell/terminal/edge_terminal.py,sha256=lafPRrvsDPYKcysvrkO-5tEZXF3h4IcTXdeJgTjleuI,2158
62
- pyedb/dotnet/edb_core/cell/terminal/padstack_instance_terminal.py,sha256=HOMNvSj8thN3RgSg2eDb_CE8PpqkcVLrIYPZGOW-IQk,3803
63
- pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py,sha256=M5qZNH-MLDkgSJABNVKmnBLyLgezm2fqJGl70EyPVUo,2586
64
- pyedb/dotnet/edb_core/cell/terminal/point_terminal.py,sha256=DafZBGjUx_OE8gZWcUKPh4cH3BRkJSj9XolhzIPOE3I,2400
65
- pyedb/dotnet/edb_core/cell/terminal/terminal.py,sha256=MvUi-03IHMm29KT_ujN3w88AdGx__dS2DfVxG4_MHok,19223
62
+ pyedb/dotnet/edb_core/cell/terminal/padstack_instance_terminal.py,sha256=XI7NiP1qT2aft7hjPK4gX42RzreiZ66aHXIHFPwUghs,3999
63
+ pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py,sha256=3y2UXqg8a7W74pjzZDljB1joCPTtmOkrIKGophDdgw4,2783
64
+ pyedb/dotnet/edb_core/cell/terminal/point_terminal.py,sha256=S3aCAuFc_QA36PVn2Cdb9L4dO3T4IikwyEVcP1FOW3I,2597
65
+ pyedb/dotnet/edb_core/cell/terminal/terminal.py,sha256=x-xUwqg1ZJQTgubuNSd3qistl982kAvSXNvAoNohcfg,19276
66
66
  pyedb/dotnet/edb_core/definition/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
67
  pyedb/dotnet/edb_core/definition/component_def.py,sha256=tYZ4L6DigwSjdQJ5AlqEbordPVZyJ6hYFNc6b3QnJ18,6514
68
68
  pyedb/dotnet/edb_core/definition/component_model.py,sha256=PhT5voy3qk8fsp94dK6TN_Zxz5aXwO_mmeIwWm7C_Hs,1944
@@ -77,7 +77,7 @@ pyedb/dotnet/edb_core/edb_data/control_file.py,sha256=_W5DDBFvm4gTq8yCvhzfiWUsfp
77
77
  pyedb/dotnet/edb_core/edb_data/design_options.py,sha256=RO9ip-T5Bfxpsl97_QEk0qDZsza3tLzIX2t25XLutys,2057
78
78
  pyedb/dotnet/edb_core/edb_data/edbvalue.py,sha256=Vj_11HXsQUNavizKp5FicORm6cjhXRh9uvxhv_D_RJc,1977
79
79
  pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py,sha256=hKFHWUl0_OCMEZJbQn5c8Y1a-BYKr8nAycIlrCoeufk,13005
80
- pyedb/dotnet/edb_core/edb_data/layer_data.py,sha256=B6cClg5KTcKUn33jYccTN0uNZZ5dQ037WHCsI-vg3Us,25748
80
+ pyedb/dotnet/edb_core/edb_data/layer_data.py,sha256=2K1rvBXAWg3s8paNU6TPNb5tC1B3bRHmiUZjVsoX_Z8,26001
81
81
  pyedb/dotnet/edb_core/edb_data/nets_data.py,sha256=Ifi5uSfnOuTLwesO9TS3_F-qa_8rpPXrJy6W5lvIWik,9684
82
82
  pyedb/dotnet/edb_core/edb_data/padstacks_data.py,sha256=wOBO86cFGnx8OIsALzlQv59XeSGBhUYhJa7rksySGRE,77523
83
83
  pyedb/dotnet/edb_core/edb_data/ports.py,sha256=wr2RQi8VExuNIVmnp7c4VpTIhODgthmJmHr01zO4ueo,8873
@@ -185,7 +185,7 @@ pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py,sha256=YmYI6WTQulL5Uf8Wx
185
185
  pyedb/misc/siw_feature_config/xtalk_scan/td_xtalk_config.py,sha256=KHa-UqcXuabiVfT2CV-UvWl5Q2qGYHF2Ye9azcAlnXc,3966
186
186
  pyedb/modeler/geometry_operators.py,sha256=g_Sy7a6R23sP6RtboJn1rl8uTuo8oeLmMF21rNkzwjk,74198
187
187
  pyedb/siwave_core/icepak.py,sha256=WnZ-t8mik7LDY06V8hZFV-TxRZJQWK7bu_8Ichx-oBs,5206
188
- pyedb-0.24.0.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
189
- pyedb-0.24.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
190
- pyedb-0.24.0.dist-info/METADATA,sha256=G3Lci5o6XNKqCo9-qFMpgqZ3Sd2ihk0vnFdJTWnk4b0,8387
191
- pyedb-0.24.0.dist-info/RECORD,,
188
+ pyedb-0.26.0.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
189
+ pyedb-0.26.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
190
+ pyedb-0.26.0.dist-info/METADATA,sha256=jAmjbUO3XTLpJ7Y-PIpgYQvcktdrERXU9caJNfVcSXc,8386
191
+ pyedb-0.26.0.dist-info/RECORD,,
File without changes