pyedb 0.55.0__py3-none-any.whl → 0.57.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 (107) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_operations.py +2 -2
  4. pyedb/configuration/cfg_ports_sources.py +1 -1
  5. pyedb/configuration/cfg_terminals.py +232 -0
  6. pyedb/configuration/configuration.py +146 -3
  7. pyedb/dotnet/clr_module.py +1 -2
  8. pyedb/dotnet/database/Variables.py +56 -41
  9. pyedb/dotnet/database/cell/layout.py +5 -1
  10. pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
  11. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
  12. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  13. pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
  14. pyedb/dotnet/database/components.py +55 -52
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +6 -3
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +5 -2
  19. pyedb/dotnet/database/edb_data/ports.py +0 -25
  20. pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
  21. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
  22. pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
  23. pyedb/dotnet/database/hfss.py +9 -8
  24. pyedb/dotnet/database/layout_validation.py +6 -3
  25. pyedb/dotnet/database/materials.py +1 -3
  26. pyedb/dotnet/database/modeler.py +7 -3
  27. pyedb/dotnet/database/nets.py +27 -19
  28. pyedb/dotnet/database/padstack.py +91 -2
  29. pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
  30. pyedb/dotnet/database/siwave.py +4 -3
  31. pyedb/dotnet/database/stackup.py +50 -26
  32. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  33. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  34. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  35. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +5 -2
  36. pyedb/dotnet/edb.py +41 -36
  37. pyedb/exceptions.py +1 -2
  38. pyedb/extensions/create_cell_array.py +408 -0
  39. pyedb/generic/data_handlers.py +17 -28
  40. pyedb/generic/design_types.py +25 -38
  41. pyedb/generic/filesystem.py +9 -4
  42. pyedb/generic/general_methods.py +6 -7
  43. pyedb/generic/plot.py +2 -2
  44. pyedb/generic/settings.py +4 -0
  45. pyedb/grpc/database/_typing.py +0 -0
  46. pyedb/grpc/database/components.py +30 -11
  47. pyedb/grpc/database/control_file.py +14 -35
  48. pyedb/grpc/database/definition/materials.py +1 -1
  49. pyedb/grpc/database/definition/package_def.py +6 -3
  50. pyedb/grpc/database/definition/padstack_def.py +4 -7
  51. pyedb/grpc/database/hfss.py +1 -4
  52. pyedb/grpc/database/hierarchy/component.py +3 -4
  53. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  54. pyedb/grpc/database/layers/layer.py +1 -2
  55. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  56. pyedb/grpc/database/layout/layout.py +117 -28
  57. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  58. pyedb/grpc/database/layout_validation.py +7 -4
  59. pyedb/grpc/database/modeler.py +241 -256
  60. pyedb/grpc/database/net/differential_pair.py +9 -2
  61. pyedb/grpc/database/net/extended_net.py +24 -9
  62. pyedb/grpc/database/net/net.py +14 -5
  63. pyedb/grpc/database/net/net_class.py +24 -7
  64. pyedb/grpc/database/nets.py +11 -43
  65. pyedb/grpc/database/padstacks.py +92 -16
  66. pyedb/grpc/database/primitive/bondwire.py +3 -67
  67. pyedb/grpc/database/primitive/circle.py +42 -3
  68. pyedb/grpc/database/primitive/padstack_instance.py +17 -19
  69. pyedb/grpc/database/primitive/path.py +154 -5
  70. pyedb/grpc/database/primitive/polygon.py +75 -9
  71. pyedb/grpc/database/primitive/primitive.py +2 -2
  72. pyedb/grpc/database/primitive/rectangle.py +105 -4
  73. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  74. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  75. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +4 -2
  76. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  77. pyedb/grpc/database/siwave.py +6 -13
  78. pyedb/grpc/database/source_excitations.py +49 -57
  79. pyedb/grpc/database/stackup.py +50 -27
  80. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  81. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  82. pyedb/grpc/database/terminal/terminal.py +19 -8
  83. pyedb/grpc/database/utility/heat_sink.py +0 -1
  84. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  85. pyedb/grpc/database/utility/value.py +1 -0
  86. pyedb/grpc/database/utility/xml_control_file.py +6 -3
  87. pyedb/grpc/edb.py +33 -24
  88. pyedb/grpc/edb_init.py +1 -0
  89. pyedb/grpc/rpc_session.py +4 -3
  90. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  91. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  92. pyedb/ipc2581/ipc2581.py +8 -7
  93. pyedb/libraries/common.py +3 -4
  94. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  95. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  96. pyedb/misc/downloads.py +1 -0
  97. pyedb/misc/misc.py +5 -2
  98. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
  99. pyedb/misc/utilities.py +0 -1
  100. pyedb/modeler/geometry_operators.py +9 -8
  101. pyedb/siwave.py +4 -6
  102. pyedb/siwave_core/__init__.py +0 -0
  103. pyedb/siwave_core/cpa/__init__.py +0 -0
  104. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/METADATA +3 -3
  105. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/RECORD +107 -102
  106. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/WHEEL +0 -0
  107. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/licenses/LICENSE +0 -0
