diff --git a/.github/workflows/add_release_documentation.yml b/.github/workflows/add_release_documentation.yml index fcf9326d7d..be9fd17f94 100644 --- a/.github/workflows/add_release_documentation.yml +++ b/.github/workflows/add_release_documentation.yml @@ -146,7 +146,7 @@ jobs: ./generate_redirections.sh $GITHUB_REF_NAME - name: Create Pull Request at DLR-AMR/t8code-website if: ${{ env.MINOR_RELEASE == 'true' }} - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: path: t8code-website title: Add documentation for t8code ${{ github.ref_name }} diff --git a/.github/workflows/tests_cmake_preparation.yml b/.github/workflows/tests_cmake_preparation.yml new file mode 100644 index 0000000000..4325e59f35 --- /dev/null +++ b/.github/workflows/tests_cmake_preparation.yml @@ -0,0 +1,196 @@ +name: CMake tests preparation + + +# 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) 2024 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. + +on: + workflow_call: + inputs: + MAKEFLAGS: + required: true + type: string + description: 'Make flags to use for compilation (like -j4)' + IGNORE_CACHE: + required: false + type: boolean + default: false + description: 'Ignore cache and force recompilation' + CACHE_COUNTER: + required: true + type: number + description: 'Counter to force updating the cache' + MPI: + required: true + type: string + description: 'Use MPI for compilation (ON/OFF)' + outputs: + USED_CACHE: + description: "Whether the cache was used" + value: ${{ jobs.cmake_preparation.outputs.USED_CACHE }} + +env: + USED_CACHE: ${{ !inputs.IGNORE_CACHE }} + +jobs: + cmake_preparation: + runs-on: ubuntu-latest + container: dlramr/t8code-ubuntu:t8-dependencies + timeout-minutes: 10 + outputs: + USED_CACHE: ${{ steps.used_cache.outputs.USED_CACHE }} + steps: +# +# Setup +# + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Update packages + run: apt-get update && apt-get upgrade -y + # This seems to be necessary because of the docker container + - name: disable ownership checks + run: git config --global --add safe.directory '*' + - name: init submodules + run: git submodule init + - name: update submodules + run: git submodule update + - name: Get input vars + run: export MAKEFLAGS="${{ inputs.MAKEFLAGS }}" + && export IGNORE_CACHE="${{ inputs.IGNORE_CACHE }}" + && export CACHE_COUNTER="${{ inputs.CACHE_COUNTER }}" + && export MPI="${{ inputs.MPI }}" + && echo MAKEFLAGS="$MAKEFLAGS" >> $GITHUB_ENV + && echo IGNORE_CACHE="$IGNORE_CACHE" >> $GITHUB_ENV + && echo CACHE_COUNTER="$CACHE_COUNTER" >> $GITHUB_ENV + && echo MPI="$MPI" >> $GITHUB_ENV +# +# SC installation +# + - name: store sc folders in var + run: echo SC_BUILD=$PWD/sc/build >> $GITHUB_ENV + && echo SC_DEBUG=$PWD/sc/build/Debug >> $GITHUB_ENV + && echo SC_RELEASE=$PWD/sc/build/Release >> $GITHUB_ENV + - name: Get sc commit hash + run: hash=`git rev-parse HEAD:sc` && echo sc_commit=$hash >> $GITHUB_ENV + - name: Check cache for previous sc installation + id: sc_cmake_cache + uses: actions/cache@v4 + with: + path: | + ${{ env.SC_DEBUG }} + ${{ env.SC_RELEASE }} + # You can increase the counter at the end to force a new key and hence recomputing the cache + key: sc-cmake-MPI-${{ inputs.MPI }}-${{ env.sc_commit }}-${{ inputs.CACHE_COUNTER }} + - name: Log that no cache was found + run: echo USED_CACHE=0 >> $GITHUB_ENV + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' }} + - name: Cache info + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + run: echo No cache found or cache will be ignored. IGNORE_CACHE=$IGNORE_CACHE + - name: if ignore cache, delete folders + if: ${{ inputs.IGNORE_CACHE == 1 }} + # The true at the end is to ignore errors that i.e. occur when the folders do not exist + run: rm -r $SC_BUILD || true + - name: make folders + run: mkdir -p $SC_DEBUG $SC_RELEASE + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: install sc + run: echo "Install sc" + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + ## sc debug + - name: sc cmake debug + run: cd $SC_DEBUG && cmake ../../ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$SC_DEBUG/install -Dmpi=$MPI -GNinja + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: sc build debug + run: cd $SC_DEBUG && ninja $MAKEFLAGS && ninja $MAKEFLAGS install + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + ## sc release + - name: sc cmake release + run: cd $SC_RELEASE && cmake ../../ -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$SC_RELEASE/install -Dmpi=$MPI -GNinja + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: sc build release + run: cd $SC_RELEASE && ninja $MAKEFLAGS && ninja $MAKEFLAGS install + if: ${{ steps.sc_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} +# +# P4EST +# + - name: store p4est folders in var + run: echo P4EST_BUILD=$PWD/p4est/build >> $GITHUB_ENV + && echo P4EST_DEBUG=$PWD/p4est/build/Debug >> $GITHUB_ENV + && echo P4EST_RELEASE=$PWD/p4est/build/Release >> $GITHUB_ENV + - name: Get p4est commit hash + run: hash=`git rev-parse HEAD:p4est` && echo p4est_commit=$hash >> $GITHUB_ENV + - name: Check cache for previous p4est installation + id: p4est_cmake_cache + uses: actions/cache@v4 + with: + path: | + ${{ env.P4EST_DEBUG }} + ${{ env.P4EST_RELEASE }} + # You can increase the counter at the end to force a new key and hence recomputing the cache + key: p4est-cmake-MPI-${{ inputs.MPI }}-${{ env.p4est_commit }}-${{ env.sc_commit }}-${{ inputs.CACHE_COUNTER }} + - name: Log that no cache was found + run: echo USED_CACHE=0 >> $GITHUB_ENV + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' }} + - name: Cache info + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + run: echo No cache found or cache will be ignored. IGNORE_CACHE=$IGNORE_CACHE + - name: install p4est + run: echo "Install p4est" + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: if ignore cache, delete folders + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + # The true at the end is to ignore errors that i.e. occur when the folders do not exist + run: rm -r $P4EST_BUILD || true + - name: make folders + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + run: mkdir -p $P4EST_DEBUG $P4EST_RELEASE + ## p4est debug + - name: p4est cmake debug + run: cd $P4EST_DEBUG && cmake ../../ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$P4EST_DEBUG/install -DP4EST_USE_SYSTEM_SC=ON -DSC_DIR=$SC_DEBUG/install/cmake -DP4EST_ENABLE_MPI=$MPI -GNinja + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: p4est build debug + run: cd $P4EST_DEBUG && ninja $MAKEFLAGS && ninja $MAKEFLAGS install + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + ## p4est release + - name: p4est cmake release + run: cd $P4EST_RELEASE && cmake ../../ -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$P4EST_RELEASE/install -DP4EST_USE_SYSTEM_SC=ON -DSC_DIR=$SC_DEBUG/install/cmake -DP4EST_ENABLE_MPI=$MPI -GNinja + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + - name: p4est build release + run: cd $P4EST_RELEASE && ninja $MAKEFLAGS && ninja $MAKEFLAGS install + if: ${{ steps.p4est_cmake_cache.outputs.cache-hit != 'true' || inputs.IGNORE_CACHE == 1 }} + + ## output cache info + - name: output cache info + id: used_cache + run: echo "USED_CACHE=$USED_CACHE" >> $GITHUB_OUTPUT + + ## tar artifact to keep permissions: https://github.com/actions/upload-artifact?tab=readme-ov-file#permission-loss + - name: Tar files + run: tar -cvf artifact.tar . + + ## upload artifacts + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: SC_P4EST_MPI_${{ inputs.MPI }} + path: ./artifact.tar + retention-days: 1 diff --git a/.github/workflows/tests_cmake_sc_p4est.yml b/.github/workflows/tests_cmake_sc_p4est.yml new file mode 100644 index 0000000000..15efd0db5b --- /dev/null +++ b/.github/workflows/tests_cmake_sc_p4est.yml @@ -0,0 +1,121 @@ +name: CMake tests sc and p4est + + +# 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) 2024 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 github CI script installs t8code and runs its tests for various configurations. +# We compile sc and p4est as thirdparty libraries and use caching to only trigger a +# new installation of them when their versions have changed in t8code. +# +# Note: To manually enforce sc and p4est installation, either increase the counter +# in the "key:" entries of the sc and p4est steps or set the variables +# SC_IGNORE_CACHE and P4EST_IGNORE_CACHE to 1 in the respective steps. + +on: + workflow_call: + 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)' + +jobs: + sc_p4est_cmake_tests: + runs-on: ubuntu-latest + container: dlramr/t8code-ubuntu:t8-dependencies + timeout-minutes: 30 + steps: +# +# Setup +# + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: SC_P4EST_MPI_${{ inputs.MPI }} + - name: untar artifact + run: tar -xf artifact.tar && rm artifact.tar + - name: Update packages + run: apt-get update && apt-get upgrade -y + # This seems to be necessary because of the docker container + - name: disable ownership checks + run: git config --global --add safe.directory '*' + - name: Get input vars + run: export MAKEFLAGS="${{ inputs.MAKEFLAGS }}" + && export MPI="${{ inputs.MPI }}" + && echo MPI="$MPI" >> $GITHUB_ENV + && echo MAKEFLAGS="$MAKEFLAGS" >> $GITHUB_ENV +# +# SC tests +# + ## save variables + - name: Save variables + run: export SC_DEBUG=$PWD/sc/build/Debug + && export SC_RELEASE=$PWD/sc/build/Release + && export P4EST_DEBUG=$PWD/p4est/build/Debug + && export P4EST_RELEASE=$PWD/p4est/build/Release + && echo SC_DEBUG="$SC_DEBUG" >> $GITHUB_ENV + && echo SC_RELEASE="$SC_RELEASE" >> $GITHUB_ENV + && echo P4EST_DEBUG="$P4EST_DEBUG" >> $GITHUB_ENV + && echo P4EST_RELEASE="$P4EST_RELEASE" >> $GITHUB_ENV + ## sc debug + - name: sc debug check + run: cd $SC_DEBUG && ninja test + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: sc_debug_MPI_${{ inputs.MPI }}.log + path: $SC_DEBUG/Testing/Temporary/LastTest.log + ## sc release + - name: sc release check + run: cd $SC_RELEASE && ninja test + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: sc_release_MPI_${{ inputs.MPI }}.log + path: $SC_RELEASE/Testing/Temporary/LastTest.log +# +# P4EST tests +# + ## p4est debug + - name: p4est debug check + run: cd $P4EST_DEBUG && ninja test + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: sp4est_debug_MPI_${{ inputs.MPI }}.log + path: $P4EST_DEBUG/Testing/Temporary/LastTest.log + ## p4est release + - name: p4est release check + run: cd $P4EST_RELEASE && ninja test + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: sp4est_release_MPI_${{ inputs.MPI }}.log + path: $P4EST_RELEASE/Testing/Temporary/LastTest.log diff --git a/.github/workflows/tests_cmake_t8code.yml b/.github/workflows/tests_cmake_t8code.yml new file mode 100644 index 0000000000..1effcaba77 --- /dev/null +++ b/.github/workflows/tests_cmake_t8code.yml @@ -0,0 +1,119 @@ +name: CMake tests t8code + + +# 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) 2024 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. + +on: + workflow_call: + 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)' + LESS_TESTS: + required: true + type: boolean + description: 'Enable less tests option for configuring' + +jobs: + t8code_cmake_tests: + timeout-minutes: 30 + runs-on: ubuntu-latest + container: dlramr/t8code-ubuntu:t8-dependencies + steps: +# +# Setup +# + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: SC_P4EST_MPI_${{ inputs.MPI }} + - name: untar artifact + run: tar -xf artifact.tar && rm artifact.tar + - name: Update packages + run: apt-get update && apt-get upgrade -y + # This seems to be necessary because of the docker container + - name: disable ownership checks + run: git config --global --add safe.directory '*' + - name: Get input vars + run: export MAKEFLAGS="${{ inputs.MAKEFLAGS }}" + && export MPI="${{ inputs.MPI }}" + && export BUILD_TYPE="${{ inputs.BUILD_TYPE }}" + && export SC_PATH=$PWD/sc/build/$BUILD_TYPE + && export P4EST_PATH=$PWD/p4est/build/$BUILD_TYPE + && echo MAKEFLAGS="$MAKEFLAGS" >> $GITHUB_ENV + && echo MPI="$MPI" >> $GITHUB_ENV + && echo BUILD_TYPE="$BUILD_TYPE" >> $GITHUB_ENV + && echo SC_PATH="$SC_PATH" >> $GITHUB_ENV + && echo P4EST_PATH="$P4EST_PATH" >> $GITHUB_ENV +# +# T8CODE +# + # build config vars + - name: less-test option + if: ${{ inputs.LESS_TESTS }} + run: export LESS_TEST_OPTION="-DT8CODE_ENABLE_LESS_TESTS=ON" + && echo LESS_TEST_OPTION="$LESS_TEST_OPTION" >> $GITHUB_ENV + - name: build config variables + run: export CONFIG_OPTIONS="${LESS_TEST_OPTION} -GNinja -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake" + && echo CONFIG_OPTIONS="$CONFIG_OPTIONS" >> $GITHUB_ENV + # cmake and test + - name: Printing MPI compiler info + run: mpicc --version && mpirun --version + - name: Printing GCC compiler info + run: gcc --version && g++ --version + - name: echo cmake line + run: echo cmake ../ $CONFIG_OPTIONS + - name: cmake + run: mkdir build && cd build && cmake ../ $CONFIG_OPTIONS + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: cmake_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}.log + path: build/CMakeFiles/CMakeOutput.log + - name: ninja + run: cd build && ninja $MAKEFLAGS + - name: ninja install + run: cd build && ninja install $MAKEFLAGS + - name: serial tests (if MPI is enabled) + run: cd build && ctest $MAKEFLAGS -R _serial + if: ${{ inputs.MPI == 'ON' }} + - name: parallel tests (if MPI is enabled) + run: cd build && ctest -R _parallel + if: ${{ inputs.MPI == 'ON' }} + - name: tests (if MPI is disabled) + run: cd build && ctest $MAKEFLAGS + if: ${{ inputs.MPI == 'OFF' }} + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-suite_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}.log + path: build/Testing/Temporary/LastTest.log diff --git a/.github/workflows/tests_cmake_t8code_linkage.yml b/.github/workflows/tests_cmake_t8code_linkage.yml new file mode 100644 index 0000000000..6e58ed8ffd --- /dev/null +++ b/.github/workflows/tests_cmake_t8code_linkage.yml @@ -0,0 +1,182 @@ +name: CMake tests t8code linkage + + +# 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) 2024 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. + +on: + workflow_call: + 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)' + LESS_TESTS: + required: true + type: boolean + description: 'Enable less tests option for configuring' + +jobs: + t8code_cmake_tests: + timeout-minutes: 60 + runs-on: ubuntu-latest + container: dlramr/t8code-ubuntu:t8-dependencies + steps: +# +# Setup +# + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: SC_P4EST_MPI_${{ inputs.MPI }} + - name: untar artifact + run: tar -xf artifact.tar && rm artifact.tar + - name: Update packages + run: apt-get update && apt-get upgrade -y + # This seems to be necessary because of the docker container + - name: disable ownership checks + run: git config --global --add safe.directory '*' + - name: Get input vars + run: export MAKEFLAGS="${{ inputs.MAKEFLAGS }}" + && export MPI="${{ inputs.MPI }}" + && export BUILD_TYPE="${{ inputs.BUILD_TYPE }}" + && export SC_PATH=$PWD/sc/build/$BUILD_TYPE + && export P4EST_PATH=$PWD/p4est/build/$BUILD_TYPE + && echo MAKEFLAGS="$MAKEFLAGS" >> $GITHUB_ENV + && echo MPI="$MPI" >> $GITHUB_ENV + && echo BUILD_TYPE="$BUILD_TYPE" >> $GITHUB_ENV + && echo SC_PATH="$SC_PATH" >> $GITHUB_ENV + && echo P4EST_PATH="$P4EST_PATH" >> $GITHUB_ENV +# +# T8CODE +# +# + # build config vars + - name: less-test option + if: ${{ inputs.LESS_TESTS }} + run: export LESS_TEST_OPTION="-DT8CODE_ENABLE_LESS_TESTS=ON" + && echo LESS_TEST_OPTION="$LESS_TEST_OPTION" >> $GITHUB_ENV + - name: build config variables + run: export CONFIG_OPTIONS="${LESS_TEST_OPTION} -GNinja -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake" + && echo CONFIG_OPTIONS="$CONFIG_OPTIONS" >> $GITHUB_ENV + # cmake and test with netcdf + - name: check NetCDF + run: echo "Checking NetCDF" + - name: echo cmake line + run: echo cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_NETCDF=ON + - name: cmake MPI NetCDF debug + run: mkdir build_netcdf && cd build_netcdf && cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_NETCDF=ON + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: cmake_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_NetCDF.log + path: build_netcdf/CMakeFiles/CMakeOutput.log + - name: make + run: cd build_netcdf && ninja $MAKEFLAGS + - name: ninja install + run: cd build_netcdf && ninja install $MAKEFLAGS + - name: serial tests (if MPI is enabled) + run: cd build_netcdf && ctest $MAKEFLAGS -R _serial + if: ${{ inputs.MPI == 'ON' }} + - name: parallel tests (if MPI is enabled) + run: cd build_netcdf && ctest -R _parallel + if: ${{ inputs.MPI == 'ON' }} + - name: tests (if MPI is disabled) + run: cd build_netcdf && ctest $MAKEFLAGS + if: ${{ inputs.MPI == 'OFF' }} + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-suite_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_NetCDF.log + path: build_netcdf/Testing/Temporary/LastTest.log +# cmake and test with OpenCASCADE + - name: check OpenCASCADE + run: echo "Checking OpenCASCADE" + - name: echo cmake line + run: echo cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_OCC=ON + - name: cmake OpenCASCADE + run: mkdir build_occ && cd build_occ && cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_OCC=ON + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: cmake_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_OCC.log + path: build_occ/CMakeFiles/CMakeOutput.log + - name: make + run: cd build_occ && ninja $MAKEFLAGS + - name: ninja install + run: cd build_occ && ninja install $MAKEFLAGS + - name: serial tests (if MPI is enabled) + run: cd build_occ && ctest $MAKEFLAGS -R _serial + if: ${{ inputs.MPI == 'ON' }} + - name: parallel tests (if MPI is enabled) + run: cd build_occ && ctest -R _parallel + if: ${{ inputs.MPI == 'ON' }} + - name: tests (if MPI is disabled) + run: cd build_occ && ctest $MAKEFLAGS + if: ${{ inputs.MPI == 'OFF' }} + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-suite_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_OCC.log + path: build_occ/Testing/Temporary/LastTest.log +# cmake and test with VTK + - name: check VTK + run: echo "Checking VTK" + - name: echo cmake line + run: echo cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_VTK=ON -DVTK_DIR=/usr/local/lib/cmake/vtk-9.1 + - name: cmake MPI VTK debug + run: mkdir build_vtk && cd build_vtk && cmake ../ $CONFIG_OPTIONS -DT8CODE_ENABLE_VTK=ON -DVTK_DIR=/usr/local/lib/cmake/vtk-9.1 + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: cmake_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_VTK.log + path: build_vtk/CMakeFiles/CMakeOutput.log + - name: make + run: cd build_vtk && ninja $MAKEFLAGS + - name: ninja install + run: cd build_vtk && ninja install $MAKEFLAGS + - name: serial tests (if MPI is enabled) + run: cd build_vtk && ctest $MAKEFLAGS -R _serial + if: ${{ inputs.MPI == 'ON' }} + - name: parallel tests (if MPI is enabled) + run: cd build_vtk && ctest -R _parallel + if: ${{ inputs.MPI == 'ON' }} + - name: tests (if MPI is disabled) + run: cd build_vtk && ctest $MAKEFLAGS + if: ${{ inputs.MPI == 'OFF' }} + - name: OnFailUploadLog + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-suite_${{ inputs.BUILD_TYPE }}_MPI_${{ inputs.MPI }}_VTK.log + path: build_vtk/Testing/Temporary/LastTest.log diff --git a/.github/workflows/tests_cmake_testsuite.yml b/.github/workflows/tests_cmake_testsuite.yml new file mode 100644 index 0000000000..ba3616153c --- /dev/null +++ b/.github/workflows/tests_cmake_testsuite.yml @@ -0,0 +1,116 @@ +name: t8code CMake testsuite + + +# 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) 2024 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 github CI script installs t8code and runs its tests for various configurations. +# We compile sc and p4est as thirdparty libraries and use caching to only trigger a +# new installation of them when their versions have changed in t8code. +# +# Note: To manually enforce sc and p4est installation, either increase the counter +# in the "CACHE_COUNTER:" entries of the sc and p4est steps or set the variables +# IGNORE_CACHE to true in the respective steps. + +on: + push: + branches: + - main + - develop + - feature-*CI* # for testing this script, all feature branches with "CI" in their name + pull_request: + branches: + - main + - develop + workflow_dispatch: # Be able to trigger this manually on github.com + # Run every night at 1:10 + schedule: + - cron: '10 1 * * *' + +jobs: + # Preparation step for tests. Repo is cloned and sc + p4est are compiled with and without MPI. + preparation: + if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule') + uses: ./.github/workflows/tests_cmake_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: + if: ((github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule')) + needs: preparation + uses: ./.github/workflows/tests_cmake_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: + if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule') + uses: ./.github/workflows/tests_cmake_t8code.yml + strategy: + fail-fast: false + matrix: + MPI: [OFF, ON] + BUILD_TYPE: [Debug, Release] + include: + - MAKEFLAGS: -j4 + needs: preparation + with: + MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + MPI: ${{ matrix.MPI }} + BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + LESS_TESTS: ${{ github.event_name == 'pull_request' }} + + + # Run t8code linkage tests with and without MPI and in serial and debug mode + t8code_linkage_tests: + if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule') + uses: ./.github/workflows/tests_cmake_t8code_linkage.yml + strategy: + fail-fast: false + matrix: + MPI: [OFF, ON] + BUILD_TYPE: [Debug, Release] + include: + - MAKEFLAGS: -j4 + needs: preparation + with: + MAKEFLAGS: ${{ matrix.MAKEFLAGS }} + MPI: ${{ matrix.MPI }} + BUILD_TYPE: ${{ matrix.BUILD_TYPE }} + LESS_TESTS: ${{ github.event_name == 'pull_request' }} + diff --git a/CMakeLists.txt b/CMakeLists.txt index c9727328e4..90dd8cdcb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ include( CTest ) option( T8CODE_BUILD_AS_SHARED_LIBRARY "Whether t8code should be built as a shared or a static library" ON ) option( T8CODE_BUILD_PEDANTIC "Compile t8code with `-Wall -pedantic -Werror` as done in the Github CI." OFF ) +option( T8CODE_EXPORT_COMPILE_COMMANDS "Export the compile commands as json. Can be used by IDEs for code completion (e.g. intellisense, clangd)" OFF ) option( T8CODE_BUILD_TESTS "Build t8code's automated tests" ON ) option( T8CODE_BUILD_TUTORIALS "Build t8code's tutorials" ON ) option( T8CODE_BUILD_EXAMPLES "Build t8code's examples" ON ) @@ -29,13 +30,20 @@ option( T8CODE_BUILD_DOCUMENTATION "Build t8code's documentation" OFF ) include(CMakeDependentOption) cmake_dependent_option( T8CODE_BUILD_DOCUMENTATION_SPHINX "Build t8code's documentation using sphinx" OFF "T8CODE_BUILD_DOCUMENTATION" OFF ) -set(T8CODE_CUSTOM_TEST_COMMAND "" CACHE STRING "Define custom test command, e.g.: mpirun -n 4") +set(T8CODE_CUSTOM_PARALLEL_TEST_COMMAND "" CACHE STRING "Define a custom command for parallel tests , e.g.: mpirun -np 8 (overwrites standard mpirun -np 4 if build with mpi)") +set(T8CODE_CUSTOM_SERIAL_TEST_COMMAND "" CACHE STRING "Define a custom command for serial tests.") -if( NOT CMAKE_BUILD_TYPE ) - set( CMAKE_BUILD_TYPE "Release" ) -endif() +# Set a default build type if none was specified +set(default_build_type "Release") -set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Release RelWithDebInfo Debug) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build. Build types available: Release Debug RelWithDebInfo" FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "RelWithDebInfo") +endif() set( CMAKE_C_STANDARD 11 ) set( CMAKE_C_STANDARD_REQUIRED ON ) @@ -57,7 +65,10 @@ if( T8CODE_ENABLE_MPI ) endif() if( T8CODE_ENABLE_VTK ) - find_package( VTK REQUIRED ) + find_package( VTK REQUIRED COMPONENTS + IOXML CommonExecutionModel CommonDataModel + IOGeometry IOXMLParser IOParallelXML IOPLY + ParallelMPI FiltersCore vtksys CommonCore zlib IOLegacy) if(VTK_FOUND) message("Found VTK") endif (VTK_FOUND) @@ -81,7 +92,6 @@ if( T8CODE_ENABLE_NETCDF ) endif (netCDF_FOUND) endif( T8CODE_ENABLE_NETCDF ) - # Override default for this libsc option set( BUILD_SHARED_LIBS ON CACHE BOOL "Build libsc as a shared library" ) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 462d0c3184..8d39c49d5a 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -4,10 +4,27 @@ function( add_t8_benchmark ) set( multiValueArgs "SOURCES" ) cmake_parse_arguments( ADD_T8_BENCHMARK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + # Get the path of the first file listed in the SOURCES list and use it to determine the build directory. + # The executable will be build in the same directory as the first source file. + list(GET ADD_T8_BENCHMARK_SOURCES 0 FIRST_SOURCE) + get_filename_component(BENCHMARK_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${FIRST_SOURCE}" DIRECTORY) + file(RELATIVE_PATH BENCHMARK_RELATIVE_DIR "${CMAKE_SOURCE_DIR}" "${BENCHMARK_SOURCE_DIR}") + set(BENCHMARK_BUILD_DIR "${CMAKE_BINARY_DIR}/${BENCHMARK_RELATIVE_DIR}") + add_executable( ${ADD_T8_BENCHMARK_NAME} ${ADD_T8_BENCHMARK_SOURCES} ) target_include_directories( ${ADD_T8_BENCHMARK_NAME} PRIVATE ${PROJECT_SOURCE_DIR} ) target_link_libraries( ${ADD_T8_BENCHMARK_NAME} PRIVATE T8 SC::SC ) + set_target_properties(${ADD_T8_BENCHMARK_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_BUILD_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${BENCHMARK_BUILD_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${BENCHMARK_BUILD_DIR}" + ) + + if( T8CODE_EXPORT_COMPILE_COMMANDS ) + set_target_properties( ${ADD_T8_BENCHMARK_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) + endif( T8CODE_EXPORT_COMPILE_COMMANDS ) + install( TARGETS ${ADD_T8_BENCHMARK_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) endfunction() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 5fcb9239eb..ad32fd28a7 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,8 +5,8 @@ else() add_library( t8example STATIC ) endif() target_sources( t8example PRIVATE common/t8_example_common.cxx common/t8_example_common_functions.cxx ) -target_include_directories( t8example PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) -target_link_libraries( t8example PRIVATE T8 ) +target_include_directories( t8example PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ${SC_INCLUDE_DIR} ) +target_link_libraries( t8example PRIVATE T8 ${SC_LIBRARIES} m ) install( TARGETS t8example DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) function( add_t8_example ) @@ -15,10 +15,27 @@ function( add_t8_example ) set( multiValueArgs "SOURCES" ) cmake_parse_arguments( ADD_T8_EXAMPLE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + # Get the path of the first file listed in the SOURCES list and use it to determine the build directory. + # The executable will be build in the same directory as the first source file. + list(GET ADD_T8_EXAMPLE_SOURCES 0 FIRST_SOURCE) + get_filename_component(EXAMPLE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${FIRST_SOURCE}" DIRECTORY) + file(RELATIVE_PATH EXAMPLE_RELATIVE_DIR "${CMAKE_SOURCE_DIR}" "${EXAMPLE_SOURCE_DIR}") + set(EXAMPLE_BUILD_DIR "${CMAKE_BINARY_DIR}/${EXAMPLE_RELATIVE_DIR}") + add_executable( ${ADD_T8_EXAMPLE_NAME} ${ADD_T8_EXAMPLE_SOURCES} ) target_link_libraries( ${ADD_T8_EXAMPLE_NAME} PRIVATE T8 t8example SC::SC ) target_include_directories( ${ADD_T8_EXAMPLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) + set_target_properties(${ADD_T8_EXAMPLE_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${EXAMPLE_BUILD_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${EXAMPLE_BUILD_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${EXAMPLE_BUILD_DIR}" + ) + + if( T8CODE_EXPORT_COMPILE_COMMANDS ) + set_target_properties( ${ADD_T8_EXAMPLE_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) + endif( T8CODE_EXPORT_COMPILE_COMMANDS ) + install( TARGETS ${ADD_T8_EXAMPLE_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) endfunction() diff --git a/example/IO/cmesh/gmsh/t8_read_msh_file.cxx b/example/IO/cmesh/gmsh/t8_read_msh_file.cxx index 48616cf92f..192976f77a 100644 --- a/example/IO/cmesh/gmsh/t8_read_msh_file.cxx +++ b/example/IO/cmesh/gmsh/t8_read_msh_file.cxx @@ -3,7 +3,7 @@ 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) 2015 the developers + Copyright (C) 2024 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 @@ -140,7 +140,7 @@ main (int argc, char *argv[]) opt = sc_options_new (argv[0]); sc_options_add_switch (opt, 'h', "help", &helpme, "Display a short help message."); - sc_options_add_string (opt, 'f', "prefix", &prefix, "", "The prefix of the tetgen files."); + sc_options_add_string (opt, 'f', "prefix", &prefix, "", "The prefix of the gmsh files."); sc_options_add_switch (opt, 'p', "partition", &partition, "If true the generated cmesh is repartitioned uniformly."); sc_options_add_int (opt, 'd', "dim", &dim, 2, "The dimension of the mesh"); sc_options_add_int (opt, 'm', "master", &master, -1, diff --git a/example/IO/forest/gmsh/t8_gmsh_to_vtk.cxx b/example/IO/forest/gmsh/t8_gmsh_to_vtk.cxx index fb8c862b89..cb0e662e51 100644 --- a/example/IO/forest/gmsh/t8_gmsh_to_vtk.cxx +++ b/example/IO/forest/gmsh/t8_gmsh_to_vtk.cxx @@ -79,9 +79,8 @@ main (int argc, char **argv) sc_options_add_string (opt, 'f', "fileprefix", &fileprefix, NULL, "Fileprefix of the msh and brep files."); sc_options_add_int (opt, 'l', "level", &level, 2, "The uniform refinement level. Default: 2"); sc_options_add_int (opt, 'd', "dimension", &dim, 3, "The dimension of the mesh. Default: 3"); - sc_options_add_int ( - opt, 'c', "use_cad", &use_cad, 0, - "Enable CAD-based curvilinear geometry. Needs a `.brep` file with the same file prefix. Default: 0"); + sc_options_add_switch (opt, 'c', "use_cad", &use_cad, + "Enable CAD-based curvilinear geometry. Needs a `.brep` file with the same file prefix."); parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); if (helpme) { diff --git a/example/geometry/t8_example_geometries.cxx b/example/geometry/t8_example_geometries.cxx index 0139974b6e..7736d72aab 100644 --- a/example/geometry/t8_example_geometries.cxx +++ b/example/geometry/t8_example_geometries.cxx @@ -139,6 +139,22 @@ struct t8_geometry_sincos: public t8_geometry return 0; } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only quad elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_QUAD) { + t8_productionf ( + "t8_geometry_sincos is not compatible with tree type %s\n It is only compatible with quad elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -203,6 +219,22 @@ struct t8_geometry_moebius: public t8_geometry_with_vertices SC_ABORT_NOT_REACHED (); } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only quad elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_QUAD) { + t8_productionf ( + "t8_geometry_moebius is not compatible with tree type %s\n It is only compatible with quad elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -273,6 +305,22 @@ struct t8_geometry_cylinder: public t8_geometry return 0; } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only quad elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_QUAD) { + t8_productionf ( + "t8_geometry_cylinder is not compatible with tree type %s\n It is only compatible with quad elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -341,6 +389,22 @@ struct t8_geometry_circle: public t8_geometry_with_vertices SC_ABORT_NOT_REACHED (); } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only quad elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_QUAD) { + t8_productionf ( + "t8_geometry_circle is not compatible with tree type %s\n It is only compatible with quad elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -434,6 +498,22 @@ struct t8_geometry_moving: public t8_geometry return 0; } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only quad elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_QUAD) { + t8_productionf ( + "t8_geometry_moving is not compatible with tree type %s\n It is only compatible with quad elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -504,6 +584,22 @@ struct t8_geometry_cube_zdistorted: public t8_geometry return 0; } + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only hex elements are supported by this geometry. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_HEX) { + t8_productionf ( + "t8_geometry_cube_zdistorted is not compatible with tree type %s\n It is only compatible with hex elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } + /** * Get the type of this geometry. * \return The type. @@ -653,7 +749,7 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) case T8_GEOM_ANALYTIC_QUAD_TO_SPHERE: t8_global_productionf ("Wrapping a quad around a sphere.\n"); t8_cmesh_register_geometry (cmesh, 3, "geom_quad_to_sphere", quad_to_sphere_callback, nullptr, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); t8_cmesh_set_join (cmesh, 0, 0, 1, 0, 0); diff --git a/p4est b/p4est index 7896878956..8206f0e56d 160000 --- a/p4est +++ b/p4est @@ -1 +1 @@ -Subproject commit 78968789560133460f0eee74897a44b3444790e5 +Subproject commit 8206f0e56d536d6d7f2e1d106c491b8c9386e28f diff --git a/pull_request_template.md b/pull_request_template.md index b253b5fe7f..e6c1982284 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -33,6 +33,6 @@ As a reviewer please read through all the code lines and make sure that the code - [ ] If a new directory with source-files is added, it must be covered by the `script/find_all_source_files.scp` to check the indentation of these files. - [ ] If this PR introduces a new feature, it must be covered in an example/tutorial and a Wiki article. -#### Licence +#### License - [ ] The author added a BSD statement to `doc/` (or already has one) diff --git a/scripts/indent_all_files.scp b/scripts/indent_all_files.scp index 2b176f09b1..8879513291 100755 --- a/scripts/indent_all_files.scp +++ b/scripts/indent_all_files.scp @@ -55,6 +55,7 @@ echo $PWD/../example/ echo $PWD/../test/ echo $PWD/../tutorials/ echo $PWD/../benchmarks/ +echo $PWD/../api/ echo read -p "Are you sure? ('Y' or 'y' to continue)" -n 1 -r echo diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6cc4516e49..d80de92643 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,10 @@ if( CMAKE_BUILD_TYPE STREQUAL "Debug" ) target_compile_definitions( T8 PUBLIC T8_ENABLE_DEBUG ) endif() +if( T8CODE_EXPORT_COMPILE_COMMANDS ) + set_target_properties( T8 PROPERTIES EXPORT_COMPILE_COMMANDS ON ) +endif( T8CODE_EXPORT_COMPILE_COMMANDS ) + if( T8CODE_ENABLE_NETCDF ) target_link_libraries( T8 PUBLIC netCDF::netcdf ) target_compile_definitions(T8 PUBLIC diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index 3c0a6b68b0..186835b722 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -104,17 +104,6 @@ t8_cmesh_is_committed (const t8_cmesh_t cmesh); */ int t8_cmesh_validate_geometry (const t8_cmesh_t cmesh); - -/** After a cmesh is committed, check whether all trees in a cmesh do have positive volume. - * Returns true if all trees have positive volume. - * \param [in] cmesh This cmesh is examined. May be NULL. - * \return True if \a cmesh is not NULL and all trees for - * which \ref t8_cmesh_set_tree_vertices - * was called, do have positive geometric volume. - * False otherwise. - */ -int -t8_cmesh_no_negative_volume (t8_cmesh_t cmesh); #endif /** Given a set of vertex coordinates for a tree of a given eclass. diff --git a/src/t8_cmesh/t8_cmesh.cxx b/src/t8_cmesh/t8_cmesh.cxx index f4684d19a3..4ab894c0fb 100644 --- a/src/t8_cmesh/t8_cmesh.cxx +++ b/src/t8_cmesh/t8_cmesh.cxx @@ -124,15 +124,45 @@ t8_cmesh_is_committed (const t8_cmesh_t cmesh) return 1; } -#ifdef T8_ENABLE_DEBUG +#if T8_ENABLE_DEBUG int t8_cmesh_validate_geometry (const t8_cmesh_t cmesh) { + /* After a cmesh is committed, check whether all trees in a cmesh are compatible + * with their geometry and if they have positive volume. + * Returns true if all trees are valid. Returns also true if no geometries are + * registered yet, since the validity computation depends on the used geometry. + */ + /* Geometry handler is not constructed yet */ if (cmesh->geometry_handler == NULL) { - return 1; + return true; } - return t8_cmesh_no_negative_volume (cmesh); + if (cmesh == NULL) { + return true; + } + if (cmesh->geometry_handler->get_num_geometries () > 0) { + /* Iterate over all trees, get their vertices and check the volume */ + for (t8_locidx_t itree = 0; itree < cmesh->num_local_trees; itree++) { + /* Check if tree and geometry are compatible. */ + const int geometry_compatible + = cmesh->geometry_handler->tree_compatible_with_geom (cmesh, t8_cmesh_get_global_id (cmesh, itree)); + if (!geometry_compatible) { + t8_debugf ("Detected incompatible geometry for tree %li\n", (long) itree); + return false; + } + if (geometry_compatible) { + /* Check for negative volume. This only makes sense if the geometry is valid for the tree. */ + const int negative_volume + = cmesh->geometry_handler->tree_negative_volume (cmesh, t8_cmesh_get_global_id (cmesh, itree)); + if (negative_volume) { + t8_debugf ("Detected negative volume in tree %li\n", (long) itree); + return false; + } + } + } + } + return true; } #endif /* T8_ENABLE_DEBUG */ @@ -400,7 +430,6 @@ t8_cmesh_get_tree_vertices (const t8_cmesh_t cmesh, const t8_locidx_t ltreeid) { T8_ASSERT (t8_cmesh_is_committed (cmesh)); T8_ASSERT (t8_cmesh_treeid_is_local_tree (cmesh, ltreeid) || t8_cmesh_treeid_is_ghost (cmesh, ltreeid)); - return (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_VERTICES_ATTRIBUTE_KEY, ltreeid); } @@ -582,39 +611,6 @@ t8_cmesh_tree_vertices_negative_volume (const t8_eclass_t eclass, const double * return eclass == T8_ECLASS_TET ? sc_prod > 0 : sc_prod < 0; } -#ifdef T8_ENABLE_DEBUG -/* After a cmesh is committed, check whether all trees in a cmesh do have positive volume. - * Returns true if all trees have positive volume. Returns also true if no geometries are - * registered yet, since the volume computation depends on the used geometry. - */ -int -t8_cmesh_no_negative_volume (const t8_cmesh_t cmesh) -{ - bool res = false; - - if (cmesh == NULL) { - return 0; - } - if (cmesh->geometry_handler == NULL) { - return 0; - } - if (cmesh->geometry_handler->get_num_geometries () > 0) { - /* Iterate over all trees, get their vertices and check the volume */ - for (t8_locidx_t itree = 0; itree < cmesh->num_local_trees; itree++) { - const int ret = cmesh->geometry_handler->tree_negative_volume (cmesh, t8_cmesh_get_global_id (cmesh, itree)); - if (ret) { - t8_debugf ("Detected negative volume in tree %li\n", (long) itree); - } - res |= ret; /* res is true if one ret value is true */ - } - return !res; - } - else { - return true; - } -} -#endif - void t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, const t8_gloidx_t gtree_id, const double *vertices, const int num_vertices) diff --git a/src/t8_cmesh/t8_cmesh_examples.cxx b/src/t8_cmesh/t8_cmesh_examples.cxx index 8425beb751..c56dad878e 100644 --- a/src/t8_cmesh/t8_cmesh_examples.cxx +++ b/src/t8_cmesh/t8_cmesh_examples.cxx @@ -20,6 +20,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include #include #include @@ -3126,8 +3127,8 @@ t8_cmesh_new_triangulated_spherical_surface_cube (const double radius, sc_MPI_Co const int nface_rot = 4; // Four triangles create a cube's face. const int ncube_rot = 6; // Six rotations of the four triangles to the six cube's faces. - constexpr int ntrees = nface_rot * ncube_rot; // Number of cmesh elements resp. trees. - const int nverts = 3; // Number of cmesh element (triangle) vertices. + const int ntrees = nface_rot * ncube_rot; // Number of cmesh elements resp. trees. + const int nverts = 3; // Number of cmesh element (triangle) vertices. // Arrays for the face connectivity computations via vertices. double all_verts[ntrees * T8_ECLASS_MAX_CORNERS * T8_ECLASS_MAX_DIM]; @@ -3139,7 +3140,7 @@ t8_cmesh_new_triangulated_spherical_surface_cube (const double radius, sc_MPI_Co all_eclasses[itree] = T8_ECLASS_TRIANGLE; } - constexpr double _CBRT = std::cbrt (1.0); + const double _CBRT = std::cbrt (1.0); const double r = radius / _CBRT; const double vertices[3][3] = { { -r, -r, r }, { r, -r, r }, { 0.0, 0.0, r } }; @@ -3220,7 +3221,7 @@ t8_cmesh_new_quadrangulated_spherical_surface (const double radius, sc_MPI_Comm all_eclasses[itree] = T8_ECLASS_QUAD; } - constexpr double _CBRT = std::cbrt (1.0); + const double _CBRT = std::cbrt (1.0); const double r = radius / _CBRT; const double vertices[4][3] = { { -r, -r, r }, { r, -r, r }, { -r, r, r }, { r, r, r } }; @@ -3514,7 +3515,7 @@ t8_cmesh_new_cubed_sphere (const double radius, sc_MPI_Comm comm) const double inner_radius = 0.6 * radius; const double outer_radius = radius; - constexpr double _CBRT = std::cbrt(1.0); + const double _CBRT = std::cbrt(1.0); const double inner_x = inner_radius / _CBRT; const double inner_y = inner_x; diff --git a/src/t8_cmesh/t8_cmesh_geometry.cxx b/src/t8_cmesh/t8_cmesh_geometry.cxx index 1fd599ea88..eca196b4bf 100644 --- a/src/t8_cmesh/t8_cmesh_geometry.cxx +++ b/src/t8_cmesh/t8_cmesh_geometry.cxx @@ -97,7 +97,7 @@ t8_cmesh_get_tree_geom_hash (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid) const size_t *hash = (const size_t *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_GEOMETRY_ATTRIBUTE_KEY, ltreeid); if (hash == nullptr) { - SC_ABORTF ("Could not find geometry for tree %ld.", gtreeid); + SC_ABORTF ("Could not find geometry for tree %ld.", static_cast (gtreeid)); } return *hash; } diff --git a/src/t8_cmesh/t8_cmesh_partition.cxx b/src/t8_cmesh/t8_cmesh_partition.cxx index 1655661496..b9de8fbc54 100644 --- a/src/t8_cmesh/t8_cmesh_partition.cxx +++ b/src/t8_cmesh/t8_cmesh_partition.cxx @@ -25,6 +25,8 @@ * TODO: document this file */ +#include + #include #include #include @@ -389,7 +391,8 @@ t8_cmesh_partition_sendrange (const t8_cmesh_t cmesh, const t8_cmesh_t cmesh_fro ret--; } - t8_debugf ("%s_first = %i, %s_last = %i, last_tree = %li\n", "send", *send_first, "send", *send_last, ret); + t8_debugf ("%s_first = %i, %s_last = %i, last_tree = %li\n", "send", *send_first, "send", *send_last, + static_cast (ret)); T8_ASSERT (*send_first >= 0); //TODO:reactivate T8_ASSERT (*send_last >= 0); @@ -1410,7 +1413,7 @@ t8_cmesh_partition_debug_listprocs (const t8_cmesh_t cmesh, const t8_cmesh_t cme } } t8_debugf ("I send to: %s\n", out); - sprintf (out, " "); + std::strcpy (out, " "); if (cmesh_from->set_partition) { for (p = 0; p < mpisize; p++) { if (t8_offset_sendsto (p, mpirank, from, to)) { @@ -1440,7 +1443,9 @@ t8_cmesh_partition_given (const t8_cmesh_t cmesh, const t8_cmesh_t cmesh_from, c size_t my_buffer_bytes = -1; char **send_buffer = NULL, *my_buffer = NULL; - int fs, ls, fr, lr; + int fs, ls; + int fr = 0; + int lr = 0; sc_MPI_Request *requests = NULL; t8_locidx_t num_ghosts, itree, num_trees; diff --git a/src/t8_cmesh/t8_cmesh_readmshfile.cxx b/src/t8_cmesh/t8_cmesh_readmshfile.cxx index de8f05b34e..18479c58d5 100644 --- a/src/t8_cmesh/t8_cmesh_readmshfile.cxx +++ b/src/t8_cmesh/t8_cmesh_readmshfile.cxx @@ -179,7 +179,7 @@ t8_cmesh_check_version_of_msh_file (FILE *fp) /* Search for the line starting with "$MeshFormat". */ while (!feof (fp) && strcmp (first_word, "$MeshFormat")) { (void) t8_cmesh_msh_read_next_line (&line, &linen, fp); - retval = sscanf (line, "%2048s", first_word); + retval = sscanf (line, "%2047s", first_word); /* Checking for read/write error */ if (retval != 1) { @@ -258,7 +258,7 @@ t8_msh_file_2_read_nodes (FILE *fp, t8_locidx_t *num_nodes, sc_mempool_t **node_ while (!feof (fp) && strcmp (first_word, "$Nodes")) { (void) t8_cmesh_msh_read_next_line (&line, &linen, fp); /* Get the first word of this line */ - retval = sscanf (line, "%2048s", first_word); + retval = sscanf (line, "%2047s", first_word); /* Checking for read/write error */ if (retval != 1) { @@ -358,7 +358,7 @@ t8_msh_file_4_read_nodes (FILE *fp, t8_locidx_t *num_nodes, sc_mempool_t **node_ while (!feof (fp) && strcmp (first_word, "$Nodes")) { (void) t8_cmesh_msh_read_next_line (&line, &linen, fp); /* Get the first word of this line */ - retval = sscanf (line, "%2048s", first_word); + retval = sscanf (line, "%2047s", first_word); /* Checking for read/write error */ if (retval != 1) { t8_global_errorf ("Premature end of line while reading nodes.\n"); @@ -524,7 +524,7 @@ t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, while (!feof (fp) && strcmp (first_word, "$Elements")) { (void) t8_cmesh_msh_read_next_line (&line, &linen, fp); /* Get the first word of this line */ - retval = sscanf (line, "%2048s", first_word); + retval = sscanf (line, "%2047s", first_word); /* Checking for read/write error */ if (retval != 1) { @@ -634,7 +634,7 @@ t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, int switch_indices[4] = { 0 }; int iswitch; T8_ASSERT (t8_eclass_to_dimension[eclass] > 1); - t8_debugf ("Correcting negative volume of tree %li\n", tree_count); + t8_debugf ("Correcting negative volume of tree %li\n", static_cast (tree_count)); switch (eclass) { case T8_ECLASS_TRIANGLE: case T8_ECLASS_QUAD: @@ -847,7 +847,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, while (!feof (fp) && strcmp (first_word, "$Elements")) { (void) t8_cmesh_msh_read_next_line (&line, &linen, fp); /* Get the first word of this line */ - retval = sscanf (line, "%2048s", first_word); + retval = sscanf (line, "%2047s", first_word); /* Checking for read/write error */ if (retval != 1) { @@ -973,7 +973,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, int switch_indices[4] = { 0 }; int iswitch; T8_ASSERT (t8_eclass_to_dimension[eclass] > 1); - t8_debugf ("Correcting negative volume of tree %li\n", tree_count); + t8_debugf ("Correcting negative volume of tree %li\n", static_cast (tree_count)); switch (eclass) { case T8_ECLASS_TRIANGLE: case T8_ECLASS_QUAD: diff --git a/src/t8_cmesh/t8_cmesh_triangle.cxx b/src/t8_cmesh/t8_cmesh_triangle.cxx index ba45711c1d..6d66dae5c4 100644 --- a/src/t8_cmesh/t8_cmesh_triangle.cxx +++ b/src/t8_cmesh/t8_cmesh_triangle.cxx @@ -262,7 +262,7 @@ t8_cmesh_triangle_read_eles (t8_cmesh_t cmesh, int corner_offset, char *filename double temp; T8_ASSERT (dim == 3); - t8_debugf ("Correcting negative volume of tree %li\n", (long) triangle - triangle_offset); + t8_debugf ("Correcting negative volume of tree %li\n", static_cast (triangle - triangle_offset)); /* We switch vertex 0 and vertex 1 */ for (i = 0; i < 3; i++) { temp = tree_vertices[i]; diff --git a/src/t8_cmesh/t8_cmesh_types.h b/src/t8_cmesh/t8_cmesh_types.h index 854d80c471..4022a4a006 100644 --- a/src/t8_cmesh/t8_cmesh_types.h +++ b/src/t8_cmesh/t8_cmesh_types.h @@ -59,9 +59,9 @@ typedef struct t8_cprofile t8_cprofile_t; /* Defined below */ +T8_ECLASS_MAX_EDGES /* Used to store which face is linked to which surface */ #define T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY \ T8_CMESH_CAD_FACE_ATTRIBUTE_KEY + 1 /* Used to store face parameters */ -#define T8_CMESH_LAGRANGE_POLY_DEGREE T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES +#define T8_CMESH_LAGRANGE_POLY_DEGREE_KEY T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES #define T8_CMESH_NEXT_POSSIBLE_KEY \ - T8_CMESH_LAGRANGE_POLY_DEGREE + 1 /* The next free value for a t8code attribute key */ + T8_CMESH_LAGRANGE_POLY_DEGREE_KEY + 1 /* The next free value for a t8code attribute key */ /** This structure holds the connectivity data of the coarse mesh. * It can either be replicated, then each process stores a copy of the whole diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index 1f85ef452a..de868e1922 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -593,11 +593,7 @@ t8_forest_ghost_search_boundary (t8_forest_t forest, t8_locidx_t ltreeid, const /* Store the new bounds at the entry for this element */ new_bounds[iface * 2] = lower; new_bounds[iface * 2 + 1] = upper; - if (lower == upper && lower == forest->mpirank) { - /* All neighbor leaves at this face are owned by the current rank */ - faces_totally_owned = faces_totally_owned && 1; - } - else { + if (lower != upper or lower != forest->mpirank) { faces_totally_owned = 0; } } diff --git a/src/t8_forest/t8_forest_partition.cxx b/src/t8_forest/t8_forest_partition.cxx index 8826af7f3a..eb77317fa4 100644 --- a/src/t8_forest/t8_forest_partition.cxx +++ b/src/t8_forest/t8_forest_partition.cxx @@ -1044,7 +1044,7 @@ static void t8_forest_partition_recvloop (t8_forest_t forest, int recv_first, int recv_last, const int recv_data, sc_array_t *data_out, char *sent_to_self, size_t byte_to_self) { - int iproc, num_receive, prev_recvd; + int iproc, prev_recvd; t8_locidx_t last_received_local_element = 0; t8_forest_t forest_from; int mpiret; @@ -1064,7 +1064,6 @@ t8_forest_partition_recvloop (t8_forest_t forest, int recv_first, int recv_last, /* In order of their ranks, receive the trees and elements from the other processes. */ - num_receive = 0; prev_recvd = 0; if (!recv_data) { forest->local_num_elements = 0; @@ -1072,7 +1071,6 @@ t8_forest_partition_recvloop (t8_forest_t forest, int recv_first, int recv_last, for (iproc = recv_first; iproc <= recv_last; iproc++) { if (!t8_forest_partition_empty (offset_from, iproc)) { /* We receive from each nonempty rank between recv_first and recv_last */ - num_receive++; if (iproc != forest->mpirank) { /* Probe for the message */ mpiret = sc_MPI_Probe (iproc, T8_MPI_PARTITION_FOREST, comm, &status); diff --git a/src/t8_geometry/t8_geometry_base.cxx b/src/t8_geometry/t8_geometry_base.cxx index c5b55fe4d8..a5a560d5a4 100644 --- a/src/t8_geometry/t8_geometry_base.cxx +++ b/src/t8_geometry/t8_geometry_base.cxx @@ -62,3 +62,25 @@ t8_geom_get_type (const t8_geometry_c *geom) return geom->t8_geom_get_type (); } + +/* Load the id and class of the newly active tree to the active_tree and active_tree_class variable. */ +void +t8_geometry::t8_geom_load_tree_data (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid) +{ + /* Set active id and eclass */ + const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); + active_tree = gtreeid; + const t8_locidx_t num_local_trees = t8_cmesh_get_num_local_trees (cmesh); + if (0 <= ltreeid && ltreeid < num_local_trees) { + active_tree_class = t8_cmesh_get_tree_class (cmesh, ltreeid); + } + else { + active_tree_class = t8_cmesh_get_ghost_class (cmesh, ltreeid - num_local_trees); + } + + /* Check whether we support this class */ + T8_ASSERT (active_tree_class == T8_ECLASS_VERTEX || active_tree_class == T8_ECLASS_TRIANGLE + || active_tree_class == T8_ECLASS_TET || active_tree_class == T8_ECLASS_QUAD + || active_tree_class == T8_ECLASS_HEX || active_tree_class == T8_ECLASS_LINE + || active_tree_class == T8_ECLASS_PRISM || active_tree_class == T8_ECLASS_PYRAMID); +} diff --git a/src/t8_geometry/t8_geometry_base.hxx b/src/t8_geometry/t8_geometry_base.hxx index df848cb2e3..01274231c5 100644 --- a/src/t8_geometry/t8_geometry_base.hxx +++ b/src/t8_geometry/t8_geometry_base.hxx @@ -98,14 +98,14 @@ struct t8_geometry /** Update a possible internal data buffer for per tree data. * This function is called before the first coordinates in a new tree are - * evaluated. You can use it for example to load the vertex coordinates of the - * tree into an internal buffer (as is done in the linear geometry). + * evaluated. + * In this base implementation we use it to load the treeid and class + * to the internal member variables \a active_tree and \a active_tree_class. * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. */ virtual void - t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) - = 0; + t8_geom_load_tree_data (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid); /** Query whether a batch of points lies inside an element. * \param [in] forest The forest. @@ -131,8 +131,8 @@ struct t8_geometry }; /** - * Check if the currently active tree has a negative volume - * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. + * Check if the currently active tree has a negative volume. + * \return True if the currently loaded tree has a negative volume. */ virtual bool t8_geom_tree_negative_volume () const @@ -142,6 +142,17 @@ struct t8_geometry return 0; }; + /** + * Check for compatibility of the currently loaded tree with the geometry. + * If the geometry has limitations these can be checked here. + * This includes for example if only specific tree types or dimensions are supported. + * If all trees are supported, this function should return true. + * \return True if the geometry is compatible with the tree. + */ + virtual bool + t8_geom_check_tree_compatibility () const + = 0; + /** * Get the dimension of this geometry. * \return The dimension. @@ -156,7 +167,7 @@ struct t8_geometry * Get the name of this geometry. * \return The name. */ - inline const std::string + inline const std::string & t8_geom_get_name () const { return name; @@ -177,14 +188,11 @@ struct t8_geometry = 0; protected: - int dimension; - /**< The dimension of reference space for which this is a geometry. */ - - std::string name; - /**< The name of this geometry. */ - - size_t hash; - /**< The hash of the name of this geometry. */ + int dimension; /**< The dimension of reference space for which this is a geometry. */ + std::string name; /**< The name of this geometry. */ + size_t hash; /**< The hash of the name of this geometry. */ + t8_gloidx_t active_tree; /**< The tree of which currently vertices are loaded. */ + t8_eclass_t active_tree_class; /**< The class of the currently active tree. */ }; T8_EXTERN_C_END (); diff --git a/src/t8_geometry/t8_geometry_handler.cxx b/src/t8_geometry/t8_geometry_handler.cxx index e22b55f2c1..57900be091 100644 --- a/src/t8_geometry/t8_geometry_handler.cxx +++ b/src/t8_geometry/t8_geometry_handler.cxx @@ -62,7 +62,7 @@ t8_geometry_handler::update_tree (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) active_geometry = get_geometry (geom_hash); SC_CHECK_ABORTF (active_geometry != nullptr, "Could not find geometry with hash %zu or tree %ld has no registered geometry.", geom_hash, - gtreeid); + static_cast (gtreeid)); } /* Get the user data for this geometry and this tree. */ active_geometry->t8_geom_load_tree_data (cmesh, gtreeid); diff --git a/src/t8_geometry/t8_geometry_handler.hxx b/src/t8_geometry/t8_geometry_handler.hxx index 207c584eae..b4229c6a4b 100644 --- a/src/t8_geometry/t8_geometry_handler.hxx +++ b/src/t8_geometry/t8_geometry_handler.hxx @@ -211,6 +211,19 @@ struct t8_geometry_handler return active_geometry->t8_geom_tree_negative_volume (); } + /** + * Check for compatibility of the tree with the assigned geometry. + * \param [in] cmesh The cmesh. + * \param [in] gtreeid The global tree id of the tree to check. + * \return True if the tree and assigned geometry are compatible. + */ + inline bool + tree_compatible_with_geom (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid) + { + update_tree (cmesh, gtreeid); + return active_geometry->t8_geom_check_tree_compatibility (); + } + /** * Increase the reference count of the geometry handler. */ @@ -249,6 +262,12 @@ struct t8_geometry_handler if (registered_geometries.find (hash) == registered_geometries.end ()) { registered_geometries.emplace (hash, std::move (geom)); } + else { + t8_productionf ("WARNING: Did not register the geometry %s because it is already registered.\n" + "Geometries only need to be registered once per process.\n" + "If you are registering a new geometry it probably has the same name as another one.\n", + geom->t8_geom_get_name ().c_str ()); + } if (registered_geometries.size () == 1) { active_geometry = registered_geometries.at (hash).get (); } diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx index 8ca8b98ba9..24dc718566 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx @@ -26,13 +26,14 @@ t8_geometry_analytic::t8_geometry_analytic (int dim, std::string name, t8_geom_a t8_geom_analytic_jacobian_fn jacobian_in, t8_geom_load_tree_data_fn load_tree_data_in, t8_geom_tree_negative_volume_fn tree_negative_volume_in, - const void *user_data_in) + t8_geom_tree_compatible_fn tree_compatible_in, const void *user_data_in) : t8_geometry (dim, name + "_" + std::to_string (dim)) { analytical_function = analytical; jacobian = jacobian_in; load_tree_data = load_tree_data_in; tree_negative_volume = tree_negative_volume_in; + tree_compatible = tree_compatible_in; user_data = user_data_in; } @@ -43,6 +44,7 @@ t8_geometry_analytic::t8_geometry_analytic (int dim, std::string name) jacobian = NULL; load_tree_data = NULL; tree_negative_volume = NULL; + tree_compatible = NULL; user_data = NULL; } @@ -87,6 +89,18 @@ t8_geometry_analytic::t8_geom_tree_negative_volume () const } } +bool +t8_geometry_analytic::t8_geom_check_tree_compatibility () const +{ + if (tree_compatible != NULL) { + /* tree_compatible if a loading function was provided. */ + return tree_compatible (); + } + else { + return true; + } +} + T8_EXTERN_C_BEGIN (); void @@ -101,10 +115,11 @@ t8_geometry_analytic_destroy (t8_geometry_c **geom) t8_geometry_c * t8_geometry_analytic_new (int dim, const char *name, t8_geom_analytic_fn analytical, t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, - t8_geom_tree_negative_volume_fn tree_negative_volume, const void *user_data) + t8_geom_tree_negative_volume_fn tree_negative_volume, + t8_geom_tree_compatible_fn tree_compatible, const void *user_data) { - t8_geometry_analytic *geom - = new t8_geometry_analytic (dim, name, analytical, jacobian, load_tree_data, tree_negative_volume, user_data); + t8_geometry_analytic *geom = new t8_geometry_analytic (dim, name, analytical, jacobian, load_tree_data, + tree_negative_volume, tree_compatible, user_data); return (t8_geometry_c *) geom; } diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h index f846437257..1f723a57a8 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h @@ -71,6 +71,11 @@ typedef void (*t8_geom_load_tree_data_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid */ typedef int (*t8_geom_tree_negative_volume_fn) (); +/** + * Definition for the tree compatible function. + */ +typedef int (*t8_geom_tree_compatible_fn) (); + T8_EXTERN_C_BEGIN (); /** Destroy a geometry analytic object. @@ -79,19 +84,31 @@ T8_EXTERN_C_BEGIN (); void t8_geometry_analytic_destroy (t8_geometry_c **geom); -/** Create a new analytical geometry. - * \return A pointer to an allocated geometry struct. - */ +/** + * Create a new analytic geometry with a given dimension. The geometry + * is viable with all tree types and uses a user-provided analytic and + * jacobian function. The actual mappings are done by these functions. + * \param [in] dim The dimension of this geometry. + * \param [in] name The name to give this geometry. + * \param [in] analytical The analytical function to use for this geometry. + * \param [in] jacobian The jacobian of \a analytical. + * \param [in] load_tree_data The function that is used to load a tree's data. + * \param [in] tree_negative_volume_in The function that is used to compute if a trees volume is negative. + * \param [in] tree_compatible_in The function that is used to check if a tree is compatible with the geometry. + * \param [in] user_data Additional user data which the geometry can use. Gets retrieved via \ref t8_geom_analytic_get_user_data. + * \return A pointer to an allocated geometry struct. + */ t8_geometry_c * t8_geometry_analytic_new (int dim, const char *name, t8_geom_analytic_fn analytical, t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, - t8_geom_tree_negative_volume_fn tree_negative_volume, const void *user_data); + t8_geom_tree_negative_volume_fn tree_negative_volume, + t8_geom_tree_compatible_fn tree_compatible, const void *user_data); /** * Load vertex data from given tree. * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree id (in the cmesh). - * \param [out] vertex_out The load tree vertices. + * \param [out] user_data The load tree vertices. */ void t8_geom_load_tree_data_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **user_data); diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx index 53331b82d9..b9ddc1df2c 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx @@ -46,10 +46,13 @@ struct t8_geometry_analytic: public t8_geometry * \param [in] analytical The analytical function to use for this geometry. * \param [in] jacobian The jacobian of \a analytical. * \param [in] load_tree_data The function that is used to load a tree's data. + * \param [in] tree_negative_volume_in The function that is used to compute if a trees volume is negative. + * \param [in] tree_compatible_in The function that is used to check if a tree is compatible with the geometry. */ t8_geometry_analytic (int dim, std::string name, t8_geom_analytic_fn analytical, t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, - t8_geom_tree_negative_volume_fn tree_negative_volume_in, const void *user_data); + t8_geom_tree_negative_volume_fn tree_negative_volume_in, + t8_geom_tree_compatible_fn tree_compatible_in, const void *user_data); /** * Constructor of the analytic geometry for testing purposes. @@ -70,7 +73,7 @@ struct t8_geometry_analytic: public t8_geometry * \return The type. */ inline t8_geometry_type_t - t8_geom_get_type () const + t8_geom_get_type () const override { return T8_GEOMETRY_TYPE_ANALYTIC; }; @@ -83,9 +86,9 @@ struct t8_geometry_analytic: public t8_geometry * \param [in] num_coords Amount of points of \f$ \mathrm{dim} \f$ to map. * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. */ - virtual void + void t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, - double *out_coords) const; + double *out_coords) const override; /** * Compute the jacobian of the \a t8_geom_evaluate map at a point in the reference space \f$ [0,1]^\mathrm{dim} \f$. @@ -100,9 +103,9 @@ struct t8_geometry_analytic: public t8_geometry * dim 1: J = (0) dim 2: J = (0 1) dim 3: J = (0 1 0) * (0) (0 0) (0 0 1) */ - virtual void + void t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, - double *jacobian) const; + double *jacobian) const override; /** * \param[in] forest The forest of the element. @@ -113,10 +116,10 @@ struct t8_geometry_analytic: public t8_geometry * \param[in, out] is_inside Array to fill with flags whether the point is inside or not * \param[in] tolerance Tolerance of the inside-check */ - virtual void + void t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, const double *points, const int num_points, int *is_inside, - const double tolerance) + const double tolerance) const override { SC_ABORTF ("Function not yet implemented"); } @@ -125,8 +128,18 @@ struct t8_geometry_analytic: public t8_geometry * Check if the currently active tree has a negative volume * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. */ - virtual bool - t8_geom_tree_negative_volume () const; + bool + t8_geom_tree_negative_volume () const override; + + /** + * Check for compatibility of the currently loaded tree with the geometry. + * If the geometry has limitations these can be checked here. + * This includes for example if only specific tree types or dimensions are supported. + * If all trees are supported, this function should return true. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const; /** Update a possible internal data buffer for per tree data. * This function is called before the first coordinates in a new tree are @@ -135,8 +148,8 @@ struct t8_geometry_analytic: public t8_geometry * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. */ - virtual void - t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); + void + t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) override; inline const void * t8_geom_analytic_get_user_data () @@ -153,11 +166,13 @@ struct t8_geometry_analytic: public t8_geometry t8_geom_tree_negative_volume_fn tree_negative_volume; /**< The function to check for negative volumes. */ + t8_geom_tree_compatible_fn tree_compatible; /**< The function to check if a tree is compatible. */ + const void *tree_data; /** Tree data pointer that can be set in \a load_tree_data and - is passed onto \a analytical_function and \a jacobian. */ + is passed onto \a analytical_function and \a jacobian. */ const void *user_data; /** Additional user data pointer that can be set in constructor - * and modified via \ref t8_geom_analytic_get_user_data. */ + and modified via \ref t8_geom_analytic_get_user_data. */ }; #endif /* !T8_GEOMETRY_ANALYTICAL_HXX */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx index 44c4b8fb18..c4b3e0ab6f 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx @@ -135,6 +135,17 @@ struct t8_geometry_cad: public t8_geometry_with_vertices virtual void t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); + /** + * Check for compatibility of the currently loaded tree with the geometry. + * This geometry supports all element types, hence it returns true. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const + { + return true; + } + /** Check if a cad_curve is a line. * \param [in] curve_index The index of the cad_curve. * \return 1 if curve is a line, 0 if curve is not a line. diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx index 31672c465d..04fcadf40f 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx @@ -20,6 +20,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include #include #include @@ -211,7 +212,7 @@ t8_geometry_cubed_spherical_shell::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx const double distance = std::abs (t8_vec_dot (active_tree_vertices, normal)); // Compute actual radius of the sphere. - constexpr double CBRT = std::cbrt (1.0); + const double CBRT = std::cbrt (1.0); const double inner_radius = distance * CBRT; const double shell_thickness = std::abs (t8_vec_dot (active_tree_vertices + t8_eclass_num_vertices[active_tree_class] * 3 / 2, normal)) * CBRT diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.cxx index f151a90ee5..c6c69b9859 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.cxx @@ -47,6 +47,7 @@ t8_geometry_lagrange::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, c { if (num_points != 1) SC_ABORT ("Error: Batch computation of geometry not yet supported."); + T8_ASSERT (t8_geom_check_tree_compatibility ()); const auto basis_functions = t8_geometry_lagrange::t8_geom_compute_basis (ref_coords); const size_t n_vertex = basis_functions.size (); for (size_t i_component = 0; i_component < T8_ECLASS_MAX_DIM; i_component++) { @@ -71,8 +72,9 @@ inline void t8_geometry_lagrange::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) { t8_geometry_with_vertices::t8_geom_load_tree_data (cmesh, gtreeid); - t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); - degree = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE, ltreeid); + const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); + degree + = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, ltreeid); T8_ASSERT (degree != NULL); } @@ -114,6 +116,25 @@ t8_geometry_lagrange::t8_geom_compute_basis (const double *ref_coords) const } } +bool +t8_geometry_lagrange::t8_geom_check_tree_compatibility () const +{ + if (*degree > T8_GEOMETRY_MAX_POLYNOMIAL_DEGREE) { + t8_debugf ("Lagrange tree with degree %i detected.\n" + "Only degrees up to %i are supported.", + *degree, T8_GEOMETRY_MAX_POLYNOMIAL_DEGREE); + return false; + } + if (active_tree_class != T8_ECLASS_LINE && active_tree_class != T8_ECLASS_TRIANGLE + && active_tree_class != T8_ECLASS_QUAD && active_tree_class != T8_ECLASS_HEX) { + t8_debugf ("Lagrange tree with class %i detected.\n" + "Only lines, triangles, quadrilaterals and hexahedra are supported with the lagrangian geometry.\n", + active_tree_class); + return false; + } + return true; +} + inline std::vector t8_geometry_lagrange::t8_geom_s2_basis (const double *ref_point) const { @@ -272,7 +293,7 @@ t8_lagrange_element::t8_lagrange_element (t8_eclass_t eclass, uint32_t degree, s /* Create a cmesh with a single element */ int dim = t8_eclass_to_dimension[eclass]; t8_cmesh_init (&cmesh); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE, °ree, sizeof (int), 1); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, °ree, sizeof (int), 1); t8_cmesh_register_geometry (cmesh, dim); t8_cmesh_set_tree_class (cmesh, 0, eclass); t8_cmesh_set_tree_vertices (cmesh, 0, nodes.data (), nodes.size ()); diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx index 3c3bbb4cff..0fbe66ef00 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx @@ -153,6 +153,14 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices virtual void t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); + /** + * Check for compatibility of the currently loaded tree with the geometry. + * This geometry supports lines, triangles, quadrilaterals and hexahedra up to degree 2. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const; + private: /** * Evaluates the basis functions of the current tree type at a point. diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx index 0141f731a8..db757e73be 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx @@ -104,6 +104,17 @@ struct t8_geometry_linear: public t8_geometry_with_vertices const double *points, const int num_points, int *is_inside, const double tolerance) const; + /** + * Check for compatibility of the currently loaded tree with the geometry. + * This geometry supports all element types, hence it returns true. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const + { + return true; + } + /* Load tree data is inherited from t8_geometry_with_vertices. */ }; diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx index b5eae50f1d..893663f2c5 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx @@ -107,11 +107,29 @@ struct t8_geometry_linear_axis_aligned: public t8_geometry_with_vertices const double tolerance) const; /** - * Check if the currently active tree has a negative volume - * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. + * Check if the currently active tree has a negative volume. + * \return True if the currently loaded tree has a negative volume. */ virtual bool t8_geom_tree_negative_volume () const; + + /** + * Check for compatibility of the currently loaded tree with the geometry. + * Only line, quad and hex elements are supported by this geometry. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const + { + if (active_tree_class != T8_ECLASS_LINE && active_tree_class != T8_ECLASS_QUAD + && active_tree_class != T8_ECLASS_HEX) { + t8_productionf ("Axis-aligned geometry is not compatible with tree type %s\n It is only compatible with line, " + "quad and hex elements.\n", + t8_eclass_to_string[active_tree_class]); + return false; + } + return true; + } }; #endif /* !T8_GEOMETRY_LINEAR_AXIS_ALIGNED_HXX */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx index 94b56ecb7c..12c7796ffd 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx @@ -49,8 +49,8 @@ struct t8_geometry_zero: public t8_geometry * Check if the currently active tree has a negative volume * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. */ - virtual bool - t8_geom_tree_negative_volume () const + bool + t8_geom_tree_negative_volume () const override { return 0; }; @@ -65,7 +65,7 @@ struct t8_geometry_zero: public t8_geometry * \return The type. */ inline t8_geometry_type_t - t8_geom_get_type () const + t8_geom_get_type () const override { return T8_GEOMETRY_TYPE_ZERO; }; @@ -79,9 +79,9 @@ struct t8_geometry_zero: public t8_geometry * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. * \note All entries in out_coords will be set to 0. */ - virtual void + void t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, - double *out_coords) const; + double *out_coords) const override; /** * Compute the jacobian of the \a t8_geom_evaluate map at a point in the reference space \f$ [0,1]^\mathrm{dim} \f$. @@ -93,9 +93,9 @@ struct t8_geometry_zero: public t8_geometry * correspond to the \f$ i \f$-th column of the jacobian (Entry \f$ 3 \cdot i + j \f$ is \f$ \frac{\partial f_j}{\partial x_i} \f$). * \note All entries in \a jacobian will be set to zero. */ - virtual void + void t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, - double *jacobian) const; + double *jacobian) const override; /** * \param[in] forest The forest of the element. @@ -106,10 +106,10 @@ struct t8_geometry_zero: public t8_geometry * \param[in, out] is_inside Array to fill with flags whether the point is inside or not * \param[in] tolerance Tolerance of the inside-check */ - virtual void + void t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, const double *points, const int num_points, int *is_inside, - const double tolerance) + const double tolerance) const override { const double zeros[3] = { 0 }; for (int i_point = 0; i_point < num_points; ++i_point) { @@ -125,8 +125,19 @@ struct t8_geometry_zero: public t8_geometry * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. */ - virtual inline void - t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); + inline void + t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) override; + + /** + * Check for compatibility of the currently loaded tree with the geometry. + * This geometry supports all element types, hence it returns true. + * \return True if the geometry is compatible with the tree. + */ + bool + t8_geom_check_tree_compatibility () const override + { + return true; + } }; #endif /* !T8_GEOMETRY_ZERO_HXX */ diff --git a/src/t8_geometry/t8_geometry_with_vertices.cxx b/src/t8_geometry/t8_geometry_with_vertices.cxx index 9ef5d14c28..33f591d478 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.cxx +++ b/src/t8_geometry/t8_geometry_with_vertices.cxx @@ -32,24 +32,13 @@ void t8_geometry_with_vertices::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) { - /* Set active id and eclass */ - t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); - active_tree = gtreeid; - const t8_locidx_t num_local_trees = t8_cmesh_get_num_local_trees (cmesh); - if (0 <= ltreeid && ltreeid < num_local_trees) { - active_tree_class = t8_cmesh_get_tree_class (cmesh, ltreeid); - } - else { - active_tree_class = t8_cmesh_get_ghost_class (cmesh, ltreeid - num_local_trees); - } + t8_geometry::t8_geom_load_tree_data (cmesh, gtreeid); /* Load this trees vertices. */ + const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); active_tree_vertices = t8_cmesh_get_tree_vertices (cmesh, ltreeid); - - /* Check whether we support this class */ - T8_ASSERT (active_tree_class == T8_ECLASS_VERTEX || active_tree_class == T8_ECLASS_TRIANGLE - || active_tree_class == T8_ECLASS_TET || active_tree_class == T8_ECLASS_QUAD - || active_tree_class == T8_ECLASS_HEX || active_tree_class == T8_ECLASS_LINE - || active_tree_class == T8_ECLASS_PRISM || active_tree_class == T8_ECLASS_PYRAMID); +#if T8_ENABLE_DEBUG + SC_CHECK_ABORTF (active_tree_vertices != NULL, "ERROR: No vertices found for tree %li\n", (long) ltreeid); +#endif } bool diff --git a/src/t8_geometry/t8_geometry_with_vertices.hxx b/src/t8_geometry/t8_geometry_with_vertices.hxx index dbaeb8e3af..57c1c82b93 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.hxx +++ b/src/t8_geometry/t8_geometry_with_vertices.hxx @@ -93,8 +93,6 @@ struct t8_geometry_with_vertices: public t8_geometry }; protected: - t8_gloidx_t active_tree; /*< The tree of which currently vertices are loaded. */ - t8_eclass_t active_tree_class; /*< The class of the currently active tree. */ const double* active_tree_vertices; /*< The vertices of the currently active tree. */ }; diff --git a/src/t8_schemes/t8_default/t8_default_common/t8_default_common.hxx b/src/t8_schemes/t8_default/t8_default_common/t8_default_common.hxx index 528840d8d0..e40861ca88 100644 --- a/src/t8_schemes/t8_default/t8_default_common/t8_default_common.hxx +++ b/src/t8_schemes/t8_default/t8_default_common/t8_default_common.hxx @@ -41,20 +41,20 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { t8_element_deinit (int length, t8_element_t *elem) const override; /** Compute the number of corners of a given element. */ - virtual int - t8_element_num_corners (const t8_element_t *elem) const; + int + t8_element_num_corners (const t8_element_t *elem) const override; /** Allocate space for a bunch of elements. */ - virtual void - t8_element_new (int length, t8_element_t **elem) const; + void + t8_element_new (int length, t8_element_t **elem) const override; /** Deallocate space for a bunch of elements. */ - virtual void - t8_element_destroy (int length, t8_element_t **elem) const; + void + t8_element_destroy (int length, t8_element_t **elem) const override; /** Return the shape of an element */ - virtual t8_element_shape_t - t8_element_shape (const t8_element_t *elem) const; + t8_element_shape_t + t8_element_shape (const t8_element_t *elem) const override; /** Count how many leaf descendants of a given uniform level an element would produce. * \param [in] t The element to be checked. @@ -64,8 +64,8 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { * Each default element (except pyramids) refines into 2^{dim * (level - level(t))} * children. */ - virtual t8_gloidx_t - t8_element_count_leaves (const t8_element_t *t, int level) const; + t8_gloidx_t + t8_element_count_leaves (const t8_element_t *t, int level) const override; /** Compute the number of siblings of an element. That is the number of * Children of its parent. @@ -73,16 +73,16 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { * \return The number of siblings of \a element. * Note that this number is >= 1, since we count the element itself as a sibling. */ - virtual int - t8_element_num_siblings (const t8_element_t *elem) const; + int + t8_element_num_siblings (const t8_element_t *elem) const override; /** Count how many leaf descendants of a given uniform level the root element will produce. * \param [in] level A refinement level. * \return The value of \ref t8_element_count_leaves if the input element * is the root (level 0) element. */ - virtual t8_gloidx_t - t8_element_count_leaves_from_root (int level) const; + t8_gloidx_t + t8_element_count_leaves_from_root (int level) const override; /** Compute the integer coordinates of a given element vertex. * The default scheme implements the Morton type SFCs. In these SFCs the @@ -108,9 +108,9 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { * \param [out] out_coords The coordinates of the points in the * reference space of the tree. */ - virtual void + void t8_element_reference_coords (const t8_element_t *elem, const double *ref_coords, const size_t num_coords, - double *out_coords) const + double *out_coords) const override = 0; /** Get the integer coordinates of the anchor node of an element. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d1475130b3..e0b14bcc28 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,13 +7,47 @@ function( add_t8_test ) set( multiValueArgs "SOURCES" ) cmake_parse_arguments( ADD_T8_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + # Get the path of the second file listed in the SOURCES list (if there is one then from the first) and use it to determine the build directory. + # We use the second file, because the first is t8_gtest_main, which is in the root test dir. The executable will be build in the same directory as the second source file. + list (LENGTH ADD_T8_TEST_SOURCES TEST_SOURCES_LENGTH) + if ( TEST_SOURCES_LENGTH GREATER 1 ) + list(GET ADD_T8_TEST_SOURCES 1 TEST_SOURCE) + else() + list(GET ADD_T8_TEST_SOURCES 0 TEST_SOURCE) + endif() + get_filename_component(TEST_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${TEST_SOURCE}" DIRECTORY) + file(RELATIVE_PATH TEST_RELATIVE_DIR "${CMAKE_SOURCE_DIR}" "${TEST_SOURCE_DIR}") + set(TEST_BUILD_DIR "${CMAKE_BINARY_DIR}/${TEST_RELATIVE_DIR}") + add_executable( ${ADD_T8_TEST_NAME} ${ADD_T8_TEST_SOURCES} ) target_link_libraries( ${ADD_T8_TEST_NAME} PRIVATE T8 gtest pthread) + set_target_properties(${ADD_T8_TEST_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${TEST_BUILD_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${TEST_BUILD_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${TEST_BUILD_DIR}" + ) + + if( T8CODE_EXPORT_COMPILE_COMMANDS ) + set_target_properties( ${ADD_T8_TEST_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) + endif( T8CODE_EXPORT_COMPILE_COMMANDS ) + # Split custom test command into a list by whitespace. - separate_arguments (T8CODE_CUSTOM_TEST_COMMAND_LIST NATIVE_COMMAND "${T8CODE_CUSTOM_TEST_COMMAND}") + # If MPI is enabled, and no custom test command is provided, use mpirun -np 4 as the default command. + # If MPI is not enabled, use the custom test command as is. + if ( T8CODE_ENABLE_MPI ) + if (${ADD_T8_TEST_NAME} MATCHES "_serial") + separate_arguments(T8CODE_TEST_COMMAND_LIST NATIVE_COMMAND ${T8CODE_CUSTOM_SERIAL_TEST_COMMAND}) + elseif ( T8CODE_CUSTOM_PARALLEL_TEST_COMMAND STREQUAL "" ) + separate_arguments (T8CODE_TEST_COMMAND_LIST NATIVE_COMMAND "mpirun -np 4") + else ( T8CODE_CUSTOM_PARALLEL_TEST_COMMAND STREQUAL "" ) + separate_arguments (T8CODE_TEST_COMMAND_LIST NATIVE_COMMAND ${T8CODE_CUSTOM_PARALLEL_TEST_COMMAND}) + endif () + else( T8CODE_ENABLE_MPI ) + separate_arguments (T8CODE_TEST_COMMAND_LIST NATIVE_COMMAND ${T8CODE_CUSTOM_SERIAL_TEST_COMMAND}) + endif ( T8CODE_ENABLE_MPI ) - add_test( NAME ${ADD_T8_TEST_NAME} COMMAND ${T8CODE_CUSTOM_TEST_COMMAND_LIST} ./${ADD_T8_TEST_NAME} ) + add_test( NAME ${ADD_T8_TEST_NAME} COMMAND ${T8CODE_TEST_COMMAND_LIST} ${TEST_BUILD_DIR}/${ADD_T8_TEST_NAME} ) endfunction() # Copy test files to build folder so that the t8_test programs can find them. @@ -21,82 +55,82 @@ function( copy_test_file TEST_FILE_NAME ) configure_file(${CMAKE_CURRENT_LIST_DIR}/testfiles/${TEST_FILE_NAME} ${CMAKE_CURRENT_BINARY_DIR}/test/testfiles/${TEST_FILE_NAME} COPYONLY) endfunction() -add_t8_test( NAME t8_gtest_cmesh_bcast SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_bcast.cxx ) -add_t8_test( NAME t8_gtest_eclass SOURCES t8_gtest_main.cxx t8_gtest_eclass.cxx ) -add_t8_test( NAME t8_gtest_vec SOURCES t8_gtest_main.cxx t8_gtest_vec.cxx ) -add_t8_test( NAME t8_gtest_mat SOURCES t8_gtest_main.cxx t8_gtest_mat.cxx ) -add_t8_test( NAME t8_gtest_refcount SOURCES t8_gtest_main.cxx t8_gtest_refcount.cxx ) -add_t8_test( NAME t8_gtest_occ_linkage SOURCES t8_gtest_main.cxx t8_gtest_occ_linkage.cxx ) -add_t8_test( NAME t8_gtest_version SOURCES t8_gtest_main.cxx t8_gtest_version.cxx ) -add_t8_test( NAME t8_gtest_basics SOURCES t8_gtest_main.cxx t8_gtest_basics.cxx ) -add_t8_test( NAME t8_gtest_netcdf_linkage SOURCES t8_gtest_main.cxx t8_gtest_netcdf_linkage.cxx ) -add_t8_test( NAME t8_gtest_vtk_linkage SOURCES t8_gtest_main.cxx t8_gtest_vtk_linkage.cxx ) - -add_t8_test( NAME t8_gtest_hypercube SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_hypercube.cxx ) -add_t8_test( NAME t8_gtest_cmesh_readmshfile SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_readmshfile.cxx ) -add_t8_test( NAME t8_gtest_cmesh_copy SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_copy.cxx ) -add_t8_test( NAME t8_gtest_cmesh_face_is_boundary SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx ) -add_t8_test( NAME t8_gtest_cmesh_partition SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_partition.cxx ) -add_t8_test( NAME t8_gtest_cmesh_set_partition_offsets SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_partition_offsets.cxx ) -add_t8_test( NAME t8_gtest_cmesh_set_join_by_vertices SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx ) -add_t8_test( NAME t8_gtest_cmesh_add_attributes_when_derive SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_add_attributes_when_derive.cxx ) -add_t8_test( NAME t8_gtest_cmesh_tree_vertices_negative_volume SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx ) - -add_t8_test( NAME t8_gtest_multiple_attributes SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_multiple_attributes.cxx ) -add_t8_test( NAME t8_gtest_attribute_gloidx_array SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_attribute_gloidx_array.cxx ) - -add_t8_test( NAME t8_gtest_shmem SOURCES t8_gtest_main.cxx t8_data/t8_gtest_shmem.cxx ) - -add_t8_test( NAME t8_gtest_element_volume SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_volume.cxx ) -add_t8_test( NAME t8_gtest_search SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_search.cxx ) -add_t8_test( NAME t8_gtest_half_neighbors SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_half_neighbors.cxx ) -add_t8_test( NAME t8_gtest_find_owner SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_find_owner.cxx ) -add_t8_test( NAME t8_gtest_user_data SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_user_data.cxx ) -add_t8_test( NAME t8_gtest_transform SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_transform.cxx ) -add_t8_test( NAME t8_gtest_ghost_exchange SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_exchange.cxx ) -add_t8_test( NAME t8_gtest_ghost_delete SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_delete.cxx ) -add_t8_test( NAME t8_gtest_ghost_and_owner SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_and_owner.cxx ) -add_t8_test( NAME t8_gtest_balance SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_balance.cxx ) -add_t8_test( NAME t8_gtest_forest_commit SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) -add_t8_test( NAME t8_gtest_forest_face_normal SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) -add_t8_test( NAME t8_gtest_element_is_leaf SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) -add_t8_test( NAME t8_gtest_element_is_boundary SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) -add_t8_test( NAME t8_gtest_partition_data SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_partition_data.cxx ) - -add_t8_test( NAME t8_gtest_permute_hole SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) -add_t8_test( NAME t8_gtest_recursive SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) -add_t8_test( NAME t8_gtest_iterate_replace SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_iterate_replace.cxx ) -add_t8_test( NAME t8_gtest_empty_local_tree SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_local_tree.cxx ) -add_t8_test( NAME t8_gtest_empty_global_tree SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_global_tree.cxx ) - -add_t8_test( NAME t8_gtest_geometry_cad SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx ) -add_t8_test( NAME t8_gtest_geometry_linear SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx ) -add_t8_test( NAME t8_gtest_geometry_lagrange SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx ) -add_t8_test( NAME t8_gtest_geometry_triangular_interpolation SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_geometry_triangular_interpolation.cxx ) -add_t8_test( NAME t8_gtest_geometry_handling SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_geometry_handling.cxx ) -add_t8_test( NAME t8_gtest_point_inside SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_point_inside.cxx ) - -add_t8_test( NAME t8_gtest_vtk_reader SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_reader.cxx ) -add_t8_test( NAME t8_gtest_vtk_writer SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_writer.cxx ) - -add_t8_test( NAME t8_gtest_nca SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) -add_t8_test( NAME t8_gtest_pyra_connectivity SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx ) -add_t8_test( NAME t8_gtest_face_neigh SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_neigh.cxx ) -add_t8_test( NAME t8_gtest_init_linear_id SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_init_linear_id.cxx ) -add_t8_test( NAME t8_gtest_ancestor SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_ancestor.cxx ) -add_t8_test( NAME t8_gtest_element_count_leaves SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_count_leaves.cxx ) -add_t8_test( NAME t8_gtest_element_ref_coords SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_ref_coords.cxx ) -add_t8_test( NAME t8_gtest_descendant SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_descendant.cxx ) -add_t8_test( NAME t8_gtest_find_parent SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_find_parent.cxx ) -add_t8_test( NAME t8_gtest_equal SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_equal.cxx ) -add_t8_test( NAME t8_gtest_successor SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_successor.cxx ) -add_t8_test( NAME t8_gtest_boundary_extrude SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_boundary_extrude.cxx ) -add_t8_test( NAME t8_gtest_face_descendant SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_descendant.cxx ) -add_t8_test( NAME t8_gtest_default SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_default.cxx ) -add_t8_test( NAME t8_gtest_child_parent_face SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_child_parent_face.cxx ) -add_t8_test( NAME t8_gtest_pack_unpack SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pack_unpack.cxx ) -add_t8_test( NAME t8_gtest_root SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_root.cxx ) -add_t8_test( NAME t8_gtest_scheme_consistency SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_scheme_consistency.cxx ) +add_t8_test( NAME t8_gtest_cmesh_bcast_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_bcast.cxx ) +add_t8_test( NAME t8_gtest_eclass_serial SOURCES t8_gtest_main.cxx t8_gtest_eclass.cxx ) +add_t8_test( NAME t8_gtest_vec_serial SOURCES t8_gtest_main.cxx t8_gtest_vec.cxx ) +add_t8_test( NAME t8_gtest_mat_serial SOURCES t8_gtest_main.cxx t8_gtest_mat.cxx ) +add_t8_test( NAME t8_gtest_refcount_serial SOURCES t8_gtest_main.cxx t8_gtest_refcount.cxx ) +add_t8_test( NAME t8_gtest_occ_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_occ_linkage.cxx ) +add_t8_test( NAME t8_gtest_version_serial SOURCES t8_gtest_main.cxx t8_gtest_version.cxx ) +add_t8_test( NAME t8_gtest_basics_serial SOURCES t8_gtest_main.cxx t8_gtest_basics.cxx ) +add_t8_test( NAME t8_gtest_netcdf_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_netcdf_linkage.cxx ) +add_t8_test( NAME t8_gtest_vtk_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_vtk_linkage.cxx ) + +add_t8_test( NAME t8_gtest_hypercube_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_hypercube.cxx ) +add_t8_test( NAME t8_gtest_cmesh_readmshfile_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_readmshfile.cxx ) +add_t8_test( NAME t8_gtest_cmesh_copy_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_copy.cxx ) +add_t8_test( NAME t8_gtest_cmesh_face_is_boundary_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx ) +add_t8_test( NAME t8_gtest_cmesh_partition_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_partition.cxx ) +add_t8_test( NAME t8_gtest_cmesh_set_partition_offsets_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_partition_offsets.cxx ) +add_t8_test( NAME t8_gtest_cmesh_set_join_by_vertices_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx ) +add_t8_test( NAME t8_gtest_cmesh_add_attributes_when_derive_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_add_attributes_when_derive.cxx ) +add_t8_test( NAME t8_gtest_cmesh_tree_vertices_negative_volume_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx ) + +add_t8_test( NAME t8_gtest_multiple_attributes_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_multiple_attributes.cxx ) +add_t8_test( NAME t8_gtest_attribute_gloidx_array_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_attribute_gloidx_array.cxx ) + +add_t8_test( NAME t8_gtest_shmem_parallel SOURCES t8_gtest_main.cxx t8_data/t8_gtest_shmem.cxx ) + +add_t8_test( NAME t8_gtest_element_volume_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_volume.cxx ) +add_t8_test( NAME t8_gtest_search_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_search.cxx ) +add_t8_test( NAME t8_gtest_half_neighbors_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_half_neighbors.cxx ) +add_t8_test( NAME t8_gtest_find_owner_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_find_owner.cxx ) +add_t8_test( NAME t8_gtest_user_data_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_user_data.cxx ) +add_t8_test( NAME t8_gtest_transform_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_transform.cxx ) +add_t8_test( NAME t8_gtest_ghost_exchange_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_exchange.cxx ) +add_t8_test( NAME t8_gtest_ghost_delete_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_delete.cxx ) +add_t8_test( NAME t8_gtest_ghost_and_owner_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_and_owner.cxx ) +add_t8_test( NAME t8_gtest_balance_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_balance.cxx ) +add_t8_test( NAME t8_gtest_forest_commit_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) +add_t8_test( NAME t8_gtest_forest_face_normal_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) +add_t8_test( NAME t8_gtest_element_is_leaf_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) +add_t8_test( NAME t8_gtest_element_is_boundary_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) +add_t8_test( NAME t8_gtest_partition_data_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_partition_data.cxx ) + +add_t8_test( NAME t8_gtest_permute_hole_serial SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) +add_t8_test( NAME t8_gtest_recursive_serial SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) +add_t8_test( NAME t8_gtest_iterate_replace_serial SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_iterate_replace.cxx ) +add_t8_test( NAME t8_gtest_empty_local_tree_parallel SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_local_tree.cxx ) +add_t8_test( NAME t8_gtest_empty_global_tree_parallel SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_global_tree.cxx ) + +add_t8_test( NAME t8_gtest_geometry_cad_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx ) +add_t8_test( NAME t8_gtest_geometry_linear_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx ) +add_t8_test( NAME t8_gtest_geometry_lagrange_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx ) +add_t8_test( NAME t8_gtest_geometry_triangular_interpolation_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_geometry_triangular_interpolation.cxx ) +add_t8_test( NAME t8_gtest_geometry_handling_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_geometry_handling.cxx ) +add_t8_test( NAME t8_gtest_point_inside_serial SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_point_inside.cxx ) + +add_t8_test( NAME t8_gtest_vtk_reader_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_reader.cxx ) +add_t8_test( NAME t8_gtest_vtk_writer_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_writer.cxx ) + +add_t8_test( NAME t8_gtest_nca_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) +add_t8_test( NAME t8_gtest_pyra_connectivity_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx ) +add_t8_test( NAME t8_gtest_face_neigh_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_neigh.cxx ) +add_t8_test( NAME t8_gtest_init_linear_id_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_init_linear_id.cxx ) +add_t8_test( NAME t8_gtest_ancestor_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_ancestor.cxx ) +add_t8_test( NAME t8_gtest_element_count_leaves_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_count_leaves.cxx ) +add_t8_test( NAME t8_gtest_element_ref_coords_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_ref_coords.cxx ) +add_t8_test( NAME t8_gtest_descendant_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_descendant.cxx ) +add_t8_test( NAME t8_gtest_find_parent_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_find_parent.cxx ) +add_t8_test( NAME t8_gtest_equal_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_equal.cxx ) +add_t8_test( NAME t8_gtest_successor_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_successor.cxx ) +add_t8_test( NAME t8_gtest_boundary_extrude_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_boundary_extrude.cxx ) +add_t8_test( NAME t8_gtest_face_descendant_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_descendant.cxx ) +add_t8_test( NAME t8_gtest_default_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_default.cxx ) +add_t8_test( NAME t8_gtest_child_parent_face_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_child_parent_face.cxx ) +add_t8_test( NAME t8_gtest_pack_unpack_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pack_unpack.cxx ) +add_t8_test( NAME t8_gtest_root_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_root.cxx ) +add_t8_test( NAME t8_gtest_scheme_consistency_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_scheme_consistency.cxx ) copy_test_file( test_cube_unstructured_1.inp ) copy_test_file( test_cube_unstructured_2.inp ) diff --git a/test/t8_cmesh/t8_gtest_hypercube.cxx b/test/t8_cmesh/t8_gtest_hypercube.cxx index 7062cad8cc..2228263236 100644 --- a/test/t8_cmesh/t8_gtest_hypercube.cxx +++ b/test/t8_cmesh/t8_gtest_hypercube.cxx @@ -63,7 +63,7 @@ TEST_P (cmesh_hypercube_trees, check_cmesh_and_its_trees) ASSERT_EQ (t8_cmesh_get_dimension (cmesh), t8_eclass_to_dimension[eclass]) << "Wrong dimension set for cmesh."; } -/* Use the testing range for eclass with [T8_ECLASS_ZERO, T8_ECLASS_COUNT]. For the generation of the cmesh with or withaout broadcast +/* Use the testing range for eclass with [T8_ECLASS_ZERO, T8_ECLASS_COUNT]. For the generation of the cmesh with or without broadcast * the booleans 0 and 1 are used. Analogue with partition. */ INSTANTIATE_TEST_SUITE_P (t8_gtest_hypercube, cmesh_hypercube_trees, testing::Combine (AllEclasses, testing::Values (0, 1), testing::Values (0, 1))); diff --git a/test/t8_forest/t8_gtest_element_volume.cxx b/test/t8_forest/t8_gtest_element_volume.cxx index 5edc73ea33..a44c990fe1 100644 --- a/test/t8_forest/t8_gtest_element_volume.cxx +++ b/test/t8_forest/t8_gtest_element_volume.cxx @@ -33,7 +33,6 @@ /** * This file tests the volume-computation of elements. */ -#define epsilon 1e-9 /* Construct a forest of a hypercube with volume 1. If the element are refined uniformly * all elements have volume 1/global_num_elements. */ @@ -109,10 +108,10 @@ TEST_P (t8_forest_volume, volume_check) const double volume = t8_forest_element_volume (forest, itree, element); if (eclass == T8_ECLASS_PYRAMID) { const double shape_volume = pyramid_control_volume ((t8_dpyramid_t *) element); - EXPECT_NEAR (volume, shape_volume, epsilon); + EXPECT_NEAR (volume, shape_volume, T8_PRECISION_SQRT_EPS); } else { - EXPECT_NEAR (volume, control_volume, epsilon); + EXPECT_NEAR (volume, control_volume, T8_PRECISION_SQRT_EPS); } } } diff --git a/test/t8_forest/t8_gtest_forest_commit.cxx b/test/t8_forest/t8_gtest_forest_commit.cxx index 0fb6be0b67..3ab727f497 100644 --- a/test/t8_forest/t8_gtest_forest_commit.cxx +++ b/test/t8_forest/t8_gtest_forest_commit.cxx @@ -30,7 +30,7 @@ #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include -/* In this test, we adapt, balance and partition a uniform forest. +/* In this test we adapt, balance and partition a uniform forest. * We do this in two ways: * 1st All operations are performed in one single call to t8_forest_commit * 2nd Each intermediate step is performed in a separate commit diff --git a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx index 8fd697abff..ce849ef8a9 100644 --- a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx +++ b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx @@ -35,9 +35,8 @@ #include #include #include -#include +#include #include - #include #include #include @@ -250,3 +249,70 @@ INSTANTIATE_TEST_SUITE_P (t8_gtest_geometry_lagrange, LagrangeCmesh, << "_degree" << std::get<1> (info.param); return test_name.str ();}); /* clang-format on */ + +#if T8_ENABLE_DEBUG + +/** + * Tests the compatibility checking for the Lagrange geometry. + * The geometry should throw assertions if the geometry is not compatible with an assigned tree. + */ +TEST (test_geometry_lagrange, incompatible_geometry) +{ + t8_cmesh_t cmesh; + int degree = 1; + + t8_debugf ("Testing geometry compatibility checking for lagrange geometry.\n"); + + /* Build a simple set geometries for the tree. */ + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_QUAD], 4); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, °ree, sizeof (degree), + 0); + + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + /* Register the t8_geometry_lagrange geometry to this cmesh. */ + t8_cmesh_register_geometry (cmesh, 2); + /* Should return true since the t8_geometry_lagrange geometry is compatible with quads. */ + ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh)); + t8_cmesh_destroy (&cmesh); + + /* Build a simple set geometries for the tree. */ + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_HEX); + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_HEX], 8); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, °ree, sizeof (degree), + 0); + t8_cmesh_set_tree_class (cmesh, 1, T8_ECLASS_PRISM); + t8_cmesh_set_tree_vertices (cmesh, 1, *t8_element_corner_ref_coords[T8_ECLASS_PRISM], 6); + t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, °ree, sizeof (degree), + 0); + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + /* Register the t8_geometry_lagrange to this cmesh. + * We register it after committing because it would throw an assertion and we do not have death tests.*/ + t8_cmesh_register_geometry (cmesh, 3); + /* Check validity after committing to circumvent the assertion. + * Should return false since the t8_geometry_lagrange geometry is not compatible with prisms. */ + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + t8_cmesh_destroy (&cmesh); + + degree = T8_GEOMETRY_MAX_POLYNOMIAL_DEGREE + 1; + /* Build a simple set geometries for the tree. */ + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_HEX); + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_HEX], 8); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_LAGRANGE_POLY_DEGREE_KEY, °ree, sizeof (degree), + 0); + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + /* Register the t8_geometry_lagrange to this cmesh. + * We register it after committing because it would throw an assertion and we do not have death tests.*/ + t8_cmesh_register_geometry (cmesh, 3); + /* Check validity after committing to circumvent the assertion. + * Should return false since the maximum polynomial degree is exceeded. */ + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + t8_cmesh_destroy (&cmesh); +} +#endif /* T8_ENABLE_DEBUG */ diff --git a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx index a3979dad77..6627dd9141 100644 --- a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx +++ b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx @@ -160,3 +160,40 @@ INSTANTIATE_TEST_SUITE_P ( t8_gtest_geometry, geometry_test, ::testing::Combine (::testing::Values (T8_GEOMETRY_TYPE_LINEAR, T8_GEOMETRY_TYPE_LINEAR_AXIS_ALIGNED), AllEclasses), print_test); + +#ifdef T8_ENABLE_DEBUG +TEST (test_geometry_linear, incompatible_geometry) +{ + t8_cmesh_t cmesh; + + t8_debugf ("Testing geometry compatibility checking for linear axis aligned geometry.\n"); + + /* Build a simple set geometries for the tree. */ + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_QUAD], 4); + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + /* Register the t8_geometry_linear_axis_aligned geometry to this cmesh. */ + t8_cmesh_register_geometry (cmesh, 2); + /* Should return true since the t8_geometry_linear_axis_aligned geometry is compatible with quads. */ + ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh)); + t8_cmesh_destroy (&cmesh); + + /* Build a simple set geometries for the tree. */ + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_TRIANGLE); + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_TRIANGLE], 3); + t8_cmesh_set_tree_class (cmesh, 1, T8_ECLASS_QUAD); + t8_cmesh_set_tree_vertices (cmesh, 1, *t8_element_corner_ref_coords[T8_ECLASS_QUAD], 4); + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + /* Register the linear axis aligned geometry to this cmesh. + * We register it after committing because it would throw an assertion and do not have death tests.*/ + t8_cmesh_register_geometry (cmesh, 2); + /* Check validity after committing to circumvent the assertion. + * Should return false since the t8_geometry_linear_axis_aligned geometry is not compatible with triangles. */ + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + t8_cmesh_destroy (&cmesh); +} +#endif /* T8_ENABLE_DEBUG */ diff --git a/test/t8_geometry/t8_gtest_geometry_handling.cxx b/test/t8_geometry/t8_gtest_geometry_handling.cxx index 3591972a8e..9ccf87c85d 100644 --- a/test/t8_geometry/t8_gtest_geometry_handling.cxx +++ b/test/t8_geometry/t8_gtest_geometry_handling.cxx @@ -120,6 +120,8 @@ TEST (test_geometry, cmesh_two_trees_and_geometries) /* Build a simple 2 tree cmesh and set geometries for the trees. */ t8_cmesh_init (&cmesh); t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); + /* We will assign a linear geometry, so we need vertices. */ + t8_cmesh_set_tree_vertices (cmesh, 0, *t8_element_corner_ref_coords[T8_ECLASS_QUAD], 4); t8_cmesh_set_tree_class (cmesh, 1, T8_ECLASS_TRIANGLE); /* Register the linear geometry and zero geometry to this cmesh. */ auto linear_geom = t8_cmesh_register_geometry (cmesh, 2); @@ -163,11 +165,11 @@ TEST (test_geometry, cmesh_geometry_unique) t8_debugf ("Testing cmesh tree geometry get with unique geometry.\n"); - /* Build a simple 2 tree cmesh and set geometries for the trees. */ + /* Build a simple 1 tree cmesh and set geometry for the trees. */ t8_cmesh_init (&cmesh); t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); /* Register the linear_geometry to this cmesh. */ - auto provided_geom = t8_cmesh_register_geometry (cmesh, 2); + auto provided_geom = t8_cmesh_register_geometry (cmesh, 2); /* Commit the cmesh */ t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index ec38320344..760dbbe65e 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -4,9 +4,26 @@ function( add_t8_tutorial ) set( multiValueArgs "SOURCES" ) cmake_parse_arguments( ADD_T8_TUTORIAL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + # Get the path of the first file listed in the SOURCES list and use it to determine the build directory. + # The executable will be build in the same directory as the first source file. + list(GET ADD_T8_TUTORIAL_SOURCES 0 FIRST_SOURCE) + get_filename_component(TUTORIAL_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${FIRST_SOURCE}" DIRECTORY) + file(RELATIVE_PATH TUTORIAL_RELATIVE_DIR "${CMAKE_SOURCE_DIR}" "${TUTORIAL_SOURCE_DIR}") + set(TUTORIAL_BUILD_DIR "${CMAKE_BINARY_DIR}/${TUTORIAL_RELATIVE_DIR}") + add_executable( ${ADD_T8_TUTORIAL_NAME} ${ADD_T8_TUTORIAL_SOURCES} ) target_link_libraries( ${ADD_T8_TUTORIAL_NAME} PRIVATE T8 SC::SC ) target_include_directories( ${ADD_T8_TUTORIAL_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) + + set_target_properties(${ADD_T8_TUTORIAL_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${TUTORIAL_BUILD_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${TUTORIAL_BUILD_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${TUTORIAL_BUILD_DIR}" + ) + + if( T8CODE_EXPORT_COMPILE_COMMANDS ) + set_target_properties( ${ADD_T8_TUTORIAL_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) + endif( T8CODE_EXPORT_COMPILE_COMMANDS ) install( TARGETS ${ADD_T8_TUTORIAL_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) endfunction()