pyedb 0.38.0__py3-none-any.whl → 0.39.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +1 -1
- pyedb/common/nets.py +53 -139
- pyedb/configuration/cfg_components.py +1 -1
- pyedb/configuration/cfg_general.py +4 -2
- pyedb/configuration/cfg_modeler.py +1 -1
- pyedb/configuration/cfg_package_definition.py +1 -1
- pyedb/configuration/cfg_padstacks.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +56 -23
- pyedb/configuration/configuration.py +18 -1
- pyedb/dotnet/{application → database}/Variables.py +21 -21
- pyedb/dotnet/{edb_core → database}/cell/connectable.py +5 -5
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/component.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/hierarchy_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/layout.py +17 -17
- pyedb/dotnet/{edb_core → database}/cell/layout_obj.py +3 -3
- pyedb/dotnet/{edb_core → database}/cell/primitive/bondwire.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/primitive/path.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/primitive/primitive.py +14 -14
- pyedb/dotnet/{edb_core → database}/cell/terminal/bundle_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/edge_terminal.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/terminal/padstack_instance_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/pingroup_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/point_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/terminal.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/voltage_regulator.py +2 -2
- pyedb/dotnet/{edb_core → database}/components.py +101 -124
- pyedb/dotnet/{edb_core → database}/definition/component_def.py +5 -5
- pyedb/dotnet/{edb_core → database}/definition/component_model.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definition_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definitions.py +2 -2
- pyedb/dotnet/{edb_core → database}/definition/package_def.py +4 -4
- pyedb/dotnet/{edb_core → database}/dotnet/database.py +8 -8
- pyedb/dotnet/{edb_core → database}/dotnet/primitive.py +9 -9
- pyedb/dotnet/{edb_core → database}/edb_data/control_file.py +12 -12
- pyedb/dotnet/{edb_core → database}/edb_data/hfss_extent_info.py +7 -7
- pyedb/dotnet/{edb_core → database}/edb_data/nets_data.py +10 -13
- pyedb/dotnet/{edb_core → database}/edb_data/padstacks_data.py +16 -16
- pyedb/dotnet/{edb_core → database}/edb_data/ports.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/primitives_data.py +5 -5
- pyedb/dotnet/{edb_core → database}/edb_data/raptor_x_simulation_setup_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/simulation_configuration.py +10 -10
- pyedb/dotnet/{edb_core → database}/edb_data/sources.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/variables.py +1 -1
- pyedb/dotnet/{edb_core → database}/geometry/polygon_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/hfss.py +8 -8
- pyedb/dotnet/{edb_core → database}/layout_obj_instance.py +1 -1
- pyedb/dotnet/{edb_core → database}/layout_validation.py +2 -2
- pyedb/dotnet/{edb_core → database}/materials.py +23 -8
- pyedb/dotnet/{edb_core → database}/modeler.py +27 -27
- pyedb/dotnet/{edb_core → database}/net_class.py +8 -8
- pyedb/dotnet/{edb_core → database}/nets.py +12 -12
- pyedb/dotnet/{edb_core → database}/padstack.py +15 -15
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/mesh_operation.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/settings.py +3 -3
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sim_setup_info.py +2 -2
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/simulation_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sweep_data.py +1 -1
- pyedb/dotnet/{edb_core → database}/siwave.py +10 -10
- pyedb/dotnet/{edb_core → database}/stackup.py +12 -12
- pyedb/dotnet/{edb_core → database}/utilities/hfss_simulation_setup.py +15 -15
- pyedb/dotnet/{edb_core → database}/utilities/obj_base.py +1 -1
- pyedb/dotnet/{edb_core → database}/utilities/simulation_setup.py +3 -3
- pyedb/dotnet/{edb_core → database}/utilities/siwave_simulation_setup.py +6 -6
- pyedb/dotnet/edb.py +117 -112
- pyedb/generic/design_types.py +26 -19
- pyedb/generic/general_methods.py +1 -1
- pyedb/generic/plot.py +0 -2
- pyedb/grpc/database/__init__.py +1 -0
- pyedb/grpc/database/components.py +2354 -0
- pyedb/grpc/database/control_file.py +1277 -0
- pyedb/grpc/database/definition/component_def.py +218 -0
- pyedb/grpc/database/definition/component_model.py +39 -0
- pyedb/grpc/database/definition/component_pin.py +32 -0
- pyedb/grpc/database/definition/materials.py +1207 -0
- pyedb/grpc/database/definition/n_port_component_model.py +34 -0
- pyedb/grpc/database/definition/package_def.py +227 -0
- pyedb/grpc/database/definition/padstack_def.py +842 -0
- pyedb/grpc/database/definitions.py +70 -0
- pyedb/grpc/database/general.py +43 -0
- pyedb/grpc/database/geometry/__init__.py +0 -0
- pyedb/grpc/database/geometry/arc_data.py +93 -0
- pyedb/grpc/database/geometry/point_3d_data.py +79 -0
- pyedb/grpc/database/geometry/point_data.py +30 -0
- pyedb/grpc/database/geometry/polygon_data.py +133 -0
- pyedb/grpc/database/hfss.py +1279 -0
- pyedb/grpc/database/hierarchy/__init__.py +0 -0
- pyedb/grpc/database/hierarchy/component.py +1301 -0
- pyedb/grpc/database/hierarchy/model.py +31 -0
- pyedb/grpc/database/hierarchy/netlist_model.py +30 -0
- pyedb/grpc/database/hierarchy/pin_pair_model.py +128 -0
- pyedb/grpc/database/hierarchy/pingroup.py +245 -0
- pyedb/grpc/database/hierarchy/s_parameter_model.py +33 -0
- pyedb/grpc/database/hierarchy/spice_model.py +48 -0
- pyedb/grpc/database/layers/__init__.py +0 -0
- pyedb/grpc/database/layers/layer.py +57 -0
- pyedb/grpc/database/layers/stackup_layer.py +410 -0
- pyedb/grpc/database/layout/__init__.py +0 -0
- pyedb/grpc/database/layout/cell.py +30 -0
- pyedb/grpc/database/layout/layout.py +196 -0
- pyedb/grpc/database/layout/voltage_regulator.py +149 -0
- pyedb/grpc/database/layout_validation.py +319 -0
- pyedb/grpc/database/modeler.py +1468 -0
- pyedb/grpc/database/net/__init__.py +0 -0
- pyedb/grpc/database/net/differential_pair.py +138 -0
- pyedb/grpc/database/net/extended_net.py +340 -0
- pyedb/grpc/database/net/net.py +198 -0
- pyedb/grpc/database/net/net_class.py +93 -0
- pyedb/grpc/database/nets.py +633 -0
- pyedb/grpc/database/padstacks.py +1500 -0
- pyedb/grpc/database/ports/__init__.py +0 -0
- pyedb/grpc/database/ports/ports.py +396 -0
- pyedb/grpc/database/primitive/__init__.py +3 -0
- pyedb/grpc/database/primitive/bondwire.py +181 -0
- pyedb/grpc/database/primitive/circle.py +75 -0
- pyedb/grpc/database/primitive/padstack_instance.py +1116 -0
- pyedb/grpc/database/primitive/path.py +346 -0
- pyedb/grpc/database/primitive/polygon.py +276 -0
- pyedb/grpc/database/primitive/primitive.py +739 -0
- pyedb/grpc/database/primitive/rectangle.py +146 -0
- pyedb/grpc/database/simulation_setup/__init__.py +0 -0
- pyedb/grpc/database/simulation_setup/adaptive_frequency.py +33 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +32 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +59 -0
- pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +35 -0
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +61 -0
- pyedb/grpc/database/simulation_setup/hfss_settings_options.py +78 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +118 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +355 -0
- pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/mesh_operation.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +33 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +64 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +125 -0
- pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +34 -0
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +119 -0
- pyedb/grpc/database/simulation_setup/sweep_data.py +32 -0
- pyedb/grpc/database/siwave.py +1023 -0
- pyedb/grpc/database/source_excitations.py +2572 -0
- pyedb/grpc/database/stackup.py +2574 -0
- pyedb/grpc/database/terminal/__init__.py +0 -0
- pyedb/grpc/database/terminal/bundle_terminal.py +218 -0
- pyedb/grpc/database/terminal/edge_terminal.py +51 -0
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +171 -0
- pyedb/grpc/database/terminal/pingroup_terminal.py +162 -0
- pyedb/grpc/database/terminal/point_terminal.py +99 -0
- pyedb/grpc/database/terminal/terminal.py +470 -0
- pyedb/grpc/database/utility/__init__.py +3 -0
- pyedb/grpc/database/utility/constants.py +25 -0
- pyedb/grpc/database/utility/heat_sink.py +124 -0
- pyedb/grpc/database/utility/hfss_extent_info.py +448 -0
- pyedb/grpc/database/utility/layout_statistics.py +277 -0
- pyedb/grpc/database/utility/rlc.py +80 -0
- pyedb/grpc/database/utility/simulation_configuration.py +3305 -0
- pyedb/grpc/database/utility/sources.py +388 -0
- pyedb/grpc/database/utility/sweep_data_distribution.py +83 -0
- pyedb/grpc/database/utility/xml_control_file.py +1277 -0
- pyedb/grpc/edb.py +4151 -0
- pyedb/grpc/edb_init.py +481 -0
- pyedb/grpc/rpc_session.py +177 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +3 -2
- pyedb/ipc2581/ecad/cad_data/feature.py +4 -3
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +32 -20
- pyedb/ipc2581/ecad/cad_data/outline.py +3 -2
- pyedb/ipc2581/ecad/cad_data/package.py +4 -3
- pyedb/ipc2581/ecad/cad_data/path.py +82 -31
- pyedb/ipc2581/ecad/cad_data/polygon.py +122 -60
- pyedb/ipc2581/ecad/cad_data/profile.py +13 -12
- pyedb/ipc2581/ecad/cad_data/step.py +53 -21
- pyedb/ipc2581/ipc2581.py +47 -49
- pyedb/modeler/geometry_operators.py +1 -1
- {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/METADATA +5 -2
- pyedb-0.39.0.dist-info/RECORD +288 -0
- pyedb-0.38.0.dist-info/RECORD +0 -195
- /pyedb/dotnet/{edb_core → database}/__init__.py +0 -0
- /pyedb/dotnet/{application → database/cell}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell → database/cell/hierarchy}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/netlist_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/pin_pair_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/s_parameter_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/spice_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/primitive/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/hierarchy → database/cell/terminal}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/terminal → database/definition}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/definition → database/dotnet}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/dotnet → database/edb_data}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/design_options.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/edbvalue.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/layer_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/utilities.py +0 -0
- /pyedb/dotnet/{edb_core → database}/general.py +0 -0
- /pyedb/dotnet/{edb_core/edb_data → database/geometry}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/geometry/point_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/adaptive_frequency_data.py +0 -0
- /pyedb/dotnet/{edb_core/geometry → database/sim_setup_data/io}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/io/siwave.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/heatsink.py +0 -0
- /pyedb/{dotnet/edb_core/sim_setup_data/io → grpc/database/definition}/__init__.py +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/LICENSE +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
import math
|
|
24
|
+
|
|
25
|
+
from ansys.edb.core.definition.padstack_def import PadstackDef as GrpcPadstackDef
|
|
26
|
+
from ansys.edb.core.definition.padstack_def_data import (
|
|
27
|
+
PadGeometryType as GrpcPadGeometryType,
|
|
28
|
+
)
|
|
29
|
+
from ansys.edb.core.definition.padstack_def_data import (
|
|
30
|
+
PadstackHoleRange as GrpcPadstackHoleRange,
|
|
31
|
+
)
|
|
32
|
+
from ansys.edb.core.definition.padstack_def_data import PadType as GrpcPadType
|
|
33
|
+
import ansys.edb.core.geometry.polygon_data
|
|
34
|
+
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
35
|
+
from ansys.edb.core.hierarchy.structure3d import MeshClosure as GrpcMeshClosure
|
|
36
|
+
from ansys.edb.core.hierarchy.structure3d import Structure3D as GrpcStructure3D
|
|
37
|
+
from ansys.edb.core.primitive.primitive import Circle as GrpcCircle
|
|
38
|
+
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
39
|
+
|
|
40
|
+
from pyedb.generic.general_methods import generate_unique_name
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PadProperties:
|
|
44
|
+
"""Manages EDB functionalities for pad properties.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
edb_padstack :
|
|
49
|
+
|
|
50
|
+
layer_name : str
|
|
51
|
+
Name of the layer.
|
|
52
|
+
pad_type :
|
|
53
|
+
Type of the pad.
|
|
54
|
+
pedbpadstack : str
|
|
55
|
+
Inherited AEDT object.
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
>>> from pyedb import Edb
|
|
60
|
+
>>> edb = Edb(myedb, edbversion="2021.2")
|
|
61
|
+
>>> edb_pad_properties = edb.padstacks.definitions["MyPad"].pad_by_layer["TOP"]
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(self, edb_padstack, layer_name, pad_type, p_edb_padstack):
|
|
65
|
+
self._edb_object = edb_padstack
|
|
66
|
+
self._pedbpadstack = p_edb_padstack
|
|
67
|
+
self.layer_name = layer_name
|
|
68
|
+
self.pad_type = pad_type
|
|
69
|
+
self._edb_padstack = self._edb_object
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def _stackup_layers(self):
|
|
73
|
+
return self._pedbpadstack._stackup_layers
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def _edb(self):
|
|
77
|
+
return self._pedbpadstack._edb
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def _pad_parameter_value(self):
|
|
81
|
+
p_val = self._edb_padstack.get_pad_parameters(self.layer_name, GrpcPadType.REGULAR_PAD)
|
|
82
|
+
if isinstance(p_val[0], ansys.edb.core.geometry.polygon_data.PolygonData):
|
|
83
|
+
p_val = [GrpcPadGeometryType.PADGEOMTYPE_POLYGON] + [i for i in p_val]
|
|
84
|
+
return p_val
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def geometry_type(self):
|
|
88
|
+
"""Geometry type.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
int
|
|
93
|
+
Type of the geometry.
|
|
94
|
+
"""
|
|
95
|
+
return self._pad_parameter_value[0].value
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def _edb_geometry_type(self):
|
|
99
|
+
return self._pad_parameter_value[0]
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def shape(self):
|
|
103
|
+
"""Pad shape.
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
str
|
|
108
|
+
pad shape.
|
|
109
|
+
"""
|
|
110
|
+
return self._pad_parameter_value[0].name.split("_")[-1].lower()
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def parameters_values(self):
|
|
114
|
+
"""Parameters.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
list
|
|
119
|
+
List of parameters.
|
|
120
|
+
"""
|
|
121
|
+
try:
|
|
122
|
+
return [i.value for i in self._pad_parameter_value[1]]
|
|
123
|
+
except TypeError:
|
|
124
|
+
return []
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def parameters_values_string(self):
|
|
128
|
+
"""Parameters value in string format."""
|
|
129
|
+
try:
|
|
130
|
+
return [str(i) for i in self._pad_parameter_value[1]]
|
|
131
|
+
except TypeError:
|
|
132
|
+
return []
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def polygon_data(self):
|
|
136
|
+
"""Parameters.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
list
|
|
141
|
+
List of parameters.
|
|
142
|
+
"""
|
|
143
|
+
p = self._pad_parameter_value[1]
|
|
144
|
+
return p if isinstance(p, ansys.edb.core.geometry.polygon_data.PolygonData) else None
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def offset_x(self):
|
|
148
|
+
"""Offset for the X axis.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
str
|
|
153
|
+
Offset for the X axis.
|
|
154
|
+
"""
|
|
155
|
+
return self._pad_parameter_value[2].value
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def offset_y(self):
|
|
159
|
+
"""Offset for the Y axis.
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
str
|
|
164
|
+
Offset for the Y axis.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
return self._pad_parameter_value[3].value
|
|
168
|
+
|
|
169
|
+
@offset_x.setter
|
|
170
|
+
def offset_x(self, value):
|
|
171
|
+
self._update_pad_parameters_parameters(offsetx=value)
|
|
172
|
+
|
|
173
|
+
@offset_y.setter
|
|
174
|
+
def offset_y(self, value):
|
|
175
|
+
self._update_pad_parameters_parameters(offsety=value)
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def rotation(self):
|
|
179
|
+
"""Rotation.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
str
|
|
184
|
+
Value for the rotation.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
return self._pad_parameter_value[4].value
|
|
188
|
+
|
|
189
|
+
@rotation.setter
|
|
190
|
+
def rotation(self, value):
|
|
191
|
+
self._update_pad_parameters_parameters(rotation=value)
|
|
192
|
+
|
|
193
|
+
@rotation.setter
|
|
194
|
+
def rotation(self, value):
|
|
195
|
+
self._update_pad_parameters_parameters(rotation=value)
|
|
196
|
+
|
|
197
|
+
@parameters_values.setter
|
|
198
|
+
def parameters_values(self, value):
|
|
199
|
+
if isinstance(value, (float, str)):
|
|
200
|
+
value = [value]
|
|
201
|
+
self._update_pad_parameters_parameters(params=value)
|
|
202
|
+
|
|
203
|
+
def _update_pad_parameters_parameters(
|
|
204
|
+
self,
|
|
205
|
+
layer_name=None,
|
|
206
|
+
pad_type=None,
|
|
207
|
+
geom_type=None,
|
|
208
|
+
params=None,
|
|
209
|
+
offsetx=None,
|
|
210
|
+
offsety=None,
|
|
211
|
+
rotation=None,
|
|
212
|
+
):
|
|
213
|
+
if layer_name is None:
|
|
214
|
+
layer_name = self.layer_name
|
|
215
|
+
if pad_type is None:
|
|
216
|
+
pad_type = GrpcPadType.REGULAR_PAD
|
|
217
|
+
if geom_type is None:
|
|
218
|
+
geom_type = self.geometry_type
|
|
219
|
+
for k in GrpcPadGeometryType:
|
|
220
|
+
if k.value == geom_type:
|
|
221
|
+
geom_type = k
|
|
222
|
+
if params is None:
|
|
223
|
+
params = self._pad_parameter_value[1]
|
|
224
|
+
elif isinstance(params, list):
|
|
225
|
+
offsetx = [GrpcValue(i, self._pedbpadstack._pedb.db) for i in params]
|
|
226
|
+
if rotation is None:
|
|
227
|
+
rotation = self._pad_parameter_value[4]
|
|
228
|
+
elif isinstance(rotation, (str, float, int)):
|
|
229
|
+
rotation = GrpcValue(rotation, self._pedbpadstack._pedb.db)
|
|
230
|
+
if offsetx is None:
|
|
231
|
+
offsetx = self._pad_parameter_value[2]
|
|
232
|
+
elif isinstance(offsetx, (str, float, int)):
|
|
233
|
+
offsetx = GrpcValue(offsetx, self._pedbpadstack._pedb.db)
|
|
234
|
+
if offsety is None:
|
|
235
|
+
offsety = self._pad_parameter_value[3]
|
|
236
|
+
elif isinstance(offsety, (str, float, int)):
|
|
237
|
+
offsety = GrpcValue(offsety, self._pedbpadstack._pedb.db)
|
|
238
|
+
self._edb_padstack.set_pad_parameters(
|
|
239
|
+
layer=layer_name,
|
|
240
|
+
pad_type=pad_type,
|
|
241
|
+
type_geom=geom_type,
|
|
242
|
+
offset_x=GrpcValue(offsetx, self._pedbpadstack._pedb.db),
|
|
243
|
+
offset_y=GrpcValue(offsety, self._pedbpadstack._pedb.db),
|
|
244
|
+
rotation=GrpcValue(rotation, self._pedbpadstack._pedb.db),
|
|
245
|
+
sizes=[GrpcValue(i, self._pedbpadstack._pedb.db) for i in params],
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class PadstackDef(GrpcPadstackDef):
|
|
250
|
+
"""Manages EDB functionalities for a padstack.
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
edb_padstack :
|
|
255
|
+
|
|
256
|
+
ppadstack : str
|
|
257
|
+
Inherited AEDT object.
|
|
258
|
+
|
|
259
|
+
Examples
|
|
260
|
+
--------
|
|
261
|
+
>>> from pyedb import Edb
|
|
262
|
+
>>> edb = Edb(myedb, edbversion="2021.2")
|
|
263
|
+
>>> edb_padstack = edb.padstacks.definitions["MyPad"]
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
def __init__(self, pedb, edb_object):
|
|
267
|
+
super().__init__(edb_object.msg)
|
|
268
|
+
self._pedb = pedb
|
|
269
|
+
self._pad_by_layer = {}
|
|
270
|
+
self._antipad_by_layer = {}
|
|
271
|
+
self._thermalpad_by_layer = {}
|
|
272
|
+
self._bounding_box = []
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def instances(self):
|
|
276
|
+
"""Definitions Instances.
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
List[:class:`PadstackInstance <pyedb.grpc.database.primitive.padstack_instance.PadstackInstance>`]
|
|
281
|
+
List of PadstackInstance objects.
|
|
282
|
+
"""
|
|
283
|
+
return [i for i in list(self._pedb.padstacks.instances.values()) if i.padstack_def.name == self.name]
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def layers(self):
|
|
287
|
+
"""Layers.
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
list[str]
|
|
292
|
+
List of layer names.
|
|
293
|
+
"""
|
|
294
|
+
return self.data.layer_names
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def start_layer(self):
|
|
298
|
+
"""Starting layer.
|
|
299
|
+
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
str
|
|
303
|
+
Name of the starting layer.
|
|
304
|
+
"""
|
|
305
|
+
return self.layers[0]
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def stop_layer(self):
|
|
309
|
+
"""Stopping layer.
|
|
310
|
+
|
|
311
|
+
Returns
|
|
312
|
+
-------
|
|
313
|
+
str
|
|
314
|
+
Name of the stopping layer.
|
|
315
|
+
"""
|
|
316
|
+
return self.layers[-1]
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def hole_diameter(self):
|
|
320
|
+
"""Hole diameter.
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
float
|
|
325
|
+
Diameter value.
|
|
326
|
+
|
|
327
|
+
"""
|
|
328
|
+
try:
|
|
329
|
+
hole_parameter = self.data.get_hole_parameters()
|
|
330
|
+
if hole_parameter[0].name.lower() == "padgeomtype_circle":
|
|
331
|
+
return round(hole_parameter[1][0].value, 6)
|
|
332
|
+
except:
|
|
333
|
+
return 0.0
|
|
334
|
+
|
|
335
|
+
@hole_diameter.setter
|
|
336
|
+
def hole_diameter(self, value):
|
|
337
|
+
hole_parameter = self.data.get_hole_parameters()
|
|
338
|
+
if not isinstance(value, list):
|
|
339
|
+
value = [GrpcValue(value)]
|
|
340
|
+
else:
|
|
341
|
+
value = [GrpcValue(p) for p in value]
|
|
342
|
+
hole_size = value
|
|
343
|
+
geometry_type = hole_parameter[0]
|
|
344
|
+
hole_offset_x = hole_parameter[2]
|
|
345
|
+
hole_offset_y = hole_parameter[3]
|
|
346
|
+
if not isinstance(geometry_type, GrpcPolygonData):
|
|
347
|
+
hole_rotation = hole_parameter[4]
|
|
348
|
+
self.data.set_hole_parameters(
|
|
349
|
+
offset_x=hole_offset_x,
|
|
350
|
+
offset_y=hole_offset_y,
|
|
351
|
+
rotation=hole_rotation,
|
|
352
|
+
type_geom=geometry_type,
|
|
353
|
+
sizes=hole_size,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def hole_type(self):
|
|
358
|
+
"""Holy type.
|
|
359
|
+
|
|
360
|
+
Returns
|
|
361
|
+
-------
|
|
362
|
+
float
|
|
363
|
+
hole type.
|
|
364
|
+
|
|
365
|
+
"""
|
|
366
|
+
return self.data.get_hole_parameters()[0].value
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def edb_hole_type(self):
|
|
370
|
+
"""EDB hole type.
|
|
371
|
+
|
|
372
|
+
Returns
|
|
373
|
+
-------
|
|
374
|
+
str
|
|
375
|
+
Hole type.
|
|
376
|
+
|
|
377
|
+
"""
|
|
378
|
+
return self.data.get_hole_parameters()[0]
|
|
379
|
+
|
|
380
|
+
@property
|
|
381
|
+
def hole_offset_x(self):
|
|
382
|
+
"""Hole offset for the X axis.
|
|
383
|
+
|
|
384
|
+
Returns
|
|
385
|
+
-------
|
|
386
|
+
float
|
|
387
|
+
Hole offset value for the X axis.
|
|
388
|
+
"""
|
|
389
|
+
try:
|
|
390
|
+
return round(self.data.get_hole_parameters()[2].value, 6)
|
|
391
|
+
except:
|
|
392
|
+
return 0.0
|
|
393
|
+
|
|
394
|
+
@hole_offset_x.setter
|
|
395
|
+
def hole_offset_x(self, value):
|
|
396
|
+
hole_parameter = list(self.data.get_hole_parameters())
|
|
397
|
+
hole_parameter[2] = GrpcValue(value, self._pedb.db)
|
|
398
|
+
self.data.set_hole_parameters(
|
|
399
|
+
offset_x=hole_parameter[2],
|
|
400
|
+
offset_y=hole_parameter[3],
|
|
401
|
+
rotation=hole_parameter[4],
|
|
402
|
+
type_geom=hole_parameter[0],
|
|
403
|
+
sizes=hole_parameter[1],
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
@property
|
|
407
|
+
def hole_offset_y(self):
|
|
408
|
+
"""Hole offset for the Y axis.
|
|
409
|
+
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
float
|
|
413
|
+
Hole offset value for the Y axis.
|
|
414
|
+
"""
|
|
415
|
+
try:
|
|
416
|
+
return round(self.data.get_hole_parameters()[3].value, 6)
|
|
417
|
+
except:
|
|
418
|
+
return 0.0
|
|
419
|
+
|
|
420
|
+
@hole_offset_y.setter
|
|
421
|
+
def hole_offset_y(self, value):
|
|
422
|
+
hole_parameter = list(self.data.get_hole_parameters())
|
|
423
|
+
hole_parameter[3] = GrpcValue(value, self._pedb.db)
|
|
424
|
+
self.data.set_hole_parameters(
|
|
425
|
+
offset_x=hole_parameter[2],
|
|
426
|
+
offset_y=hole_parameter[3],
|
|
427
|
+
rotation=hole_parameter[4],
|
|
428
|
+
type_geom=hole_parameter[0],
|
|
429
|
+
sizes=hole_parameter[1],
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def hole_rotation(self):
|
|
434
|
+
"""Hole rotation.
|
|
435
|
+
|
|
436
|
+
Returns
|
|
437
|
+
-------
|
|
438
|
+
float
|
|
439
|
+
Value for the hole rotation.
|
|
440
|
+
"""
|
|
441
|
+
try:
|
|
442
|
+
return round(self.data.get_hole_parameters()[4].value, 6)
|
|
443
|
+
except:
|
|
444
|
+
return 0.0
|
|
445
|
+
|
|
446
|
+
@hole_rotation.setter
|
|
447
|
+
def hole_rotation(self, value):
|
|
448
|
+
hole_parameter = list(self.data.get_hole_parameters())
|
|
449
|
+
hole_parameter[4] = GrpcValue(value, self._pedb.db)
|
|
450
|
+
self.data.set_hole_parameters(
|
|
451
|
+
offset_x=hole_parameter[2],
|
|
452
|
+
offset_y=hole_parameter[3],
|
|
453
|
+
rotation=hole_parameter[4],
|
|
454
|
+
type_geom=hole_parameter[0],
|
|
455
|
+
sizes=hole_parameter[1],
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def pad_by_layer(self):
|
|
460
|
+
"""Pad by layer.
|
|
461
|
+
|
|
462
|
+
Returns
|
|
463
|
+
-------
|
|
464
|
+
Dict[str, :class:`PadProperties <pyedb.grpc.database.definition.padstack_def.PadProperties>`]
|
|
465
|
+
Dictionary with layer as key and PadProperties as value.
|
|
466
|
+
"""
|
|
467
|
+
if not self._pad_by_layer:
|
|
468
|
+
for layer in self.layers:
|
|
469
|
+
try:
|
|
470
|
+
self._pad_by_layer[layer] = PadProperties(self.data, layer, GrpcPadType.REGULAR_PAD, self)
|
|
471
|
+
except:
|
|
472
|
+
self._pad_by_layer[layer] = None
|
|
473
|
+
return self._pad_by_layer
|
|
474
|
+
|
|
475
|
+
@property
|
|
476
|
+
def antipad_by_layer(self):
|
|
477
|
+
"""Antipad by layer.
|
|
478
|
+
|
|
479
|
+
Returns
|
|
480
|
+
-------
|
|
481
|
+
Dict[str, :class:`PadProperties <pyedb.grpc.database.definition.padstack_def.PadProperties>`]
|
|
482
|
+
Dictionary with layer as key and PadProperties as value.
|
|
483
|
+
"""
|
|
484
|
+
if not self._antipad_by_layer:
|
|
485
|
+
for layer in self.layers:
|
|
486
|
+
try:
|
|
487
|
+
self._pad_by_layer[layer] = PadProperties(self.data, layer, GrpcPadType.ANTI_PAD, self)
|
|
488
|
+
except:
|
|
489
|
+
self._antipad_by_layer[layer] = None
|
|
490
|
+
return self._antipad_by_layer
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def thermalpad_by_layer(self):
|
|
494
|
+
"""Thermal by layer.
|
|
495
|
+
|
|
496
|
+
Returns
|
|
497
|
+
-------
|
|
498
|
+
Dict[str, :class:`PadProperties <pyedb.grpc.database.definition.padstack_def.PadProperties>`]
|
|
499
|
+
Dictionary with layer as key and PadProperties as value.
|
|
500
|
+
"""
|
|
501
|
+
if not self._thermalpad_by_layer:
|
|
502
|
+
for layer in self.layers:
|
|
503
|
+
try:
|
|
504
|
+
self._pad_by_layer[layer] = PadProperties(self.data, layer, GrpcPadType.THERMAL_PAD, self)
|
|
505
|
+
except:
|
|
506
|
+
self._thermalpad_by_layer[layer] = None
|
|
507
|
+
return self._thermalpad_by_layer
|
|
508
|
+
|
|
509
|
+
@property
|
|
510
|
+
def hole_plating_ratio(self):
|
|
511
|
+
"""Hole plating ratio.
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
float
|
|
516
|
+
Percentage for the hole plating.
|
|
517
|
+
"""
|
|
518
|
+
return round(self.data.plating_percentage.value, 6)
|
|
519
|
+
|
|
520
|
+
@hole_plating_ratio.setter
|
|
521
|
+
def hole_plating_ratio(self, ratio):
|
|
522
|
+
self.data.plating_percentage = GrpcValue(ratio)
|
|
523
|
+
|
|
524
|
+
@property
|
|
525
|
+
def hole_plating_thickness(self):
|
|
526
|
+
"""Hole plating thickness.
|
|
527
|
+
|
|
528
|
+
Returns
|
|
529
|
+
-------
|
|
530
|
+
float
|
|
531
|
+
Thickness of the hole plating if present.
|
|
532
|
+
"""
|
|
533
|
+
try:
|
|
534
|
+
if len(self.data.get_hole_parameters()) > 0:
|
|
535
|
+
return round((self.hole_diameter * self.hole_plating_ratio / 100) / 2, 6)
|
|
536
|
+
else:
|
|
537
|
+
return 0.0
|
|
538
|
+
except:
|
|
539
|
+
return 0.0
|
|
540
|
+
|
|
541
|
+
@hole_plating_thickness.setter
|
|
542
|
+
def hole_plating_thickness(self, value):
|
|
543
|
+
"""Hole plating thickness.
|
|
544
|
+
|
|
545
|
+
Returns
|
|
546
|
+
-------
|
|
547
|
+
float
|
|
548
|
+
Thickness of the hole plating if present.
|
|
549
|
+
"""
|
|
550
|
+
hr = 200 * GrpcValue(value).value / self.hole_diameter
|
|
551
|
+
self.hole_plating_ratio = hr
|
|
552
|
+
|
|
553
|
+
@property
|
|
554
|
+
def hole_finished_size(self):
|
|
555
|
+
"""Finished hole size.
|
|
556
|
+
|
|
557
|
+
Returns
|
|
558
|
+
-------
|
|
559
|
+
float
|
|
560
|
+
Finished size of the hole (Total Size + PlatingThickess*2).
|
|
561
|
+
"""
|
|
562
|
+
try:
|
|
563
|
+
if len(self.data.get_hole_parameters()) > 0:
|
|
564
|
+
return round(self.hole_diameter - (self.hole_plating_thickness * 2), 6)
|
|
565
|
+
else:
|
|
566
|
+
return 0.0
|
|
567
|
+
except:
|
|
568
|
+
return 0.0
|
|
569
|
+
|
|
570
|
+
@property
|
|
571
|
+
def hole_range(self):
|
|
572
|
+
"""Get hole range value from padstack definition.
|
|
573
|
+
|
|
574
|
+
Returns
|
|
575
|
+
-------
|
|
576
|
+
str
|
|
577
|
+
Possible returned values are ``"through"``, ``"begin_on_upper_pad"``,
|
|
578
|
+
``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"undefined"``.
|
|
579
|
+
"""
|
|
580
|
+
return self.data.hole_range.name.lower()
|
|
581
|
+
|
|
582
|
+
@hole_range.setter
|
|
583
|
+
def hole_range(self, value):
|
|
584
|
+
if isinstance(value, str):
|
|
585
|
+
if value == "through":
|
|
586
|
+
self.data.hole_range = GrpcPadstackHoleRange.THROUGH
|
|
587
|
+
elif value == "begin_on_upper_pad":
|
|
588
|
+
self.data.hole_range = GrpcPadstackHoleRange.BEGIN_ON_UPPER_PAD
|
|
589
|
+
elif value == "end_on_lower_pad":
|
|
590
|
+
self.data.hole_range = GrpcPadstackHoleRange.END_ON_LOWER_PAD
|
|
591
|
+
elif value == "upper_pad_to_lower_pad":
|
|
592
|
+
self.data.hole_range = GrpcPadstackHoleRange.UPPER_PAD_TO_LOWER_PAD
|
|
593
|
+
else: # pragma no cover
|
|
594
|
+
self.data.hole_range = GrpcPadstackHoleRange.UNKNOWN_RANGE
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def material(self):
|
|
598
|
+
"""Return hole material name."""
|
|
599
|
+
return self.data.material.value
|
|
600
|
+
|
|
601
|
+
@material.setter
|
|
602
|
+
def material(self, value):
|
|
603
|
+
self.data.material.value = value
|
|
604
|
+
|
|
605
|
+
def convert_to_3d_microvias(self, convert_only_signal_vias=True, hole_wall_angle=15, delete_padstack_def=True):
|
|
606
|
+
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
|
|
607
|
+
|
|
608
|
+
Parameters
|
|
609
|
+
----------
|
|
610
|
+
convert_only_signal_vias : bool, optional
|
|
611
|
+
Either to convert only vias belonging to signal nets or all vias. Defaults is ``True``.
|
|
612
|
+
hole_wall_angle : float, optional
|
|
613
|
+
Angle of laser penetration in degrees. The angle defines the lowest hole diameter with this formula:
|
|
614
|
+
HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
|
|
615
|
+
The default is ``15``.
|
|
616
|
+
The lowest hole is ``0.75*HoleDepth/HoleDiam``.
|
|
617
|
+
delete_padstack_def : bool, optional
|
|
618
|
+
Whether to delete the padstack definition. The default is ``True``.
|
|
619
|
+
If ``False``, the padstack definition is not deleted and the hole size is set to zero.
|
|
620
|
+
|
|
621
|
+
Returns
|
|
622
|
+
-------
|
|
623
|
+
``True`` when successful, ``False`` when failed.
|
|
624
|
+
"""
|
|
625
|
+
|
|
626
|
+
if isinstance(self.data.get_hole_parameters()[0], GrpcPolygonData):
|
|
627
|
+
self._pedb.logger.error("Microvias cannot be applied on vias using hole shape polygon")
|
|
628
|
+
return False
|
|
629
|
+
|
|
630
|
+
if self.start_layer == self.stop_layer:
|
|
631
|
+
self._pedb.logger.error("Microvias cannot be applied when Start and Stop Layers are the same.")
|
|
632
|
+
layout = self._pedb.active_layout
|
|
633
|
+
layers = self._pedb.stackup.signal_layers
|
|
634
|
+
layer_names = [i for i in list(layers.keys())]
|
|
635
|
+
if convert_only_signal_vias:
|
|
636
|
+
signal_nets = [i for i in list(self._pedb._pedb.nets.signal_nets.keys())]
|
|
637
|
+
topl, topz, bottoml, bottomz = self._pedb.stackup.limits(True)
|
|
638
|
+
if self.start_layer in layers:
|
|
639
|
+
start_elevation = layers[self.start_layer].lower_elevation
|
|
640
|
+
else:
|
|
641
|
+
start_elevation = layers[self.instances[0].start_layer].lower_elevation
|
|
642
|
+
if self.stop_layer in layers:
|
|
643
|
+
stop_elevation = layers[self.stop_layer].upper_elevation
|
|
644
|
+
else:
|
|
645
|
+
stop_elevation = layers[self.instances[0].stop_layer].upper_elevation
|
|
646
|
+
|
|
647
|
+
diel_thick = abs(start_elevation - stop_elevation)
|
|
648
|
+
if self.hole_diameter:
|
|
649
|
+
rad1 = self.hole_diameter / 2 - math.tan(hole_wall_angle * diel_thick * math.pi / 180)
|
|
650
|
+
rad2 = self.hole_diameter / 2
|
|
651
|
+
else:
|
|
652
|
+
rad1 = 0.0
|
|
653
|
+
rad2 = 0.0
|
|
654
|
+
|
|
655
|
+
if start_elevation < (topz + bottomz) / 2:
|
|
656
|
+
rad1, rad2 = rad2, rad1
|
|
657
|
+
i = 0
|
|
658
|
+
for via in self.instances:
|
|
659
|
+
if convert_only_signal_vias and via.net_name in signal_nets or not convert_only_signal_vias:
|
|
660
|
+
pos = via.position
|
|
661
|
+
started = False
|
|
662
|
+
if len(self.pad_by_layer[self.start_layer].parameters_values) == 0:
|
|
663
|
+
self._pedb.modeler.create_polygon(
|
|
664
|
+
self.pad_by_layer[self.start_layer].polygon_data,
|
|
665
|
+
layer_name=self.start_layer,
|
|
666
|
+
net_name=via.net_name,
|
|
667
|
+
)
|
|
668
|
+
else:
|
|
669
|
+
GrpcCircle.create(
|
|
670
|
+
layout,
|
|
671
|
+
self.start_layer,
|
|
672
|
+
via.net,
|
|
673
|
+
GrpcValue(pos[0]),
|
|
674
|
+
GrpcValue(pos[1]),
|
|
675
|
+
GrpcValue(self.pad_by_layer[self.start_layer].parameters_values[0] / 2),
|
|
676
|
+
)
|
|
677
|
+
if len(self.pad_by_layer[self.stop_layer].parameters_values) == 0:
|
|
678
|
+
self._pedb.modeler.create_polygon(
|
|
679
|
+
self.pad_by_layer[self.stop_layer].polygon_data,
|
|
680
|
+
layer_name=self.stop_layer,
|
|
681
|
+
net_name=via.net_name,
|
|
682
|
+
)
|
|
683
|
+
else:
|
|
684
|
+
GrpcCircle.create(
|
|
685
|
+
layout,
|
|
686
|
+
self.stop_layer,
|
|
687
|
+
via.net,
|
|
688
|
+
GrpcValue(pos[0]),
|
|
689
|
+
GrpcValue(pos[1]),
|
|
690
|
+
GrpcValue(self.pad_by_layer[self.stop_layer].parameters_values[0] / 2),
|
|
691
|
+
)
|
|
692
|
+
for layer_name in layer_names:
|
|
693
|
+
stop = ""
|
|
694
|
+
if layer_name == via.start_layer or started:
|
|
695
|
+
start = layer_name
|
|
696
|
+
stop = layer_names[layer_names.index(layer_name) + 1]
|
|
697
|
+
cloned_circle = GrpcCircle.create(
|
|
698
|
+
layout,
|
|
699
|
+
start,
|
|
700
|
+
via.net,
|
|
701
|
+
GrpcValue(pos[0]),
|
|
702
|
+
GrpcValue(pos[1]),
|
|
703
|
+
GrpcValue(rad1),
|
|
704
|
+
)
|
|
705
|
+
cloned_circle2 = GrpcCircle.create(
|
|
706
|
+
layout,
|
|
707
|
+
stop,
|
|
708
|
+
via.net,
|
|
709
|
+
GrpcValue(pos[0]),
|
|
710
|
+
GrpcValue(pos[1]),
|
|
711
|
+
GrpcValue(rad2),
|
|
712
|
+
)
|
|
713
|
+
s3d = GrpcStructure3D.create(
|
|
714
|
+
layout, generate_unique_name("via3d_" + via.aedt_name.replace("via_", ""), n=3)
|
|
715
|
+
)
|
|
716
|
+
s3d.add_member(cloned_circle)
|
|
717
|
+
s3d.add_member(cloned_circle2)
|
|
718
|
+
if not self.data.material.value:
|
|
719
|
+
self._pedb.logger.warning(
|
|
720
|
+
f"Padstack definution {self.name} has no material defined." f"Defaulting to copper"
|
|
721
|
+
)
|
|
722
|
+
self.data.material = "copper"
|
|
723
|
+
s3d.set_material(self.data.material.value)
|
|
724
|
+
s3d.mesh_closure = GrpcMeshClosure.ENDS_CLOSED
|
|
725
|
+
started = True
|
|
726
|
+
i += 1
|
|
727
|
+
if stop == via.stop_layer:
|
|
728
|
+
break
|
|
729
|
+
if delete_padstack_def: # pragma no cover
|
|
730
|
+
via.delete()
|
|
731
|
+
else: # pragma no cover
|
|
732
|
+
self.hole_diameter = 0.0
|
|
733
|
+
self._pedb.logger.info("Padstack definition kept, hole size set to 0.")
|
|
734
|
+
|
|
735
|
+
self._pedb.logger.info(f"{i} Converted successfully to 3D Objects.")
|
|
736
|
+
return True
|
|
737
|
+
|
|
738
|
+
def split_to_microvias(self):
|
|
739
|
+
"""Convert actual padstack definition to multiple microvias definitions.
|
|
740
|
+
|
|
741
|
+
Returns
|
|
742
|
+
-------
|
|
743
|
+
List[:class:`PadstackInstance <pyedb.grpc.database.primitive.padstack_instance.PadstackInstance>`]
|
|
744
|
+
"""
|
|
745
|
+
from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
|
|
746
|
+
|
|
747
|
+
if self.start_layer == self.stop_layer:
|
|
748
|
+
self._pedb.logger.error("Microvias cannot be applied when Start and Stop Layers are the same.")
|
|
749
|
+
layout = self._pedb.active_layout
|
|
750
|
+
layers = self._pedb.stackup.signal_layers
|
|
751
|
+
layer_names = [i for i in list(layers.keys())]
|
|
752
|
+
if abs(layer_names.index(self.start_layer) - layer_names.index(self.stop_layer)) < 2:
|
|
753
|
+
self._pedb.logger.error(
|
|
754
|
+
"Conversion can be applied only if padstack definition is composed by more than 2 layers."
|
|
755
|
+
)
|
|
756
|
+
return False
|
|
757
|
+
started = False
|
|
758
|
+
new_instances = []
|
|
759
|
+
for layer_name in layer_names:
|
|
760
|
+
stop = ""
|
|
761
|
+
if layer_name == self.start_layer or started:
|
|
762
|
+
start = layer_name
|
|
763
|
+
stop = layer_names[layer_names.index(layer_name) + 1]
|
|
764
|
+
new_padstack_name = f"MV_{self.name}_{start}_{stop}"
|
|
765
|
+
included = [start, stop]
|
|
766
|
+
new_padstack_definition = GrpcPadstackDef.create(self._pedb.db, new_padstack_name)
|
|
767
|
+
new_padstack_definition.data.add_layers(included)
|
|
768
|
+
for layer in included:
|
|
769
|
+
pl = self.pad_by_layer[layer]
|
|
770
|
+
new_padstack_definition.data.set_pad_parameters(
|
|
771
|
+
layer=layer,
|
|
772
|
+
pad_type=GrpcPadType.REGULAR_PAD,
|
|
773
|
+
offset_x=GrpcValue(pl.offset_x, self._pedb.db),
|
|
774
|
+
offset_y=GrpcValue(pl.offset_y, self._pedb.db),
|
|
775
|
+
rotation=GrpcValue(pl.rotation, self._pedb.db),
|
|
776
|
+
type_geom=pl._edb_geometry_type,
|
|
777
|
+
sizes=pl.parameters_values,
|
|
778
|
+
)
|
|
779
|
+
antipads = self.antipad_by_layer
|
|
780
|
+
if layer in antipads:
|
|
781
|
+
pl = antipads[layer]
|
|
782
|
+
new_padstack_definition.data.set_pad_parameters(
|
|
783
|
+
layer=layer,
|
|
784
|
+
pad_type=GrpcPadType.ANTI_PAD,
|
|
785
|
+
offset_x=GrpcValue(pl.offset_x, self._pedb.db),
|
|
786
|
+
offset_y=GrpcValue(pl.offset_y, self._pedb.db),
|
|
787
|
+
rotation=GrpcValue(pl.rotation, self._pedb.db),
|
|
788
|
+
type_geom=pl._edb_geometry_type,
|
|
789
|
+
sizes=pl.parameters_values,
|
|
790
|
+
)
|
|
791
|
+
thermal_pads = self.thermalpad_by_layer
|
|
792
|
+
if layer in thermal_pads:
|
|
793
|
+
pl = thermal_pads[layer]
|
|
794
|
+
new_padstack_definition.data.set_pad_parameters(
|
|
795
|
+
layer=layer,
|
|
796
|
+
pad_type=GrpcPadType.THERMAL_PAD,
|
|
797
|
+
offset_x=GrpcValue(pl.offset_x, self._pedb.db),
|
|
798
|
+
offset_y=GrpcValue(pl.offset_y, self._pedb.db),
|
|
799
|
+
rotation=GrpcValue(pl.rotation, self._pedb.db),
|
|
800
|
+
type_geom=pl._edb_geometry_type,
|
|
801
|
+
sizes=pl.parameters_values,
|
|
802
|
+
)
|
|
803
|
+
new_padstack_definition.data.set_hole_parameters(
|
|
804
|
+
offset_x=GrpcValue(self.hole_offset_x, self._pedb.db),
|
|
805
|
+
offset_y=GrpcValue(self.hole_offset_y, self._pedb.db),
|
|
806
|
+
rotation=GrpcValue(self.hole_rotation, self._pedb.db),
|
|
807
|
+
type_geom=self.edb_hole_type,
|
|
808
|
+
sizes=[self.hole_diameter],
|
|
809
|
+
)
|
|
810
|
+
new_padstack_definition.data.material = self.material
|
|
811
|
+
new_padstack_definition.data.plating_percentage = GrpcValue(self.hole_plating_ratio, self._pedb.db)
|
|
812
|
+
new_instances.append(PadstackDef(self._pedb, new_padstack_definition))
|
|
813
|
+
started = True
|
|
814
|
+
if self.stop_layer == stop:
|
|
815
|
+
break
|
|
816
|
+
i = 0
|
|
817
|
+
for via in self.instances:
|
|
818
|
+
for instance in new_instances:
|
|
819
|
+
from_layer = self.data.layer_names[0]
|
|
820
|
+
to_layer = self.data.layer_names[-1]
|
|
821
|
+
from_layer = next(l for layer_name, l in self._pedb.stackup.layers.items() if l.name == from_layer)
|
|
822
|
+
to_layer = next(l for layer_name, l in self._pedb.stackup.layers.items() if l.name == to_layer)
|
|
823
|
+
padstack_instance = PadstackInstance.create(
|
|
824
|
+
layout=layout,
|
|
825
|
+
net=via.net,
|
|
826
|
+
name=generate_unique_name(instance.name),
|
|
827
|
+
padstack_def=instance,
|
|
828
|
+
position_x=via.position[0],
|
|
829
|
+
position_y=via.position[1],
|
|
830
|
+
rotation=0.0,
|
|
831
|
+
top_layer=from_layer,
|
|
832
|
+
bottom_layer=to_layer,
|
|
833
|
+
solder_ball_layer=None,
|
|
834
|
+
layer_map=None,
|
|
835
|
+
)
|
|
836
|
+
padstack_instance.is_layout_pin = via.is_pin
|
|
837
|
+
i += 1
|
|
838
|
+
via.delete()
|
|
839
|
+
self._pedb.logger.info("Created {} new microvias.".format(i))
|
|
840
|
+
return new_instances
|
|
841
|
+
|
|
842
|
+
# TODO check if update layer name is needed.
|