@@ -20,15 +20,18 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ from __future__ import annotations
23
24
 
25
+ from typing import TYPE_CHECKING
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.net.net import Net
24
29
  import re
25
30
 
26
31
  from ansys.edb.core.net.differential_pair import (
27
32
  DifferentialPair as GrpcDifferentialPair,
28
33
  )
29
34
 
30
- from pyedb.grpc.database.net.net import Net
31
-
32
35
 
33
36
  class DifferentialPairs:
34
37
  def __init__(self, pedb):
@@ -131,9 +134,13 @@ class DifferentialPair(GrpcDifferentialPair):
131
134
  @property
132
135
  def positive_net(self) -> Net:
133
136
  """Positive Net."""
137
+ from pyedb.grpc.database.net.net import Net
138
+
134
139
  return Net(self._pedb, super().positive_net)
135
140
 
136
141
  @property
137
142
  def negative_net(self) -> Net:
138
143
  """Negative Net."""
144
+ from pyedb.grpc.database.net.net import Net
145
+
139
146
  return Net(self._pedb, super().negative_net)
@@ -20,9 +20,13 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from ansys.edb.core.net.extended_net import ExtendedNet as GrpcExtendedNet
23
+ from __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
24
26
 
25
- from pyedb.grpc.database.net.net import Net
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.net.net import Net
29
+ from ansys.edb.core.net.extended_net import ExtendedNet as GrpcExtendedNet
26
30
 
27
31
 
28
32
  class ExtendedNets:
@@ -204,12 +208,21 @@ class ExtendedNets:
204
208
  val_value = cmp.rlc_values
205
209
  if refdes in exception_list:
206
210
  pass
207
- elif cmp.type == "inductor" and val_value[1] < inductor_below:
208
- pass
209
- elif cmp.type == "resistor" and val_value[0] < resistor_below:
210
- pass
211
- elif cmp.type == "capacitor" and val_value[2] > capacitor_above:
212
- pass
211
+ elif cmp.type == "inductor":
212
+ if val_value[1] is None:
213
+ continue
214
+ elif not val_value[1] < inductor_below:
215
+ continue
216
+ elif cmp.type == "resistor":
217
+ if val_value[0] is None:
218
+ continue
219
+ elif not val_value[0] < resistor_below:
220
+ continue
221
+ elif cmp.type == "capacitor":
222
+ if val_value[2] is None:
223
+ continue
224
+ elif not val_value[2] > capacitor_above:
225
+ continue
213
226
  else:
214
227
  continue
215
228
  for net in comp_dict[refdes]:
@@ -263,7 +276,7 @@ class ExtendedNet(GrpcExtendedNet):
263
276
  self._pedb = pedb
264
277
 
265
278
  @property
266
- def nets(self):
279
+ def nets(self) -> dict[str, Net]:
267
280
  """Nets dictionary.
268
281
 
269
282
  Returns
@@ -271,6 +284,8 @@ class ExtendedNet(GrpcExtendedNet):
271
284
  Dict[str, :class:`Net <pyedb.grpc.database.net.net.Net>`]
272
285
  Dict[net name, Net object].
273
286
  """
