pyedb 0.59.0__py3-none-any.whl → 0.60.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 (308) hide show
  1. pyedb/__init__.py +23 -1
  2. pyedb/common/__init__.py +21 -0
  3. pyedb/common/nets.py +22 -0
  4. pyedb/component_libraries/ansys_components.py +22 -0
  5. pyedb/configuration/__init__.py +21 -0
  6. pyedb/configuration/cfg_boundaries.py +1 -1
  7. pyedb/configuration/cfg_common.py +1 -1
  8. pyedb/configuration/cfg_components.py +1 -1
  9. pyedb/configuration/cfg_data.py +1 -1
  10. pyedb/configuration/cfg_general.py +1 -1
  11. pyedb/configuration/cfg_modeler.py +1 -1
  12. pyedb/configuration/cfg_nets.py +1 -1
  13. pyedb/configuration/cfg_operations.py +1 -1
  14. pyedb/configuration/cfg_package_definition.py +1 -1
  15. pyedb/configuration/cfg_padstacks.py +1 -1
  16. pyedb/configuration/cfg_pin_groups.py +1 -1
  17. pyedb/configuration/cfg_ports_sources.py +3 -2
  18. pyedb/configuration/cfg_s_parameter_models.py +1 -1
  19. pyedb/configuration/cfg_setup.py +5 -1
  20. pyedb/configuration/cfg_spice_models.py +1 -1
  21. pyedb/configuration/cfg_stackup.py +1 -1
  22. pyedb/configuration/cfg_terminals.py +22 -0
  23. pyedb/configuration/configuration.py +6 -5
  24. pyedb/dotnet/__init__.py +21 -0
  25. pyedb/dotnet/clr_module.py +22 -0
  26. pyedb/dotnet/database/Variables.py +1 -1
  27. pyedb/dotnet/database/__init__.py +22 -0
  28. pyedb/dotnet/database/cell/__init__.py +21 -0
  29. pyedb/dotnet/database/cell/connectable.py +1 -1
  30. pyedb/dotnet/database/cell/hierarchy/__init__.py +21 -0
  31. pyedb/dotnet/database/cell/hierarchy/component.py +1 -1
  32. pyedb/dotnet/database/cell/hierarchy/hierarchy_obj.py +1 -1
  33. pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
  34. pyedb/dotnet/database/cell/hierarchy/netlist_model.py +1 -1
  35. pyedb/dotnet/database/cell/hierarchy/pin_pair_model.py +1 -1
  36. pyedb/dotnet/database/cell/hierarchy/s_parameter_model.py +1 -1
  37. pyedb/dotnet/database/cell/hierarchy/spice_model.py +1 -1
  38. pyedb/dotnet/database/cell/layout.py +5 -4
  39. pyedb/dotnet/database/cell/layout_obj.py +1 -1
  40. pyedb/dotnet/database/cell/primitive/__init__.py +22 -0
  41. pyedb/dotnet/database/cell/primitive/bondwire.py +1 -1
  42. pyedb/dotnet/database/cell/primitive/path.py +1 -1
  43. pyedb/dotnet/database/cell/primitive/primitive.py +1 -1
  44. pyedb/dotnet/database/cell/terminal/__init__.py +21 -0
  45. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +1 -1
  46. pyedb/dotnet/database/cell/terminal/edge_terminal.py +1 -1
  47. pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
  48. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  49. pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
  50. pyedb/dotnet/database/cell/terminal/terminal.py +7 -2
  51. pyedb/dotnet/database/cell/voltage_regulator.py +1 -1
  52. pyedb/dotnet/database/components.py +1 -1
  53. pyedb/dotnet/database/definition/__init__.py +21 -0
  54. pyedb/dotnet/database/definition/component_def.py +1 -1
  55. pyedb/dotnet/database/definition/component_model.py +1 -1
  56. pyedb/dotnet/database/definition/definition_obj.py +1 -1
  57. pyedb/dotnet/database/definition/definitions.py +1 -1
  58. pyedb/dotnet/database/definition/package_def.py +1 -1
  59. pyedb/dotnet/database/dotnet/__init__.py +21 -0
  60. pyedb/dotnet/database/dotnet/database.py +1 -1
  61. pyedb/dotnet/database/dotnet/primitive.py +1 -1
  62. pyedb/dotnet/database/edb_data/__init__.py +21 -0
  63. pyedb/dotnet/database/edb_data/control_file.py +1 -1
  64. pyedb/dotnet/database/edb_data/design_options.py +1 -1
  65. pyedb/dotnet/database/edb_data/edbvalue.py +1 -1
  66. pyedb/dotnet/database/edb_data/hfss_extent_info.py +1 -1
  67. pyedb/dotnet/database/edb_data/layer_data.py +1 -1
  68. pyedb/dotnet/database/edb_data/nets_data.py +1 -1
  69. pyedb/dotnet/database/edb_data/padstacks_data.py +1 -1
  70. pyedb/dotnet/database/edb_data/ports.py +1 -1
  71. pyedb/dotnet/database/edb_data/primitives_data.py +1 -1
  72. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +1 -1
  73. pyedb/dotnet/database/edb_data/simulation_configuration.py +1 -1
  74. pyedb/dotnet/database/edb_data/sources.py +1 -1
  75. pyedb/dotnet/database/edb_data/utilities.py +1 -1
  76. pyedb/dotnet/database/edb_data/variables.py +1 -1
  77. pyedb/dotnet/database/general.py +1 -1
  78. pyedb/dotnet/database/geometry/__init__.py +21 -0
  79. pyedb/dotnet/database/geometry/point_data.py +1 -1
  80. pyedb/dotnet/database/geometry/polygon_data.py +1 -1
  81. pyedb/dotnet/database/hfss.py +1 -1
  82. pyedb/dotnet/database/layout_obj_instance.py +1 -1
  83. pyedb/dotnet/database/layout_validation.py +1 -1
  84. pyedb/dotnet/database/materials.py +1 -1
  85. pyedb/dotnet/database/modeler.py +1 -1
  86. pyedb/dotnet/database/net_class.py +1 -1
  87. pyedb/dotnet/database/nets.py +1 -1
  88. pyedb/dotnet/database/padstack.py +1 -1
  89. pyedb/dotnet/database/sim_setup_data/__init__.py +22 -0
  90. pyedb/dotnet/database/sim_setup_data/data/__init__.py +22 -0
  91. pyedb/dotnet/database/sim_setup_data/data/adaptive_frequency_data.py +1 -1
  92. pyedb/dotnet/database/sim_setup_data/data/mesh_operation.py +1 -1
  93. pyedb/dotnet/database/sim_setup_data/data/settings.py +1 -1
  94. pyedb/dotnet/database/sim_setup_data/data/sim_setup_info.py +1 -1
  95. pyedb/dotnet/database/sim_setup_data/data/simulation_settings.py +1 -1
  96. pyedb/dotnet/database/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
  97. pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +1 -1
  98. pyedb/dotnet/database/sim_setup_data/io/__init__.py +21 -0
  99. pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
  100. pyedb/dotnet/database/siwave.py +1 -1
  101. pyedb/dotnet/database/stackup.py +1 -1
  102. pyedb/dotnet/database/utilities/__init__.py +22 -0
  103. pyedb/dotnet/database/utilities/heatsink.py +23 -0
  104. pyedb/dotnet/database/utilities/hfss_simulation_setup.py +1 -1
  105. pyedb/dotnet/database/utilities/obj_base.py +1 -1
  106. pyedb/dotnet/database/utilities/simulation_setup.py +1 -1
  107. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +22 -0
  108. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +22 -0
  109. pyedb/dotnet/database/utilities/value.py +1 -1
  110. pyedb/dotnet/edb.py +49 -122
  111. pyedb/edb_logger.py +1 -1
  112. pyedb/exceptions.py +22 -0
  113. pyedb/extensions/__init__.py +21 -0
  114. pyedb/extensions/create_cell_array.py +1 -1
  115. pyedb/extensions/via_design_backend.py +22 -0
  116. pyedb/generic/__init__.py +21 -0
  117. pyedb/generic/constants.py +1 -1
  118. pyedb/generic/data_handlers.py +22 -0
  119. pyedb/generic/design_types.py +1 -1
  120. pyedb/generic/filesystem.py +22 -0
  121. pyedb/generic/general_methods.py +1 -1
  122. pyedb/generic/grpc_warnings.py +22 -0
  123. pyedb/generic/plot.py +22 -0
  124. pyedb/generic/process.py +29 -2
  125. pyedb/generic/settings.py +1 -1
  126. pyedb/grpc/__init__.py +21 -0
  127. pyedb/grpc/database/__init__.py +21 -0
  128. pyedb/grpc/database/_typing.py +21 -0
  129. pyedb/grpc/database/components.py +9 -8
  130. pyedb/grpc/database/control_file.py +1 -1
  131. pyedb/grpc/database/definition/__init__.py +21 -0
  132. pyedb/grpc/database/definition/component_def.py +1 -1
  133. pyedb/grpc/database/definition/component_model.py +1 -1
  134. pyedb/grpc/database/definition/component_pin.py +1 -1
  135. pyedb/grpc/database/definition/materials.py +1 -1
  136. pyedb/grpc/database/definition/n_port_component_model.py +1 -1
  137. pyedb/grpc/database/definition/package_def.py +1 -1
  138. pyedb/grpc/database/definition/padstack_def.py +1 -1
  139. pyedb/grpc/database/definitions.py +1 -1
  140. pyedb/grpc/database/general.py +1 -1
  141. pyedb/grpc/database/geometry/__init__.py +21 -0
  142. pyedb/grpc/database/geometry/arc_data.py +1 -1
  143. pyedb/grpc/database/geometry/point_3d_data.py +1 -1
  144. pyedb/grpc/database/geometry/point_data.py +1 -1
  145. pyedb/grpc/database/geometry/polygon_data.py +1 -1
  146. pyedb/grpc/database/hfss.py +1 -1
  147. pyedb/grpc/database/hierarchy/__init__.py +21 -0
  148. pyedb/grpc/database/hierarchy/component.py +1 -1
  149. pyedb/grpc/database/hierarchy/model.py +1 -1
  150. pyedb/grpc/database/hierarchy/netlist_model.py +1 -1
  151. pyedb/grpc/database/hierarchy/pin_pair_model.py +1 -1
  152. pyedb/grpc/database/hierarchy/pingroup.py +1 -1
  153. pyedb/grpc/database/hierarchy/s_parameter_model.py +1 -1
  154. pyedb/grpc/database/hierarchy/spice_model.py +1 -1
  155. pyedb/grpc/database/layers/__init__.py +21 -0
  156. pyedb/grpc/database/layers/layer.py +22 -0
  157. pyedb/grpc/database/layers/stackup_layer.py +1 -1
  158. pyedb/grpc/database/layout/__init__.py +21 -0
  159. pyedb/grpc/database/layout/cell.py +1 -1
  160. pyedb/grpc/database/layout/layout.py +1 -1
  161. pyedb/grpc/database/layout/voltage_regulator.py +1 -1
  162. pyedb/grpc/database/layout_validation.py +1 -1
  163. pyedb/grpc/database/modeler.py +31 -9
  164. pyedb/grpc/database/net/__init__.py +21 -0
  165. pyedb/grpc/database/net/differential_pair.py +1 -1
  166. pyedb/grpc/database/net/extended_net.py +1 -1
  167. pyedb/grpc/database/net/net.py +1 -1
  168. pyedb/grpc/database/net/net_class.py +1 -1
  169. pyedb/grpc/database/nets.py +1 -1
  170. pyedb/grpc/database/padstacks.py +8 -3
  171. pyedb/grpc/database/ports/__init__.py +21 -0
  172. pyedb/grpc/database/ports/ports.py +1 -1
  173. pyedb/grpc/database/primitive/__init__.py +22 -0
  174. pyedb/grpc/database/primitive/bondwire.py +1 -1
  175. pyedb/grpc/database/primitive/circle.py +1 -1
  176. pyedb/grpc/database/primitive/padstack_instance.py +21 -16
  177. pyedb/grpc/database/primitive/path.py +1 -1
  178. pyedb/grpc/database/primitive/polygon.py +6 -4
  179. pyedb/grpc/database/primitive/primitive.py +1 -6
  180. pyedb/grpc/database/primitive/rectangle.py +1 -1
  181. pyedb/grpc/database/simulation_setup/__init__.py +21 -0
  182. pyedb/grpc/database/simulation_setup/adaptive_frequency.py +1 -1
  183. pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +1 -1
  184. pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +1 -1
  185. pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +1 -1
  186. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +1 -1
  187. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +1 -1
  188. pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +1 -1
  189. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +1 -1
  190. pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +1 -1
  191. pyedb/grpc/database/simulation_setup/mesh_operation.py +1 -1
  192. pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +1 -1
  193. pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +1 -1
  194. pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +1 -1
  195. pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +1 -1
  196. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +22 -0
  197. pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +1 -1
  198. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +1 -1
  199. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -1
  200. pyedb/grpc/database/siwave.py +1 -1
  201. pyedb/grpc/database/source_excitations.py +1 -1
  202. pyedb/grpc/database/stackup.py +1 -1
  203. pyedb/grpc/database/terminal/__init__.py +21 -0
  204. pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
  205. pyedb/grpc/database/terminal/edge_terminal.py +1 -1
  206. pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
  207. pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
  208. pyedb/grpc/database/terminal/point_terminal.py +1 -1
  209. pyedb/grpc/database/terminal/terminal.py +1 -1
  210. pyedb/grpc/database/utility/__init__.py +22 -0
  211. pyedb/grpc/database/utility/constants.py +1 -1
  212. pyedb/grpc/database/utility/heat_sink.py +1 -1
  213. pyedb/grpc/database/utility/hfss_extent_info.py +1 -1
  214. pyedb/grpc/database/utility/layout_statistics.py +1 -1
  215. pyedb/grpc/database/utility/rlc.py +1 -1
  216. pyedb/grpc/database/utility/sources.py +1 -1
  217. pyedb/grpc/database/utility/sweep_data_distribution.py +1 -1
  218. pyedb/grpc/database/utility/value.py +1 -1
  219. pyedb/grpc/database/utility/xml_control_file.py +1 -1
  220. pyedb/grpc/edb.py +160 -989
  221. pyedb/grpc/edb_init.py +1 -1
  222. pyedb/grpc/rpc_session.py +1 -1
  223. pyedb/ipc2581/__init__.py +21 -0
  224. pyedb/ipc2581/bom/__init__.py +21 -0
  225. pyedb/ipc2581/bom/bom.py +1 -1
  226. pyedb/ipc2581/bom/bom_item.py +1 -1
  227. pyedb/ipc2581/bom/characteristics.py +1 -1
  228. pyedb/ipc2581/bom/refdes.py +1 -1
  229. pyedb/ipc2581/content/__init__.py +21 -0
  230. pyedb/ipc2581/content/color.py +1 -1
  231. pyedb/ipc2581/content/content.py +1 -1
  232. pyedb/ipc2581/content/dictionary_color.py +1 -1
  233. pyedb/ipc2581/content/dictionary_fill.py +1 -1
  234. pyedb/ipc2581/content/dictionary_line.py +1 -1
  235. pyedb/ipc2581/content/entry_color.py +1 -1
  236. pyedb/ipc2581/content/entry_line.py +1 -1
  237. pyedb/ipc2581/content/fill.py +1 -1
  238. pyedb/ipc2581/content/layer_ref.py +1 -1
  239. pyedb/ipc2581/content/standard_geometries_dictionary.py +1 -1
  240. pyedb/ipc2581/ecad/__init__.py +21 -0
  241. pyedb/ipc2581/ecad/cad_data/__init__.py +21 -0
  242. pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +1 -1
  243. pyedb/ipc2581/ecad/cad_data/cad_data.py +1 -1
  244. pyedb/ipc2581/ecad/cad_data/component.py +1 -1
  245. pyedb/ipc2581/ecad/cad_data/drill.py +1 -1
  246. pyedb/ipc2581/ecad/cad_data/feature.py +1 -1
  247. pyedb/ipc2581/ecad/cad_data/layer.py +1 -1
  248. pyedb/ipc2581/ecad/cad_data/layer_feature.py +1 -1
  249. pyedb/ipc2581/ecad/cad_data/logical_net.py +1 -1
  250. pyedb/ipc2581/ecad/cad_data/outline.py +1 -1
  251. pyedb/ipc2581/ecad/cad_data/package.py +1 -1
  252. pyedb/ipc2581/ecad/cad_data/padstack_def.py +1 -1
  253. pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +1 -1
  254. pyedb/ipc2581/ecad/cad_data/padstack_instance.py +1 -1
  255. pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +1 -1
  256. pyedb/ipc2581/ecad/cad_data/path.py +1 -1
  257. pyedb/ipc2581/ecad/cad_data/phy_net.py +1 -1
  258. pyedb/ipc2581/ecad/cad_data/pin.py +1 -1
  259. pyedb/ipc2581/ecad/cad_data/polygon.py +1 -1
  260. pyedb/ipc2581/ecad/cad_data/profile.py +1 -1
  261. pyedb/ipc2581/ecad/cad_data/stackup.py +1 -1
  262. pyedb/ipc2581/ecad/cad_data/stackup_group.py +1 -1
  263. pyedb/ipc2581/ecad/cad_data/stackup_layer.py +1 -1
  264. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  265. pyedb/ipc2581/ecad/cad_header.py +1 -1
  266. pyedb/ipc2581/ecad/ecad.py +1 -1
  267. pyedb/ipc2581/ecad/spec.py +1 -1
  268. pyedb/ipc2581/history_record.py +1 -1
  269. pyedb/ipc2581/ipc2581.py +1 -1
  270. pyedb/ipc2581/logistic_header.py +1 -1
  271. pyedb/libraries/common.py +1 -1
  272. pyedb/libraries/rf_libraries/base_functions.py +1 -1
  273. pyedb/libraries/rf_libraries/planar_antennas.py +1 -1
  274. pyedb/misc/__init__.py +21 -0
  275. pyedb/misc/aedtlib_personalib_install.py +1 -1
  276. pyedb/misc/decorators.py +22 -0
  277. pyedb/misc/downloads.py +1 -1
  278. pyedb/misc/misc.py +1 -1
  279. pyedb/misc/siw_feature_config/__init__.py +21 -0
  280. pyedb/misc/siw_feature_config/emc/__init__.py +21 -0
  281. pyedb/misc/siw_feature_config/emc/component_tags.py +22 -0
  282. pyedb/misc/siw_feature_config/emc/net_tags.py +22 -0
  283. pyedb/misc/siw_feature_config/emc/tag_library.py +22 -0
  284. pyedb/misc/siw_feature_config/emc/xml_generic.py +22 -0
  285. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
  286. pyedb/misc/siw_feature_config/xtalk_scan/fd_xtalk_scan_config.py +1 -1
  287. pyedb/misc/siw_feature_config/xtalk_scan/impedance_scan_config.py +1 -1
  288. pyedb/misc/siw_feature_config/xtalk_scan/net.py +1 -1
  289. pyedb/misc/siw_feature_config/xtalk_scan/pins.py +1 -1
  290. pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +1 -1
  291. pyedb/misc/siw_feature_config/xtalk_scan/td_xtalk_config.py +1 -1
  292. pyedb/misc/utilities.py +1 -1
  293. pyedb/modeler/geometry_operators.py +22 -0
  294. pyedb/siwave.py +22 -0
  295. pyedb/siwave_core/__init__.py +21 -0
  296. pyedb/siwave_core/cpa/__init__.py +21 -0
  297. pyedb/siwave_core/cpa/simulation_setup_data_model.py +22 -0
  298. pyedb/siwave_core/icepak.py +1 -1
  299. pyedb/siwave_core/product_properties.py +23 -0
  300. pyedb/workflow.py +22 -0
  301. pyedb/workflows/sipi/hfss_auto_configuration.py +1 -1
  302. pyedb/workflows/utilities/__init__.py +0 -0
  303. pyedb/workflows/utilities/cutout.py +1428 -0
  304. {pyedb-0.59.0.dist-info → pyedb-0.60.0.dist-info}/METADATA +1 -1
  305. pyedb-0.60.0.dist-info/RECORD +308 -0
  306. {pyedb-0.59.0.dist-info → pyedb-0.60.0.dist-info}/licenses/LICENSE +7 -7
  307. pyedb-0.59.0.dist-info/RECORD +0 -306
  308. {pyedb-0.59.0.dist-info → pyedb-0.60.0.dist-info}/WHEEL +0 -0
