Skip to content

Commit

Permalink
feat: Support argument aliases in PyFluent
Browse files Browse the repository at this point in the history
  • Loading branch information
mkundu1 committed Oct 16, 2024
1 parent 32d7442 commit 9de91b4
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 38 deletions.
66 changes: 43 additions & 23 deletions src/ansys/fluent/core/solver/flobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -1598,24 +1598,35 @@ class Map(SettingsBase[DictStateType]):

def _get_new_keywords(obj, *args, **kwds):
newkwds = {}
argNames = []
argumentNames = []
unknown_keywords = set()
# Convert positional arguments to keyword arguments
if args:
argNames = obj.argument_names[:]
for i, arg in enumerate(args):
ccls = getattr(obj, argNames[0])
newkwds[ccls.fluent_name] = ccls.to_scheme_keys(arg)
argNames.pop(0)
for arg in args:
argName = argNames.pop(0)
newkwds[argName] = arg
if kwds:
argumentNames = obj.argument_names[:]
if argNames:
argumentNames = argNames
for k, v in kwds.items():
if k in argumentNames:
ccls = getattr(obj, k)
newkwds[ccls.fluent_name] = ccls.to_scheme_keys(v)
else:
raise RuntimeError("Argument '" + str(k) + "' is invalid")
# Convert deprecated keywords through aliases
# We don't get argument-aliases from static-info yet.
argument_aliases_scm = obj.get_attr("arguments-aliases") or {}
argument_aliases = {}
for k, v in argument_aliases_scm.items():
argument_aliases[to_python_name(k)] = to_python_name(v.removeprefix("'"))
for k, v in kwds.items():
alias = argument_aliases.get(k)
if alias:
newkwds[alias] = v
elif k in obj.argument_names:
newkwds[k] = v
else:
unknown_keywords.add(k)
for k in unknown_keywords:
# Noisily ignore unknown keywords
warnings.warn(
f"Unknown keyword '{k}' for command '{obj.python_path}'. "
"It will be ignored.",
PyFluentUserWarning,
)
return newkwds


Expand Down Expand Up @@ -1676,10 +1687,9 @@ class BaseCommand(Action):

