Skip to content

Commit 8b8ac9e

Browse files
fix: Missing input files when Fluent is launched in PIM Mode (#1189)
Co-authored-by: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> (cherry picked from commit ccfb1e3)
1 parent a7c9eed commit 8b8ac9e

File tree

4 files changed

+190
-93
lines changed

4 files changed

+190
-93
lines changed

.github/workflows/ci_cd_pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ jobs:
208208
build-library:
209209
name: "Build library"
210210
runs-on: ubuntu-latest
211-
needs: [wheelhouse, doc-build, tests]
211+
# needs: [wheelhouse, doc-build, tests]
212212
steps:
213213
- uses: ansys/actions/build-library@8d3e4946f36c2a7d447b92e34b1022a5c9dc77a7 # v10.0.12
214214
with:

doc/source/changelog/1189.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Missing input files when Fluent is launched in PIM Mode

src/ansys/health/heart/pre/mesher.py

Lines changed: 118 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
import pyvista as pv
3232

3333
import ansys.fluent.core as pyfluent
34+
from ansys.fluent.core.launcher.launch_options import LaunchMode
3435
from ansys.fluent.core.session_meshing import Meshing as MeshingSession
36+
import ansys.fluent.core.utils.file_transfer_service as file_transfer_service
3537
from ansys.health.heart import LOG as LOGGER
3638
from ansys.health.heart.exceptions import SupportedFluentVersionNotFoundError
3739
from ansys.health.heart.objects import Mesh, SurfaceMesh
@@ -45,17 +47,20 @@
4547

4648
_supported_fluent_versions = ["25.2", "25.1", "24.2", "24.1"]
4749
"""List of supported Fluent versions."""
50+
_supported_fluent_versions_container = ["25.2", "24.2", "24.1"]
51+
4852
_num_cpus: bool = 2
4953
"""Number of CPUs to use for meshing."""
5054
_extra_launch_kwargs = {}
5155
"""Extra keyword arguments passed to ``pyfluent.launch_fluent()``."""
5256
_fluent_version = None
5357
"""Global variable to explicitly override the Fluent version used."""
5458

55-
# check whether containerized version of Fluent is used
56-
_uses_container = bool(int(os.getenv("PYFLUENT_LAUNCH_CONTAINER", False)))
57-
if _uses_container:
58-
_supported_fluent_versions = ["25.2", "24.2", "24.1"]
59+
_launch_mode: LaunchMode = None
60+
"""Fluent Launch mode."""
61+
62+
_uses_container: bool = False
63+
"""Global variable to switch to Fluent container mode."""
5964

6065
_fluent_ui_mode = pyfluent.UIMode(os.getenv("PYFLUENT_UI_MODE", pyfluent.UIMode.HIDDEN_GUI))
6166

@@ -238,20 +243,39 @@ def _get_cells_inside_wrapped_parts(model: _InputModel, mesh: _FluentMesh) -> pv
238243

239244
def _get_fluent_meshing_session(working_directory: str | Path) -> MeshingSession:
240245
"""Get a Fluent Meshing session."""
241-
# NOTE: when using containerized version - we need to copy all the files
242-
# to and from the mounted volume given by pyfluent.EXAMPLES_PATH (default)
243-
244246
# NOTE: There are three launch modes Fluent can be launched in:
245247
# 1. LaunchMode.PIM: Fluent is launched using the Product Instance Management (PIM) service.
246248
# 2. LaunchMode.CONTAINER: Fluent is launched in a container. (containerized mode)
247249
# 3. LaunchMode.STANDALONE: Fluent is launched as a standalone application. (fallback mode)
250+
# File transfer strategies are different for each mode.
251+
252+
# check whether containerized version of Fluent is used
253+
global _uses_container
254+
global _launch_mode
255+
global _supported_fluent_versions
256+
257+
_uses_container = bool(int(os.getenv("PYFLUENT_LAUNCH_CONTAINER", False)))
258+
if _uses_container:
259+
_supported_fluent_versions = _supported_fluent_versions_container
260+
261+
num_cpus = int(os.getenv("PYANSYS_HEART_NUM_CPU", _num_cpus))
248262

249263
if _fluent_version is None:
250264
product_version = _get_supported_fluent_version()
251265
else:
252266
product_version = _fluent_version
253267

254-
num_cpus = int(os.getenv("PYANSYS_HEART_NUM_CPU", _num_cpus))
268+
# determine launch mode
269+
if pypim.is_configured():
270+
_launch_mode = LaunchMode.PIM
271+
transfer_strategy = None
272+
273+
elif _uses_container:
274+
_launch_mode = LaunchMode.CONTAINER
275+
transfer_strategy = None
276+
else:
277+
_launch_mode = LaunchMode.STANDALONE
278+
transfer_strategy = file_transfer_service.StandaloneFileTransferStrategy()
255279

256280
LOGGER.info(f"Launching meshing session with {product_version}...")
257281

@@ -261,22 +285,27 @@ def _get_fluent_meshing_session(working_directory: str | Path) -> MeshingSession
261285
"start_transcript": False,
262286
"product_version": product_version,
263287
"ui_mode": _fluent_ui_mode,
288+
"file_transfer_service": transfer_strategy,
264289
}
265290