287
+ from pyedb.grpc.database.net.net import Net
288
+
274
289
  return {net.name: Net(self._pedb, net) for net in super().nets}
275
290
 
276
291
  @property
@@ -20,14 +20,17 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from typing import Union
23
+ from __future__ import annotations
24
24
 
25
+ from typing import TYPE_CHECKING, Union
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.primitive.circle import Circle
29
+ from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
25
30
  from ansys.edb.core.net.net import Net as GrpcNet
26
31
  from ansys.edb.core.primitive.primitive import PrimitiveType as GrpcPrimitiveType
27
32
 
28
33
  from pyedb.grpc.database.primitive.bondwire import Bondwire
29
- from pyedb.grpc.database.primitive.circle import Circle
30
- from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
31
34
  from pyedb.grpc.database.primitive.path import Path
32
35
  from pyedb.grpc.database.primitive.polygon import Polygon
33
36
  from pyedb.grpc.database.primitive.rectangle import Rectangle
@@ -76,6 +79,7 @@ class Net(GrpcNet):
76
79
  - :class:`Rectangle <pyedb.grpc.database.primitive.rectangle.Rectangle>`
77
80
  - :class:`Bondwire <pyedb.grpc.database.primitive.bondwire.Bondwire>`
78
81
  """
82
+
79
83
  primitives = super().primitives
80
84
  if not len(self.__primitives) == len(primitives):
81
85
  for primitive in primitives:
@@ -100,6 +104,8 @@ class Net(GrpcNet):
100
104
  list of :class:`PadstackInstance <pyedb.grpc.database.primitive.padstack_instance.PadstackInstance>`
101
105
  Padstack instances associated with the net.
102
106
  """
107
+ from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
108
+
103
109
  return [PadstackInstance(self._pedb, i) for i in super().padstack_instances]
104
110
 
105
111
  @property
@@ -118,8 +124,11 @@ class Net(GrpcNet):
118
124
  if component:
119
125
  try:
120
126
  components[component.name] = component
121
- except:
122
- pass
127
+ except Exception as e:
128
+ self._pedb.logger.error(
129
+ f"A(n) {type(e).__name__} error occurred while attempting to access "
130
+ f"'components' property for object {self} - Empty dict is returned: {str(e)}"
131
+ )
123
132
  return components
124
133
 
125
134
  def find_dc_short(self, fix=False) -> list[list[str, str]]:
@@ -20,9 +20,14 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ from __future__ import annotations
24
+
25
+ from typing import TYPE_CHECKING
26
+
23
27
  from ansys.edb.core.net.net_class import NetClass as GrpcNetClass
24
28
 
25
- from pyedb.grpc.database.net.net import Net
29
+ if TYPE_CHECKING:
30
+ from pyedb.grpc.database.net.net import Net
26
31
 
27
32
 
28
33
  class NetClass(GrpcNetClass):
@@ -49,6 +54,8 @@ class NetClass(GrpcNetClass):
49
54
  List[:class:`Net <pyedb.grpc.database.net.net.Net>`].
50
55
  List of Net object.
51
56
  """
57
+ from pyedb.grpc.database.net.net import Net
58
+
52
59
  return [Net(self._pedb, i) for i in super().nets]
53
60
 
54
61
  def add_net(self, net):
@@ -59,21 +66,30 @@ class NetClass(GrpcNetClass):
59
66
  bool
60
67
  """
61
68
  if isinstance(net, str):
69
+ from pyedb.grpc.database.net.net import Net
70
+
62
71
  net = Net.find_by_name(self._pedb.active_layout, name=net)
63
72
  if isinstance(net, Net) and not net.is_null:
64
73
  self.add_net(net)
65
74
  return True
66
75
  return False
67
76
 
68
- def contains_net(self, net):
69
- """Determine if a net exists in the net class.
77
+ def contains_net(self, net) -> bool:
78
+ """
79
+ Determine if a net exists in the net class.
80
+
81
+ Parameters
82
+ ----------
83
+ net : str or Net
84
+ The net to check. This can be a string representing the net name or a `Net` object.
70
85
 
