diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index d90297335..bb788a1af 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -46,16 +46,16 @@ jobs: - name: Checkout lockfile run: git lfs checkout - - uses: prefix-dev/setup-pixi@v0.9.4 + - uses: prefix-dev/setup-pixi@v0.10.0 with: - pixi-version: v0.55.0 + pixi-version: v0.69.0 frozen: true environments: ${{ matrix.python-version }} activate-environment: ${{ matrix.python-version }} - - name: Install IBCDFO + - name: Install minq run: | - pixi run -e ${{ matrix.python-version }} ./install/install_ibcdfo.sh + pixi run -e ${{ matrix.python-version }} ./install/install_minq.sh - name: Install libEnsemble, test flake8 run: | diff --git a/.github/workflows/extra.yml b/.github/workflows/extra.yml index e84ae3842..5a66e029d 100644 --- a/.github/workflows/extra.yml +++ b/.github/workflows/extra.yml @@ -48,17 +48,16 @@ jobs: - name: Checkout lockfile run: git lfs checkout - - uses: prefix-dev/setup-pixi@v0.9.4 + - uses: prefix-dev/setup-pixi@v0.10.0 with: - pixi-version: v0.55.0 - cache: true + pixi-version: v0.69.0 frozen: true environments: ${{ matrix.python-version }} activate-environment: ${{ matrix.python-version }} - - name: Install other testing dependencies + - name: Install minq run: | - pixi run -e ${{ matrix.python-version }} install/install_ibcdfo.sh + pixi run -e ${{ matrix.python-version }} ./install/install_minq.sh - name: Install libEnsemble, flake8, lock environment run: | diff --git a/.wci.yml b/.wci.yml index db127beeb..90be67844 100644 --- a/.wci.yml +++ b/.wci.yml @@ -16,8 +16,8 @@ description: | language: Python release: - version: 1.6.0 - date: 2026-03-04 + version: 1.6.1 + date: 2026-07-20 documentation: general: https://libensemble.readthedocs.io diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d950fdd3c..aafc90fa1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,24 @@ GitHub issues are referenced, and can be viewed with hyperlinks on the `github r .. _`github releases page`: https://github.com/Libensemble/libensemble/releases +Release 1.6.1 +-------------- + +:Date: July 20, 2026 + +Dependencies: + +* ``gest-api`` dependency upper-bound removed. + +:Note: + +* Tests were run on Linux and MacOS with Python versions 3.10, 3.11, 3.12, 3.13, 3.14 + +:Known Issues: + +* See known issues section in the documentation. + + Release 1.6.0 -------------- @@ -26,15 +44,15 @@ General Updates: Examples: * Adding test for ibcdfo with jax. #1591 -* Optimas/Xopt examples. #1620 / #1635 +* Optimas/Xopt examples. #1620 / #1635 * Bayesian Optimization with Xopt tutorial / notebook. * Tasmanian generators moved to community examples. Dependencies: -* ``gest-api`` is now a required dependency. #1666 +* ``gest-api`` is now a required dependency. #1666 * Remove Pydantic v1 support and Balsam. #1573 -* Python 3.14 supported. #1609 +* Python 3.14 supported. #1609 :Note: diff --git a/docs/advanced_installation.rst b/docs/advanced_installation.rst index 7af481fad..0f125f15a 100644 --- a/docs/advanced_installation.rst +++ b/docs/advanced_installation.rst @@ -12,7 +12,7 @@ automatically installed alongside libEnsemble: * `pydantic`_ ``>= 2`` * pyyaml_ ``>= v6.0`` * tomli_ ``>= 1.2.1`` -* gest-api_ ``>= 0.1,<0.2`` +* gest-api_ ``>= 0.1`` We recommend installing in a virtual environment from ``uv``, ``conda`` or another source. diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh deleted file mode 100644 index 0ed790f01..000000000 --- a/install/install_ibcdfo.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -git clone --recurse-submodules -b main https://github.com/POptUS/IBCDFO.git -pushd IBCDFO/minq/py/minq5/ -export PYTHONPATH="$PYTHONPATH:$(pwd)" -echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV -popd -pushd IBCDFO/ibcdfo_pypkg/ -pip install -e . -popd diff --git a/install/install_minq.sh b/install/install_minq.sh new file mode 100644 index 000000000..cdc325ccd --- /dev/null +++ b/install/install_minq.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +git clone https://github.com/POptUS/MINQ +pushd MINQ/py/minq5/ +export PYTHONPATH="$PYTHONPATH:$(pwd)" +echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV +popd diff --git a/libensemble/tests/regression_tests/common.py b/libensemble/tests/regression_tests/common.py index cb174d09c..ebf45cdaa 100644 --- a/libensemble/tests/regression_tests/common.py +++ b/libensemble/tests/regression_tests/common.py @@ -5,6 +5,7 @@ import glob import os import os.path +import sys import time @@ -72,6 +73,8 @@ def build_simfunc(): # Build simfunc # buildstring='mpif90 -o my_simtask.x my_simtask.f90' # On cray need to use ftn buildstring = "mpicc -o my_simtask.x ../unit_tests/simdir/my_simtask.c" + if sys.platform == "darwin": + buildstring = "mpicc -cc=clang -o my_simtask.x ../unit_tests/simdir/my_simtask.c" # subprocess.run(buildstring.split(),check=True) #Python3.5+ subprocess.check_call(buildstring.split()) diff --git a/libensemble/tests/run_tests.py b/libensemble/tests/run_tests.py index 073ab1a54..e566d451f 100755 --- a/libensemble/tests/run_tests.py +++ b/libensemble/tests/run_tests.py @@ -35,16 +35,16 @@ # Test Directories - all relative to project root dir CODE_DIR = "libensemble" LIBE_SRC_DIR = CODE_DIR -TESTING_DIR = os.path.join(CODE_DIR, "tests") +TESTING_DIR = Path(CODE_DIR) / "tests" UNIT_TEST_SUBDIRS = [ "unit_tests", "unit_tests_mpi_import", "unit_tests_nompi", "unit_tests_logger", ] -UNIT_TEST_DIRS = [os.path.join(TESTING_DIR, subdir) for subdir in UNIT_TEST_SUBDIRS] -REG_TEST_SUBDIR = os.path.join(TESTING_DIR, "regression_tests") -FUNC_TEST_SUBDIR = os.path.join(TESTING_DIR, "functionality_tests") +UNIT_TEST_DIRS = [TESTING_DIR / subdir for subdir in UNIT_TEST_SUBDIRS] +REG_TEST_SUBDIR = TESTING_DIR / "regression_tests" +FUNC_TEST_SUBDIR = TESTING_DIR / "functionality_tests" # Coverage merge and report dir COV_MERGE_DIR = TESTING_DIR @@ -129,15 +129,25 @@ def cleanup(root_dir): "opt_*.txt_flag", "test_executor_forces_tutorial", "test_executor_forces_tutorial_2", + # Coverage output generated by merge_coverage_reports + "coverage.xml", + # Cache files created by Ensemble/calling scripts + ".libe_cache_*.meta.json", + # Artifacts from forces build step + "forces_app", + "scaling_tests/forces/forces_app/forces.x", + # Task output scripts in unit tests + "libe_task_*.sh", ] dirs_to_clean = UNIT_TEST_DIRS + [REG_TEST_SUBDIR, FUNC_TEST_SUBDIR] for dir_path in dirs_to_clean: - full_path = os.path.join(root_dir, dir_path) - if "libensemble/tests/" not in full_path.replace("\\", "/"): - cprint(f"Safety check failed for {full_path}. Check directory", style="red") + full_path = Path(root_dir) / dir_path + full_path_str = str(full_path) + if "libensemble/tests/" not in full_path_str.replace("\\", "/"): + cprint(f"Safety check failed for {full_path_str}. Check directory", style="red") sys.exit(2) for pattern in patterns: - for file_path in glob.glob(os.path.join(full_path, pattern)): + for file_path in glob.glob(str(full_path / pattern)): try: if os.path.isfile(file_path) or os.path.islink(file_path): os.remove(file_path) @@ -199,8 +209,8 @@ def print_test_failed(test_num, test_script_name, comm, nprocs, duration): def merge_coverage_reports(root_dir): """Merge coverage data from multiple tests and generate a report.""" print_heading("Generating coverage reports") - tests_dir = os.path.join(root_dir, "libensemble", "tests") - cov_files = glob.glob(os.path.join(tests_dir, "**", ".cov_*"), recursive=True) + tests_dir = Path(root_dir) / "libensemble" / "tests" + cov_files = glob.glob(str(tests_dir / "**" / ".cov_*"), recursive=True) if cov_files: try: @@ -262,11 +272,14 @@ def is_open_mpi(): def build_forces(root_dir): """Build forces.x using mpicc.""" cprint("Building forces.x before running regression tests...", style="yellow", newline=True) - forces_app_dir = os.path.join(root_dir, "libensemble/tests/scaling_tests/forces/forces_app") - subprocess.run(["mpicc", "-O3", "-o", "forces.x", "forces.c", "-lm"], cwd=forces_app_dir, check=True) - destination_dir = os.path.join(root_dir, "libensemble/tests/forces_app") + forces_app_dir = Path(root_dir) / "libensemble/tests/scaling_tests/forces/forces_app" + build_cmd = ["mpicc", "-O3", "-o", "forces.x", "forces.c", "-lm"] + if platform.system() == "Darwin": + build_cmd = ["mpicc", "-cc=clang", "-O3", "-o", "forces.x", "forces.c", "-lm"] + subprocess.run(build_cmd, cwd=forces_app_dir, check=True) + destination_dir = Path(root_dir) / "libensemble/tests/forces_app" os.makedirs(destination_dir, exist_ok=True) - shutil.copy(os.path.join(forces_app_dir, "forces.x"), destination_dir) + shutil.copy(forces_app_dir / "forces.x", destination_dir) def skip_test(directives, args, current_os): @@ -335,7 +348,7 @@ def run_unit_tests(root_dir, python_exec, args): print_heading(f"Running unit tests (with pytest)") for dir_path in UNIT_TEST_DIRS: cprint(f"Entering unit test dir: {dir_path}", style="yellow", newline=True) - full_path = os.path.join(root_dir, dir_path) + full_path = Path(root_dir) / dir_path cov_rep = cov_report_type + ":cov_unit" cmd = python_exec + ["-m", "pytest", "--color=yes", "--timeout=120", "--cov", "--cov-report", cov_rep] if args.e: @@ -366,8 +379,8 @@ def run_regression_tests(root_dir, python_exec, args, current_os): reg_test_list = REG_TEST_LIST reg_test_files = [] for dir_path in test_dirs: - full_path = os.path.join(root_dir, dir_path) - reg_test_files.extend(glob.glob(os.path.join(full_path, reg_test_list))) + full_path = Path(root_dir) / dir_path + reg_test_files.extend(glob.glob(str(full_path / reg_test_list))) reg_test_files = sorted(reg_test_files) reg_pass = 0 diff --git a/libensemble/tests/unit_tests/test_executor.py b/libensemble/tests/unit_tests/test_executor.py index 95e60b286..bf90464e8 100644 --- a/libensemble/tests/unit_tests/test_executor.py +++ b/libensemble/tests/unit_tests/test_executor.py @@ -84,6 +84,10 @@ def build_simfuncs(): app_name = ".".join([sim.split(".")[0], "x"]) if not os.path.isfile(app_name): buildstring = "mpicc -o " + os.path.join("simdir", app_name) + " " + os.path.join("simdir", sim) + if sys.platform == "darwin": + buildstring = ( + "mpicc -cc=clang -o " + os.path.join("simdir", app_name) + " " + os.path.join("simdir", sim) + ) subprocess.check_call(buildstring.split()) diff --git a/libensemble/tests/unit_tests/test_executor_gpus.py b/libensemble/tests/unit_tests/test_executor_gpus.py index 239344ecd..8a1e02700 100644 --- a/libensemble/tests/unit_tests/test_executor_gpus.py +++ b/libensemble/tests/unit_tests/test_executor_gpus.py @@ -48,6 +48,10 @@ def build_simfuncs(): app_name = ".".join([sim.split(".")[0], "x"]) if not os.path.isfile(app_name): buildstring = "mpicc -o " + os.path.join("simdir", app_name) + " " + os.path.join("simdir", sim) + if sys.platform == "darwin": + buildstring = ( + "mpicc -cc=clang -o " + os.path.join("simdir", app_name) + " " + os.path.join("simdir", sim) + ) subprocess.check_call(buildstring.split()) diff --git a/libensemble/version.py b/libensemble/version.py index e4adfb83d..f49459c74 100644 --- a/libensemble/version.py +++ b/libensemble/version.py @@ -1 +1 @@ -__version__ = "1.6.0" +__version__ = "1.6.1" diff --git a/pixi.lock b/pixi.lock index 9cf2ab79c..73131cdb9 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d2d68a0828df655b53039075ebda4d8ffdaeab39262d333caaf7f2bcb287790 -size 1155359 +oid sha256:74a59b92e5682d5455717dc285d9216b08fbb3c725328dd0a4e971ed556925df +size 1195316 diff --git a/pyproject.toml b/pyproject.toml index 0b2019754..7211ca41b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,6 +105,9 @@ scipy = ">=1.15.2,<2" mpmath = "<=1.3.0" nlopt = ">=2.10.0,<3" +[tool.pixi.feature.basic.pypi-dependencies] +ibcdfo = { git = "https://github.com/POptUS/IBCDFO.git", subdirectory = "ibcdfo_pypkg" } + # "dev" dependencies needed for basic CI flake8 = ">=7.3.0,<8" coverage = ">=7.13.0,<8" @@ -204,7 +207,7 @@ tomli = ">=2.2.1,<3" # macOS dependencies [tool.pixi.target.osx-arm64.dependencies] -clang_osx-arm64 = ">=21.1.7,<22" +clang_osx-arm64 = ">=22.1.0,<23" # Linux dependencies [tool.pixi.target.linux-64.dependencies]