266-
if pypim.is_configured():
267-
session = pyfluent.PureMeshing.from_pim(**launch_config, **_extra_launch_kwargs)
268-
269-
elif _uses_container:
270-
custom_config = {
271-
"mount_source": f"{working_directory}",
272-
"mount_target": "/mnt/pyfluent/meshing",
273-
}
274-
launch_config["ui_mode"] = pyfluent.UIMode.NO_GUI_OR_GRAPHICS
275-
launch_config.update({"container_dict": custom_config})
276-
session = pyfluent.PureMeshing.from_container(**launch_config, **_extra_launch_kwargs)
277-
278-
else:
279-
session = pyfluent.PureMeshing.from_install(**launch_config, **_extra_launch_kwargs)
291+
match _launch_mode:
292+
case LaunchMode.PIM:
293+
launch_config["ui_mode"] = None
294+
LOGGER.info(f"Launching Fluent in PIM-mode with config: {launch_config}")
295+
session = pyfluent.PureMeshing.from_pim(**launch_config, **_extra_launch_kwargs)
296+
297+
case LaunchMode.CONTAINER:
298+
LOGGER.info(f"Launching Fluent in Container mode with config: {launch_config}")
299+
launch_config["container_dict"] = {
300+
"mount_source": f"{working_directory}",
301+
"mount_target": "/mnt/pyfluent/meshing",
302+
}
303+
launch_config["ui_mode"] = pyfluent.UIMode.NO_GUI_OR_GRAPHICS
304+
session = pyfluent.PureMeshing.from_container(**launch_config, **_extra_launch_kwargs)
305+
306+
case LaunchMode.STANDALONE:
307+
LOGGER.info(f"Launching Fluent in Standalone mode with config: {launch_config}")
308+
session = pyfluent.PureMeshing.from_install(**launch_config, **_extra_launch_kwargs)
280309

281310
return session
282311

