Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout auto parametrization #4002

Merged
merged 40 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6f3b815
edb intersection bug fix
svandenb-dev Jun 29, 2023
c9c9183
Merge remote-tracking branch 'origin/main'
svandenb-dev Jun 29, 2023
2c93929
Merge remote-tracking branch 'origin/main'
svandenb-dev Jun 30, 2023
13681b3
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 11, 2023
44b29bd
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 14, 2023
fa118ee
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 14, 2023
4f5170d
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 17, 2023
c532310
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 19, 2023
0ed1957
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 24, 2023
9c1f90f
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 26, 2023
b17e28d
Merge remote-tracking branch 'origin/main'
svandenb-dev Jul 27, 2023
0775a9f
Merge remote-tracking branch 'origin/main'
svandenb-dev Aug 21, 2023
8efa6e0
Merge remote-tracking branch 'origin/main'
svandenb-dev Aug 24, 2023
c32599f
Merge remote-tracking branch 'origin/main'
svandenb-dev Aug 28, 2023
64b538b
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 6, 2023
a4735a4
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 15, 2023
7ebf925
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 18, 2023
5a2c70b
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 21, 2023
38be8d7
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 21, 2023
d3cb775
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 22, 2023
52870ae
Merge remote-tracking branch 'origin/main'
svandenb-dev Sep 25, 2023
befd2f0
Merge remote-tracking branch 'origin/main'
svandenb-dev Oct 2, 2023
c84e923
Merge remote-tracking branch 'origin/main'
svandenb-dev Oct 31, 2023
f89f32b
Merge remote-tracking branch 'origin/main'
svandenb-dev Nov 8, 2023
15c110e
Merge remote-tracking branch 'origin/main'
svandenb-dev Nov 9, 2023
7edbdf9
Merge remote-tracking branch 'origin/main'
svandenb-dev Nov 14, 2023
4cfe1b6
Merge remote-tracking branch 'origin/main'
svandenb-dev Nov 23, 2023
d999259
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 1, 2023
865e3f7
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 4, 2023
2bd2260
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 5, 2023
b9afbd7
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 6, 2023
b201fa9
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 6, 2023
0e618cf
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 14, 2023
eff4bbe
Merge remote-tracking branch 'origin/main'
svandenb-dev Dec 20, 2023
3e0ee40
auto parametrization added
svandenb-dev Dec 21, 2023
b20d0f9
ironpython fix
svandenb-dev Dec 21, 2023
ead6afb
Merge branch 'main' into layout_auto_parametrization
Samuelopez-ansys Dec 21, 2023
a98af72
example created
svandenb-dev Dec 21, 2023
3920273
Merge remote-tracking branch 'origin/layout_auto_parametrization' int…
svandenb-dev Dec 21, 2023
e81678e
example created
svandenb-dev Dec 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions _unittest/test_00_EDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -3036,3 +3036,65 @@ def test_154_merge_polygon(self):
self.local_scratch.copyfolder(source_path, target_path)
edbapp = Edb(target_path, desktop_version)
assert edbapp.nets.merge_nets_polygons(["net1", "net2"])
edbapp.close_edb()

