pyedb 0.40.0__py3-none-any.whl → 0.42.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.

@@ -53,14 +53,9 @@ class CfgSetup(CfgBase):
53
53
  def _apply_freq_sweep(self, edb_setup):
54
54
  for i in self.freq_sweep:
55
55
  f_set = []
56
- kw = {}
57
- for attr in i.get_attributes(exclude="name"):
58
- if attr == "frequencies":
59
- for f in i.frequencies:
60
- f_set.append([f.distribution, f.start, f.stop, f.increment])
61
- else:
62
- kw[attr] = getattr(i, attr)
63
- edb_setup.add_sweep(i.name, frequency_set=f_set, **kw)
56
+ for f in i.frequencies:
57
+ f_set.append([f.distribution, f.start, f.stop, f.increment])
58
+ edb_setup.add_sweep(i.name, frequency_set=f_set, sweep_type=i.type)
64
59
 
65
60
 
66
61
  class CfgSIwaveACSetup(CfgSetup):
@@ -183,62 +178,141 @@ class CfgSetups:
183
178
  continue
184
179
 
185
180
  stp = {}
186
- if s.type == "hfss":
187
- for p_name in CfgHFSSSetup(self._pedb).__dict__:
188
- if p_name.startswith("_"):
189
- continue
190
- elif p_name == "type":
191
- stp[p_name] = s.type
192
- elif p_name == "f_adapt":
193
- stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].adaptive_frequency
194
- elif p_name == "max_num_passes":
195
- stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_passes
196
- elif p_name == "max_mag_delta_s":
197
- stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_delta
198
- elif p_name == "freq_sweep":
199
- f_sweep = []
200
- for _, sw in s.sweeps.items():
201
- sweep_data = {}
202
- for sw_p_name in CfgSweepData().__dict__:
203
- if sw_p_name == "frequencies":
204
- pass # Frequencies cannot be read from EDB
205
- else:
206
- sweep_data[sw_p_name] = getattr(sw, sw_p_name)
207
- f_sweep.append(sweep_data)
208
- stp["freq_sweep"] = f_sweep
209
- elif p_name == "mesh_operations":
210
- mops = []
211
- for _, i in s.mesh_operations.items():
212
- mop = {}
213
- for mop_p_name in CfgLengthMeshOperation().__dict__:
214
- mop[mop_p_name] = getattr(i, mop_p_name)
215
- mops.append(mop)
216
- stp["mesh_operations"] = mops
217
- else:
218
- stp[p_name] = getattr(s, p_name)
219
-
220
- elif s.type == "siwave_ac":
221
- for p_name in CfgSIwaveACSetup(self._pedb).__dict__:
222
- if p_name.startswith("_"):
223
- continue
224
- elif p_name == "freq_sweep":
225
- pass # Bug in EDB API
226
- else:
227
- stp[p_name] = getattr(s, p_name)
228
- elif s.type == "siwave_dc":
229
- for p_name in CfgSIwaveDCSetup(self._pedb).__dict__:
230
- if p_name.startswith("_"):
231
- continue
232
- elif p_name == "freq_sweep":
233
- pass
234
- elif p_name == "dc_ir_settings":
235
- dc_ir_s = {}
236
- for dcir_p_name in CfgDcIrSettings().__dict__:
237
- dc_ir_s[dcir_p_name] = getattr(s.dc_ir_settings, dcir_p_name)
238
- stp["dc_ir_settings"] = dc_ir_s
239
- elif p_name == "dc_slider_position":
240
- stp[p_name] = getattr(s.dc_settings, p_name)
241
- else:
242
- stp[p_name] = getattr(s, p_name)
181
+ if self._pedb.grpc:
182
+ from ansys.edb.core.simulation_setup.mesh_operation import (
183
+ LengthMeshOperation as GrpcLengthMeshOperation,
184
+ )
185
+
186
+ s_type = s.type.name.lower()
187
+ if s_type == "hfss":
188
+ for p_name in CfgHFSSSetup(self._pedb).__dict__:
189
+ if p_name.startswith("_"):
190
+ continue
191
+ elif p_name == "type":
192
+ stp[p_name] = s.type.name.lower()
193
+ elif p_name == "f_adapt":
194
+ stp[p_name] = s.settings.general.single_frequency_adaptive_solution.adaptive_frequency
195
+ elif p_name == "max_num_passes":
196
+ stp[p_name] = s.settings.general.single_frequency_adaptive_solution.max_passes
197
+ elif p_name == "max_mag_delta_s":
198
+ stp[p_name] = s.settings.general.single_frequency_adaptive_solution.max_delta
199
+ elif p_name == "freq_sweep":
200
+ f_sweep = []
201
+ for sw in s.sweep_data:
202
+ sweep_data = {}
203
+ for sw_p_name in CfgSweepData().__dict__:
204
+ if sw_p_name == "frequencies":
205
+ pass # Frequencies cannot be read from EDB
206
+ else:
207
+ sweep_data[sw_p_name] = getattr(sw, sw_p_name)
208
+ f_sweep.append(sweep_data)
209
+ stp["freq_sweep"] = f_sweep
210
+ elif p_name == "mesh_operations":
211
+ mops = []
212
+ for i in s.mesh_operations:
213
+ mop = {}
214
+ for mop_p_name in CfgLengthMeshOperation().__dict__:
215
+ if mop_p_name == "type":
216
+ if isinstance(i, GrpcLengthMeshOperation):
217
+ mop[mop_p_name] = "length"
218
+ elif mop_p_name == "nets_layers_list":
219
+ mop[mop_p_name] = i.__dict__["_net_layer_info"]
220
+ elif mop_p_name == "restrict_length":
221
+ mop[mop_p_name] = i.__dict__["_restrict_max_length"]
222
+ else:
223
+ mop[mop_p_name] = i.__dict__[f"_{mop_p_name}"]
224
+ mops.append(mop)
225
+ stp["mesh_operations"] = mops
226
+ else:
227
+ stp[p_name] = getattr(s, p_name)
228
+
229
+ elif s_type == "siwave_ac":
230
+ for p_name in CfgSIwaveACSetup(self._pedb).__dict__:
231
+ if p_name.startswith("_"):
232
+ continue
233
+ elif p_name == "freq_sweep":
234
+ pass # Bug in EDB API
235
+ else:
236
+ stp[p_name] = getattr(s, p_name)
237
+ elif s_type == "siwave_dc":
238
+ for p_name in CfgSIwaveDCSetup(self._pedb).__dict__:
239
+ if p_name.startswith("_"):
240
+ continue
241
+ elif p_name == "freq_sweep":
242
+ pass
243
+ elif p_name == "dc_ir_settings":
244
+ dc_ir_s = {}
245
+ for dcir_p_name in CfgDcIrSettings().__dict__:
246
+ dc_ir_s[dcir_p_name] = getattr(s.dc_ir_settings, dcir_p_name)
247
+ stp["dc_ir_settings"] = dc_ir_s
248
+ elif p_name == "dc_slider_position":
249
+ stp[p_name] = getattr(s.dc_settings, p_name)
250
+ else:
251
+ stp[p_name] = getattr(s, p_name)
252
+ else:
253
+ for _, s in self._pedb.setups.items():
254
+ if float(self._pedb.edbversion) < 2025.1:
255
+ if not s.type == "hfss":
256
+ self._pedb.logger.warning("Only HFSS setups are exported in 2024 R2 and earlier version.")
257
+ continue
258
+ if s.type == "hfss":
259
+ for p_name in CfgHFSSSetup(self._pedb).__dict__:
260
+ if p_name.startswith("_"):
261
+ continue
262
+ elif p_name == "type":
263
+ stp[p_name] = s.type
264
+ elif p_name == "f_adapt":
265
+ stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[
266
+ 0
267
+ ].adaptive_frequency
268
+ elif p_name == "max_num_passes":
269
+ stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_passes
270
+ elif p_name == "max_mag_delta_s":
271
+ stp[p_name] = list(s.adaptive_settings.adaptive_frequency_data_list)[0].max_delta
272
+ elif p_name == "freq_sweep":
273
+ f_sweep = []
274
+ for sw in s.sweeps.items():
275
+ sweep_data = {}
276
+ for sw_p_name in CfgSweepData().__dict__:
277
+ if sw_p_name == "frequencies":
278
+ pass # Frequencies cannot be read from EDB
279
+ else:
280
+ sweep_data[sw_p_name] = getattr(sw[1], sw_p_name)
281
+ f_sweep.append(sweep_data)
282
+ stp["freq_sweep"] = f_sweep
283
+ elif p_name == "mesh_operations":
284
+ mops = []
285
+ for _, i in s.mesh_operations.items():
286
+ mop = {}
287
+ for mop_p_name in CfgLengthMeshOperation().__dict__:
288
+ mop[mop_p_name] = getattr(i, mop_p_name)
289
+ mops.append(mop)
290
+ stp["mesh_operations"] = mops
291
+ else:
292
+ stp[p_name] = getattr(s, p_name)
293
+
294
+ elif s.type == "siwave_ac":
295
+ for p_name in CfgSIwaveACSetup(self._pedb).__dict__:
296
+ if p_name.startswith("_"):
297
+ continue
298
+ elif p_name == "freq_sweep":
299
+ pass # Bug in EDB API
300
+ else:
301
+ stp[p_name] = getattr(s, p_name)
302
+ elif s.type == "siwave_dc":
303
+ for p_name in CfgSIwaveDCSetup(self._pedb).__dict__:
304
+ if p_name.startswith("_"):
305
+ continue
306
+ elif p_name == "freq_sweep":
307
+ pass
308
+ elif p_name == "dc_ir_settings":
309
+ dc_ir_s = {}
310
+ for dcir_p_name in CfgDcIrSettings().__dict__:
311
+ dc_ir_s[dcir_p_name] = getattr(s.dc_ir_settings, dcir_p_name)
312
+ stp["dc_ir_settings"] = dc_ir_s
313
+ elif p_name == "dc_slider_position":
314
+ stp[p_name] = getattr(s.dc_settings, p_name)
315
+ else:
316
+ stp[p_name] = getattr(s, p_name)
243
317
  setups.append(stp)
