Skip to content

Commit

Permalink
Merge branch 'main' into feat/stub_file_for_meshing_utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
hpohekar authored Oct 16, 2024
2 parents cd27eff + 32d7442 commit 92f312b
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 13 deletions.
116 changes: 116 additions & 0 deletions .ci/fluent_test_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""Script to run Fluent test in Docker container."""

import argparse
import logging
import os
from pathlib import Path
from shutil import copytree
from tempfile import TemporaryDirectory
from time import sleep

import yaml

import ansys.fluent.core as pyfluent
import docker


class FluentRuntimeError(RuntimeError):
"""Exception raised when stderr is detected in Fluent output."""

pass


def run_fluent_test(journal_file: Path, launcher_args: str = "") -> None:
"""Run Fluent test.
Parameters
----------
journal_file : Path
Absolute path to the journal file.
launcher_args : str, optional
Additional arguments for the Fluent launcher.
Raises
------
FluentRuntimeError
Raised when stderr is detected in Fluent output.
"""
logging.debug(f"journal_file: {journal_file}")
src_pyfluent_dir = str(Path(pyfluent.__file__).parent)
dst_pyfluent_dir = "/ansys_inc/v251/commonfiles/CPython/3_10/linx64/Release/python/lib/python3.10/site-packages/ansys/fluent/core"
src_test_dir = str(journal_file.parent)
dst_test_dir = "/testing"
logging.debug(f"src_pyfluent_dir: {src_pyfluent_dir}")
logging.debug(f"dst_pyfluent_dir: {dst_pyfluent_dir}")
logging.debug(f"src_test_dir: {src_test_dir}")
logging.debug(f"dst_test_dir: {dst_test_dir}")

docker_client = docker.from_env()
image_name = "ghcr.io/ansys/pyfluent:v25.1.0"
container = docker_client.containers.run(
image=image_name,
volumes=[
f"{src_pyfluent_dir}:{dst_pyfluent_dir}",
f"{src_test_dir}:{dst_test_dir}",
],
working_dir=dst_test_dir,
environment={"ANSYSLMD_LICENSE_FILE": os.environ["ANSYSLMD_LICENSE_FILE"]},
command=f"3ddp {launcher_args} -gu -py -i {journal_file.name}",
detach=True,
stdout=True,
stderr=True,
)
while True:
container.reload()
if container.status == "exited":
break
stderr = container.logs(stdout=False, stderr=True)
if stderr:
stderr = stderr.decode()
for line in stderr.split("\n"):
if line.strip().startswith("Error:"):
if "Expected exception" in line: # for check_assert.py
container.stop()
else:
raise FluentRuntimeError(line)
sleep(1)
logging.debug(container.logs(stderr=True).decode())
container.remove()


MAX_TEST_PATH_LENGTH = 40


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Run Fluent test.")
parser.add_argument(
"test_dir",
help="Path to the Fluent test directory relative to the PyFluent repository root.",
)
args = parser.parse_args()
test_dir = Path.cwd() / args.test_dir
with TemporaryDirectory(ignore_cleanup_errors=True) as tmpdir:
copytree(test_dir, tmpdir, dirs_exist_ok=True)
exception_occurred = False
for test_file in Path(tmpdir).rglob("*.py"):
config_file = test_file.with_suffix(".yaml")
launcher_args = ""
if config_file.exists():
configs = yaml.safe_load(config_file.read_text())
launcher_args = configs.get("launcher_args", "")
test_file_relpath = str(test_file.relative_to(tmpdir))
print(f"Running {test_file_relpath}", end="", flush=True)
try:
run_fluent_test(test_file, launcher_args)
print(
f"{(MAX_TEST_PATH_LENGTH + 10 - len(test_file_relpath)) * '·'}PASSED"
)
except FluentRuntimeError as e:
print(
f"{(MAX_TEST_PATH_LENGTH + 10 - len(test_file_relpath)) * '·'}FAILED"
)
print(e)
exception_occurred = True
if exception_occurred:
exit(1)
83 changes: 83 additions & 0 deletions .github/workflows/test-fluent-journals.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Test Fluent journals with PyFluent changes

on:
schedule: # UTC at 0700
- cron: '0 7 * * *'
workflow_dispatch:
push:
branches:
- main

env:
ANSYSLMD_LICENSE_FILE: ${{ format('1055@{0}', secrets.LICENSE_SERVER) }}
PYFLUENT_TIMEOUT_FORCE_EXIT: 30
PYFLUENT_LAUNCH_CONTAINER: 1
PYFLUENT_LOGGING: 'DEBUG'
PYFLUENT_WATCHDOG_DEBUG: 'OFF'
PYFLUENT_HIDE_LOG_SECRETS: 1
MAIN_PYTHON_VERSION: '3.10'

jobs:
test:
name: Fluent Testing
runs-on: [self-hosted, pyfluent]
timeout-minutes: 120

steps:
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}

- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: Python-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
Python-${{ runner.os }}-${{ matrix.python-version }}
- name: Add version information
run: make version-info

- name: Install pyfluent
run: make install

- name: Retrieve PyFluent version
run: |
echo "PYFLUENT_VERSION=$(python -c "from ansys.fluent.core import __version__; print(); print(__version__)" | tail -1)" >> $GITHUB_OUTPUT
echo "PYFLUENT version is: $(python -c "from ansys.fluent.core import __version__; print(); print(__version__)" | tail -1)"
id: version

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ansys-bot
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull 25.1 Fluent docker image
run: make docker-pull
env:
FLUENT_IMAGE_TAG: v25.1.0

- name: Run 25.1 API codegen
run: make api-codegen
env:
FLUENT_IMAGE_TAG: v25.1.0

- name: Print 25.1 Fluent version info
run: |
cat src/ansys/fluent/core/generated/fluent_version_251.py
python -c "from ansys.fluent.core.generated.solver.settings_251 import SHASH; print(f'SETTINGS_HASH = {SHASH}')"
- name: Install again after codegen
run: |
rm -rf dist
make install > /dev/null
- name: Run Fluent tests
run: |
python .ci/fluent_test_runner.py tests/fluent
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ tests = ["pytest", "pytest-cov", "pytest-mock", "pytest-xdist"]
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = """
--ignore=tests/fluent
-v
--durations=0
--show-capture=all
Expand Down
6 changes: 3 additions & 3 deletions src/ansys/fluent/core/services/datamodel_tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,13 @@ def __dir__(self) -> list[str]:
for x in PyMenu(
self._service, self._version, self._mode, self._path
).get_child_names()
if x != "exit"
if x not in ["exit", "switch_to_meshing_mode"]
]

