Skip to content

feat: beta features access #4153

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

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions doc/changelog.d/4153.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
beta features access
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
"ansys-api-fluent>=0.3.35",
"ansys-api-fluent>=0.3.36",
"ansys-platform-instancemanagement~=1.1",
"ansys-tools-filetransfer>=0.1,<0.3",
"ansys-units>=0.6.dev1,<1.0",
Expand Down
29 changes: 17 additions & 12 deletions src/ansys/fluent/core/fluent_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from ansys.fluent.core.services.app_utilities import (
AppUtilitiesOld,
AppUtilitiesService,
AppUtilitiesV252,
)
from ansys.fluent.core.services.scheme_eval import SchemeEvalService
from ansys.fluent.core.utils.execution import timeout_exec, timeout_loop
Expand Down Expand Up @@ -277,18 +278,22 @@ def __init__(self, create_grpc_service, error_state):
self.scheme_eval = service_creator("scheme_eval").create(
self._scheme_eval_service
)
if (
pyfluent.FluentVersion(self.scheme_eval.version)
< pyfluent.FluentVersion.v252
):
self._app_utilities = AppUtilitiesOld(self.scheme_eval)
else:
self._app_utilities_service = create_grpc_service(
AppUtilitiesService, error_state
)
self._app_utilities = service_creator("app_utilities").create(
self._app_utilities_service
)
self._app_utilities_service = create_grpc_service(
AppUtilitiesService, error_state
)
match pyfluent.FluentVersion(self.scheme_eval.version):
case v if v < pyfluent.FluentVersion.v252:
self._app_utilities = AppUtilitiesOld(self.scheme_eval)

case pyfluent.FluentVersion.v252:
self._app_utilities = AppUtilitiesV252(
self._app_utilities_service, self.scheme_eval
)

case _:
self._app_utilities = service_creator("app_utilities").create(
self._app_utilities_service
)

@property
def product_build_info(self) -> str:
Expand Down
39 changes: 39 additions & 0 deletions src/ansys/fluent/core/services/app_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ def is_beta_enabled(
"""Is beta enabled RPC of AppUtilities service."""
return self._stub.IsBetaEnabled(request, metadata=self._metadata)

def enable_beta(
self, request: AppUtilitiesProtoModule.EnableBetaRequest
) -> AppUtilitiesProtoModule.EnableBetaResponse:
"""Is beta enabled RPC of AppUtilities service."""
return self._stub.EnableBeta(request, metadata=self._metadata)

def is_wildcard(
self, request: AppUtilitiesProtoModule.IsWildcardRequest
) -> AppUtilitiesProtoModule.IsWildcardResponse:
Expand Down Expand Up @@ -255,6 +261,18 @@ def is_beta_enabled(self) -> bool:
"""Is beta enabled."""
return self.scheme.eval("(is-beta-feature-available?)")

def enable_beta(self):
"""Enable beta features.

Raises
------
RuntimeError
Not supported before Fluent 2025 R2.
"""
raise RuntimeError(
"Enabling beta is not supported py PyFluent for Fluent versions before 2025 R2."
)

def is_wildcard(self, input: str | None = None) -> bool:
"""Is wildcard."""
return self.scheme.eval(f'(has-fnmatch-wild-card? "{input}")')
Expand Down Expand Up @@ -405,6 +423,11 @@ def is_beta_enabled(self) -> bool:
response = self.service.is_beta_enabled(request)
return response.is_beta_enabled

def enable_beta(self) -> None:
"""Enable beta features."""
request = AppUtilitiesProtoModule.EnableBetaRequest()
self.service.enable_beta(request)

def is_wildcard(self, input: str | None = None) -> bool:
"""Is wildcard."""
request = AppUtilitiesProtoModule.IsWildcardRequest()
Expand Down Expand Up @@ -456,3 +479,19 @@ def set_working_directory(self, path: str) -> None:
request = AppUtilitiesProtoModule.SetWorkingDirectoryRequest()
request.path = path
self.service.set_working_directory(request)


class AppUtilitiesV252(AppUtilities):
"""AppUtilitiesV252.
This is for methods whose implementations are missing in the 25R2 server.
"""

def __init__(self, service: AppUtilitiesService, scheme):
super().__init__(service)
self.scheme = scheme

def enable_beta(self) -> None:
"""Enable beta features."""
self.scheme.eval(
'(fl-execute-cmd "file" "beta-settings" (list (cons "enable?" #t)))'
)
9 changes: 9 additions & 0 deletions src/ansys/fluent/core/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,18 @@ def __dir__(self):
"field_data_streaming",
"start_journal",
"stop_journal",
"scheme_eval",
}
return sorted(dir_list)