@@ -521,12 +550,20 @@ def _mesh_fluid_cavities(
521550

522551
session = _get_fluent_meshing_session(work_dir_meshing)
523552

524-
# import all stls
525-
if _uses_container:
553+
if _launch_mode == LaunchMode.PIM:
554+
# Upload files to session if in PIM or Container modes.
555+
LOGGER.info(f"Uploading files to session with working directory {work_dir_meshing}...")
556+
files = glob.glob(os.path.join(work_dir_meshing, "*.stl"))
557+
for file in files:
558+
session.upload(file)
559+
# In PIM mode files are uploaded to the Fluents working directory.
560+
work_dir_meshing = "."
561+
562+
elif _launch_mode == LaunchMode.CONTAINER:
526563
# NOTE: when using a Fluent container visible files
527-
# will be in /mnt/pyfluent. So need to use relative paths
528-
# or replace dirname by /mnt/pyfluent as prefix
564+
# will be in /mnt/pyfluent. (equal to mount target)
529565
work_dir_meshing = "/mnt/pyfluent/meshing"
566+
530567
session.tui.file.import_.cad(f"no {work_dir_meshing} *.stl")
531568

532569
# merge objects
@@ -642,11 +679,18 @@ def mesh_from_manifold_input_model(
642679
os.path.join(work_dir_meshing, "fluent_meshing.log"), write_to_stdout=False
643680
)
644681

645-
# import files
646-
if _uses_container:
682+
if _launch_mode == LaunchMode.PIM:
683+
# Upload files to session if in PIM or Container modes.
684+
LOGGER.info(f"Uploading files to session with working directory {work_dir_meshing}...")
685+
files = glob.glob(os.path.join(work_dir_meshing, "*.stl"))
686+
for file in files:
687+
session.upload(file)
688+
# In PIM mode files are uploaded to the Fluents working directory.
689+
work_dir_meshing = "."
690+
691+
elif _launch_mode == LaunchMode.CONTAINER:
647692
# NOTE: when using a Fluent container visible files
648-
# will be in /mnt/pyfluent. So need to use relative paths
649-
# or replace dirname by /mnt/pyfluent as prefix
693+
# will be in /mnt/pyfluent. (equal to mount target)
650694
work_dir_meshing = "/mnt/pyfluent/meshing"
651695

652696
session.tui.file.import_.cad('no "' + work_dir_meshing + '" "*.stl" yes 40 yes mm')
@@ -706,17 +750,28 @@ def mesh_from_manifold_input_model(
706750

707751
session.tui.mesh.prepare_for_solve("yes")
708752

709-
# write to file
753+
LOGGER.info(f"Writing mesh to {path_to_output}...")
710754

711-
if _uses_container:
755+
if _launch_mode in [LaunchMode.CONTAINER, LaunchMode.PIM]:
712756
session.tui.file.write_mesh(os.path.basename(path_to_output))
713757
else:
714758
session.tui.file.write_mesh('"' + path_to_output + '"')
715-
session.exit()
716759

717-
if path_to_output != path_to_output_old:
760+
LOGGER.info(f"Copying {path_to_output} to {path_to_output_old}...")
761+
762+
if _launch_mode == LaunchMode.PIM:
763+
session.download(os.path.basename(path_to_output), path_to_output_old)
764+
else:
718765
shutil.copy(path_to_output, path_to_output_old)
719766

767+
if not os.path.isfile(path_to_output_old):
768+
raise FileNotFoundError(
769+
f"Failed to copy {os.path.basename(path_to_output)} to {path_to_output_old}. "
770+
"Please check the Fluent meshing log for errors."
771+
)
772+
773+
session.exit()
774+
720775
path_to_output = path_to_output_old
721776
else:
722777
LOGGER.info(f"Reusing: {path_to_output}")
@@ -867,15 +922,24 @@ def mesh_from_non_manifold_input_model(
867922
# launch pyfluent
868923
session = _get_fluent_meshing_session(work_dir_meshing)
869924

925+
LOGGER.info(f"Starting Fluent Meshing in mode: {_launch_mode}")
926+
870927
session.transcript.start(
871928
os.path.join(work_dir_meshing, "fluent_meshing.log"), write_to_stdout=False
872929
)
873930

874-
# # import stls
875-
if _uses_container:
931+
if _launch_mode == LaunchMode.PIM:
932+
# Upload files to session if in PIM or Container modes.
933+
LOGGER.info(f"Uploading files to session with working directory {work_dir_meshing}...")
934+
files = glob.glob(os.path.join(work_dir_meshing, "*.stl"))
935+
for file in files:
936+
session.upload(file)
937+
# In PIM mode files are uploaded to the Fluents working directory.
938+
work_dir_meshing = "."
939+
940+
elif _launch_mode == LaunchMode.CONTAINER:
876941
# NOTE: when using a Fluent container visible files
877-
# will be in /mnt/pyfluent. So need to use relative paths
878-
# or replace dirname by /mnt/pyfluent as prefix
942+
# will be in /mnt/pyfluent. (equal to mount target)
879943
work_dir_meshing = "/mnt/pyfluent/meshing"
880944

881945
session.tui.file.import_.cad("no", work_dir_meshing, "*.stl", "yes", 40, "yes", "mm")
@@ -969,13 +1033,26 @@ def mesh_from_non_manifold_input_model(
9691033
os.remove(path_to_output)
9701034

9711035
LOGGER.info(f"Writing mesh to {path_to_output}...")
972-
if _uses_container:
1036+
1037+
if _launch_mode in [LaunchMode.CONTAINER, LaunchMode.PIM]:
9731038
session.tui.file.write_mesh(os.path.basename(path_to_output))
9741039
else:
9751040
session.tui.file.write_mesh('"' + path_to_output + '"')
976-
session.exit()
9771041

978-
shutil.copy(path_to_output, path_to_output_old)
1042+
LOGGER.info(f"Copying {path_to_output} to {path_to_output_old}...")
1043+
1044+
if _launch_mode == LaunchMode.PIM:
1045+
session.download(os.path.basename(path_to_output), path_to_output_old)
1046+
else:
1047+
shutil.copy(path_to_output, path_to_output_old)
1048+
1049+
if not os.path.isfile(path_to_output_old):
1050+
raise FileNotFoundError(
1051+
f"Failed to copy {os.path.basename(path_to_output)} to {path_to_output_old}. "
1052+
"Please check the Fluent meshing log for errors."
1053+
)
1054+
1055+
session.exit()
9791056

9801057
path_to_output = path_to_output_old
9811058
else:

0 commit comments

Comments
 (0)