pyedb/grpc/edb.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
1
+ # Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
2
2
  # SPDX-License-Identifier: MIT
3
3
  #
4
4
  #
@@ -65,7 +65,7 @@ import sys
65
65
  import tempfile
66
66
  import time
67
67
  import traceback
68
- from typing import Dict, List, Union
68
+ from typing import Dict, List, Tuple, Union
69
69
  import warnings
70
70
  from zipfile import ZipFile as zpf
71
71
 
@@ -129,12 +129,13 @@ from pyedb.grpc.database.terminal.padstack_instance_terminal import (
129
129
  PadstackInstanceTerminal,
130
130
  )
131
131
  from pyedb.grpc.database.terminal.terminal import Terminal
132
- from pyedb.grpc.database.utility.constants import get_terminal_supported_boundary_types
133
132
  from pyedb.grpc.database.utility.value import Value
134
133
  from pyedb.grpc.edb_init import EdbInit
135
134
  from pyedb.ipc2581.ipc2581 import Ipc2581
135
+ from pyedb.misc.decorators import deprecate_argument_name
136
136
  from pyedb.modeler.geometry_operators import GeometryOperators
137
137
  from pyedb.workflow import Workflow
138
+ from pyedb.workflows.utilities.cutout import Cutout
138
139
 
139
140
  os.environ["no_proxy"] = "localhost,127.0.0.1"
