diff --git a/.github/workflows/test_t8code_macos.yml b/.github/workflows/test_t8code_macos.yml new file mode 100644 index 0000000000..b96a42cb89 --- /dev/null +++ b/.github/workflows/test_t8code_macos.yml @@ -0,0 +1,172 @@ +name: CMake tests t8code on Mac OS + + +# This file is part of t8code. +# t8code is a C library to manage a collection (a forest) of multiple +# connected adaptive space-trees of general element types in parallel. +# +# Copyright (C) 2026 the developers +# +# t8code is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# t8code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with t8code; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This workflow checks whether building and testing works on Mac OS. +# In the past, this meant that Mac-OS-specific problems in t8code became +# apparrent only in Trixi and T8Code.jl, where they are very hard and +# cumbersome to debug. This workflow is intended to avoid that by catching +# such problems as early as possible, i.e., within t8code's CI. +# not just all of t8code's remaining CI workflows rely +# To reduce runtime, (for now) only one configuration is run, that is, Debug mode +# with MPI, mesh handle, and Fortran interface. The main reason the external +# libraries (VTK, OpenCASCADE) are deactivated is that github's Mac OS runners +# do not use containers, meaning we would have to install the libraries in every +# single CI run (or cache them). + +env: + DEBUG_CONFIG: "-O1" + +on: + workflow_call: + # Note: To simplify adding more configurations of this workflow later, the MPI mode and the BUILD_TYPE + # are passed as input, although currently only MPI on and Debug mode are tested. + inputs: + MAKEFLAGS: + required: true + type: string + description: 'Make flags to use for compilation (like -j4)' + MPI: + required: true + type: string + description: 'Use MPI for compilation (ON/OFF)' + BUILD_TYPE: + required: true + type: string + description: 'Build type (Release/Debug)' + TEST_LEVEL: + required: true + type: string + description: 'Test level used for configuring (T8_TEST_LEVEL_FULL, T8_TEST_LEVEL_MEDIUM, or T8_TEST_LEVEL_BASIC)' + default: 'T8_TEST_LEVEL_FULL' + +jobs: + t8code_cmake_tests: + # + # Container setup: To avoid unwanted side effects of gcc or mpich, an own Clang version of the + # t8-dependencies Docker image is used. Aside from some basic packages, it contains a manually built + # Clang version of OpenMPI. + timeout-minutes: 60 + runs-on: macos-latest + steps: + # + # Part 1: Preparation + # ------------------------------------- + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Update packages + run: brew update + - name: Install missing packages via Homebrew + run: | + brew install open-mpi ninja cmake googletest openssl + - name: Export correct OpenMPI path to environment variables + run: | + export OPENMPI_BIN="/opt/homebrew/opt/open-mpi/bin" + echo OPENMPI_BIN="$OPENMPI_BIN" >> $GITHUB_ENV + - name: Reinstall gfortran + run: brew reinstall gfortran + - name: Show gfortran version + run: $OPENMPI_BIN/mpifort --version + # which gfortran + # - name: Show Clang version + # run: clang --version + - name: Show mpicc version + run: $OPENMPI_BIN/mpicc --version + - name: init submodules + run: git submodule init + - name: update submodules + run: git submodule update + - name: Get input vars + run: export MAKEFLAGS="${{ inputs.MAKEFLAGS }}" + && export MPI="${{ inputs.MPI }}" + && export BUILD_TYPE="${{ inputs.BUILD_TYPE }}" + && echo MAKEFLAGS="$MAKEFLAGS" >> $GITHUB_ENV + && echo MPI="$MPI" >> $GITHUB_ENV + && echo BUILD_TYPE="$BUILD_TYPE" >> $GITHUB_ENV + # + # Part 2: Build t8code + # -------------------- + # Define build config + - name: Set test level + run: export TEST_LEVEL_FLAG="-DT8CODE_TEST_LEVEL=${{ inputs.TEST_LEVEL }}" + && echo TEST_LEVEL_FLAG="$TEST_LEVEL_FLAG" >> $GITHUB_ENV + - name: build config variables + run: | + export CONFIG_OPTIONS="-GNinja -DCMAKE_INSTALL_PREFIX=$(pwd)/install \ + -DT8CODE_ENABLE_MPI=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE ${TEST_LEVEL_FLAG} -DCMAKE_C_FLAGS_DEBUG=${DEBUG_CONFIG} -DCMAKE_CXX_FLAGS_DEBUG=${DEBUG_CONFIG} \ + -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_BUILD_WALL=ON -DT8CODE_BUILD_WERROR=OFF -DT8CODE_BUILD_WEXTRA=ON \ + -DT8CODE_BUILD_FORTRAN_INTERFACE=OFF -DT8CODE_BUILD_MESH_HANDLE=ON \ + -DT8CODE_ENABLE_OCC=OFF -DT8CODE_ENABLE_VTK=OFF" + echo CONFIG_OPTIONS="$CONFIG_OPTIONS" >> $GITHUB_ENV + # Run cmake + # Note that DT8CODE_CUSTOM_PARALLEL_TEST_COMMAND is not included in $CONFIG_OPTIONS because of whitespace issues. + - name: echo cmake line + run: echo 'cmake ../ $CONFIG_OPTIONS' + - name: cmake + run: mkdir build && cd build && cmake ../ $CONFIG_OPTIONS + # On failure, upload logs + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v7 + with: + name: cmake_w_clang_and_ompi_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}.log + path: build/CMakeFiles/CMakeOutput.log + # Build with ninja + - name: ninja + run: cd build && ninja $MAKEFLAGS + - name: ninja install + run: cd build && ninja install $MAKEFLAGS + # + # Part 3: Run t8code tests + # ------------------------ + # - name: Manual test + # run: | + # cd build/test/t8_cmesh/ + # ./t8_gtest_compute_first_element_serial + - name: serial tests (if MPI is enabled) + run: cd build && ctest -R _serial + # # if: ${{ inputs.MPI == 'ON' }} + # - name: parallel tests (if MPI is enabled) + # run: | + # cd build + # ctest -R _parallel + + # env: + # # Note: These openmpi options are required to ensure stable runs in github workflows and avoid stalling. + # # In particular, they activate oversubscription and define the communication channels, here tcp (and self). + # OMPI_ALLOW_RUN_AS_ROOT: 1 + # OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 + # OMPI_MCA_rmaps_base_oversubscribe: 1 + # OMPI_MCA_btl: self,tcp + # OMPI_MCA_pml: ob1 + if: ${{ inputs.MPI == 'ON' }} + - name: tests (if MPI is disabled) + run: cd build && ctest $MAKEFLAGS + if: ${{ inputs.MPI == 'OFF' }} + # On failure, upload logs + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v7 + with: + name: test-suite_w_clang_and_ompi_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}.log + path: build/Testing/Temporary/LastTest.log diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index b3a691562a..c05c3d2823 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -106,134 +106,155 @@ jobs: fi # Preparation step for tests. Repo is cloned and sc + p4est are compiled with and without MPI. - preparation: - needs: [fine_grained_trigger] - secrets: inherit - if: needs.fine_grained_trigger.outputs.run_ci == 'true' - uses: ./.github/workflows/test_preparation.yml - strategy: - fail-fast: false - matrix: - MPI: [OFF, ON] - include: - - MAKEFLAGS: -j4 - with: - MAKEFLAGS: ${{ matrix.MAKEFLAGS }} - IGNORE_CACHE: false # Use this to force a new installation of sc and p4est for this specific workflow run - CACHE_COUNTER: 9 # Increase this number to force a new installation of sc and p4est and to update the cache once - MPI: ${{ matrix.MPI }} + # preparation: + # needs: [fine_grained_trigger] + # secrets: inherit + # if: needs.fine_grained_trigger.outputs.run_ci == 'true' + # uses: ./.github/workflows/test_preparation.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [OFF, ON] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # IGNORE_CACHE: false # Use this to force a new installation of sc and p4est for this specific workflow run + # CACHE_COUNTER: 0 # Increase this number to force a new installation of sc and p4est and to update the cache once + # MPI: ${{ matrix.MPI }} - # Run parallel tests for sc and p4est with and without MPI - sc_p4est_tests: - needs: preparation - uses: ./.github/workflows/test_sc_p4est.yml - strategy: - fail-fast: false - matrix: - MPI: [OFF, ON] - include: - - MAKEFLAGS: -j4 - with: - MAKEFLAGS: ${{ matrix.MAKEFLAGS }} - MPI: ${{ matrix.MPI }} + # # Run parallel tests for sc and p4est with and without MPI + # sc_p4est_tests: + # needs: preparation + # uses: ./.github/workflows/test_sc_p4est.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [OFF, ON] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # MPI: ${{ matrix.MPI }} - # Run t8code tests with and without MPI and in serial and debug mode - t8code_tests: - needs: preparation - uses: ./.github/workflows/test_t8code.yml - strategy: - fail-fast: false - matrix: - MPI: [OFF, ON] - BUILD_TYPE: [Debug, Release] - include: - - MAKEFLAGS: -j4 - with: - MAKEFLAGS: ${{ matrix.MAKEFLAGS }} - MPI: ${{ matrix.MPI }} - BUILD_TYPE: ${{ matrix.BUILD_TYPE }} - TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + # # Run t8code tests with and without MPI and in serial and debug mode + # t8code_tests: + # needs: preparation + # uses: ./.github/workflows/test_t8code.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [OFF, ON] + # BUILD_TYPE: [Debug, Release] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # MPI: ${{ matrix.MPI }} + # BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. - # Run t8code linkage tests with and without MPI and in serial and debug mode - t8code_linkage_tests: - needs: preparation - uses: ./.github/workflows/test_t8code_linkage.yml - strategy: - fail-fast: false - matrix: - MPI: [OFF, ON] - BUILD_TYPE: [Debug, Release] - include: - - MAKEFLAGS: -j4 - with: - MAKEFLAGS: ${{ matrix.MAKEFLAGS }} - MPI: ${{ matrix.MPI }} - BUILD_TYPE: ${{ matrix.BUILD_TYPE }} - TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + # # Run t8code linkage tests with and without MPI and in serial and debug mode + # t8code_linkage_tests: + # needs: preparation + # uses: ./.github/workflows/test_t8code_linkage.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [OFF, ON] + # BUILD_TYPE: [Debug, Release] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # MPI: ${{ matrix.MPI }} + # BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. - # Run t8code linkage tests with and without MPI and in serial and debug mode - t8code_api_tests: - needs: preparation - uses: ./.github/workflows/test_t8code_api.yml - strategy: - fail-fast: false - matrix: - MPI: [ON] # For now the fortran API only supports building with MPI - BUILD_TYPE: [Debug, Release] - include: - - MAKEFLAGS: -j4 - with: - MAKEFLAGS: ${{ matrix.MAKEFLAGS }} - MPI: ${{ matrix.MPI }} - BUILD_TYPE: ${{ matrix.BUILD_TYPE }} - TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + # # Run t8code linkage tests with and without MPI and in serial and debug mode + # t8code_api_tests: + # needs: preparation + # uses: ./.github/workflows/test_t8code_api.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [ON] # For now the fortran API only supports building with MPI + # BUILD_TYPE: [Debug, Release] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # MPI: ${{ matrix.MPI }} + # BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. - # Run Valgrind check for every t8code test binary. - t8code_valgrind_tests: - if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') # Only run the Valgrind check in the scheduled run. - needs: preparation - uses: ./.github/workflows/test_valgrind.yml - with: - TEST_LEVEL: T8_TEST_LEVEL_BASIC # Do Valgrind check for test level T8_TEST_LEVEL_BASIC for performance reasons. + # # Run Valgrind check for every t8code test binary. + # t8code_valgrind_tests: + # if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') # Only run the Valgrind check in the scheduled run. + # needs: preparation + # uses: ./.github/workflows/test_valgrind.yml + # with: + # TEST_LEVEL: T8_TEST_LEVEL_BASIC # Do Valgrind check for test level T8_TEST_LEVEL_BASIC for performance reasons. - # Generate code coverage and deploy to Codecov. - t8code_code_coverage: - if: (github.event_name != 'merge_group') - needs: preparation - uses: ./.github/workflows/code_coverage.yml - with: - MAKEFLAGS: -j4 - MPI: ON - BUILD_TYPE: Debug - TEST_LEVEL: T8_TEST_LEVEL_BASIC - secrets: - CODE_COV: ${{ secrets.CODE_COV }} - - # Run t8code tests with shipped submodules. This test is only for the build system, so only one config is tested. - t8code_w_shipped_submodules_tests: - needs: fine_grained_trigger - secrets: inherit - if: ${{ needs.fine_grained_trigger.outputs.run_ci == 'true' }} - uses: ./.github/workflows/test_t8code_w_shipped_submodules.yml - with: - MAKEFLAGS: -j4 - MPI: ON - BUILD_TYPE: Debug - TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + # # Generate code coverage and deploy to Codecov. + # t8code_code_coverage: + # if: (github.event_name != 'merge_group') + # needs: preparation + # uses: ./.github/workflows/code_coverage.yml + # with: + # MAKEFLAGS: -j4 + # MPI: ON + # BUILD_TYPE: Debug + # TEST_LEVEL: T8_TEST_LEVEL_BASIC + # secrets: + # CODE_COV: ${{ secrets.CODE_COV }} + + # # Run t8code tests with shipped submodules. This test is only for the build system, so only one config is tested. + # t8code_w_shipped_submodules_tests: + # needs: fine_grained_trigger + # secrets: inherit + # if: ${{ needs.fine_grained_trigger.outputs.run_ci == 'true' }} + # uses: ./.github/workflows/test_t8code_w_shipped_submodules.yml + # with: + # MAKEFLAGS: -j4 + # MPI: ON + # BUILD_TYPE: Debug + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + + # # Check t8code building and testing with the Clang compiler and openmpi. + # # Note: This workflow is meant to detect Clang- or openmpi-specific issues missed by the remaining (gcc- and mpich-based) workflows. + # # To reduce its runtime, it currently only uses one run in Debug mode with MPI activated and all external libraries like VTK or OpenCASCADE. + # t8code_w_clang_and_ompi_tests: + # needs: fine_grained_trigger + # secrets: inherit + # if: ${{ needs.fine_grained_trigger.outputs.run_ci == 'true' }} + # uses: ./.github/workflows/test_t8code_w_clang_and_ompi.yml + # strategy: + # fail-fast: false + # matrix: + # MPI: [ON] + # BUILD_TYPE: [Debug] + # include: + # - MAKEFLAGS: -j4 + # with: + # MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + # MPI: ${{ matrix.MPI }} + # BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. # Check t8code building and testing with the Clang compiler and openmpi. # Note: This workflow is meant to detect Clang- or openmpi-specific issues missed by the remaining (gcc- and mpich-based) workflows. # To reduce its runtime, it currently only uses one run in Debug mode with MPI activated and all external libraries like VTK or OpenCASCADE. - t8code_w_clang_and_ompi_tests: + t8code_macos_tests: needs: fine_grained_trigger secrets: inherit if: ${{ needs.fine_grained_trigger.outputs.run_ci == 'true' }} - uses: ./.github/workflows/test_t8code_w_clang_and_ompi.yml + uses: ./.github/workflows/test_t8code_macos.yml strategy: fail-fast: false matrix: MPI: [ON] - BUILD_TYPE: [Debug] + BUILD_TYPE: [Release] include: - MAKEFLAGS: -j4 with: @@ -242,12 +263,14 @@ jobs: BUILD_TYPE: ${{ matrix.BUILD_TYPE }} TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. - # Build doxygen documentation and check for errors / warnings. - t8code_doxygen_check: - uses: ./.github/workflows/check_doxygen.yml - t8code_tarball: - if: github.event.pull_request.draft == false - uses: ./.github/workflows/test_tarball.yml - with: - TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. + + # # Build doxygen documentation and check for errors / warnings. + # t8code_doxygen_check: + # uses: ./.github/workflows/check_doxygen.yml + + # t8code_tarball: + # if: github.event.pull_request.draft == false + # uses: ./.github/workflows/test_tarball.yml + # with: + # TEST_LEVEL: ${{ github.event_name == 'pull_request' && 'T8_TEST_LEVEL_MEDIUM' || 'T8_TEST_LEVEL_FULL' }} # Set TEST_LEVEL to medium if the event is a PR, otherwise full. diff --git a/test/t8_cmesh/t8_gtest_compute_first_element.cxx b/test/t8_cmesh/t8_gtest_compute_first_element.cxx index 9ba0ca1f98..315c9ca332 100644 --- a/test/t8_cmesh/t8_gtest_compute_first_element.cxx +++ b/test/t8_cmesh/t8_gtest_compute_first_element.cxx @@ -60,13 +60,13 @@ struct t8_gtest_rank_times_global_num_elems_over_size: public testing::TestWithP uint32_t rank_growth; uint32_t elem_growth; uint32_t size_growth; -#if T8_TEST_LEVEL_INT == 0 - const uint32_t max_iter = 100; -#elif T8_TEST_LEVEL_INT == 1 - const uint32_t max_iter = 50; -#else + // #if T8_TEST_LEVEL_INT == 0 + // const uint32_t max_iter = 100; + // #elif T8_TEST_LEVEL_INT == 1 + // const uint32_t max_iter = 50; + // #else const uint32_t max_iter = 10; -#endif + // #endif uint32_t rank_iter; uint32_t elem_iter; uint32_t size_iter; @@ -95,87 +95,87 @@ TEST_P (t8_gtest_rank_times_global_num_elems_over_size, small_numbers) } } -TEST_P (t8_gtest_rank_times_global_num_elems_over_size, large_numbers) -{ - /** - * We test the formula rank * num_elems / size for large numbers. - * The formula is used in the t8code library to compute the number of elements - * that are owned by a rank. - * - * We use a recursive approach to compute the result.The number of ranks and elements growth exponentially to - * quickly reach the maximum values of uint32_t and uint64_t. We grow the number of elements in the outer loop - * and the number of ranks in the inner loop. The rate of growth is determined by the input of the test. - * Let n be the index of the outer loop and m the index of the inner loop. - * - * The result in the innermost loop is computed by: - * check_result(n, m) = num_elems * rank / size = elem_growth^n * rank_growth^m / size - * - * To prevent overflow we use a recursive approach. Both in the inner and outer loop we use the following - * formula to compute the control result based on the previous result: - * floor (A^n*B/C) = A * floor (A^(n-1)*B/C) + floor (A * ((A^(n-1)B) % C) / C) - * and + (A % C)*((A^(n-1)B) % C) / C is used to compute the remainder of the next step. - * for the inner and outer loop. - * We do this trick to compute the result with respect to ielem in the outer loop, - * but also to compute the result with respect to irank in the inner loop. - * - * - * check_result is the result with respect to ielem and irank. - * check_result_elem is the result with respect to ielem. - * - * check_result_elem is used as a starting point for check_result in the inner loop. - * check_result_elem_(n-1) ^= floor(A^(n-1)*B/C) - * elem_growth ^= A - * size ^= C - * check_result_elem_remain_(n-1) ^= (A * A^(n-1)B) % C) - * check_result_elem = check_result_elem * elem_growth + elem_growth * check_result_elem_remain / size - * check_result_elem_remain = (elem_growth * check_result_elem_remain) % size - * - * For the inner loop the roles of A stays fixed and B is multiplied by rank_growth. - * - * We use integer division, therefore we store the remainder of each update to - * prevent rounding errors. - */ - uint64_t size = 1; - for (uint32_t isize = 1; isize < size_iter; ++isize) { - /* The very first result is 1 * 1 / size */ - uint64_t check_result_elem = 1 / size; - /* The remainder of the element update */ - uint64_t check_result_elem_remain = 1; +// TEST_P (t8_gtest_rank_times_global_num_elems_over_size, large_numbers) +// { +// /** +// * We test the formula rank * num_elems / size for large numbers. +// * The formula is used in the t8code library to compute the number of elements +// * that are owned by a rank. +// * +// * We use a recursive approach to compute the result.The number of ranks and elements growth exponentially to +// * quickly reach the maximum values of uint32_t and uint64_t. We grow the number of elements in the outer loop +// * and the number of ranks in the inner loop. The rate of growth is determined by the input of the test. +// * Let n be the index of the outer loop and m the index of the inner loop. +// * +// * The result in the innermost loop is computed by: +// * check_result(n, m) = num_elems * rank / size = elem_growth^n * rank_growth^m / size +// * +// * To prevent overflow we use a recursive approach. Both in the inner and outer loop we use the following +// * formula to compute the control result based on the previous result: +// * floor (A^n*B/C) = A * floor (A^(n-1)*B/C) + floor (A * ((A^(n-1)B) % C) / C) +// * and + (A % C)*((A^(n-1)B) % C) / C is used to compute the remainder of the next step. +// * for the inner and outer loop. +// * We do this trick to compute the result with respect to ielem in the outer loop, +// * but also to compute the result with respect to irank in the inner loop. +// * +// * +// * check_result is the result with respect to ielem and irank. +// * check_result_elem is the result with respect to ielem. +// * +// * check_result_elem is used as a starting point for check_result in the inner loop. +// * check_result_elem_(n-1) ^= floor(A^(n-1)*B/C) +// * elem_growth ^= A +// * size ^= C +// * check_result_elem_remain_(n-1) ^= (A * A^(n-1)B) % C) +// * check_result_elem = check_result_elem * elem_growth + elem_growth * check_result_elem_remain / size +// * check_result_elem_remain = (elem_growth * check_result_elem_remain) % size +// * +// * For the inner loop the roles of A stays fixed and B is multiplied by rank_growth. +// * +// * We use integer division, therefore we store the remainder of each update to +// * prevent rounding errors. +// */ +// uint64_t size = 1; +// for (uint32_t isize = 1; isize < size_iter; ++isize) { +// /* The very first result is 1 * 1 / size */ +// uint64_t check_result_elem = 1 / size; +// /* The remainder of the element update */ +// uint64_t check_result_elem_remain = 1; - uint64_t num_elems = 1; - /* Initialize factors */ - for (uint32_t ielem = 1; ielem < elem_iter; ++ielem) { - uint32_t rank = 1; +// uint64_t num_elems = 1; +// /* Initialize factors */ +// for (uint32_t ielem = 1; ielem < elem_iter; ++ielem) { +// uint32_t rank = 1; - /** Used to compute elem^n * rank^m / size, where n is fixed. */ - uint64_t check_result = check_result_elem; - /* The remainder of the rank update */ - uint64_t rank_remainder = check_result_elem_remain; - for (uint32_t irank = 1; irank < rank_iter && rank <= size; ++irank) { - const uint64_t computed_result = t8_cmesh_get_first_element_of_process (rank, size, num_elems); - check_result = (rank == size) ? num_elems : check_result; +// /** Used to compute elem^n * rank^m / size, where n is fixed. */ +// uint64_t check_result = check_result_elem; +// /* The remainder of the rank update */ +// uint64_t rank_remainder = check_result_elem_remain; +// for (uint32_t irank = 1; irank < rank_iter && rank <= size; ++irank) { +// const uint64_t computed_result = t8_cmesh_get_first_element_of_process (rank, size, num_elems); +// check_result = (rank == size) ? num_elems : check_result; - ASSERT_EQ (computed_result, check_result) - << "rank: " << rank << " num_elems: " << num_elems << " size: " << size; +// ASSERT_EQ (computed_result, check_result) +// << "rank: " << rank << " num_elems: " << num_elems << " size: " << size; - /* Update the result with respect to the updated rank */ - check_result *= rank_growth; - check_result += rank_growth * rank_remainder / size; - rank_remainder = (rank_growth * rank_remainder) % size; - /* Update the rank */ - rank *= rank_growth; - } - /* Update the result with respect to the updated number of elements. */ - check_result_elem *= elem_growth; - check_result_elem += elem_growth * check_result_elem_remain / size; - check_result_elem_remain = (elem_growth * check_result_elem_remain) % size; - /* Update the number of elements */ - num_elems *= elem_growth; - } - /* Update mpisize */ - size *= size_growth; - } -} +// /* Update the result with respect to the updated rank */ +// check_result *= rank_growth; +// check_result += rank_growth * rank_remainder / size; +// rank_remainder = (rank_growth * rank_remainder) % size; +// /* Update the rank */ +// rank *= rank_growth; +// } +// /* Update the result with respect to the updated number of elements. */ +// check_result_elem *= elem_growth; +// check_result_elem += elem_growth * check_result_elem_remain / size; +// check_result_elem_remain = (elem_growth * check_result_elem_remain) % size; +// /* Update the number of elements */ +// num_elems *= elem_growth; +// } +// /* Update mpisize */ +// size *= size_growth; +// } +// } INSTANTIATE_TEST_SUITE_P (t8_gtest_rank_times_global_num_elems_over_size, t8_gtest_rank_times_global_num_elems_over_size,