244
318
  return setups
@@ -147,19 +147,34 @@ class Configuration:
147
147
  cfg_pdef.api.set_parameters_to_edb()
148
148
  else:
149
149
  temp_pdef_data = {}
150
- for pdef_name, pdef in self._pedb.padstacks.definitions.items():
151
- pdef_data = pdef._padstack_def_data
152
- for lyr_name in list(pdef_data.GetLayerNames()):
153
- result = pdef_data.GetPadParametersValue(lyr_name, self._pedb._edb.Definition.PadType.RegularPad)
154
- flag, pad_shape, params, offset_x, offset_y, rotation = result
155
- if flag is False:
156
- result = pdef_data.GetPolygonalPadParameters(
150
+ if self._pedb.grpc:
151
+ from ansys.edb.core.definition.padstack_def_data import (
152
+ PadType as GrpcPadType,
153
+ )
154
+
155
+ for pdef_name, pdef in self._pedb.padstacks.definitions.items():
156
+ for layer in pdef.data.layer_names:
157
+ result = pdef.data.get_pad_parameters(layer, GrpcPadType.REGULAR_PAD)
158
+ if len(result) == 4:
159
+ # polygon based
160
+ temp_pdef_data[pdef_name] = pdef.data
161
+ break
162
+ else:
163
+ for pdef_name, pdef in self._pedb.padstacks.definitions.items():
164
+ pdef_data = pdef._padstack_def_data
165
+ for lyr_name in list(pdef_data.GetLayerNames()):
166
+ result = pdef_data.GetPadParametersValue(
157
167
  lyr_name, self._pedb._edb.Definition.PadType.RegularPad
158
168
  )
159
- flag, polygon_data, offset_x, offset_y, rotation = result
160
- if flag:
161
- temp_pdef_data[pdef_name] = pdef_data
162
- break
169
+ flag, pad_shape, params, offset_x, offset_y, rotation = result
170
+ if flag is False:
171
+ result = pdef_data.GetPolygonalPadParameters(
172
+ lyr_name, self._pedb._edb.Definition.PadType.RegularPad
173
+ )
174
+ flag, polygon_data, offset_x, offset_y, rotation = result
175
+ if flag:
176
+ temp_pdef_data[pdef_name] = pdef_data
177
+ break
163
178
  self.cfg_data.stackup.apply()
164
179
  for pdef_name, pdef_data in temp_pdef_data.items():
165
180
  pdef = self._pedb.padstacks.definitions[pdef_name]
@@ -43,6 +43,11 @@ class PadstackInstanceTerminal(Terminal):
43
43
  return EDBPadstackInstance(edb_padstack_instance[1], self._pedb).position
44
44
  return False
45
45
 
46
+ @property
47
+ def location(self):
48
+ """Location of the padstack instance."""
49
+ return self.position
50
+
46
51
  def create(self, padstack_instance, name=None, layer=None, is_ref=False):
47
52
  """Create an edge terminal.
48
53
 
@@ -78,3 +78,15 @@ class PointTerminal(Terminal):
78
78
  layer = self._pedb.stackup.layers[value]._edb_layer
79
79
  point_data = self._pedb.point_data(*self.location)
80
80
  self._edb_object.SetParameters(point_data, layer)
81
+
82
+ @property
83
+ def location(self):
84
+ """Location of the terminal."""
85
+
86
+ _, point_data, _ = self._edb_object.GetParameters()
87
+ return [point_data.X.ToDouble(), point_data.Y.ToDouble()]
88
+
89
+ @location.setter
90
+ def location(self, value):
91
+ layer = self.layer
92
+ self._edb_object.SetParameters(self._pedb.point_data(*value), layer._edb_object)
@@ -107,20 +107,6 @@ class Terminal(Connectable):
107
107
  """Get layer of the terminal."""
108
108
  return self._pedb.logger.error("Cannot determine terminal layer")
109
109
 
110
- @property
111
- def location(self):
112
- """Location of the terminal."""
113
- try:
114
- _, point_data, _ = self._edb_object.GetParameters()
115
- return [point_data.X.ToDouble(), point_data.Y.ToDouble()]
116
- except:
117
- self._pedb.logger.error("Cannot determine terminal location")
118
-
119
- @location.setter
120
- def location(self, value):
121
- layer = self.layer
122
- self._edb_object.SetParameters(self._pedb.point_data(*value), layer._edb_object)
123
-
124
110
  @property
125
111
  def is_circuit_port(self):
126
112
  """Whether it is a circuit port."""
@@ -861,6 +861,8 @@ class Database(EdbDotNet):
861
861
  db_path,
862
862
  read_only,
863
863
  )
864
+ if self._db.IsNull():
865
+ raise AttributeError(f"Failed to open edb file {db_path}")
864
866
  return self._db
865
867
 
866
868
  def delete(self, db_path):
@@ -510,7 +510,7 @@ class EDBPadstack(object):
510
510
  list
511
511
  List of layers.
512
512
  """
513
- return self._padstack_def_data.GetLayerNames()
513
+ return list(self._padstack_def_data.GetLayerNames())
514
514
 
515
515
  @property
516
516
  def via_start_layer(self):
@@ -521,7 +521,7 @@ class EDBPadstack(object):
521
521
  str
522
522
  Name of the starting layer.
523
523
  """
524
- return list(self.via_layers)[0]
524
+ return self.via_layers[0]
525
525
 
526
526
  @property
527
527
  def via_stop_layer(self):
@@ -532,7 +532,7 @@ class EDBPadstack(object):
532
532
  str
533
533
  Name of the stopping layer.
534
534
  """
535
- return list(self.via_layers)[-1]
535
+ return self.via_layers[-1]
536
536
 
537
537
  @property
538
538
  def hole_params(self):
@@ -2141,3 +2141,80 @@ class EDBPadstackInstance(Primitive):
2141
2141
  max_limit=max_limit,
2142
2142
  component_only=component_only,
2143
2143
  )