140
141
 
@@ -375,6 +376,30 @@ class Edb(EdbInit):
375
376
  def ansys_em_path(self):
376
377
  return self.base_path
377
378
 
379
+ @staticmethod
380
+ def number_with_units(value, units=None):
381
+ """Convert a number to a string with units. If value is a string, it's returned as is.
382
+
383
+ Parameters
384
+ ----------
385
+ value : float, int, str
386
+ Input number or string.
387
+ units : optional
388
+ Units for formatting. The default is ``None``, which uses ``"meter"``.
389
+
390
+ Returns
391
+ -------
392
+ str
393
+ String concatenating the value and unit.
394
+
395
+ """
396
+ if units is None:
397
+ units = "meter"
398
+ if isinstance(value, str):
399
+ return value
400
+ else:
401
+ return "{0}{1}".format(value, units)
402
+
378
403
  def _check_remove_project_files(self, edbpath: str, remove_existing_aedt: bool) -> None:
379
404
  aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
380
405
  files = [aedt_file, aedt_file + ".lock"]
@@ -1426,253 +1451,18 @@ class Edb(EdbInit):
1426
1451
  self.edbpath = temp_inputGDS + ".aedb"
1427
1452
  return self.open()
1428
1453
 
1429
- def _create_extent(
1430
- self,
1431
- net_signals,
1432
- extent_type,
1433
- expansion_size,
1434
- use_round_corner,
1435
- use_pyaedt_extent=False,
1436
- smart_cut=False,
1437
- reference_list=[],
1438
- include_pingroups=True,
1439
- pins_to_preserve=None,
1440
- inlcude_voids_in_extents=False,
1441
- ):
1442
- from ansys.edb.core.geometry.polygon_data import ExtentType as GrpcExtentType
1443
-
1444
- if extent_type in [
1445
- "Conforming",
1446
- "Conformal",
1447
- GrpcExtentType.CONFORMING,
1448
- 1,
1449
- ]:
1450
- if use_pyaedt_extent:
1451
- _poly = self._create_conformal(
1452
- net_signals,
1453
- expansion_size,
1454
- 1e-12,
1455
- use_round_corner,
1456
- expansion_size,
1457
- smart_cut,
1458
- reference_list,
1459
- pins_to_preserve,
1460
- inlcude_voids_in_extents=inlcude_voids_in_extents,
1461
- )
1462
- else:
1463
- _poly = self.layout.expanded_extent(
1464
- net_signals,
1465
- GrpcExtentType.CONFORMING,
1466
- expansion_size,
1467
- False,
1468
- use_round_corner,
1469
- 1,
1470
- )
1471
- elif extent_type in [
1472
- "Bounding",
1473
- GrpcExtentType.BOUNDING_BOX,
1474
- 0,
1475
- ]:
1476
- _poly = self.layout.expanded_extent(
1477
- net_signals,
1478
- GrpcExtentType.BOUNDING_BOX,
1479
- expansion_size,
1480
- False,
1481
- use_round_corner,
1482
- 1,
1483
- )
1484
- else:
1485
- if use_pyaedt_extent:
1486
- _poly = self._create_convex_hull(
1487
- net_signals,
1488
- expansion_size,
1489
- 1e-12,
1490
- use_round_corner,
1491
- expansion_size,
1492
- smart_cut,
1493
- reference_list,
1494
- pins_to_preserve,
1495
- )
1496
- else:
1497
- _poly = self.layout.expanded_extent(
1498
- net_signals,
1499
- GrpcExtentType.CONFORMING,
1500
- expansion_size,
1501
- False,
1502
- use_round_corner,
1503
- 1,
1504
- )
1505
- if not isinstance(_poly, list):
1506
- _poly = [_poly]
1507
- _poly = GrpcPolygonData.convex_hull(_poly)
1508
- return _poly
1509
-
1510
- def _create_conformal(
1511
- self,
1512
- net_signals,
1513
- expansion_size,
1514
- tolerance,
1515
- round_corner,
1516
- round_extension,
1517
- smart_cutout=False,
1518
- reference_list=[],
1519
- pins_to_preserve=None,
1520
- inlcude_voids_in_extents=False,
1521
- ):
1522
- names = []
1523
- _polys = []
1524
- for net in net_signals:
1525
- names.append(net.name)
1526
- if pins_to_preserve:
1527
- insts = self.padstacks.instances
1528
- for i in pins_to_preserve:
1529
- p = insts[i].position
1530
- pos_1 = [i - expansion_size for i in p]
1531
- pos_2 = [i + expansion_size for i in p]
1532
- plane = self.modeler.Shape("rectangle", pointA=pos_1, pointB=pos_2)
1533
- rectangle_data = self.modeler.shape_to_polygon_data(plane)
1534
- _polys.append(rectangle_data)
1535
-
1536
- for prim in self.modeler.primitives:
1537
- if prim is not None and prim.net_name in names:
1538
- _polys.append(prim)
1539
- if smart_cutout:
1540
- objs_data = self._smart_cut(reference_list, expansion_size)
1541
- _polys.extend(objs_data)
1542
- k = 0
1543
- delta = expansion_size / 5
1544
- while k < 10:
1545
- unite_polys = []
1546
- for i in _polys:
1547
- if "PolygonData" not in str(i):
1548
- obj_data = i.polygon_data.expand(
1549
- expansion_size,
1550
- round_corner,
1551
- round_extension,
1552
- tolerance,
1553
- )
1554
- else:
1555
- obj_data = i.expand(
1556
- expansion_size,
1557
- round_corner,
1558
- round_extension,
1559
- tolerance,
1560
- )
1561
- if inlcude_voids_in_extents and "PolygonData" not in str(i) and i.has_voids and obj_data:
1562
- for void in i.voids:
1563
- void_data = void.polygon_data.expand(
1564
- -1 * expansion_size,
1565
- round_corner,
1566
- round_extension,
1567
- tolerance,
1568
- )
1569
- if void_data:
1570
- for v in list(void_data):
1571
- obj_data[0].holes.append(v)
1572
- if obj_data:
1573
- if not inlcude_voids_in_extents:
1574
- unite_polys.extend(list(obj_data))
1575
- else:
1576
- voids_poly = []
1577
- try:
1578
- if i.has_voids:
1579
- area = i.area()
1580
- for void in i.voids:
1581
- void_polydata = void.polygon_data
1582
- if void_polydata.area() >= 0.05 * area:
1583
- voids_poly.append(void_polydata)
1584
- if voids_poly:
1585
- obj_data = obj_data[0].subtract(list(obj_data), voids_poly)
1586
- except Exception as e:
1587
- self.logger.error(
1588
- f"A(n) {type(e).__name__} error occurred in method _create_conformal of "
1589
- f"class Edb at iteration {k} for data {i}: {str(e)}"
1590
- )
1591
- finally:
1592
- unite_polys.extend(list(obj_data))
1593
- _poly_unite = GrpcPolygonData.unite(unite_polys)
1594
- if len(_poly_unite) == 1:
1595
- self.logger.info("Correctly computed Extension at first iteration.")
1596
- return _poly_unite[0]
1597
- k += 1
1598
- expansion_size += delta
1599
- if len(_poly_unite) == 1:
1600
- self.logger.info(f"Correctly computed Extension in {k} iterations.")
1601
- return _poly_unite[0]
1602
- else:
1603
- self.logger.info("Failed to Correctly computed Extension.")
1604
- areas = [i.area() for i in _poly_unite]
1605
- return _poly_unite[areas.index(max(areas))]
1606
-
1607
- def _smart_cut(self, reference_list=[], expansion_size=1e-12):
1608
- from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
1609
-
1610
- _polys = []
1611
- boundary_types = [
1612
- "port",
1613
- ]
1614
- terms = [term for term in self.layout.terminals if term.boundary_type in [0, 3, 4, 7, 8]]
1615
- locations = []
1616
- for term in terms:
1617
- if term.type == "PointTerminal" and term.net.name in reference_list:
1618
- pd = term.get_parameters()[1]
1619
- locations.append([Value(pd.x), Value(pd.y)])
1620
- for point in locations:
1621
- pointA = GrpcPointData([point[0] - expansion_size, point[1] - expansion_size])
1622
- pointB = GrpcPointData([point[0] + expansion_size, point[1] + expansion_size])
1623
- points = [pointA, GrpcPointData([pointB.x, pointA.y]), pointB, GrpcPointData([pointA.x, pointB.y])]
1624
- _polys.append(GrpcPolygonData(points=points))
1625
- return _polys
1626
-
1627
- def _create_convex_hull(
1628
- self,
1629
- net_signals,
1630
- expansion_size,
1631
- tolerance,
1632
- round_corner,
1633
- round_extension,
1634
- smart_cut=False,
1635
- reference_list=[],
1636
- pins_to_preserve=None,
1637
- ):
1638
- names = []
1639
- _polys = []
1640
- for net in net_signals:
1641
- names.append(net.name)
1642
- if pins_to_preserve:
1643
- insts = self.padstacks.instances
1644
- for i in pins_to_preserve:
1645
- p = insts[i].position
1646
- pos_1 = [i - 1e-12 for i in p]
1647
- pos_2 = [i + 1e-12 for i in p]
1648
- pos_3 = [pos_2[0], pos_1[1]]
1649
- pos_4 = pos_1[0], pos_2[1]
1650
- rectangle_data = GrpcPolygonData(points=[pos_1, pos_3, pos_2, pos_4])
1651
- _polys.append(rectangle_data)
1652
- for prim in self.modeler.primitives:
1653
- if not prim.is_null and not prim.net.is_null:
1654
- if prim.net.name in names:
1655
- _polys.append(prim.polygon_data)
1656
- if smart_cut:
1657
- objs_data = self._smart_cut(reference_list, expansion_size)
1658
- _polys.extend(objs_data)
1659
- _poly = GrpcPolygonData.convex_hull(_polys)
1660
- _poly = _poly.expand(
1661
- offset=expansion_size, round_corner=round_corner, max_corner_ext=round_extension, tol=tolerance
1662
- )[0]
1663
- return _poly
1664
-
1454
+ @deprecate_argument_name({"signal_list": "signal_nets", "reference_list": "reference_nets"})
1665
1455
  def cutout(
1666
1456
  self,
1667
- signal_list=None,
1668
- reference_list=None,
1457
+ signal_nets=None,
1458
+ reference_nets=None,
1669
1459
  extent_type="ConvexHull",
1670
1460
  expansion_size=0.002,
1671
1461
  use_round_corner=False,
1672
1462
  output_aedb_path=None,
1673
1463
  open_cutout_at_end=True,
1674
1464
  use_pyaedt_cutout=True,
1675
- number_of_threads=4,
1465
+ number_of_threads=1,
1676
1466
  use_pyaedt_extent_computing=True,
1677
1467
  extent_defeature=0,
1678
1468
  remove_single_pin_components=False,
@@ -1689,757 +1479,142 @@ class Edb(EdbInit):
1689
1479
  keep_lines_as_path=False,
1690
1480
  include_voids_in_extents=False,
1691
1481
  ):