def _execute_command(self, *args, **kwds):
"""Execute a command with the specified positional and keyword arguments."""
newkwds = _get_new_keywords(self, *args, **kwds)
if self.flproxy.is_interactive_mode():
prompt = self.flproxy.get_command_confirmation_prompt(
self._parent.path, self.obj_name, **newkwds
self._parent.path, self.obj_name, **kwds
)
if prompt:
valid_responses = {"y": True, "yes": True, "n": False, "no": False}
Expand All @@ -1692,7 +1702,7 @@ def _execute_command(self, *args, **kwds):
else:
print("Please enter 'y[es]' or 'n[o]'.")
with self._while_executing_command():
ret = self.flproxy.execute_cmd(self._parent.path, self.obj_name, **newkwds)
ret = self.flproxy.execute_cmd(self._parent.path, self.obj_name, **kwds)
if os.getenv("PYFLUENT_NO_FIX_PARAMETER_LIST_RETURN") != "1":
if (self._parent.path, self.obj_name) in [
("parameters/input-parameters", "list"),
Expand All @@ -1703,15 +1713,20 @@ def _execute_command(self, *args, **kwds):

def execute_command(self, *args, **kwds):
"""Execute command."""
kwds = _get_new_keywords(self, *args, **kwds)
scmKwds = {}
for arg, value in kwds.items():
argument = getattr(self, arg)
kwds[arg] = argument.before_execute(
# Convert path-like values for possible file transfer
value = argument.before_execute(
command_name=self.python_name, value=value, kwargs=kwds
)
ret = self._execute_command(*args, **kwds)
# Convert key-value to Scheme key-value
scmKwds[argument.fluent_name] = argument.to_scheme_keys(value)
ret = self._execute_command(*args, **scmKwds)
for arg, value in kwds.items():
argument = getattr(self, arg)
kwds[arg] = argument.after_execute(
argument.after_execute(
command_name=self.python_name, value=value, kwargs=kwds
)
if (
Expand Down Expand Up @@ -2128,10 +2143,15 @@ def _process_cls_names(info_dict, names, write_doc=False):
child_aliases = info.get("child-aliases") or info.get("child_aliases", {})
command_aliases = info.get("command-aliases") or info.get("command_aliases", {})
query_aliases = info.get("query-aliases") or info.get("query_aliases", {})
if child_aliases or command_aliases or query_aliases:
argument_aliases = info.get("argument-aliases") or info.get(
"argument_aliases", {}
)
if child_aliases or command_aliases or query_aliases or argument_aliases:
cls._child_aliases = {}
# No need to differentiate in the Python implementation
for k, v in (child_aliases | command_aliases | query_aliases).items():
for k, v in (
child_aliases | command_aliases | query_aliases | argument_aliases
).items():
cls._child_aliases[to_python_name(k)] = "/".join(
x if x == ".." else to_python_name(x) for x in v.split("/")
)
Expand Down
45 changes: 30 additions & 15 deletions tests/test_settings_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
to_python_name,
)
from ansys.fluent.core.utils.fluent_version import FluentVersion
from ansys.fluent.core.warnings import PyFluentUserWarning


@pytest.mark.nightly
Expand Down Expand Up @@ -150,12 +151,8 @@ def test_wildcard(new_solver_session):


@pytest.mark.fluent_version(">=23.2")
def test_wildcard_fnmatch(new_solver_session):
solver = new_solver_session
case_path = download_file("elbow_source_terms.cas.h5", "pyfluent/mixing_elbow")
solver.file.read_case(file_name=case_path)

solver.solution.initialization.hybrid_initialize()
def test_wildcard_fnmatch(mixing_elbow_case_data_session):
solver = mixing_elbow_case_data_session

mesh = solver.results.graphics.mesh
assert mesh.create("mesh-a").name() == "mesh-a"
Expand All @@ -179,10 +176,8 @@ def test_wildcard_fnmatch(new_solver_session):


@pytest.mark.fluent_version(">=23.2")
def test_wildcard_path_is_iterable(new_solver_session):
solver = new_solver_session
case_path = download_file("elbow_source_terms.cas.h5", "pyfluent/mixing_elbow")
solver.file.read(file_name=case_path, file_type="case", lightweight_setup=True)
def test_wildcard_path_is_iterable(mixing_elbow_settings_session):
solver = mixing_elbow_settings_session

velocity_inlet = solver.setup.boundary_conditions.velocity_inlet
assert [x for x in velocity_inlet] == ["inlet2", "inlet1"]
Expand Down Expand Up @@ -360,11 +355,8 @@ def test_deprecated_settings_with_custom_aliases(new_solver_session):


@pytest.mark.fluent_version(">=25.1")
def test_deprecated_settings_with_settings_api_aliases(new_solver_session):
solver = new_solver_session
case_path = download_file("mixing_elbow.cas.h5", "pyfluent/mixing_elbow")
download_file("mixing_elbow.dat.h5", "pyfluent/mixing_elbow")
solver.settings.file.read_case_data(file_name=case_path)
def test_deprecated_settings_with_settings_api_aliases(mixing_elbow_case_data_session):
solver = mixing_elbow_case_data_session
solver.settings.results.surfaces.iso_clip["clip-1"] = {}
assert solver.settings.results.surfaces.iso_clip["clip-1"].range() == {
"minimum": 0,
Expand Down Expand Up @@ -519,3 +511,26 @@ def test_commands_not_in_settings(new_solver_session):
assert command not in dir(solver.settings)
with pytest.raises(AttributeError):
getattr(solver.settings, command)


def test_deprecated_command_arguments(mixing_elbow_case_data_session):
solver = mixing_elbow_case_data_session
with pytest.warns() as record:
# all_boundary_zones is an unknown/unsupported keyword
solver.settings.results.report.fluxes.mass_flow(
all_boundary_zones=False, zones=["cold-inlet", "hot-inlet", "outlet"]
)
assert len(record) == 1
assert record[0].category == PyFluentUserWarning
assert "all_boundary_zones" in str(record[0].message)

solver.settings.results.graphics.mesh.create("m1")
solver.settings.results.graphics.mesh.make_a_copy(from_="m1", to="m2")
solver.settings.results.graphics.mesh.copy(
from_name="m1", new_name="m3"
) # deprecated
assert set(solver.settings.results.graphics.mesh.get_object_names()) == {
"m1",
"m2",
"m3",
}

0 comments on commit 9de91b4

Please sign in to comment.