71
- returns
86
+ Returns
72
87
  -------
73
- List[:class:`Net <pyedb.grpc.database.net.net.Net>`].
74
- List of Net object.
88
+ bool
89
+ True if the net exists in the net class, False otherwise.
75
90
 
76
91
  """
92
+
77
93
  if isinstance(net, str):
78
94
  net = Net.find_by_name(self._pedb.active_layout, name=net)
79
95
  return super().contains_net(net)
@@ -85,9 +101,10 @@ class NetClass(GrpcNetClass):
85
101
  -------
86
102
  bool
87
103
  """
104
+
88
105
  if isinstance(net, str):
89
106
  net = Net.find_by_name(self._pedb.active_layout, name=net)
90
107
  if isinstance(net, Net) and not net.is_null:
91
- self.remove(net)
108
+ self.remove_net(net)
92
109
  return True
93
110
  return False
@@ -95,34 +95,21 @@ class Nets(CommonNets):
95
95
  >>> print("Eligible power nets:", [net.name for net in eligible_pwr])
96
96
 
97
97
  >>> # Generate extended nets (deprecated)
98
- >>> nets.generate_extended_nets(
99
- >>> resistor_below=5,
100
- >>>inductor_below=0.5,
101
- >>> capacitor_above=0.1
102
- >>> )
98
+ >>> nets.generate_extended_nets(resistor_below=5, inductor_below=0.5, capacitor_above=0.1)
103
99
 
104
100
  >>> # Classify nets
105
- >>> nets.classify_nets(
106
- >>> power_nets=["VDD_CPU", "VDD_MEM"],
107
- >>> signal_nets=["PCIe_TX", "ETH_RX"]
108
- >>> )
101
+ >>> nets.classify_nets(power_nets=["VDD_CPU", "VDD_MEM"], signal_nets=["PCIe_TX", "ETH_RX"])
109
102
 
110
103
  >>> # Check power/ground status
111
104
  >>> is_power = nets.is_power_gound_net(["VDD_CPU", "PCIe_TX"])
112
105
  >>> print("Is power net:", is_power)
113
106
 
114
107
  >>> # Get DC-connected nets
115
- >>> dc_connected = nets.get_dcconnected_net_list(
116
- >>> ground_nets=["GND"],
117
- >>> res_value=0.002
118
- >>> )
108
+ >>> dc_connected = nets.get_dcconnected_net_list(ground_nets=["GND"], res_value=0.002)
119
109
  print("DC-connected nets:", dc_connected)
120
110
 
121
111
  >>> # Get power tree
122
- >>> comp_list, columns, net_group = nets.get_powertree(
123
- >>> power_net_name="VDD_CPU",
124
- >>> ground_nets=["GND"]
125
- >>> )
112
+ >>> comp_list, columns, net_group = nets.get_powertree(power_net_name="VDD_CPU", ground_nets=["GND"])
126
113
  >>> print("Power tree components:", comp_list)
127
114
 
128
115
  >>> # Find net by name
@@ -142,10 +129,7 @@ class Nets(CommonNets):
142
129
  >>> print("Net in component:", in_component)
143
130
 
144
131
  >>> # Find and fix disjoint nets (deprecated)
145
- >>> fixed_nets = nets.find_and_fix_disjoint_nets(
146
- >>> net_list=["PCIe_TX"],
147
- >>> clean_disjoints_less_than=1e-6
148
- >>> )
132
+ >>> fixed_nets = nets.find_and_fix_disjoint_nets(net_list=["PCIe_TX"], clean_disjoints_less_than=1e-6)
149
133
  >>> print("Fixed nets:", fixed_nets)
150
134
 
151
135
  >>> # Merge net polygons
@@ -422,11 +406,7 @@ class Nets(CommonNets):
422
406
 
423
407
  Examples
424
408
  --------