def test_155_layout_auto_parametrization(self):
source_path = os.path.join(local_path, "example_models", test_subfolder, "ANSYS-HSD_V1.aedb")
target_path = os.path.join(self.local_scratch.path, "test_auto_parameters", "test.aedb")
self.local_scratch.copyfolder(source_path, target_path)
edbapp = Edb(target_path, desktop_version)
edbapp.auto_parametrize_design(
layers=True,
layer_filter="1_Top",
materials=False,
via_holes=False,
pads=False,
antipads=False,
traces=False,
)
assert "$1_Top_thick" in edbapp.variables
edbapp.auto_parametrize_design(
layers=True, materials=False, via_holes=False, pads=False, antipads=False, traces=False
)
assert len(list(edbapp.variables.keys())) == len(list(edbapp.stackup.stackup_layers.keys()))
edbapp.auto_parametrize_design(
layers=False,
materials=True,
via_holes=False,
pads=False,
antipads=False,
traces=False,
material_filter=["copper"],
)
assert "$sigma_copper" in edbapp.variables
edbapp.auto_parametrize_design(
layers=False, materials=True, via_holes=False, pads=False, antipads=False, traces=False
)
assert len(list(edbapp.variables.values())) == 26
edbapp.auto_parametrize_design(
layers=False, materials=False, via_holes=True, pads=False, antipads=False, traces=False
)
assert len(list(edbapp.variables.values())) == 65
edbapp.auto_parametrize_design(
layers=False, materials=False, via_holes=False, pads=True, antipads=False, traces=False
)
assert len(list(edbapp.variables.values())) == 469
edbapp.auto_parametrize_design(
layers=False, materials=False, via_holes=False, pads=False, antipads=True, traces=False
)
assert len(list(edbapp.variables.values())) == 469
edbapp.auto_parametrize_design(
layers=False,
materials=False,
via_holes=False,
pads=False,
antipads=False,
traces=True,
trace_net_filter=["SFPA_Tx_Fault", "SFPA_Tx_Disable", "SFPA_SDA", "SFPA_SCL", "SFPA_Rx_LOS"],
)
assert len(list(edbapp.variables.keys())) == 474
edbapp.auto_parametrize_design(
layers=False, materials=False, via_holes=False, pads=False, antipads=False, traces=True
)
assert len(list(edbapp.variables.values())) == 2308
edbapp.close_edb()
Binary file added doc/source/_static/parametrized_design.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions examples/00-EDB/14_edb_create_parametrized_design.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
EDB: paramterized design
------------------------
This example shows how to
1, Create an HFSS simulation project using SimulationConfiguration class.
2, Create automatically parametrized design.
"""
######################################################################
#
# Final expected project
# ~~~~~~~~~~~~~~~~~~~~~~
#
# .. image:: ../../_static/parametrized_design.png
# :width: 600
# :alt: Fully automated parametrization.
######################################################################

######################################################################
# Create HFSS simulatio project
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Load an existing EDB folder.
######################################################################

import os
import pyaedt

project_path = pyaedt.generate_unique_folder_name()
target_aedb = pyaedt.downloads.download_file('edb/ANSYS-HSD_V1.aedb', destination=project_path)
print("Project folder will be", target_aedb)

aedt_version = "2024.1"
edb = pyaedt.Edb(edbpath=target_aedb, edbversion=aedt_version)
print("EDB is located at {}".format(target_aedb))

########################################################################
# Create SimulationConfiguration object and define simulation parameters
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

simulation_configuration = edb.new_simulation_configuration()
simulation_configuration.signal_nets = ["PCIe_Gen4_RX0_P", "PCIe_Gen4_RX0_N",
"PCIe_Gen4_RX1_P", "PCIe_Gen4_RX1_N"]
simulation_configuration.power_nets = ["GND"]
simulation_configuration.components = ["X1", "U1"]
simulation_configuration.do_cutout_subdesign = True
simulation_configuration.start_freq = "OGHz"
simulation_configuration.stop_freq = "20GHz"
simulation_configuration.step_freq = "10MHz"

##########################
# Build simulation project
# ~~~~~~~~~~~~~~~~~~~~~~~~

edb.build_simulation_project(simulation_configuration)

#############################
# Generated design parameters
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~
#

edb.auto_parametrize_design(layers=True, materials=True, via_holes=True, pads=True, antipads=True, traces=True)
edb.save_edb()
edb.close_edb()

######################
# Open project in AEDT
# ~~~~~~~~~~~~~~~~~~~~

hfss = pyaedt.Hfss3dLayout(projectname=target_aedb, specified_version=aedt_version)
hfss.release_desktop(False, False)
199 changes: 199 additions & 0 deletions pyaedt/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3834,3 +3834,202 @@

point_terminal = PointTerminal(self)
return point_terminal.create(name, net_name, location, layer)

@pyaedt_function_handler
def auto_parametrize_design(
self,
layers=True,
materials=True,
via_holes=True,
pads=True,
antipads=True,
traces=True,
layer_filter=None,
material_filter=None,
padstack_definition_filter=None,
trace_net_filter=None,
):
"""Assign automatically design and project variables with current values.

