pyedb 0.58.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.
- pyedb/__init__.py +23 -1
- pyedb/common/__init__.py +21 -0
- pyedb/common/nets.py +22 -0
- pyedb/component_libraries/ansys_components.py +22 -0
- pyedb/configuration/__init__.py +21 -0
- pyedb/configuration/cfg_boundaries.py +1 -1
- pyedb/configuration/cfg_common.py +1 -1
- pyedb/configuration/cfg_components.py +1 -1
- pyedb/configuration/cfg_data.py +1 -1
- pyedb/configuration/cfg_general.py +1 -1
- pyedb/configuration/cfg_modeler.py +1 -1
- pyedb/configuration/cfg_nets.py +1 -1
- pyedb/configuration/cfg_operations.py +1 -1
- pyedb/configuration/cfg_package_definition.py +1 -1
- pyedb/configuration/cfg_padstacks.py +1 -1
- pyedb/configuration/cfg_pin_groups.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +3 -2
- pyedb/configuration/cfg_s_parameter_models.py +1 -1
- pyedb/configuration/cfg_setup.py +5 -1
- pyedb/configuration/cfg_spice_models.py +1 -1
- pyedb/configuration/cfg_stackup.py +1 -1
- pyedb/configuration/cfg_terminals.py +22 -0
- pyedb/configuration/configuration.py +6 -5
- pyedb/dotnet/__init__.py +21 -0
- pyedb/dotnet/clr_module.py +22 -0
- pyedb/dotnet/database/Variables.py +1 -1
- pyedb/dotnet/database/__init__.py +22 -0
- pyedb/dotnet/database/cell/__init__.py +21 -0
- pyedb/dotnet/database/cell/connectable.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/__init__.py +21 -0
- pyedb/dotnet/database/cell/hierarchy/component.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/hierarchy_obj.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/netlist_model.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/pin_pair_model.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/s_parameter_model.py +1 -1
- pyedb/dotnet/database/cell/hierarchy/spice_model.py +1 -1
- pyedb/dotnet/database/cell/layout.py +5 -4
- pyedb/dotnet/database/cell/layout_obj.py +1 -1
- pyedb/dotnet/database/cell/primitive/__init__.py +22 -0
- pyedb/dotnet/database/cell/primitive/bondwire.py +1 -1
- pyedb/dotnet/database/cell/primitive/path.py +1 -1
- pyedb/dotnet/database/cell/primitive/primitive.py +1 -1
- pyedb/dotnet/database/cell/terminal/__init__.py +21 -0
- pyedb/dotnet/database/cell/terminal/bundle_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/edge_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/padstack_instance_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/point_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/terminal.py +7 -2
- pyedb/dotnet/database/cell/voltage_regulator.py +1 -1
- pyedb/dotnet/database/components.py +38 -40
- pyedb/dotnet/database/definition/__init__.py +21 -0
- pyedb/dotnet/database/definition/component_def.py +1 -1
- pyedb/dotnet/database/definition/component_model.py +1 -1
- pyedb/dotnet/database/definition/definition_obj.py +1 -1
- pyedb/dotnet/database/definition/definitions.py +1 -1
- pyedb/dotnet/database/definition/package_def.py +1 -1
- pyedb/dotnet/database/dotnet/__init__.py +21 -0
- pyedb/dotnet/database/dotnet/database.py +1 -1
- pyedb/dotnet/database/dotnet/primitive.py +1 -1
- pyedb/dotnet/database/edb_data/__init__.py +21 -0
- pyedb/dotnet/database/edb_data/control_file.py +1 -1
- pyedb/dotnet/database/edb_data/design_options.py +1 -1
- pyedb/dotnet/database/edb_data/edbvalue.py +1 -1
- pyedb/dotnet/database/edb_data/hfss_extent_info.py +1 -1
- pyedb/dotnet/database/edb_data/layer_data.py +1 -1
- pyedb/dotnet/database/edb_data/nets_data.py +1 -1
- pyedb/dotnet/database/edb_data/padstacks_data.py +1 -1
- pyedb/dotnet/database/edb_data/ports.py +1 -1
- pyedb/dotnet/database/edb_data/primitives_data.py +1 -1
- pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +1 -1
- pyedb/dotnet/database/edb_data/simulation_configuration.py +1 -1
- pyedb/dotnet/database/edb_data/sources.py +1 -1
- pyedb/dotnet/database/edb_data/utilities.py +1 -1
- pyedb/dotnet/database/edb_data/variables.py +1 -1
- pyedb/dotnet/database/general.py +4 -3
- pyedb/dotnet/database/geometry/__init__.py +21 -0
- pyedb/dotnet/database/geometry/point_data.py +1 -1
- pyedb/dotnet/database/geometry/polygon_data.py +1 -1
- pyedb/dotnet/database/hfss.py +1 -1
- pyedb/dotnet/database/layout_obj_instance.py +1 -1
- pyedb/dotnet/database/layout_validation.py +1 -1
- pyedb/dotnet/database/materials.py +1 -1
- pyedb/dotnet/database/modeler.py +1 -1
- pyedb/dotnet/database/net_class.py +1 -1
- pyedb/dotnet/database/nets.py +1 -1
- pyedb/dotnet/database/padstack.py +1 -1
- pyedb/dotnet/database/sim_setup_data/__init__.py +22 -0
- pyedb/dotnet/database/sim_setup_data/data/__init__.py +22 -0
- pyedb/dotnet/database/sim_setup_data/data/adaptive_frequency_data.py +1 -1
- pyedb/dotnet/database/sim_setup_data/data/mesh_operation.py +1 -1
- pyedb/dotnet/database/sim_setup_data/data/settings.py +3 -3
- pyedb/dotnet/database/sim_setup_data/data/sim_setup_info.py +1 -1
- pyedb/dotnet/database/sim_setup_data/data/simulation_settings.py +1 -1
- pyedb/dotnet/database/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
- pyedb/dotnet/database/sim_setup_data/data/sweep_data.py +1 -1
- pyedb/dotnet/database/sim_setup_data/io/__init__.py +21 -0
- pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
- pyedb/dotnet/database/siwave.py +1 -1
- pyedb/dotnet/database/stackup.py +1 -1
- pyedb/dotnet/database/utilities/__init__.py +22 -0
- pyedb/dotnet/database/utilities/heatsink.py +23 -0
- pyedb/dotnet/database/utilities/hfss_simulation_setup.py +1 -1
- pyedb/dotnet/database/utilities/obj_base.py +1 -1
- pyedb/dotnet/database/utilities/simulation_setup.py +1 -1
- pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +22 -0
- pyedb/dotnet/database/utilities/siwave_simulation_setup.py +22 -0
- pyedb/dotnet/database/utilities/value.py +1 -1
- pyedb/dotnet/edb.py +49 -122
- pyedb/edb_logger.py +1 -1
- pyedb/exceptions.py +22 -0
- pyedb/extensions/__init__.py +21 -0
- pyedb/extensions/create_cell_array.py +1 -1
- pyedb/extensions/via_design_backend.py +22 -0
- pyedb/generic/__init__.py +21 -0
- pyedb/generic/constants.py +1 -1
- pyedb/generic/data_handlers.py +22 -0
- pyedb/generic/design_types.py +1 -1
- pyedb/generic/filesystem.py +22 -0
- pyedb/generic/general_methods.py +1 -1
- pyedb/generic/grpc_warnings.py +22 -0
- pyedb/generic/plot.py +22 -0
- pyedb/generic/process.py +29 -2
- pyedb/generic/settings.py +1 -1
- pyedb/grpc/__init__.py +21 -0
- pyedb/grpc/database/__init__.py +21 -0
- pyedb/grpc/database/_typing.py +21 -0
- pyedb/grpc/database/components.py +9 -8
- pyedb/grpc/database/control_file.py +1 -1
- pyedb/grpc/database/definition/__init__.py +21 -0
- pyedb/grpc/database/definition/component_def.py +1 -1
- pyedb/grpc/database/definition/component_model.py +1 -1
- pyedb/grpc/database/definition/component_pin.py +1 -1
- pyedb/grpc/database/definition/materials.py +1 -1
- pyedb/grpc/database/definition/n_port_component_model.py +1 -1
- pyedb/grpc/database/definition/package_def.py +1 -1
- pyedb/grpc/database/definition/padstack_def.py +1 -1
- pyedb/grpc/database/definitions.py +1 -1
- pyedb/grpc/database/general.py +1 -1
- pyedb/grpc/database/geometry/__init__.py +21 -0
- pyedb/grpc/database/geometry/arc_data.py +1 -1
- pyedb/grpc/database/geometry/point_3d_data.py +1 -1
- pyedb/grpc/database/geometry/point_data.py +1 -1
- pyedb/grpc/database/geometry/polygon_data.py +1 -1
- pyedb/grpc/database/hfss.py +1 -1
- pyedb/grpc/database/hierarchy/__init__.py +21 -0
- pyedb/grpc/database/hierarchy/component.py +1 -1
- pyedb/grpc/database/hierarchy/model.py +1 -1
- pyedb/grpc/database/hierarchy/netlist_model.py +1 -1
- pyedb/grpc/database/hierarchy/pin_pair_model.py +1 -1
- pyedb/grpc/database/hierarchy/pingroup.py +1 -1
- pyedb/grpc/database/hierarchy/s_parameter_model.py +1 -1
- pyedb/grpc/database/hierarchy/spice_model.py +1 -1
- pyedb/grpc/database/layers/__init__.py +21 -0
- pyedb/grpc/database/layers/layer.py +22 -0
- pyedb/grpc/database/layers/stackup_layer.py +1 -1
- pyedb/grpc/database/layout/__init__.py +21 -0
- pyedb/grpc/database/layout/cell.py +1 -1
- pyedb/grpc/database/layout/layout.py +1 -1
- pyedb/grpc/database/layout/voltage_regulator.py +1 -1
- pyedb/grpc/database/layout_validation.py +1 -1
- pyedb/grpc/database/modeler.py +31 -9
- pyedb/grpc/database/net/__init__.py +21 -0
- pyedb/grpc/database/net/differential_pair.py +1 -1
- pyedb/grpc/database/net/extended_net.py +1 -1
- pyedb/grpc/database/net/net.py +1 -1
- pyedb/grpc/database/net/net_class.py +1 -1
- pyedb/grpc/database/nets.py +1 -1
- pyedb/grpc/database/padstacks.py +8 -3
- pyedb/grpc/database/ports/__init__.py +21 -0
- pyedb/grpc/database/ports/ports.py +1 -1
- pyedb/grpc/database/primitive/__init__.py +22 -0
- pyedb/grpc/database/primitive/bondwire.py +1 -1
- pyedb/grpc/database/primitive/circle.py +1 -1
- pyedb/grpc/database/primitive/padstack_instance.py +21 -16
- pyedb/grpc/database/primitive/path.py +1 -1
- pyedb/grpc/database/primitive/polygon.py +6 -4
- pyedb/grpc/database/primitive/primitive.py +1 -6
- pyedb/grpc/database/primitive/rectangle.py +1 -1
- pyedb/grpc/database/simulation_setup/__init__.py +21 -0
- pyedb/grpc/database/simulation_setup/adaptive_frequency.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_settings_options.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +1 -1
- pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/mesh_operation.py +1 -1
- pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +1 -1
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +1 -1
- pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +22 -0
- pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +1 -1
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +1 -1
- pyedb/grpc/database/simulation_setup/sweep_data.py +1 -1
- pyedb/grpc/database/siwave.py +1 -1
- pyedb/grpc/database/source_excitations.py +1 -1
- pyedb/grpc/database/stackup.py +1 -1
- pyedb/grpc/database/terminal/__init__.py +21 -0
- pyedb/grpc/database/terminal/bundle_terminal.py +1 -1
- pyedb/grpc/database/terminal/edge_terminal.py +1 -1
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +1 -1
- pyedb/grpc/database/terminal/pingroup_terminal.py +1 -1
- pyedb/grpc/database/terminal/point_terminal.py +1 -1
- pyedb/grpc/database/terminal/terminal.py +1 -1
- pyedb/grpc/database/utility/__init__.py +22 -0
- pyedb/grpc/database/utility/constants.py +1 -1
- pyedb/grpc/database/utility/heat_sink.py +1 -1
- pyedb/grpc/database/utility/hfss_extent_info.py +1 -1
- pyedb/grpc/database/utility/layout_statistics.py +1 -1
- pyedb/grpc/database/utility/rlc.py +1 -1
- pyedb/grpc/database/utility/sources.py +1 -1
- pyedb/grpc/database/utility/sweep_data_distribution.py +1 -1
- pyedb/grpc/database/utility/value.py +1 -1
- pyedb/grpc/database/utility/xml_control_file.py +1 -1
- pyedb/grpc/edb.py +167 -996
- pyedb/grpc/edb_init.py +8 -20
- pyedb/grpc/rpc_session.py +1 -1
- pyedb/ipc2581/__init__.py +21 -0
- pyedb/ipc2581/bom/__init__.py +21 -0
- pyedb/ipc2581/bom/bom.py +1 -1
- pyedb/ipc2581/bom/bom_item.py +1 -1
- pyedb/ipc2581/bom/characteristics.py +1 -1
- pyedb/ipc2581/bom/refdes.py +1 -1
- pyedb/ipc2581/content/__init__.py +21 -0
- pyedb/ipc2581/content/color.py +1 -1
- pyedb/ipc2581/content/content.py +1 -1
- pyedb/ipc2581/content/dictionary_color.py +1 -1
- pyedb/ipc2581/content/dictionary_fill.py +1 -1
- pyedb/ipc2581/content/dictionary_line.py +1 -1
- pyedb/ipc2581/content/entry_color.py +1 -1
- pyedb/ipc2581/content/entry_line.py +1 -1
- pyedb/ipc2581/content/fill.py +1 -1
- pyedb/ipc2581/content/layer_ref.py +1 -1
- pyedb/ipc2581/content/standard_geometries_dictionary.py +1 -1
- pyedb/ipc2581/ecad/__init__.py +21 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +21 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +1 -1
- pyedb/ipc2581/ecad/cad_data/cad_data.py +1 -1
- pyedb/ipc2581/ecad/cad_data/component.py +1 -1
- pyedb/ipc2581/ecad/cad_data/drill.py +1 -1
- pyedb/ipc2581/ecad/cad_data/feature.py +1 -1
- pyedb/ipc2581/ecad/cad_data/layer.py +1 -1
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +1 -1
- pyedb/ipc2581/ecad/cad_data/logical_net.py +1 -1
- pyedb/ipc2581/ecad/cad_data/outline.py +1 -1
- pyedb/ipc2581/ecad/cad_data/package.py +1 -1
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +1 -1
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +1 -1
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +1 -1
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +1 -1
- pyedb/ipc2581/ecad/cad_data/path.py +1 -1
- pyedb/ipc2581/ecad/cad_data/phy_net.py +1 -1
- pyedb/ipc2581/ecad/cad_data/pin.py +1 -1
- pyedb/ipc2581/ecad/cad_data/polygon.py +1 -1
- pyedb/ipc2581/ecad/cad_data/profile.py +1 -1
- pyedb/ipc2581/ecad/cad_data/stackup.py +1 -1
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +1 -1
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +1 -1
- pyedb/ipc2581/ecad/cad_data/step.py +1 -1
- pyedb/ipc2581/ecad/cad_header.py +1 -1
- pyedb/ipc2581/ecad/ecad.py +1 -1
- pyedb/ipc2581/ecad/spec.py +1 -1
- pyedb/ipc2581/history_record.py +1 -1
- pyedb/ipc2581/ipc2581.py +1 -1
- pyedb/ipc2581/logistic_header.py +1 -1
- pyedb/libraries/common.py +1 -1
- pyedb/libraries/rf_libraries/base_functions.py +1 -1
- pyedb/libraries/rf_libraries/planar_antennas.py +1 -1
- pyedb/misc/__init__.py +21 -0
- pyedb/misc/aedtlib_personalib_install.py +1 -1
- pyedb/misc/decorators.py +22 -0
- pyedb/misc/downloads.py +1 -1
- pyedb/misc/misc.py +1 -1
- pyedb/misc/siw_feature_config/__init__.py +21 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +21 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +22 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +22 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +22 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +22 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/fd_xtalk_scan_config.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/impedance_scan_config.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/net.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/pins.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +1 -1
- pyedb/misc/siw_feature_config/xtalk_scan/td_xtalk_config.py +1 -1
- pyedb/misc/utilities.py +1 -1
- pyedb/modeler/geometry_operators.py +22 -0
- pyedb/siwave.py +22 -0
- pyedb/siwave_core/__init__.py +21 -0
- pyedb/siwave_core/cpa/__init__.py +21 -0
- pyedb/siwave_core/cpa/simulation_setup_data_model.py +22 -0
- pyedb/siwave_core/icepak.py +1 -1
- pyedb/siwave_core/product_properties.py +23 -0
- pyedb/workflow.py +22 -0
- pyedb/workflows/sipi/hfss_auto_configuration.py +711 -0
- pyedb/workflows/utilities/__init__.py +0 -0
- pyedb/workflows/utilities/cutout.py +1428 -0
- {pyedb-0.58.0.dist-info → pyedb-0.60.0.dist-info}/METADATA +1 -1
- pyedb-0.60.0.dist-info/RECORD +308 -0
- {pyedb-0.58.0.dist-info → pyedb-0.60.0.dist-info}/licenses/LICENSE +7 -7
- pyedb-0.58.0.dist-info/RECORD +0 -305
- {pyedb-0.58.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 -
|
|
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
|
|
|
@@ -217,8 +218,8 @@ class Edb(EdbInit):
|
|
|
217
218
|
self.standalone = True
|
|
218
219
|
self.oproject = oproject
|
|
219
220
|
self._main = sys.modules["__main__"]
|
|
220
|
-
self.
|
|
221
|
-
if not float(self.
|
|
221
|
+
self.version = edbversion
|
|
222
|
+
if not float(self.version) >= 2025.2:
|
|
222
223
|
raise "EDB gRPC is only supported with ANSYS release 2025R2 and higher."
|
|
223
224
|
self.logger.info("Using PyEDB with gRPC as Beta until ANSYS 2025R2 official release.")
|
|
224
225
|
self.isaedtowned = isaedtowned
|
|
@@ -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"]
|
|
@@ -620,7 +645,7 @@ class Edb(EdbInit):
|
|
|
620
645
|
if self.db.is_null:
|
|
621
646
|
self.logger.warning("Error Opening db")
|
|
622
647
|
self._active_cell = None
|
|
623
|
-
self.logger.info(f"Database {os.path.split(self.edbpath)[-1]} Opened in {self.
|
|
648
|
+
self.logger.info(f"Database {os.path.split(self.edbpath)[-1]} Opened in {self.version}")
|
|
624
649
|
self._active_cell = None
|
|
625
650
|
if self.cellname:
|
|
626
651
|
for cell in self.active_db.circuit_cells:
|
|
@@ -1371,7 +1396,7 @@ class Edb(EdbInit):
|
|
|
1371
1396
|
Layer filter file.
|
|
1372
1397
|
"""
|
|
1373
1398
|
control_file_temp = os.path.join(tempfile.gettempdir(), os.path.split(inputGDS)[-1][:-3] + "xml")
|
|
1374
|
-
if float(self.
|
|
1399
|
+
if float(self.version) < 2024.1:
|
|
1375
1400
|
if not is_linux and tech_file:
|
|
1376
1401
|
self.logger.error("Technology files are supported only in Linux. Use control file instead.")
|
|
1377
1402
|
return False
|
|
@@ -1426,253 +1451,18 @@ class Edb(EdbInit):
|
|
|
1426
1451
|
self.edbpath = temp_inputGDS + ".aedb"
|
|
1427
1452
|
return self.open()
|
|
1428
1453
|
|
|
1429
|
-
|
|
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
|
-
|
|
1668
|
-
|
|
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=
|
|
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
|
|
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
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
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
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
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
|
-
|
|
1503
|
+
Whether to use round corners. The default is ``False``.
|
|
1706
1504
|
output_aedb_path : str, optional
|
|
1707
|
-
|
|
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
|
-
|
|
1507
|
+
Whether to open the cutout at the end. The default is ``True``.
|
|
1710
1508
|
use_pyaedt_cutout : bool, optional
|
|
1711
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1514
|
+
Whether to use legacy extent computing (experimental) or EDB API.
|
|
1716
1515
|
extent_defeature : float, optional
|
|
1717
|
-
|
|
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
|
|
1720
|
-
custom_extent : list
|
|
1721
|
-
|
|
1722
|
-
custom_extent_units : str
|
|
1723
|
-
Units
|
|
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
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1748
|
-
|
|
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
|
-
>>>
|
|
1753
|
-
>>> edb
|
|
1754
|
-
>>>
|
|
1755
|
-
>>>
|
|
1756
|
-
>>>
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
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
|
-
|
|
2888
|
-
return False
|
|
2060
|
+
raise ValueError("Multiple reference nets found. Please specify one.")
|
|
2889
2061
|
if not common_reference:
|
|
2890
|
-
|
|
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
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
]
|
|
2901
|
-
if len(
|
|
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.
|
|
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.
|
|
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 = [
|
|
2916
|
-
for list_obj in
|
|
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
|
|
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
|
-
|
|
2924
|
-
|
|
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
|
-
|
|
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.
|
|
@@ -3062,7 +2233,7 @@ class Edb(EdbInit):
|
|
|
3062
2233
|
if name in self.setups:
|
|
3063
2234
|
self.logger.error("Setup name already used in the layout")
|
|
3064
2235
|
return False
|
|
3065
|
-
version = self.
|
|
2236
|
+
version = self.version.split(".")
|
|
3066
2237
|
if int(version[0]) >= 2024 and int(version[-1]) >= 2 or int(version[0]) > 2024:
|
|
3067
2238
|
setup = GrpcRaptorXSimulationSetup.create(cell=self.active_cell, name=name)
|
|
3068
2239
|
return RaptorXSimulationSetup(self, setup)
|
|
@@ -3253,7 +2424,7 @@ class Edb(EdbInit):
|
|
|
3253
2424
|
defined_ports = {}
|
|
3254
2425
|
project_connexions = None
|
|
3255
2426
|
for edb_path, zone_info in zone_dict.items():
|
|
3256
|
-
edb = Edb(edbversion=self.
|
|
2427
|
+
edb = Edb(edbversion=self.version, edbpath=edb_path)
|
|
3257
2428
|
edb.cutout(
|
|
3258
2429
|
use_pyaedt_cutout=True,
|
|
3259
2430
|
custom_extent=zone_info[1],
|
|
@@ -3795,7 +2966,7 @@ class Edb(EdbInit):
|
|
|
3795
2966
|
"No padstack instances found inside evaluated voids during model creation for arbitrary waveports"
|
|
3796
2967
|
)
|
|
3797
2968
|
return False
|
|
3798
|
-
cloned_edb = Edb(edbpath=output_edb, edbversion=self.
|
|
2969
|
+
cloned_edb = Edb(edbpath=output_edb, edbversion=self.version, restart_rpc_server=True)
|
|
3799
2970
|
|
|
3800
2971
|
cloned_edb.stackup.add_layer(
|
|
3801
2972
|
layer_name="ports",
|