425
- >>> edb_nets.generate_extended_nets(
426
- ... resistor_below=5,
427
- ... inductor_below=0.5,
428
- ... capacitor_above=0.1
429
- ... )
409
+ >>> edb_nets.generate_extended_nets(resistor_below=5, inductor_below=0.5, capacitor_above=0.1)
430
410
  """
431
411
  warnings.warn("Use new method :func:`edb.extended_nets.generate_extended_nets` instead.", DeprecationWarning)
432
412
  self._pedb.extended_nets.generate_extended_nets(
@@ -487,10 +467,7 @@ class Nets(CommonNets):
487
467
 
488
468
  Examples
489
469
  --------
490
- >>> edb_nets.classify_nets(
491
- ... power_nets=["VDD_CPU", "VDD_MEM"],
492
- ... signal_nets=["PCIe_TX", "ETH_RX"]
493
- ... )
470
+ >>> edb_nets.classify_nets(power_nets=["VDD_CPU", "VDD_MEM"], signal_nets=["PCIe_TX", "ETH_RX"])
494
471
  """
495
472
  if isinstance(power_nets, str):
496
473
  power_nets = []
@@ -551,10 +528,7 @@ class Nets(CommonNets):
551
528
 
552
529
  Examples
553
530
  --------
554
- >>> dc_connected = edb_nets.get_dcconnected_net_list(
555
- ... ground_nets=["GND"],
556
- ... res_value=0.002
557
- ... )
531
+ >>> dc_connected = edb_nets.get_dcconnected_net_list(ground_nets=["GND"], res_value=0.002)
558
532
  >>> for net_group in dc_connected:
559
533
  ... print("Connected nets:", net_group)
560
534
  """
@@ -611,10 +585,7 @@ class Nets(CommonNets):
611
585
 
612
586
  Examples
613
587
  --------
614
- >>> comp_list, columns, net_group = edb_nets.get_powertree(
615
- ... power_net_name="VDD_CPU",
616
- ... ground_nets=["GND"]
617
- ... )
588
+ >>> comp_list, columns, net_group = edb_nets.get_powertree(power_net_name="VDD_CPU", ground_nets=["GND"])
618
589
  >>> print("Power tree components:", comp_list)
619
590
  """
620
591
  flag_in_ng = False
@@ -700,7 +671,7 @@ class Nets(CommonNets):
700
671
 
701
672
  Examples
702
673
  --------
703
- >>> deleted_nets = database.nets.delete(["Net1","Net2"])
674
+ >>> deleted_nets = database.nets.delete(["Net1", "Net2"])
704
675
  """
705
676
  if isinstance(netlist, str):
706
677
  netlist = [netlist]
@@ -858,10 +829,7 @@ class Nets(CommonNets):
858
829
 
859
830
  Examples
860
831
  --------
861
- >>> fixed_nets = edb_nets.find_and_fix_disjoint_nets(
862
- ... net_list=["PCIe_TX"],
863
- ... clean_disjoints_less_than=1e-6
864
- ... )
832
+ >>> fixed_nets = edb_nets.find_and_fix_disjoint_nets(net_list=["PCIe_TX"], clean_disjoints_less_than=1e-6)
865
833
  >>> print("Fixed nets:", fixed_nets)
866
834
  """
867
835
 
@@ -23,6 +23,7 @@
23
23
  """
24
24
  This module contains the `EdbPadstacks` class.
25
25
  """
26
+
26
27
  from collections import defaultdict
27
28
  import math
28
29
  from typing import Any, Dict, List, Optional, Tuple, Union
@@ -30,20 +31,12 @@ import warnings
30
31
 
31
32
  from ansys.edb.core.definition.padstack_def_data import (
32
33
  PadGeometryType as GrpcPadGeometryType,
33
- )
34
- from ansys.edb.core.definition.padstack_def_data import (
35
34
  PadstackDefData as GrpcPadstackDefData,
36
- )
37
- from ansys.edb.core.definition.padstack_def_data import (
38
35
  PadstackHoleRange as GrpcPadstackHoleRange,
39
- )
40
- from ansys.edb.core.definition.padstack_def_data import (
36
+ PadType as GrpcPadType,
41
37
  SolderballPlacement as GrpcSolderballPlacement,
42
- )
43
- from ansys.edb.core.definition.padstack_def_data import (
44
38
  SolderballShape as GrpcSolderballShape,
45
39
  )
