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

FIX: Enable field plotting with discrete sweep #5683

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8b1932d
Enable field plotting with discrete sweep
Devin-Crawford Jan 21, 2025
5da65f1
CHORE: Auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 22, 2025
1d5c9ac
Fix minor style issues
Devin-Crawford Jan 23, 2025
984da6f
CHORE: Auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 23, 2025
890051d
Fix far-field report type.
Devin-Crawford Jan 25, 2025
8fb9c84
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Jan 25, 2025
9a5e850
BUILD: Remove attrs and referencing avoid versions
SMoraisAnsys Jan 26, 2025
fd2ce1b
Merge remote-tracking branch 'origin/build/remove-packages-added-for-…
Devin-Crawford Jan 26, 2025
76969fc
Update Unit Test
Devin-Crawford Jan 26, 2025
e08bce8
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Jan 29, 2025
04f94ce
Minor fixes
Devin-Crawford Jan 29, 2025
8677e2c
Add Unit Test
Devin-Crawford Jan 30, 2025
21c82c3
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Jan 30, 2025
ea88df1
CHORE: Auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2025
3587166
Update Q3D add_sweep method
Devin-Crawford Jan 31, 2025
157f3e4
Merge remote-tracking branch 'origin/fix_HFSS_linear_step_sweep' into…
Devin-Crawford Jan 31, 2025
c88add2
CHORE: Auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 31, 2025
5b1f614
Update method to get sweep name
Devin-Crawford Feb 1, 2025
3914ee1
Merge remote-tracking branch 'origin/fix_HFSS_linear_step_sweep' into…
Devin-Crawford Feb 1, 2025
4080a64
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Feb 1, 2025
7be7616
Default setup to last adaptive for field report
Devin-Crawford Feb 1, 2025
bc1c43f
Minor update to improve unit test coverage.
Devin-Crawford Feb 3, 2025
5c9b8e1
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Feb 3, 2025
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
10 changes: 5 additions & 5 deletions src/ansys/aedt/core/hfss.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,8 +796,8 @@ def create_setup(self, name="MySetupAuto", setup_type=None, **kwargs):
"""Create an analysis setup for HFSS.

Optional arguments are passed along with ``setup_type`` and ``name``. Keyword
names correspond to the ``setup_type`` corresponding to the native AEDT API.
The list of keywords here is not exhaustive.
names correspond to keyword for the ``setup_type`` as defined in
the native AEDT API.

.. note::
This method overrides the ``Analysis.setup()`` method for the HFSS app.
Expand Down Expand Up @@ -842,9 +842,9 @@ def create_setup(self, name="MySetupAuto", setup_type=None, **kwargs):
setup.auto_update = False
for arg_name, arg_value in kwargs.items():
if setup[arg_name] is not None:
if arg_name == "MultipleAdaptiveFreqsSetup":
setup[arg_name].delete_all()
if isinstance(arg_value, list):
if arg_name == "MultipleAdaptiveFreqsSetup": # A list of frequency values is passed if
setup[arg_name].delete_all() # the default convergence criteria are to be
if isinstance(arg_value, list): # used.
for i in arg_value:
setup[arg_name][i] = [0.02]
else:
Expand Down
13 changes: 13 additions & 0 deletions src/ansys/aedt/core/modules/setup_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,19 @@ def HFSS3DLayout_AdaptiveFrequencyData(freq):

TR = {}

# Default sweep settings for Q3D
SweepQ3D = dict(
{
"IsEnabled": True,
"RangeType": "LinearStep",
"RangeStart": "1GHz",
"RangeEnd": "10GHz",
"Type": "Discrete",
"SaveFields": False,
"SaveRadFields": False,
}
)

SweepHfss3D = dict(
{
"Type": "Interpolating",
Expand Down
22 changes: 15 additions & 7 deletions src/ansys/aedt/core/modules/solve_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@
]
else:
setup_sweep_name = [i for i in self._app.existing_analysis_sweeps if self.name == i.split(" : ")[0]]
if report_category == "Fields":
sweep = self._app.nominal_adaptive # Use last adaptive if no sweep is named explicitly.
if setup_sweep_name:
return self._app.post.get_solution_data(
expressions=expressions,
Expand All @@ -437,7 +439,7 @@
context=context,
polyline_points=polyline_points,
math_formula=math_formula,
setup_sweep_name=sweep,
setup_sweep_name=sweep, # Should this be setup_sweep_name?
)
return None

Expand Down Expand Up @@ -2868,7 +2870,7 @@
return sweepdata

@pyaedt_function_handler(sweepname="name", sweeptype="sweep_type")
def add_sweep(self, name=None, sweep_type="Interpolating"):
def add_sweep(self, name=None, sweep_type="Interpolating", **props):
"""Add a sweep to the project.

