pyedb 0.12.0__py3-none-any.whl → 0.12.2__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.12.0"
47
+ __version__ = "0.12.2"
48
48
  version = __version__
49
49
 
50
50
  #
@@ -25,7 +25,7 @@ from enum import Enum
25
25
 
26
26
  class CfgBoundaries:
27
27
  def __init__(self, pdata, boundaries_dict):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self._boundaries_dict = boundaries_dict
30
30
  self.open_region = self._boundaries_dict.get("open_region", None)
31
31
  self._map_open_region_type()
@@ -60,7 +60,7 @@ class CfgSolderBallsProperties:
60
60
 
61
61
  class CfgComponent:
62
62
  def __init__(self, pdata, **kwargs):
63
- self._pedb = pdata.pedb
63
+ self._pedb = pdata._pedb
64
64
  self._comp_dict = kwargs
65
65
  self.reference_designator = ""
66
66
  self.part_type = self.ComponentType.RESISTOR
@@ -30,39 +30,58 @@ from pyedb.configuration.cfg_ports_sources import CfgPort, CfgSources
30
30
  from pyedb.configuration.cfg_s_parameter_models import CfgSParameterModel
31
31
  from pyedb.configuration.cfg_setup import CfgSetup
32
32
  from pyedb.configuration.cfg_spice_models import CfgSpiceModel
33
+ from pyedb.configuration.cfg_stackup import CfgStackup
34
+ from pyedb.generic.general_methods import pyedb_function_handler
33
35
 
34
36
 
35
37
  class CfgData(object):
36
38
  """Manages configure data."""
37
39
 
38
40
  def __init__(self, pedb, **kwargs):
39
- self.pedb = pedb
40
- self.edb_comps = self.pedb.components.components
41
+ self._pedb = pedb
42
+ self.edb_comps = self._pedb.components.components
41
43
  self.general = CfgGeneral(self, kwargs.get("general", None))
44
+
42
45
  self.boundaries = {}
43
46
  if kwargs.get("boundaries", None):
44
47
  self.boundaries = CfgBoundaries(self, kwargs.get("boundaries", None))
45
- self.nets = CfgNets(self)
48
+
49
+ self.nets = None
46
50
  if kwargs.get("nets"):
47
51
  self.nets = CfgNets(
48
52
  self, kwargs.get("nets", {}).get("signal_nets", []), kwargs.get("nets", {}).get("power_ground_nets", [])
49
53
  )
54
+
50
55
  self.components = [CfgComponent(self, **component) for component in kwargs.get("components", [])]
56
+
51
57
  self.padstacks = CfgPadstacks(self, kwargs.get("padstacks", None))
58
+
52
59
  self.pin_groups = [CfgPinGroup(self, pin_group) for pin_group in kwargs.get("pin_groups", [])]
60
+
53
61
  self.ports = [CfgPort(self, **port) for port in kwargs.get("ports", [])]
62
+
54
63
  self.sources = [CfgSources(self, **source) for source in kwargs.get("sources", [])]
55
- self.setups = [CfgSetup(self)]
64
+
65
+ self.setups = []
56
66
  if kwargs.get("setups", None):
57
67
  self.setups = [CfgSetup(self, setup) for setup in kwargs.get("setups", [])]
58
- self.stackup = None
68
+
69
+ self.stackup = CfgStackup(self._pedb, data=kwargs.get("stackup", {}))
70
+
59
71
  self.s_parameters = [
60
72
  CfgSParameterModel(self, self.general.s_parameter_library, sparam_model)
61
73
  for sparam_model in kwargs.get("s_parameters", [])
62
74
  ]
75
+
63
76
  self.spice_models = [
64
77
  CfgSpiceModel(self, self.general.spice_model_library, spice_model)
65
78
  for spice_model in kwargs.get("spice_models", [])
66
79
  ]
80
+
67
81
  self.package_definition = None
68
82
  self.operations = None
83
+
84
+ @pyedb_function_handler
85
+ def apply(self):
86
+ """Apply configuration settings to the current design"""
87
+ self.stackup.apply()
@@ -25,7 +25,7 @@ class CfgGeneral:
25
25
  """Manage configuration general settings."""
26
26
 
27
27
  def __init__(self, pdata, general_dict):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self.spice_model_library = ""
30
30
  self.s_parameter_library = ""
31
31
  if general_dict:
@@ -25,7 +25,7 @@ class CfgNets:
25
25
  """Manage configuration net class."""
26
26
 
27
27
  def __init__(self, pdata, signal_nets=None, power_nets=None):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self.signal_nets = []
30
30
  self.power_nets = []
31
31
  if signal_nets:
@@ -28,7 +28,7 @@ class CfgPadstacks:
28
28
  """Padstack data class."""
29
29
 
30
30
  def __init__(self, pdata, padstack_dict=None):
31
- self._pedb = pdata.pedb
31
+ self._pedb = pdata._pedb
32
32
  self.definitions = []
33
33
  self.instances = []
34
34
  self._padstack_dict = padstack_dict
@@ -52,7 +52,7 @@ class Definition:
52
52
  """Padstack definition data class."""
53
53
 
54
54
  def __init__(self, pdata, definition_dict):
55
- self._pedb = pdata.pedb
55
+ self._pedb = pdata._pedb
56
56
  self._definition_dict = definition_dict
57
57
  self.name = self._definition_dict.get("name", None)
58
58
  self.hole_diameter = self._definition_dict.get("hole_diameter", None)