46
- from ansys.edb.core.definition.padstack_def_data import PadType as GrpcPadType
47
40
  from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
48
41
  from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
49
42
  import numpy as np
@@ -334,7 +327,7 @@ class Padstacks(object):
334
327
  >>> groups = edb_padstacks._layout.pin_groups # New way
335
328
  """
336
329
  warnings.warn(
337
- "`pingroups` is deprecated and is now located here " "`pyedb.grpc.core.layout.pin_groups` instead.",
330
+ "`pingroups` is deprecated and is now located here `pyedb.grpc.core.layout.pin_groups` instead.",
338
331
  DeprecationWarning,
339
332
  )
340
333
  return self._layout.pin_groups
@@ -380,10 +373,7 @@ class Padstacks(object):
380
373
  Examples
381
374
  --------
382
375
  >>> via_name = edb_padstacks.create_circular_padstack(
383
- ... padstackname="VIA1",
384
- ... holediam="200um",
385
- ... paddiam="400um",
386
- ... antipaddiam="600um"
376
+ ... padstackname="VIA1", holediam="200um", paddiam="400um", antipaddiam="600um"
387
377
  ... )
388
378
  """
389
379
 
@@ -1299,8 +1289,7 @@ class Padstacks(object):
1299
1289
  List of padstack instances associated with the specified net.
