pyedb 0.53.0__py3-none-any.whl → 0.55.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.

Files changed (119) hide show
  1. pyedb/__init__.py +1 -8
  2. pyedb/configuration/cfg_boundaries.py +69 -151
  3. pyedb/configuration/cfg_components.py +201 -460
  4. pyedb/configuration/cfg_data.py +4 -2
  5. pyedb/configuration/cfg_general.py +13 -36
  6. pyedb/configuration/cfg_modeler.py +2 -1
  7. pyedb/configuration/cfg_nets.py +21 -35
  8. pyedb/configuration/cfg_operations.py +22 -151
  9. pyedb/configuration/cfg_package_definition.py +56 -112
  10. pyedb/configuration/cfg_padstacks.py +292 -688
  11. pyedb/configuration/cfg_pin_groups.py +32 -79
  12. pyedb/configuration/cfg_ports_sources.py +20 -9
  13. pyedb/configuration/cfg_s_parameter_models.py +67 -172
  14. pyedb/configuration/cfg_setup.py +102 -295
  15. pyedb/configuration/configuration.py +66 -6
  16. pyedb/dotnet/database/cell/connectable.py +38 -9
  17. pyedb/dotnet/database/cell/hierarchy/component.py +28 -28
  18. pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
  19. pyedb/dotnet/database/cell/layout.py +64 -3
  20. pyedb/dotnet/database/cell/layout_obj.py +3 -3
  21. pyedb/dotnet/database/cell/primitive/path.py +6 -8
  22. pyedb/dotnet/database/cell/primitive/primitive.py +10 -31
  23. pyedb/dotnet/database/cell/terminal/edge_terminal.py +2 -2
  24. pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
  25. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  26. pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
  27. pyedb/dotnet/database/cell/terminal/terminal.py +26 -28
  28. pyedb/dotnet/database/cell/voltage_regulator.py +0 -21
  29. pyedb/dotnet/database/components.py +99 -91
  30. pyedb/dotnet/database/definition/component_def.py +4 -4
  31. pyedb/dotnet/database/definition/component_model.py +1 -1
  32. pyedb/dotnet/database/definition/package_def.py +2 -3
  33. pyedb/dotnet/database/dotnet/database.py +27 -218
  34. pyedb/dotnet/database/dotnet/primitive.py +16 -16
  35. pyedb/dotnet/database/edb_data/control_file.py +5 -5
  36. pyedb/dotnet/database/edb_data/hfss_extent_info.py +6 -6
  37. pyedb/dotnet/database/edb_data/layer_data.py +35 -35
  38. pyedb/dotnet/database/edb_data/padstacks_data.py +65 -90
  39. pyedb/dotnet/database/edb_data/primitives_data.py +5 -5
  40. pyedb/dotnet/database/edb_data/sources.py +6 -6
  41. pyedb/dotnet/database/edb_data/variables.py +8 -4
  42. pyedb/dotnet/database/geometry/point_data.py +14 -10
  43. pyedb/dotnet/database/geometry/polygon_data.py +3 -5
  44. pyedb/dotnet/database/hfss.py +50 -52
  45. pyedb/dotnet/database/layout_validation.py +14 -11
  46. pyedb/dotnet/database/materials.py +10 -11
  47. pyedb/dotnet/database/modeler.py +104 -101
  48. pyedb/dotnet/database/nets.py +20 -23
  49. pyedb/dotnet/database/padstack.py +156 -84
  50. pyedb/dotnet/database/sim_setup_data/data/settings.py +24 -0
  51. pyedb/dotnet/database/sim_setup_data/io/siwave.py +26 -1
  52. pyedb/dotnet/database/siwave.py +47 -47
  53. pyedb/dotnet/database/stackup.py +152 -87
  54. pyedb/dotnet/database/utilities/heatsink.py +4 -4
  55. pyedb/dotnet/database/utilities/obj_base.py +3 -3
  56. pyedb/dotnet/database/utilities/simulation_setup.py +2 -2
  57. pyedb/dotnet/database/utilities/value.py +116 -0
  58. pyedb/dotnet/edb.py +248 -170
  59. pyedb/edb_logger.py +12 -27
  60. pyedb/extensions/via_design_backend.py +6 -3
  61. pyedb/generic/design_types.py +68 -21
  62. pyedb/generic/general_methods.py +0 -120
  63. pyedb/generic/process.py +44 -108
  64. pyedb/generic/settings.py +75 -19
  65. pyedb/grpc/__init__.py +0 -0
  66. pyedb/grpc/database/components.py +55 -17
  67. pyedb/grpc/database/control_file.py +5 -5
  68. pyedb/grpc/database/definition/materials.py +24 -31
  69. pyedb/grpc/database/definition/package_def.py +18 -18
  70. pyedb/grpc/database/definition/padstack_def.py +104 -51
  71. pyedb/grpc/database/geometry/arc_data.py +7 -5
  72. pyedb/grpc/database/geometry/point_3d_data.py +8 -7
  73. pyedb/grpc/database/geometry/polygon_data.py +4 -3
  74. pyedb/grpc/database/hierarchy/component.py +43 -38
  75. pyedb/grpc/database/hierarchy/pin_pair_model.py +15 -14
  76. pyedb/grpc/database/hierarchy/pingroup.py +9 -9
  77. pyedb/grpc/database/layers/stackup_layer.py +45 -44
  78. pyedb/grpc/database/layout/layout.py +17 -13
  79. pyedb/grpc/database/layout/voltage_regulator.py +7 -7
  80. pyedb/grpc/database/layout_validation.py +16 -15
  81. pyedb/grpc/database/modeler.py +60 -58
  82. pyedb/grpc/database/net/net.py +15 -14
  83. pyedb/grpc/database/nets.py +112 -31
  84. pyedb/grpc/database/padstacks.py +303 -190
  85. pyedb/grpc/database/ports/ports.py +5 -6
  86. pyedb/grpc/database/primitive/bondwire.py +8 -7
  87. pyedb/grpc/database/primitive/circle.py +4 -4
  88. pyedb/grpc/database/primitive/padstack_instance.py +191 -23
  89. pyedb/grpc/database/primitive/path.py +7 -7
  90. pyedb/grpc/database/primitive/polygon.py +3 -3
  91. pyedb/grpc/database/primitive/primitive.py +13 -17
  92. pyedb/grpc/database/primitive/rectangle.py +13 -13
  93. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +1 -1
  94. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +10 -0
  95. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +17 -1
  96. pyedb/grpc/database/siwave.py +31 -25
  97. pyedb/grpc/database/source_excitations.py +335 -233
  98. pyedb/grpc/database/stackup.py +165 -148
  99. pyedb/grpc/database/terminal/bundle_terminal.py +18 -8
  100. pyedb/grpc/database/terminal/edge_terminal.py +10 -0
  101. pyedb/grpc/database/terminal/padstack_instance_terminal.py +16 -5
  102. pyedb/grpc/database/terminal/pingroup_terminal.py +12 -11
  103. pyedb/grpc/database/terminal/point_terminal.py +4 -3
  104. pyedb/grpc/database/terminal/terminal.py +9 -9
  105. pyedb/grpc/database/utility/value.py +109 -0
  106. pyedb/grpc/database/utility/xml_control_file.py +5 -5
  107. pyedb/grpc/edb.py +130 -63
  108. pyedb/grpc/edb_init.py +3 -10
  109. pyedb/grpc/rpc_session.py +10 -10
  110. pyedb/libraries/common.py +366 -0
  111. pyedb/libraries/rf_libraries/base_functions.py +1358 -0
  112. pyedb/libraries/rf_libraries/planar_antennas.py +628 -0
  113. pyedb/misc/decorators.py +61 -0
  114. pyedb/misc/misc.py +0 -13
  115. pyedb/siwave.py +2 -2
  116. {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/METADATA +2 -3
  117. {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/RECORD +119 -112
  118. {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/WHEEL +0 -0
  119. {pyedb-0.53.0.dist-info → pyedb-0.55.0.dist-info}/licenses/LICENSE +0 -0
@@ -23,7 +23,9 @@
23
23
  """
24
24
  This module contains the `EdbPadstacks` class.
25
25
  """
26
+ from collections import defaultdict
26
27
  import math
28
+ from typing import Any, Dict, List, Optional, Tuple, Union
27
29
  import warnings
28
30
 
29
31
  from ansys.edb.core.definition.padstack_def_data import (
@@ -44,13 +46,13 @@ from ansys.edb.core.definition.padstack_def_data import (
44
46
  from ansys.edb.core.definition.padstack_def_data import PadType as GrpcPadType
45
47
  from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
46
48
  from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
47
- from ansys.edb.core.utility.value import Value as GrpcValue
48
49
  import numpy as np
49
50
  import rtree
50
51
 
51
52
  from pyedb.generic.general_methods import generate_unique_name
52
53
  from pyedb.grpc.database.definition.padstack_def import PadstackDef
53
54
  from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
55
+ from pyedb.grpc.database.utility.value import Value
54
56
  from pyedb.modeler.geometry_operators import GeometryOperators
55
57
 
56
58
 
@@ -89,37 +91,36 @@ class Padstacks(object):
89
91
  self._pedb.logger.error("Component or definition not found.")
90
92
  return
91
93
 
92
- def __init__(self, p_edb):
94
+ def __init__(self, p_edb: Any) -> None:
93
95
  self._pedb = p_edb
94
- self._instances = {}
95
- self._definitions = {}
96
+ self.__definitions: Dict[str, Any] = {}
96
97
 
97
98
  @property
98
- def _active_layout(self):
99
+ def _active_layout(self) -> Any:
99
100
  """ """
100
101
  return self._pedb.active_layout
101
102
 
102
103
  @property
103
- def _layout(self):
104
+ def _layout(self) -> Any:
104
105
  """ """
105
106
  return self._pedb.layout
106
107
 
107
108
  @property
108
- def db(self):
109
+ def db(self) -> Any:
109
110
  """Db object."""
110
111
  return self._pedb.active_db
111
112
 
112
113
  @property
113
- def _logger(self):
114
+ def _logger(self) -> Any:
114
115
  """ """
115
116
  return self._pedb.logger
116
117
 
117
118
  @property
118
- def _layers(self):
119
+ def _layers(self) -> Any:
119
120
  """ """
120
121
  return self._pedb.stackup.layers
121
122
 
122
- def int_to_pad_type(self, val=0):
123
+ def int_to_pad_type(self, val=0) -> GrpcPadType:
123
124
  """Convert an integer to an EDB.PadGeometryType.
124
125
 
125
126
  Parameters
@@ -150,7 +151,7 @@ class Padstacks(object):
150
151
  else:
151
152
  return val
152
153
 
153
- def int_to_geometry_type(self, val=0):
154
+ def int_to_geometry_type(self, val: int = 0) -> GrpcPadGeometryType:
154
155
  """Convert an integer to an EDB.PadGeometryType.
155
156
 
156
157
  Parameters
@@ -195,7 +196,7 @@ class Padstacks(object):
195
196
  return val
196
197
 
197
198
  @property
198
- def definitions(self):
199
+ def definitions(self) -> Dict[str, PadstackDef]:
199
200
  """Padstack definitions.
200
201
 
201
202
  Returns
@@ -209,16 +210,15 @@ class Padstacks(object):
209
210
  >>> for name, definition in all_definitions.items():
210
211
  ... print(f"Padstack: {name}")
211
212
  """
212
- if len(self._definitions) == len(self.db.padstack_defs):
213
- return self._definitions
214
- self._definitions = {}
215
- for padstack_def in self._pedb.db.padstack_defs:
213
+ padstack_defs = self._pedb.db.padstack_defs
214
+ self.__definitions = {}
215
+ for padstack_def in padstack_defs:
216
216
  if len(padstack_def.data.layer_names) >= 1:
217
- self._definitions[padstack_def.name] = PadstackDef(self._pedb, padstack_def)
218
- return self._definitions
217
+ self.__definitions[padstack_def.name] = PadstackDef(self._pedb, padstack_def)
218
+ return self.__definitions
219
219
 
220
220
  @property
221
- def instances(self):
221
+ def instances(self) -> Dict[int, PadstackInstance]:
222
222
  """All padstack instances (vias and pins) in the layout.
223
223
 
224
224
  Returns
@@ -228,18 +228,14 @@ class Padstacks(object):
228
228
 
229
229
  Examples
230
230
  --------
231
- >>> all_instances = edb_padstacks.instances
231
+ >>> all_instances = edb.padstacks.instances
232
232
  >>> for id, instance in all_instances.items():
233
233
  ... print(f"Instance {id}: {instance.name}")
234
234
  """
235
- pad_stack_inst = self._pedb.layout.padstack_instances
236
- if len(self._instances) == len(pad_stack_inst):
237
- return self._instances
238
- self._instances = {i.edb_uid: PadstackInstance(self._pedb, i) for i in pad_stack_inst}
239
- return self._instances
235
+ return self._pedb.layout.padstack_instances
240
236
 
241
237
  @property
242
- def instances_by_name(self):
238
+ def instances_by_name(self) -> Dict[str, PadstackInstance]:
243
239
  """All padstack instances (vias and pins) indexed by name.
244
240
 
245
241
  Returns
@@ -259,7 +255,7 @@ class Padstacks(object):
259
255
  padstack_instances[edb_padstack_instance.aedt_name] = edb_padstack_instance
260
256
  return padstack_instances
261
257
 
262
- def find_instance_by_id(self, value: int):
258
+ def find_instance_by_id(self, value: int) -> Optional[PadstackInstance]:
263
259
  """Find a padstack instance by database ID.
264
260
 
265
261
  Parameters
@@ -281,7 +277,7 @@ class Padstacks(object):
281
277
  return self._pedb.modeler.find_object_by_id(value)
282
278
 
283
279
  @property
284
- def pins(self):
280
+ def pins(self) -> Dict[int, PadstackInstance]:
285
281
  """All pin instances belonging to components.
286
282
 
287
283
  Returns
@@ -302,7 +298,7 @@ class Padstacks(object):
302
298
  return pins
303
299
 
304
300
  @property
305
- def vias(self):
301
+ def vias(self) -> Dict[int, PadstackInstance]:
306
302
  """All via instances not belonging to components.
307
303
 
308
304
  Returns
@@ -321,7 +317,7 @@ class Padstacks(object):
321
317
  return vias
322
318
 
323
319
  @property
324
- def pingroups(self):
320
+ def pingroups(self) -> List[Any]:
325
321
  """All Layout Pin groups.
326
322
 
327
323
  . deprecated:: pyedb 0.28.0
@@ -344,18 +340,19 @@ class Padstacks(object):
344
340
  return self._layout.pin_groups
345
341
 
346
342
  @property
347
- def pad_type(self):
343
+ def pad_type(self) -> GrpcPadType:
348
344
  """Return a PadType Enumerator."""
345
+ return GrpcPadType
349
346
 
350
347
  def create_circular_padstack(
351
348
  self,
352
- padstackname=None,
353
- holediam="300um",
354
- paddiam="400um",
355
- antipaddiam="600um",
356
- startlayer=None,
357
- endlayer=None,
358
- ):
349
+ padstackname: Optional[str] = None,
350
+ holediam: str = "300um",
351
+ paddiam: str = "400um",
352
+ antipaddiam: str = "600um",
353
+ startlayer: Optional[str] = None,
354
+ endlayer: Optional[str] = None,
355
+ ) -> str:
359
356
  """Create a circular padstack.
360
357
 
361
358
  Parameters
@@ -393,11 +390,11 @@ class Padstacks(object):
393
390
  padstack_def = PadstackDef.create(self._pedb.db, padstackname)
394
391
 
395
392
  padstack_data = GrpcPadstackDefData.create()
396
- list_values = [GrpcValue(holediam), GrpcValue(paddiam), GrpcValue(antipaddiam)]
393
+ list_values = [Value(holediam), Value(paddiam), Value(antipaddiam)]
397
394
  padstack_data.set_hole_parameters(
398
- offset_x=GrpcValue(0),
399
- offset_y=GrpcValue(0),
400
- rotation=GrpcValue(0),
395
+ offset_x=Value(0),
396
+ offset_y=Value(0),
397
+ rotation=Value(0),
401
398
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
402
399
  sizes=list_values,
403
400
  )
@@ -415,20 +412,20 @@ class Padstacks(object):
415
412
  layer="Default",
416
413
  pad_type=GrpcPadType.REGULAR_PAD,
417
414
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
418
- offset_x=GrpcValue(0),
419
- offset_y=GrpcValue(0),
420
- rotation=GrpcValue(0),
421
- sizes=[GrpcValue(paddiam)],
415
+ offset_x=Value(0),
416
+ offset_y=Value(0),
417
+ rotation=Value(0),
418
+ sizes=[Value(paddiam)],
422
419
  )
423
420
 
424
421
  padstack_data.set_pad_parameters(
425
422
  layer="Default",
426
423
  pad_type=GrpcPadType.ANTI_PAD,
427
424
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
428
- offset_x=GrpcValue(0),
429
- offset_y=GrpcValue(0),
430
- rotation=GrpcValue(0),
431
- sizes=[GrpcValue(antipaddiam)],
425
+ offset_x=Value(0),
426
+ offset_y=Value(0),
427
+ rotation=Value(0),
428
+ sizes=[Value(antipaddiam)],
432
429
  )
433
430
 
434
431
  for layer in layers:
@@ -441,25 +438,25 @@ class Padstacks(object):
441
438
  layer=layer,
442
439
  pad_type=GrpcPadType.ANTI_PAD,
443
440
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
444
- offset_x=GrpcValue(0),
445
- offset_y=GrpcValue(0),
446
- rotation=GrpcValue(0),
447
- sizes=[GrpcValue(antipaddiam)],
441
+ offset_x=Value(0),
442
+ offset_y=Value(0),
443
+ rotation=Value(0),
444
+ sizes=[Value(antipaddiam)],
448
445
  )
449
446
 
450
447
  padstack_data.set_pad_parameters(
451
448
  layer=layer,
452
449
  pad_type=GrpcPadType.ANTI_PAD,
453
450
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
454
- offset_x=GrpcValue(0),
455
- offset_y=GrpcValue(0),
456
- rotation=GrpcValue(0),
457
- sizes=[GrpcValue(antipaddiam)],
451
+ offset_x=Value(0),
452
+ offset_y=Value(0),
453
+ rotation=Value(0),
454
+ sizes=[Value(antipaddiam)],
458
455
  )
459
456
 
460
457
  padstack_def.data = padstack_data
461
458
 
462
- def delete_padstack_instances(self, net_names): # pragma: no cover
459
+ def delete_padstack_instances(self, net_names: Union[str, List[str]]) -> bool:
463
460
  """Delete padstack instances by net names.
464
461
 
465
462
  Parameters
@@ -487,28 +484,23 @@ class Padstacks(object):
487
484
  return True
488
485
 
489
486
  def set_solderball(self, padstackInst, sballLayer_name, isTopPlaced=True, ballDiam=100e-6):
490
- """Set solderball for a padstack instance.
487
+ """Set solderball for the given PadstackInstance.
491
488
 
492
489
  Parameters
493
490
  ----------
494
- padstackInst : int or :class:`pyedb.grpc.database.primitive.padstack_instance.PadstackInstance`
495
- Padstack instance ID or object.
496
- sballLayer_name : str
497
- Name of the layer where the solder ball is placed.
498
- isTopPlaced : bool, optional
499
- Whether the solder ball is placed on top of the layer stackup. Default is ``True``.
500
- ballDiam : float, optional
501
- Solder ball diameter in meters. Default is ``100e-6`` (100 um).
491
+ padstackInst : Edb.Cell.Primitive.PadstackInstance or int
492
+ Padstack instance id or object.
493
+ sballLayer_name : str,
494
+ Name of the layer where the solder ball is placed. No default values.
495
+ isTopPlaced : bool, optional.
496
+ Bollean triggering is the solder ball is placed on Top or Bottom of the layer stackup.
497
+ ballDiam : double, optional,
498
+ Solder ball diameter value.
502
499
 
503
500
  Returns
504
501
  -------
505
502
  bool
506
- ``True`` when successful, ``False`` when failed.
507
503
 
508
- Examples
509
- --------
510
- >>> via_id = 123
511
- >>> success = edb_padstacks.set_solderball(via_id, "SolderBall_Top", True, 150e-6)
512
504
  """
513
505
  if isinstance(padstackInst, int):
514
506
  psdef = self.definitions[self.instances[padstackInst].padstack_definition].edb_padstack
@@ -518,7 +510,7 @@ class Padstacks(object):
518
510
  psdef = padstackInst.padstack_def
519
511
  newdefdata = GrpcPadstackDefData.create(psdef.data)
520
512
  newdefdata.solder_ball_shape = GrpcSolderballShape.SOLDERBALL_CYLINDER
521
- newdefdata.solder_ball_param(GrpcValue(ballDiam), GrpcValue(ballDiam))
513
+ newdefdata.solder_ball_param(Value(ballDiam), Value(ballDiam))
522
514
  sball_placement = (
523
515
  GrpcSolderballPlacement.ABOVE_PADSTACK if isTopPlaced else GrpcSolderballPlacement.BELOW_PADSTACK
524
516
  )
@@ -568,7 +560,9 @@ class Padstacks(object):
568
560
  self, padstackinstance, use_dot_separator=use_dot_separator, name=name
569
561
  )
570
562
 
571
- def get_pin_from_component_and_net(self, refdes=None, netname=None):
563
+ def get_pin_from_component_and_net(
564
+ self, refdes: Optional[str] = None, netname: Optional[str] = None
565
+ ) -> (List)[PadstackInstance]:
572
566
  """Retrieve pins by component reference designator and net name.
573
567
 
574
568
  Parameters
@@ -637,7 +631,9 @@ class Padstacks(object):
637
631
  )
638
632
  return self.get_pin_from_component_and_net(refdes=refdes, netname=netname)
639
633
 
640
- def get_pad_parameters(self, pin, layername, pad_type="regular_pad"):
634
+ def get_pad_parameters(
635
+ self, pin: PadstackInstance, layername: str, pad_type: str = "regular_pad"
636
+ ) -> Tuple[GrpcPadGeometryType, List[float], List[float], float]:
641
637
  """Get pad parameters for a pin on a specific layer.
642
638
 
643
639
  Parameters
@@ -675,10 +671,10 @@ class Padstacks(object):
675
671
  padparams = pin.padstack_def.data.get_pad_parameters(layername, pad_type)
676
672
  if len(padparams) == 5: # non polygon via
677
673
  geometry_type = padparams[0]
678
- parameters = [i.value for i in padparams[1]]
679
- offset_x = padparams[2].value
680
- offset_y = padparams[3].value
681
- rotation = padparams[4].value
674
+ parameters = [Value(i) for i in padparams[1]]
675
+ offset_x = Value(padparams[2])
676
+ offset_y = Value(padparams[3])
677
+ rotation = Value(padparams[4])
682
678
  return geometry_type.name, parameters, offset_x, offset_y, rotation
683
679
  elif len(padparams) == 4: # polygon based
684
680
  from ansys.edb.core.geometry.polygon_data import (
@@ -686,15 +682,15 @@ class Padstacks(object):
686
682
  )
687
683
 
688
684
  if isinstance(padparams[0], GrpcPolygonData):
689
- points = [[pt.x.value, pt.y.value] for pt in padparams[0].points]
690
- offset_x = padparams[1]
691
- offset_y = padparams[2]
692
- rotation = padparams[3]
685
+ points = [[Value(pt.x), Value(pt.y)] for pt in padparams[0].points]
686
+ offset_x = Value(padparams[1])
687
+ offset_y = Value(padparams[2])
688
+ rotation = Value(padparams[3])
693
689
  geometry_type = GrpcPadGeometryType.PADGEOMTYPE_POLYGON
694
690
  return geometry_type.name, points, offset_x, offset_y, rotation
695
691
  return 0, [0], 0, 0, 0
696
692
 
697
- def set_all_antipad_value(self, value):
693
+ def set_all_antipad_value(self, value: Union[float, str]) -> bool:
698
694
  """Set anti-pad value for all padstack definitions.
699
695
 
700
696
  Parameters
@@ -725,11 +721,11 @@ class Padstacks(object):
725
721
  cloned_padstack_data.set_pad_parameters(
726
722
  layer=layer,
727
723
  pad_type=GrpcPadType.ANTI_PAD,
728
- offset_x=GrpcValue(offset_x),
729
- offset_y=GrpcValue(offset_y),
730
- rotation=GrpcValue(rotation),
724
+ offset_x=Value(offset_x),
725
+ offset_y=Value(offset_y),
726
+ rotation=Value(rotation),
731
727
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
732
- sizes=[GrpcValue(value)],
728
+ sizes=[Value(value)],
733
729
  )
734
730
  self._logger.info(
735
731
  "Pad-stack definition {}, anti-pad on layer {}, has been set to {}".format(
@@ -749,7 +745,9 @@ class Padstacks(object):
749
745
  padstack.data = cloned_padstack_data
750
746
  return all_succeed
751
747
 
752
- def check_and_fix_via_plating(self, minimum_value_to_replace=0.0, default_plating_ratio=0.2):
748
+ def check_and_fix_via_plating(
749
+ self, minimum_value_to_replace: float = 0.0, default_plating_ratio: float = 0.2
750
+ ) -> bool:
753
751
  """Check and fix via plating ratios below a minimum value.
754
752
 
755
753
  Parameters
@@ -776,7 +774,7 @@ class Padstacks(object):
776
774
  )
777
775
  return True
778
776
 
779
- def get_via_instance_from_net(self, net_list=None):
777
+ def get_via_instance_from_net(self, net_list: Optional[Union[str, List[str]]] = None) -> List[PadstackInstance]:
780
778
  """Get via instances by net names.
781
779
 
782
780
  Parameters
@@ -797,7 +795,7 @@ class Padstacks(object):
797
795
  if net_list and not isinstance(net_list, list):
798
796
  net_list = [net_list]
799
797
  via_list = []
800
- for inst in self._layout.padstack_instances:
798
+ for inst_id, inst in self._layout.padstack_instances.items():
801
799
  pad_layers_name = inst.padstack_def.data.layer_names
802
800
  if len(pad_layers_name) > 1:
803
801
  if not net_list:
@@ -809,31 +807,31 @@ class Padstacks(object):
809
807
 
810
808
  def create(
811
809
  self,
812
- padstackname=None,
813
- holediam="300um",
814
- paddiam="400um",
815
- antipaddiam="600um",
816
- pad_shape="Circle",
817
- antipad_shape="Circle",
818
- x_size="600um",
819
- y_size="600um",
820
- corner_radius="300um",
821
- offset_x="0.0",
822
- offset_y="0.0",
823
- rotation="0.0",
824
- has_hole=True,
825
- pad_offset_x="0.0",
826
- pad_offset_y="0.0",
827
- pad_rotation="0.0",
828
- pad_polygon=None,
829
- antipad_polygon=None,
830
- polygon_hole=None,
831
- start_layer=None,
832
- stop_layer=None,
833
- add_default_layer=False,
834
- anti_pad_x_size="600um",
835
- anti_pad_y_size="600um",
836
- hole_range="upper_pad_to_lower_pad",
810
+ padstackname: Optional[str] = None,
811
+ holediam: str = "300um",
812
+ paddiam: str = "400um",
813
+ antipaddiam: str = "600um",
814
+ pad_shape: str = "Circle",
815
+ antipad_shape: str = "Circle",
816
+ x_size: str = "600um",
817
+ y_size: str = "600um",
818
+ corner_radius: str = "300um",
819
+ offset_x: str = "0.0",
820
+ offset_y: str = "0.0",
821
+ rotation: str = "0.0",
822
+ has_hole: bool = True,
823
+ pad_offset_x: str = "0.0",
824
+ pad_offset_y: str = "0.0",
825
+ pad_rotation: str = "0.0",
826
+ pad_polygon: Optional[Any] = None,
827
+ antipad_polygon: Optional[Any] = None,
828
+ polygon_hole: Optional[Any] = None,
829
+ start_layer: Optional[str] = None,
830
+ stop_layer: Optional[str] = None,
831
+ add_default_layer: bool = False,
832
+ anti_pad_x_size: str = "600um",
833
+ anti_pad_y_size: str = "600um",
834
+ hole_range: str = "upper_pad_to_lower_pad",
837
835
  ):
838
836
  """Create a padstack definition.
839
837
 
@@ -896,11 +894,11 @@ class Padstacks(object):
896
894
  str
897
895
  Name of the created padstack definition.
898
896
  """
899
- holediam = GrpcValue(holediam)
900
- paddiam = GrpcValue(paddiam)
901
- antipaddiam = GrpcValue(antipaddiam)
897
+ holediam = Value(holediam)
898
+ paddiam = Value(paddiam)
899
+ antipaddiam = Value(antipaddiam)
902
900
  layers = list(self._pedb.stackup.signal_layers.keys())[:]
903
- value0 = GrpcValue("0.0")
901
+ value0 = Value("0.0")
904
902
  if not padstackname:
905
903
  padstackname = generate_unique_name("VIA")
906
904
  padstack_data = GrpcPadstackDefData.create()
@@ -913,7 +911,7 @@ class Padstacks(object):
913
911
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_CIRCLE,
914
912
  sizes=hole_param,
915
913
  )
916
- padstack_data.plating_percentage = GrpcValue(20.0)
914
+ padstack_data.plating_percentage = Value(20.0)
917
915
  elif polygon_hole:
918
916
  if isinstance(polygon_hole, list):
919
917
  polygon_hole = GrpcPolygonData(points=polygon_hole)
@@ -924,18 +922,18 @@ class Padstacks(object):
924
922
  type_geom=GrpcPadGeometryType.PADGEOMTYPE_POLYGON,
925
923
  fp=polygon_hole,
926
924
  )
927
- padstack_data.plating_percentage = GrpcValue(20.0)
925
+ padstack_data.plating_percentage = Value(20.0)
928
926
  else:
929
927
  pass
930
928
 
931
- x_size = GrpcValue(x_size)
932
- y_size = GrpcValue(y_size)
933
- corner_radius = GrpcValue(corner_radius)
934
- pad_offset_x = GrpcValue(pad_offset_x)
935
- pad_offset_y = GrpcValue(pad_offset_y)
936
- pad_rotation = GrpcValue(pad_rotation)
937
- anti_pad_x_size = GrpcValue(anti_pad_x_size)
938
- anti_pad_y_size = GrpcValue(anti_pad_y_size)
929
+ x_size = Value(x_size)
930
+ y_size = Value(y_size)
931
+ corner_radius = Value(corner_radius)
932
+ pad_offset_x = Value(pad_offset_x)
933
+ pad_offset_y = Value(pad_offset_y)
934
+ pad_rotation = Value(pad_rotation)
935
+ anti_pad_x_size = Value(anti_pad_x_size)
936
+ anti_pad_y_size = Value(anti_pad_y_size)
939
937
 
940
938
  if hole_range == "through": # pragma no cover
941
939
  padstack_data.hole_range = GrpcPadstackHoleRange.THROUGH
@@ -1031,14 +1029,14 @@ class Padstacks(object):
1031
1029
  self._logger.info(f"Padstack {padstackname} create correctly")
1032
1030
  return padstackname
1033
1031
 
1034
- def _get_pin_layer_range(self, pin):
1032
+ def _get_pin_layer_range(self, pin: PadstackInstance) -> Union[Tuple[str, str], bool]:
1035
1033
  layers = pin.get_layer_range()
1036
1034
  if layers:
1037
1035
  return layers[0], layers[1]
1038
1036
  else:
1039
1037
  return False
1040
1038
 
1041
- def duplicate(self, target_padstack_name, new_padstack_name=""):
1039
+ def duplicate(self, target_padstack_name: str, new_padstack_name: str = "") -> str:
1042
1040
  """Duplicate a padstack definition.
1043
1041
 
1044
1042
  Parameters
@@ -1062,16 +1060,16 @@ class Padstacks(object):
1062
1060
 
1063
1061
  def place(
1064
1062
  self,
1065
- position,
1066
- definition_name,
1067
- net_name="",
1068
- via_name="",
1069
- rotation=0.0,
1070
- fromlayer=None,
1071
- tolayer=None,
1072
- solderlayer=None,
1073
- is_pin=False,
1074
- ):
1063
+ position: List[float],
1064
+ definition_name: str,
1065
+ net_name: str = "",
1066
+ via_name: str = "",
1067
+ rotation: float = 0.0,
1068
+ fromlayer: Optional[str] = None,
1069
+ tolayer: Optional[str] = None,
1070
+ solderlayer: Optional[str] = None,
1071
+ is_pin: bool = False,
1072
+ ) -> PadstackInstance:
1075
1073
  """Place a padstack instance.
1076
1074
 
1077
1075
  Parameters
@@ -1105,10 +1103,10 @@ class Padstacks(object):
1105
1103
  if pad == definition_name:
1106
1104
  padstack_def = self.definitions[pad]
1107
1105
  position = GrpcPointData(
1108
- [GrpcValue(position[0], self._pedb.active_cell), GrpcValue(position[1], self._pedb.active_cell)]
1106
+ [Value(position[0], self._pedb.active_cell), Value(position[1], self._pedb.active_cell)]
1109
1107
  )
1110
1108
  net = self._pedb.nets.find_or_create_net(net_name)
1111
- rotation = GrpcValue(rotation * math.pi / 180)
1109
+ rotation = Value(rotation * math.pi / 180)
1112
1110
  sign_layers_values = {i: v for i, v in self._pedb.stackup.signal_layers.items()}
1113
1111
  sign_layers = list(sign_layers_values.keys())
1114
1112
  if not fromlayer:
@@ -1147,9 +1145,9 @@ class Padstacks(object):
1147
1145
  padstack_instance.is_layout_pin = is_pin
1148
1146
  return PadstackInstance(self._pedb, padstack_instance)
1149
1147
  else:
1150
- return False
1148
+ raise RuntimeError("Place padstack failed")
1151
1149
 
1152
- def remove_pads_from_padstack(self, padstack_name, layer_name=None):
1150
+ def remove_pads_from_padstack(self, padstack_name: str, layer_name: Optional[str] = None):
1153
1151
  """Remove pads from a padstack definition on specified layers.
