Skip to content

Commit 68ee50a

Browse files
committed
MAINT: integrate pyaedt PR 4002 changes
1 parent 559b975 commit 68ee50a

File tree

4 files changed

+329
-0
lines changed

4 files changed

+329
-0
lines changed
32.2 KB
Loading
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
EDB: parameterized design
3+
------------------------
4+
This example shows how to
5+
1, Create an HFSS simulation project using SimulationConfiguration class.
6+
2, Create automatically parametrized design.
7+
"""
8+
######################################################################
9+
#
10+
# Final expected project
11+
# ~~~~~~~~~~~~~~~~~~~~~~
12+
#
13+
# .. image:: ../../_static/parametrized_design.png
14+
# :width: 600
15+
# :alt: Fully automated parametrization.
16+
######################################################################
17+
18+
######################################################################
19+
# Create HFSS simulatio project
20+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21+
# Load an existing EDB folder.
22+
######################################################################
23+
24+
from pyaedt import Hfss3dLayout
25+
26+
import pyedb
27+
from pyedb.generic.general_methods import generate_unique_folder_name
28+
from pyedb.legacy.downloads import download_file
29+
30+
project_path = generate_unique_folder_name()
31+
target_aedb = download_file("edb/ANSYS-HSD_V1.aedb", destination=project_path)
32+
print("Project folder will be", target_aedb)
33+
34+
aedt_version = "2023.2"
35+
edb = pyedb.Edb(edbpath=target_aedb, edbversion=aedt_version)
36+
print("EDB is located at {}".format(target_aedb))
37+
38+
########################################################################
39+
# Create SimulationConfiguration object and define simulation parameters
40+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41+
42+
simulation_configuration = edb.new_simulation_configuration()
43+
simulation_configuration.signal_nets = ["PCIe_Gen4_RX0_P", "PCIe_Gen4_RX0_N", "PCIe_Gen4_RX1_P", "PCIe_Gen4_RX1_N"]
44+
simulation_configuration.power_nets = ["GND"]
45+
simulation_configuration.components = ["X1", "U1"]
46+
simulation_configuration.do_cutout_subdesign = True
47+
simulation_configuration.start_freq = "OGHz"
48+
simulation_configuration.stop_freq = "20GHz"
49+
simulation_configuration.step_freq = "10MHz"
50+
51+
##########################
52+
# Build simulation project
53+
# ~~~~~~~~~~~~~~~~~~~~~~~~
54+
55+
edb.build_simulation_project(simulation_configuration)
56+
57+
#############################
58+
# Generated design parameters
59+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~
60+
#
61+
62+
edb.auto_parametrize_design(layers=True, materials=True, via_holes=True, pads=True, antipads=True, traces=True)
63+
edb.save_edb()
64+
edb.close_edb()
65+
66+
######################
67+
# Open project in AEDT
68+
# ~~~~~~~~~~~~~~~~~~~~
69+
70+
hfss = Hfss3dLayout(projectname=target_aedb, specified_version=aedt_version)
71+
hfss.release_desktop(False, False)

src/pyedb/legacy/edb.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4012,3 +4012,199 @@ def get_point_terminal(self, name, net_name, location, layer):
40124012

40134013
point_terminal = PointTerminal(self)
40144014
return point_terminal.create(name, net_name, location, layer)
4015+
4016+
@pyedb_function_handler
4017+
def auto_parametrize_design(
4018+
self,
4019+
layers=True,
4020+
materials=True,
4021+
via_holes=True,
4022+
pads=True,
4023+
antipads=True,
4024+
traces=True,
4025+
layer_filter=None,
4026+
material_filter=None,
4027+
padstack_definition_filter=None,
4028+
trace_net_filter=None,
4029+
):
4030+
"""Assign automatically design and project variables with current values.
4031+
Parameters
4032+
----------
4033+
layers : bool, optional
4034+
``True`` enable layer thickness parametrization. Default value is ``True``.
4035+
materials : bool, optional
4036+
``True`` enable material parametrization. Default value is ``True``.
4037+
via_holes : bool, optional
4038+
``True`` enable via diameter parametrization. Default value is ``True``.
4039+
pads : bool, optional
4040+
``True`` enable pads size parametrization. Default value is ``True``.
4041+
antipads : bool, optional
4042+
``True`` enable anti pads size parametrization. Default value is ``True``.
4043+
traces : bool, optional
4044+
``True`` enable trace width parametrization. Default value is ``True``.
4045+
layer_filter : str, List(str), optional
4046+
Enable layer filter. Default value is ``None``, all layers are parametrized.
4047+
material_filter : str, List(str), optional
4048+
Enable material filter. Default value is ``None``, all material are parametrized.
4049+
padstack_definition_filter : str, List(str), optional
4050+
Enable padstack definition filter. Default value is ``None``, all padsatcks are parametrized.
4051+
trace_net_filter : str, List(str), optional
4052+
Enable nets filter for trace width parametrization. Default value is ``None``, all layers are
4053+
parametrized.
4054+
Returns
4055+
-------
4056+
List(str)
4057+
List of all parameters name created.
4058+
"""
4059+
parameters = []
4060+
if layers:
4061+
if not layer_filter:
4062+
_layers = self.stackup.stackup_layers
4063+
else:
4064+
if isinstance(layer_filter, str):
4065+
layer_filter = [layer_filter]
4066+
_layers = {k: v for k, v in self.stackup.stackup_layers.items() if k in layer_filter}
4067+
for layer_name, layer in _layers.items():
4068+
thickness_variable = "${}_thick".format(layer_name)
4069+
self._clean_string_for_variable_name(thickness_variable)
4070+
if thickness_variable not in self.variables:
4071+
self.add_design_variable(thickness_variable, layer.thickness)
4072+
layer.thickness = thickness_variable
4073+
parameters.append(thickness_variable)
4074+
if materials:
4075+
if not material_filter:
4076+
_materials = self.materials.materials
4077+
else:
4078+
_materials = {k: v for k, v in self.materials.materials.items() if k in material_filter}
4079+
for mat_name, material in _materials.items():
4080+
if material.conductivity < 1e4:
4081+
epsr_variable = "$epsr_{}".format(mat_name)
4082+
self._clean_string_for_variable_name(epsr_variable)
4083+
if epsr_variable not in self.variables:
4084+
self.add_design_variable(epsr_variable, material.permittivity)
4085+
material.permittivity = epsr_variable
4086+
parameters.append(epsr_variable)
4087+
loss_tg_variable = "$loss_tangent_{}".format(mat_name)
4088+
self._clean_string_for_variable_name(loss_tg_variable)
4089+
if not loss_tg_variable in self.variables:
4090+
self.add_design_variable(loss_tg_variable, material.loss_tangent)
4091+
material.loss_tangent = loss_tg_variable
4092+
parameters.append(loss_tg_variable)
4093+
else:
4094+
sigma_variable = "$sigma_{}".format(mat_name)
4095+
self._clean_string_for_variable_name(sigma_variable)
4096+
if not sigma_variable in self.variables:
4097+
self.add_design_variable(sigma_variable, material.conductivity)
4098+
material.conductivity = sigma_variable
4099+
parameters.append(sigma_variable)
4100+
if traces:
4101+
if not trace_net_filter:
4102+
paths = self.modeler.paths
4103+
else:
4104+
paths = [path for path in self.modeler.paths if path.net_name in trace_net_filter]
4105+
for path in paths:
4106+
trace_width_variable = "trace_w_{}_{}".format(path.net_name, path.id)
4107+
self._clean_string_for_variable_name(trace_width_variable)
4108+
if trace_width_variable not in self.variables:
4109+
self.add_design_variable(trace_width_variable, path.width)
4110+
path.width = trace_width_variable
4111+
parameters.append(trace_width_variable)
4112+
if not padstack_definition_filter:
4113+
used_padsatck_defs = list(
4114+
set([padstack_inst.padstack_definition for padstack_inst in list(self.padstacks.instances.values())])
4115+
)
4116+
padstack_defs = {k: v for k, v in self.padstacks.definitions.items() if k in used_padsatck_defs}
4117+
else:
4118+
padstack_defs = {k: v for k, v in self.padstacks.definitions.items() if k in padstack_definition_filter}
4119+
for def_name, padstack_def in padstack_defs.items():
4120+
if not padstack_def.via_start_layer == padstack_def.via_stop_layer:
4121+
if via_holes: # pragma no cover
4122+
hole_variable = self._clean_string_for_variable_name("$hole_diam_{}".format(def_name))
4123+
if hole_variable not in self.variables:
4124+
self.add_design_variable(hole_variable, padstack_def.hole_properties[0])
4125+
padstack_def.hole_properties = hole_variable
4126+
parameters.append(hole_variable)
4127+
if pads:
4128+
for layer, pad in padstack_def.pad_by_layer.items():
4129+
if pad.geometry_type == 1:
4130+
pad_diameter_variable = self._clean_string_for_variable_name(
4131+
"$pad_diam_{}_{}".format(def_name, layer)
4132+
)
4133+
if pad_diameter_variable not in self.variables:
4134+
self.add_design_variable(pad_diameter_variable, pad.parameters_values[0])
4135+
pad.parameters = {"Diameter": pad_diameter_variable}
4136+
parameters.append(pad_diameter_variable)
4137+
if pad.geometry_type == 2: # pragma no cover
4138+
pad_size_variable = self._clean_string_for_variable_name(
4139+
"$pad_size_{}_{}".format(def_name, layer)
4140+
)
4141+
if pad_size_variable not in self.variables:
4142+
self.add_design_variable(pad_size_variable, pad.parameters_values[0])
4143+
pad.parameters = {"Size": pad_size_variable}
4144+
parameters.append(pad_size_variable)
4145+
elif pad.geometry_type == 3: # pragma no cover
4146+
pad_size_variable_x = self._clean_string_for_variable_name(
4147+
"$pad_size_x_{}_{}".format(def_name, layer)
4148+
)
4149+
pad_size_variable_y = self._clean_string_for_variable_name(
4150+
"$pad_size_y_{}_{}".format(def_name, layer)
4151+
)
4152+
if pad_size_variable_x not in self.variables and pad_size_variable_y not in self.variables:
4153+
self.add_design_variable(pad_size_variable_x, pad.parameters_values[0])
4154+
self.add_design_variable(pad_size_variable_y, pad.parameters_values[1])
4155+
pad.parameters = {"XSize": pad_size_variable_x, "YSize": pad_size_variable_y}
4156+
parameters.append(pad_size_variable_x)
4157+
parameters.append(pad_size_variable_y)
4158+
if antipads:
4159+
for layer, antipad in padstack_def.antipad_by_layer.items():
4160+
if antipad.geometry_type == 1: # pragma no cover
4161+
antipad_diameter_variable = self._clean_string_for_variable_name(
4162+
"$antipad_diam_{}_{}".format(def_name, layer)
4163+
)
4164+
if antipad_diameter_variable not in self.variables: # pragma no cover
4165+
self.add_design_variable(antipad_diameter_variable, antipad.parameters_values[0])
4166+
antipad.parameters = {"Diameter": antipad_diameter_variable}
4167+
parameters.append(antipad_diameter_variable)
4168+
if antipad.geometry_type == 2: # pragma no cover
4169+
antipad_size_variable = self._clean_string_for_variable_name(
4170+
"$antipad_size_{}_{}".format(def_name, layer)
4171+
)
4172+
if antipad_size_variable not in self.variables: # pragma no cover
4173+
self.add_design_variable(antipad_size_variable, antipad.parameters_values[0])
4174+
antipad.parameters = {"Size": antipad_size_variable}
4175+
parameters.append(antipad_size_variable)
4176+
elif antipad.geometry_type == 3: # pragma no cover
4177+
antipad_size_variable_x = self._clean_string_for_variable_name(
4178+
"$antipad_size_x_{}_{}".format(def_name, layer)
4179+
)
4180+
antipad_size_variable_y = self._clean_string_for_variable_name(
4181+
"$antipad_size_y_{}_{}".format(def_name, layer)
4182+
)
4183+
if (
4184+
antipad_size_variable_x not in self.variables
4185+
and antipad_size_variable_y not in self.variables
4186+
): # pragma no cover
4187+
self.add_design_variable(antipad_size_variable_x, antipad.parameters_values[0])
4188+
self.add_design_variable(antipad_size_variable_y, antipad.parameters_values[1])
4189+
antipad.parameters = {"XSize": antipad_size_variable_x, "YSize": antipad_size_variable_y}
4190+
parameters.append(antipad_size_variable_x)
4191+
parameters.append(antipad_size_variable_y)
4192+
return parameters
4193+
4194+
@pyedb_function_handler
4195+
def _clean_string_for_variable_name(self, variable_name):
4196+
"""Remove forbidden character for variable name.
4197+
Parameter
4198+
----------
4199+
variable_name : str
4200+
Variable name.
4201+
Returns
4202+
-------
4203+
str
4204+
Edited name.
4205+
"""
4206+
if "-" in variable_name:
4207+
variable_name = variable_name.replace("-", "_")
4208+
if "+" in variable_name:
4209+
variable_name = variable_name.replace("+", "p")
4210+
return variable_name

tests/legacy/system/test_edb_nets.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,65 @@ def test_nets_merge_polygon(self):
128128
self.local_scratch.copyfolder(source_path, target_path)
129129
edbapp = EdbLegacy(target_path, desktop_version)
130130
assert edbapp.nets.merge_nets_polygons(["net1", "net2"])
131+
edbapp.close_edb()
132+
133+
def test_layout_auto_parametrization(self):
134+
source_path = os.path.join(local_path, "example_models", test_subfolder, "ANSYS-HSD_V1.aedb")
135+
target_path = os.path.join(self.local_scratch.path, "test_auto_parameters", "test.aedb")
136+
self.local_scratch.copyfolder(source_path, target_path)
137+
edbapp = EdbLegacy(target_path, desktop_version)
138+
edbapp.auto_parametrize_design(
139+
layers=True,
140+
layer_filter="1_Top",
141+
materials=False,
142+
via_holes=False,
143+
pads=False,
144+
antipads=False,
145+
traces=False,
146+
)
147+
assert "$1_Top_thick" in edbapp.variables
148+
edbapp.auto_parametrize_design(
149+
layers=True, materials=False, via_holes=False, pads=False, antipads=False, traces=False
150+
)
151+
assert len(list(edbapp.variables.keys())) == len(list(edbapp.stackup.stackup_layers.keys()))
152+
edbapp.auto_parametrize_design(
153+
layers=False,
154+
materials=True,
155+
via_holes=False,
156+
pads=False,
157+
antipads=False,
158+
traces=False,
159+
material_filter=["copper"],
160+
)
161+
assert "$sigma_copper" in edbapp.variables
162+
edbapp.auto_parametrize_design(
163+
layers=False, materials=True, via_holes=False, pads=False, antipads=False, traces=False
164+
)
165+
assert len(list(edbapp.variables.values())) == 26
166+
edbapp.auto_parametrize_design(
167+
layers=False, materials=False, via_holes=True, pads=False, antipads=False, traces=False
168+
)
169+
assert len(list(edbapp.variables.values())) == 65
170+
edbapp.auto_parametrize_design(
171+
layers=False, materials=False, via_holes=False, pads=True, antipads=False, traces=False
172+
)
173+
assert len(list(edbapp.variables.values())) == 469
174+
edbapp.auto_parametrize_design(
175+
layers=False, materials=False, via_holes=False, pads=False, antipads=True, traces=False
176+
)
177+
assert len(list(edbapp.variables.values())) == 469
178+
edbapp.auto_parametrize_design(
179+
layers=False,
180+
materials=False,
181+
via_holes=False,
182+
pads=False,
183+
antipads=False,
184+
traces=True,
185+
trace_net_filter=["SFPA_Tx_Fault", "SFPA_Tx_Disable", "SFPA_SDA", "SFPA_SCL", "SFPA_Rx_LOS"],
186+
)
187+
assert len(list(edbapp.variables.keys())) == 474
188+
edbapp.auto_parametrize_design(
189+
layers=False, materials=False, via_holes=False, pads=False, antipads=False, traces=True
190+
)
191+
assert len(list(edbapp.variables.values())) == 2308
192+
edbapp.close_edb()

0 commit comments

Comments
 (0)