1300
1290
  """
1301
1291
  warnings.warn(
1302
- "`get_padstack_instance_by_net_name` is deprecated, use `get_instances` with `net_name` "
1303
- "parameter instead.",
1292
+ "`get_padstack_instance_by_net_name` is deprecated, use `get_instances` with `net_name` parameter instead.",
1304
1293
  DeprecationWarning,
1305
1294
  )
1306
1295
  return self.get_instances(net_name=net)
@@ -1853,3 +1842,90 @@ class Padstacks(object):
1853
1842
  clusters[int(label)].append(padstack_ids[i])
1854
1843
 
1855
1844
  return dict(clusters)
1845
+
1846
+ def reduce_via_by_density(
1847
+ self, padstacks: List[int], cell_size_x: float = 1e-3, cell_size_y: float = 1e-3, delete: bool = False
1848
+ ) -> tuple[List[int], List[List[List[float]]]]:
1849
+ """
1850
+ Reduce the number of vias by density. Keep only one via which is closest to the center of the cell. The cells
1851
+ are automatically populated based on the input vias.
1852
+
1853
+ Parameters
1854
+ ----------
1855
+ padstacks: List[int]
1856
+ List of padstack ids to be reduced.
1857
+
1858
+ cell_size_x : float
1859
+ Width of each grid cell (default is 1e-3).
1860
+
1861
+ cell_size_y : float
1862
+ Height of each grid cell (default is 1e-3).
1863
+
1864
+ delete: bool
1865
+ If True, delete vias that are not kept (default is False).
1866
+
1867
+ Returns
1868
+ -------
1869
+ List[int]
1870
+ IDs of vias kept after reduction.
1871
+
1872
+ List[List[float]]
1873
+ coordinates for grid lines (for plotting).
1874
+
1875
+ """
1876
+ to_keep = set()
1877
+
1878
+ all_instances = self.instances
1879
+ positions = np.array([all_instances[_id].position for _id in padstacks])
1880
+
1881
+ x_coords, y_coords = positions[:, 0], positions[:, 1]
1882
+ x_min, x_max = np.min(x_coords), np.max(x_coords)
1883
+ y_min, y_max = np.min(y_coords), np.max(y_coords)
1884
+
1885
+ padstacks_array = np.array(padstacks)
1886
+ cell_map = {} # {(cell_x, cell_y): [(id1, [x1, y1]), (id2, [x2, y2), ...]}
1887
+ grid = []
1888
+
1889
+ for idx, pos in enumerate(positions):
1890
+ i = int((pos[0] - x_min) // cell_size_x)
1891
+ j = int((pos[1] - y_min) // cell_size_y)
1892
+ cell_key = (i, j)
1893
+ cell_map.setdefault(cell_key, []).append((padstacks_array[idx], pos))
1894
+
1895
+ for (i, j), items in cell_map.items():
1896
+ # cell center
1897
+ cell_x_min = x_min + i * cell_size_x
1898
+ cell_y_min = y_min + j * cell_size_y
1899
+ cell_x_mid = cell_x_min + 0.5 * cell_size_x
1900
+ cell_y_mid = cell_y_min + 0.5 * cell_size_y
1901
+
1902
+ grid.append(
1903
+ [
1904
+ [
1905
+ cell_x_min,
1906
+ cell_x_min + cell_size_x,
1907
+ cell_x_min + cell_size_x,
1908
+ cell_x_min,
1909
+ cell_x_min,
1910
+ ],
1911
+ [
1912
+ cell_y_min,
1913
+ cell_y_min,
1914
+ cell_y_min + cell_size_y,
1915
+ cell_y_min + cell_size_y,
1916
+ cell_y_min,
1917
+ ],
1918
+ ]
1919
+ )
1920
+
1921
+ # Find closest via to cell center
1922
+ distances = [np.linalg.norm(pos - [cell_x_mid, cell_y_mid]) for _, pos in items]
1923
+ closest_idx = np.argmin(distances)
1924
+ to_keep.add(items[closest_idx][0])
1925
+
1926
+ if delete:
1927
+ to_delete = set(padstacks) - to_keep
1928
+ for _id in to_delete:
1929
+ all_instances[_id].delete()
1930
+
1931
+ return list(to_keep), grid
@@ -21,10 +21,10 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  from ansys.edb.core.primitive.bondwire import (
24
+ Bondwire as GrpcBondWire,
24
25
  BondwireCrossSectionType as GrpcBondwireCrossSectionType,
26
+ BondwireType as GrpcBondWireType,
25
27
  )
26
- from ansys.edb.core.primitive.bondwire import Bondwire as GrpcBondWire
27
- from ansys.edb.core.primitive.bondwire import BondwireType as GrpcBondWireType
28
28
 
29
29
  from pyedb.grpc.database.utility.value import Value
30
30
 
@@ -36,6 +36,7 @@ class Bondwire(GrpcBondWire):
36
36
  super().__init__(edb_object.msg)
37
37
  self._pedb = _pedb
38
38
  self._edb_object = edb_object
39
+ # TODO add create and delete methods to keep cache in sync
39
40
 
40
41
  @property
41
42
  def material(self):
@@ -53,25 +54,6 @@ class Bondwire(GrpcBondWire):
53
54
  def material(self, value):
54
55
  self.set_material(value)
55
56
 
56
- # def __create(self, **kwargs):
57
- # return Bondwire.create(
58
- # self._pedb.layout,
59
- # kwargs.get("net"),
60
- # self._bondwire_type[kwargs.get("bondwire_type")],
61
- # kwargs.get("definition_name"),
62
- # kwargs.get("placement_layer"),
63
- # kwargs.get("width"),
64
- # kwargs.get("material"),
65
- # kwargs.get("start_context"),
66
- # kwargs.get("start_layer_name"),
67
- # kwargs.get("start_x"),
68
- # kwargs.get("start_y"),
69
- # kwargs.get("end_context"),
70
- # kwargs.get("end_layer_name"),
71
- # kwargs.get("end_x"),
72
- # kwargs.get("end_y"),
73
- # )
74
-
75
57
  @property
76
58
  def type(self):
77
59
  """str: Bondwire-type of a bondwire object. Supported values for setter: `"apd"`, `"jedec4"`, `"jedec5"`,
@@ -120,28 +102,6 @@ class Bondwire(GrpcBondWire):
120
102
  def cross_section_height(self, cross_section_height):
121
103
  super(Bondwire, self.__class__).cross_section_height.__set__(self, Value(cross_section_height))
122
104
 