@@ -78,7 +78,7 @@ class Instance:
78
78
  """Instance data class."""
79
79
 
80
80
  def __init__(self, pdata, instances_dict):
81
- self._pedb = pdata.pedb
81
+ self._pedb = pdata._pedb
82
82
  self._instances_dict = instances_dict
83
83
  self.name = self._instances_dict.get("name", "")
84
84
  self.backdrill_top = None
@@ -25,7 +25,7 @@ class CfgPinGroup:
25
25
  """Manage configuration pin group class."""
26
26
 
27
27
  def __init__(self, pdata, pingroup_dict):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self._pingroup_dict = pingroup_dict
30
30
  self.name = self._pingroup_dict.get("name", "")
31
31
  self.reference_designator = self._pingroup_dict.get("reference_designator", "")
@@ -36,7 +36,7 @@ class CfgPinGroup:
36
36
  """Apply pin group on layout."""
37
37
  if self.pins:
38
38
  if not self._pedb.siwave.create_pin_group(self.reference_designator, list(self.pins), self.name):
39
- self._pedb.loogger.error(f"Failed to create pin group on pins {self.pins}")
39
+ self._pedb.logger.error(f"Failed to create pin group on pins {self.pins}")
40
40
  return False
41
41
  self._pedb.logger.info(f"Pin group {self.name} created.")
42
42
  return True
@@ -27,7 +27,7 @@ class CfgCircuitElement:
27
27
  @property
28
28
  def pedb(self):
29
29
  """Edb."""
30
- return self._pdata.pedb
30
+ return self._pdata._pedb
31
31
 
32
32
  @pyedb_function_handler
33
33
  def __init__(self, pdata, **kwargs):
@@ -76,7 +76,7 @@ class CfgCircuitElement:
76
76
  search_radius = neg_value.get("search_radius", "5e-3")
77
77
  temp = dict()
78
78
  for i, j in pos_objs.items():
79
- temp[i] = self._pdata.pedb.padstacks.get_reference_pins(j, ref_net, search_radius, max_limit=1)[0]
79
+ temp[i] = self._pdata._pedb.padstacks.get_reference_pins(j, ref_net, search_radius, max_limit=1)[0]
80
80
  self.neg_terminal = {
81
81
  i: j.create_terminal(i + "_ref") if not j.terminal else j.terminal for i, j in temp.items()
82
82
  }
@@ -105,7 +105,7 @@ class CfgCircuitElement:
105
105
  pins.update(get_pin_obj(i))
106
106
  else:
107
107
  if terminal_type == "net":
108
- temp = self._pdata.pedb.components.get_pins(self.reference_designator, terminal_value[0])
108
+ temp = self._pdata._pedb.components.get_pins(self.reference_designator, terminal_value[0])
109
109
  elif terminal_type == "pin_group":
110
110
  pin_group = self.pedb.siwave.pin_groups[terminal_value[0]]
111
111
  temp = pin_group.pins
@@ -119,7 +119,7 @@ class CfgCircuitElement:
119
119
  else:
120
120
  pg_name = f"pg_{self.name}_{self.reference_designator}"
121
121
  pin_names = [i.pin_number for i in pins.values()]
122
- name, temp = self._pdata.pedb.siwave.create_pin_group(self.reference_designator, pin_names, pg_name)
122
+ name, temp = self._pdata._pedb.siwave.create_pin_group(self.reference_designator, pin_names, pg_name)
123
123
  return {name: temp}
124
124
 
125
125
 
@@ -25,7 +25,7 @@ from pathlib import Path
25
25
 
26
26
  class CfgSParameterModel:
27
27
  def __init__(self, pdata, path_lib, sparam_dict):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self.path_libraries = path_lib
30
30
  self._sparam_dict = sparam_dict
31
31
  self.name = self._sparam_dict.get("name", "")
@@ -89,7 +89,7 @@ class DcIrSettings:
89
89
 
90
90
  class CfgSetup:
91
91
  def __init__(self, pdata, setup_dict=None):
92
- self._pedb = pdata.pedb
92
+ self._pedb = pdata._pedb
93
93
  self._setup_dict = None
94
94
  self.name = "PyEDB_setup"
95
95
  self.type = self.SetupType.HFSS
@@ -25,7 +25,7 @@ from pathlib import Path
25
25
 
26
26
  class CfgSpiceModel:
27
27
  def __init__(self, pdata, path_lib, spice_dict):
28
- self._pedb = pdata.pedb
28
+ self._pedb = pdata._pedb
29
29
  self.path_libraries = path_lib
30
30
  self._spice_dict = spice_dict
31
31
  self.name = self._spice_dict.get("name", "")