2144
+
2145
+ def split(self):
2146
+ """Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
2147
+ pdef_name = self.padstack_definition
2148
+ position = self.position
2149
+ net_name = self.net_name
2150
+ name = self.name
2151
+ stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
2152
+ start_idx = stackup_layer_range.index(self.start_layer)
2153
+ stop_idx = stackup_layer_range.index(self.stop_layer)
2154
+ for idx, (l1, l2) in enumerate(
2155
+ list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
2156
+ ):
2157
+ self._pedb.padstacks.place(position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2)
2158
+ self.delete()
2159
+
2160
+ def convert_hole_to_conical_shape(self, angle=75):
2161
+ """Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
2162
+
2163
+ Parameters
2164
+ ----------
2165
+ angle : float, optional
2166
+ Angle of laser penetration in degrees. The angle defines the lowest hole diameter with this formula:
2167
+ HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
2168
+ The default is ``75``.
2169
+ The lowest hole is ``0.75*HoleDepth/HoleDiam``.
2170
+
2171
+ Returns
2172
+ -------
2173
+ """
2174
+ pos = self.position
2175
+ stackup_layers = self._pedb.stackup.stackup_layers
2176
+ signal_layers = self._pedb.stackup.signal_layers
2177
+ layer_idx = list(signal_layers.keys()).index(self.start_layer)
2178
+
2179
+ _layer_idx = list(stackup_layers.keys()).index(self.start_layer)
2180
+ diel_layer_idx = list(stackup_layers.keys())[_layer_idx + 1]
2181
+ diel_thickness = stackup_layers[diel_layer_idx].thickness
2182
+
2183
+ rad_large = self.definition.hole_diameter / 2
2184
+ rad_small = rad_large - diel_thickness * 1 / math.tan(math.radians(angle))
2185
+
2186
+ if layer_idx + 1 < len(signal_layers) / 2: # upper half of stack
2187
+ rad_u = rad_large
2188
+ rad_l = rad_small
2189
+ else:
2190
+ rad_u = rad_small
2191
+ rad_l = rad_large
2192
+
2193
+ layout = self._pedb.active_layout
2194
+ cloned_circle = self._edb.cell.primitive.circle.create(
2195
+ layout,
2196
+ self.start_layer,
2197
+ self._edb_padstackinstance.GetNet(),
2198
+ self._pedb.edb_value(pos[0]),
2199
+ self._pedb.edb_value(pos[1]),
2200
+ self._pedb.edb_value(rad_u),
2201
+ )
2202
+ cloned_circle2 = self._edb.cell.primitive.circle.create(
2203
+ layout,
2204
+ self.stop_layer,
2205
+ self._edb_padstackinstance.GetNet(),
2206
+ self._pedb.edb_value(pos[0]),
2207
+ self._pedb.edb_value(pos[1]),
2208
+ self._pedb.edb_value(rad_l),
2209
+ )
2210
+ s3d = self._pedb._edb.Cell.Hierarchy.Structure3D.Create(
2211
+ layout, generate_unique_name("via3d_" + self.aedt_name.replace("via_", ""), n=3)
2212
+ )
2213
+ s3d.AddMember(cloned_circle.prim_obj)
2214
+ s3d.AddMember(cloned_circle2.prim_obj)
2215
+ s3d.SetMaterial(self.definition.material)
2216
+ s3d.SetMeshClosureProp(self._pedb._edb.Cell.Hierarchy.Structure3D.TClosure.EndsClosed)
2217
+
2218
+ hole_override_enabled = True
2219
+ hole_override_diam = 0
2220
+ self._edb_object.SetHoleOverride(hole_override_enabled, self._pedb.edb_value(hole_override_diam))
@@ -811,6 +811,7 @@ class EdbSiwave(object):
811
811
 
812
812
  def add_siwave_syz_analysis(
813
813
  self,
814
+ name=None,
814
815
  accuracy_level=1,
815
816
  decade_count=10,
816
817
  sweeptype=1,
@@ -823,6 +824,8 @@ class EdbSiwave(object):
823
824
 
824
825
  Parameters
825
826
  ----------
827
+ name : str optional
828
+ Setup name.
826
829
  accuracy_level : int, optional
827
830
  Level of accuracy of SI slider. The default is ``1``.
828
831
  decade_count : int
@@ -849,7 +852,7 @@ class EdbSiwave(object):
849
852
  :class:`pyedb.dotnet.database.edb_data.siwave_simulation_setup_data.SiwaveSYZSimulationSetup`
850
853
  Setup object class.
851
854
  """
