pyedb 0.38.0__py3-none-any.whl → 0.39.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 (205) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/common/nets.py +53 -139
  3. pyedb/configuration/cfg_components.py +1 -1
  4. pyedb/configuration/cfg_general.py +4 -2
  5. pyedb/configuration/cfg_modeler.py +1 -1
  6. pyedb/configuration/cfg_package_definition.py +1 -1
  7. pyedb/configuration/cfg_padstacks.py +1 -1
  8. pyedb/configuration/cfg_ports_sources.py +56 -23
  9. pyedb/configuration/configuration.py +18 -1
  10. pyedb/dotnet/{application → database}/Variables.py +21 -21
  11. pyedb/dotnet/{edb_core → database}/cell/connectable.py +5 -5
  12. pyedb/dotnet/{edb_core → database}/cell/hierarchy/component.py +11 -11
  13. pyedb/dotnet/{edb_core → database}/cell/hierarchy/hierarchy_obj.py +1 -1
  14. pyedb/dotnet/{edb_core → database}/cell/hierarchy/model.py +1 -1
  15. pyedb/dotnet/{edb_core → database}/cell/layout.py +17 -17
  16. pyedb/dotnet/{edb_core → database}/cell/layout_obj.py +3 -3
  17. pyedb/dotnet/{edb_core → database}/cell/primitive/bondwire.py +1 -1
  18. pyedb/dotnet/{edb_core → database}/cell/primitive/path.py +4 -4
  19. pyedb/dotnet/{edb_core → database}/cell/primitive/primitive.py +14 -14
  20. pyedb/dotnet/{edb_core → database}/cell/terminal/bundle_terminal.py +2 -2
  21. pyedb/dotnet/{edb_core → database}/cell/terminal/edge_terminal.py +4 -4
  22. pyedb/dotnet/{edb_core → database}/cell/terminal/padstack_instance_terminal.py +2 -2
  23. pyedb/dotnet/{edb_core → database}/cell/terminal/pingroup_terminal.py +2 -2
  24. pyedb/dotnet/{edb_core → database}/cell/terminal/point_terminal.py +2 -2
  25. pyedb/dotnet/{edb_core → database}/cell/terminal/terminal.py +11 -11
  26. pyedb/dotnet/{edb_core → database}/cell/voltage_regulator.py +2 -2
  27. pyedb/dotnet/{edb_core → database}/components.py +101 -124
  28. pyedb/dotnet/{edb_core → database}/definition/component_def.py +5 -5
  29. pyedb/dotnet/{edb_core → database}/definition/component_model.py +1 -1
  30. pyedb/dotnet/{edb_core → database}/definition/definition_obj.py +1 -1
  31. pyedb/dotnet/{edb_core → database}/definition/definitions.py +2 -2
  32. pyedb/dotnet/{edb_core → database}/definition/package_def.py +4 -4
  33. pyedb/dotnet/{edb_core → database}/dotnet/database.py +8 -8
  34. pyedb/dotnet/{edb_core → database}/dotnet/primitive.py +9 -9
  35. pyedb/dotnet/{edb_core → database}/edb_data/control_file.py +12 -12
  36. pyedb/dotnet/{edb_core → database}/edb_data/hfss_extent_info.py +7 -7
  37. pyedb/dotnet/{edb_core → database}/edb_data/nets_data.py +10 -13
  38. pyedb/dotnet/{edb_core → database}/edb_data/padstacks_data.py +16 -16
  39. pyedb/dotnet/{edb_core → database}/edb_data/ports.py +4 -4
  40. pyedb/dotnet/{edb_core → database}/edb_data/primitives_data.py +5 -5
  41. pyedb/dotnet/{edb_core → database}/edb_data/raptor_x_simulation_setup_data.py +4 -4
  42. pyedb/dotnet/{edb_core → database}/edb_data/simulation_configuration.py +10 -10
  43. pyedb/dotnet/{edb_core → database}/edb_data/sources.py +4 -4
  44. pyedb/dotnet/{edb_core → database}/edb_data/variables.py +1 -1
  45. pyedb/dotnet/{edb_core → database}/geometry/polygon_data.py +4 -4
  46. pyedb/dotnet/{edb_core → database}/hfss.py +8 -8
  47. pyedb/dotnet/{edb_core → database}/layout_obj_instance.py +1 -1
  48. pyedb/dotnet/{edb_core → database}/layout_validation.py +2 -2
  49. pyedb/dotnet/{edb_core → database}/materials.py +23 -8
  50. pyedb/dotnet/{edb_core → database}/modeler.py +27 -27
  51. pyedb/dotnet/{edb_core → database}/net_class.py +8 -8
  52. pyedb/dotnet/{edb_core → database}/nets.py +12 -12
  53. pyedb/dotnet/{edb_core → database}/padstack.py +15 -15
  54. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/mesh_operation.py +1 -1
  55. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/settings.py +3 -3
  56. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sim_setup_info.py +2 -2
  57. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/simulation_settings.py +1 -1
  58. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
  59. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sweep_data.py +1 -1
  60. pyedb/dotnet/{edb_core → database}/siwave.py +10 -10
  61. pyedb/dotnet/{edb_core → database}/stackup.py +12 -12
  62. pyedb/dotnet/{edb_core → database}/utilities/hfss_simulation_setup.py +15 -15
  63. pyedb/dotnet/{edb_core → database}/utilities/obj_base.py +1 -1
  64. pyedb/dotnet/{edb_core → database}/utilities/simulation_setup.py +3 -3
  65. pyedb/dotnet/{edb_core → database}/utilities/siwave_simulation_setup.py +6 -6
  66. pyedb/dotnet/edb.py +117 -112
  67. pyedb/generic/design_types.py +26 -19
  68. pyedb/generic/general_methods.py +1 -1
  69. pyedb/generic/plot.py +0 -2
  70. pyedb/grpc/database/__init__.py +1 -0
  71. pyedb/grpc/database/components.py +2354 -0
  72. pyedb/grpc/database/control_file.py +1277 -0
  73. pyedb/grpc/database/definition/component_def.py +218 -0
  74. pyedb/grpc/database/definition/component_model.py +39 -0
  75. pyedb/grpc/database/definition/component_pin.py +32 -0
  76. pyedb/grpc/database/definition/materials.py +1207 -0
  77. pyedb/grpc/database/definition/n_port_component_model.py +34 -0
  78. pyedb/grpc/database/definition/package_def.py +227 -0
  79. pyedb/grpc/database/definition/padstack_def.py +842 -0
  80. pyedb/grpc/database/definitions.py +70 -0
  81. pyedb/grpc/database/general.py +43 -0
  82. pyedb/grpc/database/geometry/__init__.py +0 -0
  83. pyedb/grpc/database/geometry/arc_data.py +93 -0
  84. pyedb/grpc/database/geometry/point_3d_data.py +79 -0
  85. pyedb/grpc/database/geometry/point_data.py +30 -0
  86. pyedb/grpc/database/geometry/polygon_data.py +133 -0
  87. pyedb/grpc/database/hfss.py +1279 -0
  88. pyedb/grpc/database/hierarchy/__init__.py +0 -0
  89. pyedb/grpc/database/hierarchy/component.py +1301 -0
  90. pyedb/grpc/database/hierarchy/model.py +31 -0
  91. pyedb/grpc/database/hierarchy/netlist_model.py +30 -0
  92. pyedb/grpc/database/hierarchy/pin_pair_model.py +128 -0
  93. pyedb/grpc/database/hierarchy/pingroup.py +245 -0
  94. pyedb/grpc/database/hierarchy/s_parameter_model.py +33 -0
  95. pyedb/grpc/database/hierarchy/spice_model.py +48 -0
  96. pyedb/grpc/database/layers/__init__.py +0 -0
  97. pyedb/grpc/database/layers/layer.py +57 -0
  98. pyedb/grpc/database/layers/stackup_layer.py +410 -0
  99. pyedb/grpc/database/layout/__init__.py +0 -0
  100. pyedb/grpc/database/layout/cell.py +30 -0
  101. pyedb/grpc/database/layout/layout.py +196 -0
  102. pyedb/grpc/database/layout/voltage_regulator.py +149 -0
  103. pyedb/grpc/database/layout_validation.py +319 -0
  104. pyedb/grpc/database/modeler.py +1468 -0
  105. pyedb/grpc/database/net/__init__.py +0 -0
  106. pyedb/grpc/database/net/differential_pair.py +138 -0
  107. pyedb/grpc/database/net/extended_net.py +340 -0
  108. pyedb/grpc/database/net/net.py +198 -0
  109. pyedb/grpc/database/net/net_class.py +93 -0
  110. pyedb/grpc/database/nets.py +633 -0
  111. pyedb/grpc/database/padstacks.py +1500 -0
  112. pyedb/grpc/database/ports/__init__.py +0 -0
  113. pyedb/grpc/database/ports/ports.py +396 -0
  114. pyedb/grpc/database/primitive/__init__.py +3 -0
  115. pyedb/grpc/database/primitive/bondwire.py +181 -0
  116. pyedb/grpc/database/primitive/circle.py +75 -0
  117. pyedb/grpc/database/primitive/padstack_instance.py +1116 -0
  118. pyedb/grpc/database/primitive/path.py +346 -0
  119. pyedb/grpc/database/primitive/polygon.py +276 -0
  120. pyedb/grpc/database/primitive/primitive.py +739 -0
  121. pyedb/grpc/database/primitive/rectangle.py +146 -0
  122. pyedb/grpc/database/simulation_setup/__init__.py +0 -0
  123. pyedb/grpc/database/simulation_setup/adaptive_frequency.py +33 -0
  124. pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +32 -0
  125. pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +59 -0
  126. pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +35 -0
  127. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +61 -0
  128. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +78 -0
  129. pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +118 -0
  130. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +355 -0
  131. pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +34 -0
  132. pyedb/grpc/database/simulation_setup/mesh_operation.py +34 -0
  133. pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +34 -0
  134. pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +33 -0
  135. pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +64 -0
  136. pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +125 -0
  137. pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +34 -0
  138. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +119 -0
  139. pyedb/grpc/database/simulation_setup/sweep_data.py +32 -0
  140. pyedb/grpc/database/siwave.py +1023 -0
  141. pyedb/grpc/database/source_excitations.py +2572 -0
  142. pyedb/grpc/database/stackup.py +2574 -0
  143. pyedb/grpc/database/terminal/__init__.py +0 -0
  144. pyedb/grpc/database/terminal/bundle_terminal.py +218 -0
  145. pyedb/grpc/database/terminal/edge_terminal.py +51 -0
  146. pyedb/grpc/database/terminal/padstack_instance_terminal.py +171 -0
  147. pyedb/grpc/database/terminal/pingroup_terminal.py +162 -0
  148. pyedb/grpc/database/terminal/point_terminal.py +99 -0
  149. pyedb/grpc/database/terminal/terminal.py +470 -0
  150. pyedb/grpc/database/utility/__init__.py +3 -0
  151. pyedb/grpc/database/utility/constants.py +25 -0
  152. pyedb/grpc/database/utility/heat_sink.py +124 -0
  153. pyedb/grpc/database/utility/hfss_extent_info.py +448 -0
  154. pyedb/grpc/database/utility/layout_statistics.py +277 -0
  155. pyedb/grpc/database/utility/rlc.py +80 -0
  156. pyedb/grpc/database/utility/simulation_configuration.py +3305 -0
  157. pyedb/grpc/database/utility/sources.py +388 -0
  158. pyedb/grpc/database/utility/sweep_data_distribution.py +83 -0
  159. pyedb/grpc/database/utility/xml_control_file.py +1277 -0
  160. pyedb/grpc/edb.py +4151 -0
  161. pyedb/grpc/edb_init.py +481 -0
  162. pyedb/grpc/rpc_session.py +177 -0
  163. pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +3 -2
  164. pyedb/ipc2581/ecad/cad_data/feature.py +4 -3
  165. pyedb/ipc2581/ecad/cad_data/layer_feature.py +32 -20
  166. pyedb/ipc2581/ecad/cad_data/outline.py +3 -2
  167. pyedb/ipc2581/ecad/cad_data/package.py +4 -3
  168. pyedb/ipc2581/ecad/cad_data/path.py +82 -31
  169. pyedb/ipc2581/ecad/cad_data/polygon.py +122 -60
  170. pyedb/ipc2581/ecad/cad_data/profile.py +13 -12
  171. pyedb/ipc2581/ecad/cad_data/step.py +53 -21
  172. pyedb/ipc2581/ipc2581.py +47 -49
  173. pyedb/modeler/geometry_operators.py +1 -1
  174. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/METADATA +5 -2
  175. pyedb-0.39.0.dist-info/RECORD +288 -0
  176. pyedb-0.38.0.dist-info/RECORD +0 -195
  177. /pyedb/dotnet/{edb_core → database}/__init__.py +0 -0
  178. /pyedb/dotnet/{application → database/cell}/__init__.py +0 -0
  179. /pyedb/dotnet/{edb_core/cell → database/cell/hierarchy}/__init__.py +0 -0
  180. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/netlist_model.py +0 -0
  181. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/pin_pair_model.py +0 -0
  182. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/s_parameter_model.py +0 -0
  183. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/spice_model.py +0 -0
  184. /pyedb/dotnet/{edb_core → database}/cell/primitive/__init__.py +0 -0
  185. /pyedb/dotnet/{edb_core/cell/hierarchy → database/cell/terminal}/__init__.py +0 -0
  186. /pyedb/dotnet/{edb_core/cell/terminal → database/definition}/__init__.py +0 -0
  187. /pyedb/dotnet/{edb_core/definition → database/dotnet}/__init__.py +0 -0
  188. /pyedb/dotnet/{edb_core/dotnet → database/edb_data}/__init__.py +0 -0
  189. /pyedb/dotnet/{edb_core → database}/edb_data/design_options.py +0 -0
  190. /pyedb/dotnet/{edb_core → database}/edb_data/edbvalue.py +0 -0
  191. /pyedb/dotnet/{edb_core → database}/edb_data/layer_data.py +0 -0
  192. /pyedb/dotnet/{edb_core → database}/edb_data/utilities.py +0 -0
  193. /pyedb/dotnet/{edb_core → database}/general.py +0 -0
  194. /pyedb/dotnet/{edb_core/edb_data → database/geometry}/__init__.py +0 -0
  195. /pyedb/dotnet/{edb_core → database}/geometry/point_data.py +0 -0
  196. /pyedb/dotnet/{edb_core → database}/sim_setup_data/__init__.py +0 -0
  197. /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/__init__.py +0 -0
  198. /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/adaptive_frequency_data.py +0 -0
  199. /pyedb/dotnet/{edb_core/geometry → database/sim_setup_data/io}/__init__.py +0 -0
  200. /pyedb/dotnet/{edb_core → database}/sim_setup_data/io/siwave.py +0 -0
  201. /pyedb/dotnet/{edb_core → database}/utilities/__init__.py +0 -0
  202. /pyedb/dotnet/{edb_core → database}/utilities/heatsink.py +0 -0
  203. /pyedb/{dotnet/edb_core/sim_setup_data/io → grpc/database/definition}/__init__.py +0 -0
  204. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/LICENSE +0 -0
  205. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,2354 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ """This module contains the `Components` class.
24
+
25
+ """
26
+ import codecs
27
+ import json
28
+ import math
29
+ import os
30
+ import re
31
+ import warnings
32
+
33
+ from ansys.edb.core.definition.die_property import DieOrientation as GrpDieOrientation
34
+ from ansys.edb.core.definition.die_property import DieType as GrpcDieType
35
+ from ansys.edb.core.definition.solder_ball_property import (
36
+ SolderballShape as GrpcSolderballShape,
37
+ )
38
+ from ansys.edb.core.hierarchy.component_group import ComponentType as GrpcComponentType
39
+ from ansys.edb.core.hierarchy.spice_model import SPICEModel as GrpcSPICEModel
40
+ from ansys.edb.core.utility.rlc import Rlc as GrpcRlc
41
+ from ansys.edb.core.utility.value import Value as GrpcValue
42
+
43
+ from pyedb.component_libraries.ansys_components import (
44
+ ComponentLib,
45
+ ComponentPart,
46
+ Series,
47
+ )
48
+ from pyedb.generic.general_methods import (
49
+ generate_unique_name,
50
+ get_filename_without_extension,
51
+ )
52
+ from pyedb.grpc.database.definition.component_def import ComponentDef
53
+ from pyedb.grpc.database.definition.component_pin import ComponentPin
54
+ from pyedb.grpc.database.hierarchy.component import Component
55
+ from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
56
+ from pyedb.grpc.database.hierarchy.pingroup import PinGroup
57
+ from pyedb.grpc.database.utility.sources import SourceType
58
+ from pyedb.modeler.geometry_operators import GeometryOperators
59
+
60
+
61
+ def resistor_value_parser(r_value):
62
+ """Convert a resistor value.
63
+
64
+ Parameters
65
+ ----------
66
+ r_value : float
67
+ Resistor value.
68
+
69
+ Returns
70
+ -------
71
+ float
72
+ Resistor value.
73
+
74
+ """
75
+ if isinstance(r_value, str):
76
+ r_value = r_value.replace(" ", "")
77
+ r_value = r_value.replace("meg", "m")
78
+ r_value = r_value.replace("Ohm", "")
79
+ r_value = r_value.replace("ohm", "")
80
+ r_value = r_value.replace("k", "e3")
81
+ r_value = r_value.replace("m", "e-3")
82
+ r_value = r_value.replace("M", "e6")
83
+ r_value = float(r_value)
84
+ return r_value
85
+
86
+
87
+ class Components(object):
88
+ """Manages EDB components and related method accessible from `Edb.components` property.
89
+
90
+ Parameters
91
+ ----------
92
+ edb_class : :class:`pyedb.grpc.edb.Edb`
93
+
94
+ Examples
95
+ --------
96
+ >>> from pyedb import Edb
97
+ >>> edbapp = Edb("myaedbfolder")
98
+ >>> edbapp.components
99
+ """
100
+
101
+ def __getitem__(self, name):
102
+ """Get a component or component definition from the Edb project.
103
+
104
+ Parameters
105
+ ----------
106
+ name : str
107
+
108
+ Returns
109
+ -------
110
+ :class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`
111
+
112
+ """
113
+ if name in self.instances:
114
+ return self.instances[name]
115
+ elif name in self.definitions:
116
+ return self.definitions[name]
117
+ self._pedb.logger.error("Component or definition not found.")
118
+ return
119
+
120
+ def __init__(self, p_edb):
121
+ self._pedb = p_edb
122
+ self._cmp = {}
123
+ self._res = {}
124
+ self._cap = {}
125
+ self._ind = {}
126
+ self._ios = {}
127
+ self._ics = {}
128
+ self._others = {}
129
+ self._pins = {}
130
+ self._comps_by_part = {}
131
+ self._init_parts()
132
+ # self._padstack = Padstacks(self._pedb)
133
+ # self._excitations = self._pedb.excitations
134
+
135
+ @property
136
+ def _logger(self):
137
+ """Logger."""
138
+ return self._pedb.logger
139
+
140
+ def _init_parts(self):
141
+ a = self.instances
142
+ a = self.resistors
143
+ a = self.ICs
144
+ a = self.Others
145
+ a = self.inductors
146
+ a = self.IOs
147
+ a = self.components_by_partname
148
+ return True
149
+
150
+ @property
151
+ def _active_layout(self):
152
+ return self._pedb.active_layout
153
+
154
+ @property
155
+ def _layout(self):
156
+ return self._pedb.layout
157
+
158
+ @property
159
+ def _cell(self):
160
+ return self._pedb.cell
161
+
162
+ @property
163
+ def _db(self):
164
+ return self._pedb.active_db
165
+
166
+ @property
167
+ def instances(self):
168
+ """All Cell components objects.
169
+
170
+ Returns
171
+ -------
172
+ Dict[str, :class:`pyedb.grpc.database.cell.hierarchy.component.Component`]
173
+ Default dictionary for the EDB component.
174
+
175
+ Examples
176
+ --------
177
+
178
+ >>> from pyedb import Edb
179
+ >>> edbapp = Edb("myaedbfolder")
180
+ >>> edbapp.components.instances
181
+
182
+ """
183
+ if not self._cmp:
184
+ self.refresh_components()
185
+ return self._cmp
186
+
187
+ @property
188
+ def definitions(self):
189
+ """Retrieve component definition list.
190
+
191
+ Returns
192
+ -------
193
+ dict of :class:`EDBComponentDef`"""
194
+ return {l.name: ComponentDef(self._pedb, l) for l in self._pedb.component_defs}
195
+
196
+ @property
197
+ def nport_comp_definition(self):
198
+ """Retrieve Nport component definition list."""
199
+ m = "Ansys.Ansoft.Edb.Definition.NPortComponentModel"
200
+ return {name: l for name, l in self.definitions.items() if m in [i for i in l.model]}
201
+
202
+ def import_definition(self, file_path):
203
+ """Import component definition from json file.
204
+
205
+ Parameters
206
+ ----------
207
+ file_path : str
208
+ File path of json file.
209
+ """
210
+ with codecs.open(file_path, "r", encoding="utf-8") as f:
211
+ data = json.load(f)
212
+ for part_name, p in data["Definitions"].items():
213
+ model_type = p["Model_type"]
214
+ if part_name not in self.definitions:
215
+ continue
216
+ comp_definition = self.definitions[part_name]
217
+ comp_definition.type = p["Component_type"]
218
+
219
+ if model_type == "RLC":
220
+ comp_definition.assign_rlc_model(p["Res"], p["Ind"], p["Cap"], p["Is_parallel"])
221
+ else:
222
+ model_name = p["Model_name"]
223
+ file_path = data[model_type][model_name]
224
+ if model_type == "SParameterModel":
225
+ if "Reference_net" in p:
226
+ reference_net = p["Reference_net"]
227
+ else:
228
+ reference_net = None
229
+ comp_definition.assign_s_param_model(file_path, model_name, reference_net)
230
+ elif model_type == "SPICEModel":
231
+ comp_definition.assign_spice_model(file_path, model_name)
232
+ else:
233
+ pass
234
+ return True
235
+
236
+ def export_definition(self, file_path):
237
+ """Export component definitions to json file.
238
+
239
+ Parameters
240
+ ----------
241
+ file_path : str
242
+ File path of json file.
243
+
244
+ Returns
245
+ -------
246
+
247
+ """
248
+ data = {
249
+ "SParameterModel": {},
250
+ "SPICEModel": {},
251
+ "Definitions": {},
252
+ }
253
+ for part_name, props in self.definitions.items():
254
+ comp_list = list(props.components.values())
255
+ if comp_list:
256
+ data["Definitions"][part_name] = {}
257
+ data["Definitions"][part_name]["Component_type"] = props.type
258
+ comp = comp_list[0]
259
+ data["Definitions"][part_name]["Model_type"] = comp.model_type
260
+ if comp.model_type == "RLC":
261
+ rlc_values = [i if i else 0 for i in comp.rlc_values]
262
+ data["Definitions"][part_name]["Res"] = rlc_values[0]
263
+ data["Definitions"][part_name]["Ind"] = rlc_values[1]
264
+ data["Definitions"][part_name]["Cap"] = rlc_values[2]
265
+ data["Definitions"][part_name]["Is_parallel"] = True if comp.is_parallel_rlc else False
266
+ else:
267
+ if comp.model_type == "SParameterModel":
268
+ model = comp.s_param_model
269
+ data["Definitions"][part_name]["Model_name"] = model.name
270
+ data["Definitions"][part_name]["Reference_net"] = model.reference_net
271
+ if not model.name in data["SParameterModel"]:
272
+ data["SParameterModel"][model.name] = model.file_path
273
+ elif comp.model_type == "SPICEModel":
274
+ model = comp.spice_model
275
+ data["Definitions"][part_name]["Model_name"] = model.name
276
+ if not model.name in data["SPICEModel"]:
277
+ data["SPICEModel"][model.name] = model.file_path
278
+ else:
279
+ model = comp.netlist_model
280
+ data["Definitions"][part_name]["Model_name"] = model.netlist
281
+
282
+ with codecs.open(file_path, "w", encoding="utf-8") as f:
283
+ json.dump(data, f, ensure_ascii=False, indent=4)
284
+ return file_path
285
+
286
+ def refresh_components(self):
287
+ """Refresh the component dictionary."""
288
+ self._logger.info("Refreshing the Components dictionary.")
289
+ self._cmp = {}
290
+ for i in self._pedb.layout.groups:
291
+ if isinstance(i, Component):
292
+ if not i.is_null:
293
+ self._cmp[i.name] = i
294
+ return True
295
+
296
+ @property
297
+ def resistors(self):
298
+ """Resistors.
299
+
300
+ Returns
301
+ -------
302
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
303
+ Dictionary of resistors.
304
+
305
+ Examples
306
+ --------
307
+
308
+ >>> from pyedb import Edb
309
+ >>> edbapp = Edb("myaedbfolder")
310
+ >>> edbapp.components.resistors
311
+ """
312
+ self._res = {}
313
+ for el, val in self.instances.items():
314
+ if not val.is_null:
315
+ try:
316
+ if val.type == "resistor":
317
+ self._res[el] = val
318
+ except:
319
+ pass
320
+ return self._res
321
+
322
+ @property
323
+ def capacitors(self):
324
+ """Capacitors.
325
+
326
+ Returns
327
+ -------
328
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
329
+ Dictionary of capacitors.
330
+
331
+ Examples
332
+ --------
333
+
334
+ >>> from pyedb import Edb
335
+ >>> edbapp = Edb("myaedbfolder")
336
+ >>> edbapp.components.capacitors
337
+ """
338
+ self._cap = {}
339
+ for el, val in self.instances.items():
340
+ if not val.is_null:
341
+ try:
342
+ if val.type == "capacitor":
343
+ self._cap[el] = val
344
+ except:
345
+ pass
346
+ return self._cap
347
+
348
+ @property
349
+ def inductors(self):
350
+ """Inductors.
351
+
352
+ Returns
353
+ -------
354
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
355
+ Dictionary of inductors.
356
+
357
+ Examples
358
+ --------
359
+
360
+ >>> from pyedb import Edb
361
+ >>> edbapp = Edb("myaedbfolder")
362
+ >>> edbapp.components.inductors
363
+
364
+ """
365
+ self._ind = {}
366
+ for el, val in self.instances.items():
367
+ if not val.is_null:
368
+ try:
369
+ if val.type == "inductor":
370
+ self._ind[el] = val
371
+ except:
372
+ pass
373
+ return self._ind
374
+
375
+ @property
376
+ def ICs(self):
377
+ """Integrated circuits.
378
+
379
+ Returns
380
+ -------
381
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
382
+ Dictionary of integrated circuits.
383
+
384
+ Examples
385
+ --------
386
+
387
+ >>> from pyedb import Edb
388
+ >>> edbapp = Edb("myaedbfolder")
389
+ >>> edbapp.components.ICs
390
+
391
+ """
392
+ self._ics = {}
393
+ for el, val in self.instances.items():
394
+ if not val.is_null:
395
+ try:
396
+ if val.type == "ic":
397
+ self._ics[el] = val
398
+ except:
399
+ pass
400
+ return self._ics
401
+
402
+ @property
403
+ def IOs(self):
404
+ """Circuit inupts and outputs.
405
+
406
+ Returns
407
+ -------
408
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
409
+ Dictionary of circuit inputs and outputs.
410
+
411
+ Examples
412
+ --------
413
+
414
+ >>> from pyedb import Edb
415
+ >>> edbapp = Edb("myaedbfolder")
416
+ >>> edbapp.components.IOs
417
+
418
+ """
419
+ self._ios = {}
420
+ for el, val in self.instances.items():
421
+ if not val.is_null:
422
+ try:
423
+ if val.type == "io":
424
+ self._ios[el] = val
425
+ except:
426
+ pass
427
+ return self._ios
428
+
429
+ @property
430
+ def Others(self):
431
+ """Other core components.
432
+
433
+ Returns
434
+ -------
435
+ dict[str, .:class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent`]
436
+ Dictionary of other core components.
437
+
438
+ Examples
439
+ --------
440
+
441
+ >>> from pyedb import Edb
442
+ >>> edbapp = Edb("myaedbfolder")
443
+ >>> edbapp.components.others
444
+
445
+ """
446
+ self._others = {}
447
+ for el, val in self.instances.items():
448
+ if not val.is_null:
449
+ try:
450
+ if val.type == "other":
451
+ self._others[el] = val
452
+ except:
453
+ pass
454
+ return self._others
455
+
456
+ @property
457
+ def components_by_partname(self):
458
+ """Components by part name.
459
+
460
+ Returns
461
+ -------
462
+ dict
463
+ Dictionary of components by part name.
464
+
465
+ Examples
466
+ --------
467
+
468
+ >>> from pyedb import Edb
469
+ >>> edbapp = Edb("myaedbfolder")
470
+ >>> edbapp.components.components_by_partname
471
+
472
+ """
473
+ self._comps_by_part = {}
474
+ for el, val in self.instances.items():
475
+ if val.partname in self._comps_by_part.keys():
476
+ self._comps_by_part[val.partname].append(val)
477
+ else:
478
+ self._comps_by_part[val.partname] = [val]
479
+ return self._comps_by_part
480
+
481
+ def get_component_by_name(self, name):
482
+ """Retrieve a component by name.
483
+
484
+ Parameters
485
+ ----------
486
+ name : str
487
+ Name of the component.
488
+
489
+ Returns
490
+ -------
491
+ bool
492
+ Component object.
493
+
494
+ """
495
+ return self.instances[name]
496
+
497
+ def get_pin_from_component(self, component, net_name=None, pin_name=None):
498
+ """Return component pins.
499
+ Parameters
500
+ ----------
501
+ component: .:class: `Component` or str.
502
+ Component object or component name.
503
+ net_name : str, List[str], optional
504
+ Apply filter on net name.
505
+ pin_name : str, optional
506
+ Apply filter on specific pin name.
507
+ Return
508
+ ------
509
+ List[:clas: `PadstackInstance`]
510
+
511
+
512
+
513
+ """
514
+ if isinstance(component, Component):
515
+ component = component.name
516
+ pins = [pin for pin in list(self.instances[component].pins.values())]
517
+ if net_name:
518
+ if isinstance(net_name, str):
519
+ net_name = [net_name]
520
+ pins = [pin for pin in pins if pin.net_name in net_name]
521
+ if pin_name:
522
+ pins = [pin for pin in pins if pin.name == pin_name]
523
+ return pins
524
+
525
+ def get_components_from_nets(self, netlist=None):
526
+ """Retrieve components from a net list.
527
+
528
+ Parameters
529
+ ----------
530
+ netlist : str, optional
531
+ Name of the net list. The default is ``None``.
532
+
533
+ Returns
534
+ -------
535
+ list
536
+ List of components that belong to the signal nets.
537
+
538
+ """
539
+ cmp_list = []
540
+ if isinstance(netlist, str):
541
+ netlist = [netlist]
542
+ components = list(self.instances.keys())
543
+ for refdes in components:
544
+ cmpnets = self._cmp[refdes].nets
545
+ if set(cmpnets).intersection(set(netlist)):
546
+ cmp_list.append(refdes)
547
+ return cmp_list
548
+
549
+ def _get_edb_pin_from_pin_name(self, cmp, pin):
550
+ if not isinstance(cmp, Component):
551
+ return False
552
+ if not isinstance(pin, str):
553
+ return False
554
+ if pin in cmp.pins:
555
+ return cmp.pins[pin]
556
+ return False
557
+
558
+ def get_component_placement_vector(
559
+ self,
560
+ mounted_component,
561
+ hosting_component,
562
+ mounted_component_pin1,
563
+ mounted_component_pin2,
564
+ hosting_component_pin1,
565
+ hosting_component_pin2,
566
+ flipped=False,
567
+ ):
568
+ """Get the placement vector between 2 components.
569
+
570
+ Parameters
571
+ ----------
572
+ mounted_component : `edb.cell.hierarchy._hierarchy.Component`
573
+ Mounted component name.
574
+ hosting_component : `edb.cell.hierarchy._hierarchy.Component`
575
+ Hosting component name.
576
+ mounted_component_pin1 : str
577
+ Mounted component Pin 1 name.
578
+ mounted_component_pin2 : str
579
+ Mounted component Pin 2 name.
580
+ hosting_component_pin1 : str
581
+ Hosted component Pin 1 name.
582
+ hosting_component_pin2 : str
583
+ Hosted component Pin 2 name.
584
+ flipped : bool, optional
585
+ Either if the mounted component will be flipped or not.
586
+
587
+ Returns
588
+ -------
589
+ tuple
590
+ Tuple of Vector offset, rotation and solder height.
591
+
592
+ Examples
593
+ --------
594
+ >>> edb1 = Edb(edbpath=targetfile1, edbversion="2021.2")
595
+ >>> hosting_cmp = edb1.components.get_component_by_name("U100")
596
+ >>> mounted_cmp = edb2.components.get_component_by_name("BGA")
597
+ >>> vector, rotation, solder_ball_height = edb1.components.get_component_placement_vector(
598
+ ... mounted_component=mounted_cmp,
599
+ ... hosting_component=hosting_cmp,
600
+ ... mounted_component_pin1="A12",
601
+ ... mounted_component_pin2="A14",
602
+ ... hosting_component_pin1="A12",
603
+ ... hosting_component_pin2="A14")
604
+ """
605
+ m_pin1_pos = [0.0, 0.0]
606
+ m_pin2_pos = [0.0, 0.0]
607
+ h_pin1_pos = [0.0, 0.0]
608
+ h_pin2_pos = [0.0, 0.0]
609
+ if not isinstance(mounted_component, Component):
610
+ return False
611
+ if not isinstance(hosting_component, Component):
612
+ return False
613
+
614
+ if mounted_component_pin1:
615
+ m_pin1 = self._get_edb_pin_from_pin_name(mounted_component, mounted_component_pin1)
616
+ m_pin1_pos = self.get_pin_position(m_pin1)
617
+ if mounted_component_pin2:
618
+ m_pin2 = self._get_edb_pin_from_pin_name(mounted_component, mounted_component_pin2)
619
+ m_pin2_pos = self.get_pin_position(m_pin2)
620
+
621
+ if hosting_component_pin1:
622
+ h_pin1 = self._get_edb_pin_from_pin_name(hosting_component, hosting_component_pin1)
623
+ h_pin1_pos = self.get_pin_position(h_pin1)
624
+
625
+ if hosting_component_pin2:
626
+ h_pin2 = self._get_edb_pin_from_pin_name(hosting_component, hosting_component_pin2)
627
+ h_pin2_pos = self.get_pin_position(h_pin2)
628
+ #
629
+ vector = [h_pin1_pos[0] - m_pin1_pos[0], h_pin1_pos[1] - m_pin1_pos[1]]
630
+ vector1 = GeometryOperators.v_points(m_pin1_pos, m_pin2_pos)
631
+ vector2 = GeometryOperators.v_points(h_pin1_pos, h_pin2_pos)
632
+ multiplier = 1
633
+ if flipped:
634
+ multiplier = -1
635
+ vector1[1] = multiplier * vector1[1]
636
+
637
+ rotation = GeometryOperators.v_angle_sign_2D(vector1, vector2, False)
638
+ if rotation != 0.0:
639
+ layinst = mounted_component.layout_instance
640
+ cmpinst = layinst.GetLayoutObjInstance(mounted_component, None)
641
+ center = cmpinst.center
642
+ # center_double = [center.X.ToDouble(), center.Y.ToDouble()]
643
+ vector_center = GeometryOperators.v_points(center, m_pin1_pos)
644
+ x_v2 = vector_center[0] * math.cos(rotation) + multiplier * vector_center[1] * math.sin(rotation)
645
+ y_v2 = -1 * vector_center[0] * math.sin(rotation) + multiplier * vector_center[1] * math.cos(rotation)
646
+ new_vector = [x_v2 + center[0], y_v2 + center[1]]
647
+ vector = [h_pin1_pos[0] - new_vector[0], h_pin1_pos[1] - new_vector[1]]
648
+
649
+ if vector:
650
+ solder_ball_height = self.get_solder_ball_height(mounted_component)
651
+ return True, vector, rotation, solder_ball_height
652
+ self._logger.warning("Failed to compute vector.")
653
+ return False, [0, 0], 0, 0
654
+
655
+ def get_solder_ball_height(self, cmp):
656
+ """Get component solder ball height.
657
+
658
+ Parameters
659
+ ----------
660
+ cmp : str or `Component` object.
661
+ EDB component or str component name.
662
+
663
+ Returns
664
+ -------
665
+ double, bool
666
+ Salder ball height vale, ``False`` when failed.
667
+
668
+ """
669
+ if isinstance(cmp, str):
670
+ cmp = self.get_component_by_name(cmp)
671
+ return cmp.solder_ball_height
672
+
673
+ def get_vendor_libraries(self):
674
+ """Retrieve all capacitors and inductors libraries from ANSYS installation (used by Siwave).
675
+
676
+ Returns
677
+ -------
678
+ ComponentLib object contains nested dictionaries to navigate through [component type][vendors][series]
679
+ :class: `pyedb.component_libraries.ansys_components.ComponentPart`
680
+
681
+ Examples
682
+ --------
683
+ >>> edbapp = Edb()
684
+ >>> comp_lib = edbapp.components.get_vendor_libraries()
685
+ >>> network = comp_lib.capacitors["AVX"]["AccuP01005"]["C005YJ0R1ABSTR"].s_parameters
686
+ >>> network.write_touchstone(os.path.join(edbapp.directory, "test_export.s2p"))
687
+
688
+ """
689
+ comp_lib_path = os.path.join(self._pedb.base_path, "complib", "Locked")
690
+ comp_types = ["Capacitors", "Inductors"]
691
+ comp_lib = ComponentLib()
692
+ comp_lib.path = comp_lib_path
693
+ for cmp_type in comp_types:
694
+ folder = os.path.join(comp_lib_path, cmp_type)
695
+ vendors = {f.name: "" for f in os.scandir(folder) if f.is_dir()}
696
+ for vendor in list(vendors.keys()):
697
+ series = {f.name: Series() for f in os.scandir(os.path.join(folder, vendor)) if f.is_dir()}
698
+ for serie_name, _ in series.items():
699
+ _serie = {}
700
+ index_file = os.path.join(folder, vendor, serie_name, "index.txt")
701
+ sbin_file = os.path.join(folder, vendor, serie_name, "sdata.bin")
702
+ if os.path.isfile(index_file):
703
+ with open(index_file, "r") as f:
704
+ for line in f.readlines():
705
+ part_name, index = line.split()
706
+ _serie[part_name] = ComponentPart(part_name, int(index), sbin_file)
707
+ _serie[part_name].type = cmp_type[:-1]
708
+ f.close()
709
+ series[serie_name] = _serie
710
+ vendors[vendor] = series
711
+ if cmp_type == "Capacitors":
712
+ comp_lib.capacitors = vendors
713
+ elif cmp_type == "Inductors":
714
+ comp_lib.inductors = vendors
715
+ return comp_lib
716
+
717
+ def create_source_on_component(self, sources=None):
718
+ """Create voltage, current source, or resistor on component.
719
+
720
+ . deprecated:: pyedb 0.28.0
721
+ Use .:func:`pyedb.grpc.core.excitations.create_source_on_component` instead.
722
+
723
+ Parameters
724
+ ----------
725
+ sources : list[Source]
726
+ List of ``edb_data.sources.Source`` objects.
727
+
728
+ Returns
729
+ -------
730
+ bool
731
+ ``True`` when successful, ``False`` when failed.
732
+
733
+ """
734
+ warnings.warn(
735
+ "`create_source_on_component` is deprecated and is now located here "
736
+ "`pyedb.grpc.core.excitations.create_source_on_component` instead.",
737
+ DeprecationWarning,
738
+ )
739
+ self._pedb.excitations.create_source_on_component(self, sources=sources)
740
+
741
+ def create_port_on_pins(
742
+ self,
743
+ refdes,
744
+ pins,
745
+ reference_pins,
746
+ impedance=50.0,
747
+ port_name=None,
748
+ pec_boundary=False,
749
+ pingroup_on_single_pin=False,
750
+ ):
751
+ """Create circuit port between pins and reference ones.
752
+
753
+ . deprecated:: pyedb 0.28.0
754
+ Use :func:`pyedb.grpc.core.excitations.create_port_on_pins` instead.
755
+
756
+ Parameters
757
+ ----------
758
+ refdes : Component reference designator
759
+ str or EDBComponent object.
760
+ pins : pin name where the terminal has to be created. Single pin or several ones can be provided.If several
761
+ pins are provided a pin group will is created. Pin names can be the EDB name or the EDBPadstackInstance one.
762
+ For instance the pin called ``Pin1`` located on component ``U1``, ``U1-Pin1`` or ``Pin1`` can be provided and
763
+ will be handled.
764
+ str, [str], EDBPadstackInstance, [EDBPadstackInstance]
765
+ reference_pins : reference pin name used for terminal reference. Single pin or several ones can be provided.
766
+ If several pins are provided a pin group will is created. Pin names can be the EDB name or the
767
+ EDBPadstackInstance one. For instance the pin called ``Pin1`` located on component ``U1``, ``U1-Pin1``
768
+ or ``Pin1`` can be provided and will be handled.
769
+ str, [str], EDBPadstackInstance, [EDBPadstackInstance]
770
+ impedance : Port impedance
771
+ str, float
772
+ port_name : str, optional
773
+ Port name. The default is ``None``, in which case a name is automatically assigned.
774
+ pec_boundary : bool, optional
775
+ Whether to define the PEC boundary, The default is ``False``. If set to ``True``,
776
+ a perfect short is created between the pin and impedance is ignored. This
777
+ parameter is only supported on a port created between two pins, such as
778
+ when there is no pin group.
779
+ pingroup_on_single_pin : bool
780
+ If ``True`` force using pingroup definition on single pin to have the port created at the pad center. If
781
+ ``False`` the port is created at the pad edge. Default value is ``False``.
782
+
783
+ Returns
784
+ -------
785
+ EDB terminal created, or False if failed to create.
786
+ """
787
+ warnings.warn(
788
+ "`create_port_on_pins` is deprecated and is now located here "
789
+ "`pyedb.grpc.core.excitations.create_port_on_pins` instead.",
790
+ DeprecationWarning,
791
+ )
792
+ return self._pedb.source_excitation.create_port_on_pins(
793
+ refdes,
794
+ pins,
795
+ reference_pins,
796
+ impedance=impedance,
797
+ port_name=port_name,
798
+ pec_boundary=pec_boundary,
799
+ pingroup_on_single_pin=pingroup_on_single_pin,
800
+ )
801
+
802
+ def create_port_on_component(
803
+ self,
804
+ component,
805
+ net_list,
806
+ port_type=SourceType.CoaxPort,
807
+ do_pingroup=True,
808
+ reference_net="gnd",
809
+ port_name=None,
810
+ solder_balls_height=None,
811
+ solder_balls_size=None,
812
+ solder_balls_mid_size=None,
813
+ extend_reference_pins_outside_component=False,
814
+ ):
815
+ """Create ports on a component.
816
+
817
+ . deprecated:: pyedb 0.28.0
818
+ Use :func:`pyedb.grpc.core.excitations.create_port_on_component` instead.
819
+
820
+ Parameters
821
+ ----------
822
+ component : str or self._pedb.component
823
+ EDB component or str component name.
824
+ net_list : str or list of string.
825
+ List of nets where ports must be created on the component.
826
+ If the net is not part of the component, this parameter is skipped.
827
+ port_type : SourceType enumerator, CoaxPort or CircuitPort
828
+ Type of port to create. ``CoaxPort`` generates solder balls.
829
+ ``CircuitPort`` generates circuit ports on pins belonging to the net list.
830
+ do_pingroup : bool
831
+ True activate pingroup during port creation (only used with combination of CircPort),
832
+ False will take the closest reference pin and generate one port per signal pin.
833
+ refnet : string or list of string.
834
+ list of the reference net.
835
+ port_name : str
836
+ Port name for overwriting the default port-naming convention,
837
+ which is ``[component][net][pin]``. The port name must be unique.
838
+ If a port with the specified name already exists, the
839
+ default naming convention is used so that port creation does
840
+ not fail.
841
+ solder_balls_height : float, optional
842
+ Solder balls height used for the component. When provided default value is overwritten and must be
843
+ provided in meter.
844
+ solder_balls_size : float, optional
845
+ Solder balls diameter. When provided auto evaluation based on padstack size will be disabled.
846
+ solder_balls_mid_size : float, optional
847
+ Solder balls mid-diameter. When provided if value is different than solder balls size, spheroid shape will
848
+ be switched.
849
+ extend_reference_pins_outside_component : bool
850
+ When no reference pins are found on the component extend the pins search with taking the closest one. If
851
+ `do_pingroup` is `True` will be set to `False`. Default value is `False`.
852
+
853
+ Returns
854
+ -------
855
+ double, bool
856
+ Salder ball height vale, ``False`` when failed.
857
+
858
+ """
859
+ warnings.warn(
860
+ "`create_port_on_component` is deprecated and is now located here "
861
+ "`pyedb.grpc.core.excitations.create_port_on_component` instead.",
862
+ DeprecationWarning,
863
+ )
864
+ return self._pedb.source_excitation.create_port_on_component(
865
+ component,
866
+ net_list,
867
+ port_type=port_type,
868
+ do_pingroup=do_pingroup,
869
+ reference_net=reference_net,
870
+ port_name=port_name,
871
+ solder_balls_height=solder_balls_height,
872
+ solder_balls_size=solder_balls_size,
873
+ solder_balls_mid_size=solder_balls_mid_size,
874
+ extend_reference_pins_outside_component=extend_reference_pins_outside_component,
875
+ )
876
+
877
+ def _create_terminal(self, pin, term_name=None):
878
+ """Create terminal on component pin.
879
+
880
+ . deprecated:: pyedb 0.28.0
881
+ Use :func:`pyedb.grpc.core.excitations._create_terminal` instead.
882
+
883
+ Parameters
884
+ ----------
885
+ pin : Edb padstack instance.
886
+
887
+ term_name : Terminal name (Optional).
888
+ str.
889
+
890
+ Returns
891
+ -------
892
+ EDB terminal.
893
+ """
894
+ warnings.warn(
895
+ "`_create_terminal` is deprecated and is now located here "
896
+ "`pyedb.grpc.core.excitations._create_terminal` instead.",
897
+ DeprecationWarning,
898
+ )
899
+ self._pedb.excitations._create_terminal(pin, term_name=term_name)
900
+
901
+ def _get_closest_pin_from(self, pin, ref_pinlist):
902
+ """Returns the closest pin from given pin among the list of reference pins.
903
+
904
+ Parameters
905
+ ----------
906
+ pin : Edb padstack instance.
907
+
908
+ ref_pinlist : list of reference edb pins.
909
+
910
+ Returns
911
+ -------
912
+ Edb pin.
913
+
914
+ """
915
+ distance = 1e3
916
+ pin_position = pin.position
917
+ closest_pin = ref_pinlist[0]
918
+ for ref_pin in ref_pinlist:
919
+ temp_distance = pin_position.distance(ref_pin.position)
920
+ if temp_distance < distance:
921
+ distance = temp_distance
922
+ closest_pin = ref_pin
923
+ return closest_pin
924
+
925
+ def replace_rlc_by_gap_boundaries(self, component=None):
926
+ """Replace RLC component by RLC gap boundaries. These boundary types are compatible with 3D modeler export.
927
+ Only 2 pins RLC components are supported in this command.
928
+
929
+ Parameters
930
+ ----------
931
+ component : str
932
+ Reference designator of the RLC component.
933
+
934
+ Returns
935
+ -------
936
+ bool
937
+ ``True`` when succeed, ``False`` if it failed.
938
+
939
+ Examples
940
+ --------
941
+ >>> from pyedb import Edb
942
+ >>> edb = Edb(edb_file)
943
+ >>> for refdes, cmp in edb.components.capacitors.items():
944
+ >>> edb.components.replace_rlc_by_gap_boundaries(refdes)
945
+ >>> edb.save_edb()
946
+ >>> edb.close_edb()
947
+ """
948
+ if not component:
949
+ return False
950
+ if isinstance(component, str):
951
+ component = self.instances[component]
952
+ if not component:
953
+ self._logger.error("component %s not found.", component)
954
+ return False
955
+ if component.type in ["other", "ic", "io"]:
956
+ self._logger.info(f"Component {component.refdes} skipped to deactivate is not an RLC.")
957
+ return False
958
+ component.enabled = False
959
+ return self._pedb.source_excitation.add_rlc_boundary(component.refdes, False)
960
+
961
+ def deactivate_rlc_component(self, component=None, create_circuit_port=False, pec_boundary=False):
962
+ """Deactivate RLC component with a possibility to convert it to a circuit port.
963
+
964
+ Parameters
965
+ ----------
966
+ component : str
967
+ Reference designator of the RLC component.
968
+
969
+ create_circuit_port : bool, optional
970
+ Whether to replace the deactivated RLC component with a circuit port. The default
971
+ is ``False``.
972
+ pec_boundary : bool, optional
973
+ Whether to define the PEC boundary, The default is ``False``. If set to ``True``,
974
+ a perfect short is created between the pin and impedance is ignored. This
975
+ parameter is only supported on a port created between two pins, such as
976
+ when there is no pin group.
977
+
978
+ Returns
979
+ -------
980
+ bool
981
+ ``True`` when successful, ``False`` when failed.
982
+
983
+ Examples
984
+ --------
985
+ >>> from pyedb import Edb
986
+ >>> edb_file = r'C:\my_edb_file.aedb'
987
+ >>> edb = Edb(edb_file)
988
+ >>> for cmp in list(edb.components.instances.keys()):
989
+ >>> edb.components.deactivate_rlc_component(component=cmp, create_circuit_port=False)
990
+ >>> edb.save_edb()
991
+ >>> edb.close_edb()
992
+ """
993
+ if not component:
994
+ return False
995
+ if isinstance(component, str):
996
+ component = self.instances[component]
997
+ if not component:
998
+ self._logger.error("component %s not found.", component)
999
+ return False
1000
+ if component.type in ["other", "ic", "io"]:
1001
+ self._logger.info(f"Component {component.refdes} passed to deactivate is not an RLC.")
1002
+ return False
1003
+ component.is_enabled = False
1004
+ return self._pedb.source_excitation.add_port_on_rlc_component(
1005
+ component=component.refdes, circuit_ports=create_circuit_port, pec_boundary=pec_boundary
1006
+ )
1007
+
1008
+ def add_port_on_rlc_component(self, component=None, circuit_ports=True, pec_boundary=False):
1009
+ """Deactivate RLC component and replace it with a circuit port.
1010
+ The circuit port supports only two-pin components.
1011
+
1012
+ . deprecated:: pyedb 0.28.0
1013
+ Use :func:`pyedb.grpc.core.excitations.add_port_on_rlc_component` instead.
1014
+
1015
+ Parameters
1016
+ ----------
1017
+ component : str
1018
+ Reference designator of the RLC component.
1019
+
1020
+ circuit_ports : bool
1021
+ ``True`` will replace RLC component by circuit ports, ``False`` gap ports compatible with HFSS 3D modeler
1022
+ export.
1023
+
1024
+ pec_boundary : bool, optional
1025
+ Whether to define the PEC boundary, The default is ``False``. If set to ``True``,
1026
+ a perfect short is created between the pin and impedance is ignored. This
1027
+ parameter is only supported on a port created between two pins, such as
1028
+ when there is no pin group.
1029
+
1030
+ Returns
1031
+ -------
1032
+ bool
1033
+ ``True`` when successful, ``False`` when failed.
1034
+ """
1035
+ warnings.warn(
1036
+ "`add_port_on_rlc_component` is deprecated and is now located here "
1037
+ "`pyedb.grpc.core.excitations.add_port_on_rlc_component` instead.",
1038
+ DeprecationWarning,
1039
+ )
1040
+ return self._pedb.source_excitation.add_port_on_rlc_component(
1041
+ component=component, circuit_ports=circuit_ports, pec_boundary=pec_boundary
1042
+ )
1043
+
1044
+ def add_rlc_boundary(self, component=None, circuit_type=True):
1045
+ """Add RLC gap boundary on component and replace it with a circuit port.
1046
+ The circuit port supports only 2-pin components.
1047
+
1048
+ . deprecated:: pyedb 0.28.0
1049
+ Use :func:`pyedb.grpc.core.excitations.add_rlc_boundary` instead.
1050
+
1051
+ Parameters
1052
+ ----------
1053
+ component : str
1054
+ Reference designator of the RLC component.
1055
+ circuit_type : bool
1056
+ When ``True`` circuit type are defined, if ``False`` gap type will be used instead (compatible with HFSS 3D
1057
+ modeler). Default value is ``True``.
1058
+
1059
+ Returns
1060
+ -------
1061
+ bool
1062
+ ``True`` when successful, ``False`` when failed.
1063
+ """
1064
+ warnings.warn(
1065
+ "`add_rlc_boundary` is deprecated and is now located here "
1066
+ "`pyedb.grpc.core.excitations.add_rlc_boundary` instead.",
1067
+ DeprecationWarning,
1068
+ )
1069
+ return self._pedb.source_excitation.add_rlc_boundary(self, component=component, circuit_type=circuit_type)
1070
+
1071
+ def _create_pin_group_terminal(self, pingroup, isref=False, term_name=None, term_type="circuit"):
1072
+ """Creates an EDB pin group terminal from a given EDB pin group.
1073
+
1074
+ . deprecated:: pyedb 0.28.0
1075
+ Use :func:`pyedb.grpc.core.excitations._create_pin_group_terminal` instead.
1076
+
1077
+ Parameters
1078
+ ----------
1079
+ pingroup : Edb pin group.
1080
+
1081
+ isref : bool
1082
+ Specify if this terminal a reference terminal.
1083
+
1084
+ term_name : Terminal name (Optional). If not provided default name is Component name, Pin name, Net name.
1085
+ str.
1086
+
1087
+ term_type: Type of terminal, gap, circuit or auto.
1088
+ str.
1089
+ Returns
1090
+ -------
1091
+ Edb pin group terminal.
1092
+ """
1093
+ warnings.warn(
1094
+ "`_create_pin_group_terminal` is deprecated and is now located here "
1095
+ "`pyedb.grpc.core.excitations._create_pin_group_terminal` instead.",
1096
+ DeprecationWarning,
1097
+ )
1098
+ return self._pedb.source_excitation._create_pin_group_terminal(
1099
+ pingroup=pingroup, term_name=term_name, term_type=term_type, isref=isref
1100
+ )
1101
+
1102
+ def _is_top_component(self, cmp):
1103
+ """Test the component placement layer.
1104
+
1105
+ Parameters
1106
+ ----------
1107
+ cmp : self._pedb.component
1108
+ Edb component.
1109
+
1110
+ Returns
1111
+ -------
1112
+ bool
1113
+ ``True`` when component placed on top layer, ``False`` on bottom layer.
1114
+
1115
+
1116
+ """
1117
+ top_layer = self._pedb.stackup.signal[0].name
1118
+ if cmp.placement_layer == top_layer:
1119
+ return True
1120
+ else:
1121
+ return False
1122
+
1123
+ def _get_component_definition(self, name, pins):
1124
+ component_definition = ComponentDef.find(self._db, name)
1125
+ if component_definition.is_null:
1126
+ from ansys.edb.core.layout.cell import Cell as GrpcCell
1127
+ from ansys.edb.core.layout.cell import CellType as GrpcCellType
1128
+
1129
+ foot_print_cell = GrpcCell.create(self._pedb.active_db, GrpcCellType.FOOTPRINT_CELL, name)
1130
+ component_definition = ComponentDef.create(self._db, name, fp=foot_print_cell)
1131
+ if component_definition.is_null:
1132
+ self._logger.error(f"Failed to create component definition {name}")
1133
+ return False
1134
+ ind = 1
1135
+ for pin in pins:
1136
+ if not pin.name:
1137
+ pin.name = str(ind)
1138
+ ind += 1
1139
+ component_definition_pin = ComponentPin.create(component_definition, pin.name)
1140
+ if component_definition_pin.is_null:
1141
+ self._logger.error(f"Failed to create component definition pin {name}-{pin.name}")
1142
+ return None
1143
+ else:
1144
+ self._logger.warning("Found existing component definition for footprint {}".format(name))
1145
+ return component_definition
1146
+
1147
+ def create(
1148
+ self,
1149
+ pins,
1150
+ component_name=None,
1151
+ placement_layer=None,
1152
+ component_part_name=None,
1153
+ is_rlc=False,
1154
+ r_value=None,
1155
+ c_value=None,
1156
+ l_value=None,
1157
+ is_parallel=False,
1158
+ ):
1159
+ """Create a component from pins.
1160
+
1161
+ Parameters
1162
+ ----------
1163
+ pins : list
1164
+ List of EDB core pins.
1165
+ component_name : str
1166
+ Name of the reference designator for the component.
1167
+ placement_layer : str, optional
1168
+ Name of the layer used for placing the component.
1169
+ component_part_name : str, optional
1170
+ Part name of the component.
1171
+ is_rlc : bool, optional
1172
+ Whether if the new component will be an RLC or not.
1173
+ r_value : float
1174
+ Resistor value.
1175
+ c_value : float
1176
+ Capacitance value.
1177
+ l_value : float
1178
+ Inductor value.
1179
+ is_parallel : bool
1180
+ Using parallel model when ``True``, series when ``False``.
1181
+
1182
+ Returns
1183
+ -------
1184
+ bool
1185
+ ``True`` when successful, ``False`` when failed.
1186
+
1187
+ Examples
1188
+ --------
1189
+
1190
+ >>> from pyedb import Edb
1191
+ >>> edbapp = Edb("myaedbfolder")
1192
+ >>> pins = edbapp.components.get_pin_from_component("A1")
1193
+ >>> edbapp.components.create(pins, "A1New")
1194
+
1195
+ """
1196
+ from ansys.edb.core.hierarchy.component_group import (
1197
+ ComponentGroup as GrpcComponentGroup,
1198
+ )
1199
+
1200
+ if not component_name:
1201
+ component_name = generate_unique_name("Comp_")
1202
+ if component_part_name:
1203
+ compdef = self._get_component_definition(component_part_name, pins)
1204
+ else:
1205
+ compdef = self._get_component_definition(component_name, pins)
1206
+ if not compdef:
1207
+ return False
1208
+ new_cmp = GrpcComponentGroup.create(self._active_layout, component_name, compdef.name)
1209
+ hosting_component_location = pins[0].component.transform
1210
+ if not len(pins) == len(compdef.component_pins):
1211
+ self._pedb.logger.error(
1212
+ f"Number on pins {len(pins)} does not match component definition number "
1213
+ f"of pins {len(compdef.component_pins)}"
1214
+ )
1215
+ return False
1216
+ for padstack_instance, component_pin in zip(pins, compdef.component_pins):
1217
+ padstack_instance.is_layout_pin = True
1218
+ padstack_instance.name = component_pin.name
1219
+ new_cmp.add_member(padstack_instance)
1220
+ if not placement_layer:
1221
+ new_cmp_layer_name = pins[0].padstack_def.data.layer_names[0]
1222
+ else:
1223
+ new_cmp_layer_name = placement_layer
1224
+ if new_cmp_layer_name in self._pedb.stackup.signal_layers:
1225
+ new_cmp_placement_layer = self._pedb.stackup.signal_layers[new_cmp_layer_name]
1226
+ new_cmp.placement_layer = new_cmp_placement_layer
1227
+ new_cmp.component_type = GrpcComponentType.OTHER
1228
+ if is_rlc and len(pins) == 2:
1229
+ rlc = GrpcRlc()
1230
+ rlc.is_parallel = is_parallel
1231
+ if not r_value:
1232
+ rlc.r_enabled = False
1233
+ else:
1234
+ rlc.r_enabled = True
1235
+ rlc.r = GrpcValue(r_value)
1236
+ if l_value is None:
1237
+ rlc.l_enabled = False
1238
+ else:
1239
+ rlc.l_enabled = True
1240
+ rlc.l = GrpcValue(l_value)
1241
+ if c_value is None:
1242
+ rlc.c_enabled = False
1243
+ else:
1244
+ rlc.c_enabled = True
1245
+ rlc.C = GrpcValue(c_value)
1246
+ if rlc.r_enabled and not rlc.c_enabled and not rlc.l_enabled:
1247
+ new_cmp.component_type = GrpcComponentType.RESISTOR
1248
+ elif rlc.c_enabled and not rlc.r_enabled and not rlc.l_enabled:
1249
+ new_cmp.component_type = GrpcComponentType.CAPACITOR
1250
+ elif rlc.l_enabled and not rlc.r_enabled and not rlc.c_enabled:
1251
+ new_cmp.component_type = GrpcComponentType.INDUCTOR
1252
+ else:
1253
+ new_cmp.component_type = GrpcComponentType.RESISTOR
1254
+ pin_pair = (pins[0].name, pins[1].name)
1255
+ rlc_model = PinPairModel(self._pedb, new_cmp.component_property.model)
1256
+ rlc_model.set_rlc(pin_pair, rlc)
1257
+ component_property = new_cmp.component_property
1258
+ component_property.model = rlc_model
1259
+ new_cmp.component_property = component_property
1260
+ new_cmp.transform = hosting_component_location
1261
+ new_edb_comp = Component(self._pedb, new_cmp)
1262
+ self._cmp[new_cmp.name] = new_edb_comp
1263
+ return new_edb_comp
1264
+
1265
+ def create_component_from_pins(
1266
+ self, pins, component_name, placement_layer=None, component_part_name=None
1267
+ ): # pragma: no cover
1268
+ """Create a component from pins.
1269
+
1270
+ .. deprecated:: 0.6.62
1271
+ Use :func:`create` method instead.
1272
+
1273
+ Parameters
1274
+ ----------
1275
+ pins : list
1276
+ List of EDB core pins.
1277
+ component_name : str
1278
+ Name of the reference designator for the component.
1279
+ placement_layer : str, optional
1280
+ Name of the layer used for placing the component.
1281
+ component_part_name : str, optional
1282
+ Part name of the component. It's created a new definition if doesn't exists.
1283
+
1284
+ Returns
1285
+ -------
1286
+ bool
1287
+ ``True`` when successful, ``False`` when failed.
1288
+
1289
+ Examples
1290
+ --------
1291
+
1292
+ >>> from pyedb import Edb
1293
+ >>> edbapp = Edb("myaedbfolder")
1294
+ >>> pins = edbapp.components.get_pin_from_component("A1")
1295
+ >>> edbapp.components.create(pins, "A1New")
1296
+
1297
+ """
1298
+ warnings.warn("`create_component_from_pins` is deprecated use `create` instead..", DeprecationWarning)
1299
+ return self.create(
1300
+ pins=pins,
1301
+ component_name=component_name,
1302
+ placement_layer=placement_layer,
1303
+ component_part_name=component_part_name,
1304
+ is_rlc=False,
1305
+ )
1306
+
1307
+ def set_component_model(self, componentname, model_type="Spice", modelpath=None, modelname=None):
1308
+ """Assign a Spice or Touchstone model to a component.
1309
+
1310
+ Parameters
1311
+ ----------
1312
+ componentname : str
1313
+ Name of the component.
1314
+ model_type : str, optional
1315
+ Type of the model. Options are ``"Spice"`` and
1316
+ ``"Touchstone"``. The default is ``"Spice"``.
1317
+ modelpath : str, optional
1318
+ Full path to the model file. The default is ``None``.
1319
+ modelname : str, optional
1320
+ Name of the model. The default is ``None``.
1321
+
1322
+ Returns
1323
+ -------
1324
+ bool
1325
+ ``True`` when successful, ``False`` when failed.
1326
+
1327
+ Examples
1328
+ --------
1329
+
1330
+ >>> from pyedb import Edb
1331
+ >>> edbapp = Edb("myaedbfolder")
1332
+ >>> edbapp.components.set_component_model("A1", model_type="Spice",
1333
+ ... modelpath="pathtospfile",
1334
+ ... modelname="spicemodelname")
1335
+
1336
+ """
1337
+ if not modelname:
1338
+ modelname = get_filename_without_extension(modelpath)
1339
+ if componentname not in self.instances:
1340
+ self._pedb.logger.error(f"Component {componentname} not found.")
1341
+ return False
1342
+ component = self.instances[componentname]
1343
+ pin_number = len(component.pins)
1344
+ if model_type == "Spice":
1345
+ with open(modelpath, "r") as f:
1346
+ for line in f:
1347
+ if "subckt" in line.lower():
1348
+ pin_names = [i.strip() for i in re.split(" |\t", line) if i]
1349
+ pin_names.remove(pin_names[0])
1350
+ pin_names.remove(pin_names[0])
1351
+ break
1352
+ if len(pin_names) == pin_number:
1353
+ spice_mod = GrpcSPICEModel.create(name=modelname, path=modelpath, sub_circuit=f"{modelname}_sub")
1354
+ terminal = 1
1355
+ for pn in pin_names:
1356
+ spice_mod.add_terminal(terminal=str(terminal), pin=pn)
1357
+ terminal += 1
1358
+ component.component_property.model = spice_mod
1359
+ else:
1360
+ self._logger.error("Wrong number of Pins")
1361
+ return False
1362
+
1363
+ elif model_type == "Touchstone": # pragma: no cover
1364
+ n_port_model_name = modelname
1365
+ from ansys.edb.core.definition.component_model import (
1366
+ NPortComponentModel as GrpcNPortComponentModel,
1367
+ )
1368
+ from ansys.edb.core.hierarchy.sparameter_model import (
1369
+ SParameterModel as GrpcSParameterModel,
1370
+ )
1371
+
1372
+ n_port_model = GrpcNPortComponentModel.find_by_name(component.component_def, n_port_model_name)
1373
+ if n_port_model.is_null:
1374
+ n_port_model = GrpcNPortComponentModel.create(n_port_model_name)
1375
+ n_port_model.reference_file = modelpath
1376
+ component.component_def.add_component_model(n_port_model)
1377
+ gndnets = list(filter(lambda x: "gnd" in x.lower(), component.nets))
1378
+ if len(gndnets) > 0: # pragma: no cover
1379
+ net = gndnets[0]
1380
+ else: # pragma: no cover
1381
+ net = component.nets[len(component.nets) - 1]
1382
+ s_parameter_mod = GrpcSParameterModel.create(name=n_port_model_name, ref_net=net)
1383
+ component.component_property.model = s_parameter_mod
1384
+ return True
1385
+
1386
+ def create_pingroup_from_pins(self, pins, group_name=None):
1387
+ """Create a pin group on a component.
1388
+
1389
+ Parameters
1390
+ ----------
1391
+ pins : list
1392
+ List of EDB pins.
1393
+ group_name : str, optional
1394
+ Name for the group. The default is ``None``, in which case
1395
+ a default name is assigned as follows: ``[component Name] [NetName]``.
1396
+
1397
+ Returns
1398
+ -------
1399
+ tuple
1400
+ The tuple is structured as: (bool, pingroup).
1401
+
1402
+ Examples
1403
+ --------
1404
+ >>> from pyedb import Edb
1405
+ >>> edbapp = Edb("myaedbfolder")
1406
+ >>> edbapp.components.create_pingroup_from_pins(gndpinlist, "MyGNDPingroup")
1407
+
1408
+ """
1409
+ if len(pins) < 1:
1410
+ self._logger.error("No pins specified for pin group %s", group_name)
1411
+ return (False, None)
1412
+ if group_name is None:
1413
+ group_name = PinGroup.unique_name(self._active_layout, "pin_group")
1414
+ for pin in pins:
1415
+ pin.is_layout_pin = True
1416
+ forbiden_car = "-><"
1417
+ group_name = group_name.translate({ord(i): "_" for i in forbiden_car})
1418
+ for pgroup in list(self._pedb.active_layout.pin_groups):
1419
+ if pgroup.name == group_name:
1420
+ pin_group_exists = True
1421
+ if len(pgroup.pins) == len(pins):
1422
+ pnames = [i.name for i in pins]
1423
+ for p in pgroup.pins:
1424
+ if p.name in pnames:
1425
+ continue
1426
+ else:
1427
+ group_name = PinGroup.unique_name(self._active_layout, group_name)
1428
+ pin_group_exists = False
1429
+ else:
1430
+ group_name = PinGroup.unique_name(self._active_layout, group_name)
1431
+ pin_group_exists = False
1432
+ if pin_group_exists:
1433
+ return pgroup
1434
+ pin_group = PinGroup.create(self._active_layout, group_name, pins)
1435
+ if pin_group.is_null:
1436
+ return False
1437
+ else:
1438
+ pin_group.net = pins[0].net
1439
+ return pin_group
1440
+
1441
+ def delete_single_pin_rlc(self, deactivate_only=False):
1442
+ # type: (bool) -> list
1443
+ """Delete all RLC components with a single pin.
1444
+ Single pin component model type will be reverted to ``"RLC"``.
1445
+
1446
+ Parameters
1447
+ ----------
1448
+ deactivate_only : bool, optional
1449
+ Whether to only deactivate RLC components with a single point rather than
1450
+ delete them. The default is ``False``, in which case they are deleted.
1451
+
1452
+ Returns
1453
+ -------
1454
+ list
1455
+ List of deleted RLC components.
1456
+
1457
+
1458
+ Examples
1459
+ --------
1460
+
1461
+ >>> from pyedb import Edb
1462
+ >>> edbapp = Edb("myaedbfolder")
1463
+ >>> list_of_deleted_rlcs = edbapp.components.delete_single_pin_rlc()
1464
+ >>> print(list_of_deleted_rlcs)
1465
+
1466
+ """
1467
+ deleted_comps = []
1468
+ for comp, val in self.instances.items():
1469
+ if val.numpins < 2 and val.type in ["Resistor", "Capacitor", "Inductor"]:
1470
+ if deactivate_only:
1471
+ val.is_enabled = False
1472
+ val.model_type = "RLC"
1473
+ else:
1474
+ val.edbcomponent.delete()
1475
+ deleted_comps.append(comp)
1476
+ if not deactivate_only:
1477
+ self.refresh_components()
1478
+ self._pedb.logger.info("Deleted {} components".format(len(deleted_comps)))
1479
+ return deleted_comps
1480
+
1481
+ def delete(self, component_name):
1482
+ """Delete a component.
1483
+
1484
+ Parameters
1485
+ ----------
1486
+ component_name : str
1487
+ Name of the component.
1488
+
1489
+ Returns
1490
+ -------
1491
+ bool
1492
+ ``True`` when successful, ``False`` when failed.
1493
+
1494
+ Examples
1495
+ --------
1496
+
1497
+ >>> from pyedb import Edb
1498
+ >>> edbapp = Edb("myaedbfolder")
1499
+ >>> edbapp.components.delete("A1")
1500
+
1501
+ """
1502
+ edb_cmp = self.get_component_by_name(component_name)
1503
+ if edb_cmp is not None:
1504
+ edb_cmp.delete()
1505
+ if edb_cmp in list(self.instances.keys()):
1506
+ del self.instances[edb_cmp]
1507
+ return True
1508
+ return False
1509
+
1510
+ def disable_rlc_component(self, component_name):
1511
+ """Disable a RLC component.
1512
+
1513
+ Parameters
1514
+ ----------
1515
+ component_name : str
1516
+ Name of the RLC component.
1517
+
1518
+ Returns
1519
+ -------
1520
+ bool
1521
+ ``True`` when successful, ``False`` when failed.
1522
+
1523
+ Examples
1524
+ --------
1525
+
1526
+ >>> from pyedb import Edb
1527
+ >>> edbapp = Edb("myaedbfolder")
1528
+ >>> edbapp.components.disable_rlc_component("A1")
1529
+
1530
+ """
1531
+ cmp = self.get_component_by_name(component_name)
1532
+ if cmp is not None:
1533
+ component_property = cmp.component_property
1534
+ pin_pair_model = component_property.model
1535
+ for pin_pair in pin_pair_model.pin_pairs():
1536
+ rlc = pin_pair_model.rlc(pin_pair)
1537
+ rlc.c_enabled = False
1538
+ rlc.l_enabled = False
1539
+ rlc.r_enabled = False
1540
+ pin_pair_model.set_rlc(pin_pair, rlc)
1541
+ component_property.model = pin_pair_model
1542
+ cmp.component_property = component_property
1543
+ return True
1544
+ return False
1545
+
1546
+ def set_solder_ball(
1547
+ self,
1548
+ component="",
1549
+ sball_diam=None,
1550
+ sball_height=None,
1551
+ shape="Cylinder",
1552
+ sball_mid_diam=None,
1553
+ chip_orientation="chip_down",
1554
+ auto_reference_size=True,
1555
+ reference_size_x=0,
1556
+ reference_size_y=0,
1557
+ reference_height=0,
1558
+ ):
1559
+ """Set cylindrical solder balls on a given component.
1560
+
1561
+ Parameters
1562
+ ----------
1563
+ component : str or EDB component, optional
1564
+ Name of the discrete component.
1565
+ sball_diam : str, float, optional
1566
+ Diameter of the solder ball.
1567
+ sball_height : str, float, optional
1568
+ Height of the solder ball.
1569
+ shape : str, optional
1570
+ Shape of solder ball. Options are ``"Cylinder"``,
1571
+ ``"Spheroid"``. The default is ``"Cylinder"``.
1572
+ sball_mid_diam : str, float, optional
1573
+ Mid diameter of the solder ball.
1574
+ chip_orientation : str, optional
1575
+ Give the chip orientation, ``"chip_down"`` or ``"chip_up"``. Default is ``"chip_down"``. Only applicable on
1576
+ IC model.
1577
+ auto_reference_size : bool, optional
1578
+ Whether to automatically set reference size.
1579
+ reference_size_x : int, str, float, optional
1580
+ X size of the reference. Applicable when auto_reference_size is False.
1581
+ reference_size_y : int, str, float, optional
1582
+ Y size of the reference. Applicable when auto_reference_size is False.
1583
+ reference_height : int, str, float, optional
1584
+ Height of the reference. Applicable when auto_reference_size is False.
1585
+
1586
+ Returns
1587
+ -------
1588
+ bool
1589
+ ``True`` when successful, ``False`` when failed.
1590
+
1591
+ Examples
1592
+ --------
1593
+
1594
+ >>> from pyedb import Edb
1595
+ >>> edbapp = Edb("myaedbfolder")
1596
+ >>> edbapp.components.set_solder_ball("A1")
1597
+
1598
+ """
1599
+ if isinstance(component, str):
1600
+ if component in self.instances:
1601
+ cmp = self.instances[component]
1602
+ else:
1603
+ cmp = self.instances[component.name]
1604
+ if not sball_diam:
1605
+ pin1 = list(cmp.pins.values())[0]
1606
+ pin_layers = pin1.padstack_def.data.layer_names
1607
+ pad_params = self._pedb.padstacks.get_pad_parameters(pin=pin1, layername=pin_layers[0], pad_type=0)
1608
+ _sb_diam = min([abs(GrpcValue(val).value) for val in pad_params[1]])
1609
+ sball_diam = 0.8 * _sb_diam
1610
+ if sball_height:
1611
+ sball_height = round(GrpcValue(sball_height).value, 9)
1612
+ else:
1613
+ sball_height = round(GrpcValue(sball_diam).value, 9) / 2
1614
+
1615
+ if not sball_mid_diam:
1616
+ sball_mid_diam = sball_diam
1617
+
1618
+ if shape.lower() == "cylinder":
1619
+ sball_shape = GrpcSolderballShape.SOLDERBALL_CYLINDER
1620
+ else:
1621
+ sball_shape = GrpcSolderballShape.SOLDERBALL_SPHEROID
1622
+
1623
+ cmp_property = cmp.component_property
1624
+ if cmp.type == GrpcComponentType.IC:
1625
+ ic_die_prop = cmp_property.die_property
1626
+ ic_die_prop.die_type = GrpcDieType.FLIPCHIP
1627
+ if chip_orientation.lower() == "chip_up":
1628
+ ic_die_prop.orientation = GrpDieOrientation.CHIP_UP
1629
+ else:
1630
+ ic_die_prop.orientation = GrpDieOrientation.CHIP_DOWN
1631
+ cmp_property.die_property = ic_die_prop
1632
+
1633
+ solder_ball_prop = cmp_property.solder_ball_property
1634
+ solder_ball_prop.set_diameter(GrpcValue(sball_diam), GrpcValue(sball_mid_diam))
1635
+ solder_ball_prop.height = GrpcValue(sball_height)
1636
+
1637
+ solder_ball_prop.shape = sball_shape
1638
+ cmp_property.solder_ball_property = solder_ball_prop
1639
+
1640
+ port_prop = cmp_property.port_property
1641
+ port_prop.reference_height = GrpcValue(reference_height)
1642
+ port_prop.reference_size_auto = auto_reference_size
1643
+ if not auto_reference_size:
1644
+ port_prop.set_reference_size(GrpcValue(reference_size_x), GrpcValue(reference_size_y))
1645
+ cmp_property.port_property = port_prop
1646
+ cmp.component_property = cmp_property
1647
+ return True
1648
+
1649
+ def set_component_rlc(
1650
+ self,
1651
+ componentname,
1652
+ res_value=None,
1653
+ ind_value=None,
1654
+ cap_value=None,
1655
+ isparallel=False,
1656
+ ):
1657
+ """Update values for an RLC component.
1658
+
1659
+ Parameters
1660
+ ----------
1661
+ componentname :
1662
+ Name of the RLC component.
1663
+ res_value : float, optional
1664
+ Resistance value. The default is ``None``.
1665
+ ind_value : float, optional
1666
+ Inductor value. The default is ``None``.
1667
+ cap_value : float optional
1668
+ Capacitor value. The default is ``None``.
1669
+ isparallel : bool, optional
1670
+ Whether the RLC component is parallel. The default is ``False``.
1671
+
1672
+ Returns
1673
+ -------
1674
+ bool
1675
+ ``True`` when successful, ``False`` when failed.
1676
+
1677
+ Examples
1678
+ --------
1679
+
1680
+ >>> from pyedb import Edb
1681
+ >>> edbapp = Edb("myaedbfolder")
1682
+ >>> edbapp.components.set_component_rlc(
1683
+ ... "R1", res_value=50, ind_value=1e-9, cap_value=1e-12, isparallel=False
1684
+ ... )
1685
+
1686
+ """
1687
+ if res_value is None and ind_value is None and cap_value is None:
1688
+ self.instances[componentname].enabled = False
1689
+ self._logger.info(f"No parameters passed, component {componentname} is disabled.")
1690
+ return True
1691
+ component = self.get_component_by_name(componentname)
1692
+ pin_number = len(component.pins)
1693
+ if pin_number == 2:
1694
+ from_pin = list(component.pins.values())[0]
1695
+ to_pin = list(component.pins.values())[1]
1696
+ rlc = GrpcRlc()
1697
+ rlc.is_parallel = isparallel
1698
+ if res_value is not None:
1699
+ rlc.r_enabled = True
1700
+ rlc.r = GrpcValue(res_value)
1701
+ else:
1702
+ rlc.r_enabled = False
1703
+ if ind_value is not None:
1704
+ rlc.l_enabled = True
1705
+ rlc.l = GrpcValue(ind_value)
1706
+ else:
1707
+ rlc.l_enabled = False
1708
+ if cap_value is not None:
1709
+ rlc.c_enabled = True
1710
+ rlc.c = GrpcValue(cap_value)
1711
+ else:
1712
+ rlc.CEnabled = False
1713
+ pin_pair = (from_pin.name, to_pin.name)
1714
+ component_property = component.component_property
1715
+ model = component_property.model
1716
+ model.set_rlc(pin_pair, rlc)
1717
+ component_property.model = model
1718
+ component.component_property = component_property
1719
+ else:
1720
+ self._logger.warning(
1721
+ f"Component {componentname} has not been assigned because either it is not present in the layout "
1722
+ "or it contains a number of pins not equal to 2."
1723
+ )
1724
+ return False
1725
+ self._logger.info(f"RLC properties for Component {componentname} has been assigned.")
1726
+ return True
1727
+
1728
+ def update_rlc_from_bom(
1729
+ self,
1730
+ bom_file,
1731
+ delimiter=";",
1732
+ valuefield="Func des",
1733
+ comptype="Prod name",
1734
+ refdes="Pos / Place",
1735
+ ):
1736
+ """Update the EDC core component values (RLCs) with values coming from a BOM file.
1737
+
1738
+ Parameters
1739
+ ----------
1740
+ bom_file : str
1741
+ Full path to the BOM file, which is a delimited text file.
1742
+ Header values needed inside the BOM reader must
1743
+ be explicitly set if different from the defaults.
1744
+ delimiter : str, optional
1745
+ Value to use for the delimiter. The default is ``";"``.
1746
+ valuefield : str, optional
1747
+ Field header containing the value of the component. The default is ``"Func des"``.
1748
+ The value for this parameter must being with the value of the component
1749
+ followed by a space and then the rest of the value. For example, ``"22pF"``.
1750
+ comptype : str, optional
1751
+ Field header containing the type of component. The default is ``"Prod name"``. For
1752
+ example, you might enter ``"Inductor"``.
1753
+ refdes : str, optional
1754
+ Field header containing the reference designator of the component. The default is
1755
+ ``"Pos / Place"``. For example, you might enter ``"C100"``.
1756
+
1757
+ Returns
1758
+ -------
1759
+ bool
1760
+ ``True`` if the file contains the header and it is correctly parsed. ``True`` is
1761
+ returned even if no values are assigned.
1762
+
1763
+ """
1764
+ with open(bom_file, "r") as f:
1765
+ Lines = f.readlines()
1766
+ found = False
1767
+ refdescolumn = None
1768
+ comptypecolumn = None
1769
+ valuecolumn = None
1770
+ unmount_comp_list = list(self.instances.keys())
1771
+ for line in Lines:
1772
+ content_line = [i.strip() for i in line.split(delimiter)]
1773
+ if valuefield in content_line:
1774
+ valuecolumn = content_line.index(valuefield)
1775
+ if comptype in content_line:
1776
+ comptypecolumn = content_line.index(comptype)
1777
+ if refdes in content_line:
1778
+ refdescolumn = content_line.index(refdes)
1779
+ elif refdescolumn:
1780
+ found = True
1781
+ new_refdes = content_line[refdescolumn].split(" ")[0]
1782
+ new_value = content_line[valuecolumn].split(" ")[0]
1783
+ new_type = content_line[comptypecolumn]
1784
+ if "resistor" in new_type.lower():
1785
+ self.set_component_rlc(new_refdes, res_value=new_value)
1786
+ unmount_comp_list.remove(new_refdes)
1787
+ elif "capacitor" in new_type.lower():
1788
+ self.set_component_rlc(new_refdes, cap_value=new_value)
1789
+ unmount_comp_list.remove(new_refdes)
1790
+ elif "inductor" in new_type.lower():
1791
+ self.set_component_rlc(new_refdes, ind_value=new_value)
1792
+ unmount_comp_list.remove(new_refdes)
1793
+ for comp in unmount_comp_list:
1794
+ self.instances[comp].enabled = False
1795
+ return found
1796
+
1797
+ def import_bom(
1798
+ self,
1799
+ bom_file,
1800
+ delimiter=",",
1801
+ refdes_col=0,
1802
+ part_name_col=1,
1803
+ comp_type_col=2,
1804
+ value_col=3,
1805
+ ):
1806
+ """Load external BOM file.
1807
+
1808
+ Parameters
1809
+ ----------
1810
+ bom_file : str
1811
+ Full path to the BOM file, which is a delimited text file.
1812
+ delimiter : str, optional
1813
+ Value to use for the delimiter. The default is ``","``.
1814
+ refdes_col : int, optional
1815
+ Column index of reference designator. The default is ``"0"``.
1816
+ part_name_col : int, optional
1817
+ Column index of part name. The default is ``"1"``. Set to ``None`` if
1818
+ the column does not exist.
1819
+ comp_type_col : int, optional
1820
+ Column index of component type. The default is ``"2"``.
1821
+ value_col : int, optional
1822
+ Column index of value. The default is ``"3"``. Set to ``None``
1823
+ if the column does not exist.
1824
+
1825
+ Returns
1826
+ -------
1827
+ bool
1828
+ """
1829
+ with open(bom_file, "r") as f:
1830
+ lines = f.readlines()
1831
+ unmount_comp_list = list(self.instances.keys())
1832
+ for l in lines[1:]:
1833
+ l = l.replace(" ", "").replace("\n", "")
1834
+ if not l:
1835
+ continue
1836
+ l = l.split(delimiter)
1837
+
1838
+ refdes = l[refdes_col]
1839
+ comp = self.instances[refdes]
1840
+ if not part_name_col == None:
1841
+ part_name = l[part_name_col]
1842
+ if comp.partname == part_name:
1843
+ pass
1844
+ else:
1845
+ pinlist = self._pedb.padstacks.get_instances(refdes)
1846
+ if not part_name in self.definitions:
1847
+ comp_def = ComponentDef.create(self._db, part_name, None)
1848
+ # for pin in range(len(pinlist)):
1849
+ # ComponentPin.create(comp_def, str(pin))
1850
+
1851
+ p_layer = comp.placement_layer
1852
+ refdes_temp = comp.refdes + "_temp"
1853
+ comp.refdes = refdes_temp
1854
+
1855
+ unmount_comp_list.remove(refdes)
1856
+ comp.ungroup(True)
1857
+ self.create(pinlist, refdes, p_layer, part_name)
1858
+ self.refresh_components()
1859
+ comp = self.instances[refdes]
1860
+
1861
+ comp_type = l[comp_type_col]
1862
+ if comp_type.capitalize() in ["Resistor", "Capacitor", "Inductor", "Other"]:
1863
+ comp.type = comp_type.capitalize()
1864
+ else:
1865
+ comp.type = comp_type.upper()
1866
+
1867
+ if comp_type.capitalize() in ["Resistor", "Capacitor", "Inductor"] and refdes in unmount_comp_list:
1868
+ unmount_comp_list.remove(refdes)
1869
+ if not value_col == None:
1870
+ try:
1871
+ value = l[value_col]
1872
+ except:
1873
+ value = None
1874
+ if value:
1875
+ if comp_type == "Resistor":
1876
+ self.set_component_rlc(refdes, res_value=value)
1877
+ elif comp_type == "Capacitor":
1878
+ self.set_component_rlc(refdes, cap_value=value)
1879
+ elif comp_type == "Inductor":
1880
+ self.set_component_rlc(refdes, ind_value=value)
1881
+ for comp in unmount_comp_list:
1882
+ self.instances[comp].enabled = False
1883
+ return True
1884
+
1885
+ def export_bom(self, bom_file, delimiter=","):
1886
+ """Export Bom file from layout.
1887
+
1888
+ Parameters
1889
+ ----------
1890
+ bom_file : str
1891
+ Full path to the BOM file, which is a delimited text file.
1892
+ delimiter : str, optional
1893
+ Value to use for the delimiter. The default is ``","``.
1894
+ """
1895
+ with open(bom_file, "w") as f:
1896
+ f.writelines([delimiter.join(["RefDes", "Part name", "Type", "Value\n"])])
1897
+ for refdes, comp in self.instances.items():
1898
+ if not comp.is_enabled and comp.type in ["Resistor", "Capacitor", "Inductor"]:
1899
+ continue
1900
+ part_name = comp.partname
1901
+ comp_type = comp.type
1902
+ if comp_type == "Resistor":
1903
+ value = comp.res_value
1904
+ elif comp_type == "Capacitor":
1905
+ value = comp.cap_value
1906
+ elif comp_type == "Inductor":
1907
+ value = comp.ind_value
1908
+ else:
1909
+ value = ""
1910
+ if not value:
1911
+ value = ""
1912
+ f.writelines([delimiter.join([refdes, part_name, comp_type, value + "\n"])])
1913
+ return True
1914
+
1915
+ def find_by_reference_designator(self, reference_designator):
1916
+ """Find a component.
1917
+
1918
+ Parameters
1919
+ ----------
1920
+ reference_designator : str
1921
+ Reference designator of the component.
1922
+ """
1923
+ return self.instances[reference_designator]
1924
+
1925
+ def get_aedt_pin_name(self, pin):
1926
+ """Retrieve the pin name that is shown in AEDT.
1927
+
1928
+ .. note::
1929
+ To obtain the EDB core pin name, use `pin.GetName()`.
1930
+
1931
+ Parameters
1932
+ ----------
1933
+ pin : str
1934
+ Name of the pin in EDB core.
1935
+
1936
+ Returns
1937
+ -------
1938
+ str
1939
+ Name of the pin in AEDT.
1940
+
1941
+ Examples
1942
+ --------
1943
+
1944
+ >>> from pyedb import Edb
1945
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
1946
+ >>> edbapp.components.get_aedt_pin_name(pin)
1947
+
1948
+ """
1949
+ return pin.aedt_name
1950
+
1951
+ def get_pins(self, reference_designator, net_name=None, pin_name=None):
1952
+ """Get component pins.
1953
+
1954
+ Parameters
1955
+ ----------
1956
+ reference_designator : str
1957
+ Reference designator of the component.
1958
+ net_name : str, optional
1959
+ Name of the net.
1960
+ pin_name : str, optional
1961
+ Name of the pin.
1962
+
1963
+ Returns
1964
+ -------
1965
+
1966
+ """
1967
+ comp = self.find_by_reference_designator(reference_designator)
1968
+
1969
+ pins = comp.pins
1970
+ if net_name:
1971
+ pins = {i: j for i, j in pins.items() if j.net_name == net_name}
1972
+
1973
+ if pin_name:
1974
+ pins = {i: j for i, j in pins.items() if i == pin_name}
1975
+
1976
+ return pins
1977
+
1978
+ def get_pin_position(self, pin):
1979
+ """Retrieve the pin position in meters.
1980
+
1981
+ Parameters
1982
+ ----------
1983
+ pin : str
1984
+ Name of the pin.
1985
+
1986
+ Returns
1987
+ -------
1988
+ list
1989
+ Pin position as a list of float values in the form ``[x, y]``.
1990
+
1991
+ Examples
1992
+ --------
1993
+
1994
+ >>> from pyedb import Edb
1995
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
1996
+ >>> edbapp.components.get_pin_position(pin)
1997
+
1998
+ """
1999
+
2000
+ pt_pos = pin.position
2001
+ if pin.component.is_null:
2002
+ transformed_pt_pos = pt_pos
2003
+ else:
2004
+ transformed_pt_pos = pin.component.transform.transform_point(pt_pos)
2005
+ return [transformed_pt_pos[0].value, transformed_pt_pos[1].value]
2006
+
2007
+ def get_pins_name_from_net(self, net_name, pin_list=None):
2008
+ """Retrieve pins belonging to a net.
2009
+
2010
+ Parameters
2011
+ ----------
2012
+ pin_list : list of EDBPadstackInstance, optional
2013
+ List of pins to check. The default is ``None``, in which case all pins are checked
2014
+ net_name : str
2015
+ Name of the net.
2016
+
2017
+ Returns
2018
+ -------
2019
+ list of str names:
2020
+ Pins belonging to the net.
2021
+
2022
+ Examples
2023
+ --------
2024
+
2025
+ >>> from pyedb import Edb
2026
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
2027
+ >>> edbapp.components.get_pins_name_from_net(pin_list, net_name)
2028
+
2029
+ """
2030
+ pin_names = []
2031
+ if not pin_list:
2032
+ pin_list = []
2033
+ for i in [*self.components.values()]:
2034
+ for j in [*i.pins.values()]:
2035
+ pin_list.append(j)
2036
+ for pin in pin_list:
2037
+ if not pin.net.is_null:
2038
+ if pin.net.name == net_name:
2039
+ pin_names.append(self.get_aedt_pin_name(pin))
2040
+ return pin_names
2041
+
2042
+ def get_nets_from_pin_list(self, pins):
2043
+ """Retrieve nets with one or more pins.
2044
+
2045
+ Parameters
2046
+ ----------
2047
+ PinList : list
2048
+ List of pins.
2049
+
2050
+ Returns
2051
+ -------
2052
+ list
2053
+ List of nets with one or more pins.
2054
+
2055
+ Examples
2056
+ --------
2057
+
2058
+ >>> from pyedb import Edb
2059
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
2060
+ >>> edbapp.components.get_nets_from_pin_list(pins)
2061
+
2062
+ """
2063
+ return list(set([pin.net.name for pin in pins]))
2064
+
2065
+ def get_component_net_connection_info(self, refdes):
2066
+ """Retrieve net connection information.
2067
+
2068
+ Parameters
2069
+ ----------
2070
+ refdes :
2071
+ Reference designator for the net.
2072
+
2073
+ Returns
2074
+ -------
2075
+ dict
2076
+ Dictionary of the net connection information for the reference designator.
2077
+
2078
+ Examples
2079
+ --------
2080
+
2081
+ >>> from pyedb import Edb
2082
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
2083
+ >>> edbapp.components.get_component_net_connection_info(refdes)
2084
+
2085
+ """
2086
+ data = {"refdes": [], "pin_name": [], "net_name": []}
2087
+ for _, pin_obj in self.instances[refdes].pins.items():
2088
+ pin_name = pin_obj.name
2089
+ if not pin_obj.net.is_null:
2090
+ net_name = pin_obj.net.name
2091
+ if pin_name:
2092
+ data["refdes"].append(refdes)
2093
+ data["pin_name"].append(pin_name)
2094
+ data["net_name"].append(net_name)
2095
+ return data
2096
+
2097
+ def get_rats(self):
2098
+ """Retrieve a list of dictionaries of the reference designator, pin names, and net names.
2099
+
2100
+ Returns
2101
+ -------
2102
+ list
2103
+ List of dictionaries of the reference designator, pin names,
2104
+ and net names.
2105
+
2106
+ Examples
2107
+ --------
2108
+
2109
+ >>> from pyedb import Edb
2110
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
2111
+ >>> edbapp.components.get_rats()
2112
+
2113
+ """
2114
+ df_list = []
2115
+ for refdes in self.instances.keys():
2116
+ df = self.get_component_net_connection_info(refdes)
2117
+ df_list.append(df)
2118
+ return df_list
2119
+
2120
+ def get_through_resistor_list(self, threshold=1):
2121
+ """Retrieve through resistors.
2122
+
2123
+ Parameters
2124
+ ----------
2125
+ threshold : int, optional
2126
+ Threshold value. The default is ``1``.
2127
+
2128
+ Returns
2129
+ -------
2130
+ list
2131
+ List of through resistors.
2132
+
2133
+ Examples
2134
+ --------
2135
+
2136
+ >>> from pyedb import Edb
2137
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
2138
+ >>> edbapp.components.get_through_resistor_list()
2139
+
2140
+ """
2141
+ through_comp_list = []
2142
+ for refdes, comp_obj in self.resistors.items():
2143
+ numpins = comp_obj.numpins
2144
+
2145
+ if numpins == 2:
2146
+ value = comp_obj.res_value
2147
+ value = resistor_value_parser(value)
2148
+
2149
+ if value <= threshold:
2150
+ through_comp_list.append(refdes)
2151
+
2152
+ return through_comp_list
2153
+
2154
+ def short_component_pins(self, component_name, pins_to_short=None, width=1e-3):
2155
+ """Short pins of component with a trace.
2156
+
2157
+ Parameters
2158
+ ----------
2159
+ component_name : str
2160
+ Name of the component.
2161
+ pins_to_short : list, optional
2162
+ List of pins to short. If `None`, all pins will be shorted.
2163
+ width : float, optional
2164
+ Short Trace width. It will be used in trace computation algorithm
2165
+
2166
+ Returns
2167
+ -------
2168
+ bool
2169
+ ``True`` when successful, ``False`` when failed.
2170
+
2171
+ Examples
2172
+ --------
2173
+
2174
+ >>> from pyedb import Edb
2175
+ >>> edbapp = Edb("myaedbfolder")
2176
+ >>> edbapp.components.short_component_pins("J4A2", ["G4", "9", "3"])
2177
+
2178
+ """
2179
+ component = self.instances[component_name]
2180
+ pins = component.pins
2181
+ pins_list = []
2182
+
2183
+ for pin_name, pin in pins.items():
2184
+ if pins_to_short:
2185
+ if pin_name in pins_to_short:
2186
+ pins_list.append(pin)
2187
+ else:
2188
+ pins_list.append(pin)
2189
+ positions_to_short = []
2190
+ center = component.center
2191
+ c = [center[0], center[1], 0]
2192
+ delta_pins = []
2193
+ w = width
2194
+ for pin in pins_list:
2195
+ placement_layer = pin.placement_layer
2196
+ positions_to_short.append(pin.position)
2197
+ if placement_layer in self._pedb.padstacks.definitions[pin.padstack_def.name].pad_by_layer:
2198
+ pad = self._pedb.padstacks.definitions[pin.padstack_def.name].pad_by_layer[placement_layer]
2199
+ else:
2200
+ layer = list(self._pedb.padstacks.definitions[pin.padstack_def.name].pad_by_layer.keys())[0]
2201
+ pad = self._pedb.padstacks.definitions[pin.padstack_def.name].pad_by_layer[layer]
2202
+ pars = pad.parameters_values
2203
+ if pad.geometry_type < 6 and pars:
2204
+ delta_pins.append(max(pars) + min(pars) / 2)
2205
+ w = min(min(pars), w)
2206
+ elif pars:
2207
+ delta_pins.append(1.5 * pars[0])
2208
+ w = min(pars[0], w)
2209
+ elif pad.polygon_data: # pragma: no cover
2210
+ bbox = pad.polygon_data.bbox()
2211
+ lower = [bbox[0].x.value, bbox[0].y.value]
2212
+ upper = [bbox[1].x.value, bbox[1].y.value]
2213
+ pars = [abs(lower[0] - upper[0]), abs(lower[1] - upper[1])]
2214
+ delta_pins.append(max(pars) + min(pars) / 2)
2215
+ w = min(min(pars), w)
2216
+ else:
2217
+ delta_pins.append(1.5 * width)
2218
+ i = 0
2219
+
2220
+ while i < len(positions_to_short) - 1:
2221
+ p0 = []
2222
+ p0.append([positions_to_short[i][0] - delta_pins[i], positions_to_short[i][1], 0])
2223
+ p0.append([positions_to_short[i][0] + delta_pins[i], positions_to_short[i][1], 0])
2224
+ p0.append([positions_to_short[i][0], positions_to_short[i][1] - delta_pins[i], 0])
2225
+ p0.append([positions_to_short[i][0], positions_to_short[i][1] + delta_pins[i], 0])
2226
+ p0.append([positions_to_short[i][0], positions_to_short[i][1], 0])
2227
+ l0 = [
2228
+ GeometryOperators.points_distance(p0[0], c),
2229
+ GeometryOperators.points_distance(p0[1], c),
2230
+ GeometryOperators.points_distance(p0[2], c),
2231
+ GeometryOperators.points_distance(p0[3], c),
2232
+ GeometryOperators.points_distance(p0[4], c),
2233
+ ]
2234
+ l0_min = l0.index(min(l0))
2235
+ p1 = []
2236
+ p1.append(
2237
+ [
2238
+ positions_to_short[i + 1][0] - delta_pins[i + 1],
2239
+ positions_to_short[i + 1][1],
2240
+ 0,
2241
+ ]
2242
+ )
2243
+ p1.append(
2244
+ [
2245
+ positions_to_short[i + 1][0] + delta_pins[i + 1],
2246
+ positions_to_short[i + 1][1],
2247
+ 0,
2248
+ ]
2249
+ )
2250
+ p1.append(
2251
+ [
2252
+ positions_to_short[i + 1][0],
2253
+ positions_to_short[i + 1][1] - delta_pins[i + 1],
2254
+ 0,
2255
+ ]
2256
+ )
2257
+ p1.append(
2258
+ [
2259
+ positions_to_short[i + 1][0],
2260
+ positions_to_short[i + 1][1] + delta_pins[i + 1],
2261
+ 0,
2262
+ ]
2263
+ )
2264
+ p1.append([positions_to_short[i + 1][0], positions_to_short[i + 1][1], 0])
2265
+
2266
+ l1 = [
2267
+ GeometryOperators.points_distance(p1[0], c),
2268
+ GeometryOperators.points_distance(p1[1], c),
2269
+ GeometryOperators.points_distance(p1[2], c),
2270
+ GeometryOperators.points_distance(p1[3], c),
2271
+ GeometryOperators.points_distance(p1[4], c),
2272
+ ]
2273
+ l1_min = l1.index(min(l1))
2274
+
2275
+ trace_points = [positions_to_short[i]]
2276
+
2277
+ trace_points.append(p0[l0_min][:2])
2278
+ trace_points.append(c[:2])
2279
+ trace_points.append(p1[l1_min][:2])
2280
+
2281
+ trace_points.append(positions_to_short[i + 1])
2282
+
2283
+ self._pedb.modeler.create_trace(
2284
+ trace_points,
2285
+ layer_name=placement_layer,
2286
+ net_name="short",
2287
+ width=w,
2288
+ start_cap_style="Flat",
2289
+ end_cap_style="Flat",
2290
+ )
2291
+ i += 1
2292
+ return True
2293
+
2294
+ def create_pin_group(self, reference_designator, pin_numbers, group_name=None):
2295
+ """Create pin group on the component.
2296
+
2297
+ Parameters
2298
+ ----------
2299
+ reference_designator : str
2300
+ References designator of the component.
2301
+ pin_numbers : int, str, list[str] or list[:class: `PadstackInstance]`
2302
+ List of pins.
2303
+ group_name : str, optional
2304
+ Name of the pin group.
2305
+
2306
+ Returns
2307
+ -------
2308
+ PinGroup
2309
+ """
2310
+ if not isinstance(pin_numbers, list):
2311
+ pin_numbers = [pin_numbers]
2312
+ pin_numbers = [str(p) for p in pin_numbers]
2313
+ if group_name is None:
2314
+ group_name = PinGroup.unique_name(self._active_layout, "")
2315
+ comp = self.instances[reference_designator]
2316
+ pins = [pin for pin_name, pin in comp.pins.items() if pin_name in pin_numbers]
2317
+ if not pins:
2318
+ pins = [pin for pin_name, pin in comp.pins.items() if pin.name in pin_numbers]
2319
+ if not pins:
2320
+ self._pedb.logger.error("No pin found to create pin group")
2321
+ return False
2322
+ pingroup = PinGroup.create(self._active_layout, group_name, pins)
2323
+
2324
+ if pingroup.is_null: # pragma: no cover
2325
+ self._logger.error(f"Failed to create pin group {group_name}.")
2326
+ return False
2327
+ else:
2328
+ for pin in pins:
2329
+ if not pin.net.is_null:
2330
+ if pin.net.name:
2331
+ pingroup.net = pin.net
2332
+ return group_name
2333
+ return False
2334
+
2335
+ def create_pin_group_on_net(self, reference_designator, net_name, group_name=None):
2336
+ """Create pin group on component by net name.
2337
+
2338
+ Parameters
2339
+ ----------
2340
+ reference_designator : str
2341
+ References designator of the component.
2342
+ net_name : str
2343
+ Name of the net.
2344
+ group_name : str, optional
2345
+ Name of the pin group. The default value is ``None``.
2346
+
2347
+ Returns
2348
+ -------
2349
+ PinGroup
2350
+ """
2351
+ pins = [
2352
+ pin.name for pin in list(self.instances[reference_designator].pins.values()) if pin.net_name == net_name
2353
+ ]
2354
+ return self.create_pin_group(reference_designator, pins, group_name)