1154
1152
 
1155
1153
  Parameters
@@ -1166,8 +1164,8 @@ class Padstacks(object):
1166
1164
  """
1167
1165
  pad_type = GrpcPadType.REGULAR_PAD
1168
1166
  pad_geo = GrpcPadGeometryType.PADGEOMTYPE_CIRCLE
1169
- vals = GrpcValue(0)
1170
- params = [GrpcValue(0)]
1167
+ vals = Value(0)
1168
+ params = [Value(0)]
1171
1169
  new_padstack_definition_data = GrpcPadstackDefData(self.definitions[padstack_name].data)
1172
1170
  if not layer_name:
1173
1171
  layer_name = list(self._pedb.stackup.signal_layers.keys())
@@ -1188,18 +1186,18 @@ class Padstacks(object):
1188
1186
 
1189
1187
  def set_pad_property(
1190
1188
  self,
1191
- padstack_name,
1192
- layer_name=None,
1193
- pad_shape="Circle",
1194
- pad_params=0,
1195
- pad_x_offset=0,
1196
- pad_y_offset=0,
1197
- pad_rotation=0,
1198
- antipad_shape="Circle",
1199
- antipad_params=0,
1200
- antipad_x_offset=0,
1201
- antipad_y_offset=0,
1202
- antipad_rotation=0,
1189
+ padstack_name: str,
1190
+ layer_name: Optional[str] = None,
1191
+ pad_shape: str = "Circle",
1192
+ pad_params: Union[float, List[float]] = 0,
1193
+ pad_x_offset: float = 0,
1194
+ pad_y_offset: float = 0,
1195
+ pad_rotation: float = 0,
1196
+ antipad_shape: str = "Circle",
1197
+ antipad_params: Union[float, List[float]] = 0,
1198
+ antipad_x_offset: float = 0,
1199
+ antipad_y_offset: float = 0,
1200
+ antipad_rotation: float = 0,
1203
1201
  ):
1204
1202
  """Set pad and anti-pad properties for a padstack definition.