123
- # @property
124
- # def trajectory(self):
125
- # """Get trajectory parameters of a bondwire object.
126
- #
127
- # Returns
128
- # -------
129
- # tuple[float, float, float, float]
130
- #
131
- # Returns a tuple of the following format:
132
- # **(x1, y1, x2, y2)**
133
- # **x1** : X value of the start point.
134
- # **y1** : Y value of the start point.
135
- # **x1** : X value of the end point.
136
- # **y1** : Y value of the end point.
137
- # """
138
- # return [Value(i) for i in self.get_traj()]
139
- #
140
- # @trajectory.setter
141
- # def trajectory(self, value):
142
- # values = [Value(i) for i in value]
143
- # self.set_traj(values[0], values[1], values[2], values[3])
144
-
145
105
  @property
146
106
  def width(self):
147
107
  """:class:`Value <ansys.edb.utility.Value>`: Width of a bondwire object.
@@ -156,27 +116,3 @@ class Bondwire(GrpcBondWire):
156
116
  @width.setter
157
117
  def width(self, width):
158
118
  super(Bondwire, self.__class__).width.__set__(self, Value(width))
159
-
160
- # @property
161
- # def start_elevation(self):
162
- # layer = self.get_start_elevation(self._pedb.active_cell)
163
- # return layer.name
164
- #
165
- # @start_elevation.setter
166
- # def start_elevation(self, layer):
167
- # if not layer in self._pedb.stackup.layers:
168
- # return
169
- # layer = self._pedb.stackup.layers[layer]
170
- # self.set_start_elevation(self._pedb.active_cell, layer)
171
- #
172
- # @property
173
- # def end_elevation(self):
174
- # layer = self.get_end_elevation(self._pedb.active_cell)
175
- # return layer.name
176
- #
177
- # @end_elevation.setter
178
- # def end_elevation(self, layer):
179
- # if not layer in self._pedb.stackup.layers:
180
- # return
181
- # layer = self._pedb.stackup.layers[layer]
182
- # self.set_end_elevation(self._pedb.active_cell, layer)
@@ -21,18 +21,57 @@
21
21
  # SOFTWARE.
22
22
 
23
23
 
24
+ from typing import Union
25
+
24
26
  from ansys.edb.core.primitive.circle import Circle as GrpcCircle
25
27
 
28
+ from pyedb.grpc.database.layers.layer import Layer
29
+ from pyedb.grpc.database.net.net import Net
26
30
  from pyedb.grpc.database.primitive.primitive import Primitive
27
31
  from pyedb.grpc.database.utility.value import Value
28
32
 
29
33
 
30
34
  class Circle(GrpcCircle, Primitive):
31
- def __init__(self, pedb, edb_object):
32
- GrpcCircle.__init__(self, edb_object.msg)
33
- Primitive.__init__(self, pedb, edb_object)
35
+ def __init__(self, pedb, edb_object=None):
36
+ if edb_object:
37
+ GrpcCircle.__init__(self, edb_object.msg)
38
+ Primitive.__init__(self, pedb, edb_object)
34
39
  self._pedb = pedb
35
40
 
41
+ def create(
42
+ self,
43
+ layout=None,
44
+ layer: Union[str, Layer] = None,
45
+ net: Union[str, Net, None] = None,
46
+ center_x: float = None,
47
+ center_y: float = None,
48
+ radius: float = 0.0,
49
+ ):
50
+ if not layout:
51
+ layout = self._pedb.active_layout
52
+ if not layer:
53
+ raise ValueError("Layer must be provided to create a circle.")
54
+ if center_x is None or center_y is None:
55
+ raise ValueError("Center x and y values must be provided to create a circle.")
56
+ edb_object = GrpcCircle.create(
57
+ layout=layout,
58
+ layer=layer,
59
+ net=net,
60
+ center_x=Value(center_x),
61
+ center_y=Value(center_y),
62
+ radius=Value(radius),
63
+ )
64
+ new_circle = Circle(self._pedb, edb_object)
65
+ GrpcCircle.__init__(self, edb_object.msg)
66
+ Primitive.__init__(self, self._pedb, edb_object)
67
+ self._pedb.modeler._add_primitive(new_circle)
68
+ return new_circle
69
+
70
+ def delete(self):
71
+ """Delete the circle from the layout."""
72
+ self._pedb.modeler._remove_primitive(self)
73
+ super().delete()
74
+
36
75
  def get_parameters(self) -> tuple[float, float, float]:
37
76
  """Returns parameters.
38
77