@@ -0,0 +1,135 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+
24
+ from pyedb.generic.general_methods import pyedb_function_handler
25
+
26
+
27
+ class CfgStackup:
28
+ def __init__(self, pedb, data):
29
+ self._pedb = pedb
30
+
31
+ self.materials = [CfgMaterial(self._pedb, **mat) for mat in data.get("materials", [])]
32
+ self.layers = [CfgLayer(self._pedb, **lay) for lay in data.get("layers", [])]
33
+
34
+ @pyedb_function_handler
35
+ def apply(self):
36
+ """Apply configuration settings to the current design"""
37
+ if len(self.materials):
38
+ self.__apply_materials()
39
+ if len(self.layers):
40
+ self.__apply_layers()
41
+
42
+ @pyedb_function_handler
43
+ def __apply_layers(self):
44
+ """Apply layer settings to the current design"""
45
+ layers = list()
46
+ layers.extend(self.layers)
47
+ input_signal_layers = [i for i in layers if i.type.lower() == "signal"]
48
+ if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
49
+ self._pedb.logger.error("Input signal layer count do not match.")
50
+ return False
51
+
52
+ removal_list = []
53
+ lc_signal_layers = []
54
+ for name, obj in self._pedb.stackup.all_layers.items():
55
+ if obj.type == "dielectric":
56
+ removal_list.append(name)
57
+ elif obj.type == "signal":
58
+ lc_signal_layers.append(obj.id)
59
+ for l in removal_list:
60
+ self._pedb.stackup.remove_layer(l)
61
+
62
+ # update all signal layers
63
+ id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
64
+ signal_idx = 0
65
+ for l in layers:
66
+ if l.type == "signal":
67
+ layer_id = lc_signal_layers[signal_idx]
68
+ layer_name = id_name[layer_id]
69
+ attrs = {
70
+ i: j for i, j in l.__dict__.items() if not i.startswith("_") and isinstance(j, (int, float, str))
71
+ }
72
+ self._pedb.stackup.layers[layer_name].update(**attrs)
73
+ signal_idx = signal_idx + 1
74
+
75
+ # add all dielectric layers. Dielectric layers must be added last. Otherwise,
76
+ # dielectric layer will occupy signal and document layer id.
77
+ prev_layer_clone = None
78
+ l = layers.pop(0)
79
+ if l.type == "signal":
80
+ prev_layer_clone = self._pedb.stackup.layers[l.name]
81
+ else:
82
+ attrs = {i: j for i, j in l.__dict__.items() if not i.startswith("_") and isinstance(j, (int, float, str))}
83
+ prev_layer_clone = self._pedb.stackup.add_layer_top(**attrs)
84
+ for idx, l in enumerate(layers):
85
+ if l.type == "dielectric":
86
+ attrs = {
87
+ i: j for i, j in l.__dict__.items() if not i.startswith("_") and isinstance(j, (int, float, str))
88
+ }
89
+ prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **attrs)
90
+ elif l.type == "signal":
91
+ prev_layer_clone = self._pedb.stackup.layers[l.name]
92
+
93
+ @pyedb_function_handler
94
+ def __apply_materials(self):
95
+ """Apply material settings to the current design"""
96
+ materials_in_db = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
97
+ for mat_in_cfg in self.materials:
98
+ if mat_in_cfg.name.lower() in materials_in_db:
99
+ self._pedb.materials.delete_material(materials_in_db[mat_in_cfg.name.lower()])
100
+
101
+ attrs = {
102
+ i: j
103
+ for i, j in mat_in_cfg.__dict__.items()
104
+ if not i.startswith("_") and isinstance(j, (int, float, str))
105
+ }
106
+ mat = self._pedb.materials.add_material(**attrs)
107
+
108
+
109
+ class CfgMaterial:
110
+ def __init__(self, pedb, **kwargs):
111
+ self._pedb = pedb
112
+ self.name = kwargs.get("name")
113
+ self.permittivity = kwargs.get("permittivity", None)
114
+ self.conductivity = kwargs.get("conductivity", None)
115
+ self.dielectric_loss_tangent = kwargs.get("dielectric_loss_tangent", None)
116
+ self.magnetic_loss_tangent = kwargs.get("magnetic_loss_tangent", None)
117
+ self.mass_density = kwargs.get("mass_density", None)
118
+ self.permeability = kwargs.get("permeability", None)
119
+ self.poisson_ratio = kwargs.get("poisson_ratio", None)
120
+ self.specific_heat = kwargs.get("specific_heat", None)
121
+ self.thermal_conductivity = kwargs.get("thermal_conductivity", None)
122
+ self.youngs_modulus = kwargs.get("youngs_modulus", None)
123
+ self.thermal_expansion_coefficient = kwargs.get("thermal_expansion_coefficient", None)
124
+
125
+
126
+ class CfgLayer:
127
+ def __init__(self, pedb, **kwargs):
128
+ self._pedb = pedb
129
+ self.name = kwargs.get("name", None)
130
+ self.type = kwargs.get("type", None)
131
+ self.material = kwargs.get("material", None)
132
+ self.fill_material = kwargs.get("fill_material", None)
133
+ self.thickness = kwargs.get("thickness", None)
134
+ self.etch_factor = kwargs.get("etch_factor", None)
135
+ self.lower_elevation = kwargs.get("lower_elevation", None)
@@ -27,7 +27,6 @@ import toml
27
27
 
28
28
  from pyedb.configuration.cfg_data import CfgData
29
29
  from pyedb.dotnet.edb_core.definition.package_def import PackageDef
30
- from pyedb.dotnet.edb_core.stackup import LayerCollection
31
30
  from pyedb.generic.general_methods import pyedb_function_handler
32
31
 
33
32
 
@@ -133,8 +132,6 @@ class Configuration:
133
132
  port.create()
134
133
 
135
134
  # Configure sources
136
- """if "sources" in self.data:
137
- self._load_sources()"""
138
135
  for source in self.cfg_data.sources:
139
136
  source.create()
140
137
 
@@ -143,8 +140,7 @@ class Configuration:
143
140
  setup.apply()
144
141
 
145
142
  # Configure stackup
146
- if "stackup" in self.data:
147
- self._load_stackup()
143
+ self.cfg_data.stackup.apply()
148
144
 
149
145
  # Configure S-parameter