Parameters
Expand All @@ -2878,6 +2880,8 @@
case a name is automatically assigned.
sweep_type : str, optional
Type of the sweep. The default is ``"Interpolating"``.
**props : Optional context-dependent keyword arguments can be passed
to the sweep setup

Returns
-------
Expand All @@ -2895,14 +2899,18 @@
self._app.logger.warning("This method only applies to HFSS and Q3D. Use add_eddy_current_sweep method.")
return False
if self.setuptype <= 4:
sweep_n = SweepHFSS(self, name=name, sweep_type=sweep_type)
sweep_n = SweepHFSS(self, name=name, sweep_type=sweep_type, props=props)
elif self.setuptype in [14, 30, 31]:
sweep_n = SweepMatrix(self, name=name, sweep_type=sweep_type)
sweep_n = SweepMatrix(self, name=name, sweep_type=sweep_type) # TODO: add , props=props)
else:
self._app.logger.warning("This method only applies to HFSS, Q2D, and Q3D.")
return False
sweep_n.create()
self.sweeps.append(sweep_n)
for setup in self.p_app.setups:
if self.name == setup.name:
setup.sweeps.append(sweep_n)
break
return sweep_n

@pyaedt_function_handler(sweepname="name")
Expand Down Expand Up @@ -4013,7 +4021,7 @@
return sweepdata

@pyaedt_function_handler(sweepname="name", sweeptype="sweep_type")
def add_sweep(self, name=None, sweep_type="Interpolating"):
def add_sweep(self, name=None, sweep_type="Interpolating", **props):
"""Add a sweep to the project.

Parameters
Expand All @@ -4040,9 +4048,9 @@
self._app.logger.warning("This method only applies to HFSS and Q3D. Use add_eddy_current_sweep method.")
return False
if self.setuptype <= 4:
sweep_n = SweepHFSS(self, name=name, sweep_type=sweep_type)
sweep_n = SweepHFSS(self, name=name, sweep_type=sweep_type, props=props)

Check warning on line 4051 in src/ansys/aedt/core/modules/solve_setup.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/modules/solve_setup.py#L4051

Added line #L4051 was not covered by tests
elif self.setuptype in [14, 30, 31]:
sweep_n = SweepMatrix(self, name=name, sweep_type=sweep_type)
sweep_n = SweepMatrix(self, name=name, sweep_type=sweep_type, props=props)
else:
self._app.logger.warning("This method only applies to HFSS, Q2D, and Q3D.")
return False
Expand Down
54 changes: 35 additions & 19 deletions src/ansys/aedt/core/modules/solve_sweeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from ansys.aedt.core.generic.settings import settings
from ansys.aedt.core.modules.setup_templates import Sweep3DLayout
from ansys.aedt.core.modules.setup_templates import SweepHfss3D
from ansys.aedt.core.modules.setup_templates import SweepQ3D
from ansys.aedt.core.modules.setup_templates import SweepSiwave

open3 = open
Expand Down Expand Up @@ -108,25 +109,38 @@
def __init__(self, setup, name, sweep_type="Interpolating", props=None):
self._app = setup
self.oanalysis = setup.omodule
self.props = {}
self.setup_name = setup.name
self.name = name
self.props = copy.deepcopy(SweepHfss3D)
if props:
self.props = props
if "RangeStep" in props.keys(): # LinearCount is the default sweep type. Change it if RangeStep is passed.
if "RangeCount" in props.keys():
self._app.logger.message(

Check warning on line 118 in src/ansys/aedt/core/modules/solve_sweeps.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/modules/solve_sweeps.py#L118

Added line #L118 was not covered by tests
"Inconsistent arguments 'RangeCount' and 'RangeStep' passed to 'SweepHFSS',"
)
self._app.logger.message("Default remains 'LinearCount' sweep type.")
self._app.logger.message("") # Add a space to the log file.

Check warning on line 122 in src/ansys/aedt/core/modules/solve_sweeps.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/modules/solve_sweeps.py#L121-L122

Added lines #L121 - L122 were not covered by tests
else:
self.props["RangeType"] = "LinearStep"
for key, value in props.items():
try:
self.props[key] = value
except ValueError:
error_message = f"Parameter '{key}' is invalid and will be ignored."
self._app.logger.warning(error_message)

Check warning on line 130 in src/ansys/aedt/core/modules/solve_sweeps.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/modules/solve_sweeps.py#L128-L130

Added lines #L128 - L130 were not covered by tests

# for t in SweepHfss3D:
# _tuple2dict(t, self.props)
if SequenceMatcher(None, sweep_type.lower(), "interpolating").ratio() > 0.8:
sweep_type = "Interpolating"
elif SequenceMatcher(None, sweep_type.lower(), "discrete").ratio() > 0.8:
sweep_type = "Discrete"
elif SequenceMatcher(None, sweep_type.lower(), "fast").ratio() > 0.8:
sweep_type = "Fast"
else:
self.props = copy.deepcopy(SweepHfss3D)
# for t in SweepHfss3D:
# _tuple2dict(t, self.props)
if SequenceMatcher(None, sweep_type.lower(), "interpolating").ratio() > 0.8:
sweep_type = "Interpolating"
elif SequenceMatcher(None, sweep_type.lower(), "discrete").ratio() > 0.8:
sweep_type = "Discrete"
elif SequenceMatcher(None, sweep_type.lower(), "fast").ratio() > 0.8:
sweep_type = "Fast"
else:
warnings.warn("Invalid sweep type. `Interpolating` will be set as the default.")
sweep_type = "Interpolating"
self.props["Type"] = sweep_type
warnings.warn("Invalid sweep type. `Interpolating` will be set as the default.")
sweep_type = "Interpolating"
self.props["Type"] = sweep_type

@property
def is_solved(self):
Expand Down Expand Up @@ -612,17 +626,19 @@
"""