1692
- """Create layout cutout with various options.
1482
+ """Create a cutout using an approach entirely based on PyAEDT.
1483
+ This method replaces all legacy cutout methods in PyAEDT.
1484
+ It does in sequence:
1485
+ - delete all nets not in list,
1486
+ - create a extent of the nets,
1487
+ - check and delete all vias not in the extent,
1488
+ - check and delete all the primitives not in extent,
1489
+ - check and intersect all the primitives that intersect the extent.
1693
1490
 
1694
1491
  Parameters
1695
1492
  ----------
1696
- signal_list : list, optional
1697
- Signal nets to include.
1698
- reference_list : list, optional
1699
- Reference nets to include.
1493
+ signal_nets : list
1494
+ List of signal strings.
1495
+ reference_nets : list, optional
1496
+ List of references to add. The default is ``["GND"]``.
1700
1497
  extent_type : str, optional
1701
- Cutout type ("Conforming", "ConvexHull", "Bounding").
1702
- expansion_size : float, optional
1703
- Boundary expansion size (meters).
1498
+ Type of the extension. Options are ``"Conforming"``, ``"ConvexHull"``, and
1499
+ ``"Bounding"``. The default is ``"Conforming"``.
1500
+ expansion_size : float, str, optional
1501
+ Expansion size ratio in meters. The default is ``0.002``.
1704
1502
  use_round_corner : bool, optional
1705
- Use rounded corners. Default False.
1503
+ Whether to use round corners. The default is ``False``.
1706
1504
  output_aedb_path : str, optional
1707
- Output AEDB path.
1505
+ Full path and name for the new AEDB file. If None, then current aedb will be cutout.
1708
1506
  open_cutout_at_end : bool, optional
1709
- Open cutout when finished. Default True.
1507
+ Whether to open the cutout at the end. The default is ``True``.
1710
1508
  use_pyaedt_cutout : bool, optional
1711
- Use PyAEDT cutout method. Default True.
1509
+ Whether to use new PyAEDT cutout method or EDB API method.
1510
+ New method is faster than native API method since it benefits of multithread.
1712
1511
  number_of_threads : int, optional
1713
- Thread count for PyAEDT cutout.
1512
+ Number of thread to use. Default is 4. Valid only if ``use_pyaedt_cutout`` is set to ``True``.
1714
1513
  use_pyaedt_extent_computing : bool, optional
1715
- Use PyAEDT extent computation. Default True.
1514
+ Whether to use legacy extent computing (experimental) or EDB API.
1716
1515
  extent_defeature : float, optional
1717
- Geometry simplification factor.
1516
+ Defeature the cutout before applying it to produce simpler geometry for mesh (Experimental).
1517
+ It applies only to Conforming bounding box. Default value is ``0`` which disable it.
1718
1518
  remove_single_pin_components : bool, optional
1719
- Remove single-pin components. Default False.
1720
- custom_extent : list, optional
1721
- Custom polygon points for cutout.
1722
- custom_extent_units : str, optional
1723
- Units for custom_extent points.
1519
+ Remove all Single Pin RLC after the cutout is completed. Default is `False`.
1520
+ custom_extent : list
1521
+ Points list defining the cutout shape. This setting will override `extent_type` field.
1522
+ custom_extent_units : str
1523
+ Units of the point list. The default is ``"mm"``. Valid only if `custom_extend` is provided.
1724
1524
  include_partial_instances : bool, optional
1725
- Include partial padstack instances. Default False.
1726
- keep_voids : bool, optional
1727
- Preserve voids in cutout. Default True.
1525
+ Whether to include padstack instances that have bounding boxes intersecting with point list polygons.
1526
+ This operation may slow down the cutout export.Valid only if `custom_extend` and
1527
+ `use_pyaedt_cutout` is provided.
1528
+ keep_voids : bool
1529
+ Boolean used for keep or not the voids intersecting the polygon used for clipping the layout.
1530
+ Default value is ``True``, ``False`` will remove the voids.Valid only if `custom_extend` is provided.
1728
1531
  check_terminals : bool, optional
1729
- Verify terminal references. Default False.
1532
+ Whether to check for all reference terminals and increase extent to include them into the cutout.
1533
+ This applies to components which have a model (spice, touchstone or netlist) associated.
1730
1534
  include_pingroups : bool, optional
1731
- Include pin groups. Default False.
1535
+ Whether to check for all pingroups terminals and increase extent to include them into the cutout.
1536
+ It requires ``check_terminals``.
1732
1537
  expansion_factor : int, optional
1733
- Auto-expansion factor. Default 0 (disabled).
1538
+ The method computes a float representing the largest number between
1539
+ the dielectric thickness or trace width multiplied by the expansion_factor factor.
1540
+ The trace width search is limited to nets with ports attached. Works only if `use_pyaedt_cutout`.
1541
+ Default is `0` to disable the search.
1734
1542
  maximum_iterations : int, optional
1735
- Max auto-expansion iterations. Default 10.
1543
+ Maximum number of iterations before stopping a search for a cutout with an error.
1544
+ Default is `10`.
1736
1545
  preserve_components_with_model : bool, optional