1205
1203
 
@@ -1245,18 +1243,18 @@ class Padstacks(object):
1245
1243
  pad_shape = shape_dict[pad_shape]
1246
1244
  if not isinstance(pad_params, list):
1247
1245
  pad_params = [pad_params]
1248
- pad_params = [GrpcValue(i) for i in pad_params]
1249
- pad_x_offset = GrpcValue(pad_x_offset)
1250
- pad_y_offset = GrpcValue(pad_y_offset)
1251
- pad_rotation = GrpcValue(pad_rotation)
1246
+ pad_params = [Value(i) for i in pad_params]
1247
+ pad_x_offset = Value(pad_x_offset)
1248
+ pad_y_offset = Value(pad_y_offset)
1249
+ pad_rotation = Value(pad_rotation)
1252
1250
 
1253
1251
  antipad_shape = shape_dict[antipad_shape]
1254
1252
  if not isinstance(antipad_params, list):
1255
1253
  antipad_params = [antipad_params]
1256
- antipad_params = [GrpcValue(i) for i in antipad_params]
1257
- antipad_x_offset = GrpcValue(antipad_x_offset)
1258
- antipad_y_offset = GrpcValue(antipad_y_offset)
1259
- antipad_rotation = GrpcValue(antipad_rotation)
1254
+ antipad_params = [Value(i) for i in antipad_params]
1255
+ antipad_x_offset = Value(antipad_x_offset)
1256
+ antipad_y_offset = Value(antipad_y_offset)
1257
+ antipad_rotation = Value(antipad_rotation)
1260
1258
  new_padstack_def = GrpcPadstackDefData(self.definitions[padstack_name].data.msg)