852
- setup = self._pedb.create_siwave_syz_setup()
855
+ setup = self._pedb.create_siwave_syz_setup(name=name)
853
856
  sweep = "linear count"
854
857
  if sweeptype == 2:
855
858
  sweep = "log scale"
@@ -239,7 +239,7 @@ class SimulationSetup(object):
239
239
  """List of frequency sweeps."""
240
240
  return {i.name: i for i in self.sim_setup_info.sweep_data_list}
241
241
 
242
- def add_sweep(self, name, frequency_set: list = None, **kwargs):
242
+ def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
243
243
  """Add frequency sweep.
244
244
 
245
245
  Parameters
@@ -248,7 +248,8 @@ class SimulationSetup(object):
248
248
  Name of the frequency sweep. The default is ``None``.
249
249
  frequency_set : list, optional
250
250
  List of frequency points. The default is ``None``.
251
-
251
+ sweep_type : str, optional
252
+ Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
252
253
  Returns
253
254
  -------
254
255
 
@@ -265,7 +266,7 @@ class SimulationSetup(object):
265
266
  for k, v in kwargs.items():
266
267
  if k in dir(sweep_data):
267
268
  setattr(sweep_data, k, v)
268
- sweep_data.freq_sweep_type = kwargs.get("sweep_type") if kwargs.get("sweep_type") else "interpolation"
269
+ sweep_data.type = sweep_type
269
270
 
270
271
  if frequency_set is None:
271
272
  sweep_type = "linear_scale"
@@ -285,6 +286,10 @@ class SimulationSetup(object):
285
286
  self._update_setup()
286
287
  return sweep_data
287
288
 
289
+ def delete(self):
290
+ """Delete current simulation setup."""
291
+ self._pedb.layout.cell.DeleteSimulationSetup(self.name)
292
+
288
293
  def _add_frequency_sweep(self, sweep_data):
289
294
  """Add a frequency sweep.
