pyedb 0.27.0__py3-none-any.whl → 0.29.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +44 -74
  3. pyedb/configuration/cfg_common.py +1 -1
  4. pyedb/configuration/cfg_components.py +31 -105
  5. pyedb/configuration/cfg_data.py +4 -9
  6. pyedb/configuration/cfg_operations.py +19 -13
  7. pyedb/configuration/cfg_padstacks.py +66 -89
  8. pyedb/configuration/cfg_pin_groups.py +7 -8
  9. pyedb/configuration/cfg_ports_sources.py +4 -2
  10. pyedb/configuration/cfg_s_parameter_models.py +85 -29
  11. pyedb/configuration/configuration.py +48 -13
  12. pyedb/dotnet/application/Variables.py +43 -41
  13. pyedb/dotnet/edb.py +12 -4
  14. pyedb/dotnet/edb_core/cell/hierarchy/component.py +199 -0
  15. pyedb/dotnet/edb_core/cell/layout.py +4 -1
  16. pyedb/dotnet/edb_core/cell/primitive/primitive.py +2 -0
  17. pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py +3 -3
  18. pyedb/dotnet/edb_core/cell/terminal/terminal.py +4 -3
  19. pyedb/dotnet/edb_core/definition/component_def.py +17 -1
  20. pyedb/dotnet/edb_core/definition/component_model.py +0 -4
  21. pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +3 -3
  22. pyedb/dotnet/edb_core/edb_data/nets_data.py +10 -7
  23. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +301 -45
  24. pyedb/dotnet/edb_core/edb_data/primitives_data.py +2 -2
  25. pyedb/dotnet/edb_core/general.py +11 -0
  26. pyedb/dotnet/edb_core/layout_validation.py +3 -3
  27. pyedb/dotnet/edb_core/modeler.py +5 -2
  28. pyedb/dotnet/edb_core/nets.py +162 -181
  29. pyedb/edb_logger.py +1 -1
  30. pyedb/siwave.py +33 -7
  31. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/METADATA +5 -5
  32. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/RECORD +34 -34
  33. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/LICENSE +0 -0
  34. {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/WHEEL +0 -0
@@ -47,10 +47,10 @@ class PinGroupTerminal(Terminal):
47
47
  -------
48
48
  :class:`pyedb.dotnet.edb_core.edb_data.terminals.PinGroupTerminal`
49
49
  """
50
- net_obj = self._pedb.edb_api.cell.net.find_by_name(self._pedb.active_layout, net_name)
50
+ net_obj = self._pedb.layout.find_net_by_name(net_name)
51
51
  term = self._pedb.edb_api.cell.terminal.PinGroupTerminal.Create(
52
52
  self._pedb.active_layout,
53
- net_obj.api_object,
53
+ net_obj._edb_object,
54
54
  name,
55
55
  self._pedb.siwave.pin_groups[pin_group_name]._edb_object,
56
56
  is_ref,
@@ -60,7 +60,7 @@ class PinGroupTerminal(Terminal):
60
60
  msg = f"Failed to create terminal. "
61
61
  if name in self._pedb.terminals:
62
62
  msg += f"Terminal {name} already exists."
63
- raise Exception(msg)
63
+ raise ValueError(msg)
64
64
  else:
65
65
  return term
66
66
 
@@ -223,9 +223,10 @@ class Terminal(Connectable):
223
223
  """Get reference terminal."""
224
224
 
225
225
  edb_terminal = self._edb_object.GetReferenceTerminal()
226
- terminal = self._pedb.terminals[edb_terminal.GetName()]
227
- if not terminal.is_null:
228
- return terminal
226
+ if not edb_terminal.IsNull():
227
+ return self._pedb.terminals[edb_terminal.GetName()]
228
+ else:
229
+ return None
229
230
 
230
231
  @ref_terminal.setter
231
232
  def ref_terminal(self, value):
@@ -23,6 +23,7 @@
23
23
  import os
24
24
 
25
25
  from pyedb.dotnet.edb_core.definition.component_model import NPortComponentModel
26
+ from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
26
27
  from pyedb.dotnet.edb_core.utilities.obj_base import ObjBase
27
28
 
28
29
 
@@ -171,7 +172,7 @@ class EDBComponentDef(ObjBase):
171
172
  def component_models(self):
172
173
  temp = {}
173
174
  for i in list(self._edb_object.GetComponentModels()):
174
- temp_type = i.ToString().split(".")[0]
175
+ temp_type = i.ToString().split(".")[-1]
175
176
  if temp_type == "NPortComponentModel":
176
177
  edb_object = NPortComponentModel(self._pedb, i)
177
178
  temp[edb_object.name] = edb_object
@@ -197,3 +198,18 @@ class EDBComponentDef(ObjBase):
197
198
  footprint_cell = self._pedb._active_cell.cell.Create(self._pedb.active_db, cell_type, name)
198
199
  edb_object = self._pedb.edb_api.definition.ComponentDef.Create(self._pedb.active_db, name, footprint_cell)
199
200
  return EDBComponentDef(self._pedb, edb_object)
201
+
202
+ def get_properties(self):
203
+ data = {}
204
+ temp = []
205
+ for i in list(self._edb_object.ComponentDefPins):
206
+ temp.append(i.GetName())
207
+ data["pin_order"] = temp
208
+ return data
209
+
210
+ def set_properties(self, **kwargs):
211
+ pin_order = kwargs.get("pin_order")
212
+ if pin_order:
213
+ old = {i.GetName(): i for i in list(self._edb_object.ComponentDefPins)}
214
+ temp = convert_py_list_to_net_list([old[str(i)] for i in pin_order])
215
+ self._edb_object.ReorderPins(temp)
@@ -30,10 +30,6 @@ class ComponentModel(ObjBase):
30
30
  super().__init__(pedb, edb_object)
31
31
  self._model_type_mapping = {"PinPairModel": self._pedb.edb_api.cell}
32
32
 
33
- def name(self):
34
- """Name of the component model."""
35
- return self._edb_object.GetName()
36
-
37
33
 
38
34
  class NPortComponentModel(ComponentModel):
39
35
  """Class for n-port component models."""
@@ -22,7 +22,7 @@
22
22
 
23
23
  from pyedb.dotnet.edb_core.edb_data.edbvalue import EdbValue
24
24
  from pyedb.dotnet.edb_core.edb_data.primitives_data import cast
25
- from pyedb.dotnet.edb_core.general import convert_pytuple_to_nettuple
25
+ from pyedb.dotnet.edb_core.general import convert_pytuple_to_nettuple, pascal_to_snake
26
26
 
27
27
 
28
28
  class HfssExtentInfo:
@@ -192,7 +192,7 @@ class HfssExtentInfo:
192
192
  @property
193
193
  def dielectric_extent_type(self):
194
194
  """Dielectric extent type."""
195
- return self._edb_hfss_extent_info.DielectricExtentType.ToString().lower()
195
+ return pascal_to_snake(self._edb_hfss_extent_info.DielectricExtentType.ToString())
196
196
 
197
197
  @dielectric_extent_type.setter
198
198
  def dielectric_extent_type(self, value):
@@ -204,7 +204,7 @@ class HfssExtentInfo:
204
204
  @property
205
205
  def extent_type(self):
206
206
  """Extent type."""
207
- return self._edb_hfss_extent_info.ExtentType.ToString().lower()
207
+ return pascal_to_snake(self._edb_hfss_extent_info.ExtentType.ToString())
208
208
 
209
209
  @extent_type.setter
210
210
  def extent_type(self, value):
@@ -19,7 +19,6 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
-
23
22
  from pyedb.dotnet.edb_core.dotnet.database import (
24
23
  DifferentialPairDotNet,
25
24
  ExtendedNetDotNet,
@@ -58,7 +57,10 @@ class EDBNetsData(NetDotNet):
58
57
  -------
59
58
  list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
60
59
  """
61
- return [self._app.layout.find_object_by_id(i.GetId()) for i in self.net_object.Primitives]
60
+ from pyedb.dotnet.edb_core.cell.layout import primitive_cast
61
+
62
+ return [primitive_cast(self._app, i) for i in self.net_object.Primitives]
63
+ # return [self._app.layout.find_object_by_id(i.GetId()) for i in self.net_object.Primitives]
62
64
 
63
65
  @property
64
66
  def padstack_instances(self):
@@ -67,10 +69,11 @@ class EDBNetsData(NetDotNet):
67
69
  Returns
68
70
  -------
69
71
  list of :class:`pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`"""
70
- name = self.name
71
- return [
72
- EDBPadstackInstance(i, self._app) for i in self.net_object.PadstackInstances if i.GetNet().GetName() == name
73
- ]
72
+ # name = self.name
73
+ # return [
74
+ # EDBPadstackInstance(i, self._app) for i in self.net_object.PadstackInstances if i.GetNet().GetName() == name
75
+ # ]
76
+ return [EDBPadstackInstance(i, self._app) for i in self.net_object.PadstackInstances]
74
77
 
75
78
  @property
76
79
  def components(self):
@@ -133,7 +136,7 @@ class EDBNetsData(NetDotNet):
133
136
  Whether to show the plot or not. Default is `True`.
134
137
  """
135
138
 
136
- self._app.nets.plot(
139
+ return self._app.nets.plot(
137
140
  self.name,
138
141
  layers=layers,
139
142
  show_legend=show_legend,
@@ -29,7 +29,12 @@ from pyedb.dotnet.clr_module import String
29
29
  from pyedb.dotnet.edb_core.cell.primitive.primitive import Primitive
30
30
  from pyedb.dotnet.edb_core.dotnet.database import PolygonDataDotNet
31
31
  from pyedb.dotnet.edb_core.edb_data.edbvalue import EdbValue
32
- from pyedb.dotnet.edb_core.general import PadGeometryTpe, convert_py_list_to_net_list
32
+ from pyedb.dotnet.edb_core.general import (
33
+ PadGeometryTpe,
34
+ convert_py_list_to_net_list,
35
+ pascal_to_snake,
36
+ snake_to_pascal,
37
+ )
33
38
  from pyedb.generic.general_methods import generate_unique_name
34
39
  from pyedb.modeler.geometry_operators import GeometryOperators
35
40
 
@@ -406,19 +411,231 @@ class EDBPadstack(object):
406
411
  >>> edb_padstack = edb.padstacks.definitions["MyPad"]
407
412
  """
408
413
 
414
+ PAD_SHAPE_PARAMETERS = {
415
+ "circle": ["diameter"],
416
+ "square": ["size"],
417
+ "rectangle": ["x_size", "y_size"],
418
+ "oval": ["x_size", "y_size", "corner_radius"],
419
+ "bullet": ["x_size", "y_size", "corner_radius"],
420
+ "round45": ["inner", "channel_width", "isolation_gap"],
421
+ "round90": ["inner", "channel_width", "isolation_gap"],
422
+ "no_geometry": [],
423
+ }
424
+
409
425
  def __init__(self, edb_padstack, ppadstack):
426
+ self._edb_object = edb_padstack
410
427
  self.edb_padstack = edb_padstack
411
428
  self._ppadstack = ppadstack
412
- self.pad_by_layer = {}
413
- self.antipad_by_layer = {}
414
- self.thermalpad_by_layer = {}
415
429
  self._bounding_box = []
416
430
  self._hole_params = None
431
+
432
+ @property
433
+ def pad_by_layer(self):
434
+ """Regular pad property."""
435
+ temp = {}
436
+ for layer in self.via_layers:
437
+ temp[layer] = EDBPadProperties(self._edb_object, layer, 0, self)
438
+ return temp
439
+
440
+ @property
441
+ def antipad_by_layer(self):
442
+ """Anti pad property."""
443
+ temp = {}
417
444
  for layer in self.via_layers:
418
- self.pad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 0, self)
419
- self.antipad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 1, self)
420
- self.thermalpad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 2, self)
421
- pass
445
+ temp[layer] = EDBPadProperties(self._edb_object, layer, 1, self)
446
+ return temp
447
+
448
+ @property
449
+ def thermalpad_by_layer(self):
450
+ """Thermal pad property."""
451
+ temp = {}
452
+ for layer in self.via_layers:
453
+ temp[layer] = EDBPadProperties(self._edb_object, layer, 2, self)
454
+ return temp
455
+
456
+ @property
457
+ def _padstack_def_data(self):
458
+ """Get padstack definition data.
459
+
460
+ Returns
461
+ -------
462
+
463
+ """
464
+ pstack_data = self._edb_object.GetData()
465
+ return self._edb.definition.PadstackDefData(pstack_data)
466
+
467
+ @_padstack_def_data.setter
468
+ def _padstack_def_data(self, value):
469
+ self._edb_object.SetData(value)
470
+
471
+ @property
472
+ def pad_parameters(self) -> dict:
473
+ """Pad parameters.
474
+
475
+ Returns
476
+ -------
477
+ dict
478
+ params = {
479
+ 'regular_pad': [
480
+ {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0.1mm', 'offset_y': '0', 'rotation': '0',
481
+ 'diameter': '0.5mm'}
482
+ ],
483
+ 'anti_pad': [
484
+ {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
485
+ 'diameter': '1mm'}
486
+ ],
487
+ 'thermal_pad': [
488
+ {'layer_name': '1_Top', 'shape': 'round90', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
489
+ 'inner': '1mm', 'channel_width': '0.2mm', 'isolation_gap': '0.3mm'},
490
+ ],
491
+ 'hole': [
492
+ {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
493
+ 'diameter': '0.1499997mm'},
494
+ ]
495
+ }
496
+ """
497
+ pdef_data = self._padstack_def_data
498
+ pad_type_list = [
499
+ self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
500
+ self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
501
+ self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
502
+ self._ppadstack._pedb._edb.Definition.PadType.Hole,
503
+ ]
504
+ data = {}
505
+ for pad_type in pad_type_list:
506
+ pad_type_name = pascal_to_snake(pad_type.ToString())
507
+ temp_list = []
508
+ for lyr_name in list(pdef_data.GetLayerNames()):
509
+ result = pdef_data.GetPadParametersValue(lyr_name, pad_type)
510
+ _, pad_shape, params, offset_x, offset_y, rotation = result
511
+ pad_shape = pascal_to_snake(pad_shape.ToString())
512
+
513
+ pad_params = {}
514
+ pad_params["layer_name"] = lyr_name
515
+ pad_params["shape"] = pad_shape
516
+ pad_params["offset_x"] = offset_x.ToString()
517
+ pad_params["offset_y"] = offset_y.ToString()
518
+ pad_params["rotation"] = rotation.ToString()
519
+
520
+ for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[pad_shape]):
521
+ pad_params[i] = params[idx].ToString()
522
+ temp_list.append(pad_params)
523
+ data[pad_type_name] = temp_list
524
+ return data
525
+
526
+ @pad_parameters.setter
527
+ def pad_parameters(self, params: dict):
528
+ original_params = self.pad_parameters
529
+ pdef_data = self._padstack_def_data
530
+
531
+ pad_type_list = [
532
+ self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
533
+ self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
534
+ self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
535
+ self._ppadstack._pedb._edb.Definition.PadType.Hole,
536
+ ]
537
+ for pad_type in pad_type_list:
538
+ pad_type_name = pascal_to_snake(pad_type.ToString())
539
+ rpp = params.get(pad_type_name, [])
540
+ for idx, layer_data in enumerate(rpp):
541
+ # Get geometry type from kwargs
542
+ p = layer_data.get("shape")
543
+ temp_param = []
544
+
545
+ # Handle Circle geometry type
546
+ if p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle.ToString()):
547
+ temp_param.append(layer_data["diameter"])
548
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle
549
+
550
+ # Handle Square geometry type
551
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Square.ToString()):
552
+ temp_param.append(layer_data["size"])
553
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Square
554
+
555
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle.ToString()):
556
+ temp_param.append(layer_data["x_size"])
557
+ temp_param.append(layer_data["y_size"])
558
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle
559
+
560
+ # Handle Oval geometry type
561
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval.ToString()):
562
+ temp_param.append(layer_data["x_size"])
563
+ temp_param.append(layer_data["y_size"])
564
+ temp_param.append(layer_data["corner_radius"])
565
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval
566
+
567
+ # Handle Bullet geometry type
568
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet.ToString()):
569
+ temp_param.append(layer_data["x_size"])
570
+ temp_param.append(layer_data["y_size"])
571
+ temp_param.append(layer_data["corner_radius"])
572
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet
573
+
574
+ # Handle Round45 geometry type
575
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45.ToString()):
576
+ temp_param.append(layer_data["inner"])
577
+ temp_param.append(layer_data["channel_width"])
578
+ temp_param.append(layer_data["isolation_gap"])
579
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45
580
+
581
+ # Handle Round90 geometry type
582
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90.ToString()):
583
+ temp_param.append(layer_data["inner"])
584
+ temp_param.append(layer_data["channel_width"])
585
+ temp_param.append(layer_data["isolation_gap"])
586
+ pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90
587
+ elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.NoGeometry.ToString()):
588
+ continue
589
+
590
+ # Set pad parameters for the current layer
591
+ default = original_params[pad_type_name]
592
+ pdef_data.SetPadParameters(
593
+ layer_data["layer_name"],
594
+ pad_type,
595
+ pad_shape,
596
+ convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
597
+ self._ppadstack._pedb.edb_value(layer_data.get("offset_x", default[idx].get("offset_x", 0))),
598
+ self._ppadstack._pedb.edb_value(layer_data.get("offset_y", default[idx].get("offset_y", 0))),
599
+ self._ppadstack._pedb.edb_value(layer_data.get("rotation", default[idx].get("rotation", 0))),
600
+ )
601
+ self._padstack_def_data = pdef_data
602
+
603
+ @property
604
+ def hole_parameters(self):
605
+ pdef_data = self._padstack_def_data
606
+ _, hole_shape, params, offset_x, offset_y, rotation = pdef_data.GetHoleParametersValue()
607
+ hole_shape = pascal_to_snake(hole_shape.ToString())
608
+
609
+ hole_params = {}
610
+ hole_params["shape"] = hole_shape
611
+ for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[hole_shape]):
612
+ hole_params[i] = params[idx].ToString()
613
+ hole_params["offset_x"] = offset_x.ToString()
614
+ hole_params["offset_y"] = offset_y.ToString()
615
+ hole_params["rotation"] = rotation.ToString()
616
+ return hole_params
617
+
618
+ @hole_parameters.setter
619
+ def hole_parameters(self, params: dict):
620
+ original_params = self.hole_parameters
621
+ pdef_data = self._padstack_def_data
622
+
623
+ temp_param = []
624
+ shape = params["shape"]
625
+ if shape == "no_geometry":
626
+ return # .net api doesn't tell how to set no_geometry shape.
627
+ for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[shape]):
628
+ temp_param.append(params[i])
629
+ pedb_shape = getattr(self._ppadstack._pedb._edb.Definition.PadGeometryType, snake_to_pascal(shape))
630
+
631
+ pdef_data.SetHoleParameters(
632
+ pedb_shape,
633
+ convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
634
+ self._ppadstack._pedb.edb_value(params.get("offset_x", original_params.get("offset_x", 0))),
635
+ self._ppadstack._pedb.edb_value(params.get("offset_y", original_params.get("offset_y", 0))),
636
+ self._ppadstack._pedb.edb_value(params.get("rotation", original_params.get("rotation", 0))),
637
+ )
638
+ self._padstack_def_data = pdef_data
422
639
 
423
640
  @property
424
641
  def instances(self):
@@ -455,7 +672,7 @@ class EDBPadstack(object):
455
672
  list
456
673
  List of layers.
457
674
  """
458
- return self.edb_padstack.GetData().GetLayerNames()
675
+ return self._padstack_def_data.GetLayerNames()
459
676
 
460
677
  @property
461
678
  def via_start_layer(self):
@@ -488,7 +705,7 @@ class EDBPadstack(object):
488
705
  return self._hole_params
489
706
 
490
707
  @property
491
- def hole_parameters(self):
708
+ def _hole_parameters(self):
492
709
  """Hole parameters.
493
710
 
494
711
  Returns
@@ -496,8 +713,7 @@ class EDBPadstack(object):
496
713
  list
497
714
  List of the hole parameters.
498
715
  """
499
- self._hole_parameters = self.hole_params[2]
500
- return self._hole_parameters
716
+ return self.hole_params[2]
501
717
 
502
718
  @property
503
719
  def hole_diameter(self):
@@ -540,7 +756,7 @@ class EDBPadstack(object):
540
756
  if not hole_type:
541
757
  hole_type = self.hole_type
542
758
  if not params:
543
- params = self.hole_parameters
759
+ params = self._hole_parameters
544
760
  if isinstance(params, list):
545
761
  params = convert_py_list_to_net_list(params)
546
762
  if not offsetx:
@@ -709,14 +925,13 @@ class EDBPadstack(object):
709
925
  str
710
926
  Material of the hole.
711
927
  """
712
- return self.edb_padstack.GetData().GetMaterial()
928
+ return self._padstack_def_data.GetMaterial()
713
929
 
714
930
  @material.setter
715
931
  def material(self, materialname):
716
- originalPadstackDefinitionData = self.edb_padstack.GetData()
717
- newPadstackDefinitionData = self._edb.definition.PadstackDefData(originalPadstackDefinitionData)
718
- newPadstackDefinitionData.SetMaterial(materialname)
719
- self.edb_padstack.SetData(newPadstackDefinitionData)
932
+ pdef_data = self._padstack_def_data
933
+ pdef_data.SetMaterial(materialname)
934
+ self._padstack_def_data = pdef_data
720
935
 
721
936
  @property
722
937
  def padstack_instances(self):
@@ -736,36 +951,15 @@ class EDBPadstack(object):
736
951
  -------
737
952
  str
738
953
  Possible returned values are ``"through"``, ``"begin_on_upper_pad"``,
739
- ``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"undefined"``.
954
+ ``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"unknown_range"``.
740
955
  """
741
- cloned_padstackdef_data = self._edb.definition.PadstackDefData(self.edb_padstack.GetData())
742
- hole_ange_type = int(cloned_padstackdef_data.GetHoleRange())
743
- if hole_ange_type == 0: # pragma no cover
744
- return "through"
745
- elif hole_ange_type == 1: # pragma no cover
746
- return "begin_on_upper_pad"
747
- elif hole_ange_type == 2: # pragma no cover
748
- return "end_on_lower_pad"
749
- elif hole_ange_type == 3: # pragma no cover
750
- return "upper_pad_to_lower_pad"
751
- else: # pragma no cover
752
- return "undefined"
956
+ return pascal_to_snake(self._padstack_def_data.GetHoleRange().ToString())
753
957
 
754
958
  @hole_range.setter
755
959
  def hole_range(self, value):
756
- if isinstance(value, str): # pragma no cover
757
- cloned_padstackdef_data = self._edb.definition.PadstackDefData(self.edb_padstack.GetData())
758
- if value == "through": # pragma no cover
759
- cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.Through)
760
- elif value == "begin_on_upper_pad": # pragma no cover
761
- cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.BeginOnUpperPad)
762
- elif value == "end_on_lower_pad": # pragma no cover
763
- cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.EndOnLowerPad)
764
- elif value == "upper_pad_to_lower_pad": # pragma no cover
765
- cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.UpperPadToLowerPad)
766
- else: # pragma no cover
767
- return
768
- self.edb_padstack.SetData(cloned_padstackdef_data)
960
+ pdef_data = self._padstack_def_data
961
+ pdef_data.SetHoleRange(getattr(self._edb.definition.PadstackHoleRange, snake_to_pascal(value)))
962
+ self._padstack_def_data = pdef_data
769
963
 
