From 02e32af1df00f600585370114ec2d3a40bbd9f43 Mon Sep 17 00:00:00 2001 From: Mainak Kundu <94432368+mkundu1@users.noreply.github.com> Date: Thu, 28 Mar 2024 08:35:49 -0400 Subject: [PATCH 1/3] build: Bump version 0.21.dev0 (#2626) * build: Bump version 0.21.dev0 * fix: skip some tests * Fix meshing workflow test. --------- Co-authored-by: Prithwish Mukherjee --- pyproject.toml | 2 +- src/ansys/fluent/core/_version.py | 2 +- tests/parametric/test_parametric_workflow.py | 31 ++++++++++++++++++++ tests/test_new_meshing_workflow.py | 4 --- tests/test_settings_api.py | 1 + 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e65c26b1f6b..2271c1cf28d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] # Check https://python-poetry.org/docs/pyproject/ for all available sections name = "ansys-fluent-core" -version = "0.20.dev12" +version = "0.21.dev0" description = "PyFluent provides Pythonic access to Ansys Fluent" license = "MIT" authors = ["ANSYS, Inc. "] diff --git a/src/ansys/fluent/core/_version.py b/src/ansys/fluent/core/_version.py index f4c1c4d1220..0fbcd63d179 100644 --- a/src/ansys/fluent/core/_version.py +++ b/src/ansys/fluent/core/_version.py @@ -6,7 +6,7 @@ """ # major, minor, patch -version_info = 0, 20, "dev12" +version_info = 0, 21, "dev0" # Nice string for the version __version__ = ".".join(map(str, version_info)) diff --git a/tests/parametric/test_parametric_workflow.py b/tests/parametric/test_parametric_workflow.py index 773b8aa1b42..17fb2896362 100644 --- a/tests/parametric/test_parametric_workflow.py +++ b/tests/parametric/test_parametric_workflow.py @@ -201,3 +201,34 @@ def test_parametric_workflow(): solver_session.file.parametric_project.archive(archive_name=write_archive_name) assert archive_name.exists() solver_session.exit() + + +@pytest.mark.fluent_version(">=24.2") +def test_parameters_list_function(load_static_mixer_settings_only): + solver = load_static_mixer_settings_only + solver.tui.define.parameters.enable_in_TUI("yes") + + velocity_inlet = solver.tui.define.boundary_conditions.set.velocity_inlet + velocity_inlet("inlet1", (), "vmag", "yes", "inlet1_vel", 1, "quit") + velocity_inlet("inlet1", (), "temperature", "yes", "inlet1_temp", 300, "quit") + velocity_inlet("inlet2", (), "vmag", "yes", "no", "inlet2_vel", 1, "quit") + velocity_inlet("inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit") + + solver.solution.report_definitions.surface["outlet-temp-avg"] = {} + outlet_temp_avg = solver.solution.report_definitions.surface["outlet-temp-avg"] + outlet_temp_avg.report_type = "surface-areaavg" + outlet_temp_avg.field = "temperature" + outlet_temp_avg.surface_names = ["outlet"] + + solver.solution.report_definitions.surface["outlet-vel-avg"] = {} + outlet_vel_avg = solver.solution.report_definitions.surface["outlet-vel-avg"] + outlet_vel_avg.report_type = "surface-areaavg" + outlet_vel_avg.field = "velocity-magnitude" + outlet_vel_avg.surface_names = ["outlet"] + + create_output_param = solver.tui.define.parameters.output_parameters.create + create_output_param("report-definition", "outlet-temp-avg") + create_output_param("report-definition", "outlet-vel-avg") + + assert len(solver.parameters.input_parameters.list()) == 4 + assert len(solver.parameters.output_parameters.list()) == 2 diff --git a/tests/test_new_meshing_workflow.py b/tests/test_new_meshing_workflow.py index f6494dfd690..6965c013410 100644 --- a/tests/test_new_meshing_workflow.py +++ b/tests/test_new_meshing_workflow.py @@ -5,7 +5,6 @@ from ansys.fluent.core import examples from ansys.fluent.core.meshing.watertight import watertight_workflow -from ansys.fluent.core.utils.fluent_version import FluentVersion from tests.test_datamodel_service import disable_datamodel_cache # noqa: F401 @@ -550,11 +549,8 @@ def test_workflow_and_data_model_methods_new_meshing_workflow(new_mesh_session): "import_body_of_influence_geometry", "set_up_periodic_boundaries", "create_local_refinement_regions", - "load_cad_geometry", "run_custom_journal", ] - if meshing.get_fluent_version() < FluentVersion.v242: - _next_possible_tasks.remove("load_cad_geometry") assert ( watertight.task("import_geom_wtm").get_next_possible_tasks() == _next_possible_tasks diff --git a/tests/test_settings_api.py b/tests/test_settings_api.py index 90ad3c7b44b..bec8c0cc3d4 100644 --- a/tests/test_settings_api.py +++ b/tests/test_settings_api.py @@ -154,6 +154,7 @@ def test_api_upgrade(new_solver_session, capsys): ".file.read_case" in capsys.readouterr().out +@pytest.mark.skip @pytest.mark.fluent_version(">=24.2") def test_deprecated_settings(new_solver_session): solver = new_solver_session From 51fc833aec5bf38572be891a95c2a68b47ee0f8c Mon Sep 17 00:00:00 2001 From: Mainak Kundu <94432368+mkundu1@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:49:03 -0400 Subject: [PATCH 2/3] fix: dict set-state with alias (#2630) --- src/ansys/fluent/core/solver/flobject.py | 5 +- tests/test_settings_api.py | 67 ++++++++++++++++-------- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index 7d8fb195a61..93779000e3f 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -661,10 +661,11 @@ def _unalias(cls, value): ) ret_alias = ret comps = alias.split("/") + aliased_cls = cls for i, comp in enumerate(comps): - cls = cls._child_classes[comp] + aliased_cls = aliased_cls._child_classes[comp] if i == len(comps) - 1: - ret_alias[comp] = cls._unalias(v) + ret_alias[comp] = aliased_cls._unalias(v) else: ret_alias[comp] = {} ret_alias = ret_alias[comp] diff --git a/tests/test_settings_api.py b/tests/test_settings_api.py index bec8c0cc3d4..8b3baa44db2 100644 --- a/tests/test_settings_api.py +++ b/tests/test_settings_api.py @@ -154,7 +154,6 @@ def test_api_upgrade(new_solver_session, capsys): ".file.read_case" in capsys.readouterr().out -@pytest.mark.skip @pytest.mark.fluent_version(">=24.2") def test_deprecated_settings(new_solver_session): solver = new_solver_session @@ -189,56 +188,76 @@ def test_deprecated_settings(new_solver_session): ) assert ( len( - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t._child_aliases + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature._child_aliases ) > 0 ) assert ( - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t._child_aliases[ - "constant" - ] + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature._child_aliases["constant"] == "value" ) with pytest.warns(DeprecatedSettingWarning): - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.constant = 400 + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature.constant = 400 - assert solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value() == 400 + assert ( + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temperature.value() + == 400 + ) assert ( len( - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t._child_aliases + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature._child_aliases ) > 0 ) assert isinstance( - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t._child_alias_objs[ - "constant" - ], + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature._child_alias_objs["constant"], _Alias, ) - solver.setup.boundary_conditions.wall["wall-inlet"].thermal._setattr( - "_child_aliases", {"temp": "t"} - ) with pytest.warns(DeprecatedSettingWarning): - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temp.value = 410 + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value = 410 - assert solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value() == 410 + assert ( + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temperature.value() + == 410 + ) solver.setup.boundary_conditions._setattr("_child_aliases", {"w": "wall"}) with pytest.warns(DeprecatedSettingWarning): - solver.setup.boundary_conditions.w["wall-inlet"].thermal.t.value = 420 + solver.setup.boundary_conditions.w["wall-inlet"].thermal.temperature.value = 420 - assert solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value() == 420 + assert ( + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temperature.value() + == 420 + ) solver.setup._setattr("_child_aliases", {"bc": "boundary_conditions"}) with pytest.warns(DeprecatedSettingWarning): - solver.setup.bc.wall["wall-inlet"].thermal.t.value = 430 + solver.setup.bc.wall["wall-inlet"].thermal.temperature.value = 430 - assert solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value() == 430 + assert ( + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temperature.value() + == 430 + ) with pytest.warns(DeprecatedSettingWarning): - solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.constant = 400 + solver.setup.boundary_conditions.wall[ + "wall-inlet" + ].thermal.temperature.constant = 400 - assert solver.setup.boundary_conditions.wall["wall-inlet"].thermal.t.value() == 400 + assert ( + solver.setup.boundary_conditions.wall["wall-inlet"].thermal.temperature.value() + == 400 + ) solver.results._setattr("_child_aliases", {"gr": "graphics"}) with pytest.warns(DeprecatedSettingWarning): @@ -270,6 +289,10 @@ def test_deprecated_settings(new_solver_session): solver.setup.cell_zone_conditions.fluid["elbow-fluid"] = {"material": "air"} + solver.setup.boundary_conditions.wall["wall-inlet"] = { + "thermal": {"q_dot": {"value": 2000000000}, "wall_thickness": {"value": 0.002}} + } + @pytest.mark.fluent_version(">=24.2") def test_command_return_type(new_solver_session): From 80d492e07ad0413b58bf02661e013d81e8000827 Mon Sep 17 00:00:00 2001 From: Prithwish Mukherjee <109645853+prmukherj@users.noreply.github.com> Date: Thu, 28 Mar 2024 23:14:50 +0530 Subject: [PATCH 3/3] refactor: update enhanced meshing interface (#2606) * Return solver session only when switch_to_solver is successful. * Fix add_child_and_update * Add tests for 2D Meshing workflow. * Fix _add_child * Add documentation. * Update styling. * Revert changes in switching to solver. * Refactoring. * Refactor and update tests. * Fix test import. * Bug fixing. * Fix behaviour of defer_update * Update src/ansys/fluent/core/workflow.py Co-authored-by: Mainak Kundu <94432368+mkundu1@users.noreply.github.com> * Fix for defer_update. * Fix doc. * Update fluent version check. * Update doc/source/user_guide/meshing_workflow/meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc/source/user_guide/meshing_workflow/meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc/source/user_guide/meshing_workflow/meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc style. * Update doc/source/user_guide/meshing_workflow/meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc/source/user_guide/meshing_workflow/meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc style. * Update doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/meshing/meshing_workflow.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/meshing/meshing_workflow.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/meshing/meshing_workflow.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/meshing/meshing_workflow.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/session_base_meshing.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update src/ansys/fluent/core/workflow.py Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Update docs. * Update meshing test. * Update const. call from Solver. --------- Co-authored-by: Mainak Kundu <94432368+mkundu1@users.noreply.github.com> Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- .../meshing_workflow/meshing_workflows.rst | 220 +++++++++++++++++- .../new_meshing_workflows.rst | 160 +++++++++++++ src/ansys/fluent/core/meshing/2d_meshing.py | 25 -- .../fluent/core/meshing/faulttolerant.py | 25 -- .../fluent/core/meshing/meshing_workflow.py | 200 +++++++++------- .../fluent/core/meshing/topology_based.py | 25 -- src/ansys/fluent/core/meshing/watertight.py | 32 --- src/ansys/fluent/core/session_base_meshing.py | 25 +- src/ansys/fluent/core/session_solver.py | 4 +- src/ansys/fluent/core/workflow.py | 38 ++- tests/test_meshing_workflow.py | 186 +++++++++++++-- tests/test_new_meshing_workflow.py | 159 ++++++++++++- 12 files changed, 850 insertions(+), 249 deletions(-) delete mode 100644 src/ansys/fluent/core/meshing/2d_meshing.py delete mode 100644 src/ansys/fluent/core/meshing/faulttolerant.py delete mode 100644 src/ansys/fluent/core/meshing/topology_based.py delete mode 100644 src/ansys/fluent/core/meshing/watertight.py diff --git a/doc/source/user_guide/meshing_workflow/meshing_workflows.rst b/doc/source/user_guide/meshing_workflow/meshing_workflows.rst index e9521789aab..e4b4348fd41 100644 --- a/doc/source/user_guide/meshing_workflow/meshing_workflows.rst +++ b/doc/source/user_guide/meshing_workflow/meshing_workflows.rst @@ -572,9 +572,223 @@ Switch to solution mode solver = meshing.switch_to_solver() -Sample use of CommandArguments ------------------------------- -This simple example shows you how to use the ``CommandArgument`` attributes and explicit + +2D meshing workflow +------------------- +Use the **2D** meshing workflow to mesh specific two-dimensional geometries. +The following example shows how to use the 2D Meshing workflow. + +Import geometry +~~~~~~~~~~~~~~~ + +.. code:: python + + import ansys.fluent.core as pyfluent + from ansys.fluent.core import examples + + import_file_name = examples.download_file('NACA0012.fmd', 'pyfluent/airfoils') + meshing = pyfluent.launch_fluent( + mode="meshing", precision='double', processor_count=2 + ) + meshing.workflow.InitializeWorkflow(WorkflowType="2D Meshing") + meshing.workflow.TaskObject["Load CAD Geometry"].Arguments.set_state( + { + r"FileName": import_file_name, + r"LengthUnit": r"mm", + r"Refaceting": { + r"Refacet": False, + }, + } + ) + meshing.workflow.TaskObject["Load CAD Geometry"].Execute() + +Set regions and boundaries +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Update Regions"].Execute() + meshing.workflow.TaskObject["Update Boundaries"].Arguments.set_state( + { + r"SelectionType": r"zone", + } + ) + meshing.workflow.TaskObject["Update Boundaries"].Execute() + +Define global sizing +~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Define Global Sizing"].Arguments.set_state( + { + r"CurvatureNormalAngle": 20, + r"MaxSize": 2000, + r"MinSize": 5, + r"SizeFunctions": r"Curvature", + } + ) + meshing.workflow.TaskObject["Define Global Sizing"].Execute() + +Add body of influence +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"boi_1", + r"BOIExecution": r"Body Of Influence", + r"BOIFaceLabelList": [r"boi"], + r"BOISize": 50, + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + +Set edge sizing +~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"edgesize_1", + r"BOIExecution": r"Edge Size", + r"BOISize": 5, + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + r"EdgeLabelList": [r"airfoil-te"], + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + +Set curvature sizing +~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"curvature_1", + r"BOICurvatureNormalAngle": 10, + r"BOIExecution": r"Curvature", + r"BOIMaxSize": 2, + r"BOIMinSize": 1.5, + r"BOIScopeTo": r"edges", + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + r"EdgeLabelList": [r"airfoil"], + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + +Add boundary layer +~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Add 2D Boundary Layers"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"aspect-ratio_1", + r"NumberOfLayers": 4, + r"OffsetMethodType": r"aspect-ratio", + } + ) + meshing.workflow.TaskObject["Add 2D Boundary Layers"].AddChildAndUpdate( + DeferUpdate=False + ) + +Generate surface mesh +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + + meshing.workflow.TaskObject["aspect-ratio_1"].Revert() + meshing.workflow.TaskObject["aspect-ratio_1"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"uniform_1", + r"FirstLayerHeight": 2, + r"NumberOfLayers": 4, + r"OffsetMethodType": r"uniform", + } + ) + meshing.workflow.TaskObject["aspect-ratio_1"].Execute() + + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state(None) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + + meshing.workflow.TaskObject["uniform_1"].Revert() + meshing.workflow.TaskObject["uniform_1"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"smooth-transition_1", + r"FirstLayerHeight": 2, + r"NumberOfLayers": 7, + r"OffsetMethodType": r"smooth-transition", + } + ) + meshing.workflow.TaskObject["uniform_1"].Execute() + + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state(None) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + +Export Fluent 2D mesh +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + meshing.workflow.TaskObject["Export Fluent 2D Mesh"].Arguments.set_state( + { + r"FileName": r"mesh1.msh.h5", + } + ) + meshing.workflow.TaskObject["Export Fluent 2D Mesh"].Execute() + +Switch to solver mode +~~~~~~~~~~~~~~~~~~~~~ + +Switching to solver mode is not allowed in 2D Meshing mode. + + +Sample use of ``CommandArguments`` +---------------------------------- +This simple example shows how to use the ``CommandArgument`` attributes and explicit attribute access methods in a watertight geometry meshing workflow. .. Note:: diff --git a/doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst b/doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst index 00b01bf7d33..6f68f306c4b 100644 --- a/doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst +++ b/doc/source/user_guide/meshing_workflow/new_meshing_workflows.rst @@ -453,3 +453,163 @@ Switch to solution mode .. code:: python solver = meshing.switch_to_solver() + + +2D meshing workflow +------------------- +Use the **2D** meshing workflow to mesh specific two-dimensional geometries. +The following example shows you how to use the 2D meshing workflow. + +Import geometry +~~~~~~~~~~~~~~~ + +.. code:: python + + import ansys.fluent.core as pyfluent + from ansys.fluent.core import examples + + import_file_name = examples.download_file('NACA0012.fmd', 'pyfluent/airfoils') + meshing = pyfluent.launch_fluent( + mode="meshing", precision='double', processor_count=2 + ) + two_dim_mesh = new_mesh_session.two_dimensional_meshing() + + two_dim_mesh.load_cad_geometry_2d.file_name = import_file_name + two_dim_mesh.load_cad_geometry_2d.length_unit = "mm" + two_dim_mesh.load_cad_geometry_2d.refaceting.refacet = False + two_dim_mesh.load_cad_geometry_2d() + +Set regions and boundaries +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.update_regions_2d() + two_dim_mesh.update_boundaries_2d.selection_type = "zone" + two_dim_mesh.update_boundaries_2d() + +Define global sizing +~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.define_global_sizing_2d.curvature_normal_angle = 20 + two_dim_mesh.define_global_sizing_2d.max_size = 2000.0 + two_dim_mesh.define_global_sizing_2d.min_size = 5.0 + two_dim_mesh.define_global_sizing_2d.size_functions = "Curvature" + two_dim_mesh.define_global_sizing_2d() + +Adding BOI +~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "boi_1" + two_dim_mesh.add_local_sizing_2d.boi_execution = "Body Of Influence" + two_dim_mesh.add_local_sizing_2d.boi_face_label_list = ["boi"] + two_dim_mesh.add_local_sizing_2d.boi_size = 50.0 + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + +Set edge sizing +~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "edgesize_1" + two_dim_mesh.add_local_sizing_2d.boi_execution = "Edge Size" + two_dim_mesh.add_local_sizing_2d.boi_size = 5.0 + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.edge_label_list = ["airfoil-te"] + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + +Set curvature sizing +~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "curvature_1" + two_dim_mesh.add_local_sizing_2d.boi_curvature_normal_angle = 10 + two_dim_mesh.add_local_sizing_2d.boi_execution = "Curvature" + two_dim_mesh.add_local_sizing_2d.boi_max_size = 2 + two_dim_mesh.add_local_sizing_2d.boi_min_size = 1.5 + two_dim_mesh.add_local_sizing_2d.boi_scope_to = "edges" + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.edge_label_list = ["airfoil"] + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + +Add boundary layer +~~~~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.add_2d_boundary_layers.add_child = "yes" + two_dim_mesh.add_2d_boundary_layers.bl_control_name = "aspect-ratio_1" + two_dim_mesh.add_2d_boundary_layers.number_of_layers = 4 + two_dim_mesh.add_2d_boundary_layers.offset_method_type = "aspect-ratio" + two_dim_mesh.add_2d_boundary_layers.add_child_and_update(defer_update=False) + +Generate surface mesh +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + + two_dim_mesh.task("aspect-ratio_1").revert() + two_dim_mesh.task("aspect-ratio_1").add_child = "yes" + two_dim_mesh.task("aspect-ratio_1").bl_control_name = "uniform_1" + two_dim_mesh.task("aspect-ratio_1").first_layer_height = 2 + two_dim_mesh.task("aspect-ratio_1").number_of_layers = 4 + two_dim_mesh.task("aspect-ratio_1").offset_method_type = "uniform" + two_dim_mesh.task("aspect-ratio_1")() + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + + two_dim_mesh.task("uniform_1").revert() + two_dim_mesh.task("uniform_1").add_child = "yes" + two_dim_mesh.task("uniform_1").bl_control_name = "smooth-transition_1" + two_dim_mesh.task("uniform_1").first_layer_height = 2 + two_dim_mesh.task("uniform_1").number_of_layers = 7 + two_dim_mesh.task("uniform_1").offset_method_type = "smooth-transition" + two_dim_mesh.task("uniform_1")() + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + +Switch to solution mode +~~~~~~~~~~~~~~~~~~~~~~~ + +Switching to solver is not allowed in 2D Meshing mode. diff --git a/src/ansys/fluent/core/meshing/2d_meshing.py b/src/ansys/fluent/core/meshing/2d_meshing.py deleted file mode 100644 index 58ee04a0545..00000000000 --- a/src/ansys/fluent/core/meshing/2d_meshing.py +++ /dev/null @@ -1,25 +0,0 @@ -"""2D Meshing workflow module.""" - -from typing import Union - -from ..session_meshing import Meshing -from ..session_pure_meshing import PureMeshing -from .meshing_workflow import TwoDimensionalMeshingWorkflow - - -def two_dim_workflow( - session: Union[Meshing, PureMeshing] -) -> TwoDimensionalMeshingWorkflow: - """Meshing workflow wrapper, initialized as 2D Meshing. - - Parameters - ---------- - session: Union[Meshing, PureMeshing] - Meshing session object. - - Returns - ------- - TwoDimensionalMeshingWorkflow - 2D meshing workflow wrapper. - """ - return session.two_dimensional_meshing() diff --git a/src/ansys/fluent/core/meshing/faulttolerant.py b/src/ansys/fluent/core/meshing/faulttolerant.py deleted file mode 100644 index cfbffdc0920..00000000000 --- a/src/ansys/fluent/core/meshing/faulttolerant.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Fault-tolerant workflow module.""" - -from typing import Union - -from ..session_meshing import Meshing -from ..session_pure_meshing import PureMeshing -from .meshing_workflow import FaultTolerantMeshingWorkflow - - -def fault_tolerant_workflow( - session: Union[Meshing, PureMeshing] -) -> FaultTolerantMeshingWorkflow: - """Meshing workflow wrapper, initialized as fault-tolerant. - - Parameters - ---------- - session: Union[Meshing, PureMeshing] - Meshing session object. - - Returns - ------- - FaultTolerantMeshingWorkflow - Fault-tolerant meshing workflow wrapper. - """ - return session.fault_tolerant() diff --git a/src/ansys/fluent/core/meshing/meshing_workflow.py b/src/ansys/fluent/core/meshing/meshing_workflow.py index 9e5a366fe4c..4238b9107c1 100644 --- a/src/ansys/fluent/core/meshing/meshing_workflow.py +++ b/src/ansys/fluent/core/meshing/meshing_workflow.py @@ -3,9 +3,11 @@ from __future__ import annotations +from enum import Enum from typing import Optional from ansys.fluent.core.services.datamodel_se import PyMenuGeneric +from ansys.fluent.core.utils.fluent_version import FluentVersion from ansys.fluent.core.workflow import ClassicWorkflow, Workflow @@ -16,6 +18,7 @@ def __init__( self, workflow: PyMenuGeneric, meshing: PyMenuGeneric, + fluent_version: FluentVersion, ) -> None: """Initialize ClassicMeshingWorkflow. @@ -25,8 +28,12 @@ def __init__( Underlying workflow object. meshing : PyMenuGeneric Meshing object. + fluent_version: FluentVersion + Version of Fluent in this session. """ - super().__init__(workflow=workflow, command_source=meshing) + super().__init__( + workflow=workflow, command_source=meshing, fluent_version=fluent_version + ) class MeshingWorkflow(Workflow): @@ -37,6 +44,9 @@ def __init__( self, workflow: PyMenuGeneric, meshing: PyMenuGeneric, + name: str, + identifier: str, + fluent_version: FluentVersion, ) -> None: """Initialize MeshingWorkflow. @@ -45,43 +55,66 @@ def __init__( workflow : PyMenuGeneric Underlying workflow object. meshing : PyMenuGeneric - The meshing object. - """ - super().__init__(workflow=workflow, command_source=meshing) - - -class WatertightMeshingWorkflow(MeshingWorkflow): - """Provides watertight meshing specialization of the workflow wrapper.""" - - def __init__(self, workflow: PyMenuGeneric, meshing: PyMenuGeneric) -> None: - """Initialize WatertightMeshingWorkflow. - - Parameters - ---------- - workflow : PyMenuGeneric - The underlying workflow object. - meshing : PyMenuGeneric - The meshing object. + Meshing object. + name: str + Workflow name to initialize it. + identifier: str + Workflow name to identify it from global settings. + fluent_version: FluentVersion + Version of Fluent in this session. """ - super().__init__(workflow=workflow, meshing=meshing) + super().__init__( + workflow=workflow, command_source=meshing, fluent_version=fluent_version + ) self._meshing = meshing + self._name = name + self._identifier = identifier def reinitialize(self) -> None: - """Initialize a watertight workflow.""" - self._new_workflow(name="Watertight Geometry") + """Initialize a workflow.""" + self._new_workflow(name=self._name) def __getattribute__(self, item: str): if ( item != "reinitialize" and not item.startswith("_") - and not self._meshing.GlobalSettings.EnableCleanCAD() + and not getattr(self._meshing.GlobalSettings, self._identifier)() ): raise RuntimeError( - "'Watertight' objects are inaccessible from other workflows." + f"'{self._name}' objects are inaccessible from other workflows." ) return super().__getattribute__(item) +class WatertightMeshingWorkflow(MeshingWorkflow): + """Provides watertight meshing specialization of the workflow wrapper.""" + + def __init__( + self, + workflow: PyMenuGeneric, + meshing: PyMenuGeneric, + fluent_version: FluentVersion, + ) -> None: + """Initialize WatertightMeshingWorkflow. + + Parameters + ---------- + workflow : PyMenuGeneric + Underlying workflow object. + meshing : PyMenuGeneric + Meshing object. + fluent_version: FluentVersion + Version of Fluent in this session. + """ + super().__init__( + workflow=workflow, + meshing=meshing, + name="Watertight Geometry", + identifier="EnableCleanCAD", + fluent_version=fluent_version, + ) + + class FaultTolerantMeshingWorkflow(MeshingWorkflow): """Provides fault-tolerant meshing specialization of the workflow wrapper.""" @@ -91,40 +124,33 @@ def __init__( meshing: PyMenuGeneric, part_management: PyMenuGeneric, pm_file_management: PyMenuGeneric, + fluent_version: FluentVersion, ) -> None: """Initialize FaultTolerantMeshingWorkflow. Parameters ---------- workflow : PyMenuGeneric - The underlying workflow object. + Underlying workflow object. meshing : PyMenuGeneric - The meshing object. + Meshing object. part_management : PyMenuGeneric - The part-management object. + Part management object. pm_file_management : PyMenuGeneric - The part-management file-management object. + File management object in the part management object. + fluent_version: FluentVersion + Version of Fluent in this session. """ - super().__init__(workflow=workflow, meshing=meshing) - self._meshing = meshing + super().__init__( + workflow=workflow, + meshing=meshing, + name="Fault-tolerant Meshing", + identifier="EnableComplexMeshing", + fluent_version=fluent_version, + ) self._part_management = part_management self._pm_file_management = pm_file_management - def reinitialize(self): - """Initialize a fault-tolerant workflow.""" - self._new_workflow("Fault-tolerant Meshing") - - def __getattribute__(self, item): - if ( - item != "reinitialize" - and not item.startswith("_") - and not self._meshing.GlobalSettings.EnableComplexMeshing() - ): - raise RuntimeError( - "'Fault-tolerant' objects are inaccessible from other workflows." - ) - return super().__getattribute__(item) - @property def part_management(self) -> Optional[PyMenuGeneric]: """Access part-management in fault-tolerant mode. @@ -143,7 +169,7 @@ def pm_file_management(self): Returns ------- Optional[PyMenuGeneric] - Part-management file-management object . + File management object in the part management object. """ return self._pm_file_management @@ -151,62 +177,66 @@ def pm_file_management(self): class TwoDimensionalMeshingWorkflow(MeshingWorkflow): """Provides 2D meshing specialization of the workflow wrapper.""" - def __init__(self, workflow: PyMenuGeneric, meshing: PyMenuGeneric) -> None: + def __init__( + self, + workflow: PyMenuGeneric, + meshing: PyMenuGeneric, + fluent_version: FluentVersion, + ) -> None: """Initialize TwoDimensionalMeshingWorkflow. Parameters ---------- workflow : PyMenuGeneric - The underlying workflow object. + Underlying workflow object. meshing : PyMenuGeneric - The meshing object. + Meshing object. + fluent_version: FluentVersion + Version of Fluent in this session. """ - super().__init__(workflow=workflow, meshing=meshing) - self._meshing = meshing - - def reinitialize(self) -> None: - """Initialize a 2D meshing workflow.""" - self._new_workflow(name="2D Meshing") - - def __getattribute__(self, item: str): - if ( - item != "reinitialize" - and not item.startswith("_") - and not self._meshing.GlobalSettings.EnablePrime2dMeshing() - ): - raise RuntimeError( - "'2D Meshing' objects are inaccessible from other workflows." - ) - return super().__getattribute__(item) + super().__init__( + workflow=workflow, + meshing=meshing, + name="2D Meshing", + identifier="EnablePrime2dMeshing", + fluent_version=fluent_version, + ) class TopologyBasedMeshingWorkflow(MeshingWorkflow): """Provides topology-based meshing specialization of the workflow wrapper.""" - def __init__(self, workflow: PyMenuGeneric, meshing: PyMenuGeneric) -> None: + def __init__( + self, + workflow: PyMenuGeneric, + meshing: PyMenuGeneric, + fluent_version: FluentVersion, + ) -> None: """Initialize TopologyBasedMeshingWorkflow. Parameters ---------- workflow : PyMenuGeneric - The underlying workflow object. + Underlying workflow object. meshing : PyMenuGeneric - The meshing object. + Meshing object. + fluent_version: FluentVersion + Version of Fluent in this session. """ - super().__init__(workflow=workflow, meshing=meshing) - self._meshing = meshing - - def reinitialize(self) -> None: - """Initialize a topology based meshing workflow.""" - self._new_workflow(name="Topology Based Meshing") - - def __getattribute__(self, item: str): - if ( - item != "reinitialize" - and not item.startswith("_") - and not self._meshing.GlobalSettings.EnablePrimeMeshing() - ): - raise RuntimeError( - "'Topology Based Meshing' objects are inaccessible from other workflows." - ) - return super().__getattribute__(item) + super().__init__( + workflow=workflow, + meshing=meshing, + name="Topology Based Meshing", + identifier="EnablePrimeMeshing", + fluent_version=fluent_version, + ) + + +class WorkflowMode(Enum): + """Provides an enum of supported Fluent meshing workflow modes.""" + + CLASSIC_MESHING_MODE = ClassicMeshingWorkflow + WATERTIGHT_MESHING_MODE = WatertightMeshingWorkflow + FAULT_TOLERANT_MESHING_MODE = FaultTolerantMeshingWorkflow + TWO_DIMENSIONAL_MESHING_MODE = TwoDimensionalMeshingWorkflow + TOPOLOGY_BASED_MESHING_MODE = TopologyBasedMeshingWorkflow diff --git a/src/ansys/fluent/core/meshing/topology_based.py b/src/ansys/fluent/core/meshing/topology_based.py deleted file mode 100644 index d8cd1b9e728..00000000000 --- a/src/ansys/fluent/core/meshing/topology_based.py +++ /dev/null @@ -1,25 +0,0 @@ -"""2D Meshing workflow module.""" - -from typing import Union - -from ..session_meshing import Meshing -from ..session_pure_meshing import PureMeshing -from .meshing_workflow import TopologyBasedMeshingWorkflow - - -def topology_based_workflow( - session: Union[Meshing, PureMeshing] -) -> TopologyBasedMeshingWorkflow: - """Meshing workflow wrapper, initialized as 2D Meshing. - - Parameters - ---------- - session: Union[Meshing, PureMeshing] - Meshing session object. - - Returns - ------- - TwoDimensionalMeshingWorkflow - 2D meshing workflow wrapper. - """ - return session.topology_based() diff --git a/src/ansys/fluent/core/meshing/watertight.py b/src/ansys/fluent/core/meshing/watertight.py deleted file mode 100644 index 4728d8faf2d..00000000000 --- a/src/ansys/fluent/core/meshing/watertight.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Watertight workflow module.""" - -from typing import Optional, Union - -from ..session_meshing import Meshing -from ..session_pure_meshing import PureMeshing -from .meshing_workflow import WatertightMeshingWorkflow - - -def watertight_workflow( - session: Union[Meshing, PureMeshing], geometry_file_name: Optional[str] = None -) -> WatertightMeshingWorkflow: - """Meshing workflow wrapper, initialized as watertight. - - Parameters - ---------- - session: Union[Meshing, PureMeshing] - Meshing session object. - geometry_file_name : Optional[str] - The path of a valid geometry file to import. Can be unset. - - Returns - ------- - WatertightMeshingWorkflow - Watertight meshing workflow wrapper. - """ - watertight = session.watertight() - if geometry_file_name: - import_geometry = watertight.import_geometry - import_geometry.file_name = geometry_file_name - import_geometry() - return watertight diff --git a/src/ansys/fluent/core/session_base_meshing.py b/src/ansys/fluent/core/session_base_meshing.py index 1806a5c6693..a1e7c42c44e 100644 --- a/src/ansys/fluent/core/session_base_meshing.py +++ b/src/ansys/fluent/core/session_base_meshing.py @@ -4,13 +4,7 @@ import logging from ansys.fluent.core.fluent_connection import FluentConnection -from ansys.fluent.core.meshing.meshing_workflow import ( - ClassicMeshingWorkflow, - FaultTolerantMeshingWorkflow, - TopologyBasedMeshingWorkflow, - TwoDimensionalMeshingWorkflow, - WatertightMeshingWorkflow, -) +from ansys.fluent.core.meshing.meshing_workflow import WorkflowMode from ansys.fluent.core.services.datamodel_se import PyMenuGeneric from ansys.fluent.core.services.datamodel_tui import TUIMenu from ansys.fluent.core.session_shared import _CODEGEN_MSG_DATAMODEL, _CODEGEN_MSG_TUI @@ -152,9 +146,10 @@ def _workflow_se(self): def workflow(self): """Datamodel root of workflow.""" if not self._old_workflow: - self._old_workflow = ClassicMeshingWorkflow( + self._old_workflow = WorkflowMode.CLASSIC_MESHING_MODE.value( self._workflow_se, self.meshing, + self.get_fluent_version(), ) return self._old_workflow @@ -162,9 +157,10 @@ def workflow(self): def watertight_workflow(self): """Datamodel root of workflow exposed in object-oriented manner.""" if not self._wt_workflow: - self._wt_workflow = WatertightMeshingWorkflow( + self._wt_workflow = WorkflowMode.WATERTIGHT_MESHING_MODE.value( self._workflow_se, self.meshing, + self.get_fluent_version(), ) return self._wt_workflow @@ -172,21 +168,23 @@ def watertight_workflow(self): def fault_tolerant_workflow(self): """Datamodel root of workflow exposed in object-oriented manner.""" if not self._ft_workflow: - self._ft_workflow = FaultTolerantMeshingWorkflow( + self._ft_workflow = WorkflowMode.FAULT_TOLERANT_MESHING_MODE.value( self._workflow_se, self.meshing, self.PartManagement, self.PMFileManagement, + self.get_fluent_version(), ) return self._ft_workflow @property def two_dimensional_meshing_workflow(self): - """Datamodel root of workflow exposed in object-oriented manner.""" + """Data model root of the workflow exposed in an object-oriented manner.""" if not self._2dm_workflow: - self._2dm_workflow = TwoDimensionalMeshingWorkflow( + self._2dm_workflow = WorkflowMode.TWO_DIMENSIONAL_MESHING_MODE.value( self._workflow_se, self.meshing, + self.get_fluent_version(), ) return self._2dm_workflow @@ -194,9 +192,10 @@ def two_dimensional_meshing_workflow(self): def topology_based_meshing_workflow(self): """Datamodel root of workflow exposed in object-oriented manner.""" if not self._tb_workflow: - self._tb_workflow = TopologyBasedMeshingWorkflow( + self._tb_workflow = WorkflowMode.TOPOLOGY_BASED_MESHING_MODE.value( self._workflow_se, self.meshing, + self.get_fluent_version(), ) return self._tb_workflow diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index 3b9181637ed..c0342359ed3 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -197,7 +197,9 @@ def _workflow_se(self): def workflow(self): """Datamodel root for workflow.""" if not self._workflow: - self._workflow = ClassicWorkflow(self._workflow_se, Solver) + self._workflow = ClassicWorkflow( + self._workflow_se, Solver, self.get_fluent_version() + ) return self._workflow @property diff --git a/src/ansys/fluent/core/workflow.py b/src/ansys/fluent/core/workflow.py index ab4e15b7eba..a4ef42a6ff9 100644 --- a/src/ansys/fluent/core/workflow.py +++ b/src/ansys/fluent/core/workflow.py @@ -16,6 +16,7 @@ PyMenuGeneric, PySingletonCommandArgumentsSubItem, ) +from ansys.fluent.core.utils.fluent_version import FluentVersion def camel_to_snake_case(camel_case_str: str) -> str: @@ -180,6 +181,7 @@ def __init__( _task_list=[], _task_objects={}, _dynamic_interface=command_source._dynamic_interface, + _fluent_version=command_source._fluent_version, ) ) @@ -979,21 +981,33 @@ def _add_child(self, state: Optional[dict] = None) -> None: state = state or {} if self._dynamic_interface: state.update({"add_child": "yes"}) - self.arguments.set_state(state) + self.arguments.update_dict(state) else: state.update({"AddChild": "yes"}) - self._task.Arguments.set_state(state) + self._task.Arguments.update_dict(state) - def add_child_and_update(self, state=None): + def add_child_and_update(self, state=None, defer_update=None): """Add a child to this CompoundTask and update. Parameters ---------- state : Optional[dict] Optional state. + defer_update : bool, default: False + Whether to defer the update. """ self._add_child(state) - self._task.AddChildAndUpdate() + if self._fluent_version >= FluentVersion.v241: + if defer_update is None: + defer_update = False + self._task.AddChildAndUpdate(DeferUpdate=defer_update) + else: + if defer_update is not None: + warnings.warn( + " The 'defer_update()' method is supported in Fluent 2024 R1 and later.", + UserWarning, + ) + self._task.AddChildAndUpdate() return self.last_child() def last_child(self) -> BaseTask: @@ -1060,7 +1074,12 @@ class Workflow: __call__() """ - def __init__(self, workflow: PyMenuGeneric, command_source: PyMenuGeneric) -> None: + def __init__( + self, + workflow: PyMenuGeneric, + command_source: PyMenuGeneric, + fluent_version: FluentVersion, + ) -> None: """Initialize WorkflowWrapper. Parameters @@ -1094,6 +1113,7 @@ def __init__(self, workflow: PyMenuGeneric, command_source: PyMenuGeneric) -> No "task_object", "workflow", } + self._fluent_version = fluent_version def task(self, name: str) -> BaseTask: """Get a TaskObject by name, in a ``BaseTask`` wrapper. The wrapper adds extra @@ -1394,7 +1414,12 @@ class ClassicWorkflow: __call__() """ - def __init__(self, workflow: PyMenuGeneric, command_source: PyMenuGeneric) -> None: + def __init__( + self, + workflow: PyMenuGeneric, + command_source: PyMenuGeneric, + fluent_version: FluentVersion, + ) -> None: """Initialize ClassicWorkflow. Parameters @@ -1410,6 +1435,7 @@ def __init__(self, workflow: PyMenuGeneric, command_source: PyMenuGeneric) -> No threading.RLock() ) # TODO: sort out issues with these un-used variables. self._dynamic_interface = False + self._fluent_version = fluent_version @property def TaskObject(self) -> TaskContainer: diff --git a/tests/test_meshing_workflow.py b/tests/test_meshing_workflow.py index b73cd711f34..cc1dfcba038 100644 --- a/tests/test_meshing_workflow.py +++ b/tests/test_meshing_workflow.py @@ -11,7 +11,6 @@ shared_watertight_workflow_session, ) -from ansys.fluent.core.meshing.faulttolerant import fault_tolerant_workflow from ansys.fluent.core.utils.fluent_version import FluentVersion @@ -364,29 +363,6 @@ def test_iterate_meshing_workflow_task_container(new_mesh_session): assert tasks[0].name() == "Import Geometry" -@pytest.mark.fluent_version("==23.2") -@pytest.mark.codegen_required -def test_fault_tolerant_workflow(exhaust_system_geometry, new_mesh_session): - fault_tolerant = fault_tolerant_workflow(session=new_mesh_session) - part_management = fault_tolerant.part_management - file_name = exhaust_system_geometry - part_management.LoadFmdFile(FilePath=file_name) - part_management.MoveCADComponentsToNewObject( - Paths=[r"/Bottom,1", r"/Left,1", r"/Others,1", r"/Right,1", r"/Top,1"] - ) - part_management.Node["Object"].Rename(NewName=r"Engine") - import_cad = fault_tolerant.task("Import CAD and Part Management") - import_cad.Arguments.setState( - { - r"CreateObjectPer": r"Custom", - r"FMDFileName": file_name, - r"FileLoaded": r"yes", - r"ObjectSetting": r"DefaultObjectSetting", - } - ) - import_cad() - - @pytest.mark.codegen_required def test_modified_workflow(new_mesh_session): meshing = new_mesh_session @@ -451,3 +427,165 @@ def test_new_workflow_structure(new_mesh_session): msg.value.args[0] == "'WatertightMeshingWorkflow' object has no attribute 'TaskObject'" ) + + +@pytest.mark.nightly +@pytest.mark.codegen_required +@pytest.mark.fluent_version(">=24.2") +def test_new_2d_meshing_workflow(new_mesh_session): + # Import geometry + # import_file_name = examples.download_file( + # "mixing_elbow.pmdb", "pyfluent/mixing_elbow" + # ) + import_file_name = r"C:\ANSYSDev\PyFluent_Dev_01\pyfluent\NACA0012.fmd" + meshing = new_mesh_session + meshing.workflow.InitializeWorkflow(WorkflowType="2D Meshing") + meshing.workflow.TaskObject["Load CAD Geometry"].Arguments.set_state( + { + r"FileName": import_file_name, + r"LengthUnit": r"mm", + r"Refaceting": { + r"Refacet": False, + }, + } + ) + meshing.workflow.TaskObject["Load CAD Geometry"].Execute() + + meshing.workflow.TaskObject["Update Regions"].Execute() + meshing.workflow.TaskObject["Update Boundaries"].Arguments.set_state( + { + r"SelectionType": r"zone", + } + ) + meshing.workflow.TaskObject["Update Boundaries"].Execute() + + meshing.workflow.TaskObject["Define Global Sizing"].Arguments.set_state( + { + r"CurvatureNormalAngle": 20, + r"MaxSize": 2000, + r"MinSize": 5, + r"SizeFunctions": r"Curvature", + } + ) + meshing.workflow.TaskObject["Define Global Sizing"].Execute() + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"boi_1", + r"BOIExecution": r"Body Of Influence", + r"BOIFaceLabelList": [r"boi"], + r"BOISize": 50, + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"edgesize_1", + r"BOIExecution": r"Edge Size", + r"BOISize": 5, + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + r"EdgeLabelList": [r"airfoil-te"], + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + + meshing.workflow.TaskObject["Add Local Sizing"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BOIControlName": r"curvature_1", + r"BOICurvatureNormalAngle": 10, + r"BOIExecution": r"Curvature", + r"BOIMaxSize": 2, + r"BOIMinSize": 1.5, + r"BOIScopeTo": r"edges", + r"BOIZoneorLabel": r"label", + r"DrawSizeControl": True, + r"EdgeLabelList": [r"airfoil"], + } + ) + meshing.workflow.TaskObject["Add Local Sizing"].AddChildAndUpdate(DeferUpdate=False) + + meshing.workflow.TaskObject["Add 2D Boundary Layers"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"aspect-ratio_1", + r"NumberOfLayers": 4, + r"OffsetMethodType": r"aspect-ratio", + } + ) + meshing.workflow.TaskObject["Add 2D Boundary Layers"].AddChildAndUpdate( + DeferUpdate=False + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + + meshing.workflow.TaskObject["aspect-ratio_1"].Revert() + meshing.workflow.TaskObject["aspect-ratio_1"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"uniform_1", + r"FirstLayerHeight": 2, + r"NumberOfLayers": 4, + r"OffsetMethodType": r"uniform", + } + ) + meshing.workflow.TaskObject["aspect-ratio_1"].Execute() + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state(None) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + meshing.workflow.TaskObject["uniform_1"].Revert() + meshing.workflow.TaskObject["uniform_1"].Arguments.set_state( + { + r"AddChild": r"yes", + r"BLControlName": r"smooth-transition_1", + r"FirstLayerHeight": 2, + r"NumberOfLayers": 7, + r"OffsetMethodType": r"smooth-transition", + } + ) + meshing.workflow.TaskObject["uniform_1"].Execute() + + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state(None) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Arguments.set_state( + { + r"Surface2DPreferences": { + r"MergeEdgeZonesBasedOnLabels": r"no", + r"MergeFaceZonesBasedOnLabels": r"no", + r"ShowAdvancedOptions": True, + }, + } + ) + meshing.workflow.TaskObject["Generate the Surface Mesh"].Execute() + + meshing.workflow.TaskObject["Export Fluent 2D Mesh"].Arguments.set_state( + { + r"FileName": r"C:\ANSYSDev\PyFluent_Dev_01\pyfluent\out\case1.msh.h5", + } + ) + meshing.workflow.TaskObject["Export Fluent 2D Mesh"].Execute() + + # Switch to solution mode + solver = meshing.switch_to_solver() + assert not solver diff --git a/tests/test_new_meshing_workflow.py b/tests/test_new_meshing_workflow.py index 6965c013410..5ee54f38fea 100644 --- a/tests/test_new_meshing_workflow.py +++ b/tests/test_new_meshing_workflow.py @@ -4,7 +4,6 @@ import pytest from ansys.fluent.core import examples -from ansys.fluent.core.meshing.watertight import watertight_workflow from tests.test_datamodel_service import disable_datamodel_cache # noqa: F401 @@ -473,6 +472,123 @@ def test_new_fault_tolerant_workflow(new_mesh_session): assert solver +@pytest.mark.nightly +@pytest.mark.codegen_required +@pytest.mark.fluent_version(">=24.2") +def test_new_2d_meshing_workflow(new_mesh_session): + # Import geometry + import_file_name = examples.download_file("NACA0012.fmd", "pyfluent/airfoils") + two_dim_mesh = new_mesh_session.two_dimensional_meshing() + + two_dim_mesh.load_cad_geometry_2d.file_name = import_file_name + two_dim_mesh.load_cad_geometry_2d.length_unit = "mm" + two_dim_mesh.load_cad_geometry_2d.refaceting.refacet = False + two_dim_mesh.load_cad_geometry_2d() + + # Set regions and boundaries + two_dim_mesh.update_regions_2d() + two_dim_mesh.update_boundaries_2d.selection_type = "zone" + two_dim_mesh.update_boundaries_2d() + + # Define global sizing + two_dim_mesh.define_global_sizing_2d.curvature_normal_angle = 20 + two_dim_mesh.define_global_sizing_2d.max_size = 2000.0 + two_dim_mesh.define_global_sizing_2d.min_size = 5.0 + two_dim_mesh.define_global_sizing_2d.size_functions = "Curvature" + two_dim_mesh.define_global_sizing_2d() + + # Add local sizing + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "boi_1" + two_dim_mesh.add_local_sizing_2d.boi_execution = "Body Of Influence" + two_dim_mesh.add_local_sizing_2d.boi_face_label_list = ["boi"] + two_dim_mesh.add_local_sizing_2d.boi_size = 50.0 + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "edgesize_1" + two_dim_mesh.add_local_sizing_2d.boi_execution = "Edge Size" + two_dim_mesh.add_local_sizing_2d.boi_size = 5.0 + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.edge_label_list = ["airfoil-te"] + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + + two_dim_mesh.add_local_sizing_2d.add_child = "yes" + two_dim_mesh.add_local_sizing_2d.boi_control_name = "curvature_1" + two_dim_mesh.add_local_sizing_2d.boi_curvature_normal_angle = 10 + two_dim_mesh.add_local_sizing_2d.boi_execution = "Curvature" + two_dim_mesh.add_local_sizing_2d.boi_max_size = 2 + two_dim_mesh.add_local_sizing_2d.boi_min_size = 1.5 + two_dim_mesh.add_local_sizing_2d.boi_scope_to = "edges" + two_dim_mesh.add_local_sizing_2d.boi_zoneor_label = "label" + two_dim_mesh.add_local_sizing_2d.draw_size_control = True + two_dim_mesh.add_local_sizing_2d.edge_label_list = ["airfoil"] + two_dim_mesh.add_local_sizing_2d.add_child_and_update(defer_update=False) + + # Add boundary layer + two_dim_mesh.add_2d_boundary_layers.add_child = "yes" + two_dim_mesh.add_2d_boundary_layers.bl_control_name = "aspect-ratio_1" + two_dim_mesh.add_2d_boundary_layers.number_of_layers = 4 + two_dim_mesh.add_2d_boundary_layers.offset_method_type = "aspect-ratio" + two_dim_mesh.add_2d_boundary_layers.add_child_and_update(defer_update=False) + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + + two_dim_mesh.task("aspect-ratio_1").revert() + two_dim_mesh.task("aspect-ratio_1").add_child = "yes" + two_dim_mesh.task("aspect-ratio_1").bl_control_name = "uniform_1" + two_dim_mesh.task("aspect-ratio_1").first_layer_height = 2 + two_dim_mesh.task("aspect-ratio_1").number_of_layers = 4 + two_dim_mesh.task("aspect-ratio_1").offset_method_type = "uniform" + two_dim_mesh.task("aspect-ratio_1")() + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + + two_dim_mesh.task("uniform_1").revert() + two_dim_mesh.task("uniform_1").add_child = "yes" + two_dim_mesh.task("uniform_1").bl_control_name = "smooth-transition_1" + two_dim_mesh.task("uniform_1").first_layer_height = 2 + two_dim_mesh.task("uniform_1").number_of_layers = 7 + two_dim_mesh.task("uniform_1").offset_method_type = "smooth-transition" + two_dim_mesh.task("uniform_1")() + + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_edge_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.merge_face_zones_based_on_labels = ( + "no" + ) + two_dim_mesh.generate_initial_surface_mesh.surface2_d_preferences.show_advanced_options = ( + True + ) + two_dim_mesh.generate_initial_surface_mesh() + + # Switch to solution mode + solver = new_mesh_session.switch_to_solver() + assert solver + + @pytest.mark.codegen_required @pytest.mark.fluent_version(">=23.2") def test_updating_state_in_new_meshing_workflow(new_mesh_session): @@ -565,9 +681,9 @@ def test_workflow_and_data_model_methods_new_meshing_workflow(new_mesh_session): @pytest.mark.fluent_version(">=23.2") @pytest.mark.codegen_required def test_watertight_workflow(mixing_elbow_geometry, new_mesh_session): - watertight = watertight_workflow( - geometry_file_name=mixing_elbow_geometry, session=new_mesh_session - ) + watertight = new_mesh_session.watertight() + watertight.import_geometry.file_name = mixing_elbow_geometry + watertight.import_geometry() add_local_sizing = watertight.add_local_sizing assert not add_local_sizing.ordered_children() add_local_sizing._add_child(state={"boi_face_label_list": ["cold-inlet"]}) @@ -583,9 +699,9 @@ def test_watertight_workflow(mixing_elbow_geometry, new_mesh_session): @pytest.mark.fluent_version(">=23.2") @pytest.mark.codegen_required def test_watertight_workflow_children(mixing_elbow_geometry, new_mesh_session): - watertight = watertight_workflow( - geometry_file_name=mixing_elbow_geometry, session=new_mesh_session - ) + watertight = new_mesh_session.watertight() + watertight.import_geometry.file_name = mixing_elbow_geometry + watertight.import_geometry() add_local_sizing = watertight.add_local_sizing assert not add_local_sizing.ordered_children() add_local_sizing._add_child(state={"boi_face_label_list": ["cold-inlet"]}) @@ -619,9 +735,9 @@ def test_watertight_workflow_children(mixing_elbow_geometry, new_mesh_session): @pytest.mark.fluent_version(">=23.2") @pytest.mark.codegen_required def test_watertight_workflow_dynamic_interface(mixing_elbow_geometry, new_mesh_session): - watertight = watertight_workflow( - geometry_file_name=mixing_elbow_geometry, session=new_mesh_session - ) + watertight = new_mesh_session.watertight() + watertight.import_geometry.file_name = mixing_elbow_geometry + watertight.import_geometry() create_volume_mesh = watertight.create_volume_mesh assert create_volume_mesh is not None watertight.delete_tasks(list_of_tasks=["create_volume_mesh"]) @@ -651,6 +767,29 @@ def test_watertight_workflow_dynamic_interface(mixing_elbow_geometry, new_mesh_s watertight.create_volume_mesh +@pytest.mark.fluent_version("==23.2") +@pytest.mark.codegen_required +def test_fault_tolerant_workflow(exhaust_system_geometry, new_mesh_session): + fault_tolerant = new_mesh_session.fault_tolerant() + part_management = fault_tolerant.part_management + file_name = exhaust_system_geometry + part_management.LoadFmdFile(FilePath=file_name) + part_management.MoveCADComponentsToNewObject( + Paths=[r"/Bottom,1", r"/Left,1", r"/Others,1", r"/Right,1", r"/Top,1"] + ) + part_management.Node["Object"].Rename(NewName=r"Engine") + import_cad = fault_tolerant.task("Import CAD and Part Management") + import_cad.Arguments.setState( + { + r"CreateObjectPer": r"Custom", + r"FMDFileName": file_name, + r"FileLoaded": r"yes", + r"ObjectSetting": r"DefaultObjectSetting", + } + ) + import_cad() + + @pytest.mark.fluent_version(">=23.2") @pytest.mark.codegen_required def test_extended_wrapper(new_mesh_session, mixing_elbow_geometry):