diff --git a/.github/workflows/add_release_documentation.yml b/.github/workflows/add_release_documentation.yml index 39643b46bb..849ecf1ae4 100644 --- a/.github/workflows/add_release_documentation.yml +++ b/.github/workflows/add_release_documentation.yml @@ -62,7 +62,7 @@ jobs: # This step is necessary to get the newest package data - name: checkout if: ${{ env.MINOR_RELEASE == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: path: t8code fetch-tags: true @@ -116,7 +116,7 @@ jobs: # upload documentation - name: Checkout t8code-website repo if: ${{ env.MINOR_RELEASE == 'true' }} - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} repository: DLR-AMR/t8code-website diff --git a/.github/workflows/build_cmake_tarball.yml b/.github/workflows/build_cmake_tarball.yml index 8991a9eb92..888e744a44 100644 --- a/.github/workflows/build_cmake_tarball.yml +++ b/.github/workflows/build_cmake_tarball.yml @@ -49,7 +49,7 @@ jobs: # # Setup and bootstrap # - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-tags: true # required to get version tags fetch-depth: 0 # required to get all history, especially the version tags @@ -98,7 +98,7 @@ jobs: timeout-minutes: 90 steps: - name: Download tarball - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: tarballs path: tarballs diff --git a/.github/workflows/check_indentation.yml b/.github/workflows/check_indentation.yml index a4384e370b..221143ff48 100644 --- a/.github/workflows/check_indentation.yml +++ b/.github/workflows/check_indentation.yml @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-tags: true # required to get version tags fetch-depth: 0 # required to get all history, especially the version tags diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml index ec18302494..189136d31a 100644 --- a/.github/workflows/code_coverage.yml +++ b/.github/workflows/code_coverage.yml @@ -57,7 +57,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact @@ -91,7 +91,7 @@ jobs: run: export TEST_LEVEL_FLAG="-DT8CODE_TEST_LEVEL=${{ inputs.TEST_LEVEL }}" && echo TEST_LEVEL_FLAG="$TEST_LEVEL_FLAG" >> $GITHUB_ENV - name: build config variables - run: export CONFIG_OPTIONS="${TEST_LEVEL_FLAG} -DT8CODE_CODE_COVERAGE=ON -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_BUILD_WALL=ON -DT8CODE_BUILD_WERROR=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake" + run: export CONFIG_OPTIONS="${TEST_LEVEL_FLAG} -DT8CODE_CODE_COVERAGE=ON -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_BUILD_WALL=ON -DT8CODE_BUILD_WERROR=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DT8CODE_BUILD_FORTRAN_INTERFACE=ON -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake -DT8CODE_BUILD_BENCHMARKS=OFF -DT8CODE_BUILD_DOCUMENTATION=OFF -DT8CODE_BUILD_EXAMPLES=OFF -DT8CODE_BUILD_TUTORIALS=OFF" && echo CONFIG_OPTIONS="$CONFIG_OPTIONS" >> $GITHUB_ENV # cmake - name: echo cmake line diff --git a/.github/workflows/move_card.yml b/.github/workflows/move_card.yml index 118a0388c9..013e420da6 100644 --- a/.github/workflows/move_card.yml +++ b/.github/workflows/move_card.yml @@ -111,6 +111,9 @@ jobs: evaluate_pr: runs-on: ubuntu-latest + # Don't run in parallel on the same PR. Otherwise multiple issues might be created for the same PR. + concurrency: + group: pr-move-card-${{ github.event.pull_request.id }} outputs: NUMBER_IS_SET: ${{ steps.get_pr_issue_link.outputs.NUMBER_IS_SET }} CLEAN_ISSUE_NUMBER: ${{ steps.get_pr_issue_link.outputs.CLEAN_ISSUE_NUMBER }} diff --git a/.github/workflows/quick_pr.yml b/.github/workflows/quick_pr.yml index 1f7ac88028..3ac8032299 100644 --- a/.github/workflows/quick_pr.yml +++ b/.github/workflows/quick_pr.yml @@ -42,14 +42,12 @@ jobs: outputs: ISSUE_NUMBER: ${{ steps.create_issue_and_output_number.outputs.ISSUE_NUMBER }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: - repository: ${{ github.event.repository.full_name }} - ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 0 - name: "Set up environment" - run: echo "GITHUB_TOKEN=${{ secrets.PAT }}" >> $GITHUB_ENV + run: echo "GH_TOKEN=${{ secrets.PAT }}" >> $GITHUB_ENV - name: "Create Issue" id: create_issue_and_output_number @@ -69,12 +67,21 @@ jobs: # Create the new issue. Use the DEFAULT_PROJECT to directly add it to the project. # Letting GH add the Issue to the project by automatization can lead to a delay, # and the following worfkflows will try to move a card that doesn't exist yet. - new_issue_url=$(gh issue create \ - --title "$TITLE" \ - --assignee "$AUTHOR" \ - --body "$ISSUE_BODY" \ - --project "${{ inputs.DEFAULT_PROJECT }}" - ) + # Only assign the issue if the author is not a bot + if [[ "$AUTHOR" == *"[bot]"* ]]; then + new_issue_url=$(gh issue create \ + --title "$TITLE" \ + --body "$ISSUE_BODY" \ + --project "${{ inputs.DEFAULT_PROJECT }}" + ) + else + new_issue_url=$(gh issue create \ + --title "$TITLE" \ + --assignee "$AUTHOR" \ + --body "$ISSUE_BODY" \ + --project "${{ inputs.DEFAULT_PROJECT }}" + ) + fi echo "new_issue_url=$new_issue_url" # Extract the issue number from the URL. # The URL is in the format https://github.com/orga-name/repo-name/issues/issues_number diff --git a/.github/workflows/spell_check.yml b/.github/workflows/spell_check.yml index 868ec5a724..dd409c41e0 100644 --- a/.github/workflows/spell_check.yml +++ b/.github/workflows/spell_check.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check spelling uses: crate-ci/typos@master - name: check macros diff --git a/.github/workflows/tests_cmake_preparation.yml b/.github/workflows/tests_cmake_preparation.yml index 855ce2ee87..e9a1ea20b4 100644 --- a/.github/workflows/tests_cmake_preparation.yml +++ b/.github/workflows/tests_cmake_preparation.yml @@ -60,7 +60,7 @@ jobs: # # Setup # - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - name: Update packages diff --git a/.github/workflows/tests_cmake_sc_p4est.yml b/.github/workflows/tests_cmake_sc_p4est.yml index d96be4422f..4b75af52dc 100644 --- a/.github/workflows/tests_cmake_sc_p4est.yml +++ b/.github/workflows/tests_cmake_sc_p4est.yml @@ -52,7 +52,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact diff --git a/.github/workflows/tests_cmake_t8code.yml b/.github/workflows/tests_cmake_t8code.yml index b12320345b..c643ca3ab0 100644 --- a/.github/workflows/tests_cmake_t8code.yml +++ b/.github/workflows/tests_cmake_t8code.yml @@ -55,7 +55,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact diff --git a/.github/workflows/tests_cmake_t8code_api.yml b/.github/workflows/tests_cmake_t8code_api.yml index aaecd6897e..6530676689 100644 --- a/.github/workflows/tests_cmake_t8code_api.yml +++ b/.github/workflows/tests_cmake_t8code_api.yml @@ -55,7 +55,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact diff --git a/.github/workflows/tests_cmake_t8code_linkage.yml b/.github/workflows/tests_cmake_t8code_linkage.yml index fe1e1a2cb1..a717279cdb 100644 --- a/.github/workflows/tests_cmake_t8code_linkage.yml +++ b/.github/workflows/tests_cmake_t8code_linkage.yml @@ -55,7 +55,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact diff --git a/.github/workflows/tests_cmake_t8code_w_shipped_submodules.yml b/.github/workflows/tests_cmake_t8code_w_shipped_submodules.yml index 2de77f88ca..e531568f23 100644 --- a/.github/workflows/tests_cmake_t8code_w_shipped_submodules.yml +++ b/.github/workflows/tests_cmake_t8code_w_shipped_submodules.yml @@ -54,7 +54,7 @@ jobs: # # Setup # - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - name: Update packages diff --git a/.github/workflows/tests_cmake_testsuite.yml b/.github/workflows/tests_cmake_testsuite.yml index 7f20bade55..35ebe104a4 100644 --- a/.github/workflows/tests_cmake_testsuite.yml +++ b/.github/workflows/tests_cmake_testsuite.yml @@ -56,7 +56,7 @@ jobs: outputs: run_ci: ${{ steps.set_run_ci.outputs.RUN_CI }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} diff --git a/.github/workflows/tests_cmake_valgrind.yml b/.github/workflows/tests_cmake_valgrind.yml index 5b21d11804..629c2ba7f4 100644 --- a/.github/workflows/tests_cmake_valgrind.yml +++ b/.github/workflows/tests_cmake_valgrind.yml @@ -51,7 +51,7 @@ jobs: # Setup # - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: SC_P4EST_MPI_${{ inputs.MPI }} - name: untar artifact @@ -86,7 +86,7 @@ jobs: run: export TEST_LEVEL_FLAG="-DT8CODE_TEST_LEVEL=${{ inputs.TEST_LEVEL }}" && echo TEST_LEVEL_FLAG="$TEST_LEVEL_FLAG" >> $GITHUB_ENV - name: build config variables - run: export CONFIG_OPTIONS="${TEST_LEVEL_FLAG} -GNinja -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_BUILD_WALL=ON -DT8CODE_BUILD_WERROR=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake" + run: export CONFIG_OPTIONS="${TEST_LEVEL_FLAG} -GNinja -DT8CODE_USE_SYSTEM_SC=ON -DT8CODE_USE_SYSTEM_P4EST=ON -DT8CODE_BUILD_PEDANTIC=ON -DT8CODE_BUILD_WALL=ON -DT8CODE_BUILD_WERROR=ON -DT8CODE_ENABLE_MPI=$MPI -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSC_DIR=$SC_PATH/install/cmake -DP4EST_DIR=$P4EST_PATH/install/cmake -DT8CODE_BUILD_FORTRAN_INTERFACE=ON" && echo CONFIG_OPTIONS="$CONFIG_OPTIONS" >> $GITHUB_ENV # cmake - name: echo cmake line diff --git a/.github/workflows/update_documentation.yml b/.github/workflows/update_documentation.yml index ca7b5670f9..b57abf57fe 100644 --- a/.github/workflows/update_documentation.yml +++ b/.github/workflows/update_documentation.yml @@ -44,7 +44,7 @@ jobs: # # Setup and bootstrap # - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-tags: true # required to get version tags fetch-depth: 0 # required to get all history, especially the version tags @@ -81,7 +81,7 @@ jobs: # upload documentation - name: Checkout t8code-website repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} repository: DLR-AMR/t8code-website diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000..350ba31607 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,65 @@ +# 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) 2025 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. + +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + apt_packages: + - cmake + jobs: + post_checkout: + # Fetch all tags to ensure we can build documentation for any version + # The tags are needed to determine the version number of the documentation + - git fetch --unshallow --tags || true + post_install: + - bash ./scripts/configure_for_rtd.sh + + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "doc/" directory with Sphinx +sphinx: + configuration: doc/source/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + # fail_on_warning: true + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: doc/requirements.txt \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b7d3de75ac..1707a4f0ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ elseif(T8CODE_TEST_LEVEL STREQUAL "T8_TEST_LEVEL_MEDIUM" ) set(T8_TEST_LEVEL_INT 1) elseif(T8CODE_TEST_LEVEL STREQUAL "T8_TEST_LEVEL_FULL" ) set(T8_TEST_LEVEL_INT 0) -else() +else() message( FATAL_ERROR "Invalid string for T8CODE_TEST_LEVEL: ${T8CODE_TEST_LEVEL}. Valid options are T8_TEST_LEVEL_FULL, T8_TEST_LEVEL_MEDIUM, or T8_TEST_LEVEL_BASIC.") endif() @@ -131,11 +131,11 @@ if( T8CODE_ENABLE_OCC ) endif( T8CODE_ENABLE_OCC ) if( T8CODE_ENABLE_NETCDF ) - find_package( netCDF REQUIRED ) - if(netCDF_FOUND) - message("Found netCDF") + find_package( NetCDF REQUIRED ) + if(NetCDF_FOUND) + message("Found NetCDF") include(cmake/CheckNetCDFPar.cmake) - endif (netCDF_FOUND) + endif (NetCDF_FOUND) endif( T8CODE_ENABLE_NETCDF ) # Override default for this libsc option @@ -162,7 +162,10 @@ else() # Capture the list of variables before adding the subdirectory to mark the added ones as advanced. get_cmake_property(_vars_before_sc VARIABLES ) + list( APPEND CMAKE_MESSAGE_CONTEXT "sc" ) add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/sc ) + list( POP_BACK CMAKE_MESSAGE_CONTEXT ) + add_library(SC INTERFACE) # Capture the list of variables after adding the subdirectory get_cmake_property(_vars_after_sc VARIABLES ) # Compute the difference (new variables added by the subdirectory) @@ -175,6 +178,38 @@ else() # Mark the new variables as advanced mark_as_advanced( FORCE ${_new_sc_vars} ) + + ########################## Fix for OpenMPI ############################################ + # OpenMPI sometimes has a mismatch between their C and CXX interface which produces a warning in SC. + # The warning makes t8codes build fail when Werror is activated. This fix checks if t8code + # is linked against OpenMPI and then suppresses that Werror treats this warning as error. + # The warning is still displayed while compiling. + # We compile a test program mich checks if a OpenMPI specific macro is defined and then apply the fix. + + include(CheckIncludeFile) + + # Check if mpi.h is available + check_include_file("mpi.h" MPI_HEADER_FOUND) + + if(MPI_HEADER_FOUND) + # Create a temporary C++ source file to check for OpenMPI-specific macros + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" + #include + #ifndef OPEN_MPI + #error 'Not OpenMPI' + #endif + int main() { return 0; }" HAS_OPENMPI) + + if(HAS_OPENMPI) + message(STATUS "OpenMPI detected via mpi.h") + # Suppress warning + target_compile_options(SC::SC INTERFACE -Wno-error=cast-function-type) + endif() + else() + message(WARNING "mpi.h not found!") + endif() + ########################## End of fix for OpenMPI ############################################ endif() if ( T8CODE_USE_SYSTEM_P4EST ) @@ -185,7 +220,9 @@ else() # Capture the list of variables before adding the subdirectory to mark the added ones as advanced. get_cmake_property( _vars_before_p4est VARIABLES ) + list( APPEND CMAKE_MESSAGE_CONTEXT "p4est" ) add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/p4est ) + list( POP_BACK CMAKE_MESSAGE_CONTEXT ) # Capture the list of variables after adding the subdirectory get_cmake_property( _vars_after_p4est VARIABLES ) # Compute the difference (new variables added by the subdirectory) diff --git a/NEWS.md b/NEWS.md index d022863e73..13b66a47c9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -54,7 +54,7 @@ for (t8_locidx_t itree = 0; itree < num_local_trees; ++itree){ /* Get the number of elements in the tree itree. */ const t8_locidx_t num_elems = t8_forest_get_tree_num_elements (forest, itree); /* Loop over all elements */ - for (t8locidx_t ielem = 0; ielem < num_elems; ++ielem){ + for (t8_locidx_t ielem = 0; ielem < num_elems; ++ielem){ /* Get the element with tree-local-id ielem */ const t8_element_t *elem = t8_forest_get_element_in_tree (forest, itree, ielem); /* Call a function on that element */ @@ -74,7 +74,7 @@ for (t8_locidx_t itree = 0; itree < num_local_trees; ++itree){ /* Get the class of the tree. */ const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, itree); /* Loop over all elements */ - for (t8locidx_t ielem = 0; ielem < num_elems; ++ielem){ + for (t8_locidx_t ielem = 0; ielem < num_elems; ++ielem){ /* Get the element with tree-local-id ielem */ const t8_element_t *elem = t8_forest_get_element_in_tree (forest, itree, ielem); /* Call a function on that element */ @@ -124,7 +124,7 @@ A list of all renamings (without considering the deletion of the prefix) is here - `t8_element_linear_id` -> `element_set_linear_id` - `t8_element_first_descendant` -> `element_get_first_descendant` - `t8_element_last_descendant` -> `element_get_last_descendant` -- `t8_element_successor` -> `element_construct_successsor` +- `t8_element_successor` -> `element_construct_successor` - `t8_element_anchor` -> `element_get_anchor` - `t8_element_vertex_integer_coords` -> `element_get_vertex_integer_coords` - `t8_element_vertex_reference_coords` -> `element_get_vertex_reference_coords` diff --git a/README.md b/README.md index cdc0b37db8..78f844477d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -:rotating_light: **Become part of our Conference on Adaptive Mesh Refinement and Applications (AMR25) on September 02-04, 2025!** Although the abstract submission phase is already over, you can still register as a participant! Visit the [AMR25 website](https://dlr.de/AMR25) for further information. :rotating_light: - [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7034838.svg)](https://doi.org/10.5281/zenodo.7034838) [![t8code CI](https://github.com/DLR-AMR/t8code/actions/workflows/tests_cmake_testsuite.yml/badge.svg)](https://github.com/DLR-AMR/t8code/actions/workflows/tests_cmake_testsuite.yml) [![codecov](https://codecov.io/gh/dlr-amr/t8code/branch/main/graph/badge.svg)](https://codecov.io/gh/dlr-amr/t8code) +[![docs](https://app.readthedocs.org/projects/t8code/badge/?version=latest)](https://t8code.readthedocs.io/en/latest/)

diff --git a/benchmarks/t8_time_partition.cxx b/benchmarks/t8_time_partition.cxx index 0a37576257..42d80d94ee 100644 --- a/benchmarks/t8_time_partition.cxx +++ b/benchmarks/t8_time_partition.cxx @@ -76,7 +76,7 @@ t8_time_cmesh_translate_coordinates (t8_cmesh_t cmesh, double x, sc_MPI_Comm com SC_CHECK_MPI (mpiret); for (itree = 0; itree < t8_cmesh_get_num_local_trees (cmesh); itree++) { /* loop over all trees and get a pointer to their vertices */ - vertices = (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), 0, itree); + vertices = (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_VERTICES_ATTRIBUTE_KEY, itree); eclass = t8_cmesh_get_tree_class (cmesh, itree); for (ivertex = 0; ivertex < t8_eclass_num_vertices[eclass]; ivertex++) { /* For each tree vertex, translate its x-coordinate */ diff --git a/cmake/CheckNetCDFPar.cmake b/cmake/CheckNetCDFPar.cmake index bc8dbbeb4c..0abf1c6357 100644 --- a/cmake/CheckNetCDFPar.cmake +++ b/cmake/CheckNetCDFPar.cmake @@ -20,7 +20,7 @@ include( CheckCSourceCompiles ) function( check_netcdf_par ) - set( CMAKE_REQUIRED_LIBRARIES netCDF::netcdf ) + set( CMAKE_REQUIRED_LIBRARIES NetCDF::NetCDF ) check_c_source_compiles( " diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake new file mode 100755 index 0000000000..18c06a8961 --- /dev/null +++ b/cmake/FindNetCDF.cmake @@ -0,0 +1,134 @@ +# based on https://github.com/Kitware/VTK/blob/master/CMake/FindNetCDF.cmake + +#[==[ +Provides the following variables: + + * `NetCDF_FOUND`: Whether NetCDF was found or not. + * `NetCDF_INCLUDE_DIRS`: Include directories necessary to use NetCDF. + * `NetCDF_LIBRARIES`: Libraries necessary to use NetCDF. + * `NetCDF_VERSION`: The version of NetCDF found. + * `NetCDF::NetCDF`: A target to use with `target_link_libraries`. + * `NetCDF_HAS_PARALLEL`: Whether or not NetCDF was found with parallel IO support. +#]==] + +function(FindNetCDF_get_is_parallel_aware include_dir) + file(STRINGS "${include_dir}/netcdf_meta.h" _netcdf_lines + REGEX "#define[ \t]+NC_HAS_PARALLEL[ \t]") + string(REGEX REPLACE ".*NC_HAS_PARALLEL[ \t]*([0-1]+).*" "\\1" _netcdf_has_parallel "${_netcdf_lines}") + if (_netcdf_has_parallel) + set(NetCDF_HAS_PARALLEL TRUE PARENT_SCOPE) + else() + set(NetCDF_HAS_PARALLEL FALSE PARENT_SCOPE) + endif() +endfunction() + +find_package(netCDF CONFIG QUIET) + +if (netCDF_FOUND) + # Forward the variables in a consistent way. + set(NetCDF_FOUND "${netCDF_FOUND}") + set(NetCDF_INCLUDE_DIRS "${netCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${netCDF_LIBRARIES}") + set(NetCDF_VERSION "${NetCDFVersion}") + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_INCLUDE_DIRS NetCDF_LIBRARIES + VERSION_VAR NetCDF_VERSION) + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF INTERFACE IMPORTED) + if (TARGET "netCDF::netcdf") + # 4.7.3 + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "netCDF::netcdf") + elseif (TARGET "netcdf") + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "netcdf") + else () + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "${netCDF_LIBRARIES}") + endif () + endif () + + FindNetCDF_get_is_parallel_aware("${NetCDF_INCLUDE_DIRS}") + # Skip the rest of the logic in this file. + return () +endif () + +find_package(PkgConfig QUIET) +if (PkgConfig_FOUND) + pkg_check_modules(_NetCDF QUIET netcdf IMPORTED_TARGET) + if (_NetCDF_FOUND) + # Forward the variables in a consistent way. + set(NetCDF_FOUND "${_NetCDF_FOUND}") + # somehow pkg-config strips INCLUDEDIR from flags in some settings + if(_NetCDF_INCLUDE_DIRS) + set(NetCDF_INCLUDE_DIRS "${_NetCDF_INCLUDE_DIRS}") + else() + set(NetCDF_INCLUDE_DIRS "${_NetCDF_INCLUDEDIR}") + endif() + set(NetCDF_LIBRARIES "${_NetCDF_LIBRARIES}") + set(NetCDF_VERSION "${_NetCDF_VERSION}") + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_INCLUDE_DIRS NetCDF_LIBRARIES + VERSION_VAR NetCDF_VERSION) + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF INTERFACE IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + INTERFACE_LINK_LIBRARIES "PkgConfig::_NetCDF" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIRS}") # somehow lost sometimes + endif () + + FindNetCDF_get_is_parallel_aware("${_NetCDF_INCLUDEDIR}") + # Skip the rest of the logic in this file. + return () + endif () +endif () + +find_path(NetCDF_INCLUDE_DIR + NAMES netcdf.h + DOC "netcdf include directories") +mark_as_advanced(NetCDF_INCLUDE_DIR) + +find_library(NetCDF_LIBRARY + NAMES netcdf + DOC "netcdf library") +mark_as_advanced(NetCDF_LIBRARY) + +if (NetCDF_INCLUDE_DIR) + file(STRINGS "${NetCDF_INCLUDE_DIR}/netcdf_meta.h" _netcdf_version_lines + REGEX "#define[ \t]+NC_VERSION_(MAJOR|MINOR|PATCH|NOTE)") + string(REGEX REPLACE ".*NC_VERSION_MAJOR *\([0-9]*\).*" "\\1" _netcdf_version_major "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_MINOR *\([0-9]*\).*" "\\1" _netcdf_version_minor "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_PATCH *\([0-9]*\).*" "\\1" _netcdf_version_patch "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_NOTE *\"\([^\"]*\)\".*" "\\1" _netcdf_version_note "${_netcdf_version_lines}") + set(NetCDF_VERSION "${_netcdf_version_major}.${_netcdf_version_minor}.${_netcdf_version_patch}${_netcdf_version_note}") + unset(_netcdf_version_major) + unset(_netcdf_version_minor) + unset(_netcdf_version_patch) + unset(_netcdf_version_note) + unset(_netcdf_version_lines) + + FindNetCDF_get_is_parallel_aware("${NetCDF_INCLUDE_DIR}") +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_LIBRARY NetCDF_INCLUDE_DIR + VERSION_VAR NetCDF_VERSION) + +if (NetCDF_FOUND) + set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${NetCDF_LIBRARY}") + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + IMPORTED_LOCATION "${NetCDF_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIR}") + endif () +endif () diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake index 30edee6de8..373d08ae3f 100644 --- a/cmake/FindSphinx.cmake +++ b/cmake/FindSphinx.cmake @@ -18,12 +18,25 @@ # along with t8code; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +include(FindPackageHandleStandardArgs) + +find_package(PythonInterp) +if(PYTHONINTERP_FOUND) + get_filename_component(_PYTHON_DIR "${PYTHON_EXECUTABLE}" DIRECTORY) + set( + _PYTHON_PATHS + "${_PYTHON_DIR}" + "{_PYTHON_DIR}/bin" + "{_PYTHON_DIR}/Scripts" + ) +endif() + #Look for an executable called sphinx-build find_program(SPHINX_EXECUTABLE - NAMES sphinx-build + NAMES sphinx-build sphinx-build.exe sphinx-build.py + HINTS ${_PYTHON_PATHS} DOC "Path to sphinx-build executable") -include(FindPackageHandleStandardArgs) #Handle standard arguments to find_package like REQUIRED and QUIET find_package_handle_standard_args(Sphinx diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 0df64241d2..e32f137d88 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -39,8 +39,8 @@ if(T8CODE_BUILD_DOCUMENTATION) add_custom_command( OUTPUT ${DOXYGEN_INDEX_FILE} DEPENDS ${T8_PUBLIC_HEADERS} - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} - MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} COMMENT "Generating documentation" VERBATIM) @@ -53,9 +53,9 @@ endif(T8CODE_BUILD_DOCUMENTATION) if (T8CODE_BUILD_DOCUMENTATION_SPHINX) find_package(Sphinx REQUIRED) - + configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) - + if (SPHINX_FOUND) set(SPHINX_SOURCE ${PROJECT_SOURCE_DIR}/doc/source) set(SPHINX_BUILD ${PROJECT_BINARY_DIR}/doc/sphinx) @@ -75,7 +75,7 @@ if (T8CODE_BUILD_DOCUMENTATION_SPHINX) add_custom_command( OUTPUT ${SPHINX_INDEX_FILE} COMMAND ${SPHINX_EXECUTABLE} -b html # Tell Breathe where to find the Doxygen output - -Dbreathe_projects.T8code=${DOXYGEN_OUTPUT_DIR}/xml + -Dbreathe_projects.t8code=${DOXYGEN_OUTPUT_DIR}/xml ${SPHINX_SOURCE} ${SPHINX_BUILD} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS @@ -85,7 +85,7 @@ if (T8CODE_BUILD_DOCUMENTATION_SPHINX) MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py COMMENT "Generating documentation with Sphinx") - + # Nice named target so we can run the job easily add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) else (SPHINX_FOUND) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 8b1b64cfec..7757f3eec8 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -2044,7 +2044,7 @@ MAN_LINKS = NO # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = YES # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -2560,7 +2560,7 @@ PLANTUML_INCLUDE_PATH = # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 90 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 0000000000..8eded424b7 --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,4 @@ +breathe +exhale +sphinx +sphinx-rtd-theme diff --git a/doc/source/conf.in b/doc/source/conf.in index d8a545cf09..6d07884714 100644 --- a/doc/source/conf.in +++ b/doc/source/conf.in @@ -1,3 +1,23 @@ +# 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) 2025 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. + # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: @@ -6,6 +26,8 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +import subprocess, os + project = 't8code' copyright = '2024, Johannes Holke, David Knapp, Sandro Elsweijer, Ioannis Lilikakis, Lukas Dreyer, Jakob Fußbroich, Carsten Burstedde, Chiara Hergl, Johannes Markert, Niklas Boeing, Florian Becker, Prasanna Ponnusamy' author = 'Johannes Holke, David Knapp, Sandro Elsweijer, Ioannis Lilikakis, Lukas Dreyer, Jakob Fußbroich, Carsten Burstedde, Chiara Hergl, Johannes Markert, Niklas Boeing, Florian Becker, Prasanna Ponnusamy' @@ -14,7 +36,7 @@ version = '@VERSION@' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = [ "breathe", "exhale", "sphinx.ext.mathjax", "sphinx.ext.graphviz" ] +extensions = [ 'breathe', 'exhale', 'sphinx.ext.mathjax', 'sphinx.ext.graphviz' ] templates_path = ['_templates'] exclude_patterns = [] @@ -23,12 +45,59 @@ exclude_patterns = [] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output +# Breathe Configuration +breathe_projects = {} + +# configure the Doxyfile and create outputfiles. Only needed for a run on the readthedocs servers. +def configureDoxyfile(input_dir, output_dir): + with open('../Doxyfile.in', 'r') as file : + filedata = file.read() + + filedata = filedata.replace('@top_srcdir@', input_dir) + filedata = filedata.replace('@top_builddir@', output_dir) + + with open('../Doxyfile', 'w') as file: + file.write(filedata) + + # go to the doc directory + doc_dir = input_dir + '/doc' + os.chdir(doc_dir) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + if not os.path.exists(output_dir + '/xml'): + os.makedirs(output_dir + '/xml') + if not os.path.exists(output_dir + '/html'): + os.makedirs(output_dir + '/html') + if not os.path.exists(output_dir + '/latex'): + os.makedirs(output_dir + '/latex') + # Run doxygen + subprocess.call('doxygen Doxyfile', shell=True) + +# Check if we're running on Read the Docs' servers +read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True' +print("Running on Read the Docs:", read_the_docs_build) + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +breathe_projects = {} + +if read_the_docs_build: + input_dir = '../../' + output_dir = 'build' + configureDoxyfile(input_dir, output_dir) + breathe_projects["t8code"] = output_dir + '/xml' + html_theme = 'sphinx_rtd_theme' +html_theme_options = { + "collapse_navigation":True +} html_static_path = ['_static'] html_logo = '../../t8code_logo.png' +html_extra_path = ['../../build/html'] -# Breathe Configuration -breathe_default_project = "T8code" +breathe_default_project = "t8code" breathe_implementation_filename_extensions = ['.c', '.cpp'] # Setup the exhale extension @@ -36,7 +105,7 @@ exhale_args = { # These arguments are required "containmentFolder": "./api", "rootFileName": "library_root.rst", - "doxygenStripFromPath": "@top_srcdir@", + "doxygenStripFromPath": "../..", # Heavily encouraged optional argument (see docs) "rootFileTitle": "Library API", # Suggested optional arguments diff --git a/doc/source/index.rst b/doc/source/index.rst index 41ba4cfda2..7fefb9eb84 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -54,7 +54,7 @@ You find more information on t8code in the t8code Wiki. .. toctree:: - :maxdepth: 5 + :maxdepth: 3 :caption: Contents: api/library_root diff --git a/scripts/configure_for_rtd.sh b/scripts/configure_for_rtd.sh new file mode 100644 index 0000000000..68b42d859b --- /dev/null +++ b/scripts/configure_for_rtd.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# 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) 2025 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. + +git submodule init +git submodule update + +# Create the build directory +mkdir build + +# Navigate into the build directory +cd build + + +cmake .. -DT8CODE_BUILD_DOCUMENTATION=ON -DT8CODE_BUILD_DOCUMENTATION_SPHINX=ON -DT8CODE_ENABLE_MPI=OFF + +# Return to the parent directory +cd .. \ No newline at end of file diff --git a/scripts/valgrind_suppressions_file.supp b/scripts/valgrind_suppressions_file.supp index e8d8861140..0b82249193 100644 --- a/scripts/valgrind_suppressions_file.supp +++ b/scripts/valgrind_suppressions_file.supp @@ -4,5 +4,5 @@ ... obj:/usr/*libmpich* fun:PMPI_Init - fun:main + ... } \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 795f50ec33..96d35c5366 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,7 +20,7 @@ if ( ${T8CODE_BUILD_AS_SHARED_LIBRARY} ) add_library( T8 SHARED ) - set_target_properties( T8 PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${T8CODE_VERSION_RAW}) + set_target_properties( T8 PROPERTIES VERSION ${T8CODE_VERSION_MAJOR}.${T8CODE_VERSION_MINOR}.${T8CODE_VERSION_PATCH} SOVERSION ${T8CODE_VERSION_RAW}) set_target_properties( T8 PROPERTIES POSITION_INDEPENDENT_CODE ON ) else() add_library( T8 STATIC ) @@ -58,7 +58,7 @@ if( T8CODE_EXPORT_COMPILE_COMMANDS ) endif( T8CODE_EXPORT_COMPILE_COMMANDS ) if( T8CODE_ENABLE_NETCDF ) - target_link_libraries( T8 PUBLIC netCDF::netcdf ) + target_link_libraries( T8 PUBLIC NetCDF::NetCDF ) target_compile_definitions(T8 PUBLIC T8_ENABLE_NETCDF=1 $<$,$>:T8_ENABLE_NETCDF_PAR=1> ) @@ -114,10 +114,12 @@ if( T8CODE_ENABLE_OCC ) target_link_libraries( T8 PUBLIC ${OpenCASCADE_LIBRARIES} ) target_sources(T8 PRIVATE t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx + t8_data/t8_cad.cxx ) install( FILES t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx t8_geometry/t8_geometry_implementations/t8_geometry_cad.h + t8_data/t8_cad.hxx DESTINATION include ) endif() @@ -152,30 +154,30 @@ target_sources( T8 PRIVATE t8_eclass.c t8_element_shape.c t8_element.cxx - t8_refcount.c - t8_version.c - t8_vtk.c - t8_cmesh/t8_cmesh.cxx - t8_cmesh/t8_cmesh_cad.cxx - t8_cmesh/t8_cmesh_triangle.cxx - t8_cmesh/t8_cmesh_stash.c - t8_cmesh/t8_cmesh_save.cxx - t8_cmesh/t8_cmesh_trees.cxx - t8_cmesh/t8_cmesh_commit.cxx - t8_cmesh/t8_cmesh_partition.cxx - t8_cmesh/t8_cmesh_copy.c - t8_cmesh/t8_cmesh_geometry.cxx - t8_cmesh/t8_cmesh_examples.cxx - t8_cmesh/t8_cmesh_helpers.cxx - t8_cmesh/t8_cmesh_offset.c - t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.cxx - t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx - t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx + t8_refcount.c + t8_version.c + t8_vtk.c + t8_cmesh/t8_cmesh.cxx + t8_cmesh/t8_cmesh_cad.cxx + t8_cmesh/t8_cmesh_triangle.cxx + t8_cmesh/t8_cmesh_stash.c + t8_cmesh/t8_cmesh_save.cxx + t8_cmesh/t8_cmesh_trees.cxx + t8_cmesh/t8_cmesh_commit.cxx + t8_cmesh/t8_cmesh_partition.cxx + t8_cmesh/t8_cmesh_copy.c + t8_cmesh/t8_cmesh_geometry.cxx + t8_cmesh/t8_cmesh_examples.cxx + t8_cmesh/t8_cmesh_helpers.cxx + t8_cmesh/t8_cmesh_offset.c + t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.cxx + t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx + t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx t8_cmesh/t8_cmesh_readmshfile.cxx - t8_data/t8_shmem.c - t8_data/t8_containers.cxx - t8_forest/t8_forest_adapt.cxx - t8_forest/t8_forest_partition.cxx + t8_data/t8_shmem.c + t8_data/t8_containers.cxx + t8_forest/t8_forest_adapt.cxx + t8_forest/t8_forest_partition.cxx t8_forest/t8_forest.cxx t8_forest/t8_forest_private.cxx t8_forest/t8_forest_iterate.cxx @@ -183,6 +185,7 @@ target_sources( T8 PRIVATE t8_forest/t8_forest_search/t8_forest_search.cxx t8_forest/t8_forest_ghost/t8_forest_ghost.cxx t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_face.cxx + t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.cxx t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_w_search.cxx t8_forest/t8_forest_ghost/t8_forest_ghost_definition_c_interface.cxx t8_forest/t8_forest_ghost/t8_forest_ghost_definition_base.cxx @@ -259,8 +262,6 @@ install( FILES t8_types/t8_vec.h t8_version.h t8_vtk.h - t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx - t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h TYPE INCLUDE ) @@ -270,8 +271,8 @@ install( DIRECTORY t8_cmesh TYPE INCLUDE FILES_MATCHING PATTERN "*.h" PATTERN "t8_cmesh/t8_cmesh_copy.h" EXCLUDE PATTERN "t8_cmesh/t8_cmesh_offset.h" EXCLUDE PATTERN "t8_cmesh/t8_cmesh_partition.h" EXCLUDE - PATTERN "t8_cmesh/t8_cmesh_trees.h" EXCLUDE - PATTERN "t8_cmesh/t8_cmesh_vertex_connectivity/*.h" EXCLUDE + PATTERN "t8_cmesh/t8_cmesh_trees.h" EXCLUDE + PATTERN "t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_*.hxx" EXCLUDE ) install( DIRECTORY t8_data TYPE INCLUDE FILES_MATCHING PATTERN "*.h" ) @@ -279,7 +280,6 @@ install( DIRECTORY t8_forest TYPE INCLUDE FILES_MATCHING PATTERN "*.h" PATTERN "t8_forest/t8_forest_balance.h" EXCLUDE PATTERN "t8_forest/t8_forest_ghost/t8_forest_ghost.h " EXCLUDE PATTERN "t8_forest/t8_forest_private.h" EXCLUDE - PATTERN "t8_forest/t8_forest_types.h" EXCLUDE ) install( DIRECTORY t8_geometry DESTINATION include FILES_MATCHING PATTERN "*.h" PATTERN "t8_geometry/t8_geometry_implementations/t8_geometry_cad.h" EXCLUDE) diff --git a/src/Makefile.am b/src/Makefile.am index 4c19c133aa..eb32a98f28 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,7 @@ libt8_installed_headers_cmesh = \ src/t8_cmesh/t8_cmesh_types.h \ src/t8_cmesh/t8_cmesh_stash.h libt8_installed_headers_data = \ + src/t8_data/t8_cad.hxx \ src/t8_data/t8_shmem.h src/t8_data/t8_containers.h \ src/t8_data/t8_data_handler.hxx \ src/t8_data/t8_element_array_iterator.hxx diff --git a/src/t8.h b/src/t8.h index 164d19e923..4590312a5c 100644 --- a/src/t8.h +++ b/src/t8.h @@ -119,19 +119,25 @@ typedef uint64_t t8_linearidx_t; /** The MPI datatype of t8_linearidx_t */ #define T8_MPI_LINEARIDX sc_MPI_UNSIGNED_LONG_LONG +/** The padding size is the size of a void pointer*/ #define T8_PADDING_SIZE (sizeof (void *)) /** Compute the number of bytes that have to be added to a given byte_count * such that it is a multiple of the padding size */ #define T8_ADD_PADDING(_x) ((T8_PADDING_SIZE - ((_x) % T8_PADDING_SIZE)) % T8_PADDING_SIZE) -/** Define precisions for computations */ +/** Define machine precision for computations */ #define T8_PRECISION_EPS SC_EPS +/** Define square root of machine precision for computations */ #define T8_PRECISION_SQRT_EPS sqrt (T8_PRECISION_EPS) /** Access multidimensional data on one-dimensional C arrays. */ +/** Access onedimensional data on one-dimensional C arrays. */ #define T8_1D_TO_1D(nx, i) (i) +/** Access twodimensional data on one-dimensional C arrays. */ #define T8_2D_TO_1D(nx, ny, i, j) ((i) * (ny) + (j)) +/** Access threedimensional data on one-dimensional C arrays. */ #define T8_3D_TO_1D(nx, ny, nz, i, j, k) (((i) * (ny) + (j)) * (nz) + (k)) +/** Access fourdimensional data on one-dimensional C arrays. */ #define T8_4D_TO_1D(nx, ny, nz, nl, i, j, k, l) ((((i) * (ny) + (j)) * (nz) + (k)) * (nl) + (l)) /** Communication tags used internal to t8code. */ @@ -283,11 +289,12 @@ void t8_init (int log_threshold); /** Return a pointer to an array element indexed by a t8_locidx_t. + * \param [in] array The array of elements. * \param [in] index needs to be in [0]..[elem_count-1]. - * \return A void * pointing to entry \a it in \a array. + * \return A void * pointing to entry \a index in \a array. */ void * -t8_sc_array_index_locidx (const sc_array_t *array, const t8_locidx_t it); +t8_sc_array_index_locidx (const sc_array_t *array, const t8_locidx_t index); /** Return values for subroutines to indicate if they fail or success. */ #define T8_SUBROUTINE_SUCCESS 1 /* true */ diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index 7e89711312..9265632c98 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -33,7 +33,7 @@ #include #include -/* Forward pointer reference to hidden cmesh implementation. +/** Forward pointer reference to hidden cmesh implementation. * This reference needs to be known by t8_geometry, hence we * put it before the include. */ typedef struct t8_cmesh *t8_cmesh_t; @@ -54,9 +54,11 @@ typedef struct t8_cmesh *t8_cmesh_t; * edit: This should be achieved now. */ -/* Forward pointer references to hidden implementations of - * tree and ghost tree. */ +/** Forward pointer references to hidden implementations of + * tree. */ typedef struct t8_ctree *t8_ctree_t; +/** Forward pointer references to hidden implementations of + * ghost tree. */ typedef struct t8_cghost *t8_cghost_t; T8_EXTERN_C_BEGIN (); @@ -146,7 +148,7 @@ t8_cmesh_set_derive (t8_cmesh_t cmesh, t8_cmesh_t set_from); * \param [in] mpisize The number of processes. * \param [in] comm The MPI communicator to use. Its mpisize must match \a mpisize. * The shared memory type must have been set. Best practice would be - * calling \ref sc_shmem_set_type (comm, T8_SHMEM_BEST_TYPE). + * calling sc_shmem_set_type (comm, T8_SHMEM_BEST_TYPE). * \return A t8_shmem_array struct that stores \a mpisize + 1 t8_gloidx_t entries. * \see t8_shmem.h */ @@ -751,7 +753,7 @@ t8_cmesh_get_partition_table (t8_cmesh_t cmesh); /** Calculate the section of a uniform forest for the current rank. * \param [in] cmesh The cmesh to be considered. * \param [in] level The uniform refinement level to be created. - * \param [in] scheme The element scheme for which to compute the bounds. + * \param [in] tree_scheme The element scheme for which to compute the bounds. * \param [out] first_local_tree The first tree that contains elements belonging to the calling processor. * \param [out] child_in_tree_begin The tree-local index of the first element belonging to the calling processor. Not computed if NULL. * \param [out] last_local_tree The last tree that contains elements belonging to the calling processor. @@ -770,7 +772,7 @@ t8_cmesh_uniform_bounds_equal_element_count (t8_cmesh_t cmesh, const int level, /** * Calculate the section of a uniform hybrid forest for the current rank. Needed for hybrid meshes, especially * meshes where not all elements refine into 1:2^dim manner. The section is calculated without assuming such refinement - * and each process computes its number of elements on the given \var level, communicates the number to other processes, + * and each process computes its number of elements on the given \a level, communicates the number to other processes, * and the correct section is computed based on this information. * * \param [in] cmesh The cmesh to be considered. @@ -819,7 +821,6 @@ t8_cmesh_unref (t8_cmesh_t *pcmesh); * \param [in,out] pcmesh This cmesh must have a reference count of one. * It can be in any state (committed or not). * Then it effectively calls \ref t8_cmesh_unref. - * \param [in] comm A mpi communicator that is valid with \a cmesh. */ void t8_cmesh_destroy (t8_cmesh_t *pcmesh); diff --git a/src/t8_cmesh/t8_cmesh_commit.cxx b/src/t8_cmesh/t8_cmesh_commit.cxx index 26135dec56..3bae26f378 100644 --- a/src/t8_cmesh/t8_cmesh_commit.cxx +++ b/src/t8_cmesh/t8_cmesh_commit.cxx @@ -599,9 +599,8 @@ t8_cmesh_commit (t8_cmesh_t cmesh, sc_MPI_Comm comm) * but only if the vertex_to_tree instance is not yet committed * and if the tree_to_vertex instance is not empty. */ - if (cmesh->vertex_connectivity->get_vertex_to_tree_state () == 0 - && cmesh->vertex_connectivity->get_tree_to_vertex_state () == 1) { - cmesh->vertex_connectivity->build_vertex_to_tree (cmesh); + if (cmesh->vertex_connectivity->get_state () == t8_cmesh_vertex_connectivity::state::TREE_TO_VERTEX_VALID) { + cmesh->vertex_connectivity->build_vertex_to_tree (); } #if T8_ENABLE_DEBUG @@ -621,7 +620,7 @@ t8_cmesh_commit (t8_cmesh_t cmesh, sc_MPI_Comm comm) t8_stash_destroy (&cmesh->stash); } - t8_debugf ("committed cmesh with %li local and %lli global trees and" + t8_debugf ("Committed cmesh with %li local and %lli global trees and" " %li ghosts.\n", (long) cmesh->num_local_trees, (long long) cmesh->num_trees, (long) cmesh->num_ghosts); diff --git a/src/t8_cmesh/t8_cmesh_readmshfile.cxx b/src/t8_cmesh/t8_cmesh_readmshfile.cxx index 105f50c469..db1314dfc3 100644 --- a/src/t8_cmesh/t8_cmesh_readmshfile.cxx +++ b/src/t8_cmesh/t8_cmesh_readmshfile.cxx @@ -48,14 +48,14 @@ const t8_eclass_t t8_msh_tree_type_to_eclass[T8_NUM_GMSH_ELEM_CLASSES + 1] = { T8_ECLASS_COUNT, /* 0 is not valid */ T8_ECLASS_LINE, /* 1 */ - T8_ECLASS_TRIANGLE, - T8_ECLASS_QUAD, - T8_ECLASS_TET, + T8_ECLASS_TRIANGLE, + T8_ECLASS_QUAD, + T8_ECLASS_TET, T8_ECLASS_HEX, /* 5 */ - T8_ECLASS_PRISM, + T8_ECLASS_PRISM, T8_ECLASS_PYRAMID, /* 7 This is the last first order tree type, except the Point, which is type 15 */ /* We do not support type 8 to 14 */ - T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, + T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_COUNT, T8_ECLASS_VERTEX /* 15 */ }; @@ -175,6 +175,73 @@ struct t8_msh_file_node { } + /** + * Copy constructor + * \param [in] other The node to copy. + */ + t8_msh_file_node (const t8_msh_file_node &other) + : parameters (other.parameters), coordinates (other.coordinates), index (other.index), + parametric (other.parametric), entity_dim (other.entity_dim), entity_tag (other.entity_tag) + { + } + + /** + * Move constructor. + * \param [in] other The node to move. + */ + t8_msh_file_node (t8_msh_file_node &&other) noexcept + : parameters (std::move (other.parameters)), coordinates (std::move (other.coordinates)), index (other.index), + parametric (other.parametric), entity_dim (other.entity_dim), entity_tag (other.entity_tag) + { + other.index = -1; + other.parametric = false; + other.entity_dim = -1; + other.entity_tag = -1; + } + + /** + * Copy assignment operator. + * \param [in] other The node to copy. + * \return Reference to this node. + */ + t8_msh_file_node & + operator= (const t8_msh_file_node &other) + { + if (this != &other) { + parameters = other.parameters; + coordinates = other.coordinates; + index = other.index; + parametric = other.parametric; + entity_dim = other.entity_dim; + entity_tag = other.entity_tag; + } + return *this; + } + + /** + * Move assignment operator. + * \param [in] other The node to move. + * \return Reference to this node. + */ + t8_msh_file_node & + operator= (t8_msh_file_node &&other) noexcept + { + if (this != &other) { + parameters = std::move (other.parameters); + coordinates = std::move (other.coordinates); + index = other.index; + parametric = other.parametric; + entity_dim = other.entity_dim; + entity_tag = other.entity_tag; + + other.index = -1; + other.parametric = false; + other.entity_dim = -1; + other.entity_tag = -1; + } + return *this; + } + std::array parameters; /**< Parameters of the node in the parametric space, if applicable. * For example, for a point on a curve, this would be the parameter on the curve. */ std::array coordinates; /**< Coordinates of the node in physical space. */ @@ -558,12 +625,12 @@ t8_msh_file_4_read_nodes (FILE *fp) /** * Adds the elements of \a fp and dimension \a dim into the \a cmesh. - * Returns a list of all vertex indices of each tree. + * Returns a list of all vertex indices of each tree. * \param [in, out] cmesh The cmesh. * \param [in, out] fp The msh file. * \param [in, out] vertices A hashtable filled with the nodes of the msh file. * \param [in, out] dim The dimension of nodes to read in. - * \return + * \return */ static std::optional t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_table vertices, const int dim) @@ -787,20 +854,20 @@ t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_tab */ static void t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const int geometry_index, - const int num_face_nodes, const t8_geometry_cad_c *geometry_cad, + const int num_face_nodes, const t8_geometry_cad *geometry_cad, double *parameters) { switch (geometry_dim) { /* Check for closed U parameter in case of an edge. */ case 1: /* Only correct the U parameter if the edge is closed. */ - if (geometry_cad->t8_geom_is_edge_closed (geometry_index)) { - /* Get the parametric bounds of the closed geometry + if (geometry_cad->get_cad_manager ()->t8_geom_is_edge_closed (geometry_index)) { + /* Get the parametric bounds of the closed geometry * edge -> [Umin, Umax] */ double parametric_bounds[2]; /* Get the parametric edge bounds. */ - geometry_cad->t8_geom_get_edge_parametric_bounds (geometry_index, parametric_bounds); + geometry_cad->get_cad_manager ()->t8_geom_get_edge_parametric_bounds (geometry_index, parametric_bounds); /* Check the upper an the lower parametric bound. */ for (int bound = 0; bound < 2; ++bound) { /* Iterate over both nodes of the edge. */ @@ -832,12 +899,12 @@ t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const in /* Iterate over both parameters. 0 stands for the U parameter an 1 for the V parameter. */ for (int param_dim = 0; param_dim < 2; ++param_dim) { /* Only correct the surface parameters if they are closed */ - if (geometry_cad->t8_geom_is_surface_closed (geometry_index, param_dim)) { + if (geometry_cad->get_cad_manager ()->t8_geom_is_surface_closed (geometry_index, param_dim)) { /* Get the parametric bounds of the closed geometry * surface -> [Umin, Umax, Vmin, Vmax] */ double parametric_bounds[4]; - geometry_cad->t8_geom_get_face_parametric_bounds (geometry_index, parametric_bounds); + geometry_cad->get_cad_manager ()->t8_geom_get_face_parametric_bounds (geometry_index, parametric_bounds); /* Check the upper an the lower parametric bound. */ for (int bound = 0; bound < 2; ++bound) { /* Iterate over every corner node of the tree. */ @@ -879,17 +946,540 @@ t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const in } #endif /* T8_ENABLE_OCC */ +/** + * This function stores the entity dimensions, tags, and parameters of each node in a given + * tree in arrays. These arrays are then passed to the tree as attributes in cmesh. + * \param [in, out] cmesh The cmesh. + * \param [in] tree_count The index of the tree. + * \param [in] tree_nodes The array of the nodes of the tree. + * \param [in] num_nodes The number of nodes. + */ +static void +t8_store_element_node_data (t8_cmesh_t cmesh, t8_gloidx_t tree_count, + std::array *tree_nodes, int num_nodes) +{ + + int entity_dim_array[T8_ECLASS_MAX_CORNERS * 2]; + double parameter_array[T8_ECLASS_MAX_CORNERS * 2]; + + for (int node_i = 0; node_i < num_nodes; node_i++) { + t8_msh_file_node ¤t_node = (*tree_nodes)[node_i]; + + /* Store entity_dim and the entity_tag in the entity_dim_array. */ + entity_dim_array[2 * node_i] = current_node.entity_dim; + entity_dim_array[2 * node_i + 1] = current_node.entity_tag; + + /* Store the parameters of the node in the parameter_array. */ + parameter_array[2 * node_i] = current_node.parameters[0]; + parameter_array[2 * node_i + 1] = current_node.parameters[1]; + } + + /* Give the tree information about the dimension, tag and the parameters of the vertices. + * Each parameter set is given to the tree via its attribute key*/ + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_NODE_GEOMETRY_ATTRIBUTE_KEY, + entity_dim_array, T8_ECLASS_MAX_CORNERS * 2 * sizeof (int), 0); + + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_NODE_PARAMETERS_ATTRIBUTE_KEY, + parameter_array, T8_ECLASS_MAX_CORNERS * 2 * sizeof (int), 0); +} + +#if T8_ENABLE_OCC +/** + * This function calculates the parametric geometries of a tree based on its element class + * and links it to either a CAD-based geometry or a linear geometry. It validates the element class + * and assigns geometric attributes (e.g., face and edge parameters) to the tree. If the geometry + * cannot be processed, the function returns 0. + * + * \param [in, out] cmesh The computational mesh to which the tree belongs. + * \param [in] eclass The element class of the tree (e.g., triangle, quadrilateral, tetrahedron). + * \param [in] dim The dimension of the geometry (e.g., 2D or 3D). + * \param [in] tree_count The index of the tree in the computational mesh. + * \param [in] cad_geometry_base A pointer to the CAD-based geometry object. + * \param [in] linear_geometry_base A pointer to the linear geometry object. + * \param [in] tree_nodes An array of nodes representing the vertices of the tree. + * \param [in] face_nodes An array of nodes representing the faces of the tree. + * \param [in] edge_nodes An array of nodes representing the edges of the tree. + * + * \return True if the tree geometry was successfully processed; false otherwise. + * + */ +static bool +t8_cmesh_process_tree_geometry (t8_cmesh_t cmesh, t8_eclass_t eclass, int dim, t8_gloidx_t tree_count, + const t8_geometry_c *cad_geometry_base, const t8_geometry_c *linear_geometry_base, + std::array tree_nodes, + std::array face_nodes, + std::array edge_nodes) +{ + /* Calculate the parametric geometries of the tree */ + T8_ASSERT (cad_geometry_base->t8_geom_get_type () == T8_GEOMETRY_TYPE_CAD); + const t8_geometry_cad *cad_geometry = dynamic_cast (cad_geometry_base); + /* Check for right element class */ + if (eclass != T8_ECLASS_TRIANGLE && eclass != T8_ECLASS_QUAD && eclass != T8_ECLASS_HEX && eclass != T8_ECLASS_TET + && eclass != T8_ECLASS_PRISM) { + t8_errorf ("%s element detected. The cad geometry currently only supports quad, tri, hex, tet and prism elements.", + t8_eclass_to_string[eclass]); + return 0; + } + int tree_is_linked = 0; + double parameters[T8_ECLASS_MAX_CORNERS_2D * 2]; + int edge_geometries[T8_ECLASS_MAX_EDGES * 2] = { 0 }; + int face_geometries[T8_ECLASS_MAX_FACES] = { 0 }; + /* We look at each face to check, if it is linked to a cad surface */ + T8_ASSERT (t8_eclass_to_dimension[eclass] == dim); + int num_faces; + switch (dim) { + case 0: + num_faces = 0; + break; + case 1: + num_faces = 0; + break; + case 2: + num_faces = 1; + break; + case 3: + num_faces = t8_eclass_num_faces[eclass]; + break; + default: + SC_ABORTF ("Invalid dimension of tree. Dimension: %i\n", dim); + } + for (int i_tree_faces = 0; i_tree_faces < num_faces; ++i_tree_faces) { + const int face_eclass = dim == 2 ? eclass : t8_eclass_face_types[eclass][i_tree_faces]; + const int num_face_nodes = t8_eclass_num_vertices[face_eclass]; + const int num_face_edges = t8_eclass_num_faces[face_eclass]; + + /* Save each node of face separately. Face nodes of 2D elements are also tree nodes. + * Face nodes of 3D elements need to be translated to tree nodes. */ + for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { + if (dim == 2) { + face_nodes[i_face_node] = tree_nodes[i_face_node]; + } + else { + face_nodes[i_face_node] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_faces][i_face_node]]; + } + } + + /* A face can only be linked to an cad surface if all nodes of the face are parametric or on a vertex + * (gmsh labels nodes on vertices as not parametric) */ + int all_parametric = 1; + for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { + if (!face_nodes[i_face_nodes].parametric && face_nodes[i_face_nodes].entity_dim != 0) { + all_parametric = 0; + break; + } + } + /* Skip face if not all nodes are parametric */ + if (!all_parametric) { + continue; + } + /* Now we can check if the face is connected to a surface */ + int surface_index = 0; + /* If one node is already on a surface we can check if the rest lies also on the surface. */ + for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { + if (face_nodes[i_face_nodes].entity_dim == 2) { + surface_index = face_nodes[i_face_nodes].entity_tag; + break; + } + } + /* If not we can take two curves and look if they share a surface and then use this surface */ + if (!surface_index) { + /* To do this we can look if there are two curves, otherwise we have to check which vertices + * share the same curve. */ + int edge1_index = 0; + int edge2_index = 0; + /* We search for 2 different curves */ + for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { + if (face_nodes[i_face_nodes].entity_dim == 1) { + if (edge1_index == 0) { + edge1_index = face_nodes[i_face_nodes].entity_tag; + } + else if (face_nodes[i_face_nodes].entity_tag != edge1_index) { + edge2_index = face_nodes[i_face_nodes].entity_tag; + break; + } + } + } + /* If there are less than 2 curves we can look at the vertices and check, + * if two of them are on the same curve */ + if (edge2_index == 0) { + /* For each edge of face */ + for (int i_face_edges = 0; i_face_edges < num_face_edges; ++i_face_edges) { + /* Save nodes separately */ + const int node1_number = t8_face_vertex_to_tree_vertex[face_eclass][i_tree_faces][0]; + const t8_msh_file_node node1 = face_nodes[node1_number]; + const int node2_number = t8_face_vertex_to_tree_vertex[face_eclass][i_tree_faces][1]; + const t8_msh_file_node node2 = face_nodes[node2_number]; + + /* If both nodes are on a vertex we look if both vertices share an edge */ + if (node1.entity_dim == 0 && node2.entity_dim == 0) { + int common_edge + = cad_geometry->get_cad_manager ()->t8_geom_get_common_edge (node1.entity_tag, node2.entity_tag); + if (common_edge > 0) { + if (edge1_index == 0) { + edge1_index = common_edge; + } + else if (edge2_index == 0 && common_edge != edge1_index) { + edge2_index = common_edge; + break; + } + } + } + } + } + if (edge2_index > 0) { + surface_index = cad_geometry->get_cad_manager ()->t8_geom_get_common_face (edge1_index, edge2_index); + } + else { + continue; + } + } + /* Now we can check if every node lies on the surface and retrieve its parameters */ + if (surface_index) { + int all_nodes_on_surface = 1; + for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { + /* We check if the node is on the right surface */ + if (face_nodes[i_face_nodes].entity_dim == 2) { + /* Check if node is on the right surface */ + if (face_nodes[i_face_nodes].entity_tag != surface_index) { + all_nodes_on_surface = 0; + break; + } + } + else { + /* If it is on another geometry we retrieve its parameters */ + if (face_nodes[i_face_nodes].entity_dim == 0) { + if (cad_geometry->get_cad_manager ()->t8_geom_is_vertex_on_face (face_nodes[i_face_nodes].entity_tag, + surface_index)) { + cad_geometry->get_cad_manager ()->t8_geom_get_parameters_of_vertex_on_face ( + face_nodes[i_face_nodes].entity_tag, surface_index, face_nodes[i_face_nodes].parameters.data ()); + face_nodes[i_face_nodes].entity_dim = 2; + } + else { + all_nodes_on_surface = 0; + break; + } + } + if (face_nodes[i_face_nodes].entity_dim == 1) { + if (cad_geometry->get_cad_manager ()->t8_geom_is_edge_on_face (face_nodes[i_face_nodes].entity_tag, + surface_index)) { + cad_geometry->get_cad_manager ()->t8_geom_edge_parameter_to_face_parameters ( + face_nodes[i_face_nodes].entity_tag, surface_index, num_face_nodes, + face_nodes[i_face_nodes].parameters[0], NULL, face_nodes[i_face_nodes].parameters.data ()); + face_nodes[i_face_nodes].entity_dim = 2; + } + else { + all_nodes_on_surface = 0; + break; + } + } + } + } + /* Abort if not all nodes are on the surface or if the surface is a plane */ + if (!all_nodes_on_surface || cad_geometry->get_cad_manager ()->t8_geom_is_plane (surface_index)) { + continue; + } + /* If we have found a surface we link it to the face */ + face_geometries[i_tree_faces] = surface_index; + tree_is_linked = 1; + for (int i_face_edges = 0; i_face_edges < num_face_edges; ++i_face_edges) { + /* We lock the edges of the face for surfaces, so that we do not link the same surface again + * to the edges of the face */ + if (dim == 2) /* 2D */ + { + edge_geometries[i_face_edges + t8_eclass_num_edges[eclass]] = -1; + } + else /* 3D */ + { + edge_geometries[t8_face_edge_to_tree_edge[eclass][i_tree_faces][i_face_edges] + t8_eclass_num_edges[eclass]] + = -1; + } + } + /* We retrieve the parameters of the nodes and give them to the tree */ + for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { + parameters[i_face_nodes * 2] = face_nodes[i_face_nodes].parameters[0]; + parameters[i_face_nodes * 2 + 1] = face_nodes[i_face_nodes].parameters[1]; + } + /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ + for (int param_dim = 0; param_dim < 2; ++param_dim) { + if (cad_geometry->get_cad_manager ()->t8_geom_is_surface_closed (surface_index, param_dim)) { + t8_cmesh_correct_parameters_on_closed_geometry (2, surface_index, num_face_nodes, cad_geometry, parameters); + } + } + + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + i_tree_faces, parameters, + num_face_nodes * 2 * sizeof (double), 0); + } + } + const int num_edges = t8_eclass_num_edges[eclass]; + /* Then we look for geometries linked to the edges */ + for (int i_tree_edges = 0; i_tree_edges < num_edges; ++i_tree_edges) { + if (t8_eclass_to_dimension[eclass] == 3) { + edge_nodes[0] = tree_nodes[t8_edge_vertex_to_tree_vertex[eclass][i_tree_edges][0]]; + edge_nodes[1] = tree_nodes[t8_edge_vertex_to_tree_vertex[eclass][i_tree_edges][1]]; + } + else { + edge_nodes[0] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_edges][0]]; + edge_nodes[1] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_edges][1]]; + } + /* Both nodes have to be parametric or on a vertex to be linked to a curve or surface */ + if ((!edge_nodes[0].parametric && edge_nodes[0].entity_dim != 0) + || (!edge_nodes[1].parametric && edge_nodes[1].entity_dim != 0)) { + continue; + } + /* An edge can be linked to a curve as well as a surface. + * Therefore, we have to save the geometry dim and tag */ + int edge_geometry_dim = 0; + int edge_geometry_tag = 0; + /* We check which is the highest dim a node geometry has and what is its tag */ + if (edge_nodes[0].entity_dim > edge_nodes[1].entity_dim) { + edge_geometry_dim = edge_nodes[0].entity_dim; + if (edge_nodes[0].entity_dim > 0) { + edge_geometry_tag = edge_nodes[0].entity_tag; + } + } + else { + edge_geometry_dim = edge_nodes[1].entity_dim; + if (edge_nodes[1].entity_dim > 0) { + edge_geometry_tag = edge_nodes[1].entity_tag; + } + } + /* If both nodes are on two different faces we can skip this edge. */ + if (edge_nodes[0].entity_dim == 2 && edge_nodes[1].entity_dim == 2 + && edge_nodes[0].entity_tag != edge_nodes[1].entity_tag) { + continue; + } + + /* If one vertex lies on a geometry of a higher dim as the other, we have to check, + * if the geometry of lower dimension is on that geometry. */ + { + int is_on_geom = 1; + for (int i_edge = 0; i_edge < 2; ++i_edge) { + if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 1) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_edge_on_face (edge_nodes[i_edge].entity_tag, + edge_geometry_tag)) { + is_on_geom = 0; + break; + } + } + else if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 0) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_vertex_on_face (edge_nodes[i_edge].entity_tag, + edge_geometry_tag)) { + is_on_geom = 0; + break; + } + } + else if (edge_geometry_dim == 1 && edge_nodes[i_edge].entity_dim == 0) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_vertex_on_edge (edge_nodes[i_edge].entity_tag, + edge_geometry_tag)) { + is_on_geom = 0; + break; + } + } + } + if (!is_on_geom) { + continue; + } + } + + /* If both nodes are on a vertex we still got no edge. + * But we can look if both vertices share an edge and use this edge. + * If not we can skip this edge. */ + if (edge_geometry_dim == 0 && edge_geometry_tag == 0) { + int common_curve = cad_geometry->get_cad_manager ()->t8_geom_get_common_edge (edge_nodes[0].entity_tag, + edge_nodes[1].entity_tag); + if (common_curve > 0) { + edge_geometry_tag = common_curve; + edge_geometry_dim = 1; + } + else { + continue; + } + } + /* If both nodes are on different edges we have to look if both edges share a surface. + * If not we can skip this edge */ + if (edge_nodes[0].entity_dim == 1 && edge_nodes[1].entity_dim == 1 + && edge_nodes[0].entity_tag != edge_nodes[1].entity_tag) { + int common_surface = cad_geometry->get_cad_manager ()->t8_geom_get_common_face (edge_nodes[0].entity_tag, + edge_nodes[1].entity_tag); + if (common_surface > 0) { + edge_geometry_tag = common_surface; + edge_geometry_dim = 2; + } + else { + continue; + } + } + /* If we have found a curve we can look for the parameters */ + if (edge_geometry_dim == 1) { + /* Check if adjacent faces carry a surface and if this edge lies on the surface */ + for (int i_adjacent_face = 0; i_adjacent_face < 2; ++i_adjacent_face) { + if (face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]] > 0) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_edge_on_face ( + edge_geometry_tag, face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]])) { + t8_global_errorf ("Error: Adjacent edge and face of a tree carry " + "incompatible geometries.\n"); + return 0; + } + } + } + for (int i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { + /* Some error checking */ + if (edge_nodes[i_edge_node].entity_dim == 2) { + t8_global_errorf ("Error: Node %li should lie on a vertex or an edge, " + "but it lies on a surface.\n", + edge_nodes[i_edge_node].index); + return 0; + } + if (edge_nodes[i_edge_node].entity_dim == 1 && edge_nodes[i_edge_node].entity_tag != edge_geometry_tag) { + t8_global_errorf ("Error: Node %li should lie on a specific edge, " + "but it lies on another edge.\n", + edge_nodes[i_edge_node].index); + return 0; + } + if (edge_nodes[i_edge_node].entity_dim == 0) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_vertex_on_edge (edge_nodes[i_edge_node].entity_tag, + edge_geometry_tag)) { + t8_global_errorf ("Error: Node %li should lie on a vertex which lies on an edge, " + "but the vertex does not lie on that edge.\n", + edge_nodes[i_edge_node].index); + return 0; + } + } + + /* If the node lies on a vertex we retrieve its parameter on the curve */ + if (edge_nodes[i_edge_node].entity_dim == 0) { + cad_geometry->get_cad_manager ()->t8_geom_get_parameter_of_vertex_on_edge ( + edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters.data ()); + edge_nodes[i_edge_node].entity_dim = 1; + } + } + + /* Abort if the edge is a line */ + if (cad_geometry->get_cad_manager ()->t8_geom_is_line (edge_geometry_tag)) { + continue; + } + + edge_geometries[i_tree_edges] = edge_geometry_tag; + tree_is_linked = 1; + parameters[0] = edge_nodes[0].parameters[0]; + parameters[1] = edge_nodes[1].parameters[0]; + + /* Corrects the parameters on the edge if it is closed to prevent disorted elements. */ + if (cad_geometry->get_cad_manager ()->t8_geom_is_edge_closed (edge_geometry_tag)) { + t8_cmesh_correct_parameters_on_closed_geometry (1, edge_geometry_tag, 2, cad_geometry, parameters); + } + + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, + 2 * sizeof (double), 0); + } + /* If we have found a surface we can look for the parameters. + * If the edge is locked for edges on surfaces we have to skip this edge */ + else if (edge_geometry_dim == 2 && edge_geometries[i_tree_edges + num_edges] >= 0) { + /* If the node lies on a geometry with a different dimension we try to retrieve the parameters */ + for (int i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { + /* Some error checking */ + if (edge_nodes[i_edge_node].entity_dim == 2 && edge_nodes[i_edge_node].entity_tag != edge_geometry_tag) { + t8_global_errorf ("Error: Node %li should lie on a specific face, but it lies on another face.\n", + edge_nodes[i_edge_node].index); + return 0; + } + if (edge_nodes[i_edge_node].entity_dim == 0) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_vertex_on_face (edge_nodes[i_edge_node].entity_tag, + edge_geometry_tag)) { + t8_global_errorf ("Error: Node %li should lie on a vertex which lies on a face, " + "but the vertex does not lie on that face.\n", + edge_nodes[i_edge_node].index); + return 0; + } + } + if (edge_nodes[i_edge_node].entity_dim == 1) { + if (!cad_geometry->get_cad_manager ()->t8_geom_is_edge_on_face (edge_nodes[i_edge_node].entity_tag, + edge_geometry_tag)) { + t8_global_errorf ("Error: Node %li should lie on an edge which lies on a face, " + "but the edge does not lie on that face.\n", + edge_nodes[i_edge_node].index); + return 0; + } + } + + /* If the node lies on a vertex we retrieve its parameters on the surface */ + if (edge_nodes[i_edge_node].entity_dim == 0) { + cad_geometry->get_cad_manager ()->t8_geom_get_parameters_of_vertex_on_face ( + edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters.data ()); + edge_nodes[i_edge_node].entity_dim = 2; + } + /* If the node lies on an edge we have to do the same */ + if (edge_nodes[i_edge_node].entity_dim == 1) { + const int num_face_nodes = t8_eclass_num_vertices[eclass]; + cad_geometry->get_cad_manager ()->t8_geom_edge_parameter_to_face_parameters ( + edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, num_face_nodes, + edge_nodes[i_edge_node].parameters[0], parameters, edge_nodes[i_edge_node].parameters.data ()); + edge_nodes[i_edge_node].entity_dim = 2; + } + } + + /* Abort if the edge is a line */ + if (cad_geometry->get_cad_manager ()->t8_geom_is_line (edge_geometry_tag)) { + continue; + } + + edge_geometries[i_tree_edges + t8_eclass_num_edges[eclass]] = edge_geometry_tag; + tree_is_linked = 1; + parameters[0] = edge_nodes[0].parameters[0]; + parameters[1] = edge_nodes[0].parameters[1]; + parameters[2] = edge_nodes[1].parameters[0]; + parameters[3] = edge_nodes[1].parameters[1]; + + /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ + for (int param_dim = 0; param_dim < 2; ++param_dim) { + if (cad_geometry->get_cad_manager ()->t8_geom_is_surface_closed (edge_geometry_tag, param_dim)) { + t8_cmesh_correct_parameters_on_closed_geometry (2, edge_geometry_tag, 2, cad_geometry, parameters); + } + } + + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, + 4 * sizeof (double), 0); + } + } + /* Remove the -1 used to lock the edges */ + for (int i_edge = 0; i_edge < T8_ECLASS_MAX_EDGES * 2; ++i_edge) { + if (edge_geometries[i_edge] < 0) { + edge_geometries[i_edge] = 0; + } + } + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, face_geometries, + num_faces * sizeof (int), 0); + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edge_geometries, + 2 * num_edges * sizeof (int), 0); + + /* Now we set the tree geometry according to the tree linkage status. */ + if (tree_is_linked) { + t8_cmesh_set_tree_geometry (cmesh, tree_count, cad_geometry_base); + t8_debugf ("Registering tree %li with geometry %s \n", tree_count, cad_geometry_base->t8_geom_get_name ().c_str ()); + } + else { + t8_cmesh_set_tree_geometry (cmesh, tree_count, linear_geometry_base); + t8_debugf ("Registering tree %li with geometry %s \n", tree_count, + linear_geometry_base->t8_geom_get_name ().c_str ()); + } + return 1; +} +#endif /* T8_ENABLE_OCC */ + /* fp should be set after the Nodes section, right before the tree section. * If vertex_indices is not NULL, it is allocated and will store * for each tree the indices of its vertices. - * They are stored as arrays of long ints. + * They are stored as arrays of long ints. * If cad geometry is used, the geometry is passed as a pointer here. * We cannot access this geometry over the cmesh interface since the cmesh * is not committed yet. */ static std::optional t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_table vertices, const int dim, const t8_geometry_c *linear_geometry_base, const int use_cad_geometry, - [[maybe_unused]] const t8_geometry_c *cad_geometry_base) + [[maybe_unused]] const t8_geometry_c *cad_geometry_base, const bool store_node_data) { char *line = (char *) malloc (1024), *line_modify; char first_word[2048] = "\0"; @@ -899,7 +1489,8 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_tab t8_eclass_t eclass; t8_msh_file_node Node; #if T8_ENABLE_OCC - t8_msh_file_node face_nodes[T8_ECLASS_MAX_CORNERS_2D], edge_nodes[2]; + std::array face_nodes; + std::array edge_nodes; #endif /* T8_ENABLE_OCC */ long lnum_trees, lnum_blocks, entity_tag; int retval; @@ -1115,6 +1706,11 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_tab t8_cmesh_set_tree_vertices (cmesh, tree_count, tree_vertices.data (), num_nodes); t8_cmesh_set_global_vertices_of_tree (cmesh, tree_count, global_id_of_node, num_nodes); + /* Add two arrays if store_node_data is true. One with the dimension and indices of the nodes and one with the coordinates. */ + if (store_node_data) { + t8_store_element_node_data (cmesh, tree_count, &tree_nodes, num_nodes); + } + if (!use_cad_geometry) { /* Set the geometry of the tree to be linear. * If we use an cad geometry, we set the geometry in accordance, @@ -1122,480 +1718,16 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, const t8_msh_node_tab t8_cmesh_set_tree_geometry (cmesh, tree_count, linear_geometry_base); } else { - /* Calculate the parametric geometries of the tree */ #if T8_ENABLE_OCC - T8_ASSERT (cad_geometry_base->t8_geom_get_type () == T8_GEOMETRY_TYPE_CAD); - const t8_geometry_cad_c *cad_geometry = dynamic_cast (cad_geometry_base); - /* Check for right element class */ - if (eclass != T8_ECLASS_TRIANGLE && eclass != T8_ECLASS_QUAD && eclass != T8_ECLASS_HEX - && eclass != T8_ECLASS_TET && eclass != T8_ECLASS_PRISM) { - t8_errorf ( - "%s element detected. The cad geometry currently only supports quad, tri, hex and prism elements.", - t8_eclass_to_string[eclass]); + if (!t8_cmesh_process_tree_geometry (cmesh, eclass, dim, tree_count, cad_geometry_base, linear_geometry_base, + tree_nodes, face_nodes, edge_nodes)) { free (line); t8_cmesh_destroy (&cmesh); return std::nullopt; } - int tree_is_linked = 0; - double parameters[T8_ECLASS_MAX_CORNERS_2D * 2]; - int edge_geometries[T8_ECLASS_MAX_EDGES * 2] = { 0 }; - int face_geometries[T8_ECLASS_MAX_FACES] = { 0 }; - /* We look at each face to check, if it is linked to a cad surface */ - T8_ASSERT (t8_eclass_to_dimension[eclass] == dim); - int num_faces; - switch (dim) { - case 0: - num_faces = 0; - break; - case 1: - num_faces = 0; - break; - case 2: - num_faces = 1; - break; - case 3: - num_faces = t8_eclass_num_faces[eclass]; - break; - default: - SC_ABORTF ("Invalid dimension of tree. Dimension: %i\n", dim); - } - for (int i_tree_faces = 0; i_tree_faces < num_faces; ++i_tree_faces) { - const int face_eclass = dim == 2 ? eclass : t8_eclass_face_types[eclass][i_tree_faces]; - const int num_face_nodes = t8_eclass_num_vertices[face_eclass]; - const int num_face_edges = t8_eclass_num_faces[face_eclass]; - - /* Save each node of face separately. Face nodes of 2D elements are also tree nodes. - * Face nodes of 3D elements need to be translated to tree nodes. */ - for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { - if (dim == 2) { - face_nodes[i_face_node] = tree_nodes[i_face_node]; - } - else { - face_nodes[i_face_node] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_faces][i_face_node]]; - } - } - - /* A face can only be linked to an cad surface if all nodes of the face are parametric or on a vertex - * (gmsh labels nodes on vertices as not parametric) */ - int all_parametric = 1; - for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { - if (!face_nodes[i_face_nodes].parametric && face_nodes[i_face_nodes].entity_dim != 0) { - all_parametric = 0; - break; - } - } - /* Skip face if not all nodes are parametric */ - if (!all_parametric) { - continue; - } - /* Now we can check if the face is connected to a surface */ - int surface_index = 0; - /* If one node is already on a surface we can check if the rest lies also on the surface. */ - for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { - if (face_nodes[i_face_nodes].entity_dim == 2) { - surface_index = face_nodes[i_face_nodes].entity_tag; - break; - } - } - /* If not we can take two curves and look if they share a surface and then use this surface */ - if (!surface_index) { - /* To do this we can look if there are two curves, otherwise we have to check which vertices - * share the same curve. */ - int edge1_index = 0; - int edge2_index = 0; - /* We search for 2 different curves */ - for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { - if (face_nodes[i_face_nodes].entity_dim == 1) { - if (edge1_index == 0) { - edge1_index = face_nodes[i_face_nodes].entity_tag; - } - else if (face_nodes[i_face_nodes].entity_tag != edge1_index) { - edge2_index = face_nodes[i_face_nodes].entity_tag; - break; - } - } - } - /* If there are less than 2 curves we can look at the vertices and check, - * if two of them are on the same curve */ - if (edge2_index == 0) { - /* For each edge of face */ - for (int i_face_edges = 0; i_face_edges < num_face_edges; ++i_face_edges) { - /* Save nodes separately */ - const int node1_number = t8_face_vertex_to_tree_vertex[face_eclass][i_tree_faces][0]; - const t8_msh_file_node node1 = face_nodes[node1_number]; - const int node2_number = t8_face_vertex_to_tree_vertex[face_eclass][i_tree_faces][1]; - const t8_msh_file_node node2 = face_nodes[node2_number]; - - /* If both nodes are on a vertex we look if both vertices share an edge */ - if (node1.entity_dim == 0 && node2.entity_dim == 0) { - int common_edge = cad_geometry->t8_geom_get_common_edge (node1.entity_tag, node2.entity_tag); - if (common_edge > 0) { - if (edge1_index == 0) { - edge1_index = common_edge; - } - else if (edge2_index == 0 && common_edge != edge1_index) { - edge2_index = common_edge; - break; - } - } - } - } - } - if (edge2_index > 0) { - surface_index = cad_geometry->t8_geom_get_common_face (edge1_index, edge2_index); - } - else { - continue; - } - } - /* Now we can check if every node lies on the surface and retrieve its parameters */ - if (surface_index) { - int all_nodes_on_surface = 1; - for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { - /* We check if the node is on the right surface */ - if (face_nodes[i_face_nodes].entity_dim == 2) { - /* Check if node is on the right surface */ - if (face_nodes[i_face_nodes].entity_tag != surface_index) { - all_nodes_on_surface = 0; - break; - } - } - else { - /* If it is on another geometry we retrieve its parameters */ - if (face_nodes[i_face_nodes].entity_dim == 0) { - if (cad_geometry->t8_geom_is_vertex_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { - cad_geometry->t8_geom_get_parameters_of_vertex_on_face ( - face_nodes[i_face_nodes].entity_tag, surface_index, - face_nodes[i_face_nodes].parameters.data ()); - face_nodes[i_face_nodes].entity_dim = 2; - } - else { - all_nodes_on_surface = 0; - break; - } - } - if (face_nodes[i_face_nodes].entity_dim == 1) { - if (cad_geometry->t8_geom_is_edge_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { - cad_geometry->t8_geom_edge_parameter_to_face_parameters ( - face_nodes[i_face_nodes].entity_tag, surface_index, num_face_nodes, - face_nodes[i_face_nodes].parameters[0], NULL, face_nodes[i_face_nodes].parameters.data ()); - face_nodes[i_face_nodes].entity_dim = 2; - } - else { - all_nodes_on_surface = 0; - break; - } - } - } - } - /* Abort if not all nodes are on the surface or if the surface is a plane */ - if (!all_nodes_on_surface || cad_geometry->t8_geom_is_plane (surface_index)) { - continue; - } - /* If we have found a surface we link it to the face */ - face_geometries[i_tree_faces] = surface_index; - tree_is_linked = 1; - for (int i_face_edges = 0; i_face_edges < num_face_edges; ++i_face_edges) { - /* We lock the edges of the face for surfaces, so that we do not link the same surface again - * to the edges of the face */ - if (dim == 2) /* 2D */ - { - edge_geometries[i_face_edges + t8_eclass_num_edges[eclass]] = -1; - } - else /* 3D */ - { - edge_geometries[t8_face_edge_to_tree_edge[eclass][i_tree_faces][i_face_edges] - + t8_eclass_num_edges[eclass]] - = -1; - } - } - /* We retrieve the parameters of the nodes and give them to the tree */ - for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { - parameters[i_face_nodes * 2] = face_nodes[i_face_nodes].parameters[0]; - parameters[i_face_nodes * 2 + 1] = face_nodes[i_face_nodes].parameters[1]; - } - /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ - for (int param_dim = 0; param_dim < 2; ++param_dim) { - if (cad_geometry->t8_geom_is_surface_closed (surface_index, param_dim)) { - t8_cmesh_correct_parameters_on_closed_geometry (2, surface_index, num_face_nodes, cad_geometry, - parameters); - } - } - - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + i_tree_faces, parameters, - num_face_nodes * 2 * sizeof (double), 0); - } - } - const int num_edges = t8_eclass_num_edges[eclass]; - /* Then we look for geometries linked to the edges */ - for (int i_tree_edges = 0; i_tree_edges < num_edges; ++i_tree_edges) { - if (t8_eclass_to_dimension[eclass] == 3) { - edge_nodes[0] = tree_nodes[t8_edge_vertex_to_tree_vertex[eclass][i_tree_edges][0]]; - edge_nodes[1] = tree_nodes[t8_edge_vertex_to_tree_vertex[eclass][i_tree_edges][1]]; - } - else { - edge_nodes[0] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_edges][0]]; - edge_nodes[1] = tree_nodes[t8_face_vertex_to_tree_vertex[eclass][i_tree_edges][1]]; - } - /* Both nodes have to be parametric or on a vertex to be linked to a curve or surface */ - if ((!edge_nodes[0].parametric && edge_nodes[0].entity_dim != 0) - || (!edge_nodes[1].parametric && edge_nodes[1].entity_dim != 0)) { - continue; - } - /* An edge can be linked to a curve as well as a surface. - * Therefore, we have to save the geometry dim and tag */ - int edge_geometry_dim = 0; - int edge_geometry_tag = 0; - /* We check which is the highest dim a node geometry has and what is its tag */ - if (edge_nodes[0].entity_dim > edge_nodes[1].entity_dim) { - edge_geometry_dim = edge_nodes[0].entity_dim; - if (edge_nodes[0].entity_dim > 0) { - edge_geometry_tag = edge_nodes[0].entity_tag; - } - } - else { - edge_geometry_dim = edge_nodes[1].entity_dim; - if (edge_nodes[1].entity_dim > 0) { - edge_geometry_tag = edge_nodes[1].entity_tag; - } - } - /* If both nodes are on two different faces we can skip this edge. */ - if (edge_nodes[0].entity_dim == 2 && edge_nodes[1].entity_dim == 2 - && edge_nodes[0].entity_tag != edge_nodes[1].entity_tag) { - continue; - } - - /* If one vertex lies on a geometry of a higher dim as the other, we have to check, - * if the geometry of lower dimension is on that geometry. */ - { - int is_on_geom = 1; - for (int i_edge = 0; i_edge < 2; ++i_edge) { - if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 1) { - if (!cad_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { - is_on_geom = 0; - break; - } - } - else if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 0) { - if (!cad_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { - is_on_geom = 0; - break; - } - } - else if (edge_geometry_dim == 1 && edge_nodes[i_edge].entity_dim == 0) { - if (!cad_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { - is_on_geom = 0; - break; - } - } - } - if (!is_on_geom) { - continue; - } - } - - /* If both nodes are on a vertex we still got no edge. - * But we can look if both vertices share an edge and use this edge. - * If not we can skip this edge. */ - if (edge_geometry_dim == 0 && edge_geometry_tag == 0) { - int common_curve - = cad_geometry->t8_geom_get_common_edge (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); - if (common_curve > 0) { - edge_geometry_tag = common_curve; - edge_geometry_dim = 1; - } - else { - continue; - } - } - /* If both nodes are on different edges we have to look if both edges share a surface. - * If not we can skip this edge */ - if (edge_nodes[0].entity_dim == 1 && edge_nodes[1].entity_dim == 1 - && edge_nodes[0].entity_tag != edge_nodes[1].entity_tag) { - int common_surface - = cad_geometry->t8_geom_get_common_face (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); - if (common_surface > 0) { - edge_geometry_tag = common_surface; - edge_geometry_dim = 2; - } - else { - continue; - } - } - /* If we have found a curve we can look for the parameters */ - if (edge_geometry_dim == 1) { - /* Check if adjacent faces carry a surface and if this edge lies on the surface */ - for (int i_adjacent_face = 0; i_adjacent_face < 2; ++i_adjacent_face) { - if (face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]] > 0) { - if (!cad_geometry->t8_geom_is_edge_on_face ( - edge_geometry_tag, face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]])) { - t8_global_errorf ("Error: Adjacent edge and face of a tree carry " - "incompatible geometries.\n"); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - } - } - for (int i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { - /* Some error checking */ - if (edge_nodes[i_edge_node].entity_dim == 2) { - t8_global_errorf ("Error: Node %li should lie on a vertex or an edge, " - "but it lies on a surface.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - if (edge_nodes[i_edge_node].entity_dim == 1 - && edge_nodes[i_edge_node].entity_tag != edge_geometry_tag) { - t8_global_errorf ("Error: Node %li should lie on a specific edge, " - "but it lies on another edge.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - if (edge_nodes[i_edge_node].entity_dim == 0) { - if (!cad_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge_node].entity_tag, - edge_geometry_tag)) { - t8_global_errorf ("Error: Node %li should lie on a vertex which lies on an edge, " - "but the vertex does not lie on that edge.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - } - - /* If the node lies on a vertex we retrieve its parameter on the curve */ - if (edge_nodes[i_edge_node].entity_dim == 0) { - cad_geometry->t8_geom_get_parameter_of_vertex_on_edge ( - edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters.data ()); - edge_nodes[i_edge_node].entity_dim = 1; - } - } - - /* Abort if the edge is a line */ - if (cad_geometry->t8_geom_is_line (edge_geometry_tag)) { - continue; - } - - edge_geometries[i_tree_edges] = edge_geometry_tag; - tree_is_linked = 1; - parameters[0] = edge_nodes[0].parameters[0]; - parameters[1] = edge_nodes[1].parameters[0]; - - /* Corrects the parameters on the edge if it is closed to prevent disorted elements. */ - if (cad_geometry->t8_geom_is_edge_closed (edge_geometry_tag)) { - t8_cmesh_correct_parameters_on_closed_geometry (1, edge_geometry_tag, 2, cad_geometry, parameters); - } - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, - 2 * sizeof (double), 0); - } - /* If we have found a surface we can look for the parameters. - * If the edge is locked for edges on surfaces we have to skip this edge */ - else if (edge_geometry_dim == 2 && edge_geometries[i_tree_edges + num_edges] >= 0) { - /* If the node lies on a geometry with a different dimension we try to retrieve the parameters */ - for (int i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { - /* Some error checking */ - if (edge_nodes[i_edge_node].entity_dim == 2 - && edge_nodes[i_edge_node].entity_tag != edge_geometry_tag) { - t8_global_errorf ("Error: Node %li should lie on a specific face, but it lies on another face.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - if (edge_nodes[i_edge_node].entity_dim == 0) { - if (!cad_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge_node].entity_tag, - edge_geometry_tag)) { - t8_global_errorf ("Error: Node %li should lie on a vertex which lies on a face, " - "but the vertex does not lie on that face.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - } - if (edge_nodes[i_edge_node].entity_dim == 1) { - if (!cad_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge_node].entity_tag, edge_geometry_tag)) { - t8_global_errorf ("Error: Node %li should lie on an edge which lies on a face, " - "but the edge does not lie on that face.\n", - edge_nodes[i_edge_node].index); - free (line); - t8_cmesh_destroy (&cmesh); - return std::nullopt; - } - } - - /* If the node lies on a vertex we retrieve its parameters on the surface */ - if (edge_nodes[i_edge_node].entity_dim == 0) { - cad_geometry->t8_geom_get_parameters_of_vertex_on_face ( - edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters.data ()); - edge_nodes[i_edge_node].entity_dim = 2; - } - /* If the node lies on an edge we have to do the same */ - if (edge_nodes[i_edge_node].entity_dim == 1) { - const int num_face_nodes = t8_eclass_num_vertices[eclass]; - cad_geometry->t8_geom_edge_parameter_to_face_parameters ( - edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, num_face_nodes, - edge_nodes[i_edge_node].parameters[0], parameters, edge_nodes[i_edge_node].parameters.data ()); - edge_nodes[i_edge_node].entity_dim = 2; - } - } - - /* Abort if the edge is a line */ - if (cad_geometry->t8_geom_is_line (edge_geometry_tag)) { - continue; - } - - edge_geometries[i_tree_edges + t8_eclass_num_edges[eclass]] = edge_geometry_tag; - tree_is_linked = 1; - parameters[0] = edge_nodes[0].parameters[0]; - parameters[1] = edge_nodes[0].parameters[1]; - parameters[2] = edge_nodes[1].parameters[0]; - parameters[3] = edge_nodes[1].parameters[1]; - - /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ - for (int param_dim = 0; param_dim < 2; ++param_dim) { - if (cad_geometry->t8_geom_is_surface_closed (edge_geometry_tag, param_dim)) { - t8_cmesh_correct_parameters_on_closed_geometry (2, edge_geometry_tag, 2, cad_geometry, parameters); - } - } - - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, - 4 * sizeof (double), 0); - } - } - /* Remove the -1 used to lock the edges */ - for (int i_edge = 0; i_edge < T8_ECLASS_MAX_EDGES * 2; ++i_edge) { - if (edge_geometries[i_edge] < 0) { - edge_geometries[i_edge] = 0; - } - } - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, - face_geometries, num_faces * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, - edge_geometries, 2 * num_edges * sizeof (int), 0); - - /* Now we set the tree geometry according to the tree linkage status. */ - if (tree_is_linked) { - t8_cmesh_set_tree_geometry (cmesh, tree_count, cad_geometry_base); - t8_debugf ("Registering tree %li with geometry %s \n", tree_count, - cad_geometry_base->t8_geom_get_name ().c_str ()); - } - else { - t8_cmesh_set_tree_geometry (cmesh, tree_count, linear_geometry_base); - t8_debugf ("Registering tree %li with geometry %s \n", tree_count, - linear_geometry_base->t8_geom_get_name ().c_str ()); - } -#else /* !T8_ENABLE_OCC */ - SC_ABORTF ("OCC not linked"); +#else /* T8_ENABLE_OCC */ + SC_ABORTF ("OCC not linked."); #endif /* T8_ENABLE_OCC */ } } @@ -1849,7 +1981,7 @@ t8_cmesh_msh_file_find_neighbors (t8_cmesh_t cmesh, const t8_msh_tree_vertex_ind /* This part should be callable from C */ T8_EXTERN_C_BEGIN (); -/* This is a helper function to properly register the +/* This is a helper function to properly register the * geometries for the cmesh created in t8_cmesh_from_msh_file. * It should be called by all processes of the cmesh. * Returns T8_SUBROUTINE_SUCCESS on success, T8_SUBROUTINE_FAILURE on cad usage error: use_cad_geometry true, but OCC not linked. @@ -1990,7 +2122,7 @@ t8_cmesh_from_msh_file (const char *fileprefix, const int partition, sc_MPI_Comm return NULL; } indices = t8_cmesh_msh_file_4_read_eles (cmesh, file, *vertices_opt, dim, linear_geometry, use_cad_geometry, - cad_geometry); + cad_geometry, true); break; } diff --git a/src/t8_cmesh/t8_cmesh_types.h b/src/t8_cmesh/t8_cmesh_types.h index ab813a8285..4f3a839660 100644 --- a/src/t8_cmesh/t8_cmesh_types.h +++ b/src/t8_cmesh/t8_cmesh_types.h @@ -52,28 +52,21 @@ typedef struct t8_cprofile t8_cprofile_t; /* Defined below */ * and provide informative error messages both in debug and non-debug. */ -/* Definitions for attribute identifiers that are reserved for a special purpose. +/* Definitions for attribute identifiers that are reserved for a special purpose. * T8_CMESH_NEXT_POSSIBLE_KEY is the first unused key, hence it can be repurposed for different attributes.*/ -/** Used to store vertex coordinates. */ -#define T8_CMESH_VERTICES_ATTRIBUTE_KEY 0 -/** Used to store global vertex ids. */ -#define T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY 1 -/** Used to store the name of a tree's geometry. */ -#define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 2 -/** Used to store which edge is linked to which geometry */ -#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 3 -/** Used to store edge parameters */ -#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 4 -/** Used to store which face is linked to which surface */ -#define T8_CMESH_CAD_FACE_ATTRIBUTE_KEY \ - T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY \ - +T8_ECLASS_MAX_EDGES -/** Used to store face parameters */ -#define T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY T8_CMESH_CAD_FACE_ATTRIBUTE_KEY + 1 -/** Used to store parameters of lagrangian polynomials */ -#define T8_CMESH_LAGRANGE_POLY_DEGREE_KEY T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES -/** The next free value for a t8code attribute key */ -#define T8_CMESH_NEXT_POSSIBLE_KEY T8_CMESH_LAGRANGE_POLY_DEGREE_KEY + 1 +/* clang-format off */ +#define T8_CMESH_VERTICES_ATTRIBUTE_KEY 0 /** Used to store vertex coordinates. */ +#define T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY 1 /** Used to store global vertex ids. */ +#define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 2 /** Used to store the name of a tree's geometry. */ +#define T8_CMESH_NODE_GEOMETRY_ATTRIBUTE_KEY 3 /** Used to store the geometry dimension and tag of the nodes of a tree. */ +#define T8_CMESH_NODE_PARAMETERS_ATTRIBUTE_KEY 4 /** Used to store node parameters of a tree. Used in combination with T8_CMESH_NODE_GEOMETRY_ATTRIBUTE_KEY */ +#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 5 /** Used to store which edge is linked to which geometry */ +#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 6 /** Used to store edge parameters */ +#define T8_CMESH_CAD_FACE_ATTRIBUTE_KEY T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + 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_KEY T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES /** Used to store parameters of lagrangian polynomials */ +#define T8_CMESH_NEXT_POSSIBLE_KEY T8_CMESH_LAGRANGE_POLY_DEGREE_KEY + 1 /** The next free value for a t8code attribute key */ +/* clang-format on */ /** This structure holds the connectivity data of the coarse mesh. * It can either be replicated, then each process stores a copy of the whole @@ -118,7 +111,7 @@ typedef struct t8_cmesh int mpisize; /**< Number of MPI processes. */ t8_refcount_t rc; /**< The reference count of the cmesh. */ t8_gloidx_t num_trees; /**< The global number of trees */ - t8_locidx_t num_local_trees; /**< If partitioned the number of trees on this process. + t8_locidx_t num_local_trees; /**< If partitioned the number of trees on this process. Otherwise the global number of trees. */ t8_locidx_t num_ghosts; /**< If partitioned the number of neighbor trees owned by different processes. */ @@ -134,10 +127,10 @@ typedef struct t8_cmesh t8_cmesh_trees_t trees; /**< structure that holds all local trees and ghosts */ - t8_gloidx_t first_tree; /**< The global index of the first local tree on this process. + t8_gloidx_t first_tree; /**< The global index of the first local tree on this process. Zero if the cmesh is not partitioned. -1 if this processor is empty. See also https://github.com/DLR-AMR/t8code/wiki/Tree-indexing */ - int8_t first_tree_shared; /**< If partitioned true if the first tree on this process is also the last tree + int8_t first_tree_shared; /**< If partitioned true if the first tree on this process is also the last tree on the next process. Always zero if num_local_trees = 0 */ t8_shmem_array_t tree_offsets; /**< If partitioned for each process the global index of its first local tree @@ -271,7 +264,7 @@ typedef struct t8_part_tree /* TODO: Extend this structure with meaningful entries. * Maybe the number of shipped trees per process is useful? */ -/** +/** * This struct is used to profile cmesh algorithms. * The cmesh struct stores a pointer to a profile struct, and if * it is nonzero, various runtimes and data measurements are stored here. diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.hxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.hxx index 925824bbb3..7780ac21af 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.hxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.hxx @@ -44,8 +44,9 @@ #include #include #include +#include -/** forward declaration of ttv class needed since the two class headers include each other. */ +/** forward declaration of the class needed since the two class headers include each other. */ class t8_cmesh_vertex_conn_vertex_to_tree; /** @@ -54,14 +55,14 @@ class t8_cmesh_vertex_conn_vertex_to_tree; class t8_cmesh_vertex_conn_tree_to_vertex { public: /** Standard constructor. Does nothing. */ - t8_cmesh_vertex_conn_tree_to_vertex (): state (EMPTY) + t8_cmesh_vertex_conn_tree_to_vertex (): current_state (state::EMPTY) { } /** Constructor from a cmesh where all the attributes are set. * Currently unclear if we implement this eventually. * If we do so: Should the cmesh be already committed, or in pre-commit state but attributes set? - * + * * \note This function is not implemented yet. */ t8_cmesh_vertex_conn_tree_to_vertex ([[maybe_unused]] const t8_cmesh_t cmesh) @@ -75,8 +76,8 @@ class t8_cmesh_vertex_conn_tree_to_vertex { * \param [in] cmesh_from A committed cmesh. * \param [in] cmesh An initialized but not committed cmesh that is to be derived from \a cmesh_from. * \param [in] vtt A committed vertex to tree connectivity for \a cmesh_from. - * - * As a result a tree to vertec connectivity for \a cmesh will be constructed. + * + * As a result a tree to vertex connectivity for \a cmesh will be constructed. * \note \a cmesh_from must be committed. * \note \a cmesh must not be committed. * \note \a vtt must be committed. @@ -115,49 +116,42 @@ class t8_cmesh_vertex_conn_tree_to_vertex { t8_cmesh_set_attribute_gloidx_array (cmesh, global_tree, t8_get_package_id (), T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY, global_tree_vertices, num_vertices, data_persists); - state = FILLED; + current_state = state::FILLED; } /* TODO: What if the attribute is not set? error handling */ /** Return the global vertex indices of a local tree. * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree in \a cmesh. - * \param [in] num_vertices The count of local vertices of \a local_tree * \return An array of length \a num_vertices containing the global vertex ids of \a local_tree's vertices. */ - inline const t8_gloidx_t * - get_global_vertices (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int num_vertices) const + inline const std::span + get_global_vertices (const t8_cmesh_t cmesh, const t8_locidx_t local_tree) const { T8_ASSERT (t8_cmesh_is_committed (cmesh)); -#if T8_ENABLE_DEBUG - /* Verify that num_vertices matches the number of tree vertices */ + /* Get num tree_vertices to create a view */ const t8_eclass_t tree_class = t8_cmesh_get_tree_class (cmesh, local_tree); const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; - T8_ASSERT (num_vertices == num_tree_vertices); -#endif - - t8_debugf ("Getting %i global vertices for local tree %i.\n", num_vertices, local_tree); const t8_gloidx_t *global_vertices = t8_cmesh_get_attribute_gloidx_array ( - cmesh, t8_get_package_id (), T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY, local_tree, num_vertices); + cmesh, t8_get_package_id (), T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY, local_tree, num_tree_vertices); T8_ASSERT (global_vertices != NULL); - return global_vertices; + const std::span view (global_vertices, num_tree_vertices); + return view; } /* TODO: What if the attribute is not set? error handling */ /** Return a single global vertex id of a single local vertex. - * - * + * + * * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree of \a cmesh. * \param [in] local_tree_vertex A local vertex of \a local_tree - * \param [in] num_tree_vertices The count of vertices of \a local_tree - * \return The global id of the local vertex \a local_tree_vertex of \a local_tree. + * \return The global id of the local vertex \a local_tree_vertex of \a local_tree. */ t8_gloidx_t - get_global_vertex (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex, - const int num_tree_vertices) const + get_global_vertex (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex) const { T8_ASSERT (t8_cmesh_is_committed (cmesh)); @@ -167,25 +161,27 @@ class t8_cmesh_vertex_conn_tree_to_vertex { * for a potential attacker to gain access to memory possibly not owned by the caller. * We do not check in non-debugging mode for (obvious) performance reasons. */ T8_ASSERT (0 <= local_tree_vertex); - T8_ASSERT (local_tree_vertex < num_tree_vertices); - - return get_global_vertices (cmesh, local_tree, num_tree_vertices)[local_tree_vertex]; + const std::span global_vertices = get_global_vertices (cmesh, local_tree); + T8_ASSERT (global_vertices.size () > static_cast (local_tree_vertex)); + return global_vertices[local_tree_vertex]; } friend struct t8_cmesh_vertex_connectivity; private: - enum state { + enum class state { EMPTY, /*< Is initialized but empty. */ FILLED /*< Is filled with at least one entry. */ - } state; + }; /** Return the state of this object. */ - inline enum state - get_state () + inline state + get_state () const { - return state; + return current_state; } + + state current_state; }; #endif /* !T8_CMESH_VERTEX_CONN_TREE_TO_VERTEX_HXX */ diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx index 13874ffe34..e301228d67 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx @@ -41,15 +41,14 @@ t8_cmesh_vertex_conn_vertex_to_tree::build_from_ttv (const t8_cmesh_t cmesh, t8_ const t8_locidx_t num_local_trees_and_ghosts = num_local_trees + num_ghosts; for (t8_locidx_t itree = 0; itree < num_local_trees_and_ghosts; ++itree) { - const t8_eclass_t tree_class = t8_cmesh_get_tree_class (cmesh, itree); - const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; /* Get the global vertex ids of this tree. */ - const t8_gloidx_t* global_indices = ttv.get_global_vertices (cmesh, itree, num_tree_vertices); + auto global_indices = ttv.get_global_vertices (cmesh, itree); /* Iterate over all local tree vertices and add the global id to the list. */ - for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) { - add_vertex_to_tree (cmesh, global_indices[ivertex], itree, ivertex); + int ivertex = 0; + for (auto global_index : global_indices) { + add_vertex_to_tree (cmesh, global_index, itree, ivertex++); } } @@ -57,7 +56,7 @@ t8_cmesh_vertex_conn_vertex_to_tree::build_from_ttv (const t8_cmesh_t cmesh, t8_ state = COMMITTED; } -/* Mark as ready for commit. Meaning that all +/* Mark as ready for commit. Meaning that all * global vertex ids have been added. * After commit, no vertex ids can be added anymore. */ void @@ -129,7 +128,7 @@ t8_cmesh_vertex_conn_vertex_to_tree::sort_list_by_tree_id () for (auto& [global_id, tree_vertex_list] : vertex_to_tree) { /* Check that the list contains at least one entry. */ T8_ASSERT (tree_vertex_list.size () > 0); - /* Sort the list of local tree vertices according to their + /* Sort the list of local tree vertices according to their * local tree id. */ std::sort (tree_vertex_list.begin (), tree_vertex_list.end (), t8_cmesh_tree_vertex_pair_compare); } @@ -138,8 +137,8 @@ t8_cmesh_vertex_conn_vertex_to_tree::sort_list_by_tree_id () int t8_cmesh_vertex_conn_vertex_to_tree::contains_all_vertices (const t8_cmesh_t cmesh) const { - /* We need to check that each local tree/ghost and each vertex - * exists exactly once in the list. + /* We need to check that each local tree/ghost and each vertex + * exists exactly once in the list. * We do so by setting up an indicator array storing the * number of vertices for each tree and count down for each occurrence. * At the end the values must be zero. */ diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.hxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.hxx index 6242abc3ca..14a2f1c7a1 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.hxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.hxx @@ -40,9 +40,9 @@ class t8_cmesh_vertex_conn_tree_to_vertex; /** This class stores the vertex to tree lookup for * global vertex indices for a cmesh. * Thus, given a global vertex id the class provides - * information about the trees the vertex belongs to and + * information about the trees the vertex belongs to and * the corresponding local vertex ids inside these trees. - * + * * In particular, this class stores the lookup * * global_vertex_id -> List of (tree, tree_local_vertex) @@ -98,7 +98,7 @@ class t8_cmesh_vertex_conn_vertex_to_tree { set_vertex_to_tree_list (const t8_cmesh_t cmesh); /** Get the list of global trees and local vertex ids a global vertex is connected to. - * + * * \param [in] global_vertex_id The global id of a vertex in the cmesh. * \return The list of local tree ids and local vertex ids of \a global_vertex_id. */ @@ -122,10 +122,10 @@ class t8_cmesh_vertex_conn_vertex_to_tree { /** Get the state of the vertex to tree object. * An object is either initialized (before commit) or committed (ready to use). - * \return INITIALIZED or COMMITTED + * \return INITIALIZED or COMMITTED */ inline int - get_state () + get_state () const { return state; } @@ -134,8 +134,8 @@ class t8_cmesh_vertex_conn_vertex_to_tree { /** A single (tree, local vertex) value connected to a global vertex is added to the vertex_to_tree_list. * \param [in] cmesh must be committed. - * \param [in] global_vertex_id The global id of the vertex to be added. - * \param [in] ltreeid The local tree id of a tree that \a global_vertex_id is connected to. + * \param [in] global_vertex_id The global id of the vertex to be added. + * \param [in] ltreeid The local tree id of a tree that \a global_vertex_id is connected to. * \param [in] tree_vertex The local vertex id of \a ltreeid that \a global_vertex_id is connected to. */ void diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx index f5a4f7d75d..a58c5b5cac 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx @@ -29,26 +29,6 @@ #include #include -/* -Use case - -initialize cmeesh -Add trees -Add tree to vertex information -Start commit cmesh - commit cmesh internally - build vertex to tree information -Finish commit cmesh - -Access vtt and ttv information - --> ttv must be added before commit -global tree id -> vertex_list - --> vtt must be added after commit (not by user) - -*/ - /* Setter functions */ void @@ -76,18 +56,21 @@ t8_cmesh_get_num_local_vertices (const t8_cmesh_t cmesh) } const t8_gloidx_t * -t8_cmesh_get_global_vertices_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int num_vertices) +t8_cmesh_get_global_vertices_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, int *num_vertices) { T8_ASSERT (t8_cmesh_is_committed (cmesh)); - return cmesh->vertex_connectivity->get_global_vertices_of_tree (cmesh, local_tree, num_vertices); + const auto global_vertices = cmesh->vertex_connectivity->get_global_vertices_of_tree (local_tree); + *num_vertices = global_vertices.size (); + return global_vertices.data (); } t8_gloidx_t -t8_cmesh_get_global_vertex_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex, - const int num_vertices) +t8_cmesh_get_global_vertex_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex) { T8_ASSERT (t8_cmesh_is_committed (cmesh)); - const t8_gloidx_t *vertices_of_tree = t8_cmesh_get_global_vertices_of_tree (cmesh, local_tree, num_vertices); + int num_vertices; + const t8_gloidx_t *vertices_of_tree = t8_cmesh_get_global_vertices_of_tree (cmesh, local_tree, &num_vertices); + T8_ASSERT (num_vertices > local_tree_vertex); return vertices_of_tree[local_tree_vertex]; } diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h index 6724041295..a3857ceb61 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h @@ -32,7 +32,7 @@ T8_EXTERN_C_BEGIN (); /** * t8_cmesh_vertex_connectivity_c - * + * * Opaque pointer to the cmesh vertex connectivity structure. */ typedef struct t8_cmesh_vertex_connectivity *t8_cmesh_vertex_connectivity_c; @@ -66,22 +66,20 @@ t8_cmesh_get_num_local_vertices (const t8_cmesh_t cmesh); /** Get the global vertex indices of a tree in its local vertex order. * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree in \a cmesh. - * \param [in] num_vertices The number of vertices of \a local_tree + * \param [out] num_vertices The number of vertices of \a local_tree * \return The global vertices of \a local_tree */ const t8_gloidx_t * -t8_cmesh_get_global_vertices_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int num_vertices); +t8_cmesh_get_global_vertices_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, int *num_vertices); /** Get a single global vertex index of a local tree's local vertex. * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree in \a cmesh. * \param [in] local_tree_vertex A local vertex of \a local_tree -* \param [in] num_vertices The number of vertices of \a local_tree * \return The global vertex matching \a local_tree_vertex of \a local_tree. */ t8_gloidx_t -t8_cmesh_get_global_vertex_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex, - const int num_vertices); +t8_cmesh_get_global_vertex_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex); /** Get the number of global trees a global vertex is connected to. * \param [in] cmesh A committed cmesh. diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx index bd8b58a27d..4bda30fb0f 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx @@ -43,21 +43,21 @@ struct t8_cmesh_vertex_connectivity /** * Constructor. */ - t8_cmesh_vertex_connectivity (): global_number_of_vertices (0), local_number_of_vertices (0) {}; + t8_cmesh_vertex_connectivity () + : current_state (state::INITIALIZED), global_number_of_vertices (0), local_number_of_vertices (0), + associated_cmesh (nullptr) {}; /** * Destructor. */ ~t8_cmesh_vertex_connectivity () {}; - /** Given a cmesh, build up the vertex_to_tree and tree_to_vertex members. - * \param [in] cmesh A cmesh that has been initialized, but not committed. - * On error, state will be set to ERROR. - * The cmesh must not be committed, but all tree information and neighbor information must - * have been set. - * Currently, \a cmesh has to be replicated. */ - void - build (const t8_cmesh_t cmesh); + /** The state this connectivity can be in. */ + enum class state { + INITIALIZED, /**< Initialized but not filled */ + TREE_TO_VERTEX_VALID, /**< Ready to use, but only tree_to_vertex functionality. */ + VALID /**< Ready to use for full vertex connectivity. Cannot be altered anymore. */ + }; /* Setter functions */ @@ -74,30 +74,29 @@ struct t8_cmesh_vertex_connectivity const t8_gloidx_t *global_tree_vertices, const int num_vertices) { T8_ASSERT (t8_cmesh_is_initialized (cmesh)); + T8_ASSERT (!t8_cmesh_is_committed (cmesh)); + T8_ASSERT (current_state != state::VALID); + current_state = state::TREE_TO_VERTEX_VALID; + if (associated_cmesh == nullptr) { + associated_cmesh = cmesh; + } + T8_ASSERT (associated_cmesh == cmesh); return tree_to_vertex.set_global_vertex_ids_of_tree_vertices (cmesh, global_tree, global_tree_vertices, num_vertices); } - /** The state this connectivity can be in. */ - enum t8_cmesh_vertex_connectivity_state_t { - INITIALIZED, /*< Initialized but not valid. I.e. not ready to use. */ - VERTEX_TO_TREE_VALID, /*< Ready to use, but only vertex_to_tree functionality. */ - TREE_TO_VERTEX_VALID, /*< Ready to use, but only tree_to_vertex functionality. */ - VTT_AND_TTV_VALID /*< Ready to use with both ttv and vtt functinoality. */ - }; - - /** Function to fill vtt from a cmesh with ttv information. + /** Function to fill vtt from the stored ttv information. * Sets all global ids and associated tree vertices from - * the given input cmesh. - * Afterwards, the vtt is set to committed and can be used. - * \param [in] cmesh A committed cmesh with set tree to vertex entries (stored in this object) + * the associated cmesh. + * Afterwards, this class is ready to be used and cannot be altered. */ void - build_vertex_to_tree (const t8_cmesh_t cmesh) + build_vertex_to_tree () { - vertex_to_tree.build_from_ttv (cmesh, tree_to_vertex); + T8_ASSERT (current_state == state::TREE_TO_VERTEX_VALID); + vertex_to_tree.build_from_ttv (associated_cmesh, tree_to_vertex); global_number_of_vertices = vertex_to_tree.vertex_to_tree.size (); - state = VTT_AND_TTV_VALID; + current_state = state::VALID; } /* Getter functions */ @@ -106,14 +105,14 @@ struct t8_cmesh_vertex_connectivity * \return The total number of global vertices of \a cmesh. */ inline t8_gloidx_t - get_global_number_of_vertices () + get_global_number_of_vertices () const { return global_number_of_vertices; } /** Return the number of process local global vertices of a cmesh. - * \return The number of process local global vertices of \a cmesh. -*/ + * \return The number of process local global vertices of \a cmesh. + */ inline t8_gloidx_t get_local_number_of_vertices () { @@ -123,28 +122,39 @@ struct t8_cmesh_vertex_connectivity /** Return the state of the connectivity. * \return The current state (initialized, committed, etc) of this object. - * \ref t8_cmesh_vertex_connectivity_state_t + * \ref state */ - inline t8_cmesh_vertex_connectivity_state_t - get_state () + inline state + get_state () const { - return state; + return current_state; } /** Given a global vertex id, return the list of trees that share this vertex. * \param [in] vertex_id A global vertex id. * \return The trees and their local vertex ids matching \a vertex_id. */ - inline const vtt_storage_type & - vertex_to_trees (const t8_gloidx_t vertex_id); + inline const tree_vertex_list & + vertex_to_trees (const t8_gloidx_t vertex_id) const + { + T8_ASSERT (vertex_to_tree.is_committed ()); + T8_ASSERT (current_state == state::VALID); + return vertex_to_tree.get_tree_list_of_vertex (vertex_id); + } /** Given a local tree (or ghost) return the list of global vertices * this tree has (in order of its local vertices). * \param [in] ltree A local tree id. * \return The list of global vertices that this tree has. */ - inline const t8_locidx_t * - tree_to_vertices (const t8_locidx_t ltree); + inline const std::span + tree_to_vertices (const t8_locidx_t ltree) const + { + T8_ASSERT (current_state >= state::TREE_TO_VERTEX_VALID); + T8_ASSERT (tree_to_vertex.get_state () == t8_cmesh_vertex_conn_tree_to_vertex::state::FILLED); + T8_ASSERT (associated_cmesh != nullptr); + return tree_to_vertex.get_global_vertices (associated_cmesh, ltree); + } /** Given a local tree (or ghost) and a local vertex of that tree * return the global vertex id of that vertex. @@ -153,44 +163,50 @@ struct t8_cmesh_vertex_connectivity * \return The global vertex associated with \a ltree_vertex. */ inline t8_gloidx_t - treevertex_to_vertex (const t8_locidx_t ltree, const t8_locidx_t ltree_vertex); + treevertex_to_vertex (const t8_locidx_t ltree, const t8_locidx_t ltree_vertex) const + { + T8_ASSERT (current_state >= state::TREE_TO_VERTEX_VALID); + T8_ASSERT (tree_to_vertex.get_state () == t8_cmesh_vertex_conn_tree_to_vertex::state::FILLED); + T8_ASSERT (associated_cmesh != nullptr); + return tree_to_vertex.get_global_vertex (associated_cmesh, ltree, ltree_vertex); + } /** Get the global vertex indices of a tree in its local vertex order. - * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree in \a cmesh. - * \param [in] num_vertices The number of vertices of \a local_tree * \return The global vertices of \a local_tree */ - inline const t8_gloidx_t * - get_global_vertices_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int num_vertices) + inline const std::span + get_global_vertices_of_tree (const t8_locidx_t local_tree) const { - return tree_to_vertex.get_global_vertices (cmesh, local_tree, num_vertices); + T8_ASSERT (current_state >= state::TREE_TO_VERTEX_VALID); + T8_ASSERT (tree_to_vertex.get_state () == t8_cmesh_vertex_conn_tree_to_vertex::state::FILLED); + T8_ASSERT (associated_cmesh != nullptr); + return tree_to_vertex.get_global_vertices (associated_cmesh, local_tree); } /** Get a single global vertex index of a local tree's local vertex. - * \param [in] cmesh A committed cmesh. * \param [in] local_tree A local tree in \a cmesh. * \param [in] local_tree_vertex A local vertex of \a local_tree - * \param [in] num_vertices The number of vertices of \a local_tree * \return The global vertex matching \a local_tree_vertex of \a local_tree. */ inline t8_gloidx_t - get_global_vertex_of_tree (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex, - const int num_vertices) + get_global_vertex_of_tree (const t8_locidx_t local_tree, const int local_tree_vertex) const { - T8_ASSERT (t8_cmesh_is_committed (cmesh)); - const t8_gloidx_t *vertices_of_tree = get_global_vertices_of_tree (cmesh, local_tree, num_vertices); + T8_ASSERT (associated_cmesh != nullptr); + auto vertices_of_tree = get_global_vertices_of_tree (local_tree); + T8_ASSERT (vertices_of_tree.size () > static_cast (local_tree_vertex)); return vertices_of_tree[local_tree_vertex]; } /** Get the list of global trees and local vertex ids a global vertex is connected to. - * + * * \param [in] global_vertex_id The global id of a vertex in the cmesh. * \return The list of global tree ids and local vertex ids of \a global_vertex_id. */ inline const tree_vertex_list & - get_tree_list_of_vertex (const t8_gloidx_t global_vertex_id) + get_tree_list_of_vertex (const t8_gloidx_t global_vertex_id) const { + T8_ASSERT (current_state == state::VALID); return vertex_to_tree.get_tree_list_of_vertex (global_vertex_id); } @@ -200,32 +216,15 @@ struct t8_cmesh_vertex_connectivity * Example: For a quad where all 4 vertices map to a single global vertex this function will return 4. */ inline int - get_num_trees_at_vertex (const t8_gloidx_t global_vertex_id) + get_num_trees_at_vertex (const t8_gloidx_t global_vertex_id) const { + T8_ASSERT (current_state == state::VALID); return get_tree_list_of_vertex (global_vertex_id).size (); } - /** Get the current state of the vertex_to_tree instance. - * \return The current state of vertex_to_tree. - */ - inline int - get_vertex_to_tree_state () - { - return vertex_to_tree.get_state (); - } - - /** Get the current state of the tree_to_vertex instance. - * \return The current state of tree_to_vertex. - */ - inline int - get_tree_to_vertex_state () - { - return tree_to_vertex.get_state (); - } - private: - /** The internal state. Indicating whether no, the vtt, the ttv, or both are valid and ready to use. */ - t8_cmesh_vertex_connectivity_state_t state; + /** The internal state. Indicating whether this structure is new and unfilled, the ttv was filled or the vertex conn was built completely. */ + state current_state; /** The process global number of global vertices. */ t8_gloidx_t global_number_of_vertices; @@ -239,6 +238,9 @@ struct t8_cmesh_vertex_connectivity /** The internal tree to vertex storage. */ t8_cmesh_vertex_conn_tree_to_vertex tree_to_vertex; + + /** A pointer to the cmesh for attribute retrieval */ + t8_cmesh_t associated_cmesh; }; #endif /* !T8_CMESH_VERTEX_CONNECTIVITY */ diff --git a/src/t8_data/t8_cad.cxx b/src/t8_data/t8_cad.cxx new file mode 100644 index 0000000000..61acf30452 --- /dev/null +++ b/src/t8_data/t8_cad.cxx @@ -0,0 +1,302 @@ +/* + 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 classes in parallel. + + Copyright (C) 2025 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +t8_cad::t8_cad (std::string fileprefix) +{ + BRep_Builder builder; + std::ifstream is (fileprefix + ".brep"); + if (is.is_open () == false) { + SC_ABORTF ("Cannot find the file %s.brep.\n", fileprefix.c_str ()); + } + BRepTools::Read (cad_shape, is, builder); + is.close (); + if (cad_shape.IsNull ()) { + SC_ABORTF ("Could not read brep file or brep file contains no shape. " + "The cad file may be written with a newer cad version. " + "Linked cad version: %s", + OCC_VERSION_COMPLETE); + } + TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); + TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); + TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); +} + +t8_cad::t8_cad (const TopoDS_Shape cad_shape) +{ + if (cad_shape.IsNull ()) { + SC_ABORTF ("Shape is null. \n"); + } + TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); + TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); + TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); +} + +t8_cad::t8_cad () +{ + cad_shape.Nullify (); +} + +int +t8_cad::t8_geom_is_line (const int curve_index) const +{ + const Handle_Geom_Curve curve = t8_geom_get_cad_curve (curve_index); + const GeomAdaptor_Curve curve_adaptor (curve); + return curve_adaptor.GetType () == GeomAbs_Line; +} + +int +t8_cad::t8_geom_is_plane (const int surface_index) const +{ + const Handle_Geom_Surface surface = t8_geom_get_cad_surface (surface_index); + const GeomAdaptor_Surface surface_adaptor (surface); + return surface_adaptor.GetType () == GeomAbs_Plane; +} + +const gp_Pnt +t8_cad::t8_geom_get_cad_point (const int index) const +{ + T8_ASSERT (index <= cad_shape_vertex_map.Size ()); + return BRep_Tool::Pnt (TopoDS::Vertex (cad_shape_vertex_map.FindKey (index))); +} + +const Handle_Geom_Curve +t8_cad::t8_geom_get_cad_curve (const int index) const +{ + T8_ASSERT (index <= cad_shape_edge_map.Size ()); + Standard_Real first, last; + return BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (index)), first, last); +} + +const Handle_Geom_Surface +t8_cad::t8_geom_get_cad_surface (const int index) const +{ + T8_ASSERT (index <= cad_shape_face_map.Size ()); + return BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (index))); +} + +const TopTools_IndexedMapOfShape +t8_cad::t8_geom_get_cad_shape_vertex_map () const +{ + return cad_shape_vertex_map; +} + +const TopTools_IndexedMapOfShape +t8_cad::t8_geom_get_cad_shape_edge_map () const +{ + return cad_shape_edge_map; +} + +const TopTools_IndexedMapOfShape +t8_cad::t8_geom_get_cad_shape_face_map () const +{ + return cad_shape_face_map; +} + +int +t8_cad::t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const +{ + const TopTools_ListOfShape collection1 = cad_shape_vertex2edge_map.FindFromIndex (vertex1_index); + const TopTools_ListOfShape collection2 = cad_shape_vertex2edge_map.FindFromIndex (vertex2_index); + + for (auto edge1 = collection1.begin (); edge1 != collection1.end (); ++edge1) { + for (auto edge2 = collection2.begin (); edge2 != collection2.end (); ++edge2) { + if (edge1->IsEqual (*edge2)) { + return cad_shape_edge2face_map.FindIndex (*edge1); + } + } + } + return 0; +} + +int +t8_cad::t8_geom_get_common_face (const int edge1_index, const int edge2_index) const +{ + const TopTools_ListOfShape collection1 = cad_shape_edge2face_map.FindFromIndex (edge1_index); + const TopTools_ListOfShape collection2 = cad_shape_edge2face_map.FindFromIndex (edge2_index); + + for (auto face1 = collection1.begin (); face1 != collection1.end (); ++face1) { + for (auto face2 = collection2.begin (); face2 != collection2.end (); ++face2) { + if (face1->IsEqual (*face2)) { + return cad_shape_face_map.FindIndex (*face1); + } + } + } + return 0; +} + +int +t8_cad::t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const +{ + const TopTools_ListOfShape collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); + return collection.Contains (cad_shape_edge_map.FindKey (edge_index)); +} + +int +t8_cad::t8_geom_is_edge_on_face (const int edge_index, const int face_index) const +{ + const TopTools_ListOfShape collection = cad_shape_edge2face_map.FindFromIndex (edge_index); + return collection.Contains (cad_shape_face_map.FindKey (face_index)); +} + +int +t8_cad::t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const +{ + const TopTools_ListOfShape edge_collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); + for (auto edge = edge_collection.begin (); edge != edge_collection.end (); ++edge) { + const TopTools_ListOfShape face_collection = cad_shape_edge2face_map.FindFromKey (*edge); + if (face_collection.Contains (cad_shape_face_map.FindKey (face_index))) { + return 1; + } + } + return 0; +} + +void +t8_cad::t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, double *edge_param) const +{ + T8_ASSERT (t8_cad::t8_geom_is_vertex_on_edge (vertex_index, edge_index)); + TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); + TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); + *edge_param = BRep_Tool::Parameter (vertex, edge); +} + +void +t8_cad::t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, + double *face_params) const +{ + T8_ASSERT (t8_cad::t8_geom_is_vertex_on_face (vertex_index, face_index)); + gp_Pnt2d uv; + TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); + TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); + uv = BRep_Tool::Parameters (vertex, face); + face_params[0] = uv.X (); + face_params[1] = uv.Y (); +} + +void +t8_cad::t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, const int num_face_nodes, + const double edge_param, const double *surface_params, + double *face_params) const +{ + T8_ASSERT (t8_cad::t8_geom_is_edge_on_face (edge_index, face_index)); + Standard_Real first, last; + gp_Pnt2d uv; + TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); + TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); + Handle_Geom2d_Curve curve_on_surface = BRep_Tool::CurveOnSurface (edge, face, first, last); + Handle_Geom_Surface surface = BRep_Tool::Surface (face); + curve_on_surface->D0 (edge_param, uv); + face_params[0] = uv.X (); + face_params[1] = uv.Y (); + + /* Check for right conversion of edge to surface parameter and correct if needed */ + /* Checking u parameter */ + if (surface_params != NULL) { + double parametric_bounds[4]; + surface->Bounds (parametric_bounds[0], parametric_bounds[1], parametric_bounds[2], parametric_bounds[3]); + if (surface->IsUClosed ()) { + for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { + if (surface_params[i_face_node * 2] == parametric_bounds[0]) { + if (face_params[0] == parametric_bounds[1]) { + face_params[0] = parametric_bounds[0]; + } + } + else if (surface_params[i_face_node * 2] == parametric_bounds[1]) { + if (face_params[0] == parametric_bounds[0]) { + face_params[0] = parametric_bounds[1]; + } + } + } + } + /* Checking v parameter */ + if (surface->IsVClosed ()) { + for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { + if (surface_params[i_face_node * 2 + 1] == parametric_bounds[0]) { + if (face_params[1] == parametric_bounds[1]) { + face_params[1] = parametric_bounds[0]; + } + } + else if (surface_params[i_face_node * 2 + 1] == parametric_bounds[1]) { + if (face_params[1] == parametric_bounds[0]) { + face_params[1] = parametric_bounds[1]; + } + } + } + } + } +} + +void +t8_cad::t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const +{ + const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (surface_index); + cad_surface->Bounds (bounds[0], bounds[1], bounds[2], bounds[3]); +} + +void +t8_cad::t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const +{ + const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); + bounds[0] = cad_edge->FirstParameter (); + bounds[1] = cad_edge->LastParameter (); +} + +int +t8_cad::t8_geom_is_edge_closed (int edge_index) const +{ + const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); + return cad_edge->IsClosed (); +} + +int +t8_cad::t8_geom_is_surface_closed (int geometry_index, int parameter) const +{ + const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (geometry_index); + switch (parameter) { + case 0: + return cad_surface->IsUClosed (); + break; + case 1: + return cad_surface->IsVClosed (); + break; + default: + SC_ABORT_NOT_REACHED (); + break; + } +} diff --git a/src/t8_data/t8_cad.hxx b/src/t8_data/t8_cad.hxx new file mode 100644 index 0000000000..26915aeb59 --- /dev/null +++ b/src/t8_data/t8_cad.hxx @@ -0,0 +1,237 @@ +/* + 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 classes in parallel. + + Copyright (C) 2025 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. +*/ + +/** \file t8_geometry_cad.hxx + * This file implements the t8_cad class. It manages OpenCASCADE shapes and implements + * helper functions for working with the shapes. + */ + +#ifndef T8_CAD_HXX +#define T8_CAD_HXX + +#include +#include +#include +#include + +class t8_cad { + public: + /** + * Constructor of the cad shape. + * The shape is initialized based on a .brep file with the given prefix. + * The internal structure extracts and stores geometric information such as + * vertices, edges, and faces from this file. The number and type of vertices + * should match the tree type (quad/hex/tri), and the cad data must be valid. + * This constructor is intended for general use, including file-based mesh creation. + * + * \param [in] fileprefix Prefix of a .brep file from which to extract cad geometry. + */ + t8_cad (std::string fileprefix); + + /** + * Constructor of the cad shape. + * The shape is initialized directly from an existing TopoDS_Shape. + * This constructor is especially useful for use in scripts, testing, + * or integration with mesh generators that already provide geometry in memory. + * It avoids file I/O and allows full control over the CAD input. + * + * \param [in] cad_shape cad shape geometry object. + */ + t8_cad (const TopoDS_Shape cad_shape); + + /** + * Constructor of the cad shape for testing purposes. Sets an invalid cad_shape. + */ + t8_cad (); + + /** 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. + */ + int + t8_geom_is_line (const int curve_index) const; + + /** Check if a cad_surface is a plane. + * \param [in] surface_index The index of the cad_surface. + * \return 1 if surface is a plane linear, 0 if surface is not a plane. + */ + int + t8_geom_is_plane (const int surface_index) const; + + /** Get an cad point from the cad_shape. + * \param [in] index The index of the point in the cad_shape. + * \return The cad point. + */ + const gp_Pnt + t8_geom_get_cad_point (const int index) const; + + /** Get an cad curve from the cad_shape. + * \param [in] index The index of the curve in the cad_shape. + * \return The cad curve. + */ + const Handle_Geom_Curve + t8_geom_get_cad_curve (const int index) const; + + /** Get an cad surface from the cad_shape. + * \param [in] index The index of the surface in the cad_shape. + * \return The cad surface. + */ + const Handle_Geom_Surface + t8_geom_get_cad_surface (const int index) const; + + /** Get the cad_shape_vertex2edge_map. + * \return The cad_shape_vertex_map. + */ + const TopTools_IndexedMapOfShape + t8_geom_get_cad_shape_vertex_map () const; + + /** Get the cad_shape_edge2face_map. + * \return The cad_shape_edge_map. + */ + const TopTools_IndexedMapOfShape + t8_geom_get_cad_shape_edge_map () const; + + /** Get the cad_shape_face_map. + * \return The cad_shape_face_map. + */ + const TopTools_IndexedMapOfShape + t8_geom_get_cad_shape_face_map () const; + + /** Check if two cad points share a common cad edge. + * \param [in] vertex1_index The index of the first cad point. + * \param [in] vertex2_index The index of the second cad point. + * \return Index of the shared edge. 0 if there is no shared edge. + */ + int + t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const; + + /** Check if two cad edges share a common cad face. + * \param [in] edge1_index The index of the first cad edge. + * \param [in] edge2_index The index of the second cad edge. + * \return Index of the shared face. 0 if there is no shared face. + */ + int + t8_geom_get_common_face (const int edge1_index, const int edge2_index) const; + + /** Check if a cad vertex lies on an cad edge. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] edge_index The index of the cad edge. + * \return 1 if vertex lies on edge, otherwise 0. + */ + int + t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const; + + /** Check if a cad vertex lies on an cad edge. + * \param [in] edge_index The index of the cad vertex. + * \param [in] face_index The index of the cad edge. + * \return 1 if vertex lies on edge, otherwise 0. + */ + int + t8_geom_is_edge_on_face (const int edge_index, const int face_index) const; + + /** Check if a cad vertex lies on an cad face. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] face_index The index of the cad face. + * \return 1 if vertex lies on face, otherwise 0. + */ + int + t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const; + + /** Retrieves the parameter of an cad vertex on an cad edge. + * The vertex has to lie on the edge. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] edge_index The index of the cad edge. + * \param [out] edge_param The parameter of the vertex on the edge. + */ + void + t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, double *edge_param) const; + + /** Retrieves the parameters of an cad vertex on a cad face. + * The vertex has to lie on the face. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] face_index The index of the cad face. + * \param [out] face_params The parameters of the vertex on the face. + */ + void + t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, double *face_params) const; + + /** Converts the parameters of an cad edge to the corresponding parameters on an cad face. + * The edge has to lie on the face. + * For the conversion of edge parameters of mesh elements to topological face parameters of a closed surface, it is additionally + * checked, whether the conversion was correct, to prevent disorted elements. + * \param [in] edge_index The index of the cad edge, which parameters should be converted to face parameters. + * \param [in] face_index The index of the cad face, on to which the edge parameters should be converted. + * \param [in] num_face_nodes The number of the face nodes of the evaluated element. Only needed for closed surface check, otherwise NULL. + * \param [in] edge_param The parameter on the edge. + * \param [in] surface_param The parameters of the surface nodes. + * When provided, there are additional checks for closed geometries. + * If there are no surface parameter + * to pass in to the function, you can pass NULL. + * \param [out] face_params The corresponding parameters on the face. + */ + void + t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, const int num_face_nodes, + const double edge_param, const double *surface_params, + double *face_params) const; + + /** Finds the parametric bounds of an cad face. + * \param [in] face_index The index of the cad face. + * \param [out] bounds The parametric bounds of the cad face. + */ + void + t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const; + + /** Finds the parametric bounds of an cad edge. + * \param [in] edge_index The index of the cad edge. + * \param [out] bounds The parametric bounds of the cad edge. + */ + void + t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const; + + /** Checks if an edge is closed in its U parameter. + * \param [in] edge_index The index of the closed edge. + * \return 1 if edge is closed in U. 0 if edge is not closed in U. + */ + int + t8_geom_is_edge_closed (int edge_index) const; + + /** Checks if a surface is closed in its U parameter or V parameter. + * \param [in] geometry_index The index of the closed geometry. + * \param [in] parameter The parameter, which should be check for closeness. + * 0 stands for the U parameter and 1 for the V parameter. + * \return 1 if geometry is closed in U. 0 if geometry is not closed in U. + */ + int + t8_geom_is_surface_closed (int geometry_index, int parameter) const; + + private: + TopoDS_Shape cad_shape; /**< cad geometry */ + TopTools_IndexedMapOfShape cad_shape_vertex_map; /**< Map of all TopoDS_Vertex in shape. */ + TopTools_IndexedMapOfShape cad_shape_edge_map; /**< Map of all TopoDS_Edge in shape. */ + TopTools_IndexedMapOfShape cad_shape_face_map; /**< Map of all TopoDS_Face in shape. */ + TopTools_IndexedDataMapOfShapeListOfShape + cad_shape_vertex2edge_map; /**< Maps all TopoDS_Vertex of shape to all its connected TopoDS_Edge */ + TopTools_IndexedDataMapOfShapeListOfShape + cad_shape_edge2face_map; /**< Maps all TopoDS_Edge of shape to all its connected TopoDS_Face */ +}; + +#endif /* !T8_CAD_HXX */ diff --git a/src/t8_data/t8_containers.h b/src/t8_data/t8_containers.h index b8ae00f6f5..efa2ff6d6b 100644 --- a/src/t8_data/t8_containers.h +++ b/src/t8_data/t8_containers.h @@ -33,7 +33,7 @@ #include /** The t8_element_array_t is an array to store t8_element_t * of a given - * eclass_scheme implementation. It is a wrapper around \ref sc_array_t. + * eclass_scheme implementation. It is a wrapper around sc_array_t. * Each time, a new element is created by the functions for \ref t8_element_array_t, * the eclass function either \ref t8_element_new or \ref t8_element_init is called * for the element. @@ -41,9 +41,12 @@ */ typedef struct { - const t8_scheme_c *scheme; /**< A scheme of which elements should be stored */ - t8_eclass_t tree_class; /**< The tree class of the elements stored in the array */ - sc_array_t array; /**< The array in which the elements are stored */ + /** + * The scheme of which elements should be stored. + */ + const t8_scheme_c *scheme; /**!< A scheme of which elements should be stored */ + t8_eclass_t tree_class; /**!< The tree class of the elements stored in the array */ + sc_array_t array; /**!< The array in which the elements are stored */ } t8_element_array_t; T8_EXTERN_C_BEGIN (); @@ -151,7 +154,7 @@ void t8_element_array_copy (t8_element_array_t *dest, const t8_element_array_t *src); /** Enlarge an array by one element. - * \param [in, ou] element_array Array structure to be modified. + * \param [in, out] element_array Array structure to be modified. * \return Returns a pointer to a newly added element for which \ref t8_element_init * was called. */ @@ -159,7 +162,7 @@ t8_element_t * t8_element_array_push (t8_element_array_t *element_array); /** Enlarge an array by a number of elements. - * \param [in, ou] element_array Array structure to be modified. + * \param [in, out] element_array Array structure to be modified. * \param [in] count The number of elements to add. * \return Returns a pointer to the newly added elements for which \ref t8_element_init * was called. diff --git a/src/t8_data/t8_element_array_iterator.hxx b/src/t8_data/t8_element_array_iterator.hxx index 3c9e56eb2a..96a1f3ddcc 100644 --- a/src/t8_data/t8_element_array_iterator.hxx +++ b/src/t8_data/t8_element_array_iterator.hxx @@ -47,39 +47,70 @@ class t8_element_array_iterator { private: - const t8_scheme* scheme; /*!< The scheme of the elements residing within the array. */ - const sc_array_t* elements; /*!< A pointer to the actual serialized array of element pointers. */ - t8_locidx_t current_index { 0 }; /*!< The index the iterator currently points to. */ - t8_eclass_t tree_class; /*!< The tree class of the elements in the array. */ + const t8_scheme* scheme; /**< The scheme of the elements residing within the array. */ + const sc_array_t* elements; /**< A pointer to the actual serialized array of element pointers. */ + t8_locidx_t current_index { 0 }; /**< The index the iterator currently points to. */ + t8_eclass_t tree_class; /**< The tree class of the elements in the array. */ public: - using iterator_category = std::random_access_iterator_tag; - using difference_type = std::ptrdiff_t; - using pointer = t8_element_t**; - using value_type = t8_element_t*; - using reference = t8_element_t*&; + using iterator_category = std::random_access_iterator_tag; /**< The iterator category. */ + using difference_type = std::ptrdiff_t; /**< The difference type for the iterator. */ + using pointer = t8_element_t**; /**< The pointer type for the iterator. */ + using value_type = t8_element_t*; /**< The value type for the iterator. */ + using reference = t8_element_t*&; /**< The reference type for the iterator. */ /* Constructors */ t8_element_array_iterator () = delete; + + /** + * Constructor for the iterator. + * \param [in] element_array The element array to iterate over. + * \param [in] position The position in the array to start iterating from. + */ t8_element_array_iterator (const t8_element_array_t* element_array, const t8_locidx_t position) : scheme { t8_element_array_get_scheme (element_array) }, elements { t8_element_array_get_array (element_array) }, current_index { position }, tree_class (t8_element_array_get_tree_class (element_array)) {}; - /* Copy/Move Constructors/Assignment-Operators */ + /** + * Copy constructor for the iterator. + * \param [in] other The iterator to copy from. + */ t8_element_array_iterator (const t8_element_array_iterator& other) = default; + + /** + * Assignment operator for the iterator. + * \param [in] other The iterator to assign from. + * \return A reference to this iterator. + */ t8_element_array_iterator& operator= (const t8_element_array_iterator& other) = default; + /** + * Move constructor for the iterator. + * \param [in] other The iterator to move from. + */ t8_element_array_iterator (t8_element_array_iterator&& other) = default; + + /** + * Move assignment operator for the iterator. + * \param [in] other The iterator to move from. + * \return A reference to this iterator. + */ t8_element_array_iterator& operator= (t8_element_array_iterator&& other) = default; - /* Destructor */ + /** Destructor for the iterator. + * The iterator does not own the elements it points to, so no cleanup is necessary. + */ ~t8_element_array_iterator () = default; /* Dereferencing operator of the iterator wrapper returning a value_type (a t8_element_t-pointer * casted from the serialized char-bytes in the underlying sc_array_t). */ + /** + * Dereference operator for the iterator. + * \return A pointer to the element at the current index in the array. + */ value_type operator* () { @@ -87,6 +118,11 @@ class t8_element_array_iterator { return static_cast (t8_sc_array_index_locidx (elements, current_index)); }; + /** + * Subscript operator for the iterator. + * \param [in] n The index to access. + * \return A pointer to the element at the given index in the array. + */ value_type operator[] (const difference_type n) const { @@ -95,12 +131,21 @@ class t8_element_array_iterator { }; /* Pre- and Postfix increment */ + /** + * Pre-increment operator for the iterator. + * \return A reference to this iterator after incrementing. + */ t8_element_array_iterator& operator++ () { ++current_index; return *this; }; + + /** + * Post-increment operator for the iterator. + * \return A copy of this iterator before incrementing. + */ t8_element_array_iterator operator++ (int) { @@ -110,12 +155,21 @@ class t8_element_array_iterator { }; /* Pre- and Postfix decrement */ + /** + * Pre-decrement operator for the iterator. + * \return A reference to this iterator after decrementing. + */ t8_element_array_iterator& operator-- () { --current_index; return *this; }; + + /** + * Post-decrement operator for the iterator. + * \return A copy of this iterator before decrementing. + */ t8_element_array_iterator operator-- (int) { @@ -125,12 +179,23 @@ class t8_element_array_iterator { }; /* Arithmetic assignment operators */ + /** + * Add a number to the current index of the iterator. + * \param [in] n The number to add. + * \return A reference to this iterator after adding. + */ t8_element_array_iterator& operator+= (const difference_type n) { current_index += n; return *this; } + + /** + * Subtract a number from the current index of the iterator. + * \param [in] n The number to subtract. + * \return A reference to this iterator after subtracting. + */ t8_element_array_iterator& operator-= (const difference_type n) { @@ -139,33 +204,79 @@ class t8_element_array_iterator { return *this; } /* Comparison operators */ + /** + * Equality operator for the iterator. + * \param [in] iter1 The first iterator to compare. + * \param [in] iter2 The second iterator to compare. + * \return True if both iterators point to the same element in the same array, false otherwise. + */ friend bool operator== (const t8_element_array_iterator& iter1, const t8_element_array_iterator& iter2) { return (iter1.elements->array == iter2.elements->array && iter1.current_index == iter2.current_index); }; + + /** + * Inequality operator for the iterator. + * \param [in] iter1 The first iterator to compare. + * \param [in] iter2 The second iterator to compare. + * \return True if both iterators do not point to the same element in the same array, false otherwise. + */ friend bool operator!= (const t8_element_array_iterator& iter1, const t8_element_array_iterator& iter2) { return (iter1.elements->array != iter2.elements->array || iter1.current_index != iter2.current_index); }; + + /** + * Comparison operators for the iterator. + * These operators allow comparing two iterators based on their current index within the same array. + * \param [in] lhs The left-hand side iterator. + * \param [in] rhs The right-hand side iterator. + * \return True if the left-hand side iterator points to an element with a lower index than the right-hand side iterator, + * false otherwise. + */ friend bool operator< (const t8_element_array_iterator& lhs, const t8_element_array_iterator& rhs) { T8_ASSERT (lhs.elements->array == rhs.elements->array); return lhs.current_index < rhs.current_index; } + + /** + * Greater-than operator for the iterator. + * \param [in] lhs The left-hand side iterator. + * \param [in] rhs The right-hand side iterator. + * \return True if the left-hand side iterator points to an element with a higher index than the right-hand side iterator, + * false otherwise. + */ friend bool operator> (const t8_element_array_iterator& lhs, const t8_element_array_iterator& rhs) { T8_ASSERT (rhs.elements->array == lhs.elements->array); return rhs.current_index < lhs.current_index; } + + /** + * Less-than-or-equal operator for the iterator. + * \param [in] lhs The left-hand side iterator. + * \param [in] rhs The right-hand side iterator. + * \return True if the left-hand side iterator points to an element with a lower or equal index than the right-hand side iterator, + * false otherwise. + */ friend bool operator<= (const t8_element_array_iterator& lhs, const t8_element_array_iterator& rhs) { return !(rhs < lhs); } + + /** + * Greater-than-or-equal operator for the iterator. + * \param [in] lhs The left-hand side iterator. + * \param [in] rhs The right-hand side iterator. + * \return True if the left-hand side iterator points to an element with a higher or equal index than the right-hand side iterator, + * false otherwise. + */ friend bool operator>= (const t8_element_array_iterator& lhs, const t8_element_array_iterator& rhs) { @@ -173,6 +284,12 @@ class t8_element_array_iterator { } /* Arithmetic operators */ + /** + * Plus operator for the iterator. + * \param [in] iter The iterator to operate on. + * \param [in] n The number to add. + * \return A new iterator with the updated index. + */ friend t8_element_array_iterator operator+ (const t8_element_array_iterator& iter, const difference_type n) { @@ -180,11 +297,25 @@ class t8_element_array_iterator { tmp_iterator += n; return tmp_iterator; } + + /** + * Plus operator for the iterator. + * \param [in] n The number to add. + * \param [in] iter The iterator to operate on. + * \return A new iterator with the updated index. + */ friend t8_element_array_iterator operator+ (const difference_type n, const t8_element_array_iterator& iter) { return iter + n; } + + /** + * Minus operator for the iterator. + * \param [in] iter The iterator to operate on. + * \param [in] n The number to subtract. + * \return A new iterator with the updated index. + */ friend t8_element_array_iterator operator- (const t8_element_array_iterator& iter, const difference_type n) { @@ -192,6 +323,13 @@ class t8_element_array_iterator { tmp_iterator -= n; return tmp_iterator; } + + /** + * Difference operator for the iterator. + * \param [in] lhs The left-hand side iterator. + * \param [in] rhs The right-hand side iterator. + * \return The difference in indices between the two iterators. + */ friend difference_type operator- (const t8_element_array_iterator& lhs, const t8_element_array_iterator& rhs) { diff --git a/src/t8_data/t8_shmem.c b/src/t8_data/t8_shmem.c index 1e780da87b..64468fa175 100644 --- a/src/t8_data/t8_shmem.c +++ b/src/t8_data/t8_shmem.c @@ -33,15 +33,15 @@ * The array uses sc_shmem shared memory.*/ typedef struct t8_shmem_array { - void *array; /*< Pointer to the actual memory. */ - size_t elem_size; /*< Size of one entry in byte. */ - size_t elem_count; /*< Total count of entries. */ - sc_MPI_Comm comm; /*< MPI communicator. */ - int writing_possible; /*< True if we can currently write into this array. False if not. */ + void *array; /**< Pointer to the actual memory. */ + size_t elem_size; /**< Size of one entry in byte. */ + size_t elem_count; /**< Total count of entries. */ + sc_MPI_Comm comm; /**< MPI communicator. */ + int writing_possible; /**< True if we can currently write into this array. False if not. */ int - write_start_called; /*< True if t8_shmem_array_start_writing was called and no call to t8_shmem_array_end_writing happened yet. */ + write_start_called; /**< True if t8_shmem_array_start_writing was called and no call to t8_shmem_array_end_writing happened yet. */ #if T8_ENABLE_DEBUG - sc_shmem_type_t shmem_type; /*< Shared memory type of the communicator (at time of initializing the array). */ + sc_shmem_type_t shmem_type; /**< Shared memory type of the communicator (at time of initializing the array). */ #endif } t8_shmem_array_struct_t; @@ -220,6 +220,7 @@ t8_shmem_array_prefix (const void *sendbuf, t8_shmem_array_t recvarray, const in * \param[in] sendcount The number of items this proc sends * \param[in, out] recvcounts On input a zero-initialized array that is going to be filled with the number of elements send by rank i * \param[in, out] displs On input a zero-initialized array that is going to be filled with the displacements + * \param[in] comm The MPI communicator to use * \returns The total number of items */ static int @@ -480,7 +481,6 @@ t8_shmem_array_index_for_writing (t8_shmem_array_t array, size_t index) return ((char *) array->array) + index * array->elem_size; } -/* TODO: implement */ int t8_shmem_array_is_equal (t8_shmem_array_t array_a, t8_shmem_array_t array_b) { diff --git a/src/t8_data/t8_shmem.h b/src/t8_data/t8_shmem.h index 4fcef5cadb..973de0812a 100644 --- a/src/t8_data/t8_shmem.h +++ b/src/t8_data/t8_shmem.h @@ -30,7 +30,7 @@ #include #include -typedef struct t8_shmem_array *t8_shmem_array_t; +typedef struct t8_shmem_array *t8_shmem_array_t; /**< A shared memory array structure. */ /** Defines the shared memory type that is best suited for t8code and the * current machine. @@ -138,7 +138,7 @@ t8_shmem_array_copy (t8_shmem_array_t dest, t8_shmem_array_t source); * \param[in] sendbuf the source from this process * \param[in] sendcount the number of items to allgather * \param[in] sendtype the type of items to allgather - * \param[in,out] recvbuf the destination shmem array + * \param[in,out] recvarray the destination shmem array * \param[in] recvcount the number of items to allgather * \param[in] recvtype the type of items to allgather * \note Writing mode must be disabled for \a recvarray. @@ -264,8 +264,11 @@ t8_shmem_array_index (t8_shmem_array_t array, size_t index); void * t8_shmem_array_index_for_writing (t8_shmem_array_t array, size_t index); -/* TODO: implement and comment */ -/* returns true if arrays are equal +/** + * Check if two t8_shmem arrays are equal. + * \param [in] array_a The first t8_shmem_array to compare. + * \param [in] array_b The second t8_shmem_array to compare. + * \return 1 if the arrays are equal, 0 otherwise. * \note Writing mode must be disabled for \a array_a and \a array_b. */ int diff --git a/src/t8_data/t8_vector_handler.hxx b/src/t8_data/t8_vector_handler.hxx index ab1f21910c..e41dce66a2 100644 --- a/src/t8_data/t8_vector_handler.hxx +++ b/src/t8_data/t8_vector_handler.hxx @@ -37,6 +37,9 @@ #include #include +/** + * A base class for vector handlers. + */ class t8_abstract_vector_handler { public: /** @@ -171,8 +174,8 @@ class t8_vector_handler: public t8_abstract_vector_handler { /** * Compute the size of the buffer that is needed to pack the data. - * - * \param[in] data The data to be set. + * + * \param[in] comm The MPI communicator used for the operation. * \return The size of the buffer. */ int diff --git a/src/t8_element.h b/src/t8_element.h index 239ccd0fb5..0d5fa03d8f 100644 --- a/src/t8_element.h +++ b/src/t8_element.h @@ -40,13 +40,13 @@ T8_EXTERN_C_BEGIN (); typedef struct t8_element t8_element_t; /** This array holds the reference coordinates of each vertex of each element. - * It can e.g. be used with the \ref t8_element_reference_coords function. + * It can e.g. be used with the \ref t8_scheme::element_get_reference_coords function. * Usage: t8_element_corner_ref_coords[eclass][vertex][dimension] */ extern const double t8_element_corner_ref_coords[T8_ECLASS_COUNT][T8_ECLASS_MAX_CORNERS][3]; /** This array holds the reference coordinates of the centroid of each element. - * It can e.g. be used with the \ref t8_element_reference_coords function. + * It can e.g. be used with the \ref t8_scheme::element_get_reference_coords function. * Usage: t8_element_centroid_ref_coords[eclass][dimension] */ extern const double t8_element_centroid_ref_coords[T8_ECLASS_COUNT][3]; diff --git a/src/t8_element_shape.h b/src/t8_element_shape.h index 8c8d405008..a6b1ce11f0 100644 --- a/src/t8_element_shape.h +++ b/src/t8_element_shape.h @@ -45,7 +45,7 @@ typedef t8_eclass_t t8_element_shape_t; /** The maximum number of cornes a 3-dimensional element class can have. */ #define T8_ELEMENT_SHAPE_MAX_CORNERS 8 -/* Maximum possible number of corner nodes of an element in a specific dimension */ +/** Maximum possible number of corner nodes of an element in a specific dimension */ extern const int t8_element_shape_max_num_corner[T8_ECLASS_MAX_DIM + 1]; /** The number of codimension-one boundaries of an element class. */ diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index 832d59a33c..24f4c54a6a 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -435,8 +435,8 @@ t8_forest_element_from_ref_coords_ext (t8_forest_t forest, t8_locidx_t ltreeid, double stretched_ref_coords[T8_ECLASS_MAX_CORNERS * T8_ECLASS_MAX_DIM]; for (size_t i_coord = 0; i_coord < num_coords; ++i_coord) { for (int dim = 0; dim < tree_dim; ++dim) { - stretched_ref_coords[i_coord * tree_dim + dim] - = 0.5 + ((ref_coords[i_coord * tree_dim + dim] - 0.5) * stretch_factors[dim]); + stretched_ref_coords[i_coord * T8_ECLASS_MAX_DIM + dim] + = 0.5 + ((ref_coords[i_coord * T8_ECLASS_MAX_DIM + dim] - 0.5) * stretch_factors[dim]); } } scheme->element_get_reference_coords (tree_class, element, stretched_ref_coords, num_coords, tree_ref_coords); diff --git a/src/t8_forest/t8_forest_balance.cxx b/src/t8_forest/t8_forest_balance.cxx index 2b6fb7c317..13b73dd027 100644 --- a/src/t8_forest/t8_forest_balance.cxx +++ b/src/t8_forest/t8_forest_balance.cxx @@ -35,14 +35,27 @@ /* We want to export the whole implementation to be callable from "C" */ T8_EXTERN_C_BEGIN (); -/* This is the adapt function called during one round of balance. +/** This is the adapt function called during one round of balance. * We refine an element if it has any face neighbor with a level larger * than the element's level + 1. - */ -/* TODO: We currently do not adapt recursively since some functions such + * + * TODO: We currently do not adapt recursively since some functions such * as half neighbor computation require the forest to be committed. Thus, * we pass forest_from as a parameter. But doing so is not valid anymore - * if we refine recursively. */ + * if we refine recursively. + * + * \param[in, out] forest The forest to be adapted / balanced. + * \param[in] forest_from The forest from which the current one is derived. + * \param[in] ltree_id The local id of the tree the element is in. + * \param[in] tree_class The element class of the tree the element is in. + * \param[in] lelement_id The local id of the element within the tree. + * \param[in] scheme The scheme class. + * \param[in] is_family A switch indicating whether the passed elements form a family. + * \param[in] num_elements The number of elements passed as input. + * \param[in] elements The elements array. + * + * \return 1 if the element(s) has/have to be refined, 0 otherwise. + */ static int t8_forest_balance_adapt (t8_forest_t forest, t8_forest_t forest_from, const t8_locidx_t ltree_id, const t8_eclass_t tree_class, [[maybe_unused]] const t8_locidx_t lelement_id, @@ -102,7 +115,11 @@ t8_forest_balance_adapt (t8_forest_t forest, t8_forest_t forest_from, const t8_l return 0; } -/* Collective function to compute the maximum occurring refinement level in a forest */ +/** + * Collective function to compute the maximum occurring refinement level in a forest + * + * \param[in,out] forest The forest which the maximum refinement level is computed for and stored in. + */ static void t8_forest_compute_max_element_level (t8_forest_t forest) { diff --git a/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.cxx b/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.cxx new file mode 100644 index 0000000000..fd07aaf552 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.cxx @@ -0,0 +1,644 @@ +/* + 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 classes in parallel. + + Copyright (C) 2025 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; eithere 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. +*/ + +/** \file t8_forest_ghost_definition_overlap.cxx + * Implements a class of define ghost for PUMA. + */ + +#include +#include +/* The overlap ghost definition uses the standalone scheme for the stretching factor. */ +#include +#include +#include +#include + +/** + * Getter, setter and more for the uniform stretch factor. + */ + +std::array +t8_forest_ghost_definition_overlap::get_uniform_stretch_factor () const +{ + T8_ASSERT (_has_uniform_stretch_factor); + return _uniform_stretch_factor; +} + +void +t8_forest_ghost_definition_overlap::set_uniform_stretch_factor (std::array stretch_factors) +{ + _uniform_stretch_factor = stretch_factors; + _has_uniform_stretch_factor = true; +} + +bool +t8_forest_ghost_definition_overlap::has_uniform_stretch_factor () const +{ + return _has_uniform_stretch_factor; +} + +void +t8_forest_ghost_definition_overlap::unable_uniform_stretch_factor () +{ + _has_uniform_stretch_factor = false; +} + +/** + * Algorithms for the pre-, postprocessing of the search and the search it self. + */ + +bool +t8_forest_ghost_definition_overlap::do_ghost (t8_forest_t forest) +{ + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + if (tree_class != T8_ECLASS_QUAD && tree_class != T8_ECLASS_HEX) { + return T8_SUBROUTINE_FAILURE; + } + /* communicate ownerships */ + communicate_ownerships (forest); + + /* build cover of all processes */ + build_all_cover (forest); + + /* Initialize the ghost structure */ + t8_forest_ghost_init (&forest->ghosts, T8_GHOST_USER_DEFINED); + + /* search for ghost elements */ + /* t8_forest_element_from_ref_coords_ext */ + search_for_ghost_elements (forest); + + /* communicate ghost elements */ + communicate_ghost_elements (forest); + + /* clean up */ + clean_up (forest); + + return T8_SUBROUTINE_SUCCESS; +} + +void +t8_forest_ghost_definition_overlap::communicate_ownerships (t8_forest_t forest) +{ + /** Call the communicate ownership function of the base class. */ + t8_forest_ghost_definition::communicate_ownerships (forest); + if (!_has_uniform_stretch_factor) { + /** Exchange also the max stretch factors of the processes, if no uniform factor is given. */ + communicate_max_stretch_factor (forest); + } +} + +void +t8_forest_ghost_definition_overlap::communicate_max_stretch_factor (t8_forest_t forest) +{ + sc_MPI_Comm comm; + + T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (_max_stretch_factors == NULL); + + comm = forest->mpicomm; + /* Set the shmem array type of comm */ + t8_shmem_init (comm); + t8_shmem_set_type (comm, T8_SHMEM_BEST_TYPE); + /* Initialize the offset array as a shmem array + * holding 3 * mpisize many doubles */ + t8_shmem_array_init (&_max_stretch_factors, sizeof (double), 3 * forest->mpisize, comm); + /* Calculate the max stretch factors of all local elements. */ + double max_local_stretch_factors[3]; + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + t8_locidx_t num_leaf_elements = t8_forest_get_tree_num_leaf_elements (forest, 0); + for (t8_locidx_t ielement = 0; ielement < num_leaf_elements; ++ielement) { + const t8_element_t *element = t8_forest_get_leaf_element_in_tree (forest, 0, ielement); + if (tree_class == T8_ECLASS_QUAD) { + const t8_standalone_element *element_carsted + = (const t8_standalone_element *) element; + for (int dim = 0; dim < 3; ++dim) { + /** Update the max stretch factor, if necessary. */ + max_local_stretch_factors[dim] + = std::max (element_carsted->stretch_factors[dim], max_local_stretch_factors[dim]); + } + } + else if (tree_class == T8_ECLASS_HEX) { + const t8_standalone_element *element_carsted + = (const t8_standalone_element *) element; + for (int dim = 0; dim < 3; ++dim) { + /** Update the max stretch factor, if necessary. */ + max_local_stretch_factors[dim] + = std::max (element_carsted->stretch_factors[dim], max_local_stretch_factors[dim]); + } + } + } + /* Collect all max_stretch_factors in the array */ + t8_shmem_array_allgather (&max_local_stretch_factors, 3, sc_MPI_DOUBLE, _max_stretch_factors, 3, sc_MPI_DOUBLE); +} + +void +t8_forest_ghost_definition_overlap::clean_up (t8_forest_t forest) +{ + /* Clear up the same part, as in the parents class. */ + t8_forest_ghost_definition::clean_up (forest); + + /* Clean up the build covers. */ + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + const t8_scheme *eclass_scheme = t8_forest_get_scheme (forest); + for (std::vector cover : _list_of_covers) { + for (t8_element_t *cover_element : cover) { + eclass_scheme->element_destroy (tree_class, 1, &cover_element); + } + } + /* Clean up the over all max stretch factors list. */ + if (_max_stretch_factors != NULL) { + t8_shmem_array_destroy (&_max_stretch_factors); + } +} + +/** + * \note the given cubes are treated as closed cubes, + * i.e. an intersection in one corner is enough to have an intersection. + */ +bool +check_if_intersection (double lu_corner_one[6], double lu_corner_two[6], const int dimension) +{ + for (int d = 0; d < dimension; ++d) { + // to change the cubes to open cubes you have to change the < and the > in the second if to an <= and >= + if (lu_corner_one[d] < lu_corner_two[d]) { + if (lu_corner_one[3 + d] < lu_corner_two[d]) { + return false; + } + } + else { + if (lu_corner_one[d] > lu_corner_two[d + 3]) { + return false; + } + } + } + return true; +} + +void +t8_forest_ghost_definition_overlap::search_for_ghost_elements (t8_forest_t forest) +{ + /* Use the cover of all the other processes + * to check if the overlap with the owe elements + * add them to remote elements. */ + T8_ASSERT (t8_forest_is_committed (forest)); + + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + + /* To compute lower left and upper right corner later, get ref cords. */ + double ref_cords[2 * T8_ECLASS_MAX_DIM]; + int num_of_corners = T8_ELEMENT_NUM_CORNERS[tree_class]; + for (int i = 0; i < 2 * T8_ECLASS_MAX_DIM; i++) { + // i%3 = 0,1,2, 0,1,2 + ref_cords[i] + = t8_element_corner_ref_coords[tree_class][(i / T8_ECLASS_MAX_DIM) * (num_of_corners - 1)][i % T8_ECLASS_MAX_DIM]; + } + double coords_out[2 * T8_ECLASS_MAX_DIM]; + /* Iterate over the elements of the forest. */ + t8_locidx_t num_leaf_elements = t8_forest_get_tree_num_leaf_elements (forest, 0); + const int dimension = T8_ELEMENT_DIM[tree_class]; + for (t8_locidx_t ielement = 0; ielement < num_leaf_elements; ++ielement) { + /* Get the local element and its coords. */ + const t8_element_t *element = t8_forest_get_leaf_element_in_tree (forest, 0, ielement); + if (_has_uniform_stretch_factor) { + /* If a uniform stretch factor is given use this. */ + t8_forest_element_from_ref_coords_ext (forest, 0, element, ref_cords, 2, coords_out, + _uniform_stretch_factor.data ()); + } + else { + /* If no uniform stretch factor is given, use the factor of the element. */ + if (tree_class == T8_ECLASS_QUAD) { + t8_standalone_element *element_carsted = (t8_standalone_element *) element; + t8_forest_element_from_ref_coords_ext (forest, 0, element, ref_cords, 2, coords_out, + element_carsted->stretch_factors); + } + else if (tree_class == T8_ECLASS_HEX) { + t8_standalone_element *element_carsted = (t8_standalone_element *) element; + t8_forest_element_from_ref_coords_ext (forest, 0, element, ref_cords, 2, coords_out, + element_carsted->stretch_factors); + } + } + + for (int remote_rank = 0; remote_rank < forest->mpisize; ++remote_rank) { + if (remote_rank == forest->mpirank) { + /* Skip the process it self. */ + continue; + } + for (int icover_element = 0; icover_element < (int) _list_of_covers[remote_rank].size (); ++icover_element) { + /** Get the coords of the cover element. */ + double coords_cover_element[6]; + double *stretch_factor_cover_element; + if (_has_uniform_stretch_factor) { + stretch_factor_cover_element = _uniform_stretch_factor.data (); + } + else { + stretch_factor_cover_element = (double *) t8_shmem_array_get_array (_max_stretch_factors); + } + t8_forest_element_from_ref_coords_ext (forest, 0, _list_of_covers[remote_rank][icover_element], ref_cords, 2, + coords_cover_element, stretch_factor_cover_element); + /** Check if the local element and the element of the cover have an intersection. */ + bool has_intersection = check_if_intersection (coords_out, coords_cover_element, dimension); + if (has_intersection) { + t8_ghost_add_remote (forest, forest->ghosts, remote_rank, 0, element, ielement); + } + } + } /* End iteration over the remote ranks. */ + } /* End iteration over the local elements. */ +} + +/** + * This subroutine of the cover build function is a recursion in the first iteration. + * It builds the cover from the first element to the ancestor, + * by recursively calling this subroutine on a higher level. + * \par forest [in] The forest. + * \par tree_class [in] The tree class of the tree, + * \par eclass_scheme [in] The scheme of the elements. + * \par first_element [in] Point to the first element, which should be covered by the cover. + * \par lin_id_first_element [in] The linear id of the first element at max level. + * \par ancestors [in] An ancestor of the first element, which is covered by the cover. + * \par cover [in, out] The cover in progress. + */ +int +t8_ghost_puma_recursion_first_descandance (t8_forest_t forest, const t8_eclass_t tree_class, + const t8_scheme *eclass_scheme, const t8_element_t *first_element, + const t8_linearidx_t lin_id_first_element, const t8_element_t *ancestors, + std::vector &cover) +{ + /** In the recursion, build the four children of accessor and check witch of the is ancessor of the first element. + * All elements after this accessor are part of the cover. + * Start recursion at accessor again, if this element is not already the first element. + */ + /* Allocate memory for the childrens. */ + t8_element_t **children = T8_ALLOC (t8_element_t *, 4); + eclass_scheme->element_new (tree_class, 4, children); + eclass_scheme->element_get_children (tree_class, ancestors, 4, children); + /* Store max level for the loop. */ + int max_level = eclass_scheme->get_maxlevel (tree_class); + /* Define temporary element, for the search. */ + t8_element_t *child_first_nca; + eclass_scheme->element_new (tree_class, 1, &child_first_nca); + bool child_found = false; + /* Iterate forward over the childrens of accessor.*/ + for (int child_index = 0; child_index < 4; child_index++) { + /* If the child is found, that is accessor of the first element, only add the childrens after this to the cover. */ + if (child_found) { + // add element to cover + t8_element_t *element_for_cover; + eclass_scheme->element_new (tree_class, 1, &element_for_cover); + eclass_scheme->element_copy (tree_class, children[child_index], element_for_cover); + cover.push_back (element_for_cover); + /* If the child is not found yet */ + } + else { + /* Check if the nca of the child and the first element is the child itself. */ + eclass_scheme->element_get_nca (tree_class, first_element, children[child_index], child_first_nca); + if (eclass_scheme->element_is_equal (tree_class, children[child_index], child_first_nca)) { + /* If so, the child, witch is accessor of the first element, is found. */ + child_found = true; + /* Check if the child is already the first element. */ + if (eclass_scheme->element_get_linear_id (tree_class, children[child_index], max_level) + == lin_id_first_element) { + /* If the child is the first element, add the childe to the cover. */ + t8_element_t *element_for_cover; + eclass_scheme->element_new (tree_class, 1, &element_for_cover); + eclass_scheme->element_copy (tree_class, children[child_index], element_for_cover); + cover.push_back (element_for_cover); + } + else { + /* If the child is not the first element, continuo the recursion on the child. */ + t8_ghost_puma_recursion_first_descandance (forest, tree_class, eclass_scheme, first_element, + lin_id_first_element, children[child_index], cover); + } + } + } + } + /** Clean up. */ + eclass_scheme->element_destroy (tree_class, 1, &child_first_nca); + eclass_scheme->element_destroy (tree_class, 4, children); + T8_FREE (children); + return 0; +} + +/** + * This subroutine of the cover build function is a recursion in the second iteration. + * It builds the cover from the first element to the ancestor, + * by recursively calling this subroutine on a higher level. + * \par forest [in] The forest. + * \par tree_class [in] The tree class of the tree, + * \par eclass_scheme [in] The scheme of the elements. + * \par last_element [in] Point to the first element, which should be covered by the cover. + * \par lin_id_last_element [in] The linear id of the first element at max level. + * \par ancestors [in] An ancestor of the first element, which is covered by the cover. + * \par cover [in, out] The cover in progress. + */ +int +t8_ghost_puma_recursion_last_descandance (t8_forest_t forest, const t8_eclass_t tree_class, + const t8_scheme_c *eclass_scheme, const t8_element_t *last_element, + const t8_linearidx_t lin_id_last_element, const t8_element_t *ancestors, + std::vector &cover) +{ + /* Allocate memory for the childrens. */ + t8_element_t **children = T8_ALLOC (t8_element_t *, 4); + eclass_scheme->element_new (tree_class, 4, children); + eclass_scheme->element_get_children (tree_class, ancestors, 4, children); + + t8_element_t *child_first_nca; + eclass_scheme->element_new (tree_class, 1, &child_first_nca); + + bool child_found = false; + for (int child_index = 4 - 1; child_index > -1; child_index--) { + if (child_found) { + t8_element_t *element_for_cover; + eclass_scheme->element_new (tree_class, 1, &element_for_cover); + eclass_scheme->element_copy (tree_class, children[child_index], element_for_cover); + cover.push_back (element_for_cover); + } + else { + /* Get nca of last element and child[i] of ancestor. */ + eclass_scheme->element_get_nca (tree_class, last_element, children[child_index], child_first_nca); + if (eclass_scheme->element_is_equal (tree_class, children[child_index], child_first_nca)) { + child_found = true; + } + } + } + + eclass_scheme->element_destroy (tree_class, 1, &child_first_nca); + eclass_scheme->element_destroy (tree_class, 4, children); + T8_FREE (children); + + return 0; +} + +/** + * To create a cover, we iterate over the forest in three ways. + * Here in the first iteration, we iterate forwards over the children of the nca with the first element. + * \param [in] forest The forest. + * \param [in] children Array of childrens of the nca of the first and the last element. + * \param [in] tree_class Class of the tree. + * \param [in] eclass_scheme Scheme of the forest. + * \param [in] first_element Pointer to the first element. + * \return index of the child of nca, witch is the parent of the first element. + * cover : The forest is covered from the first element to the last leaf, + * which is the ancestor of the first element and a child of the nca. + */ +int +build_cover_forward_iteration (t8_forest_t forest, t8_element_t **children, const t8_eclass_t tree_class, + const t8_scheme_c *eclass_scheme, const t8_element_t *first_element, + const t8_linearidx_t lin_id_first_element, std::vector &cover) +{ + /* To reduce memory use, create an element, and use it multiple times in the iterations. */ + t8_element_t *child_first_nca; + eclass_scheme->element_new (tree_class, 1, &child_first_nca); + const int max_level = t8_forest_get_maxlevel (forest); + /* To fill the cover with the in between of the children witch war parent of first and last element. */ + int parent_of_first_element_and_child_of_nca = 4; + for (int child_index = 0; child_index < 4; child_index++) { + /* Get nca of child[i] and first_element*/ + eclass_scheme->element_get_nca (tree_class, first_element, children[child_index], child_first_nca); + + /* Check nca_child_first == child */ + if (eclass_scheme->element_is_equal (tree_class, children[child_index], child_first_nca)) { + if (eclass_scheme->element_get_linear_id (tree_class, children[child_index], max_level) == lin_id_first_element) { + /* If the child is the first element, add the child to cover. */ + t8_element_t *element_for_cover; + eclass_scheme->element_new (tree_class, 1, &element_for_cover); + eclass_scheme->element_copy (tree_class, children[child_index], element_for_cover); + cover.push_back (element_for_cover); + } + else { + /* If the child is not the first element, start a recursion on this child. */ + t8_ghost_puma_recursion_first_descandance (forest, tree_class, eclass_scheme, first_element, + lin_id_first_element, children[child_index], cover); + } + /* Update the return value. */ + parent_of_first_element_and_child_of_nca = child_index; + /* If the child, witch is accessor of the first element, is found, do not test the other children. */ + break; + } + } + eclass_scheme->element_destroy (tree_class, 1, &child_first_nca); + return parent_of_first_element_and_child_of_nca; +} + +/** + * To create a cover, we iterate over the forest in three ways. + * Here in the second iteration, we iterate backward over the children of the nca with the last element. + * \param [in] forest The forest. + * \param [in] children Array of childrens of the nca of the first and the last element. + * \param [in] tree_class Class of the tree. + * \param [in] eclass_scheme Scheme of the forest. + * \param [in] last_element Pointer to the last element. + * \return index of the child of nca, witch is the parent of the last element. + * cover : The forest is covered from the first leaf, + * which is the ancestor of the last element and a child of the nca, to the last element. + */ +int +build_cover_backward_iteration (t8_forest_t forest, t8_element_t **children, const t8_eclass_t tree_class, + const t8_scheme_c *eclass_scheme, const t8_element_t *last_element, + const t8_linearidx_t lin_id_last_element, + std::vector &revers_last_cover_part) +{ + /* To reduce memory use, create an element, and use it multiple times in the iterations. */ + t8_element_t *child_first_nca; + eclass_scheme->element_new (tree_class, 1, &child_first_nca); + const int max_level = t8_forest_get_maxlevel (forest); + /* To fill the cover with the in between of the children witch war parent of first and last element. */ + int parent_of_last_element_and_child_of_nca = 0; + + for (int child_index = 3; child_index > -1; child_index--) { + /* get nca of child[i] and last_element*/ + eclass_scheme->element_get_nca (tree_class, last_element, children[child_index], child_first_nca); + if (eclass_scheme->element_is_equal (tree_class, children[child_index], child_first_nca)) { + /* Child is parent of last_element */ + if (eclass_scheme->element_get_linear_id (tree_class, children[child_index], max_level) != lin_id_last_element) { + /* If the child is not the last element, start a recursion on the child. */ + t8_ghost_puma_recursion_last_descandance (forest, tree_class, eclass_scheme, last_element, lin_id_last_element, + children[child_index], revers_last_cover_part); + } + /* If the child is found, witch is accessor of the last element, update the return value. */ + parent_of_last_element_and_child_of_nca = child_index; + /* If the child, witch is accessor of the last element, is found, do not test the other children. */ + break; + } + } + eclass_scheme->element_destroy (tree_class, 1, &child_first_nca); + return parent_of_last_element_and_child_of_nca; +} + +/** Build a cover for a given process. + * A set of elements is a cover of a process, + * if for each leaf element in the process, there is an element in the cover, + * that is equal to an ancestor of this leaf element or equal as the element it self. + * Moreover the leafs of every other process have no ancestor in the cover. + * \param [in] forest The forest. + * \param [in] process The process for which the cover is built. + * \return The cover of the leafs of the process elements. + * \note This function allocate memory for the cover. New elements are build here. + */ +std::vector +build_cover_of_process (t8_forest_t forest, const int process) +{ + T8_ASSERT (t8_forest_is_committed (forest)); + + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + const t8_scheme *eclass_scheme = t8_forest_get_scheme (forest); + const int max_level = t8_forest_get_maxlevel (forest); + T8_ASSERT (tree_class == T8_ECLASS_QUAD || tree_class == T8_ECLASS_HEX); + + /** The vector where the final cover of process be stored. */ + std::vector cover {}; + /** In the recursion to find the cover of the last relevant child of nca, + * the elements are pushed in reversed order. This vector will be slicet at the end with the cover vector. */ + std::vector revers_last_cover_part {}; + /* Define pointer for necessary elements in search */ + t8_element_t *first_element; + t8_element_t *last_element; + t8_element_t *nca; // nca of the first and last element + /* Create temporary elements for the search. */ + eclass_scheme->element_new (tree_class, 1, &first_element); + eclass_scheme->element_new (tree_class, 1, &last_element); + eclass_scheme->element_new (tree_class, 1, &nca); + + /* Initialization of the temporary elements. For the last process some parts are different. */ + /* Get the id of first descendant of the given rank and set the first element to it. */ + const t8_linearidx_t lin_id_first_element + = *(t8_linearidx_t *) t8_shmem_array_index (forest->global_first_desc, process); + eclass_scheme->element_set_linear_id (tree_class, first_element, max_level, lin_id_first_element); + /* In case of the last process, the last element is a special case, because there is no entry process+1 in global_first_desc. */ + const t8_linearidx_t lin_id_last_element + = (process + 1 < forest->mpisize) + ? *(t8_linearidx_t *) t8_shmem_array_index (forest->global_first_desc, process + 1) + : 0; + if (process + 1 < forest->mpisize) { + /* The process is not the last one. As last element we use the first descadant of the next process. */ + eclass_scheme->element_set_linear_id (tree_class, last_element, max_level, lin_id_last_element); + /** If first and last element have the same id. No work to do. Return empty cover. */ + if (lin_id_first_element == lin_id_last_element) { + return cover; + } + /* Compute parent of first and last element with min. level. */ + eclass_scheme->element_get_nca (tree_class, first_element, last_element, nca); + } + else { + /* The given process is the last one.*/ + /* No last element computed. Use as nca the root element.*/ + eclass_scheme->set_to_root (tree_class, nca); + } + /** Create the children of nca. */ + const int max_num_children = eclass_scheme->get_max_num_children (tree_class); + t8_element_t **children = T8_ALLOC (t8_element_t *, max_num_children); + eclass_scheme->element_new (tree_class, max_num_children, children); + eclass_scheme->element_get_children (tree_class, nca, max_num_children, children); + /** + * Iterate over the children of nca, in tree ways. + * 1. forward: Search for the parent of the first element. + * If necessary, do a recursion on this to calculate the first part of the cover. + * 2. backward: Search for the parent of the last element. + * If necessary, do a recursion on this to calculate the last part of the cover. + * 3. forward: Add the children of nca between the parents of the first and last elements to the cover. + */ + + /** + * Cover of the child of nca that is parent of the first element. + * to fill the cover with the in between of the children witch war parent of first and last element. + */ + const int parent_of_first_element_and_child_of_nca = build_cover_forward_iteration ( + forest, children, tree_class, eclass_scheme, first_element, lin_id_first_element, cover); + /** + * Cover of the child of nca that is parent of the last element. + * If there is no last element (e.g. the process is the last process), + * skip this stepp. + */ + int parent_of_last_element_and_child_of_nca = max_num_children; + if (process + 1 < forest->mpisize) { + parent_of_last_element_and_child_of_nca = build_cover_backward_iteration ( + forest, children, tree_class, eclass_scheme, last_element, lin_id_last_element, revers_last_cover_part); + } + /** + * Cover of the child of nca that are in between + */ + for (int inbetween_childrens = parent_of_first_element_and_child_of_nca + 1; + inbetween_childrens < parent_of_last_element_and_child_of_nca; ++inbetween_childrens) { + /* Add element in between to cover */ + t8_element_t *element_for_cover; + eclass_scheme->element_new (tree_class, 1, &element_for_cover); + eclass_scheme->element_copy (tree_class, children[inbetween_childrens], element_for_cover); + cover.push_back (element_for_cover); + } + /** Slice the cover and the last part of it together. */ + std::reverse (revers_last_cover_part.begin (), revers_last_cover_part.end ()); + for (auto &element_pt : revers_last_cover_part) { + cover.push_back (element_pt); + } + + /* Destroy temporary build elements. */ + eclass_scheme->element_destroy (tree_class, max_num_children, children); + T8_FREE (children); + eclass_scheme->element_destroy (tree_class, 1, &nca); + eclass_scheme->element_destroy (tree_class, 1, &last_element); + eclass_scheme->element_destroy (tree_class, 1, &first_element); + /* Return the final cover of the process. */ + return cover; +} + +/** + * Build a list of covers with a cover for every process. + * \param [in] forest The forest. + */ +void +t8_forest_ghost_definition_overlap::build_all_cover (t8_forest_t forest) +{ + T8_ASSERT (_list_of_covers.empty ()); + /* Get treeclass of forest. */ + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + /* Iterate over all processes. */ + for (int p = 0; p < forest->mpisize; ++p) { + std::vector cover = build_cover_of_process (forest, p); + /** If the process hase communicates stretch facotres apply them to the cover. */ + if (_max_stretch_factors != NULL || _has_uniform_stretch_factor) { + /** Get max stretch facotres of the process p. */ + double max_stretch_factors[3]; + for (int dim = 0; dim < 3; ++dim) { + max_stretch_factors[dim] = _has_uniform_stretch_factor + ? _uniform_stretch_factor[dim] + : *(double *) t8_shmem_array_index (_max_stretch_factors, 3 * p + dim); + } + /** Set the stretch factor of all cover elements to the max stretch factor of the process. */ + for (int index = 0; index < (int) cover.size (); ++index) { + if (tree_class == T8_ECLASS_QUAD) { + t8_standalone_element *element_carsted + = (t8_standalone_element *) cover[index]; + for (int dim = 0; dim < 3; ++dim) { + element_carsted->stretch_factors[dim] = max_stretch_factors[dim]; + } + } + else if (tree_class == T8_ECLASS_HEX) { + t8_standalone_element *element_carsted = (t8_standalone_element *) cover[index]; + for (int dim = 0; dim < 3; ++dim) { + element_carsted->stretch_factors[dim] = max_stretch_factors[dim]; + } + } + } + } + /** Add the cover to the list of covers. */ + _list_of_covers.push_back (cover); + } +} diff --git a/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.hxx b/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.hxx new file mode 100644 index 0000000000..b7da471c03 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost/t8_forest_ghost_implementations/t8_forest_ghost_definition_overlap.hxx @@ -0,0 +1,127 @@ +/* + 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 classes in parallel. + + Copyright (C) 2025 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. +*/ + +/** \file t8_forest_ghost_definition_overlap.hxx + * Implements a class of define ghost for PUMA. + */ + +#ifndef T8_FOREST_GHOST_DEFINITION_OVERLAP_HXX +#define T8_FOREST_GHOST_DEFINITION_OVERLAP_HXX + +#include +#include +#include +#include + +/** + * Base class for a ghost definition with elements with stretch factors. + */ +struct t8_forest_ghost_definition_overlap: public t8_forest_ghost_definition +{ + public: + /** Base constructor with no arguments. We need this since it + * is called from derived class constructors. */ + t8_forest_ghost_definition_overlap (): t8_forest_ghost_definition (T8_GHOST_USER_DEFINED) + { + } + + /** Constructor for ghost definition overlap with uniform stretch factor. */ + t8_forest_ghost_definition_overlap (std::array stretch_factors) + : t8_forest_ghost_definition (T8_GHOST_USER_DEFINED), _uniform_stretch_factor (stretch_factors) + { + _has_uniform_stretch_factor = true; + } + + /** Get the uniform stretch factor of the ghost definition. + * \return uniform stretch factor in every dimension, or NULL if there is no uniform stretch factor. + */ + std::array + get_uniform_stretch_factor () const; + /** Set a uniform stretch factor for each dimension. */ + void + set_uniform_stretch_factor (std::array stretch_factors); + /** Get if the ghost definition uses a uniform stretch factor + * or computes an communicate max factors for every process. */ + bool + has_uniform_stretch_factor () const; + /** Change the strategy of the ghost definition from a uniform stretch factor + * to compute and communicate max stretch factors for each process. + */ + void + unable_uniform_stretch_factor (); + + /** Create one layer of ghost elements for a forest. + * \param [in,out] forest The forest. + * \return T8_SUBROUTINE_SUCCESS if successful, T8_SUBROUTINE_FAILURE if not. + * \a forest must be committed before calling this function. + */ + virtual bool + do_ghost (t8_forest_t forest) override; + + protected: + /** + * Compute and collect ownerships to create the necessary offset + * for elements, trees and first descendant. + * Use memory_flag to record the allocation of memory. + * If there is no uniform stretch factor, the maximum stretch factor for each process is communicated. + * \note this function could be used in do_ghost + */ + void + communicate_ownerships (t8_forest_t forest) override; + + /** + * \note this function could be used in communicate_ownership. + */ + void + communicate_max_stretch_factor (t8_forest_t forest); + + /** Build a cover (coarsest possible grid of the local elements of a single process) + * for each process. + * \param [in] forest Committed forest with elements with uniform stretch factor + */ + void + build_all_cover (t8_forest_t forest); + + /** Each process uses a the minimal covers from the communication + * to check which of its elements overlap with those of the others + * and creates lists of remote ghost elements for them. + */ + virtual void + search_for_ghost_elements (t8_forest_t forest); + + /** + * If memory was allocated for the offset array in communicate_ownerships it is released here. + * Use memory_flag for this. + */ + virtual void + clean_up (t8_forest_t forest) override; + + bool _has_uniform_stretch_factor = false; + + std::array _uniform_stretch_factor; + + std::vector> _list_of_covers {}; + + t8_shmem_array_t _max_stretch_factors = NULL; +}; + +#endif /* T8_FOREST_GHOST_DEFINITION_OVERLAP_HXX */ diff --git a/src/t8_forest/t8_forest_iterate.cxx b/src/t8_forest/t8_forest_iterate.cxx index de904c08ed..c1b951f28e 100644 --- a/src/t8_forest/t8_forest_iterate.cxx +++ b/src/t8_forest/t8_forest_iterate.cxx @@ -36,8 +36,16 @@ typedef struct int num_children; } t8_forest_child_type_query_t; -/* This is the function that we call in sc_split_array to determine for an - * element E that is a descendant of an element e, of which of e's children, E is a descendant. */ +/** + * This is the function that we call in sc_split_array to determine for an + * element E that is a descendant of an element e, of which of e's children, E is a descendant. + * + * \param[in] leaf_elements The larray of eaf elements. + * \param[in] index The local id of the element within the leaf_elements array. + * \param[in] data The query data. + * + * \return The element's ancestor id at the stored level is returned as the element's type. + */ static size_t t8_forest_determine_child_type (sc_array_t *leaf_elements, size_t index, void *data) { @@ -434,14 +442,14 @@ t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_fo } } T8_ASSERT (family_size <= scheme->element_get_num_children (tree_class, elem_new)); -#if T8_DEBUG +#if T8_ENABLE_DEBUG /* Check whether elem_old is the first element of the family */ for (t8_locidx_t ielem = 1; ielem < scheme->element_get_num_children (tree_class, elem_old) && ielem_old - ielem >= 0; ielem++) { const t8_element_t *elem_old_debug = t8_forest_get_leaf_element_in_tree (forest_old, itree, ielem_old - ielem); scheme->element_get_parent (tree_class, elem_old_debug, elem_parent); - SC_CHECK_ABORT (!scheme->t8_element_equal (elem_new, elem_parent), + SC_CHECK_ABORT (!scheme->element_is_equal (tree_class, elem_new, elem_parent), "elem_old is not the first of the family."); } #endif diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx index 29a6ea3375..a2a11cc2ee 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -99,8 +99,8 @@ t8_search_base::search_recursion (const t8_locidx_t ltreeid, t8_element_t *eleme * we construct an array of these leaves */ t8_element_array_init_view (&child_leaves, leaf_elements, indexa, indexb - indexa); /* Enter the recursion */ - search_recursion (ltreeid, children[ichild], ts, &child_leaves, indexa + tree_lindex_of_first_leaf); update_queries (new_active_queries); + search_recursion (ltreeid, children[ichild], ts, &child_leaves, indexa + tree_lindex_of_first_leaf); } } @@ -138,6 +138,7 @@ t8_search_base::do_search () T8_ASSERT (t8_forest_is_committed (forest)); const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (this->forest); for (t8_locidx_t itree = 0; itree < num_local_trees; itree++) { + this->init_queries (); this->search_tree (itree); } } @@ -145,9 +146,12 @@ t8_search_base::do_search () /* #################### t8_forest_search c interface #################### */ T8_EXTERN_C_BEGIN (); +/** + * The structure that contains the C++ search object. Needed for the C interface. + */ struct t8_forest_c_search { - t8_search *cpp_search; + t8_search *cpp_search; /**< The C++ search object. */ }; void @@ -190,9 +194,12 @@ t8_forest_search_destroy (t8_forest_search_c_wrapper search) search->cpp_search = NULL; } +/** + * The structure that contains the C++ search object with queries. Needed for the C interface. + */ struct t8_forest_search_with_queries { - t8_search_with_queries *cpp_search; + t8_search_with_queries *cpp_search; /**< The C++ search object with queries. */ }; void @@ -258,11 +265,27 @@ t8_forest_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper s search->cpp_search = NULL; } +/** + * The structure that contains the C++ search object with batched queries. Needed for the C interface. + */ struct t8_forest_search_with_batched_queries { - t8_search_with_batched_queries *cpp_search; - t8_search_batched_queries_callback_c_wrapper queries_callback; - + t8_search_with_batched_queries *cpp_search; /**< The C++ search object. */ + t8_search_batched_queries_callback_c_wrapper queries_callback; /**< The C++ query object. */ + + /** + * A wrapper function that converts the C callback to the C++ callback. + * \param[in] forest the forest on which the search is performed + * \param[in] ltreeid the local tree id of the tree being searched + * \param[in] element the element being searched + * \param[in] is_leaf whether the element is a leaf + * \param[in] leaf_elements the array of leaf elements + * \param[in] tree_leaf_index the index of the first leaf in the tree + * \param[in] queries a vector of pointers to the queries + * \param[in] active_query_indices a vector of indices of the active queries + * \param[out] query_matches a vector of booleans indicating whether each query matched + * \param[in] user_data a pointer to user data + */ void wrapped_queries_callback (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.h b/src/t8_forest/t8_forest_search/t8_forest_search.h index 6991f3dc76..f17d2cb365 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.h +++ b/src/t8_forest/t8_forest_search/t8_forest_search.h @@ -32,16 +32,61 @@ T8_EXTERN_C_BEGIN (); +/** + * A call-back function used by \ref t8_forest_init_search for searching elements. Is called on an element and the + * search criterion should be checked on that element. Return true if the search criterion is met, false otherwise. + * + * \param[in] forest the forest + * \param[in] ltreeid the local tree id of the current tree in the cmesh. + * \param[in] element the element for which the search criterion is checked + * \param[in] is_leaf true if and only if \a element is a leaf element + * \param[in] leaf_elements the leaf elements in \a forest + * \param[in] tree_leaf_index the local index of the first leaf in \a leaf_elements + * \param[in] user_data a user data pointer that can be set by the user + * \returns non-zero if the search criterion is met, zero otherwise. + */ typedef int (*t8_search_element_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, void *user_data); +/** A call-back function used by \ref t8_forest_init_search_with_queries for searching elements and + * executing queries. Is called on an element and all queries are checked on that element. All positive + * queries are passed further down to the children of the element up to leaf elements of the tree. + * The results of the check are stored in \a query_matches. + * + * \param[in] forest the forest + * \param[in] ltreeid the local tree id of the current tree in the cmesh. + * \param[in] element the element for which the search criterion is checked + * \param[in] is_leaf true if and only if \a element is a leaf element + * \param[in] leaf_elements the leaf elements in \a forest + * \param[in] tree_leaf_index the local index of the first leaf in \a leaf_elements + * \param[in] queries a pointer to an array of queries + * \param[in] user_data a user data pointer that can be set by the user + */ typedef int (*t8_search_queries_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, void *queries, void *user_data); +/** A call-back function used by \ref t8_forest_init_search_with_batched_queries for searching elements and + * executing batched queries. Is called on an element and all queries are checked on that element. All positive + * queries are passed further down to the children of the element up to leaf elements of the tree. + * The results of the check are stored in \a query_matches. + * + * \param[in] forest the forest + * \param[in] ltreeid the local tree id of the current tree in the cmesh. + * \param[in] element the element for which the search criterion is checked + * \param[in] is_leaf true if and only if \a element is a leaf element + * \param[in] leaf_elements the leaf elements in \a forest + * \param[in] tree_leaf_index the local index of the first leaf in \a leaf_elements + * \param[in] queries a pointer to an array of queries + * \param[in] active_query_indices a pointer to an array of indices of active queries in \a queries + * \param[in,out] query_matches a pointer to an array of length \a num_active_queries. + * If query_matches[i] is true, then the element 'matches' the query of the + * active query with index active_query_indices[i]. + * \param[in] user_data a user data pointer that can be set by the user + */ typedef void (*t8_search_batched_queries_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, const t8_element_array_t *leaf_elements, @@ -49,59 +94,155 @@ typedef void (*t8_search_batched_queries_callback_c_wrapper) (t8_forest_t forest const size_t *active_query_indices, int *query_matches, void *user_data); +/** A wrapper around the forest search context */ typedef struct t8_forest_c_search *t8_forest_search_c_wrapper; +/** Initialize the forest search context + * \param[in,out] search the search context to initialize + * \param[in] element_callback the callback function that checks the search criterion on an element + * \param[in] forest the forest on which the search is performed + */ void t8_forest_init_search (t8_forest_search_c_wrapper search, t8_search_element_callback_c_wrapper element_callback, const t8_forest_t forest); + +/** Update the forest on which the search is performed + * \param[in,out] search the search context to update + * \param[in] forest the new forest to use + */ void t8_forest_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest); + +/** Update the user data pointer in the search context + * \param[in,out] search the search context to update + * \param[in] udata the new user data pointer to use + */ void t8_forest_search_update_user_data (t8_forest_search_c_wrapper search, void *udata); + +/** Perform the search + * \param[in,out] search the search context to use + */ void t8_forest_search_do_search (t8_forest_search_c_wrapper search); + +/** Destroy the search context + * \param[in,out] search the search context to destroy + */ void t8_forest_search_destroy (t8_forest_search_c_wrapper search); +/** + * A wrapper around the forest search with queries context + */ typedef struct t8_forest_search_with_queries *t8_forest_search_with_queries_c_wrapper; +/** + * Initialize the forest search with queries context + * \param[in,out] search_with_queries the search with queries context to initialize + * \param[in] element_callback the callback function that checks the search criterion on an element + * \param[in] queries_callback the callback function that checks the queries on an element + * \param[in] queries a pointer to an array of queries + * \param[in] num_queries the number of queries in the array + * \param[in] forest the forest on which the search is performed + */ void t8_forest_init_search_with_queries (t8_forest_search_with_queries_c_wrapper search_with_queries, t8_search_element_callback_c_wrapper element_callback, t8_search_queries_callback_c_wrapper queries_callback, void **queries, const size_t num_queries, const t8_forest_t forest); + +/** Update the forest on which the search with queries is performed + * \param[in,out] search_with_queries the search with queries context to update + * \param[in] forest the new forest to use + */ void t8_forest_search_with_queries_update_forest (t8_forest_search_with_queries_c_wrapper search_with_queries, const t8_forest_t forest); + +/** Update the user data pointer in the search with queries context + * \param[in,out] search_with_queries the search with queries context to update + * \param[in] udata the new user data pointer to use + */ void t8_forest_search_with_queries_update_user_data (t8_forest_search_with_queries_c_wrapper search_with_queries, void *udata); + +/** Update the queries in the search with queries context + * \param[in,out] search_with_queries the search with queries context to update + * \param[in] queries a pointer to an array of queries + * \param[in] num_queries the number of queries in the array + */ void t8_forest_search_with_queries_update_queries (t8_forest_search_with_queries_c_wrapper search_with_queries, void **queries, const size_t num_queries); + +/** Destroy the search with queries context + * \param[in,out] search the search with queries context to destroy + */ void t8_forest_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper search); + +/** Perform the search with queries + * \param[in,out] search the search with queries context to use + */ void t8_forest_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper search); +/** + * A wrapper around the forest search with batched queries context + */ typedef struct t8_forest_search_with_batched_queries *t8_forest_search_with_batched_queries_c_wrapper; +/** + * Initialize the forest search with batched queries context + * \param[in,out] search_with_queries the search with batched queries context to initialize + * \param[in] element_callback the callback function that checks the search criterion on an element + * \param[in] queries_callback the callback function that checks the batched queries on an element + * \param[in] queries a pointer to an array of queries + * \param[in] num_queries the number of queries in the array + * \param[in] forest the forest on which the search is performed + */ void t8_forest_init_search_with_batched_queries (t8_forest_search_with_batched_queries_c_wrapper search_with_queries, t8_search_element_callback_c_wrapper element_callback, t8_search_batched_queries_callback_c_wrapper queries_callback, void **queries, const size_t num_queries, const t8_forest_t forest); + +/** Update the forest on which the search with batched queries is performed + * \param[in,out] search_with_queries the search with batched queries context to update + * \param[in] forest the new forest to use + */ void t8_forest_search_with_batched_queries_update_forest ( t8_forest_search_with_batched_queries_c_wrapper search_with_queries, const t8_forest_t forest); + +/** Update the user data pointer in the search with batched queries context + * \param[in,out] search_with_queries the search with batched queries context to update + * \param[in] udata the new user data pointer to use + */ void t8_forest_search_with_batched_queries_update_user_data ( t8_forest_search_with_batched_queries_c_wrapper search_with_queries, void *udata); + +/** Update the queries in the search with batched queries context + * \param[in,out] search_with_queries the search with batched queries context to update + * \param[in] queries a pointer to an array of queries + * \param[in] num_queries the number of queries in the array + */ void t8_forest_search_with_batched_queries_update_queries ( t8_forest_search_with_batched_queries_c_wrapper search_with_queries, void **queries, const size_t num_queries); + +/** Destroy the search with batched queries context + * \param[in,out] search the search with batched queries context to destroy + */ void t8_forest_search_with_batched_queries_destroy (t8_forest_search_with_batched_queries_c_wrapper search); + +/** Perform the search with batched queries + * \param[in,out] search the search with batched queries context to use + */ void t8_forest_search_with_batched_queries_do_search (t8_forest_search_with_batched_queries_c_wrapper search); diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 6bee0c5b4b..0a02d1d143 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -38,8 +38,8 @@ #include /** - * \typedef t8_search_element_callback - * \brief A callback function type used for searching elements in a forest. + * t8_search_element_callback + * A callback function type used for searching elements in a forest. * * This callback function is invoked during the search process in a forest. It allows * custom operations to be performed on each element encountered during the search. @@ -62,8 +62,7 @@ using t8_search_element_callback = std::function; /** - * \typedef t8_search_queries_callback - * \brief A callback function type used for search queries within a forest. + * A callback function type used for search queries within a forest. * * \tparam Query_T The type of the query. * \tparam Udata The type of user data, defaults to void. @@ -83,8 +82,8 @@ using t8_search_query_callback = std::function; /** - * \typedef t8_search_batched_queries_callback - * \brief A callback function type used for search queries within a forest. Processes a batch of queries. + * t8_search_batched_queries_callback + * A callback function type used for search queries within a forest. Processes a batch of queries. * * \tparam Query_T The type of the query. * \tparam Udata The type of user data, defaults to void. @@ -107,8 +106,8 @@ using t8_search_batched_queries_callback = std::function &active_query_indices, std::vector &query_matches, Udata *user_data)>; /** - * \typedef t8_partition_search_element_callback - * \brief A callback function type used for searching elements in the partition of a forest. + * t8_partition_search_element_callback + * A callback function type used for searching elements in the partition of a forest. * * This callback function is invoked during the partition search process in a forest. It allows * custom operations to be performed on each element encountered during the search. @@ -129,8 +128,8 @@ using t8_partition_search_element_callback const int pfirst, const int plast, Udata *user_data)>; /** - * \typedef t8_partition_search_query_callback - * \brief A callback function type used for searching queries in the partition of a forest. + * t8_partition_search_query_callback + * A callback function type used for searching queries in the partition of a forest. * * \tparam Query_T The type of the query. * \tparam Udata The type of user data, defaults to void. @@ -145,12 +144,12 @@ using t8_partition_search_element_callback */ template using t8_partition_search_query_callback - = std::function; /** - * \typedef t8_partition_search_batched_queries_callback - * \brief A callback function type used for searching queries in the partition of a forest. Processes a batch of queries. + * t8_partition_search_batched_queries_callback + * A callback function type used for searching queries in the partition of a forest. Processes a batch of queries. * * \tparam Query_T The type of the query. * \tparam Udata The type of user data, defaults to void. @@ -171,9 +170,12 @@ using t8_partition_search_batched_queries_callback = std::function &queries, const std::vector &active_query_indices, std::vector &query_matches, Udata *user_data)>; +/** + * A base class that performs a search in a forest. + */ class t8_search_base { public: - /** \brief Constructor for the t8_search_base class. + /** Constructor for the t8_search_base class. * * * This constructor initializes a t8_search_base object with the given forest. @@ -190,7 +192,7 @@ class t8_search_base { } } - /** \brief Update the forest for the search. + /** Update the forest for the search. * * This function updates the forest for the search. If the current forest is not null, * it decrements the reference count of the forest. It then asserts that the new forest @@ -210,7 +212,7 @@ class t8_search_base { this->forest = forest; } - /** \brief Destructor for the t8_search_base class. + /** Destructor for the t8_search_base class. * * This destructor decrements the reference count of the forest if it is not null. */ @@ -221,13 +223,16 @@ class t8_search_base { } } - /** \brief Perform the search. + /** Perform the search. * * This function performs the search in the forest. */ void do_search (); + /** + * The forest on which the search is performed. + */ t8_forest_t forest; private: @@ -241,7 +246,7 @@ class t8_search_base { void search_tree (const t8_locidx_t ltreeid); - /** \brief Recursively searches the tree. + /** Recursively searches the tree. * * This function performs a recursive search operation on the tree identified by the given local tree ID. * It uses the given \a element_callback function to process each element encountered during the search. @@ -257,14 +262,14 @@ class t8_search_base { search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_scheme *ts, t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf); - /** \brief Checks if the search should stop due to empty queries. + /** Checks if the search should stop due to empty queries. * */ virtual bool stop_due_to_queries () = 0; - /** \brief Checks an element during the search. + /** Checks an element during the search. * * This function is called for each element encountered during the search. * It passes the arguments to the callback function provided by the user. @@ -282,7 +287,7 @@ class t8_search_base { const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; - /** \brief Checks queries during the search. + /** Checks queries during the search. * * This function is called to check queries during the search. * It passes the arguments to the callback function provided by the user. @@ -300,7 +305,7 @@ class t8_search_base { = 0; /** - * \brief Function the gives the user the opportunity to update the queries after + * Function the gives the user the opportunity to update the queries after * each step in the recursion. * * \param old_query_indices @@ -308,11 +313,30 @@ class t8_search_base { virtual void update_queries (std::vector &old_query_indices) = 0; + + /** + * Function gives the user the opportunity to set the queries to the initial + * full set before searching each tree. + * + */ + virtual void + init_queries () + = 0; }; +/** + * A class that performs a search in a forest. + * \tparam Udata The type of user data to be used in the search. + */ template class t8_search: public t8_search_base { public: + /** + * Constructor for the t8_search class. + * \param[in] element_callback A callback function to be called for each element during the search. + * \param[in] forest A pointer to the forest to be searched. Defaults to nullptr + * \param[in] user_data A pointer to user-defined data to be passed to the callback function. Defaults to nullptr. + */ t8_search (t8_search_element_callback element_callback, t8_forest_t forest = nullptr, Udata *user_data = nullptr) : t8_search_base (forest), element_callback (element_callback) @@ -322,7 +346,7 @@ class t8_search: public t8_search_base { } } - /** \brief Updates the user data associated with the object. + /** Updates the user data associated with the object. * * This function sets the user data pointer to the provided Udata object. * @@ -336,17 +360,35 @@ class t8_search: public t8_search_base { } } + /** + * Destructor for the t8_search class. + */ virtual ~t8_search () = default; + /** + * The user data associated with the object. + */ Udata *user_data; private: + /** + * Checks if the search should stop due to empty queries. + */ bool stop_due_to_queries () override { return false; } + /** + * Checks an element during the search by invoking the user-defined callback function. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] is_leaf A bool indicating whether the current element is a leaf or not. + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current leaf element within the tree. + * \return True if the search should continue, false otherwise. + */ bool check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) override @@ -355,6 +397,15 @@ class t8_search: public t8_search_base { return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); } + /** + * A no-op implementation of the check_queries function. + * \param[in] new_active_queries A vector of indices of active queries. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] is_leaf A bool indicating whether the current element is a leaf or not. + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current leaf element within the tree. + */ void check_queries ([[maybe_unused]] std::vector &new_active_queries, [[maybe_unused]] const t8_locidx_t ltreeid, [[maybe_unused]] const t8_element_t *element, [[maybe_unused]] const bool is_leaf, @@ -364,17 +415,33 @@ class t8_search: public t8_search_base { return; } + /** + * A no-op implementation of the update_queries function. + * \param[in] old_query_indices A vector of indices of old queries. + */ void update_queries ([[maybe_unused]] std::vector &old_query_indices) override { return; } + /** + * A no-op implementation of the init_queries function. + */ + void + init_queries () override + { + return; + } + + /** + * The element callback function used during the search. + */ t8_search_element_callback element_callback; }; /** - * \brief A class that performs a search in a forest with queries. + * A class that performs a search in a forest with queries. * Uses a filter-view to filter out the active queries. It is recommended to use this version of the search * if the number of queries is small or if the queries do not need any further computations to be evaluated. * @@ -384,32 +451,57 @@ class t8_search: public t8_search_base { template class t8_search_with_queries: public t8_search { public: + /** + * Constructor for the t8_search_with_queries class. + * \param[in] element_callback A callback function to be called for each element during the search. + * \param[in] queries_callback A callback function to be called for each query during the search. + * \param[in] queries A reference to a vector of queries to be processed. + * \param[in] forest A pointer to the forest to be searched. Defaults to nullptr + * \param[in] user_data A pointer to user-defined data to be passed to the callback function. Defaults to nullptr. + */ t8_search_with_queries (t8_search_element_callback element_callback, t8_search_query_callback queries_callback, std::vector &queries, const t8_forest_t forest = nullptr, Udata *user_data = nullptr) : t8_search (element_callback, forest, user_data), queries_callback (queries_callback), queries (queries) { - this->active_queries.resize (queries.size ()); - std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } + /** + * Update the queries for the search. + * \param[in] queries A reference to a vector of queries to be processed. + */ void update_queries (std::vector &queries) { this->queries = queries; } + /** + * Destructor for the t8_search_with_queries class. + */ ~t8_search_with_queries () { } private: + /** + * Checks if the search should stop due to empty queries. + */ bool stop_due_to_queries () override { return this->active_queries.empty (); } + /** + * Checks the queries against the current element. + * \param[in] new_active_queries A reference to a vector of new active query indices. + * \param[in] ltreeid The ID of the local tree. + * \param[in] element A pointer to the current element being checked. + * \param[in] is_leaf A boolean indicating if the current element is a leaf. + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current element in the leaf array. + */ void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, @@ -417,30 +509,50 @@ class t8_search_with_queries: public t8_search { { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { - auto positive_queries = this->active_queries | std::ranges::views::filter ([&] (size_t &query_index) { - return this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, - tree_leaf_index, queries[query_index], this->user_data); - }); - if (!is_leaf) { - new_active_queries.assign (positive_queries.begin (), positive_queries.end ()); - std::swap (this->active_queries, new_active_queries); - } + std::copy_if (this->active_queries.begin (), this->active_queries.end (), std::back_inserter (new_active_queries), + [&] (size_t &query_index) { + return this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, + tree_leaf_index, queries[query_index], this->user_data); + }); } } + /** + * Updates the queries for the search. + * \param[in] old_query_indices A reference to a vector of queries to be processed. + */ void update_queries (std::vector &old_query_indices) override { - std::swap (this->active_queries, old_query_indices); + this->active_queries = old_query_indices; + } + + /** + * Initializes the queries for the search. + */ + void + init_queries () override + { + this->active_queries.resize (this->queries.size ()); + std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } + /** + * A reference to a vector of queries to be processed. + */ t8_search_query_callback queries_callback; + /** + * A reference to a vector of queries to be processed. + */ std::vector &queries; + /** + * A vector of indices of active queries. + */ std::vector active_queries; }; /** - * \brief A class that performs a search in a forest with batched queries. + * A class that performs a search in a forest with batched queries. * * All active queries are passed to the callback function, which processes them in a batch. It is recommended to * use this version of the searcch if further computations have to be done to evaluate the queries. That way these @@ -452,30 +564,56 @@ class t8_search_with_queries: public t8_search { template class t8_search_with_batched_queries: public t8_search { public: + /** + * Constructor for the t8_search_with_batched_queries class. + * \param[in] element_callback A callback function to be called for each element during the search. + * \param[in] queries_callback A callback function to be called for processing batched queries. + * \param[in] queries A reference to a vector of queries to be processed. + * \param[in] forest A pointer to the forest to be searched. Defaults to nullptr + * \param[in] user_data A pointer to user-defined data to be passed to the callback function. Defaults to nullptr. + */ t8_search_with_batched_queries (t8_search_element_callback element_callback, t8_search_batched_queries_callback queries_callback, std::vector &queries, const t8_forest_t forest = nullptr, Udata *user_data = nullptr) : t8_search (element_callback, forest, user_data), queries_callback (queries_callback), queries (queries) { - this->active_queries.resize (queries.size ()); - std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } + /** + * Update the queries for the search. + * \param[in] queries A reference to a vector of queries to be processed. + */ void update_queries (std::vector &queries) { this->queries = queries; } + /** + * Destructor for the t8_search_with_batched_queries class. + */ virtual ~t8_search_with_batched_queries () = default; private: + /** + * Checks if the search should stop due to empty queries. + */ bool stop_due_to_queries () override { return this->active_queries.empty (); } + + /** + * Checks the queries against the current element. + * \param[in] new_active_queries A reference to a vector of new active query indices. + * \param[in] ltreeid The ID of the local tree. + * \param[in] element A pointer to the current element being checked. + * \param[in] is_leaf A boolean indicating if the current element is a leaf. + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current element in the leaf array. + */ void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, @@ -483,33 +621,54 @@ class t8_search_with_batched_queries: public t8_search { { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { - std::vector query_matches (this->active_queries.size ()); + std::vector query_matches (this->queries.size ()); this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, this->active_queries, query_matches, this->user_data); - if (!is_leaf) { - auto positive_queries = this->active_queries | std::ranges::views::filter ([&] (size_t &query_index) { - return query_matches[query_index]; - }); - new_active_queries.assign (positive_queries.begin (), positive_queries.end ()); - } + std::copy_if (this->active_queries.begin (), this->active_queries.end (), std::back_inserter (new_active_queries), + [&] (size_t &query_index) { return query_matches[query_index]; }); } - std::swap (new_active_queries, this->active_queries); } + /** + * Updates the queries for the search. + * \param[in] old_query_indices A reference to a vector of queries to be processed. + */ void update_queries (std::vector &old_query_indices) override { - std::swap (this->active_queries, old_query_indices); + this->active_queries = old_query_indices; + } + + /** + * Initializes the queries for the search. + */ + void + init_queries () override + { + this->active_queries.resize (this->queries.size ()); + std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } + /** + * The callback function for processing batched queries. + */ t8_search_batched_queries_callback queries_callback; + /** + * A reference to a vector of queries to be processed. + */ std::vector &queries; + /** + * A vector of indices of active queries. + */ std::vector active_queries; }; +/** + * A class that performs a search in the partition of a forest. + */ class t8_partition_search_base { public: - /** \brief Constructor for the t8_partition_search_base class. + /** Constructor for the t8_partition_search_base class. * * * This constructor initializes a t8_partition_search_base object with the @@ -526,7 +685,7 @@ class t8_partition_search_base { } } - /** \brief Update the forest for the search. + /** Update the forest for the search. * * This function updates the forest for the search. If the current forest is not null, * it decrements the reference count of the forest. It then asserts that the new forest @@ -546,7 +705,7 @@ class t8_partition_search_base { this->forest = forest; } - /** \brief Destructor for the t8_partition_search_base class. + /** Destructor for the t8_partition_search_base class. * * This destructor decrements the reference count of the forest if it is not null. */ @@ -557,33 +716,35 @@ class t8_partition_search_base { } } - /** \brief Perform the search. + /** Perform the search. * * This function performs the search in the forest. */ void do_search (); + /** + * A pointer to the forest whose partition is searched. + */ t8_forest_t forest; private: - /** \brief Checks if the search should stop due to empty queries. + /** Checks if the search should stop due to empty queries. * */ virtual bool stop_due_to_queries () = 0; - /** \brief Checks an element during the search. + /** Checks an element during the search. * * This function is called for each element encountered during the search. * It passes the arguments to the callback function provided by the user. * * \param[in] ltreeid The local tree ID of the current element. * \param[in] element A pointer to the current element being processed. - * \param[in] is_leaf A bool indicating whether the current element is a leaf (non-zero) or not (zero). - * \param[in] leaf_elements A pointer to an array of leaf elements. - * \param[in] tree_leaf_index The index of the current leaf element within the tree. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. * * \return True if the search should continue, false otherwise. */ @@ -591,7 +752,7 @@ class t8_partition_search_base { check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast) = 0; - /** \brief Checks queries during the search. + /** Checks queries during the search. * * This function is called to check queries during the search. * It passes the arguments to the callback function provided by the user. @@ -599,9 +760,8 @@ class t8_partition_search_base { * \param[in] new_active_queries A vector of indices of active queries. * \param[in] ltreeid The local tree ID of the current element. * \param[in] element A pointer to the current element being processed. - * \param[in] is_leaf A bool indicating whether the current element is a leaf (non-zero) or not (zero). - * \param[in] leaf_elements A pointer to an array of leaf elements. - * \param[in] tree_leaf_index The index of the current leaf element within the tree. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. */ virtual void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, @@ -609,19 +769,39 @@ class t8_partition_search_base { = 0; /** - * \brief Function the gives the user the opportunity to update the queries after - * each step in the recursion. + * Function the gives the user the opportunity to update the queries after each step in the recursion. * * \param old_query_indices */ virtual void update_queries (std::vector &old_query_indices) = 0; + + /** + * Function gives the user the opportunity to set the queries to the initial full set before searching each tree. + */ + virtual void + init_queries () + = 0; }; +/** + * A class that performs a search in the partition of a forest and supports the usage of user data. + * \tparam Udata + */ template class t8_partition_search: public t8_partition_search_base { public: + /** + * Constructor for the t8_partition_search class. + * This constructor initializes a t8_partition_search object with the given element callback, + * forest, and user data. If the forest is not null, it increments the reference count + * of the forest and asserts that the forest is committed. + * + * \param[in] element_callback A callback function of type t8_partition_search_element_callback. + * \param[in] forest A pointer to a t8_forest_t object. Defaults to nullptr. + * \param[in] user_data A pointer to a Udata object. Defaults to nullptr. + */ t8_partition_search (t8_partition_search_element_callback element_callback, t8_forest_t forest = nullptr, Udata *user_data = nullptr) : t8_partition_search_base (forest), element_callback (element_callback) @@ -631,7 +811,7 @@ class t8_partition_search: public t8_partition_search_base { } } - /** \brief Updates the user data associated with the object. + /** Updates the user data associated with the object. * * This function sets the user data pointer to the provided Udata object. * @@ -645,15 +825,29 @@ class t8_partition_search: public t8_partition_search_base { } } + /** + * A pointer to the user data associated with the object. + */ Udata *user_data; private: + /** + * In the partition search without queries, the search never stops due to empty queries. + */ bool stop_due_to_queries () override { return false; } + /** + * In the partition search without queries, the element check simply forwards the call to the user callback. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. + * \return True if the search should continue, false otherwise. + */ bool check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast) override { @@ -661,6 +855,14 @@ class t8_partition_search: public t8_partition_search_base { return this->element_callback (this->forest, ltreeid, element, pfirst, plast, user_data); } + /** + * In the partition search without queries, no queries are checked. + * \param[in] new_active_queries A vector of indices of active queries. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. + */ void check_queries ([[maybe_unused]] std::vector &new_active_queries, [[maybe_unused]] const t8_locidx_t ltreeid, [[maybe_unused]] const t8_element_t *element, [[maybe_unused]] const int pfirst, @@ -669,17 +871,33 @@ class t8_partition_search: public t8_partition_search_base { return; } + /** + * In the partition search without queries, no queries are updated. + * \param[in] old_query_indices A vector of indices of old queries. + */ void update_queries ([[maybe_unused]] std::vector &old_query_indices) { return; } + /** + * In the partition search without queries, no queries are initialized. + */ + void + init_queries () override + { + return; + } + + /** + * The element callback function. + */ t8_partition_search_element_callback element_callback; }; /** - * \brief A class that performs a search in the partition of a forest with queries. + * A class that performs a search in the partition of a forest with queries. * Uses a filter-view to filter out the active queries. It is recommended to use this version of the search * if the number of queries is small or if the queries do not need any further computations to be evaluated. * @@ -689,6 +907,18 @@ class t8_partition_search: public t8_partition_search_base { template class t8_partition_search_with_queries: public t8_partition_search { public: + /** + * Constructor for the t8_partition_search_with_queries class. + * This constructor initializes a t8_partition_search_with_queries object with the given + * element callback, queries callback, forest, and user data. If the forest is not null, it increments + * the reference count of the forest and asserts that the forest is committed. + * + * \param[in] element_callback A callback function of type t8_partition_search_element_callback. + * \param[in] queries_callback A callback function of type t8_partition_search_query_callback. + * \param[in] queries A reference to a vector of Query_T objects. + * \param[in] forest A pointer to a t8_forest_t object. Defaults to nullptr. + * \param[in] user_data A pointer to a Udata object. Defaults to nullptr. + */ t8_partition_search_with_queries (t8_partition_search_element_callback element_callback, t8_partition_search_query_callback queries_callback, std::vector &queries, const t8_forest_t forest = nullptr, @@ -696,57 +926,96 @@ class t8_partition_search_with_queries: public t8_partition_search { : t8_partition_search (element_callback, forest, user_data), queries_callback (queries_callback), queries (queries) { - this->active_queries.resize (queries.size ()); - std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } - + /** + * Updates the queries associated with the object. + * + * \param[in] queries A reference to a vector of Query_T objects. + */ void update_queries (std::vector &queries) { this->queries = queries; } + /** + * Destructor for the t8_partition_search_with_queries class. + */ ~t8_partition_search_with_queries () { } private: + /** + * Stops the search if there are no active queries. + * + * \return True if the search should stop, false otherwise. + */ bool stop_due_to_queries () override { return this->active_queries.empty (); } + /** + * Checks queries during the search by invoking the user-provided callback function. + * + * \param[in] new_active_queries A vector of indices of active queries. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. + */ void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast) override { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { - auto positive_queries = this->active_queries | std::ranges::views::filter ([&] (size_t &query_index) { - return this->queries_callback (this->forest, ltreeid, element, pfirst, plast, - queries[query_index], this->user_data); - }); - if (pfirst != plast) { - new_active_queries.assign (positive_queries.begin (), positive_queries.end ()); - std::swap (this->active_queries, new_active_queries); - } + std::copy_if (this->active_queries.begin (), this->active_queries.end (), std::back_inserter (new_active_queries), + [&] (size_t &query_index) { + return this->queries_callback (this->forest, ltreeid, element, pfirst, plast, + queries[query_index], this->user_data); + }); } } + /** + * Updates the queries associated with the object. + * + * \param[in] old_query_indices A vector of indices of old queries. + */ void update_queries (std::vector &old_query_indices) { - std::swap (this->active_queries, old_query_indices); + this->active_queries = old_query_indices; } + /** + * Initializes the queries associated with the object. + */ + void + init_queries () override + { + this->active_queries.resize (this->queries.size ()); + std::iota (this->active_queries.begin (), this->active_queries.end (), 0); + } + /** + * Callback function for processing queries. + */ t8_partition_search_query_callback queries_callback; + /** + * A reference to a vector of queries. + */ std::vector &queries; + /** + * A vector of indices of active queries. + */ std::vector active_queries; }; /** - * \brief A class that performs a search in the partition of a forest with batched queries. + * A class that performs a search in the partition of a forest with batched queries. * * All active queries are passed to the callback function, which processes them in a batch. It is recommended to * use this version of the searcch if further computations have to be done to evaluate the queries. That way these @@ -758,6 +1027,18 @@ class t8_partition_search_with_queries: public t8_partition_search { template class t8_partition_search_with_batched_queries: public t8_partition_search { public: + /** + * Constructor for the t8_partition_search_with_batched_queries class. + * This constructor initializes a t8_partition_search_with_batched_queries object with the given + * element callback, queries callback, forest, and user data. If the forest is not null, it increments + * the reference count of the forest and asserts that the forest is committed. + * + * \param[in] element_callback A callback function of type t8_partition_search_element_callback. + * \param[in] queries_callback A callback function of type t8_partition_search_batched_queries_callback. + * \param[in] queries A reference to a vector of Query_T objects. + * \param[in] forest A pointer to a t8_forest_t object. Defaults to nullptr. + * \param[in] user_data A pointer to a Udata object. Defaults to nullptr. + */ t8_partition_search_with_batched_queries ( t8_partition_search_element_callback element_callback, t8_partition_search_batched_queries_callback queries_callback, std::vector &queries, @@ -765,53 +1046,89 @@ class t8_partition_search_with_batched_queries: public t8_partition_search (element_callback, forest, user_data), queries_callback (queries_callback), queries (queries) { - this->active_queries.resize (queries.size ()); - std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } - + /** + * Updates the queries associated with the object. + */ void update_queries (std::vector &queries) { this->queries = queries; } + /** + * Destructor for the t8_partition_search_with_batched_queries class. + */ ~t8_partition_search_with_batched_queries () { } private: + /** + * In the partition search with batched queries, the search stops if there are no active queries left. + * \return True if the search should stop, false otherwise. + */ bool stop_due_to_queries () override { return this->active_queries.empty (); } + + /** + * Checks queries during the search by invoking the user-provided callback function. + * \param[in] new_active_queries A vector of indices of active queries. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] pfirst The first processor that owns part of \a element. + * \param[in] plast The last processor that owns part of \a element. + */ void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast) override { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { - std::vector query_matches (this->active_queries.size ()); + std::vector query_matches (this->queries.size ()); this->queries_callback (this->forest, ltreeid, element, pfirst, plast, this->queries, this->active_queries, query_matches, this->user_data); - if (pfirst != plast) { - auto positive_queries = this->active_queries | std::ranges::views::filter ([&] (size_t &query_index) { - return query_matches[query_index]; - }); - new_active_queries.assign (positive_queries.begin (), positive_queries.end ()); - } + std::copy_if (this->active_queries.begin (), this->active_queries.end (), std::back_inserter (new_active_queries), + [&] (size_t &query_index) { return query_matches[query_index]; }); } std::swap (new_active_queries, this->active_queries); } + /** + * Updates the queries associated with the object. + * \param[in] old_query_indices A vector of indices of old queries. + */ void update_queries (std::vector &old_query_indices) { - std::swap (this->active_queries, old_query_indices); + this->active_queries = old_query_indices; + } + /** + * Initializes the queries associated with the object. + */ + void + init_queries () override + { + this->active_queries.resize (this->queries.size ()); + std::iota (this->active_queries.begin (), this->active_queries.end (), 0); } + /** + * Callback function for processing batched queries. + */ t8_partition_search_batched_queries_callback queries_callback; + + /** + * A reference to a vector of queries. + */ std::vector &queries; + + /** + * A vector of indices of active queries. + */ std::vector active_queries; }; diff --git a/src/t8_geometry/t8_geometry.h b/src/t8_geometry/t8_geometry.h index 4c19c6b080..314c93bddf 100644 --- a/src/t8_geometry/t8_geometry.h +++ b/src/t8_geometry/t8_geometry.h @@ -98,17 +98,17 @@ t8_geometry_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_c /** This function returns the geometry type of a tree. * \param[in] cmesh The cmesh * \param[in] gtreeid The global id of the tree - * \return The geometry type of the tree with id \ref gtreeid + * \return The geometry type of the tree with id \a gtreeid */ t8_geometry_type_t t8_geometry_get_type (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); /** * Check if a tree has a negative volume - * + * * \param[in] cmesh The cmesh to check * \param[in] gtreeid The global id of the tree - * \return True if the tree with id \ref gtreeid has a negative volume. False otherwise. + * \return True if the tree with id \a gtreeid has a negative volume. False otherwise. */ int t8_geometry_tree_negative_volume (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid); diff --git a/src/t8_geometry/t8_geometry_base.cxx b/src/t8_geometry/t8_geometry_base.cxx index bb68077fd9..307d06e437 100644 --- a/src/t8_geometry/t8_geometry_base.cxx +++ b/src/t8_geometry/t8_geometry_base.cxx @@ -27,10 +27,6 @@ #include #include -/** Get the name of a geometry. - * \param [in] geom A geometry. - * \return The name of \a geom. - */ const char * t8_geom_get_name (const t8_geometry_c *geom) { @@ -39,10 +35,6 @@ t8_geom_get_name (const t8_geometry_c *geom) return geom->t8_geom_get_name ().c_str (); } -/** Get the type of the geometry. - * \param [in] geom A geometry. - * \return The type of \a geom. - */ t8_geometry_type_t t8_geom_get_type (const t8_geometry_c *geom) { diff --git a/src/t8_geometry/t8_geometry_base.h b/src/t8_geometry/t8_geometry_base.h index 5c8f82f181..74b9c47649 100644 --- a/src/t8_geometry/t8_geometry_base.h +++ b/src/t8_geometry/t8_geometry_base.h @@ -43,8 +43,7 @@ const char * t8_geom_get_name (const t8_geometry_c *geom); /** Get the type of a geometry. - * - * \param [in] geom A geometry. + * \param [in] geom A geometry. * \return The type of \a geom. */ t8_geometry_type_t diff --git a/src/t8_geometry/t8_geometry_base.hxx b/src/t8_geometry/t8_geometry_base.hxx index a4ab71cf2f..062ad1e49e 100644 --- a/src/t8_geometry/t8_geometry_base.hxx +++ b/src/t8_geometry/t8_geometry_base.hxx @@ -47,7 +47,9 @@ T8_EXTERN_C_BEGIN (); struct t8_geometry { public: - /* Basic constructor that sets the name. */ + /** Basic constructor that sets the name. + * \param [in] name The name of the geometry. Used to distinct the geometry from other geometries. + */ t8_geometry (std::string name): name (name), hash (t8_geometry_compute_hash (name)) { if (t8_geometry_hash_is_null (hash)) { @@ -87,7 +89,7 @@ struct t8_geometry /** * Compute the jacobian of the \a t8_geom_evaluate map at a point in the reference space \f$ [0,1]^\mathrm{dim} \f$. * \param [in] cmesh The cmesh in which the point lies. - * \param [in] glreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. * \param [in] ref_coords Array of tree dimension x \a num_coords many entries, specifying points in \f$ [0,1]^\mathrm{dim} \f$. * \param [in] num_coords Amount of points of \f$ \mathrm{dim} \f$ to map. * \param [out] jacobian The jacobian at \a ref_coords. Array of size \a num_coords x dimension x 3. Indices \f$ 3 \cdot i\f$ , \f$ 3 \cdot i+1 \f$ , \f$ 3 \cdot i+2 \f$ @@ -109,21 +111,21 @@ struct t8_geometry virtual void 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. - * \param [in] ltree_id The forest local id of the tree in which the element is. - * \param [in] element The element. - * \param [in] points 3-dimensional coordinates of the points to check - * \param [in] num_points The number of points to check - * \param [in, out] is_inside An array of length \a num_points, filled with 0/1 on output. True (non-zero) if a \a point - * lies within an \a element, false otherwise. The return value is also true if the point - * lies on the element boundary. Thus, this function may return true for different leaf - * elements, if they are neighbors and the point lies on the common boundary. - * \param [in] tolerance Tolerance that we allow the point to not exactly match the element. - * If this value is larger we detect more points. - * If it is zero we probably do not detect points even if they are inside - * due to rounding errors. - */ + /** Query whether a batch of points lies inside an element. + * \param [in] forest The forest. + * \param [in] ltreeid The forest local id of the tree in which the element is. + * \param [in] element The element. + * \param [in] points 3-dimensional coordinates of the points to check + * \param [in] num_points The number of points to check + * \param [in, out] is_inside An array of length \a num_points, filled with 0/1 on output. True (non-zero) if a \a point + * lies within an \a element, false otherwise. The return value is also true if the point + * lies on the element boundary. Thus, this function may return true for different leaf + * elements, if they are neighbors and the point lies on the common boundary. + * \param [in] tolerance Tolerance that we allow the point to not exactly match the element. + * If this value is larger we detect more points. + * If it is zero we probably do not detect points even if they are inside + * due to rounding errors. + */ virtual void t8_geom_point_batch_inside_element ([[maybe_unused]] t8_forest_t forest, [[maybe_unused]] t8_locidx_t ltreeid, [[maybe_unused]] const t8_element_t *element, @@ -168,11 +170,11 @@ struct t8_geometry /** * Compute the bounding box of the currently active tree. - * + * * \param [in] cmesh The cmesh. * \param [out] bounds The bounding box of the tree in the form (xmin, xmax, ymin, ymax, zmin, zmax). * \return True if the bounding box was computed successfully, false otherwise. - * + * * \note This function updates the active tree to the provided \a gtreeid. */ virtual bool @@ -182,6 +184,10 @@ struct t8_geometry return false; } + /** + * Get the hash value of this geometry. + * \return The hash. + */ inline t8_geometry_hash t8_geom_get_hash () const { diff --git a/src/t8_geometry/t8_geometry_extended.hxx b/src/t8_geometry/t8_geometry_extended.hxx index 7e9ba4600c..7fe7799021 100644 --- a/src/t8_geometry/t8_geometry_extended.hxx +++ b/src/t8_geometry/t8_geometry_extended.hxx @@ -32,31 +32,49 @@ T8_EXTERN_C_BEGIN (); -/* This class extends the functionality of a geometry. +/** + * This class extends the functionality of a geometry. * While t8_geometry only provides the mapping and jacobian * from reference space to physical space, the extended geometry * also provides functions to compute the volume of an element, - * face normals, etc... */ + * face normals, etc... + */ struct t8_geometry_extended: t8_geometry { public: - /* TODO: Properly define these functions. */ + /** + * Compute the volume of the element. + * \return The volume. + */ virtual double t8_geom_element_volume () = 0; + /** + * Compute the centroid of the element. + */ virtual void t8_geom_element_centroid () = 0; - virtual void + /** + * Compute the area of the face. + * \return The area. + */ + virtual double t8_geom_face_area () = 0; + /** + * Compute the centroid of the face. + */ virtual void t8_geom_face_centroid () = 0; + /** + * Compute the normal vector of the face. + */ virtual void t8_geom_face_normal () = 0; diff --git a/src/t8_geometry/t8_geometry_handler.hxx b/src/t8_geometry/t8_geometry_handler.hxx index 5b6673d7eb..b5af9c63fe 100644 --- a/src/t8_geometry/t8_geometry_handler.hxx +++ b/src/t8_geometry/t8_geometry_handler.hxx @@ -34,6 +34,12 @@ #include #include +/** + * Handles the geometries of a \ref t8_cmesh. + * Each tree can be assigned a geometry in this handler. The geometries + * get assigned using their hash value. + * Stores geometries of type \ref t8_geometry. + */ struct t8_geometry_handler { public: @@ -235,7 +241,7 @@ struct t8_geometry_handler * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree id of the tree for which the bounding box should be returned. * \param [out] bounds The bounding box of the tree, in the format [xmin, xmax, ymin, ymax, zmin, zmax]. - * + * * \note This function updates the active tree to the provided \a gtreeid. */ inline bool diff --git a/src/t8_geometry/t8_geometry_helpers.h b/src/t8_geometry/t8_geometry_helpers.h index 554cec4553..caf57a020a 100644 --- a/src/t8_geometry/t8_geometry_helpers.h +++ b/src/t8_geometry/t8_geometry_helpers.h @@ -74,9 +74,9 @@ t8_geom_linear_interpolation (const double *coefficients, const double *corner_v * or the reference tet (interpolation_dim = 3) with points * (0,0,0) (1,0,0) (1,1,0) (1,1,1). * \param [in] coefficients An array of size \a interpolation_dim giving the coefficients in the reference triangle/tet used for the interpolation - * \param [in] corner_values An array of size + * \param [in] corner_values An array of size 3 * \a corner_value_dim for \a interpolation_dim == 2 or - 4 * \a corner_value_dim for \a interpolation_dim == 3, + 4 * \a corner_value_dim for \a interpolation_dim == 3, giving the function values of the triangle/tetrahedron for each corner (in zorder) * \param [in] corner_value_dim The dimension of the \a corner_values. * \param [in] interpolation_dim The dimension of the interpolation (2 for triangle, 3 for tetrahedron) @@ -168,7 +168,7 @@ double t8_geom_get_scaling_factor_of_edge_on_face_prism (int edge_index, int face_index, const double *ref_coords); /** Calculates the scaling factor for the displacement of an face through the volume of a prism element. - * \param [in] face_index Index of the displaced face. + * \param [in] face Index of the displaced face. * \param [in] ref_coords Array containing the coordinates of the reference point. * \return The scaling factor of the face displacement * at the point of the reference coordinates inside the prism volume. @@ -177,11 +177,11 @@ double t8_geom_get_scaling_factor_face_through_volume_prism (const int face, const double *ref_coords); /** Check if a point lies inside a vertex - * + * * \param[in] vertex_coords The coordinates of the vertex * \param[in] point The coordinates of the point to check * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. + * \return 0 if the point is outside, 1 otherwise. */ int t8_vertex_point_inside (const double vertex_coords[3], const double point[3], const double tolerance); @@ -189,36 +189,36 @@ t8_vertex_point_inside (const double vertex_coords[3], const double point[3], co /** * Check if a point is inside a line that is defined by a starting point \a p_0 * and a vector \a vec - * + * * \param[in] p_0 Starting point of the line * \param[in] vec Direction of the line (not normalized) * \param[in] point The coordinates of the point to check * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. + * \return 0 if the point is outside, 1 otherwise. */ int t8_line_point_inside (const double *p_0, const double *vec, const double *point, const double tolerance); /** - * Check if a point is inside of a triangle described by a point \a p_0 and two vectors \a v and \a w. - * + * Check if a point is inside of a triangle described by a point \a p_0 and two vectors \a v and \a w. + * * \param[in] p_0 The first vertex of a triangle * \param[in] v The vector from p_0 to p_1 (second vertex in the triangle) * \param[in] w The vector from p_0 to p_2 (third vertex in the triangle) * \param[in] point The coordinates of the point to check * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. + * \return 0 if the point is outside, 1 otherwise. */ int t8_triangle_point_inside (const double p_0[3], const double v[3], const double w[3], const double point[3], const double tolerance); -/** Check if a point lays on the inner side of a plane of a bilinearly interpolated volume element. - * the plane is described by a point and the normal of the face. +/** Check if a point lays on the inner side of a plane of a bilinearly interpolated volume element. + * the plane is described by a point and the normal of the face. * \param[in] point_on_face A point on the plane * \param[in] face_normal The normal of the face * \param[in] point The point to check - * \return 0 if the point is outside, 1 otherwise. + * \return 0 if the point is outside, 1 otherwise. */ int t8_plane_point_inside (const double point_on_face[3], const double face_normal[3], const double point[3]); 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 b7255e15c6..a0d42afbc1 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h @@ -37,7 +37,7 @@ * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. * \param [in] ref_coords Array of dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. - * \param [in] num_coords + * \param [in] num_coords The number of coordinates in \a ref_coords. * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. * \param [in] tree_data The data of the current tree as loaded by a \ref t8_geom_load_tree_data_fn. * \param [in] user_data The user data pointer stored in the geometry. @@ -91,13 +91,13 @@ t8_geometry_analytic_destroy (t8_geometry_c **geom); * Create a new analytic geometry. 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] 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. + * \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 The function that is used to compute if a trees volume is negative. + * \param [in] tree_compatible 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. * \return A pointer to an allocated geometry struct. */ t8_geometry_c * @@ -107,7 +107,7 @@ t8_geometry_analytic_new (const char *name, t8_geom_analytic_fn analytical, t8_g t8_geom_tree_compatible_fn tree_compatible, const void *user_data); /** - * Load vertex data from given tree. + * Load vertex data from given tree. * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree id (in the cmesh). * \param [out] user_data The load tree vertices. 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 c5fd960bb9..02a1220651 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx @@ -34,6 +34,11 @@ #include #include +/** + * Geometry which maps the trees interior to a user-specified analytical function. + * No class has to be implemented and every member function can be filled with + * a function pointer. + */ struct t8_geometry_analytic: public t8_geometry { public: @@ -41,12 +46,13 @@ struct t8_geometry_analytic: public t8_geometry * Constructor of the analytic geometry. 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] 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] 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 User data saved by the geometry. Can be accessed via \ref t8_geom_analytic_get_user_data. */ t8_geometry_analytic (std::string name, t8_geom_analytic_fn analytical, t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, @@ -59,7 +65,7 @@ struct t8_geometry_analytic: public t8_geometry */ t8_geometry_analytic (std::string name); - /** The destructor. + /** The destructor. */ virtual ~t8_geometry_analytic () { @@ -126,7 +132,7 @@ 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. + * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. */ bool t8_geom_tree_negative_volume () const override; @@ -143,7 +149,7 @@ struct t8_geometry_analytic: public 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 + * 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). * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. @@ -151,6 +157,10 @@ struct t8_geometry_analytic: public t8_geometry void t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) override; + /** + * Returns the user data stored in this geometry. + * \return The user data. + */ inline const void * t8_geom_analytic_get_user_data () { @@ -168,7 +178,7 @@ struct t8_geometry_analytic: public t8_geometry 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 + 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. */ const void *user_data; /** Additional user data pointer that can be set in constructor diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx index 85d96e11ec..f7225ca0d7 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.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 classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2025 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 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,8 +38,8 @@ #include #include #include -#include -#include +#include +#include /* The lookup table contains the coordinate of each edge of a tetrahedron, * which is used for the interpolation. @@ -50,43 +51,17 @@ const int t8_face_ref_coords_tet[4][2] = { { 2, 1 }, { 0, 1 }, { 0, 1 }, { 0, 2 t8_geometry_cad::t8_geometry_cad (std::string fileprefix, std::string name_in): t8_geometry_with_vertices (name_in) { - BRep_Builder builder; - std::string current_file (fileprefix); - std::ifstream is (current_file + ".brep"); - if (is.is_open () == false) { - SC_ABORTF ("Cannot find the file %s.brep.\n", fileprefix.c_str ()); - } - BRepTools::Read (cad_shape, is, builder); - is.close (); - if (cad_shape.IsNull ()) { - SC_ABORTF ("Could not read brep file or brep file contains no shape. " - "The cad file may be written with a newer cad version. " - "Linked cad version: %s", - OCC_VERSION_COMPLETE); - } - TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); - TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); - TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); - TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); - TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); + cad_manager = std::make_shared (fileprefix); } t8_geometry_cad::t8_geometry_cad (const TopoDS_Shape cad_shape, std::string name_in) : t8_geometry_with_vertices (name_in) { - if (cad_shape.IsNull ()) { - SC_ABORTF ("Shape is null. \n"); - } - TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); - TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); - TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); - TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); - TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); + cad_manager = std::make_shared (cad_shape); } t8_geometry_cad::t8_geometry_cad (): t8_geometry_with_vertices ("t8_geom_cad") { - cad_shape.Nullify (); } void @@ -166,9 +141,6 @@ t8_geometry_cad::t8_geom_evaluate_cad_tri (t8_cmesh_t cmesh, t8_gloidx_t gtreeid const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); const int num_edges = t8_eclass_num_edges[active_tree_class]; - Handle_Geom_Curve curve; - Handle_Geom_Surface surface; - Standard_Real first, last; gp_Pnt pnt; double displacement; double scaling_factor; @@ -196,7 +168,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_tri (t8_cmesh_t cmesh, t8_gloidx_t gtreeid * / | | / | y * / | | / / | * 0----E2----1 | 0---------E2--------1 x--x - * + * */ /* Linear mapping from ref_coords to out_coords for each reference point */ @@ -250,9 +222,9 @@ t8_geometry_cad::t8_geom_evaluate_cad_tri (t8_cmesh_t cmesh, t8_gloidx_t gtreeid t8_geom_linear_interpolation (&ref_intersection[(i_edge == 0) + offset_2d], edge_parameters, 1, 1, &interpolated_curve_parameter); /* Convert the interpolated edge parameter of each reference point to surface parameters */ - t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, - interpolated_curve_parameter, face_parameters, - converted_edge_surface_parameters + offset_2d); + cad_manager->t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, + interpolated_curve_parameter, face_parameters, + converted_edge_surface_parameters + offset_2d); } double edge_surface_parameters[4]; @@ -280,28 +252,15 @@ t8_geometry_cad::t8_geom_evaluate_cad_tri (t8_cmesh_t cmesh, t8_gloidx_t gtreeid scaled_displacement = displacement * scaling_factor; interpolated_surface_parameters[dim + offset_2d] += scaled_displacement; } - /* Retrieve surface */ - T8_ASSERT (*faces <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (*faces))); - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - /* Evaluate surface and save result */ - surface->D0 (interpolated_surface_parameters[offset_2d], interpolated_surface_parameters[offset_2d + 1], pnt); + pnt = process_surface (i_edge + num_edges, interpolated_surface_parameters, offset_2d); for (int dim = 0; dim < 3; ++dim) { out_coords[dim + offset_3d] = pnt.Coord (dim + 1); } } } - /* Retrieve surface */ - T8_ASSERT (*faces <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (*faces))); - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - - /* Evaluate surface and save result */ - surface->D0 (interpolated_surface_parameters[0], interpolated_surface_parameters[1], pnt); + pnt = process_surface (*faces, interpolated_surface_parameters, 0); for (int dim = 0; dim < 3; ++dim) { out_coords[dim] = pnt.Coord (dim + 1); @@ -336,27 +295,14 @@ t8_geometry_cad::t8_geom_evaluate_cad_tri (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Interpolate between the curve parameters of the current edge with the ref_intersection of each reference point */ t8_geom_linear_interpolation (&ref_intersection[(i_edge == 0) + offset_2d], parameters, 1, 1, &interpolated_curve_parameter); - /* Retrieve curve */ - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); - /* Check if curve is valid */ - T8_ASSERT (!curve.IsNull ()); - - /* Calculate point on curve with interpolated parameters. */ - curve->D0 (interpolated_curve_parameter, pnt); + pnt = process_curve (i_edge, interpolated_curve_parameter); } else { /* Interpolate between the surface parameters of the current edge with the ref_intersection of each reference point */ t8_geom_linear_interpolation (&ref_intersection[(i_edge == 0) + offset_2d], parameters, 2, 1, interpolated_surface_parameters + offset_2d); - T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_parameters[offset_2d], interpolated_surface_parameters[offset_2d + 1], - pnt); + + pnt = process_surface (i_edge + num_edges, interpolated_surface_parameters, offset_2d); } /* Determine the scaling factor by calculating the distances from the opposite vertex * to the glob_intersection and to the reference point */ @@ -390,9 +336,6 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); const int num_edges = t8_eclass_num_edges[active_tree_class]; gp_Pnt pnt; - Handle_Geom_Curve curve; - Handle_Geom_Surface surface; - Standard_Real first, last; /* Check if face has a linked geometry */ if (*faces > 0) { @@ -430,7 +373,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei * | | y * | | | * 0 -------E2------- 1 x-- x - * + * */ const int edge_orthogonal_direction = (i_edge >> 1); const int edge_direction = 1 - edge_orthogonal_direction; @@ -441,22 +384,19 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei const double *edge_parameters = (double *) t8_cmesh_get_attribute ( cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (edge_parameters != NULL); - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); - - /* Check if curve is valid */ - T8_ASSERT (!curve.IsNull ()); for (size_t coord = 0; coord < num_coords; ++coord) { const int offset_3d = coord * 3; const int offset_2d = coord * 2; + /* Interpolate between curve parameters and surface parameters of the same nodes */ t8_geom_linear_interpolation (&ref_coords[edge_direction + offset_2d], edge_parameters, 1, 1, temp_edge_parameters); + pnt = process_curve (i_edge, temp_edge_parameters[0]); + /* Convert curve parameter to surface parameters */ - t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters ( + cad_manager->t8_geom_edge_parameter_to_face_parameters ( edges[i_edge], *faces, num_face_nodes, temp_edge_parameters[0], face_parameters, temp_edge_parameters); /* Interpolate between the surface parameters of the current edge */ @@ -480,8 +420,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei } /* Retrieve surface */ - T8_ASSERT (*faces <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (*faces))); + auto surface = cad_manager->t8_geom_get_cad_surface (*faces); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -519,7 +458,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei * | | y * | | | * 0 -------E2------- 1 x-- x - * + * */ const int edge_orthogonal_direction = (i_edge >> 1); const int edge_direction = 1 - edge_orthogonal_direction; @@ -537,12 +476,13 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei /* Curves have only one parameter u, surfaces have two, u and v. * Therefore, we have to distinguish if the edge has a curve or surface linked to it. */ if (edges[i_edge] > 0) { - /* Get curve */ - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); + + /* Retrieve curve */ + auto curve = cad_manager->t8_geom_get_cad_curve (edges[i_edge]); /* Check if curve are valid */ T8_ASSERT (!curve.IsNull ()); + for (size_t coord = 0; coord < num_coords; ++coord) { const int offset_3d = coord * 3; const int offset_2d = coord * 2; @@ -570,8 +510,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei } else { /* Get surface */ - T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); + auto surface = cad_manager->t8_geom_get_cad_surface (edges[i_edge + num_edges]); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -622,9 +561,6 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid double temp_edge_vertices[2 * 3], temp_face_vertices[T8_ECLASS_MAX_CORNERS_2D * 3], interpolated_curve_param, interpolated_surface_params[2], cur_delta[3]; double interpolated_surface_parameters[2], interpolated_coords[3]; - Handle_Geom_Curve curve; - Handle_Geom_Surface surface; - Standard_Real first, last; for (size_t coord = 0; coord < num_coords; ++coord) { const int offset_3d = coord * 3; @@ -632,16 +568,16 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Check each edge for a geometry. */ for (int i_edge = 0; i_edge < num_edges; ++i_edge) { - /* We have to check for curves as well as surfaces. Linked curves are stored - * in the first half of the array, surfaces in the second. - * If a curve is connected to this edge we have to also check, + /* We have to check for curves as well as surfaces. Linked curves are stored + * in the first half of the array, surfaces in the second. + * If a curve is connected to this edge we have to also check, * if a surface is connected to at least one of the two adjacent faces. */ if (edges[i_edge] > 0 || edges[i_edge + num_edges] > 0) { /* Check if only a surface or a curve is present. Abort if both is true. */ T8_ASSERT (!(edges[i_edge] > 0 && edges[i_edge + num_edges] > 0)); - /* + /* * _0 * _- / \ * E0 / \ @@ -670,31 +606,21 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Interpolate between the parameters of the current edge. Same procedure as above. * Curves have only one parameter u, surfaces have two, u and v. * Therefore, we have to distinguish if the edge has a curve or surface linked to it. */ + if (edges[i_edge] > 0) { /* Check for linked curves */ /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&interpolation_coeff, parameters, 1, 1, &interpolated_curve_param); - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - /* Retrieve the curve and check if curve is valid */ - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); - T8_ASSERT (!curve.IsNull ()); - - /* Calculate point on curve with the interpolated parameter */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (i_edge, interpolated_curve_param); } else { /* Check for linked surfaces */ /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&interpolation_coeff, parameters, 2, 1, interpolated_surface_params); - T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); + T8_ASSERT (edges[i_edge + num_edges] <= cad_manager->t8_geom_get_cad_shape_face_map ().Size ()); - /* Retrieve the surface and check if surface is valid */ - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_params[0], interpolated_surface_params[1], pnt); + pnt = process_surface (i_edge + num_edges, interpolated_surface_params, 0); } /* Compute displacement between vertex interpolation and curve evaluation with interpolated parameters */ @@ -722,10 +648,10 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Check if face has a linked surface */ if (faces[i_faces] > 0) { - /* + /* * The faces of a tetrahedron are numerated in such a way, - * that face X is the opposing face to the corner node X. - * + * that face X is the opposing face to the corner node X. + * * _0 * _- / \ * _- / \ @@ -746,7 +672,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid double face_intersection[3] = { 0 }; t8_geom_get_tet_face_intersection (i_faces, ref_coords + offset_3d, face_intersection); - /* Turn 3D face_intersection into 2D coordinates on current face + /* Turn 3D face_intersection into 2D coordinates on current face * for parameter interpolation */ double face_intersection_2d[2]; face_intersection_2d[0] = face_intersection[t8_face_ref_coords_tet[i_faces][0]]; @@ -783,13 +709,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid t8_geom_linear_interpolation (interpolation_coeff, edge_vertices_on_face, 3, 1, interpolated_edge_coordinates); - /* Retrieve the curve of the edge and check if it is valid */ - T8_ASSERT (edges[i_tree_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_tree_edge])), first, last); - T8_ASSERT (!curve.IsNull ()); - - /* Calculate point on curve with interpolated parameter */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (i_tree_edge, interpolated_curve_param); /* Calculate the same scaling factors for the neighbouring faces * as in the evaluation of the edges of tetrahedral tree */ @@ -815,13 +735,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_tet (t8_cmesh_t cmesh, t8_gloidx_t gtreeid interpolated_coords[dim] += face_displacement_from_edges[dim]; } - /* Retrieve the surface and check if it is valid */ - T8_ASSERT (faces[i_faces] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (faces[i_faces]))); - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated surface parameters */ - surface->D0 (interpolated_surface_parameters[0], interpolated_surface_parameters[1], pnt); + pnt = process_surface (i_faces, interpolated_surface_params, 0); /* Compute the scaling factor. The scaling happens along the straight from * the opposite vertex of the face to the face_intersection. */ @@ -868,18 +782,15 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid double interpolated_curve_param, interpolated_surface_params[2], cur_delta[3]; gp_Pnt pnt; double interpolation_coeffs[2], temp_face_vertices[T8_ECLASS_MAX_CORNERS_2D * 3], temp_edge_vertices[2 * 3]; - Handle_Geom_Curve curve; - Handle_Geom_Surface surface; - Standard_Real first, last; for (size_t coord = 0; coord < num_coords; ++coord) { const int offset_3d = coord * 3; /* Check each edge for a geometry. */ for (int i_edge = 0; i_edge < num_edges; ++i_edge) { - /* We have to check for curves as well as surfaces. Linked curves are stored - * in the first half of the array, surfaces in the second. - * If a curve is connected to this edge we have to also check, + /* We have to check for curves as well as surfaces. Linked curves are stored + * in the first half of the array, surfaces in the second. + * If a curve is connected to this edge we have to also check, * if a surface is connected to at least one of the two adjacent faces. */ if (edges[i_edge] > 0 || edges[i_edge + num_edges] > 0) { /* Check if only a surface or a curve is present. Abort if both is true. */ @@ -900,7 +811,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid * | / | / * |/ |/ * 0 -------E0------- 1 - * + * */ const int edge_direction = i_edge / 4; /* Save the edge vertices temporarily. */ @@ -920,28 +831,14 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid t8_geom_linear_interpolation (&ref_coords[edge_direction + offset_3d], parameters, 1, 1, &interpolated_curve_param); - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); - - /* Check if curve are valid */ - T8_ASSERT (!curve.IsNull ()); - - /* Calculate point on curve with interpolated parameters. */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (i_edge, interpolated_curve_param); } else { /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&ref_coords[edge_direction + offset_3d], parameters, 2, 1, interpolated_surface_params); - T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); - - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_params[0], interpolated_surface_params[1], pnt); + pnt = process_surface (i_edge + num_edges, interpolated_surface_params, 0); } /* Compute displacement between vertex interpolation and curve evaluation with interpolated parameters */ @@ -950,9 +847,9 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid cur_delta[2] = pnt.Z () - interpolated_coords[offset_3d + 2]; /* Multiply curve displacement with corresponding ref coords. - * The edges are indexed so that all edges which satisfy i_edge % 4 == 0 - * have to multiplied with the inversed (1 - ref_coord) - * coordinate. All edges which satisfy i_edge % 4 == 1 have to multiplied with one + * The edges are indexed so that all edges which satisfy i_edge % 4 == 0 + * have to multiplied with the inversed (1 - ref_coord) + * coordinate. All edges which satisfy i_edge % 4 == 1 have to multiplied with one * inversed ref_coord and so forth... * An exception are edge 5 and 6, which have to be switched because they do not follow that rule. * Edges which are located at ref_coord[i] = 0 have to be multiplied with (1 - ref_coord[i]) and if the @@ -990,7 +887,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid for (int i_faces = 0; i_faces < num_faces; ++i_faces) { /* Check if face has a linked surface */ if (faces[i_faces] > 0) { - /* Allocate some variables and save the normal direction of the face and the face vertices + /* Allocate some variables and save the normal direction of the face and the face vertices * in a separate array for later usage. */ const int face_normal_direction = i_faces / 2; t8_geom_get_face_vertices (T8_ECLASS_HEX, active_tree_vertices, i_faces, 3, temp_face_vertices); @@ -1050,16 +947,8 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid t8_geom_linear_interpolation (&ref_coords[edge_direction + offset_3d], edge_vertices_on_face, 3, 1, interpolated_edge_coordinates); - /* Retrieve the curve of the edge */ - T8_ASSERT (edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]] - <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey ( - edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]])), - first, last); - /* Check if curve is valid */ - T8_ASSERT (!curve.IsNull ()); - /* Calculate point on curve with interpolated parameters */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge], + interpolated_curve_param); /* Calculate the displacement generated by the presence of the curve */ if (i_face_edge % 2 == 0) { @@ -1076,11 +965,11 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid } /* Convert the interpolated parameter of the curve into the corresponding parameters on the surface */ const int num_face_nodes = t8_eclass_num_vertices[T8_ECLASS_QUAD]; - t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters ( + cad_manager->t8_geom_edge_parameter_to_face_parameters ( edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]], faces[i_faces], num_face_nodes, interpolated_curve_param, surface_parameters, surface_parameters_from_curve); - /* Calculate the displacement between the interpolated parameters on the surface + /* Calculate the displacement between the interpolated parameters on the surface * and the parameters on the surface converted from the parameter of the curve * and scale them with the corresponding ref coord */ if (i_face_edge % 2 == 0) { @@ -1105,7 +994,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid interpolation_coeffs[1] = ref_coords[((face_normal_direction + 2) % 3) + offset_3d]; /* The normal vectors of the faces 0, 1, 4, 5 of a hex point in the same direction * as the corresponding axis (normal(f0) = (1, 0, 0)). The faces 2 and 3 are oriented - * in the other direction (normal(f2) = (0, -1, 0)). Therefore we have to switch two + * in the other direction (normal(f2) = (0, -1, 0)). Therefore we have to switch two * vertices to change the orientation. Here we switch vertex 1 and 2. */ double temp_surface_parameters[8]; memcpy (temp_surface_parameters, surface_parameters, sizeof (double) * 8); @@ -1139,17 +1028,9 @@ t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid interpolated_surface_params[dim] += surface_parameter_displacement_from_edges[dim]; } - /* Retrieve the surface of the edge */ - T8_ASSERT (faces[i_faces] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (faces[i_faces]))); - - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); + pnt = process_surface (i_faces, interpolated_surface_params, 0); - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_params[0], interpolated_surface_params[1], pnt); - - /* Compute the displacement between surface and interpolated coords, scale them with the appropriate ref_coord + /* Compute the displacement between surface and interpolated coords, scale them with the appropriate ref_coord * and add them to the out_coords. */ if (i_faces % 2 == 0) { out_coords[offset_3d] @@ -1178,10 +1059,10 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree const size_t num_coords, double *out_coords) const { T8_ASSERT (active_tree_class == T8_ECLASS_PRISM); - /* The array contains the coordinate [x,y,z] to interpolate for each edge of a prism. + /* The array contains the coordinate [x,y,z] to interpolate for each edge of a prism. * For example: On edge 0 the interpolation coordinate is y. */ const int t8_interpolation_coefficient_prism_edge[9] = { 1, 0, 0, 1, 0, 0, 2, 2, 2 }; - /* The array contains the coordinates [x,y,z] to interpolate for each face of a prism. + /* The array contains the coordinates [x,y,z] to interpolate for each face of a prism. * For example: On face 0 the interpolation coordinates are y and z. */ const int t8_interpolation_coefficients_prism_face[5][2] = { { 1, 2 }, { 0, 2 }, { 0, 2 }, { 0, 1 }, { 0, 1 } }; @@ -1193,15 +1074,12 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree gp_Pnt pnt; double interpolated_coords[3], interpolation_coeffs[3], temp_face_vertices[T8_ECLASS_MAX_CORNERS_2D * 3], temp_edge_vertices[2 * 3]; - Handle_Geom_Curve curve; - Handle_Geom_Surface surface; - Standard_Real first, last; /* Check each edge for a geometry. */ for (int i_edge = 0; i_edge < T8_DPRISM_EDGES; ++i_edge) { - /* We have to check for curves as well as surfaces. Linked curves are stored - * in the first half of the array, surfaces in the second. - * If a curve is connected to this edge we have to also check, + /* We have to check for curves as well as surfaces. Linked curves are stored + * in the first half of the array, surfaces in the second. + * If a curve is connected to this edge we have to also check, * if a surface is connected to at least one of the two adjacent faces. */ if (edges[i_edge] > 0 || edges[i_edge + T8_DPRISM_EDGES] > 0) { /* Check if only a surface or a curve is present. Abort if both is true. */ @@ -1212,9 +1090,9 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree * |_- _- / \ * 0----x _- / \ * _- / \ - * E6 E5 E3 - * _- / \ - * _- / \ + * E6 E5 E3 + * _- / \ + * _- / \ * _- _3-----E4----_-5 * 1 _- _- * / \ E8 _- @@ -1248,28 +1126,14 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree t8_geom_linear_interpolation (&ref_coords[t8_interpolation_coefficient_prism_edge[i_edge] + offset_3d], parameters, 1, 1, &interpolated_curve_param); - T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); - - /* Check if curve are valid */ - T8_ASSERT (!curve.IsNull ()); - - /* Compute point on curve with interpolated parameters. */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (i_edge, interpolated_curve_param); } else { /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&ref_coords[t8_interpolation_coefficient_prism_edge[i_edge] + offset_3d], parameters, 2, 1, interpolated_surface_params); - T8_ASSERT (edges[i_edge + T8_DPRISM_EDGES] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + T8_DPRISM_EDGES]))); - - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_params[0], interpolated_surface_params[1], pnt); + pnt = process_surface (i_edge + T8_DPRISM_EDGES, interpolated_surface_params, 0); } /* Compute displacement between vertex interpolation and curve evaluation with interpolated parameters */ @@ -1337,13 +1201,7 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree t8_geom_linear_interpolation (&ref_coords[interpolation_coeff + offset_3d], edge_vertices_on_face, 3, 1, interpolated_edge_coordinates); - /* Retrieve the curve of the edge */ - T8_ASSERT (edges[i_tree_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_tree_edge])), first, last); - /* Check if curve is valid */ - T8_ASSERT (!curve.IsNull ()); - /* Calculate point on curve with interpolated parameters */ - curve->D0 (interpolated_curve_param, pnt); + pnt = process_curve (i_tree_edge, interpolated_curve_param); /* Compute the scaling_factor of the edge displacement on the current face */ double scaling_factor = t8_geom_get_scaling_factor_of_edge_on_face_prism ( @@ -1376,17 +1234,9 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree interpolated_coords[dim] += face_displacement_from_edges[dim]; } - /* Retrieve the surface of the edge */ - T8_ASSERT (faces[i_faces] <= cad_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (faces[i_faces]))); + pnt = process_surface (i_faces, interpolated_surface_params, 0); - /* Check if surface is valid */ - T8_ASSERT (!surface.IsNull ()); - - /* Compute point on surface with interpolated parameters */ - surface->D0 (interpolated_surface_params[0], interpolated_surface_params[1], pnt); - - /* Compute the displacement between surface and interpolated coords, scale them with the appropriate scaling_factor + /* Compute the displacement between surface and interpolated coords, scale them with the appropriate scaling_factor * and add them to the out_coords. */ double scaling_factor = t8_geom_get_scaling_factor_face_through_volume_prism (i_faces, ref_coords + offset_3d); @@ -1398,236 +1248,6 @@ t8_geometry_cad::t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtree } } -int -t8_geometry_cad::t8_geom_is_line (const int curve_index) const -{ - const Handle_Geom_Curve curve = t8_geom_get_cad_curve (curve_index); - const GeomAdaptor_Curve curve_adaptor (curve); - return curve_adaptor.GetType () == GeomAbs_Line; -} - -int -t8_geometry_cad::t8_geom_is_plane (const int surface_index) const -{ - const Handle_Geom_Surface surface = t8_geom_get_cad_surface (surface_index); - const GeomAdaptor_Surface surface_adaptor (surface); - return surface_adaptor.GetType () == GeomAbs_Plane; -} - -const gp_Pnt -t8_geometry_cad::t8_geom_get_cad_point (const int index) const -{ - T8_ASSERT (index <= cad_shape_vertex_map.Size ()); - return BRep_Tool::Pnt (TopoDS::Vertex (cad_shape_vertex_map.FindKey (index))); -} - -const Handle_Geom_Curve -t8_geometry_cad::t8_geom_get_cad_curve (const int index) const -{ - T8_ASSERT (index <= cad_shape_edge_map.Size ()); - Standard_Real first, last; - return BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (index)), first, last); -} - -const Handle_Geom_Surface -t8_geometry_cad::t8_geom_get_cad_surface (const int index) const -{ - T8_ASSERT (index <= cad_shape_face_map.Size ()); - return BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (index))); -} - -const TopTools_IndexedMapOfShape -t8_geometry_cad::t8_geom_get_cad_shape_vertex_map () const -{ - return cad_shape_vertex_map; -} - -const TopTools_IndexedMapOfShape -t8_geometry_cad::t8_geom_get_cad_shape_edge_map () const -{ - return cad_shape_edge_map; -} - -const TopTools_IndexedMapOfShape -t8_geometry_cad::t8_geom_get_cad_shape_face_map () const -{ - return cad_shape_face_map; -} - -int -t8_geometry_cad::t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const -{ - const TopTools_ListOfShape collection1 = cad_shape_vertex2edge_map.FindFromIndex (vertex1_index); - const TopTools_ListOfShape collection2 = cad_shape_vertex2edge_map.FindFromIndex (vertex2_index); - - for (auto edge1 = collection1.begin (); edge1 != collection1.end (); ++edge1) { - for (auto edge2 = collection2.begin (); edge2 != collection2.end (); ++edge2) { - if (edge1->IsEqual (*edge2)) { - return cad_shape_edge2face_map.FindIndex (*edge1); - } - } - } - return 0; -} - -int -t8_geometry_cad::t8_geom_get_common_face (const int edge1_index, const int edge2_index) const -{ - const TopTools_ListOfShape collection1 = cad_shape_edge2face_map.FindFromIndex (edge1_index); - const TopTools_ListOfShape collection2 = cad_shape_edge2face_map.FindFromIndex (edge2_index); - - for (auto face1 = collection1.begin (); face1 != collection1.end (); ++face1) { - for (auto face2 = collection2.begin (); face2 != collection2.end (); ++face2) { - if (face1->IsEqual (*face2)) { - return cad_shape_face_map.FindIndex (*face1); - } - } - } - return 0; -} - -int -t8_geometry_cad::t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const -{ - const TopTools_ListOfShape collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); - return collection.Contains (cad_shape_edge_map.FindKey (edge_index)); -} - -int -t8_geometry_cad::t8_geom_is_edge_on_face (const int edge_index, const int face_index) const -{ - const TopTools_ListOfShape collection = cad_shape_edge2face_map.FindFromIndex (edge_index); - return collection.Contains (cad_shape_face_map.FindKey (face_index)); -} - -int -t8_geometry_cad::t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const -{ - const TopTools_ListOfShape edge_collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); - for (auto edge = edge_collection.begin (); edge != edge_collection.end (); ++edge) { - const TopTools_ListOfShape face_collection = cad_shape_edge2face_map.FindFromKey (*edge); - if (face_collection.Contains (cad_shape_face_map.FindKey (face_index))) { - return 1; - } - } - return 0; -} - -void -t8_geometry_cad::t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, - double *edge_param) const -{ - T8_ASSERT (t8_geometry_cad::t8_geom_is_vertex_on_edge (vertex_index, edge_index)); - TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); - TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); - *edge_param = BRep_Tool::Parameter (vertex, edge); -} - -void -t8_geometry_cad::t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, - double *face_params) const -{ - T8_ASSERT (t8_geometry_cad::t8_geom_is_vertex_on_face (vertex_index, face_index)); - gp_Pnt2d uv; - TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); - TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); - uv = BRep_Tool::Parameters (vertex, face); - face_params[0] = uv.X (); - face_params[1] = uv.Y (); -} - -void -t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, - const int num_face_nodes, const double edge_param, - const double *surface_params, double *face_params) const -{ - T8_ASSERT (t8_geometry_cad::t8_geom_is_edge_on_face (edge_index, face_index)); - Standard_Real first, last; - gp_Pnt2d uv; - TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); - TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); - Handle_Geom2d_Curve curve_on_surface = BRep_Tool::CurveOnSurface (edge, face, first, last); - Handle_Geom_Surface surface = BRep_Tool::Surface (face); - curve_on_surface->D0 (edge_param, uv); - face_params[0] = uv.X (); - face_params[1] = uv.Y (); - - /* Check for right conversion of edge to surface parameter and correct if needed */ - /* Checking u parameter */ - if (surface_params != NULL) { - double parametric_bounds[4]; - surface->Bounds (parametric_bounds[0], parametric_bounds[1], parametric_bounds[2], parametric_bounds[3]); - if (surface->IsUClosed ()) { - for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { - if (surface_params[i_face_node * 2] == parametric_bounds[0]) { - if (face_params[0] == parametric_bounds[1]) { - face_params[0] = parametric_bounds[0]; - } - } - else if (surface_params[i_face_node * 2] == parametric_bounds[1]) { - if (face_params[0] == parametric_bounds[0]) { - face_params[0] = parametric_bounds[1]; - } - } - } - } - /* Checking v parameter */ - if (surface->IsVClosed ()) { - for (int i_face_node = 0; i_face_node < num_face_nodes; ++i_face_node) { - if (surface_params[i_face_node * 2 + 1] == parametric_bounds[0]) { - if (face_params[1] == parametric_bounds[1]) { - face_params[1] = parametric_bounds[0]; - } - } - else if (surface_params[i_face_node * 2 + 1] == parametric_bounds[1]) { - if (face_params[1] == parametric_bounds[0]) { - face_params[1] = parametric_bounds[1]; - } - } - } - } - } -} - -void -t8_geometry_cad::t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const -{ - const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (surface_index); - cad_surface->Bounds (bounds[0], bounds[1], bounds[2], bounds[3]); -} - -void -t8_geometry_cad::t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const -{ - const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); - bounds[0] = cad_edge->FirstParameter (); - bounds[1] = cad_edge->LastParameter (); -} - -int -t8_geometry_cad::t8_geom_is_edge_closed (int edge_index) const -{ - const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); - return cad_edge->IsClosed (); -} - -int -t8_geometry_cad::t8_geom_is_surface_closed (int geometry_index, int parameter) const -{ - const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (geometry_index); - switch (parameter) { - case 0: - return cad_surface->IsUClosed (); - break; - case 1: - return cad_surface->IsVClosed (); - break; - default: - SC_ABORT_NOT_REACHED (); - break; - } -} - /* This part should be callable from C */ T8_EXTERN_C_BEGIN (); @@ -1650,4 +1270,38 @@ t8_geometry_cad_destroy (t8_geometry_cad_c **geom) *geom = NULL; } +gp_Pnt +t8_geometry_cad::process_curve (const int edge_index, const double interpolated_curve_param) const +{ + gp_Pnt pnt; + + /* Retrieve the curve of the edge */ + auto curve = cad_manager->t8_geom_get_cad_curve (edges[edge_index]); + + /* Check if curve is valid */ + T8_ASSERT (!curve.IsNull ()); + + /* Calculate point on curve with interpolated parameters */ + curve->D0 (interpolated_curve_param, pnt); + + return pnt; +} +gp_Pnt +t8_geometry_cad::process_surface (const int face_index, const double *interpolated_surface_params, + const int offset) const +{ + gp_Pnt pnt; + + /* Retrieve the surface of the edge */ + auto surface = cad_manager->t8_geom_get_cad_surface (faces[face_index]); + + /* Check if surface is valid */ + T8_ASSERT (!surface.IsNull ()); + + /* Compute point on surface with interpolated parameters */ + surface->D0 (interpolated_surface_params[offset], interpolated_surface_params[offset + 1], pnt); + + return pnt; +} + T8_EXTERN_C_END (); diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h index 6717031e09..ec079bebf6 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h @@ -47,11 +47,10 @@ T8_EXTERN_C_BEGIN (); * The vertices are saved via the \ref t8_cmesh_set_tree_vertices function. * Since the internals of this geometry are finely tuned to the .brep file * it is recommended to only use it with the \ref t8_cmesh_from_msh_file function. - * \param [in] dim 0 <= tree dimension <= 3. The dimension. * \param [in] fileprefix Prefix of a .brep file from which to extract an cad geometry. - * \param [in] name The name to give this geometry. + * \param [in] name_in The name to give this geometry. * \return A pointer to an allocated t8_geometry_cad struct, as - * if the \ref t8_geometry_cad (std::string fileprefix, std::string name) + * if the \ref t8_geometry_cad (std::string fileprefix, std::string name) * constructor was called. */ t8_geometry_cad_c * 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 121b9aa6c2..d009089e7f 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2025 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 @@ -21,8 +21,8 @@ */ /** \file t8_geometry_cad.hxx - * This geometry implements OpenCASCADE geometries. It enables the option to link different - * 1 and 2 dimensional cad geometries to the edges and faces of refinement trees. + * This geometry implements OpenCASCADE geometries. It enables the option to link different + * 1 and 2 dimensional cad geometries to the edges and faces of refinement trees. * The geometry of the refinement tree is extended into the volume accordingly. */ @@ -33,7 +33,8 @@ #include #include #include - +#include +#include #include #include #include @@ -67,7 +68,7 @@ struct t8_geometry_cad: public t8_geometry_with_vertices * additional geometry information, which is given via the \a cad_shape. * The vertices are saved via the \ref t8_cmesh_set_tree_vertices function. * This constructor can be used in short scripts or in combination with a - * mesh generator, to omit the file IO of the + * mesh generator, to omit the file IO of the * \ref t8_geometry_cad (std::string fileprefix, std::string name) constructor. * \param [in] cad_shape cad shape geometry. * \param [in] name The name to give this geometry. @@ -122,7 +123,7 @@ struct t8_geometry_cad: public t8_geometry_with_vertices /** 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 + * 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). * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. @@ -141,165 +142,11 @@ struct t8_geometry_cad: public t8_geometry_with_vertices 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. - */ - int - t8_geom_is_line (const int curve_index) const; - - /** Check if a cad_surface is a plane. - * \param [in] surface_index The index of the cad_surface. - * \return 1 if surface is a plane linear, 0 if surface is not a plane. - */ - int - t8_geom_is_plane (const int surface_index) const; - - /** Get an cad point from the cad_shape. - * \param [in] index The index of the point in the cad_shape. - * \return The cad point. - */ - const gp_Pnt - t8_geom_get_cad_point (const int index) const; - - /** Get an cad curve from the cad_shape. - * \param [in] index The index of the curve in the cad_shape. - * \return The cad curve. - */ - const Handle_Geom_Curve - t8_geom_get_cad_curve (const int index) const; - - /** Get an cad surface from the cad_shape. - * \param [in] index The index of the surface in the cad_shape. - * \return The cad surface. - */ - const Handle_Geom_Surface - t8_geom_get_cad_surface (const int index) const; - - /** Get the cad_shape_vertex2edge_map. - * \return The cad_shape_vertex_map. - */ - const TopTools_IndexedMapOfShape - t8_geom_get_cad_shape_vertex_map () const; - - /** Get the cad_shape_edge2face_map. - * \return The cad_shape_edge_map. - */ - const TopTools_IndexedMapOfShape - t8_geom_get_cad_shape_edge_map () const; - - /** Get the cad_shape_face_map. - * \return The cad_shape_face_map. - */ - const TopTools_IndexedMapOfShape - t8_geom_get_cad_shape_face_map () const; - - /** Check if two cad points share a common cad edge. - * \param [in] vertex1_index The index of the first cad point. - * \param [in] vertex2_index The index of the second cad point. - * \return Index of the shared edge. 0 if there is no shared edge. - */ - int - t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const; - - /** Check if two cad edges share a common cad face. - * \param [in] edge1_index The index of the first cad edge. - * \param [in] edge2_index The index of the second cad edge. - * \return Index of the shared face. 0 if there is no shared face. - */ - int - t8_geom_get_common_face (const int edge1_index, const int edge2_index) const; - - /** Check if a cad vertex lies on an cad edge. - * \param [in] vertex_index The index of the cad vertex. - * \param [in] edge_index The index of the cad edge. - * \return 1 if vertex lies on edge, otherwise 0. - */ - int - t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const; - - /** Check if a cad vertex lies on an cad edge. - * \param [in] edge_index The index of the cad vertex. - * \param [in] face_index The index of the cad edge. - * \return 1 if vertex lies on edge, otherwise 0. - */ - int - t8_geom_is_edge_on_face (const int edge_index, const int face_index) const; - - /** Check if a cad vertex lies on an cad face. - * \param [in] vertex_index The index of the cad vertex. - * \param [in] face_index The index of the cad face. - * \return 1 if vertex lies on face, otherwise 0. - */ - int - t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const; - - /** Retrieves the parameter of an cad vertex on an cad edge. - * The vertex has to lie on the edge. - * \param [in] vertex_index The index of the cad vertex. - * \param [in] edge_index The index of the cad edge. - * \param [out] edge_param The parameter of the vertex on the edge. - */ - void - t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, double *edge_param) const; - - /** Retrieves the parameters of an cad vertex on a cad face. - * The vertex has to lie on the face. - * \param [in] vertex_index The index of the cad vertex. - * \param [in] face_index The index of the cad face. - * \param [out] face_params The parameters of the vertex on the face. - */ - void - t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, double *face_params) const; - - /** Converts the parameters of an cad edge to the corresponding parameters on an cad face. - * The edge has to lie on the face. - * For the conversion of edge parameters of mesh elements to topological face parameters of a closed surface, it is additionally - * checked, whether the conversion was correct, to prevent disorted elements. - * \param [in] edge_index The index of the cad edge, which parameters should be converted to face parameters. - * \param [in] face_index The index of the cad face, on to which the edge parameters should be converted. - * \param [in] num_face_nodes The number of the face nodes of the evaluated element. Only needed for closed surface check, otherwise NULL. - * \param [in] edge_param The parameter on the edge. - * \param [in] surface_param The parameters of the surface nodes. - * When provided, there are additional checks for closed geometries. - * If there are no surface parameter - * to pass in to the function, you can pass NULL. - * \param [out] face_params The corresponding parameters on the face. - */ - void - t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, const int num_face_nodes, - const double edge_param, const double *surface_params, - double *face_params) const; - - /** Finds the parametric bounds of an cad face. - * \param [in] face_index The index of the cad face. - * \param [out] bounds The parametric bounds of the cad face. - */ - void - t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const; - - /** Finds the parametric bounds of an cad edge. - * \param [in] edge_index The index of the cad edge. - * \param [out] bounds The parametric bounds of the cad edge. - */ - void - t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const; - - /** Checks if an edge is closed in its U parameter. - * \param [in] edge_index The index of the closed edge. - * \return 1 if edge is closed in U. 0 if edge is not closed in U. - */ - int - t8_geom_is_edge_closed (int edge_index) const; - - /** Checks if a surface is closed in its U parameter or V parameter. - * \param [in] geometry_index The index of the closed geometry. - * \param [in] parameter The parameter, which should be check for closeness. - * 0 stands for the U parameter and 1 for the V parameter. - * \return 1 if geometry is closed in U. 0 if geometry is not closed in U. - */ - int - t8_geom_is_surface_closed (int geometry_index, int parameter) const; + std::shared_ptr + get_cad_manager () const + { + return cad_manager; + } private: /** @@ -327,7 +174,7 @@ struct t8_geometry_cad: public t8_geometry_with_vertices double *out_coords) const; /** - * Map a point in the reference space $$[0,1]^3$$ to $$\mathbb R^3$$. Only for tet trees. + * Map a point in the reference space \f$ [0,1]^3 \f$ to \f$ \mathbb R^3 \f$. Only for tet trees. * \param [in] cmesh The cmesh in which the point lies. * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. * \param [in] ref_coords Array of tree dimension x \a num_coords many entries, specifying points in \f$ [0,1]^\mathrm{dim} \f$. @@ -362,16 +209,16 @@ struct t8_geometry_cad: public t8_geometry_with_vertices t8_geom_evaluate_cad_prism (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - const int *edges; /**< The linked edges of the currently active tree. */ - const int *faces; /**< The linked faces of the currently active tree. */ - TopoDS_Shape cad_shape; /**< cad geometry */ - TopTools_IndexedMapOfShape cad_shape_vertex_map; /**< Map of all TopoDS_Vertex in shape. */ - TopTools_IndexedMapOfShape cad_shape_edge_map; /**< Map of all TopoDS_Edge in shape. */ - TopTools_IndexedMapOfShape cad_shape_face_map; /**< Map of all TopoDS_Face in shape. */ - TopTools_IndexedDataMapOfShapeListOfShape - cad_shape_vertex2edge_map; /**< Maps all TopoDS_Vertex of shape to all its connected TopoDS_Edge */ - TopTools_IndexedDataMapOfShapeListOfShape - cad_shape_edge2face_map; /**< Maps all TopoDS_Edge of shape to all its connected TopoDS_Face */ + const int *edges; /**< The linked edges of the currently active tree. */ + const int *faces; /**< The linked faces of the currently active tree. */ + + std::shared_ptr cad_manager; /**< The CAD manager of the geometry. */ + + gp_Pnt + process_curve (const int edge_index, const double interpolated_curve_param) const; + + gp_Pnt + process_surface (const int face_index, const double *interpolated_surface_params, const int offset) const; }; #endif /* !T8_GEOMETRY_CAD_HXX */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx index ee1b0b89f0..3fa875a042 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx @@ -66,7 +66,14 @@ struct t8_geometry_quadrangulated_disk: public t8_geometry_with_vertices t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, @@ -136,7 +143,14 @@ struct t8_geometry_triangulated_spherical_surface: public t8_geometry_with_verti t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, @@ -195,7 +209,14 @@ struct t8_geometry_tessellated_spherical_surface: public t8_geometry_with_vertic t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, @@ -256,7 +277,14 @@ struct t8_geometry_cubed_spherical_shell: public t8_geometry_with_vertices t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, @@ -315,7 +343,14 @@ struct t8_geometry_prismed_spherical_shell: public t8_geometry_with_vertices t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, @@ -374,7 +409,14 @@ struct t8_geometry_cubed_sphere: public t8_geometry_with_vertices t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; - /* Jacobian, not implemented. */ + /** + * Jacobian, not implemented. + * \param[in] cmesh The cmesh in which the point lies. + * \param[in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param[in] ref_coords Array of tree dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param[in] num_coords The number of points to map. + * \param[in] jacobian The Jacobian matrix to be filled. + */ void t8_geom_evaluate_jacobian ([[maybe_unused]] t8_cmesh_t cmesh, [[maybe_unused]] t8_gloidx_t gtreeid, [[maybe_unused]] const double *ref_coords, [[maybe_unused]] const size_t num_coords, 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 c81f8742ec..e52d884153 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_lagrange.hxx @@ -39,11 +39,12 @@ #include #include +/** The maximum polynomial degree currently implemented. */ #define T8_GEOMETRY_MAX_POLYNOMIAL_DEGREE 2 /** * Mapping with Lagrange basis functions - * + * * The enumeration of the nodal basis functions depends on the node numbering * scheme. While this is a convention, we came up with the following rules to * guide us when constructing new mappings: @@ -67,16 +68,16 @@ * assigned based on increasing face IDs, then increasing edge IDs, then * increasing vertex IDs. For volume elements, the volume nodes are assigned * lastly. This hierarchical construction satisfies rule 1 at the mesh level. - * + * * You can verify these rules by checking the documentation of the * \a t8_geom_xxx_basis methods of this class * (e.g. t8_geometry_lagrange::t8_geom_t6_basis). - * + * */ struct t8_geometry_lagrange: public t8_geometry_with_vertices { public: - /** + /** * Constructor of the Lagrange geometry with a given dimension. The geometry * is compatible with all tree types and uses as many vertices as the number of Lagrange * basis functions used for the mapping. @@ -98,19 +99,19 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices /** * Maps points from the reference space to the physical space \f$ \mathbb{R}^3 \f$. - * + * * For linear elements, it gives the same result as \ref t8_geom_compute_linear_geometry. - * + * * The mapping is performed via Lagrange interpolation according to - * + * * \f$ \mathbf{x}(\vec{\xi}) = \sum\limits_{i=1}^{N_{\mathrm{vertex}}} \psi_i(\vec{\xi}) \mathbf{x}_i \f$ - * + * * where \f$ \vec{\xi} \f$ is the point in the reference space to be mapped, \f$ \mathbf{x} \f$ is the mapped point we search, * \f$ \psi_i(\vec{\xi}) \f$ are the basis functions associated with the vertices, and \f$ \mathbf{x}_i \f$ are the * vertices of the current tree in the physical space. - * The basis functions are specific to the tree type, see e.g. \ref t8_geom_t6_basis. + * The basis functions are specific to the tree type, see e.g. t8_geom_t6_basis . * The vertices of the current tree were set with \ref t8_cmesh_set_tree_vertices. - * + * * \param [in] cmesh The cmesh in which the point lies. * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. * \param [in] ref_coords Array of tree dimension x \a num_points entries, specifying points in the reference space. @@ -136,7 +137,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices /** 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 polynomial degree of the + * evaluated. You can use it for example to load the polynomial degree of the * Lagrange basis into an internal buffer (as is done in the Lagrange geometry). * \param [in] cmesh The cmesh. * \param [in] gtreeid The global tree. @@ -166,7 +167,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x --------- x 0 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -178,7 +179,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x ----x---- x 0 2 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -197,7 +198,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x --------- x 0 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -216,7 +217,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x --- x --- x 0 5 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -235,7 +236,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x --------- x 0 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -254,7 +255,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x ----x---- x 0 6 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -277,7 +278,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x --------- x --> 0 1 \endverbatim - * \param ref_point Point in the reference space. + * \param [in] ref_point Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -300,7 +301,7 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices x ----x---- x --> x ----x---- x --> x ----x---- x --> 0 18 1 9 20 13 4 19 5 \endverbatim - * \param ref_point Point in the reference space. + * \param ref_point [in] Point in the reference space. * \return Basis functions evaluated at the reference point. */ inline std::vector @@ -312,9 +313,9 @@ struct t8_geometry_lagrange: public t8_geometry_with_vertices /** * Flatten a vector of vector into a single vector. - * + * * \tparam T Template parameter of a vector. - * \param vec Nested vector to be flattened. + * \param [in] vec Nested vector to be flattened. * \return Flattened vector. */ template @@ -330,7 +331,7 @@ flatten (const std::vector> &vec) /** * A single coarse mesh cell with Lagrange geometry. - * + * * This class is essentially a wrapper around a cmesh. * By having a single element instead of a mesh, understanding and * testing is made easier. Several topological utilities are provided, @@ -341,19 +342,19 @@ class t8_lagrange_element { public: /** * Construct a new t8_lagrange_element object. - * - * \param eclass Element class (line, quad, etc.) - * \param degree Polynomial degree (1, 2, ...) - * \param nodes x,y,z coordinates of the nodes, adhering to the numbering - * convention. + * + * \param [in] eclass Element class (line, quad, etc.) + * \param [in] degree Polynomial degree (1, 2, ...) + * \param [in] nodes x,y,z coordinates of the nodes, adhering to the numbering + * convention. */ t8_lagrange_element (t8_eclass_t eclass, uint32_t degree, std::vector &nodes); /** * Destroy the t8_lagrange_element object. - * + * * The cmesh wrapped by this class is also destroyed. - * + * */ ~t8_lagrange_element () { @@ -362,7 +363,7 @@ class t8_lagrange_element { /** * Get the type of the element. - * + * * \return Element class of the element. */ t8_eclass_t @@ -370,7 +371,7 @@ class t8_lagrange_element { /** * Element classes of the faces of this element. - * + * * \return Element classes of the faces, enumerated according to the face * ordering conventions of t8code. */ @@ -379,25 +380,25 @@ class t8_lagrange_element { /** * Coordinates of the specified node. - * - * \param node Node label. Node numbering starts at 0. - * \return x,y,z coordinates of the node. + * + * \param [in] node Node label. Node numbering starts at 0. + * \return x,y,z coordinates of the node. */ std::vector get_node_coords (uint32_t node) const; /** * Coordinates of the specified nodes. - * - * \param nodes Node labels. Node numbering starts at 0. - * \return x,y,z coordinates of the nodes. + * + * \param [in] nodes Node labels. Node numbering starts at 0. + * \return x,y,z coordinates of the nodes. */ std::vector> get_node_coords (std::vector &nodes) const; /** * Node labels on the faces of the element. - * + * * \return Node labels on each face of the element. */ std::vector> @@ -405,11 +406,11 @@ class t8_lagrange_element { /** * Decompose the element into its faces. - * + * * t8_lagrange_element()-s of codimension 1 are created. The original element * is not modified and the decomposition is not recursive. * The faces can further be decomposed by calling this method on them. - * + * * \return Lagrange elements from the faces. */ std::vector @@ -417,20 +418,20 @@ class t8_lagrange_element { /** * Physical coordinates of a point given in the reference domain. - * - * \param point Parametric coordinates of the point to be mapped. - * For 2D elements, only the first two coordinates are - * considered. For the 1D line element, only the first. - * \return Coordinates in the physical space. + * + * \param [in] ref_point Parametric coordinates of the point to be mapped. + * For 2D elements, only the first two coordinates are + * considered. For the 1D line element, only the first. + * \return Coordinates in the physical space. */ std::array evaluate (const std::array &ref_point) const; /** * Sample random points in the reference domain. - * - * \param n_point Number of points to generate. - * \return Coordinates of the points, given in x,y,z. + * + * \param [in] n_point Number of points to generate. + * \return Coordinates of the points, given in x,y,z. */ std::vector> sample (uint32_t n_point) const; @@ -457,19 +458,19 @@ class t8_lagrange_element { 0 1 face 2 \endverbatim - * - * \param eclass Element class of the element onto which we map. - * d-dimensional elements can only be mapped to the faces of - * d+1-dimensional elements. - * \param face_id Face ID of the element onto which we map. - * Faces in an element are numbered according to the t8code - * conventions. The selected face must have the same type as - * the element from which we map. For instance, an element of - * type T8_ECLASS_QUAD can only be mapped onto face 4 of a - * T8_ECLASS_PYRAMID, since the other faces of a pyramidal - * element are triangles. - * \param coord x,y,z coordinates of the point in this element. - * \return x,y,z coordinates of the mapped point. + * + * \param [in] eclass Element class of the element onto which we map. + * d-dimensional elements can only be mapped to the faces of + * d+1-dimensional elements. + * \param [in] face_id Face ID of the element onto which we map. + * Faces in an element are numbered according to the t8code + * conventions. The selected face must have the same type as + * the element from which we map. For instance, an element of + * type \ref T8_ECLASS_QUAD can only be mapped onto face 4 of a + * \ref T8_ECLASS_PYRAMID, since the other faces of a pyramidal + * element are triangles. + * \param [in] coord x,y,z coordinates of the point in this element. + * \return x,y,z coordinates of the mapped point. */ std::array map_on_face (t8_eclass eclass, const int face_id, const std::array &coord) const; @@ -496,6 +497,11 @@ class t8_lagrange_element { /** Number of nodes in the Lagrange element of a given class and degree */ static constexpr uint32_t lagrange_nodes[T8_ECLASS_COUNT][2] = { { 1, 1 }, { 2, 3 }, { 4, 9 }, { 3, 6 }, { 8, 27 } }; + /** Inbuilt function to create a uniform forest. + * \param [in] cmesh The cmesh to use. + * \param [in] level The level of the uniform forest. + * \return The forest. + */ t8_forest_t create_uniform_forest (t8_cmesh_t cmesh, uint32_t level) const; }; 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 75b65e9b42..4525ae3c81 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx @@ -31,10 +31,14 @@ #include #include +/** + * Linear geometry. Performs a (tri-/bi-)linear interpolation between the + * vertices of the assigned tree. Produces linear trees and elements. + */ struct t8_geometry_linear: public t8_geometry_with_vertices { public: - /** + /** * Constructor of the linear geometry. The geometry * is viable with all tree types and uses as many vertices as the tree type has. * The vertices are saved via the \ref t8_cmesh_set_tree_vertices function. @@ -42,7 +46,7 @@ struct t8_geometry_linear: public t8_geometry_with_vertices */ t8_geometry_linear (); - /** The destructor. + /** The destructor. * Clears the allocated memory. */ virtual ~t8_geometry_linear (); 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 2b25cb0c58..d3670b3074 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 @@ -22,7 +22,7 @@ /** \file t8_geometry_linear_axis_aligned.hxx * Definition of an axis-aligned geometry. It maps from - * \f$ [0,1]^\mathrm{dim} \f$ to \f$ \mathbb{R}^3 \f$, using two vertices. + * \f$ [0,1]^\mathrm{dim} \f$ to \f$ \mathbb{R}^3 \f$, using two vertices. */ #ifndef T8_GEOMETRY_LINEAR_AXIS_ALIGNED_HXX @@ -32,6 +32,11 @@ #include #include +/** + * Linear and axis-aligned geometry for cartesian grids. Interpolates in the cartesian + * space opened by two points. Needs only two vertices per tree, regardless of the + * dimension. Only valid for line, quad and hex trees. + */ struct t8_geometry_linear_axis_aligned: public t8_geometry_with_vertices { public: @@ -44,7 +49,7 @@ struct t8_geometry_linear_axis_aligned: public t8_geometry_with_vertices */ t8_geometry_linear_axis_aligned (); - /** The destructor. + /** The destructor. */ virtual ~t8_geometry_linear_axis_aligned (); @@ -122,12 +127,18 @@ struct t8_geometry_linear_axis_aligned: public t8_geometry_with_vertices return true; } + /** + * Compute the bounding box of the currently active tree. + * \param[in] cmesh The cmesh to check compatibility with. + * \param[in, out] bounds The bounding box of the cmesh. + * \return True if the geometry is compatible with the cmesh, false otherwise. + */ virtual bool get_tree_bounding_box ([[maybe_unused]] const t8_cmesh_t cmesh, double bounds[6]) const { T8_ASSERT (cmesh != NULL); T8_ASSERT (active_tree_vertices != NULL); - /* For axis aligned geometries the active tree vertices already describe the bounding box. + /* For axis aligned geometries the active tree vertices already describe the bounding box. * We only have to reorder them. */ bounds[0] = active_tree_vertices[0]; bounds[1] = active_tree_vertices[3]; 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 8aec8cd138..18d062c3c2 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx @@ -33,6 +33,9 @@ #include #include +/** + * Zero geometry which maps every point to zero. Only meant for debugging purposes. + */ struct t8_geometry_zero: public t8_geometry { public: @@ -46,7 +49,7 @@ 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. + * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. */ bool t8_geom_tree_negative_volume () const override @@ -54,7 +57,7 @@ struct t8_geometry_zero: public t8_geometry return 0; }; - /** The destructor. + /** The destructor. * Clears the allocated memory. */ virtual ~t8_geometry_zero (); diff --git a/src/t8_geometry/t8_geometry_with_vertices.hxx b/src/t8_geometry/t8_geometry_with_vertices.hxx index 471d0b4f9c..7a1b6d0058 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.hxx +++ b/src/t8_geometry/t8_geometry_with_vertices.hxx @@ -21,7 +21,7 @@ */ /** \file t8_geometry_with_vertices.hxx - * Implements the inherited struct t8_geometry_with_vertices, which can be + * Implements the inherited struct t8_geometry_with_vertices, which can be * used for geometries that use vertex coordinate information of the cmesh. */ @@ -36,10 +36,20 @@ T8_EXTERN_C_BEGIN (); +/** + * Base class for vertex-based geometries. This class implements + * member variables storing tree vertex information and updates them before + * each member function call. Derived classes should not completely overwrite + * the \ref t8_geom_load_tree_data function since this function takes care + * of the updates. Instead the derived classes \ref t8_geom_load_tree_data + * function should also call the function of this base class. + */ struct t8_geometry_with_vertices: public t8_geometry { public: - /* Basic constructor that sets the name. */ + /** Basic constructor that sets the name. + * \param [in] name The name of the geometry. Used to distinct the geometry from other geometries. + */ t8_geometry_with_vertices (std::string name): t8_geometry (name) { active_tree_vertices = NULL; @@ -77,7 +87,7 @@ struct t8_geometry_with_vertices: 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. + * \return True (non-zero) if the currently loaded tree has a negative volume. 0 otherwise. */ virtual bool t8_geom_tree_negative_volume () const; @@ -93,7 +103,7 @@ struct t8_geometry_with_vertices: public t8_geometry }; protected: - const double* active_tree_vertices; /*< The vertices of the currently active tree. */ + const double* active_tree_vertices; /**< The vertices of the currently active tree. */ }; T8_EXTERN_C_END (); diff --git a/src/t8_mat.h b/src/t8_mat.h index d598254c54..8a042a10de 100644 --- a/src/t8_mat.h +++ b/src/t8_mat.h @@ -114,7 +114,7 @@ t8_mat_mult_vec (const double mat[3][3], const double a[3], double b[3]) /** Apply matrix-matrix multiplication: C = A*B. * \param [in] A 3x3-matrix. * \param [in] B 3x3-matrix. - * \param [int,out] C 3x3-matrix. + * \param [in,out] C 3x3-matrix. */ static inline void t8_mat_mult_mat (const double A[3][3], const double B[3][3], double C[3][3]) diff --git a/src/t8_netcdf.h b/src/t8_netcdf.h index e367f2dfca..a536f87404 100644 --- a/src/t8_netcdf.h +++ b/src/t8_netcdf.h @@ -47,14 +47,20 @@ typedef enum t8_netcdf_variable_type { T8_NETCDF_DOUBLE = 2 } t8_netcdf_variable_type_t; -/* Struct for elementwise data variable for a NetCDF file */ +/** Struct for elementwise data variable for a NetCDF file */ typedef struct { + /** short name of the variable*/ const char *variable_name; + /** long name of the variable*/ const char *variable_long_name; + /** unit of the variable*/ const char *variable_units; + /** datatype of the variable*/ t8_netcdf_variable_type_t datatype; + /** The unique identifier netCDF assigns to this variable once it is defined in the file*/ int var_user_dimid; + /** user data for the variable*/ sc_array_t *var_user_data; } t8_netcdf_variable_t; @@ -64,7 +70,6 @@ typedef struct * \param [in] var_long_name A string describing the variable a bit more and what it is about. * \param [in] var_unit The units in which the data is provided. * \param [in] var_data A sc_array_t holding the elementwise data of the variable. - * \param [in] num_extern_netcdf_vars The number of extern user-defined variables which hold elementwise data (if none, set it to 0). */ t8_netcdf_variable_t * t8_netcdf_create_var (t8_netcdf_variable_type_t var_type, const char *var_name, const char *var_long_name, @@ -75,7 +80,6 @@ t8_netcdf_create_var (t8_netcdf_variable_type_t var_type, const char *var_name, * \param [in] var_long_name A string describing the variable a bit more and what it is about. * \param [in] var_unit The units in which the data is provided. * \param [in] var_data A sc_array_t holding the elementwise data of the variable. - * \param [in] num_extern_netcdf_vars The number of extern user-defined variables which hold elementwise data (if none, set it to 0). */ t8_netcdf_variable_t * t8_netcdf_create_integer_var (const char *var_name, const char *var_long_name, const char *var_unit, @@ -86,7 +90,6 @@ t8_netcdf_create_integer_var (const char *var_name, const char *var_long_name, c * \param [in] var_long_name A string describing the variable a bit more and what it is about. * \param [in] var_unit The units in which the data is provided. * \param [in] var_data A sc_array_t holding the elementwise data of the variable. - * \param [in] num_extern_netcdf_vars The number of extern user-defined variables which hold elementwise data (if none, set it to 0). */ t8_netcdf_variable_t * t8_netcdf_create_double_var (const char *var_name, const char *var_long_name, const char *var_unit, 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 7e1b87cc3c..72955c45ae 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 @@ -33,12 +33,12 @@ #include #include -/* Macro to check whether a pointer (VAR) to a base class, comes from an +/** Macro to check whether a pointer (VAR) to a base class, comes from an * implementation of a child class (TYPE). */ #define T8_COMMON_IS_TYPE(VAR, TYPE) ((dynamic_cast (VAR)) != NULL) /** This class independent function assumes an sc_mempool_t as context. - * It is suitable as the element_new callback in \ref t8_eclass_scheme. + * It is suitable as the element_new callback in \ref t8_default_scheme_common.. * We assume that the mempool has been created with the correct element size. * \param [in,out] scheme_context An element is allocated in this sc_mempool_t. * \param [in] length Non-negative number of elements to allocate. @@ -57,7 +57,7 @@ t8_default_mempool_alloc (sc_mempool_t *scheme_context, int length, t8_element_t } /** This class independent function assumes an sc_mempool_t as context. - * It is suitable as the element_destroy callback in \ref t8_default_common. + * It is suitable as the element_destroy callback in \ref t8_default_scheme_common. * We assume that the mempool has been created with the correct element size. * \param [in,out] scheme_context An element is returned to this sc_mempool_t. * \param [in] length Non-negative number of elements to destroy. @@ -84,6 +84,9 @@ count_leaves_from_level (const int element_level, const int refinement_level, co return element_level > refinement_level ? 0 : (1ULL << (dimension * (refinement_level - element_level))); } +/** Common interface of the default schemes for each element shape. + * \tparam TUnderlyingEclassScheme The default scheme class of the element shape. + */ template class t8_default_scheme_common: public t8_crtp_operator { private: @@ -217,6 +220,14 @@ class t8_default_scheme_common: public t8_crtp_operatorunderlying ().element_get_level (t); + const int element_level = this->underlying ().element_get_level (element); const int dim = t8_eclass_to_dimension[eclass]; return count_leaves_from_level (element_level, level, dim); } @@ -298,6 +309,12 @@ class t8_default_scheme_common: public t8_crtp_operator { public: /** Constructor which calls the specialized constructor for the base. */ @@ -56,9 +57,9 @@ class t8_default_scheme_hex: public t8_default_scheme_common int -t8_dline_get_level (const t8_dline_t *l) +t8_dline_get_level (const t8_dline_t *line) { - return l->level; + return line->level; } void -t8_dline_copy (const t8_dline_t *l, t8_dline_t *dest) +t8_dline_copy (const t8_dline_t *line, t8_dline_t *dest) { - memcpy (dest, l, sizeof (t8_dline_t)); + memcpy (dest, line, sizeof (t8_dline_t)); } int -t8_dline_compare (const t8_dline_t *l1, const t8_dline_t *l2) +t8_dline_compare (const t8_dline_t *line1, const t8_dline_t *line2) { t8_linearidx_t id1, id2; /* Compute the linear ids of the elements */ - id1 = l1->x; - id2 = l2->x; + id1 = line1->x; + id2 = line2->x; if (id1 == id2) { /* The linear ids are the same, the line with the smaller level * is considered smaller */ - return l1->level - l2->level; + return line1->level - line2->level; } /* return negative if id1 < id2, zero if id1 = id2, positive if id1 > id2 */ return id1 < id2 ? -1 : id1 != id2; } int -t8_dline_equal (const t8_dline_t *l1, const t8_dline_t *l2) +t8_dline_equal (const t8_dline_t *line1, const t8_dline_t *line2) { - return (l1->level == l2->level && l1->x == l2->x); + return (line1->level == line2->level && line1->x == line2->x); } void -t8_dline_parent (const t8_dline_t *l, t8_dline_t *parent) +t8_dline_parent (const t8_dline_t *line, t8_dline_t *parent) { t8_dline_coord_t h; - T8_ASSERT (l->level > 0); + T8_ASSERT (line->level > 0); /* Get the length of l */ - h = T8_DLINE_LEN (l->level); + h = T8_DLINE_LEN (line->level); /* Set coordinates of parent */ - parent->x = l->x & ~h; + parent->x = line->x & ~h; /* Set the parent's level */ - parent->level = l->level - 1; + parent->level = line->level - 1; } void -t8_dline_ancestor (const t8_dline_t *l, int level, t8_dline_t *ancestor) +t8_dline_ancestor (const t8_dline_t *line, int level, t8_dline_t *ancestor) { /* Compute the new x-coordinate by setting all bits in positions * greater than level to zero. */ - ancestor->x = l->x & ~(T8_DLINE_LEN (level) - 1); + ancestor->x = line->x & ~(T8_DLINE_LEN (level) - 1); /* set the level */ ancestor->level = level; } void -t8_dline_child (const t8_dline_t *l, int childid, t8_dline_t *child) +t8_dline_child (const t8_dline_t *line, int childid, t8_dline_t *child) { t8_dline_coord_t h; - T8_ASSERT (l->level < T8_DLINE_MAXLEVEL); + T8_ASSERT (line->level < T8_DLINE_MAXLEVEL); T8_ASSERT (childid == 0 || childid == 1); /* Compute the length of the child */ - h = T8_DLINE_LEN (l->level + 1); + h = T8_DLINE_LEN (line->level + 1); /* If childid = 0 then the children x coord is the same as l's, * if childid = 1 then it is x + h. */ - child->x = l->x + (childid == 0 ? 0 : h); + child->x = line->x + (childid == 0 ? 0 : h); /* The children level */ - child->level = l->level + 1; + child->level = line->level + 1; } void -t8_dline_face_neighbour (const t8_dline_t *l, t8_dline_t *neigh, int face, int *dual_face) +t8_dline_face_neighbour (const t8_dline_t *line, t8_dline_t *neigh, int face, int *dual_face) { T8_ASSERT (0 <= face && face < T8_DLINE_FACES); - neigh->level = l->level; + neigh->level = line->level; switch (face) { case 0: - neigh->x = l->x - T8_DLINE_LEN (l->level); + neigh->x = line->x - T8_DLINE_LEN (line->level); break; case 1: - neigh->x = l->x + T8_DLINE_LEN (l->level); + neigh->x = line->x + T8_DLINE_LEN (line->level); break; } if (dual_face != NULL) { @@ -122,24 +122,24 @@ t8_dline_face_neighbour (const t8_dline_t *l, t8_dline_t *neigh, int face, int * } void -t8_dline_nearest_common_ancestor (const t8_dline_t *t1, const t8_dline_t *t2, t8_dline_t *r) +t8_dline_nearest_common_ancestor (const t8_dline_t *line1, const t8_dline_t *line2, t8_dline_t *nca) { int level; t8_dline_coord_t exclusive_or; /* At first we compute the first level at which the two x-coordinates differ */ - exclusive_or = t1->x ^ t2->x; + exclusive_or = line1->x ^ line2->x; level = SC_LOG2_32 (exclusive_or) + 1; T8_ASSERT (level <= T8_DLINE_MAXLEVEL); /* Compute the new x-coordinate by zeroing out all higher levels */ - r->x = t1->x & ~((1 << level) - 1); - r->level = SC_MIN (T8_DLINE_MAXLEVEL - level, SC_MIN (t1->level, t2->level)); + nca->x = line1->x & ~((1 << level) - 1); + nca->level = SC_MIN (T8_DLINE_MAXLEVEL - level, SC_MIN (line1->level, line2->level)); } int -t8_dline_ancestor_id (const t8_dline_t *l, int level) +t8_dline_ancestor_id (const t8_dline_t *line, int level) { t8_dline_coord_t h; @@ -153,44 +153,44 @@ t8_dline_ancestor_id (const t8_dline_t *l, int level) /* If the h bit is set in l's x coordinate, then acestor id is 1 * else 0. */ - return (l->x & h) != 0; + return (line->x & h) != 0; } int -t8_dline_face_parent_face (const t8_dline_t *l, int face) +t8_dline_face_parent_face (const t8_dline_t *line, int face) { T8_ASSERT (0 <= face && face < T8_DLINE_FACES); - if (l->level == 0) { + if (line->level == 0) { return face; } /* If the child id is 0 and face is 0, then the parent's face is 0. * If the child id is 1 and face is 1, then the parent's face is 1. * In the other cases, this is an inner face. */ - return t8_dline_child_id (l) == face ? face : -1; + return t8_dline_child_id (line) == face ? face : -1; } int -t8_dline_child_id (const t8_dline_t *elem) +t8_dline_child_id (const t8_dline_t *line) { - T8_ASSERT (elem->level < T8_DLINE_MAXLEVEL); + T8_ASSERT (line->level < T8_DLINE_MAXLEVEL); /* bitshifting the Levelbit to first position & check if it is 1 or 0 */ - return ((elem->x >> (T8_DLINE_MAXLEVEL - elem->level)) & 1); + return ((line->x >> (T8_DLINE_MAXLEVEL - line->level)) & 1); } void -t8_dline_childrenpv (const t8_dline_t *elem, t8_dline_t *c[T8_DLINE_CHILDREN]) +t8_dline_childrenpv (const t8_dline_t *line, t8_dline_t *c[T8_DLINE_CHILDREN]) { - const int8_t level = elem->level; + const int8_t level = line->level; - T8_ASSERT (elem->level < T8_DLINE_MAXLEVEL); + T8_ASSERT (line->level < T8_DLINE_MAXLEVEL); /* Set the Level, Level increases */ c[0]->level = level + 1; c[1]->level = level + 1; /* Set the coordinates of the children */ - c[0]->x = elem->x; - c[1]->x = elem->x + T8_DLINE_LEN (c[1]->level); + c[0]->x = line->x; + c[1]->x = line->x + T8_DLINE_LEN (c[1]->level); } int @@ -225,7 +225,7 @@ t8_dline_is_familypv (const t8_dline_t *f[]) } int -t8_dline_is_root_boundary (const t8_dline_t *p, int face) +t8_dline_is_root_boundary (const t8_dline_t *line, int face) { /* A line is at the boundary if and only if * face = 0 and x = 0 @@ -233,43 +233,43 @@ t8_dline_is_root_boundary (const t8_dline_t *p, int face) * face = 1 and x = Maximum x - length of line */ if (face == 0) { - return p->x == 0; + return line->x == 0; } else { - return p->x == T8_DLINE_ROOT_LEN - T8_DLINE_LEN (p->level); + return line->x == T8_DLINE_ROOT_LEN - T8_DLINE_LEN (line->level); } } int -t8_dline_is_inside_root (const t8_dline_t *l) +t8_dline_is_inside_root (const t8_dline_t *line) { - return (l->x >= 0 && l->x < T8_DLINE_ROOT_LEN); + return (line->x >= 0 && line->x < T8_DLINE_ROOT_LEN); } void -t8_dline_init_linear_id (t8_dline_t *l, int level, t8_linearidx_t id) +t8_dline_init_linear_id (t8_dline_t *line, int level, t8_linearidx_t id) { T8_ASSERT (0 <= level && level <= T8_DLINE_MAXLEVEL); T8_ASSERT (id < ((t8_linearidx_t) 1) << level); /* Set the level */ - l->level = level; + line->level = level; /* Set the new x coordinate */ - l->x = id << (T8_DLINE_MAXLEVEL - level); + line->x = id << (T8_DLINE_MAXLEVEL - level); } void -t8_dline_successor (const t8_dline_t *l, t8_dline_t *succ, int level) +t8_dline_successor (const t8_dline_t *line, t8_dline_t *succ, int level) { t8_dline_coord_t h = 0; - T8_ASSERT (1 <= level && level <= l->level); - T8_ASSERT (l->x < T8_DLINE_ROOT_LEN - T8_DLINE_LEN (level)); + T8_ASSERT (1 <= level && level <= line->level); + T8_ASSERT (line->x < T8_DLINE_ROOT_LEN - T8_DLINE_LEN (level)); /* To compute the successor we zero out all bits in places bigger * than level and then we add the length of a line of level. */ h = T8_DLINE_LEN (level) - 1; - succ->x = l->x & ~h; + succ->x = line->x & ~h; succ->x += T8_DLINE_LEN (level); succ->level = level; } @@ -304,87 +304,87 @@ t8_dline_transform_face (const t8_dline_t *line1, t8_dline_t *line2, int orienta } void -t8_dline_first_descendant (const t8_dline_t *l, t8_dline_t *s, int level) +t8_dline_first_descendant (const t8_dline_t *line, t8_dline_t *desc, int level) { - T8_ASSERT (level >= l->level && level <= T8_DLINE_MAXLEVEL); + T8_ASSERT (level >= line->level && level <= T8_DLINE_MAXLEVEL); - s->level = level; - s->x = l->x; + desc->level = level; + desc->x = line->x; } void -t8_dline_last_descendant (const t8_dline_t *l, t8_dline_t *s, int level) +t8_dline_last_descendant (const t8_dline_t *line, t8_dline_t *desc, int level) { - T8_ASSERT (level >= l->level && level <= T8_DLINE_MAXLEVEL); + T8_ASSERT (level >= line->level && level <= T8_DLINE_MAXLEVEL); - s->level = level; - s->x = l->x + T8_DLINE_LEN (l->level) - T8_DLINE_LEN (level); + desc->level = level; + desc->x = line->x + T8_DLINE_LEN (line->level) - T8_DLINE_LEN (level); } void -t8_dline_vertex_integer_coords (const t8_dline_t *elem, const int vertex, int coords[]) +t8_dline_vertex_integer_coords (const t8_dline_t *line, const int vertex, int coords[]) { T8_ASSERT (vertex == 0 || vertex == 1); if (vertex == 0) { - coords[0] = elem->x; + coords[0] = line->x; } else if (vertex == 1) { - coords[0] = elem->x + T8_DLINE_LEN (elem->level); + coords[0] = line->x + T8_DLINE_LEN (line->level); } } void -t8_dline_vertex_ref_coords (const t8_dline_t *elem, const int vertex, double coordinates[1]) +t8_dline_vertex_ref_coords (const t8_dline_t *line, const int vertex, double coordinates[1]) { /* we need to set and initial value to prevent compiler warning. */ int coords_int = -1; T8_ASSERT (vertex == 0 || vertex == 1); /* Compute integer coordinates and divide by root length. */ - t8_dline_vertex_integer_coords (elem, vertex, &coords_int); + t8_dline_vertex_integer_coords (line, vertex, &coords_int); coordinates[0] = coords_int / (double) T8_DLINE_ROOT_LEN; } void -t8_dline_compute_reference_coords (const t8_dline_t *elem, const double *ref_coords, const size_t num_coords, +t8_dline_compute_reference_coords (const t8_dline_t *line, const double *ref_coords, const size_t num_coords, const size_t skip_coords, double *out_coords) { - T8_ASSERT (t8_dline_is_valid (elem)); + T8_ASSERT (t8_dline_is_valid (line)); for (size_t coord = 0; coord < num_coords; ++coord) { const size_t offset = coord * (1 + skip_coords); const size_t offset_3d = coord * 3; - out_coords[offset] = elem->x; - out_coords[offset] += T8_DLINE_LEN (elem->level) * ref_coords[offset_3d]; + out_coords[offset] = line->x; + out_coords[offset] += T8_DLINE_LEN (line->level) * ref_coords[offset_3d]; out_coords[offset] /= (double) T8_DLINE_ROOT_LEN; } } t8_linearidx_t -t8_dline_linear_id (const t8_dline_t *elem, int level) +t8_dline_linear_id (const t8_dline_t *line, int level) { t8_linearidx_t id; T8_ASSERT (level <= T8_DLINE_MAXLEVEL && level >= 0); /* this preserves the high bits from negative numbers */ - id = elem->x >> (T8_DLINE_MAXLEVEL - level); + id = line->x >> (T8_DLINE_MAXLEVEL - level); return id; } int -t8_dline_is_valid (const t8_dline_t *l) +t8_dline_is_valid (const t8_dline_t *line) { t8_dline_coord_t max_coord; max_coord = ((int64_t) 2 * T8_DLINE_ROOT_LEN) - 1; /* A line is valid if its level and its x coordinates are in the * correct bounds of the root three and its left and right neighbor */ - return 0 <= l->level && l->level <= T8_DLINE_MAXLEVEL && -T8_DLINE_ROOT_LEN <= l->x && l->x <= max_coord; + return 0 <= line->level && line->level <= T8_DLINE_MAXLEVEL && -T8_DLINE_ROOT_LEN <= line->x && line->x <= max_coord; } void -t8_dline_init (t8_dline_t *l) +t8_dline_init (t8_dline_t *line) { - l->level = l->x = 0; + line->level = line->x = 0; } diff --git a/src/t8_schemes/t8_default/t8_default_line/t8_dline_bits.h b/src/t8_schemes/t8_default/t8_default_line/t8_dline_bits.h index 5dc4f205fb..cfbc3ba67b 100644 --- a/src/t8_schemes/t8_default/t8_default_line/t8_dline_bits.h +++ b/src/t8_schemes/t8_default/t8_default_line/t8_dline_bits.h @@ -34,119 +34,119 @@ T8_EXTERN_C_BEGIN (); /** Compute the level of a line. - * \param [in] l Line whose level is computed. - * \return The level of \a l. + * \param [in] line Line whose level is computed. + * \return The level of \a line. */ int -t8_dline_get_level (const t8_dline_t *l); +t8_dline_get_level (const t8_dline_t *line); /** Copy all values from one line to another. - * \param [in] l The line to be copied. + * \param [in] line The line to be copied. * \param [in,out] dest Existing line whose data will be filled with the data - * of \a l. + * of \a line. */ void -t8_dline_copy (const t8_dline_t *l, t8_dline_t *dest); +t8_dline_copy (const t8_dline_t *line, t8_dline_t *dest); -/** Compare two elements. returns negative if l1 < l2, zero if l1 equals l2 - * and positive if l1 > l2. - * If l2 is a copy of l1 then the elements are equal. +/** Compare two elements. returns negative if line1 < line2, zero if line1 equals line2 + * and positive if line1 > line2. + * If line2 is a copy of line1 then the elements are equal. */ int -t8_dline_compare (const t8_dline_t *l1, const t8_dline_t *l2); +t8_dline_compare (const t8_dline_t *line1, const t8_dline_t *line2); /** Check if two elements are equal. -* \param [in] elem1 The first element. -* \param [in] elem2 The second element. +* \param [in] line1 The first element. +* \param [in] line2 The second element. * \return 1 if the elements are equal, 0 if they are not equal */ int -t8_dline_equal (const t8_dline_t *elem1, const t8_dline_t *elem2); +t8_dline_equal (const t8_dline_t *line1, const t8_dline_t *line2); /** Compute the parent of a line. - * \param [in] l The input line. + * \param [in] line The input line. * \param [in,out] parent Existing line whose data will be filled with the parent - * data of \a l. + * data of \a line. */ void -t8_dline_parent (const t8_dline_t *l, t8_dline_t *parent); +t8_dline_parent (const t8_dline_t *line, t8_dline_t *parent); /** Compute the ancestor of a line at a given level. - * \param [in] t Input line. - * \param [in] level A smaller level than \a t. + * \param [in] line Input line. + * \param [in] level A smaller level than \a line. * \param [in,out] ancestor Existing line whose data will - * be filled with the data of \a t's ancestor on + * be filled with the data of \a line's ancestor on * level \a level. - * \note The line \a ancestor may point to the same line as \a t. + * \note The line \a ancestor may point to the same line as \a line. */ void -t8_dline_ancestor (const t8_dline_t *t, int level, t8_dline_t *ancestor); +t8_dline_ancestor (const t8_dline_t *line, int level, t8_dline_t *ancestor); /** Compute the childid-th child in Morton order of a line. - * \param [in] l Input Line. + * \param [in] line Input Line. * \param [in] childid The id of the child, 0 or 1, in Morton order. * \param [in,out] child Existing Line whose data will be filled * with the date of l's childid-th child. */ void -t8_dline_child (const t8_dline_t *l, int childid, t8_dline_t *child); +t8_dline_child (const t8_dline_t *line, int childid, t8_dline_t *child); /** Compute the face neighbor of a line. - * \param [in] l Input line. + * \param [in] line Input line. * \param [in,out] neigh Existing line whose data will be filled. * \param [in] face The face across which to generate the neighbor. * \param [out] dual_face If not NULL, the face number as seen from \a neigh * is stored. - * \note \a l may point to the same line as \a n. + * \note \a line may point to the same line as \a neigh. */ void -t8_dline_face_neighbour (const t8_dline_t *l, t8_dline_t *neigh, int face, int *dual_face); +t8_dline_face_neighbour (const t8_dline_t *line, t8_dline_t *neigh, int face, int *dual_face); /** Computes the nearest common ancestor of two lines in the same tree. - * \param [in] l1 First input line. - * \param [in] l2 Second input line. - * \param [in,out] r Existing line whose data will be filled. - * \note \a l1, \a l2, \a r may point to the same line. + * \param [in] line1 First input line. + * \param [in] line2 Second input line. + * \param [in,out] nca Existing line whose data will be filled. + * \note \a line1, \a line2, \a nca may point to the same line. */ void -t8_dline_nearest_common_ancestor (const t8_dline_t *t1, const t8_dline_t *t2, t8_dline_t *r); +t8_dline_nearest_common_ancestor (const t8_dline_t *line1, const t8_dline_t *line2, t8_dline_t *nca); /** Compute the position of the ancestor of this child at level \a level within * its siblings. - * \param [in] l line to be considered. + * \param [in] line line to be considered. * \param [in] level level to be considered. * \return Returns its child id 0 or 1. */ int -t8_dline_ancestor_id (const t8_dline_t *l, int level); +t8_dline_ancestor_id (const t8_dline_t *line, int level); /** Given a face of a line return the face number * of the parent of the line that matches the line's face. Or return -1 if * no face of the parent matches the face. - * \param [in] l The line. + * \param [in] line The line. * \param [in] face The number of the face. - * \return If \a face of \a l is also a face of \a l's parent, + * \return If \a face of \a line is also a face of \a line's parent, * the face number of this face. Otherwise -1. */ int -t8_dline_face_parent_face (const t8_dline_t *l, int face); +t8_dline_face_parent_face (const t8_dline_t *line, int face); /** Compute the position of the ancestor of this child at level \a level within * its siblings. - * \param [in] t line to be considered. + * \param [in] line line to be considered. * \return Returns its child id in 0,1 */ int -t8_dline_child_id (const t8_dline_t *t); +t8_dline_child_id (const t8_dline_t *line); /** Compute the 2 children of a line, array version. - * \param [in] t Input line. + * \param [in] line Input line. * \param [in,out] c Pointers to the 2 computed children in Morton order. * t may point to the same quadrant as c[0]. */ void -t8_dline_childrenpv (const t8_dline_t *t, t8_dline_t *c[T8_DLINE_CHILDREN]); +t8_dline_childrenpv (const t8_dline_t *line, t8_dline_t *c[T8_DLINE_CHILDREN]); /** Check whether a collection of two lines is a family in Morton order. * \param [in] f An array of two lines. @@ -156,46 +156,46 @@ int t8_dline_is_familypv (const t8_dline_t *f[]); /** Compute whether a given line shares a given face with its root tree. - * \param [in] p The input line. - * \param [in] face A face of \a p. + * \param [in] line The input line. + * \param [in] face A face of \a line. * \return True if \a face is a subface of the line's root element. */ int -t8_dline_is_root_boundary (const t8_dline_t *p, int face); +t8_dline_is_root_boundary (const t8_dline_t *line, int face); /** Test if a line lies inside of the root line, * that is the line of level 0, anchor node (0,0) - * \param [in] l Input line. - * \return true If \a l lies inside of the root line. + * \param [in] line Input line. + * \return true If \a line lies inside of the root line. */ int -t8_dline_is_inside_root (const t8_dline_t *l); +t8_dline_is_inside_root (const t8_dline_t *line); /** Initialize a line as the line with a given global id in a uniform * refinement of a given level. * - * \param [in,out] l Existing line whose data will be filled. + * \param [in,out] line Existing line whose data will be filled. * \param [in] id Index to be considered. * \param [in] level level of uniform grid to be considered. */ void -t8_dline_init_linear_id (t8_dline_t *l, int level, t8_linearidx_t id); +t8_dline_init_linear_id (t8_dline_t *line, int level, t8_linearidx_t id); /** Computes the successor of a line in a uniform grid of level \a level. - * \param [in] l line whose id will be computed. - * \param [in,out] s Existing line whose data will be filled with the - * data of \a l's successor on level \a level. + * \param [in] line line whose id will be computed. + * \param [in,out] succ Existing line whose data will be filled with the + * data of \a line's successor on level \a level. * \param [in] level level of uniform grid to be considered. */ void -t8_dline_successor (const t8_dline_t *l, t8_dline_t *succ, int level); +t8_dline_successor (const t8_dline_t *line, t8_dline_t *succ, int level); /** Suppose we have two trees that share a common face f. * Given a Line e that is a subface of f in one of the trees * and given the orientation of the tree connection, construct the face * Line of the respective tree neighbor that logically coincides with e * but lies in the coordinate system of the neighbor tree. - * \param [in] elem1 The face element. - * \param [in,out] elem2 On return the face element \a elem1 with respect + * \param [in] line1 The face element. + * \param [in,out] line2 On return the face element \a line1 with respect * to the coordinate system of the other tree. * \param [in] orientation The orientation of the tree-tree connection. * 0 if vertex 0 of face 0 coincides with vertex 0 of face 1. @@ -217,47 +217,47 @@ t8_dline_extrude_face (const t8_dvertex_t *face, int root_face, t8_dline_t *line /** Compute the first descendant of a line at a given level. This is the descendant of * the line in a uniform level refinement that has the smallest id. - * \param [in] l Line whose descendant is computed. - * \param [out] s Existing line whose data will be filled with the data - * of \a l's first descendant on level \a level. - * \param [in] level The refinement level. Must be greater than \a l's refinement + * \param [in] line Line whose descendant is computed. + * \param [out] desc Existing line whose data will be filled with the data + * of \a line's first descendant on level \a level. + * \param [in] level The refinement level. Must be greater than \a line's refinement * level. */ void -t8_dline_first_descendant (const t8_dline_t *l, t8_dline_t *s, int level); +t8_dline_first_descendant (const t8_dline_t *line, t8_dline_t *desc, int level); /** Compute the last descendant of a line at a given level. This is the descendant of * the line in a uniform level refinement that has the largest id. - * \param [in] l Line whose descendant is computed. - * \param [out] s Existing line whose data will be filled with the data - * of \a l's last descendant on level \a level. - * \param [in] level The refinement level. Must be greater than \a l's refinement + * \param [in] line Line whose descendant is computed. + * \param [out] desc Existing line whose data will be filled with the data + * of \a line's last descendant on level \a level. + * \param [in] level The refinement level. Must be greater than \a line's refinement * level. */ void -t8_dline_last_descendant (const t8_dline_t *l, t8_dline_t *s, int level); +t8_dline_last_descendant (const t8_dline_t *line, t8_dline_t *desc, int level); /** Compute the first or second vertex of a line. - * \param [in] elem Line whose vertex is computed. - * \param [in] vertex The number of the vertex of \a elem + * \param [in] line Line whose vertex is computed. + * \param [in] vertex The number of the vertex of \a line * \param [out] coords The coordinates of the computed vertex */ void -t8_dline_vertex_integer_coords (const t8_dline_t *elem, const int vertex, int coords[]); +t8_dline_vertex_integer_coords (const t8_dline_t *line, const int vertex, int coords[]); /** Compute the coordinates of a vertex of a line when the * tree (level 0 line) is embedded in [0,1]^1. - * \param [in] t Input line. + * \param [in] line Input line. * \param [in] vertex The number of the vertex. * \param [out] coordinates An array of 1 double that * will be filled with the reference coordinates of the vertex. */ void -t8_dline_vertex_ref_coords (const t8_dline_t *elem, const int vertex, double coordinates[1]); +t8_dline_vertex_ref_coords (const t8_dline_t *line, const int vertex, double coordinates[1]); /** Convert points in the reference space of a line element to points in the * reference space of the tree (level 0) embedded in [0,1]^1. - * \param [in] elem Input line. + * \param [in] line Input line. * \param [in] ref_coords The reference coordinates in the line * (\a num_coords times \f$ [0,1]^1 \f$) * \param [in] num_coords Number of coordinates to evaluate @@ -270,30 +270,31 @@ t8_dline_vertex_ref_coords (const t8_dline_t *elem, const int vertex, double coo * of the points on the line. */ void -t8_dline_compute_reference_coords (const t8_dline_t *elem, const double *ref_coords, const size_t num_coords, +t8_dline_compute_reference_coords (const t8_dline_t *line, const double *ref_coords, const size_t num_coords, const size_t skip_coords, double *out_coords); /** Computes the linear position of a line in an uniform grid. - * \param [in] line Line whose id will be computed. + * \param [in] line Pointer to a line element whose id will be computed. + * \param [in] level Refinement level of the line element. * \return Returns the linear position of this line on a grid. */ t8_linearidx_t -t8_dline_linear_id (const t8_dline_t *elem, int level); +t8_dline_linear_id (const t8_dline_t *line, int level); /** Query whether all entries of a line are in valid ranges. - * \param [in] l line to be considered. - * \return True, if \a l is a valid line and it is safe to call any - * function in this file on \a l. + * \param [in] line line to be considered. + * \return True, if \a line is a valid line and it is safe to call any + * function in this file on \a line. * False otherwise. */ int -t8_dline_is_valid (const t8_dline_t *l); +t8_dline_is_valid (const t8_dline_t *line); /** Set default values for a line, such that it passes \ref t8_dline_is_valid. - * \param [in] l line to be initialized + * \param [in] line line to be initialized */ void -t8_dline_init (t8_dline_t *l); +t8_dline_init (t8_dline_t *line); T8_EXTERN_C_END (); diff --git a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.cxx b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.cxx index e4c10e29c9..6e3e4bc1f1 100644 --- a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.cxx +++ b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.cxx @@ -397,10 +397,10 @@ t8_default_scheme_prism::element_get_anchor (const t8_element_t *elem, int ancho } void -t8_default_scheme_prism::element_get_vertex_integer_coords (const t8_element_t *elem, int vertex, int coords[]) const +t8_default_scheme_prism::element_get_vertex_integer_coords (const t8_element_t *element, int vertex, int coords[]) const { - T8_ASSERT (element_is_valid (elem)); - t8_dprism_vertex_integer_coords ((const t8_dprism_t *) elem, vertex, coords); + T8_ASSERT (element_is_valid (element)); + t8_dprism_vertex_integer_coords ((const t8_dprism_t *) element, vertex, coords); } void @@ -436,10 +436,10 @@ t8_default_scheme_prism::refines_irregular (void) const #if T8_ENABLE_DEBUG int -t8_default_scheme_prism::element_is_valid (const t8_element_t *elem) const +t8_default_scheme_prism::element_is_valid (const t8_element_t *element) const { - T8_ASSERT (elem != NULL); - return t8_dprism_is_valid ((const t8_dprism_t *) elem); + T8_ASSERT (element != NULL); + return t8_dprism_is_valid ((const t8_dprism_t *) element); } void diff --git a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.hxx b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.hxx index 6032ad25a7..5d920b7771 100644 --- a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.hxx +++ b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism.hxx @@ -58,7 +58,7 @@ class t8_default_scheme_prism: public t8_default_scheme_common level ? 0 : 2 * sc_intpow64 (8, level_diff) - sc_intpow64 (6, level_diff); @@ -383,10 +383,11 @@ t8_default_scheme_pyramid::element_get_anchor (const t8_element_t *elem, int anc } void -t8_default_scheme_pyramid::element_get_vertex_integer_coords (const t8_element_t *t, int vertex, int coords[]) const +t8_default_scheme_pyramid::element_get_vertex_integer_coords (const t8_element_t *element, int vertex, + int coords[]) const { - T8_ASSERT (element_is_valid (t)); - t8_dpyramid_compute_integer_coords ((const t8_dpyramid_t *) t, vertex, coords); + T8_ASSERT (element_is_valid (element)); + t8_dpyramid_compute_integer_coords ((const t8_dpyramid_t *) element, vertex, coords); } void @@ -426,10 +427,10 @@ t8_default_scheme_pyramid::refines_irregular () const #if T8_ENABLE_DEBUG int -t8_default_scheme_pyramid::element_is_valid (const t8_element_t *elem) const +t8_default_scheme_pyramid::element_is_valid (const t8_element_t *element) const { - T8_ASSERT (elem != NULL); - return t8_dpyramid_is_valid ((const t8_dpyramid_t *) elem); + T8_ASSERT (element != NULL); + return t8_dpyramid_is_valid ((const t8_dpyramid_t *) element); } void diff --git a/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid.hxx b/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid.hxx index fc30dd5463..0f220ff51b 100644 --- a/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid.hxx +++ b/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid.hxx @@ -56,7 +56,7 @@ class t8_default_scheme_pyramid: public t8_default_scheme_commonp.user_long = (long) (coord); \ } while (0) +/** Default implementation of the scheme for the quad element class. */ class t8_default_scheme_quad: public t8_default_scheme_common { public: /** Constructor which calls the specialized constructor for the base. */ @@ -94,7 +95,7 @@ class t8_default_scheme_quad: public t8_default_scheme_common { public: /** Constructor which calls the specialized constructor for the base. */ @@ -53,7 +54,7 @@ class t8_default_scheme_tet: public t8_default_scheme_common t2 + * \param [in] tet1 Tetrahedron one. + * \param [in] tet2 Tetrahedron two. + * \return Returns negative if tet1 < tet2, zero if tet1 = tet2, positive if tet1 > tet2 */ int -t8_dtet_compare (const t8_dtet_t *t1, const t8_dtet_t *t2); +t8_dtet_compare (const t8_dtet_t *tet1, const t8_dtet_t *tet2); /** Check if two elements are equal. -* \param [in] elem1 The first element. -* \param [in] elem2 The second element. +* \param [in] tet1 The first element. +* \param [in] tet2 The second element. * \return 1 if the elements are equal, 0 if they are not equal */ int -t8_dtet_equal (const t8_dtet_t *elem1, const t8_dtet_t *elem2); +t8_dtet_equal (const t8_dtet_t *tet1, const t8_dtet_t *tet2); /** Compute the parent of a tetrahedron. - * \param [in] elem Input tetrahedron. - * \param [in,out] parent Existing tetrahedron whose data will be filled with the data of elem's parent. - * \note \a elem may point to the same tetrahedron as \a parent. + * \param [in] tet Input tetrahedron. + * \param [in,out] parent Existing tetrahedron whose data will be filled with the data of \a tet's parent. + * \note \a t may point to the same tetrahedron as \a parent. */ void -t8_dtet_parent (const t8_dtet_t *t, t8_dtet_t *parent); +t8_dtet_parent (const t8_dtet_t *tet, t8_dtet_t *parent); /** Compute the ancestor of a tetrahedron at a given level. - * \param [in] t Input tetrahedron. - * \param [in] level A smaller level than \a t. - * \param [in,out] ancestor Existing tetrahedron whose data will be filled with the data of \a t's ancestor on + * \param [in] tet Input tetrahedron. + * \param [in] level A smaller level than \a tet. + * \param [in,out] ancestor Existing tetrahedron whose data will be filled with the data of \a tet's ancestor on * level \a level. - * \note The tetrahedron \a ancestor may point to the same tetrahedron as \a t. + * \note The tetrahedron \a ancestor may point to the same tetrahedron as \a tet. */ void -t8_dtet_ancestor (const t8_dtet_t *t, int level, t8_dtet_t *ancestor); +t8_dtet_ancestor (const t8_dtet_t *tet, int level, t8_dtet_t *ancestor); /** Compute the childid-th child in Morton order of a tetrahedron t. - * \param [in] t Input tetrahedron. + * \param [in] tet Input tetrahedron. * \param [in,out] childid The id of the child, 0..7 in Bey order. * \param [out] child Existing tetrahedron whose data will be filled with the date of t's childid-th child. */ void -t8_dtet_child (const t8_dtet_t *elem, int childid, t8_dtet_t *child); +t8_dtet_child (const t8_dtet_t *tet, int childid, t8_dtet_t *child); /** Compute the 8 children of a tetrahedron, array version. - * \param [in] t Input tetrahedron. + * \param [in] tet Input tetrahedron. * \param [in,out] c Pointers to the 8 computed children in Morton order. t may point to the same quadrant as c[0]. */ void -t8_dtet_childrenpv (const t8_dtet_t *t, t8_dtet_t *c[T8_DTET_CHILDREN]); +t8_dtet_childrenpv (const t8_dtet_t *tet, t8_dtet_t *c[T8_DTET_CHILDREN]); /** Check whether a collection of eight tetrahedra is a family in Morton order. * \param [in] f An array of eight tetrahedra. @@ -137,31 +137,31 @@ int t8_dtet_is_familypv (const t8_dtet_t *f[]); /** Compute a specific sibling of a tetrahedron. - * \param [in] elem Input tetrahedron. + * \param [in] tet Input tetrahedron. * \param [in,out] sibling Existing tetrahedron whose data will be filled with the data of sibling no. sibling_id of - * elem. + * \a tet. * \param [in] sibid The id of the sibling computed, 0..7 in Bey order. */ void -t8_dtet_sibling (const t8_dtet_t *elem, int sibid, t8_dtet_t *sibling); +t8_dtet_sibling (const t8_dtet_t *tet, int sibid, t8_dtet_t *sibling); /** Compute the face neighbor of a tetrahedron. - * \param [in] t Input tetrahedron. + * \param [in] tet Input tetrahedron. * \param [in] face The face across which to generate the neighbor. - * \param [in,out] n Existing tetrahedron whose data will be filled. - * \note \a t may point to the same tetrahedron as \a n. + * \param [in,out] neigh Existing tetrahedron whose data will be filled. + * \note \a tet may point to the same tetrahedron as \a neigh. */ int -t8_dtet_face_neighbour (const t8_dtet_t *t, int face, t8_dtet_t *n); +t8_dtet_face_neighbour (const t8_dtet_t *tet, int face, t8_dtet_t *neigh); /** Computes the nearest common ancestor of two tetrahedra in the same tree. - * \param [in] t1 First input tetrahedron. - * \param [in] t2 Second input tetrahedron. - * \param [in,out] r Existing tetrahedron whose data will be filled. - * \note \a t1, \a t2, \a r may point to the same tetrahedron. + * \param [in] tet1 First input tetrahedron. + * \param [in] tet2 Second input tetrahedron. + * \param [in,out] nca Existing tetrahedron whose data will be filled. + * \note \a tet1, \a tet2, \a nca may point to the same tetrahedron. */ void -t8_dtet_nearest_common_ancestor (const t8_dtet_t *t1, const t8_dtet_t *t2, t8_dtet_t *r); +t8_dtet_nearest_common_ancestor (const t8_dtet_t *tet1, const t8_dtet_t *tet2, t8_dtet_t *nca); /** Given a tetrahedron and a face of the tetrahedron, compute all children of the tetrahedron that touch the face. * \param [in] tet The tetrahedron. @@ -170,6 +170,7 @@ t8_dtet_nearest_common_ancestor (const t8_dtet_t *t1, const t8_dtet_t *t2, t8_dt * stored. They will be stored in order of their child_id. * \param [in] num_children The number of tetrahedra in \a children. Must match the number of children that touch * \a face. + * \param [in,out] child_indices The indices of the children in \a children. Only filled if this is null previously. */ void t8_dtet_children_at_face (const t8_dtet_t *tet, int face, t8_dtet_t *children[], int num_children, int *child_indices); @@ -186,9 +187,9 @@ t8_dtet_face_child_face (const t8_dtet_t *tet, int face, int face_child); /** Given a face of an tet return the face number of the parent of the tet that matches the tet's face. Or return -1 if * no face of the parent matches the face. - * \param [in] elem The tet. + * \param [in] tet The tet. * \param [in] face Then number of the face. - * \return If \a face of \a elem is also a face of \a elem's parent, the face number of this face. + * \return If \a face of \a tet is also a face of \a tet's parent, the face number of this face. * Otherwise -1. */ int @@ -196,195 +197,220 @@ t8_dtet_face_parent_face (const t8_dtet_t *tet, int face); /** Given a tetrahedron and a face of this tetrahedron. If the face lies on the tree boundary, return the face number * of the tree face. If not the return value is arbitrary. - * \param [in] t The tetrahedron. - * \param [in] face The index of a face of \a t. + * \param [in] tet The tetrahedron. + * \param [in] face The index of a face of \a tet. * \return The index of the tree face that \a face is a subface of, if \a face is on a tree boundary. - * Any arbitrary integer if \a is not at a tree boundary. + * Any arbitrary integer if \a face is not at a tree boundary. * \note For boundary tetrahedra, this function is the inverse of \ref t8_dtet_root_face_to_face. */ int -t8_dtet_tree_face (t8_dtet_t *t, int face); +t8_dtet_tree_face (t8_dtet_t *tet, int face); /** Given a tetrahedron and a face of the root tetrahedron. If the tetrahedron lies on the tree boundary, * return the corresponding face number of the tetrahedron. If not the return value is arbitrary. - * \param [in] t The tetrahedron. - * \param [in] face The index of a face of the root tetrahedron. - * \return The index of the face of \a t that is a subface of \a face, if \a t is on the tree boundary. - * Any arbitrary integer if \a t is not at a tree boundary. + * \param [in] tet The tetrahedron. + * \param [in] root_face The index of a face of the root tetrahedron. + * \return The index of the face of \a tet that is a subface of \a root_face, if \a tet is on the tree boundary. + * Any arbitrary integer if \a tet is not at a tree boundary. * \note For boundary tetrahedra, this function is the inverse of \ref t8_dtet_tree_face. */ int -t8_dtet_root_face_to_face (t8_dtet_t *t, int root_face); +t8_dtet_root_face_to_face (t8_dtet_t *tet, int root_face); /** Test if a tetrahedron lies inside of the root tetrahedron, that is the tetrahedron of level 0, anchor node (0,0,0) * and type 0. - * \param [in] t Input tetrahedron. - * \return true If \a t lies inside of the root tetrahedron. + * \param [in] tet Input tetrahedron. + * \return true If \a tet lies inside of the root tetrahedron. */ int -t8_dtet_is_inside_root (t8_dtet_t *t); +t8_dtet_is_inside_root (t8_dtet_t *tet); /** Compute whether a given tetrahedron shares a given face with its root tree. - * \param [in] t The input tet. - * \param [in] face A face of \a t. + * \param [in] tet The input tet. + * \param [in] face A face of \a tet. * \return True if \a face is a subface of the tet's root element. */ int -t8_dtet_is_root_boundary (const t8_dtet_t *t, int face); +t8_dtet_is_root_boundary (const t8_dtet_t *tet, int face); /** Test if two tetrahedra have the same coordinates, type and level. - * \return true if \a t1 describes the same tetrahedron as \a t2. + * \return true if \a tet1 describes the same tetrahedron as \a tet2. */ int -t8_dtet_is_equal (const t8_dtet_t *t1, const t8_dtet_t *t2); +t8_dtet_is_equal (const t8_dtet_t *tet1, const t8_dtet_t *tet2); /** Test if two tetrahedra are siblings. - * \param [in] t1 First tetrahedron to be tested. - * \param [in] t2 Second tetrahedron to be tested. - * \return true if \a t1 is equal to or a sibling of \a t2. + * \param [in] tet1 First tetrahedron to be tested. + * \param [in] tet2 Second tetrahedron to be tested. + * \return true if \a tet1 is equal to or a sibling of \a tet2. */ int -t8_dtet_is_sibling (const t8_dtet_t *t1, const t8_dtet_t *t2); +t8_dtet_is_sibling (const t8_dtet_t *tet1, const t8_dtet_t *tet2); /** Test if a tetrahedron is the parent of another tetrahedron. - * \param [in] t tetrahedron to be tested. - * \param [in] c Possible child tetrahedron. - * \return true if \a t is the parent of \a c. + * \param [in] tet tetrahedron to be tested. + * \param [in] child Possible child tetrahedron. + * \return true if \a tet is the parent of \a child. */ int -t8_dtet_is_parent (const t8_dtet_t *t, const t8_dtet_t *c); +t8_dtet_is_parent (const t8_dtet_t *tet, const t8_dtet_t *child); /** Test if a tetrahedron is an ancestor of another tetrahedron. - * \param [in] t tetrahedron to be tested. + * \param [in] tet tetrahedron to be tested. * \param [in] c Descendent tetrahedron. - * \return true if \a t is equal to or an ancestor of \a c. + * \return true if \a tet is equal to or an ancestor of \a c. */ int -t8_dtet_is_ancestor (const t8_dtet_t *t, const t8_dtet_t *c); +t8_dtet_is_ancestor (const t8_dtet_t *tet, const t8_dtet_t *c); /** Computes the linear position of a tetrahedron in a uniform grid. - * \param [in] t tetrahedron whose id will be computed. + * \param [in] tet tetrahedron whose id will be computed. * \param [in] level level of uniform grid to be considered. * \return Returns the linear position of this tetrahedron on a grid of level \a level. * \note This id is not the Morton index. */ t8_linearidx_t -t8_dtet_linear_id (const t8_dtet_t *t, int level); +t8_dtet_linear_id (const t8_dtet_t *tet, int level); /** * Same as init_linear_id, but we only consider the subtree. Used for computing the index of a * tetrahedron lying in a pyramid - * \param [in, out] t Existing triangle whose data will be filled + * \param [in, out] tet Existing tet whose data will be filled * \param id Index to be considered * \param start_level The level of the root of the subtree * \param end_level Level of uniform grid to be considered * \param parenttype The type of the parent. */ void -t8_dtet_init_linear_id_with_level (t8_dtet_t *t, t8_linearidx_t id, int start_level, int end_level, +t8_dtet_init_linear_id_with_level (t8_dtet_t *tet, t8_linearidx_t id, int start_level, int end_level, t8_dtet_type_t parenttype); /** Initialize a tetrahedron as the tetrahedron with a given global id in a uniform refinement of a given level. - * \param [in,out] t Existing tetrahedron whose data will be filled. + * \param [in,out] tet Existing tetrahedron whose data will be filled. * \param [in] id Index to be considered. * \param [in] level level of uniform grid to be considered. */ void -t8_dtet_init_linear_id (t8_dtet_t *t, t8_linearidx_t id, int level); +t8_dtet_init_linear_id (t8_dtet_t *tet, t8_linearidx_t id, int level); /** Initialize a tetrahedron as the root tetrahedron (type 0 at level 0) - * \param [in,out] t Existing tetrahedron whose data will be filled. + * \param [in,out] tet Existing tetrahedron whose data will be filled. */ void -t8_dtet_init_root (t8_dtet_t *t); +t8_dtet_init_root (t8_dtet_t *tet); /** Computes the successor of a tetrahedron in a uniform grid of level \a level. - * \param [in] t tetrahedron whose id will be computed. - * \param [out] s Existing tetrahedron whose data will be filled with the + * \param [in] tet tetrahedron whose id will be computed. + * \param [out] succ Existing tetrahedron whose data will be filled with the * data of t's successor on level \a level. * \param [in] level level of uniform grid to be considered. */ void -t8_dtet_successor (const t8_dtet_t *t, t8_dtet_t *s, int level); +t8_dtet_successor (const t8_dtet_t *tet, t8_dtet_t *succ, int level); /** Compute the first descendant of a tetrahedron at a given level. This is the descendant of * the tetrahedron in a uniform maxlevel refinement that has the smaller id. - * \param [in] t tetrahedron whose descendant is computed. - * \param [in] level A given level. Must be greater or equal to \a t's level. + * \param [in] tet tetrahedron whose descendant is computed. + * \param [in] level A given level. Must be greater or equal to \a tet's level. * \param [out] s Existing tetrahedron whose data will be filled with the data * of t's first descendant. */ void -t8_dtet_first_descendant (const t8_dtet_t *t, t8_dtet_t *s, int level); +t8_dtet_first_descendant (const t8_dtet_t *tet, t8_dtet_t *s, int level); /** Compute the last descendant of a tetrahedron at a given level. This is the descendant of - * the tetrahedron in a uniform maxlevel refinement that has the bigges id. - * \param [in] t tetrahedron whose descendant is computed. - * \param [in] level A given level. Must be greater or equal to \a t's level. + * the tetrahedron in a uniform maxlevel refinement that has the biggest id. + * \param [in] tet tetrahedron whose descendant is computed. + * \param [in] level A given level. Must be greater or equal to \a tet's level. * \param [out] s Existing tetrahedron whose data will be filled with the data of t's last descendant. */ void -t8_dtet_last_descendant (const t8_dtet_t *t, t8_dtet_t *s, int level); +t8_dtet_last_descendant (const t8_dtet_t *tet, t8_dtet_t *s, int level); /** Compute the descendant of a tetrahedron in a given corner. - * \param [in] t Tetrahedron whose descendant is computed. + * \param [in] tet Tetrahedron whose descendant is computed. * \param [out] s Existing tetrahedron whose data will be filled with the data of t's descendant in \a corner. * \param [in] corner The corner in which the descendant should lie. - * \param [in] level The refinement level of the descendant. Must be greater or equal to \a t's level. + * \param [in] level The refinement level of the descendant. Must be greater or equal to \a tet's level. */ void -t8_dtet_corner_descendant (const t8_dtet_t *t, t8_dtet_t *s, int corner, int level); +t8_dtet_corner_descendant (const t8_dtet_t *tet, t8_dtet_t *s, int corner, int level); /** Computes the predecessor of a tetrahedron in a uniform grid of level \a level. - * \param [in] t tetrahedron whose id will be computed. + * \param [in] tet tetrahedron whose id will be computed. * \param [in,out] s Existing tetrahedron whose data will be filled with the data of t's predecessor on level \a level. * \param [in] level level of uniform grid to be considered. */ void -t8_dtet_predecessor (const t8_dtet_t *t, t8_dtet_t *s, int level); +t8_dtet_predecessor (const t8_dtet_t *tet, t8_dtet_t *s, int level); /** Compute the position of the ancestor of this child at level \a level within its siblings. - * \param [in] t tetrahedron to be considered. + * \param [in] tet tetrahedron to be considered. * \param [in] level level to be considered. * \return Returns its child id in 0..7 */ int -t8_dtet_ancestor_id (const t8_dtet_t *t, int level); +t8_dtet_ancestor_id (const t8_dtet_t *tet, int level); /** Compute the position of the ancestor of this child at level \a level within its siblings. - * \param [in] t tetrahedron to be considered. + * \param [in] tet tetrahedron to be considered. * \return Returns its child id in 0..7 */ int -t8_dtet_child_id (const t8_dtet_t *t); +t8_dtet_child_id (const t8_dtet_t *tet); /** Return the level of a tetrahedron. - * \param [in] t tetrahedron to be considered. - * \return The level of \a t. + * \param [in] tet tetrahedron to be considered. + * \return The level of \a tet. */ int -t8_dtet_get_level (const t8_dtet_t *t); +t8_dtet_get_level (const t8_dtet_t *tet); /** Query whether all entries of a tet are in valid ranges. - * \param [in] t tet to be considered. - * \return True, if \a t is a valid tet and it is safe to call any function on \a t. False otherwise. + * \param [in] tet tet to be considered. + * \return True, if \a tet is a valid tet and it is safe to call any function on \a tet. False otherwise. */ int -t8_dtet_is_valid (const t8_dtet_t *t); +t8_dtet_is_valid (const t8_dtet_t *tet); /** Set sensible default values for a tet. - * \param [in,out] t A tet. + * \param [in,out] tet A tet. */ void -t8_dtet_init (t8_dtet_t *t); - +t8_dtet_init (t8_dtet_t *tet); + +/** Packs an array of tet elements into contiguous memory. + * Tets are packed as x, y, z coordinates, type and level. + * Compare MPI_Pack function. + * \param [in] elements The element array to be packed. + * \param [in] count Number of elements to be packed. + * \param [out] send_buffer Output buffer. + * \param [in] buffer_size Output buffer size. + * \param [in,out] position Current position in buffer. + * \param [in] comm Communicator. + */ void t8_dtet_element_pack (t8_dtet_t **const elements, const unsigned int count, void *send_buffer, const int buffer_size, int *position, sc_MPI_Comm comm); +/** Returns the upper bound on the amount of space needed to pack \a count elements. + * Compare MPI_Pack_size function. + * \param [in] count Number of packed elements. + * \param [in] comm Communicator. + * \param [out] pack_size Upper bound on size of packed elements. + */ void t8_dtet_element_pack_size (const unsigned int count, sc_MPI_Comm comm, int *pack_size); +/** Unpack a buffer of tet elements into contiguous memory. + * Compare MPI_Unpack function. + * \param [in] recvbuf Buffer to be unpacked. + * \param [in] buffer_size Size of \a recvbuf. + * \param [in,out] position Current position in buffer. + * \param [out] elements Array with the tet elements (output buffer). + * \param [in] count Number of elements to be unpacked. + * \param [in] comm Communicator. + */ void t8_dtet_element_unpack (void *recvbuf, const int buffer_size, int *position, t8_dtet_t **elements, const unsigned int count, sc_MPI_Comm comm); diff --git a/src/t8_schemes/t8_default/t8_default_tet/t8_dtri_to_dtet.h b/src/t8_schemes/t8_default/t8_default_tet/t8_dtri_to_dtet.h index 28009478f5..cbed7944c6 100644 --- a/src/t8_schemes/t8_default/t8_default_tet/t8_dtri_to_dtet.h +++ b/src/t8_schemes/t8_default/t8_default_tet/t8_dtri_to_dtet.h @@ -20,7 +20,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_dtet_to_dtri.h +/** \file t8_dtri_to_dtet.h + * In this file, we redefine macros, types,... of the code for triangles + * to use the default implementation also for tetrahedra in 3D to + * avoid code duplication. */ #ifndef T8_DTRI_TO_DTET_H @@ -30,87 +33,90 @@ T8_EXTERN_C_BEGIN (); +/** Define macro used in the default triangle implementation to check + * if we are in the case where the tri implementation is used for tets. + */ #define T8_DTRI_TO_DTET -/* redefine macros */ -#define T8_DTRI_MAXLEVEL T8_DTET_MAXLEVEL -#define T8_DTRI_ROOT_LEN T8_DTET_ROOT_LEN -#define T8_DTRI_LEN T8_DTET_LEN -#define T8_DTRI_FACES T8_DTET_FACES -#define T8_DTRI_DIM T8_DTET_DIM -#define T8_DTRI_CHILDREN T8_DTET_CHILDREN -#define T8_DTRI_FACES T8_DTET_FACES -#define T8_DTRI_FACE_CHILDREN T8_DTET_FACE_CHILDREN -#define T8_DTRI_CORNERS T8_DTET_CORNERS -#define T8_DTRI_NUM_TYPES T8_DTET_NUM_TYPES +/** Redefine macros. */ +#define T8_DTRI_MAXLEVEL T8_DTET_MAXLEVEL /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_ROOT_LEN T8_DTET_ROOT_LEN /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_LEN T8_DTET_LEN /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_FACES T8_DTET_FACES /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_DIM T8_DTET_DIM /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_CHILDREN T8_DTET_CHILDREN /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_FACES T8_DTET_FACES /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_FACE_CHILDREN T8_DTET_FACE_CHILDREN /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_CORNERS T8_DTET_CORNERS /**< Wrapper of tri macro to tet.*/ +#define T8_DTRI_NUM_TYPES T8_DTET_NUM_TYPES /**< Wrapper of tri macro to tet.*/ -/* redefine types */ -#define t8_dtri_coord_t t8_dtet_coord_t -#define t8_dtri_type_t t8_dtet_type_t -#define t8_dtri_t t8_dtet_t -#define t8_dtri_cube_id_t t8_dtet_cube_id_t +/** Redefine types. */ +#define t8_dtri_coord_t t8_dtet_coord_t /**< Wrapper of tri type to tet.*/ +#define t8_dtri_type_t t8_dtet_type_t /**< Wrapper of tri type to tet.*/ +#define t8_dtri_t t8_dtet_t /**< Wrapper of tri type to tet.*/ +#define t8_dtri_cube_id_t t8_dtet_cube_id_t /**< Wrapper of tri type to tet.*/ -/* external variables */ -#define t8_dtri_cid_type_to_parenttype t8_dtet_cid_type_to_parenttype -#define t8_dtri_type_of_child t8_dtet_type_of_child -#define t8_dtri_type_of_child_morton t8_dtet_type_of_child_morton -#define t8_dtri_index_to_bey_number t8_dtet_index_to_bey_number -#define t8_dtri_beyid_to_vertex t8_dtet_beyid_to_vertex -#define t8_dtri_type_cid_to_beyid t8_dtet_type_cid_to_beyid -#define t8_dtri_type_beyid_to_Iloc t8_dtet_type_beyid_to_Iloc -#define t8_dtri_parenttype_cid_to_Iloc t8_dtet_parenttype_cid_to_Iloc -#define t8_dtri_parenttype_Iloc_to_type t8_dtet_parenttype_Iloc_to_type -#define t8_dtri_parenttype_Iloc_to_cid t8_dtet_parenttype_Iloc_to_cid -#define t8_dtri_type_cid_to_Iloc t8_dtet_type_cid_to_Iloc -#define t8_dtri_face_corner t8_dtet_face_corner +/** External variables. */ +#define t8_dtri_cid_type_to_parenttype t8_dtet_cid_type_to_parenttype /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_type_of_child t8_dtet_type_of_child /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_type_of_child_morton t8_dtet_type_of_child_morton /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_index_to_bey_number t8_dtet_index_to_bey_number /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_beyid_to_vertex t8_dtet_beyid_to_vertex /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_type_cid_to_beyid t8_dtet_type_cid_to_beyid /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_type_beyid_to_Iloc t8_dtet_type_beyid_to_Iloc /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_parenttype_cid_to_Iloc t8_dtet_parenttype_cid_to_Iloc /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_parenttype_Iloc_to_type t8_dtet_parenttype_Iloc_to_type /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_parenttype_Iloc_to_cid t8_dtet_parenttype_Iloc_to_cid /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_type_cid_to_Iloc t8_dtet_type_cid_to_Iloc /**< Wrapper of tri variable to tet.*/ +#define t8_dtri_face_corner t8_dtet_face_corner /**< Wrapper of tri variable to tet.*/ -/* functions in d8_dtri_bits.h */ -#define t8_dtri_is_equal t8_dtet_is_equal -#define t8_dtri_copy t8_dtet_copy -#define t8_dtri_compare t8_dtet_compare -#define t8_dtri_equal t8_dtet_equal -#define t8_dtri_parent t8_dtet_parent -#define t8_dtri_ancestor t8_dtet_ancestor -#define t8_dtri_compute_all_coords t8_dtet_compute_all_coords -#define t8_dtri_compute_integer_coords t8_dtet_compute_integer_coords -#define t8_dtri_compute_vertex_ref_coords t8_dtet_compute_vertex_ref_coords -#define t8_dtri_compute_reference_coords t8_dtet_compute_reference_coords -#define t8_dtri_child t8_dtet_child -#define t8_dtri_childrenpv t8_dtet_childrenpv -#define t8_dtri_is_familypv t8_dtet_is_familypv -#define t8_dtri_sibling t8_dtet_sibling -#define t8_dtri_face_neighbour t8_dtet_face_neighbour -#define t8_dtri_nearest_common_ancestor t8_dtet_nearest_common_ancestor -#define t8_dtri_children_at_face t8_dtet_children_at_face -#define t8_dtri_face_child_face t8_dtet_face_child_face -#define t8_dtri_face_parent_face t8_dtet_face_parent_face -#define t8_dtri_tree_face t8_dtet_tree_face -#define t8_dtri_root_face_to_face t8_dtet_root_face_to_face -#define t8_dtri_is_inside_root t8_dtet_is_inside_root -#define t8_dtri_is_root_boundary t8_dtet_is_root_boundary -#define t8_dtri_is_sibling t8_dtet_is_sibling -#define t8_dtri_is_parent t8_dtet_is_parent -#define t8_dtri_is_ancestor t8_dtet_is_ancestor -#define t8_dtri_linear_id t8_dtet_linear_id -#define t8_dtri_linear_id_corner_desc t8_dtet_linear_id_corner_desc -#define t8_dtri_init_linear_id t8_dtet_init_linear_id -#define t8_dtri_init_root t8_dtet_init_root -#define t8_dtri_successor t8_dtet_successor -#define t8_dtri_first_descendant t8_dtet_first_descendant -#define t8_dtri_last_descendant t8_dtet_last_descendant -#define t8_dtri_corner_descendant t8_dtet_corner_descendant -#define t8_dtri_predecessor t8_dtet_predecessor -#define t8_dtri_ancestor_id t8_dtet_ancestor_id -#define t8_dtri_child_id t8_dtet_child_id -#define t8_dtri_get_level t8_dtet_get_level -#define t8_dtri_is_valid t8_dtet_is_valid -#define t8_dtri_init t8_dtet_init -#define t8_dtri_init_linear_id_with_level t8_dtet_init_linear_id_with_level -#define t8_dtri_linear_id_with_level t8_dtet_linear_id_with_level -#define t8_dtri_debug_print t8_dtet_debug_print -#define t8_dtri_element_pack t8_dtet_element_pack -#define t8_dtri_element_pack_size t8_dtet_element_pack_size -#define t8_dtri_element_unpack t8_dtet_element_unpack +/** Functions in t8_dtri_bits.h. */ +#define t8_dtri_is_equal t8_dtet_is_equal /**< Wrapper of tri function to tet.*/ +#define t8_dtri_copy t8_dtet_copy /**< Wrapper of tri function to tet.*/ +#define t8_dtri_compare t8_dtet_compare /**< Wrapper of tri function to tet.*/ +#define t8_dtri_equal t8_dtet_equal /**< Wrapper of tri function to tet.*/ +#define t8_dtri_parent t8_dtet_parent /**< Wrapper of tri function to tet.*/ +#define t8_dtri_ancestor t8_dtet_ancestor /**< Wrapper of tri function to tet.*/ +#define t8_dtri_compute_all_coords t8_dtet_compute_all_coords /**< Wrapper of tri function to tet.*/ +#define t8_dtri_compute_integer_coords t8_dtet_compute_integer_coords /**< Wrapper of tri function to tet.*/ +#define t8_dtri_compute_vertex_ref_coords t8_dtet_compute_vertex_ref_coords /**< Wrapper of tri function to tet.*/ +#define t8_dtri_compute_reference_coords t8_dtet_compute_reference_coords /**< Wrapper of tri function to tet.*/ +#define t8_dtri_child t8_dtet_child /**< Wrapper of tri function to tet.*/ +#define t8_dtri_childrenpv t8_dtet_childrenpv /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_familypv t8_dtet_is_familypv /**< Wrapper of tri function to tet.*/ +#define t8_dtri_sibling t8_dtet_sibling /**< Wrapper of tri function to tet.*/ +#define t8_dtri_face_neighbour t8_dtet_face_neighbour /**< Wrapper of tri function to tet.*/ +#define t8_dtri_nearest_common_ancestor t8_dtet_nearest_common_ancestor /**< Wrapper of tri function to tet.*/ +#define t8_dtri_children_at_face t8_dtet_children_at_face /**< Wrapper of tri function to tet.*/ +#define t8_dtri_face_child_face t8_dtet_face_child_face /**< Wrapper of tri function to tet.*/ +#define t8_dtri_face_parent_face t8_dtet_face_parent_face /**< Wrapper of tri function to tet.*/ +#define t8_dtri_tree_face t8_dtet_tree_face /**< Wrapper of tri function to tet.*/ +#define t8_dtri_root_face_to_face t8_dtet_root_face_to_face /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_inside_root t8_dtet_is_inside_root /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_root_boundary t8_dtet_is_root_boundary /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_sibling t8_dtet_is_sibling /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_parent t8_dtet_is_parent /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_ancestor t8_dtet_is_ancestor /**< Wrapper of tri function to tet.*/ +#define t8_dtri_linear_id t8_dtet_linear_id /**< Wrapper of tri function to tet.*/ +#define t8_dtri_linear_id_corner_desc t8_dtet_linear_id_corner_desc /**< Wrapper of tri function to tet.*/ +#define t8_dtri_init_linear_id t8_dtet_init_linear_id /**< Wrapper of tri function to tet.*/ +#define t8_dtri_init_root t8_dtet_init_root /**< Wrapper of tri function to tet.*/ +#define t8_dtri_successor t8_dtet_successor /**< Wrapper of tri function to tet.*/ +#define t8_dtri_first_descendant t8_dtet_first_descendant /**< Wrapper of tri function to tet.*/ +#define t8_dtri_last_descendant t8_dtet_last_descendant /**< Wrapper of tri function to tet.*/ +#define t8_dtri_corner_descendant t8_dtet_corner_descendant /**< Wrapper of tri function to tet.*/ +#define t8_dtri_predecessor t8_dtet_predecessor /**< Wrapper of tri function to tet.*/ +#define t8_dtri_ancestor_id t8_dtet_ancestor_id /**< Wrapper of tri function to tet.*/ +#define t8_dtri_child_id t8_dtet_child_id /**< Wrapper of tri function to tet.*/ +#define t8_dtri_get_level t8_dtet_get_level /**< Wrapper of tri function to tet.*/ +#define t8_dtri_is_valid t8_dtet_is_valid /**< Wrapper of tri function to tet.*/ +#define t8_dtri_init t8_dtet_init /**< Wrapper of tri function to tet.*/ +#define t8_dtri_init_linear_id_with_level t8_dtet_init_linear_id_with_level /**< Wrapper of tri function to tet.*/ +#define t8_dtri_linear_id_with_level t8_dtet_linear_id_with_level /**< Wrapper of tri function to tet.*/ +#define t8_dtri_debug_print t8_dtet_debug_print /**< Wrapper of tri function to tet.*/ +#define t8_dtri_element_pack t8_dtet_element_pack /**< Wrapper of tri function to tet.*/ +#define t8_dtri_element_pack_size t8_dtet_element_pack_size /**< Wrapper of tri function to tet.*/ +#define t8_dtri_element_unpack t8_dtet_element_unpack /**< Wrapper of tri function to tet.*/ T8_EXTERN_C_END (); diff --git a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.cxx b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.cxx index 2bf0064e13..c61ba494d4 100644 --- a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.cxx +++ b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.cxx @@ -503,9 +503,9 @@ t8_default_scheme_tri::refines_irregular () const #if T8_ENABLE_DEBUG int -t8_default_scheme_tri::element_is_valid (const t8_element_t *t) const +t8_default_scheme_tri::element_is_valid (const t8_element_t *element) const { - return t8_dtri_is_valid ((const t8_dtri_t *) t); + return t8_dtri_is_valid ((const t8_dtri_t *) element); } void diff --git a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.hxx b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.hxx index f9b8d9989c..a73027919c 100644 --- a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.hxx +++ b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.hxx @@ -37,6 +37,7 @@ /* Forward declaration of the scheme so we can use it as an argument in the eclass schemes function. */ class t8_scheme; +/** Default implementation of the scheme for the triangular element class. */ class t8_default_scheme_tri: public t8_default_scheme_common { public: /** Constructor which calls the specialized constructor for the base. */ @@ -53,7 +54,7 @@ class t8_default_scheme_tri: public t8_default_scheme_commonlevel then the cube-id 0 is returned. */ static t8_dtri_cube_id_t -compute_cubeid (const t8_dtri_t *t, int level) +compute_cubeid (const t8_dtri_t *element, int level) { t8_dtri_cube_id_t id = 0; t8_dtri_coord_t h; @@ -47,10 +47,10 @@ compute_cubeid (const t8_dtri_t *t, int level) return 0; } - id |= ((t->x & h) ? 0x01 : 0); - id |= ((t->y & h) ? 0x02 : 0); + id |= ((element->x & h) ? 0x01 : 0); + id |= ((element->y & h) ? 0x02 : 0); #ifdef T8_DTRI_TO_DTET - id |= ((t->z & h) ? 0x04 : 0); + id |= ((element->z & h) ? 0x04 : 0); #endif return id; @@ -61,14 +61,14 @@ compute_cubeid (const t8_dtri_t *t, int level) * greater than t->level. This method runs in O(t->level - level). */ static t8_dtri_type_t -compute_type_ext (const t8_dtri_t *t, int level, t8_dtri_type_t known_type, int known_level) +compute_type_ext (const t8_dtri_t *element, int level, t8_dtri_type_t known_type, int known_level) { int8_t type = known_type; t8_dtri_cube_id_t cid; int i; T8_ASSERT (0 <= level && level <= known_level); - T8_ASSERT (known_level <= t->level); + T8_ASSERT (known_level <= element->level); if (level == known_level) { return known_type; } @@ -78,7 +78,7 @@ compute_type_ext (const t8_dtri_t *t, int level, t8_dtri_type_t known_type, int return 0; } for (i = known_level; i > level; i--) { - cid = compute_cubeid (t, i); + cid = compute_cubeid (element, i); /* compute type as the type of T^{i+1}, that is T's ancestor of level i+1 */ type = t8_dtri_cid_type_to_parenttype[cid][type]; } @@ -90,76 +90,77 @@ compute_type_ext (const t8_dtri_t *t, int level, t8_dtri_type_t known_type, int * O(t->level - level). */ static t8_dtri_type_t -compute_type (const t8_dtri_t *t, int level) +compute_type (const t8_dtri_t *element, int level) { - return compute_type_ext (t, level, t->type, t->level); + return compute_type_ext (element, level, element->type, element->level); } void -t8_dtri_copy (const t8_dtri_t *t, t8_dtri_t *dest) +t8_dtri_copy (const t8_dtri_t *element, t8_dtri_t *dest) { - if (t == dest) { + if (element == dest) { /* Do nothing if they are already the same. */ return; } - memcpy (dest, t, sizeof (t8_dtri_t)); + memcpy (dest, element, sizeof (t8_dtri_t)); } int -t8_dtri_equal (const t8_dtri_t *elem1, const t8_dtri_t *elem2) +t8_dtri_equal (const t8_dtri_t *element1, const t8_dtri_t *element2) { - return (elem1->level == elem2->level && elem1->type == elem2->type && elem1->x == elem2->x && elem1->y == elem2->y + return (element1->level == element2->level && element1->type == element2->type && element1->x == element2->x + && element1->y == element2->y #ifdef T8_DTRI_TO_DTET - && elem1->z == elem2->z + && element1->z == element2->z #endif ); } int -t8_dtri_compare (const t8_dtri_t *t1, const t8_dtri_t *t2) +t8_dtri_compare (const t8_dtri_t *element1, const t8_dtri_t *element2) { int maxlvl; t8_linearidx_t id1, id2; /* Compute the bigger level of the two */ - maxlvl = SC_MAX (t1->level, t2->level); + maxlvl = SC_MAX (element1->level, element2->level); /* Compute the linear ids of the elements */ - id1 = t8_dtri_linear_id (t1, maxlvl); - id2 = t8_dtri_linear_id (t2, maxlvl); + id1 = t8_dtri_linear_id (element1, maxlvl); + id2 = t8_dtri_linear_id (element2, maxlvl); if (id1 == id2) { /* The linear ids are the same, the triangle with the smaller level is considered smaller */ - T8_ASSERT (t1->level != t2->level || t8_dtri_is_equal (t1, t2)); - return t1->level - t2->level; + T8_ASSERT (element1->level != element2->level || t8_dtri_is_equal (element1, element2)); + return element1->level - element2->level; } /* return negative if id1 < id2, zero if id1 = id2, positive if id1 > id2 */ return id1 < id2 ? -1 : id1 != id2; } void -t8_dtri_parent (const t8_dtri_t *t, t8_dtri_t *parent) +t8_dtri_parent (const t8_dtri_t *element, t8_dtri_t *parent) { t8_dtri_cube_id_t cid; t8_dtri_coord_t h; - T8_ASSERT (t->level > 0); + T8_ASSERT (element->level > 0); - h = T8_DTRI_LEN (t->level); + h = T8_DTRI_LEN (element->level); /* Compute type of parent */ - cid = compute_cubeid (t, t->level); - parent->type = t8_dtri_cid_type_to_parenttype[cid][t->type]; + cid = compute_cubeid (element, element->level); + parent->type = t8_dtri_cid_type_to_parenttype[cid][element->type]; /* Set coordinates of parent */ - parent->x = t->x & ~h; - parent->y = t->y & ~h; + parent->x = element->x & ~h; + parent->y = element->y & ~h; #ifdef T8_DTRI_TO_DTET - parent->z = t->z & ~h; + parent->z = element->z & ~h; #endif - parent->level = t->level - 1; + parent->level = element->level - 1; } void -t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) +t8_dtri_ancestor (const t8_dtri_t *element, int level, t8_dtri_t *ancestor) { - /* TODO: find out, at which level difference it is faster to use * + /* TODO: find out, at which level difference it is faster to use * the arithmetic computation of ancestor type * opposed to iteratively computing the parent type. */ @@ -173,22 +174,22 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) #endif #endif /* T8_DTRI_TO_DTET */ - /* delta_{x,y} = t->{x,y} - ancestor->{x,y} + /* delta_{x,y} = element->{x,y} - ancestor->{x,y} * the difference of the coordinates. * Needed to compute the type of the ancestor. */ - delta_x = t->x & (T8_DTRI_LEN (level) - 1); - delta_y = t->y & (T8_DTRI_LEN (level) - 1); + delta_x = element->x & (T8_DTRI_LEN (level) - 1); + delta_y = element->y & (T8_DTRI_LEN (level) - 1); #ifdef T8_DTRI_TO_DTET - delta_z = t->z & (T8_DTRI_LEN (level) - 1); + delta_z = element->z & (T8_DTRI_LEN (level) - 1); #endif /* The coordinates of the ancestor. It is necessary * to compute the delta first, since ancestor and t * could point to the same triangle. */ - ancestor->x = t->x & ~(T8_DTRI_LEN (level) - 1); - ancestor->y = t->y & ~(T8_DTRI_LEN (level) - 1); + ancestor->x = element->x & ~(T8_DTRI_LEN (level) - 1); + ancestor->y = element->y & ~(T8_DTRI_LEN (level) - 1); #ifdef T8_DTRI_TO_DTET - ancestor->z = t->z & ~(T8_DTRI_LEN (level) - 1); + ancestor->z = element->z & ~(T8_DTRI_LEN (level) - 1); #endif #ifndef T8_DTRI_TO_DTET @@ -202,7 +203,7 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) } else { T8_ASSERT (diff_xy == 0); - ancestor->type = t->type; + ancestor->type = element->type; } #else @@ -224,7 +225,7 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) } else { T8_ASSERT (diff_xy == 0); - if (t->type == 0 || t->type == 1 || t->type == 5) { + if (element->type == 0 || element->type == 1 || element->type == 5) { possible_types[2] = possible_types[3] = possible_types[4] = 0; } else { @@ -241,7 +242,7 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) } else { T8_ASSERT (diff_xz == 0); - if (t->type == 0 || t->type == 1 || t->type == 2) { + if (element->type == 0 || element->type == 1 || element->type == 2) { possible_types[3] = possible_types[4] = possible_types[5] = 0; } else { @@ -258,7 +259,7 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) } else { T8_ASSERT (diff_yz == 0); - if (t->type == 1 || t->type == 2 || t->type == 3) { + if (element->type == 1 || element->type == 2 || element->type == 3) { possible_types[0] = possible_types[4] = possible_types[5] = 0; } else { @@ -286,7 +287,7 @@ t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor) /* Compute the coordinates of a given vertex of a triangle/tet */ void -t8_dtri_compute_integer_coords (const t8_dtri_t *elem, const int vertex, t8_dtri_coord_t coordinates[T8_DTRI_DIM]) +t8_dtri_compute_integer_coords (const t8_dtri_t *element, const int vertex, t8_dtri_coord_t coordinates[T8_DTRI_DIM]) { /* Calculate the vertex coordinates of a triangle/tetrahedron in relation to its orientation. Orientations are * described here: https://doi.org/10.1137/15M1040049 @@ -317,8 +318,8 @@ t8_dtri_compute_integer_coords (const t8_dtri_t *elem, const int vertex, t8_dtri t8_dtri_coord_t h; T8_ASSERT (0 <= vertex && vertex < T8_DTRI_FACES); - type = elem->type; - h = T8_DTRI_LEN (elem->level); + type = element->type; + h = T8_DTRI_LEN (element->level); #ifndef T8_DTRI_TO_DTET ei = type; #else @@ -326,10 +327,10 @@ t8_dtri_compute_integer_coords (const t8_dtri_t *elem, const int vertex, t8_dtri ej = (ei + ((type % 2 == 0) ? 2 : 1)) % 3; #endif - coordinates[0] = elem->x; - coordinates[1] = elem->y; + coordinates[0] = element->x; + coordinates[1] = element->y; #ifdef T8_DTRI_TO_DTET - coordinates[2] = elem->z; + coordinates[2] = element->z; #endif if (vertex == 0) { return; @@ -354,12 +355,12 @@ t8_dtri_compute_integer_coords (const t8_dtri_t *elem, const int vertex, t8_dtri } void -t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *elem, const int vertex, double coordinates[T8_DTRI_DIM]) +t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *element, const int vertex, double coordinates[T8_DTRI_DIM]) { int coords_int[T8_DTRI_DIM]; T8_ASSERT (0 <= vertex && vertex < T8_DTRI_CORNERS); - t8_dtri_compute_integer_coords (elem, vertex, coords_int); + t8_dtri_compute_integer_coords (element, vertex, coords_int); /* Since the integer coordinates are coordinates w.r.t to * the embedding into [0,T8_DTRI_ROOT_LEN]^d, we just need * to divide them by the root length. */ @@ -371,7 +372,7 @@ t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *elem, const int vertex, doub } void -t8_dtri_compute_reference_coords (const t8_dtri_t *elem, const double *ref_coords, const size_t num_coords, +t8_dtri_compute_reference_coords (const t8_dtri_t *element, const double *ref_coords, const size_t num_coords, #ifndef T8_DTRI_TO_DTET const size_t skip_coords, #endif @@ -404,8 +405,8 @@ t8_dtri_compute_reference_coords (const t8_dtri_t *elem, const double *ref_coord t8_dtri_type_t type; t8_dtri_coord_t h; - type = elem->type; - h = T8_DTRI_LEN (elem->level); + type = element->type; + h = T8_DTRI_LEN (element->level); #ifndef T8_DTRI_TO_DTET const int tri_orientation = type; #else @@ -423,10 +424,10 @@ t8_dtri_compute_reference_coords (const t8_dtri_t *elem, const double *ref_coord #else const size_t offset = 3 * coord; #endif - out_coords[offset + 0] = elem->x; - out_coords[offset + 1] = elem->y; + out_coords[offset + 0] = element->x; + out_coords[offset + 1] = element->y; #ifdef T8_DTRI_TO_DTET - out_coords[offset + 2] = elem->z; + out_coords[offset + 2] = element->z; #endif #ifndef T8_DTRI_TO_DTET out_coords[offset + tri_orientation] += h * ref_coords[offset_3d + 0]; @@ -451,7 +452,7 @@ t8_dtri_compute_reference_coords (const t8_dtri_t *elem, const double *ref_coord /* Compute the coordinates of each vertex of a triangle/tet */ void -t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[T8_DTRI_FACES][T8_DTRI_DIM]) +t8_dtri_compute_all_coords (const t8_dtri_t *element, t8_dtri_coord_t coordinates[T8_DTRI_FACES][T8_DTRI_DIM]) { /* Calculate the vertex coordinates of a triangle/tetrahedron in * relation to its orientation. Orientations are described here: @@ -483,8 +484,8 @@ t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[T int i; t8_dtri_coord_t h; - type = elem->type; - h = T8_DTRI_LEN (elem->level); + type = element->type; + h = T8_DTRI_LEN (element->level); #ifndef T8_DTRI_TO_DTET ei = type; #else @@ -492,10 +493,10 @@ t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[T ej = (ei + ((type % 2 == 0) ? 2 : 1)) % 3; #endif - coordinates[0][0] = elem->x; - coordinates[0][1] = elem->y; + coordinates[0][0] = element->x; + coordinates[0][1] = element->y; #ifdef T8_DTRI_TO_DTET - coordinates[0][2] = elem->z; + coordinates[0][2] = element->z; #endif for (i = 0; i < T8_DTRI_DIM; i++) { coordinates[1][i] = coordinates[0][i]; @@ -519,7 +520,7 @@ t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[T int ivertex; t8_dtri_coord_t coords[T8_DTRI_DIM]; for (ivertex = 0; ivertex < T8_DTRI_FACES; ivertex++) { - t8_dtri_compute_integer_coords (elem, ivertex, coords); + t8_dtri_compute_integer_coords (element, ivertex, coords); T8_ASSERT (coords[0] == coordinates[ivertex][0]); T8_ASSERT (coords[1] == coordinates[ivertex][1]); #ifdef T8_DTRI_TO_DTET @@ -535,96 +536,96 @@ t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[T * It is possible that the function is called with * elem = child */ void -t8_dtri_child (const t8_dtri_t *t, int childid, t8_dtri_t *child) +t8_dtri_child (const t8_dtri_t *element, int childid, t8_dtri_t *child) { t8_dtri_t *c = (t8_dtri_t *) child; t8_dtri_coord_t t_coordinates[T8_DTRI_DIM]; int vertex; int Bey_cid; - T8_ASSERT (t->level < T8_DTRI_MAXLEVEL); + T8_ASSERT (element->level < T8_DTRI_MAXLEVEL); T8_ASSERT (0 <= childid && childid < T8_DTRI_CHILDREN); - Bey_cid = t8_dtri_index_to_bey_number[t->type][childid]; + Bey_cid = t8_dtri_index_to_bey_number[element->type][childid]; /* Compute anchor coordinates of child */ if (Bey_cid == 0) { /* TODO: would it be better do drop this if and * capture it with (t->x+t->x)>>1 below? */ - c->x = t->x; - c->y = t->y; + c->x = element->x; + c->y = element->y; #ifdef T8_DTRI_TO_DTET - c->z = t->z; + c->z = element->z; #endif } else { vertex = t8_dtri_beyid_to_vertex[Bey_cid]; /* i-th anchor coordinate of child is (X_(0,i)+X_(vertex,i))/2 * where X_(i,j) is the j-th coordinate of t's ith node */ - t8_dtri_compute_integer_coords (t, vertex, t_coordinates); - c->x = (t->x + t_coordinates[0]) >> 1; - c->y = (t->y + t_coordinates[1]) >> 1; + t8_dtri_compute_integer_coords (element, vertex, t_coordinates); + c->x = (element->x + t_coordinates[0]) >> 1; + c->y = (element->y + t_coordinates[1]) >> 1; #ifdef T8_DTRI_TO_DTET - c->z = (t->z + t_coordinates[2]) >> 1; + c->z = (element->z + t_coordinates[2]) >> 1; #endif } /* Compute type of child */ - c->type = t8_dtri_type_of_child[t->type][Bey_cid]; + c->type = t8_dtri_type_of_child[element->type][Bey_cid]; - c->level = t->level + 1; + c->level = element->level + 1; } void -t8_dtri_childrenpv (const t8_dtri_t *t, t8_dtri_t *c[T8_DTRI_CHILDREN]) +t8_dtri_childrenpv (const t8_dtri_t *element, t8_dtri_t *children[T8_DTRI_CHILDREN]) { t8_dtri_coord_t t_coordinates[T8_DTRI_FACES][T8_DTRI_DIM]; - const int8_t level = t->level + 1; + const int8_t level = element->level + 1; int i; int Bey_cid; int vertex; - t8_dtri_type_t t_type = t->type; + t8_dtri_type_t t_type = element->type; - T8_ASSERT (t->level < T8_DTRI_MAXLEVEL); - t8_dtri_compute_all_coords (t, t_coordinates); + T8_ASSERT (element->level < T8_DTRI_MAXLEVEL); + t8_dtri_compute_all_coords (element, t_coordinates); /* We use t_coordinates[0] for t->x,y,z to ensure that the function is valid - * if called with t = c[0]. If we would use t->x later it would be the newly - * computed value c[0]->x. */ - c[0]->x = t_coordinates[0][0]; /* t->x */ - c[0]->y = t_coordinates[0][1]; /* t->y */ + * if called with t = children[0]. If we would use t->x later it would be the newly + * computed value children[0]->x. */ + children[0]->x = t_coordinates[0][0]; /* t->x */ + children[0]->y = t_coordinates[0][1]; /* t->y */ #ifdef T8_DTRI_TO_DTET - c[0]->z = t_coordinates[0][2]; /* t->z */ + children[0]->z = t_coordinates[0][2]; /* t->z */ #endif - c[0]->type = t_type; - c[0]->level = level; + children[0]->type = t_type; + children[0]->level = level; for (i = 1; i < T8_DTRI_CHILDREN; i++) { Bey_cid = t8_dtri_index_to_bey_number[t_type][i]; vertex = t8_dtri_beyid_to_vertex[Bey_cid]; /* i-th anchor coordinate of child is (X_(0,i)+X_(vertex,i))/2 * where X_(i,j) is the j-th coordinate of t's ith node */ - c[i]->x = (t_coordinates[0][0] + t_coordinates[vertex][0]) >> 1; - c[i]->y = (t_coordinates[0][1] + t_coordinates[vertex][1]) >> 1; + children[i]->x = (t_coordinates[0][0] + t_coordinates[vertex][0]) >> 1; + children[i]->y = (t_coordinates[0][1] + t_coordinates[vertex][1]) >> 1; #ifdef T8_DTRI_TO_DTET - c[i]->z = (t_coordinates[0][2] + t_coordinates[vertex][2]) >> 1; + children[i]->z = (t_coordinates[0][2] + t_coordinates[vertex][2]) >> 1; #endif - c[i]->type = t8_dtri_type_of_child[t_type][Bey_cid]; - c[i]->level = level; + children[i]->type = t8_dtri_type_of_child[t_type][Bey_cid]; + children[i]->level = level; #if T8_ENABLE_DEBUG { /* We check whether the child computed here equals to the child * computed in the t8_dtri_child function. */ t8_dtri_t check_child; - /* We use c[0] here instead of t, since we explicitly allow t=c[0] as input + /* We use children[0] here instead of t, since we explicitly allow t=children[0] as input * and thus the values of t may be already overwritten. However the only - * difference from c[0] to t is in the level. */ - c[0]->level--; - t8_dtri_child (c[0], i, &check_child); - T8_ASSERT (check_child.x == c[i]->x && check_child.y == c[i]->y); - T8_ASSERT (check_child.type == c[i]->type && check_child.level == c[i]->level); + * difference from children[0] to t is in the level. */ + children[0]->level--; + t8_dtri_child (children[0], i, &check_child); + T8_ASSERT (check_child.x == children[i]->x && check_child.y == children[i]->y); + T8_ASSERT (check_child.type == children[i]->type && check_child.level == children[i]->level); #ifdef T8_DTRI_TO_DTET - T8_ASSERT (check_child.z == c[i]->z); + T8_ASSERT (check_child.z == children[i]->z); #endif - c[0]->level++; + children[0]->level++; } #endif } @@ -666,18 +667,18 @@ t8_dtri_is_familypv (const t8_dtri_t *f[]) * parent and child * TODO: CB agrees, make this as non-redundant as possible */ void -t8_dtri_sibling (const t8_dtri_t *elem, int sibid, t8_dtri_t *sibling) +t8_dtri_sibling (const t8_dtri_t *element, int sibid, t8_dtri_t *sibling) { T8_ASSERT (0 <= sibid && sibid < T8_DTRI_CHILDREN); - T8_ASSERT (((const t8_dtri_t *) elem)->level > 0); - t8_dtri_parent (elem, sibling); + T8_ASSERT (((const t8_dtri_t *) element)->level > 0); + t8_dtri_parent (element, sibling); t8_dtri_child (sibling, sibid, sibling); } /* Saves the neighbour of T along face "face" in N - * returns the facenumber of N along which T is its neighbour */ + * returns the face number of N along which T is its neighbour */ int -t8_dtri_face_neighbour (const t8_dtri_t *t, int face, t8_dtri_t *n) +t8_dtri_face_neighbour (const t8_dtri_t *element, int face, t8_dtri_t *neigh) { /* TODO: document what happens if outside of root tet */ int type_new, type_old; @@ -690,13 +691,13 @@ t8_dtri_face_neighbour (const t8_dtri_t *t, int face, t8_dtri_t *n) T8_ASSERT (0 <= face && face < T8_DTRI_FACES); - level = t->level; - type_old = t->type; + level = element->level; + type_old = element->type; type_new = type_old; - coords[0] = t->x; - coords[1] = t->y; + coords[0] = element->x; + coords[1] = element->y; #ifdef T8_DTRI_TO_DTET - coords[2] = t->z; + coords[2] = element->z; #endif #ifndef T8_DTRI_TO_DTET @@ -741,18 +742,18 @@ t8_dtri_face_neighbour (const t8_dtri_t *t, int face, t8_dtri_t *n) } /* 3D end */ #endif - n->x = coords[0]; - n->y = coords[1]; + neigh->x = coords[0]; + neigh->y = coords[1]; #ifdef T8_DTRI_TO_DTET - n->z = coords[2]; + neigh->z = coords[2]; #endif - n->level = level; - n->type = type_new; + neigh->level = level; + neigh->type = type_new; return ret; } void -t8_dtri_nearest_common_ancestor (const t8_dtri_t *t1, const t8_dtri_t *t2, t8_dtri_t *r) +t8_dtri_nearest_common_ancestor (const t8_dtri_t *element1, const t8_dtri_t *element2, t8_dtri_t *nca) { int maxlevel, c_level, r_level; t8_dtri_type_t t1_type_at_l, t2_type_at_l; @@ -763,10 +764,10 @@ t8_dtri_nearest_common_ancestor (const t8_dtri_t *t1, const t8_dtri_t *t2, t8_dt uint32_t maxclor; /* Find the level of the nca */ - exclorx = t1->x ^ t2->x; - exclory = t1->y ^ t2->y; + exclorx = element1->x ^ element2->x; + exclory = element1->y ^ element2->y; #ifdef T8_DTRI_TO_DTET - exclorz = t1->z ^ t2->z; + exclorz = element1->z ^ element2->z; maxclor = exclorx | exclory | exclorz; #else @@ -776,25 +777,25 @@ t8_dtri_nearest_common_ancestor (const t8_dtri_t *t1, const t8_dtri_t *t2, t8_dt T8_ASSERT (maxlevel <= T8_DTRI_MAXLEVEL); - c_level = (int8_t) SC_MIN (T8_DTRI_MAXLEVEL - maxlevel, (int) SC_MIN (t1->level, t2->level)); + c_level = (int8_t) SC_MIN (T8_DTRI_MAXLEVEL - maxlevel, (int) SC_MIN (element1->level, element2->level)); r_level = c_level; /* c_level is the level of the nca cube surrounding t1 and t2. * If t1 and t2 have different types at this level, then we have to shrink this * level further. */ - t1_type_at_l = compute_type (t1, c_level); - t2_type_at_l = compute_type (t2, c_level); + t1_type_at_l = compute_type (element1, c_level); + t2_type_at_l = compute_type (element2, c_level); while (t1_type_at_l != t2_type_at_l) { r_level--; - t1_type_at_l = compute_type_ext (t1, r_level, t1_type_at_l, r_level + 1); - t2_type_at_l = compute_type_ext (t2, r_level, t2_type_at_l, r_level + 1); + t1_type_at_l = compute_type_ext (element1, r_level, t1_type_at_l, r_level + 1); + t2_type_at_l = compute_type_ext (element2, r_level, t2_type_at_l, r_level + 1); } T8_ASSERT (r_level >= 0); /* Construct the ancestor of the first triangle at this level */ - t8_dtri_ancestor (t1, r_level, r); + t8_dtri_ancestor (element1, r_level, nca); } void -t8_dtri_children_at_face (const t8_dtri_t *tri, int face, t8_dtri_t *children[], +t8_dtri_children_at_face (const t8_dtri_t *element, int face, t8_dtri_t *children[], __attribute__ ((unused)) int num_children, int *child_indices) { int child_ids_local[T8_DTRI_FACE_CHILDREN], i, *child_ids; @@ -811,27 +812,27 @@ t8_dtri_children_at_face (const t8_dtri_t *tri, int face, t8_dtri_t *children[], #ifndef T8_DTRI_TO_DTET /* Triangle version */ /* The first child is '0' for faces 1 and 2 and '1+type' for face 0 */ - child_ids[0] = face == 0 ? 1 + tri->type : 0; + child_ids[0] = face == 0 ? 1 + element->type : 0; /* The second child is '1 + type' for face 2 and '3' for faces 0 and 1 */ - child_ids[1] = face == 2 ? 1 + tri->type : 3; + child_ids[1] = face == 2 ? 1 + element->type : 3; #else /* Tetrahedron version */ for (i = 0; i < T8_DTET_FACE_CHILDREN; i++) { - child_ids[i] = t8_dtet_face_child_id_by_type[tri->type][face][i]; + child_ids[i] = t8_dtet_face_child_id_by_type[element->type][face][i]; } #endif /* Compute the children at the face. * We revert the order to compute children[0] last, since the usage - * allows for tri == children[0]. + * allows for element == children[0]. */ for (i = T8_DTRI_FACE_CHILDREN - 1; i >= 0; i--) { - t8_dtri_child (tri, child_ids[i], children[i]); + t8_dtri_child (element, child_ids[i], children[i]); } } int -t8_dtri_tree_face (__attribute__ ((unused)) t8_dtri_t *t, int face) +t8_dtri_tree_face (__attribute__ ((unused)) t8_dtri_t *element, int face) { T8_ASSERT (0 <= face && face < T8_DTRI_FACES); /* TODO: Assert if boundary */ @@ -844,7 +845,7 @@ t8_dtri_tree_face (__attribute__ ((unused)) t8_dtri_t *t, int face) /* For tets only tets of type not 3 can have tree boundary faces. * All these tets of type not 0 (types 1, 2, 4, and 5) can only have one of * their faces as boundary face. */ - switch (t->type) { + switch (element->type) { case 0: return face; break; @@ -870,11 +871,11 @@ t8_dtri_tree_face (__attribute__ ((unused)) t8_dtri_t *t, int face) } int -t8_dtri_root_face_to_face (__attribute__ ((unused)) t8_dtri_t *t, int root_face) +t8_dtri_root_face_to_face (__attribute__ ((unused)) t8_dtri_t *element, int root_face) { T8_ASSERT (0 <= root_face && root_face < T8_DTRI_FACES); #ifndef T8_DTRI_TO_DTET - T8_ASSERT (t->type == 0); + T8_ASSERT (element->type == 0); /* For triangles of type 0 the face number coincides with the number of the * root tree face. Triangles of type 1 cannot lie on the boundary of the * tree and thus the return value can be arbitrary. */ @@ -883,8 +884,8 @@ t8_dtri_root_face_to_face (__attribute__ ((unused)) t8_dtri_t *t, int root_face) /* For tets only tets of type not 3 can have tree boundary faces. * All these tets of type not 0 (types 1, 2, 4, and 5) can only have one of * their faces as boundary face. */ - T8_ASSERT (t->type != 3); - switch (t->type) { + T8_ASSERT (element->type != 3); + switch (element->type) { case 0: return root_face; break; @@ -1100,31 +1101,31 @@ t8_dtri_transform_face (const t8_dtri_t *trianglein, t8_dtri_t *triangle2, int o #endif int -t8_dtri_is_inside_root (t8_dtri_t *t) +t8_dtri_is_inside_root (t8_dtri_t *element) { int is_inside; - if (t->level == 0) { + if (element->level == 0) { /* A level 0 simplex is only inside the root simplex if it * is the root simplex. */ - return t->type == 0 && t->x == 0 && t->y == 0 + return element->type == 0 && element->x == 0 && element->y == 0 #ifdef T8_DTRI_TO_DTET - && t->z == 0 + && element->z == 0 #endif ; } - is_inside = (t->x >= 0 && t->x < T8_DTRI_ROOT_LEN) && (t->y >= 0) && + is_inside = (element->x >= 0 && element->x < T8_DTRI_ROOT_LEN) && (element->y >= 0) && #ifdef T8_DTRI_TO_DTET - (t->z >= 0) && + (element->z >= 0) && #endif #ifndef T8_DTRI_TO_DTET - (t->y - t->x <= 0) && (t->y == t->x ? t->type == 0 : 1) && + (element->y - element->x <= 0) && (element->y == element->x ? element->type == 0 : 1) && #else - (t->z - t->x <= 0) && (t->y - t->z <= 0) && (t->z == t->x ? (0 <= t->type && t->type < 3) : 1) - && /* types 0, 1, 2 */ - (t->y == t->z ? (0 == t->type || 4 <= t->type) : 1) && /* types 0, 4, 5 */ + (element->z - element->x <= 0) && (element->y - element->z <= 0) + && (element->z == element->x ? (0 <= element->type && element->type < 3) : 1) && /* types 0, 1, 2 */ + (element->y == element->z ? (0 == element->type || 4 <= element->type) : 1) && /* types 0, 4, 5 */ /* If the anchor is on the x-y-z diagonal, only type 0 tets are inside root. */ - ((t->x == t->y && t->y == t->z) ? t->type == 0 : 1) && + ((element->x == element->y && element->y == element->z) ? element->type == 0 : 1) && #endif 1; #if T8_ENABLE_DEBUG @@ -1132,27 +1133,27 @@ t8_dtri_is_inside_root (t8_dtri_t *t) { t8_dtri_t root; t8_dtri_init_root (&root); - T8_ASSERT (is_inside == t8_dtri_is_ancestor (&root, t)); + T8_ASSERT (is_inside == t8_dtri_is_ancestor (&root, element)); } #endif return is_inside; } int -t8_dtri_is_root_boundary (const t8_dtri_t *t, int face) +t8_dtri_is_root_boundary (const t8_dtri_t *element, int face) { /* Dependent on the type and the face we have to check * different conditions */ #ifndef T8_DTRI_TO_DTET - switch (t->type) { + switch (element->type) { case 0: switch (face) { case 0: - return t->x == T8_DTRI_ROOT_LEN - T8_DTRI_LEN (t->level); + return element->x == T8_DTRI_ROOT_LEN - T8_DTRI_LEN (element->level); case 1: - return t->x == t->y; + return element->x == element->y; case 2: - return t->y == 0; + return element->y == 0; default: SC_ABORT_NOT_REACHED (); } @@ -1162,35 +1163,35 @@ t8_dtri_is_root_boundary (const t8_dtri_t *t, int face) SC_ABORT_NOT_REACHED (); } #else - switch (t->type) { + switch (element->type) { case 0: switch (face) { case 0: - return t->x == T8_DTET_ROOT_LEN - T8_DTET_LEN (t->level); + return element->x == T8_DTET_ROOT_LEN - T8_DTET_LEN (element->level); case 1: - return t->x == t->z; + return element->x == element->z; case 2: - return t->y == t->z; + return element->y == element->z; case 3: - return t->y == 0; + return element->y == 0; default: SC_ABORT_NOT_REACHED (); } case 1: /* type 1 tets are only boundary at face 0 */ - return face == 0 && t->x == T8_DTET_ROOT_LEN - T8_DTET_LEN (t->level); + return face == 0 && element->x == T8_DTET_ROOT_LEN - T8_DTET_LEN (element->level); case 2: /* type 1 tets are only boundary at face 2 */ - return face == 2 && t->x == t->z; + return face == 2 && element->x == element->z; case 3: /* type 3 tets are never at the root boundary */ return 0; case 4: /* type 4 tets are only boundary at face 1 */ - return face == 1 && t->y == t->z; + return face == 1 && element->y == element->z; case 5: /* type 5 tets are only boundary at face 3 */ - return face == 3 && t->y == 0; + return face == 3 && element->y == 0; default: SC_ABORT_NOT_REACHED (); } @@ -1200,11 +1201,12 @@ t8_dtri_is_root_boundary (const t8_dtri_t *t, int face) } int -t8_dtri_is_equal (const t8_dtri_t *t1, const t8_dtri_t *t2) +t8_dtri_is_equal (const t8_dtri_t *element1, const t8_dtri_t *element2) { - return (t1->level == t2->level && t1->type == t2->type && t1->x == t2->x && t1->y == t2->y + return (element1->level == element2->level && element1->type == element2->type && element1->x == element2->x + && element1->y == element2->y #ifdef T8_DTRI_TO_DTET - && t1->z == t2->z + && element1->z == element2->z #endif ); } @@ -1212,7 +1214,7 @@ t8_dtri_is_equal (const t8_dtri_t *t1, const t8_dtri_t *t2) /* we check if t1 and t2 lie in the same subcube and have * the same level and parent type */ int -t8_dtri_is_sibling (const t8_dtri_t *t1, const t8_dtri_t *t2) +t8_dtri_is_sibling (const t8_dtri_t *element1, const t8_dtri_t *element2) { t8_dtri_coord_t exclorx, exclory; #ifdef T8_DTRI_TO_DTET @@ -1221,46 +1223,46 @@ t8_dtri_is_sibling (const t8_dtri_t *t1, const t8_dtri_t *t2) t8_dtri_cube_id_t cid1, cid2; - if (t1->level == 0) { - return t2->level == 0 && t1->x == t2->x && t1->y == t2->y && + if (element1->level == 0) { + return element2->level == 0 && element1->x == element2->x && element1->y == element2->y && #ifdef T8_DTRI_TO_DTET - t1->z == t2->z && + element1->z == element2->z && #endif 1; } - exclorx = t1->x ^ t2->x; - exclory = t1->y ^ t2->y; + exclorx = element1->x ^ element2->x; + exclory = element1->y ^ element2->y; #ifdef T8_DTRI_TO_DTET - exclorz = t1->z ^ t2->z; + exclorz = element1->z ^ element2->z; #endif - cid1 = compute_cubeid (t1, t1->level); - cid2 = compute_cubeid (t2, t2->level); + cid1 = compute_cubeid (element1, element1->level); + cid2 = compute_cubeid (element2, element2->level); - return (t1->level == t2->level) && ((exclorx & ~T8_DTRI_LEN (t1->level)) == 0) - && ((exclory & ~T8_DTRI_LEN (t1->level)) == 0) && + return (element1->level == element2->level) && ((exclorx & ~T8_DTRI_LEN (element1->level)) == 0) + && ((exclory & ~T8_DTRI_LEN (element1->level)) == 0) && #ifdef T8_DTRI_TO_DTET - ((exclorz & ~T8_DTRI_LEN (t1->level)) == 0) && + ((exclorz & ~T8_DTRI_LEN (element1->level)) == 0) && #endif - t8_dtri_cid_type_to_parenttype[cid1][t1->type] == t8_dtri_cid_type_to_parenttype[cid2][t2->type]; + t8_dtri_cid_type_to_parenttype[cid1][element1->type] == t8_dtri_cid_type_to_parenttype[cid2][element2->type]; } int -t8_dtri_is_parent (const t8_dtri_t *t, const t8_dtri_t *c) +t8_dtri_is_parent (const t8_dtri_t *element, const t8_dtri_t *child) { t8_dtri_cube_id_t cid; - cid = compute_cubeid (c, c->level); - return (t->level + 1 == c->level) && (t->x == (c->x & ~T8_DTRI_LEN (c->level))) - && (t->y == (c->y & ~T8_DTRI_LEN (c->level))) && + cid = compute_cubeid (child, child->level); + return (element->level + 1 == child->level) && (element->x == (child->x & ~T8_DTRI_LEN (child->level))) + && (element->y == (child->y & ~T8_DTRI_LEN (child->level))) && #ifdef T8_DTRI_TO_DTET - (t->z == (c->z & ~T8_DTRI_LEN (c->level))) && + (element->z == (child->z & ~T8_DTRI_LEN (child->level))) && #endif - t->type == t8_dtri_cid_type_to_parenttype[cid][c->type] && 1; + element->type == t8_dtri_cid_type_to_parenttype[cid][child->type] && 1; } int -t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c) +t8_dtri_is_ancestor (const t8_dtri_t *element, const t8_dtri_t *child) { t8_dtri_coord_t n1, n2; t8_dtri_coord_t exclorx; @@ -1272,17 +1274,17 @@ t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c) #endif int8_t type_t; - if (t->level > c->level) { + if (element->level > child->level) { return 0; } - if (t->level == c->level) { - return t8_dtri_is_equal (t, c); + if (element->level == child->level) { + return t8_dtri_is_equal (element, child); } - exclorx = (t->x ^ c->x) >> (T8_DTRI_MAXLEVEL - t->level); - exclory = (t->y ^ c->y) >> (T8_DTRI_MAXLEVEL - t->level); + exclorx = (element->x ^ child->x) >> (T8_DTRI_MAXLEVEL - element->level); + exclory = (element->y ^ child->y) >> (T8_DTRI_MAXLEVEL - element->level); #ifdef T8_DTRI_TO_DTET - exclorz = (t->z ^ c->z) >> (T8_DTRI_MAXLEVEL - t->level); + exclorz = (element->z ^ child->z) >> (T8_DTRI_MAXLEVEL - element->level); #endif if (exclorx == 0 && exclory == 0 @@ -1290,15 +1292,15 @@ t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c) && exclorz == 0 #endif ) { - /* t and c have the same cube as ancestor. + /* element and child have the same cube as ancestor. * Now check if t has the correct type to be c's ancestor. */ - type_t = t->type; + type_t = element->type; #ifndef T8_DTRI_TO_DTET /* 2D */ - n1 = (type_t == 0) ? c->x - t->x : c->y - t->y; - n2 = (type_t == 0) ? c->y - t->y : c->x - t->x; + n1 = (type_t == 0) ? child->x - element->x : child->y - element->y; + n2 = (type_t == 0) ? child->y - element->y : child->x - element->x; - return !(n1 >= T8_DTRI_LEN (t->level) || n2 < 0 || n2 - n1 > 0 || (n2 == n1 && c->type == 1 - type_t)); + return !(n1 >= T8_DTRI_LEN (element->level) || n2 < 0 || n2 - n1 > 0 || (n2 == n1 && child->type == 1 - type_t)); #else /* 3D */ /* Compute the coordinate directions according to this table: @@ -1308,28 +1310,28 @@ t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c) * dir3 z y x z y x */ /* clang-format off */ - n1 = type_t / 2 == 0 ? c->x - t->x : /* type(t) is 0 or 1 */ - type_t / 2 == 2 ? c->z - t->z : c->y - t->y; /* type(t) is (4 or 5) or (2 or 3) */ - n2 = (type_t + 1) / 2 == 2 ? c->x - t->x : /* type(t) is 3 or 4 */ - (type_t + 1) / 2 == 1 ? c->z - t->z : c->y - t->y; /* type(t) is (1 or 2) or (0 or 5) */ - dir3 = type_t % 3 == 2 ? c->x - t->x : /* type(t) is 2 or 5 */ - type_t % 3 == 0 ? c->z - t->z : c->y - t->y; /* type(t) is (0 or 3) or (1 or 4) */ + n1 = type_t / 2 == 0 ? child->x - element->x : /* type(t) is 0 or 1 */ + type_t / 2 == 2 ? child->z - element->z : child->y - element->y; /* type(t) is (4 or 5) or (2 or 3) */ + n2 = (type_t + 1) / 2 == 2 ? child->x - element->x : /* type(t) is 3 or 4 */ + (type_t + 1) / 2 == 1 ? child->z - element->z : child->y - element->y; /* type(t) is (1 or 2) or (0 or 5) */ + dir3 = type_t % 3 == 2 ? child->x - element->x : /* type(t) is 2 or 5 */ + type_t % 3 == 0 ? child->z - element->z : child->y - element->y; /* type(t) is (0 or 3) or (1 or 4) */ sign = (type_t % 2 == 0) ? 1 : -1; /* clang-format on */ type_t += 6; /* We need to compute modulo six and want to avoid negative numbers when subtracting from type_t. */ - return !(n1 >= T8_DTRI_LEN (t->level) || n2 < 0 || dir3 - n1 > 0 || n2 - dir3 > 0 + return !(n1 >= T8_DTRI_LEN (element->level) || n2 < 0 || dir3 - n1 > 0 || n2 - dir3 > 0 || (dir3 == n2 - && (c->type == (type_t + sign * 1) % 6 || c->type == (type_t + sign * 2) % 6 - || c->type == (type_t + sign * 3) % 6)) + && (child->type == (type_t + sign * 1) % 6 || child->type == (type_t + sign * 2) % 6 + || child->type == (type_t + sign * 3) % 6)) || (dir3 == n1 - && (c->type == (type_t - sign * 1) % 6 || c->type == (type_t - sign * 2) % 6 - || c->type == (type_t - sign * 3) % 6)) + && (child->type == (type_t - sign * 1) % 6 || child->type == (type_t - sign * 2) % 6 + || child->type == (type_t - sign * 3) % 6)) /* On the x-y-z diagonal only tets of the same type can be * ancestor of each other. */ - || (dir3 == n2 && n2 == n1 && type_t - 6 != c->type)); + || (dir3 == n2 && n2 == n1 && type_t - 6 != child->type)); #endif } else { @@ -1339,27 +1341,27 @@ t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c) /* Compute the linear id of the first descendant of a triangle/tet */ static t8_linearidx_t -t8_dtri_linear_id_first_desc (const t8_dtri_t *t, int level) +t8_dtri_linear_id_first_desc (const t8_dtri_t *element, int level) { /* The id of the first descendant is the id of t in a uniform level * refinement */ - return t8_dtri_linear_id (t, level); + return t8_dtri_linear_id (element, level); } /* Compute the linear id of the last descendant of a triangle/tet */ static t8_linearidx_t -t8_dtri_linear_id_last_desc (const t8_dtri_t *t, int level) +t8_dtri_linear_id_last_desc (const t8_dtri_t *element, int level) { t8_linearidx_t id = 0, t_id; int exponent; - T8_ASSERT (level >= t->level); + T8_ASSERT (level >= element->level); /* The id of the last descendant at level consists of the id of t in * the first digits and then the local ids of all last children * (3 in 2d, 7 in 3d) */ - t_id = t8_dtri_linear_id (t, t->level); - exponent = level - t->level; + t_id = t8_dtri_linear_id (element, element->level); + exponent = level - element->level; /* Set the last bits to the local ids of always choosing the last child * of t */ id = (((t8_linearidx_t) 1) << T8_DTRI_DIM * exponent) - 1; @@ -1370,53 +1372,53 @@ t8_dtri_linear_id_last_desc (const t8_dtri_t *t, int level) /* Construct the linear id of a descendant in a corner of t */ static t8_linearidx_t -t8_dtri_linear_id_corner_desc (const t8_dtri_t *t, int corner, int level) +t8_dtri_linear_id_corner_desc (const t8_dtri_t *element, int corner, int level) { t8_linearidx_t id = 0, t_id, child_id; int it; T8_ASSERT (0 <= corner && corner < T8_DTRI_CORNERS); - T8_ASSERT (t->level <= level && level <= T8_DTRI_MAXLEVEL); + T8_ASSERT (element->level <= level && level <= T8_DTRI_MAXLEVEL); switch (corner) { case 0: - return t8_dtri_linear_id_first_desc (t, level); + return t8_dtri_linear_id_first_desc (element, level); break; case 1: /* Falls down to case 2 in 3D */ #ifndef T8_DTRI_TO_DTET /* For type 0 triangles, the first corner descendant arises from always * taking the first child. For type 1 triangles it is always the second child. */ - child_id = t8_dtri_parenttype_beyid_to_Iloc[t->type][1]; + child_id = t8_dtri_parenttype_beyid_to_Iloc[element->type][1]; break; #else case 2: - /* For tets, the first corner descnendant arises from always taking the n-th + /* For tets, the first corner descendant arises from always taking the n-th * child, where n is the local child id corresponding to Bey-id corner. */ - child_id = t8_dtet_parenttype_beyid_to_Iloc[t->type][corner]; + child_id = t8_dtet_parenttype_beyid_to_Iloc[element->type][corner]; break; #endif case T8_DTRI_DIM: /* In 2D the 2nd corner and in 3D the 3rd corner correspond to the last - * descendant of t */ - return t8_dtri_linear_id_last_desc (t, level); + * descendant of element. */ + return t8_dtri_linear_id_last_desc (element, level); break; default: SC_ABORT_NOT_REACHED (); } /* This part is executed for corner 1 (2D) or corner 1 and 2 (3D) */ - t_id = t8_dtri_linear_id (t, t->level); - for (it = 0; it < level - t->level; it++) { + t_id = t8_dtri_linear_id (element, element->level); + for (it = 0; it < level - element->level; it++) { /* Store child_id at every position of the new id after t's level and * up to level */ id |= child_id << (T8_DTRI_DIM * it); } /* At the beginning add the linear id of t */ - id |= t_id << (T8_DTRI_DIM * (level - t->level)); + id |= t_id << (T8_DTRI_DIM * (level - element->level)); return id; } t8_linearidx_t -t8_dtri_linear_id (const t8_dtri_t *t, int level) +t8_dtri_linear_id (const t8_dtri_t *element, int level) { t8_linearidx_t id = 0; int8_t type_temp = 0; @@ -1426,21 +1428,21 @@ t8_dtri_linear_id (const t8_dtri_t *t, int level) int my_level; T8_ASSERT (0 <= level && level <= T8_DTRI_MAXLEVEL); - my_level = t->level; + my_level = element->level; exponent = 0; /* If the given level is bigger than t's level * we first fill up with the ids of t's descendants at t's * origin with the same type as t */ if (level > my_level) { exponent = (level - my_level) * T8_DTRI_DIM; - type_temp = t->type; + type_temp = element->type; level = my_level; } else { - type_temp = compute_type (t, level); + type_temp = compute_type (element, level); } for (i = level; i > 0; i--) { - cid = compute_cubeid (t, i); + cid = compute_cubeid (element, i); id |= ((t8_linearidx_t) t8_dtri_type_cid_to_Iloc[type_temp][cid]) << exponent; exponent += T8_DTRI_DIM; /* multiply with 4 (2d) resp. 8 (3d) */ type_temp = t8_dtri_cid_type_to_parenttype[cid][type_temp]; @@ -1449,7 +1451,7 @@ t8_dtri_linear_id (const t8_dtri_t *t, int level) } void -t8_dtri_init_linear_id_with_level (t8_dtri_t *t, t8_linearidx_t id, const int start_level, const int end_level, +t8_dtri_init_linear_id_with_level (t8_dtri_t *element, t8_linearidx_t id, const int start_level, const int end_level, t8_dtri_type_t parenttype) { int i; @@ -1460,10 +1462,10 @@ t8_dtri_init_linear_id_with_level (t8_dtri_t *t, t8_linearidx_t id, const int st t8_dtri_type_t type; T8_ASSERT (id <= ((t8_linearidx_t) 1) << (T8_DTRI_DIM * end_level)); /*Ensure, that the function is called with a valid element */ - T8_ASSERT (t->level == start_level); - T8_ASSERT (t8_dtri_is_valid (t)); + T8_ASSERT (element->level == start_level); + T8_ASSERT (t8_dtri_is_valid (element)); - t->level = end_level; + element->level = end_level; type = parenttype; /* This is the type of the parent triangle */ for (i = start_level; i <= end_level; i++) { @@ -1474,17 +1476,17 @@ t8_dtri_init_linear_id_with_level (t8_dtri_t *t, t8_linearidx_t id, const int st /* Get the type and cube-id of T's ancestor on level i */ cid = t8_dtri_parenttype_Iloc_to_cid[type][local_index]; type = t8_dtri_parenttype_Iloc_to_type[type][local_index]; - t->x |= (cid & 1) ? 1 << offset_coords : 0; - t->y |= (cid & 2) ? 1 << offset_coords : 0; + element->x |= (cid & 1) ? 1 << offset_coords : 0; + element->y |= (cid & 2) ? 1 << offset_coords : 0; #ifdef T8_DTRI_TO_DTET - t->z |= (cid & 4) ? 1 << offset_coords : 0; + element->z |= (cid & 4) ? 1 << offset_coords : 0; #endif } - t->type = type; + element->type = type; } void -t8_dtri_init_linear_id (t8_dtri_t *t, t8_linearidx_t id, int level) +t8_dtri_init_linear_id (t8_dtri_t *element, t8_linearidx_t id, int level) { int i; int offset_coords, offset_index; @@ -1494,11 +1496,11 @@ t8_dtri_init_linear_id (t8_dtri_t *t, t8_linearidx_t id, int level) t8_dtri_type_t type; T8_ASSERT (id <= ((t8_linearidx_t) 1) << (T8_DTRI_DIM * level)); - t->level = level; - t->x = 0; - t->y = 0; + element->level = level; + element->x = 0; + element->y = 0; #ifdef T8_DTRI_TO_DTET - t->z = 0; + element->z = 0; #endif type = 0; /* This is the type of the root triangle */ for (i = 1; i <= level; i++) { @@ -1509,24 +1511,24 @@ t8_dtri_init_linear_id (t8_dtri_t *t, t8_linearidx_t id, int level) /* Get the type and cube-id of T's ancestor on level i */ cid = t8_dtri_parenttype_Iloc_to_cid[type][local_index]; type = t8_dtri_parenttype_Iloc_to_type[type][local_index]; - t->x |= (cid & 1) ? 1 << offset_coords : 0; - t->y |= (cid & 2) ? 1 << offset_coords : 0; + element->x |= (cid & 1) ? 1 << offset_coords : 0; + element->y |= (cid & 2) ? 1 << offset_coords : 0; #ifdef T8_DTRI_TO_DTET - t->z |= (cid & 4) ? 1 << offset_coords : 0; + element->z |= (cid & 4) ? 1 << offset_coords : 0; #endif } - t->type = type; + element->type = type; } void -t8_dtri_init_root (t8_dtri_t *t) +t8_dtri_init_root (t8_dtri_t *element) { - t->level = 0; - t->type = 0; - t->x = 0; - t->y = 0; + element->level = 0; + element->type = 0; + element->x = 0; + element->y = 0; #ifdef T8_DTRI_TO_DTET - t->z = 0; + element->z = 0; #endif } @@ -1535,7 +1537,7 @@ t8_dtri_init_root (t8_dtri_t *t) * 'increment' must be greater than -4 (-8) and smaller than +4 (+8). * Before calling this function s should store the same entries as t. */ static void -t8_dtri_succ_pred_recursion (const t8_dtri_t *t, t8_dtri_t *s, int level, int increment) +t8_dtri_succ_pred_recursion (const t8_dtri_t *element, t8_dtri_t *s, int level, int increment) { t8_dtri_type_t type_level, type_level_p1; t8_dtri_cube_id_t cid; @@ -1544,20 +1546,20 @@ t8_dtri_succ_pred_recursion (const t8_dtri_t *t, t8_dtri_t *s, int level, int in /* We exclude the case level = 0, because the root triangle does * not have a successor. */ - T8_ASSERT (1 <= level && level <= t->level); + T8_ASSERT (1 <= level && level <= element->level); T8_ASSERT (-T8_DTRI_CHILDREN < increment && increment < T8_DTRI_CHILDREN); if (increment == 0) { - t8_dtri_copy (t, s); + t8_dtri_copy (element, s); return; } - cid = compute_cubeid (t, level); - type_level = compute_type (t, level); + cid = compute_cubeid (element, level); + type_level = compute_type (element, level); local_index = t8_dtri_type_cid_to_Iloc[type_level][cid]; local_index = (local_index + T8_DTRI_CHILDREN + increment) % T8_DTRI_CHILDREN; if (local_index == 0) { sign = increment < 0 ? -1 : increment > 0; - t8_dtri_succ_pred_recursion (t, s, level - 1, sign); + t8_dtri_succ_pred_recursion (element, s, level - 1, sign); type_level_p1 = s->type; /* We stored the type of s at level-1 in s->type */ } else { @@ -1577,47 +1579,47 @@ t8_dtri_succ_pred_recursion (const t8_dtri_t *t, t8_dtri_t *s, int level, int in } void -t8_dtri_successor (const t8_dtri_t *t, t8_dtri_t *s, int level) +t8_dtri_successor (const t8_dtri_t *element, t8_dtri_t *s, int level) { - t8_dtri_copy (t, s); - t8_dtri_succ_pred_recursion (t, s, level, 1); + t8_dtri_copy (element, s); + t8_dtri_succ_pred_recursion (element, s, level, 1); } void -t8_dtri_first_descendant (const t8_dtri_t *t, t8_dtri_t *s, int level) +t8_dtri_first_descendant (const t8_dtri_t *element, t8_dtri_t *s, int level) { t8_linearidx_t id; - T8_ASSERT (level >= t->level); + T8_ASSERT (level >= element->level); /* Compute the linear id of the first descendant */ - id = t8_dtri_linear_id_first_desc (t, level); + id = t8_dtri_linear_id_first_desc (element, level); /* The first descendant has exactly this id */ t8_dtri_init_linear_id (s, id, level); } void -t8_dtri_last_descendant (const t8_dtri_t *t, t8_dtri_t *s, int level) +t8_dtri_last_descendant (const t8_dtri_t *element, t8_dtri_t *s, int level) { t8_linearidx_t id; - T8_ASSERT (level >= t->level); + T8_ASSERT (level >= element->level); /* Compute the linear id of t's last descendant */ - id = t8_dtri_linear_id_last_desc (t, level); + id = t8_dtri_linear_id_last_desc (element, level); /* Set s to math this linear id */ t8_dtri_init_linear_id (s, id, level); } void -t8_dtri_corner_descendant (const t8_dtri_t *t, t8_dtri_t *s, int corner, int level) +t8_dtri_corner_descendant (const t8_dtri_t *element, t8_dtri_t *s, int corner, int level) { t8_linearidx_t id; - T8_ASSERT (t->level <= level && level <= T8_DTRI_MAXLEVEL); + T8_ASSERT (element->level <= level && level <= T8_DTRI_MAXLEVEL); T8_ASSERT (0 <= corner && corner < T8_DTRI_CORNERS); switch (corner) { case 0: /* The 0-the corner descendant is just the first descendant */ - t8_dtri_first_descendant (t, s, level); + t8_dtri_first_descendant (element, s, level); break; case 1: #ifdef T8_DTRI_TO_DTET /* In 3D corner 1 and 2 are handled the same */ @@ -1625,12 +1627,12 @@ t8_dtri_corner_descendant (const t8_dtri_t *t, t8_dtri_t *s, int corner, int lev #endif /* Compute the linear id of the descendant and construct a triangle with * this id */ - id = t8_dtri_linear_id_corner_desc (t, corner, level); + id = t8_dtri_linear_id_corner_desc (element, corner, level); t8_dtri_init_linear_id (s, id, level); break; case T8_DTRI_DIM: /* The 2nd corner (2D) or 3rd corner (3D) descendant is just the last descendant */ - t8_dtri_last_descendant (t, s, level); + t8_dtri_last_descendant (element, s, level); break; default: SC_ABORT_NOT_REACHED (); @@ -1638,40 +1640,40 @@ t8_dtri_corner_descendant (const t8_dtri_t *t, t8_dtri_t *s, int corner, int lev } void -t8_dtri_predecessor (const t8_dtri_t *t, t8_dtri_t *s, int level) +t8_dtri_predecessor (const t8_dtri_t *element, t8_dtri_t *s, int level) { - t8_dtri_copy (t, s); - t8_dtri_succ_pred_recursion (t, s, level, -1); + t8_dtri_copy (element, s); + t8_dtri_succ_pred_recursion (element, s, level, -1); } int -t8_dtri_ancestor_id (const t8_dtri_t *t, int level) +t8_dtri_ancestor_id (const t8_dtri_t *element, int level) { t8_dtri_cube_id_t cid; t8_dtri_type_t type; T8_ASSERT (0 <= level && level <= T8_DTRI_MAXLEVEL); - T8_ASSERT (level <= t->level); + T8_ASSERT (level <= element->level); - cid = compute_cubeid (t, level); - type = compute_type (t, level); + cid = compute_cubeid (element, level); + type = compute_type (element, level); return t8_dtri_type_cid_to_Iloc[type][cid]; } int -t8_dtri_child_id (const t8_dtri_t *t) +t8_dtri_child_id (const t8_dtri_t *element) { - return t8_dtri_type_cid_to_Iloc[t->type][compute_cubeid (t, t->level)]; + return t8_dtri_type_cid_to_Iloc[element->type][compute_cubeid (element, element->level)]; } int -t8_dtri_get_level (const t8_dtri_t *t) +t8_dtri_get_level (const t8_dtri_t *element) { - return t->level; + return element->level; } int -t8_dtri_is_valid (const t8_dtri_t *t) +t8_dtri_is_valid (const t8_dtri_t *element) { int is_valid; t8_dtri_coord_t max_coord; @@ -1681,26 +1683,26 @@ t8_dtri_is_valid (const t8_dtri_t *t) /* A triangle/tet is valid if: */ /* The level is in the valid range */ - is_valid = 0 <= t->level && t->level <= T8_DTRI_MAXLEVEL; + is_valid = 0 <= element->level && element->level <= T8_DTRI_MAXLEVEL; /* The coordinates are in valid ranges, we allow the x,y,z coordinates * to lie in the 3x3 neighborhood of the root cube. */ max_coord = ((int64_t) 2 * T8_DTRI_ROOT_LEN) - 1; - is_valid = is_valid && -T8_DTRI_ROOT_LEN <= t->x && t->x <= max_coord; - is_valid = is_valid && -T8_DTRI_ROOT_LEN <= t->y && t->y <= max_coord; + is_valid = is_valid && -T8_DTRI_ROOT_LEN <= element->x && element->x <= max_coord; + is_valid = is_valid && -T8_DTRI_ROOT_LEN <= element->y && element->y <= max_coord; #ifdef T8_DTRI_TO_DTET - is_valid = is_valid && -T8_DTRI_ROOT_LEN <= t->z && t->z <= max_coord; + is_valid = is_valid && -T8_DTRI_ROOT_LEN <= element->z && element->z <= max_coord; #endif /* Its type is in the valid range */ - is_valid = is_valid && 0 <= t->type && t->type < T8_DTRI_NUM_TYPES; + is_valid = is_valid && 0 <= element->type && element->type < T8_DTRI_NUM_TYPES; return is_valid; } void -t8_dtri_init (t8_dtri_t *t) +t8_dtri_init (t8_dtri_t *element) { /* Set all values to zero */ - memset (t, 0, sizeof (*t)); + memset (element, 0, sizeof (*element)); } /* triangles (tets) are packed as x,y (,z) coordinates, type and level */ diff --git a/src/t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.h b/src/t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.h index 3cb1c4d97f..15d0812712 100644 --- a/src/t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.h +++ b/src/t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.h @@ -33,67 +33,67 @@ T8_EXTERN_C_BEGIN (); /** Copy the values of one triangle to another. - * \param [in] t Triangle whose values will be copied. + * \param [in] element Triangle whose values will be copied. * \param [in,out] dest Existing triangle whose data will be - * filled with the data of \a t. * + * filled with the data of \a element. */ void -t8_dtri_copy (const t8_dtri_t *t, t8_dtri_t *dest); +t8_dtri_copy (const t8_dtri_t *element, t8_dtri_t *dest); /** Compare two triangle in their linear order. - * \param [in] t1 Triangle one. - * \param [in] t2 Triangle two. - * \return Returns negative if t1 < t2, zero if t1 = t2, positive if t1 > t2 + * \param [in] element1 Triangle one. + * \param [in] element2 Triangle two. + * \return Returns negative if tri1 < tri2, zero if tri1 = tri2, positive if tri1 > tri2 */ int -t8_dtri_compare (const t8_dtri_t *t1, const t8_dtri_t *t2); +t8_dtri_compare (const t8_dtri_t *element1, const t8_dtri_t *element2); /** Check if two elements are equal. -* \param [in] elem1 The first element. -* \param [in] elem2 The second element. +* \param [in] element1 The first element. +* \param [in] element2 The second element. * \return 1 if the elements are equal, 0 if they are not equal */ int -t8_dtri_equal (const t8_dtri_t *elem1, const t8_dtri_t *elem2); +t8_dtri_equal (const t8_dtri_t *element1, const t8_dtri_t *element2); /** Compute the parent of a triangle. - * \param [in] elem Input triangle. + * \param [in] element Input triangle. * \param [in,out] parent Existing triangle whose data will be filled with the data of elem's parent. - * \note \a elem may point to the same triangle as \a parent. + * \note \a element may point to the same triangle as \a parent. */ void -t8_dtri_parent (const t8_dtri_t *t, t8_dtri_t *parent); +t8_dtri_parent (const t8_dtri_t *element, t8_dtri_t *parent); /** Compute the ancestor of a triangle at a given level. - * \param [in] t Input triangle. - * \param [in] level A smaller level than \a t. - * \param [in,out] ancestor Existing triangle whose data will be filled with the data of \a t's ancestor on level + * \param [in] element Input triangle. + * \param [in] level A smaller level than \a element. + * \param [in,out] ancestor Existing triangle whose data will be filled with the data of \a element's ancestor on level * \a level. - * \note The triangle \a ancestor may point to the same triangle as \a t. + * \note The triangle \a ancestor may point to the same triangle as \a element. */ void -t8_dtri_ancestor (const t8_dtri_t *t, int level, t8_dtri_t *ancestor); +t8_dtri_ancestor (const t8_dtri_t *element, int level, t8_dtri_t *ancestor); /** Compute the coordinates of a vertex of a triangle. - * \param [in] elem Input triangle. + * \param [in] element Input triangle. * \param [in] vertex The number of the vertex. * \param [out] coordinates An array of 2 t8_dtri_coord_t that will be filled with the coordinates of the vertex. */ void -t8_dtri_compute_integer_coords (const t8_dtri_t *elem, const int vertex, t8_dtri_coord_t coordinates[2]); +t8_dtri_compute_integer_coords (const t8_dtri_t *element, const int vertex, t8_dtri_coord_t coordinates[2]); /** Compute the reference coordinates of a vertex of a triangle when the * tree (level 0 triangle) is embedded in \f$ [0,1]^2 \f$. - * \param [in] elem Input triangle. + * \param [in] element Input triangle. * \param [in] vertex The number of the vertex. * \param [out] coordinates An array of 2 double that will be filled with the reference coordinates of the vertex. */ void -t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *elem, const int vertex, double coordinates[2]); +t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *element, const int vertex, double coordinates[2]); /** Convert points in the reference space of a tri element to points in the * reference space of the tree (level 0) embedded in \f$ [0,1]^2 \f$. - * \param [in] elem Input triangle. + * \param [in] element Input triangle. * \param [in] ref_coords The reference coordinates in the triangle * (\a num_coords times \f$ [0,1]^2 \f$) * \param [in] num_coords Number of coordinates to evaluate @@ -106,30 +106,30 @@ t8_dtri_compute_vertex_ref_coords (const t8_dtri_t *elem, const int vertex, doub * of the points on the triangle. */ void -t8_dtri_compute_reference_coords (const t8_dtri_t *elem, const double *ref_coords, const size_t num_coords, +t8_dtri_compute_reference_coords (const t8_dtri_t *element, const double *ref_coords, const size_t num_coords, const size_t skip_coords, double *out_coords); /** Compute the coordinates of the four vertices of a triangle. - * \param [in] elem Input triangle. + * \param [in] element Input triangle. * \param [out] coordinates An array of 4x3 t8_dtri_coord_t that will be filled with the coordinates of t's vertices. */ void -t8_dtri_compute_all_coords (const t8_dtri_t *elem, t8_dtri_coord_t coordinates[3][2]); +t8_dtri_compute_all_coords (const t8_dtri_t *element, t8_dtri_coord_t coordinates[3][2]); /** Compute the childid-th child in Morton order of a triangle. - * \param [in] t Input triangle. + * \param [in] element Input triangle. * \param [in,out] childid The id of the child, 0..7 in Morton order. * \param [out] child Existing triangle whose data will be filled with the date of t's childid-th child. */ void -t8_dtri_child (const t8_dtri_t *t, int childid, t8_dtri_t *child); +t8_dtri_child (const t8_dtri_t *element, int childid, t8_dtri_t *child); /** Compute the 4 children of a triangle, array version. - * \param [in] t Input triangle. - * \param [in,out] c Pointers to the 4 computed children in Morton order. t may point to the same quadrant as c[0]. + * \param [in] element Input triangle. + * \param [in,out] children Pointers to the 4 computed children in Morton order. t may point to the same quadrant as c[0]. */ void -t8_dtri_childrenpv (const t8_dtri_t *t, t8_dtri_t *c[T8_DTRI_CHILDREN]); +t8_dtri_childrenpv (const t8_dtri_t *element, t8_dtri_t *children[T8_DTRI_CHILDREN]); /** Check whether a collection of eight triangles is a family in Morton order. * \param [in] f An array of eight triangles. @@ -139,42 +139,44 @@ int t8_dtri_is_familypv (const t8_dtri_t *f[]); /** Compute a specific sibling of a triangle. - * \param [in] elem Input triangle. - * \param [in,out] sibling Existing triangle whose data will be filled with the data of sibling no. sibling_id of - * elem. + * \param [in] element Input triangle. * \param [in] sibid The id of the sibling computed, 0..7 in Bey order. + * \param [in,out] sibling Existing triangle whose data will be filled with the data of sibling no. sibling_id of + * \a element. */ void -t8_dtri_sibling (const t8_dtri_t *elem, int sibid, t8_dtri_t *sibling); +t8_dtri_sibling (const t8_dtri_t *element, int sibid, t8_dtri_t *sibling); /** Compute the face neighbor of a triangle. - * \param [in] t Input triangle. + * \param [in] element Input triangle. * \param [in] face The face across which to generate the neighbor. - * \param [in,out] n Existing triangle whose data will be filled. - * \note \a t may point to the same triangle as \a n. + * \param [in,out] neigh Existing triangle whose data will be filled. + * \note \a element may point to the same triangle as \a neigh. */ int -t8_dtri_face_neighbour (const t8_dtri_t *t, int face, t8_dtri_t *n); +t8_dtri_face_neighbour (const t8_dtri_t *element, int face, t8_dtri_t *neigh); /** Computes the nearest common ancestor of two triangles in the same tree. - * \param [in] t1 First input triangle. - * \param [in] t2 Second input triangle. - * \param [in,out] r Existing triangle whose data will be filled. - * \note \a t1, \a t2, \a r may point to the same quadrant. + * \param [in] element1 First input triangle. + * \param [in] element2 Second input triangle. + * \param [in,out] nca Existing triangle whose data will be filled. + * \note \a element1, \a element2, \a nca may point to the same quadrant. */ void -t8_dtri_nearest_common_ancestor (const t8_dtri_t *t1, const t8_dtri_t *t2, t8_dtri_t *r); +t8_dtri_nearest_common_ancestor (const t8_dtri_t *element1, const t8_dtri_t *element2, t8_dtri_t *nca); /** Given a triangle and a face of the triangle, compute all children of the triangle that touch the face. - * \param [in] tri The triangle. - * \param [in] face A face of \a tri. - * \param [in,out] children Allocated triangles, in which the children of \a tri that share a face with \a face are + * \param [in] element The triangle. + * \param [in] face A face of \a element. + * \param [in,out] children Allocated triangles, in which the children of \a element that share a face with \a face are * stored. They will be stored in order of their child_id. * \param [in] num_children The number of triangles in \a children. Must match the number of children that touch * \a face. + * \param [in,out] child_indices The indices of the children in \a children. Only filled if this is null previously. */ void -t8_dtri_children_at_face (const t8_dtri_t *tri, int face, t8_dtri_t *children[], int num_children, int *child_indices); +t8_dtri_children_at_face (const t8_dtri_t *element, int face, t8_dtri_t *children[], int num_children, + int *child_indices); /** Given a face of a triangle and a child number of a child of that face, return the face number of the child of the * triangle that matches the child face. @@ -198,25 +200,25 @@ t8_dtri_face_parent_face (const t8_dtri_t *triangle, int face); /** Given a triangle and a face of this triangle. If the face lies on the tree boundary, return the face number of the * tree face. If not the return value is arbitrary. - * \param [in] t The triangle. - * \param [in] face The index of a face of \a t. + * \param [in] element The triangle. + * \param [in] face The index of a face of \a element. * \return The index of the tree face that \a face is a subface of, if \a face is on a tree boundary. Any arbitrary - * integer if \a t is not at a tree boundary. + * integer if \a element is not at a tree boundary. * \note For boundary triangles, this function is the inverse of \ref t8_dtri_root_face_to_face */ int -t8_dtri_tree_face (t8_dtri_t *t, int face); +t8_dtri_tree_face (t8_dtri_t *element, int face); /** Given a triangle and a face of the root triangle. If the triangle lies on the tree boundary, return the * corresponding face number of the triangle. If not the return value is arbitrary. - * \param [in] t The triangle. - * \param [in] face The index of a face of the root element. - * \return The index of the face of \a t that is a subface of \a face, if \a t is on the tree boundary. - * Any arbitrary integer if \a t is not at a tree boundary. + * \param [in] element The triangle. + * \param [in] root_face The index of a face of the root element. + * \return The index of the face of \a element that is a subface of \a root_face, if \a element is on the tree boundary. + * Any arbitrary integer if \a element is not at a tree boundary. * \note For boundary triangles, this function is the inverse of \ref t8_dtri_tree_face */ int -t8_dtri_root_face_to_face (t8_dtri_t *t, int root_face); +t8_dtri_root_face_to_face (t8_dtri_t *element, int root_face); /** Suppose we have two trees that share a common triangle f. Given a triangle e that is a subface of f in one of the * trees and given the orientation of the tree connection, construct the face triangle of the respective tree neighbor @@ -238,179 +240,204 @@ t8_dtri_transform_face (const t8_dtri_t *trianglein, t8_dtri_t *triangle2, int o int is_smaller_face); /** Test if a triangle lies inside of the root triangle, that is the triangle of level 0, anchor node (0,0) and type 0. - * \param [in] t Input triangle. - * \return true If \a t lies inside of the root triangle. + * \param [in] element Input triangle. + * \return true If \a element lies inside of the root triangle. */ int -t8_dtri_is_inside_root (t8_dtri_t *t); +t8_dtri_is_inside_root (t8_dtri_t *element); /** Compute whether a given triangle shares a given face with its root tree. - * \param [in] t The input triangle. - * \param [in] face A face of \a t. + * \param [in] element The input triangle. + * \param [in] face A face of \a element. * \return True if \a face is a subface of the triangle's root element. */ int -t8_dtri_is_root_boundary (const t8_dtri_t *t, int face); +t8_dtri_is_root_boundary (const t8_dtri_t *element, int face); /** Test if two triangles have the same coordinates, type and level. - * \return true if \a t1 describes the same triangle as \a t2. + * \return true if \a element1 describes the same triangle as \a element2. */ int -t8_dtri_is_equal (const t8_dtri_t *t1, const t8_dtri_t *t2); +t8_dtri_is_equal (const t8_dtri_t *element1, const t8_dtri_t *element2); /** Test if two triangles are siblings. - * \param [in] t1 First triangle to be tested. - * \param [in] t2 Second triangle to be tested. - * \return true if \a t1 is equal to or a sibling of \a t2. * + * \param [in] element1 First triangle to be tested. + * \param [in] element2 Second triangle to be tested. + * \return true if \a element1 is equal to or a sibling of \a element2. */ int -t8_dtri_is_sibling (const t8_dtri_t *t1, const t8_dtri_t *t2); +t8_dtri_is_sibling (const t8_dtri_t *element1, const t8_dtri_t *element2); /** Test if a triangle is the parent of another triangle. - * \param [in] t triangle to be tested. - * \param [in] c Possible child triangle. - * \return true if \a t is the parent of \a c. + * \param [in] element triangle to be tested. + * \param [in] child Possible child triangle. + * \return true if \a element is the parent of \a child. */ int -t8_dtri_is_parent (const t8_dtri_t *t, const t8_dtri_t *c); +t8_dtri_is_parent (const t8_dtri_t *element, const t8_dtri_t *child); /** Test if a triangle is an ancestor of another triangle. - * \param [in] t triangle to be tested. - * \param [in] c Descendent triangle. - * \return true if \a t is equal to or an ancestor of \a c. + * \param [in] element triangle to be tested. + * \param [in] child Descendent triangle. + * \return true if \a element is equal to or an ancestor of \a child. */ int -t8_dtri_is_ancestor (const t8_dtri_t *t, const t8_dtri_t *c); +t8_dtri_is_ancestor (const t8_dtri_t *element, const t8_dtri_t *child); /** Computes the linear position of a triangle in a uniform grid. - * \param [in] t triangle whose id will be computed. + * \param [in] element triangle whose id will be computed. * \param [in] level level of uniform grid to be considered. * \return Returns the linear position of this triangle on a grid of level \a level. * \note This id is not the Morton index. */ t8_linearidx_t -t8_dtri_linear_id (const t8_dtri_t *t, int level); +t8_dtri_linear_id (const t8_dtri_t *element, int level); /** * Same as init_linear_id, but we only consider the subtree. Used for computing the index of a tetrahedron lying in a * pyramid - * \param [in, out] t Existing triangle whose data will be filled + * \param [in, out] element Existing triangle whose data will be filled * \param [in] id Index to be considered * \param [in] start_level The level of the root of the subtree * \param [in] end_level Level of uniform grid to be considered * \param [in] parenttype The type of the parent. */ void -t8_dtri_init_linear_id_with_level (t8_dtri_t *t, t8_linearidx_t id, const int start_level, const int end_level, +t8_dtri_init_linear_id_with_level (t8_dtri_t *element, t8_linearidx_t id, const int start_level, const int end_level, t8_dtri_type_t parenttype); /** Initialize a triangle as the triangle with a given global id in a uniform refinement of a given level. * - * \param [in,out] t Existing triangle whose data will be filled. + * \param [in,out] element Existing triangle whose data will be filled. * \param [in] id Index to be considered. * \param [in] level level of uniform grid to be considered. */ void -t8_dtri_init_linear_id (t8_dtri_t *t, t8_linearidx_t id, int level); +t8_dtri_init_linear_id (t8_dtri_t *element, t8_linearidx_t id, int level); /** Initialize a triangle as the root triangle (type 0 at level 0) - * \param [in,out] t Existing triangle whose data will be filled. + * \param [in,out] element Existing triangle whose data will be filled. */ void -t8_dtri_init_root (t8_dtri_t *t); +t8_dtri_init_root (t8_dtri_t *element); /** Computes the successor of a triangle in a uniform grid of level \a level. - * \param [in] t triangle whose id will be computed. + * \param [in] element triangle whose id will be computed. * \param [in,out] s Existing triangle whose data will be filled with the * data of t's successor on level \a level. * \param [in] level level of uniform grid to be considered. */ void -t8_dtri_successor (const t8_dtri_t *t, t8_dtri_t *s, int level); +t8_dtri_successor (const t8_dtri_t *element, t8_dtri_t *s, int level); /** Compute the first descendant of a triangle at a given level. This is the descendant of * the triangle in a uniform maxlevel refinement that has the smaller id. - * \param [in] t Triangle whose descendant is computed. - * \param [in] level A given level. Must be grater or equal to \a t's level. + * \param [in] element Triangle whose descendant is computed. + * \param [in] level A given level. Must be grater or equal to \a element's level. * \param [out] s Existing triangle whose data will be filled with the data * of t's first descendant. */ void -t8_dtri_first_descendant (const t8_dtri_t *t, t8_dtri_t *s, int level); +t8_dtri_first_descendant (const t8_dtri_t *element, t8_dtri_t *s, int level); /** Compute the last descendant of a triangle at a given level. This is the descendant of * the triangle in a uniform maxlevel refinement that has the biggest id. - * \param [in] t Triangle whose descendant is computed. - * \param [in] level A given level. Must be grater or equal to \a t's level. + * \param [in] element Triangle whose descendant is computed. + * \param [in] level A given level. Must be grater or equal to \a element's level. * \param [out] s Existing triangle whose data will be filled with the data * of t's last descendant. */ void -t8_dtri_last_descendant (const t8_dtri_t *t, t8_dtri_t *s, int level); +t8_dtri_last_descendant (const t8_dtri_t *element, t8_dtri_t *s, int level); /** Compute the descendant of a triangle in a given corner. - * \param [in] t Triangle whose descendant is computed. + * \param [in] element Triangle whose descendant is computed. * \param [out] s Existing triangle whose data will be filled with the data * of t's descendant in \a corner. * \param [in] corner The corner in which the descendant should lie. * \param [in] level The refinement level of the descendant. Must be greater or - * equal to \a t's level. + * equal to \a element's level. */ void -t8_dtri_corner_descendant (const t8_dtri_t *t, t8_dtri_t *s, int corner, int level); +t8_dtri_corner_descendant (const t8_dtri_t *element, t8_dtri_t *s, int corner, int level); /** Computes the predecessor of a triangle in a uniform grid of level \a level. - * \param [in] t triangle whose id will be computed. + * \param [in] element triangle whose id will be computed. * \param [in,out] s Existing triangle whose data will be filled with the - * data of t's predecessor on level \a level. + * data of \a element's predecessor on level \a level. * \param [in] level level of uniform grid to be considered. */ void -t8_dtri_predecessor (const t8_dtri_t *t, t8_dtri_t *s, int level); +t8_dtri_predecessor (const t8_dtri_t *element, t8_dtri_t *s, int level); /** Compute the position of the ancestor of this child at level \a level within its siblings. - * \param [in] t triangle to be considered. + * \param [in] element triangle to be considered. * \param [in] level level to be considered. * \return Returns its child id in 0..3 */ int -t8_dtri_ancestor_id (const t8_dtri_t *t, int level); +t8_dtri_ancestor_id (const t8_dtri_t *element, int level); /** Compute the position of the ancestor of this child at level \a level within its siblings. - * \param [in] t triangle to be considered. + * \param [in] element triangle to be considered. * \return Returns its child id in 0..3 */ int -t8_dtri_child_id (const t8_dtri_t *t); +t8_dtri_child_id (const t8_dtri_t *element); /** Return the level of a triangle. - * \param [in] t triangle to be considered. - * \return The level of \a t. + * \param [in] element triangle to be considered. + * \return The level of \a element. */ int -t8_dtri_get_level (const t8_dtri_t *t); +t8_dtri_get_level (const t8_dtri_t *element); /** Query whether all entries of a triangle are in valid ranges. - * \param [in] t triangle to be considered. - * \return True, if \a t is a valid triangle and it is safe to call any function on \a t. False otherwise. + * \param [in] element triangle to be considered. + * \return True, if \a element is a valid triangle and it is safe to call any function on \a element. False otherwise. */ int -t8_dtri_is_valid (const t8_dtri_t *t); +t8_dtri_is_valid (const t8_dtri_t *element); #if T8_ENABLE_DEBUG /** Set sensible default values for a triangle. - * \param [in,out] t A triangle. + * \param [in,out] element A triangle. */ void -t8_dtri_init (t8_dtri_t *t); +t8_dtri_init (t8_dtri_t *element); #endif +/** Packs an array of triangle elements into contiguous memory. + * Triangles are packed as x and y coordinates, type and level. + * Compare MPI_Pack function. + * \param [in] elements The element array to be packed. + * \param [in] count Number of elements to be packed. + * \param [out] send_buffer Output buffer. + * \param [in] buffer_size Output buffer size. + * \param [in,out] position Current position in buffer. + * \param [in] comm Communicator. + */ void t8_dtri_element_pack (t8_dtri_t **const elements, const unsigned int count, void *send_buffer, const int buffer_size, int *position, sc_MPI_Comm comm); +/** Returns the upper bound on the amount of space needed to pack \a count elements. + * Compare MPI_Pack_size function. + * \param [in] count Number of packed elements. + * \param [in] comm Communicator. + * \param [out] pack_size Upper bound on size of packed elements. + */ void t8_dtri_element_pack_size (const unsigned int count, sc_MPI_Comm comm, int *pack_size); +/** Unpack a buffer of triangle elements into contiguous memory. + * Compare MPI_Unpack function. + * \param [in] recvbuf Buffer to be unpacked. + * \param [in] buffer_size Size of \a recvbuf. + * \param [in,out] position Current position in buffer. + * \param [out] elements Array with the triangle elements (output buffer). + * \param [in] count Number of elements to be unpacked. + * \param [in] comm Communicator. + */ void t8_dtri_element_unpack (void *recvbuf, const int buffer_size, int *position, t8_dtri_t **elements, const unsigned int count, sc_MPI_Comm comm); diff --git a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx index 72b0fc180d..a6b61c11b2 100644 --- a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx +++ b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx @@ -310,12 +310,12 @@ t8_default_scheme_vertex::element_get_reference_coords ([[maybe_unused]] const t #if T8_ENABLE_DEBUG int -t8_default_scheme_vertex::element_is_valid ([[maybe_unused]] const t8_element_t *elem) +t8_default_scheme_vertex::element_is_valid ([[maybe_unused]] const t8_element_t *element) { - /* A vertex is always valid, since it only saves the level as uint8, - which therefore automatically is >= 0 and <= 255 (=MAXLEVEL)*/ - return 1; + /* Check maxlevel, nothing else is saved in a vertex. */ + const t8_dvertex_t *vertex = (t8_dvertex_t *) element; + return vertex->level <= T8_DVERTEX_MAXLEVEL; } void diff --git a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.hxx b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.hxx index 2fab3b150e..471cb8c896 100644 --- a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.hxx +++ b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.hxx @@ -30,6 +30,7 @@ /* Forward declaration of the scheme so we can use it as an argument in the eclass schemes function. */ class t8_scheme; +/** Default implementation of the scheme for the vertex element class. */ class t8_default_scheme_vertex: public t8_default_scheme_common { public: /** Constructor which calls the specialized constructor for the base. */ @@ -46,7 +47,7 @@ class t8_default_scheme_vertex: public t8_default_scheme_common= 1, since we count the element itself as a sibling. */ int -t8_element_get_num_siblings (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_num_siblings (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); -/** Compute a specific sibling of a given element \b elem and store it in \b sibling. +/** Compute a specific sibling of a given element \b element and store it in \b sibling. * \b sibling needs to be an existing element. No memory is allocated by this function. - * \b elem and \b sibling can point to the same element, then the entries of - * \b elem are overwritten by the ones of its i-th sibling. + * \b element and \b sibling can point to the same element, then the entries of + * \b element are overwritten by the ones of its i-th sibling. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element whose sibling will be computed. + * \param [in] element The element whose sibling will be computed. * \param [in] sibid The id of the sibling computed. * \param [in,out] sibling This element's entries will be overwritten by those - * of \b elem's sibid-th sibling. + * of \b element's sibid-th sibling. * The storage for this element must exist * and match the element class of the sibling. */ void -t8_element_get_sibling (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_sibling (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int sibid, t8_element_t *sibling); /** Compute the number of corners of an element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \return The number of corners of \a element. */ int -t8_element_get_num_corners (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_num_corners (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Compute the number of faces of an element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \return The number of faces of \a element. */ int -t8_element_get_num_faces (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_num_faces (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Compute the maximum number of faces of a given element and all of its * descendants. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \return The number of faces of \a element. */ int -t8_element_get_max_num_faces (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_max_num_faces (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Compute the number of children of an element when it is refined. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \return The number of children of \a element. */ int -t8_element_get_num_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_num_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Return the max number of children of an eclass. * \param [in] scheme The scheme of the forest. @@ -229,12 +230,12 @@ t8_get_max_num_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class /** Compute the number of children of an element's face when the element is refined. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. - * \param [in] face A face of \a elem. - * \return The number of children of \a face if \a elem is to be refined. + * \param [in] element The element. + * \param [in] face A face of \a element. + * \return The number of children of \a face if \a element is to be refined. */ int -t8_element_get_num_face_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_num_face_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face); /** Return the corner number of an element's face corner. @@ -258,7 +259,7 @@ t8_element_get_num_face_children (const t8_scheme_c *scheme, const t8_eclass_t t * 'outside' of the element. */ int -t8_element_get_face_corner (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_face_corner (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face, const int corner); /** Compute the face numbers of the faces sharing an element's corner. @@ -276,57 +277,57 @@ t8_element_get_face_corner (const t8_scheme_c *scheme, const t8_eclass_t tree_cl * \return The face number of the \a face-th face at \a corner. */ int -t8_element_get_corner_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_corner_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int corner, const int face); /** Construct the child element of a given number. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem This must be a valid element, bigger than maxlevel. + * \param [in] element This must be a valid element, bigger than maxlevel. * \param [in] childid The number of the child to construct. * \param [in,out] child The storage for this element must exist. * On output, a valid element. - * It is valid to call this function with elem = child. + * It is valid to call this function with element = child. */ void -t8_element_get_child (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_child (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int childid, t8_element_t *child); /** Construct all children of a given element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem This must be a valid element, bigger than maxlevel. + * \param [in] element This must be a valid element, bigger than maxlevel. * \param [in] length The length of the output array \a c must match * the number of children. * \param [in,out] c The storage for these \a length elements must exist * and match the element class in the children's ordering. * On output, all children are valid. - * It is valid to call this function with elem = c[0]. + * It is valid to call this function with element = c[0]. * \see t8_element_num_children */ void -t8_element_get_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_children (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int length, t8_element_t *c[]); /** Compute the child id of an element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem This must be a valid element. - * \return The child id of elem. + * \param [in] element This must be a valid element. + * \return The child id of element. */ int -t8_element_get_child_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_child_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Compute the ancestor id of an element, that is the child id * at a given level. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem This must be a valid element. - * \param [in] level A refinement level. Must satisfy \a level < elem.level - * \return The child_id of \a elem in regard to its \a level ancestor. + * \param [in] element This must be a valid element. + * \param [in] level A refinement level. Must satisfy \a level < element.level + * \return The child_id of \a element in regard to its \a level ancestor. */ int -t8_element_get_ancestor_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_ancestor_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int level); /** Query whether a given set of elements is a family or not. @@ -358,35 +359,35 @@ t8_element_get_nca (const t8_scheme_c *scheme, const t8_eclass_t tree_class, con /** Compute the shape of the face of an element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. - * \param [in] face A face of \a elem. + * \param [in] element The element. + * \param [in] face A face of \a element. * \return The element shape of the face. * I.e. T8_ECLASS_LINE for quads, T8_ECLASS_TRIANGLE for tets * and depending on the face number either T8_ECLASS_QUAD or * T8_ECLASS_TRIANGLE for prisms. */ t8_element_shape_t -t8_element_get_face_shape (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_face_shape (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face); /** Given an element and a face of the element, compute all children of * the element that touch the face. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. - * \param [in] face A face of \a elem. - * \param [in,out] children Allocated elements, in which the children of \a elem + * \param [in] element The element. + * \param [in] face A face of \a element. + * \param [in,out] children Allocated elements, in which the children of \a element * that share a face with \a face are stored. * They will be stored in order of their linear id. * \param [in] num_children The number of elements in \a children. Must match * the number of children that touch \a face. - * \ref t8_element_num_face_children + * \ref t8_scheme::element_get_num_face_children * \param [in,out] child_indices If not NULL, an array of num_children integers must be given, * on output its i-th entry is the child_id of the i-th face_child. - * It is valid to call this function with elem = children[0]. + * It is valid to call this function with element = children[0]. */ void -t8_element_get_children_at_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_children_at_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *children[], const int num_children, int *child_indices); /** Given a face of an element and a child number of a child of that face, return the face number @@ -397,22 +398,22 @@ t8_element_get_children_at_face (const t8_scheme_c *scheme, const t8_eclass_t tr * | | | x | x--x * | | | | | * x ---- x x x ---- x - * elem face face_child Returns the face number f + * element face face_child Returns the face number f * \endverbatim * * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \param [in] face Then number of the face. * \param [in] face_child A number 0 <= \a face_child < num_face_children, - * specifying a child of \a elem that shares a face with \a face. + * specifying a child of \a element that shares a face with \a face. * These children are counted in linear order. This coincides with - * the order of children from a call to \ref t8_element_children_at_face. - * \return The face number of the face of a child of \a elem + * the order of children from a call to \ref t8_scheme::element_get_children_at_face. + * \return The face number of the face of a child of \a element * that coincides with \a face_child. */ int -t8_element_face_get_child_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_face_get_child_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face, const int face_child); /** Given a face of an element return the face number @@ -421,14 +422,14 @@ t8_element_face_get_child_face (const t8_scheme_c *scheme, const t8_eclass_t tre * * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. + * \param [in] element The element. * \param [in] face Then number of the face. - * \return If \a face of \a elem is also a face of \a elem's parent, + * \return If \a face of \a element is also a face of \a element's parent, * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ int -t8_element_face_get_parent_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_face_get_parent_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face); /** Given an element and a face of this element. If the face lies on the @@ -436,14 +437,14 @@ t8_element_face_get_parent_face (const t8_scheme_c *scheme, const t8_eclass_t tr * If not the return value is arbitrary. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element. - * \param [in] face The index of a face of \a elem. + * \param [in] element The element. + * \param [in] face The index of a face of \a element. * \return The index of the tree face that \a face is a subface of, if * \a face is on a tree boundary. * Any arbitrary integer if \a is not at a tree boundary. */ int -t8_element_get_tree_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_tree_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face); /** Suppose we have two trees that share a common face f. @@ -479,79 +480,81 @@ t8_element_transform_face (const t8_scheme_c *scheme, const t8_eclass_t tree_cla * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. * \param [in] face A face element. - * \param [in,out] elem An allocated element. The entries will be filled with + * \param [in,out] element An allocated element. The entries will be filled with * the data of the element that has \a face as a face and * lies within the root tree. * \param [in] root_face The index of the face of the root tree in which \a face * lies. - * \return The face number of the face of \a elem that coincides + * \return The face number of the face of \a element that coincides * with \a face. */ int t8_element_extrude_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *face, - t8_element_t *elem, int root_face); + t8_element_t *element, int root_face); /** Construct the boundary element at a specific face. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The input element. + * \param [in] element The input element. * \param [in] face The index of the face of which to construct the * boundary element. * \param [in,out] boundary An allocated element of dimension of \a element * minus 1. The entries will be filled with the entries * of the face of \a element. - * If \a elem is of class T8_ECLASS_VERTEX, then \a boundary must be NULL + * If \a element is of class T8_ECLASS_VERTEX, then \a boundary must be NULL * and will not be modified. */ void -t8_element_get_boundary_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_boundary_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *boundary); /** Construct the first descendant of an element at a given level that touches a given face. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \param [in, out] first_desc An allocated element. This element's data will be - * filled with the data of the first descendant of \a elem + * filled with the data of the first descendant of \a element * that shares a face with \a face. * \param [in] level The level, at which the first descendant is constructed */ void -t8_element_get_first_descendant_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, - const int face, t8_element_t *first_desc, const int level); +t8_element_get_first_descendant_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, + const t8_element_t *element, const int face, t8_element_t *first_desc, + const int level); /** Construct the last descendant of an element at a given level that touches a given face. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \param [in, out] last_desc An allocated element. This element's data will be - * filled with the data of the last descendant of \a elem + * filled with the data of the last descendant of \a element * that shares a face with \a face. * \param [in] level The level, at which the last descendant is constructed */ void -t8_element_get_last_descendant_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, - const int face, t8_element_t *last_desc, const int level); +t8_element_get_last_descendant_face (const t8_scheme_c *scheme, const t8_eclass_t tree_class, + const t8_element_t *element, const int face, t8_element_t *last_desc, + const int level); /** Compute whether a given element shares a given face with its root tree. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \return True if \a face is a subface of the element's root element. */ int -t8_element_is_root_boundary (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_is_root_boundary (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int face); /** Construct the face neighbor of a given element if this face neighbor * is inside the root tree. Return 0 otherwise. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element to be considered. - * \param [in,out] neigh If the face neighbor of \a elem along \a face is inside + * \param [in] element The element to be considered. + * \param [in,out] neigh If the face neighbor of \a element along \a face is inside * the root tree, this element's data is filled with the * data of the face neighbor. Otherwise the data can be modified * arbitrarily. @@ -564,65 +567,69 @@ t8_element_is_root_boundary (const t8_scheme_c *scheme, const t8_eclass_t tree_c * on output. */ int -t8_element_get_face_neighbor_inside (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, - t8_element_t *neigh, const int face, int *neigh_face); +t8_element_get_face_neighbor_inside (const t8_scheme_c *scheme, const t8_eclass_t tree_class, + const t8_element_t *element, t8_element_t *neigh, const int face, int *neigh_face); /** Return the shape of an allocated element according its type. * For example, a child of an element can be an element of a different shape * and has to be handled differently - according to its shape. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. -* \param [in] elem The element to be considered +* \param [in] element The element to be considered * \return The shape of the element as an eclass */ t8_element_shape_t -t8_element_get_shape (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_get_shape (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** Initialize the entries of an allocated element according to a * given linear id in a uniform refinement. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in,out] elem The element whose entries will be set. + * \param [in,out] element The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ void -t8_element_set_linear_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, t8_element_t *elem, const int level, - const t8_linearidx_t id); +t8_element_set_linear_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, t8_element_t *element, + const int level, const t8_linearidx_t id); /** Compute the linear id of a given element in a hypothetical uniform * refinement of a given level. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element whose id we compute. + * \param [in] element The element whose id we compute. * \param [in] level The level of the uniform refinement to consider. * \return The linear id of the element. */ t8_linearidx_t -t8_element_get_linear_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_linear_id (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int level); /** Compute the first descendant of a given element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element whose descendant is computed. - * \param [out] desc The first element in a uniform refinement of \a elem - * of the maximum possible level. + * \param [in] element The element whose descendant is computed. + * \param [out] desc The first element in a uniform refinement of \a element + * at level \a level. + * \param [in] level The uniform refinement level at which the descendant is computed. + * \a level must be greater or equal to the level of \a element. */ void -t8_element_get_first_descendant (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_first_descendant (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *desc, const int level); /** Compute the last descendant of a given element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element whose descendant is computed. - * \param [out] desc The last element in a uniform refinement of \a elem + * \param [in] element The element whose descendant is computed. + * \param [out] desc The last element in a uniform refinement of \a element * of the maximum possible level. + * \param [in] level The uniform refinement level at which the descendant is computed. + * \a level must be greater or equal to the level of \a element. */ void -t8_element_get_last_descendant (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_get_last_descendant (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *desc, const int level); /** Construct the successor in a uniform refinement of a given element. @@ -630,7 +637,6 @@ t8_element_get_last_descendant (const t8_scheme_c *scheme, const t8_eclass_t tre * \param [in] tree_class The eclass of tree the elements are part of. * \param [in] elem1 The element whose successor should be constructed. * \param [in,out] elem2 The element whose entries will be set. - * \param [in] level The level of the uniform refinement to consider. */ void t8_element_get_successor (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem1, @@ -638,32 +644,34 @@ t8_element_get_successor (const t8_scheme_c *scheme, const t8_eclass_t tree_clas /** Compute the coordinates of a given element vertex inside a reference tree * that is embedded into [0,1]^d (d = dimension). - * \param [in] t The element to be considered. - * \param [in] vertex The id of the vertex whose coordinates shall be computed. - * \param [out] coords An array of at least as many doubles as the element's dimension + * \param [in] scheme The scheme of the forest. + * \param [in] tree_class The eclass of tree the elements are part of. + * \param [in] element The element to be considered. + * \param [in] vertex The id of the vertex whose coordinates shall be computed. + * \param [out] coords An array of at least as many doubles as the element's dimension * whose entries will be filled with the coordinates of \a vertex. - * \warning coords should be zero-initialized, as only the first d coords will be set, but when used elsewhere + * \warning coords should be zero-initialized, as only the first d coords will be set, but when used elsewhere * all coords might be used. */ void -t8_element_get_vertex_reference_coords (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *t, - const int vertex, double coords[]); +t8_element_get_vertex_reference_coords (const t8_scheme_c *scheme, const t8_eclass_t tree_class, + const t8_element_t *element, const int vertex, double coords[]); /** Count how many leaf descendants of a given uniform level an element would produce. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] t The element to be checked. + * \param [in] element The element to be checked. * \param [in] level A refinement level. - * \return Suppose \a t is uniformly refined up to level \a level. The return value + * \return Suppose \a element is uniformly refined up to level \a level. The return value * is the resulting number of elements (of the given level). - * If \a level < t8_element_get_level(t), the return value should be 0. + * If \a level < t8_element_get_level(element), the return value should be 0. * - * Example: If \a t is a line element that refines into 2 line elements on each level, + * Example: If \a element is a line element that refines into 2 line elements on each level, * then the return value is max(0, 2^{\a level - level(\a t)}). - * Thus, if \a t's level is 0, and \a level = 3, the return value is 2^3 = 8. + * Thus, if \a element's level is 0, and \a level = 3, the return value is 2^3 = 8. */ t8_gloidx_t -t8_element_count_leaves (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *t, +t8_element_count_leaves (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, const int level); /** Count how many leaf descendants of a given uniform level the root element will produce. @@ -686,20 +694,20 @@ t8_element_count_leaves_from_root (const t8_scheme_c *scheme, const t8_eclass_t * and other membervariables do have meaningful values. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element to be checked. - * \return True if \a elem is safe to use. False otherwise. + * \param [in] element The element to be checked. + * \return True if \a element is safe to use. False otherwise. * \note An element that is constructed with \ref t8_element_new * must pass this test. - * \note An element for which \ref t8_element_init was called must pass + * \note An element for which \ref t8_scheme::element_init was called must pass * this test. * \note This function is used for debugging to catch certain errors. * These can for example occur when an element points to a region * of memory which should not be interpreted as an element. - * \note We recommend to use the assertion T8_ASSERT (t8_element_is_valid (elem)) + * \note We recommend to use the assertion T8_ASSERT (t8_element_is_valid (element)) * in the implementation of each of the functions in this file. */ int -t8_element_is_valid (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_is_valid (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** * Print a given element. For a example for a triangle print the coordinates @@ -708,19 +716,22 @@ t8_element_is_valid (const t8_scheme_c *scheme, const t8_eclass_t tree_class, co * * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in] elem The element to print + * \param [in] element The element to print */ void -t8_element_debug_print (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem); +t8_element_debug_print (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element); /** * \brief Fill a string with readable information about the element * - * \param[in] elem The element to translate into human-readable information + * \param [in] scheme The scheme of the forest. + * \param [in] tree_class The eclass of the current tree. + * \param[in] element The element to translate into human-readable information. * \param[in, out] debug_string The string to fill. + * \param[in] string_size The length of \a debug_string. */ void -t8_element_to_string (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *elem, +t8_element_to_string (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const t8_element_t *element, char *debug_string, const int string_size); #endif @@ -732,24 +743,43 @@ t8_element_to_string (const t8_scheme_c *scheme, const t8_eclass_t tree_class, c * On output all these pointers will point to an allocated and initialized element. * \note Not every element that is created in t8code will be created by a call * to this function. However, if an element is not created using \ref t8_element_new, - * then it is guaranteed that \ref t8_element_init is called on it. + * then it is guaranteed that \ref t8_scheme::element_init is called on it. * \note In debugging mode, an element that was created with \ref t8_element_new * must pass \ref t8_element_is_valid. - * \note If an element was created by \ref t8_element_new then \ref t8_element_init + * \note If an element was created by \ref t8_element_new then \ref t8_scheme::element_init * may not be called for it. Thus, \ref t8_element_new should initialize an element - * in the same way as a call to \ref t8_element_init would. + * in the same way as a call to \ref t8_scheme::element_init would. * \see t8_element_init - * \see t8_element_is_valid + * \see element_is_valid */ void t8_element_new (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const int length, t8_element_t **elems); +/** Initialize an array of allocated elements. +* \param [in] scheme The scheme to use. +* \param [in] tree_class The eclass of the current tree. +* \param [in] length The number of elements to be initialized. +* \param [in,out] elem On input an array of \a length many allocated +* elements. +* \note In debugging mode, an element that was passed to \ref t8_element_init +* must pass \ref t8_element_is_valid. +* \note If an element was created by \ref t8_element_new then \ref t8_element_init +* may not be called for it. Thus, \ref t8_element_init should initialize an element +* in the same way as a call to \ref t8_element_new would. +* \note Every call to \ref t8_element_init must be matched by a call to \ref t8_element_deinit +* \see t8_element_deinit +* \see t8_element_new +* \see t8_element_is_valid +*/ +void +t8_element_init (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const int length, t8_element_t *elem); + /** Deallocate an array of elements. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. * \param [in] length The number of elements in the array. * \param [in,out] elems On input an array of \b length many allocated element pointers. On output all these pointers - * will be freed. \b elem itself will not be freed by this function. + * will be freed. \b element itself will not be freed by this function. */ void t8_element_destroy (const t8_scheme_c *scheme, const t8_eclass_t tree_class, const int length, t8_element_t **elems); @@ -757,10 +787,10 @@ t8_element_destroy (const t8_scheme_c *scheme, const t8_eclass_t tree_class, con /** Fills an element with the root element. * \param [in] scheme The scheme of the forest. * \param [in] tree_class The eclass of tree the elements are part of. - * \param [in,out] elem The element to be filled with root. + * \param [in,out] element The element to be filled with root. */ void -t8_element_set_to_root (const t8_scheme_c *scheme, const t8_eclass_t tree_class, t8_element_t *elem); +t8_element_set_to_root (const t8_scheme_c *scheme, const t8_eclass_t tree_class, t8_element_t *element); /** Pack multiple elements into contiguous memory, so they can be sent via MPI. * \param [in] scheme The scheme of the forest. diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index f97d835729..705aa76f54 100644 --- a/src/t8_schemes/t8_scheme.hxx +++ b/src/t8_schemes/t8_scheme.hxx @@ -156,11 +156,12 @@ class t8_scheme { return std::holds_alternative (eclass_schemes[tree_class]); } - /** Get the eclass an eclass scheme is valid for. \Note: This function should return the input value as long as the - * eclass schemes are soreted correctly. In the future, the trees will access the schemes by a key and then this - * function will make more sense. + /** Get the eclass an eclass scheme is valid for. * \param [in] tree_class The eclass of the current tree. * \return The valid tree class for the eclass scheme. + * \note This function should return the input value as long as the + * eclass schemes are soreted correctly. In the future, the trees will access the schemes by a key and then this + * function will make more sense. */ inline t8_eclass_t get_eclass_scheme_eclass (const t8_eclass_t tree_class) const @@ -203,13 +204,13 @@ class t8_scheme { /** Return the level of a particular element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose level should be returned. - * \return The level of \a elem. + * \param [in] element The element whose level should be returned. + * \return The level of \a element. */ inline int - element_get_level (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_level (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_level (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_get_level (element); }, eclass_schemes[tree_class]); }; /** Copy all entries of \a source to \a dest. \a dest must be an existing @@ -257,114 +258,117 @@ class t8_scheme { /** * Indicates if an element is refinable. Possible reasons for being not refinable could be * that the element has reached its max level. - * \param [in] elem The element to check. + * \param [in] tree_class The eclass of the current tree. + * \param [in] element The element to check. * \return True if the element is refinable. */ inline bool - element_is_refinable (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_is_refinable (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_is_refinable (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_is_refinable (element); }, + eclass_schemes[tree_class]); }; - /** Compute the parent of a given element \a elem and store it in \a parent. + /** Compute the parent of a given element \a element and store it in \a parent. * \a parent needs to be an existing element. No memory is allocated by this function. - * \a elem and \a parent can point to the same element, then the entries of - * \a elem are overwritten by the ones of its parent. + * \a element and \a parent can point to the same element, then the entries of + * \a element are overwritten by the ones of its parent. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose parent will be computed. + * \param [in] element The element whose parent will be computed. * \param [in,out] parent This element's entries will be overwritten by those - * of \a elem's parent. + * of \a element's parent. * The storage for this element must exist * and match the element class of the parent. * For a pyramid, for example, it may be either a - * tetrahedron or a pyramid depending on \a elem's childid. + * tetrahedron or a pyramid depending on \a element's childid. */ inline void - element_get_parent (const t8_eclass_t tree_class, const t8_element_t *elem, t8_element_t *parent) const + element_get_parent (const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *parent) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_parent (elem, parent); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_parent (element, parent); }, eclass_schemes[tree_class]); }; /** Compute the number of siblings of an element. That is the number of * Children of its parent. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. + * \param [in] element The element. * \return The number of siblings of \a element. * Note that this number is >= 1, since we count the element itself as a sibling. */ inline int - element_get_num_siblings (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_num_siblings (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_siblings (elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_siblings (element); }, eclass_schemes[tree_class]); }; - /** Compute a specific sibling of a given element \a elem and store it in \a sibling. + /** Compute a specific sibling of a given element \a element and store it in \a sibling. * \a sibling needs to be an existing element. No memory is allocated by this function. - * \a elem and \a sibling can point to the same element, then the entries of - * \a elem are overwritten by the ones of its sibid-th sibling. + * \a element and \a sibling can point to the same element, then the entries of + * \a element are overwritten by the ones of its sibid-th sibling. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose sibling will be computed. + * \param [in] element The element whose sibling will be computed. * \param [in] sibid The id of the sibling computed. * \param [in,out] sibling This element's entries will be overwritten by those - * of \a elem's sibid-th sibling. + * of \a element's sibid-th sibling. * The storage for this element must exist * and match the element class of the sibling. */ inline void - element_get_sibling (const t8_eclass_t tree_class, const t8_element_t *elem, const int sibid, + element_get_sibling (const t8_eclass_t tree_class, const t8_element_t *element, const int sibid, t8_element_t *sibling) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_sibling (elem, sibid, sibling); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_sibling (element, sibid, sibling); }, eclass_schemes[tree_class]); }; /** Compute the number of corners of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \return The number of corners of \a elem. + * \param [in] element The element. + * \return The number of corners of \a element. */ inline int - element_get_num_corners (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_num_corners (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_corners (elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_corners (element); }, eclass_schemes[tree_class]); }; /** Compute the number of faces of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \return The number of faces of \a elem. + * \param [in] element The element. + * \return The number of faces of \a element. */ inline int - element_get_num_faces (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_num_faces (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_faces (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_faces (element); }, + eclass_schemes[tree_class]); }; /** Compute the maximum number of faces of a given element and all of its * descendants. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \return The maximum number of faces of \a elem and its descendants. + * \param [in] element The element. + * \return The maximum number of faces of \a element and its descendants. */ inline int - element_get_max_num_faces (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_max_num_faces (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_max_num_faces (elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_max_num_faces (element); }, eclass_schemes[tree_class]); }; /** Return the number of children of an element when it is refined. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose number of children is returned. - * \return The number of children of \a elem if it is to be refined. + * \param [in] element The element whose number of children is returned. + * \return The number of children of \a element if it is to be refined. */ inline int - element_get_num_children (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_num_children (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_children (elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_children (element); }, eclass_schemes[tree_class]); }; @@ -380,14 +384,14 @@ class t8_scheme { /** Return the number of children of an element's face when the element is refined. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose face is considered. - * \param [in] face A face of \a elem. - * \return The number of children of \a face if \a elem is to be refined. + * \param [in] element The element whose face is considered. + * \param [in] face A face of \a element. + * \return The number of children of \a face if \a element is to be refined. */ inline int - element_get_num_face_children (const t8_eclass_t tree_class, const t8_element_t *elem, const int face) const + element_get_num_face_children (const t8_eclass_t tree_class, const t8_element_t *element, const int face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_face_children (elem, face); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_num_face_children (element, face); }, eclass_schemes[tree_class]); }; @@ -435,61 +439,62 @@ class t8_scheme { /** Construct the child element of a given number. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem This must be a valid element, bigger than maxlevel. + * \param [in] element This must be a valid element, bigger than maxlevel. * \param [in] childid The number of the child to construct. * \param [in,out] child The storage for this element must exist. * On output, a valid element. - * It is valid to call this function with elem = child. + * It is valid to call this function with element = child. */ inline void - element_get_child (const t8_eclass_t tree_class, const t8_element_t *elem, const int childid, + element_get_child (const t8_eclass_t tree_class, const t8_element_t *element, const int childid, t8_element_t *child) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_child (elem, childid, child); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_child (element, childid, child); }, eclass_schemes[tree_class]); }; /** Construct all children of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem This must be a valid element, bigger than maxlevel. + * \param [in] element This must be a valid element, bigger than maxlevel. * \param [in] length The length of the output array \a c must match * the number of children. * \param [in,out] c The storage for these \a length elements must exist. * On output, all children are valid. - * It is valid to call this function with elem = c[0]. - * \see t8_element_num_children + * It is valid to call this function with element = c[0]. + * \see element_get_num_children */ inline void - element_get_children (const t8_eclass_t tree_class, const t8_element_t *elem, const int length, + element_get_children (const t8_eclass_t tree_class, const t8_element_t *element, const int length, t8_element_t *c[]) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_children (elem, length, c); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_children (element, length, c); }, eclass_schemes[tree_class]); }; /** Compute the child id of an element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem This must be a valid element. - * \return The child id of elem. + * \param [in] element This must be a valid element. + * \return The child id of element. */ inline int - element_get_child_id (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_child_id (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_child_id (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_get_child_id (element); }, + eclass_schemes[tree_class]); }; /** Compute the ancestor id of an element, that is the child id * at a given level. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem This must be a valid element. - * \param [in] level A refinement level. Must satisfy \a level <= elem.level - * \return The child_id of \a elem in regard to its \a level ancestor. - * \note The ancestor id at elem.level is the same as the child id. + * \param [in] element This must be a valid element. + * \param [in] level A refinement level. Must satisfy \a level <= element.level + * \return The child_id of \a element in regard to its \a level ancestor. + * \note The ancestor id at element.level is the same as the child id. */ inline int - element_get_ancestor_id (const t8_eclass_t tree_class, const t8_element_t *elem, const int level) const + element_get_ancestor_id (const t8_eclass_t tree_class, const t8_element_t *element, const int level) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_ancestor_id (elem, level); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_ancestor_id (element, level); }, eclass_schemes[tree_class]); }; @@ -527,42 +532,42 @@ class t8_scheme { /** Compute the shape of the face of an element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \param [in] face A face of \a elem. + * \param [in] element The element. + * \param [in] face A face of \a element. * \return The element shape of the face. * I.e. T8_ECLASS_LINE for quads, T8_ECLASS_TRIANGLE for tets * and depending on the face number either T8_ECLASS_QUAD or * T8_ECLASS_TRIANGLE for prisms. */ inline t8_element_shape_t - element_get_face_shape (const t8_eclass_t tree_class, const t8_element_t *elem, const int face) const + element_get_face_shape (const t8_eclass_t tree_class, const t8_element_t *element, const int face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_face_shape (elem, face); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_face_shape (element, face); }, eclass_schemes[tree_class]); }; /** Given an element and a face of the element, compute all children of * the element that touch the face. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \param [in] face A face of \a elem. - * \param [in,out] children Allocated elements, in which the children of \a elem + * \param [in] element The element. + * \param [in] face A face of \a element. + * \param [in,out] children Allocated elements, in which the children of \a element * that share a face with \a face are stored. * They will be stored in order of their linear id. * \param [in] num_children The number of elements in \a children. Must match * the number of children that touch \a face. - * \ref t8_element_num_face_children + * \ref element_get_num_face_children * \param [in,out] child_indices If not NULL, an array of num_children integers must be given, * on output its i-th entry is the child_id of the i-th face_child. - * It is valid to call this function with elem = children[0]. + * It is valid to call this function with element = children[0]. */ inline void - element_get_children_at_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face, + element_get_children_at_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *children[], int num_children, int *child_indices) const { return std::visit ( [&] (auto &&scheme) { - return scheme.element_get_children_at_face (elem, face, children, num_children, child_indices); + return scheme.element_get_children_at_face (element, face, children, num_children, child_indices); }, eclass_schemes[tree_class]); }; @@ -575,24 +580,24 @@ class t8_scheme { | | | x | x--x | | | | | x ---- x x x ---- x - elem face face_child Returns the face number f + element face face_child Returns the face number f \endverbatim * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. + * \param [in] element The element. * \param [in] face Then number of the face. * \param [in] face_child A number 0 <= \a face_child < num_face_children, - * specifying a child of \a elem that shares a face with \a face. + * specifying a child of \a element that shares a face with \a face. * These children are counted in linear order. This coincides with - * the order of children from a call to \ref t8_element_children_at_face. - * \return The face number of the face of a child of \a elem + * the order of children from a call to \ref element_get_children_at_face. + * \return The face number of the face of a child of \a element * that coincides with \a face_child. */ inline int - element_face_get_child_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face, + element_face_get_child_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face, const int face_child) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_face_get_child_face (elem, face, face_child); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_face_get_child_face (element, face, face_child); }, eclass_schemes[tree_class]); }; @@ -600,27 +605,27 @@ class t8_scheme { * of the parent of the element that matches the element's face. Or return -1 if * no face of the parent matches the face. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. + * \param [in] element The element. * \param [in] face Then number of the face. - * \return If \a face of \a elem is also a face of \a elem's parent, + * \return If \a face of \a element is also a face of \a element's parent, * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ inline int - element_face_get_parent_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face) const + element_face_get_parent_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_face_get_parent_face (elem, face); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_face_get_parent_face (element, face); }, eclass_schemes[tree_class]); }; /** Given an element and a face of this element. If the face lies on the * tree boundary, return the face number of the tree face. * If not the return value is arbitrary. - * You can call \ref t8_element_is_root_boundary to query whether the face is + * You can call \ref element_is_root_boundary to query whether the face is * at the tree boundary. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \param [in] face The index of a face of \a elem. + * \param [in] element The element. + * \param [in] face The index of a face of \a element. * \return The index of the tree face that \a face is a subface of, if * \a face is on a tree boundary. * Any arbitrary integer if \a is not at a tree boundary. @@ -628,9 +633,9 @@ class t8_scheme { * the element does not lie on the root boundary. */ inline int - element_get_tree_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face) const + element_get_tree_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_tree_face (elem, face); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_tree_face (element, face); }, eclass_schemes[tree_class]); }; @@ -670,96 +675,96 @@ class t8_scheme { * face. * \param [in] tree_class The eclass of the current tree. * \param [in] face A face element. - * \param [in,out] elem An allocated element. The entries will be filled with + * \param [in,out] element An allocated element. The entries will be filled with * the data of the element that has \a face as a face and * lies within the root tree. * \param [in] root_face The index of the face of the root tree in which \a face * lies. - * \return The face number of the face of \a elem that coincides + * \return The face number of the face of \a element that coincides * with \a face. */ inline int - element_extrude_face (const t8_eclass_t tree_class, const t8_element_t *face, t8_element_t *elem, + element_extrude_face (const t8_eclass_t tree_class, const t8_element_t *face, t8_element_t *element, const int root_face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_extrude_face (face, elem, root_face, this); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_extrude_face (face, element, root_face, this); }, eclass_schemes[tree_class]); }; /** Construct the boundary element at a specific face. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The input element. + * \param [in] element The input element. * \param [in] face The index of the face of which to construct the * boundary element. * \param [in,out] boundary An allocated element of dimension of \a element * minus 1. The entries will be filled with the entries * of the face of \a element. - * If \a elem is of class T8_ECLASS_VERTEX, then \a boundary must be NULL + * If \a element is of class T8_ECLASS_VERTEX, then \a boundary must be NULL * and will not be modified. */ inline void - element_get_boundary_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face, + element_get_boundary_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *boundary) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_boundary_face (elem, face, boundary, this); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_boundary_face (element, face, boundary, this); }, eclass_schemes[tree_class]); }; /** Construct the first descendant of an element at a given level that touches a given face. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \param [in, out] first_desc An allocated element. This element's data will be - * filled with the data of the first descendant of \a elem + * filled with the data of the first descendant of \a element * that shares a face with \a face. * \param [in] level The level, at which the first descendant is constructed */ inline void - element_get_first_descendant_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face, + element_get_first_descendant_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *first_desc, const int level) const { return std::visit ( - [&] (auto &&scheme) { return scheme.element_get_first_descendant_face (elem, face, first_desc, level); }, + [&] (auto &&scheme) { return scheme.element_get_first_descendant_face (element, face, first_desc, level); }, eclass_schemes[tree_class]); }; /** Construct the last descendant of an element at a given level that touches a given face. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \param [in, out] last_desc An allocated element. This element's data will be - * filled with the data of the last descendant of \a elem + * filled with the data of the last descendant of \a element * that shares a face with \a face. * \param [in] level The level, at which the last descendant is constructed */ inline void - element_get_last_descendant_face (const t8_eclass_t tree_class, const t8_element_t *elem, const int face, + element_get_last_descendant_face (const t8_eclass_t tree_class, const t8_element_t *element, const int face, t8_element_t *last_desc, const int level) const { return std::visit ( - [&] (auto &&scheme) { return scheme.element_get_last_descendant_face (elem, face, last_desc, level); }, + [&] (auto &&scheme) { return scheme.element_get_last_descendant_face (element, face, last_desc, level); }, eclass_schemes[tree_class]); }; /** Compute whether a given element shares a given face with its root tree. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The input element. - * \param [in] face A face of \a elem. + * \param [in] element The input element. + * \param [in] face A face of \a element. * \return True if \a face is a subface of the element's root element. * \note You can compute the corresponding face number of the tree via \ref element_get_tree_face. */ inline bool - element_is_root_boundary (const t8_eclass_t tree_class, const t8_element_t *elem, const int face) const + element_is_root_boundary (const t8_eclass_t tree_class, const t8_element_t *element, const int face) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_is_root_boundary (elem, face); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_is_root_boundary (element, face); }, eclass_schemes[tree_class]); }; /** Construct the face neighbor of a given element if this face neighbor * is inside the root tree. Return 0 otherwise. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element to be considered. - * \param [in,out] neigh If the face neighbor of \a elem along \a face is inside + * \param [in] element The element to be considered. + * \param [in,out] neigh If the face neighbor of \a element along \a face is inside * the root tree, this element's data is filled with the * data of the face neighbor. Otherwise the data can be modified * arbitrarily. @@ -772,11 +777,11 @@ class t8_scheme { * on output. */ inline int - element_get_face_neighbor_inside (const t8_eclass_t tree_class, const t8_element_t *elem, t8_element_t *neigh, + element_get_face_neighbor_inside (const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *neigh, const int face, int *neigh_face) const { return std::visit ( - [&] (auto &&scheme) { return scheme.element_get_face_neighbor_inside (elem, neigh, face, neigh_face); }, + [&] (auto &&scheme) { return scheme.element_get_face_neighbor_inside (element, neigh, face, neigh_face); }, eclass_schemes[tree_class]); }; @@ -784,91 +789,91 @@ class t8_scheme { * For example, a child of an element can be an element of a different shape * and has to be handled differently - according to its shape. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element to be considered + * \param [in] element The element to be considered * \return The shape of the element as an eclass */ inline t8_element_shape_t - element_get_shape (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_get_shape (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_shape (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_get_shape (element); }, eclass_schemes[tree_class]); }; /** Initialize the entries of an allocated element according to a * given linear id in a uniform refinement. * \param [in] tree_class The eclass of the current tree. - * \param [in,out] elem The element whose entries will be set. + * \param [in,out] element The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ inline void - element_set_linear_id (const t8_eclass_t tree_class, t8_element_t *elem, const int level, + element_set_linear_id (const t8_eclass_t tree_class, t8_element_t *element, const int level, const t8_linearidx_t id) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_set_linear_id (elem, level, id); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_set_linear_id (element, level, id); }, eclass_schemes[tree_class]); }; /** Compute the linear id of a given element in a hypothetical uniform * refinement of a given level. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose id we compute. + * \param [in] element The element whose id we compute. * \param [in] level The level of the uniform refinement to consider. * \return The linear id of the element. */ inline t8_linearidx_t - element_get_linear_id (const t8_eclass_t tree_class, const t8_element_t *elem, const int level) const + element_get_linear_id (const t8_eclass_t tree_class, const t8_element_t *element, const int level) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_linear_id (elem, level); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_linear_id (element, level); }, eclass_schemes[tree_class]); }; /** Compute the first descendant of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose descendant is computed. - * \param [out] desc The first element in a uniform refinement of \a elem + * \param [in] element The element whose descendant is computed. + * \param [out] desc The first element in a uniform refinement of \a element * of the given level. * \param [in] level The level, at which the descendant is computed. */ inline void - element_get_first_descendant (const t8_eclass_t tree_class, const t8_element_t *elem, t8_element_t *desc, + element_get_first_descendant (const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *desc, const int level) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_first_descendant (elem, desc, level); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_first_descendant (element, desc, level); }, eclass_schemes[tree_class]); }; /** Compute the last descendant of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element whose descendant is computed. - * \param [out] desc The last element in a uniform refinement of \a elem + * \param [in] element The element whose descendant is computed. + * \param [out] desc The last element in a uniform refinement of \a element * of the given level. * \param [in] level The level, at which the descendant is computed. */ inline void - element_get_last_descendant (const t8_eclass_t tree_class, const t8_element_t *elem, t8_element_t *desc, + element_get_last_descendant (const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *desc, const int level) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_last_descendant (elem, desc, level); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_get_last_descendant (element, desc, level); }, eclass_schemes[tree_class]); }; /** Construct the successor in a uniform refinement of a given element. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem1 The element whose successor should be constructed. - * \param [in,out] elem2 The element whose entries will be set. + * \param [in] element The element whose successor should be constructed. + * \param [in,out] successor The element whose entries will be set to the successor of \a element. */ inline void - element_construct_successor (const t8_eclass_t tree_class, const t8_element_t *t, t8_element_t *s) const + element_construct_successor (const t8_eclass_t tree_class, const t8_element_t *element, t8_element_t *successor) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_construct_successor (t, s); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_construct_successor (element, successor); }, eclass_schemes[tree_class]); }; /** Compute the coordinates of a given element vertex inside a reference tree * that is embedded into [0,1]^d (d = dimension). * \param [in] tree_class The eclass of the current tree. - * \param [in] t The element to be considered. + * \param [in] element The element to be considered. * \param [in] vertex The id of the vertex whose coordinates shall be computed. * \param [out] coords An array of at least as many doubles as the element's dimension * whose entries will be filled with the coordinates of \a vertex. @@ -876,29 +881,30 @@ class t8_scheme { * all coords might be used. */ inline void - element_get_vertex_reference_coords (const t8_eclass_t tree_class, const t8_element_t *t, const int vertex, + element_get_vertex_reference_coords (const t8_eclass_t tree_class, const t8_element_t *element, const int vertex, double coords[]) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_get_vertex_reference_coords (t, vertex, coords); }, - eclass_schemes[tree_class]); + return std::visit ( + [&] (auto &&scheme) { return scheme.element_get_vertex_reference_coords (element, vertex, coords); }, + eclass_schemes[tree_class]); }; /** Convert points in the reference space of an element to points in the * reference space of the tree. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element. - * \param [in] coords_input The coordinates \f$ [0,1]^\mathrm{dim} \f$ of the point + * \param [in] element The element. + * \param [in] ref_coords The coordinates \f$ [0,1]^\mathrm{dim} \f$ of the point * in the reference space of the element. * \param [in] num_coords Number of \f$ dim\f$-sized coordinates to evaluate. * \param [out] out_coords The coordinates of the points in the * reference space of the tree. */ inline void - element_get_reference_coords (const t8_eclass_t tree_class, const t8_element_t *elem, const double *ref_coords, + element_get_reference_coords (const t8_eclass_t tree_class, const t8_element_t *element, const double *ref_coords, const size_t num_coords, double *out_coords) const { return std::visit ( - [&] (auto &&scheme) { return scheme.element_get_reference_coords (elem, ref_coords, num_coords, out_coords); }, + [&] (auto &&scheme) { return scheme.element_get_reference_coords (element, ref_coords, num_coords, out_coords); }, eclass_schemes[tree_class]); }; @@ -943,22 +949,22 @@ class t8_scheme { * For example this could mean that all coordinates are in valid ranges * and other membervariables do have meaningful values. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element to be checked. - * \return True if \a elem is safe to use. False otherwise. - * \note An element that is constructed with \ref t8_element_new + * \param [in] element The element to be checked. + * \return True if \a element is safe to use. False otherwise. + * \note An element that is constructed with \ref element_new * must pass this test. - * \note An element for which \ref t8_element_init was called must pass + * \note An element for which \ref element_init was called must pass * this test. * \note This function is used for debugging to catch certain errors. * These can for example occur when an element points to a region * of memory which should not be interpreted as an element. - * \note We recommend to use the assertion T8_ASSERT (t8_element_is_valid (elem)) + * \note We recommend to use the assertion T8_ASSERT (element_is_valid (element)) * in the implementation of each of the functions in this file. */ inline int - element_is_valid (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_is_valid (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_is_valid (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_is_valid (element); }, eclass_schemes[tree_class]); }; /** @@ -966,25 +972,27 @@ class t8_scheme { * and the level of the triangle. This function is only available in the * debugging configuration. * \param [in] tree_class The eclass of the current tree. - * \param [in] elem The element to print + * \param [in] element The element to print */ inline void - element_debug_print (const t8_eclass_t tree_class, const t8_element_t *elem) const + element_debug_print (const t8_eclass_t tree_class, const t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_debug_print (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_debug_print (element); }, + eclass_schemes[tree_class]); }; /** * Fill a string with readable information about the element * \param [in] tree_class The eclass of the current tree. - * \param[in] elem The element to translate into human-readable information + * \param[in] element The element to translate into human-readable information. * \param[in, out] debug_string The string to fill. + * \param[in] string_size The length of \a debug_string. */ inline void - element_to_string (const t8_eclass_t tree_class, const t8_element_t *elem, char *debug_string, + element_to_string (const t8_eclass_t tree_class, const t8_element_t *element, char *debug_string, const int string_size) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_to_string (elem, debug_string, string_size); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_to_string (element, debug_string, string_size); }, eclass_schemes[tree_class]); }; #endif @@ -993,91 +1001,93 @@ class t8_scheme { * and put pointers to the elements in the provided array. * \param [in] tree_class The eclass of the current tree. * \param [in] length The number of elements to be allocated. - * \param [in,out] elems On input an array of \a length many element pointers. + * \param [in,out] elements On input an array of \a length many element pointers. * On output all these pointers will point to an allocated * and initialized element. * \note There are two ways to create multiple elements of the same type. Create an - * array of element pointers and fill it with t8_element_new, or allocate memory - * for \a length times \a element_size many bytes, and fill them with t8_element_init. + * array of element pointers and fill it with \ref element_new, or allocate memory + * for \a length times \a element_size many bytes, and fill them with element_init. * To access a specific element, offset calculation needs to be done manually, as - * t8_element_t is incomplete. - * \note In debugging mode, an element that was created with \ref t8_element_new - * must pass \ref t8_element_is_valid (for example the root element). - * \note If an element was created by \ref t8_element_new then \ref t8_element_init - * may not be called for it. Thus, \ref t8_element_new should initialize an element - * in the same way as a call to \ref t8_element_init would. - * \note Every call to \ref t8_element_new must be matched by a call to \ref t8_element_destroy - * \see t8_element_destroy - * \see t8_element_init - * \see t8_element_is_valid + * \ref t8_element_t is incomplete. + * \note In debugging mode, an element that was created with \ref element_new + * must pass \ref element_is_valid (for example the root element). + * \note If an element was created by \ref element_new then \ref element_init + * may not be called for it. Thus, \ref element_new should initialize an element + * in the same way as a call to \ref element_init would. + * \note Every call to \ref element_new must be matched by a call to \ref element_destroy + * \see element_destroy + * \see element_init + * \see element_is_valid */ inline void - element_new (const t8_eclass_t tree_class, const int length, t8_element_t **elem) const + element_new (const t8_eclass_t tree_class, const int length, t8_element_t **elements) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_new (length, elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_new (length, elements); }, + eclass_schemes[tree_class]); }; /** Initialize an array of allocated elements. * \param [in] tree_class The eclass of the current tree. * \param [in] length The number of elements to be initialized. - * \param [in,out] elems On input an array of \a length many allocated + * \param [in,out] elements On input an array of \a length many allocated * elements. - * \note In debugging mode, an element that was passed to \ref t8_element_init - * must pass \ref t8_element_is_valid. - * \note If an element was created by \ref t8_element_new then \ref t8_element_init - * may not be called for it. Thus, \ref t8_element_init should initialize an element - * in the same way as a call to \ref t8_element_new would. - * \note Every call to \ref t8_element_init must be matched by a call to \ref t8_element_deinit - * \see t8_element_deinit - * \see t8_element_new - * \see t8_element_is_valid + * \note In debugging mode, an element that was passed to \ref element_init + * must pass \ref element_is_valid. + * \note If an element was created by \ref element_new then \ref element_init + * may not be called for it. Thus, \ref element_init should initialize an element + * in the same way as a call to \ref element_new would. + * \note Every call to \ref element_init must be matched by a call to \ref element_deinit + * \see element_deinit + * \see element_new + * \see element_is_valid */ inline void - element_init (const t8_eclass_t tree_class, const int length, t8_element_t *elem) const + element_init (const t8_eclass_t tree_class, const int length, t8_element_t *elements) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_init (length, elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.element_init (length, elements); }, + eclass_schemes[tree_class]); }; /** Deinitialize an array of allocated elements. * \param [in] tree_class The eclass of the current tree. * \param [in] length The number of elements to be deinitialized. - * \param [in,out] elems On input an array of \a length many allocated + * \param [in,out] elements On input an array of \a length many allocated * and initialized elements, on output an array of * \a length many allocated, but not initialized elements. - * \note Call this function if you called t8_element_init on the element pointers. - * \see t8_element_init + * \note Call this function if you called \ref element_init on the element pointers. + * \see element_init */ inline void - element_deinit (const t8_eclass_t tree_class, const int length, t8_element_t *elem) const + element_deinit (const t8_eclass_t tree_class, const int length, t8_element_t *elements) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_deinit (length, elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_deinit (length, elements); }, eclass_schemes[tree_class]); }; /** Deallocate an array of elements. * \param [in] tree_class The eclass of the current tree. * \param [in] length The number of elements in the array. - * \param [in,out] elem On input an array of \a length many allocated + * \param [in,out] elements On input an array of \a length many allocated * element pointers. * On output all these pointers will be freed. - * \a elem itself will not be freed by this function. - * \see t8_element_new + * \a element itself will not be freed by this function. + * \see element_new */ inline void - element_destroy (const t8_eclass_t tree_class, const int length, t8_element_t **elem) const + element_destroy (const t8_eclass_t tree_class, const int length, t8_element_t **elements) const { - return std::visit ([&] (auto &&scheme) { return scheme.element_destroy (length, elem); }, + return std::visit ([&] (auto &&scheme) { return scheme.element_destroy (length, elements); }, eclass_schemes[tree_class]); }; /** create the root element * \param [in] tree_class The eclass of the current tree. - * \param [in,out] elem The element that is filled with the root + * \param [in,out] element The element that is filled with the root */ inline void - set_to_root (const t8_eclass_t tree_class, t8_element_t *elem) const + set_to_root (const t8_eclass_t tree_class, t8_element_t *element) const { - return std::visit ([&] (auto &&scheme) { return scheme.set_to_root (elem); }, eclass_schemes[tree_class]); + return std::visit ([&] (auto &&scheme) { return scheme.set_to_root (element); }, eclass_schemes[tree_class]); }; /** Pack multiple elements into contiguous memory, so they can be sent via MPI. diff --git a/src/t8_schemes/t8_scheme_builder.hxx b/src/t8_schemes/t8_scheme_builder.hxx index c71fea3416..269f1f10e6 100644 --- a/src/t8_schemes/t8_scheme_builder.hxx +++ b/src/t8_schemes/t8_scheme_builder.hxx @@ -38,6 +38,9 @@ class t8_scheme_builder { t8_scheme_builder (): scheme (new t8_scheme) {}; ~t8_scheme_builder () {}; + /** Datatype for scheme variable, storing a variant of + * all scheme types. \see t8_scheme::scheme_var + */ using scheme_var = t8_scheme::scheme_var; /** Add a new element class scheme to the scheme. diff --git a/src/t8_schemes/t8_standalone/t8_standalone_elements.hxx b/src/t8_schemes/t8_standalone/t8_standalone_elements.hxx index e7caf5f45e..22b9a79822 100644 --- a/src/t8_schemes/t8_standalone/t8_standalone_elements.hxx +++ b/src/t8_schemes/t8_standalone/t8_standalone_elements.hxx @@ -29,12 +29,30 @@ #define t8_standalone_element t8_standalone +/** Dimension of the standalone element types */ constexpr uint8_t T8_ELEMENT_DIM[T8_ECLASS_COUNT] = { 0, 1, 2, 2, 3, 3, 3, 3 }; -constexpr uint8_t T8_ELEMENT_MAXLEVEL[T8_ECLASS_COUNT] = { 255, 30, 30, 29, 21, 21, 21, 18 }; + +/** Maximum level of the standalone element types + * \note The maxlevel is lower than 255 so that we can use \ref t8_scheme::element_get_level (uint8_t) + * to iterate to maxlevel: + * for (t8_element_level level = 0; level <= T8_ELEMENT_MAXLEVEL[T8_ECLASS_VERTEX]; ++level) + * Otherwise, t8_element_level would overflow after 255 and we would have an infinite loop. +*/ +constexpr uint8_t T8_ELEMENT_MAXLEVEL[T8_ECLASS_COUNT] = { 254, 30, 30, 29, 21, 21, 21, 18 }; + +/** Maximum number of faces of the standalone element types */ constexpr uint8_t T8_ELEMENT_MAX_NUM_FACES[T8_ECLASS_COUNT] = { 1, 2, 4, 3, 6, 4, 5, 5 }; + +/** Number of children of the standalone element types */ constexpr uint8_t T8_ELEMENT_NUM_CHILDREN[T8_ECLASS_COUNT] = { 1, 2, 4, 4, 8, 8, 8, 10 }; + +/** Number of corners (vertices) of the standalone element types */ constexpr uint8_t T8_ELEMENT_NUM_CORNERS[T8_ECLASS_COUNT] = { 1, 2, 4, 3, 8, 4, 6, 5 }; + +/** Actual number of faces of the standalone element types */ constexpr uint8_t T8_ELEMENT_NUM_FACES[T8_ECLASS_COUNT] = { 0, 2, 4, 3, 6, 4, 5, 5 }; + +/** Number of face children of the standalone element types */ constexpr uint8_t T8_ELEMENT_MAX_NUM_FACECHILDREN[T8_ECLASS_COUNT] = { 0, 1, 2, 2, 4, 4, 4, 4 }; constexpr uint8_t T8_ELEMENT_NUM_EQUATIONS[T8_ECLASS_COUNT] = { 0, 0, 0, 1, 0, 3, 1, 2 }; @@ -49,6 +67,8 @@ using t8_element_type = std::bitset; template using t8_element_coords = std::array; + +/** The data container describing a refined element in a refined tree, where the root element has class \a TEclass */ template struct t8_standalone_element { @@ -56,6 +76,7 @@ struct t8_standalone_element t8_element_coords coords; /** The refinement level of the element relative to the root at level 0. */ t8_element_level level; + double stretch_factors[3]; }; #endif /* T8_STANDALONE_ELEMENTS_HXX */ diff --git a/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx b/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx index 0a36d2c1ff..ce014ae988 100644 --- a/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx +++ b/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx @@ -29,6 +29,7 @@ #include #include +/** A templated implementation of the scheme interface based on cutting planes. */ template struct t8_standalone_scheme { @@ -721,7 +722,7 @@ struct t8_standalone_scheme * They will be stored in order of their linear id. * \param [in] num_children The number of elements in \a children. Must match * the number of children that touch \a face. - * \ref t8_element_num_face_children + * \ref element_get_num_face_children * \param [in,out] child_indices If not NULL, an array of num_children integers must be given, * on output its i-th entry is the child_id of the i-th face_child. * It is valid to call this function with elem = children[0]. @@ -766,7 +767,7 @@ struct t8_standalone_scheme * \param [in] face_child A number 0 <= \a face_child < num_face_children, * specifying a child of \a elem that shares a face with \a face. * These children are counted in linear order. This coincides with - * the order of children from a call to \ref t8_element_children_at_face. + * the order of children from a call to \ref element_get_children_at_face. * \return The face number of the face of a child of \a elem * that coincides with \a face_child. */ @@ -882,7 +883,7 @@ struct t8_standalone_scheme * \param [in] elem The input element. * \param [in] face A face of \a elem. * \return True if \a face is a subface of the element's root element. - * \note You can compute the corresponding face number of the tree via \ref t8_element_tree_face. + * \note You can compute the corresponding face number of the tree via \ref element_get_tree_face. */ static constexpr int element_is_root_boundary (const t8_element_t *elem, const int face) noexcept @@ -1248,15 +1249,15 @@ struct t8_standalone_scheme } /** Count how many leaf descendants of a given uniform level an element would produce. - * \param [in] t The element to be checked. + * \param [in] elem The element to be checked. * \param [in] level A refinement level. - * \return Suppose \a t is uniformly refined up to level \a level. The return value + * \return Suppose \a elem is uniformly refined up to level \a level. The return value * is the resulting number of elements (of the given level). * If \a level < t8_element_level(t), the return value should be 0. * - * Example: If \a t is a line element that refines into 2 line elements on each level, + * Example: If \a elem is a line element that refines into 2 line elements on each level, * then the return value is max(0, 2^{\a level - level(\a t)}). - * Thus, if \a t's level is 0, and \a level = 3, the return value is 2^3 = 8. + * Thus, if \a elem's level is 0, and \a level = 3, the return value is 2^3 = 8. */ static constexpr t8_gloidx_t element_count_leaves (const t8_element_t *elem, const t8_element_level level) noexcept @@ -1353,8 +1354,8 @@ struct t8_standalone_scheme * reference space of the tree. * * \param [in] elem The element. - * \param [in] coords_input The coordinates of the point in the reference space of the element. - * \param [in] user_data User data. + * \param [in] ref_coords The coordinates of the point in the reference space of the element. + * \param [in] num_coords The number of coordinates to evaluate. * \param [out] out_coords The coordinates of the point in the reference space of the tree. */ static constexpr void @@ -1400,22 +1401,22 @@ struct t8_standalone_scheme /* TODO: would it be better to directly allocate an array of elements, * not element pointers? */ void - element_new (const int length, t8_element_t **elem) const noexcept + element_new (const int length, t8_element_t **elems) const noexcept { /* allocate memory */ T8_ASSERT (this->scheme_context != NULL); T8_ASSERT (0 <= length); - T8_ASSERT (elem != NULL); + T8_ASSERT (elems != NULL); for (int i = 0; i < length; ++i) { - elem[i] = (t8_element_t *) sc_mempool_alloc ((sc_mempool_t *) this->scheme_context); + elems[i] = (t8_element_t *) sc_mempool_alloc ((sc_mempool_t *) this->scheme_context); } /* in debug mode, set sensible default values. */ #if T8_ENABLE_DEBUG { for (int i = 0; i < length; i++) { - element_init (1, elem[i]); + element_init (1, elems[i]); } } #endif @@ -1434,10 +1435,10 @@ struct t8_standalone_scheme * \see element_is_valid */ static inline void - element_init ([[maybe_unused]] const int length, [[maybe_unused]] t8_element_t *elem) noexcept + element_init ([[maybe_unused]] const int length, [[maybe_unused]] t8_element_t *elems) noexcept { #if T8_ENABLE_DEBUG - t8_standalone_element *el = (t8_standalone_element *) elem; + t8_standalone_element *el = (t8_standalone_element *) elems; /* Set all values to 0 */ for (int ielem = 0; ielem < length; ielem++) { element_set_linear_id ((t8_element_t *) (el + ielem), 0, 0); @@ -1455,7 +1456,7 @@ struct t8_standalone_scheme * \see element_init */ static constexpr void - element_deinit ([[maybe_unused]] const int length, [[maybe_unused]] t8_element_t *elem) noexcept + element_deinit ([[maybe_unused]] const int length, [[maybe_unused]] t8_element_t *elems) noexcept { } @@ -1464,16 +1465,16 @@ struct t8_standalone_scheme * \param [in,out] elems On input an array of \b length many allocated * element pointers. * On output all these pointers will be freed. - * \b elem itself will not be freed by this function. + * \b elems itself will not be freed by this function. */ void - element_destroy (const int length, t8_element_t **elem) const noexcept + element_destroy (const int length, t8_element_t **elems) const noexcept { T8_ASSERT (this->scheme_context != NULL); T8_ASSERT (0 <= length); - T8_ASSERT (elem != NULL); + T8_ASSERT (elems != NULL); for (int i = 0; i < length; ++i) { - sc_mempool_free ((sc_mempool_t *) scheme_context, elem[i]); + sc_mempool_free ((sc_mempool_t *) scheme_context, elems[i]); } } @@ -1537,6 +1538,12 @@ struct t8_standalone_scheme * ToDo-Type */ } + /** + * Fill a string with readable information about the element + * \param[in] elem The element to translate into human-readable information + * \param[in, out] debug_string The string to fill. + * \param[in] string_size Buffer size of c-string + */ static constexpr void element_to_string (const t8_element_t *elem, char *debug_string, const int string_size) noexcept { @@ -2141,6 +2148,23 @@ t8_standalone_scheme::element_transform_face ([[maybe_unused]] return; }; +/** Implementation of \ref element_transform_face for lines + * \param [in] elem1 The face element. + * \param [in,out] elem2 On return the face element \a elem1 with respective + * to the coordinate system of the other tree. + * \param [in] orientation The orientation of the tree-tree connection. + * \see t8_cmesh_set_join + * \param [in] sign Depending on the topological orientation of the two tree faces, + * either 0 (both faces have opposite orientation) + * or 1 (both faces have the same top. orientation). + * \ref t8_eclass_face_orientation + * \param [in] is_smaller_face Flag to declare whether \a elem1 belongs to + * the smaller face. A face f of tree T is smaller than + * f' of T' if either the eclass of T is smaller or if + * the classes are equal and f inline void t8_standalone_scheme::element_transform_face (const t8_element_t *elem1, @@ -2164,6 +2188,24 @@ t8_standalone_scheme::element_transform_face (const t8_element_t return; }; +/** Implementation of \ref element_transform_face for quads + * \param [in] elem1 The face element. + * \param [in,out] elem2 On return the face element \a elem1 with respective + * to the coordinate system of the other tree. + * \param [in] orientation The orientation of the tree-tree connection. + * \see t8_cmesh_set_join + * \param [in] sign Depending on the topological orientation of the two tree faces, + * either 0 (both faces have opposite orientation) + * or 1 (both faces have the same top. orientation). + * \ref t8_eclass_face_orientation + * \param [in] is_smaller_face Flag to declare whether \a elem1 belongs to + * the smaller face. A face f of tree T is smaller than + * f' of T' if either the eclass of T is smaller or if + * the classes are equal and f inline void t8_standalone_scheme::element_transform_face (const t8_element_t *elem1, t8_element_t *elem2, @@ -2235,6 +2277,24 @@ t8_standalone_scheme::element_transform_face (const t8_element_t return; }; +/** Implementation of \ref element_transform_face for triangles. + * \param [in] elem1 The face element. + * \param [in,out] elem2 On return the face element \a elem1 with respective + * to the coordinate system of the other tree. + * \param [in] orientation The orientation of the tree-tree connection. + * \see t8_cmesh_set_join + * \param [in] sign Depending on the topological orientation of the two tree faces, + * either 0 (both faces have opposite orientation) + * or 1 (both faces have the same top. orientation). + * \ref t8_eclass_face_orientation + * \param [in] is_smaller_face Flag to declare whether \a elem1 belongs to + * the smaller face. A face f of tree T is smaller than + * f' of T' if either the eclass of T is smaller or if + * the classes are equal and f inline void t8_standalone_scheme::element_transform_face ([[maybe_unused]] const t8_element_t *elem1, diff --git a/src/t8_types/t8_operators.hxx b/src/t8_types/t8_operators.hxx index 2b44e1eaf9..31bddeaa9d 100644 --- a/src/t8_types/t8_operators.hxx +++ b/src/t8_types/t8_operators.hxx @@ -32,7 +32,7 @@ along with t8code; if not, write to the Free Software Foundation, Inc., #include /** - * \brief The CRTP pattern for operators. + * The CRTP pattern for operators. * * \tparam TUnderlying * \tparam crtpType @@ -40,12 +40,18 @@ along with t8code; if not, write to the Free Software Foundation, Inc., template class crtpType> struct t8_crtp_operator { + /** + * Get the underlying type. + */ constexpr TUnderlying& underlying () noexcept { return static_cast (*this); } + /** + * Get the underlying type. + */ constexpr const TUnderlying& underlying () const noexcept { @@ -60,14 +66,19 @@ struct t8_crtp_operator */ /** - * \brief A template for addable types. Provides the + operator. + * A template for addable types. Provides the + operator. * * \tparam TUnderlying */ template struct Addable: t8_crtp_operator { - + /** + * Add the value of \a other to the underlying type. + * + * \param [in] other The value to add to the underlying type. + * \return The underlying type after the addition. + */ constexpr TUnderlying operator+ (const TUnderlying& other) const noexcept { @@ -76,13 +87,19 @@ struct Addable: t8_crtp_operator }; /** - * \brief A template for subtractable types. Provides the - operator. + * A template for subtractable types. Provides the - operator. * * \tparam TUnderlying */ template struct Subtractable: t8_crtp_operator { + /** + * Subtract the value of \a other from the underlying type. + * + * \param [in] other The value to subtract from the underlying type. + * \return The underlying type after the subtraction. + */ constexpr TUnderlying operator- (const TUnderlying& other) const noexcept { @@ -91,13 +108,19 @@ struct Subtractable: t8_crtp_operator }; /** - * \brief A template for multipliable types. Provides the * operator. + * A template for multipliable types. Provides the * operator. * * \tparam TUnderlying */ template struct Multipliable: t8_crtp_operator { + /** + * Multiply the underlying type with \a other. + * + * \param [in] other The value to multiply the underlying type with. + * \return The underlying type after the multiplication. + */ constexpr TUnderlying operator* (const TUnderlying& other) const noexcept { @@ -106,13 +129,19 @@ struct Multipliable: t8_crtp_operator }; /** - * \brief A template for dividable types. Provides the / operator. + * A template for dividable types. Provides the / operator. * * \tparam TUnderlying */ template struct Dividable: t8_crtp_operator { + /** + * Divide the underlying type by \a other. + * + * \param [in] other The value to divide the underlying type by. + * \return The underlying type after the division. + */ constexpr TUnderlying operator/ (const TUnderlying& other) const noexcept { @@ -121,13 +150,19 @@ struct Dividable: t8_crtp_operator }; /** - * \brief A template for add-assignable types. Provides the += operator. + * A template for add-assignable types. Provides the += operator. * * \tparam TUnderlying */ template struct AddAssignable: t8_crtp_operator { + /** + * Add-assign the value of \a other to the underlying type. + * + * \param [in] other The value to add to the underlying type. + * \return The underlying type after the addition. + */ constexpr TUnderlying& operator+= (const TUnderlying& other) noexcept { @@ -137,7 +172,7 @@ struct AddAssignable: t8_crtp_operator }; /** - * \brief A template for incrementable types. Provides the ++ operator. + * A template for incrementable types. Provides the ++ operator. * * \tparam TUnderlying * @@ -146,6 +181,11 @@ struct AddAssignable: t8_crtp_operator template struct PrefixIncrementable: t8_crtp_operator { + /** + * Increment the underlying type. + * + * \return The underlying type after the increment. + */ TUnderlying& operator++ () noexcept { @@ -155,7 +195,7 @@ struct PrefixIncrementable: t8_crtp_operator }; /** - * \brief A template for decrementable types. Provides the -- operator. + * A template for decrementable types. Provides the -- operator. * * \tparam TUnderlying * @@ -164,6 +204,11 @@ struct PrefixIncrementable: t8_crtp_operator template struct PrefixDecrementable: t8_crtp_operator { + /** + * Decrement the underlying type. + * + * \return The underlying type after the decrement. + */ TUnderlying& operator-- () noexcept { @@ -173,13 +218,20 @@ struct PrefixDecrementable: t8_crtp_operator }; /** - * \brief A template for printable types. Provides the << operator. + * A template for printable types. Provides the << operator. * * \tparam TUnderlying */ template struct Printable: t8_crtp_operator { + /** + * Print the underlying type to the output stream. + * + * \param [in] os The output stream to print to. + * \param [in] obj The object to print. + * \return The output stream after printing. + */ friend std::ostream& operator<< (std::ostream& os, const TUnderlying& obj) { @@ -189,13 +241,19 @@ struct Printable: t8_crtp_operator }; /** - * \brief A template for swapping types. Used to make a type swappable. + * A template for swapping types. Used to make a type swappable. * * \tparam TUnderlying */ template struct Swapable: t8_crtp_operator { + /** + * Swap the underlying type with another underlying type. + * + * \param [in,out] lhs The left-hand side of the swap. + * \param [in,out] other The right-hand side of the swap. + */ constexpr void swap (TUnderlying& lhs, TUnderlying& other) noexcept { @@ -204,19 +262,32 @@ struct Swapable: t8_crtp_operator }; /** - * \brief A template for equality comparable types. Provides the == operator. + * A template for equality comparable types. Provides the == operator. * * \tparam TUnderlying */ template struct EqualityComparable: t8_crtp_operator { + /** + * Check if the underlying types are equal. + * + * \param [in] lhs The left-hand side of the equality check. + * \param [in] rhs The right-hand side of the equality check. + * \return True if the underlying types are equal, false otherwise. + */ friend constexpr bool operator== (const TUnderlying& lhs, const TUnderlying& rhs) noexcept { return lhs.get () == rhs.get (); } + /** + * Check if the underlying type is not equal to another underlying type. + * + * \param [in] other The other underlying type to compare with. + * \return True if the underlying types are not equal, false otherwise. + */ constexpr bool operator!= (TUnderlying const& other) const { @@ -225,66 +296,109 @@ struct EqualityComparable: t8_crtp_operator }; /** - * \brief A template for hashable types. Used to make a type hashable. + * A template for hashable types. Used to make a type hashable. * * \tparam TUnderlying */ template struct Hashable { + /** Set if the underlying type is hashable. */ static constexpr bool is_hashable = true; }; /** - * \brief A template for random accessible types. Provides the [] operator. + * A template for random accessible types. Provides the [] operator. * * \tparam TUnderlying */ template struct RandomAccessible: t8_crtp_operator { + /** + * Get the element at the given index. + * + * \param [in] index The index of the element to get. + * \return The element at the given index. + */ auto operator[] (std::size_t index) -> decltype (auto) { return this->underlying ().get ()[index]; } + /** + * Get the element at the given index. + * + * \param [in] index The index of the element to get. + * \return The element at the given index. + */ auto operator[] (std::size_t index) const -> decltype (auto) { return this->underlying ().get ()[index]; } + /** + * Get an iterator to the beginning of the underlying type. + * + * \return An iterator to the beginning of the underlying type. + */ auto begin () -> decltype (auto) { return this->underlying ().get ().begin (); } + /** + * Get an iterator to the begin of the underlying type. + * + * \return An iterator to the begin of the underlying type. + */ auto begin () const -> decltype (auto) { return this->underlying ().get ().begin (); } + /** + * Get an iterator to the end of the underlying type. + * + * \return An iterator to the end of the underlying type. + */ auto end () -> decltype (auto) { return this->underlying ().get ().end (); } + /** + * Get an iterator to the end of the underlying type. + * + * \return An iterator to the end of the underlying type. + */ auto end () const -> decltype (auto) { return this->underlying ().get ().end (); } + /** + * Get a pointer to the data of the underlying type. + * + * \return A pointer to the data of the underlying type. + */ auto data () -> decltype (auto) { return this->underlying ().get ().data (); } + /** + * Get a pointer to the data of the underlying type. + * + * \return A pointer to the data of the underlying type. + */ auto data () const -> decltype (auto) { diff --git a/src/t8_types/t8_type.hxx b/src/t8_types/t8_type.hxx index 3999177dc7..021ce62af4 100644 --- a/src/t8_types/t8_type.hxx +++ b/src/t8_types/t8_type.hxx @@ -31,7 +31,7 @@ #include /** - * \brief An implementation of strong type with additional competences. + * An implementation of strong type with additional competences. * * This class template allows the creation of a type that can be extended with * multiple competences. Each competence is a template class that takes the @@ -46,16 +46,19 @@ template class... competence> class T8Type: public competence>... { public: + /** The type of the value stored in this strong type. */ using value_type = T; + /** Default constructor */ explicit constexpr T8Type () = default; + /** Constructor with value */ explicit constexpr T8Type (const T& value): value_ (value) { } /** - * \brief Construct a new T8Type object + * Construct a new T8Type object * * \tparam T_ref * \param value @@ -69,6 +72,7 @@ class T8Type: public competence>... { { } + /** Copy constructor */ constexpr T8Type& operator= (const T& value) { @@ -76,12 +80,22 @@ class T8Type: public competence>... { return *this; } + /** + * Get a reference to the stored value. + * + * \return A reference to the stored value. + */ constexpr T& get () noexcept { return value_; } + /** + * Get a const reference to the stored value. + * + * \return A const reference to the stored value. + */ constexpr T const& get () const noexcept { @@ -109,7 +123,7 @@ class T8Type: public competence>... { namespace std { /** - * \brief Functor for hashing T8Type objects. + * Functor for hashing T8Type objects. * * This struct defines a functor that computes the hash value of a T8Type object. * It uses the std::hash function to generate the hash value based on the underlying @@ -125,9 +139,17 @@ namespace std template class... competence> struct hash> { + /** The implementation of the T8Type with the given competences. */ using T8TypeImpl = T8Type; + /** Check if the T8TypeImpl is hashable. */ using checkIfHashable = typename std::enable_if::type; + /** + * Compute the hash value of a T8Type object. + * + * \param x The T8Type object to hash. + * \return The computed hash value. + */ size_t operator() (T8Type const& x) const { diff --git a/src/t8_types/t8_vec.h b/src/t8_types/t8_vec.h index 4d094812a3..d11d9085ba 100644 --- a/src/t8_types/t8_vec.h +++ b/src/t8_types/t8_vec.h @@ -69,7 +69,7 @@ t8_ax (double vec_x[3], const double alpha); /** Compute Y = alpha * X * \param [in] vec_x A 3D vector. - * \param [out] vec_z On output set to \a alpha * \a vec_x. + * \param [out] vec_y On output set to \a alpha * \a vec_x. * \param [in] alpha A factor. */ void @@ -98,6 +98,7 @@ t8_axpy (const double vec_x[3], double vec_y[3], const double alpha); * \param [in] vec_x A 3D vector. * \param [in] vec_y A 3D vector. * \param [out] vec_z On output set \a to vec_y + \a alpha * \a vec_x + * \param [in] alpha A factor for the multiplication of \a vec_x. */ void t8_axpyz (const double vec_x[3], const double vec_y[3], double vec_z[3], const double alpha); @@ -121,7 +122,7 @@ t8_cross_3D (const double vec_x[3], const double vec_y[3], double cross[3]); /** Cross product of X and Y * \param [in] vec_x A 2D vector. * \param [in] vec_y A 2D vector. - * \param [out] cross On output, the cross product of \a vec_x and \a vec_y. + * \return The cross product of \a vec_x and \a vec_y. */ double t8_cross_2D (const double vec_x[2], const double vec_y[2]); @@ -156,7 +157,7 @@ t8_rescale (double vec[3], const double new_length); * \param [in] p1 A 3D vector. * \param [in] p2 A 3D vector. * \param [in] p3 A 3D vector. - * \param [out] Normal vector of the triangle. (Not necessarily of length 1!) + * \param [out] normal vector of the triangle. (Not necessarily of length 1!) */ void t8_normal_of_tri (const double p1[3], const double p2[3], const double p3[3], double normal[3]); diff --git a/src/t8_types/t8_vec.hxx b/src/t8_types/t8_vec.hxx index 00b67cd9b8..81c5515244 100644 --- a/src/t8_types/t8_vec.hxx +++ b/src/t8_types/t8_vec.hxx @@ -47,12 +47,28 @@ struct t8_point_tag { }; +/** + * Type alias for a vector. + * \tparam dim Dimension of the vector. + */ template using t8_vec = T8Type, t8_vec_tag, EqualityComparable, Swapable, RandomAccessible>; + +/** Type alias for a 3D vector. + * \note This is a convenience type alias for 3D vectors. + */ using t8_3D_vec = t8_vec<3>; +/** + * Type alias for a point in N-dimensional space. + * \tparam dim Dimension of the point. + */ template using t8_point = T8Type, t8_point_tag, EqualityComparable, Swapable, RandomAccessible>; + +/** Type alias for a 3D point. + * \note This is a convenience type alias for 3D points. + */ using t8_3D_point = t8_point<3>; /** Vector norm. @@ -78,14 +94,18 @@ t8_normalize (t8_vec &vec) } /** Make a copy of a vector or point. - * \param [in] src -t8_type_copy (T const &src, T const &dest) -static inline void -*/ + * \param [in] src The source vector or point. + * \param [out] dest The destination vector or point. + */ template static inline void t8_copy (const T &src, T &dest); +/** + * Copy a vector. + * \param [in] src The source vector. + * \param [out] dest The destination vector. + */ template constexpr void t8_copy (const t8_vec &src, t8_vec &dest) @@ -93,6 +113,11 @@ t8_copy (const t8_vec &src, t8_vec &dest) std::copy (src.begin (), src.end (), dest.begin ()); } +/** + * Copy a point. + * \param [in] src The source point. + * \param [out] dest The destination point. + */ template constexpr void t8_copy (const t8_point &src, t8_point &dest) @@ -171,6 +196,7 @@ t8_axpy (const t8_vec &vec_x, t8_vec &vec_y, const double alpha) * \param [in] vec_x An N-dimensional vector. * \param [in] vec_y An N-dimensional vector. * \param [out] vec_z On output set \a to vec_y + \a alpha * \a vec_x + * \param [in] alpha A factor for the multiplication of \a vec_x. */ template constexpr void @@ -194,7 +220,7 @@ t8_dot (const t8_vec &vec_x, const t8_vec &vec_y) /** Cross product of X and Y * \param [in] vec_x A 2D vector. * \param [in] vec_y A 2D vector. - * \param [out] cross On output, the cross product of \a vec_x and \a vec_y. + * \return The cross product of \a vec_x and \a vec_y. */ static inline double t8_cross_2D (const t8_vec<2> &vec_x, const t8_vec<2> &vec_y) @@ -259,7 +285,7 @@ t8_rescale (t8_vec &vec, const double new_length) * \param [in] p1 A 3D vector. * \param [in] p2 A 3D vector. * \param [in] p3 A 3D vector. - * \param [out] Normal vector of the triangle. (Not necessarily of length 1!) + * \param [out] normal vector of the triangle. (Not necessarily of length 1!) */ static inline void t8_normal_of_tri (const t8_3D_vec &p1, const t8_3D_vec &p2, const t8_3D_vec &p3, t8_3D_vec &normal) diff --git a/src/t8_version.h b/src/t8_version.h index be0b48f56d..245c6d4514 100644 --- a/src/t8_version.h +++ b/src/t8_version.h @@ -51,9 +51,11 @@ #include #endif -/* In order to convert a macro to a string, we +/** In order to convert a macro to a string, we * need to pass it through these two helper macros. */ #define T8_STRINGIFY(arg) #arg +/** In order to convert a macro to a string, we + * need to pass it through these two helper macros. */ #define T8_STRINGIFY_MIDDLE(arg) T8_STRINGIFY (arg) /** The T8_VERSION_POINT macro as a string */ diff --git a/src/t8_vtk.h b/src/t8_vtk.h index ddb8f39f6c..be404f82d3 100644 --- a/src/t8_vtk.h +++ b/src/t8_vtk.h @@ -60,6 +60,10 @@ typedef enum { T8_VTK_VECTOR /* 3 double values per element */ } t8_vtk_data_type_t; +/** A data field for VTK output. + * This struct is used to store data that is written to the VTK files. + * It contains the type of the data, a description, and the actual data array. + */ typedef struct { t8_vtk_data_type_t type; /**< Describes of which type the data array is */ diff --git a/src/t8_vtk/t8_vtk_types.h b/src/t8_vtk/t8_vtk_types.h index b610dc333f..4f9f122f85 100644 --- a/src/t8_vtk/t8_vtk_types.h +++ b/src/t8_vtk/t8_vtk_types.h @@ -20,6 +20,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_types.h + * This file contains types and constants used in the vtk writer. + */ + #ifndef T8_VTK_TYPES #define T8_VTK_TYPES @@ -63,6 +68,10 @@ typedef enum vtk_file_type { VTK_NUM_TYPES = 5 } vtk_file_type_t; +/** + * Enumerator for the success of reading a vtk file. + * This is used to indicate whether the reading was successful or not. + */ typedef enum vtk_read_success { read_failure = 0, read_success = 1 } vtk_read_success_t; #endif /* T8_VTK_TYPES */ diff --git a/src/t8_vtk/t8_vtk_write_ASCII.cxx b/src/t8_vtk/t8_vtk_write_ASCII.cxx index e3691d774c..ee6275a4e0 100644 --- a/src/t8_vtk/t8_vtk_write_ASCII.cxx +++ b/src/t8_vtk/t8_vtk_write_ASCII.cxx @@ -60,7 +60,7 @@ typedef enum { T8_VTK_KERNEL_INIT, T8_VTK_KERNEL_EXECUTE, T8_VTK_KERNEL_CLEANUP * \param [in] tree The local tree of the forest with id \a ltree_id. * \param [in] element_index An index of an element inside \a tree. * \param [in] element A pointer to the current element. - * \param [in] scheme The eclass scheme of the current element. + * \param [in] tree_class The eclass of the current tree. * \param [in] is_ghost Non-zero if the current element is a ghost element. * In this cas \a tree is NULL. * All ghost element will be traversed after all elements are @@ -768,7 +768,7 @@ t8_forest_vtk_write_points (t8_forest_t forest, FILE *vtufile, const int write_g if (sreturn >= BUFSIZ) { /* The output was truncated */ - /* Note: gcc >= 7.1 prints a warning if we + /* Note: gcc >= 7.1 prints a warning if we * do not check the return value of snprintf. */ t8_debugf ("Warning: Truncated vtk point data description to '%s'\n", description); } @@ -944,7 +944,7 @@ t8_cmesh_vtk_write_file_ext (const t8_cmesh_t cmesh, const char *fileprefix, con T8_ASSERT (t8_cmesh_is_committed (cmesh)); T8_ASSERT (fileprefix != NULL); - /* Constants used as return values in order + /* Constants used as return values in order * to have more readable code. */ constexpr int write_successful = 1; constexpr int write_failure = 0; @@ -984,7 +984,6 @@ t8_cmesh_vtk_write_file_ext (const t8_cmesh_t cmesh, const char *fileprefix, con vtufile = fopen (vtufilename, "wb"); if (vtufile == NULL) { t8_global_errorf ("Could not open file %s for output.\n", vtufilename); - fclose (vtufile); return write_failure; } fprintf (vtufile, "\n"); diff --git a/src/t8_vtk/t8_vtk_write_ASCII.hxx b/src/t8_vtk/t8_vtk_write_ASCII.hxx index 2c15bcf739..1d0d73c611 100644 --- a/src/t8_vtk/t8_vtk_write_ASCII.hxx +++ b/src/t8_vtk/t8_vtk_write_ASCII.hxx @@ -20,6 +20,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_write_ASCII.hxx + * This file contains the function to write a forest in ASCII VTK format. + */ + #ifndef T8_VTK_WRITE_ASCII_HXX #define T8_VTK_WRITE_ASCII_HXX @@ -51,6 +56,15 @@ t8_forest_vtk_write_ASCII (t8_forest_t forest, const char *fileprefix, const int const int write_level, const int write_element_id, int write_ghosts, const int num_data, t8_vtk_data_field_t *data); +/** Write the cmesh in .pvtu file format. Writes one .vtu file per + * process and a meta .pvtu file. + * This function writes ASCII files and can be used when + * t8code is not configure with "--enable-vtk" and + * \ref t8_cmesh_vtk_write_file_via_API is not available. + * \param [in] cmesh The cmesh. + * \param [in] fileprefix The prefix of the output files. + * \return True if successful, false if not (process local). + */ int t8_cmesh_vtk_write_ASCII (t8_cmesh_t cmesh, const char *fileprefix); diff --git a/src/t8_vtk/t8_vtk_writer.cxx b/src/t8_vtk/t8_vtk_writer.cxx index 7f1a1a6508..fe813153de 100644 --- a/src/t8_vtk/t8_vtk_writer.cxx +++ b/src/t8_vtk/t8_vtk_writer.cxx @@ -28,8 +28,8 @@ #if T8_ENABLE_VTK /** - * \brief template specialization for forests. - * + * Template specialization for forests. + * */ template <> void @@ -68,8 +68,8 @@ vtk_writer::t8_grid_tree_to_vtk_cells ( } /** - * \brief template specialization for cmeshes. - * + * Template specialization for cmeshes. + * */ template <> void @@ -89,6 +89,9 @@ vtk_writer::t8_grid_tree_to_vtk_cells ( } #endif /* T8_ENABLE_VTK */ +/** + * Write a forest to a VTK file in ASCII format. + */ template <> bool vtk_writer::write_ASCII (const t8_forest_t forest) @@ -98,11 +101,14 @@ vtk_writer::write_ASCII (const t8_forest_t forest) this->data); } +/** + * Write a cmesh to a VTK file in ASCII format. + */ template <> bool -vtk_writer::write_ASCII (const t8_cmesh_t forest) +vtk_writer::write_ASCII (const t8_cmesh_t cmesh) { - return t8_cmesh_vtk_write_ASCII (forest, this->fileprefix.c_str ()); + return t8_cmesh_vtk_write_ASCII (cmesh, this->fileprefix.c_str ()); } /* Implementation of the c-interface */ diff --git a/src/t8_vtk/t8_vtk_writer.h b/src/t8_vtk/t8_vtk_writer.h index 8f051e29f5..4b8d47a884 100644 --- a/src/t8_vtk/t8_vtk_writer.h +++ b/src/t8_vtk/t8_vtk_writer.h @@ -20,6 +20,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_writer.h + * This file contains wrappers for the vtk writer functions. + */ + #ifndef T8_VTK_WRITER_C_INTERFACE_H #define T8_VTK_WRITER_C_INTERFACE_H diff --git a/src/t8_vtk/t8_vtk_writer.hxx b/src/t8_vtk/t8_vtk_writer.hxx index d00228a446..701acb54c4 100644 --- a/src/t8_vtk/t8_vtk_writer.hxx +++ b/src/t8_vtk/t8_vtk_writer.hxx @@ -20,6 +20,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_writer.hxx + * This file contains the function to write a forest in ASCII VTK format. + */ + #ifndef T8_VTK_WRITER_HXX #define T8_VTK_WRITER_HXX @@ -94,6 +99,12 @@ class vtk_writer { } #if T8_ENABLE_VTK + /** + * Convert a grid to a vtkUnstructuredGrid. + * + * \param[in] grid The forest or cmesh that is translated. + * \param[out] unstructuredGrid The vtkUnstructuredGrid to fill with the data of \a grid. + */ void grid_to_vtkUnstructuredGrid (const grid_t grid, vtkSmartPointer unstructuredGrid) { diff --git a/src/t8_vtk/t8_vtk_writer_helper.hxx b/src/t8_vtk/t8_vtk_writer_helper.hxx index b896995834..6564b9fa27 100644 --- a/src/t8_vtk/t8_vtk_writer_helper.hxx +++ b/src/t8_vtk/t8_vtk_writer_helper.hxx @@ -20,12 +20,19 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_writer_helper.hxx + * + * This file contains helper functions for the vtk writer. + */ + #ifndef T8_VTK_WRITER_HELPER #define T8_VTK_WRITER_HELPER #include #include +/** The maximum number of corners for a quadratic vtk element */ #define T8_FOREST_VTK_QUADRATIC_ELEMENT_MAX_CORNERS 20 /** Lookup table for number of nodes for curved eclasses. */ const int t8_curved_eclass_num_nodes[T8_ECLASS_COUNT] = { 1, 3, 8, 6, 20, 10, 15, 13 }; @@ -120,7 +127,7 @@ grid_local_num_elements (const grid_t grid); * * \tparam grid_t Either a cmesh or a forest. * \param[in] grid The forest/cmesh to use. - * \param[in, out] Bounds defined by xmin, xmax, ymin, ymax, zmin, zmax. + * \param[in, out] bounds defined by xmin, xmax, ymin, ymax, zmin, zmax. */ template void diff --git a/src/t8_vtk/t8_with_vtk/t8_vtk_parallel.hxx b/src/t8_vtk/t8_with_vtk/t8_vtk_parallel.hxx index 9cda8af4d4..a44db7038a 100644 --- a/src/t8_vtk/t8_with_vtk/t8_vtk_parallel.hxx +++ b/src/t8_vtk/t8_with_vtk/t8_vtk_parallel.hxx @@ -35,7 +35,8 @@ * * \param[in] filename The name of a parallel vtk file to a distributed vtkUnstructuredGrid * \param[in] grid On input a vtkSmartPointer, that will hold the grid described - * by the pieces read on this proc. + * by the pieces read on this proc. + * \param[in] comm The MPI communicator to use for reading the file. * \returns non-zero on success, zero if the reading failed. */ vtk_read_success_t @@ -47,8 +48,9 @@ t8_read_parallel_unstructured (const char *filename, vtkSmartPointer * * \param[in] filename The name of a parallel vtk file to a distributed vtkPolyData * \param[in] grid On input a vtkSmartPointer, that will hold the grid described - * by the pieces read on this proc. - * \returns non-zero on success, zero if the reading failed. + * by the pieces read on this proc. + * \param[in] comm The MPI communicator to use for reading the file. + * \returns read_success on success, read_failure if the reading failed. */ vtk_read_success_t t8_read_parallel_polyData (const char *filename, vtkSmartPointer grid, sc_MPI_Comm comm); diff --git a/src/t8_vtk/t8_with_vtk/t8_vtk_polydata.hxx b/src/t8_vtk/t8_with_vtk/t8_vtk_polydata.hxx index 0a10b1e4f0..d9406463e4 100644 --- a/src/t8_vtk/t8_with_vtk/t8_vtk_polydata.hxx +++ b/src/t8_vtk/t8_with_vtk/t8_vtk_polydata.hxx @@ -21,6 +21,7 @@ */ /** + * \file t8_vtk_polydata.hxx * This file contains all helper functions to translate vtk-polydata. * */ diff --git a/src/t8_vtk/t8_with_vtk/t8_vtk_reader.cxx b/src/t8_vtk/t8_with_vtk/t8_vtk_reader.cxx index 20f78f141b..f0792c2be6 100644 --- a/src/t8_vtk/t8_with_vtk/t8_vtk_reader.cxx +++ b/src/t8_vtk/t8_with_vtk/t8_vtk_reader.cxx @@ -48,8 +48,8 @@ #include /** - * If the vertices of a tree describe a negative \param, - * permute the tree vertices. + * If the vertices of a tree describe a negative volume, we need to + * permute the \a tree_vertices. * * \param[in, out] tree_vertices The vertices of a tree * \param[in] eclass The eclass of the tree. @@ -214,7 +214,9 @@ t8_vtk_grid_get_dimension (vtkSmartPointer vtkGrid) * \param[in] vtkGrid The vtkGrid that gets translated * \param[in, out] cmesh An empty cmesh that is filled with the data. * \param[in] first_tree The global id of the first tree. Will be the global id of the first tree on this proc. - * \param[in] comm A communicator. + * \param[in] comm A communicator. + * \param[in] package_id The package id of the cmesh. + * \param[in] starting_key The starting key of the attributes in the cmesh. * \return The number of elements that have been read by the process. */ diff --git a/src/t8_vtk/t8_with_vtk/t8_vtk_reader.hxx b/src/t8_vtk/t8_with_vtk/t8_vtk_reader.hxx index 10ba6e68e9..6b24a5ce6a 100644 --- a/src/t8_vtk/t8_with_vtk/t8_vtk_reader.hxx +++ b/src/t8_vtk/t8_with_vtk/t8_vtk_reader.hxx @@ -20,6 +20,12 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** + * \file t8_vtk_reader.hxx + * This file contains functions to read different VTK supported formats into + * t8code data structures. + */ + #ifndef T8_VTK_READER #define T8_VTK_READER @@ -40,7 +46,7 @@ * \param[in] main_proc The main reading process * \param[in] distributed_grid Flag if the vtkGrid is distributed over several procs. * \param[in] comm The communicator. - * \param[in] package_id The package id of the application. It is generated with the usage of \ref sc_package_register. + * \param[in] package_id The package id of the application. It is generated with the usage of sc_package_register. * \param[in] starting_key If the application already registered attributes, the starting key is used so that the existing attributes are not overwritten. * \return The committed cmesh */ @@ -50,7 +56,7 @@ t8_vtkGrid_to_cmesh (vtkSmartPointer vtkGrid, const int partition, c /** * Given a pointer to a vtkDataSet a vtkPointSet storing a set of points of - * is constructed. The cell data of vtkDataSet is mapt on the points of vtkPointSet. + * is constructed. The cell data of vtkDataSet is mapped on the points of vtkPointSet. * * \param[in] vtkGrid A pointer to a vtkDataSet * \return A pointer to a vtkPointSet @@ -112,7 +118,7 @@ t8_vtk_reader_pointSet (const char *filename, const int partition, const int mai * \param[in] main_proc The main reading processor * \param[in] comm An mpi-communicator * \param[in] vtk_file_type A vtk-filetype that is readable by t8code. - * \param[in] package_id The package id of the application. It is generated with the usage of \ref sc_package_register. + * \param[in] package_id The package id of the application. It is generated with the usage of sc_package_register. * \param[in] starting_key If the application already registered attributes, the starting key is used so that the existing attributes are not overwritten. * \return A committed cmesh. */ diff --git a/src/t8_vtk/t8_with_vtk/t8_vtk_unstructured.hxx b/src/t8_vtk/t8_with_vtk/t8_vtk_unstructured.hxx index 49ebca4b7f..385f9363e7 100644 --- a/src/t8_vtk/t8_with_vtk/t8_vtk_unstructured.hxx +++ b/src/t8_vtk/t8_with_vtk/t8_vtk_unstructured.hxx @@ -24,6 +24,7 @@ #define T8_CMESH_VTK_UNSTRUCTURED_READER /** + * \file t8_vtk_unstructured.hxx * This file contains all helper-functions needed to read a vtkUnstructuredGrid * from a file using the vtk-library. */ diff --git a/test/api/t8_fortran_interface/t8_test_mpi_init.f90 b/test/api/t8_fortran_interface/t8_test_mpi_init.f90 index 665a6d0ec7..4fb9bc1b0c 100644 --- a/test/api/t8_fortran_interface/t8_test_mpi_init.f90 +++ b/test/api/t8_fortran_interface/t8_test_mpi_init.f90 @@ -46,6 +46,15 @@ program t8_test_mpi_init call t8_fortran_init_all_f (ccomm) call t8_fortran_finalize_f () + + call t8_fortran_mpi_comm_delete_f(ccomm) + call MPI_Finalize(ierror) + + if (ierror /= 0) then + print *, 'MPI Finalize failed.' + stop 1 + endif print *, 'All good!' stop 0 + end program diff --git a/test/t8_cmesh/t8_gtest_cmesh_vertex_conn.cxx b/test/t8_cmesh/t8_gtest_cmesh_vertex_conn.cxx index cb80c63654..813f7d123a 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_vertex_conn.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_vertex_conn.cxx @@ -27,30 +27,30 @@ #include /** \file In this file we test the global cmesh vertex numbers. - * + * * We build a test cmesh consisting of two coarse triangles joined together * and associate global vertex numbers with the cmesh's vertices. * This cmesh has 4 global vertices in total. - * + * * We then perform three tests - * + * * 1) check_tree_to_vertex * Here we test the tree_to_vertex connectivity. * That is, given a tree id, we get a list of the global vertices of that tree * (in local vertex order) and check whether this list is correct. - * + * * 2) check_vertex_to_tree * Here we test the vertex_to_tree connectivity. * Given a global vertex index, the vertex_to_tree connectivity returns a list * of pairs (local tree_id, local_vertex_id) of all the local trees and their local * vertices that are connected to the global vertex. * We check whether this list is correct. - * + * * 3) check_global_vertex_number * We verify that the number of global vertices is 4. * We additionally verify that the process local number of global vertices is 4 as well. * This is true, since the cmesh is not partitioned. - * + * * Additionally, t8_test_cmesh_vertex_conn_partitioned is the start of a test * suite with partitioned cmesh that is currently disabled and could be enabled and extended * when cmesh vertex connectivity supports partitioned cmeshes. @@ -72,7 +72,7 @@ class t8_test_cmesh_vertex_conn: public testing::Test { x ----- x /2\2 1/ - / \ / + / \ / /0 1 \0/ x ----- x @@ -81,10 +81,10 @@ class t8_test_cmesh_vertex_conn: public testing::Test { 2 3 x ---- x /\ / - / \ / + / \ / / \ / 0 x ---- x 1 - + */ const t8_eclass_t tree_class = T8_ECLASS_TRIANGLE; @@ -97,7 +97,7 @@ class t8_test_cmesh_vertex_conn: public testing::Test { constexpr t8_gloidx_t global_vertices_of_tree_1[testcase_num_vertices_per_tree] = { 1, 3, 2 }; t8_cmesh_set_global_vertices_of_tree (cmesh, 0, global_vertices_of_tree_0, testcase_num_vertices_per_tree); t8_cmesh_set_global_vertices_of_tree (cmesh, 1, global_vertices_of_tree_1, testcase_num_vertices_per_tree); - /* TODO: When cmesh becomes a class implement a cmesh member function to do this instead: + /* TODO: When cmesh becomes a class implement a cmesh member function to do this instead: cmesh.set_global_vertices_of_tree (0, global_vertices_of_tree_0, testcase_num_vertices_per_tree); cmesh.set_global_vertices_of_tree (1, global_vertices_of_tree_1, testcase_num_vertices_per_tree); */ @@ -127,10 +127,14 @@ TEST_F (t8_test_cmesh_vertex_conn, check_tree_to_vertex) ASSERT_FALSE (t8_cmesh_is_partitioned (cmesh)); /* Get the vertices of the trees and check their values. */ + int returned_num_vertices_per_tree; const t8_gloidx_t *check_global_vertices_tree_0 - = t8_cmesh_get_global_vertices_of_tree (cmesh, 0, testcase_num_vertices_per_tree); + = t8_cmesh_get_global_vertices_of_tree (cmesh, 0, &returned_num_vertices_per_tree); + EXPECT_EQ (testcase_num_vertices_per_tree, returned_num_vertices_per_tree); const t8_gloidx_t *check_global_vertices_tree_1 - = t8_cmesh_get_global_vertices_of_tree (cmesh, 1, testcase_num_vertices_per_tree); + = t8_cmesh_get_global_vertices_of_tree (cmesh, 1, &returned_num_vertices_per_tree); + EXPECT_EQ (testcase_num_vertices_per_tree, returned_num_vertices_per_tree); + EXPECT_EQ (check_global_vertices_tree_0[0], 0); EXPECT_EQ (check_global_vertices_tree_0[1], 1); EXPECT_EQ (check_global_vertices_tree_0[2], 2); @@ -149,10 +153,10 @@ TEST_F (t8_test_cmesh_vertex_conn, check_vertex_to_tree) ASSERT_FALSE (t8_cmesh_is_partitioned (cmesh)); /* - + The vertex to tree lists should have been built up with the following entries ( x:y corresponding to tree x, local tree vertex y) - + 0: 0:0 1: 0:1, 1:0 2: 0:2, 1:2 @@ -225,8 +229,8 @@ class t8_test_cmesh_vertex_conn_partitioned: public testing::Test { */ /* We want to have as many trees as mpiranks, so that - * each rank has at least one tree when partitioned. - * Compute the mpisize and assign it to the number of trees: + * each rank has at least one tree when partitioned. + * Compute the mpisize and assign it to the number of trees: * */ const sc_MPI_Comm comm = sc_MPI_COMM_WORLD; int mpiret = sc_MPI_Comm_size (comm, &mpisize); diff --git a/test/t8_cmesh/t8_gtest_cmesh_vertex_conn_tree_to_vertex.cxx b/test/t8_cmesh/t8_gtest_cmesh_vertex_conn_tree_to_vertex.cxx index aab79649b8..e5ae977a35 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_vertex_conn_tree_to_vertex.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_vertex_conn_tree_to_vertex.cxx @@ -50,19 +50,19 @@ Note to future developers: 2. derive a cmesh from it 3. Add vertices to the direved cmesh 4. commit the derived cmesh - - This is implemented in the + + This is implemented in the cmesh_vertex_conn_ttv_with_core_classes cmesh_vertex_conn_ttv_with_cmesh_functions test suites. - + However, as of now (i.e. April 2025), we cannot not add attributes (and hence vertices) while deriving a cmesh. It is only possible to add attributes when constructing a new cmesh from scratch. Thus, the test suites are currently disabled/commented out with #if 0 blocks. Instead, we currently create a bunch of test cmeshes ourself from scratch. - This is implemented in the + This is implemented in the cmesh_vertex_conn_ttv_with_core_classes_temp cmesh_vertex_conn_ttv_with_cmesh_functions_temp test suites. @@ -127,12 +127,13 @@ TEST_P (cmesh_vertex_conn_ttv_with_core_classes, DISABLED_get_global) const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; /* Get all vertices */ - const t8_gloidx_t *global_vertices = ttv.get_global_vertices (cmesh, itree, num_tree_vertices); + auto global_vertices = ttv.get_global_vertices (cmesh, itree); + EXPECT_EQ (global_vertices.size (), num_tree_vertices); const t8_gloidx_t start_index = itree * T8_ECLASS_MAX_CORNERS; for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) { /* Get the stored global vertex id */ - const t8_gloidx_t global_vertex = ttv.get_global_vertex (cmesh, itree, ivertex, num_tree_vertices); + const t8_gloidx_t global_vertex = ttv.get_global_vertex (cmesh, itree, ivertex); /* Check value */ EXPECT_EQ (global_vertex, start_index + ivertex); EXPECT_EQ (global_vertices[ivertex], start_index + ivertex); @@ -144,7 +145,13 @@ TEST_P (cmesh_vertex_conn_ttv_with_core_classes, DISABLED_get_global) * as soon as we can enable the tests cmesh_vertex_conn_ttv. * That is as soon as we can add attributes to cmeshes while deriving. */ +#if T8_TEST_LEVEL_INT >= 2 +#define VTT_TEST_MAX_NUM_TREES 10 +#elif T8_TEST_LEVEL_INT == 1 +#define VTT_TEST_MAX_NUM_TREES 50 +#else #define VTT_TEST_MAX_NUM_TREES 100 +#endif class cmesh_vertex_conn_ttv_with_core_classes_temp: public testing::TestWithParam> { @@ -206,13 +213,14 @@ TEST_P (cmesh_vertex_conn_ttv_with_core_classes_temp, get_global) const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; /* Get all vertices */ - const t8_gloidx_t *global_vertices = ttv.get_global_vertices (cmesh, itree, num_tree_vertices); + auto global_vertices = ttv.get_global_vertices (cmesh, itree); + EXPECT_EQ (global_vertices.size (), num_tree_vertices); const t8_gloidx_t global_tree_id = t8_cmesh_get_global_id (cmesh, itree); const t8_gloidx_t start_index = global_tree_id * T8_ECLASS_MAX_CORNERS; for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) { /* Get the stored global vertex id */ - const t8_gloidx_t global_vertex = ttv.get_global_vertex (cmesh, itree, ivertex, num_tree_vertices); + const t8_gloidx_t global_vertex = ttv.get_global_vertex (cmesh, itree, ivertex); /* Check value */ EXPECT_EQ (global_vertex, start_index + ivertex); EXPECT_EQ (global_vertices[ivertex], start_index + ivertex); @@ -232,9 +240,9 @@ TEST_P (cmesh_vertex_conn_ttv_with_core_classes_temp, convert_to_vtt) t8_cmesh_vertex_conn_vertex_to_tree vtt; vtt.build_from_ttv (cmesh, ttv); /* Since global tree i is mapped to vertices: - * i*T8_ECLASS_MAX_CORNERS, i*T8_ECLASS_MAX_CORNERS + 1, ... + * i*T8_ECLASS_MAX_CORNERS, i*T8_ECLASS_MAX_CORNERS + 1, ... * and this mapping is unique, we know that the list for vertex j - * must contain + * must contain * global tree j / T8_ECLASS_MAX_CORNERS * with local vertex j % T8_ECLASS_MAX_CORNERS */ ASSERT_TRUE (vtt.is_committed ()); @@ -314,12 +322,14 @@ TEST_P (cmesh_vertex_conn_ttv_with_cmesh_functions, DISABLED_get_global) const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; /* Get all vertices */ - const t8_gloidx_t *global_vertices = t8_cmesh_get_global_vertices_of_tree (cmesh, itree, num_tree_vertices); + int returned_num_vertices = -1; + const t8_gloidx_t *global_vertices = t8_cmesh_get_global_vertices_of_tree (cmesh, itree, &returned_num_vertices); + EXPECT_EQ (returned_num_vertices, num_tree_vertices); const t8_gloidx_t start_index = itree * T8_ECLASS_MAX_CORNERS; for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) { /* Get the stored global vertex id */ - const t8_gloidx_t global_vertex = t8_cmesh_get_global_vertex_of_tree (cmesh, itree, ivertex, num_tree_vertices); + const t8_gloidx_t global_vertex = t8_cmesh_get_global_vertex_of_tree (cmesh, itree, ivertex); /* Check value */ EXPECT_EQ (global_vertex, start_index + ivertex); EXPECT_EQ (global_vertices[ivertex], start_index + ivertex); @@ -331,8 +341,6 @@ TEST_P (cmesh_vertex_conn_ttv_with_cmesh_functions, DISABLED_get_global) * as soon as we can enable the tests cmesh_vertex_conn_ttv. * That is as soon as we can add attributes to cmeshes while deriving. */ -#define VTT_TEST_MAX_NUM_TREES 100 - class cmesh_vertex_conn_ttv_with_cmesh_functions_temp: public testing::TestWithParam> { protected: @@ -391,13 +399,14 @@ TEST_P (cmesh_vertex_conn_ttv_with_cmesh_functions_temp, get_global) const int num_tree_vertices = t8_eclass_num_vertices[tree_class]; /* Get all vertices */ - const t8_gloidx_t *global_vertices = t8_cmesh_get_global_vertices_of_tree (cmesh, itree, num_tree_vertices); + int returned_num_vertices = -1; + const t8_gloidx_t *global_vertices = t8_cmesh_get_global_vertices_of_tree (cmesh, itree, &returned_num_vertices); const t8_gloidx_t global_tree_id = t8_cmesh_get_global_id (cmesh, itree); const t8_gloidx_t start_index = global_tree_id * T8_ECLASS_MAX_CORNERS; for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) { /* Get the stored global vertex id */ - const t8_gloidx_t global_vertex = t8_cmesh_get_global_vertex_of_tree (cmesh, itree, ivertex, num_tree_vertices); + const t8_gloidx_t global_vertex = t8_cmesh_get_global_vertex_of_tree (cmesh, itree, ivertex); /* Check value */ EXPECT_EQ (global_vertex, start_index + ivertex); EXPECT_EQ (global_vertices[ivertex], start_index + ivertex); diff --git a/tutorials/general/t8_step5_element_data.cxx b/tutorials/general/t8_step5_element_data.cxx index b1e7648fbb..63402ca25f 100644 --- a/tutorials/general/t8_step5_element_data.cxx +++ b/tutorials/general/t8_step5_element_data.cxx @@ -117,11 +117,11 @@ t8_step5_create_element_data (t8_forest_t forest) /* Let us now fill the data with something. * For this, we iterate through all trees and for each tree through all its elements, calling - * t8_forest_get_element_in_tree to get a pointer to the current element. + * t8_forest_get_leaf_element_in_tree to get a pointer to the current element. * This is the recommended and most performant way. * An alternative is to iterate over the number of local elements and use * t8_forest_get_leaf_element. However, this function needs to perform a binary search - * for the element and the tree it is in, while t8_forest_get_element_in_tree has a + * for the element and the tree it is in, while t8_forest_get_leaf_element_in_tree has a * constant look up time. You should only use t8_forest_get_leaf_element if you do not know * in which tree an element is. */ diff --git a/tutorials/general/t8_step5_element_data_c_interface.c b/tutorials/general/t8_step5_element_data_c_interface.c index 483d61c3aa..ffd22b3e75 100644 --- a/tutorials/general/t8_step5_element_data_c_interface.c +++ b/tutorials/general/t8_step5_element_data_c_interface.c @@ -119,11 +119,11 @@ t8_step5_create_element_data (t8_forest_t forest) /* Let us now fill the data with something. * For this, we iterate through all trees and for each tree through all its elements, calling - * t8_forest_get_element_in_tree to get a pointer to the current element. + * t8_forest_get_leaf_element_in_tree to get a pointer to the current element. * This is the recommended and most performant way. * An alternative is to iterate over the number of local elements and use * t8_forest_get_leaf_element. However, this function needs to perform a binary search - * for the element and the tree it is in, while t8_forest_get_element_in_tree has a + * for the element and the tree it is in, while t8_forest_get_leaf_element_in_tree has a * constant look up time. You should only use t8_forest_get_leaf_element if you do not know * in which tree an element is. */