def enable_beta_features(self):
"""Enable access to Fluent beta-features"""
self._app_utilities.enable_beta()

@property
def _is_beta_enabled(self):
return self._app_utilities.is_beta_enabled()


class Fields:
"""Container for field and solution variables."""
Expand Down
14 changes: 9 additions & 5 deletions src/ansys/fluent/core/session_pure_meshing.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,12 @@ def topology_based(self):

Raises
------
RuntimeError
AttributeError
If beta features are not enabled in Fluent.
"""
if not self._app_utilities.is_beta_enabled():
raise RuntimeError("Topology-based Meshing is a beta feature in Fluent.")
self._base_meshing.topology_based_meshing_workflow.initialize()
return self._base_meshing.topology_based_meshing_workflow
if not self._is_beta_enabled:
raise AttributeError("Topology-based Meshing is a beta feature in Fluent.")
return self._base_meshing.topology_based_meshing_workflow()

@property
def PartManagement(self):
Expand Down Expand Up @@ -238,3 +237,8 @@ def transfer_mesh_to_solvers(
clean_up_mesh_file,
overwrite_previous,
)

def __dir__(self):
if self._fluent_connection is not None and self._is_beta_enabled is False:
return sorted(set(super().__dir__()) - {"topology_based"})
return super().__dir__()
1 change: 1 addition & 0 deletions src/ansys/fluent/core/session_pure_meshing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ class PureMeshing:
clean_up_mesh_file: bool = ...,
overwrite_previous: bool = ...,
): ...
def enable_beta_features(self): ...
44 changes: 36 additions & 8 deletions src/ansys/fluent/core/session_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,44 @@ def __getattr__(self, name):
raise ex

def __dir__(self):
if self._fluent_connection is None:
return ["is_active"]
dir_list = set(list(self.__dict__.keys()) + dir(type(self))) - {
dir_list = set(super().__dir__()) - {
"svar_data",
"svar_info",
"reduction",
"field_data",
"field_info",
"field_data_streaming",
"start_journal",
"stop_journal",
}
if self._fluent_connection is not None and self._is_beta_enabled is False:
return sorted(dir_list - {"switch_to_meshing"})
return sorted(dir_list)

def switch_to_meshing(self):
"""Switch to meshing mode and return a meshing session object. Deactivate this
object's public interface and streaming services.

Raises
------
AttributeError
If beta features are not enabled in Fluent.

