Skip to content

Commit f314545

Browse files
feat: Expose both object and method classes for builtin commands (#4340)
Supports following syntaxes for built-in commands like read-case: ``` import ansys.fluent.core as pyfluent read_case_obj = pyfluent.solver.ReadCase(settings_source = <solver_session>) # returns the command object read_case_obj.is_active() read_case(file_name=<case_file>) pyfluent.solver.read_case(settings_source = <solver_session>, file_name=<case_file>) # executes the command ``` --------- Co-authored-by: pyansys-ci-bot <[email protected]>
1 parent 68af41f commit f314545

File tree

7 files changed

+78
-40
lines changed

7 files changed

+78
-40
lines changed

doc/changelog.d/4340.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Expose both object and method classes for builtin commands

src/ansys/fluent/core/codegen/builtin_settingsgen.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@
2222

2323
"""Generate builtin setting classes."""
2424

25+
import re
26+
2527
from ansys.fluent.core import FluentVersion, config
26-
from ansys.fluent.core.solver.flobject import CreatableNamedObjectMixin, NamedObject
28+
from ansys.fluent.core.solver.flobject import (
29+
CreatableNamedObjectMixin,
30+
NamedObject,
31+
_ChildNamedObjectAccessorMixin,
32+
)
2733
from ansys.fluent.core.solver.settings_builtin_data import DATA
2834
from ansys.fluent.core.utils.fluent_version import all_versions
2935

@@ -41,6 +47,13 @@ def _get_settings_root(version: str):
4147
return settings.root
4248

4349

50+
def _convert_camel_case_to_snake_case(name: str) -> str:
51+
"""Convert CamelCase to snake_case."""
52+
# Replace uppercase letters with lowercase and prepend an underscore
53+
name = re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
54+
return name
55+
56+
4457
def _get_named_objects_in_path(root, path, kind):
4558
named_objects = []
4659
cls = root
@@ -52,6 +65,8 @@ def _get_named_objects_in_path(root, path, kind):
5265
cls = cls.child_object_type
5366
final_type = ""
5467
if kind == "NamedObject":
68+
if not issubclass(cls, (NamedObject, _ChildNamedObjectAccessorMixin)):
69+
raise TypeError(f"{cls.__name__} is not NamedObject type.")
5570
if issubclass(cls, CreatableNamedObjectMixin):
5671
final_type = "Creatable"
5772
else:
@@ -72,8 +87,11 @@ def generate(version: str):
7287
"from ansys.fluent.core.solver.flobject import SettingsBase\n\n\n"
7388
)
7489
f.write("__all__ = [\n")
75-
for name, _ in DATA.items():
90+
for name, (kind, _) in DATA.items():
7691
f.write(f' "{name}",\n')
92+
if kind == "Command":
93+
command_name = _convert_camel_case_to_snake_case(name)
94+
f.write(f' "{command_name}",\n')
7795
f.write("]\n\n")
7896
for name, v in DATA.items():
7997
kind, path = v
@@ -86,35 +104,39 @@ def generate(version: str):
86104
if kind == "NamedObject":
87105
kind = f"{final_type}NamedObject"
88106
f.write(f"class {name}(_{kind}Setting):\n")
89-
doc_kind = "command" if kind == "Command" else "setting"
107+
doc_kind = "command object" if kind == "Command" else "setting"
90108
f.write(f' """{name} {doc_kind}."""\n\n')
109+
f.write(f' _db_name = "{name}"\n\n')
110+
f.write(" def __init__(self")
111+
for named_object in named_objects:
112+
f.write(f", {named_object}: str")
113+
f.write(", settings_source: SettingsBase | Solver | None = None")
114+
if kind == "NonCreatableNamedObject":
115+
f.write(", name: str = None")
116+
elif kind == "CreatableNamedObject":
117+
f.write(", name: str = None, new_instance_name: str = None")
118+
f.write("):\n")
119+
f.write(" super().__init__(settings_source=settings_source")
120+
if kind == "NonCreatableNamedObject":
121+
f.write(", name=name")
122+
elif kind == "CreatableNamedObject":
123+
f.write(", name=name, new_instance_name=new_instance_name")
124+
for named_object in named_objects:
125+
f.write(f", {named_object}={named_object}")
126+
f.write(")\n\n")
91127
if kind == "Command":
128+
command_name = _convert_camel_case_to_snake_case(name)
129+
f.write(f"class {command_name}(_{kind}Setting):\n")
130+
f.write(f' """{command_name} command."""\n\n')
131+
f.write(f' _db_name = "{name}"\n\n')
92132
f.write(
93133
" def __new__(cls, settings_source: SettingsBase | Solver | None = None, **kwargs):\n"
94134
)
95135
f.write(" instance = super().__new__(cls)\n")
96136
f.write(
97137
" instance.__init__(settings_source=settings_source, **kwargs)\n"
98138
)
99-
f.write(" return instance(**kwargs")
100-
else:
101-
f.write(" def __init__(self")
102-
for named_object in named_objects:
103-
f.write(f", {named_object}: str")
104-
f.write(", settings_source: SettingsBase | Solver | None = None")
105-
if kind == "NonCreatableNamedObject":
106-
f.write(", name: str = None")
107-
elif kind == "CreatableNamedObject":
108-
f.write(", name: str = None, new_instance_name: str = None")
109-
f.write("):\n")
110-
f.write(" super().__init__(settings_source=settings_source")
111-
if kind == "NonCreatableNamedObject":
112-
f.write(", name=name")
113-
elif kind == "CreatableNamedObject":
114-
f.write(", name=name, new_instance_name=new_instance_name")
115-
for named_object in named_objects:
116-
f.write(f", {named_object}={named_object}")
117-
f.write(")\n\n")
139+
f.write(" return instance(**kwargs)\n\n")
118140