290
295
 
pyedb/dotnet/edb.py CHANGED
@@ -46,6 +46,7 @@ from pyedb.dotnet.database.Variables import decompose_variable_value
46
46
  from pyedb.dotnet.database.cell.layout import Layout
47
47
  from pyedb.dotnet.database.cell.terminal.terminal import Terminal
48
48
  from pyedb.dotnet.database.components import Components
49
+ import pyedb.dotnet.database.dotnet.database
49
50
  from pyedb.dotnet.database.dotnet.database import Database
50
51
  from pyedb.dotnet.database.edb_data.control_file import (
51
52
  ControlFile,
@@ -277,7 +278,7 @@ class Edb(Database):
277
278
  if self.active_cell:
278
279
  self.logger.info("EDB initialized.")
279
280
  else:
280
- self.logger.info("Failed to initialize DLLs.")
281
+ raise AttributeError("Failed to initialize DLLs.")
281
282
 
282
283
  def __enter__(self):
283
284
  return self
@@ -548,10 +549,7 @@ class Edb(Database):
548
549
  self.run_as_standalone(self.standalone)
549
550
 
550
551
  # self.logger.info("EDB Standalone %s", self.standalone)
551
- try:
552
- self.open(self.edbpath, self.isreadonly)
553
- except Exception as e:
554
- self.logger.error("Builder is not Initialized.")
552
+ self.open(self.edbpath, self.isreadonly)
555
553
  if not self.active_db:
556
554
  self.logger.warning("Error Opening db")
557
555
  self._active_cell = None
@@ -761,6 +759,23 @@ class Edb(Database):
761
759
  """Active cell."""
762
760
  return self._active_cell
763
761
 
762
+ @active_cell.setter
763
+ def active_cell(self, value):
764
+ if isinstance(value, str):
765
+ _cell = [cell for cell in self.circuit_cells if cell.GetName() == value]
766
+ if _cell:
767
+ self._active_cell = _cell[0]
768
+ self._init_objects()
769
+ self.logger.info(f"Cell {value} set as active")
770
+ else:
771
+ raise f"Design {value} not found in database."
772
+ elif isinstance(value, pyedb.dotnet.database.dotnet.database.CellClassDotNet):
773
+ self._active_cell = value
774
+ self._init_objects()
775
+ self.logger.info(f"Cell {value.GetName()} set as active")
776
+ else:
777
+ raise "No valid design."
778
+
764
779
  @property
765
780
  def core_components(self): # pragma: no cover
766
781
  """Edb Components methods and properties.
@@ -2274,8 +2274,7 @@ class Components(object):
2274
2274
  pingroup = PinGroup.create(self._active_layout, group_name, pins)
2275
2275
 
2276
2276
  if pingroup.is_null: # pragma: no cover
2277
- self._logger.error(f"Failed to create pin group {group_name}.")
2278
- return False
2277
+ raise RuntimeError(f"Failed to create pin group {group_name}.")
2279
2278
  else:
2280
2279
  for pin in pins:
2281
2280
  if not pin.net.is_null:
@@ -41,6 +41,7 @@ from ansys.edb.core.hierarchy.pin_pair_model import PinPairModel as GrpcPinPairM
41
41
  from ansys.edb.core.hierarchy.sparameter_model import (
42
42
  SParameterModel as GrpcSParameterModel,
43
43
  )
44
+ from ansys.edb.core.hierarchy.spice_model import SPICEModel as GrpcSPICEModel
44
45
  from ansys.edb.core.primitive.primitive import PadstackInstance as GrpcPadstackInstance
45
46
  from ansys.edb.core.terminal.terminals import (
46
47
  PadstackInstanceTerminal as GrpcPadstackInstanceTerminal,
@@ -49,6 +50,7 @@ from ansys.edb.core.utility.rlc import Rlc as GrpcRlc
49
50
  from ansys.edb.core.utility.value import Value as GrpcValue
50
51
 
51
52
  from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
53
+ from pyedb.grpc.database.hierarchy.s_parameter_model import SparamModel
52
54
  from pyedb.grpc.database.hierarchy.spice_model import SpiceModel
53
55
  from pyedb.grpc.database.layers.stackup_layer import StackupLayer
54
56
  from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
@@ -204,7 +206,13 @@ class Component(GrpcComponentGroup):
204
206
  :class:`Model <ansys.edb.core.hierarchy.model.Model>`
205
207
 
206
208
  """
207
- return self.component_property.model
209
+
210
+ if isinstance(self.component_property.model, GrpcSPICEModel):
211
+ return SpiceModel(edb_object=self.component_property.model.msg)
212
+ elif isinstance(self.component_property.model, GrpcSParameterModel):
213
+ return SparamModel(edb_object=self.component_property.model.msg)
214
+ else:
215
+ return self.component_property.model
208
216
 
209
217
  @model.setter
210
218
  def model(self, value):
@@ -28,6 +28,6 @@ from ansys.edb.core.hierarchy.sparameter_model import (
28
28
  class SparamModel(GrpcSParameterModel): # pragma: no cover
29
29
  """Manage :class:`SParameterModel <ansys.edb.core.hierarchy.sparameter_model.SParameterModel>`"""
30
30
 
31
- def __init__(self, edb_model):
31
+ def __init__(self, edb_object):
32
32
  super().__init__(self.msg)
33
- self._edb_model = edb_model
33
+ self._edb_model = edb_object
@@ -46,3 +46,7 @@ class SpiceModel(GrpcSpiceModel): # pragma: no cover
46
46
 
47
47
  """
48
48
  return self.model_name
49
+
50
+ @property
51
+ def spice_file_path(self):
52
+ return self.model_path