150
146
  for s_parameter_model in self.cfg_data.s_parameters:
@@ -182,56 +178,44 @@ class Configuration:
182
178
  layers = data.get("layers")
183
179
 
184
180
  if layers:
185
- lc = self._pedb.stackup
186
181
  input_signal_layers = [i for i in layers if i["type"].lower() == "signal"]
187
- if not len(input_signal_layers) == len(lc.signal_layers):
182
+ if not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
188
183
  self._pedb.logger.error("Input signal layer count do not match.")
189
184
  return False
190
185
 
191
- layer_clones = []
192
- doc_layer_clones = []
193
- for name, obj in lc.layers.items():
194
- if obj.is_stackup_layer:
195
- if obj.type == "signal": # keep signal layers
196
- layer_clones.append(obj)
197
- else:
198
- doc_layer_clones.append(obj)
199
-
200
- lc_new = LayerCollection(self._pedb)
201
- lc_new.auto_refresh = False
202
- signal_layer_ids = {}
203
- top_layer_clone = None
204
-
205
- # add all signal layers
186
+ removal_list = []
187
+ lc_signal_layers = []
188
+ for name, obj in self._pedb.stackup.all_layers.items():
189
+ if obj.type == "dielectric":
190
+ removal_list.append(name)
191
+ elif obj.type == "signal":
192
+ lc_signal_layers.append(obj.id)
193
+ for l in removal_list:
194
+ self._pedb.stackup.remove_layer(l)
195
+
196
+ # update all signal layers
197
+ id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
198
+ signal_idx = 0
206
199
  for l in layers:
207
200
  if l["type"] == "signal":
208
- clone = layer_clones.pop(0)
209
- clone.update(**l)
210
- lc_new.add_layer_bottom(name=clone.name, layer_clone=clone)
211
- signal_layer_ids[clone.name] = clone.id
212
-
213
- # add all document layers at bottom
214
- for l in doc_layer_clones:
215
- doc_layer = lc_new.add_document_layer(name=l.name, layer_clone=l)
216
- first_doc_layer_name = doc_layer.name
201
+ layer_id = lc_signal_layers[signal_idx]
202
+ layer_name = id_name[layer_id]
203
+ self._pedb.stackup.layers[layer_name].update(**l)
204
+ signal_idx = signal_idx + 1
217
205
 
218
206
  # add all dielectric layers. Dielectric layers must be added last. Otherwise,
219
207
  # dielectric layer will occupy signal and document layer id.
220
208
  prev_layer_clone = None
221
209
  l = layers.pop(0)
222
210
  if l["type"] == "signal":
223
- prev_layer_clone = lc_new.layers[l["name"]]
211
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
224
212
  else:
225
- prev_layer_clone = lc_new.add_layer_top(**l)
213
+ prev_layer_clone = self._pedb.stackup.add_layer_top(**l)
226
214
  for idx, l in enumerate(layers):
227
215
  if l["type"] == "dielectric":
228
- prev_layer_clone = lc_new.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
229
- else:
230
- prev_layer_clone = lc_new.layers[l["name"]]
231
-
232
- lc._edb_object = lc_new._edb_object
233
- lc_new.auto_refresh = True
234
- lc.update_layout()
216
+ prev_layer_clone = self._pedb.stackup.add_layer_below(base_layer_name=prev_layer_clone.name, **l)
217
+ elif l["type"] == "signal":
218
+ prev_layer_clone = self._pedb.stackup.layers[l["name"]]
235
219
 
236
220
  @pyedb_function_handler
237
221
  def _load_operations(self):
pyedb/dotnet/edb.py CHANGED
@@ -846,9 +846,7 @@ class Edb(Database):
846
846
  >>> edbapp.stackup.layers["TOP"].thickness == 4e-05
847
847
  >>> edbapp.stackup.add_layer("Diel", "GND", layer_type="dielectric", thickness="0.1mm", material="FR4_epoxy")
848
848
  """
849
- if not self._stackup2 and self.active_db:
850
- self._stackup2 = Stackup(self, self.layout.layer_collection)
851
- return self._stackup2
849
+ return Stackup(self, self.layout.layer_collection)
852
850
 
853
851
  @property
854
852
  def materials(self):
@@ -257,8 +257,8 @@ class StackupLayerEdbClass(LayerEdbClass):
257
257
  self._lower_elevation = 0.0
258
258
 
259
259
  def _create(self, layer_type):
260
- layer_type = self._layer_name_mapping[layer_type]
261
- layer_type = self._layer_type_mapping[layer_type]
260
+ layer_type_edb_name = self._layer_name_mapping[layer_type]
261
+ layer_type = self._layer_type_mapping[layer_type_edb_name]
262
262
  self._edb_object = self._pedb.edb_api.cell._cell.StackupLayer(
263
263
  self._name,
264
264
  layer_type,
@@ -69,8 +69,6 @@ logger = logging.getLogger(__name__)
69
69
 
70
70
 
71
71
  class LayerCollection(object):
72
- auto_refresh = True
73
-
74
72
  def __init__(self, pedb, edb_object=None):
75
73
  self._pedb = pedb
76
74
 
@@ -91,17 +89,21 @@ class LayerCollection(object):
91
89
  "multizone": self._pedb.edb_api.cell._cell.LayerCollectionMode.MultiZone,
92
90
  }
93
91
 
94
- def update_layout(self, stackup=None):
92
+ def update_layout(self):
95
93
  """Set layer collection into edb.
96
94
 
97
95
  Parameters