def __getattribute__(self, name) -> Any:
if name == "exit" and not self._path:
if name in ["exit", "switch_to_meshing_mode"] and not self._path:
raise AttributeError(
f"'{self.__class__.__name__}' object has no attribute 'exit'"
f"'{self.__class__.__name__}' object has no attribute '{name}'"
)
try:
attr = super().__getattribute__(name)
Expand Down
1 change: 1 addition & 0 deletions src/ansys/fluent/core/solver/flobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -2089,6 +2089,7 @@ def _process_cls_names(info_dict, names, write_doc=False):
commands = info.get("commands")
if commands:
commands.pop("exit", None)
commands.pop("switch-to-meshing-mode", None)
if commands and not user_creatable:
commands.pop("create", None)
if commands:
Expand Down
2 changes: 2 additions & 0 deletions tests/fluent/test_assert/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
assert False, "Expected exception"
exit()
21 changes: 21 additions & 0 deletions tests/fluent/test_meshing_workflow/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from ansys.fluent.core.examples import download_file

geometry_file = download_file("mixing_elbow.pmdb", "pyfluent/mixing_elbow")
watertight = meshing.watertight()
watertight.import_geometry.file_name.set_state(geometry_file)
assert watertight.import_geometry.length_unit() == "mm"
watertight.import_geometry.length_unit = "in"
assert watertight.import_geometry.length_unit() == "in"
assert watertight.import_geometry.cad_import_options.feature_angle() == 40.0
watertight.import_geometry.cad_import_options.feature_angle.set_state(25.0)
assert watertight.import_geometry.cad_import_options.feature_angle() == 25.0
assert watertight.import_geometry.cad_import_options.one_zone_per.allowed_values() == [
"body",
"face",
"object",
]
assert watertight.import_geometry.cad_import_options.one_zone_per() == "body"
watertight.import_geometry.cad_import_options.one_zone_per = "face"
assert watertight.import_geometry.cad_import_options.one_zone_per() == "face"
watertight.import_geometry()
exit()
1 change: 1 addition & 0 deletions tests/fluent/test_meshing_workflow/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
launcher_args: -meshing
12 changes: 12 additions & 0 deletions tests/fluent/test_settings_api/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from ansys.fluent.core.examples import download_file

case_name = download_file("mixing_elbow.cas.h5", "pyfluent/mixing_elbow")
solver.settings.file.read_case(file_name=case_name)
viscous_settings = solver.settings.setup.models.viscous
assert viscous_settings.model() == "k-omega"
allowed_values = viscous_settings.model.allowed_values()
assert "k-epsilon" in allowed_values
assert len(allowed_values) > 5
viscous_settings.model = "k-epsilon"
assert viscous_settings.model() == "k-epsilon"
exit()
2 changes: 2 additions & 0 deletions tests/fluent/test_version/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
assert ansys.fluent.core.__version__ == "0.27.dev0"
exit()
10 changes: 5 additions & 5 deletions tests/test_settings_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,10 @@ def test_child_alias_with_parent_path(mixing_elbow_settings_session):


@pytest.mark.fluent_version(">=25.1")
def test_exit_not_in_settings(new_solver_session):
def test_commands_not_in_settings(new_solver_session):
solver = new_solver_session

assert "exit" not in dir(solver.settings)

with pytest.raises(AttributeError):
solver.settings.exit()
for command in ["exit", "switch_to_meshing_mode"]:
assert command not in dir(solver.settings)
with pytest.raises(AttributeError):
getattr(solver.settings, command)
10 changes: 5 additions & 5 deletions tests/test_tui_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ def test_exit_not_in_meshing_tui(new_meshing_session):
meshing.tui.exit()


def test_exit_not_in_solver_tui(new_solver_session):
def test_commands_not_in_solver_tui(new_solver_session):
solver = new_solver_session

assert "exit" not in dir(solver.tui)

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

0 comments on commit 92f312b

Please sign in to comment.