1737
- Keep components with models. Default False.
1546
+ Whether to preserve all pins of components that have associated models (Spice or NPort).
1547
+ This parameter is applicable only for a PyAEDT cutout (except point list).
1738
1548
  simple_pad_check : bool, optional
1739
- Use simplified pad checking. Default True.
1549
+ Whether to use the center of the pad to find the intersection with extent or use the bounding box.
1550
+ Second method is much slower and requires to disable multithread on padstack removal.
1551
+ Default is `True`.
1740
1552
  keep_lines_as_path : bool, optional
1741
- Preserve paths as lines. Default False.
1553
+ Whether to keep the lines as Path after they are cutout or convert them to PolygonData.
1554
+ This feature works only in Electronics Desktop (3D Layout).
1555
+ If the flag is set to ``True`` it can cause issues in SiWave once the Edb is imported.
1556
+ Default is ``False`` to generate PolygonData of cut lines.
1742
1557
  include_voids_in_extents : bool, optional
1743
- Include voids in extent calculation. Default False.
1558
+ Whether to compute and include voids in pyaedt extent before the cutout. Cutout time can be affected.
1559
+ It works only with Conforming cutout.
1560
+ Default is ``False`` to generate extent without voids.
1561
+
1744
1562
 
1745
1563
  Returns
1746
1564
  -------
1747
- list or bool
1748
- Cutout boundary points if successful, False otherwise.
1565
+ List
1566
+ List of coordinate points defining the extent used for clipping the design. If it failed return an empty
1567
+ list.
1749
1568
 
1750
1569
  Examples
1751
1570
  --------