1261
1259
  if not layer_name:
1262
1260
  layer_name = list(self._pedb.stackup.signal_layers.keys())
@@ -1284,15 +1282,38 @@ class Padstacks(object):
1284
1282
  self.definitions[padstack_name].data = new_padstack_def
1285
1283
  return True
1286
1284
 
1285
+ def get_padstack_instance_by_net_name(self, net: str):
1286
+ """Get padstack instances by net name.
1287
+
1288
+ .. deprecated:: 0.55.0
1289
+ Use: :func:`get_instances` with `net_name` parameter instead.
1290
+
1291
+ Parameters
1292
+ ----------
1293
+ net : str
1294
+ Net name to filter padstack instances.
1295
+
1296
+ Returns
1297
+ -------
1298
+ list[:class:`pyedb.grpc.database.primitive.padstack_instance.PadstackInstance`]
1299
+ List of padstack instances associated with the specified net.
1300
+ """
1301
+ warnings.warn(
1302
+ "`get_padstack_instance_by_net_name` is deprecated, use `get_instances` with `net_name` "
1303
+ "parameter instead.",
1304
+ DeprecationWarning,
1305
+ )
1306
+ return self.get_instances(net_name=net)
1307
+
1287
1308
  def get_instances(
1288
1309
  self,
1289
- name=None,
1290
- pid=None,
1291
- definition_name=None,
1292
- net_name=None,
1293
- component_reference_designator=None,
1294
- component_pin=None,
1295
- ):
1310
+ name: Optional[str] = None,
1311
+ pid: Optional[int] = None,
1312
+ definition_name: Optional[str] = None,
1313
+ net_name: Optional[str] = None,
1314
+ component_reference_designator: Optional[str] = None,
1315
+ component_pin: Optional[str] = None,
1316
+ ) -> List[PadstackInstance]:
1296
1317
  """Get padstack instances by search criteria.
1297
1318
 
1298
1319
  Parameters
@@ -1319,7 +1340,7 @@ class Padstacks(object):
1319
1340
  if pid:
1320
1341
  return instances_by_id[pid]
1321
1342
  elif name:
1322
- instances = [inst for inst in list(self.instances.values()) if inst.name == name]
1343
+ instances = [inst for inst in list(self.instances.values()) if inst.aedt_name == name]
1323
1344
  if instances:
1324
1345
  return instances
1325
1346
  else:
@@ -1344,8 +1365,13 @@ class Padstacks(object):
1344
1365
  return instances
1345
1366
 
1346
1367
  def get_reference_pins(
1347
- self, positive_pin, reference_net="gnd", search_radius=5e-3, max_limit=0, component_only=True
1348
- ):
1368
+ self,
1369
+ positive_pin: Union[int, str, PadstackInstance],
1370
+ reference_net: str = "gnd",
1371
+ search_radius: float = 5e-3,
1372
+ max_limit: int = 0,
1373
+ component_only: bool = True,
1374
+ ) -> List[PadstackInstance]:
1349
1375
  """Find reference pins near a specified pin.
