From 5608139b706fb65e994d807ff7f335e8596f0233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Mon, 13 Jul 2026 09:58:28 +0200 Subject: [PATCH] Add support for C++26 Remove array comparison deprecated in C++20 and removed in C++26 (P2865R6). Support C++26's new std::to_string implementation. Update runner images, bump C++ compiler toolchains, bump Caliper version, change waLBerla mirror, simplify CI/CD workflows. --- .github/actions/build_and_check/action.yml | 14 ------ .github/workflows/deploy.yml | 2 +- .github/workflows/push_pull.yml | 45 ++++++++++++------- .gitlab-ci.yml | 4 +- CMakeLists.txt | 4 +- .../tests/AutoParameters_test.cpp | 7 ++- testsuite/python/caliper.py | 2 +- testsuite/python/integrator_exceptions.py | 2 +- testsuite/python/lb.py | 6 +-- .../python/reaction_methods_interface.py | 4 +- 10 files changed, 47 insertions(+), 43 deletions(-) delete mode 100644 .github/actions/build_and_check/action.yml diff --git a/.github/actions/build_and_check/action.yml b/.github/actions/build_and_check/action.yml deleted file mode 100644 index a17d9184a0b..00000000000 --- a/.github/actions/build_and_check/action.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: 'Build and check' -description: 'Build espresso and run checks' -runs: - using: "composite" - steps: - - run: | - export myconfig=maxset with_cuda=false with_hdf5=false test_timeout=800 check_skip_long=true - if test -d venv; then . venv/bin/activate; fi - bash maintainer/CI/build_cmake.sh - shell: bash - # This is a workaround for the unfortunate interaction of MacOS and OpenMPI 4 - # See https://github.com/open-mpi/ompi/issues/6518 - env: - OMPI_MCA_btl: "self,tcp" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 40d5ae3af04..fcbb239d459 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,7 +9,7 @@ permissions: jobs: deploy_docs: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 if: ${{ github.repository == 'espressomd/espresso' }} environment: deploy_documentation steps: diff --git a/.github/workflows/push_pull.yml b/.github/workflows/push_pull.yml index 33f2d376fac..b4478330d2c 100644 --- a/.github/workflows/push_pull.yml +++ b/.github/workflows/push_pull.yml @@ -24,13 +24,13 @@ jobs: - name: Install dependencies run: | echo '' > Brewfile - for dep in boost boost-mpi libomp fftw gsl ccache ninja; do echo "brew \"${dep}\"" >> Brewfile; done + for dep in boost boost-mpi libomp fftw gsl ccache ninja hdf5-mpi; do echo "brew \"${dep}\"" >> Brewfile; done brew bundle check >/dev/null 2>&1 || brew bundle --verbose --no-upgrade # set up Xcode compiler echo "::group::List available Xcode compilers" ls /Applications | grep Xcode echo "::endgroup::" - sudo xcode-select -switch /Applications/Xcode_26.2.0.app + sudo xcode-select -switch /Applications/Xcode_26.6.0.app # Python dependencies python -m venv venv . venv/bin/activate @@ -38,21 +38,28 @@ jobs: deactivate shell: bash - name: Build and check - uses: ./.github/actions/build_and_check + run: | + if test -d venv; then . venv/bin/activate; fi + bash maintainer/CI/build_cmake.sh env: build_procs: 3 check_procs: 3 cmake_params: '-D ESPRESSO_TEST_NP=3' + myconfig: 'maxset' with_ccache: 'true' + with_cuda: 'false' + with_hdf5: 'true' with_fftw: 'true' with_gsl: 'true' with_walberla: 'true' with_walberla_avx: 'false' + check_skip_long: 'true' + test_timeout: 800 debian: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 container: - image: ghcr.io/espressomd/docker/debian:ab5bc64f5c3cc7330952f8b3bf321270ca53960c-base-layer + image: ghcr.io/espressomd/docker/debian:c6ad9809eed1d0e9f26f4968559b234ea3b8bf82-base-layer credentials: username: ${{ github.actor }} password: ${{ secrets.github_token }} @@ -70,7 +77,9 @@ jobs: - name: Get runner specifications run: lscpu | egrep 'Model name|Socket|Thread|NUMA|CPU\(s\)' - name: Build and check - uses: ./.github/actions/build_and_check + run: | + if test -d venv; then . venv/bin/activate; fi + bash maintainer/CI/build_cmake.sh env: build_procs: 4 check_procs: 4 @@ -90,10 +99,10 @@ jobs: OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 ubuntu: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 if: ${{ github.repository == 'espressomd/espresso' }} container: - image: ghcr.io/espressomd/docker/ubuntu-wo-dependencies:ab5bc64f5c3cc7330952f8b3bf321270ca53960c-base-layer + image: ghcr.io/espressomd/docker/ubuntu-wo-dependencies:c6ad9809eed1d0e9f26f4968559b234ea3b8bf82-base-layer credentials: username: ${{ github.actor }} password: ${{ secrets.github_token }} @@ -111,12 +120,14 @@ jobs: - name: Get runner specifications run: lscpu | egrep 'Model name|Socket|Thread|NUMA|CPU\(s\)' - name: Build and check - uses: ./.github/actions/build_and_check + run: | + if test -d venv; then . venv/bin/activate; fi + bash maintainer/CI/build_cmake.sh env: build_procs: 4 check_procs: 4 - CC: 'gcc-13' - CXX: 'g++-13' + CC: 'gcc-16' + CXX: 'g++-16' myconfig: 'maxset' with_ccache: 'true' with_cuda: 'false' @@ -132,10 +143,10 @@ jobs: OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 fedora: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 if: ${{ github.repository == 'espressomd/espresso' }} container: - image: ghcr.io/espressomd/docker/fedora:ab5bc64f5c3cc7330952f8b3bf321270ca53960c-base-layer + image: ghcr.io/espressomd/docker/fedora:c6ad9809eed1d0e9f26f4968559b234ea3b8bf82-base-layer credentials: username: ${{ github.actor }} password: ${{ secrets.github_token }} @@ -153,7 +164,9 @@ jobs: - name: Get runner specifications run: lscpu | egrep 'Model name|Socket|Thread|NUMA|CPU\(s\)' - name: Build and check - uses: ./.github/actions/build_and_check + run: | + if test -d venv; then . venv/bin/activate; fi + bash maintainer/CI/build_cmake.sh env: build_procs: 4 check_procs: 4 @@ -170,4 +183,6 @@ jobs: with_walberla: 'true' with_walberla_avx: 'false' with_stokesian_dynamics: 'true' - cmake_params: '-D CMAKE_CXX_STANDARD=23 -D CMAKE_INCLUDE_PATH=/usr/include/mpich-x86_64 -D CMAKE_PREFIX_PATH=/usr/lib64/mpich/lib/ -D ESPRESSO_TEST_NT=1' + check_skip_long: 'true' + test_timeout: 800 + cmake_params: '-D CMAKE_CXX_STANDARD=26 -D CMAKE_INCLUDE_PATH=/usr/include/mpich-x86_64 -D CMAKE_PREFIX_PATH=/usr/lib64/mpich/lib/ -D ESPRESSO_TEST_NT=1' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8959167738a..0f84be3a1d8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: ghcr.io/espressomd/docker/ubuntu:ab5bc64f5c3cc7330952f8b3bf321270ca53960c +image: ghcr.io/espressomd/docker/ubuntu:c6ad9809eed1d0e9f26f4968559b234ea3b8bf82 stages: - prepare @@ -16,7 +16,7 @@ stages: .notification_job_template: ¬ification_job_definition <<: *global_job_definition - image: ghcr.io/espressomd/docker/alpine:ab5bc64f5c3cc7330952f8b3bf321270ca53960c + image: ghcr.io/espressomd/docker/alpine:c6ad9809eed1d0e9f26f4968559b234ea3b8bf82 variables: GET_SOURCES_ATTEMPTS: 3 dependencies: [] diff --git a/CMakeLists.txt b/CMakeLists.txt index 9273456b368..4fb53d1c7ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1035,7 +1035,7 @@ if(ESPRESSO_BUILD_WITH_WALBERLA) # cmake-format: off FetchContent_Declare( walberla - GIT_REPOSITORY https://i10git.cs.fau.de/walberla/walberla.git + GIT_REPOSITORY https://github.com/lssfau/walberla.git GIT_TAG 3247aa73 # v7.2 with patches ) # cmake-format: on @@ -1108,7 +1108,7 @@ if(ESPRESSO_BUILD_WITH_CALIPER) FetchContent_Declare( caliper GIT_REPOSITORY https://github.com/LLNL/Caliper.git - GIT_TAG v2.14.0 + GIT_TAG v2.15.0 ) # cmake-format: on set(CALIPER_OPTION_PREFIX on CACHE BOOL "") diff --git a/src/script_interface/tests/AutoParameters_test.cpp b/src/script_interface/tests/AutoParameters_test.cpp index 7ff21b58aff..468410c376a 100644 --- a/src/script_interface/tests/AutoParameters_test.cpp +++ b/src/script_interface/tests/AutoParameters_test.cpp @@ -22,6 +22,8 @@ #include "script_interface/auto_parameters/AutoParameters.hpp" +#include +#include #include using ScriptInterface::AutoParameters; @@ -34,13 +36,14 @@ struct A : AutoParameters { }; BOOST_AUTO_TEST_CASE(basic) { + using namespace std::literals; A a{0, 42}; auto const ¶meters = a.valid_parameters(); BOOST_CHECK(parameters.size() == 2u); - BOOST_CHECK(std::ranges::find(parameters, "i") != parameters.end()); - BOOST_CHECK(std::ranges::find(parameters, "j") != parameters.end()); + BOOST_CHECK(std::ranges::find(parameters, "i"sv) != parameters.end()); + BOOST_CHECK(std::ranges::find(parameters, "j"sv) != parameters.end()); BOOST_CHECK(0 == std::get(a.get_parameter("i"))); BOOST_CHECK(42 == std::get(a.get_parameter("j"))); diff --git a/testsuite/python/caliper.py b/testsuite/python/caliper.py index f830b422cf5..09068d7830a 100644 --- a/testsuite/python/caliper.py +++ b/testsuite/python/caliper.py @@ -73,7 +73,7 @@ def test_runtime_report(self): if not line.startswith("WARNING:"): lines = lines[i:] break - header = "Path\tMin time/rank\tMax time/rank\tAvg time/rank\tTime %" + header = "Path\tMin time/rank\tAvg time/rank\tMax time/rank\tTime %" self.assertEqual(lines[0].split(), header.split(), msg=f"Caliper summary should start with '{header}'") labels = [line[:36].rstrip() for line in lines[1:]] diff --git a/testsuite/python/integrator_exceptions.py b/testsuite/python/integrator_exceptions.py index a7a99745529..6d523cf4d02 100644 --- a/testsuite/python/integrator_exceptions.py +++ b/testsuite/python/integrator_exceptions.py @@ -273,7 +273,7 @@ def test_temperature_change(self): self.system.thermostat.set_langevin(kT=1., gamma=1., seed=42) self.system.thermostat.set_langevin(kT=2., gamma=1., seed=42) self.system.thermostat.set_brownian(kT=2., gamma=1., seed=42) - with self.assertRaisesRegex(RuntimeError, "Cannot set parameter 'kT' to 1.0*: there are currently active thermostats with kT=2.0*"): + with self.assertRaisesRegex(RuntimeError, "Cannot set parameter 'kT' to 1[.0]*: there are currently active thermostats with kT=2[.0]*"): self.system.thermostat.set_brownian(kT=1., gamma=1., seed=42) with self.assertRaisesRegex(RuntimeError, f"Parameter 'kT' is read-only"): self.system.thermostat.kT = 2. diff --git a/testsuite/python/lb.py b/testsuite/python/lb.py index 9a2378913cc..855640e1d09 100644 --- a/testsuite/python/lb.py +++ b/testsuite/python/lb.py @@ -508,7 +508,7 @@ def test_temperature_mismatch(self): self.system.thermostat.set_langevin(kT=2., seed=23, gamma=2.) lbf = self.lb_class(kT=1., seed=42, **self.params, **self.lb_params) self.system.lb = lbf - with self.assertRaisesRegex(RuntimeError, "Cannot set parameter 'kT' to 1.0*: there are currently active thermostats with kT=2.0*"): + with self.assertRaisesRegex(RuntimeError, r"Cannot set parameter 'kT' to (1[.0]*|0\.99[0-9]+): there are currently active thermostats with kT=(2[.0]*|1\.99[0-9]+)"): self.system.thermostat.set_lb(LB_fluid=lbf, seed=23, gamma=2.) self.assertFalse(self.system.thermostat.lb.is_active) self.assertTrue(self.system.thermostat.langevin.is_active) @@ -869,9 +869,9 @@ def params_with_tau(tau): self.lb_class(**params_with_tau(self.system.time_step), **self.lb_params) - with self.assertRaisesRegex(ValueError, r"LB tau \(0\.0100[0-9]+\) must be >= MD time_step \(0\.0200[0-9]+\)"): + with self.assertRaisesRegex(ValueError, r"LB tau \(0\.01(?:0*|00[0-9]+)\) must be >= MD time_step \(0\.02(?:0*|00[0-9]+)\)"): self.system.time_step = 2.0 * lbf.get_params()["tau"] - with self.assertRaisesRegex(ValueError, r"LB tau \(0\.0100[0-9]+\) must be an integer multiple of the MD time_step \(0\.0080[0-9]+\)"): + with self.assertRaisesRegex(ValueError, r"LB tau \(0\.01(?:0*|00[0-9]+)\) must be an integer multiple of the MD time_step \(0\.008(?:0*|0[0-9]+)\)"): self.system.time_step = 0.8 * lbf.get_params()["tau"] self.system.lb = None diff --git a/testsuite/python/reaction_methods_interface.py b/testsuite/python/reaction_methods_interface.py index 7eb5169cd63..d45f8017792 100644 --- a/testsuite/python/reaction_methods_interface.py +++ b/testsuite/python/reaction_methods_interface.py @@ -349,7 +349,7 @@ def test_exceptions(self): with self.assertRaisesRegex(ValueError, "Invalid value for 'exclusion_range'"): espressomd.reaction_methods.ReactionEnsemble( kT=1., seed=12, exclusion_range=-1.) - with self.assertRaisesRegex(ValueError, "Invalid excluded_radius value for type 1: radius -0.10"): + with self.assertRaisesRegex(ValueError, r"Invalid excluded_radius value for type 1: radius -0\.1[0]*"): espressomd.reaction_methods.ReactionEnsemble( kT=1., seed=12, exclusion_range=1., exclusion_radius_per_type={1: -0.1}) with self.assertRaisesRegex(ValueError, "Unknown search algorithm 'unknown'"): @@ -357,7 +357,7 @@ def test_exceptions(self): kT=1., seed=12, exclusion_range=1., search_algorithm="unknown") method = espressomd.reaction_methods.ReactionEnsemble( kT=1., exclusion_range=1., seed=12, exclusion_radius_per_type={1: 0.1}) - with self.assertRaisesRegex(ValueError, "Invalid excluded_radius value for type 2: radius -0.10"): + with self.assertRaisesRegex(ValueError, r"Invalid excluded_radius value for type 2: radius -0\.1[0]*"): method.exclusion_radius_per_type = {2: -0.1} self.assertEqual(list(method.exclusion_radius_per_type.keys()), [1])