1752
- >>> # Create a basic cutout:
1753
- >>> edb.cutout(signal_list=["Net1"], reference_list=["GND"])
1754
- >>> # Create cutout with custom polygon:
1755
- >>> custom_poly = [[0, 0], [10e-3, 0], [10e-3, 10e-3], [0, 10e-3]]
1756
- >>> edb.cutout(custom_extent=custom_poly)
1757
- """
1758
- if expansion_factor > 0:
1759
- expansion_size = self.calculate_initial_extent(expansion_factor)
1760
- if signal_list is None:
1761
- signal_list = []
1762
- if isinstance(reference_list, str):
1763
- reference_list = [reference_list]
1764
- elif reference_list is None:
1765
- reference_list = []
1766
- if not use_pyaedt_cutout and custom_extent:
1767
- return self._create_cutout_on_point_list(
1768
- custom_extent,
1769
- units=custom_extent_units,
1770
- output_aedb_path=output_aedb_path,
1771
- open_cutout_at_end=open_cutout_at_end,
1772
- nets_to_include=signal_list + reference_list,
1773
- include_partial_instances=include_partial_instances,
1774
- keep_voids=keep_voids,
1775
- )
1776
- elif not use_pyaedt_cutout:
1777
- return self._create_cutout_legacy(
1778
- signal_list=signal_list,
1779
- reference_list=reference_list,
1780
- extent_type=extent_type,
1781
- expansion_size=expansion_size,
1782
- use_round_corner=use_round_corner,
1783
- output_aedb_path=output_aedb_path,
1784
- open_cutout_at_end=open_cutout_at_end,
1785
- use_pyaedt_extent_computing=use_pyaedt_extent_computing,
1786
- check_terminals=check_terminals,
1787
- include_pingroups=include_pingroups,
1788
- inlcude_voids_in_extents=include_voids_in_extents,
1789
- )
1790
- else:
1791
- legacy_path = self.edbpath
1792
- if expansion_factor > 0 and not custom_extent:
1793
- start = time.time()
1794
- self.save_edb()
1795
- dummy_path = self.edbpath.replace(".aedb", "_smart_cutout_temp.aedb")
1796
- working_cutout = False
1797
- i = 1
1798
- expansion = expansion_size
1799
- while i <= maximum_iterations:
1800
- self.logger.info("-----------------------------------------")
1801
- self.logger.info(f"Trying cutout with {expansion * 1e3}mm expansion size")
1802
- self.logger.info("-----------------------------------------")
1803
- result = self._create_cutout_multithread(
1804
- signal_list=signal_list,
1805
- reference_list=reference_list,
1806
- extent_type=extent_type,
1807
- expansion_size=expansion,
1808
- use_round_corner=use_round_corner,
1809
- number_of_threads=number_of_threads,
1810
- custom_extent=custom_extent,
1811
- output_aedb_path=dummy_path,
1812
- remove_single_pin_components=remove_single_pin_components,
1813
- use_pyaedt_extent_computing=use_pyaedt_extent_computing,
1814
- extent_defeature=extent_defeature,
1815
- custom_extent_units=custom_extent_units,
1816
- check_terminals=check_terminals,
1817
- include_pingroups=include_pingroups,
1818
- preserve_components_with_model=preserve_components_with_model,
1819
- include_partial=include_partial_instances,
1820
- simple_pad_check=simple_pad_check,
1821
- keep_lines_as_path=keep_lines_as_path,
1822
- inlcude_voids_in_extents=include_voids_in_extents,
1823
- )
1824
- if self.are_port_reference_terminals_connected():
1825
- if output_aedb_path:
1826
- self.save_edb_as(output_aedb_path)
1827
- else:
1828
- self.save_edb_as(legacy_path)
1829
- working_cutout = True
1830
- break
1831
- self.close_edb()
1832
- self.edbpath = legacy_path
1833
- self.open()
1834
- i += 1
1835
- expansion = expansion_size * i
1836
- if working_cutout:
1837
- msg = f"Cutout completed in {i} iterations with expansion size of {expansion * 1e3}mm"
1838
- self.logger.info_timer(msg, start)
1839
- else:
1840
- msg = f"Cutout failed after {i} iterations and expansion size of {expansion * 1e3}mm"
1841
- self.logger.info_timer(msg, start)
1842
- return False
1843
- else:
1844
- result = self._create_cutout_multithread(
1845
- signal_list=signal_list,
1846
- reference_list=reference_list,
1847
- extent_type=extent_type,
1848
- expansion_size=expansion_size,
1849
- use_round_corner=use_round_corner,
1850
- number_of_threads=number_of_threads,
1851
- custom_extent=custom_extent,
1852
- output_aedb_path=output_aedb_path,
1853
- remove_single_pin_components=remove_single_pin_components,
1854
- use_pyaedt_extent_computing=use_pyaedt_extent_computing,
1855
- extent_defeature=extent_defeature,
1856
- custom_extent_units=custom_extent_units,
1857
- check_terminals=check_terminals,
1858
- include_pingroups=include_pingroups,
1859
- preserve_components_with_model=preserve_components_with_model,
1860
- include_partial=include_partial_instances,
1861
- simple_pad_check=simple_pad_check,
1862
- keep_lines_as_path=keep_lines_as_path,
1863
- inlcude_voids_in_extents=include_voids_in_extents,
1864
- )
1865
- if result and not open_cutout_at_end and self.edbpath != legacy_path:
1866
- self.save_edb()
1867
- self.close_edb()
1868
- self.edbpath = legacy_path
1869
- self.open_edb()
1870
- return result
1871
-
1872
- def _create_cutout_legacy(
1873
- self,
1874
- signal_list=[],
1875
- reference_list=["GND"],
1876
- extent_type="Conforming",
1877
- expansion_size=0.002,
1878
- use_round_corner=False,
1879
- output_aedb_path=None,
1880
- open_cutout_at_end=True,
1881
- use_pyaedt_extent_computing=False,
1882
- remove_single_pin_components=False,
1883
- check_terminals=False,
1884
- include_pingroups=True,
1885
- inlcude_voids_in_extents=False,
1886
- ):
1887
- expansion_size = Value(expansion_size)
1888
-
1889
- # validate nets in layout
1890
- net_signals = [net for net in self.layout.nets if net.name in signal_list]
1891
-
1892
- # validate references in layout
1893
- _netsClip = [net for net in self.layout.nets if net.name in reference_list]
1894
-
1895
- _poly = self._create_extent(
1896
- net_signals,
1897
- extent_type,
1898
- expansion_size,
1899
- use_round_corner,
1900
- use_pyaedt_extent_computing,
1901
- smart_cut=check_terminals,
1902
- reference_list=reference_list,
1903
- include_pingroups=include_pingroups,
1904
- inlcude_voids_in_extents=inlcude_voids_in_extents,
1905
- )
1906
- _poly1 = GrpcPolygonData(arcs=_poly.arc_data, closed=True)
1907
- if inlcude_voids_in_extents:
1908
- for hole in _poly.holes:
1909
- if hole.area() >= 0.05 * _poly1.area():
1910
- _poly1.holes.append(hole)
1911
- _poly = _poly1
1912
- # Create new cutout cell/design
1913
- included_nets_list = signal_list + reference_list
1914
- included_nets = [net for net in self.layout.nets if net.name in included_nets_list]
1915
- _cutout = self.active_cell.cutout(included_nets, _netsClip, _poly, True)
1916
- # _cutout.simulation_setups = self.active_cell.simulation_setups see bug #433 status.
1917
- _dbCells = [_cutout]
1918
- if output_aedb_path:
1919
- from ansys.edb.core.database import Database as GrpcDatabase
1920
-
1921
- db2 = GrpcDatabase.create(output_aedb_path)
1922
- db2.copy_cells(_dbCells) # Copies cutout cell/design to db2 project
1923
- if len(list(db2.top_circuit_cells)) > 0:
1924
- for net in db2.top_circuit_cells[0].layout.nets:
1925
- if not net.name in included_nets_list:
1926
- net.delete()
1927
- db2.save()
1928
- for c in self.active_db.top_circuit_cells:
1929
- if c.name == _cutout.name:
1930
- c.delete()
1931
- if open_cutout_at_end: # pragma: no cover
1932
- self._db = db2
1933
- self.edbpath = output_aedb_path
1934
- self._active_cell = self.top_circuit_cells[0]
1935
- self.edbpath = self.directory
1936
- self._init_objects()
1937
- if remove_single_pin_components:
1938
- self.components.delete_single_pin_rlc()
1939
- self.logger.info_timer("Single Pins components deleted")
1940
- self.components.refresh_components()
1941
- else:
1942
- if remove_single_pin_components:
1943
- try:
1944
- from ansys.edb.core.hierarchy.component_group import (
1945
- ComponentGroup as GrpcComponentGroup,
1946
- )
1947
-
1948
- layout = db2.circuit_cells[0].layout
1949
- _cmps = [l for l in layout.groups if isinstance(l, GrpcComponentGroup) and l.num_pins < 2]
1950
- for _cmp in _cmps:
1951
- _cmp.delete()
1952
- except:
1953
- self.logger.error("Failed to remove single pin components.")
1954
- db2.close()
1955
- source = os.path.join(output_aedb_path, "edb.def.tmp")
1956
- target = os.path.join(output_aedb_path, "edb.def")
1957
- self._wait_for_file_release(file_to_release=output_aedb_path)
1958
- if os.path.exists(source) and not os.path.exists(target):
1959
- try:
1960
- shutil.copy(source, target)
1961
- except Exception as e:
1962
- self.logger.error(f"Failed to copy {source} to {target} - {type(e).__name__}: {str(e)}")
1963
- elif open_cutout_at_end:
1964
- self._active_cell = _cutout
1965
- self._init_objects()
1966
- if remove_single_pin_components:
1967
- self.components.delete_single_pin_rlc()
1968
- self.logger.info_timer("Single Pins components deleted")
1969
- self.components.refresh_components()
1970
- return [[Value(pt.x), Value(pt.y)] for pt in _poly.without_arcs().points]
1971
-
1972
- def _create_cutout_multithread(
1973
- self,
1974
- signal_list=[],
1975
- reference_list=["GND"],
1976
- extent_type="Conforming",
1977
- expansion_size=0.002,
1978
- use_round_corner=False,
1979
- number_of_threads=4,
1980
- custom_extent=None,
1981
- output_aedb_path=None,
1982
- remove_single_pin_components=False,
1983
- use_pyaedt_extent_computing=False,
1984
- extent_defeature=0.0,
1985
- custom_extent_units="mm",
1986
- check_terminals=False,
1987
- include_pingroups=True,
1988
- preserve_components_with_model=False,
1989
- include_partial=False,
1990
- simple_pad_check=True,
1991
- keep_lines_as_path=False,
1992
- inlcude_voids_in_extents=False,
1993
- ):
1994
- from concurrent.futures import ThreadPoolExecutor
1995
-
1996
- if output_aedb_path:
1997
- self.save_edb_as(output_aedb_path)
1998
- self.logger.info("Cutout Multithread started.")
1999
- expansion_size = Value(expansion_size)
2000
-
2001
- timer_start = self.logger.reset_timer()
2002
- if custom_extent:
2003
- if not reference_list and not signal_list:
2004
- reference_list = self.nets.netlist[::]
2005
- all_list = reference_list
2006
- else:
2007
- reference_list = reference_list + signal_list
2008
- all_list = reference_list
2009
- else:
2010
- all_list = signal_list + reference_list
2011
- pins_to_preserve = []
2012
- nets_to_preserve = []
2013
- if preserve_components_with_model:
2014
- for el in self.components.instances.values():
2015
- if el.model_type in [
2016
- "SPICEModel",
2017
- "SParameterModel",
2018
- "NetlistModel",
2019
- ] and list(set(el.nets[:]) & set(signal_list[:])):
2020
- pins_to_preserve.extend([i.edb_uid for i in el.pins.values()])
2021
- nets_to_preserve.extend(el.nets)
2022
- if include_pingroups:
2023
- for pingroup in self.layout.pin_groups:
2024
- for pin_name, pin in pingroup.pins.items():
2025
- if pin_name in reference_list:
2026
- pins_to_preserve.append(pin.edb_uid)
2027
- if check_terminals:
2028
- terms = [
2029
- term for term in self.layout.terminals if term.boundary_type in get_terminal_supported_boundary_types()
2030
- ]
2031
- for term in terms:
2032
- if isinstance(term, PadstackInstanceTerminal):
2033
- if term.net.name in reference_list:
2034
- pins_to_preserve.append(term.edb_uid)
2035
- delete_list = []
2036
-
2037
- for i in self.nets.nets.values():
2038
- name = i.name
2039
- if name not in all_list and name not in nets_to_preserve:
2040
- delete_list.append(i)
2041
- # i.delete()
2042
- for i in delete_list:
2043
- i.delete()
2044
- reference_pinsts = []
2045
- reference_prims = []
2046
- reference_paths = []
2047
- delete_list = []
2048
- for i in self.padstacks.instances.values():
2049
- net_name = i.net_name
2050
- id = i.id
2051
- if net_name not in all_list and id not in pins_to_preserve:
2052
- delete_list.append(i)
2053
- # i.delete()
2054
- elif net_name in reference_list and id not in pins_to_preserve:
2055
- reference_pinsts.append(i)
2056
- for i in self.modeler.primitives:
2057
- if not i.is_null and not i.net.is_null:
2058
- if i.net.name not in all_list:
2059
- # i.delete()
2060
- delete_list.append(i)
2061
- elif i.net.name in reference_list and not i.is_void:
2062
- if keep_lines_as_path and isinstance(i, Path):
2063
- reference_paths.append(i)
2064
- else:
2065
- reference_prims.append(i)
2066
- self.logger.info_timer("Net clean up")
2067
- self.logger.reset_timer()
2068
- for i in delete_list:
2069
- i.delete()
2070
- if custom_extent and isinstance(custom_extent, list):
2071
- if custom_extent[0] != custom_extent[-1]:
2072
- custom_extent.append(custom_extent[0])
2073
- custom_extent = [
2074
- [
2075
- self.number_with_units(i[0], custom_extent_units),
2076
- self.number_with_units(i[1], custom_extent_units),
2077
- ]
2078
- for i in custom_extent
2079
- ]
2080
- _poly = GrpcPolygonData(points=custom_extent)
2081
- elif custom_extent:
2082
- _poly = custom_extent
2083
- else:
2084
- net_signals = [net for net in self.layout.nets if net.name in signal_list]
2085
- _poly = self._create_extent(
2086
- net_signals,
2087
- extent_type,
2088
- expansion_size,
2089
- use_round_corner,
2090
- use_pyaedt_extent_computing,
2091
- smart_cut=check_terminals,
2092
- reference_list=reference_list,
2093
- include_pingroups=include_pingroups,
2094
- pins_to_preserve=pins_to_preserve,
2095
- inlcude_voids_in_extents=inlcude_voids_in_extents,
2096
- )
2097
- from ansys.edb.core.geometry.polygon_data import (
2098
- ExtentType as GrpcExtentType,
2099
- )
2100
-
2101
- if extent_type in ["Conformal", "Conforming", GrpcExtentType.CONFORMING, 1]:
2102
- if extent_defeature > 0:
2103
- _poly = _poly.defeature(extent_defeature)
2104
- _poly1 = GrpcPolygonData(arcs=_poly.arc_data, closed=True)
2105
- if inlcude_voids_in_extents:
2106
- for hole in list(_poly.holes):
2107
- if hole.area() >= 0.05 * _poly1.area():
2108
- _poly1.holes.append(hole)
2109
- self.logger.info(f"Number of voids included:{len(list(_poly1.holes))}")
2110
- _poly = _poly1
2111
- if not _poly.points:
2112
- self._logger.error("Failed to create Extent.")
2113
- return []
2114
- self.logger.info_timer("Expanded Net Polygon Creation")
2115
- self.logger.reset_timer()
2116
- _poly_list = [_poly]
2117
- prims_to_delete = []
2118
- poly_to_create = []
2119
- pins_to_delete = []
2120
-
2121
- def intersect(poly1, poly2):
2122
- if not isinstance(poly2, list):
2123
- poly2 = [poly2]
2124
- return poly1.intersect(poly1, poly2)
2125
-
2126
- def subtract(poly, voids):
2127
- return poly.subtract(poly, voids)
2128
-
2129
- def clip_path(path):
2130
- pdata = path.polygon_data
2131
- int_data = _poly.intersection_type(pdata)
2132
- if int_data == 0:
2133
- prims_to_delete.append(path)
2134
- return
2135
- result = path.set_clip_info(_poly, True)
2136
- if not result:
2137
- self.logger.info(f"Failed to clip path {path.id}. Clipping as polygon.")
2138
- reference_prims.append(path)
2139
-
2140
- def clean_prim(prim_1): # pragma: no cover
2141
- pdata = prim_1.polygon_data
2142
- int_data = _poly.intersection_type(pdata)
2143
- if int_data == 2:
2144
- if not inlcude_voids_in_extents:
2145
- return
2146
- skip = False
2147
- for hole in list(_poly.Holes):
2148
- if hole.intersection_type(pdata) == 0:
2149
- prims_to_delete.append(prim_1)
2150
- return
2151
- elif hole.intersection_type(pdata) == 1:
2152
- skip = True
2153
- if skip:
2154
- return
2155
- elif int_data == 0:
2156
- prims_to_delete.append(prim_1)
2157
- return
2158
- list_poly = intersect(_poly, pdata)
2159
- if list_poly:
2160
- net = prim_1.net.name
2161
- voids = prim_1.voids
2162
- for p in list_poly:
2163
- if not p.points:
2164
- continue
2165
- list_void = []
2166
- if voids:
2167
- voids_data = [void.polygon_data for void in voids]
2168
- list_prims = subtract(p, voids_data)
2169
- for prim in list_prims:
2170
- if prim.points:
2171
- poly_to_create.append([prim, prim_1.layer.name, net, list_void])
2172
- else:
2173
- poly_to_create.append([p, prim_1.layer.name, net, list_void])
2174
-
2175
- prims_to_delete.append(prim_1)
2176
-
2177
- def pins_clean(pinst):
2178
- if not pinst.in_polygon(_poly, include_partial=include_partial, simple_check=simple_pad_check):
2179
- pins_to_delete.append(pinst)
2180
-
2181
- if not simple_pad_check:
2182
- pad_cores = 1
2183
- else:
2184
- pad_cores = number_of_threads
2185
- with ThreadPoolExecutor(pad_cores) as pool:
2186
- pool.map(lambda item: pins_clean(item), reference_pinsts)
2187
-
2188
- for pin in pins_to_delete:
2189
- pin.delete()
2190
-
2191
- self.logger.info_timer(f"Padstack Instances removal completed. {len(pins_to_delete)} instances removed.")
2192
- self.logger.reset_timer()
2193
-
2194
- for item in reference_paths:
2195
- clip_path(item)
2196
- for prim in reference_prims: # removing multithreading as failing with new layer from primitive
2197
- clean_prim(prim)
2198
-
2199
- for el in poly_to_create:
2200
- self.modeler.create_polygon(el[0], el[1], net_name=el[2], voids=el[3])
2201
-
2202
- for prim in prims_to_delete:
2203
- prim.delete()
2204
-
2205
- self.logger.info_timer(f"Primitives cleanup completed. {len(prims_to_delete)} primitives deleted.")
2206
- self.logger.reset_timer()
2207
-
2208
- i = 0
2209
- for _, val in self.components.instances.items():
2210
- if val.numpins == 0:
2211
- val.delete()
2212
- i += 1
2213
- i += 1
2214
- self.logger.info(f"Deleted {i} additional components")
2215
- if remove_single_pin_components:
2216
- self.components.delete_single_pin_rlc()
2217
- self.logger.info_timer("Single Pins components deleted")
2218
-
2219
- self.components.refresh_components()
2220
- if output_aedb_path:
2221
- self.save_edb()
2222
- self.logger.info_timer("Cutout completed.", timer_start)
2223
- self.logger.reset_timer()
2224
- return [[Value(pt.x), Value(pt.y)] for pt in _poly.without_arcs().points]
2225
-
2226
- def get_conformal_polygon_from_netlist(self, netlist=None) -> Union[bool, Polygon]:
2227
- """Returns conformal polygon data based on a netlist.
2228
-
2229
- Parameters
2230
- ----------
2231
- netlist : List of net names.
2232
- list[str]
2233
-
2234
- Returns
2235
- -------
2236
- :class:`PolygonData <ansys.edb.core.geometry.polygon_data.PolygonData>`
2237
- """
2238
- from ansys.edb.core.geometry.polygon_data import ExtentType as GrpcExtentType
2239
-
2240
- temp_edb_path = self.edbpath[:-5] + "_temp_aedb.aedb"
2241
- shutil.copytree(self.edbpath, temp_edb_path)
2242
- temp_edb = Edb(temp_edb_path)
2243
- for via in list(temp_edb.padstacks.instances.values()):
2244
- via.pin.delete()
2245
- if netlist:
2246
- nets = [net for net in temp_edb.layout.nets if net.name in netlist]
2247
- _poly = temp_edb.layout.expanded_extent(nets, GrpcExtentType.CONFORMING, 0.0, True, True, 1)
2248
- else:
2249
- nets = [net for net in temp_edb.layout.nets if "gnd" in net.name.lower()]
2250
- _poly = temp_edb.layout.expanded_extent(nets, GrpcExtentType.CONFORMING, 0.0, True, True, 1)
2251
- temp_edb.close()
2252
- if _poly:
2253
- return _poly
2254
- else:
2255
- return False
2256
-
2257
- def number_with_units(self, value, units=None) -> str:
2258
- """Convert a number to a string with units. If value is a string, it's returned as is.
2259
-
2260
- Parameters
2261
- ----------
2262
- value : float, int, str
2263
- Input number or string.
2264
- units : optional
2265
- Units for formatting. The default is ``None``, which uses ``"meter"``.
2266
-
2267
- Returns
2268
- -------
2269
- str
2270
- String concatenating the value and unit.
2271
-
2272
- """
2273
- if units is None:
2274
- units = "meter"
2275
- if isinstance(value, str):
2276
- return value
2277
- else:
2278
- return f"{value}{units}"
2279
-
2280
- def _create_cutout_on_point_list(
2281
- self,
2282
- point_list,
2283
- units="mm",
2284
- output_aedb_path=None,
2285
- open_cutout_at_end=True,
2286
- nets_to_include=None,
2287
- include_partial_instances=False,
2288
- keep_voids=True,
2289
- ):
2290
- from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
2291
-
2292
- if point_list[0] != point_list[-1]:
2293
- point_list.append(point_list[0])
2294
- point_list = [[self.number_with_units(i[0], units), self.number_with_units(i[1], units)] for i in point_list]
2295
- polygon_data = GrpcPolygonData(points=[GrpcPointData(pt) for pt in point_list])
2296
- _ref_nets = []
2297
- if nets_to_include:
2298
- self.logger.info(f"Creating cutout on {len(nets_to_include)} nets.")
2299
- else:
2300
- self.logger.info("Creating cutout on all nets.") # pragma: no cover
2301
-
2302
- # Check Padstack Instances overlapping the cutout
2303
- pinstance_to_add = []
2304
- if include_partial_instances:
2305
- if nets_to_include:
2306
- pinst = [i for i in list(self.padstacks.instances.values()) if i.net_name in nets_to_include]
2307
- else:
2308
- pinst = [i for i in list(self.padstacks.instances.values())]
2309
- for p in pinst:
2310
- pin_position = p.position # check bug #434 status
2311
- if polygon_data.is_inside(p.position): # check bug #434 status
2312
- pinstance_to_add.append(p)
2313
- # validate references in layout
2314
- for _ref in self.nets.nets:
2315
- if nets_to_include:
2316
- if _ref in nets_to_include:
2317
- _ref_nets.append(self.nets.nets[_ref])
2318
- else:
2319
- _ref_nets.append(self.nets.nets[_ref]) # pragma: no cover
2320
- if keep_voids:
2321
- voids = [p for p in self.modeler.circles if p.is_void]
2322
- voids2 = [p for p in self.modeler.polygons if p.is_void]
2323
- voids.extend(voids2)
2324
- else:
2325
- voids = []
2326
- voids_to_add = []
2327
- for circle in voids:
2328
- if polygon_data.get_intersection_type(circle.polygon_data) >= 3:
2329
- voids_to_add.append(circle)
2330
-
2331
- _netsClip = _ref_nets
2332
- # Create new cutout cell/design
2333
- _cutout = self.active_cell.cutout(_netsClip, _netsClip, polygon_data)
2334
- layout = _cutout.layout
2335
- cutout_obj_coll = layout.padstack_instances
2336
- ids = []
2337
- for lobj in cutout_obj_coll:
2338
- ids.append(lobj.id)
2339
- if include_partial_instances:
2340
- from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
2341
- from ansys.edb.core.primitive.padstack_instance import (
2342
- PadstackInstance as GrpcPadstackInstance,
2343
- )
2344
-
2345
- p_missing = [i for i in pinstance_to_add if i.id not in ids]
2346
- self.logger.info(f"Added {len(p_missing)} padstack instances after cutout")
2347
- for p in p_missing:
2348
- position = GrpcPointData(p.position)
2349
- net = self.nets.find_or_create_net(p.net_name)
2350
- rotation = Value(p.rotation)
2351
- sign_layers = list(self.stackup.signal_layers.keys())
2352
- if not p.start_layer: # pragma: no cover
2353
- fromlayer = self.stackup.signal_layers[sign_layers[0]]
2354
- else:
2355
- fromlayer = self.stackup.signal_layers[p.start_layer]
2356
-
2357
- if not p.stop_layer: # pragma: no cover
2358
- tolayer = self.stackup.signal_layers[sign_layers[-1]]
2359
- else:
2360
- tolayer = self.stackup.signal_layers[p.stop_layer]
2361
- for pad in list(self.padstacks.definitions.keys()):
2362
- if pad == p.padstack_definition:
2363
- padstack = self.padstacks.definitions[pad]
2364
- padstack_instance = GrpcPadstackInstance.create(
2365
- layout=_cutout.layout,
2366
- net=net,
2367
- name=p.name,
2368
- padstack_def=padstack,
2369
- position_x=position.x,
2370
- position_y=position.y,
2371
- rotation=rotation,
2372
- top_layer=fromlayer,
2373
- bottom_layer=tolayer,
2374
- layer_map=None,
2375
- solder_ball_layer=None,
2376
- )
2377
- padstack_instance.is_layout_pin = p.is_pin
2378
- break
2379
-
2380
- for void_circle in voids_to_add:
2381
- if isinstance(void_circle, Circle):
2382
- res = void_circle.get_parameters()
2383
- cloned_circle = Circle.create(
2384
- layout=layout,
2385
- layer=void_circle.layer.name,
2386
- net=void_circle.net,
2387
- center_x=res[0].x,
2388
- center_y=res[0].y,
2389
- radius=res[1],
2390
- )
2391
- cloned_circle.is_negative = True
2392
- elif isinstance(void_circle, Polygon):
2393
- cloned_polygon = Polygon.create(
2394
- layout,
2395
- void_circle.layer.name,
2396
- void_circle.net,
2397
- void_circle.polygon_data,
2398
- )
2399
- cloned_polygon.is_negative = True
2400
- layers = [i for i in list(self.stackup.signal_layers.keys())]
2401
- for layer in layers:
2402
- layer_primitves = self.modeler.get_primitives(layer_name=layer)
2403
- if len(layer_primitves) == 0:
2404
- self.modeler.create_polygon(point_list, layer, net_name="DUMMY")
2405
- self.logger.info(f"Cutout {_cutout.name} created correctly")
2406
- for _setup in self.active_cell.simulation_setups:
2407
- # Add the create Simulation setup to cutout cell
2408
- # might need to add a clone setup method.
2409
- pass
2410
-
2411
- _dbCells = [_cutout]
2412
- if output_aedb_path:
2413
- from ansys.edb.core.database import Database as GrpcDatabase
2414
-
2415
- db2 = GrpcDatabase.create(output_aedb_path)
2416
- db2.save()
2417
- cell_copied = db2.copy_cells(_dbCells) # Copies cutout cell/design to db2 project
2418
- cell = cell_copied[0]
2419
- cell.name = os.path.basename(output_aedb_path[:-5])
2420
- db2.save()
2421
- for c in list(self.active_db.top_circuit_cells):
2422
- if c.name == _cutout.name:
2423
- c.delete()
2424
- if open_cutout_at_end: # pragma: no cover
2425
- db2.save()
2426
- self._db = db2
2427
- self.edbpath = output_aedb_path
2428
- self._active_cell = cell
2429
- self.edbpath = self.directory
2430
- self._init_objects()
2431
- else:
2432
- db2.close()
2433
- source = os.path.join(output_aedb_path, "edb.def.tmp")
2434
- target = os.path.join(output_aedb_path, "edb.def")
2435
- self._wait_for_file_release(file_to_release=output_aedb_path)
2436
- if os.path.exists(source) and not os.path.exists(target):
2437
- try:
2438
- shutil.copy(source, target)
2439
- self.logger.warning("aedb def file manually created.")
2440
- except Exception as e:
2441
- self.logger.error(f"Failed to copy {source} to {target} - {type(e).__name__}: {str(e)}")
2442
- return [[Value(pt.x), Value(pt.y)] for pt in polygon_data.without_arcs().points]
1571
+ >>> from pyedb import Edb
1572
+ >>> edb = Edb(r"C:\\test.aedb", version="2022.2")
1573
+ >>> edb.logger.info_timer("Edb Opening")
1574
+ >>> edb.logger.reset_timer()
1575
+ >>> start = time.time()
1576
+ >>> signal_list = []
1577
+ >>> for net in edb.nets.netlist:
1578
+ >>> if "3V3" in net:
1579
+ >>> signal_list.append(net)
1580
+ >>> power_list = ["PGND"]
1581
+ >>> edb.cutout(signal_nets=signal_list, reference_nets=power_list, extent_type="Conforming")
1582
+ >>> end_time = str((time.time() - start) / 60)
1583
+ >>> edb.logger.info("Total legacy cutout time in min %s", end_time)
1584
+ >>> edb.nets.plot(signal_list, None, color_by_net=True)
1585
+ >>> edb.nets.plot(power_list, None, color_by_net=True)
1586
+ >>> edb.save()
1587
+ >>> edb.close()
1588
+
1589
+
1590
+ """
1591
+ cutout = Cutout(self)
1592
+ cutout.expansion_size = expansion_size
1593
+ cutout.signals = signal_nets
1594
+ cutout.references = reference_nets
1595
+ cutout.extent_type = extent_type
1596
+ cutout.expansion_size = expansion_size
1597
+ cutout.use_round_corner = use_round_corner
1598
+ cutout.output_file = output_aedb_path
1599
+ cutout.open_cutout_at_end = open_cutout_at_end
1600
+ cutout.use_pyaedt_cutout = use_pyaedt_cutout
1601
+ cutout.number_of_threads = number_of_threads
1602
+ cutout.use_pyaedt_extent_computing = use_pyaedt_extent_computing
1603
+ cutout.extent_defeatured = extent_defeature
1604
+ cutout.remove_single_pin_components = remove_single_pin_components
1605
+ cutout.custom_extent = custom_extent
1606
+ cutout.custom_extent_units = custom_extent_units
1607
+ cutout.include_partial_instances = include_partial_instances
1608
+ cutout.keep_voids = keep_voids
1609
+ cutout.check_terminals = check_terminals
1610
+ cutout.include_pingroups = include_pingroups
1611
+ cutout.expansion_factor = expansion_factor
1612
+ cutout.maximum_iterations = maximum_iterations
1613
+ cutout.preserve_components_with_model = preserve_components_with_model
1614
+ cutout.simple_pad_check = simple_pad_check
1615
+ cutout.keep_lines_as_path = keep_lines_as_path
1616
+ cutout.include_voids_in_extents = include_voids_in_extents
1617
+ return cutout.run()
2443
1618
 