1350
1376
 
1351
1377
  Parameters
@@ -1390,7 +1416,7 @@ class Padstacks(object):
1390
1416
  pinlist = [pin[1] for pin in sorted(pin_dict.items())[:max_limit]]
1391
1417
  return pinlist
1392
1418
 
1393
- def get_padstack_instances_rtree_index(self, nets=None):
1419
+ def get_padstack_instances_rtree_index(self, nets: Optional[Union[str, List[str]]] = None) -> rtree.index.Index:
1394
1420
  """Returns padstack instances Rtree index.
1395
1421
 
1396
1422
  Parameters
@@ -1415,7 +1441,12 @@ class Padstacks(object):
1415
1441
  padstack_instances_index.insert(inst.edb_uid, inst.position)
1416
1442
  return padstack_instances_index
1417
1443
 
1418
- def get_padstack_instances_id_intersecting_polygon(self, points, nets=None, padstack_instances_index=None):
1444
+ def get_padstack_instances_id_intersecting_polygon(
1445
+ self,
1446
+ points: List[Tuple[float, float]],
1447
+ nets: Optional[Union[str, List[str]]] = None,
1448
+ padstack_instances_index: Optional[Dict[int, Tuple[float, float]]] = None,
1449
+ ) -> List[int]:
1419
1450
  """Returns the list of padstack instances ID intersecting a given bounding box and nets.
