diff --git a/.github/workflows/build_cmake_tarball.yml b/.github/workflows/build_cmake_tarball.yml index d5db4e723a..b63e420873 100644 --- a/.github/workflows/build_cmake_tarball.yml +++ b/.github/workflows/build_cmake_tarball.yml @@ -41,7 +41,7 @@ jobs: build: if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule') - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest container: dlramr/t8code-ubuntu:t8-dependencies timeout-minutes: 90 steps: @@ -59,8 +59,6 @@ jobs: uses: nikeee/setup-pandoc@v1 - name: Test pandoc run: pandoc --version - # On the github Ubuntu 20.04, sudo is not available by default - # we need it, however, to update/upgrade our packages. - name: Update packages run: sudo apt-get update && sudo apt-get upgrade -y # This step is necessary to get the newest package data @@ -99,14 +97,12 @@ jobs: test-tarball: needs: build - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest container: dlramr/t8code-ubuntu:t8-dependencies timeout-minutes: 90 steps: - name: install sudo run: apt update && apt install sudo - # On the github Ubuntu 20.04, sudo is not available by default - # we need it, however, to update/upgrade our packages. - name: Update packages run: sudo apt-get update && sudo apt-get upgrade -y # This step is necessary to get the newest package data diff --git a/.github/workflows/check_indentation.yml b/.github/workflows/check_indentation.yml index 920ddcb609..592b4c5ee7 100644 --- a/.github/workflows/check_indentation.yml +++ b/.github/workflows/check_indentation.yml @@ -31,15 +31,11 @@ name: t8code indentation check # The output is uploaded as an artifact to the github page. on: + merge_group: push: branches: - main - - develop - - feature-*CI* # for testing this script, all feature branches with "CI" in their name pull_request: - branches: - - main - - develop workflow_dispatch: # Be able to trigger this manually on github.com # Run every night at 1:05 schedule: @@ -48,7 +44,7 @@ on: jobs: indent: if: (github.event_name == 'schedule' && github.repository == 'DLR-AMR/t8code') || (github.event_name != 'schedule') - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -58,8 +54,6 @@ jobs: # Deactivated the install sudo because it failed. #- name: install sudo # run: apt update && apt install sudo - # On the github Ubuntu 20.04, sudo is not available by default - # we need it, however, to update/upgrade our packages. - name: Update packages run: sudo apt-get update && sudo apt-get upgrade -y # This step is necessary to get the newest package data diff --git a/.github/workflows/mattermost_issue.yml b/.github/workflows/mattermost_issue.yml index a0126646b5..7c4f351c12 100644 --- a/.github/workflows/mattermost_issue.yml +++ b/.github/workflows/mattermost_issue.yml @@ -39,7 +39,7 @@ env: jobs: send_mm_message_issue: if: github.repository == 'DLR-AMR/t8code' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: debug_before_build run: echo ${{ env.message_build}} diff --git a/.github/workflows/mattermost_pull_request.yml b/.github/workflows/mattermost_pull_request.yml index 97b78825c9..42c2e0fc73 100644 --- a/.github/workflows/mattermost_pull_request.yml +++ b/.github/workflows/mattermost_pull_request.yml @@ -28,7 +28,7 @@ name: Mattermost_message_pull_request on: # Triggers the workflow on pull request events on the feature-CI_mattermost_messages, develop or main branch pull_request: - branches: [ feature-CI_mattermost_messages, develop, main ] + branches: types: [ opened, synchronize, reopened, closed] # Allows you to run this workflow manually from the Actions tab @@ -39,7 +39,7 @@ env: jobs: send_mm_message_pr: if: github.repository == 'DLR-AMR/t8code' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: debug_before_build run: echo ${{ env.message_build}} diff --git a/.github/workflows/spell_check.yml b/.github/workflows/spell_check.yml index 035aa4e7aa..67fdeec024 100644 --- a/.github/workflows/spell_check.yml +++ b/.github/workflows/spell_check.yml @@ -1,10 +1,10 @@ name: spell_check on: + merge_group: push: branches: - main - - feature-*CI* # for testing this script, all feature branches with "CI" in their name pull_request: workflow_dispatch: # Be able to trigger this manually on github.com diff --git a/.github/workflows/tests_cmake_testsuite.yml b/.github/workflows/tests_cmake_testsuite.yml index 85ef8b9462..ff80a72c66 100644 --- a/.github/workflows/tests_cmake_testsuite.yml +++ b/.github/workflows/tests_cmake_testsuite.yml @@ -31,15 +31,11 @@ name: t8code CMake testsuite # IGNORE_CACHE to true in the respective steps. on: + merge_group: push: branches: - main - - develop - - feature-*CI* # for testing this script, all feature branches with "CI" in their name pull_request: - branches: - - main - - develop workflow_dispatch: # Be able to trigger this manually on github.com # Run every night at 1:10 schedule: diff --git a/AUTHORS b/AUTHORS index ad1666da1b..bc9866178f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -26,5 +26,5 @@ Contributors: Andrew Kirby Hendrik Ranocha Michael Schlottke-Lakemper - Kathrin Schoenlein + Katrin Schoenlein diff --git a/CITATION.cff b/CITATION.cff index 31385733f9..5b38fb5fa3 100755 --- a/CITATION.cff +++ b/CITATION.cff @@ -113,9 +113,9 @@ authors: family-names: Schlottke-Lakemper email: m.schlottke-lakemper@acom.rwth-aachen.de affiliation: "RWTH Aachen" - - given-names: Kathrin + - given-names: Katrin family-names: Schoenlein - email: kathrin.schoenlein@dlr.de + email: katrin.schoenlein@dlr.de affiliation: "German Aerospace Center (DLR)" - given-names: Tabea family-names: Leistikow diff --git a/README.md b/README.md index 5010ff1049..c4e99e24ed 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,9 @@ to install the package on your system. [6] **Geometry controlled refinement for hexahedra**: Elsweijer, Sandro and Holke, Johannes and Kleinert, Jan and Reith, Dirk (2022) *Constructing a Volume Geometry Map for Hexahedra with Curved Boundary Geometries*. In: SIAM International Meshing Roundtable Workshop 2022. SIAM International Meshing Roundtable Workshop 2022, 22. - 25. Feb. 2022, [Full text available](https://elib.dlr.de/186570/1/ConstructingAVolumeGeometryMapForHexahedraWithCurvedBoundaryGeometries.pdf) + [7] **JOSS entry**: + Holke, Johannes and Markert, Johannes, et. al. (2025) *t8code - modular adaptive mesh refinement in the exascale era*. In: Journal of Open Source Software, [Full text available](https://www.theoj.org/joss-papers/joss.06887/10.21105.joss.06887.pdf) + ### Theses with t8code relations An (incomplete) list of theses written with or about t8code: diff --git a/api/t8_fortran_interface/CMakeLists.txt b/api/t8_fortran_interface/CMakeLists.txt index 3072277cd3..3636be24b6 100644 --- a/api/t8_fortran_interface/CMakeLists.txt +++ b/api/t8_fortran_interface/CMakeLists.txt @@ -8,11 +8,11 @@ target_include_directories( T8 PRIVATE ${CMAKE_CURRENT_LIST_DIR} ) # Install header files. install( FILES ${CMAKE_CURRENT_LIST_DIR}/t8_fortran_interface.h - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/t8_fortran_interface + DESTINATION include/t8_fortran_interface ) # Install module files. install( FILES ${CMAKE_BINARY_DIR}/src/t8_fortran_interface_mod.mod - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/t8_fortran_interface + DESTINATION include/t8_fortran_interface ) diff --git a/api/t8_fortran_interface/t8_fortran_interface.c b/api/t8_fortran_interface/t8_fortran_interface.c index 7606ab9e1b..4c2f6c6d8c 100644 --- a/api/t8_fortran_interface/t8_fortran_interface.c +++ b/api/t8_fortran_interface/t8_fortran_interface.c @@ -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) 2024 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 diff --git a/api/t8_fortran_interface/t8_fortran_interface.h b/api/t8_fortran_interface/t8_fortran_interface.h index 195205f280..e6bdf2104d 100644 --- a/api/t8_fortran_interface/t8_fortran_interface.h +++ b/api/t8_fortran_interface/t8_fortran_interface.h @@ -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) 2024 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 diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 00d128dacf..aec3145190 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -25,7 +25,7 @@ function( add_t8_benchmark ) set_target_properties( ${ADD_T8_BENCHMARK_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) endif( T8CODE_EXPORT_COMPILE_COMMANDS ) - install( TARGETS ${ADD_T8_BENCHMARK_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + install( TARGETS ${ADD_T8_BENCHMARK_NAME} DESTINATION bin ) endfunction() add_t8_benchmark( NAME t8_time_partition SOURCES t8_time_partition.cxx ) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 541155e66a..840c5cba26 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -457,7 +457,7 @@ LOOKUP_CACHE_SIZE = 0 # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you +# which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. diff --git a/doc/author_brandt.txt b/doc/author_brandt.txt new file mode 100644 index 0000000000..095dab52be --- /dev/null +++ b/doc/author_brandt.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Hannes Brandt (brandt@ins.uni-bonn.de) diff --git a/doc/author_nguyenxuan.txt b/doc/author_nguyenxuan.txt new file mode 100644 index 0000000000..cb949c35c7 --- /dev/null +++ b/doc/author_nguyenxuan.txt @@ -0,0 +1,2 @@ +I place my contributions to t8code under the FreeBSD license. +Tu Nguyen Xuan (tu.nguyenxuan@dlr.de) \ No newline at end of file diff --git a/doc/author_ploetzke.txt b/doc/author_ploetzke.txt new file mode 100644 index 0000000000..f33e3e26b3 --- /dev/null +++ b/doc/author_ploetzke.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Lena Plötzke (lena.ploetzke@gmx.de) \ No newline at end of file diff --git a/doc/author_spenke.txt b/doc/author_spenke.txt new file mode 100644 index 0000000000..0e7b6ec0dc --- /dev/null +++ b/doc/author_spenke.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Thomas Spenke (thomas.spenke@dlr.de) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index a01a9c6e6e..33393167f9 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -7,7 +7,7 @@ endif() target_sources( t8example PRIVATE common/t8_example_common.cxx common/t8_example_common_functions.cxx ) target_include_directories( t8example PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ${SC_INCLUDE_DIR} ) target_link_libraries( t8example PRIVATE T8 ${SC_LIBRARIES} m ) -install( TARGETS t8example DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) +install( TARGETS t8example DESTINATION lib ) function( add_t8_example ) set( options "" ) @@ -36,7 +36,7 @@ function( add_t8_example ) set_target_properties( ${ADD_T8_EXAMPLE_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) endif( T8CODE_EXPORT_COMPILE_COMMANDS ) - install( TARGETS ${ADD_T8_EXAMPLE_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + install( TARGETS ${ADD_T8_EXAMPLE_NAME} DESTINATION bin ) endfunction() add_t8_example( NAME t8_advection SOURCES advect/t8_advection.cxx ) diff --git a/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx b/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx index 91eb788b7f..8e214a27c5 100644 --- a/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx +++ b/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx @@ -131,7 +131,7 @@ main (int argc, char **argv) snprintf (usage, BUFSIZ, "Usage:\t%s \n\t%s -h\t for a brief overview of all options.", basename (argv[0]), basename (argv[0])); sreturn = snprintf (help, BUFSIZ, - "This program reads a .vtk-file and constructs a mesh representing the given Data." + "This program reads a .vtk-file and constructs a mesh representing the given Data.\n" "Arguments can be passed via:\n%s\n\n", usage); if (sreturn >= BUFSIZ) { @@ -151,7 +151,7 @@ main (int argc, char **argv) sc_options_add_string (opt, 'f', "vtk-file", &vtk_file, "", "The prefix of the .vtk file."); sc_options_add_string (opt, 'o', "output", &out_file, "output", "The prefix of the output-file."); sc_options_add_int (opt, 'c', "num_cell_values", &num_keys, 0, "Number of values per cell stored in the vtk-file."); - sc_options_add_bool (opt, 'p', "partition", &partition, 0, "If set, partition the cmesh uniformly."); + sc_options_add_switch (opt, 'p', "partition", &partition, "If set, partition the cmesh uniformly."); sc_options_add_int (opt, 't', "type_of_file", &vtk_file_type_int, -1, "Set the type of the data in the file.\n" "\t\t\t\t\t0 for vtkUnstructuredGrid,\n" diff --git a/p4est b/p4est index 851774a0c9..8399186d4e 160000 --- a/p4est +++ b/p4est @@ -1 +1 @@ -Subproject commit 851774a0c993aaf6f1719da6fd62c2f3acd761ee +Subproject commit 8399186d4ea214361ce0d183b9bbd340a417075e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91a8ddfcba..98783ebaff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,7 +60,7 @@ endif() if( T8CODE_ENABLE_OCC ) target_compile_definitions( T8 PUBLIC T8_WITH_OCC=1 ) - target_include_directories( T8 PUBLIC ${OpenCASCADE_INCLUDE_DIR} ) + target_include_directories( T8 SYSTEM PUBLIC ${OpenCASCADE_INCLUDE_DIR} ) target_link_libraries( T8 PUBLIC ${OpenCASCADE_LIBRARIES} ) endif() @@ -122,7 +122,8 @@ target_sources( T8 PRIVATE t8_forest/t8_forest_ghost.cxx t8_forest/t8_forest_iterate.cxx t8_forest/t8_forest_balance.cxx - t8_forest/t8_forest_netcdf.cxx + t8_forest/t8_forest_netcdf.cxx + t8_forest/t8_forest_search/t8_forest_search.cxx t8_geometry/t8_geometry.cxx t8_geometry/t8_geometry_helpers.c t8_geometry/t8_geometry_base.cxx @@ -155,7 +156,6 @@ target_sources( T8 PRIVATE t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.c t8_schemes/t8_default/t8_default_tri/t8_dtri_connectivity.c t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx - t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.c t8_schemes/t8_standalone/t8_standalone.cxx t8_vtk/t8_vtk_polydata.cxx t8_vtk/t8_vtk_unstructured.cxx @@ -204,26 +204,27 @@ install( FILES t8_vec.h t8_version.h t8_vtk.h - t8_windows.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include + t8_windows.h DESTINATION include ) -install( DIRECTORY t8_cmesh DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.h" ) -install( DIRECTORY t8_data DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.h" ) -install( DIRECTORY t8_forest DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING +install( DIRECTORY t8_cmesh DESTINATION include FILES_MATCHING PATTERN "*.h" ) +install( DIRECTORY t8_data DESTINATION include FILES_MATCHING PATTERN "*.h" ) +install( DIRECTORY t8_forest DESTINATION include FILES_MATCHING PATTERN "*.h" PATTERN "*private.h" EXCLUDE ) -install( DIRECTORY t8_geometry DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.h" ) -install( DIRECTORY t8_schemes DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.h" ) -install( DIRECTORY t8_vtk DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.h" ) - -install( DIRECTORY t8_cmesh DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) -install( DIRECTORY t8_data DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) -install( DIRECTORY t8_forest DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) -install( DIRECTORY t8_geometry DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) -install( DIRECTORY t8_schemes DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) -install( DIRECTORY t8_vtk DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" ) - -install( TARGETS T8 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) +install( DIRECTORY t8_geometry DESTINATION include FILES_MATCHING PATTERN "*.h" ) +install( DIRECTORY t8_schemes DESTINATION include FILES_MATCHING PATTERN "*.h" ) +install( DIRECTORY t8_vtk DESTINATION include FILES_MATCHING PATTERN "*.h" ) + +install( DIRECTORY t8_cmesh DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_data DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_forest DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_geometry DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_schemes DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_vtk DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) +install( DIRECTORY t8_types DESTINATION include FILES_MATCHING PATTERN "*.hxx" ) + +install( TARGETS T8 DESTINATION lib ) install( TARGETS T8 EXPORT ${PROJECT_NAME}-targets ) include( CMakePackageConfigHelpers ) diff --git a/src/Makefile.am b/src/Makefile.am index 00d6f18b19..b0c31b0bbf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,9 @@ libt8_installed_headers_forest = \ src/t8_forest/t8_forest_profiling.h \ src/t8_forest/t8_forest_io.h \ src/t8_forest/t8_forest_adapt.h \ - src/t8_forest/t8_forest_iterate.h src/t8_forest/t8_forest_partition.h + src/t8_forest/t8_forest_iterate.h \ + src/t8_forest/t8_forest_partition.h \ + src/t8_forest/t8_forest_search/t8_forest_search.hxx libt8_installed_headers_geometry = \ src/t8_geometry/t8_geometry.h \ src/t8_geometry/t8_geometry_handler.hxx \ @@ -139,6 +141,7 @@ libt8_compiled_sources = \ src/t8_forest/t8_forest_partition.cxx src/t8_forest/t8_forest.cxx \ src/t8_forest/t8_forest_private.c \ src/t8_forest/t8_forest_ghost.cxx src/t8_forest/t8_forest_iterate.cxx \ + src/t8_forest/t8_forest_search/t8_forest_search.cxx \ src/t8_version.c \ src/t8_vtk.c src/t8_forest/t8_forest_balance.cxx \ src/t8_forest/t8_forest_netcdf.cxx \ diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index da5d48e101..ea1043ca8f 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -769,11 +769,6 @@ t8_cmesh_unref (t8_cmesh_t *pcmesh); void t8_cmesh_destroy (t8_cmesh_t *pcmesh); -/* Functions for constructing complete and committed cmeshes */ - -t8_cmesh_t -t8_cmesh_new_testhybrid (sc_MPI_Comm comm); - /** Compute y = ax + b on an array of doubles, interpreting * each 3 as one vector x * \param[in] coords_in The incoming coordinates of the vectors diff --git a/src/t8_cmesh.hxx b/src/t8_cmesh.hxx index ed428b0089..238dd64fcd 100644 --- a/src/t8_cmesh.hxx +++ b/src/t8_cmesh.hxx @@ -24,7 +24,8 @@ * We define the coarse mesh of trees in this file. */ -#pragma once +#ifndef T8_CMESH_HXX +#define T8_CMESH_HXX #include #include @@ -48,3 +49,5 @@ t8_cmesh_register_geometry (t8_cmesh_t cmesh, _args &&...args) } return cmesh->geometry_handler->register_geometry (std::forward<_args> (args)...); } + +#endif /* T8_CMESH_HXX */ diff --git a/src/t8_cmesh/t8_cmesh_examples.cxx b/src/t8_cmesh/t8_cmesh_examples.cxx index 6305792407..49c46ea168 100644 --- a/src/t8_cmesh/t8_cmesh_examples.cxx +++ b/src/t8_cmesh/t8_cmesh_examples.cxx @@ -680,12 +680,6 @@ t8_cmesh_new_hypercube (t8_eclass_t eclass, sc_MPI_Comm comm, int do_bcast, int SC_CHECK_ABORT (eclass != T8_ECLASS_PYRAMID || !periodic, "The pyramid cube mesh cannot be periodic.\n"); - if (do_partition) { - t8_global_errorf ( - "WARNING: Partitioning the hypercube cmesh is currently not supported.\n" - "Using this cmesh will crash when vertices are used. See also https://github.com/DLR-AMR/t8code/issues/79\n"); - } - mpiret = sc_MPI_Comm_rank (comm, &mpirank); SC_CHECK_MPI (mpiret); if (!do_bcast || mpirank == 0) { diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index 3b1f8bac36..e79d7fff5d 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -3685,7 +3685,6 @@ t8_eclass_t t8_forest_get_tree_class (const t8_forest_t forest, const t8_locidx_t ltreeid) { t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); - T8_ASSERT (0 <= ltreeid && ltreeid < num_local_trees + t8_forest_get_num_ghost_trees (forest)); if (ltreeid < num_local_trees) { /* The id belongs to a local tree */ diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index 1dcb4c3f35..65cd17f38c 100644 --- a/src/t8_forest/t8_forest_general.h +++ b/src/t8_forest/t8_forest_general.h @@ -61,10 +61,10 @@ T8_EXTERN_C_BEGIN (); * of the new forest that are either refined, coarsened or the same as elements in the old forest. * * \param [in] forest_old The forest that is adapted - * \param [in] forest_new The forest that is newly constructed from \a forest_old + * \param [in, out] forest_new The forest that is newly constructed from \a forest_old * \param [in] which_tree The local tree containing \a first_outgoing and \a first_incoming * \param [in] tree_class The eclass of the local tree containing \a first_outgoing and \a first_incoming - * \param [in] scheme The scheme of the forest + * \param [in] scheme The scheme of the forest * \param [in] refine -1 if family in \a forest_old got coarsened, 0 if element * has not been touched, 1 if element got refined and -2 if * element got removed. See return of t8_forest_adapt_t. @@ -101,7 +101,7 @@ typedef void (*t8_forest_replace_t) (t8_forest_t forest_old, t8_forest_t forest_ * \param [in] which_tree The local tree containing \a elements. * \param [in] tree_class The eclass of \a which_tree. * \param [in] lelement_id The local element id in \a forest_old in the tree of the current element. - * \param [in] scheme The scheme of the forest. + * \param [in] scheme The scheme of the forest. * \param [in] is_family If 1, the first \a num_elements entries in \a elements form a family. If 0, they do not. * \param [in] num_elements The number of entries in \a elements that are defined * \param [in] elements Pointers to a family or, if \a is_family is zero, @@ -119,7 +119,7 @@ typedef int (*t8_forest_adapt_t) (t8_forest_t forest, t8_forest_t forest_from, t /** Create a new forest with reference count one. * This forest needs to be specialized with the t8_forest_set_* calls. - * Currently it is manatory to either call the functions \ref + * Currently it is mandatory to either call the functions \ref * t8_forest_set_mpicomm, \ref t8_forest_set_cmesh, and \ref t8_forest_set_scheme, * or to call one of \ref t8_forest_set_copy, \ref t8_forest_set_adapt, or * \ref t8_forest_set_partition. It is illegal to mix these calls, or to @@ -249,7 +249,7 @@ t8_forest_set_copy (t8_forest_t forest, const t8_forest_t from); * and it is recursive otherwise. * \note This setting can be combined with \ref t8_forest_set_partition and \ref * t8_forest_set_balance. The order in which these operations are executed is always - * 1) Adapt 2) Balance 3) Partition + * 1) Adapt 2) Partition 3) Balance. * \note This setting may not be combined with \ref t8_forest_set_copy and overwrites * this setting. */ @@ -312,7 +312,7 @@ t8_forest_get_user_function (const t8_forest_t forest); * operation. * \note This setting can be combined with \ref t8_forest_set_adapt and \ref * t8_forest_set_balance. The order in which these operations are executed is always - * 1) Adapt 2) Balance 3) Partition + * 1) Adapt 2) Partition 3) Balance. * If \ref t8_forest_set_balance is called with the \a no_repartition parameter set as * false, it is not necessary to call \ref t8_forest_set_partition additionally. * \note This setting may not be combined with \ref t8_forest_set_copy and overwrites @@ -339,8 +339,8 @@ t8_forest_set_partition (t8_forest_t forest, const t8_forest_t set_from, int set * If \a no_repartition is false, an additional call of \ref t8_forest_set_partition is not * necessary. * \note This setting can be combined with \ref t8_forest_set_adapt and \ref - * t8_forest_set_balance. The order in which these operations are executed is always - * 1) Adapt 2) Balance 3) Partition. + * t8_forest_set_partition. The order in which these operations are executed is always + * 1) Adapt 2) Partition 3) Balance. * \note This setting may not be combined with \ref t8_forest_set_copy and overwrites * this setting. */ @@ -615,8 +615,8 @@ t8_forest_leaf_face_neighbors_ext (t8_forest_t forest, t8_locidx_t ltreeid, cons t8_gloidx_t *gneigh_tree, int *orientation); /** Exchange ghost information of user defined element data. - * \param[in] forest The forest. Must be committed. - * \param[in] element_data An array of length num_local_elements + num_ghosts + * \param [in] forest The forest. Must be committed. + * \param [in] element_data An array of length num_local_elements + num_ghosts * storing one value for each local element and ghost in \a forest. * After calling this function the entries for the ghost elements * are update with the entries in the \a element_data array of diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index 7cbbde1edc..1ce40f6ca0 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -152,7 +152,7 @@ t8_ghost_remote_equal_function (const void *remote_dataa, const void *remote_dat } /** This struct is used during a ghost data exchange. - * Since we use asynchronuous communication, we store the + * Since we use asynchronous communication, we store the * send buffers and mpi requests until we end the communication. */ typedef struct diff --git a/src/t8_forest/t8_forest_iterate.cxx b/src/t8_forest/t8_forest_iterate.cxx index 87cdd2dad1..3b381b1b7f 100644 --- a/src/t8_forest/t8_forest_iterate.cxx +++ b/src/t8_forest/t8_forest_iterate.cxx @@ -536,4 +536,11 @@ t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_fo t8_global_productionf ("Done t8_forest_iterate_replace\n"); } +void +t8_forest_search_partition (const t8_forest_t forest, t8_forest_partition_search_fn search_fn, + t8_forest_partition_query_fn query_fn, sc_array_t *queries) +{ + SC_ABORT ("not implemented yet"); +} + T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_iterate.h b/src/t8_forest/t8_forest_iterate.h index 5f1ac2f27b..06eebf1f7e 100644 --- a/src/t8_forest/t8_forest_iterate.h +++ b/src/t8_forest/t8_forest_iterate.h @@ -79,6 +79,48 @@ typedef void (*t8_forest_query_fn) (t8_forest_t forest, const t8_locidx_t ltreei const int is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, sc_array_t *queries, sc_array_t *query_indices, int *query_matches, const size_t num_active_queries); +/** + * A call-back function used by \ref t8_forest_search_partition describing a search-criterion. 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. Since the cmesh has to be + * replicated, it coincides with the global tree id. + * \param[in] element the element for which the search criterion is checked + * \param[in] pfirst the first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the last processor that owns part of \a element. Guaranteed to be non-empty. + * \returns non-zero if the search criterion is met, zero otherwise. + */ +typedef int (*t8_forest_partition_search_fn) (const t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int pfirst, const int plast); + +/** + * A call-back function used by \ref t8_forest_search_partition for 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. 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. Since the cmesh has to be + * replicated, it coincides with the global tree id. + * \param[in] element the element for which the query is executed + * \param[in] pfirst the first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the last processor that owns part of \a element. Guaranteed to be non-empty. + * if this is equal to \a pfirst, then the recursion will stop for + * \a element's branch after this function returns. + * \param[in] queries an array of queries that are checked by the function + * \param[in] query_indices an array of size_t entries, where each entry is an index of a query in \a queries. + * \param[in, out] query_matches an array of length \a num_active_queries. + * If the element is not a leaf must be set to true or false at the i-th index for + * each query, specifying whether the element 'matches' the query of the i-th query + * index or not. When the element is a leaf we can return before all entries are set. + * \param[in] num_active_queries The number of currently active queries (equals the number of entries of + * \a query_matches and entries of \a query_indices). + */ +typedef void (*t8_forest_partition_query_fn) (const t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int pfirst, const int plast, + void *queries, sc_array_t *query_indices, int *query_matches, + const size_t num_active_queries); T8_EXTERN_C_BEGIN (); @@ -134,6 +176,25 @@ t8_forest_search (t8_forest_t forest, t8_forest_search_fn search_fn, t8_forest_q void t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_forest_replace_t replace_fn); +/** + * Perform a top-down search of the global partition, executing a callback on + * each intermediate element. The search will enter each tree at least once. + * The recursion will only go down branches that are split between multiple processors. + * This is not a collective function. It does not communicate. + * The function expects the coarse mesh to be replicated. + * If the callback returns false for an element, its descendants + * are not further searched. + * To pass user data to \b search_fn function use \ref t8_forest_set_user_data + * + * \param[in] forest the forest to be searched + * \param[in] search_fn a search callback function called on elements + * \param[in] query_fn a query callback function called for all active queries of an element + * \param[in,out] queries an array of queries that are checked by the function + */ +void +t8_forest_search_partition (const t8_forest_t forest, t8_forest_partition_search_fn search_fn, + t8_forest_partition_query_fn query_fn, sc_array_t *queries); + T8_EXTERN_C_END (); #endif /* !T8_FOREST_ITERATE_H */ diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx new file mode 100644 index 0000000000..82842763fc --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -0,0 +1,353 @@ +/* +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) 2024 the developers + +t8code is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +t8code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with t8code; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "t8_forest/t8_forest_search/t8_forest_search.hxx" +#include "t8_forest/t8_forest_search/t8_forest_search.h" +#include +#include +#include +#include + +void +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) +{ + /* Assertions to check for necessary requirements */ + /* The forest must be committed */ + T8_ASSERT (t8_forest_is_committed (this->forest)); + /* The tree must be local */ + T8_ASSERT (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (this->forest)); + + const size_t elem_count = t8_element_array_get_count (leaf_elements); + if (elem_count == 0) { + /* There are no leaves left, so we have nothing to do */ + return; + } + + if (this->stop_due_to_queries ()) { + return; + } + + const t8_eclass_t eclass = t8_forest_get_eclass (this->forest, ltreeid); + + bool is_leaf = false; + if (elem_count == 1) { + /* There is only one leaf left, we check whether it is the same as element and if so call the callback function */ + const t8_element_t *leaf = t8_element_array_index_locidx (leaf_elements, 0); + + SC_CHECK_ABORT (ts->element_get_level (eclass, element) <= ts->element_get_level (eclass, leaf), + "Search: element level greater than leaf level\n"); + if (ts->element_get_level (eclass, element) == ts->element_get_level (eclass, leaf)) { + T8_ASSERT (t8_forest_element_is_leaf (this->forest, leaf, ltreeid)); + T8_ASSERT (ts->element_is_equal (eclass, element, leaf)); + /* The element is the leaf */ + is_leaf = true; + } + } + /* Call the callback function for the element */ + const bool ret = check_element (ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + + if (!ret) { + /* The function returned false. We abort the recursion */ + return; + } + std::vector new_active_queries; + this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + + if (is_leaf) { + return; + } + + /* Enter the recursion (the element is definitely not a leaf at this point) */ + /* We compute all children of E, compute their leaf arrays and call search_recursion */ + /* allocate the memory to store the children */ + const int num_children = ts->element_get_num_children (eclass, element); + t8_element_t **children = T8_ALLOC (t8_element_t *, num_children); + ts->element_new (eclass, num_children, children); + /* Memory for the indices that split the leaf_elements array */ + size_t *split_offsets = T8_ALLOC (size_t, num_children + 1); + /* Compute the children */ + ts->element_get_children (eclass, element, num_children, children); + /* Split the leaves array in portions belonging to the children of element */ + t8_forest_split_array (element, leaf_elements, split_offsets); + for (int ichild = 0; ichild < num_children; ichild++) { + /* Check if there are any leaf elements for this child */ + const size_t indexa = split_offsets[ichild]; /* first leaf of this child */ + const size_t indexb = split_offsets[ichild + 1]; /* first leaf of next child */ + if (indexa < indexb) { + t8_element_array_t child_leaves; + /* There exist leaves of this child in leaf_elements, + * 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); + } + } + + /* clean-up */ + ts->element_destroy (eclass, num_children, children); + T8_FREE (children); + T8_FREE (split_offsets); +} + +void +t8_search_base::search_tree (const t8_locidx_t ltreeid) +{ + const t8_eclass_t eclass = t8_forest_get_eclass (this->forest, ltreeid); + const t8_scheme *ts = t8_forest_get_scheme (this->forest); + t8_element_array_t *leaf_elements = t8_forest_tree_get_leaves (this->forest, ltreeid); + + /* assert for empty tree */ + T8_ASSERT (t8_element_array_get_count (leaf_elements) >= 0); + /* Get the first and last leaf of this tree */ + const t8_element_t *first_el = t8_element_array_index_locidx (leaf_elements, 0); + const t8_element_t *last_el + = t8_element_array_index_locidx (leaf_elements, t8_element_array_get_count (leaf_elements) - 1); + /* Compute their nearest common ancestor */ + t8_element_t *nca; + ts->element_new (eclass, 1, &nca); + ts->element_get_nca (eclass, first_el, last_el, nca); + + /* Start the top-down search */ + this->search_recursion (ltreeid, nca, ts, leaf_elements, 0); + + ts->element_destroy (eclass, 1, &nca); +} + +void +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->search_tree (itree); + } +} + +/* #################### t8_forest_search c interface #################### */ +T8_EXTERN_C_BEGIN (); + +struct t8_forest_c_search +{ + t8_search *cpp_search; +}; + +void +t8_forest_init_search (t8_forest_search_c_wrapper search, t8_search_element_callback_c_wrapper element_callback, + const t8_forest_t forest) +{ + T8_ASSERT (search != NULL); + T8_ASSERT (element_callback != NULL); + search->cpp_search = new t8_search (element_callback, forest); +} + +void +t8_forest_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest) +{ + T8_ASSERT (search != NULL); + T8_ASSERT (forest != NULL); + search->cpp_search->update_forest (forest); +} + +void +t8_forest_search_update_user_data (t8_forest_search_c_wrapper search, void *udata) +{ + T8_ASSERT (search != NULL); + T8_ASSERT (udata != NULL); + search->cpp_search->update_user_data (&udata); +} + +void +t8_forest_search_do_search (t8_forest_search_c_wrapper search) +{ + T8_ASSERT (search != NULL); + search->cpp_search->do_search (); +} + +void +t8_forest_search_destroy (t8_forest_search_c_wrapper search) +{ + T8_ASSERT (search != NULL); + delete search->cpp_search; + search->cpp_search = NULL; +} + +struct t8_forest_search_with_queries +{ + t8_search_with_queries *cpp_search; +}; + +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) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (element_callback != NULL); + T8_ASSERT (queries_callback != NULL); + T8_ASSERT (queries != NULL); + T8_ASSERT (forest != NULL); + + std::vector queries_vector = std::vector (queries, queries + num_queries); + + search_with_queries->cpp_search + = new t8_search_with_queries (element_callback, queries_callback, queries_vector, forest); +} + +void +t8_forest_search_with_queries_update_forest (t8_forest_search_with_queries_c_wrapper search_with_queries, + const t8_forest_t forest) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (forest != NULL); + search_with_queries->cpp_search->update_forest (forest); +} + +void +t8_forest_search_with_queries_update_user_data (t8_forest_search_with_queries_c_wrapper search_with_queries, + void *udata) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (udata != NULL); + search_with_queries->cpp_search->update_user_data (&udata); +} + +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) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (queries != NULL); + + std::vector queries_vector = std::vector (queries, queries + num_queries); + + search_with_queries->cpp_search->update_queries (queries_vector); +} + +void +t8_forest_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper search) +{ + T8_ASSERT (search != NULL); + search->cpp_search->do_search (); +} + +void +t8_forest_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper search) +{ + T8_ASSERT (search != NULL); + delete search->cpp_search; + search->cpp_search = NULL; +} + +struct t8_forest_search_with_batched_queries +{ + t8_search_with_batched_queries *cpp_search; + t8_search_batched_queries_callback_c_wrapper queries_callback; + + 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, + const t8_locidx_t tree_leaf_index, const std::vector &queries, + const std::vector &active_query_indices, std::vector &query_matches, + void *user_data) + { + std::vector query_matches_int (query_matches.size ()); + queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, queries.data (), + active_query_indices.data (), query_matches_int.data (), user_data); + std::transform (query_matches_int.begin (), query_matches_int.end (), query_matches.begin (), + [] (int val) { return static_cast (val); }); + } +}; + +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) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (element_callback != NULL); + T8_ASSERT (queries_callback != NULL); + T8_ASSERT (queries != NULL); + T8_ASSERT (forest != NULL); + + std::vector queries_vector = std::vector (queries, queries + num_queries); + + search_with_queries->queries_callback = queries_callback; + + search_with_queries->cpp_search = new t8_search_with_batched_queries ( + element_callback, + [&search_with_queries] ( + 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, const t8_locidx_t tree_leaf_index, const std::vector &queries, + const std::vector &active_query_indices, std::vector &query_matches, void *user_data) { + search_with_queries->wrapped_queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, + queries, active_query_indices, query_matches, user_data); + }, + queries_vector, forest); +} + +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) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (forest != NULL); + search_with_queries->cpp_search->update_forest (forest); +} + +void +t8_forest_search_with_batched_queries_update_user_data ( + t8_forest_search_with_batched_queries_c_wrapper search_with_queries, void *udata) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (udata != NULL); + search_with_queries->cpp_search->update_user_data (&udata); +} +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) +{ + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (queries != NULL); + + std::vector queries_vector = std::vector (queries, queries + num_queries); + + search_with_queries->cpp_search->update_queries (queries_vector); +} +void +t8_forest_search_with_batched_queries_destroy (t8_forest_search_with_batched_queries_c_wrapper search) +{ + T8_ASSERT (search != NULL); + delete search->cpp_search; + search->cpp_search = NULL; +} + +void +t8_forest_search_with_batched_queries_do_search (t8_forest_search_with_batched_queries_c_wrapper search) +{ + T8_ASSERT (search != NULL); + search->cpp_search->do_search (); +} +T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.h b/src/t8_forest/t8_forest_search/t8_forest_search.h new file mode 100644 index 0000000000..6991f3dc76 --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search.h @@ -0,0 +1,110 @@ +/* + 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) 2024 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** \file t8_forest_search.h + * This is the C interface for the search functionality. The user can define search and query callbacks + * to perform the search and query operations on the forest. +*/ + +#ifndef T8_FOREST_SEARCH_C_INTERFACE_H +#define T8_FOREST_SEARCH_C_INTERFACE_H + +#include + +T8_EXTERN_C_BEGIN (); + +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); + +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); + +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, + const t8_locidx_t tree_leaf_index, const void *queries, + const size_t *active_query_indices, int *query_matches, + void *user_data); + +typedef struct t8_forest_c_search *t8_forest_search_c_wrapper; + +void +t8_forest_init_search (t8_forest_search_c_wrapper search, t8_search_element_callback_c_wrapper element_callback, + const t8_forest_t forest); +void +t8_forest_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest); +void +t8_forest_search_update_user_data (t8_forest_search_c_wrapper search, void *udata); +void +t8_forest_search_do_search (t8_forest_search_c_wrapper search); +void +t8_forest_search_destroy (t8_forest_search_c_wrapper search); + +typedef struct t8_forest_search_with_queries *t8_forest_search_with_queries_c_wrapper; + +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); +void +t8_forest_search_with_queries_update_forest (t8_forest_search_with_queries_c_wrapper search_with_queries, + const t8_forest_t forest); +void +t8_forest_search_with_queries_update_user_data (t8_forest_search_with_queries_c_wrapper search_with_queries, + void *udata); +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); +void +t8_forest_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper search); +void +t8_forest_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper search); + +typedef struct t8_forest_search_with_batched_queries *t8_forest_search_with_batched_queries_c_wrapper; + +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); +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); +void +t8_forest_search_with_batched_queries_update_user_data ( + t8_forest_search_with_batched_queries_c_wrapper search_with_queries, void *udata); +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); +void +t8_forest_search_with_batched_queries_destroy (t8_forest_search_with_batched_queries_c_wrapper search); +void +t8_forest_search_with_batched_queries_do_search (t8_forest_search_with_batched_queries_c_wrapper search); + +T8_EXTERN_C_END (); + +#endif // T8_FOREST_SEARCH_C_INTERFACE_H diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx new file mode 100644 index 0000000000..5ee577180e --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -0,0 +1,816 @@ +/* + 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) 2024 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** \file t8_forest_search.hxx + * A C++ interface for the search functionality. The user can define search and query callbacks + * to perform the search and query operations on the forest. Implementation details regarding the + * callback handling are given by https://stackoverflow.com/questions/2298242/callback-functions-in-c + * We decided for option 4, using std::function together with templates. +*/ + +#ifndef T8_FOREST_SEARCH_HXX +#define T8_FOREST_SEARCH_HXX + +#include +#include +#include // Ensure t8_forest_t is defined +#include +#include +#include + +/** + * \typedef t8_search_element_callback + * \brief 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. + * + * \tparam Udata The type of user data passed to the callback. Defaults to void. + * + * \param[in] forest The forest in which the search is being performed. + * \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] user_data A reference to user-defined data passed to the callback. + * + * \return True if the search should continue, false otherwise. + */ +template +using t8_search_element_callback = std::function; + +/** + * \typedef t8_search_queries_callback + * \brief 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. + * + * \param[in] forest The forest in which the search is performed. + * \param[in] ltreeid The local tree ID within the forest. + * \param[in] element The element being queried. + * \param[in] is_leaf A flag indicating if the element is a leaf. + * \param[in] leaf_elements The array of leaf elements. + * \param[in] tree_leaf_index The index of the leaf within the tree. + * \param[in] query A single query to be processed. + * \param[in] user_data User-defined data passed to the callback. + */ +template +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. + * + * \tparam Query_T The type of the query. + * \tparam Udata The type of user data, defaults to void. + * + * \param[in] forest The forest in which the search is performed. + * \param[in] ltreeid The local tree ID within the forest. + * \param[in] element The element being queried. + * \param[in] is_leaf A flag indicating if the element is a leaf. + * \param[in] leaf_elements The array of leaf elements. + * \param[in] tree_leaf_index The index of the leaf within the tree. + * \param[in] queries A vector of queries to be processed. + * \param[in, out] active_query_indices A vector of indices of active queries. + * \param[in, out] query_matches A vector of query matches. Each entry corresponds to a query in the queries vector. + * \param[in] user_data User-defined data passed to the callback. + */ +template +using t8_search_batched_queries_callback = std::function &queries, + const std::vector &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. + * + * 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. + * + * \tparam Udata The type of user data passed to the callback. Defaults to void. + * + * \param[in] forest The forest whose partition is searched. + * \param[in] ltreeid The local tree ID of the current tree in the cmesh. + * \param[in] element A pointer to the current element being processed. + * \param[in] pfirst The first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast The last processor that owns part of \a element. Guaranteed to be non-empty. + * + * \return True, if the search should continue, false otherwise. + */ +template +using t8_partition_search_element_callback + = std::function; + +/** + * \typedef t8_partition_search_query_callback + * \brief 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. + * + * \param[in] forest The forest whose partition is searched. + * \param[in] ltreeid The local tree ID within the forest. + * \param[in] element The element being queried. + * \param[in] pfirst The first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast The last processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] query A single query to be processed. + * \param[in] user_data User-defined data passed to the 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. + * + * \tparam Query_T The type of the query. + * \tparam Udata The type of user data, defaults to void. + * + * \param[in] forest The forest whose partition is searched. + * \param[in] ltreeid The local tree ID within the forest. + * \param[in] element The element being queried. + * \param[in] pfirst The first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast The last processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] queries A vector of queries to be processed. + * \param[in, out] active_query_indices A vector of indices of active queries. + * \param[in, out] query_matches A vector of query matches. Each entry corresponds to a query in the queries vector. + * \param[in] user_data User-defined data passed to the callback. + */ +template +using t8_partition_search_batched_queries_callback = std::function &queries, const std::vector &active_query_indices, + std::vector &query_matches, Udata *user_data)>; + +class t8_search_base { + public: + /** \brief Constructor for the t8_search_base class. + * + * + * This constructor initializes a t8_search_base object with the given forest. + * If the forest is not null, it increments the reference count of the forest + * and asserts that the forest is committed. + * + * \param[in] forest A pointer to a t8_forest_t object. Defaults to nullptr. + */ + t8_search_base (t8_forest_t forest = nullptr): forest (forest) + { + if (forest != nullptr) { + t8_forest_ref (forest); + T8_ASSERT (t8_forest_is_committed (forest)); + } + } + + /** \brief 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 + * is not null and is committed. Finally, it increments the reference count of the new forest. + * + * \param[in] forest A pointer to a t8_forest_t object. + */ + void + update_forest (t8_forest_t forest) + { + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } + T8_ASSERT (forest != nullptr); + T8_ASSERT (t8_forest_is_committed (forest)); + t8_forest_ref (forest); + this->forest = forest; + } + + /** \brief Destructor for the t8_search_base class. + * + * This destructor decrements the reference count of the forest if it is not null. + */ + ~t8_search_base () + { + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } + } + + /** \brief Perform the search. + * + * This function performs the search in the forest. + */ + void + do_search (); + + t8_forest_t forest; + + private: + /** @brief Searches a tree within the forest. + * + * This function performs a search operation on a tree identified by the given local tree ID. + * It uses the \a search_recursion function to perform the search. + * + * \param[in] ltreeid The local tree ID of the tree to be searched. + */ + void + search_tree (const t8_locidx_t ltreeid); + + /** \brief 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. + * If a query_callback function is provided, it is used to process queries during the search. + * + * \param[in] ltreeid The local tree ID of the tree to be searched. + * \param[in] element The element to be searched. + * \param[in] ts The element class scheme. + * \param[in] leaf_elements The array of leaf elements. + * \param[in] tree_lindex_of_first_leaf The index of the first leaf in the tree. + */ + void + 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. + * + */ + virtual bool + stop_due_to_queries () + = 0; + + /** \brief 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. + * + * \return True if the search should continue, false otherwise. + */ + virtual 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) + = 0; + + /** \brief 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. + * + * \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. + */ + virtual 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, const t8_locidx_t tree_leaf_index) + = 0; + + /** + * \brief 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; +}; + +template +class t8_search: public t8_search_base { + public: + 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) + { + if (user_data != nullptr) { + this->user_data = user_data; + } + } + + /** \brief Updates the user data associated with the object. + * + * This function sets the user data pointer to the provided Udata object. + * + * \param[in] udata A pointer to the Udata object to be set as the user data. + */ + void + update_user_data (Udata *udata) + { + if (udata != nullptr) { + this->user_data = udata; + } + } + + virtual ~t8_search () = default; + + Udata *user_data; + + private: + bool + stop_due_to_queries () override + { + return false; + } + + 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 + { + T8_ASSERT (t8_forest_is_committed (this->forest)); + return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); + } + + 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, + const t8_locidx_t tree_leaf_index) override + { + return; + } + + void + update_queries (std::vector &old_query_indices) + { + return; + } + + t8_search_element_callback element_callback; +}; + +/** + * \brief 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. + * + * \tparam Query_T The type of queries + * \tparam Udata The type of the user data, defaults to void. +*/ +template +class t8_search_with_queries: public t8_search { + public: + 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); + } + + void + update_queries (std::vector &queries) + { + this->queries = queries; + } + + ~t8_search_with_queries () + { + } + + private: + bool + stop_due_to_queries () override + { + return this->active_queries.empty (); + } + + 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, + const t8_locidx_t tree_leaf_index) 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, 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); + } + } + } + + void + update_queries (std::vector &old_query_indices) + { + std::swap (this->active_queries, old_query_indices); + } + + t8_search_query_callback queries_callback; + std::vector &queries; + std::vector active_queries; +}; + +/** + * \brief 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 + * precomputations are not done for every call to the callback again and only have to be evaluated once per call. + * + * \tparam Query_T The type of queries + * \tparam Udata The type of the user data, defaults to void. + */ +template +class t8_search_with_batched_queries: public t8_search { + public: + 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); + } + + void + update_queries (std::vector &queries) + { + this->queries = queries; + } + + virtual ~t8_search_with_batched_queries () = default; + + private: + bool + stop_due_to_queries () override + { + return this->active_queries.empty (); + } + 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, + const t8_locidx_t tree_leaf_index) override + { + T8_ASSERT (new_active_queries.empty ()); + if (!this->active_queries.empty ()) { + std::vector query_matches (this->active_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::swap (new_active_queries, this->active_queries); + } + + void + update_queries (std::vector &old_query_indices) + { + std::swap (this->active_queries, old_query_indices); + } + + t8_search_batched_queries_callback queries_callback; + std::vector &queries; + std::vector active_queries; +}; + +class t8_partition_search_base { + public: + /** \brief Constructor for the t8_partition_search_base class. + * + * + * This constructor initializes a t8_partition_search_base object with the + * given forest. If the forest is not null, it increments the reference count + * of the forest and asserts that the forest is committed. + * + * \param[in] forest A pointer to a t8_forest_t object. Defaults to nullptr. + */ + t8_partition_search_base (t8_forest_t forest = nullptr): forest (forest) + { + if (forest != nullptr) { + t8_forest_ref (forest); + T8_ASSERT (t8_forest_is_committed (forest)); + } + } + + /** \brief 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 + * is not null and is committed. Finally, it increments the reference count of the new forest. + * + * \param[in] forest A pointer to a t8_forest_t object. + */ + void + update_forest (t8_forest_t forest) + { + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } + T8_ASSERT (forest != nullptr); + T8_ASSERT (t8_forest_is_committed (forest)); + t8_forest_ref (forest); + this->forest = forest; + } + + /** \brief Destructor for the t8_partition_search_base class. + * + * This destructor decrements the reference count of the forest if it is not null. + */ + ~t8_partition_search_base () + { + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } + } + + /** \brief Perform the search. + * + * This function performs the search in the forest. + */ + void + do_search (); + + t8_forest_t forest; + + private: + /** \brief Checks if the search should stop due to empty queries. + * + */ + virtual bool + stop_due_to_queries () + = 0; + + /** \brief 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. + * + * \return True if the search should continue, false otherwise. + */ + virtual bool + 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. + * + * This function is called to check queries during the search. + * It passes the arguments to the callback function provided by the user. + * + * \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. + */ + virtual void + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const int pfirst, const int plast) + = 0; + + /** + * \brief 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; +}; + +template +class t8_partition_search: public t8_partition_search_base { + public: + 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) + { + if (user_data != nullptr) { + this->user_data = user_data; + } + } + + /** \brief Updates the user data associated with the object. + * + * This function sets the user data pointer to the provided Udata object. + * + * \param[in] udata A pointer to the Udata object to be set as the user data. + */ + void + update_user_data (Udata *udata) + { + if (udata != nullptr) { + this->user_data = udata; + } + } + + Udata *user_data; + + private: + bool + stop_due_to_queries () override + { + return false; + } + + bool + check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast) override + { + T8_ASSERT (t8_forest_is_committed (this->forest)); + return this->element_callback (this->forest, ltreeid, element, pfirst, plast, user_data); + } + + 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 + { + return; + } + + void + update_queries (std::vector &old_query_indices) + { + return; + } + + t8_partition_search_element_callback element_callback; +}; + +/** + * \brief 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. + * + * \tparam Query_T The type of queries + * \tparam Udata The type of the user data, defaults to void. +*/ +template +class t8_partition_search_with_queries: public t8_partition_search { + public: + 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, + Udata *user_data = nullptr) + : 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); + } + + void + update_queries (std::vector &queries) + { + this->queries = queries; + } + + ~t8_partition_search_with_queries () + { + } + + private: + bool + stop_due_to_queries () override + { + return this->active_queries.empty (); + } + + 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); + } + } + } + + void + update_queries (std::vector &old_query_indices) + { + std::swap (this->active_queries, old_query_indices); + } + + t8_partition_search_query_callback queries_callback; + std::vector &queries; + std::vector active_queries; +}; + +/** + * \brief 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 + * precomputations are not done for every call to the callback again and only have to be evaluated once per call. + * + * \tparam Query_T The type of queries + * \tparam Udata The type of the user data, defaults to void. + */ +template +class t8_partition_search_with_batched_queries: public t8_partition_search { + public: + t8_partition_search_with_batched_queries ( + t8_partition_search_element_callback element_callback, + t8_partition_search_batched_queries_callback queries_callback, std::vector &queries, + const t8_forest_t forest = nullptr, Udata *user_data = nullptr) + : 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); + } + + void + update_queries (std::vector &queries) + { + this->queries = queries; + } + + ~t8_partition_search_with_batched_queries () + { + } + + private: + bool + stop_due_to_queries () override + { + return this->active_queries.empty (); + } + 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 ()); + 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::swap (new_active_queries, this->active_queries); + } + + void + update_queries (std::vector &old_query_indices) + { + std::swap (this->active_queries, old_query_indices); + } + + t8_partition_search_batched_queries_callback queries_callback; + std::vector &queries; + std::vector active_queries; +}; + +#endif // T8_FOREST_SEARCH_HXX diff --git a/src/t8_schemes/t8_crtp.hxx b/src/t8_schemes/t8_crtp.hxx deleted file mode 100644 index 1c9e1467d6..0000000000 --- a/src/t8_schemes/t8_crtp.hxx +++ /dev/null @@ -1,48 +0,0 @@ -/* - 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) 2024 the developers - - t8code is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - t8code is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with t8code; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/** \file t8_crtp.hxx - * This file implements a helper class for CRTP implementations. - */ - -#ifndef T8_CRTP_HXX -#define T8_CRTP_HXX - -/** CRTP helper class, adds static "upcasting" methods for const and non const objects. - * \tparam TUnderlying The CRTP derived class. - */ -template -class t8_crtp { - public: - inline TUnderlying& - underlying () - { - return static_cast (*this); - } - inline TUnderlying const& - underlying () const - { - return static_cast (*this); - } -}; - -#endif /* !T8_CRTP_HXX */ diff --git a/src/t8_schemes/t8_default/Makefile.am b/src/t8_schemes/t8_default/Makefile.am index 20ab4f0505..d7a2f2f682 100644 --- a/src/t8_schemes/t8_default/Makefile.am +++ b/src/t8_schemes/t8_default/Makefile.am @@ -10,8 +10,7 @@ libt8_installed_headers_default_common += \ src/t8_schemes/t8_default/t8_default_common/t8_default_common.hxx libt8_installed_headers_default_vertex += \ src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.hxx \ - src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex.h \ - src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.h + src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex.h libt8_installed_headers_default_line += \ src/t8_schemes/t8_default/t8_default_line/t8_default_line.hxx \ src/t8_schemes/t8_default/t8_default_line/t8_dline.h \ @@ -62,7 +61,6 @@ libt8_compiled_sources += \ src/t8_schemes/t8_default/t8_default_tri/t8_dtri_bits.c \ src/t8_schemes/t8_default/t8_default_tri/t8_dtri_connectivity.c \ src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex.cxx \ - src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.c \ src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid.cxx \ src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c \ src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c 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 9d9bdb7d74..0f402a79be 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 @@ -28,7 +28,7 @@ #define T8_DEFAULT_COMMON_HXX #include -#include +#include #include #include @@ -84,7 +84,7 @@ count_leaves_from_level (const int element_level, const int refinement_level, co } template -class t8_default_scheme_common: public t8_crtp { +class t8_default_scheme_common: public t8_crtp_operator { private: friend TUnderlyingEclassScheme; /** Private constructor which can only be used by derived schemes. diff --git a/src/t8_schemes/t8_default/t8_default_line/t8_default_line.cxx b/src/t8_schemes/t8_default/t8_default_line/t8_default_line.cxx index 89ed58f541..48dbbdf578 100644 --- a/src/t8_schemes/t8_default/t8_default_line/t8_default_line.cxx +++ b/src/t8_schemes/t8_default/t8_default_line/t8_default_line.cxx @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -193,7 +192,7 @@ t8_default_scheme_line::element_get_boundary_face (const t8_element_t *elem, int /* Since each vertex is the same, we just construct a vertex of the same level * as elem. */ - t8_dvertex_init_linear_id ((t8_dvertex_t *) boundary, element_get_level (elem), 0); + t8_default_scheme_vertex::element_set_linear_id (boundary, element_get_level (elem), 0); } /** Construct the first descendant of an element that touches a given face. */ diff --git a/src/t8_schemes/t8_default/t8_default_line/t8_dline.h b/src/t8_schemes/t8_default/t8_default_line/t8_dline.h index c1e2ccde10..7ea41eb44d 100644 --- a/src/t8_schemes/t8_default/t8_default_line/t8_dline.h +++ b/src/t8_schemes/t8_default/t8_default_line/t8_dline.h @@ -51,8 +51,8 @@ typedef int32_t t8_dline_coord_t; typedef struct t8_dline { - int8_t level; t8_dline_coord_t x; + int8_t level; } t8_dline_t; #endif /* T8_DLINE_H */ diff --git a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.cxx b/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.cxx index 99937636cd..92a5a032f9 100644 --- a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.cxx +++ b/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.cxx @@ -490,7 +490,7 @@ t8_default_scheme_quad::element_extrude_face (const t8_element_t *face, t8_eleme p4est_quadrant_t *q = (p4est_quadrant_t *) elem; T8_ASSERT (element_is_valid (elem)); - T8_ASSERT (scheme->element_is_valid (T8_ECLASS_LINE, elem)); + T8_ASSERT (scheme->element_is_valid (T8_ECLASS_LINE, face)); T8_ASSERT (0 <= root_face && root_face < P4EST_FACES); /* * The faces of the root quadrant are enumerated like this: 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 5c7bea179f..a73c01fe78 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 @@ -22,10 +22,15 @@ #include #include -#include -/* We want to export the whole implementation to be callable from "C" */ -T8_EXTERN_C_BEGIN (); +/** Print a vertex (unused static helper function for debugging) + * \param [in] v vertex to be considered. + */ +inline static void +t8_dvertex_debug_print (const t8_dvertex_t *v) +{ + t8_debugf ("level: %i\n", v->level); +} size_t t8_default_scheme_vertex::get_element_size (void) const @@ -43,7 +48,7 @@ int t8_default_scheme_vertex::element_get_level (const t8_element_t *elem) const { T8_ASSERT (element_is_valid (elem)); - return t8_dvertex_get_level ((const t8_dvertex_t *) elem); + return ((const t8_dvertex_t *) elem)->level; } void @@ -51,19 +56,19 @@ t8_default_scheme_vertex::element_copy (const t8_element_t *source, t8_element_t { T8_ASSERT (element_is_valid (source)); T8_ASSERT (element_is_valid (dest)); - t8_dvertex_copy ((const t8_dvertex_t *) source, (t8_dvertex_t *) dest); + memcpy ((t8_dvertex_t *) dest, (const t8_dvertex_t *) source, sizeof (t8_dvertex_t)); } int t8_default_scheme_vertex::element_compare (const t8_element_t *elem1, const t8_element_t *elem2) const { - return t8_dvertex_compare ((const t8_dvertex_t *) elem1, (const t8_dvertex_t *) elem2); + return ((const t8_dvertex_t *) elem1)->level - ((const t8_dvertex_t *) elem2)->level; } int t8_default_scheme_vertex::element_is_equal (const t8_element_t *elem1, const t8_element_t *elem2) const { - return t8_dvertex_equal ((const t8_dvertex_t *) elem1, (const t8_dvertex_t *) elem2); + return ((const t8_dvertex_t *) elem1)->level == ((const t8_dvertex_t *) elem2)->level; } void @@ -74,18 +79,20 @@ t8_default_scheme_vertex::element_get_parent (const t8_element_t *elem, t8_eleme T8_ASSERT (element_is_valid (elem)); T8_ASSERT (element_is_valid (parent)); - t8_dvertex_parent (v, p); + T8_ASSERT (v->level > 0); + + /* Set the parent's level */ + p->level = v->level - 1; } void -t8_default_scheme_vertex::element_get_sibling (const t8_element_t *elem, int sibid, t8_element_t *sibling) const +t8_default_scheme_vertex::element_get_sibling (const t8_element_t *elem, const int sibid, t8_element_t *sibling) const { - const t8_dvertex_t *v = (const t8_dvertex_t *) elem; - t8_dvertex_t *s = (t8_dvertex_t *) sibling; - T8_ASSERT (element_is_valid (elem)); T8_ASSERT (element_is_valid (sibling)); - t8_dvertex_sibling (v, sibid, s); + T8_ASSERT (sibid == 0); + + this->element_copy (elem, sibling); } int @@ -124,7 +131,10 @@ t8_default_scheme_vertex::element_get_child (const t8_element_t *elem, int child T8_ASSERT (element_is_valid (child)); T8_ASSERT (childid == 0); - t8_dvertex_child (v, c); + T8_ASSERT (v->level < T8_DVERTEX_MAXLEVEL); + + /* The children level */ + c->level = v->level + 1; } void @@ -137,20 +147,24 @@ t8_default_scheme_vertex::element_get_children (const t8_element_t *elem, int le T8_ASSERT (element_is_valid (c[i])); } #endif - t8_dvertex_childrenpv ((const t8_dvertex_t *) elem, (t8_dvertex_t **) c); + const t8_dvertex_t *v = (const t8_dvertex_t *) elem; + T8_ASSERT (v->level < T8_DVERTEX_MAXLEVEL); + + /* Set the Level, Level increases */ + ((t8_dvertex_t **) c)[0]->level = v->level + 1; } int t8_default_scheme_vertex::element_get_child_id (const t8_element_t *elem) const { T8_ASSERT (element_is_valid (elem)); - return t8_dvertex_child_id ((const t8_dvertex_t *) elem); + return 0; } int t8_default_scheme_vertex::element_get_ancestor_id (const t8_element_t *elem, int level) const { - return t8_dvertex_ancestor_id ((const t8_dvertex_t *) elem, level); + return 0; } int @@ -161,7 +175,7 @@ t8_default_scheme_vertex::elements_are_family (t8_element_t *const *fam) const T8_ASSERT (element_is_valid (fam[i])); } #endif - return t8_dvertex_is_familypv ((const t8_dvertex_t **) fam); + return ((const t8_dvertex_t **) fam)[0]->level > 0; } void @@ -174,7 +188,9 @@ t8_default_scheme_vertex::element_get_nca (const t8_element_t *elem1, const t8_e T8_ASSERT (element_is_valid (elem1)); T8_ASSERT (element_is_valid (elem2)); - t8_dvertex_nearest_common_ancestor (v1, v2, c); + + /* The nca is the one of the two vertices with smaller level */ + c->level = SC_MIN (v1->level, v2->level); } /** Transform the coordinates of a vertex considered as boundary element @@ -186,26 +202,25 @@ t8_default_scheme_vertex::element_transform_face (const t8_element_t *elem1, t8_ T8_ASSERT (element_is_valid (elem1)); T8_ASSERT (element_is_valid (elem2)); - t8_dvertex_transform_face ((const t8_dvertex_t *) elem1, (t8_dvertex_t *) elem2); + ((t8_dvertex_t *) elem2)->level = ((const t8_dvertex_t *) elem1)->level; } int t8_default_scheme_vertex::element_is_root_boundary (const t8_element_t *elem, int face) const { - const t8_dvertex_t *v = (const t8_dvertex_t *) elem; - T8_ASSERT (element_is_valid (elem)); - return t8_dvertex_is_root_boundary (v, face); + return 1; } void -t8_default_scheme_vertex::element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const +t8_default_scheme_vertex::element_set_linear_id (t8_element_t *elem, const int level, const t8_linearidx_t id) { T8_ASSERT (0 <= level && level <= T8_DVERTEX_MAXLEVEL); - T8_ASSERT (0 <= id && id < ((t8_linearidx_t) 1) << 3 * level); + T8_ASSERT (0 == id); T8_ASSERT (element_is_valid (elem)); - t8_dvertex_init_linear_id ((t8_dvertex_t *) elem, level, id); + /* Set the level */ + ((t8_dvertex_t *) elem)->level = level; } t8_linearidx_t @@ -214,7 +229,7 @@ t8_default_scheme_vertex::element_get_linear_id (const t8_element_t *elem, int l T8_ASSERT (element_is_valid (elem)); T8_ASSERT (0 <= level && level <= T8_DVERTEX_MAXLEVEL); - return t8_dvertex_linear_id ((const t8_dvertex_t *) elem, level); + return 0; } void @@ -223,7 +238,9 @@ t8_default_scheme_vertex::element_get_first_descendant (const t8_element_t *elem T8_ASSERT (element_is_valid (elem)); T8_ASSERT (element_is_valid (desc)); T8_ASSERT (0 <= level && level <= T8_DVERTEX_MAXLEVEL); - t8_dvertex_first_descendant ((const t8_dvertex_t *) elem, (t8_dvertex_t *) desc, level); + T8_ASSERT (level >= ((const t8_dvertex_t *) elem)->level); + + ((t8_dvertex_t *) desc)->level = level; } void @@ -232,7 +249,9 @@ t8_default_scheme_vertex::element_get_last_descendant (const t8_element_t *elem, T8_ASSERT (element_is_valid (elem)); T8_ASSERT (element_is_valid (desc)); T8_ASSERT (0 <= level && level <= T8_DVERTEX_MAXLEVEL); - t8_dvertex_last_descendant ((const t8_dvertex_t *) elem, (t8_dvertex_t *) desc, level); + T8_ASSERT (level >= ((const t8_dvertex_t *) elem)->level); + + ((t8_dvertex_t *) desc)->level = level; } void @@ -249,7 +268,9 @@ void t8_default_scheme_vertex::element_get_vertex_integer_coords (const t8_element_t *elem, int vertex, int coords[]) const { T8_ASSERT (element_is_valid (elem)); - t8_dvertex_vertex_integer_coords ((const t8_dvertex_t *) elem, vertex, coords); + T8_ASSERT (vertex == 0); + + coords[0] = 0; } void @@ -259,7 +280,7 @@ t8_default_scheme_vertex::element_get_vertex_reference_coords (const t8_element_ T8_ASSERT (element_is_valid (elem)); T8_ASSERT (vertex == 0); - t8_dvertex_vertex_ref_coords ((const t8_dvertex_t *) elem, vertex, coords); + coords[0] = 0; } void @@ -267,15 +288,20 @@ t8_default_scheme_vertex::element_get_reference_coords (const t8_element_t *elem const size_t num_coords, double *out_coords) const { T8_ASSERT (element_is_valid (elem)); - t8_dvertex_compute_reference_coords ((const t8_dvertex_t *) elem, ref_coords, num_coords, out_coords); + T8_ASSERT (fabs (ref_coords[0]) <= T8_PRECISION_EPS); + + for (size_t coord = 0; coord < num_coords; ++coord) { + out_coords[coord] = 0; + } } #ifdef T8_ENABLE_DEBUG int -t8_default_scheme_vertex::element_is_valid (const t8_element_t *elem) const +t8_default_scheme_vertex::element_is_valid (const t8_element_t *elem) { - return t8_dvertex_is_valid ((const t8_dvertex_t *) elem); + const t8_dvertex *v = (const t8_dvertex_t *) elem; + return 0 <= v->level && v->level <= T8_DVERTEX_MAXLEVEL; } void @@ -317,7 +343,7 @@ t8_default_scheme_vertex::element_init (int length, t8_element_t *elem) const #ifdef T8_ENABLE_DEBUG t8_dvertex_t *vertexs = (t8_dvertex_t *) elem; for (int i = 0; i < length; i++) { - t8_dvertex_init (vertexs + i); + vertexs[i].level = 0; } #endif } @@ -368,5 +394,3 @@ t8_default_scheme_vertex::element_MPI_Unpack (void *recvbuf, const int buffer_si SC_CHECK_MPI (mpiret); } } - -T8_EXTERN_C_END (); 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 291a564a34..c48000b803 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 @@ -20,19 +20,12 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_default_vertex.h - * The default implementation for vertices. Interface between the - * \file t8_default_common.hxx definitions and the element type specific - * implementations in \file t8_dvertex_bits.h - */ - #ifndef T8_DEFAULT_VERTEX_HXX #define T8_DEFAULT_VERTEX_HXX #include #include #include -#include /* Forward declaration of the scheme so we can use it as an argument in the eclass schemes function. */ class t8_scheme; @@ -502,8 +495,8 @@ class t8_default_scheme_vertex: public t8_default_scheme_common - -int -t8_dvertex_get_level (const t8_dvertex_t *v) -{ - return v->level; -} - -void -t8_dvertex_copy (const t8_dvertex_t *v, t8_dvertex_t *dest) -{ - memcpy (dest, v, sizeof (t8_dvertex_t)); -} - -int -t8_dvertex_equal (const t8_dvertex_t *elem1, const t8_dvertex_t *elem2) -{ - return elem1->level == elem2->level; -} - -int -t8_dvertex_compare (const t8_dvertex_t *v1, const t8_dvertex_t *v2) -{ - /* The vertex with the smaller level - * is considered smaller */ - return v1->level - v2->level; -} - -void -t8_dvertex_parent (const t8_dvertex_t *v, t8_dvertex_t *parent) -{ - T8_ASSERT (v->level > 0); - - /* Set the parent's level */ - parent->level = v->level - 1; -} - -void -t8_dvertex_child (const t8_dvertex_t *v, t8_dvertex_t *child) -{ - T8_ASSERT (v->level < T8_DVERTEX_MAXLEVEL); - - /* The children level */ - child->level = v->level + 1; -} - -void -t8_dvertex_nearest_common_ancestor (const t8_dvertex_t *v1, const t8_dvertex_t *v2, t8_dvertex_t *r) -{ - /* The nca is the one of the two vertices with smaller level */ - r->level = SC_MIN (v1->level, v2->level); -} - -int -t8_dvertex_ancestor_id (const t8_dvertex_t *v, int level) -{ - /* There is only one possible child id, 0 */ - return 0; -} - -int -t8_dvertex_child_id (const t8_dvertex_t *v) -{ - /* There is only one possible child id, 0 */ - return 0; -} - -void -t8_dvertex_sibling (const t8_dvertex_t *v, int sibid, t8_dvertex_t *s) -{ - T8_ASSERT (sibid == 0); - - t8_dvertex_copy (v, s); -} - -void -t8_dvertex_childrenpv (const t8_dvertex_t *v, t8_dvertex_t *c[T8_DVERTEX_CHILDREN]) -{ - T8_ASSERT (v->level < T8_DVERTEX_MAXLEVEL); - - /* Set the Level, Level increases */ - c[0]->level = v->level + 1; -} - -int -t8_dvertex_is_familypv (const t8_dvertex_t *f[]) -{ - /* A vertex with level greater 0 is always a family */ - return f[0]->level > 0; -} - -int -t8_dvertex_is_root_boundary (const t8_dvertex_t *v, int face) -{ - /* A vertex is always at the root boundary */ - return 1; -} - -int -t8_dvertex_is_inside_root (const t8_dvertex_t *v) -{ - /* A vertex is always inside root */ - return 1; -} - -void -t8_dvertex_init_linear_id (t8_dvertex_t *v, int level, t8_linearidx_t id) -{ - T8_ASSERT (0 <= level && level <= T8_DVERTEX_MAXLEVEL); - T8_ASSERT (0 == id); - - /* Set the level */ - v->level = level; -} - -void -t8_dvertex_transform_face (const t8_dvertex_t *vertex1, t8_dvertex_t *vertex2) -{ - /* The transformed vertex is the same vertex */ - vertex2->level = vertex1->level; -} - -void -t8_dvertex_first_descendant (const t8_dvertex_t *v, t8_dvertex_t *s, int level) -{ - T8_ASSERT (level >= v->level && level <= T8_DVERTEX_MAXLEVEL); - - s->level = level; -} - -void -t8_dvertex_last_descendant (const t8_dvertex_t *v, t8_dvertex_t *s, int level) -{ - T8_ASSERT (level >= v->level && level <= T8_DVERTEX_MAXLEVEL); - - s->level = level; -} - -void -t8_dvertex_vertex_integer_coords (const t8_dvertex_t *elem, const int vertex, int coords[]) -{ - T8_ASSERT (vertex == 0); - - coords[0] = 0; -} - -void -t8_dvertex_vertex_ref_coords (const t8_dvertex_t *elem, const int vertex, double coords[]) -{ - T8_ASSERT (vertex == 0); - - coords[0] = 0; -} - -void -t8_dvertex_compute_reference_coords (const t8_dvertex_t *elem, const double *ref_coords, const size_t num_coords, - double *out_coords) -{ - T8_ASSERT (fabs (ref_coords[0]) <= T8_PRECISION_EPS); - T8_ASSERT (t8_dvertex_is_valid (elem)); - for (size_t coord = 0; coord < num_coords; ++coord) { - out_coords[coord] = 0; - } -} - -t8_linearidx_t -t8_dvertex_linear_id (const t8_dvertex_t *elem, int level) -{ - T8_ASSERT (level <= T8_DVERTEX_MAXLEVEL && level >= 0); - - return 0; -} - -int -t8_dvertex_is_valid (const t8_dvertex_t *v) -{ - /* A vertex is valid if its level is in the valid range */ - return 0 <= v->level && v->level <= T8_DVERTEX_MAXLEVEL; -} - -void -t8_dvertex_debug_print (const t8_dvertex_t *v) -{ - t8_debugf ("level: %i\n", v->level); -} - -void -t8_dvertex_init (t8_dvertex_t *v) -{ - v->level = 0; -} diff --git a/src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.h b/src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.h deleted file mode 100644 index f205adecbe..0000000000 --- a/src/t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - 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) 2015 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_dvertex_bits.h - * Definitions of vertex-specific functions. - */ - -#ifndef T8_DVERTEX_BITS_H -#define T8_DVERTEX_BITS_H - -#include -#include - -T8_EXTERN_C_BEGIN (); - -/** Compute the level of a vertex. - * \param [in] l vertex whose level is computed. - * \return The level of \a l. - */ -int -t8_dvertex_get_level (const t8_dvertex_t *v); - -/** Copy all values from one vertex to another. - * \param [in] l The vertex to be copied. - * \param [in,out] dest Existing vertex whose data will be filled with the data - * of \a l. - */ -void -t8_dvertex_copy (const t8_dvertex_t *v, t8_dvertex_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. - */ -int -t8_dvertex_compare (const t8_dvertex_t *l1, const t8_dvertex_t *l2); - -/** Check if two elements are equal. -* \param [in] elem1 The first element. -* \param [in] elem2 The second element. -* \return 1 if the elements are equal, 0 if they are not equal -*/ -int -t8_dvertex_equal (const t8_dvertex_t *elem1, const t8_dvertex_t *elem2); - -/** Compute the parent of a vertex. - * \param [in] l The input vertex. - * \param [in,out] parent Existing vertex whose data will be filled with the parent - * data of \a l. - */ -void -t8_dvertex_parent (const t8_dvertex_t *v, t8_dvertex_t *parent); - -/** Compute the childid-th child in Morton order of a vertex. - * \param [in] l Input vertex. - * \param [in] childid The id of the child, 0 or 1, in Morton order. - * \param [in,out] child Existing vertex whose data will be filled - * with the date of l's childid-th child. - */ -void -t8_dvertex_child (const t8_dvertex_t *v, t8_dvertex_t *child); - -/** Computes the nearest common ancestor of two vertexs in the same tree. - * \param [in] l1 First input vertex. - * \param [in] l2 Second input vertex. - * \param [in,out] r Existing vertex whose data will be filled. - * \note \a l1, \a l2, \a r may point to the same vertex. - */ -void -t8_dvertex_nearest_common_ancestor (const t8_dvertex_t *t1, const t8_dvertex_t *t2, t8_dvertex_t *r); - -/** Compute the position of the ancestor of this child at level \a level within - * its siblings. - * \param [in] l vertex to be considered. - * \param [in] level level to be considered. - * \return Returns its child id 0 or 1. - */ -int -t8_dvertex_ancestor_id (const t8_dvertex_t *v, int level); - -/** Compute the position of the ancestor of this child at level \a level within - * its siblings. - * \param [in] t vertex to be considered. - * \return Returns its child id in 0,1 - */ -int -t8_dvertex_child_id (const t8_dvertex_t *t); - -/** Compute the sibling of a vertex. - * \param [in] v vertex to be considered. - * \param [in] sibid The id of the sibling, must be 0. - * \param [out] s The sibling of \a v. For vertices \a s is just a copy of \a v. - */ -void -t8_dvertex_sibling (const t8_dvertex_t *v, int sibid, t8_dvertex_t *s); - -/** Compute the 2 children of a vertex, array version. - * \param [in] t Input vertex. - * \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_dvertex_childrenpv (const t8_dvertex_t *t, t8_dvertex_t *c[T8_DVERTEX_CHILDREN]); - -/** Check whether a collection of two vertexs is a family in Morton order. - * \param [in] f An array of two vertexs. - * \return Nonzero if \a f is a family of vertexs. - */ -int -t8_dvertex_is_familypv (const t8_dvertex_t *f[]); - -/** Compute whether a given vertex shares a given face with its root tree. - * \param [in] p The input vertex. - * \param [in] face A face of \a p. - * \return True if \a face is a subface of the vertex's root element. - */ -int -t8_dvertex_is_root_boundary (const t8_dvertex_t *p, int face); - -/** Test if a vertex lies inside of the root vertex, - * that is the vertex of level 0, anchor node (0,0) - * \param [in] l Input vertex. - * \return true If \a l lies inside of the root vertex. - */ -int -t8_dvertex_is_inside_root (const t8_dvertex_t *v); - -/** Initialize a vertex as the vertex with a given global id in a uniform - * refinement of a given level. * - * \param [in,out] l Existing vertex whose data will be filled. - * \param [in] id Index to be considered. - * \param [in] level level of uniform grid to be considered. - */ -void -t8_dvertex_init_linear_id (t8_dvertex_t *v, int level, t8_linearidx_t id); - -/** Suppose we have two trees that share a common vertex face f. - * Given a vertex e that is a subface of f in one of the trees - * and given the orientation of the tree connection, construct the face - * vertex 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 - * to the coordinate system of the other tree. - * \note For vertices this function is equivalent to copy. - */ -void -t8_dvertex_transform_face (const t8_dvertex_t *vertex1, t8_dvertex_t *vertex2); - -/** Compute the first descendant of a vertex at a given level. This is the descendant of - * the vertex in a uniform level refinement that has the smallest id. - * \param [in] l vertex whose descendant is computed. - * \param [out] s Existing vertex 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 - * level. - */ -void -t8_dvertex_first_descendant (const t8_dvertex_t *v, t8_dvertex_t *s, int level); - -/** Compute the last descendant of a vertex at a given level. This is the descendant of - * the vertex in a uniform level refinement that has the largest id. - * \param [in] l vertex whose descendant is computed. - * \param [out] s Existing vertex 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 - * level. - */ -void -t8_dvertex_last_descendant (const t8_dvertex_t *v, t8_dvertex_t *s, int level); - -/** Compute the coordinates of a vertex (always 0). - * \param [in] elem vertex whose vertex is computed. - * \param [in] vertex The number of the vertex of \a elem - * \param [out] coords The coordinates of the computed vertex - */ -void -t8_dvertex_vertex_integer_coords (const t8_dvertex_t *elem, int vertex, int coords[]); - -/** Compute the coordinates of a vertex (always 0) inside the [0,1]^0 reference space. - * \param [in] elem vertex whose vertex is computed. - * \param [in] vertex The number of the vertex of \a elem (must be 0). - * \param [out] coords The coordinates of the computed vertex, must have one entry (will be set to 0). - */ -void -t8_dvertex_vertex_ref_coords (const t8_dvertex_t *elem, int vertex, double coords[]); - -/** Convert points in the reference space of a vertex element to points in the - * reference space of the tree (level 0) embedded in \f$ [0,1]^1 \f$. - * \param [in] elem Input vertex. - * \param [in] ref_coords The reference coordinates in the vertex - * (\a num_coords times \f$ [0,1]^1 \f$) - * \param [in] num_coords Number of coordinates to evaluate - * \param [out] out_coords An array of \a num_coords x 1 x double that - * will be filled with the reference coordinates - * of the points on the vertex (will be set to 0). - */ -void -t8_dvertex_compute_reference_coords (const t8_dvertex_t *elem, const double *ref_coords, const size_t num_coords, - double *out_coords); - -/** Computes the linear position of a vertex in an uniform grid. - * \param [in] vertex vertex whose id will be computed. - * \return Returns the linear position of this vertex on a grid. - */ -t8_linearidx_t -t8_dvertex_linear_id (const t8_dvertex_t *elem, int level); - -/** Query whether all entries of a vertex are in valid ranges. - * \param [in] l vertex to be considered. - * \return True, if \a l is a valid vertex and it is safe to call any - * function in this file on \a l. - * False otherwise. - */ -int -t8_dvertex_is_valid (const t8_dvertex_t *v); - -/** Print a vertex - * \param [in] v vertex to be considered. - */ -void -t8_dvertex_debug_print (const t8_dvertex_t *v); - -/** Set default values for a vertex, such that it passes \ref t8_dvertex_is_valid. - * \param [in] l vertex to be initialized - */ -void -t8_dvertex_init (t8_dvertex_t *v); - -T8_EXTERN_C_END (); - -#endif /* T8_DVERTEX_BITS_H */ diff --git a/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx b/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx index 6b02ec0d95..5c013a2732 100644 --- a/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx +++ b/src/t8_schemes/t8_standalone/t8_standalone_implementation.hxx @@ -950,8 +950,7 @@ struct t8_standalone_scheme /* get id in subtree of child */ id -= sum_descendants_of_children_before; } - T8_ASSERT (id < T8_ELEMENT_NUM_CHILDREN[TEclass]); - element_get_child ((const t8_element_t *) el, id, (t8_element_t *) el); + T8_ASSERT (id == 0); return; } diff --git a/src/t8_types/t8_operators.hxx b/src/t8_types/t8_operators.hxx new file mode 100644 index 0000000000..2c25cd4ca0 --- /dev/null +++ b/src/t8_types/t8_operators.hxx @@ -0,0 +1,239 @@ +/* +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) 2024 the developers + +t8code is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +t8code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with t8code; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef T8_OPERATORS_HXX +#define T8_OPERATORS_HXX + +#include +#include + +/** + * \file This file provides the CRTP pattern for operators. + * The operators can be used by a \a T8Type to extend the functionality of the type. + */ + +/** + * \brief The CRTP pattern for operators. + * + * \tparam TUnderlying + * \tparam crtpType + */ +template class crtpType> +struct t8_crtp_operator +{ + constexpr TUnderlying& + underlying () noexcept + { + return static_cast (*this); + } + + constexpr const TUnderlying& + underlying () const noexcept + { + return static_cast (*this); + } +}; + +/* + * The following is a list of competences that can be added to a type. + * Each competence provides access to an operator of the underlying type. That way instead of + * typing `my_int.get() + my_other_int.get()` you can type `my_int + my_other_int`. + */ + +/** + * \brief A template for addable types. Provides the + operator. + * + * \tparam TUnderlying + */ +template +struct Addable: t8_crtp_operator +{ + + constexpr TUnderlying + operator+ (const TUnderlying& other) const noexcept + { + return TUnderlying (this->underlying ().get () + other.get ()); + } +}; + +/** + * \brief A template for subtractable types. Provides the - operator. + * + * \tparam TUnderlying + */ +template +struct Subtractable: t8_crtp_operator +{ + constexpr TUnderlying + operator- (const TUnderlying& other) const noexcept + { + return TUnderlying (this->underlying ().get () - other.get ()); + } +}; + +/** + * \brief A template for multipliable types. Provides the * operator. + * + * \tparam TUnderlying + */ +template +struct Multipliable: t8_crtp_operator +{ + constexpr TUnderlying + operator* (const TUnderlying& other) const noexcept + { + return TUnderlying (this->underlying ().get () * other.get ()); + } +}; + +/** + * \brief A template for dividable types. Provides the / operator. + * + * \tparam TUnderlying + */ +template +struct Dividable: t8_crtp_operator +{ + constexpr TUnderlying + operator/ (const TUnderlying& other) const noexcept + { + return TUnderlying (this->underlying ().get () / other.get ()); + } +}; + +/** + * \brief A template for add-assignable types. Provides the += operator. + * + * \tparam TUnderlying + */ +template +struct AddAssignable: t8_crtp_operator +{ + constexpr TUnderlying& + operator+= (const TUnderlying& other) noexcept + { + this->underlying ().get () += other.get (); + return this->underlying (); + } +}; + +/** + * \brief A template for incrementable types. Provides the ++ operator. + * + * \tparam TUnderlying + * + * \note The operator is a prefix operator. + */ +template +struct PrefixIncrementable: t8_crtp_operator +{ + constexpr TUnderlying& + operator++ () noexcept + { + ++this->underlying ().get (); + return this->underlying (); + } +}; + +/** + * \brief A template for decrementable types. Provides the -- operator. + * + * \tparam TUnderlying + * + * \note The operator is a prefix operator. + */ +template +struct PrefixDecrementable: t8_crtp_operator +{ + constexpr TUnderlying& + operator-- () noexcept + { + --this->underlying ().get (); + return this->underlying (); + } +}; + +template +struct Printable: t8_crtp_operator +{ + void + print (std::ostream& os) const + { + os << this->underlying ().get (); + } +}; + +/** + * \brief A template for swapping types. Used to make a type swappable. + * + * \tparam TUnderlying + */ +template +struct Swapable: t8_crtp_operator +{ + constexpr void + swap (TUnderlying& lhs, TUnderlying& other) noexcept + { + std::swap (lhs.get (), other.get ()); + } +}; + +/** + * \brief A template for equality comparable types. Provides the == operator. + * + * \tparam TUnderlying + */ +template +struct EqualityComparable: t8_crtp_operator +{ + constexpr bool + operator== (TUnderlying const& other) const noexcept + { + return this->underlying ().get () == other.get (); + } +}; + +/** + * \brief A template for << types. Provides the << operator. + * + * \tparam T + */ +template +std::ostream& +operator<< (std::ostream& os, T8Type const& p) +{ + p.print (os); + return os; +} + +/** + * \brief A template for hashable types. Used to make a type hashable. + * + * \tparam T + */ +template +struct Hashable +{ + static constexpr bool is_hashable = true; +}; + +#endif /* T8_OPERATORS_HXX */ diff --git a/src/t8_types/t8_type.hxx b/src/t8_types/t8_type.hxx new file mode 100644 index 0000000000..78d56bdf04 --- /dev/null +++ b/src/t8_types/t8_type.hxx @@ -0,0 +1,124 @@ +/* + 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) 2024 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** + * \file This files gives a template for strong types in t8code. + */ + +#ifndef T8_TYPE_HXX +#define T8_TYPE_HXX + +#include + +/** + * \brief 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 + * main type as a template parameter. + * + * This is heavily inspired by (and taken from) https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/ + * + * \tparam T The type of the value to be stored. + * \tparam Parameter An additional parameter for the type. + * \tparam competence Variadic template parameter for the competences. + */ +template class... competence> +class T8Type: public competence>... { + public: + using value_type = T; + + explicit constexpr T8Type () = default; + + explicit constexpr T8Type (const T& value): value_ (value) + { + } + + /** + * \brief Construct a new T8Type object + * + * \tparam T_ref + * \param value + * + * \note This constructor is only enabled if T is not a reference. + */ + template + explicit constexpr T8Type (T&& value, + typename std::enable_if {}, std::nullptr_t>::type = nullptr) + : value_ (std::move (value)) + { + } + + constexpr T8Type& + operator= (const T& value) + { + value_ = value; + return *this; + } + + constexpr T& + get () noexcept + { + return value_; + } + + constexpr T const& + get () const noexcept + { + return std::move (value_); + } + + private: + T value_; +}; + +namespace std +{ +/** + * \brief 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 + * type T of the T8Type object. + * + * \tparam T The underlying type of the T8Type object. + * \tparam Parameter Additional parameters for the T8Type object. + * \tparam competence Variadic template parameters for additional competencies. + * + * \note This functor is enabled only if the T8Type object is hashable, as determined + * by the is_hashable member of the T8TypeImpl type. + */ +template class... competence> +struct hash> +{ + using T8TypeImpl = T8Type; + using checkIfHashable = typename std::enable_if::type; + + size_t + operator() (T8Type const& x) const + { + return std::hash {}(x.get ()); + } +}; +} // namespace std + +#endif /* T8_TYPE_HXX */ diff --git a/src/t8_vtk/t8_vtk_writer.hxx b/src/t8_vtk/t8_vtk_writer.hxx index 4ea31281dd..8f0f9dfef9 100644 --- a/src/t8_vtk/t8_vtk_writer.hxx +++ b/src/t8_vtk/t8_vtk_writer.hxx @@ -143,7 +143,7 @@ class vtk_writer { * * \param[in] write_treeid true or false */ - void + inline void set_write_treeid (const bool write_treeid) { this->write_treeid = write_treeid; @@ -154,7 +154,7 @@ class vtk_writer { * * \param[in] write_mpirank true or false */ - void + inline void set_write_mpirank (const bool write_mpirank) { this->write_mpirank = write_mpirank; @@ -165,7 +165,7 @@ class vtk_writer { * * \param[in] write_level true or false */ - void + inline void set_write_level (const bool write_level) { this->write_level = write_level; @@ -176,7 +176,7 @@ class vtk_writer { * * \param[in] write_element_id true or false */ - void + inline void set_write_element_id (const bool write_element_id) { this->write_element_id = write_element_id; @@ -187,7 +187,7 @@ class vtk_writer { * * \param[in] write_ghosts true or false */ - void + inline void set_write_ghosts (const bool write_ghosts) { this->write_ghosts = write_ghosts; @@ -199,7 +199,7 @@ class vtk_writer { * * \param[in] curved_flag true or false */ - void + inline void set_curved_flag (const bool curved_flag) { this->curved_flag = curved_flag; @@ -209,7 +209,7 @@ class vtk_writer { * Set the fileprefix for the output files. * \param[in] fileprefix */ - void + inline void set_fileprefix (std::string fileprefix) { this->fileprefix = fileprefix; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ffe99f46b7..4e6d164d86 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ add_library( gtest ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/googletest-mpi/gtest/gtest-all.cc ) -target_include_directories( gtest PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/googletest-mpi ${CMAKE_CURRENT_LIST_DIR}/.. ) +target_include_directories( gtest SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/googletest-mpi ${CMAKE_CURRENT_LIST_DIR}/.. ) function( add_t8_test ) set( options "" ) @@ -74,6 +74,8 @@ add_t8_test( NAME t8_gtest_basics_serial SOURCES t8_gtest_main.cxx t8 add_t8_test( NAME t8_gtest_netcdf_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_netcdf_linkage.cxx ) add_t8_test( NAME t8_gtest_vtk_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_vtk_linkage.cxx ) +add_t8_test( NAME t8_gtest_type_serial SOURCES t8_gtest_main.cxx t8_types/t8_gtest_type.cxx ) + add_t8_test( NAME t8_gtest_hypercube_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_hypercube.cxx ) add_t8_test( NAME t8_gtest_cmesh_readmshfile_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_readmshfile.cxx ) add_t8_test( NAME t8_gtest_cmesh_copy_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_copy.cxx ) @@ -123,7 +125,7 @@ add_t8_test( NAME t8_gtest_vtk_writer_parallel SOURCES t8_gtest_main.cxx t8_IO/ add_t8_test( NAME t8_gtest_nca_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) add_t8_test( NAME t8_gtest_pyra_connectivity_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx ) add_t8_test( NAME t8_gtest_face_neigh_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_neigh.cxx ) -add_t8_test( NAME t8_gtest_init_linear_id_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_init_linear_id.cxx ) +add_t8_test( NAME t8_gtest_get_linear_id_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_get_linear_id.cxx ) add_t8_test( NAME t8_gtest_ancestor_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_ancestor.cxx ) add_t8_test( NAME t8_gtest_ancestor_id_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_ancestor_id.cxx ) add_t8_test( NAME t8_gtest_element_count_leaves_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_count_leaves.cxx ) @@ -139,6 +141,8 @@ add_t8_test( NAME t8_gtest_child_parent_face_serial SOURCES t8_gtest_main.cx add_t8_test( NAME t8_gtest_pack_unpack_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pack_unpack.cxx ) add_t8_test( NAME t8_gtest_root_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_root.cxx ) add_t8_test( NAME t8_gtest_scheme_consistency_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_scheme_consistency.cxx ) +add_t8_test( NAME t8_gtest_input_equal_output_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_input_equal_output.cxx ) +add_t8_test( NAME t8_gtest_set_linear_id_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_set_linear_id.cxx ) if( T8CODE_BUILD_FORTRAN_INTERFACE AND T8CODE_ENABLE_MPI ) add_t8_test( NAME t8_test_fortran_mpi_interface_init_parallel SOURCES api/t8_fortran_interface/t8_test_mpi_init.f90 ) diff --git a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx index 9376cb60f0..0ed910f015 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx @@ -27,6 +27,7 @@ #include "t8_cmesh/t8_cmesh_partition.h" #include #include +#include /* We create a cmesh, partition it and repartition it several times. * At the end we result in the same partition as at the beginning and we @@ -34,20 +35,28 @@ * passed. */ -class t8_cmesh_partition_class: public testing::TestWithParam { +class t8_cmesh_partition_class: public testing::TestWithParam> { protected: void SetUp () override { - size_t found = GetParam ()->name.find (std::string ("empty")); + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); + size_t found = std::get<1> (GetParam ())->name.find (std::string ("empty")); if (found != std::string::npos) { /* Tests not working for empty cmeshes */ GTEST_SKIP (); } - - cmesh_original = GetParam ()->cmesh_create (); + cmesh_original = std::get<1> (GetParam ())->cmesh_create (); } + void + TearDown () override + { + scheme->unref (); + } + t8_cmesh_t cmesh_original; + const t8_scheme *scheme; }; static void @@ -78,7 +87,8 @@ TEST_P (t8_cmesh_partition_class, test_cmesh_partition_concentrate) t8_cmesh_init (&cmesh_partition); t8_cmesh_set_derive (cmesh_partition, cmesh_original); /* Uniform partition according to level */ - t8_cmesh_set_partition_uniform (cmesh_partition, level, t8_scheme_new_default ()); + scheme->ref (); + t8_cmesh_set_partition_uniform (cmesh_partition, level, scheme); t8_cmesh_commit (cmesh_partition, sc_MPI_COMM_WORLD); test_cmesh_committed (cmesh_partition); @@ -118,7 +128,8 @@ TEST_P (t8_cmesh_partition_class, test_cmesh_partition_concentrate) for (int i = 0; i < 2; i++) { t8_cmesh_init (&cmesh_partition_new2); t8_cmesh_set_derive (cmesh_partition_new2, cmesh_partition_new1); - t8_cmesh_set_partition_uniform (cmesh_partition_new2, level, t8_scheme_new_default ()); + scheme->ref (); + t8_cmesh_set_partition_uniform (cmesh_partition_new2, level, scheme); t8_cmesh_commit (cmesh_partition_new2, sc_MPI_COMM_WORLD); cmesh_partition_new1 = cmesh_partition_new2; } @@ -128,5 +139,5 @@ TEST_P (t8_cmesh_partition_class, test_cmesh_partition_concentrate) } /* Test all cmeshes over all different inputs we get through their id */ -INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_partition, t8_cmesh_partition_class, AllCmeshsParam, - pretty_print_base_example); +INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_partition, t8_cmesh_partition_class, + testing::Combine (AllSchemeCollections, AllCmeshsParam), pretty_print_base_example_scheme); diff --git a/test/t8_cmesh/t8_gtest_multiple_attributes.cxx b/test/t8_cmesh/t8_gtest_multiple_attributes.cxx index 28ae877b12..74857a27a3 100644 --- a/test/t8_cmesh/t8_gtest_multiple_attributes.cxx +++ b/test/t8_cmesh/t8_gtest_multiple_attributes.cxx @@ -25,33 +25,35 @@ #include #include #include +#include /* Test if multiple attributes are partitioned correctly. */ /** Return a partitioned cmesh from \a cmesh. */ static t8_cmesh_t -t8_cmesh_partition_cmesh (t8_cmesh_t cmesh, sc_MPI_Comm comm) +t8_cmesh_partition_cmesh (t8_cmesh_t cmesh, const t8_scheme *scheme, sc_MPI_Comm comm) { t8_cmesh_t cmesh_partition; t8_cmesh_init (&cmesh_partition); t8_cmesh_set_derive (cmesh_partition, cmesh); - t8_cmesh_set_partition_uniform (cmesh_partition, 0, t8_scheme_new_default ()); + t8_cmesh_set_partition_uniform (cmesh_partition, 0, scheme); t8_cmesh_commit (cmesh_partition, comm); return cmesh_partition; } -class cmesh_multiple_attributes: public testing::TestWithParam { +class cmesh_multiple_attributes: public testing::TestWithParam> { protected: void SetUp () override { - num_trees = GetParam (); + const int scheme_id = std::get<0> (GetParam ()); + num_trees = std::get<1> (GetParam ()); cmesh_one_at = t8_cmesh_new_row_of_cubes (num_trees, 0, 0, sc_MPI_COMM_WORLD); - cmesh_one_at = t8_cmesh_partition_cmesh (cmesh_one_at, sc_MPI_COMM_WORLD); + cmesh_one_at = t8_cmesh_partition_cmesh (cmesh_one_at, create_from_scheme_id (scheme_id), sc_MPI_COMM_WORLD); cmesh_mult_at = t8_cmesh_new_row_of_cubes (num_trees, 1, 0, sc_MPI_COMM_WORLD); - cmesh_mult_at = t8_cmesh_partition_cmesh (cmesh_mult_at, sc_MPI_COMM_WORLD); + cmesh_mult_at = t8_cmesh_partition_cmesh (cmesh_mult_at, create_from_scheme_id (scheme_id), sc_MPI_COMM_WORLD); cmesh_mult_at_from_stash = t8_cmesh_new_row_of_cubes (num_trees, 1, 1, sc_MPI_COMM_WORLD); } @@ -152,4 +154,5 @@ TEST_P (cmesh_multiple_attributes, multiple_attributes) } /* Test for different number of trees. */ -INSTANTIATE_TEST_SUITE_P (t8_gtest_multiple_attributes, cmesh_multiple_attributes, testing::Range (1, 10)); +INSTANTIATE_TEST_SUITE_P (t8_gtest_multiple_attributes, cmesh_multiple_attributes, + testing::Combine (AllSchemeCollections, testing::Range (1, 10))); diff --git a/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx b/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx index 6824cd7f15..959b04a3eb 100644 --- a/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx +++ b/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx @@ -49,6 +49,14 @@ auto pretty_print_base_example = [] (const testing::TestParamInfo> &info) { + std::string name; + std::get<1> (info.param)->param_to_string (name); + name += std::string ("scheme_") + std::to_string (std::get<0> (info.param)); + name += std::string ("_") + std::to_string (info.index); + return name; +}; + namespace cmesh_list { std::vector cart_prod_vec = { new_from_class::cmesh_example, diff --git a/test/t8_forest/t8_gtest_balance.cxx b/test/t8_forest/t8_gtest_balance.cxx index 3f2e5c7d16..3914382ad2 100644 --- a/test/t8_forest/t8_gtest_balance.cxx +++ b/test/t8_forest/t8_gtest_balance.cxx @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -40,7 +41,7 @@ #include #include -class gtest_balance: public testing::TestWithParam> { +class gtest_balance: public testing::TestWithParam, int, int>> { public: static const int kNumTrees = 4; @@ -48,11 +49,14 @@ class gtest_balance: public testing::TestWithParam (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (std::get<0> (GetParam ())); ilevel = std::get<1> (GetParam ()); ido_periodic = std::get<2> (GetParam ()); } - t8_eclass_t ieclass; + t8_eclass_t eclass; + const t8_scheme *scheme; int ilevel; int ido_periodic; }; @@ -62,12 +66,12 @@ class gtest_balance: public testing::TestWithParamunref (); GTEST_SKIP_ ("The pyramid cube mesh cannot be periodic."); - - const t8_scheme *default_scheme = t8_scheme_new_default (); - t8_cmesh_t cmesh = t8_cmesh_new_hypercube (ieclass, sc_MPI_COMM_WORLD, 0, 0, ido_periodic); - t8_forest_t forest = t8_forest_new_uniform (cmesh, default_scheme, ilevel, 0, sc_MPI_COMM_WORLD); + } + t8_cmesh_t cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, ido_periodic); + t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, ilevel, 0, sc_MPI_COMM_WORLD); EXPECT_EQ (t8_forest_is_balanced (forest), 1); @@ -122,7 +126,7 @@ t8_gtest_balance_refine_certain_trees (t8_forest_t forest, t8_forest_t forest_fr * \return The adapted forest; as shown above */ static t8_forest_t -t8_gtest_obtain_forest_for_balance_tests (const std::vector &trees_to_refine, +t8_gtest_obtain_forest_for_balance_tests (const std::vector &trees_to_refine, const t8_scheme *scheme, int additional_refinement = 0) { const double boundary_coords[12] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0 }; @@ -132,7 +136,7 @@ t8_gtest_obtain_forest_for_balance_tests (const std::vector &trees_ t8_forest_t forest; t8_forest_init (&forest); t8_forest_set_cmesh (forest, cmesh, sc_MPI_COMM_WORLD); - t8_forest_set_scheme (forest, t8_scheme_new_default ()); + t8_forest_set_scheme (forest, scheme); t8_forest_commit (forest); gtest_balance_adapt_data adapt_data; @@ -194,10 +198,10 @@ t8_gtest_check_custom_balanced_forest (t8_forest_t balanced_forest, * |__|__|__|__|__ __ __ __| |__|__|__|__|__ __|__ __| * */ -TEST (gtest_balance, balance_adapted_forest_no_repartition) +TEST_P (gtest_balance, balance_adapted_forest_no_repartition) { std::vector trees_to_refine { 0 }; - t8_forest_t forest = t8_gtest_obtain_forest_for_balance_tests (trees_to_refine); + t8_forest_t forest = t8_gtest_obtain_forest_for_balance_tests (trees_to_refine, scheme, 0); const int flag_no_repartition = 1; @@ -216,12 +220,12 @@ TEST (gtest_balance, balance_adapted_forest_no_repartition) /** * \brief Tests whether an already balanced forest remains unchanged after another balance iteration. */ -TEST (gtest_balance, balance_consistency_test) +TEST_P (gtest_balance, balance_consistency_test) { const int additional_refinement = 2; std::vector trees_to_refine { 1, 2 }; - t8_forest_t forest = t8_gtest_obtain_forest_for_balance_tests (trees_to_refine, additional_refinement); + t8_forest_t forest = t8_gtest_obtain_forest_for_balance_tests (trees_to_refine, scheme, additional_refinement); int flag_no_repartition = 0; t8_forest_t balanced_forest; @@ -243,5 +247,11 @@ TEST (gtest_balance, balance_consistency_test) t8_forest_unref (&already_balanced_forest); } +#ifdef T8_ENABLE_LESS_TESTS +const int maxlvl = 4; +#else +const int maxlvl = 5; +#endif + INSTANTIATE_TEST_SUITE_P (t8_gtest_balance, gtest_balance, - testing::Combine (AllEclasses, testing::Range (0, 5), testing::Range (0, 2))); + testing::Combine (DefaultScheme, testing::Range (0, maxlvl), testing::Range (0, 2))); diff --git a/test/t8_forest/t8_gtest_element_is_leaf.cxx b/test/t8_forest/t8_gtest_element_is_leaf.cxx index e2475ca61e..a2f0ca767d 100644 --- a/test/t8_forest/t8_gtest_element_is_leaf.cxx +++ b/test/t8_forest/t8_gtest_element_is_leaf.cxx @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -35,8 +36,12 @@ */ /* Maximum uniform level for forest. */ -#define T8_IS_LEAF_MAX_LVL 4 +#ifdef T8_ENABLE_LESS_TESTS +#define T8_IS_LEAF_MAX_LVL 3 +#else +#define T8_IS_LEAF_MAX_LVL 4 +#endif /* Adapt a forest such that always the first child of a * family is refined and no other elements. This results in a highly * imbalanced forest. */ @@ -62,21 +67,22 @@ t8_test_adapt_first_child (t8_forest_t forest, t8_forest_t forest_from, t8_locid return 0; } -class element_is_leaf: public testing::TestWithParam> { +class element_is_leaf: public testing::TestWithParam> { protected: void SetUp () override { /* Construct a cmesh */ - const int level = std::get<0> (GetParam ()); - t8_cmesh_t cmesh = std::get<1> (GetParam ())->cmesh_create (); + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); + const int level = std::get<1> (GetParam ()); + t8_cmesh_t cmesh = std::get<2> (GetParam ())->cmesh_create (); if (t8_cmesh_is_empty (cmesh)) { /* forest_commit does not support empty cmeshes, we skip this case */ + scheme->unref (); t8_cmesh_unref (&cmesh); GTEST_SKIP (); } - /* Build the default scheme (TODO: Test this with all schemes) */ - scheme = t8_scheme_new_default (); forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); t8_forest_ref (forest); //const int maxlevel = t8_forest_get_maxlevel (forest); @@ -148,14 +154,17 @@ TEST_P (element_is_leaf, element_is_leaf_adapt) /* Define a lambda to beatify gtest output for tuples . * This will set the correct level and cmesh name as part of the test case name. */ auto pretty_print_level_and_cmesh_params - = [] (const testing::TestParamInfo> &info) { - std::string name = std::string ("Level_") + std::to_string (std::get<0> (info.param)); + = [] (const testing::TestParamInfo> &info) { + std::string name = std::string ("Level_") + std::to_string (std::get<1> (info.param)); std::string cmesh_name; - std::get<1> (info.param)->param_to_string (cmesh_name); + std::get<2> (info.param)->param_to_string (cmesh_name); name += std::string ("_") + cmesh_name; + name += std::string ("scheme_") + std::to_string (std::get<0> (info.param)); + name += std::string ("_") + std::to_string (info.index); return name; }; INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_leaf, element_is_leaf, - testing::Combine (testing::Range (0, T8_IS_LEAF_MAX_LVL), AllCmeshsParam), + testing::Combine (AllSchemeCollections, testing::Range (0, T8_IS_LEAF_MAX_LVL), + AllCmeshsParam), pretty_print_level_and_cmesh_params); diff --git a/test/t8_forest/t8_gtest_element_volume.cxx b/test/t8_forest/t8_gtest_element_volume.cxx index 7cd5132b69..1e0ddb79ec 100644 --- a/test/t8_forest/t8_gtest_element_volume.cxx +++ b/test/t8_forest/t8_gtest_element_volume.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,14 +38,15 @@ /* Construct a forest of a hypercube with volume 1. If the element are refined uniformly * all elements have volume 1/global_num_elements. */ -class t8_forest_volume: public testing::TestWithParam> { +class t8_forest_volume: public testing::TestWithParam, int>> { protected: void SetUp () override { - eclass = std::get<0> (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (std::get<0> (GetParam ())); level = std::get<1> (GetParam ()); - scheme = t8_scheme_new_default (); t8_cmesh_t cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); } @@ -118,4 +120,4 @@ TEST_P (t8_forest_volume, volume_check) } INSTANTIATE_TEST_SUITE_P (t8_gtest_element_volume, t8_forest_volume, - testing::Combine (AllEclasses, testing::Range (0, 4))); + testing::Combine (DefaultScheme, testing::Range (0, 4))); diff --git a/test/t8_forest/t8_gtest_find_owner.cxx b/test/t8_forest/t8_gtest_find_owner.cxx index e4d950e231..f7d4fecdad 100644 --- a/test/t8_forest/t8_gtest_find_owner.cxx +++ b/test/t8_forest/t8_gtest_find_owner.cxx @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -33,20 +34,20 @@ #include #include -class forest_find_owner: public testing::TestWithParam { +class forest_find_owner: public testing::TestWithParam> { protected: void SetUp () override { - tree_class = GetParam (); - - default_scheme = t8_scheme_new_default (); + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); + tree_class = std::get<1> (GetParam ()); /* Construct a coarse mesh of one tree */ cmesh = t8_cmesh_new_from_class (tree_class, sc_MPI_COMM_WORLD); } t8_eclass_t tree_class; t8_cmesh_t cmesh; - const t8_scheme *default_scheme; + const t8_scheme *scheme; }; #if 0 @@ -95,10 +96,10 @@ TEST_P (forest_find_owner, find_owner) /* build the cmesh */ cmesh = t8_test_create_cmesh (itype, tree_class, sc_MPI_COMM_WORLD); /* We reuse the scheme for all forests and thus ref it */ - t8_scheme_ref (default_scheme); + t8_scheme_ref (scheme); /* build the forest */ t8_forest_t forest = - t8_forest_new_uniform (cmesh, default_scheme, level, 0, + t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); for (int itree = 0, t8_gloidx_t global_elem_num = 0; itree < t8_forest_get_num_global_trees (forest); itree++) { @@ -130,7 +131,7 @@ TEST_P (forest_find_owner, find_owner) } /* clean-up */ scheme->element_destroy (tree_class, 1, &element); - t8_scheme_unref (&default_scheme); + t8_scheme_unref (&scheme); } #endif @@ -144,7 +145,7 @@ TEST_P (forest_find_owner, find_multiple_owners) /* initialize the array of owners to store ints */ sc_array_init (&owners, sizeof (int)); /* Build a uniform forest */ - t8_forest_t forest = t8_forest_new_uniform (cmesh, default_scheme, level, 0, sc_MPI_COMM_WORLD); + t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); const t8_scheme *scheme = t8_forest_get_scheme (forest); /* Construct the root element */ scheme->element_new (tree_class, 1, &root_element); @@ -169,4 +170,4 @@ TEST_P (forest_find_owner, find_multiple_owners) sc_array_reset (&owners); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_find_owner, forest_find_owner, AllEclasses, print_eclass); +INSTANTIATE_TEST_SUITE_P (t8_gtest_find_owner, forest_find_owner, DefaultScheme); diff --git a/test/t8_forest/t8_gtest_forest_commit.cxx b/test/t8_forest/t8_gtest_forest_commit.cxx index b2d0b7c986..206f839737 100644 --- a/test/t8_forest/t8_gtest_forest_commit.cxx +++ b/test/t8_forest/t8_gtest_forest_commit.cxx @@ -29,6 +29,7 @@ #include #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include +#include /* In this test we adapt, balance and partition a uniform forest. * We do this in two ways: @@ -38,15 +39,18 @@ * After these two forests are created, we check for equality. */ -class forest_commit: public testing::TestWithParam { +class forest_commit: public testing::TestWithParam> { protected: void SetUp () override { + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); /* Construct a cmesh */ - cmesh = GetParam ()->cmesh_create (); + cmesh = std::get<1> (GetParam ())->cmesh_create (); if (t8_cmesh_is_empty (cmesh)) { /* forest_commit does not support empty cmeshes*/ + scheme->unref (); GTEST_SKIP (); } } @@ -56,6 +60,7 @@ class forest_commit: public testing::TestWithParam { t8_cmesh_destroy (&cmesh); } t8_cmesh_t cmesh; + const t8_scheme *scheme; }; /* Adapt a forest such that always the first child of a @@ -138,8 +143,6 @@ TEST_P (forest_commit, test_forest_commit) const int level_step = 2; - const t8_scheme *scheme = t8_scheme_new_default (); - /* Compute the first level, such that no process is empty */ int min_level = t8_forest_min_nonempty_level (cmesh, scheme); /* Use one level with empty processes */ @@ -167,4 +170,5 @@ TEST_P (forest_commit, test_forest_commit) t8_debugf ("Done testing forest commit."); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_forest_commit, forest_commit, AllCmeshsParam, pretty_print_base_example); +INSTANTIATE_TEST_SUITE_P (t8_gtest_forest_commit, forest_commit, + testing::Combine (AllSchemeCollections, AllCmeshsParam), pretty_print_base_example_scheme); diff --git a/test/t8_forest/t8_gtest_forest_face_normal.cxx b/test/t8_forest/t8_gtest_forest_face_normal.cxx index 2b83917755..09ba93a540 100644 --- a/test/t8_forest/t8_gtest_forest_face_normal.cxx +++ b/test/t8_forest/t8_gtest_forest_face_normal.cxx @@ -29,19 +29,21 @@ #include #include #include +#include /** * This file tests the face normal computation of elements. */ -class class_forest_face_normal: public testing::TestWithParam> { +class class_forest_face_normal: public testing::TestWithParam, int>> { protected: void SetUp () override { - eclass = std::get<0> (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (std::get<0> (GetParam ())); level = std::get<1> (GetParam ()); - scheme = t8_scheme_new_default (); t8_cmesh_t cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); const int do_face_ghost = 1; forest = t8_forest_new_uniform (cmesh, scheme, level, do_face_ghost, sc_MPI_COMM_WORLD); @@ -113,4 +115,4 @@ TEST_P (class_forest_face_normal, back_and_forth) } INSTANTIATE_TEST_SUITE_P (t8_gtest_forest_face_normal, class_forest_face_normal, - testing::Combine (AllEclasses, testing::Range (0, 2))); + testing::Combine (DefaultScheme, testing::Range (0, 2))); diff --git a/test/t8_forest/t8_gtest_ghost_and_owner.cxx b/test/t8_forest/t8_gtest_ghost_and_owner.cxx index 0ce758557a..1d7cbe628e 100644 --- a/test/t8_forest/t8_gtest_ghost_and_owner.cxx +++ b/test/t8_forest/t8_gtest_ghost_and_owner.cxx @@ -29,6 +29,7 @@ #include #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include +#include /* This test program tests the forest ghost layer. * We adapt a forest and create its ghost layer. Afterwards, we @@ -36,15 +37,15 @@ * element is in face the owner that is stored in the ghost layer. */ -class forest_ghost_owner: public testing::TestWithParam { +class forest_ghost_owner: public testing::TestWithParam> { protected: void SetUp () override { - - scheme = t8_scheme_new_default (); + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); /* Construct a cmesh */ - cmesh = GetParam ()->cmesh_create (); + cmesh = std::get<1> (GetParam ())->cmesh_create (); if (t8_cmesh_is_empty (cmesh)) { /* empty cmeshes are currently not supported */ GTEST_SKIP (); @@ -145,4 +146,5 @@ TEST_P (forest_ghost_owner, test_ghost_owner) } } -INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_and_owner, forest_ghost_owner, AllCmeshsParam, pretty_print_base_example); +INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_and_owner, forest_ghost_owner, + testing::Combine (AllSchemeCollections, AllCmeshsParam), pretty_print_base_example_scheme); diff --git a/test/t8_forest/t8_gtest_ghost_delete.cxx b/test/t8_forest/t8_gtest_ghost_delete.cxx index 1cecbd8df4..10957cce84 100644 --- a/test/t8_forest/t8_gtest_ghost_delete.cxx +++ b/test/t8_forest/t8_gtest_ghost_delete.cxx @@ -28,6 +28,7 @@ #include #include #include +#include /* This test is executed on a subcommunicator of exactly 2 procs, because it demonstrates a configuration that is currently not working. See https://github.com/DLR-AMR/t8code/issues/825. * A partitioned square of uniform refinement level 1 is adapted once, where only the lower half is refined. @@ -54,7 +55,7 @@ test_adapt_holes (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which return 0; } -class DISABLED_forest_ghost_exchange_holes: public testing::Test { +class DISABLED_forest_ghost_exchange_holes: public testing::TestWithParam { protected: void SetUp () override @@ -79,7 +80,8 @@ class DISABLED_forest_ghost_exchange_holes: public testing::Test { if (comm != sc_MPI_COMM_NULL) { sc_MPI_Comm_size (comm, &size); T8_ASSERT (size <= 2); - scheme = t8_scheme_new_default (); + const int scheme_id = GetParam (); + scheme = create_from_scheme_id (scheme_id); /* Construct a cmesh */ cmesh = t8_cmesh_new_hypercube (T8_ECLASS_QUAD, comm, 0, 0, 0); } @@ -103,7 +105,7 @@ class DISABLED_forest_ghost_exchange_holes: public testing::Test { t8_cmesh_t cmesh; }; -TEST_F (DISABLED_forest_ghost_exchange_holes, errorTest) +TEST_P (DISABLED_forest_ghost_exchange_holes, errorTest) { /* This test tests the functionality described in Issue: https://github.com/DLR-AMR/t8code/issues/825 */ @@ -118,3 +120,5 @@ TEST_F (DISABLED_forest_ghost_exchange_holes, errorTest) t8_forest_unref (&forest); } } + +INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_delete, DISABLED_forest_ghost_exchange_holes, AllSchemeCollections); diff --git a/test/t8_forest/t8_gtest_ghost_exchange.cxx b/test/t8_forest/t8_gtest_ghost_exchange.cxx index bbe93e2d43..fd7593a0d6 100644 --- a/test/t8_forest/t8_gtest_ghost_exchange.cxx +++ b/test/t8_forest/t8_gtest_ghost_exchange.cxx @@ -29,6 +29,7 @@ #include #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include +#include /* TODO: when this test works for all cmeshes remove if statement in test_cmesh_ghost_exchange_all () */ @@ -43,14 +44,15 @@ * in a second test, we store the element's linear id in the data array. */ -class forest_ghost_exchange: public testing::TestWithParam { +class forest_ghost_exchange: public testing::TestWithParam> { protected: void SetUp () override { - scheme = t8_scheme_new_default (); + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); /* Construct a cmesh */ - cmesh = GetParam ()->cmesh_create (); + cmesh = std::get<1> (GetParam ())->cmesh_create (); if (t8_cmesh_is_empty (cmesh)) { /* empty cmeshes are currently not supported */ GTEST_SKIP (); @@ -195,4 +197,5 @@ TEST_P (forest_ghost_exchange, test_ghost_exchange) } } -INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_exchange, forest_ghost_exchange, AllCmeshsParam, pretty_print_base_example); +INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_exchange, forest_ghost_exchange, + testing::Combine (AllSchemeCollections, AllCmeshsParam), pretty_print_base_example_scheme); diff --git a/test/t8_forest/t8_gtest_half_neighbors.cxx b/test/t8_forest/t8_gtest_half_neighbors.cxx index ba55170bda..2a752361c5 100644 --- a/test/t8_forest/t8_gtest_half_neighbors.cxx +++ b/test/t8_forest/t8_gtest_half_neighbors.cxx @@ -32,17 +32,17 @@ #include #include #include -#include +#include -class forest_half_neighbors: public testing::TestWithParam> { +class forest_half_neighbors: public testing::TestWithParam, int>> { protected: void SetUp () override { - eclass = std::get<0> (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (std::get<0> (GetParam ())); cmesh_type = std::get<1> (GetParam ()); - - default_scheme = t8_scheme_new_default (); /* Construct a coarse mesh of one tree */ cmesh = t8_cmesh_new_from_class (eclass, sc_MPI_COMM_WORLD); } @@ -50,7 +50,7 @@ class forest_half_neighbors: public testing::TestWithParam #include #include +#include #include #include @@ -45,6 +46,7 @@ * function \see TestPartitionData. */ class t8_test_partition_data_t { + public: t8_test_partition_data_t () = default; t8_test_partition_data_t (const t8_gloidx_t value): data { value } {}; @@ -211,6 +213,19 @@ t8_test_partition_data_adapt (t8_forest_t forest, t8_forest_t forest_from, t8_lo } } +class t8_test_partition_data_test: public testing::TestWithParam> { + + protected: + void + SetUp () override + { + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (GetParam ()); + } + const t8_scheme* scheme; + t8_eclass_t eclass; +}; /** * \brief Construct a new TEST object for the t8_forest_partition_data functionality. * The tests constructs a hypercube forest of the triangle class in which the first tree is refined @@ -221,11 +236,10 @@ t8_test_partition_data_adapt (t8_forest_t forest, t8_forest_t forest_from, t8_lo * partition given by the partitioned forest. * At last the data is checked for compliance with the partition of the partitioned forest. */ -TEST (partition_data, test_partition_data) +TEST_P (t8_test_partition_data_test, test_partition_data) { /* Build a forest */ - t8_cmesh_t cmesh = t8_cmesh_new_hypercube (T8_ECLASS_TRIANGLE, sc_MPI_COMM_WORLD, 0, 0, 0); - const t8_scheme* scheme = t8_scheme_new_default (); + t8_cmesh_t cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); t8_forest_t base_forest = t8_forest_new_uniform (cmesh, scheme, 1, 0, sc_MPI_COMM_WORLD); /* Adapt the forest examplary. */ @@ -251,3 +265,5 @@ TEST (partition_data, test_partition_data) t8_forest_unref (&initial_forest); t8_forest_unref (&partitioned_forest); } + +INSTANTIATE_TEST_SUITE_P (t8_gtest_partititon_data, t8_test_partition_data_test, DefaultScheme); diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 884d8f6795..1edaa40e62 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -26,23 +26,25 @@ #include #include #include -#include +#include #include #include +#include -class forest_search: public testing::TestWithParam> { +class forest_search: public testing::TestWithParam, int>> { protected: void SetUp () override { - eclass = std::get<0> (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (std::get<0> (GetParam ())); level = std::get<1> (GetParam ()); - default_scheme = t8_scheme_new_default (); /* Construct a cube coarse mesh */ cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); /* Build a uniform forest */ - forest = t8_forest_new_uniform (cmesh, default_scheme, level, 0, sc_MPI_COMM_WORLD); + forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); } void TearDown () override @@ -52,7 +54,7 @@ class forest_search: public testing::TestWithParam> { int level; t8_cmesh_t cmesh; t8_forest_t forest; - const t8_scheme *default_scheme; + const t8_scheme *scheme; }; /* A search function that matches all elements. @@ -60,92 +62,100 @@ class forest_search: public testing::TestWithParam> { * with one int for each local leaf. * If this function is called for a leaf, it sets the corresponding entry to 1. */ -static int -t8_test_search_all_fn (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) +bool +t8_test_search_all_fn (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, const t8_locidx_t tree_leaf_index, + std::vector *user_data) { - sc_array_t *matched_leaves = (sc_array_t *) t8_forest_get_user_data (forest); + T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (user_data != nullptr); if (is_leaf) { - t8_locidx_t test_ltreeid; const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); - const t8_scheme *scheme = t8_forest_get_scheme (forest); - + const t8_scheme *ts = t8_forest_get_scheme (forest); const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); /* Set the corresponding entry to 1 */ - *(int *) t8_sc_array_index_locidx (matched_leaves, tree_offset + tree_leaf_index) = 1; + (*user_data)[tree_offset + tree_leaf_index] = true; /* Test whether tree_leaf_index is actually the index of the element */ + t8_locidx_t test_ltreeid; const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); - EXPECT_ELEM_EQ (scheme, tree_class, element, test_element); + EXPECT_ELEM_EQ (ts, tree_class, element, test_element); EXPECT_EQ (ltreeid, test_ltreeid) << "Tree mismatch in search."; } - return 1; + return true; } -static void -t8_test_search_query_all_fn (t8_forest_t forest, 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, - sc_array_t *queries, sc_array_t *query_indices, int *query_matches, - const size_t num_active_queries) +inline bool +t8_test_search_query_all_fn (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, + const t8_locidx_t tree_leaf_index, const int &querie, std::vector *user_data) { - EXPECT_TRUE (queries != NULL) << "query callback must be called with queries argument. "; - EXPECT_EQ (num_active_queries, (long unsigned int) 1) << "Wrong number of active queries passed to query callback."; - for (size_t iquery = 0; iquery < num_active_queries; iquery++) { - void *query = sc_array_index_int (queries, iquery); - /* The query callback is always called with a query */ - EXPECT_TRUE (query != NULL) << "query " << iquery << " is NULL."; - /* The query is an int with value 42 (see below) */ - EXPECT_EQ (*(int *) query, 42) << "Wrong query argument passed to query callback."; - if (is_leaf) { - /* Test whether tree_leaf_index is actually the index of the element */ - t8_locidx_t test_ltreeid; - const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); - const t8_scheme *scheme = t8_forest_get_scheme (forest); - - t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); - t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); - EXPECT_ELEM_EQ (scheme, tree_class, element, test_element); - EXPECT_EQ (ltreeid, test_ltreeid) << "Tree mismatch in search."; - } - query_matches[iquery] = 1; + /* The query is an int with value 42 (see below) */ + EXPECT_EQ (querie, 42) << "Wrong query argument passed to query callback."; + if (is_leaf) { + /* Test whether tree_leaf_index is actually the index of the element */ + t8_locidx_t test_ltreeid; + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); + const t8_scheme *ts = t8_forest_get_scheme (forest); + + const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); + const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); + EXPECT_ELEM_EQ (ts, tree_class, element, test_element); + EXPECT_EQ (ltreeid, test_ltreeid) << "Tree mismatch in search."; } + return true; } -TEST_P (forest_search, test_search_one_query_matches_all) +TEST_P (forest_search, t8_test_search_all_fn) { - const int query = 42; - sc_array_t queries; - sc_array_t matched_leaves; + t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); + /* set up an array in which we flag whether an element was matched in the + * search */ + std::vector matched_leaves (num_elements, false); + /* Call search. This search matches all elements. After this call we expect + * all entries in the matched_leaves array to be set to 1. */ + + t8_search> search (t8_test_search_all_fn); + + search.update_user_data (&matched_leaves); + search.update_forest (forest); + search.do_search (); + + /* Check whether matched_leaves entries are all 1 */ + for (size_t i = 0; i < matched_leaves.size (); ++i) { + ASSERT_TRUE (matched_leaves[i]) << "Search did not match all leaves. Mismatch at leaf " << i; + } + + t8_forest_unref (&forest); +} + +TEST_P (forest_search, test_search_one_query_matches_all) +{ /* set up a single query containing our query */ - sc_array_init_size (&queries, sizeof (int), 1); - *(int *) sc_array_index (&queries, 0) = query; + std::vector queries = { 42 }; t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); /* set up an array in which we flag whether an element was matched in the * search */ - sc_array_init_size (&matched_leaves, sizeof (int), num_elements); - /* write 0 in every entry */ - for (t8_locidx_t ielement = 0; ielement < num_elements; ++ielement) { - *(int *) t8_sc_array_index_locidx (&matched_leaves, ielement) = 0; - } + std::vector matched_leaves (num_elements, false); - /* Set the array as user data so that we can access it in the search callback */ - t8_forest_set_user_data (forest, &matched_leaves); /* Call search. This search matches all elements. After this call we expect * all entries in the matched_leaves array to be set to 1. */ - t8_forest_search (forest, t8_test_search_all_fn, t8_test_search_query_all_fn, &queries); + t8_search_with_queries> search (t8_test_search_all_fn, t8_test_search_query_all_fn, queries); + + search.update_queries (queries); + search.update_user_data (&matched_leaves); + search.update_forest (forest); + search.do_search (); /* Check whether matched_leaves entries are all 1 */ - for (t8_locidx_t ielement = 0; ielement < num_elements; ++ielement) { - ASSERT_TRUE (*(int *) t8_sc_array_index_locidx (&matched_leaves, ielement)) - << "Search did not match all leaves. First mismatch at leaf " << ielement; + for (size_t i = 0; i < matched_leaves.size (); ++i) { + ASSERT_TRUE (matched_leaves[i]) << "Search did not match all leaves. Mismatch at leaf " << i; } t8_forest_unref (&forest); - sc_array_reset (&matched_leaves); - sc_array_reset (&queries); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, testing::Combine (AllEclasses, testing::Range (0, 6))); +INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, testing::Combine (DefaultScheme, testing::Range (0, 6))); diff --git a/test/t8_forest/t8_gtest_transform.cxx b/test/t8_forest/t8_gtest_transform.cxx index 736cbb3f79..d1e1966a3a 100644 --- a/test/t8_forest/t8_gtest_transform.cxx +++ b/test/t8_forest/t8_gtest_transform.cxx @@ -37,17 +37,19 @@ #include #include #include +#include -class forest_transform: public testing::TestWithParam> { +class forest_transform: public testing::TestWithParam, int>> { protected: void SetUp () override { - tree_class = std::get<0> (GetParam ()); + const int scheme_id = std::get<0> (std::get<0> (GetParam ())); + scheme = create_from_scheme_id (scheme_id); + tree_class = std::get<1> (std::get<0> (GetParam ())); level = std::get<1> (GetParam ()); t8_debugf ("\n\n\nTesting eclass %s with level %i", t8_eclass_to_string[tree_class], level); - default_scheme = t8_scheme_new_default (); /* Construct a coarse mesh of one tree */ cmesh = t8_cmesh_new_from_class (tree_class, sc_MPI_COMM_WORLD); @@ -55,7 +57,7 @@ class forest_transform: public testing::TestWithParam t8_forest_init (&forest); t8_forest_set_level (forest, level); t8_forest_set_cmesh (forest, cmesh, sc_MPI_COMM_WORLD); - t8_forest_set_scheme (forest, default_scheme); + t8_forest_set_scheme (forest, scheme); t8_forest_commit (forest); } void @@ -65,7 +67,7 @@ class forest_transform: public testing::TestWithParam } t8_eclass_t tree_class; t8_cmesh_t cmesh; - const t8_scheme *default_scheme; + const t8_scheme *scheme; t8_forest_t forest; int level; }; @@ -170,10 +172,11 @@ TEST_P (forest_transform, test_forest_transform_elements) /* Get a pointer to the element */ t8_element_t *element = t8_forest_get_element (forest, ielem, NULL); /* perform the transform test */ - t8_test_transform_element (default_scheme, element, tree_class); + t8_test_transform_element (scheme, element, tree_class); } } INSTANTIATE_TEST_SUITE_P (t8_gtest_forest_transform, forest_transform, - testing::Combine (testing::Range (T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE), + testing::Combine (::testing::Combine (AllSchemeCollections, + ::testing::Range (T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE)), testing::Range (0, 6))); diff --git a/test/t8_forest/t8_gtest_user_data.cxx b/test/t8_forest/t8_gtest_user_data.cxx index bc8b01a410..177c76b143 100644 --- a/test/t8_forest/t8_gtest_user_data.cxx +++ b/test/t8_forest/t8_gtest_user_data.cxx @@ -29,16 +29,27 @@ #include #include #include +#include /* Test t8_forest_set/get_user_data. * We build a forest and set user data for it. * We then retrieve the data and check whether it is the same. */ -TEST (user_data, test_user_data) +class forest_user_data: public testing::TestWithParam { + protected: + void + SetUp () override + { + const int scheme_id = GetParam (); + scheme = create_from_scheme_id (scheme_id); + } + const t8_scheme *scheme; +}; + +TEST_P (forest_user_data, test_user_data) { /* Build a forest */ t8_cmesh_t cmesh = t8_cmesh_new_hypercube (T8_ECLASS_TRIANGLE, sc_MPI_COMM_WORLD, 0, 0, 0); - const t8_scheme *scheme = t8_scheme_new_default (); t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, 1, 0, sc_MPI_COMM_WORLD); /* Define user data */ double data = 42.42; @@ -92,11 +103,10 @@ t8_test_function_second (void) * We build a forest and set a user function for it. * We then retrieve the function and check whether it is the same. */ -TEST (user_data, test_user_function) +TEST_P (forest_user_data, test_user_function) { /* Build a forest */ t8_cmesh_t cmesh = t8_cmesh_new_hypercube (T8_ECLASS_TRIANGLE, sc_MPI_COMM_WORLD, 0, 0, 0); - const t8_scheme *scheme = t8_scheme_new_default (); t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, 1, 0, sc_MPI_COMM_WORLD); double (*funpointer) (int); @@ -123,3 +133,5 @@ TEST (user_data, test_user_function) /* clean up */ t8_forest_unref (&forest); } + +INSTANTIATE_TEST_SUITE_P (t8_gtest_ghost_user_data, forest_user_data, AllSchemeCollections); diff --git a/test/t8_forest_incomplete/t8_gtest_recursive.cxx b/test/t8_forest_incomplete/t8_gtest_recursive.cxx index 9cc11dbbc1..95eca74ff2 100644 --- a/test/t8_forest_incomplete/t8_gtest_recursive.cxx +++ b/test/t8_forest_incomplete/t8_gtest_recursive.cxx @@ -155,4 +155,4 @@ TEST_P (recursive_tree, test_recursive) ASSERT_TRUE (t8_forest_is_equal (forest, forest_base)); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_recursive, recursive_tree, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_recursive, recursive_tree, AllSchemes, print_all_schemes); diff --git a/test/t8_gtest_main.cxx b/test/t8_gtest_main.cxx index e0008b01c0..48239d582c 100644 --- a/test/t8_gtest_main.cxx +++ b/test/t8_gtest_main.cxx @@ -1,3 +1,25 @@ +/* + 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 diff --git a/test/t8_gtest_schemes.hxx b/test/t8_gtest_schemes.hxx index f803364e72..45b1360b9a 100644 --- a/test/t8_gtest_schemes.hxx +++ b/test/t8_gtest_schemes.hxx @@ -41,7 +41,15 @@ create_from_scheme_id (const int scheme_id) } } +static const char *t8_scheme_to_string[] = { "default", "standalone" }; + +auto print_all_schemes = [] (const testing::TestParamInfo> &info) { + return std::string (t8_scheme_to_string[std::get<0> (info.param)]) + "_" + + t8_eclass_to_string[std::get<1> (info.param)]; +}; + #define AllSchemes ::testing::Combine (::testing::Range (0, 2), ::testing::Range (T8_ECLASS_ZERO, T8_ECLASS_COUNT)) -/* Only used for disabling face tests*/ -#define DefaultSchemes ::testing::Combine (::testing::Range (0, 1), ::testing::Range (T8_ECLASS_ZERO, T8_ECLASS_COUNT)) +#define AllSchemeCollections ::testing::Values (0) +#define DefaultScheme ::testing::Combine (::testing::Values (0), ::testing::Range (T8_ECLASS_ZERO, T8_ECLASS_COUNT)) + #endif /* T8_GTEST_SCHEMES_HXX */ diff --git a/test/t8_schemes/t8_gtest_ancestor_id.cxx b/test/t8_schemes/t8_gtest_ancestor_id.cxx index d88b641335..23fd898498 100644 --- a/test/t8_schemes/t8_gtest_ancestor_id.cxx +++ b/test/t8_schemes/t8_gtest_ancestor_id.cxx @@ -83,4 +83,4 @@ TEST_P (class_ancestor_id, t8_recursive_dfs_ancestor_id) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_ancestor_id, class_ancestor_id, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_ancestor_id, class_ancestor_id, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_bfs_base.hxx b/test/t8_schemes/t8_gtest_bfs_base.hxx new file mode 100644 index 0000000000..2fc1ef3cd8 --- /dev/null +++ b/test/t8_schemes/t8_gtest_bfs_base.hxx @@ -0,0 +1,111 @@ +/* + 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_gtest_bfs_base.hxx + * A base class for breadth first search tests. + */ + +#ifndef T8_GTEST_BFS_BASE_HXX +#define T8_GTEST_BFS_BASE_HXX + +#include +#include +#include +#include + +class TestBFS: public testing::TestWithParam> { + public: + /** recursive tests check something for all descendants of a starting element (currently only root) upto maxlevel +*/ + virtual void + check_element () {}; + + /** recursive breadth first search to iterate over all descendants of elem up to max_bfs_recursion_level */ + void + check_recursive_bfs_to_max_lvl (const int max_bfs_recursion_level) + { + std::queue queue; + queue.push (element); + + while (!queue.empty () && current_level <= max_bfs_recursion_level) { + const int level_size = queue.size (); + for (int ilevel = 0; ilevel < level_size; ++ilevel) { + element = queue.front (); + queue.pop (); + + // Process the current element + check_element (); + + // Stop at maximum recursion level. + if (current_level < max_bfs_recursion_level) { + // Add all children of the current element to the queue + const int num_children = scheme->element_get_num_children (eclass, element); + for (int jchild = 0; jchild < num_children; ++jchild) { + t8_element_t *child; + scheme->element_new (eclass, 1, &child); + scheme->element_get_child (eclass, element, jchild, child); + queue.push (child); + } + } + // Free the current element + scheme->element_destroy (eclass, 1, &element); + } + ++current_level; + } + } + + void + bfs_test_setup () + { + const int scheme_id = std::get<0> (GetParam ()); + scheme = create_from_scheme_id (scheme_id); + eclass = std::get<1> (GetParam ()); + scheme->element_new (eclass, 1, &element); + scheme->get_root (eclass, element); + } + + void + bfs_test_teardown () + { + scheme->unref (); + } + + void + SetUp () override + { + bfs_test_setup (); + } + + void + TearDown () override + { + bfs_test_teardown (); + } + + const t8_scheme *scheme; + t8_eclass_t eclass; + t8_element_t *element; + int current_level = 0; +}; + +#endif /* T8_GTEST_BFS_BASE_HXX */ diff --git a/test/t8_schemes/t8_gtest_boundary_extrude.cxx b/test/t8_schemes/t8_gtest_boundary_extrude.cxx index 2217055590..a994546cd3 100644 --- a/test/t8_schemes/t8_gtest_boundary_extrude.cxx +++ b/test/t8_schemes/t8_gtest_boundary_extrude.cxx @@ -92,4 +92,4 @@ TEST_P (class_test_boundary_extrude, test_boundary_extrude_dfs) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_boundary_extrude, DefaultSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_boundary_extrude, DefaultScheme); diff --git a/test/t8_schemes/t8_gtest_child_parent_face.cxx b/test/t8_schemes/t8_gtest_child_parent_face.cxx index edaf057f69..1e8ce8108d 100644 --- a/test/t8_schemes/t8_gtest_child_parent_face.cxx +++ b/test/t8_schemes/t8_gtest_child_parent_face.cxx @@ -80,4 +80,4 @@ TEST_P (class_child_parent_face, t8_recursive_dfs_child_parent_face) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_child_parent_face, class_child_parent_face, DefaultSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_child_parent_face, class_child_parent_face, DefaultScheme); diff --git a/test/t8_schemes/t8_gtest_descendant.cxx b/test/t8_schemes/t8_gtest_descendant.cxx index ade669a018..8df2d2dc5e 100644 --- a/test/t8_schemes/t8_gtest_descendant.cxx +++ b/test/t8_schemes/t8_gtest_descendant.cxx @@ -159,4 +159,4 @@ TEST_P (class_schemes_descendant, test_recursive_descendant) t8_large_step_descendant (elem, desc, test, scheme, eclass, maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_descendant, class_schemes_descendant, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_descendant, class_schemes_descendant, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_element_count_leaves.cxx b/test/t8_schemes/t8_gtest_element_count_leaves.cxx index 0c7820df9d..9e74fea9bb 100644 --- a/test/t8_schemes/t8_gtest_element_count_leaves.cxx +++ b/test/t8_schemes/t8_gtest_element_count_leaves.cxx @@ -128,4 +128,4 @@ TEST_P (class_element_leaves, test_element_count_leaves_one_level) scheme->element_destroy (eclass, 1, &element); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_count_leaves, class_element_leaves, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_count_leaves, class_element_leaves, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_equal.cxx b/test/t8_schemes/t8_gtest_equal.cxx index c38516d990..e3b42b483e 100644 --- a/test/t8_schemes/t8_gtest_equal.cxx +++ b/test/t8_schemes/t8_gtest_equal.cxx @@ -84,4 +84,4 @@ TEST_P (class_test_equal, test_equal_dfs) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_equal, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_equal, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_face_descendant.cxx b/test/t8_schemes/t8_gtest_face_descendant.cxx index 2947b80181..696bb45483 100644 --- a/test/t8_schemes/t8_gtest_face_descendant.cxx +++ b/test/t8_schemes/t8_gtest_face_descendant.cxx @@ -120,4 +120,4 @@ TEST_P (class_descendant, t8_check_face_desc) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_face_descendant, class_descendant, DefaultSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_face_descendant, class_descendant, DefaultScheme); diff --git a/test/t8_schemes/t8_gtest_face_neigh.cxx b/test/t8_schemes/t8_gtest_face_neigh.cxx index c2138968c4..9051e5ed08 100644 --- a/test/t8_schemes/t8_gtest_face_neigh.cxx +++ b/test/t8_schemes/t8_gtest_face_neigh.cxx @@ -199,4 +199,4 @@ TEST_P (face_neigh, recursive_check_diff) t8_recursive_check_diff (child, element, neigh, scheme, eclass, maxlvl, level); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_face_neigh, face_neigh, DefaultSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_face_neigh, face_neigh, DefaultScheme); diff --git a/test/t8_schemes/t8_gtest_find_parent.cxx b/test/t8_schemes/t8_gtest_find_parent.cxx index 1e6dcf8519..f27ef7a896 100644 --- a/test/t8_schemes/t8_gtest_find_parent.cxx +++ b/test/t8_schemes/t8_gtest_find_parent.cxx @@ -74,4 +74,4 @@ TEST_P (class_find_parent, t8_compute_child_find_parent) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_find_parent, class_find_parent, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_find_parent, class_find_parent, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_init_linear_id.cxx b/test/t8_schemes/t8_gtest_get_linear_id.cxx similarity index 95% rename from test/t8_schemes/t8_gtest_init_linear_id.cxx rename to test/t8_schemes/t8_gtest_get_linear_id.cxx index 1403046fb5..c13f710b5a 100644 --- a/test/t8_schemes/t8_gtest_init_linear_id.cxx +++ b/test/t8_schemes/t8_gtest_get_linear_id.cxx @@ -28,7 +28,7 @@ #include #include -class linear_id: public testing::TestWithParam> { +class get_linear_id: public testing::TestWithParam> { protected: void SetUp () override @@ -68,7 +68,7 @@ t8_test_init_linear_id_refine_everything (t8_forest_t forest, t8_forest_t forest } /* Iterate over the leaves of a uniformly refined forest and check the id*/ -TEST_P (linear_id, uniform_forest) +TEST_P (get_linear_id, uniform_forest) { t8_forest_t forest, forest_adapt; t8_cmesh_t cmesh; @@ -115,7 +115,7 @@ TEST_P (linear_id, uniform_forest) /* Test, if the linear_id of descendants of an element is the same as the id of element * (on the level defined by the element) */ -TEST_P (linear_id, id_at_other_level) +TEST_P (get_linear_id, id_at_other_level) { #ifdef T8_ENABLE_LESS_TESTS const int max_lvl = 3; /* Maximal level to compute elements on */ @@ -148,4 +148,4 @@ TEST_P (linear_id, id_at_other_level) } } -INSTANTIATE_TEST_SUITE_P (t8_test_init_linear_id, linear_id, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_test_get_linear_id, get_linear_id, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_input_equal_output.cxx b/test/t8_schemes/t8_gtest_input_equal_output.cxx new file mode 100644 index 0000000000..ae2bb29d31 --- /dev/null +++ b/test/t8_schemes/t8_gtest_input_equal_output.cxx @@ -0,0 +1,99 @@ +/* + 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 "t8_gtest_dfs_base.hxx" +#include + +/* The mainly tested function in this test is element_get_children_at_face. The function allows that the input elem is equal children[0] (output). +Therefore the test checks if this is true and the input is not overridden in the loop or is overridden in the last iteration. +This is tested by comparing the output of two cases. In the first case the condition is not true in the second case elem is equal children[0]. */ +class class_test_equal: public TestDFS { + void + check_element () override + { + for (int iface = 0; iface < scheme->element_get_num_faces (eclass, element); iface++) { + + const int num_children = scheme->element_get_num_face_children (eclass, element, iface); + + elems1 = T8_ALLOC (t8_element_t *, num_children); + elems2 = T8_ALLOC (t8_element_t *, num_children); + + scheme->element_new (eclass, num_children, elems1); + scheme->element_new (eclass, num_children, elems2); + + /* Copy element */ + t8_element_t *first_of_elems1 = elems1[0]; + scheme->element_copy (eclass, element, first_of_elems1); + + scheme->element_get_children_at_face (eclass, element, iface, elems2, num_children, NULL); + + scheme->element_get_children_at_face (eclass, first_of_elems1, iface, elems1, num_children, NULL); + + for (int ichild = 0; ichild < num_children; ichild++) { + t8_element_t *child1 = elems1[ichild]; + t8_element_t *child2 = elems2[ichild]; + + EXPECT_ELEM_EQ (scheme, eclass, child1, child2); + } + + /* Destroy element */ + scheme->element_destroy (eclass, num_children, elems1); + scheme->element_destroy (eclass, num_children, elems2); + + T8_FREE (elems1); + T8_FREE (elems2); + } + } + + protected: + void + SetUp () override + { + dfs_test_setup (); + /* Get element and initialize it */ + } + void + TearDown () override + { + /* Destroy DFS test */ + dfs_test_teardown (); + } + t8_element_t **elems1; + t8_element_t **elems2; +}; + +TEST_P (class_test_equal, test_equal_dfs) +{ +#ifdef T8_ENABLE_LESS_TESTS + const int maxlvl = 3; +#else + const int maxlvl = 5; +#endif + check_recursive_dfs_to_max_lvl (maxlvl); +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_equal, DefaultScheme, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_nca.cxx b/test/t8_schemes/t8_gtest_nca.cxx index fa94665fa3..5410f4587a 100644 --- a/test/t8_schemes/t8_gtest_nca.cxx +++ b/test/t8_schemes/t8_gtest_nca.cxx @@ -315,4 +315,4 @@ TEST_P (nca, recursive_check_higher_level) scheme->element_destroy (tree_class, 1, &correct_nca_high_level); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_nca, nca, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_nca, nca, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_pack_unpack.cxx b/test/t8_schemes/t8_gtest_pack_unpack.cxx index 22e68b08fd..a3fb2a03d6 100644 --- a/test/t8_schemes/t8_gtest_pack_unpack.cxx +++ b/test/t8_schemes/t8_gtest_pack_unpack.cxx @@ -135,4 +135,4 @@ TEST_P (class_test_pack, test_equal_dfs) check_recursive_dfs_to_max_lvl (maxlvl); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_pack, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_pack, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_root.cxx b/test/t8_schemes/t8_gtest_root.cxx index e7c820e77a..3aee580ce7 100644 --- a/test/t8_schemes/t8_gtest_root.cxx +++ b/test/t8_schemes/t8_gtest_root.cxx @@ -70,4 +70,4 @@ TEST_P (root, equals_linear_id_0_0) scheme->element_destroy (eclass, 1, &root_compare); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_root, root, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_root, root, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_set_linear_id.cxx b/test/t8_schemes/t8_gtest_set_linear_id.cxx new file mode 100644 index 0000000000..dff524ddaa --- /dev/null +++ b/test/t8_schemes/t8_gtest_set_linear_id.cxx @@ -0,0 +1,80 @@ +/* + 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 "t8_gtest_bfs_base.hxx" + +/** In this test we iterate through all elements. + * On every level we check if the element is equal to the element we get when setting it from the linear id. + * The id_counter is then increased to match the id of the next leaf. After we have reached the last element on a level, + * we increase the level and reset the id_counter to 0. + */ +class class_test_set_linear_id: public TestBFS { + void + check_element () override + { + if (computed_level < current_level) { + computed_level = current_level; + id_counter = 0; + } + scheme->element_set_linear_id (eclass, test_element, current_level, id_counter); + id_counter++; + EXPECT_ELEM_EQ (scheme, eclass, element, test_element); + } + + protected: + void + SetUp () override + { + bfs_test_setup (); + /* Get element and initialize it */ + scheme->element_new (eclass, 1, &test_element); + } + void + TearDown () override + { + /* Destroy element */ + scheme->element_destroy (eclass, 1, &test_element); + + /* Destroy BFS test */ + bfs_test_teardown (); + } +#if T8_ENABLE_LESS_TESTS + const int maxlvl = 3; +#else + const int maxlvl = 5; +#endif + int computed_level = 0; + t8_linearidx_t id_counter = 0; + t8_element_t *test_element; +}; + +TEST_P (class_test_set_linear_id, test_linear_id_bfs) +{ + check_recursive_bfs_to_max_lvl (maxlvl); +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_test_all_imps, class_test_set_linear_id, AllSchemes, print_all_schemes); diff --git a/test/t8_schemes/t8_gtest_successor.cxx b/test/t8_schemes/t8_gtest_successor.cxx index b1c4c2aa77..7a3075046e 100644 --- a/test/t8_schemes/t8_gtest_successor.cxx +++ b/test/t8_schemes/t8_gtest_successor.cxx @@ -154,4 +154,4 @@ TEST_P (class_successor, test_recursive_and_deep_successor) t8_deep_successor (element, successor, last, scheme, tree_class); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_successor, class_successor, AllSchemes); +INSTANTIATE_TEST_SUITE_P (t8_gtest_successor, class_successor, AllSchemes, print_all_schemes); diff --git a/test/t8_types/t8_gtest_type.cxx b/test/t8_types/t8_gtest_type.cxx new file mode 100644 index 0000000000..718772f967 --- /dev/null +++ b/test/t8_types/t8_gtest_type.cxx @@ -0,0 +1,193 @@ +/* +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) 2024 the developers + +t8code is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +t8code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with t8code; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +/* Tags to differencce between strong types */ +struct dummy_int +{ +}; +struct dummy_int_2 +{ +}; +struct dummy_double +{ +}; + +struct dummy_ref_int +{ +}; + +struct dummy_ref_double +{ +}; + +struct dummy_double_3 +{ +}; + +struct dummy_name_tag +{ +}; + +typedef struct +{ + int x; + double y; +} int_and_double_struct; + +struct int_and_double_tag +{ +}; + +/* Strong types for testing */ +using DummyInt = T8Type; +using DummyInt2 = T8Type; +using DummyDouble = T8Type; +using DummyRefInt = T8Type; +using DummyRefDouble = T8Type; +using Dummy3DVec = T8Type, dummy_double_3, EqualityComparable, Swapable>; +using DummyName = T8Type; +using int_and_double = T8Type; + +/** + * Test if the the strong types are different. + * + */ +TEST (t8_gtest_type, strong_type_equality) +{ + EXPECT_TRUE ((std::is_same::value)); + EXPECT_TRUE ((std::is_same::value)); + EXPECT_TRUE ((std::is_same::value)); + + EXPECT_FALSE ((std::is_same::value)); + EXPECT_FALSE ((std::is_same::value)); + EXPECT_FALSE ((std::is_same::value)); + EXPECT_FALSE ((std::is_same::value)); + EXPECT_FALSE ((std::is_same::value)); + EXPECT_FALSE ((std::is_same::value)); +} + +/** + * Check the sizes of the strong types. + */ +TEST (t8_gtest_type, strong_type_size) +{ + EXPECT_EQ (sizeof (DummyInt), sizeof (int)); + EXPECT_EQ (sizeof (DummyDouble), sizeof (double)); + EXPECT_EQ (sizeof (DummyRefInt), sizeof (int *)); + EXPECT_EQ (sizeof (DummyRefDouble), sizeof (double *)); + EXPECT_EQ (sizeof (Dummy3DVec), sizeof (std::array)); + EXPECT_EQ (sizeof (DummyName), sizeof (std::string)); + EXPECT_EQ (sizeof (int_and_double), sizeof (int_and_double_struct)); +} + +/** + * Test if each strong type holds the correct values (e.g. the get operator works). + * + */ +TEST (t8_gtest_type, strong_type_get) +{ + DummyInt dummy_int (5); + DummyInt2 dummy_int_2 (10); + DummyDouble dummy_double (3.14); + DummyRefInt dummy_ref_int (dummy_int.get ()); + DummyRefDouble dummy_ref_double (dummy_double.get ()); + + EXPECT_EQ (dummy_int.get (), 5); + EXPECT_EQ (dummy_int_2.get (), 10); + EXPECT_EQ (dummy_double.get (), 3.14); + EXPECT_EQ (dummy_ref_int.get (), 5); + EXPECT_EQ (dummy_ref_double.get (), 3.14); + + std::vector vec (10000); + + std::iota (vec.begin (), vec.end (), DummyInt (0)); + std::for_each (vec.begin (), vec.end (), [&dummy_int] (DummyInt &i) { i += dummy_int; }); + + std::for_each (vec.begin (), vec.end (), [n = 5] (const DummyInt &i) mutable { EXPECT_EQ (i.get (), n++); }); +} + +/** + * Test if the operators of the strong types work. + */ +TEST (t8_gtest_type, operators) +{ + DummyInt my_int (5); + DummyInt my_other_int (10); + DummyInt my_result_int = my_int + my_other_int; + EXPECT_EQ (my_result_int.get (), 15); + my_result_int = my_int - my_other_int; + EXPECT_EQ (my_result_int.get (), -5); + my_result_int = my_int * my_other_int; + EXPECT_EQ (my_result_int.get (), 50); + my_result_int = my_int / my_other_int; + EXPECT_EQ (my_result_int.get (), 0); + my_result_int = ++my_int; + EXPECT_EQ (my_result_int.get (), 6); + my_result_int = --my_int; + EXPECT_EQ (my_result_int.get (), 5); + + Dummy3DVec vec1 ({ 1.0, 2.0, 3.0 }); + Dummy3DVec vec2 = vec1; + EXPECT_EQ (vec1, vec2); + Dummy3DVec vec3 ({ 2.0, 2.0, 3.0 }); + EXPECT_NE (vec1, vec3); + swap (vec1, vec3); + EXPECT_NE (vec1, vec3); + EXPECT_EQ (vec3, vec2); +} + +TEST (t8_gtest_type, use_constexpr) +{ + constexpr DummyInt my_int (5); + constexpr DummyInt my_other_int (10); + constexpr DummyInt my_result_int = my_int + my_other_int; + static_assert (my_result_int.get () == 15, "constexpr operator+ failed"); + constexpr DummyInt my_result_int2 = my_int - my_other_int; + static_assert (my_result_int2.get () == -5, "constexpr operator- failed"); + constexpr DummyInt my_result_int3 = my_int * my_other_int; + static_assert (my_result_int3.get () == 50, "constexpr operator* failed"); + constexpr DummyInt my_result_int4 = my_int / my_other_int; + static_assert (my_result_int4.get () == 0, "constexpr operator/ failed"); + constexpr DummyInt my_int_eq (5); + static_assert (my_int_eq == my_int, "constexpr operator== failed"); +} + +/** + * Test if the strong types are hashable. + */ +TEST (t8_gtest_type, hashable) +{ + std::unordered_map my_map + = { { DummyName ("one"), 1 }, { DummyName ("two"), 2 }, { DummyName ("three"), 3 } }; + + EXPECT_EQ (my_map[DummyName ("one")], 1); + EXPECT_EQ (my_map[DummyName ("two")], 2); + EXPECT_EQ (my_map[DummyName ("three")], 3); +} diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index 98d3cf0442..088d4c0dec 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -25,7 +25,7 @@ function( add_t8_tutorial ) set_target_properties( ${ADD_T8_TUTORIAL_NAME} PROPERTIES EXPORT_COMPILE_COMMANDS ON ) endif( T8CODE_EXPORT_COMPILE_COMMANDS ) - install( TARGETS ${ADD_T8_TUTORIAL_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + install( TARGETS ${ADD_T8_TUTORIAL_NAME} DESTINATION bin ) endfunction() #copy tutorial files to the exact same location in the builddir as they are in the source dir diff --git a/tutorials/general/t8_step1_coarsemesh.cxx b/tutorials/general/t8_step1_coarsemesh.cxx index e4cd562ba5..5e7a92dcd6 100644 --- a/tutorials/general/t8_step1_coarsemesh.cxx +++ b/tutorials/general/t8_step1_coarsemesh.cxx @@ -40,7 +40,7 @@ #include /* cmesh-writer interface. */ #include /* A collection of exemplary cmeshes */ -/* Builds cmesh of 6 tetrahedra that build up a unit cube. +/** Builds cmesh of 6 tetrahedra that build up a unit cube. * \param [in] comm MPI Communicator to use. * \return The coarse mesh. */ @@ -65,7 +65,7 @@ t8_step1_build_tetcube_coarse_mesh (sc_MPI_Comm comm) return cmesh; } -/* Write vtk (or more accurately vtu) files of the cmesh. +/** Write vtk (or more accurately vtu) files of the cmesh. * \param [in] cmesh A coarse mesh. * \param [in] prefix A string that is used as a prefix of the output files. * @@ -79,7 +79,7 @@ t8_step1_write_cmesh_vtk (t8_cmesh_t cmesh, const char *prefix) t8_cmesh_vtk_write_file (cmesh, prefix); } -/* Destroy a cmesh. This will free all allocated memory. +/** Destroy a cmesh. This will free all allocated memory. * \param [in] cmesh A cmesh. */ static void diff --git a/tutorials/general/t8_step2_uniform_forest.cxx b/tutorials/general/t8_step2_uniform_forest.cxx index 4931c807fc..a9480860e8 100644 --- a/tutorials/general/t8_step2_uniform_forest.cxx +++ b/tutorials/general/t8_step2_uniform_forest.cxx @@ -52,7 +52,7 @@ #include /* default refinement scheme. */ #include -/* Builds cmesh of 2 prisms that build up a unit cube. +/** Builds cmesh of 2 prisms that build up a unit cube. * See step1 for a detailed description. * \param [in] comm MPI Communicator to use. * \return The coarse mesh. @@ -69,7 +69,7 @@ t8_step2_build_prismcube_coarse_mesh (sc_MPI_Comm comm) return cmesh; } -/* Build a uniform forest on a cmesh +/** Build a uniform forest on a cmesh * using the default refinement scheme. * \param [in] comm MPI Communicator to use. * \param [in] cmesh The coarse mesh to use. @@ -83,13 +83,13 @@ t8_step2_build_uniform_forest (sc_MPI_Comm comm, t8_cmesh_t cmesh, int level) t8_forest_t forest; const t8_scheme *scheme = t8_scheme_new_default (); - /* Creat the uniform forest. */ + /* Create the uniform forest. */ forest = t8_forest_new_uniform (cmesh, scheme, level, 0, comm); return forest; } -/* Write vtk (or more accurately vtu) files of the forest. +/** Write vtk (or more accurately vtu) files of the forest. * \param [in] forest A forest. * \param [in] prefix A string that is used as a prefix of the output files. * @@ -102,7 +102,7 @@ t8_step2_write_forest_vtk (t8_forest_t forest, const char *prefix) t8_forest_write_vtk (forest, prefix); } -/* Destroy a forest. This will free all allocated memory. +/** Destroy a forest. This will free all allocated memory. * \param [in] forest A forest. * NOTE: This will also free the memory of the scheme and the cmesh, since * the forest took ownership of them. diff --git a/tutorials/general/t8_step3_adapt_forest.cxx b/tutorials/general/t8_step3_adapt_forest.cxx index 7007b7c229..af463feae5 100644 --- a/tutorials/general/t8_step3_adapt_forest.cxx +++ b/tutorials/general/t8_step3_adapt_forest.cxx @@ -33,7 +33,7 @@ * of any element will change by at most +-1. * * How you can experiment here: - * - Look at the paraview output files of the unifomr and the adapted forest. + * - Look at the paraview output files of the uniform and the adapted forest. * For the adapted forest you can apply a slice filter to look into the cube. * - Run the program with different process numbers. You should see that refining is * independent of the number of processes, but coarsening is not. @@ -45,7 +45,7 @@ * - Use t8_productionf to print the local number of elements on each process. * Notice, that the uniform forest is evenly distributed, but that the adapted forest * is not. This is due to the fact that we do not repartition our forest here. - * - Add a maximum refinement level to the adapt_data struct and use non-recursive refinement. + * - Add a maximum refinement level to the adapt_data struct and use recursive refinement. * Do not refine an element if it has reached the maximum level. (Hint: scheme->element_get_level) */ @@ -61,9 +61,6 @@ T8_EXTERN_C_BEGIN (); -/* This is our own defined data that we will pass on to the - * adaptation callback. */ - /** The adaptation callback function. This function will be called once for each element * and the return value decides whether this element should be refined or not. * return > 0 -> This element should get refined. @@ -80,8 +77,8 @@ T8_EXTERN_C_BEGIN (); * \param [in] which_tree The process local id of the current tree. * \param [in] tree_class The eclass of \a which_tree. * \param [in] lelement_id The tree local index of the current element (or the first of the family). - * \param [in] scheme The refinement scheme for this tree's element class. - * \param [in] is_family if 1, the first \a num_elements entries in \a elements form a family. If 0, they do not. + * \param [in] scheme The refinement scheme for this tree's element class. + * \param [in] is_family If 1, the first \a num_elements entries in \a elements form a family. If 0, they do not. * \param [in] num_elements The number of entries in \a elements elements that are defined. * \param [in] elements The element or family of elements to consider for refinement/coarsening. */ diff --git a/tutorials/general/t8_step4_partition_balance_ghost.cxx b/tutorials/general/t8_step4_partition_balance_ghost.cxx index 80d08ac7f4..fffead74ba 100644 --- a/tutorials/general/t8_step4_partition_balance_ghost.cxx +++ b/tutorials/general/t8_step4_partition_balance_ghost.cxx @@ -25,7 +25,7 @@ * This is step4 of the t8code tutorials. * After generating a coarse mesh (step1), building a uniform forest * on it (step2) and adapting this forest (step3) - * we will now lear how to control the forest creation in more detail, + * we will now learn how to control the forest creation in more detail, * how to partition and balance a forest and how to generate a layer of ghost elements. * * Partition: Each forest is distributed among the MPI processes. Partitioning a forest means @@ -269,6 +269,8 @@ t8_step4_main (int argc, char **argv) t8_step3_print_forest_information (forest); /* Write forest to vtu files. */ t8_forest_write_vtk_ext (forest, prefix_partition_ghost, 1, 1, 1, 1, 1, 0, 1, 0, NULL); + t8_global_productionf (" [step4] Wrote repartitioned forest with ghost layer to vtu files: %s*\n", + prefix_partition_ghost); /* * Balance diff --git a/tutorials/general/t8_step5_element_data.cxx b/tutorials/general/t8_step5_element_data.cxx index b3ec59e0f1..c5ebe289fe 100644 --- a/tutorials/general/t8_step5_element_data.cxx +++ b/tutorials/general/t8_step5_element_data.cxx @@ -214,8 +214,8 @@ t8_step5_output_data_to_vtu (t8_forest_t forest, struct t8_step5_data_per_elemen element_volumes[ielem] = data[ielem].volume; } { - /* To write user defined data, we need to extended output function t8_forest_vtk_write_file - * from t8_forest_vtk.h. Despite writin user data, it also offers more control over which + /* To write user defined data, we need the extended output function t8_forest_vtk_write_file + * from t8_forest_vtk.h. Despite writing user data, it also offers more control over which * properties of the forest to write. */ int write_treeid = 1; int write_mpirank = 1; diff --git a/tutorials/general/t8_step6_stencil.cxx b/tutorials/general/t8_step6_stencil.cxx index 29c99c4795..2198ae7668 100644 --- a/tutorials/general/t8_step6_stencil.cxx +++ b/tutorials/general/t8_step6_stencil.cxx @@ -107,7 +107,7 @@ t8_step6_build_forest (sc_MPI_Comm comm, int dim, int level) } /* Allocate and fill the element data array with `heights` from an arbitrary - * mathematical function. Returns a pointer to the array which is then ownded + * mathematical function. Returns a pointer to the array which is then owned * by the calling scope. */ static struct data_per_element * t8_step6_create_element_data (t8_forest_t forest) @@ -420,7 +420,7 @@ t8_step6_main (int argc, char **argv) /* Output the data to vtu files. */ t8_step6_output_data_to_vtu (forest, data, prefix_forest_with_data); - t8_global_productionf (" Wrote forest and data to %s*.\n", prefix_forest_with_data); + t8_global_productionf (" [step6] Wrote forest and data to %s*.\n", prefix_forest_with_data); /* * Clean-up @@ -431,7 +431,7 @@ t8_step6_main (int argc, char **argv) /* Destroy the forest. */ t8_forest_unref (&forest); - t8_global_productionf (" Destroyed forest.\n"); + t8_global_productionf (" [step6] Destroyed forest.\n"); sc_finalize (); diff --git a/tutorials/general/t8_step7_interpolation.cxx b/tutorials/general/t8_step7_interpolation.cxx index 6f4d86daca..ecc5e6b528 100644 --- a/tutorials/general/t8_step7_interpolation.cxx +++ b/tutorials/general/t8_step7_interpolation.cxx @@ -37,9 +37,6 @@ #include #include #include - -#include - #include T8_EXTERN_C_BEGIN (); @@ -55,15 +52,15 @@ struct t8_step7_element_data_t /* This is our own defined data that we will pass on to the * adaptation callback. */ -typedef struct t8_step7_adapt_data +struct t8_step7_adapt_data { double midpoint[3]; /* The midpoint of our sphere. */ double refine_if_inside_radius; /* if an element's center is smaller than this value, we refine the element. */ double coarsen_if_outside_radius; /* if an element's center is larger this value, we coarsen its family. */ sc_array_t *element_data; -} t8_step7_adapt_data; +}; -/* Set the value of an element to a given entry */ +/* Set the value of an element to a given entry. */ static void t8_element_set_value (const t8_step7_adapt_data *adapt_data, t8_locidx_t ielement, double value) { @@ -72,25 +69,23 @@ t8_element_set_value (const t8_step7_adapt_data *adapt_data, t8_locidx_t ielemen *((t8_step7_element_data_t *) t8_sc_array_index_locidx (adapt_data->element_data, ielement)) = elem_data; } -/* Set the value of an element to a given entry */ +/* Set the value of an element to a given element data. */ static void t8_element_set_element (const t8_step7_adapt_data *adapt_data, t8_locidx_t ielement, t8_step7_element_data_t element) { *((t8_step7_element_data_t *) t8_sc_array_index_locidx (adapt_data->element_data, ielement)) = element; } -/* Get the value of an element to a given entry - */ +/* Get the value of an element. */ static t8_step7_element_data_t t8_element_get_value (const t8_step7_adapt_data *adapt_data, t8_locidx_t ielement) { return *((t8_step7_element_data_t *) t8_sc_array_index_locidx ((adapt_data->element_data), ielement)); } -/* This is our own defined data that we will pass on to the - * adaptation callback. */ - -/** The adaptation callback function. This function will be called once for each element +/** The adaptation callback function. + * The function is the same as the one in step 3, but with the type t8_step7_adapt_data instead of t8_step3_adapt_data. + * This function will be called once for each element * and the return value decides whether this element should be refined or not. * return > 0 -> This element should get refined. * return = 0 -> This element should not get refined. @@ -107,8 +102,8 @@ t8_element_get_value (const t8_step7_adapt_data *adapt_data, t8_locidx_t ielemen * \param [in] tree_class The eclass of \a which_tree * \param [in] tree_class The tree_class of the elements of the tree. * \param [in] lelement_id The tree local index of the current element (or the first of the family). - * \param [in] scheme The refinement scheme of the forest. - * \param [in] is_family if 1, the first \a num_elements entries in \a elements form a family. If 0, they do not. + * \param [in] scheme The refinement scheme of the forest. + * \param [in] is_family If 1, the first \a num_elements entries in \a elements form a family. If 0, they do not. * \param [in] num_elements The number of entries in \a elements elements that are defined. * \param [in] elements The element or family of elements to consider for refinement/coarsening. */ @@ -120,9 +115,8 @@ t8_step7_adapt_callback (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_ /* Our adaptation criterion is to look at the midpoint coordinates of the current element and if * they are inside a sphere around a given midpoint we refine, if they are outside, we coarsen. */ double centroid[3]; /* Will hold the element midpoint. */ - /* In t8_step3_adapt_forest we pass a t8_step3_adapt_data pointer as user data to the - * t8_forest_new_adapt function. This pointer is stored as the used data of the new forest - * and we can now access it with t8_forest_get_user_data (forest). */ + /* In t8_adapt_forest, we store user data (a t8_step7_adapt_data pointer) for the new forest using the t8_forest_set_user_data function. + * We can now access it with t8_forest_get_user_data (forest). */ const struct t8_step7_adapt_data *adapt_data = (const struct t8_step7_adapt_data *) t8_forest_get_user_data (forest); double dist; /* Will store the distance of the element's midpoint and the sphere midpoint. */ @@ -151,12 +145,12 @@ t8_step7_adapt_callback (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_ return 0; } -/* Adapt a forest according to a callback function. +/** Adapt a forest according to a callback function. * This will create a new forest and return it. * Create a new forest that is adapted from \a forest with our adaptation callback. * We provide the adapt_data as user data that is stored as the used_data pointer of the * new forest (see also t8_forest_set_user_data). - * The 0, 0 arguments are flags that control + * * \param [in] forest_from Forest that should be adapted * \param [in] adapt_fn Function that defines how to adapt the forest - Callback function * \param [in] do_partition If non-zero the new_forest should partition the existing forest. As the second parameter @@ -187,15 +181,15 @@ t8_adapt_forest (t8_forest_t forest_from, t8_forest_adapt_t adapt_fn, int do_par return forest_new; } -/* Replace callback to decide how to interpolate a refined or coarsened element. +/** Replace callback to decide how to interpolate a refined or coarsened element. * If an element is refined, each child gets the value of its parent. * If elements are coarsened, the parent gets the average value of the children. - * Outgoing are the old elements and incoming the new ones + * Outgoing are the old elements and incoming the new ones. * \param [in] forest_old non adapted forest - * \param [in] forest_new adapted forest + * \param [in, out] forest_new adapted forest with interpolated user data for element(s) * \param [in] which_tree tree_id of the analyzed element * \param [in] tree_class The eclass of the tree - * \param [in] scheme Scheme of the forest + * \param [in] scheme Scheme of the forest * \param [in] refine ==0 - do nothing, == -1 - coarsen, == 1 - refine * \param [in] num_outgoing number of the elements not refined forest * \param [in] first_outgoing index of the old element @@ -237,7 +231,7 @@ t8_forest_replace (t8_forest_t forest_old, t8_forest_t forest_new, t8_locidx_t w t8_forest_set_user_data (forest_new, adapt_data_new); } -/* Write the forest and the data corresponding to the forest in a vtu file. +/** Write the forest and the data corresponding to the forest in a vtu file. * * \param [in] forest Forest that should written in the vtu file * \param [in] data Data corresponding to the forest @@ -338,7 +332,9 @@ t8_interpolation () t8_forest_set_user_data (forest, data); /* Write vtu file */ - t8_write_vtu (forest, data, "t8_step7_uniform_forest"); + const char *prefix_uniform_forest = "t8_step7_uniform_forest"; + t8_write_vtu (forest, data, prefix_uniform_forest); + t8_global_productionf (" [step7] Wrote uniform forest with data to %s*.\n", prefix_uniform_forest); /* Build a second forest to store the adapted forest - keep the old one */ t8_forest_ref (forest); @@ -353,18 +349,21 @@ t8_interpolation () = sc_array_new_count (sizeof (t8_step7_element_data_t), t8_forest_get_local_num_elements (forest_adapt)); /* Initialize user_data element for the adapted forest */ - (*adapt_data).midpoint[0] = (*data).midpoint[0]; - (*adapt_data).midpoint[1] = (*data).midpoint[1]; - (*adapt_data).midpoint[2] = (*data).midpoint[2]; - (*adapt_data).refine_if_inside_radius = (*data).refine_if_inside_radius; - (*adapt_data).coarsen_if_outside_radius = (*data).coarsen_if_outside_radius; + adapt_data->midpoint[0] = data->midpoint[0]; + adapt_data->midpoint[1] = data->midpoint[1]; + adapt_data->midpoint[2] = data->midpoint[2]; + adapt_data->refine_if_inside_radius = data->refine_if_inside_radius; + adapt_data->coarsen_if_outside_radius = data->coarsen_if_outside_radius; t8_forest_set_user_data (forest_adapt, adapt_data); t8_forest_iterate_replace (forest_adapt, forest, t8_forest_replace); /* Write the adapted forest to a vtu file */ adapt_data = (struct t8_step7_adapt_data *) t8_forest_get_user_data (forest_adapt); - t8_write_vtu (forest_adapt, adapt_data, "t8_step7_adapt_forest"); + + const char *prefix_adapted_forest = "t8_step7_adapt_forest"; + t8_write_vtu (forest_adapt, adapt_data, prefix_adapted_forest); + t8_global_productionf (" [step7] Wrote adapted forest with data to %s*.\n", prefix_adapted_forest); /* Free the memory */ sc_array_destroy (adapt_data->element_data); @@ -397,7 +396,7 @@ t8_step7_main (int argc, char **argv) /* Initialize t8code with log level SC_LP_PRODUCTION. See sc.h for more info on the log levels. */ t8_init (SC_LP_PRODUCTION); - /* Create forest, define data on forest, adapt forest, interpolate data */ + /* Create forest, define data on forest, adapt forest, interpolate data. */ t8_interpolation (); sc_finalize (); diff --git a/tutorials/general/t8_tutorial_build_cmesh.cxx b/tutorials/general/t8_tutorial_build_cmesh.cxx index 122636fc49..b39afed317 100644 --- a/tutorials/general/t8_tutorial_build_cmesh.cxx +++ b/tutorials/general/t8_tutorial_build_cmesh.cxx @@ -144,13 +144,14 @@ t8_cmesh_new_periodic_hybrid_2d (sc_MPI_Comm comm) /* 1. Defining an array with all vertices */ /* Just all vertices of all trees. partly duplicated */ - double vertices[60] = { 0, 0, 0, /* tree 0, triangle */ - 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 0, /* tree 1, triangle */ - 0.5, 0.5, 0, 0, 0.5, 0, 0.5, 0, 0, /* tree 2, quad */ - 1, 0, 0, 0.5, 0.5, 0, 1, 0.5, 0, 0, 0.5, 0, /* tree 3, quad */ - 0.5, 0.5, 0, 0, 1, 0, 0.5, 1, 0, 0.5, 0.5, 0, /* tree 4, triangle */ - 1, 0.5, 0, 1, 1, 0, 0.5, 0.5, 0, /* tree 5, triangle */ - 1, 1, 0, 0.5, 1, 0 }; + double vertices[60] = { + 0, 0, 0, 0.5, 0, 0, 0.5, 0.5, 0, /* tree 0, triangle */ + 0, 0, 0, 0.5, 0.5, 0, 0, 0.5, 0, /* tree 1, triangle */ + 0.5, 0, 0, 1, 0, 0, 0.5, 0.5, 0, 1, 0.5, 0, /* tree 2, quad */ + 0, 0.5, 0, 0.5, 0.5, 0, 0, 1, 0, 0.5, 1, 0, /* tree 3, quad */ + 0.5, 0.5, 0, 1, 0.5, 0, 1, 1, 0, /* tree 4, triangle */ + 0.5, 0.5, 0, 1, 1, 0, 0.5, 1, 0 /* tree 5, triangle */ + }; /* 2. Initialization of the mesh */ t8_cmesh_t cmesh; @@ -303,7 +304,7 @@ t8_cmesh_new_hybrid_gate_3d (sc_MPI_Comm comm) t8_cmesh_register_geometry (cmesh); /* Use linear geometry */ - /* Defitition of the classes of the different trees */ + /* Definition of the classes of the different trees */ t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_TET); t8_cmesh_set_tree_class (cmesh, 1, T8_ECLASS_TET); t8_cmesh_set_tree_class (cmesh, 2, T8_ECLASS_PRISM); @@ -492,9 +493,9 @@ t8_tutorial_build_cmesh_main (int argc, char **argv) /* Output the meshes to vtu files. */ t8_cmesh_vtk_write_file (cmesh_2D, prefix_2D); - t8_global_productionf ("[tutorial] Wrote the 2D cmesh to vtu files.\n"); + t8_global_productionf ("[tutorial] Wrote the 2D cmesh to %s*.\n", prefix_2D); t8_cmesh_vtk_write_file (cmesh_3D, prefix_3D); - t8_global_productionf ("[tutorial] Wrote the 3D cmesh to vtu files.\n"); + t8_global_productionf ("[tutorial] Wrote the 3D cmesh to %s*.\n", prefix_3D); /* * Clean-up diff --git a/tutorials/general/t8_tutorial_search.cxx b/tutorials/general/t8_tutorial_search.cxx index 2beacc085b..7d2976b80a 100644 --- a/tutorials/general/t8_tutorial_search.cxx +++ b/tutorials/general/t8_tutorial_search.cxx @@ -99,11 +99,11 @@ * Those are all leaves in the forest and hence the search will stop after * executing the query callback. * - * Afterwards the search will continue simarly in the second tree. + * Afterwards the search will continue similarly in the second tree. * * Note that the performance of the search could be improved by using an approximative check * on all but the leaf elements. - * This check should return true whenenever a particle is inside an element, but may have false positives. + * This check should return true whenever a particle is inside an element, but may have false positives. * */ @@ -118,20 +118,20 @@ #include /* Example forest adaptation from step 3 */ /* Our search query, a particle together with a flag. */ -typedef struct +struct t8_tutorial_search_particle_t { double coordinates[3]; /* The coordinates of our particle. */ int is_inside_partition; /* Will be set to true if the particles lies inside this process' parallel partition. */ -} t8_tutorial_search_particle_t; +}; /* Additional user data that we process during search. * For each element we count the number of particles that it contains * and we count the total number of elements that we constructed during search. */ -typedef struct +struct t8_tutorial_search_user_data_t { sc_array *particles_per_element; /* For each element the number of particles inside it. */ t8_locidx_t num_elements_searched; /* The total number of elements created. */ -} t8_tutorial_search_user_data_t; +}; /* * The search callback. @@ -305,7 +305,7 @@ t8_tutorial_search_for_particles (t8_forest_t forest, sc_array *particles) sc_array_reset (&particles_per_element); } -/* Create an array of a given number of particles on the root process +/** Create an array of a given number of particles on the root process * and broadcast it to all other processes. * \param [in] num_particles The number of particles to create. * \param [in] seed The seed to be used for the random number generator.