2444
1619
  @staticmethod
2445
1620
  def write_export3d_option_config_file(path_to_output, config_dictionaries=None):
@@ -2880,55 +2055,51 @@ class Edb(EdbInit):
2880
2055
  self.logger.reset_timer()
2881
2056
  if not common_reference:
2882
2057
  ref_terminals = [term for term in all_sources if term.is_reference_terminal]
2883
- common_reference = list(
2884
- set([i.reference_terminal.net.name for i in all_sources if i.is_reference_terminal])
2885
- )
2058
+ common_reference = list(set([i.net.name for i in ref_terminals]))
2886
2059
  if len(common_reference) > 1:
2887
- self.logger.error("More than 1 reference found.")
2888
- return False
2060
+ raise ValueError("Multiple reference nets found. Please specify one.")
2889
2061
  if not common_reference:
2890
- self.logger.error("No Reference found.")
2891
- return False
2892
-
2062
+ raise ValueError("No reference net found. Please specify one.")
2893
2063
  common_reference = common_reference[0]
2894
2064
  all_sources = [i for i in all_sources if i.net.name != common_reference]
2895
-
2896
- setList = [
2897
- set(i.reference_object.get_connected_object_id_set())
2898
- for i in all_sources
2899
- if i.reference_object and i.reference_net.name == common_reference
2900
- ]
2901
- if len(setList) != len(all_sources):
2065
+ layout_inst = self.layout.layout_instance
2066
+ layout_obj_inst = layout_inst.get_layout_obj_instance_in_context(all_sources[0], None) # 2nd arg was []
2067
+ connected_objects = [loi.layout_obj.id for loi in layout_inst.get_connected_objects(layout_obj_inst, True)]
2068
+ connected_primitives = [self.modeler.get_primitive(obj, edb_uid=False) for obj in connected_objects]
2069
+ connected_primitives = [item for item in connected_primitives if item is not None]
2070
+ set_list = list(set([obj.net_name for obj in connected_primitives]))
2071
+ if len(set_list) != len(all_sources):
2902
2072
  self.logger.error("No Reference found.")