1420
1451
 
1421
1452
  Parameters
@@ -1446,7 +1477,12 @@ class Padstacks(object):
1446
1477
  ind for ind, pt in padstack_instances_index.items() if GeometryOperators.is_point_in_polygon(pt, points)
1447
1478
  ]
1448
1479
 
1449
- def get_padstack_instances_intersecting_bounding_box(self, bounding_box, nets=None, padstack_instances_index=None):
1480
+ def get_padstack_instances_intersecting_bounding_box(
1481
+ self,
1482
+ bounding_box: List[float],
1483
+ nets: Optional[Union[str, List[str]]] = None,
1484
+ padstack_instances_index: Optional[rtree.index.Index] = None,
1485
+ ) -> List[PadstackInstance]:
1450
1486
  """Returns the list of padstack instances ID intersecting a given bounding box and nets.
1451
1487
  Parameters
1452
1488
  ----------
@@ -1475,12 +1511,12 @@ class Padstacks(object):
1475
1511
 
1476
1512
  def merge_via_along_lines(
1477
1513
  self,
1478
- net_name="GND",
1479
- distance_threshold=5e-3,
1480
- minimum_via_number=6,
1481
- selected_angles=None,
1482
- padstack_instances_id=None,
1483
- ):
1514
+ net_name: str = "GND",
1515
+ distance_threshold: float = 5e-3,
1516
+ minimum_via_number: int = 6,
1517
+ selected_angles: Optional[List[float]] = None,
1518
+ padstack_instances_id: Optional[List[int]] = None,
1519
+ ) -> None:
1484
1520
  """Replace padstack instances along lines into a single polygon.