def __init__(self, setup, name, sweep_type="Interpolating", props=None):
self._app = setup
self._app = setup # TODO: Remove sweep_type as an argument as it can be passed in props
self.oanalysis = setup.omodule
self.setup_name = setup.name
self.name = name
self.props = {}
self.props = copy.deepcopy(SweepQ3D)
if props:
self.props = props
for key, value in props.items():
if key in self.props:
self.props[key] = value
else:
self.props["Type"] = sweep_type
if sweep_type == "Discrete":
self.props["isenabled"] = True
self.props["IsEnabled"] = True
self.props["RangeType"] = "LinearCount"
self.props["RangeStart"] = "2.5GHz"
self.props["RangeStep"] = "1GHz"
Expand Down
48 changes: 42 additions & 6 deletions src/ansys/aedt/core/visualization/post/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,28 @@
report_category = self.available_report_types[0]
if report_category:
return list(self.oreportsetup.GetAvailableSolutions(report_category))
return None # pragma: no cover
return None

Check warning on line 497 in src/ansys/aedt/core/visualization/post/common.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/post/common.py#L497

Added line #L497 was not covered by tests

@pyaedt_function_handler() # pragma: no cover
def _get_setup_from_sweep_name(self, sweep_name):
if ":" not in sweep_name:
sweep_names = [] # Look for sweep name in setups if the setup is not
for s in self._app.setups: # passed explicitly in setup_sweep_name.
for sweep in s.sweeps:
this_name = s.name + " : " + sweep.name if sweep.name == sweep_name else None
if this_name:
sweep_names.append(this_name)
if len(sweep_names) > 1:
warning_str = "More than one sweep with name '{setup_sweep_name}' found. "
warning_str += f"Returning '{sweep_names[0]}'."
self.logger.warning(warning_str)
return sweep_names[0]
elif len(sweep_names) == 1:
return sweep_names[0]
else:
return sweep_name # Nothing found, pass the sweep name through.
else:
return sweep_name

@pyaedt_function_handler()
def _get_plot_inputs(self):
Expand Down Expand Up @@ -1211,7 +1232,12 @@
>>> m3d.release_desktop(False, False)
"""
if not setup_sweep_name:
setup_sweep_name = self._app.nominal_sweep
if report_category == "Fields":
setup_sweep_name = self._app.nominal_adaptive # Field report and no sweep name passed.
else:
setup_sweep_name = self._app.nominal_sweep
elif domain == "Sweep":
setup_sweep_name = self._get_setup_from_sweep_name(setup_sweep_name)
if not domain:
domain = "Sweep"
setup_name = setup_sweep_name.split(":")[0]
Expand Down Expand Up @@ -1654,6 +1680,8 @@
solution_name = self._app.nominal_sweep
else:
solution_name = self._app.nominal_adaptive
else:
solution_name = self._get_setup_from_sweep_name(solution_name) # If only the sweep name is passed.
if props.get("report_category", None) and props["report_category"] in TEMPLATES_BY_NAME:
if props.get("context", {"context": {}}).get("domain", "") == "Spectral":
report_temp = TEMPLATES_BY_NAME["Spectrum"]
Expand Down Expand Up @@ -1979,7 +2007,8 @@
>>> solutions = report.get_solution_data()
"""
if not setup:
setup = self._post_app._app.nominal_sweep
# setup = self._post_app._app.nominal_sweep
setup = self._post_app._app.nominal_adaptive
rep = None
if "Fields" in self._templates:
rep = ansys.aedt.core.visualization.report.field.Fields(self._post_app, "Fields", setup)
Expand Down Expand Up @@ -2111,7 +2140,7 @@
return rep