2903
2073
  return False
2904
2074
  cmps = [
2905
2075
  i
2906
2076
  for i in list(self.components.resistors.values())
2907
- if i.numpins == 2 and common_reference in i.nets and self._decompose_variable_value(i.res_value) <= 1
2077
+ if i.num_pins == 2 and common_reference in i.nets and i.res_value <= 1
2908
2078
  ]
2909
2079
  cmps.extend(
2910
- [i for i in list(self.components.inductors.values()) if i.numpins == 2 and common_reference in i.nets]
2080
+ [i for i in list(self.components.inductors.values()) if i.num_pins == 2 and common_reference in i.nets]
2911
2081
  )
2912
2082
 
2913
2083
  for cmp in cmps:
2914
2084
  found = False
2915
- ids = [i.id for i in cmp.pinlist]
2916
- for list_obj in setList:
2085
+ ids = [v.id for i, v in cmp.pins.items()]
2086
+ for list_obj in set_list:
2917
2087
  if len(set(ids).intersection(list_obj)) == 1:
2918
- for list_obj2 in setList:
2088
+ for list_obj2 in set_list:
2919
2089
  if list_obj2 != list_obj and len(set(ids).intersection(list_obj)) == 1:
2920
2090
  if (ids[0] in list_obj and ids[1] in list_obj2) or (
2921
2091
  ids[1] in list_obj and ids[0] in list_obj2
2922
2092
  ):
2923
- setList[setList.index(list_obj)] = list_obj.union(list_obj2)
2924
- setList[setList.index(list_obj2)] = list_obj.union(list_obj2)
2093
+ set_list[set_list.index(list_obj)] = list_obj.union(list_obj2)
2094
+ set_list[set_list.index(list_obj2)] = list_obj.union(list_obj2)
2925
2095
  found = True
2926
2096
  break
2927
2097
  if found:
2928
2098
  break
2929
2099
 
2930
2100
  # Get the set intersections for all the ID sets.
2931
- iDintersection = set.intersection(*setList)
2101
+ set_list = set(set_list)
2102
+ iDintersection = set.intersection(set_list)
2932
2103
  self.logger.info_timer(f"Terminal reference primitive IDs total intersections = {len(iDintersection)}\n\n")
2933
2104
 
2934
2105
  # If the intersections are non-zero, the terminal references are connected.