770
964
  def convert_to_3d_microvias(self, convert_only_signal_vias=True, hole_wall_angle=15, delete_padstack_def=True):
771
965
  """Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
@@ -984,7 +1178,7 @@ class EDBPadstack(object):
984
1178
  )
985
1179
  new_padstack_definition_data.SetHoleParameters(
986
1180
  self.hole_type,
987
- self.hole_parameters,
1181
+ self._hole_parameters,
988
1182
  self._get_edb_value(self.hole_offset_x),
989
1183
  self._get_edb_value(self.hole_offset_y),
990
1184
  self._get_edb_value(self.hole_rotation),
@@ -1128,6 +1322,18 @@ class EDBPadstack(object):
1128
1322
  self.edb_padstack.SetData(new_padstack_data)
1129
1323
  return True
1130
1324
 
1325
+ def set_properties(self, **kwargs):
1326
+ for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
1327
+ value = kwargs.get(k, False)
1328
+ if value:
1329
+ setattr(self, k, value)
1330
+
1331
+ def get_properties(self):
1332
+ kwargs = {}
1333
+ for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
1334
+ kwargs[k] = getattr(self, k)
1335
+ return kwargs
1336
+
1131
1337
 
1132
1338
  class EDBPadstackInstance(Primitive):
1133
1339
  """Manages EDB functionalities for a padstack.