98
96
  ----------
99
97
  stackup
100
98
  """
101
- if stackup:
102
- self._edb_object = stackup._edb_object
103
99
  self._pedb.layout.layer_collection = self._edb_object
104
100
 
101
+ @pyedb_function_handler()
102
+ def refresh_layer_collection(self):
103
+ """Refresh layer collection from Edb. This method is run on demand after all edit operations on stackup."""
104
+ self._edb_object = self._pedb.edb_api.cell._cell.LayerCollection(self._pedb.layout.layer_collection)
105
+ self._lc = self._edb_object
106
+
105
107
  @pyedb_function_handler
106
108
  def _add_layer(self, add_method, base_layer_name="", **kwargs):
107
109
  """Add a layer to edb.
@@ -115,7 +117,13 @@ class LayerCollection(object):
115
117
  if layer_clone:
116
118
  obj = layer_clone
117
119
  else:
118
- obj = StackupLayerEdbClass(self._pedb, edb_object=None, **kwargs)
120
+ layer_type = kwargs.get("layer_type", None)
121
+ if not layer_type:
122
+ layer_type = kwargs["type"]
123
+ if layer_type in ["signal", "dielectric"]:
124
+ obj = StackupLayerEdbClass(self._pedb, edb_object=None, **kwargs)
125
+ else:
126
+ obj = LayerEdbClass(self._pedb, edb_object=None, **kwargs)
119
127
  method_top_bottom = None
120
128
  method_above_below = None
121
129
  if add_method == "add_layer_top":
@@ -134,8 +142,7 @@ class LayerCollection(object):
134
142
  obj = obj if method_top_bottom(obj._edb_object) else False
135
143
  elif method_above_below:
136
144
  obj = obj if method_above_below(obj._edb_object, base_layer_name) else False
137
- if self.auto_refresh:
138
- self.update_layout()
145
+ self.update_layout()
139
146
  return obj
140
147
 
141
148
  @pyedb_function_handler
@@ -268,8 +275,7 @@ class LayerCollection(object):
268
275
  lc.AddLayerBottom(i._edb_object)
269
276
 
270
277
  self._edb_object = lc
271
- if self.auto_refresh:
272
- self.update_layout()
278
+ self.update_layout()
273
279
 
274
280
  if not obj:
275
281
  logger.info("Layer clone was not found in stackup or non stackup layers.")
@@ -278,33 +284,32 @@ class LayerCollection(object):
278
284
  @property
279
285
  def stackup_layers(self):
280
286
  """Retrieve the dictionary of signal and dielectric layers."""
281
- temp = list(self._edb_object.Layers((self._pedb.edb_api.cell.layer_type_set.StackupLayerSet)))
282
- layers = OrderedDict()
283
- for i in temp:
284
- name = i.GetName()
285
- layers[name] = StackupLayerEdbClass(self._pedb, i.Clone(), name=name)
286
- return layers
287
+ warnings.warn("Use new property :func:`layers` instead.", DeprecationWarning)
288
+ return self.layers
287
289
 
288
290
  @property
289
291
  def non_stackup_layers(self):
290
292
  """Retrieve the dictionary of signal layers."""
291
- temp = list(self._edb_object.Layers(self._layer_type_set_mapping["non_stackup_layer_set"]))
292
- layers = OrderedDict()
293
- for i in temp:
294
- name = i.GetName()
295
- layers[name] = LayerEdbClass(self._pedb, i, name=name)
296
- return layers
293
+ return {name: obj for name, obj in self.all_layers.items() if not obj.is_stackup_layer}
297
294
 
298
295
  @property