@pyaedt_function_handler(setup_name="setup")
def far_field(self, expressions=None, setup=None, sphere_name=None, source_context=None):
def far_field(self, expressions=None, setup=None, sphere_name=None, source_context=None, **variations):
"""Create a Far Field Report object.

Parameters
Expand Down Expand Up @@ -2146,10 +2175,17 @@
setup = self._post_app._app.nominal_sweep
rep = None
if "Far Fields" in self._templates:
rep = ansys.aedt.core.visualization.report.field.FarField(self._post_app, "Far Fields", setup)
rep = ansys.aedt.core.visualization.report.field.FarField(self._post_app, "Far Fields", setup, **variations)
rep.far_field_sphere = sphere_name
rep.source_context = source_context
rep.expressions = self._retrieve_default_expressions(expressions, rep, setup)
rep.report_type = "Radiation Pattern"
if expressions:
if type(expressions) == list:
rep.expressions = expressions

Check warning on line 2184 in src/ansys/aedt/core/visualization/post/common.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/post/common.py#L2184

Added line #L2184 was not covered by tests
else:
rep.expressions = [expressions]
else:
rep.expressions = self._retrieve_default_expressions(expressions, rep, setup)

Check warning on line 2188 in src/ansys/aedt/core/visualization/post/common.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/post/common.py#L2188

Added line #L2188 was not covered by tests
return rep

@pyaedt_function_handler(setup_name="setup", sphere_name="infinite_sphere")
Expand Down
14 changes: 7 additions & 7 deletions src/ansys/aedt/core/visualization/report/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,19 @@
class FarField(CommonReport):
"""Provides for managing far field reports."""

def __init__(self, app, report_category, setup_name, expressions=None):
def __init__(self, app, report_category, setup_name, expressions=None, **variations):
CommonReport.__init__(self, app, report_category, setup_name, expressions)
variation_defaults = {"Phi": ["All"], "Theta": ["All"], "Freq": ["Nominal"]}
self.domain = "Sweep"
self.primary_sweep = "Phi"
self.secondary_sweep = "Theta"
self.source_context = None
self.source_group = None
if "Phi" not in self.variations:
self.variations["Phi"] = ["All"]
if "Theta" not in self.variations:
self.variations["Theta"] = ["All"]
if "Freq" not in self.variations:
self.variations["Freq"] = ["Nominal"]
for key, default_value in variation_defaults.items():
if key in variations:
self.variations[key] = variations[key]

Check warning on line 144 in src/ansys/aedt/core/visualization/report/field.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/report/field.py#L144

Added line #L144 was not covered by tests
else:
self.variations[key] = default_value

@property
def far_field_sphere(self):
Expand Down
Binary file not shown.
20 changes: 20 additions & 0 deletions tests/system/general/test_11_Setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ def test_01_create_hfss_setup(self):
max_delta_phase=8,
custom_entries=[["1", "2", 0.03, 4]],
)
setup2 = self.aedtapp.create_setup(
"MulitFreqSetup", MultipleAdaptiveFreqsSetup=["1GHz", "2GHz"], MaximumPasses=3
)
assert setup2.props["SolveType"] == "MultiFrequency"
assert setup2.props["MaximumPasses"] == 3

def test_01b_create_hfss_sweep(self):
self.aedtapp.save_project()
Expand All @@ -121,6 +126,21 @@ def test_01b_create_hfss_sweep(self):
assert sweep3.props["Type"] == "Discrete"
sweep4 = setup1.create_frequency_sweep("GHz", 23, 25, 401, sweep_type="Fast")
assert sweep4.props["Type"] == "Fast"
range_start = "1GHz"
range_end = "2GHz"
range_step = "0.5GHz"
sweep5 = setup1.add_sweep(
"DiscSweep5",
sweep_type="Discrete",
RangeStart=range_start,
RangeEnd=range_end,
RangeStep=range_step,
SaveFields=True,
)
assert sweep5.props["Type"] == "Discrete"
assert sweep5.props["RangeStart"] == range_start
assert sweep5.props["RangeEnd"] == range_end
assert sweep5.props["RangeStep"] == range_step

def test_01c_create_hfss_setup_auto_open(self):
self.aedtapp.duplicate_design("auto_open")
Expand Down
Loading