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

Merged
merged 31 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 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
10091d2
Merge branch 'main' into fix_HFSS_linear_step_sweep
maxcapodi78 Feb 6, 2025
002cb30
Merge branch 'main' into fix_HFSS_linear_step_sweep
Devin-Crawford Feb 7, 2025
d11573f
Merge branch 'main' into fix_HFSS_linear_step_sweep
Samuelopez-ansys Feb 7, 2025
39dea75
Pass props to sweep.
Devin-Crawford Feb 7, 2025
bed1f92
Merge remote-tracking branch 'origin/fix_HFSS_linear_step_sweep' into…
Devin-Crawford Feb 7, 2025
8857b69
CHORE: Auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 7, 2025
e3280a7
Correct message handling in solve_sweeps.py
Devin-Crawford Feb 7, 2025
d9c30d3
Correct message handling in solve_sweeps.py
Devin-Crawford Feb 7, 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 @@ -814,8 +814,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 @@ -860,9 +860,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 @@ -1614,6 +1614,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
31 changes: 27 additions & 4 deletions src/ansys/aedt/core/modules/solve_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,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 @@ -442,7 +444,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 @@ -2873,7 +2875,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 @@ -2883,6 +2885,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 @@ -2896,9 +2900,18 @@
if not name:
name = generate_unique_name("Sweep")
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) # TODO: add , props=props)

Check warning on line 2905 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#L2904-L2905

Added lines #L2904 - L2905 were not covered by tests
else:
self._app.logger.warning("This method only applies to HFSS, Q2D, and Q3D.")
return False

Check warning on line 2908 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#L2907-L2908

Added lines #L2907 - L2908 were not covered by tests
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 @@ -4126,7 +4139,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 @@ -4150,6 +4163,16 @@
name = generate_unique_name("Sweep")
if self.setuptype in [14, 30, 31]:
sweep_n = SweepMatrix(self, name=name, sweep_type=sweep_type)
if self.setuptype == 7:
self._app.logger.warning("This method only applies to HFSS and Q3D. Use add_eddy_current_sweep method.")
return False

Check warning on line 4168 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#L4167-L4168

Added lines #L4167 - L4168 were not covered by tests
if self.setuptype <= 4:
sweep_n = SweepHFSS(self, name=name, sweep_type=sweep_type, props=props)

Check warning on line 4170 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#L4170

Added line #L4170 was not covered by tests
elif self.setuptype in [14, 30, 31]:
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

Check warning on line 4175 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#L4174-L4175

Added lines #L4174 - L4175 were not covered by tests
sweep_n.create()
self.sweeps.append(sweep_n)
for setup in self.p_app.setups:
Expand Down
51 changes: 32 additions & 19 deletions src/ansys/aedt/core/modules/solve_sweeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from ansys.aedt.core.modules.setup_templates import Sweep3DLayout
from ansys.aedt.core.modules.setup_templates import SweepEddyCurrent
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 @@ -109,25 +110,35 @@
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.p_app.logger.info(

Check warning on line 119 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#L119

Added line #L119 was not covered by tests
"Inconsistent arguments 'RangeCount' and 'RangeStep' passed to 'SweepHFSS',"
)
self._app.p_app.logger.info("Default remains 'LinearCount' sweep type.")

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#L122

Added line #L122 was not covered by tests
else:
self.props["RangeType"] = "LinearStep"
for key, value in props.items():
if key in self.props.keys():
self.props[key] = value
else:
error_message = f"Parameter '{key}' is invalid and will be ignored."
self._app.p_app.logger.warning(error_message)

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 +623,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
Loading