@@ -1466,6 +1672,56 @@ class EDBPadstackInstance(Primitive):
1466
1672
  else:
1467
1673
  return
1468
1674
 
1675
+ @property
1676
+ def backdrill_parameters(self):
1677
+ data = {}
1678
+ flag, drill_to_layer, offset, diameter = self._edb_object.GetBackDrillParametersLayerValue(
1679
+ self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer),
1680
+ self._pedb.edb_value(0),
1681
+ self._pedb.edb_value(0.0),
1682
+ True,
1683
+ )
1684
+ if flag:
1685
+ if drill_to_layer.GetName():
1686
+ data["from_bottom"] = {
1687
+ "drill_to_layer": drill_to_layer.GetName(),
1688
+ "diameter": diameter.ToString(),
1689
+ "stub_length": offset.ToString(),
1690
+ }
1691
+ flag, drill_to_layer, offset, diameter = self._edb_object.GetBackDrillParametersLayerValue(
1692
+ self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer),
1693
+ self._pedb.edb_value(0),
1694
+ self._pedb.edb_value(0.0),
1695
+ False,
1696
+ )
1697
+ if flag:
1698
+ if drill_to_layer.GetName():
1699
+ data["from_top"] = {
1700
+ "drill_to_layer": drill_to_layer.GetName(),
1701
+ "diameter": diameter.ToString(),
1702
+ "stub_length": offset.ToString(),
1703
+ }
1704
+ return data
1705
+
1706
+ @backdrill_parameters.setter
1707
+ def backdrill_parameters(self, params):
1708
+ from_bottom = params.get("from_bottom")
1709
+ if from_bottom:
1710
+ self._edb_object.SetBackDrillParameters(
1711
+ self._pedb.stackup.layers[from_bottom.get("drill_to_layer")]._edb_object,
1712
+ self._pedb.edb_value(from_bottom.get("stub_length")),
1713
+ self._pedb.edb_value(from_bottom.get("diameter")),
1714
+ True,
1715
+ )
1716
+ from_top = params.get("from_top")
1717
+ if from_top:
1718
+ self._edb_object.SetBackDrillParameters(
1719
+ self._pedb.stackup.layers[from_top.get("drill_to_layer")]._edb_object,
1720
+ self._pedb.edb_value(from_top.get("stub_length")),
1721
+ self._pedb.edb_value(from_top.get("diameter")),
1722
+ False,
1723
+ )
1724
+
1469
1725
  def set_backdrill_bottom(self, drill_depth, drill_diameter, offset=0.0):
