3131import pyvista as pv
3232
3333import ansys .fluent .core as pyfluent
34+ from ansys .fluent .core .launcher .launch_options import LaunchMode
3435from ansys .fluent .core .session_meshing import Meshing as MeshingSession
36+ import ansys .fluent .core .utils .file_transfer_service as file_transfer_service
3537from ansys .health .heart import LOG as LOGGER
3638from ansys .health .heart .exceptions import SupportedFluentVersionNotFoundError
3739from ansys .health .heart .objects import Mesh , SurfaceMesh
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
239244def _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