1485
1521
 
1486
1522
  Detect all pad-stack instances that are placed along lines and replace them by a single polygon based one
@@ -1622,7 +1658,13 @@ class Padstacks(object):
1622
1658
 
1623
1659
  return True
1624
1660
 
1625
- def merge_via(self, contour_boxes, net_filter=None, start_layer=None, stop_layer=None):
1661
+ def merge_via(
1662
+ self,
1663
+ contour_boxes: List[List[float]],
1664
+ net_filter: Optional[Union[str, List[str]]] = None,
1665
+ start_layer: Optional[str] = None,
1666
+ stop_layer: Optional[str] = None,
1667
+ ) -> bool:
1626
1668
  """Evaluate pad-stack instances included on the provided point list and replace all by single instance.
1627
1669
 
1628
1670
  Parameters
@@ -1688,7 +1730,9 @@ class Padstacks(object):
1688
1730
  [self.instances[inst].delete() for inst in instances]
1689
1731
  return merged_via_ids
1690
1732
 
1691
- def reduce_via_in_bounding_box(self, bounding_box, x_samples, y_samples, nets=None):
1733
+ def reduce_via_in_bounding_box(
1734
+ self, bounding_box: List[float], x_samples: int, y_samples: int, nets: Optional[Union[str, List[str]]] = None
1735
+ ) -> bool:
1692
1736
  """
