pyedb 0.59.0__py3-none-any.whl → 0.61.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 (318) 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 +36 -8
  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 +9 -7
  32. pyedb/dotnet/database/cell/hierarchy/hierarchy_obj.py +1 -1
  33. pyedb/dotnet/database/cell/hierarchy/model.py +2 -29
  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 +11 -15
  37. pyedb/dotnet/database/cell/hierarchy/spice_model.py +14 -8
  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 +6 -2
  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 +6 -4
  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 +3 -2
  86. pyedb/dotnet/database/net_class.py +1 -1
  87. pyedb/dotnet/database/nets.py +1 -1
  88. pyedb/dotnet/database/padstack.py +188 -2
  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 +119 -123
  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 +22 -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 +2 -2
  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 +17 -10
  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 +209 -9
  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 +111 -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 +230 -990
  221. pyedb/grpc/edb_init.py +1 -1
  222. pyedb/grpc/rpc_session.py +17 -4
  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/__init__.py +21 -0
  302. pyedb/workflows/job_manager/__init__.py +21 -0
  303. pyedb/workflows/job_manager/backend/__init__.py +21 -0
  304. pyedb/workflows/job_manager/backend/job_manager_handler.py +910 -0
  305. pyedb/workflows/job_manager/backend/job_submission.py +1169 -0
  306. pyedb/workflows/job_manager/backend/service.py +1663 -0
  307. pyedb/workflows/job_manager/backend/start_service.py +86 -0
  308. pyedb/workflows/job_manager/backend/submit_job_on_scheduler.py +168 -0
  309. pyedb/workflows/job_manager/backend/submit_local_job.py +166 -0
  310. pyedb/workflows/sipi/hfss_auto_configuration.py +1 -1
  311. pyedb/workflows/utilities/__init__.py +21 -0
  312. pyedb/workflows/utilities/cutout.py +1428 -0
  313. pyedb/workflows/utilities/hfss_log_parser.py +446 -0
  314. {pyedb-0.59.0.dist-info → pyedb-0.61.0.dist-info}/METADATA +7 -4
  315. pyedb-0.61.0.dist-info/RECORD +318 -0
  316. {pyedb-0.59.0.dist-info → pyedb-0.61.0.dist-info}/licenses/LICENSE +7 -7
  317. pyedb-0.59.0.dist-info/RECORD +0 -306
  318. {pyedb-0.59.0.dist-info → pyedb-0.61.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,14 @@ 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.job_manager.backend.job_manager_handler import JobManagerHandler
139
+ from pyedb.workflows.utilities.cutout import Cutout
138
140
 
139
141
  os.environ["no_proxy"] = "localhost,127.0.0.1"
140
142
 
@@ -375,6 +377,30 @@ class Edb(EdbInit):
375
377
  def ansys_em_path(self):
376
378
  return self.base_path
377
379
 
380
+ @staticmethod
381
+ def number_with_units(value, units=None):
382
+ """Convert a number to a string with units. If value is a string, it's returned as is.
383
+
384
+ Parameters
385
+ ----------
386
+ value : float, int, str
387
+ Input number or string.
388
+ units : optional
389
+ Units for formatting. The default is ``None``, which uses ``"meter"``.
390
+
391
+ Returns
392
+ -------
393
+ str
394
+ String concatenating the value and unit.
395
+
396
+ """
397
+ if units is None:
398
+ units = "meter"
399
+ if isinstance(value, str):
400
+ return value
401
+ else:
402
+ return "{0}{1}".format(value, units)
403
+
378
404
  def _check_remove_project_files(self, edbpath: str, remove_existing_aedt: bool) -> None:
379
405
  aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
380
406
  files = [aedt_file, aedt_file + ".lock"]
@@ -405,6 +431,7 @@ class Edb(EdbInit):
405
431
  self._source_excitation = SourceExcitation(self)
406
432
  self._differential_pairs = DifferentialPairs(self)
407
433
  self._extended_nets = ExtendedNets(self)
434
+ self._job_manager = JobManagerHandler(self)
408
435
 
409
436
  def value(self, val) -> float:
410
437
  """Convert a value into a pyedb value."""
@@ -414,6 +441,17 @@ class Edb(EdbInit):
414
441
  context = self.active_cell if not str(val).startswith("$") else self.active_db
415
442
  return Value(GrpcValue(val, context), context)
416
443
 
444
+ @property
445
+ def job_manager(self):
446
+ """Job manager for handling simulation tasks.
447
+
448
+ Returns
449
+ -------
450
+ :class:`JobManagerHandler <pyedb.workflows.job_manager.job_manager_handler.JobManagerHandler>`
451
+ Job manager instance for submitting and managing simulation jobs.
452
+ """
453
+ return self._job_manager
454
+
417
455
  @property
418
456
  def cell_names(self) -> List[str]:
419
457
  """List of all cell names in the database.
@@ -847,6 +885,62 @@ class Edb(EdbInit):
847
885
  self.edbpath = os.path.join(working_dir, aedb_name)
848
886
  return self.open_edb()
849
887
 
888
+ def import_vlctech_stackup(
889
+ self,
890
+ vlctech_file,
891
+ working_dir="",
892
+ export_xml=None,
893
+ ):
894
+ """Import a vlc.tech file and generate an ``edb.def`` file in the working directory containing only the stackup.
895
+
896
+ Parameters
897
+ ----------
898
+ vlctech_file : str
899
+ Full path to the technology stackup file. It must be vlc.tech.
900
+ working_dir : str, optional
901
+ Directory in which to create the ``aedb`` folder. The name given to the AEDB file
902
+ is the same as the name of the board file.
903
+ export_xml : str, optional
904
+ Export technology file in XML control file format.
905
+
906
+ Returns
907
+ -------
908
+ Full path to the AEDB file : str
909
+
910
+ """
911
+ if not working_dir:
912
+ working_dir = os.path.dirname(vlctech_file)
913
+ command = os.path.join(self.base_path, "helic", "tools", "raptorh", "bin", "make-edb")
914
+ if is_windows:
915
+ command += ".exe"
916
+ else:
917
+ os.environ["HELIC_ROOT"] = os.path.join(self.base_path, "helic")
918
+ cmd_make_edb = [
919
+ command,
920
+ "-t",
921
+ "{}".format(vlctech_file),
922
+ "-o",
923
+ "{}".format(os.path.join(working_dir, "vlctech")),
924
+ ]
925
+ if export_xml:
926
+ cmd_make_edb.extend(["-x", "{}".format(export_xml)])
927
+
928
+ try:
929
+ subprocess.run(cmd_make_edb, check=True) # nosec
930
+ except subprocess.CalledProcessError as e: # nosec
931
+ raise RuntimeError(
932
+ "Failed to create edb. Please check if the executable is present in the base path."
933
+ ) from e
934
+
935
+ if not os.path.exists(os.path.join(working_dir, "vlctech.aedb")):
936
+ self.logger.error("Failed to create edb. Please check if the executable is present in the base path.")
937
+ return False
938
+ else:
939
+ self.logger.info("edb successfully created.")
940
+ self.edbpath = os.path.join(working_dir, "vlctech.aedb")
941
+ self.open()
942
+ return self.edbpath
943
+
850
944
  def export_to_ipc2581(self, ipc_path=None, units="MILLIMETER") -> str:
851
945
  """Export design to IPC2581 format.
852
946
 
@@ -1426,253 +1520,18 @@ class Edb(EdbInit):
1426
1520
  self.edbpath = temp_inputGDS + ".aedb"
1427
1521
  return self.open()
1428
1522
 
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
-
1523
+ @deprecate_argument_name({"signal_list": "signal_nets", "reference_list": "reference_nets"})
1665
1524
  def cutout(
1666
1525
  self,
1667
- signal_list=None,
1668
- reference_list=None,
1526
+ signal_nets=None,
1527
+ reference_nets=None,
1669
1528
  extent_type="ConvexHull",
1670
1529
  expansion_size=0.002,
1671
1530
  use_round_corner=False,
1672
1531
  output_aedb_path=None,
1673
1532
  open_cutout_at_end=True,
1674
1533
  use_pyaedt_cutout=True,
1675
- number_of_threads=4,
1534
+ number_of_threads=1,
1676
1535
  use_pyaedt_extent_computing=True,
1677
1536
  extent_defeature=0,
1678
1537
  remove_single_pin_components=False,
@@ -1689,757 +1548,142 @@ class Edb(EdbInit):
1689
1548
  keep_lines_as_path=False,
1690
1549
  include_voids_in_extents=False,
1691
1550
  ):
1692
- """Create layout cutout with various options.
1551
+ """Create a cutout using an approach entirely based on PyAEDT.
1552
+ This method replaces all legacy cutout methods in PyAEDT.
1553
+ It does in sequence:
1554
+ - delete all nets not in list,
1555
+ - create a extent of the nets,
1556
+ - check and delete all vias not in the extent,
1557
+ - check and delete all the primitives not in extent,
1558
+ - check and intersect all the primitives that intersect the extent.
1693
1559
 
1694
1560
  Parameters
1695
1561
  ----------
1696
- signal_list : list, optional
1697
- Signal nets to include.
1698
- reference_list : list, optional
1699
- Reference nets to include.
1562
+ signal_nets : list
1563
+ List of signal strings.
1564
+ reference_nets : list, optional
1565
+ List of references to add. The default is ``["GND"]``.
1700
1566
  extent_type : str, optional
1701
- Cutout type ("Conforming", "ConvexHull", "Bounding").
1702
- expansion_size : float, optional
1703
- Boundary expansion size (meters).
1567
+ Type of the extension. Options are ``"Conforming"``, ``"ConvexHull"``, and
1568
+ ``"Bounding"``. The default is ``"Conforming"``.
1569
+ expansion_size : float, str, optional
1570
+ Expansion size ratio in meters. The default is ``0.002``.
1704
1571
  use_round_corner : bool, optional
1705
- Use rounded corners. Default False.
1572
+ Whether to use round corners. The default is ``False``.
1706
1573
  output_aedb_path : str, optional
1707
- Output AEDB path.
1574
+ Full path and name for the new AEDB file. If None, then current aedb will be cutout.
1708
1575
  open_cutout_at_end : bool, optional
1709
- Open cutout when finished. Default True.
1576
+ Whether to open the cutout at the end. The default is ``True``.
1710
1577
  use_pyaedt_cutout : bool, optional
1711
- Use PyAEDT cutout method. Default True.
1578
+ Whether to use new PyAEDT cutout method or EDB API method.
1579
+ New method is faster than native API method since it benefits of multithread.
1712
1580
  number_of_threads : int, optional
1713
- Thread count for PyAEDT cutout.
1581
+ Number of thread to use. Default is 4. Valid only if ``use_pyaedt_cutout`` is set to ``True``.
1714
1582
  use_pyaedt_extent_computing : bool, optional
1715
- Use PyAEDT extent computation. Default True.
1583
+ Whether to use legacy extent computing (experimental) or EDB API.
1716
1584
  extent_defeature : float, optional
1717
- Geometry simplification factor.
1585
+ Defeature the cutout before applying it to produce simpler geometry for mesh (Experimental).
1586
+ It applies only to Conforming bounding box. Default value is ``0`` which disable it.
1718
1587
  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.
1588
+ Remove all Single Pin RLC after the cutout is completed. Default is `False`.
1589
+ custom_extent : list
1590
+ Points list defining the cutout shape. This setting will override `extent_type` field.
1591
+ custom_extent_units : str
1592
+ Units of the point list. The default is ``"mm"``. Valid only if `custom_extend` is provided.
1724
1593
  include_partial_instances : bool, optional
1725
- Include partial padstack instances. Default False.
1726
- keep_voids : bool, optional
1727
- Preserve voids in cutout. Default True.
1594
+ Whether to include padstack instances that have bounding boxes intersecting with point list polygons.
1595
+ This operation may slow down the cutout export.Valid only if `custom_extend` and
1596
+ `use_pyaedt_cutout` is provided.
1597
+ keep_voids : bool
1598
+ Boolean used for keep or not the voids intersecting the polygon used for clipping the layout.
1599
+ Default value is ``True``, ``False`` will remove the voids.Valid only if `custom_extend` is provided.
1728
1600
  check_terminals : bool, optional
1729
- Verify terminal references. Default False.
1601
+ Whether to check for all reference terminals and increase extent to include them into the cutout.
1602
+ This applies to components which have a model (spice, touchstone or netlist) associated.
1730
1603
  include_pingroups : bool, optional
1731
- Include pin groups. Default False.
1604
+ Whether to check for all pingroups terminals and increase extent to include them into the cutout.
1605
+ It requires ``check_terminals``.
1732
1606
  expansion_factor : int, optional
1733
- Auto-expansion factor. Default 0 (disabled).
1607
+ The method computes a float representing the largest number between
1608
+ the dielectric thickness or trace width multiplied by the expansion_factor factor.
1609
+ The trace width search is limited to nets with ports attached. Works only if `use_pyaedt_cutout`.
1610
+ Default is `0` to disable the search.
1734
1611
  maximum_iterations : int, optional
1735
- Max auto-expansion iterations. Default 10.
1612
+ Maximum number of iterations before stopping a search for a cutout with an error.
1613
+ Default is `10`.
1736
1614
  preserve_components_with_model : bool, optional
1737
- Keep components with models. Default False.
1615
+ Whether to preserve all pins of components that have associated models (Spice or NPort).
1616
+ This parameter is applicable only for a PyAEDT cutout (except point list).
1738
1617
  simple_pad_check : bool, optional
1739
- Use simplified pad checking. Default True.
1618
+ Whether to use the center of the pad to find the intersection with extent or use the bounding box.
1619
+ Second method is much slower and requires to disable multithread on padstack removal.
1620
+ Default is `True`.
1740
1621
  keep_lines_as_path : bool, optional
1741
- Preserve paths as lines. Default False.
1622
+ Whether to keep the lines as Path after they are cutout or convert them to PolygonData.
1623
+ This feature works only in Electronics Desktop (3D Layout).
1624
+ If the flag is set to ``True`` it can cause issues in SiWave once the Edb is imported.
1625
+ Default is ``False`` to generate PolygonData of cut lines.
1742
1626
  include_voids_in_extents : bool, optional
1743
- Include voids in extent calculation. Default False.
1627
+ Whether to compute and include voids in pyaedt extent before the cutout. Cutout time can be affected.
1628
+ It works only with Conforming cutout.
1629
+ Default is ``False`` to generate extent without voids.
1630
+
1744
1631
 
1745
1632
  Returns
1746
1633
  -------
1747
- list or bool
1748
- Cutout boundary points if successful, False otherwise.
1634
+ List
1635
+ List of coordinate points defining the extent used for clipping the design. If it failed return an empty
1636
+ list.
1749
1637
 
1750
1638
  Examples
1751
1639
  --------
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]
1640
+ >>> from pyedb import Edb
1641
+ >>> edb = Edb(r"C:\\test.aedb", version="2022.2")
1642
+ >>> edb.logger.info_timer("Edb Opening")
1643
+ >>> edb.logger.reset_timer()
1644
+ >>> start = time.time()
1645
+ >>> signal_list = []
1646
+ >>> for net in edb.nets.netlist:
1647
+ >>> if "3V3" in net:
1648
+ >>> signal_list.append(net)
1649
+ >>> power_list = ["PGND"]
1650
+ >>> edb.cutout(signal_nets=signal_list, reference_nets=power_list, extent_type="Conforming")
1651
+ >>> end_time = str((time.time() - start) / 60)
1652
+ >>> edb.logger.info("Total legacy cutout time in min %s", end_time)
1653
+ >>> edb.nets.plot(signal_list, None, color_by_net=True)
1654
+ >>> edb.nets.plot(power_list, None, color_by_net=True)
1655
+ >>> edb.save()
1656
+ >>> edb.close()
1657
+
1658
+
1659
+ """
1660
+ cutout = Cutout(self)
1661
+ cutout.expansion_size = expansion_size
1662
+ cutout.signals = signal_nets
1663
+ cutout.references = reference_nets
1664
+ cutout.extent_type = extent_type
1665
+ cutout.expansion_size = expansion_size
1666
+ cutout.use_round_corner = use_round_corner
1667
+ cutout.output_file = output_aedb_path
1668
+ cutout.open_cutout_at_end = open_cutout_at_end
1669
+ cutout.use_pyaedt_cutout = use_pyaedt_cutout
1670
+ cutout.number_of_threads = number_of_threads
1671
+ cutout.use_pyaedt_extent_computing = use_pyaedt_extent_computing
1672
+ cutout.extent_defeatured = extent_defeature
1673
+ cutout.remove_single_pin_components = remove_single_pin_components
1674
+ cutout.custom_extent = custom_extent
1675
+ cutout.custom_extent_units = custom_extent_units
1676
+ cutout.include_partial_instances = include_partial_instances
1677
+ cutout.keep_voids = keep_voids
1678
+ cutout.check_terminals = check_terminals
1679
+ cutout.include_pingroups = include_pingroups
1680
+ cutout.expansion_factor = expansion_factor
1681
+ cutout.maximum_iterations = maximum_iterations
1682
+ cutout.preserve_components_with_model = preserve_components_with_model
1683
+ cutout.simple_pad_check = simple_pad_check
1684
+ cutout.keep_lines_as_path = keep_lines_as_path
1685
+ cutout.include_voids_in_extents = include_voids_in_extents
1686
+ return cutout.run()
2443
1687
 
2444
1688
  @staticmethod
2445
1689
  def write_export3d_option_config_file(path_to_output, config_dictionaries=None):
@@ -2880,55 +2124,51 @@ class Edb(EdbInit):
2880
2124
  self.logger.reset_timer()
2881
2125
  if not common_reference:
2882
2126
  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
- )
2127
+ common_reference = list(set([i.net.name for i in ref_terminals]))
2886
2128
  if len(common_reference) > 1:
2887
- self.logger.error("More than 1 reference found.")
2888
- return False
2129
+ raise ValueError("Multiple reference nets found. Please specify one.")
2889
2130
  if not common_reference:
2890
- self.logger.error("No Reference found.")
2891
- return False
2892
-
2131
+ raise ValueError("No reference net found. Please specify one.")
2893
2132
  common_reference = common_reference[0]
2894
2133
  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):
2134
+ layout_inst = self.layout.layout_instance
2135
+ layout_obj_inst = layout_inst.get_layout_obj_instance_in_context(all_sources[0], None) # 2nd arg was []
2136
+ connected_objects = [loi.layout_obj.id for loi in layout_inst.get_connected_objects(layout_obj_inst, True)]
2137
+ connected_primitives = [self.modeler.get_primitive(obj, edb_uid=False) for obj in connected_objects]
2138
+ connected_primitives = [item for item in connected_primitives if item is not None]
2139
+ set_list = list(set([obj.net_name for obj in connected_primitives]))
2140
+ if len(set_list) != len(all_sources):
2902
2141
  self.logger.error("No Reference found.")
2903
2142
  return False
2904
2143
  cmps = [
2905
2144
  i
2906
2145
  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
2146
+ if i.num_pins == 2 and common_reference in i.nets and i.res_value <= 1
2908
2147
  ]
2909
2148
  cmps.extend(
2910
- [i for i in list(self.components.inductors.values()) if i.numpins == 2 and common_reference in i.nets]
2149
+ [i for i in list(self.components.inductors.values()) if i.num_pins == 2 and common_reference in i.nets]
2911
2150
  )
2912
2151
 
2913
2152
  for cmp in cmps:
2914
2153
  found = False
2915
- ids = [i.id for i in cmp.pinlist]
2916
- for list_obj in setList:
2154
+ ids = [v.id for i, v in cmp.pins.items()]
2155
+ for list_obj in set_list:
2917
2156
  if len(set(ids).intersection(list_obj)) == 1:
2918
- for list_obj2 in setList:
2157
+ for list_obj2 in set_list:
2919
2158
  if list_obj2 != list_obj and len(set(ids).intersection(list_obj)) == 1:
2920
2159
  if (ids[0] in list_obj and ids[1] in list_obj2) or (
2921
2160
  ids[1] in list_obj and ids[0] in list_obj2
2922
2161
  ):
2923
- setList[setList.index(list_obj)] = list_obj.union(list_obj2)
2924
- setList[setList.index(list_obj2)] = list_obj.union(list_obj2)
2162
+ set_list[set_list.index(list_obj)] = list_obj.union(list_obj2)
2163
+ set_list[set_list.index(list_obj2)] = list_obj.union(list_obj2)
2925
2164
  found = True
2926
2165
  break
2927
2166
  if found:
2928
2167
  break
2929
2168
 
2930
2169
  # Get the set intersections for all the ID sets.
2931
- iDintersection = set.intersection(*setList)
2170
+ set_list = set(set_list)
2171
+ iDintersection = set.intersection(set_list)
2932
2172
  self.logger.info_timer(f"Terminal reference primitive IDs total intersections = {len(iDintersection)}\n\n")
2933
2173
 
2934
2174
  # If the intersections are non-zero, the terminal references are connected.
@@ -3956,7 +3196,7 @@ class Edb(EdbInit):
3956
3196
  except subprocess.CalledProcessError as e: # nosec
3957
3197
  raise RuntimeError(
3958
3198
  "EDBDiff.exe execution failed. Please check if the executable is present in the base path."
3959
- )
3199
+ ) from e
3960
3200
 
3961
3201
  if not os.path.exists(os.path.join(results, "EDBDiff.csv")):
3962
3202
  self.logger.error("Comparison execution failed")