299
- def layers_by_id(self):
300
- """Retrieve the list of layers with their ids."""
301
- layer_list = list(self._layer_collection.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
302
- temp = []
296
+ def all_layers(self):
297
+ self.refresh_layer_collection()
298
+ layer_list = list(self._edb_object.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
299
+ temp = dict()
303
300
  for i in layer_list:
304
- obj = StackupLayerEdbClass(self._pedb, i.Clone(), name=i.GetName)
305
- temp.append([obj.id, obj.name])
301
+ if i.IsStackupLayer():
302
+ obj = StackupLayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
303
+ else:
304
+ obj = LayerEdbClass(self._pedb, i.Clone(), name=i.GetName())
305
+ temp[obj.name] = obj
306
306
  return temp
307
307
 
308
+ @property
309
+ def layers_by_id(self):
310
+ """Retrieve the list of layers with their ids."""
311
+ return [[obj.id, name] for name, obj in self.all_layers.items()]
312
+
308
313
  @property
309
314
  def layers(self):
310
315
  """Retrieve the dictionary of layers.
@@ -313,22 +318,14 @@ class LayerCollection(object):
313
318
  -------
314
319
  Dict[str, :class:`pyedb.dotnet.edb_core.edb_data.layer_data.LayerEdbClass`]
315
320
  """
316
- _lays = OrderedDict()
317
- layer_list = list(self._edb_object.Layers(self._pedb.edb_api.cell.layer_type_set.AllLayerSet))
318
- for l in layer_list:
319
- name = l.GetName()
320
- if not l.IsStackupLayer():
321
- _lays[name] = LayerEdbClass(self._pedb, l, name=name)
322
- else:
323
- _lays[name] = StackupLayerEdbClass(self._pedb, l, name=name)
324
- return _lays
321
+ return {name: obj for name, obj in self.all_layers.items() if obj.is_stackup_layer}
325
322
 
326
323
 
327
324
  class Stackup(LayerCollection):
328
325
  """Manages EDB methods for stackup accessible from `Edb.stackup` property."""
329
326
 
330
327
  def __getitem__(self, item):
331
- return self.layers[item]
328
+ return self.all_layers[item]
332
329
 
333
330
  def __init__(self, pedb, edb_object=None):
334
331
  super().__init__(pedb, edb_object)
@@ -576,12 +573,6 @@ class Stackup(LayerCollection):
576
573
  )
577
574
  return True
578
575
 
579
- @pyedb_function_handler()
580
- def refresh_layer_collection(self):
581
- """Refresh layer collection from Edb. This method is run on demand after all edit operations on stackup."""
582
- self._lc = self._pedb.edb_api.cell._cell.LayerCollection(self._pedb.layout.layer_collection)
583
- self._edb_object = self._lc
584
-
585
576
  @property
586
577
  def _layer_collection(self):
587
578
  """Copy of EDB layer collection.
@@ -591,8 +582,7 @@ class Stackup(LayerCollection):
591
582
  :class:`Ansys.Ansoft.Edb.Cell.LayerCollection`
592
583
  Collection of layers.
593
584
  """
594
- if not self._lc:
595
- self.refresh_layer_collection()
585
+ self.refresh_layer_collection()
596
586
  return self._lc
597
587
 
598
588
  @property
@@ -620,7 +610,7 @@ class Stackup(LayerCollection):
620
610
  self._layer_collection.SetMode(mode.Overlapping)
621
611
  elif value == 2 or value == mode.MultiZone or value == "MultiZone":
622
612
  self._layer_collection.SetMode(mode.MultiZone)
623
- self._pedb.layout.layer_collection = self._layer_collection
613
+ self.update_layout()
624
614
 
625
615
  @property
626
616
  def stackup_mode(self):
@@ -744,9 +734,8 @@ class Stackup(LayerCollection):
744
734
  _lc.AddStackupLayerAtElevation(layer_clone)
745
735
  elif operation == "non_stackup":
746
736
  _lc.AddLayerBottom(layer_clone)
747
- if self.auto_refresh:
748
- self._pedb.layout.layer_collection = _lc
749
- self.refresh_layer_collection()
737
+ self._pedb.layout.layer_collection = _lc
738
+ self.refresh_layer_collection()
750
739
  return True
751
740
 
752
741
  @pyedb_function_handler()
@@ -814,17 +803,7 @@ class Stackup(LayerCollection):
814
803
  bool
815
804
  "True" if successful, ``False`` if failed.
816
805
  """
817
- outlineLayer = self._pedb.edb_api.cell.layer.FindByName(self._pedb.layout.layer_collection, outline_name)
818
- if outlineLayer.IsNull():
819
- return self.add_layer(
820
- outline_name,
821
- layer_type="outline",
822
- material="",
823
- fillMaterial="",
824
- thickness="",
825
- )
826
- else:
827
- return False
806
+ return self.add_document_layer(name="Outline", layer_type="outline")
828
807
 
829
808
  # TODO: Update optional argument material into material_name and fillMaterial into fill_material_name
830
809
  @pyedb_function_handler()
pyedb/siwave.py CHANGED
@@ -11,6 +11,7 @@ from __future__ import absolute_import # noreorder
11
11
  import os
12
12
  import pkgutil
13
13
  import sys
14
+ import time
14
15
  import warnings
15
16
 
16
17
  from pyedb.dotnet.clr_module import _clr
@@ -362,9 +363,29 @@ class Siwave(object): # pragma no cover
362
363
  ``True`` when successful, ``False`` when failed.
363
364
 
364
365
  """
366
+ if not os.path.splitext(file_path)[-1] == ".htm":
367
+ fpath = file_path + ".htm"
368
+ else:
369
+ fpath = file_path
365
370
  self.oproject.ScrExportDcSimReportScaling("All", "All", -1, -1, False)
366
- flag = self.oproject.ScrExportDcSimReport(simulation_name, background_color, file_path)
367
- return True if flag == 0 else False
371
+ flag = self.oproject.ScrExportDcSimReport(simulation_name, background_color, fpath)
372
+ if flag == 0:
373
+ while True:
374
+ self._logger.info(f"Exporting Siwave DC simulation report to {fpath}.")
375
+ if os.path.isfile(fpath):
376
+ break
377
+ else:
378
+ time.sleep(1)
379
+ os.path.getsize(fpath)
380
+ while True:
381
+ file_size = os.path.getsize(fpath)
382
+ if file_size > 0:
383
+ break
384
+ else:
385
+ time.sleep(1)
386
+ return True
387
+ else:
388
+ return False
368
389
 
369
390
  @pyedb_function_handler
370
391
  def run_dc_simulation(self, export_dc_power_data_to_icepak=False):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyedb
3
- Version: 0.12.0
3
+ Version: 0.12.2
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>
@@ -24,7 +24,7 @@ Requires-Dist: toml == 0.10.2
24
24
  Requires-Dist: Rtree >= 1.2.0
25
25
  Requires-Dist: ansys-sphinx-theme>=0.10.0,<0.17 ; extra == "doc"
26
26
  Requires-Dist: imageio>=2.30.0,<2.35 ; extra == "doc"
27
- Requires-Dist: ipython>=8.13.0,<8.25 ; extra == "doc"
27
+ Requires-Dist: ipython>=8.13.0,<8.26 ; extra == "doc"
28
28
  Requires-Dist: jupyterlab>=4.0.0,<4.3 ; extra == "doc"
29
29
  Requires-Dist: matplotlib>=3.5.0,<3.10 ; extra == "doc"
30
30
  Requires-Dist: nbsphinx>=0.9.0,<0.10 ; extra == "doc"
@@ -1,23 +1,24 @@
1
- pyedb/__init__.py,sha256=NdSqRuOcb6BkvaUJJ65vhYSlT5l50M9SK2aD7jz-veA,1521
1
+ pyedb/__init__.py,sha256=89W_Pm5u7UQKGWpl8TOyWDGSuIu-mEWVfdt-4e9APlQ,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=c2stPkGPdM9c0wJ19SJq_uiYTdW3sp-uO8MVA_iDw30,12548
4
+ pyedb/siwave.py,sha256=E6KoOaGqn6sfFSVe-iyh-oOC4D0c-X8iFAaX8z2Bcgs,13204
5
5
  pyedb/configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- pyedb/configuration/cfg_boundaries.py,sha256=iThJw52omnGikp20uNVgW4w0VcrzF68dXUaMb2MfOt4,6646
7
- pyedb/configuration/cfg_components.py,sha256=cvQfMjh6HBTVzVuDI7A8zkEhtgraG25dJqHRH-FbkTA,8789
8
- pyedb/configuration/cfg_data.py,sha256=ZThr2rpCj4axwrBr-aQWtiTztEhRAZb1pX-S3_92aJQ,3483
9
- pyedb/configuration/cfg_general.py,sha256=dB5Tpird4uiyrseOe8-QlWKsat15TjMLar5I8VZME3c,1625
10
- pyedb/configuration/cfg_nets.py,sha256=mJvN_ON4Qw5psNV3agXCQAhVJbRnBpRZu1Ti3b7QnMw,1879
11
- pyedb/configuration/cfg_padstacks.py,sha256=5ta0xkdSaf4qk5lXjM-U4GB2vNS31nhEGsZwwRlhPUI,5568
12
- pyedb/configuration/cfg_pin_groups.py,sha256=BAv-u1e8aPXSTBwUBzDkzRiXB2mfCqb60I5tTrwgI7Y,2877
13
- pyedb/configuration/cfg_ports_sources.py,sha256=kicbrgw1YLB2m7xJhrjo9LcfcbwTncGguuzEjZ2pUcQ,7787
14
- pyedb/configuration/cfg_s_parameter_models.py,sha256=HPo4sgF5tVefUwgzlP8pDBVSZ1x_pY2EiOtA0-QXjc8,2854
15
- pyedb/configuration/cfg_setup.py,sha256=zhq285s5P4s90Dm5s550ldwyIVO8aXiPjAwy87ipRXU,8791
16
- pyedb/configuration/cfg_spice_models.py,sha256=5gr28-4u4uj4qY8vgYFAI_PgzOQp-wPgTMMc_WcAN_w,2434
17
- pyedb/configuration/configuration.py,sha256=ykDlI3v8w8x-qWuV8PrwIAHVe9jmBwCb8OeJLfBF4lk,10965
6
+ pyedb/configuration/cfg_boundaries.py,sha256=ckb-OfaObItwy-xc0LqkHJyeCfKC5vg668olPjZbaKo,6647
7
+ pyedb/configuration/cfg_components.py,sha256=S9_viU-hzuiOyKfAx91VL8MgAQAGFoS9Ep6f_eerEvM,8790
8
+ pyedb/configuration/cfg_data.py,sha256=MBER7GwieKSpkTiwVT4bMP2dvKIBx_Ku4qBcp7KIM4E,3788
9
+ pyedb/configuration/cfg_general.py,sha256=0dtd-rkQt2aYR3EOL0c3sNuDuJs7htRos1OWck3rxaI,1626
10
+ pyedb/configuration/cfg_nets.py,sha256=SCiBTUVHX3Ub91MEU88m0xcHIot_axT9QTFJ8LawppI,1880
11
+ pyedb/configuration/cfg_padstacks.py,sha256=5t799x_mfwLjCAic-B13v3I6FgDswysXdcKmeOxz4Uo,5571
12
+ pyedb/configuration/cfg_pin_groups.py,sha256=aidsOXTHhEyE8UGRiT1nvyn-3sD0CU_n8RR19AmhQrk,2877
13
+ pyedb/configuration/cfg_ports_sources.py,sha256=XDwvlCkbwlAjMpvrK_q7MVWQEVsyItXOFH3VkjGnC04,7791
14
+ pyedb/configuration/cfg_s_parameter_models.py,sha256=NzS3eBjBSnd7ZDk_TsX04dqRcRXompjx1DxCe1UzWMw,2855
15
+ pyedb/configuration/cfg_setup.py,sha256=XDpddzsIXWMHmrY-qonS5aQaFdS2OUZDQy5v8qWLCXE,8792
16
+ pyedb/configuration/cfg_spice_models.py,sha256=tBY3okFiEffMGvBkpmZQrCrovpt-d62k51_WkkV4jqo,2435
17
+ pyedb/configuration/cfg_stackup.py,sha256=RiOqyhAga5EcOVQld2GQf8KU0ZPc8LQP-wNnulaDsM0,6122
18
+ pyedb/configuration/configuration.py,sha256=Jkk8w8da7HxDZuIiXN428FVw4y85oBky8v4EC_NquIs,10524
18
19
  pyedb/dotnet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  pyedb/dotnet/clr_module.py,sha256=Mo13Of3DVSA5HR-5xZEXOiHApIKy52CUxtJ2gPkEu1A,3406
20
- pyedb/dotnet/edb.py,sha256=GmGixrH9_i98d_NJEWUMpd5BeGGbjyqTL1zve0Mlqfw,172892
21
+ pyedb/dotnet/edb.py,sha256=jSt794srQBzaxt3-iZqcv4ziOgNThWn46k3-V3svJqc,172798
21
22
  pyedb/dotnet/application/Variables.py,sha256=nov1kIyJO25iz8pvbU3MK1meMpRLwtISmzYqJhc7Ouo,79042
22
23
  pyedb/dotnet/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
24
  pyedb/dotnet/edb_core/__init__.py,sha256=nIRLJ8VZLcMAp12zmGsnZ5x2BEEl7q_Kj_KAOXxVjpQ,52
@@ -32,7 +33,7 @@ pyedb/dotnet/edb_core/nets.py,sha256=ZQ5sk7cgTQJTbHd7JQa7MmBBV_crsWGtcLhKpSbfYMw
32
33
  pyedb/dotnet/edb_core/obj_base.py,sha256=lufR0sZj0QfZ2wlNvLL6aM1KVqCNY2A7taPPdWcK20w,3312
33
34
  pyedb/dotnet/edb_core/padstack.py,sha256=PqXkSfyLRtdehm72sYiVMBUkNlDkivJ-eRoQWCzwNgw,57439
34
35
  pyedb/dotnet/edb_core/siwave.py,sha256=4v68zlCO-Czv8A3qtckfQ94jRFbMxM4kuoEDVRo_cmM,62495
35
- pyedb/dotnet/edb_core/stackup.py,sha256=rg2LnxUyfd9Nnrj9uAd-0dkr65TQk7iMe0lS6cglaFc,122900
36
+ pyedb/dotnet/edb_core/stackup.py,sha256=Zko2gaotcJnILv_4SlZYzFc-NGblmTFBmEua7BSLcHU,122186
36
37
  pyedb/dotnet/edb_core/cell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
38
  pyedb/dotnet/edb_core/cell/hierarchy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  pyedb/dotnet/edb_core/cell/hierarchy/model.py,sha256=cJzNJLiuuoesfCL8-jWo8LbgGbfXrTYNQqmeeE38ieM,3309
@@ -55,7 +56,7 @@ pyedb/dotnet/edb_core/edb_data/edbvalue.py,sha256=Vj_11HXsQUNavizKp5FicORm6cjhXR
55
56
  pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py,sha256=5koQSKdYC6Deh4haLUDAxnHlRa-j5S6g4eyAfiGgZP8,13190
56
57
  pyedb/dotnet/edb_core/edb_data/hfss_pi_simulation_setup_data.py,sha256=v3z3h_27v3jRmDXqUjBS8P6UZMi-zuZQrZiYbE-RDw4,15657
57
58
  pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py,sha256=naka5Bm9Ditb6Cj_F1KMrxwGk8Cn2fPtnXlyGb9IY9E,49039
58
- pyedb/dotnet/edb_core/edb_data/layer_data.py,sha256=HVPmE_Rny29J1c8qlJ3TSNZaMOTSxTgE9_vIiQJG0cE,25900
59
+ pyedb/dotnet/edb_core/edb_data/layer_data.py,sha256=N3OIxdx1oeX3Lg1nmM-UcJ_8NQdaQD-_XgUEVlGLzOI,25918
59
60
  pyedb/dotnet/edb_core/edb_data/nets_data.py,sha256=iBegT3fa5DwvjD0Wfd-wlJztFrb33I5v6nzSUhNS6-I,10099
60
61
  pyedb/dotnet/edb_core/edb_data/padstacks_data.py,sha256=IiF_wS9ZnyW-8W3wbcvinPAaL0LVuPGU74tHFZgZ1ZQ,79729
61
62
  pyedb/dotnet/edb_core/edb_data/ports.py,sha256=FYxB2rDUtN_OsYAbodXbc5mA_d0BUebmin_B5kkUw3U,9223
@@ -148,7 +149,7 @@ pyedb/misc/siw_feature_config/emc/tag_library.py,sha256=yUK4w3hequU017E2DbkA4KE2
148
149
  pyedb/misc/siw_feature_config/emc/xml_generic.py,sha256=55X-V0OxWq-v7FTiDVjaZif8V_2xxsvJlJ8bs9Bf61I,2521
149
150
  pyedb/modeler/geometry_operators.py,sha256=LDqEaeerw9H8Yva-SJhX3Afdni08OciO9t5G0c_tdqs,66820
150
151
  pyedb/siwave_core/icepak.py,sha256=WnZ-t8mik7LDY06V8hZFV-TxRZJQWK7bu_8Ichx-oBs,5206
151
- pyedb-0.12.0.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
152
- pyedb-0.12.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
153
- pyedb-0.12.0.dist-info/METADATA,sha256=nkaA2TVEuG-IKFuseaCrohmgXT6V21jmp3ZsaCao8RE,8354
154
- pyedb-0.12.0.dist-info/RECORD,,
152
+ pyedb-0.12.2.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
153
+ pyedb-0.12.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
154
+ pyedb-0.12.2.dist-info/METADATA,sha256=VnGytyBl-OtwnFYcDmzYWAxxSoszRnv4Ypc1Qiz8LVg,8354
155
+ pyedb-0.12.2.dist-info/RECORD,,
File without changes