1693
1737
  reduce the number of vias intersecting bounding box and nets by x and y samples.
1694
1738
 
@@ -1740,3 +1784,72 @@ class Padstacks(object):
1740
1784
  if item not in to_keep:
1741
1785
  all_instances[item].delete()
1742
1786
  return True
1787
+
1788
+ @staticmethod
1789
+ def dbscan(
1790
+ padstack: Dict[int, List[float]], max_distance: float = 1e-3, min_samples: int = 5
1791
+ ) -> Dict[int, List[str]]:
1792
+ """
1793
+ density based spatial clustering for padstack instances
1794
+
1795
+ Parameters
1796
+ ----------
1797
+ padstack : dict.
1798
+ padstack id: [x, y]
1799
+
1800
+ max_distance: float
1801
+ maximum distance between two points to be included in one cluster
1802
+
1803
+ min_samples: int
1804
+ minimum number of points that a cluster must have
1805
+
1806
+ Returns
1807
+ -------
1808
+ dict
1809
+ clusters {cluster label: [padstack ids]} <
1810
+ """
1811
+
1812
+ padstack_ids = list(padstack.keys())
1813
+ xy_array = np.array([padstack[pid] for pid in padstack_ids])
1814
+ n = len(padstack_ids)
1815
+
1816
+ labels = -1 * np.ones(n, dtype=int)
1817
+ visited = np.zeros(n, dtype=bool)
1818
+ cluster_id = 0
1819
+
1820
+ def region_query(point_idx):
1821
+ distances = np.linalg.norm(xy_array - xy_array[point_idx], axis=1)
1822
+ return np.where(distances <= max_distance)[0]
1823
+
1824
+ def expand_cluster(point_idx, neighbors):
1825
+ nonlocal cluster_id
1826
+ labels[point_idx] = cluster_id
1827
+ i = 0
1828
+ while i < len(neighbors):
1829
+ neighbor_idx = neighbors[i]
1830
+ if not visited[neighbor_idx]:
1831
+ visited[neighbor_idx] = True
1832
+ neighbor_neighbors = region_query(neighbor_idx)
1833
+ if len(neighbor_neighbors) >= min_samples:
1834
+ neighbors = np.concatenate((neighbors, neighbor_neighbors))
1835
+ if labels[neighbor_idx] == -1:
1836
+ labels[neighbor_idx] = cluster_id
1837
+ i += 1
1838
+
1839
+ for point_idx in range(n):
1840
+ if visited[point_idx]:
1841
+ continue
1842
+ visited[point_idx] = True
1843
+ neighbors = region_query(point_idx)
1844
+ if len(neighbors) < min_samples:
1845
+ labels[point_idx] = -1
1846
+ else:
1847
+ expand_cluster(point_idx, neighbors)
1848
+ cluster_id += 1
1849
+
1850
+ # group point IDs by label
1851
+ clusters = defaultdict(list)
1852
+ for i, label in enumerate(labels):
1853
+ clusters[int(label)].append(padstack_ids[i])
1854
+
1855
+ return dict(clusters)