1470
1726
  """Set backdrill from bottom.
1471
1727
 
@@ -158,7 +158,7 @@ class EdbPolygon(Primitive):
158
158
 
159
159
  Examples
160
160
  --------
161
- >>> edbapp = pyaedt.Edb("myproject.aedb")
161
+ >>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
162
162
  >>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
163
163
  >>> for polygon in top_layer_polygon:
164
164
  >>> polygon.move(vector=["2mm", "100um"])
@@ -191,7 +191,7 @@ class EdbPolygon(Primitive):
191
191
 
192
192
  Examples
193
193
  --------
194
- >>> edbapp = pyaedt.Edb("myproject.aedb")
194
+ >>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
195
195
  >>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
196
196
  >>> for polygon in top_layer_polygon:
197
197
  >>> polygon.rotate(angle=45)
@@ -28,6 +28,7 @@ This module contains EDB general methods and related methods.
28
28
  from __future__ import absolute_import # noreorder
29
29
 
30
30
  import logging
31
+ import re
31
32
 
32
33
  from pyedb.dotnet.clr_module import Dictionary, List, Tuple
33
34
 
@@ -140,6 +141,16 @@ def convert_net_list_to_py_list(netlist):
140
141
  return pylist
141
142
 
142
143
 
144
+ def pascal_to_snake(s):
145
+ # Convert PascalCase to snake_case
146
+ return re.sub(r"(?<!^)(?=[A-Z])", "_", s).lower()
147
+
148
+
149
+ def snake_to_pascal(s):
150
+ # Split the string at underscores and capitalize the first letter of each part
151
+ return "".join(word.capitalize() for word in s.split("_"))
152
+
153
+
143
154
  class PadGeometryTpe(Enum): # pragma: no cover
144
155
  Circle = 1
145
156
  Square = 2
@@ -190,9 +190,9 @@ class LayoutValidation:
190
190
  l1 = objs[0].get_connected_object_id_set()
191
191
  l1.append(objs[0].id)
192
192
  repetition = False
193
- for net_list in net_groups:
194
- if set(l1).intersection(net_list):
195
- net_groups.append([i for i in l1 if i not in net_list])
193
+ for id_by_net in net_groups:
194
+ if set(l1).intersection(id_by_net):
195
+ net_groups.append([i for i in l1 if i not in id_by_net])
196
196
  repetition = True
197
197
  if not repetition:
198
198
  net_groups.append(l1)
@@ -1460,6 +1460,9 @@ class Modeler(object):
1460
1460
  self._pedb.active_layout, name, convert_py_list_to_net_list(pins)
1461
1461
  )
1462
1462
  if obj.IsNull():
1463
- self._logger.debug("Pin group creation returned Null obj.")
1464
- return False
1463
+ raise RuntimeError(f"Failed to create pin group {name}.")
1464
+ else:
1465
+ net_obj = [i.GetNet() for i in pins if not i.GetNet().IsNull()]
1466
+ if net_obj:
1467
+ obj.SetNet(net_obj[0])
1465
1468
  return self._pedb.siwave.pin_groups[name]