Returns
-------
Meshing
"""
if not self._is_beta_enabled:
raise AttributeError(
"Switching to meshing mode is a beta feature in Fluent."
)
from ansys.fluent.core.session_meshing import Meshing

self.settings.switch_to_meshing_mode()
for cb in self._fluent_connection.finalizer_cbs:
cb()
meshing_session = Meshing(
fluent_connection=self._fluent_connection,
scheme_eval=self.scheme,
file_transfer_service=self._file_transfer_service,
)
self._fluent_connection = None
self.__doc__ = (
"The solver session is no longer usable after switching to meshing mode."
)
return meshing_session
1 change: 1 addition & 0 deletions src/ansys/fluent/core/session_solver.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ class Solver:
def write_case(self, file_name: str): ...
@property
def settings(self) -> settings_root.root: ...
def enable_beta_features(self): ...
1 change: 0 additions & 1 deletion src/ansys/fluent/core/solver/flobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -2159,7 +2159,6 @@ def _process_cls_names(info_dict, names, write_doc=False):
commands = info.get("commands")
if commands:
commands.pop("exit", None)
commands.pop("switch-to-meshing-mode", None)
if commands and not user_creatable:
commands.pop("create", None)
if commands:
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,13 @@ def new_solver_session():
solver.exit()


@pytest.fixture
def new_solver_session_wo_exit():
solver = create_session()
yield solver
# Exit is intentionally avoided here. Please exit from the method using this.


@pytest.fixture
def new_solver_session_t4():
solver = create_session(processor_count=4)
Expand Down
102 changes: 102 additions & 0 deletions tests/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,3 +745,105 @@ def test_solver_attr_lookup(new_solver_session):
solver.xyz
with pytest.raises(AttributeError):
solver.settings.xyz


@pytest.mark.fluent_version(">=25.2")
def test_beta_meshing_session(new_meshing_session_wo_exit):
meshing = new_meshing_session_wo_exit
assert "topology_based" not in dir(meshing)
with pytest.raises(AttributeError):
tp = meshing.topology_based()
meshing.enable_beta_features()
assert "topology_based" in dir(meshing)
tp = meshing.topology_based()
assert tp

assert meshing.is_active() is True
solver = meshing.switch_to_solver()
assert meshing.is_active() is False
assert solver.is_active() is True
solver.exit()


@pytest.mark.fluent_version(">=25.2")
def test_beta_solver_session(new_solver_session_wo_exit):
solver = new_solver_session_wo_exit
assert solver.is_active() is True
assert "switch_to_meshing" not in dir(solver)
with pytest.raises(AttributeError):
meshing = solver.switch_to_meshing()
solver.enable_beta_features()
assert "switch_to_meshing" in dir(solver)
meshing = solver.switch_to_meshing()

assert solver.is_active() is False
assert meshing.is_active() is True
meshing.exit()


@pytest.mark.fluent_version(">=24.2")
def test_error_raised_for_beta_feature_access_for_older_versions(
new_meshing_session, new_solver_session
):
meshing = new_meshing_session
solver = new_solver_session

if meshing.get_fluent_version() >= FluentVersion.v252:
meshing.enable_beta_features()
assert "topology_based" in dir(meshing)
else:
with pytest.raises(RuntimeError):
meshing.enable_beta_features()

if solver.get_fluent_version() >= FluentVersion.v252:
solver.enable_beta_features()
assert "switch_to_meshing" in dir(solver)
else:
with pytest.raises(RuntimeError):
solver.enable_beta_features()


@pytest.mark.fluent_version(">=25.2")
def test_dir_for_session(new_meshing_session_wo_exit):
meshing = new_meshing_session_wo_exit

for attr in [
"watertight",
"fault_tolerant",
"two_dimensional_meshing",
"fields",
"scheme",
]:
assert getattr(meshing, attr)
assert attr in dir(meshing)

for attr in ["field_data", "field_info", "scheme_eval"]:
# Deprecated methods are accessible but hidden in dir()
assert getattr(meshing, attr)
assert attr not in dir(meshing)

solver = meshing.switch_to_solver()

assert dir(meshing) == ["is_active"]

for attr in ["read_case_lightweight", "settings"]:
assert getattr(solver, attr)
assert attr in dir(solver)

for attr in [
"field_data",
"field_info",
"scheme_eval",
"svar_data",
"svar_info",
"reduction",
]:
# Deprecated methods are accessible but hidden in dir()
assert getattr(solver, attr)
assert attr not in dir(solver)

solver.enable_beta_features()
meshing_new = solver.switch_to_meshing()

assert dir(solver) == ["is_active"]
assert len(dir(meshing_new)) > 1
7 changes: 3 additions & 4 deletions tests/test_settings_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,10 +621,9 @@ def test_nested_alias(mixing_elbow_settings_session):
def test_commands_not_in_settings(new_solver_session):
solver = new_solver_session

for command in ["exit", "switch_to_meshing_mode"]:
assert command not in dir(solver.settings)
with pytest.raises(AttributeError):
getattr(solver.settings, command)
assert "exit" not in dir(solver.settings)
with pytest.raises(AttributeError):
solver.settings.exit()


@pytest.mark.fluent_version(">=25.1")
Expand Down
Loading