119141
with open(_PYI_FILE, "w") as f:
120142
for version in FluentVersion:

src/ansys/fluent/core/launcher/fluent_container.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ def configure_container_dict(
350350
environment={
351351
"ANSYSLMD_LICENSE_FILE": license_server,
352352
"REMOTING_PORTS": f"{container_grpc_port}/portspan=2",
353+
"FLUENT_ALLOW_REMOTE_GRPC_CONNECTION": "1",
353354
}
354355
)
355356

src/ansys/fluent/core/launcher/slurm_launcher.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ def _prepare(self):
460460
launch_cmd += _build_journal_argument(
461461
self._argvals["topy"], self._argvals["journal_file_names"]
462462
)
463+
launch_cmd += ' --setenv="FLUENT_ALLOW_REMOTE_GRPC_CONNECTION=1"'
463464

464465
logger.debug(f"Launching Fluent with command: {launch_cmd}")
465466
proc = subprocess.Popen(launch_cmd, **kwargs)

src/ansys/fluent/core/solver/settings_builtin_bases.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def is_root_obj(obj):
5252

5353

5454
def _get_settings_obj(settings_root, builtin_settings_obj):
55-
builtin_cls_name = builtin_settings_obj.__class__.__name__
55+
builtin_cls_db_name = builtin_settings_obj.__class__._db_name
5656
obj = settings_root
57-
path = DATA[builtin_cls_name][1]
57+
path = DATA[builtin_cls_db_name][1]
5858
found_path = None
5959
if isinstance(path, dict):
6060
version = FluentVersion(obj._version)
@@ -63,7 +63,7 @@ def _get_settings_obj(settings_root, builtin_settings_obj):
6363
found_path = p
6464
break
6565
if found_path is None:
66-
raise RuntimeError(f"{builtin_cls_name} is not supported in {version}.")
66+
raise RuntimeError(f"{builtin_cls_db_name} is not supported in {version}.")
6767
elif isinstance(path, str):
6868
found_path = path
6969
comps = found_path.split(".")

src/ansys/fluent/core/solver/settings_builtin_data.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,26 +225,14 @@
225225
"VelocityInlet": ("NamedObject", "setup.boundary_conditions.velocity_inlet"),
226226
"WallBoundaries": ("Singleton", "setup.boundary_conditions.wall"),
227227
"WallBoundary": ("NamedObject", "setup.boundary_conditions.wall"),
228-
"NonReflectingBoundaries": (
229-
"Singleton",
230-
{
231-
since(FluentVersion.v241): "setup.boundary_conditions.non_reflecting_bc",
232-
},
233-
),
234228
"NonReflectingBoundary": (
235-
"NamedObject",
236-
{
237-
since(FluentVersion.v241): "setup.boundary_conditions.non_reflecting_bc",
238-
},
239-
),
240-
"PerforatedWallBoundaries": (
241229
"Singleton",
242230
{
243-
since(FluentVersion.v241): "setup.boundary_conditions.perforated_wall",
231+
since(FluentVersion.v241): "setup.boundary_conditions.non_reflecting_bc",
244232
},
245233
),
246234
"PerforatedWallBoundary": (
247-
"NamedObject",
235+
"Singleton",
248236
{
249237
since(FluentVersion.v241): "setup.boundary_conditions.perforated_wall",
250238
},

tests/test_builtin_settings.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,31 @@ def test_builtin_settings(mixing_elbow_case_data_session):
563563
)
564564
== solver.parametric_studies["mixing_elbow-Solve"].design_points["Base DP"]
565565
)
566+
assert ReadCase(settings_source=solver) == solver.file.read_case
567+
assert ReadData(settings_source=solver) == solver.file.read_data
568+
assert ReadCaseData(settings_source=solver) == solver.file.read_case_data
569+
if fluent_version >= FluentVersion.v241:
570+
assert WriteCase(settings_source=solver) == solver.file.write_case
571+
assert WriteData(settings_source=solver) == solver.file.write_data
572+
assert WriteCaseData(settings_source=solver) == solver.file.write_case_data
573+
else:
574+
with pytest.raises(RuntimeError):
575+
WriteCase(settings_source=solver)
576+
with pytest.raises(RuntimeError):
577+
WriteData(settings_source=solver)
578+
with pytest.raises(RuntimeError):
579+
WriteCaseData(settings_source=solver)
580+
assert (
581+
Initialize(settings_source=solver) == solver.solution.initialization.initialize
582+
)
583+
assert (
584+
Calculate(settings_source=solver) == solver.solution.run_calculation.calculate
585+
)
586+
assert Iterate(settings_source=solver) == solver.solution.run_calculation.iterate
587+
assert (
588+
DualTimeIterate(settings_source=solver)
589+
== solver.solution.run_calculation.dual_time_iterate
590+
)
566591

567592

568593
@pytest.mark.codegen_required
@@ -706,5 +731,5 @@ def test_context_manager_2(new_solver_session):
706731
)
707732

708733
with using(solver):
709-
ReadCase(file_name=import_filename)
734+
read_case(file_name=import_filename)
710735
assert Viscous().model() == "k-omega"

0 commit comments

Comments
 (0)