Skip to content

Commit 761344a

Browse files
REFACTOR: split post_common_3d.py application (#5955)
Co-authored-by: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com>
1 parent 2798c55 commit 761344a

9 files changed

Lines changed: 1585 additions & 1270 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
split post_common_3d.py application

src/ansys/aedt/core/visualization/post/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ def post_processor(app=None, project=None, design=None, version=None):
5353
from ansys.aedt.core.visualization.post.post_circuit import PostProcessorCircuit as PostProcessor
5454
elif app.design_type in ["HFSS 3D Layout Design", "HFSS 3D Layout"]:
5555
from ansys.aedt.core.visualization.post.post_3dlayout import PostProcessor3DLayout as PostProcessor
56+
elif app.design_type in ["Maxwell 2D", "Maxwell 3D"]:
57+
from ansys.aedt.core.visualization.post.post_maxwell import PostProcessorMaxwell as PostProcessor
58+
elif app.design_type in ["HFSS"]:
59+
from ansys.aedt.core.visualization.post.post_hfss import PostProcessorHFSS as PostProcessor
5660
else:
5761
from ansys.aedt.core.visualization.post.post_common_3d import PostProcessor3D as PostProcessor
5862
if PostProcessor:

src/ansys/aedt/core/visualization/post/post_3dlayout.py

Lines changed: 353 additions & 0 deletions
Large diffs are not rendered by default.

src/ansys/aedt/core/visualization/post/post_common_3d.py

Lines changed: 1 addition & 1252 deletions
Large diffs are not rendered by default.

src/ansys/aedt/core/visualization/post/post_hfss.py

Lines changed: 469 additions & 0 deletions
Large diffs are not rendered by default.

src/ansys/aedt/core/visualization/post/post_icepak.py

Lines changed: 375 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates.
4+
# SPDX-License-Identifier: MIT
5+
#
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
25+
"""
26+
This module contains the `PostProcessor3D` class.
27+
28+
It contains all advanced postprocessing functionalities for creating and editing plots in the 3D tools.
29+
"""
30+
31+
import random
32+
import string
33+
34+
from ansys.aedt.core.generic.general_methods import pyaedt_function_handler
35+
from ansys.aedt.core.visualization.post.field_data import FieldPlot
36+
from ansys.aedt.core.visualization.post.post_3dlayout import PostProcessor3DLayout
37+
from ansys.aedt.core.visualization.post.post_common_3d import PostProcessor3D
38+
39+
40+
class PostProcessorMaxwell(PostProcessor3D):
41+
"""Manages the specific Maxwell postprocessing functions.
42+
43+
.. note::
44+
Some functionalities are available only when AEDT is running in the graphical mode.
45+
46+
Parameters
47+
----------
48+
app : :class:`ansys.aedt.core.application.analysis_3d.FieldAnalysis3D`
49+
Inherited parent object. The parent object must provide the members
50+
`_modeler`, `_desktop`, `_odesign`, and `logger`.
51+
52+
"""
53+
54+
def __init__(self, app):
55+
PostProcessor3D.__init__(self, app)
56+
self.post_3dlayout = PostProcessor3DLayout(app)
57+
58+
@pyaedt_function_handler(quantityName="quantity", setup_name="setup")
59+
def _create_fieldplot_line_traces(
60+
self,
61+
seeding_faces_ids,
62+
in_volume_tracing_ids,
63+
surface_tracing_ids,
64+
quantity,
65+
setup,
66+
intrinsics,
67+
plot_name=None,
68+
field_type="",
69+
):
70+
if not setup:
71+
setup = self._app.existing_analysis_sweeps[0]
72+
if not intrinsics:
73+
for i in self._app.setups:
74+
if i.name == setup.split(" : ")[0]:
75+
intrinsics = i.default_intrinsics
76+
self._app.desktop_class.close_windows()
77+
try:
78+
self._app.modeler.fit_all()
79+
except Exception: # pragma: no cover
80+
self.logger.debug("Something went wrong with `fit_all` while creating field plot with line traces.")
81+
self._desktop.TileWindows(0)
82+
self._app.desktop_class.active_design(self._oproject, self._app.design_name)
83+
84+
char_set = string.ascii_uppercase + string.digits
85+
if not plot_name:
86+
plot_name = quantity + "_" + "".join(random.sample(char_set, 6))
87+
plot = FieldPlot(
88+
self,
89+
objects=in_volume_tracing_ids,
90+
surfaces=surface_tracing_ids,
91+
solution=setup,
92+
quantity=quantity,
93+
intrinsics=intrinsics,
94+
seeding_faces=seeding_faces_ids,
95+
)
96+
if field_type:
97+
plot.field_type = field_type
98+
plot.name = plot_name
99+
plot.plot_folder = plot_name
100+
101+
plt = plot.create()
102+
if plt:
103+
self.field_plots[plot_name] = plot
104+
return plot
105+
else:
106+
return False
107+
108+
@pyaedt_function_handler(IntrinsincDict="intrinsics", setup_name="setup")
109+
def create_fieldplot_line_traces(
110+
self,
111+
seeding_faces,
112+
in_volume_tracing_objs=None,
113+
surface_tracing_objs=None,
114+
setup=None,
115+
intrinsics=None,
116+
plot_name=None,
117+
field_type="DC R/L Fields",
118+
):
119+
"""
120+
Create a field plot of the line.
121+
122+
Parameters
123+
----------
124+
seeding_faces : list
125+
List of seeding faces.
126+
in_volume_tracing_objs : list
127+
List of the in-volume tracing objects.
128+
surface_tracing_objs : list
129+
List of the surface tracing objects.
130+
setup : str, optional
131+
Name of the setup in the format ``"setupName : sweepName"``. The default
132+
is ``None``.
133+
intrinsics : dict, str, optional
134+
Intrinsic variables required to compute the field before the export.
135+
These are typically: frequency, time and phase.
136+
It can be provided either as a dictionary or as a string.
137+
If it is a dictionary, keys depend on the solution type and can be expressed in lower or camel case as:
138+
- ``"Freq"`` or ``"Frequency"``.
139+
- ``"Time"``.
140+
- ``"Phase"``.
141+
If it is a string, it can either be ``"Freq"`` or ``"Time"`` depending on the solution type.
142+
The default is ``None`` in which case the intrinsics value is automatically computed based on the setup.
143+
plot_name : str, optional
144+
Name of the field plot to create. The default is ``None``.
145+
field_type : str, optional
146+
Field type to plot. Valid only for Q3D Field plots.
147+
148+
Returns
149+
-------
150+
type
151+
Plot object.
152+
153+
References
154+
----------
155+
>>> oModule.CreateFieldPlot
156+
157+
Examples
158+
--------
159+
>>> from ansys.aedt.core import Maxwell2d
160+
>>> aedtapp = Maxwell2d()
161+
>>> # Intrinsics is provided as a dictionary.
162+
>>> intrinsics = {"Freq": "5GHz", "Phase": "180deg"}
163+
>>> min_value = aedtapp.post.get_scalar_field_value(quantity_name, "Minimum", setup_name, intrinsics=intrinsics)
164+
>>> plot1 = aedtapp.post.create_fieldplot_line_traces(seeding_faces=["Ground", "Electrode", "Region"],
165+
>>> in_volume_tracing_objs="Region",
166+
>>> plot_name="LineTracesTest",
167+
>>> intrinsics=intrinsics)
168+
>>> # Intrinsics is provided as a string. Phase is automatically assigned to 0deg.
169+
>>> min_value = aedtapp.post.get_scalar_field_value(quantity_name, "Minimum", setup_name, intrinsics="5GHz")
170+
>>> plot1 = aedtapp.post.create_fieldplot_line_traces(seeding_faces=["Ground", "Electrode", "Region"],
171+
>>> in_volume_tracing_objs="Region",
172+
>>> plot_name="LineTracesTest",
173+
>>> intrinsics="200Hz")
174+
"""
175+
intrinsics = self._check_intrinsics(intrinsics, setup=setup)
176+
if self._app.solution_type != "Electrostatic":
177+
self.logger.error("Field line traces is valid only for electrostatic solution")
178+
return False
179+
if plot_name and plot_name in list(self.field_plots.keys()):
180+
self.logger.info(f"Plot {plot_name} exists. returning the object.")
181+
return self.field_plots[plot_name]
182+
if not isinstance(seeding_faces, list):
183+
seeding_faces = [seeding_faces]
184+
seeding_faces_ids = []
185+
for face in seeding_faces:
186+
if self._app.modeler[face]:
187+
seeding_faces_ids.append(self._app.modeler[face].id)
188+
else:
189+
self.logger.error(f"Object {face} doesn't exist in current design")
190+
return False
191+
in_volume_tracing_ids = []
192+
if not in_volume_tracing_objs:
193+
in_volume_tracing_ids.append(0)
194+
elif not isinstance(in_volume_tracing_objs, list):
195+
in_volume_tracing_objs = [in_volume_tracing_objs]
196+
for obj in in_volume_tracing_objs:
197+
if self._app.modeler[obj]:
198+
in_volume_tracing_ids.append(self._app.modeler[obj].id)
199+
else:
200+
self.logger.error(f"Object {obj} doesn't exist in current design")
201+
return False
202+
elif isinstance(in_volume_tracing_objs, list):
203+
for obj in in_volume_tracing_objs:
204+
if not self._app.modeler[obj]:
205+
self.logger.error(f"Object {obj} doesn't exist in current design")
206+
return False
207+
surface_tracing_ids = []
208+
if not surface_tracing_objs:
209+
surface_tracing_ids.append(0)
210+
elif not isinstance(surface_tracing_objs, list):
211+
surface_tracing_objs = [surface_tracing_objs]
212+
for obj in surface_tracing_objs:
213+
if self._app.modeler[obj]:
214+
surface_tracing_ids.append(self._app.modeler[obj].id)
215+
else:
216+
self.logger.error(f"Object {obj} doesn't exist in current design")
217+
return False
218+
elif isinstance(surface_tracing_objs, list):
219+
for obj in surface_tracing_objs:
220+
if not self._app.modeler[obj]:
221+
self.logger.error(f"Object {obj} doesn't exist in current design")
222+
return False
223+
seeding_faces_ids.insert(0, len(seeding_faces_ids))
224+
if in_volume_tracing_ids != [0]:
225+
in_volume_tracing_ids.insert(0, len(in_volume_tracing_ids))
226+
if surface_tracing_ids != [0]:
227+
surface_tracing_ids.insert(0, len(surface_tracing_ids))
228+
return self._create_fieldplot_line_traces(
229+
seeding_faces_ids,
230+
in_volume_tracing_ids,
231+
surface_tracing_ids,
232+
"FieldLineTrace",
233+
setup,
234+
intrinsics,
235+
plot_name,
236+
field_type=field_type,
237+
)
238+
239+
@pyaedt_function_handler()
240+
def create_fieldplot_layers(
241+
self, layers, quantity, setup=None, nets=None, plot_on_surface=True, intrinsics=None, name=None
242+
):
243+
# type: (list, str, str, list, bool, dict, str) -> FieldPlot
244+
"""Create a field plot of stacked layer plot.
245+
246+
This plot is valid from AEDT 2023 R2 and later. Nets can be used as a filter.
247+
Dielectrics will be included into the plot.
248+
It works when a layout components in 3d modeler is used.
249+
250+
Parameters
251+
----------
252+
layers : list
253+
List of layers to plot. For example:
254+
``["Layer1","Layer2"]``. If empty list is provided
255+
all layers are considered.
256+
quantity : str
257+
Name of the quantity to plot.
258+
setup : str, optional
259+
Name of the setup. The default is ``None``, in which case the ``nominal_adaptive``
260+
setup is used. Make sure to build a setup string in the form of
261+
``"SetupName : SetupSweep"``, where ``SetupSweep`` is the sweep name to
262+
use in the export or ``LastAdaptive``.
263+
nets : list, optional
264+
List of nets to filter the field plot. Optional.
265+
plot_on_surface : bool, optional
266+
Whether if the plot has to be on surfaces or inside the objects.
267+
It is applicable only to layout components. Default is ``True``.
268+
intrinsics : dict, str, optional
269+
Intrinsic variables required to compute the field before the export.
270+
These are typically: frequency, time and phase.
271+
It can be provided either as a dictionary or as a string.
272+
If it is a dictionary, keys depend on the solution type and can be expressed in lower or camel case as:
273+
274+
- ``"Freq"`` or ``"Frequency"``.
275+
- ``"Time"``.
276+
- ``"Phase"``.
277+
278+
If it is a string, it can either be ``"Freq"`` or ``"Time"`` depending on the solution type.
279+
The default is ``None`` in which case the intrinsics value is automatically computed based on the setup.
280+
name : str, optional
281+
Name of the field plot to create.
282+
283+
Returns
284+
-------
285+
:class:``ansys.aedt.core.modules.solutions.FieldPlot`` or bool
286+
Plot object.
287+
288+
References
289+
----------
290+
>>> oModule.CreateFieldPlot
291+
"""
292+
return self.post_3dlayout.create_fieldplot_layers(
293+
layers, quantity, setup, nets, plot_on_surface, intrinsics, name
294+
)
295+
296+
@pyaedt_function_handler()
297+
def create_fieldplot_layers_nets(
298+
self, layers_nets, quantity, setup=None, intrinsics=None, plot_on_surface=True, plot_name=None
299+
):
300+
# type: (list, str, str, dict, bool, str) -> FieldPlot
301+
"""Create a field plot of stacked layer plot on specified matrix of layers and nets.
302+
303+
This plot is valid from AEDT 2023 R2 and later in HFSS 3D Layout
304+
and any modeler where a layout component is used.
305+
306+
Parameters
307+
----------
308+
layers_nets : list
309+
List of layers and nets to plot. For example:
310+
``[["Layer1", "GND", "PWR"], ["Layer2", "VCC"], ...]``. If ``"no-layer"`` is provided as first argument,
311+
all layers are considered. If ``"no-net"`` is provided or the list contains only layer name, all the
312+
nets are automatically considered.
313+
quantity : str
314+
Name of the quantity to plot.
315+
setup : str, optional
316+
Name of the setup. The default is ``None``, in which case the ``nominal_adaptive``
317+
setup is used. Make sure to build a setup string in the form of
318+
``"SetupName : SetupSweep"``, where ``SetupSweep`` is the sweep name to
319+
use in the export or ``LastAdaptive``.
320+
intrinsics : dict, str, optional
321+
Intrinsic variables required to compute the field before the export.
322+
These are typically: frequency, time and phase.
323+
It can be provided either as a dictionary or as a string.
324+
If it is a dictionary, keys depend on the solution type and can be expressed in lower or camel case as:
325+
326+
- ``"Freq"`` or ``"Frequency"``.
327+
- ``"Time"``.
328+
- ``"Phase"``.
329+
330+
If it is a string, it can either be ``"Freq"`` or ``"Time"`` depending on the solution type.
331+
The default is ``None`` in which case the intrinsics value is automatically computed based on the setup.
332+
plot_on_surface : bool, optional
333+
Whether if the plot has to be on surfaces or inside the objects.
334+
It is applicable only to layout components. Default is ``True``.
335+
plot_name : str, optional
336+
Name of the field plot to create.
337+
338+
Returns
339+
-------
340+
:class:``ansys.aedt.core.modules.solutions.FieldPlot``
341+
Plot object.
342+
343+
References
344+
----------
345+
>>> oModule.CreateFieldPlot
346+
"""
347+
return self.post_3dlayout.create_fieldplot_layers_nets(
348+
layers_nets, quantity, setup, intrinsics, plot_on_surface, plot_name
349+
)

0 commit comments

Comments
 (0)