Skip to content

Commit

Permalink
FIX: Improve 3d layout plots (#5355)
Browse files Browse the repository at this point in the history
Co-authored-by: maxcapodi78 <Shark78>
Co-authored-by: Samuel Lopez <[email protected]>
  • Loading branch information
maxcapodi78 and Samuelopez-ansys authored Nov 6, 2024
1 parent c46eca8 commit e580d7a
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 21 deletions.
151 changes: 130 additions & 21 deletions src/ansys/aedt/core/visualization/post/post_common_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ def _get_intrinsic(self, setup):

@pyaedt_function_handler(list_objs="assignment")
def _get_volume_objects(self, assignment):
obj_list = []
if self._app.solution_type not in ["HFSS3DLayout", "HFSS 3D Layout Design"]:
obj_list = []
editor = self._app._odesign.SetActiveEditor("3D Modeler")
Expand Down Expand Up @@ -1340,36 +1341,53 @@ def create_fieldplot_line_traces(
)

@pyaedt_function_handler()
def _get_3dl_layers_nets(self, layers, nets, setup):
def _get_all_3dl_layers_nets(self, setup):
try:
get_ids = self._odesign.GetGeometryIdsForAllNetLayerCombinations(setup)
except: # pragma no cover
get_ids = []
k = 0
get_ids_dict = {}
key = ""
list_to_add = []
while k < len(get_ids):
if get_ids[k].startswith("PlotGeomInfo"):
if key:
get_ids_dict[key] = list_to_add
key = get_ids[k].replace("PlotGeomInfo for ", "").replace(" (net/layer combination):", "")
list_to_add = []
else:
try:
list_to_add.append(int(get_ids[k]))
except ValueError:
pass
k = k + 1
return get_ids_dict

@pyaedt_function_handler()
def _get_3dl_layers_nets(self, layers, nets, setup, include_dielectrics):
lst_faces = []
new_layers = []
ids_dict = self._get_all_3dl_layers_nets(setup)
if not layers:
new_layers.extend([f"{i}" for i in self._app.modeler.edb.stackup.dielectric_layers.keys()])
if include_dielectrics:
new_layers.extend([f"{i}" for i in self._app.modeler.edb.stackup.dielectric_layers.keys()])
for layer in self._app.modeler.edb.stackup.signal_layers.keys():
if not nets:
nets = list(self._app.modeler.edb.nets.nets.keys())
for el in nets:
try:
get_ids = self._odesign.GetGeometryIdsForNetLayerCombination(el, layer, setup)
except:
get_ids = []
if isinstance(get_ids, (tuple, list)) and len(get_ids) > 2:
lst_faces.extend([int(i) for i in get_ids[2:]])

if f"{el}/{layer}" in ids_dict:
lst_faces.extend(ids_dict[f"{el}/{layer}"])
else:
for layer in layers:
if layer in self._app.modeler.edb.stackup.dielectric_layers:
if layer in self._app.modeler.edb.stackup.dielectric_layers and include_dielectrics:
new_layers.append(f"{layer}")
elif layer in self._app.modeler.edb.stackup.signal_layers:
if not nets:
nets = list(self._app.modeler.edb.nets.nets.keys())
for el in nets:
try:
get_ids = self._odesign.GetGeometryIdsForNetLayerCombination(el, layer, setup)
except:
get_ids = []
if isinstance(get_ids, (tuple, list)) and len(get_ids) > 2:
lst_faces.extend([int(i) for i in get_ids[2:]])
if f"{el}/{layer}" in ids_dict:
lst_faces.extend(ids_dict[f"{el}/{layer}"])
return lst_faces, new_layers

@pyaedt_function_handler()
Expand All @@ -1395,9 +1413,9 @@ def create_fieldplot_layers(
):
# type: (list, str, str, list, bool, dict, str) -> FieldPlot
"""Create a field plot of stacked layer plot.
This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout.
This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout. Nets can be used as a filter.
Dielectrics will be included into the plot.
It works when a layout components in 3d modeler is used.
In order to plot on signal layers use the method ``create_fieldplot_layers_nets``.
Parameters
----------
Expand All @@ -1414,6 +1432,9 @@ def create_fieldplot_layers(
use in the export or ``LastAdaptive``.
nets : list, optional
List of nets to filter the field plot. Optional.
plot_on_surface : bool, optional
Whether if the plot has to be on surfaces or inside the objects.
It is applicable only to layout components. Default is ``True``.
intrinsics : dict, str, optional
Intrinsic variables required to compute the field before the export.
These are typically: frequency, time and phase.
Expand Down Expand Up @@ -1453,7 +1474,7 @@ def create_fieldplot_layers(
return self.field_plots[name]

if self._app.design_type in ["HFSS 3D Layout Design"]:
lst_faces, new_layers = self._get_3dl_layers_nets(layers, nets, setup)
lst_faces, new_layers = self._get_3dl_layers_nets(layers, nets, setup, include_dielectrics=True)
if new_layers:
plt = self._create_fieldplot(
new_layers, quantity, setup, intrinsics, "ObjList", name, create_plot=False
Expand Down Expand Up @@ -1484,12 +1505,89 @@ def create_fieldplot_layers(
return self._create_fieldplot(dielectrics, quantity, setup, intrinsics, "ObjList", name)
return False

@pyaedt_function_handler()
def create_fieldplot_nets(
self, nets, quantity, setup=None, layers=None, plot_on_surface=True, intrinsics=None, name=None
):
# type: (list, str, str, list, bool, dict, str) -> FieldPlot
"""Create a field plot of stacked layer plot based on a net selections. Layers can be used as a filter.
Dielectrics will be excluded from the plot.
This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout.
It works when a layout components in 3d modeler is used.
Parameters
----------
nets : list, optional
List of nets to filter the field plot.
quantity : str
Name of the quantity to plot.
setup : str, optional
Name of the setup. The default is ``None``, in which case the ``nominal_adaptive``
setup is used. Make sure to build a setup string in the form of
``"SetupName : SetupSweep"``, where ``SetupSweep`` is the sweep name to
use in the export or ``LastAdaptive``.
layers : list, optional
List of layers to plot. For example:
``["Layer1","Layer2"]``. If empty list is provided
all layers are considered.
intrinsics : dict, str, optional
Intrinsic variables required to compute the field before the export.
These are typically: frequency, time and phase.
It can be provided either as a dictionary or as a string.
If it is a dictionary, keys depend on the solution type and can be expressed in lower or camel case as:
- ``"Freq"`` or ``"Frequency"``.
- ``"Time"``.
- ``"Phase"``.
If it is a string, it can either be ``"Freq"`` or ``"Time"`` depending on the solution type.
The default is ``None`` in which case the intrinsics value is automatically computed based on the setup.
plot_on_surface : bool, optional
Whether if the plot has to be on surfaces or inside the objects.
It is applicable only to layout components. Default is ``True``.
name : str, optional
Name of the field plot to create.
Returns
-------
:class:``ansys.aedt.core.modules.solutions.FieldPlot`` or bool
Plot object.
References
----------
>>> oModule.CreateFieldPlot
"""
intrinsics = self._app._check_intrinsics(intrinsics, setup=setup)
if not setup:
setup = self._app.existing_analysis_sweeps[0]
if nets is None:
nets = []
if not (
"APhi" in self.post_solution_type and settings.aedt_version >= "2023.2"
) and not self._app.design_type in ["HFSS", "HFSS 3D Layout Design"]:
self.logger.error("This method requires AEDT 2023 R2 and Maxwell 3D Transient APhi Formulation.")
return False
if name and name in list(self.field_plots.keys()):
self.logger.info(f"Plot {name} exists. returning the object.")
return self.field_plots[name]

if self._app.design_type in ["HFSS 3D Layout Design"]:
lst_faces, new_layers = self._get_3dl_layers_nets(layers, nets, setup, include_dielectrics=False)
return self._create_fieldplot(lst_faces, quantity, setup, intrinsics, "FacesList", name)
else:
_, new_layers = self._get_3d_layers_nets(layers, nets)
if plot_on_surface:
plot_type = "LayerNetsExtFace"
else:
plot_type = "LayerNets"
return self._create_fieldplot(new_layers, quantity, setup, intrinsics, plot_type, name)

@pyaedt_function_handler(quantity_name="quantity", setup_name="setup")
def create_fieldplot_layers_nets(
self, layers_nets, quantity, setup=None, intrinsics=None, plot_on_surface=True, plot_name=None
):
# type: (list, str, str, dict, bool, str) -> FieldPlot
"""Create a field plot of stacked layer plot.
"""Create a field plot of stacked layer plot on specified matrix of layers and nets.
This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout
and any modeler where a layout component is used.
Expand Down Expand Up @@ -1520,7 +1618,8 @@ def create_fieldplot_layers_nets(
If it is a string, it can either be ``"Freq"`` or ``"Time"`` depending on the solution type.
The default is ``None`` in which case the intrinsics value is automatically computed based on the setup.
plot_on_surface : bool, optional
Whether the plot is to be on the surface or volume of traces.
Whether if the plot has to be on surfaces or inside the objects.
It is applicable only to layout components. Default is ``True``.
plot_name : str, optional
Name of the field plot to create.
Expand Down Expand Up @@ -1548,7 +1647,17 @@ def create_fieldplot_layers_nets(
if not setup:
setup = self._app.existing_analysis_sweeps[0]
lst = []
if len(layers_nets) == 0:

dicts_in = self._get_all_3dl_layers_nets(setup)
for _, v in dicts_in.items():
lst.extend(v)
for layer in layers_nets:
if len(layer) == 1:
dicts_in = self._get_all_3dl_layers_nets(setup)
for v, i in dicts_in.items():
if v.split("/")[1] == layer[0] or v.split("/")[0] == layer[0]:
lst.extend(i)
for el in layer[1:]:
el = "<no-net>" if el == "no-net" else el
try:
Expand Down
11 changes: 11 additions & 0 deletions tests/system/general/test_41_3dlayout_modeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,17 @@ def test_42_post_processing_3d_layout(self, add_app):

assert pl1
assert pl1.export_image_from_aedtplt(tempfile.gettempdir())
pl2 = test.post.create_fieldplot_nets(
["V3P3_S5"],
"Mag_E",
layers=["LYR_1"],
intrinsics={"Freq": "1GHz"},
name="Test_Layers2",
)

assert pl2
assert pl2.export_image_from_aedtplt(tempfile.gettempdir())

self.aedtapp.close_project(test.project_name)

@pytest.mark.skipif(is_linux, reason="Bug on linux")
Expand Down

0 comments on commit e580d7a

Please sign in to comment.