Parameters
----------
layers : bool, optional
``True`` enable layer thickness parametrization. Default value is ``True``.
materials : bool, optional
``True`` enable material parametrization. Default value is ``True``.
via_holes : bool, optional
``True`` enable via diameter parametrization. Default value is ``True``.
pads : bool, optional
``True`` enable pads size parametrization. Default value is ``True``.
antipads : bool, optional
``True`` enable anti pads size parametrization. Default value is ``True``.
traces : bool, optional
``True`` enable trace width parametrization. Default value is ``True``.
layer_filter : str, List(str), optional
Enable layer filter. Default value is ``None``, all layers are parametrized.
material_filter : str, List(str), optional
Enable material filter. Default value is ``None``, all material are parametrized.
padstack_definition_filter : str, List(str), optional
Enable padstack definition filter. Default value is ``None``, all padsatcks are parametrized.
trace_net_filter : str, List(str), optional
Enable nets filter for trace width parametrization. Default value is ``None``, all layers are
parametrized.
Returns
-------
List(str)
List of all parameters name created.
"""
parameters = []
if layers:
if not layer_filter:
_layers = self.stackup.stackup_layers
else:
if isinstance(layer_filter, str):
layer_filter = [layer_filter]
_layers = {k: v for k, v in self.stackup.stackup_layers.items() if k in layer_filter}
for layer_name, layer in _layers.items():
thickness_variable = "${}_thick".format(layer_name)
self._clean_string_for_variable_name(thickness_variable)
if thickness_variable not in self.variables:
self.add_design_variable(thickness_variable, layer.thickness)
layer.thickness = thickness_variable
parameters.append(thickness_variable)
if materials:
if not material_filter:
_materials = self.materials.materials
else:
_materials = {k: v for k, v in self.materials.materials.items() if k in material_filter}
for mat_name, material in _materials.items():
if material.conductivity < 1e4:
epsr_variable = "$epsr_{}".format(mat_name)
self._clean_string_for_variable_name(epsr_variable)
if epsr_variable not in self.variables:
self.add_design_variable(epsr_variable, material.permittivity)
material.permittivity = epsr_variable
parameters.append(epsr_variable)
loss_tg_variable = "$loss_tangent_{}".format(mat_name)
self._clean_string_for_variable_name(loss_tg_variable)
if not loss_tg_variable in self.variables:
self.add_design_variable(loss_tg_variable, material.loss_tangent)
material.loss_tangent = loss_tg_variable
parameters.append(loss_tg_variable)
else:
sigma_variable = "$sigma_{}".format(mat_name)
self._clean_string_for_variable_name(sigma_variable)
if not sigma_variable in self.variables:
self.add_design_variable(sigma_variable, material.conductivity)
material.conductivity = sigma_variable
parameters.append(sigma_variable)
if traces:
if not trace_net_filter:
paths = self.modeler.paths
else:
paths = [path for path in self.modeler.paths if path.net_name in trace_net_filter]
for path in paths:
trace_width_variable = "trace_w_{}_{}".format(path.net_name, path.id)
self._clean_string_for_variable_name(trace_width_variable)
if trace_width_variable not in self.variables:
self.add_design_variable(trace_width_variable, path.width)
path.width = trace_width_variable
parameters.append(trace_width_variable)
if not padstack_definition_filter:
used_padsatck_defs = list(
set([padstack_inst.padstack_definition for padstack_inst in list(self.padstacks.instances.values())])
)
padstack_defs = {k: v for k, v in self.padstacks.definitions.items() if k in used_padsatck_defs}
else:
padstack_defs = {k: v for k, v in self.padstacks.definitions.items() if k in padstack_definition_filter}

Check warning on line 3941 in pyaedt/edb.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/edb.py#L3941

Added line #L3941 was not covered by tests
for def_name, padstack_def in padstack_defs.items():
if not padstack_def.via_start_layer == padstack_def.via_stop_layer:
if via_holes: # pragma no cover
hole_variable = self._clean_string_for_variable_name("$hole_diam_{}".format(def_name))
if hole_variable not in self.variables:
self.add_design_variable(hole_variable, padstack_def.hole_properties[0])
padstack_def.hole_properties = hole_variable
parameters.append(hole_variable)
if pads:
for layer, pad in padstack_def.pad_by_layer.items():
if pad.geometry_type == 1:
pad_diameter_variable = self._clean_string_for_variable_name(
"$pad_diam_{}_{}".format(def_name, layer)
)
if pad_diameter_variable not in self.variables:
self.add_design_variable(pad_diameter_variable, pad.parameters_values[0])
pad.parameters = {"Diameter": pad_diameter_variable}
parameters.append(pad_diameter_variable)
if pad.geometry_type == 2: # pragma no cover
pad_size_variable = self._clean_string_for_variable_name(
"$pad_size_{}_{}".format(def_name, layer)
)
if pad_size_variable not in self.variables:
self.add_design_variable(pad_size_variable, pad.parameters_values[0])
pad.parameters = {"Size": pad_size_variable}
parameters.append(pad_size_variable)
elif pad.geometry_type == 3: # pragma no cover
pad_size_variable_x = self._clean_string_for_variable_name(
"$pad_size_x_{}_{}".format(def_name, layer)
)
pad_size_variable_y = self._clean_string_for_variable_name(
"$pad_size_y_{}_{}".format(def_name, layer)
)
if pad_size_variable_x not in self.variables and pad_size_variable_y not in self.variables:
self.add_design_variable(pad_size_variable_x, pad.parameters_values[0])
self.add_design_variable(pad_size_variable_y, pad.parameters_values[1])
pad.parameters = {"XSize": pad_size_variable_x, "YSize": pad_size_variable_y}
parameters.append(pad_size_variable_x)
parameters.append(pad_size_variable_y)
if antipads:
for layer, antipad in padstack_def.antipad_by_layer.items():
if antipad.geometry_type == 1: # pragma no cover
antipad_diameter_variable = self._clean_string_for_variable_name(
"$antipad_diam_{}_{}".format(def_name, layer)
)
if antipad_diameter_variable not in self.variables: # pragma no cover
self.add_design_variable(antipad_diameter_variable, antipad.parameters_values[0])
antipad.parameters = {"Diameter": antipad_diameter_variable}
parameters.append(antipad_diameter_variable)
if antipad.geometry_type == 2: # pragma no cover
antipad_size_variable = self._clean_string_for_variable_name(
"$antipad_size_{}_{}".format(def_name, layer)
)
if antipad_size_variable not in self.variables: # pragma no cover
self.add_design_variable(antipad_size_variable, antipad.parameters_values[0])
antipad.parameters = {"Size": antipad_size_variable}
parameters.append(antipad_size_variable)
elif antipad.geometry_type == 3: # pragma no cover
antipad_size_variable_x = self._clean_string_for_variable_name(
"$antipad_size_x_{}_{}".format(def_name, layer)
)
antipad_size_variable_y = self._clean_string_for_variable_name(
"$antipad_size_y_{}_{}".format(def_name, layer)
)
if (
antipad_size_variable_x not in self.variables
and antipad_size_variable_y not in self.variables
): # pragma no cover
self.add_design_variable(antipad_size_variable_x, antipad.parameters_values[0])
self.add_design_variable(antipad_size_variable_y, antipad.parameters_values[1])
antipad.parameters = {"XSize": antipad_size_variable_x, "YSize": antipad_size_variable_y}
parameters.append(antipad_size_variable_x)
parameters.append(antipad_size_variable_y)
return parameters

@pyaedt_function_handler
def _clean_string_for_variable_name(self, variable_name):
"""Remove forbidden character for variable name.

Parameter
----------
variable_name : str
Variable name.

Returns
-------
str
Edited name.
"""
if "-" in variable_name:
variable_name = variable_name.replace("-", "_")
if "+" in variable_name:
variable_name = variable_name.replace("+", "p")
return variable_name
Loading