diff --git a/.github/workflows/add_release_documentation.yml b/.github/workflows/add_release_documentation.yml index 54113f8eab..5ac4235eb2 100644 --- a/.github/workflows/add_release_documentation.yml +++ b/.github/workflows/add_release_documentation.yml @@ -119,19 +119,27 @@ jobs: if: ${{ env.MINOR_RELEASE == 'true' }} run: | cd t8code-website/content + # Generate new folder for the newest documentation and copy documentation mkdir -p doc/$GITHUB_REF_NAME cp -r ../../t8code/build_debug/doc/html/* doc/$GITHUB_REF_NAME/ + # Add a link to the newest documentation in the documentation webpage cd pages today=`date +'%Y-%m-%d %H:%M'` sed -i s/"^Date:.*"/"Date: $today"/g 4_Documentation.md - csplit -z 4_Documentation.md /"t8code dev"/+1 + # Split documentation webpage after t8code latest and append newest documentation + csplit -z 4_Documentation.md /"t8code latest"/+1 mv xx00 4_Documentation.md echo " - [t8code $GITHUB_REF_NAME](../doc/$GITHUB_REF_NAME/index.html)" >> 4_Documentation.md cat xx01 >> 4_Documentation.md rm xx01 + # Refresh redirect to t8code latest + cd ../doc + echo '' > latest.html + # Refresh redirections for complete latest documentation + ./generate_redirections.sh $GITHUB_REF_NAME - name: Create Pull Request at DLR-AMR/t8code-website if: ${{ env.MINOR_RELEASE == 'true' }} - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: path: t8code-website title: Add documentation for t8code ${{ github.ref_name }} diff --git a/.github/workflows/tests_t8code_linkage_parallel_debug.yml b/.github/workflows/tests_t8code_linkage_parallel_debug.yml index fae6d3602b..cef908feae 100644 --- a/.github/workflows/tests_t8code_linkage_parallel_debug.yml +++ b/.github/workflows/tests_t8code_linkage_parallel_debug.yml @@ -205,25 +205,25 @@ jobs: - name: check OpenCASCADE run: echo "Checking OpenCASCADE with MPI in debugging mode" - name: configure MPI OpenCASCADE debug - run: mkdir build_occ && cd build_occ && ../configure $CONFIG_DEBUG --with-occ CFLAGS="$CFLAGS_var -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -I/usr/include/opencascade" + run: mkdir build_cad && cd build_cad && ../configure $CONFIG_DEBUG --with-occ CFLAGS="$CFLAGS_var -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -I/usr/include/opencascade" - name: OnFailUploadLog if: failure() uses: actions/upload-artifact@v4 with: - name: config_occ_debug_MPI.log - path: build_occ/config.log + name: config_cad_debug_MPI.log + path: build_cad/config.log - name: make - run: cd build_occ && make $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" + run: cd build_cad && make $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" - name: make install - run: cd build_occ && make install $MAKEFLAGS + run: cd build_cad && make install $MAKEFLAGS - name: make check - run: cd build_occ && make check $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" + run: cd build_cad && make check $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" - name: OnFailUploadLog if: failure() uses: actions/upload-artifact@v4 with: - name: test-suite_occ.log - path: build_occ/test-suite.log + name: test-suite_cad.log + path: build_cad/test-suite.log # configure and test with MPI and VTK (debug mode) - name: check VTK run: echo "Checking VTK with MPI in debugging mode" diff --git a/.github/workflows/tests_t8code_linkage_parallel_release.yml b/.github/workflows/tests_t8code_linkage_parallel_release.yml index 90ec479fdf..fc16d7486a 100644 --- a/.github/workflows/tests_t8code_linkage_parallel_release.yml +++ b/.github/workflows/tests_t8code_linkage_parallel_release.yml @@ -205,25 +205,25 @@ jobs: - name: check OpenCASCADE run: echo "Checking OpenCASCADE with MPI in release mode" - name: configure MPI OpenCASCADE release - run: mkdir build_occ && cd build_occ && ../configure $CONFIG_RELEASE --with-occ CFLAGS="$CFLAGS_var -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -I/usr/include/opencascade" + run: mkdir build_cad && cd build_cad && ../configure $CONFIG_RELEASE --with-cad CFLAGS="$CFLAGS_var -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -I/usr/include/opencascade" - name: OnFailUploadLog if: failure() uses: actions/upload-artifact@v4 with: - name: config_occ_release_MPI.log - path: build_occ/config.log + name: config_cad_release_MPI.log + path: build_cad/config.log - name: make - run: cd build_occ && make $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" + run: cd build_cad && make $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" - name: make install - run: cd build_occ && make install $MAKEFLAGS + run: cd build_cad && make install $MAKEFLAGS - name: make check - run: cd build_occ && make check $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" + run: cd build_cad && make check $MAKEFLAGS CFLAGS="$CFLAGS_var -Werror -I/usr/include/opencascade" CXXFLAGS="$CXXFLAGS_var -Werror -I/usr/include/opencascade" - name: OnFailUploadLog if: failure() uses: actions/upload-artifact@v4 with: - name: test-suite_occ.log - path: build_occ/test-suite.log + name: test-suite_cad.log + path: build_cad/test-suite.log # configure and test with MPI and VTK (release mode) - name: check VTK run: echo "Checking VTK with MPI in release mode" diff --git a/.gitignore b/.gitignore index e536e16531..ecc0d1ed99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ sc/ p4est/ build-aux/ +build/ .deps/ .libs/ @@ -87,7 +88,7 @@ test/t8_geometry/t8_test_geometry test/t8_geometry/t8_test_point_inside test/t8_gtest_main test/t8_schemes/t8_test_descendant -test/t8_schemes/t8_test_element_count_leafs +test/t8_schemes/t8_test_element_count_leaves test/t8_schemes/t8_test_find_parent test/t8_schemes/t8_test_init_linear_id test/t8_schemes/t8_test_pyra_face_descendant diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..5e07b82cb8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,68 @@ +cmake_minimum_required( VERSION 3.16 ) +project( T8CODE DESCRIPTION "Parallel algorithms and data structures for tree-based AMR with arbitrary element shapes." LANGUAGES C CXX ) +include( CTest ) + + +option( T8CODE_BUILD_AS_SHARED_LIBRARY "Whether t8code should be built as a shared or a static library" ON ) +option( T8CODE_BUILD_TESTS "Build t8code's automated tests" ON ) +option( T8CODE_BUILD_TUTORIALS "Build t8code's tutorials" ON ) +option( T8CODE_BUILD_EXAMPLES "Build t8code's examples" ON ) + +option( T8CODE_ENABLE_MPI "Enable t8code's features which rely on MPI" ON ) +option( T8CODE_ENABLE_VTK "Enable t8code's features which rely on VTK" OFF ) + + +if( NOT CMAKE_BUILD_TYPE ) + set( CMAKE_BUILD_TYPE "Release" ) +endif() + +set( CMAKE_C_STANDARD 11 ) +set( CMAKE_C_STANDARD_REQUIRED ON ) +set( CMAKE_C_EXTENSIONS OFF ) +list( APPEND CMAKE_C_FLAGS "-Wall" ) + +set( CMAKE_CXX_STANDARD 17 ) +set( CMAKE_CXX_STANDARD_REQUIRED ON ) +set( CMAKE_CXX_EXTENSIONS OFF ) +list( APPEND CMAKE_CXX_FLAGS "-Wall" ) + + +if( T8CODE_ENABLE_MPI ) + find_package( MPI COMPONENTS C REQUIRED ) + if( NOT MPIEXEC_EXECUTABLE ) + message( FATAL_ERROR "MPIEXEC was not found" ) + endif() + set( SC_ENABLE_MPI ON ) + set( mpi ON ) # This is very dirty, we should consider fixing this in the p4est repo +endif() + +if( T8CODE_ENABLE_VTK ) + find_package( VTK REQUIRED ) +endif() + +# Override default for this libsc option +set( BUILD_SHARED_LIBS ON CACHE BOOL "Build libsc as a shared library" ) + +# Prevent `libsc` and `p4est` from overwriting the default install prefix. +set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE) + +# Rpath options necessary for shared library install to work correctly in user projects. +set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) +set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) + +add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/sc ) +add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/p4est ) +add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/src ) + +if ( T8CODE_BUILD_TESTS ) + add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/test ) +endif() + +if ( T8CODE_BUILD_TUTORIALS ) + add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/tutorials ) +endif() + +if ( T8CODE_BUILD_EXAMPLES ) + add_subdirectory( ${CMAKE_CURRENT_LIST_DIR}/example ) +endif() \ No newline at end of file diff --git a/benchmarks/t8_time_set_join_by_vertices.cxx b/benchmarks/t8_time_set_join_by_vertices.cxx index 96f5a49c5c..09b09f2087 100644 --- a/benchmarks/t8_time_set_join_by_vertices.cxx +++ b/benchmarks/t8_time_set_join_by_vertices.cxx @@ -161,7 +161,7 @@ main (int argc, char **argv) const int dim = 3; const int main_proc = 0; const int partition = 0; - const int use_occ_geometry = 0; + const int use_cad_geometry = 0; t8_cmesh_t cmesh; @@ -173,7 +173,7 @@ main (int argc, char **argv) sc_flops_start (&fi); sc_flops_snap (&fi, &snapshot); - cmesh = t8_cmesh_from_msh_file (meshfile, partition, sc_MPI_COMM_WORLD, dim, main_proc, use_occ_geometry); + cmesh = t8_cmesh_from_msh_file (meshfile, partition, sc_MPI_COMM_WORLD, dim, main_proc, use_cad_geometry); /* Measure passed time. */ sc_flops_shot (&fi, &snapshot); diff --git a/benchmarks/time_forest_partition.cxx b/benchmarks/time_forest_partition.cxx index b1362311bc..3b62cf19d9 100644 --- a/benchmarks/time_forest_partition.cxx +++ b/benchmarks/time_forest_partition.cxx @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -254,7 +254,7 @@ t8_time_forest_cmesh_mshfile (t8_cmesh_t cmesh, const char *vtu_prefix, sc_MPI_C snprintf (forest_vtu, BUFSIZ, "%s_forest_partition_%03d", vtu_prefix, time_step); snprintf (cmesh_vtu, BUFSIZ, "%s_cmesh_partition_%03d", vtu_prefix, time_step); t8_forest_write_vtk (forest_partition, forest_vtu); - t8_cmesh_vtk_write_file (t8_forest_get_cmesh (forest_partition), cmesh_vtu, 1.0); + t8_cmesh_vtk_write_file (t8_forest_get_cmesh (forest_partition), cmesh_vtu); t8_debugf ("Wrote partitioned forest and cmesh\n"); } if (cmesh_is_partitioned) { @@ -288,7 +288,7 @@ t8_time_forest_cmesh_mshfile (t8_cmesh_t cmesh, const char *vtu_prefix, sc_MPI_C * file and mesh_dim must be specified. */ t8_cmesh_t t8_time_forest_create_cmesh (const char *msh_file, int mesh_dim, const char *cmesh_file, int num_files, - sc_MPI_Comm comm, int init_level, int stride, int use_occ) + sc_MPI_Comm comm, int init_level, int stride, int use_cad) { t8_cmesh_t cmesh; t8_cmesh_t cmesh_partition; @@ -297,7 +297,7 @@ t8_time_forest_create_cmesh (const char *msh_file, int mesh_dim, const char *cme T8_ASSERT (msh_file == NULL || cmesh_file == NULL); if (msh_file != NULL) { - if (use_occ) { + if (use_cad) { partition = 0; t8_global_productionf ("The cmesh is not partitioned due to the usage of the curved mesh option. \n" "Timing will not be comparable to non-curved meshes. \n"); @@ -306,7 +306,7 @@ t8_time_forest_create_cmesh (const char *msh_file, int mesh_dim, const char *cme partition = 1; } /* Create a cmesh from the given mesh files */ - cmesh = t8_cmesh_from_msh_file ((char *) msh_file, partition, comm, mesh_dim, 0, use_occ); + cmesh = t8_cmesh_from_msh_file ((char *) msh_file, partition, comm, mesh_dim, 0, use_cad); } else { T8_ASSERT (cmesh_file != NULL); @@ -337,9 +337,9 @@ main (int argc, char *argv[]) int mpiret, mpisize; int first_argc; int level, level_diff; - int help = 0, no_vtk, do_ghost, do_balance, use_occ; + int help = 0, no_vtk, do_ghost, do_balance, use_cad; int dim, num_files; - int test_tet, test_linear_cylinder, test_occ_cylinder; + int test_tet, test_linear_cylinder, test_cad_cylinder; int stride; int cmesh_level; double T, delta_t, cfl; @@ -384,16 +384,16 @@ main (int argc, char *argv[]) "Use a cmesh that tests all tet face-to-face connections." " If this option is used -o is enabled automatically. Not allowed with -f and -c."); sc_options_add_switch (opt, 'L', "test-linear-cylinder", &test_linear_cylinder, - "Use a linear cmesh to compare linear and occ geometry performance." + "Use a linear cmesh to compare linear and cad geometry performance." " If this option is used -o is enabled automatically. Not allowed with -f and -c."); - sc_options_add_switch (opt, 'O', "test-occ-cylinder", &test_occ_cylinder, - "Use a occ cmesh to compare linear and occ geometry performance." + sc_options_add_switch (opt, 'O', "test-cad-cylinder", &test_cad_cylinder, + "Use a cad cmesh to compare linear and cad geometry performance." " If this option is used -o is enabled automatically. Not allowed with -f and -c."); sc_options_add_int (opt, 'l', "level", &level, 0, "The initial uniform refinement level of the forest."); sc_options_add_int (opt, 'r', "rlevel", &level_diff, 1, "The number of levels that the forest is refined from the initial level."); sc_options_add_int (opt, '\0', "cmesh-level", &cmesh_level, -1, - "Starting level of the linear or occ cmesh, default is 0. Only viable with -L or -O."); + "Starting level of the linear or cad cmesh, default is 0. Only viable with -L or -O."); sc_options_add_double (opt, 'x', "xmin", x_min_max, 0, "The minimum x coordinate in the mesh."); sc_options_add_double (opt, 'X', "xmax", x_min_max + 1, 1, "The maximum x coordinate in the mesh."); sc_options_add_double (opt, 'T', "time", &T, 1, @@ -406,20 +406,20 @@ main (int argc, char *argv[]) "Overwrites any other delta_t setting."); sc_options_add_switch (opt, 'g', "ghost", &do_ghost, "Create ghost elements."); sc_options_add_switch (opt, 'b', "balance", &do_balance, "Establish a 2:1 balance in the forest."); - sc_options_add_switch (opt, 'z', "use_occ", &use_occ, + sc_options_add_switch (opt, 'z', "use_cad", &use_cad, "If used, meshes will be curved to original geometries (msh- and brep-files necessary)."); /* parse command line options */ first_argc = sc_options_parse (t8_get_package_id (), SC_LP_DEFAULT, opt, argc, argv); /* check for wrong usage of arguments */ if (first_argc < 0 || first_argc != argc || dim < 2 || dim > 3 - || (cmeshfileprefix == NULL && mshfileprefix == NULL && test_tet == 0 && test_occ_cylinder == 0 + || (cmeshfileprefix == NULL && mshfileprefix == NULL && test_tet == 0 && test_cad_cylinder == 0 && test_linear_cylinder == 0) || stride <= 0 || (num_files - 1) * stride >= mpisize || cfl < 0 || T <= 0 - || test_tet + test_linear_cylinder + test_occ_cylinder > 1 - || (cmesh_level >= 0 && (!test_linear_cylinder && !test_occ_cylinder)) - || ((mshfileprefix != NULL || cmeshfileprefix != NULL) && (test_linear_cylinder || test_occ_cylinder || test_tet)) - || (mshfileprefix == NULL && use_occ)) { + || test_tet + test_linear_cylinder + test_cad_cylinder > 1 + || (cmesh_level >= 0 && (!test_linear_cylinder && !test_cad_cylinder)) + || ((mshfileprefix != NULL || cmeshfileprefix != NULL) && (test_linear_cylinder || test_cad_cylinder || test_tet)) + || (mshfileprefix == NULL && use_cad)) { sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); return 1; } @@ -438,25 +438,25 @@ main (int argc, char *argv[]) } t8_global_productionf ("Using delta_t = %f\n", delta_t); if (mshfileprefix != NULL) { - cmesh = t8_time_forest_create_cmesh (mshfileprefix, dim, NULL, -1, sc_MPI_COMM_WORLD, level, stride, use_occ); + cmesh = t8_time_forest_create_cmesh (mshfileprefix, dim, NULL, -1, sc_MPI_COMM_WORLD, level, stride, use_cad); vtu_prefix = mshfileprefix; } else if (test_tet) { cmesh = t8_cmesh_new_tet_orientation_test (sc_MPI_COMM_WORLD); vtu_prefix = "test_tet"; } - else if (test_linear_cylinder || test_occ_cylinder) { + else if (test_linear_cylinder || test_cad_cylinder) { if (cmesh_level < 0) { cmesh_level = 0; } cmesh = t8_cmesh_new_hollow_cylinder (sc_MPI_COMM_WORLD, 4 * sc_intpow (2, cmesh_level), - sc_intpow (2, cmesh_level), sc_intpow (2, cmesh_level), test_occ_cylinder); - test_linear_cylinder ? vtu_prefix = "test_linear_cylinder" : vtu_prefix = "test_occ_cylinder"; + sc_intpow (2, cmesh_level), sc_intpow (2, cmesh_level), test_cad_cylinder); + test_linear_cylinder ? vtu_prefix = "test_linear_cylinder" : vtu_prefix = "test_cad_cylinder"; } else { T8_ASSERT (cmeshfileprefix != NULL); cmesh - = t8_time_forest_create_cmesh (NULL, -1, cmeshfileprefix, num_files, sc_MPI_COMM_WORLD, level, stride, use_occ); + = t8_time_forest_create_cmesh (NULL, -1, cmeshfileprefix, num_files, sc_MPI_COMM_WORLD, level, stride, use_cad); vtu_prefix = cmeshfileprefix; } t8_time_forest_cmesh_mshfile (cmesh, vtu_prefix, sc_MPI_COMM_WORLD, level, level + level_diff, no_vtk, x_min_max, T, diff --git a/benchmarks/time_partition.cxx b/benchmarks/time_partition.cxx index a071353fbe..df5c8704bf 100644 --- a/benchmarks/time_partition.cxx +++ b/benchmarks/time_partition.cxx @@ -132,7 +132,7 @@ t8_time_cmesh_partition_brick (int x, int y, int z, sc_MPI_Comm comm, int no_vtk mpiret = sc_MPI_Comm_rank (comm, &mpirank); SC_CHECK_MPI (mpiret); - t8_cmesh_vtk_write_file (cmesh_partition, "cmesh_box_partition", 1.0); + t8_cmesh_vtk_write_file (cmesh_partition, "cmesh_box_partition"); } /* memory clean-up */ t8_cmesh_destroy (&cmesh_partition); diff --git a/doc/author_dutka.txt b/doc/author_dutka.txt new file mode 100644 index 0000000000..f2401f4078 --- /dev/null +++ b/doc/author_dutka.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Alexandre Dutka diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000000..a44b444a33 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,52 @@ +# Conditionally adding new sources to the main T8 target as in the original BS looked wrong... +add_library( t8example ) +target_sources( t8example PRIVATE common/t8_example_common.cxx common/t8_example_common_functions.cxx ) +target_include_directories( t8example PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) +target_link_libraries( t8example PRIVATE T8 ) +install( TARGETS t8example DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) + +function( add_t8_example ) + set( options "" ) + set( oneValueArgs "NAME" ) + set( multiValueArgs "SOURCES" ) + cmake_parse_arguments( ADD_T8_EXAMPLE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + add_executable( ${ADD_T8_EXAMPLE_NAME} ${ADD_T8_EXAMPLE_SOURCES} ) + target_link_libraries( ${ADD_T8_EXAMPLE_NAME} PRIVATE T8 t8example SC::SC ) + target_include_directories( ${ADD_T8_EXAMPLE_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) + + install( TARGETS ${ADD_T8_EXAMPLE_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/example ) +endfunction() + +add_t8_example( NAME t8_advection SOURCES advect/t8_advection.cxx ) + +add_t8_example( NAME t8_cmesh_partition SOURCES cmesh/t8_cmesh_partition.cxx ) +add_t8_example( NAME t8_cmesh_set_join_by_vertices SOURCES cmesh/t8_cmesh_set_join_by_vertices.cxx ) +add_t8_example( NAME t8_cmesh_geometry_examples SOURCES cmesh/t8_cmesh_geometry_examples.cxx ) +add_t8_example( NAME t8_cmesh_create_partitioned SOURCES cmesh/t8_cmesh_create_partitioned.cxx ) +add_t8_example( NAME t8_cmesh_hypercube_pad SOURCES cmesh/t8_cmesh_hypercube_pad.cxx ) + +add_t8_example( NAME t8_face_neighbor SOURCES forest/t8_face_neighbor.cxx ) +add_t8_example( NAME t8_test_ghost SOURCES forest/t8_test_ghost.cxx ) +add_t8_example( NAME t8_test_face_iterate SOURCES forest/t8_test_face_iterate.cxx ) +add_t8_example( NAME t8_test_ghost_large_level_diff SOURCES forest/t8_test_ghost_large_level_diff.cxx ) + +add_t8_example( NAME t8_example_geometries SOURCES geometry/t8_example_geometries.cxx ) + +add_t8_example( NAME t8_cmesh_load_save SOURCES IO/cmesh/t8_cmesh_load_save.cxx ) +add_t8_example( NAME t8_read_msh_file SOURCES IO/cmesh/gmsh/t8_read_msh_file.cxx ) +add_t8_example( NAME t8_load_and_refine_square_w_hole SOURCES IO/cmesh/gmsh/t8_load_and_refine_square_w_hole.cxx ) +add_t8_example( NAME t8_write_cmesh_netcdf SOURCES IO/cmesh/netcdf/t8_write_cmesh_netcdf.cxx ) +add_t8_example( NAME t8_read_tetgen SOURCES IO/cmesh/tetgen/t8_read_tetgen_file.cxx ) +add_t8_example( NAME t8_time_tetgen SOURCES IO/cmesh/tetgen/t8_time_tetgen_file.cxx ) +add_t8_example( NAME t8_forest_tetgen SOURCES IO/cmesh/tetgen/t8_forest_from_tetgen.cxx ) +add_t8_example( NAME t8_read_triangle SOURCES IO/cmesh/triangle/t8_read_triangle_file.cxx ) +add_t8_example( NAME t8_cmesh_read_from_vtk SOURCES IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx ) +add_t8_example( NAME t8_netcdf_compilation_status SOURCES IO/forest/netcdf/t8_netcdf_status.c ) +add_t8_example( NAME t8_write_forest_netcdf SOURCES IO/forest/netcdf/t8_write_forest_netcdf.cxx ) + +add_t8_example( NAME t8_example_spheres SOURCES remove/t8_example_spheres.cxx ) +add_t8_example( NAME t8_example_gauss_blob SOURCES remove/t8_example_gauss_blob.cxx ) +add_t8_example( NAME t8_example_empty_trees SOURCES remove/t8_example_empty_trees.cxx ) + +add_t8_example( NAME t8_version SOURCES version/t8_version.cxx ) \ No newline at end of file diff --git a/example/IO/cmesh/gmsh/t8_load_and_refine_square_w_hole.cxx b/example/IO/cmesh/gmsh/t8_load_and_refine_square_w_hole.cxx index 107c14bfdf..ffe4caa3f4 100644 --- a/example/IO/cmesh/gmsh/t8_load_and_refine_square_w_hole.cxx +++ b/example/IO/cmesh/gmsh/t8_load_and_refine_square_w_hole.cxx @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/example/IO/cmesh/gmsh/t8_read_msh_file.cxx b/example/IO/cmesh/gmsh/t8_read_msh_file.cxx index fc5b7d5566..0678e9e3ed 100644 --- a/example/IO/cmesh/gmsh/t8_read_msh_file.cxx +++ b/example/IO/cmesh/gmsh/t8_read_msh_file.cxx @@ -40,7 +40,7 @@ t8_read_msh_file_vtk (t8_cmesh_t cmesh, const char *prefix) SC_CHECK_MPI (mpiret); snprintf (fileprefix, BUFSIZ, "%s_t8_msh", prefix); - if (!t8_cmesh_vtk_write_file (cmesh, fileprefix, 1.)) { + if (!t8_cmesh_vtk_write_file (cmesh, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } else { diff --git a/example/IO/cmesh/t8_cmesh_load_save.cxx b/example/IO/cmesh/t8_cmesh_load_save.cxx index 0a949b9e6d..9a5e9ab0db 100644 --- a/example/IO/cmesh/t8_cmesh_load_save.cxx +++ b/example/IO/cmesh/t8_cmesh_load_save.cxx @@ -40,14 +40,14 @@ t8_cmesh_load_distribute (const char *fileprefix, int num_files, int no_vtk) else { t8_debugf ("Successfully loaded cmesh from %s files\n", fileprefix); if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh, "cmesh_dist_loaded", 1.0); + t8_cmesh_vtk_write_file (cmesh, "cmesh_dist_loaded"); } t8_cmesh_init (&cmesh_partition); t8_cmesh_set_derive (cmesh_partition, cmesh); t8_cmesh_set_partition_uniform (cmesh_partition, 0, t8_scheme_new_default_cxx ()); t8_cmesh_commit (cmesh_partition, sc_MPI_COMM_WORLD); if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh_partition, "cmesh_dist_loaded_partition", 1.0); + t8_cmesh_vtk_write_file (cmesh_partition, "cmesh_dist_loaded_partition"); } t8_cmesh_destroy (&cmesh_partition); } diff --git a/example/IO/cmesh/tetgen/t8_forest_from_tetgen.cxx b/example/IO/cmesh/tetgen/t8_forest_from_tetgen.cxx index 2658b72242..d56a7ed4cf 100644 --- a/example/IO/cmesh/tetgen/t8_forest_from_tetgen.cxx +++ b/example/IO/cmesh/tetgen/t8_forest_from_tetgen.cxx @@ -45,7 +45,7 @@ t8_cmesh_from_tetgen (const char *prefix, int do_partition) t8_debugf ("Successfully constructed cmesh from %s files.\n", prefix); t8_debugf ("cmesh has:\n\t%lli tetrahedra\n", (long long) t8_cmesh_get_num_trees (cmesh)); snprintf (fileprefix, BUFSIZ, "%s_t8_tetgen_%04d", prefix, mpirank); - if (!t8_cmesh_vtk_write_file (cmesh, fileprefix, 1.)) { + if (!t8_cmesh_vtk_write_file (cmesh, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } else { diff --git a/example/IO/cmesh/tetgen/t8_read_tetgen_file.cxx b/example/IO/cmesh/tetgen/t8_read_tetgen_file.cxx index 2ae0d27cd2..824722f64a 100644 --- a/example/IO/cmesh/tetgen/t8_read_tetgen_file.cxx +++ b/example/IO/cmesh/tetgen/t8_read_tetgen_file.cxx @@ -42,7 +42,7 @@ t8_read_tetgen_file_build_cmesh (const char *prefix, int do_dup, int do_partitio t8_debugf ("Successfully constructed cmesh from %s files.\n", prefix); t8_debugf ("cmesh has:\n\t%lli tetrahedra\n", (long long) t8_cmesh_get_num_trees (cmesh)); snprintf (fileprefix, BUFSIZ, "%s_t8_tetgen", prefix); - if (!t8_cmesh_vtk_write_file (cmesh, fileprefix, 1.)) { + if (!t8_cmesh_vtk_write_file (cmesh, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } else { @@ -60,7 +60,7 @@ t8_read_tetgen_file_build_cmesh (const char *prefix, int do_dup, int do_partitio t8_debugf ("Successfully partitioned %s.\n", "cmesh"); t8_debugf ("cmesh has:\n\t%li local tetrahedra\n", (long) t8_cmesh_get_num_local_trees (cmesh_partitioned)); snprintf (fileprefix, BUFSIZ, "%s_t8_tetgen_partitioned", prefix); - if (!t8_cmesh_vtk_write_file (cmesh_partitioned, fileprefix, 1.)) { + if (!t8_cmesh_vtk_write_file (cmesh_partitioned, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } else { diff --git a/example/IO/cmesh/tetgen/t8_time_tetgen_file.cxx b/example/IO/cmesh/tetgen/t8_time_tetgen_file.cxx index eeb6204b03..4540e706e5 100644 --- a/example/IO/cmesh/tetgen/t8_time_tetgen_file.cxx +++ b/example/IO/cmesh/tetgen/t8_time_tetgen_file.cxx @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/example/IO/cmesh/triangle/t8_read_triangle_file.cxx b/example/IO/cmesh/triangle/t8_read_triangle_file.cxx index d413bf99ce..b5ba185158 100644 --- a/example/IO/cmesh/triangle/t8_read_triangle_file.cxx +++ b/example/IO/cmesh/triangle/t8_read_triangle_file.cxx @@ -48,7 +48,7 @@ t8_read_triangle_file_build_cmesh (const char *prefix, int do_dup, int do_partit t8_cmesh_set_partition_uniform (cmesh_part, 1, t8_scheme_new_default_cxx ()); t8_cmesh_commit (cmesh_part, sc_MPI_COMM_WORLD); snprintf (fileprefix, BUFSIZ, "%s_t8_triangle_partition", prefix); - if (!t8_cmesh_vtk_write_file (cmesh_part, fileprefix, 1.0)) { + if (!t8_cmesh_vtk_write_file (cmesh_part, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } t8_cmesh_destroy (&cmesh_part); @@ -56,7 +56,7 @@ t8_read_triangle_file_build_cmesh (const char *prefix, int do_dup, int do_partit t8_debugf ("Successfully constructed cmesh from %s files.\n", prefix); t8_debugf ("cmesh has:\n\t%lli triangles\n", (long long) t8_cmesh_get_num_trees (cmesh)); snprintf (fileprefix, BUFSIZ, "%s_t8_triangle", prefix); - if (!t8_cmesh_vtk_write_file (cmesh, fileprefix, 1.)) { + if (!t8_cmesh_vtk_write_file (cmesh, fileprefix)) { t8_debugf ("Wrote to file %s\n", fileprefix); } else { 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 a328edad3a..392a7829b5 100644 --- a/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx +++ b/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx @@ -49,7 +49,7 @@ t8_forest_construct_from_vtk (const char *prefix, sc_MPI_Comm comm, const int va } char out_file[BUFSIZ]; snprintf (out_file, BUFSIZ - 9, "%s_cmesh_in", out_prefix); - t8_cmesh_vtk_write_file (cmesh_in, out_file, 1.0); + t8_cmesh_vtk_write_file (cmesh_in, out_file); t8_cmesh_t cmesh; if (partition) { @@ -58,7 +58,7 @@ t8_forest_construct_from_vtk (const char *prefix, sc_MPI_Comm comm, const int va t8_cmesh_set_partition_uniform (cmesh, 0, t8_scheme_new_default_cxx ()); t8_cmesh_commit (cmesh, comm); snprintf (out_file, BUFSIZ - 16, "%s_cmesh_partition", out_prefix); - t8_cmesh_vtk_write_file (cmesh, out_file, 1.0); + t8_cmesh_vtk_write_file (cmesh, out_file); } else { cmesh = cmesh_in; diff --git a/example/advect/t8_advection.cxx b/example/advect/t8_advection.cxx index c6259df6b8..1855ba3386 100644 --- a/example/advect/t8_advection.cxx +++ b/example/advect/t8_advection.cxx @@ -834,16 +834,16 @@ t8_advect_problem_partition (t8_advect_problem_t *problem, int measure_time) } static t8_cmesh_t -t8_advect_create_cmesh (sc_MPI_Comm comm, int cube_type, const char *mshfile, int level, int dim, int use_occ_geometry) +t8_advect_create_cmesh (sc_MPI_Comm comm, int cube_type, const char *mshfile, int level, int dim, int use_cad_geometry) { if (mshfile != NULL) { /* Load from .msh file and partition */ t8_cmesh_t cmesh, cmesh_partition; T8_ASSERT (mshfile != NULL); - cmesh = t8_cmesh_from_msh_file (mshfile, 0, comm, dim, 0, use_occ_geometry); - /* The partitioning of the occ geometry is not yet available */ - if (use_occ_geometry) { + cmesh = t8_cmesh_from_msh_file (mshfile, 0, comm, dim, 0, use_cad_geometry); + /* The partitioning of the cad geometry is not yet available */ + if (use_cad_geometry) { t8_productionf ("cmesh was not partitioned. Partitioning is not yet " "available with the curved geometry\n"); return cmesh; @@ -1489,7 +1489,7 @@ main (int argc, char *argv[]) int level, reflevel, dim, cube_type, dummy_op; int parsed, helpme, no_vtk, vtk_freq, adapt_freq; int volume_refine; - int flow_arg, use_occ_geometry; + int flow_arg, use_cad_geometry; double T, cfl, band_width; t8_levelset_sphere_data_t ls_data; /* brief help message */ @@ -1546,8 +1546,8 @@ main (int argc, char *argv[]) "and be in ASCII format version 2. -d must be specified."); sc_options_add_int (opt, 'd', "dim", &dim, -1, "In combination with -f: The dimension of the mesh. 1 <= d <= 3."); - sc_options_add_switch (opt, 'O', "occ", &use_occ_geometry, - "In combination with -f: Use the occ geometry, only viable if a " + sc_options_add_switch (opt, 'O', "cad", &use_cad_geometry, + "In combination with -f: Use the cad geometry, only viable if a " ".brep file of the same name is present."); sc_options_add_double (opt, 'T', "end-time", &T, 1, "The duration of the simulation. Default: 1"); @@ -1628,10 +1628,10 @@ main (int argc, char *argv[]) ls_data.M[1] = ls_data.M[2] = 0; } - cmesh = t8_advect_create_cmesh (sc_MPI_COMM_WORLD, cube_type, mshfile, level, dim, use_occ_geometry); + cmesh = t8_advect_create_cmesh (sc_MPI_COMM_WORLD, cube_type, mshfile, level, dim, use_cad_geometry); u = t8_advect_choose_flow (flow_arg); if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh, "advection_cmesh", 1.0); + t8_cmesh_vtk_write_file (cmesh, "advection_cmesh"); } /* Computation */ t8_advect_solve (cmesh, u, t8_levelset_sphere, &ls_data, level, level + reflevel, T, cfl, sc_MPI_COMM_WORLD, diff --git a/example/cmesh/t8_cmesh_geometry_examples.cxx b/example/cmesh/t8_cmesh_geometry_examples.cxx index d2064bcabc..c11b092b81 100644 --- a/example/cmesh/t8_cmesh_geometry_examples.cxx +++ b/example/cmesh/t8_cmesh_geometry_examples.cxx @@ -114,7 +114,7 @@ main (int argc, char **argv) t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); - t8_cmesh_vtk_write_file (cmesh, prefix_cmesh, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); t8_global_productionf ("Wrote %s.\n", prefix_cmesh); t8_write_forest_to_vtu (forest, prefix_forest); @@ -124,17 +124,37 @@ main (int argc, char **argv) } { - const char *prefix_cmesh = "t8_triangulated_spherical_surface_cmesh"; - const char *prefix_forest = "t8_triangulated_spherical_surface_forest"; + const char *prefix_cmesh = "t8_triangulated_spherical_surface_octahedron_cmesh"; + const char *prefix_forest = "t8_triangulated_spherical_surface_octahedron_forest"; const int uniform_level = 5; - const double radius = 1.0; + const double radius = 42.0; + + t8_cmesh_t cmesh = t8_cmesh_new_triangulated_spherical_surface_octahedron (radius, comm); + + t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); + + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); + t8_global_productionf ("Wrote %s.\n", prefix_cmesh); + + t8_write_forest_to_vtu (forest, prefix_forest); + t8_global_productionf ("Wrote %s.\n\n", prefix_forest); + + t8_forest_unref (&forest); + } - t8_cmesh_t cmesh = t8_cmesh_new_triangulated_spherical_surface (radius, comm); + { + const char *prefix_cmesh = "t8_triangulated_spherical_surface_icosahedron_cmesh"; + const char *prefix_forest = "t8_triangulated_spherical_surface_icosahedron_forest"; + + const int uniform_level = 5; + const double radius = 42.0; + + t8_cmesh_t cmesh = t8_cmesh_new_triangulated_spherical_surface_icosahedron (radius, comm); t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); - t8_cmesh_vtk_write_file (cmesh, prefix_cmesh, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); t8_global_productionf ("Wrote %s.\n", prefix_cmesh); t8_write_forest_to_vtu (forest, prefix_forest); @@ -148,13 +168,13 @@ main (int argc, char **argv) const char *prefix_forest = "t8_quadrangulated_spherical_surface_forest"; const int uniform_level = 5; - const double radius = 1.0; + const double radius = 42.0; t8_cmesh_t cmesh = t8_cmesh_new_quadrangulated_spherical_surface (radius, comm); t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); - t8_cmesh_vtk_write_file (cmesh, prefix_cmesh, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); t8_global_productionf ("Wrote %s.\n", prefix_cmesh); t8_write_forest_to_vtu (forest, prefix_forest); @@ -168,8 +188,10 @@ main (int argc, char **argv) const char *prefix_forest = "t8_cubed_spherical_shell_forest"; const int uniform_level = 1; - constexpr double inner_radius = std::sqrt (3); - const double shell_thickness = 0.2; + + const double inner_radius = 42.0; + const double shell_thickness = 5.0; + const int num_levels = 3; const int num_layers = 2; @@ -177,7 +199,55 @@ main (int argc, char **argv) t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); - t8_cmesh_vtk_write_file (cmesh, prefix_cmesh, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); + t8_global_productionf ("Wrote %s.\n", prefix_cmesh); + + t8_write_forest_to_vtu (forest, prefix_forest); + t8_global_productionf ("Wrote %s.\n\n", prefix_forest); + + t8_forest_unref (&forest); + } + + { + const char *prefix_cmesh = "t8_prismed_spherical_shell_octahedron_cmesh"; + const char *prefix_forest = "t8_prismed_spherical_shell_octahedron_forest"; + + const int uniform_level = 3; + const double inner_radius = 42.0; + const double shell_thickness = 5.0; + const int num_levels = 2; + const int num_layers = 1; + + t8_cmesh_t cmesh + = t8_cmesh_new_prismed_spherical_shell_octahedron (inner_radius, shell_thickness, num_levels, num_layers, comm); + + t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); + + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); + t8_global_productionf ("Wrote %s.\n", prefix_cmesh); + + t8_write_forest_to_vtu (forest, prefix_forest); + t8_global_productionf ("Wrote %s.\n\n", prefix_forest); + + t8_forest_unref (&forest); + } + + { + const char *prefix_cmesh = "t8_prismed_spherical_shell_icosahedron_cmesh"; + const char *prefix_forest = "t8_prismed_spherical_shell_icosahedron_forest"; + + const int uniform_level = 3; + const double inner_radius = 42.0; + const double shell_thickness = 5.0; + const int num_levels = 2; + const int num_layers = 1; + + t8_cmesh_t cmesh + = t8_cmesh_new_prismed_spherical_shell_icosahedron (inner_radius, shell_thickness, num_levels, num_layers, comm); + + t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), uniform_level, 0, comm); + + t8_cmesh_vtk_write_file (cmesh, prefix_cmesh); t8_global_productionf ("Wrote %s.\n", prefix_cmesh); t8_write_forest_to_vtu (forest, prefix_forest); diff --git a/example/cmesh/t8_cmesh_hypercube_pad.cxx b/example/cmesh/t8_cmesh_hypercube_pad.cxx index 3e8239a653..9615ae2969 100644 --- a/example/cmesh/t8_cmesh_hypercube_pad.cxx +++ b/example/cmesh/t8_cmesh_hypercube_pad.cxx @@ -55,7 +55,7 @@ main (int argc, char **argv) t8_global_productionf (" [step1] Local number of trees:\t%i\n", local_num_trees); t8_global_productionf (" [step1] Global number of trees:\t%li\n", global_num_trees); - t8_cmesh_vtk_write_file (cmesh, prefix, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix); t8_cmesh_destroy (&cmesh); diff --git a/example/cmesh/t8_cmesh_partition.cxx b/example/cmesh/t8_cmesh_partition.cxx index 069f4e3836..67bdef72c1 100644 --- a/example/cmesh/t8_cmesh_partition.cxx +++ b/example/cmesh/t8_cmesh_partition.cxx @@ -49,7 +49,7 @@ t8_random_partition (int level) cmesh = t8_cmesh_new_from_p8est (conn, sc_MPI_COMM_WORLD, 1); p8est_connectivity_destroy (conn); snprintf (file, BUFSIZ, "t8_brick_random"); - t8_cmesh_vtk_write_file (cmesh, file, 1.); + t8_cmesh_vtk_write_file (cmesh, file); t8_cmesh_init (&cmesh_part); @@ -70,14 +70,14 @@ t8_random_partition (int level) t8_cmesh_commit (cmesh_part2, sc_MPI_COMM_WORLD); snprintf (file, BUFSIZ, "t8_brick_partition_random2"); - t8_cmesh_vtk_write_file (cmesh_part2, file, 1.0); + t8_cmesh_vtk_write_file (cmesh_part2, file); } else { cmesh_part2 = cmesh_part; t8_cmesh_ref (cmesh_part); } snprintf (file, BUFSIZ, "t8_brick_partition_random"); - t8_cmesh_vtk_write_file (cmesh_part, file, 1.0); + t8_cmesh_vtk_write_file (cmesh_part, file); t8_cmesh_destroy (&cmesh); t8_cmesh_unref (&cmesh_part); t8_cmesh_destroy (&cmesh_part2); @@ -106,7 +106,7 @@ t8_partition (int level, int partition_from) cmesh = t8_cmesh_new_from_p4est (conn, sc_MPI_COMM_WORLD, partition_from); p4est_connectivity_destroy (conn); snprintf (file, BUFSIZ, "t8_brick"); - t8_cmesh_vtk_write_file (cmesh, file, 1.); + t8_cmesh_vtk_write_file (cmesh, file); t8_cmesh_init (&cmesh_part); /* We still need access to cmesh later */ @@ -123,14 +123,14 @@ t8_partition (int level, int partition_from) t8_cmesh_offset_concentrate (1, sc_MPI_COMM_WORLD, t8_cmesh_get_num_trees (cmesh))); t8_cmesh_commit (cmesh_part2, sc_MPI_COMM_WORLD); snprintf (file, BUFSIZ, "t8_brick_partition2"); - t8_cmesh_vtk_write_file (cmesh_part2, file, 1.0); + t8_cmesh_vtk_write_file (cmesh_part2, file); } else { cmesh_part2 = cmesh_part; t8_cmesh_ref (cmesh_part); } snprintf (file, BUFSIZ, "t8_brick_partition"); - t8_cmesh_vtk_write_file (cmesh_part, file, 1.0); + t8_cmesh_vtk_write_file (cmesh_part, file); t8_cmesh_destroy (&cmesh); t8_cmesh_unref (&cmesh_part); t8_cmesh_destroy (&cmesh_part2); diff --git a/example/cmesh/t8_cmesh_set_join_by_vertices.cxx b/example/cmesh/t8_cmesh_set_join_by_vertices.cxx index 7673dcd02d..82a7708078 100644 --- a/example/cmesh/t8_cmesh_set_join_by_vertices.cxx +++ b/example/cmesh/t8_cmesh_set_join_by_vertices.cxx @@ -197,10 +197,10 @@ main (int argc, char **argv) const int dim = 3; const int main_proc = 0; const int partition = 0; - const int use_occ_geometry = 0; + const int use_cad_geometry = 0; t8_cmesh_t cmesh - = t8_cmesh_from_msh_file (meshfile, partition, sc_MPI_COMM_WORLD, dim, main_proc, use_occ_geometry); + = t8_cmesh_from_msh_file (meshfile, partition, sc_MPI_COMM_WORLD, dim, main_proc, use_cad_geometry); test_with_cmesh (cmesh); diff --git a/example/forest/t8_test_face_iterate.cxx b/example/forest/t8_test_face_iterate.cxx index 20a66b21d0..07262f5444 100644 --- a/example/forest/t8_test_face_iterate.cxx +++ b/example/forest/t8_test_face_iterate.cxx @@ -92,7 +92,7 @@ t8_test_fiterate (t8_forest_t forest) = t8_forest_get_element_in_tree (forest, itree, t8_forest_get_tree_num_elements (forest, itree) - 1); ts->t8_element_new (1, &nca); ts->t8_element_nca (first_el, last_el, nca); - leaf_elements = t8_forest_tree_get_leafs (forest, itree); + leaf_elements = t8_forest_tree_get_leaves (forest, itree); for (iface = 0; iface < ts->t8_element_num_faces (nca); iface++) { udata.count = 0; @@ -110,7 +110,7 @@ t8_test_fiterate_refine_and_partition (t8_cmesh_t cmesh, int level, sc_MPI_Comm t8_cmesh_t cmesh_partition; if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh, "test_fiterate_cmesh0", 1.0); + t8_cmesh_vtk_write_file (cmesh, "test_fiterate_cmesh0"); } if (partition_cmesh) { /* partition the initial cmesh according to a uniform forest */ @@ -124,7 +124,7 @@ t8_test_fiterate_refine_and_partition (t8_cmesh_t cmesh, int level, sc_MPI_Comm cmesh_partition = cmesh; } if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh_partition, "test_fiterate_cmesh1", 1.0); + t8_cmesh_vtk_write_file (cmesh_partition, "test_fiterate_cmesh1"); } forest = t8_forest_new_uniform (cmesh_partition, t8_scheme_new_default_cxx (), level, 0, comm); diff --git a/example/forest/t8_test_ghost.cxx b/example/forest/t8_test_ghost.cxx index bcfb64babb..ef07d0dc84 100644 --- a/example/forest/t8_test_ghost.cxx +++ b/example/forest/t8_test_ghost.cxx @@ -119,7 +119,7 @@ t8_test_ghost_refine_and_partition (t8_cmesh_t cmesh, const int level, sc_MPI_Co t8_forest_adapt_t adapt_fn; if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh, "test_ghost_cmesh0", 1.0); + t8_cmesh_vtk_write_file (cmesh, "test_ghost_cmesh0"); } if (partition_cmesh) { /* partition the initial cmesh according to a uniform forest */ @@ -133,7 +133,7 @@ t8_test_ghost_refine_and_partition (t8_cmesh_t cmesh, const int level, sc_MPI_Co cmesh_partition = cmesh; } if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh_partition, "test_ghost_cmesh1", 1.0); + t8_cmesh_vtk_write_file (cmesh_partition, "test_ghost_cmesh1"); } forest = t8_forest_new_uniform (cmesh_partition, t8_scheme_new_default_cxx (), level, 1, comm); diff --git a/example/forest/t8_test_ghost_large_level_diff.cxx b/example/forest/t8_test_ghost_large_level_diff.cxx index 2368a14d00..787dcb565c 100644 --- a/example/forest/t8_test_ghost_large_level_diff.cxx +++ b/example/forest/t8_test_ghost_large_level_diff.cxx @@ -145,7 +145,7 @@ t8_ghost_large_level_diff (const char *prefix, int dim, int level, int refine, i t8_cmesh_set_partition_uniform (cmesh_partition, level, t8_scheme_new_default_cxx ()); t8_cmesh_commit (cmesh_partition, comm); if (!no_vtk) { - t8_cmesh_vtk_write_file (cmesh_partition, "partitioned_cmesh", 1.0); + t8_cmesh_vtk_write_file (cmesh_partition, "partitioned_cmesh"); } /* New */ diff --git a/example/geometry/t8_example_geometries.cxx b/example/geometry/t8_example_geometries.cxx index 1922b350ea..a8ab9f7f8d 100644 --- a/example/geometry/t8_example_geometries.cxx +++ b/example/geometry/t8_example_geometries.cxx @@ -26,9 +26,10 @@ #include #include #include -#include +#include #include -#include +#include +#include #include #include @@ -63,10 +64,11 @@ typedef enum { T8_GEOM_CIRCLE, T8_GEOM_3D, T8_GEOM_MOVING, - T8_GEOM_OCC_TRIANGLE, - T8_GEOM_OCC_CURVE_CUBE, - T8_GEOM_OCC_SURFACE_CUBES, - T8_GEOM_OCC_SURFACE_CYLINDER, + T8_GEOM_ANALYTIC_QUAD_TO_SPHERE, + T8_GEOM_CAD_TRIANGLE, + T8_GEOM_CAD_CURVE_CUBE, + T8_GEOM_CAD_SURFACE_CUBES, + T8_GEOM_CAD_SURFACE_CYLINDER, T8_GEOM_COUNT } t8_example_geom_type; @@ -510,6 +512,23 @@ t8_geom_adapt_boundary (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t return 0; } +void +quad_to_sphere_callback (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + double *out_coords, const void *tree_data, const void *user_data) +{ + for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { + const size_t offset = 3 * i_coord; + + const double radius = 1.0; + const double latitude = 2 * M_PI * ref_coords[offset + 0]; + const double longitude = ref_coords[offset + 1] * M_PI; + + out_coords[offset + 0] = radius * sin (longitude) * cos (latitude); + out_coords[offset + 1] = radius * sin (longitude) * sin (latitude); + out_coords[offset + 2] = radius * cos (longitude); + } +} + static void t8_analytic_geom (int level, t8_example_geom_type geom_type) { @@ -595,12 +614,21 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); snprintf (vtuname, BUFSIZ, "forest_moving_lvl_%i", level); break; - case T8_GEOM_OCC_TRIANGLE: { + case T8_GEOM_ANALYTIC_QUAD_TO_SPHERE: + t8_global_productionf ("Wrapping a quad around a sphere.\n"); + + geometry = new t8_geometry_analytic (3, "geom_quad_to_sphere", quad_to_sphere_callback, NULL, NULL, NULL); + t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_QUAD); + t8_cmesh_set_join (cmesh, 0, 0, 1, 0, 0); + + snprintf (vtuname, BUFSIZ, "forest_quad_to_sphere"); + break; + case T8_GEOM_CAD_TRIANGLE: { #if T8_WITH_OCC - t8_global_productionf ("Creating uniform level %i forests with an occ triangle geometry.\n", level); + t8_global_productionf ("Creating uniform level %i forests with an cad triangle geometry.\n", level); /* Constructing a triangle with one curved edge (f2) */ - Handle_Geom_BSplineCurve occ_curve; + Handle_Geom_BSplineCurve cad_curve; TColgp_Array1OfPnt point_array (1, 3); TopoDS_Shape shape; @@ -610,17 +638,17 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) point_array (3) = gp_Pnt (1.0, 2.0, 0.0); /* Generate bsplines from arrays. */ - occ_curve = GeomAPI_PointsToBSpline (point_array).Curve (); + cad_curve = GeomAPI_PointsToBSpline (point_array).Curve (); /* Fill shape with bsplines so that we can create a geometry with this shape. */ - shape = BRepBuilderAPI_MakeEdge (occ_curve).Edge (); + shape = BRepBuilderAPI_MakeEdge (cad_curve).Edge (); - /* Create an occ geometry. */ - t8_geometry_occ *geometry_occ = new t8_geometry_occ (3, shape, "occ curve dim=3"); + /* Create an cad geometry. */ + t8_geometry_cad *geometry_cad = new t8_geometry_cad (3, shape, "cad curve dim=3"); /* The arrays indicate which face/edge carries a geometry. * 0 means no geometry and any other number indicates the position of the geometry - * in the global geometry array. Here edge 1 carries the created occ_curve. */ + * in the global geometry array. Here edge 1 carries the created cad_curve. */ int faces[1] = { 0 }; int edges[6] = { 0, 1, 0, 0, 0, 0 }; /* Create tree 0 */ @@ -633,28 +661,28 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Give the tree information about its curves and the parameters of the vertices. * Each parameter set is given to the tree via its attribute key + the edge or face index it corresponds with. */ - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 1 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 1 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 6 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + 1, + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + 1, parameters_edge, 2 * sizeof (double), 0); - geometry = geometry_occ; - snprintf (vtuname, BUFSIZ, "forest_occ_triangle_lvl_%i", level); + geometry = geometry_cad; + snprintf (vtuname, BUFSIZ, "forest_cad_triangle_lvl_%i", level); break; #else /* !T8_WITH_OCC */ SC_ABORTF ("OCC not linked"); #endif /* T8_WITH_OCC */ } - case T8_GEOM_OCC_CURVE_CUBE: { + case T8_GEOM_CAD_CURVE_CUBE: { #if T8_WITH_OCC - t8_global_productionf ("Creating uniform level %i forests with occ curve geometries.\n", level); + t8_global_productionf ("Creating uniform level %i forests with cad curve geometries.\n", level); - /* Create two occ bsplines which oscillate along the x-axis. + /* Create two cad bsplines which oscillate along the x-axis. * For this we need to define two arrays from which we create the bsplines. */ - Handle_Geom_Curve occ_curve0; - Handle_Geom_Curve occ_curve1; + Handle_Geom_Curve cad_curve0; + Handle_Geom_Curve cad_curve1; TColgp_Array1OfPnt point_array0 (1, 5); TColgp_Array1OfPnt point_array1 (1, 5); TopoDS_Shape shape; @@ -673,19 +701,19 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) point_array1 (5) = gp_Pnt (1, 1, 1); /* Generate bsplines from arrays. */ - occ_curve0 = GeomAPI_PointsToBSpline (point_array0).Curve (); - occ_curve1 = GeomAPI_PointsToBSpline (point_array1).Curve (); + cad_curve0 = GeomAPI_PointsToBSpline (point_array0).Curve (); + cad_curve1 = GeomAPI_PointsToBSpline (point_array1).Curve (); /* Fill shape with bsplines so that we can create a geometry with this shape. */ - shape = BRepBuilderAPI_MakeEdge (occ_curve0).Edge (); - shape = BRepAlgoAPI_Fuse (shape, BRepBuilderAPI_MakeEdge (occ_curve1).Edge ()); + shape = BRepBuilderAPI_MakeEdge (cad_curve0).Edge (); + shape = BRepAlgoAPI_Fuse (shape, BRepBuilderAPI_MakeEdge (cad_curve1).Edge ()); - /* Create an occ geometry. */ - t8_geometry_occ *geometry_occ = new t8_geometry_occ (3, shape, "occ curve dim=3"); + /* Create an cad geometry. */ + t8_geometry_cad *geometry_cad = new t8_geometry_cad (3, shape, "cad curve dim=3"); /* The arrays indicate which face/edge carries a geometry. * 0 means no geometry and any other number indicates the position of the geometry - * in the global geometry array. Here edge 0 carries occ_curve0 and edge 3 carries occ_curve1. + * in the global geometry array. Here edge 0 carries cad_curve0 and edge 3 carries cad_curve1. * We add them in the next step. */ int faces[6] = { 0, 0, 0, 0, 0, 0 }; int edges[24] = { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -701,28 +729,28 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Give the tree information about its curves and the parameters of the vertices. * Each parameter set is given to the tree via its attribute key + the edge or face index it corresponds with. */ - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + 0, parameters, + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + 0, parameters, 2 * sizeof (double), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + 3, parameters, + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + 3, parameters, 2 * sizeof (double), 0); - geometry = geometry_occ; - snprintf (vtuname, BUFSIZ, "forest_occ_curve_cube_lvl_%i", level); + geometry = geometry_cad; + snprintf (vtuname, BUFSIZ, "forest_cad_curve_cube_lvl_%i", level); break; -#else /* !T8_WITH_OCC */ +#else /* !T8_WITH_cad */ SC_ABORTF ("OCC not linked"); -#endif /* T8_WITH_OCC */ +#endif /* T8_WITH_cad */ } - case T8_GEOM_OCC_SURFACE_CUBES: { + case T8_GEOM_CAD_SURFACE_CUBES: { #if T8_WITH_OCC - t8_global_productionf ("Creating uniform level %i forests with a occ surface geometry.\n", level); + t8_global_productionf ("Creating uniform level %i forests with a cad surface geometry.\n", level); - /* Create a occ bspline surface with 2D array of knots */ - Handle_Geom_Surface occ_surface; + /* Create a cad bspline surface with 2D array of knots */ + Handle_Geom_Surface cad_surface; TColgp_Array2OfPnt point_array (1, 5, 1, 3); TopoDS_Shape shape; @@ -772,8 +800,8 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Generate bspline surface from array and fill shape with it * so that we can create a geometry with this shape. */ - occ_surface = GeomAPI_PointsToBSplineSurface (point_array).Surface (); - shape = BRepBuilderAPI_MakeFace (occ_surface, 1e-6).Face (); + cad_surface = GeomAPI_PointsToBSplineSurface (point_array).Surface (); + shape = BRepBuilderAPI_MakeFace (cad_surface, 1e-6).Face (); /* The arrays indicate which face/edge carries a geometry. * 0 means no geometry and any other number indicates the position of the geometry @@ -782,8 +810,8 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) int faces[6] = { 0, 0, 0, 0, 0, 1 }; int edges[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - /* Create occ geometry. */ - t8_geometry_occ *geometry_occ = new t8_geometry_occ (3, shape, "occ surface dim=3"); + /* Create cad geometry. */ + t8_geometry_cad *geometry_cad = new t8_geometry_cad (3, shape, "cad surface dim=3"); /* Create tree 0 */ t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_HEX); @@ -802,11 +830,11 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Give tree 0 information about its surface and the parameters of the vertices. * Each parameter set is given to the tree via its attribute key + the edge or face index it corresponds with. */ - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 5, parameters0, + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 5, parameters0, 8 * sizeof (double), 0); /* Create tree 1 */ @@ -826,28 +854,28 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Give tree 1 information about its surface and the parameters of the vertices. * Each parameter set is given to the tree via its attribute key + the edge or face index it corresponds with. * We can use the same edges and faces array, because we link the surface to the same face on tree 1. */ - t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), + t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 5, parameters1, + t8_cmesh_set_attribute (cmesh, 1, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 5, parameters1, 8 * sizeof (double), 0); /* Join tree 0 and tree 1 together */ t8_cmesh_set_join (cmesh, 0, 1, 1, 0, 0); - geometry = geometry_occ; - snprintf (vtuname, BUFSIZ, "forest_occ_surface_cubes_lvl_%i", level); + geometry = geometry_cad; + snprintf (vtuname, BUFSIZ, "forest_cad_surface_cubes_lvl_%i", level); break; #else /* !T8_WITH_OCC */ SC_ABORTF ("OCC not linked"); #endif /* T8_WITH_OCC */ } - case T8_GEOM_OCC_SURFACE_CYLINDER: { + case T8_GEOM_CAD_SURFACE_CYLINDER: { #if T8_WITH_OCC - t8_global_productionf ("Creating uniform level %i forests with an occ cylinder geometry.\n", level); + t8_global_productionf ("Creating uniform level %i forests with an cad cylinder geometry.\n", level); - /* Create occ cylinder surfaces. We use an outer radius of 0.5 to get a diameter of 1. */ + /* Create cad cylinder surfaces. We use an outer radius of 0.5 to get a diameter of 1. */ double radius_inner = 0.25; double radius_outer = 0.5; @@ -880,8 +908,8 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) int faces[6] = { 1, 2, 0, 0, 0, 0 }; int edges[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - /* Create occ geometry. */ - t8_geometry_occ *geometry_occ = new t8_geometry_occ (3, shape, "occ surface dim=3"); + /* Create cad geometry. */ + t8_geometry_cad *geometry_cad = new t8_geometry_cad (3, shape, "cad surface dim=3"); /* Create corresponding trees and parameters. * Here we create num trees by a coordinate transformation from cylinder to cartesian coordinates. */ @@ -932,24 +960,24 @@ t8_analytic_geom (int level, t8_example_geom_type geom_type) /* Give the trees information about their surfaces and the parameters of the vertices. * Each parameter set is given to the tree via its attribute key + face index it corresponds with. * We can use the same edges and faces array, because we link the surface to the same faces on every tree.*/ - t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), + t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 1); - t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), + t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 1); - t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, + t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, parameters + i * 8, 8 * sizeof (double), 0); - t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, + t8_cmesh_set_attribute (cmesh, i, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, parameters + i * 8, 8 * sizeof (double), 0); } - geometry = geometry_occ; + geometry = geometry_cad; T8_FREE (vertices); T8_FREE (parameters); snprintf (vtuname, BUFSIZ, "forest_geometry_cylinder_lvl_%i", level); break; -#else /* !T8_WITH_OCC */ +#else /* !T8_WITH_cad */ SC_ABORTF ("OCC not linked"); -#endif /* T8_WITH_OCC */ +#endif /* T8_WITH_cad */ } default: SC_ABORT_NOT_REACHED (); @@ -1066,10 +1094,11 @@ main (int argc, char **argv) "\t\t The mesh will not be uniform. Instead it is refined at the domain boundary.\n" "\t\t5 - A cube that is distorted in z-direction with one 3D cube tree.\n" "\t\t6 - A moving mesh consisting of a single 2D quad tree.\n" - "\t\t7 - A curved triangle with an occ curve.\n" - "\t\t8 - A cube with two occ curves as edges.\n" - "\t\t9 - Two cubes with one occ surface as face.\n" - "\t\t10 - A hollow cylinder with a occ surface on the in- and outside.\n"); + "\t\t7 - A quad morphed into a sphere.\n" + "\t\t8 - A curved triangle with an cad curve.\n" + "\t\t9 - A cube with two cad curves as edges.\n" + "\t\t10 - Two cubes with one cad surface as face.\n" + "\t\t11 - A hollow cylinder with a cad surface on the in- and outside.\n"); parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); if (helpme) { diff --git a/example/remove/t8_example_empty_trees.cxx b/example/remove/t8_example_empty_trees.cxx index ca03fe0b5f..9aac0dce47 100644 --- a/example/remove/t8_example_empty_trees.cxx +++ b/example/remove/t8_example_empty_trees.cxx @@ -50,10 +50,10 @@ t8_strip_of_quads (t8_gloidx_t num_trees, t8_gloidx_t empty_tree, const char **v { const double boundary_coords[12] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0 }; - const t8_geometry_c *geometry = t8_geometry_linear_axis_aligned_new (2); + const int use_axis_alined = 1; t8_cmesh_t cmesh - = t8_cmesh_new_hypercube_pad (T8_ECLASS_QUAD, sc_MPI_COMM_WORLD, boundary_coords, num_trees, 1, 0, geometry); + = t8_cmesh_new_hypercube_pad (T8_ECLASS_QUAD, sc_MPI_COMM_WORLD, boundary_coords, num_trees, 1, 0, use_axis_alined); t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), 0, 0, sc_MPI_COMM_WORLD); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..86961ac219 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,203 @@ +if ( ${T8CODE_BUILD_AS_SHARED_LIBRARY} ) + add_library( T8 SHARED ) + set_target_properties( T8 PROPERTIES POSITION_INDEPENDENT_CODE ON ) +else() + add_library( T8 STATIC ) +endif() + +set_target_properties( T8 PROPERTIES OUTPUT_NAME t8 ) + +target_compile_definitions( T8 PUBLIC T8_CMAKE_BUILD ) +target_compile_definitions( T8 PUBLIC T8_CC="${CMAKE_C_COMPILER}" ) +target_compile_definitions( T8 PUBLIC T8_CFLAGS="${CMAKE_C_FLAGS}" ) +target_compile_definitions( T8 PUBLIC T8_CPP="${CMAKE_CXX_COMPILER}" ) +target_compile_definitions( T8 PUBLIC T8_CPPFLAGS="${CMAKE_CXX_FLAGS}" ) +target_compile_definitions( T8 PUBLIC T8_LDFLAGS="${CMAKE_SHARED_LINKER_FLAGS}" ) +target_compile_definitions( T8 PUBLIC T8_LIBS="Not available with CMake builds" ) + + +find_package( Git REQUIRED ) +execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags + COMMAND cut -c 2- + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + OUTPUT_VARIABLE T8CODE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE ) +execute_process( COMMAND echo ${T8CODE_VERSION} + COMMAND cut -d. -f1 + OUTPUT_VARIABLE T8CODE_VERSION_MAJOR + OUTPUT_STRIP_TRAILING_WHITESPACE ) +execute_process( COMMAND echo ${T8CODE_VERSION} + COMMAND cut -d. -f2 + OUTPUT_VARIABLE T8CODE_VERSION_MINOR + OUTPUT_STRIP_TRAILING_WHITESPACE ) +execute_process( COMMAND echo ${T8CODE_VERSION} + COMMAND cut -d. -f3 + OUTPUT_VARIABLE T8CODE_VERSION_POINT + OUTPUT_STRIP_TRAILING_WHITESPACE ) + +target_compile_definitions( T8 PUBLIC T8_PACKAGE_STRING="t8 ${T8CODE_VERSION}" ) +target_compile_definitions( T8 PUBLIC T8_VERSION="${T8CODE_VERSION}" ) +target_compile_definitions( T8 PUBLIC T8_VERSION_MAJOR=${T8CODE_VERSION_MAJOR} ) +target_compile_definitions( T8 PUBLIC T8_VERSION_MINOR=${T8CODE_VERSION_MINOR} ) +target_compile_definitions( T8 PUBLIC T8_VERSION_POINT=${T8CODE_VERSION_POINT} ) + + +target_include_directories( T8 PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) +target_link_libraries( T8 PUBLIC P4EST::P4EST SC::SC ) + +if ( CMAKE_BUILD_TYPE STREQUAL "Debug" ) + target_compile_definitions( T8 PUBLIC T8_ENABLE_DEBUG ) +endif() + +if ( T8CODE_ENABLE_MPI ) + target_compile_definitions( T8 PUBLIC T8_ENABLE_MPI ) + target_compile_definitions( T8 PUBLIC T8_ENABLE_MPIIO ) + target_link_libraries( T8 PUBLIC MPI::MPI_C ) +endif() + +if( T8CODE_ENABLE_VTK ) + target_compile_definitions( T8 PUBLIC T8_VTK_VERSION_USED="${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}" ) + target_compile_definitions( T8 PUBLIC T8_WITH_VTK=1 ) + target_include_directories( T8 PUBLIC ${VTK_INCLUDE_DIRS} ) + target_link_libraries( T8 PUBLIC ${VTK_LIBRARIES} ) +endif() + +target_sources( T8 PRIVATE + t8.c + t8_eclass.c + t8_mesh.c + t8_element.c + t8_element_cxx.cxx + t8_element_c_interface.cxx + t8_refcount.c + t8_cmesh/t8_cmesh.c + t8_cmesh/t8_cmesh_cad.cxx + t8_cmesh/t8_cmesh_cxx.cxx + t8_cmesh/t8_cmesh_triangle.c + t8_cmesh/t8_cmesh_vtk_writer.c + t8_cmesh/t8_cmesh_stash.c + t8_cmesh/t8_cmesh_vtk_reader.cxx + t8_cmesh/t8_cmesh_save.c + t8_cmesh/t8_cmesh_netcdf.c + t8_cmesh/t8_cmesh_trees.c + t8_cmesh/t8_cmesh_commit.c + t8_cmesh/t8_cmesh_partition.c + t8_cmesh/t8_cmesh_copy.c + t8_data/t8_shmem.c + t8_cmesh/t8_cmesh_geometry.cxx + t8_cmesh/t8_cmesh_examples.c + t8_cmesh/t8_cmesh_helpers.c + t8_data/t8_containers.cxx + t8_cmesh/t8_cmesh_offset.c + t8_cmesh/t8_cmesh_readmshfile.cxx + t8_forest/t8_forest.c + t8_forest/t8_forest_adapt.cxx + t8_geometry/t8_geometry.cxx + t8_geometry/t8_geometry_helpers.c + t8_geometry/t8_geometry_base.cxx + t8_geometry/t8_geometry_with_vertices.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_zero.cxx + t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx + t8_forest/t8_forest_partition.cxx + t8_forest/t8_forest_cxx.cxx + t8_forest/t8_forest_private.c + t8_forest/t8_forest_vtk.cxx + t8_forest/t8_forest_ghost.cxx + t8_forest/t8_forest_iterate.cxx + t8_version.c + t8_vtk.c + t8_forest/t8_forest_balance.cxx + t8_forest/t8_forest_netcdf.cxx + t8_element_shape.c + t8_netcdf.c + t8_cmesh/t8_cmesh_testcases.c + t8_vtk/t8_vtk_polydata.cxx + t8_vtk/t8_vtk_unstructured.cxx + t8_vtk/t8_vtk_parallel.cxx + t8_vtk/t8_vtk_reader.cxx + t8_schemes/t8_default/t8_default_cxx.cxx + t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.cxx + t8_schemes/t8_default/t8_default_hex/t8_default_hex_cxx.cxx + t8_schemes/t8_default/t8_default_hex/t8_dhex_bits.c + t8_schemes/t8_default/t8_default_line/t8_default_line_cxx.cxx + t8_schemes/t8_default/t8_default_line/t8_dline_bits.c + t8_schemes/t8_default/t8_default_prism/t8_default_prism_cxx.cxx + t8_schemes/t8_default/t8_default_prism/t8_dprism_bits.c + t8_schemes/t8_default/t8_default_quad/t8_default_quad_cxx.cxx + t8_schemes/t8_default/t8_default_quad/t8_dquad_bits.c + t8_schemes/t8_default/t8_default_tet/t8_default_tet_cxx.cxx + t8_schemes/t8_default/t8_default_tet/t8_dtet_bits.c + t8_schemes/t8_default/t8_default_tet/t8_dtet_connectivity.c + t8_schemes/t8_default/t8_default_tri/t8_default_tri_cxx.cxx + 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.cxx + t8_schemes/t8_default/t8_default_vertex/t8_dvertex_bits.c + t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid_cxx.cxx + t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c + t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c +) + +set( T8_PUBLIC_HEADERS + t8.h + t8_eclass.h + t8_mesh.h + t8_element_cxx.hxx + t8_element.h + t8_element_c_interface.h + t8_refcount.h + t8_cmesh.h t8_cmesh_triangle.h + t8_cmesh_tetgen.h t8_cmesh_readmshfile.h + t8_cmesh_vtk_writer.h + t8_cmesh_vtk_reader.hxx + t8_vec.h + t8_version.h + t8_vtk.h + t8_cmesh_netcdf.h + t8_forest_netcdf.h + t8_element_shape.h + t8_netcdf.h + t8_cmesh/t8_cmesh_testcases.h + t8_cmesh/t8_cmesh_save.h + t8_cmesh/t8_cmesh_examples.h + t8_cmesh/t8_cmesh_geometry.h + t8_cmesh/t8_cmesh_helpers.h + t8_cmesh/t8_cmesh_cad.hxx + t8_data/t8_shmem.h + t8_data/t8_containers.h + t8_forest/t8_forest.h + t8_forest/t8_forest_general.h + t8_forest/t8_forest_geometrical.h + t8_forest/t8_forest_profiling.h + t8_forest/t8_forest_io.h + t8_forest/t8_forest_adapt.h + t8_forest/t8_forest_vtk.h + t8_forest/t8_forest_to_vtkUnstructured.hxx + t8_forest/t8_forest_iterate.h + t8_forest/t8_forest_partition.h + t8_geometry/t8_geometry.h + t8_geometry/t8_geometry_base.hxx + t8_geometry/t8_geometry_base.h + t8_geometry/t8_geometry_with_vertices.hxx + t8_geometry/t8_geometry_with_vertices.h + t8_geometry/t8_geometry_helpers.h + t8_geometry/t8_geometry_implementations/t8_geometry_linear.h + t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.h + t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx + t8_geometry/t8_geometry_implementations/t8_geometry_examples.h + t8_geometry/t8_geometry_implementations/t8_geometry_cad.h + t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx + t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx + t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx + t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx + t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx + t8_vtk/t8_vtk_reader.hxx + t8_vtk/t8_vtk_types.h +) + +install( FILES ${T8_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include ) +install( TARGETS T8 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) diff --git a/src/Makefile.am b/src/Makefile.am index 42ca28aa9b..b684c8e34d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,7 +41,7 @@ libt8_installed_headers_cmesh = \ src/t8_cmesh/t8_cmesh_examples.h \ src/t8_cmesh/t8_cmesh_geometry.h \ src/t8_cmesh/t8_cmesh_helpers.h \ - src/t8_cmesh/t8_cmesh_occ.hxx + src/t8_cmesh/t8_cmesh_cad.hxx libt8_installed_headers_data = \ src/t8_data/t8_shmem.h src/t8_data/t8_containers.h libt8_installed_headers_forest = \ @@ -65,9 +65,10 @@ libt8_installed_headers_geometry_impl = \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.h \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.h \ src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx \ + src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h \ src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.h \ - src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.h \ - src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.hxx \ + src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h \ + src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx \ @@ -104,7 +105,7 @@ libt8_compiled_sources = \ src/t8_element.c src/t8_element_cxx.cxx \ src/t8_element_c_interface.cxx \ src/t8_refcount.c src/t8_cmesh/t8_cmesh.c \ - src/t8_cmesh/t8_cmesh_occ.cxx \ + src/t8_cmesh/t8_cmesh_cad.cxx \ src/t8_cmesh/t8_cmesh_cxx.cxx src/t8_cmesh/t8_cmesh_triangle.c \ src/t8_cmesh/t8_cmesh_vtk_writer.c src/t8_cmesh/t8_cmesh_stash.c \ src/t8_cmesh/t8_cmesh_vtk_reader.cxx \ @@ -124,7 +125,7 @@ libt8_compiled_sources = \ src/t8_geometry/t8_geometry_base.cxx \ src/t8_geometry/t8_geometry_with_vertices.cxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx \ - src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.cxx \ + src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx \ src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.cxx \ @@ -156,9 +157,13 @@ src_libt8_la_CPPFLAGS = $(AM_CPPFLAGS) $(T8_CPPFLAGS) ## This is the official API versioning scheme of libtool. Please see: ## Read https://www.gnu.org/software/libtool/manual/libtool.html#Versioning src_libt8_la_LDFLAGS = -version-info 2:0:0 -src_libt8_la_LIBADD = @T8_P4EST_LDADD@ @T8_SC_LDADD@ +src_libt8_la_LIBADD = @T8_P4EST_LIBADD@ @T8_SC_LIBADD@ +EXTRA_src_libt8_la_DEPENDENCIES = @T8_SC_EDEPS@ + +AM_LDFLAGS = +AM_LDFLAGS += @T8_SC_RPATH@ LDADD += src/libt8.la @T8_P4EST_LDADD@ @T8_SC_LDADD@ -EXTRA_src_libt8_la_DEPENDENCIES = @T8_P4EST_LDADD@ @T8_SC_LDADD@ + nodist_include_HEADERS += $(libt8_generated_headers) dist_include_HEADERS = $(libt8_installed_headers) diff --git a/src/t8.h b/src/t8.h index cf5d00d356..c4da06a1fe 100644 --- a/src/t8.h +++ b/src/t8.h @@ -30,7 +30,9 @@ #define T8_H /* include config headers */ +#ifndef T8_CMAKE_BUILD #include +#endif #include #if (defined(T8_ENABLE_MPI) && !defined(SC_ENABLE_MPI)) || (!defined(T8_ENABLE_MPI) && defined(SC_ENABLE_MPI)) #error "MPI configured differently in t8code and libsc" diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index 89c82017a1..2043209a4b 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -119,7 +119,7 @@ t8_cmesh_no_negative_volume (t8_cmesh_t cmesh); */ /* TODO: write a test for this function */ int -t8_cmesh_tree_vertices_negative_volume (t8_eclass_t eclass, double *vertices, int num_vertices); +t8_cmesh_tree_vertices_negative_volume (const t8_eclass_t eclass, const double *vertices, const int num_vertices); /* TODO: Currently it is not possible to destroy set_from before * cmesh is destroyed. */ @@ -671,7 +671,7 @@ t8_cmesh_get_attribute (const t8_cmesh_t cmesh, const int package_id, const int * \param [in] package_id The identifier of a valid software package. \see sc_package_register * \param [in] key A key used to identify the attribute under all * attributes of this tree with the same \a package_id. - * \param [in] tree_id The local number of the tree. + * \param [in] ltree_id The local number of the tree. * \param [in] data_count The number of entries in the array that are requested. * This must be smaller or equal to the \a data_count parameter * of the corresponding call to \ref t8_cmesh_set_attribute_gloidx_array diff --git a/src/t8_cmesh/t8_cmesh.c b/src/t8_cmesh/t8_cmesh.c index 68c0cd8e25..8187c2f034 100644 --- a/src/t8_cmesh/t8_cmesh.c +++ b/src/t8_cmesh/t8_cmesh.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -388,22 +389,6 @@ t8_cmesh_get_attribute (const t8_cmesh_t cmesh, const int package_id, const int cmesh->trees, is_ghost ? t8_cmesh_ltreeid_to_ghostid (cmesh, ltree_id) : ltree_id, package_id, key, NULL, is_ghost); } -/* Return the attribute pointer of a tree for a gloidx_t array. - * \param [in] cmesh The cmesh. - * \param [in] package_id The identifier of a valid software package. \see sc_package_register - * \param [in] key A key used to identify the attribute under all - * attributes of this tree with the same \a package_id. - * \param [in] tree_id The local number of the tree. - * \param [out] data_count The number of entries in the array that are requested. - * This must be smaller or equal to the \a data_count parameter - * of the corresponding call to \ref t8_cmesh_set_attribute_gloidx_array - * \return The attribute pointer of the tree \a ltree_id or NULL if the attribute is not found. - * \note \a cmesh must be committed before calling this function. - * \note No check is performed whether the attribute actually stored \a data_count many entries since - * we do not store the number of data entries of the attribute array. - * You can keep track of the data count yourself by using another attribute. - * \see t8_cmesh_set_attribute_gloidx_array - */ t8_gloidx_t * t8_cmesh_get_attribute_gloidx_array (const t8_cmesh_t cmesh, const int package_id, const int key, const t8_locidx_t ltree_id, const size_t data_count) @@ -468,7 +453,7 @@ t8_cmesh_set_tree_class (t8_cmesh_t cmesh, t8_gloidx_t gtree_id, t8_eclass_t tre * coordinates does have negative volume. */ int -t8_cmesh_tree_vertices_negative_volume (t8_eclass_t eclass, double *vertices, int num_vertices) +t8_cmesh_tree_vertices_negative_volume (const t8_eclass_t eclass, const double *vertices, const int num_vertices) { double v_1[3], v_2[3], v_j[3], cross[3], sc_prod; int i, j; @@ -549,7 +534,14 @@ t8_cmesh_no_negative_volume (t8_cmesh_t cmesh) if (vertices != NULL) { /* Vertices are set */ eclass = t8_cmesh_get_tree_class (cmesh, itree); - ret = t8_cmesh_tree_vertices_negative_volume (eclass, vertices, t8_eclass_num_vertices[eclass]); + const t8_gloidx_t gtree_id = t8_cmesh_get_global_id (cmesh, itree); + if (t8_geometry_get_type (cmesh, gtree_id) == T8_GEOMETRY_TYPE_LINEAR_AXIS_ALIGNED) { + /* Tree has negative volume if the diagonal goes from v_max to v_min and not vice versa */ + ret = vertices[3] < vertices[0] && vertices[4] < vertices[1] && vertices[5] < vertices[2]; + } + else { + ret = t8_cmesh_tree_vertices_negative_volume (eclass, vertices, t8_eclass_num_vertices[eclass]); + } if (ret) { t8_debugf ("Detected negative volume in tree %li\n", (long) itree); } @@ -561,7 +553,8 @@ t8_cmesh_no_negative_volume (t8_cmesh_t cmesh) #endif void -t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtree_id, double *vertices, int num_vertices) +t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, const t8_gloidx_t gtree_id, const double *vertices, + const int num_vertices) { T8_ASSERT (cmesh != NULL); T8_ASSERT (vertices != NULL); diff --git a/src/t8_cmesh/t8_cmesh_occ.cxx b/src/t8_cmesh/t8_cmesh_cad.cxx similarity index 89% rename from src/t8_cmesh/t8_cmesh_occ.cxx rename to src/t8_cmesh/t8_cmesh_cad.cxx index 94c864e88c..29d5932bc1 100644 --- a/src/t8_cmesh/t8_cmesh_occ.cxx +++ b/src/t8_cmesh/t8_cmesh_cad.cxx @@ -20,14 +20,14 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_cmesh_occ.cxx +/** \file t8_cmesh_cad.cxx * * TODO: document this file */ -#include +#include #include -#include +#include #if T8_WITH_OCC #include @@ -48,16 +48,16 @@ t8_cmesh_t t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int num_axial_trees, int num_radial_trees, - int with_occ_geometry) + int with_cad_geometry) { /* Create the cmesh and the geometry */ t8_cmesh_t cmesh; t8_cmesh_init (&cmesh); t8_cmesh_set_profiling (cmesh, 1); - if (with_occ_geometry) { + if (with_cad_geometry) { #if T8_WITH_OCC - /* Create the two occ cylinder surfaces */ + /* Create the two cad cylinder surfaces */ const double radius_inner = 0.25; const double radius_outer = 0.5; const gp_Pnt origin (0, 0, 0); @@ -75,13 +75,13 @@ t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int nu const TopoDS_Face face_inner = TopoDS::Face (BRepPrimAPI_MakePrism (edge_inner, height)); const Handle_Geom_Surface cylinder_inner = BRep_Tool::Surface (face_inner); - /* Fill a shape with cylinders and register an occ geometry with this shape. */ + /* Fill a shape with cylinders and register an cad geometry with this shape. */ TopoDS_Shape shape; shape = BRepBuilderAPI_MakeFace (cylinder_outer, 1e-6).Face (); shape = BRepAlgoAPI_Fuse (shape, BRepBuilderAPI_MakeFace (cylinder_inner, 1e-6).Face ()); - t8_geometry_occ *geometry_occ = new t8_geometry_occ (3, shape, "occ surface dim=3"); + t8_geometry_cad *geometry_cad = new t8_geometry_cad (3, shape, "cad surface dim=3"); - t8_cmesh_register_geometry (cmesh, geometry_occ); + t8_cmesh_register_geometry (cmesh, geometry_cad); #else /* !T8_WITH_OCC */ SC_ABORTF ("OCC not linked"); @@ -105,7 +105,7 @@ t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int nu const double dphi = 2.0 * M_PI / num_tangential_trees; const double dh = 1.0 / num_axial_trees; /* Allocate memory for saving the node coordinates - * and in case of usage of the occ geometry, the node parameters */ + * and in case of usage of the cad geometry, the node parameters */ double *vertices; vertices = T8_ALLOC (double, num_tangential_trees *num_axial_trees *num_radial_trees * 24); #if T8_WITH_OCC @@ -164,9 +164,9 @@ t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int nu vertices + ((i_tangential_trees * num_axial_trees + i_axial_trees) * num_radial_trees + i_radial_trees) * 24, 24); - /* Assign parameters if occ is enabled */ + /* Assign parameters if cad is enabled */ #if T8_WITH_OCC - if (with_occ_geometry) { + if (with_cad_geometry) { /* Calculate parameters if cell lies on boundary */ const int current_tree_parameters = (i_tangential_trees * num_axial_trees + i_axial_trees) * 8; if (i_radial_trees == 0 || i_radial_trees == num_radial_trees - 1) { @@ -185,62 +185,62 @@ t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int nu = (i_tangential_trees * num_axial_trees + i_axial_trees) * num_radial_trees + i_radial_trees; /* If geometry on both sides of cell */ if (num_radial_trees == 1) { - /* Assign occ geometries to the corresponding faces */ + /* Assign cad geometries to the corresponding faces */ int faces[6] = { 0 }; faces[0] = cylinder_outer_index; faces[1] = cylinder_inner_index; /* Assign attributes to cmesh cells */ - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, parameters + current_tree_parameters, 8 * sizeof (double), 1); t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, parameters + current_tree_parameters, 8 * sizeof (double), 1); } /* If geometry only on face 1 */ else if (i_radial_trees == 0) { - /* Assign occ geometries to the corresponding faces */ + /* Assign cad geometries to the corresponding faces */ int faces[6] = { 0 }; faces[1] = cylinder_inner_index; /* Assign attributes to cmesh cells */ - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 1, parameters + current_tree_parameters, 8 * sizeof (double), 1); } /* If geometry only on face 0 */ else if (i_radial_trees == num_radial_trees - 1) { - /* Assign occ geometries to the corresponding faces */ + /* Assign cad geometries to the corresponding faces */ int faces[6] = { 0 }; faces[0] = cylinder_outer_index; /* Assign attributes to cmesh cells */ - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + 0, parameters + current_tree_parameters, 8 * sizeof (double), 1); } /* If there is no geometry */ else { - /* Assign occ geometries to the corresponding faces */ + /* Assign cad geometries to the corresponding faces */ int faces[6] = { 0 }; /* Assign attributes to cmesh cells */ - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, + t8_cmesh_set_attribute (cmesh, current_tree, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); } } diff --git a/src/t8_cmesh/t8_cmesh_occ.hxx b/src/t8_cmesh/t8_cmesh_cad.hxx similarity index 84% rename from src/t8_cmesh/t8_cmesh_occ.hxx rename to src/t8_cmesh/t8_cmesh_cad.hxx index 2ebda29fe9..b900bcdb3f 100644 --- a/src/t8_cmesh/t8_cmesh_occ.hxx +++ b/src/t8_cmesh/t8_cmesh_cad.hxx @@ -20,28 +20,28 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_cmesh_occ.hxx - * We define coarse meshes with occ geometries here +/** \file t8_cmesh_cad.hxx + * We define coarse meshes with cad geometries here */ -#ifndef T8_CMESH_OCC_HXX -#define T8_CMESH_OCC_HXX +#ifndef T8_CMESH_CAD_HXX +#define T8_CMESH_CAD_HXX #include /** Construct a hollow cylinder out of hexes with an inner diameter of 0.5, * an outer diameter of 1 and a height of 1. The number of cells used in each direction can be specified. - * A cylindrical occ surface can be linked to the inner and outer faces of the cylinder trees, to use the - * occ geometry. + * A cylindrical cad surface can be linked to the inner and outer faces of the cylinder trees, to use the + * cad geometry. * \param [in] comm The mpi communicator to use. * \param [in] num_tangential_trees Number of trees distributed around the cylinder. * \param [in] num_axial_trees Number of trees distributed along the height of the cylinder. * \param [in] num_radial_trees Number of trees distributed along the thickness of the cylinder. - * \param [in] with_occ_geometry Link the cylinder to a occ geometry, 0 or 1. + * \param [in] with_cad_geometry Link the cylinder to a cad geometry, 0 or 1. * \return A valid cmesh, as if _init and _commit had been called. */ t8_cmesh_t t8_cmesh_new_hollow_cylinder (sc_MPI_Comm comm, int num_tangential_trees, int num_axial_trees, int num_radial_trees, - int with_occ_geometry); + int with_cad_geometry); #endif /* !T8_CMESH_H */ diff --git a/src/t8_cmesh/t8_cmesh_cxx.cxx b/src/t8_cmesh/t8_cmesh_cxx.cxx index 01060ed504..16b770606c 100644 --- a/src/t8_cmesh/t8_cmesh_cxx.cxx +++ b/src/t8_cmesh/t8_cmesh_cxx.cxx @@ -72,7 +72,7 @@ t8_cmesh_uniform_bounds (t8_cmesh_t cmesh, int level, t8_scheme_cxx_t *ts, t8_gl if (cmesh->num_trees_per_eclass[tree_class] > 0) { tree_scheme = ts->eclass_schemes[tree_class]; T8_ASSERT (tree_scheme != NULL); - children_per_tree = tree_scheme->t8_element_count_leafs_from_root (level); + children_per_tree = tree_scheme->t8_element_count_leaves_from_root (level); T8_ASSERT (children_per_tree >= 0); global_num_children += cmesh->num_trees_per_eclass[tree_class] * children_per_tree; } diff --git a/src/t8_cmesh/t8_cmesh_examples.c b/src/t8_cmesh/t8_cmesh_examples.c index 97aeea2ec6..62e0cfdf51 100644 --- a/src/t8_cmesh/t8_cmesh_examples.c +++ b/src/t8_cmesh/t8_cmesh_examples.c @@ -987,7 +987,6 @@ t8_cmesh_set_vertices_2D (t8_cmesh_t cmesh, const t8_eclass_t eclass, const doub */ for (t8_locidx_t quad_y_id = 0; quad_y_id < quads_y; quad_y_id++) { for (t8_locidx_t quad_x_id = 0; quad_x_id < quads_x; quad_x_id++) { - memcpy (vertices, box, 3 * sizeof (double)); /* Vertex 0 */ t8_vec_axpyz (box, box_dir, vertices + 6, 1.0); /* Vertex 2 */ @@ -1259,7 +1258,7 @@ t8_cmesh_set_vertices_3D (t8_cmesh_t cmesh, const t8_eclass_t eclass, const doub t8_cmesh_t t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const double *boundary, t8_locidx_t polygons_x, - t8_locidx_t polygons_y, t8_locidx_t polygons_z, const t8_geometry_c *geometry) + t8_locidx_t polygons_y, t8_locidx_t polygons_z, const int use_axis_aligned) { SC_CHECK_ABORT (eclass != T8_ECLASS_PYRAMID, "Pyramids are not yet supported."); const int dim = t8_eclass_to_dimension[eclass]; @@ -1280,7 +1279,7 @@ t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const do t8_cmesh_t cmesh; t8_cmesh_init (&cmesh); - const int is_axis_aligned = t8_geom_get_type (geometry) == T8_GEOMETRY_TYPE_LINEAR_AXIS_ALIGNED; + t8_geometry_c *geometry = use_axis_aligned ? t8_geometry_linear_axis_aligned_new (dim) : t8_geometry_linear_new (dim); t8_cmesh_register_geometry (cmesh, geometry); @@ -1296,11 +1295,11 @@ t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const do /* Set the vertices of all trees. */ if (dim == 3) { T8_ASSERT (eclass == T8_ECLASS_HEX || eclass == T8_ECLASS_TET || eclass == T8_ECLASS_PRISM); - t8_cmesh_set_vertices_3D (cmesh, eclass, boundary, polygons_x, polygons_y, polygons_z, is_axis_aligned); + t8_cmesh_set_vertices_3D (cmesh, eclass, boundary, polygons_x, polygons_y, polygons_z, use_axis_aligned); } else if (dim == 2) { T8_ASSERT (eclass == T8_ECLASS_QUAD || eclass == T8_ECLASS_TRIANGLE); - t8_cmesh_set_vertices_2D (cmesh, eclass, boundary, polygons_x, polygons_y, is_axis_aligned); + t8_cmesh_set_vertices_2D (cmesh, eclass, boundary, polygons_x, polygons_y, use_axis_aligned); } else if (dim == 1) { T8_ASSERT (eclass == T8_ECLASS_LINE); @@ -1316,9 +1315,9 @@ t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const do double vertices[6]; /* Set first vertex to lower end of line */ - t8_vec_axy (boundary, vertices, 1.0); + memcpy (vertices, boundary, 3 * sizeof (double)); /* Set second vertex to lower end of line + line_dir */ - t8_vec_axpyz (vertices + 3, boundary, line_dir, 1.0); + t8_vec_axpyz (line_dir, boundary, vertices + 3, 1.0); for (t8_gloidx_t tree_x = 0; tree_x < polygons_x; tree_x++) { t8_cmesh_set_tree_vertices (cmesh, tree_x, vertices, 2); @@ -1421,7 +1420,7 @@ t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const do if (eclass == T8_ECLASS_HEX) { const t8_locidx_t tree_id_0 = poly_id_0; const t8_locidx_t tree_id_1 = poly_id_0 + polygons_y * polygons_x; - t8_cmesh_set_join (cmesh, tree_id_0, tree_id_1, 5, 4, 4); + t8_cmesh_set_join (cmesh, tree_id_0, tree_id_1, 5, 4, 0); } else if (eclass == T8_ECLASS_TET) { t8_locidx_t tree_id_0 = poly_id_0 * 6 + 5; @@ -2801,7 +2800,7 @@ t8_cmesh_new_squared_disk (const double radius, sc_MPI_Comm comm) } t8_cmesh_t -t8_cmesh_new_triangulated_spherical_surface (const double radius, sc_MPI_Comm comm) +t8_cmesh_new_triangulated_spherical_surface_octahedron (const double radius, sc_MPI_Comm comm) { /* Initialization of the mesh */ t8_cmesh_t cmesh; @@ -2868,6 +2867,144 @@ t8_cmesh_new_triangulated_spherical_surface (const double radius, sc_MPI_Comm co return cmesh; } +t8_cmesh_t +t8_cmesh_new_triangulated_spherical_surface_icosahedron (const double radius, sc_MPI_Comm comm) +{ + /* Initialization of the mesh */ + t8_cmesh_t cmesh; + t8_cmesh_init (&cmesh); + + t8_geometry_c *geometry = t8_geometry_triangulated_spherical_surface_new (); + + t8_cmesh_register_geometry (cmesh, geometry); /* Use linear geometry */ + + const int ntrees = 20; /* Number of cmesh elements resp. trees, i.e. number of triangles in an icosahedron. */ + const int nverts = 3; /* Number of cmesh element vertices,. */ + + /* Arrays for the face connectivity computations via vertices. */ + double all_verts[ntrees * T8_ECLASS_MAX_CORNERS * T8_ECLASS_MAX_DIM]; + t8_eclass_t all_eclasses[ntrees]; + + /* Defitition of the tree class. */ + for (int itree = 0; itree < ntrees; itree++) { + t8_cmesh_set_tree_class (cmesh, itree, T8_ECLASS_TRIANGLE); + all_eclasses[itree] = T8_ECLASS_TRIANGLE; + } + + const double alpha = 63.43494882292201 / 180.0 * M_PI; /* Icosahedral angle. */ + + double vertices_top[3 * 3]; + double vertices_bot[3 * 3]; + + { + /* Prepare initial triangle on the top of the icosahedron. */ + double rot_mat[3][3]; + + vertices_top[0] = 0.0; + vertices_top[1] = 0.0; + vertices_top[2] = radius; + + t8_mat_init_yrot (rot_mat, alpha); + t8_mat_mult_vec (rot_mat, vertices_top + 0, vertices_top + 3); + + t8_mat_init_zrot (rot_mat, 2.0 / 5.0 * M_PI); + t8_mat_mult_vec (rot_mat, vertices_top + 3, vertices_top + 6); + } + + { + /* Prepare initial triangle on the bottom of the icosahedron. */ + double rot_mat[3][3]; + double tmp_vec[3]; + + vertices_bot[0] = 0.0; + vertices_bot[1] = 0.0; + vertices_bot[2] = -radius; + + t8_mat_init_yrot (rot_mat, -alpha); + t8_mat_mult_vec (rot_mat, vertices_bot + 0, tmp_vec); + + t8_mat_init_zrot (rot_mat, 0.5 * 2.0 / 5.0 * M_PI); + t8_mat_mult_vec (rot_mat, tmp_vec, vertices_bot + 3); + + t8_mat_init_zrot (rot_mat, 2.0 / 5.0 * M_PI); + t8_mat_mult_vec (rot_mat, vertices_bot + 3, vertices_bot + 6); + } + + /* Create the cmesh in 5 bands of 4 triangles. + * Rotate the initial top and bottom triangle around the z axis. + * The two triangles on the "belly" that are connecting the top and bottom triangle share vertices + * with the top and bottom triangle, so we can construct them in one go as well. + */ + int itree = -1; + for (int turn = 0; turn < 5; turn++) { + double rot_mat[3][3]; + double rot_vertices_top[4 * 3]; + double rot_vertices_bot[4 * 3]; + + double belly_top[3 * 3]; + double belly_bot[3 * 3]; + + t8_mat_init_zrot (rot_mat, turn * 2.0 / 5.0 * M_PI); + + for (int ivert = 0; ivert < nverts; ivert++) { + t8_mat_mult_vec (rot_mat, vertices_top + 3 * ivert, rot_vertices_top + 3 * ivert); + t8_mat_mult_vec (rot_mat, vertices_bot + 3 * ivert, rot_vertices_bot + 3 * ivert); + } + + for (int ivert = 0; ivert < 2; ivert++) { + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + belly_top[3 * ivert + icoord] = rot_vertices_top[3 * (ivert + 1) + icoord]; + belly_bot[3 * ivert + icoord] = rot_vertices_bot[3 * (ivert + 1) + icoord]; + } + } + + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + belly_top[6 + icoord] = rot_vertices_bot[3 * 1 + icoord]; + belly_bot[6 + icoord] = rot_vertices_top[3 * 2 + icoord]; + } + + /* Set the tree vertices and gather all vertices, so that the facejoins can in the end be deduced from global vertices */ + t8_cmesh_set_tree_vertices (cmesh, ++itree, rot_vertices_top, nverts); + for (int ivert = 0; ivert < nverts; ivert++) { + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + all_verts[T8_3D_TO_1D (ntrees, T8_ECLASS_MAX_CORNERS, T8_ECLASS_MAX_DIM, itree, ivert, icoord)] + = rot_vertices_top[3 * ivert + icoord]; + } + } + + t8_cmesh_set_tree_vertices (cmesh, ++itree, belly_top, nverts); + for (int ivert = 0; ivert < nverts; ivert++) { + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + all_verts[T8_3D_TO_1D (ntrees, T8_ECLASS_MAX_CORNERS, T8_ECLASS_MAX_DIM, itree, ivert, icoord)] + = belly_top[3 * ivert + icoord]; + } + } + + t8_cmesh_set_tree_vertices (cmesh, ++itree, belly_bot, nverts); + for (int ivert = 0; ivert < nverts; ivert++) { + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + all_verts[T8_3D_TO_1D (ntrees, T8_ECLASS_MAX_CORNERS, T8_ECLASS_MAX_DIM, itree, ivert, icoord)] + = belly_bot[3 * ivert + icoord]; + } + } + + t8_cmesh_set_tree_vertices (cmesh, ++itree, rot_vertices_bot, nverts); + for (int ivert = 0; ivert < nverts; ivert++) { + for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { + all_verts[T8_3D_TO_1D (ntrees, T8_ECLASS_MAX_CORNERS, T8_ECLASS_MAX_DIM, itree, ivert, icoord)] + = rot_vertices_bot[3 * ivert + icoord]; + } + } + } + + /* Face connectivity. */ + t8_cmesh_set_join_by_vertices (cmesh, ntrees, all_eclasses, all_verts, NULL, 0); + + /* Commit the mesh */ + t8_cmesh_commit (cmesh, comm); + return cmesh; +} + t8_cmesh_t t8_cmesh_new_quadrangulated_spherical_surface (const double radius, sc_MPI_Comm comm) { @@ -2934,37 +3071,20 @@ t8_cmesh_new_quadrangulated_spherical_surface (const double radius, sc_MPI_Comm return cmesh; } -t8_cmesh_t -t8_cmesh_new_cubed_spherical_shell (const double inner_radius, const double shell_thickness, const int num_levels, - const int num_layers, sc_MPI_Comm comm) +typedef t8_cmesh_t (t8_inner_sphere_creator_t) (const double inner_radius, sc_MPI_Comm comm); + +static t8_cmesh_t +t8_cmesh_new_spherical_shell (t8_eclass_t eclass, t8_geometry_c *geometry, + t8_inner_sphere_creator_t inner_sphere_creator, const double inner_radius, + const double shell_thickness, const int num_levels, const int num_layers, + sc_MPI_Comm comm) { /* Initialization of the mesh */ t8_cmesh_t cmesh; t8_cmesh_init (&cmesh); - t8_geometry_c *geometry = t8_geometry_cubed_spherical_shell_new (); t8_cmesh_register_geometry (cmesh, geometry); - /* Square root of three. */ - const double SQRT3 = 1.7320508075688772; - - const int two_to_nl = 1 << num_levels; /* 2^num_levels */ - - /* clang-format off */ - const int ntrees = t8_eclass_num_faces[T8_ECLASS_HEX] * two_to_nl * two_to_nl * num_layers; /* Number of cmesh cells. */ - const int nverts = t8_eclass_num_vertices[T8_ECLASS_HEX]; /* Number of vertices per cmesh cell. */ - - /* Arrays for the face connectivity computations via vertices. */ - double *all_verts = T8_ALLOC (double, ntrees * T8_ECLASS_MAX_CORNERS * T8_ECLASS_MAX_DIM); - t8_eclass_t *all_eclasses = T8_ALLOC (t8_eclass_t, ntrees); - /* clang-format on */ - - /* Defitition of the tree class. */ - for (int itree = 0; itree < ntrees; itree++) { - t8_cmesh_set_tree_class (cmesh, itree, T8_ECLASS_HEX); - all_eclasses[itree] = T8_ECLASS_HEX; - } - /* Here is what we do: Construct a 3D cmesh from a 2D forest. */ int mpi_rank; @@ -2976,49 +3096,78 @@ t8_cmesh_new_cubed_spherical_shell (const double inner_radius, const double shel sc_MPI_Comm_split (comm, mpi_rank, mpi_rank, &local_comm); /* Create 2D quadrangulated spherical surface of given refinement level per patch. */ - t8_forest_t forest = t8_forest_new_uniform (t8_cmesh_new_quadrangulated_spherical_surface (inner_radius, local_comm), + t8_forest_t forest = t8_forest_new_uniform (inner_sphere_creator (inner_radius, local_comm), t8_scheme_new_default_cxx (), num_levels, 0, local_comm); - /* Get the number of trees that have elements of this process. */ - t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + /* clang-format off */ + const int ntrees = t8_forest_get_local_num_elements (forest) * num_layers; /* Number of 3D cmesh elements resp. trees. */ + const int nverts = t8_eclass_num_vertices[eclass]; /* Number of vertices per cmesh element. */ + + /* Arrays for the face connectivity computations via vertices. */ + double *all_verts = T8_ALLOC (double, ntrees * T8_ECLASS_MAX_CORNERS * T8_ECLASS_MAX_DIM); + t8_eclass_t *all_eclasses = T8_ALLOC (t8_eclass_t, ntrees); + /* clang-format on */ + + /* Defitition of the tree class. */ + for (int itree = 0; itree < ntrees; itree++) { + t8_cmesh_set_tree_class (cmesh, itree, eclass); + all_eclasses[itree] = eclass; + } /* Tree index of the to-be-created 3D cmesh. */ int itree = 0; /* Loop over all local trees in the forest. */ - for (t8_locidx_t itree_quad = 0, current_index = 0; itree_quad < num_local_trees; ++itree_quad) { + for (t8_locidx_t itree_local = 0; itree_local < t8_forest_get_num_local_trees (forest); ++itree_local) { /* Get the number of elements of this tree. */ - const t8_locidx_t num_elements_in_tree = t8_forest_get_tree_num_elements (forest, itree_quad); + const t8_locidx_t num_elements_in_tree = t8_forest_get_tree_num_elements (forest, itree_local); + + /* Element class scheme of the current tree. */ + t8_eclass_t eclass_2d = t8_forest_get_eclass (forest, itree_local); /* Loop over all local elements in the tree. */ - for (t8_locidx_t ielement = 0; ielement < num_elements_in_tree; ++ielement, ++current_index) { - const t8_element_t *element = t8_forest_get_element_in_tree (forest, itree_quad, ielement); + for (t8_locidx_t ielement = 0; ielement < num_elements_in_tree; ++ielement) { + const t8_element_t *element = t8_forest_get_element_in_tree (forest, itree_local, ielement); /* Retrieve 2D element vertices. */ - double quad_vertices[4 * 3]; - for (int ivert = 0; ivert < 4; ivert++) { - t8_forest_element_coordinate (forest, itree_quad, element, ivert, quad_vertices + ivert * 3); + double elem_vertices_2d[T8_ECLASS_MAX_CORNERS * 3]; + for (int ivert = 0; ivert < t8_eclass_num_vertices[eclass_2d]; ivert++) { + t8_forest_element_coordinate (forest, itree_local, element, ivert, elem_vertices_2d + ivert * 3); } - /* Transfer the coordinates from the 2D forest mesh to the 2D cmesh and stack hexes along radial direction. */ + { + /* Here, we check if the face normal vector of the 2D element points + * outward with respect to the sphere's center. If not, the node ordering is flipped. + * Note, this works for triangles and quads. + */ + double normal[3]; + t8_vec_tri_normal (elem_vertices_2d, elem_vertices_2d + 3, elem_vertices_2d + 6, normal); + + if (t8_vec_dot (elem_vertices_2d, normal) < 0.0) { + t8_vec_swap (elem_vertices_2d + 3, elem_vertices_2d + 6); + } + } + + /* Transfer the coordinates from the 2D forest mesh to the cmesh via stacking 3D elements along radial direction. */ for (int istack = 0; istack < num_layers; istack++) { - const double iscale = 1.0 + istack * shell_thickness / inner_radius / num_layers / SQRT3; - const double oscale = 1.0 + (istack + 1) * shell_thickness / inner_radius / num_layers / SQRT3; + const double iscale = 1.0 + istack * shell_thickness / inner_radius / num_layers; + const double oscale = 1.0 + (istack + 1) * shell_thickness / inner_radius / num_layers; - double hex_vertices[8 * 3]; - for (int ivert = 0; ivert < 4; ivert++) { + double elem_vertices_3d[T8_ECLASS_MAX_CORNERS * 3]; + for (int ivert = 0; ivert < t8_eclass_num_vertices[eclass_2d]; ivert++) { for (int i = 0; i < 3; i++) { - hex_vertices[0 + ivert * 3 + i] = iscale * quad_vertices[ivert * 3 + i]; - hex_vertices[4 * 3 + ivert * 3 + i] = oscale * quad_vertices[ivert * 3 + i]; + elem_vertices_3d[ivert * 3 + i] = iscale * elem_vertices_2d[ivert * 3 + i]; + elem_vertices_3d[t8_eclass_num_vertices[eclass] / 2 * 3 + ivert * 3 + i] + = oscale * elem_vertices_2d[ivert * 3 + i]; } } - t8_cmesh_set_tree_vertices (cmesh, itree, hex_vertices, nverts); + t8_cmesh_set_tree_vertices (cmesh, itree, elem_vertices_3d, nverts); for (int ivert = 0; ivert < nverts; ivert++) { for (int icoord = 0; icoord < T8_ECLASS_MAX_DIM; icoord++) { all_verts[T8_3D_TO_1D (ntrees, T8_ECLASS_MAX_CORNERS, T8_ECLASS_MAX_DIM, itree, ivert, icoord)] - = hex_vertices[ivert * 3 + icoord]; + = elem_vertices_3d[ivert * 3 + icoord]; } } @@ -3043,3 +3192,30 @@ t8_cmesh_new_cubed_spherical_shell (const double inner_radius, const double shel return cmesh; } + +t8_cmesh_t +t8_cmesh_new_prismed_spherical_shell_icosahedron (const double inner_radius, const double shell_thickness, + const int num_levels, const int num_layers, sc_MPI_Comm comm) +{ + return t8_cmesh_new_spherical_shell (T8_ECLASS_PRISM, t8_geometry_prismed_spherical_shell_new (), + t8_cmesh_new_triangulated_spherical_surface_icosahedron, inner_radius, + shell_thickness, num_levels, num_layers, comm); +} + +t8_cmesh_t +t8_cmesh_new_prismed_spherical_shell_octahedron (const double inner_radius, const double shell_thickness, + const int num_levels, const int num_layers, sc_MPI_Comm comm) +{ + return t8_cmesh_new_spherical_shell (T8_ECLASS_PRISM, t8_geometry_prismed_spherical_shell_new (), + t8_cmesh_new_triangulated_spherical_surface_octahedron, inner_radius, + shell_thickness, num_levels, num_layers, comm); +} + +t8_cmesh_t +t8_cmesh_new_cubed_spherical_shell (const double inner_radius, const double shell_thickness, const int num_levels, + const int num_layers, sc_MPI_Comm comm) +{ + return t8_cmesh_new_spherical_shell (T8_ECLASS_HEX, t8_geometry_cubed_spherical_shell_new (), + t8_cmesh_new_quadrangulated_spherical_surface, inner_radius, shell_thickness, + num_levels, num_layers, comm); +} diff --git a/src/t8_cmesh/t8_cmesh_examples.h b/src/t8_cmesh/t8_cmesh_examples.h index 51d737841d..13d5f11077 100644 --- a/src/t8_cmesh/t8_cmesh_examples.h +++ b/src/t8_cmesh/t8_cmesh_examples.h @@ -131,7 +131,7 @@ t8_cmesh_new_hypercube (t8_eclass_t eclass, sc_MPI_Comm comm, int do_bcast, int */ t8_cmesh_t t8_cmesh_new_hypercube_pad (const t8_eclass_t eclass, sc_MPI_Comm comm, const double *boundary, t8_locidx_t polygons_x, - t8_locidx_t polygons_y, t8_locidx_t polygons_z, const t8_geometry_c *geometry); + t8_locidx_t polygons_y, t8_locidx_t polygons_z, const int use_axis_aligned); /** Hybercube with 6 Tets, 6 Prism, 4 Hex. * \param [in] comm The mpi communicator to be used. @@ -321,13 +321,21 @@ t8_cmesh_new_row_of_cubes (t8_locidx_t num_trees, const int set_attributes, cons t8_cmesh_t t8_cmesh_new_squared_disk (const double radius, sc_MPI_Comm comm); -/** Construct a triangulated spherical surface of given radius. +/** Construct a triangulated spherical surface of given radius: octahedron version. * \param [in] radius Radius of the sphere. * \param [in] comm The MPI communicator used to commit the cmesh * \return A cmesh representing the spherical surface. */ t8_cmesh_t -t8_cmesh_new_triangulated_spherical_surface (const double radius, sc_MPI_Comm comm); +t8_cmesh_new_triangulated_spherical_surface_octahedron (const double radius, sc_MPI_Comm comm); + +/** Construct a triangulated spherical surface of given radius: icosahedron version. + * \param [in] radius Radius of the sphere. + * \param [in] comm The MPI communicator used to commit the cmesh + * \return A cmesh representing the spherical surface. + */ +t8_cmesh_t +t8_cmesh_new_triangulated_spherical_surface_icosahedron (const double radius, sc_MPI_Comm comm); /** Construct a quadrangulated spherical surface of given radius. * \param [in] radius Radius of the sphere. @@ -337,6 +345,30 @@ t8_cmesh_new_triangulated_spherical_surface (const double radius, sc_MPI_Comm co t8_cmesh_t t8_cmesh_new_quadrangulated_spherical_surface (const double radius, sc_MPI_Comm comm); +/** Construct a spherical shell discretized by prisms of given inner radius and thickness: octahedron version. + * \param [in] inner_radius Radius of the inner side of the shell. + * \param [in] shell_thickness Thickness of the shell. + * \param [in] num_levels Refinement level per patch in longitudinal and latitudinal direction. + * \param [in] num_layers Number of layers of the shell. + * \param [in] comm The MPI communicator used to commit the cmesh + * \return A cmesh representing the spherical surface. + */ +t8_cmesh_t +t8_cmesh_new_prismed_spherical_shell_octahedron (const double inner_radius, const double shell_thickness, + const int num_levels, const int num_layers, sc_MPI_Comm comm); + +/** Construct a spherical shell discretized by prisms of given inner radius and thickness: icosahedron version. + * \param [in] inner_radius Radius of the inner side of the shell. + * \param [in] shell_thickness Thickness of the shell. + * \param [in] num_levels Refinement level per patch in longitudinal and latitudinal direction. + * \param [in] num_layers Number of layers of the shell. + * \param [in] comm The MPI communicator used to commit the cmesh + * \return A cmesh representing the spherical surface. + */ +t8_cmesh_t +t8_cmesh_new_prismed_spherical_shell_icosahedron (const double inner_radius, const double shell_thickness, + const int num_levels, const int num_layers, sc_MPI_Comm comm); + /** Construct a cubed spherical shell of given inner radius and thickness. * \param [in] inner_radius Radius of the inner side of the shell. * \param [in] shell_thickness Thickness of the shell. diff --git a/src/t8_cmesh/t8_cmesh_readmshfile.cxx b/src/t8_cmesh/t8_cmesh_readmshfile.cxx index c0cc748547..d0ad3522f4 100644 --- a/src/t8_cmesh/t8_cmesh_readmshfile.cxx +++ b/src/t8_cmesh/t8_cmesh_readmshfile.cxx @@ -23,8 +23,8 @@ #include #include #include -#include -#include +#include +#include #include "t8_cmesh_types.h" #include "t8_cmesh_stash.h" @@ -696,25 +696,25 @@ t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, * \param [in] geometry_index The index of the geometry. * \param [in] num_face_nodes The number of the nodes of the surface. * NULL if the geometry is an edge. - * \param [in] geometry_occ The occ_geometry. + * \param [in] geometry_cad The cad_geometry. * \param [in,out] parameters The parameters to be corrected. */ static void t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const int geometry_index, - const int num_face_nodes, const t8_geometry_occ_c *geometry_occ, + const int num_face_nodes, const t8_geometry_cad_c *geometry_cad, double *parameters) { switch (geometry_dim) { /* Check for closed U parameter in case of an edge. */ case 1: /* Only correct the U parameter if the edge is closed. */ - if (geometry_occ->t8_geom_is_edge_closed (geometry_index)) { + if (geometry_cad->t8_geom_is_edge_closed (geometry_index)) { /* Get the parametric bounds of the closed geometry * edge -> [Umin, Umax] */ double parametric_bounds[2]; /* Get the parametric edge bounds. */ - geometry_occ->t8_geom_get_edge_parametric_bounds (geometry_index, parametric_bounds); + geometry_cad->t8_geom_get_edge_parametric_bounds (geometry_index, parametric_bounds); /* Check the upper an the lower parametric bound. */ for (int bound = 0; bound < 2; ++bound) { /* Iterate over both nodes of the edge. */ @@ -746,12 +746,12 @@ t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const in /* Iterate over both parameters. 0 stands for the U parameter an 1 for the V parameter. */ for (int param_dim = 0; param_dim < 2; ++param_dim) { /* Only correct the surface parameters if they are closed */ - if (geometry_occ->t8_geom_is_surface_closed (geometry_index, param_dim)) { + if (geometry_cad->t8_geom_is_surface_closed (geometry_index, param_dim)) { /* Get the parametric bounds of the closed geometry * surface -> [Umin, Umax, Vmin, Vmax] */ double parametric_bounds[4]; - geometry_occ->t8_geom_get_face_parametric_bounds (geometry_index, parametric_bounds); + geometry_cad->t8_geom_get_face_parametric_bounds (geometry_index, parametric_bounds); /* Check the upper an the lower parametric bound. */ for (int bound = 0; bound < 2; ++bound) { /* Iterate over every corner node of the tree. */ @@ -797,13 +797,13 @@ t8_cmesh_correct_parameters_on_closed_geometry (const int geometry_dim, const in * If vertex_indices is not NULL, it is allocated and will store * for each tree the indices of its vertices. * They are stored as arrays of long ints. - * If occ geometry is used, the geometry is passed as a pointer here. + * If cad geometry is used, the geometry is passed as a pointer here. * We cannot access this geometry over the cmesh interface since the cmesh * is not committed yet. */ static int t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, sc_array_t **vertex_indices, int dim, - const t8_geometry_c *linear_geometry_base, const int use_occ_geometry, - const t8_geometry_c *occ_geometry_base) + const t8_geometry_c *linear_geometry_base, const int use_cad_geometry, + const t8_geometry_c *cad_geometry_base) { char *line = (char *) malloc (1024), *line_modify; char first_word[2048] = "\0"; @@ -1003,9 +1003,9 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, *(long **) sc_array_push (*vertex_indices) = stored_indices; } - if (!use_occ_geometry) { + if (!use_cad_geometry) { /* Set the geometry of the tree to be linear. - * If we use an occ geometry, we set the geometry in accordance, + * If we use an cad geometry, we set the geometry in accordance, * if the tree is linked to a geometry or not */ const char *geom_name = linear_geometry_base->t8_geom_get_name (); t8_cmesh_set_tree_geometry (cmesh, tree_count, geom_name); @@ -1013,11 +1013,11 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, else { /* Calculate the parametric geometries of the tree */ #if T8_WITH_OCC - T8_ASSERT (occ_geometry_base->t8_geom_get_type () == T8_GEOMETRY_TYPE_OCC); - const t8_geometry_occ_c *occ_geometry = dynamic_cast (occ_geometry_base); + T8_ASSERT (cad_geometry_base->t8_geom_get_type () == T8_GEOMETRY_TYPE_CAD); + const t8_geometry_cad_c *cad_geometry = dynamic_cast (cad_geometry_base); /* Check for right element class */ if (eclass != T8_ECLASS_TRIANGLE && eclass != T8_ECLASS_QUAD && eclass != T8_ECLASS_HEX) { - t8_errorf ("%s element detected. The occ geometry currently only supports quad, tri and hex elements.", + t8_errorf ("%s element detected. The cad geometry currently only supports quad, tri and hex elements.", t8_eclass_to_string[eclass]); goto die_ele; } @@ -1025,7 +1025,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, double parameters[T8_ECLASS_MAX_CORNERS_2D * 2]; int edge_geometries[T8_ECLASS_MAX_EDGES * 2] = { 0 }; int face_geometries[T8_ECLASS_MAX_FACES] = { 0 }; - /* We look at each face to check, if it is linked to a occ surface */ + /* We look at each face to check, if it is linked to a cad surface */ T8_ASSERT (t8_eclass_to_dimension[eclass] == dim); int num_faces; switch (dim) { @@ -1060,7 +1060,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } } - /* A face can only be linked to an occ surface if all nodes of the face are parametric or on a vertex + /* A face can only be linked to an cad surface if all nodes of the face are parametric or on a vertex * (gmsh labels nodes on vertices as not parametric) */ int all_parametric = 1; for (int i_face_nodes = 0; i_face_nodes < num_face_nodes; ++i_face_nodes) { @@ -1113,7 +1113,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, /* If both nodes are on a vertex we look if both vertices share an edge */ if (node1.entity_dim == 0 && node2.entity_dim == 0) { - int common_edge = occ_geometry->t8_geom_get_common_edge (node1.entity_tag, node2.entity_tag); + int common_edge = cad_geometry->t8_geom_get_common_edge (node1.entity_tag, node2.entity_tag); if (common_edge > 0) { if (edge1_index == 0) { edge1_index = common_edge; @@ -1127,7 +1127,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } } if (edge2_index > 0) { - surface_index = occ_geometry->t8_geom_get_common_face (edge1_index, edge2_index); + surface_index = cad_geometry->t8_geom_get_common_face (edge1_index, edge2_index); } else { continue; @@ -1148,8 +1148,8 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, else { /* If it is on another geometry we retrieve its parameters */ if (face_nodes[i_face_nodes].entity_dim == 0) { - if (occ_geometry->t8_geom_is_vertex_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { - occ_geometry->t8_geom_get_parameters_of_vertex_on_face ( + if (cad_geometry->t8_geom_is_vertex_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { + cad_geometry->t8_geom_get_parameters_of_vertex_on_face ( face_nodes[i_face_nodes].entity_tag, surface_index, face_nodes[i_face_nodes].parameters); face_nodes[i_face_nodes].entity_dim = 2; } @@ -1159,8 +1159,8 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } } if (face_nodes[i_face_nodes].entity_dim == 1) { - if (occ_geometry->t8_geom_is_edge_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { - occ_geometry->t8_geom_edge_parameter_to_face_parameters ( + if (cad_geometry->t8_geom_is_edge_on_face (face_nodes[i_face_nodes].entity_tag, surface_index)) { + cad_geometry->t8_geom_edge_parameter_to_face_parameters ( face_nodes[i_face_nodes].entity_tag, surface_index, num_face_nodes, face_nodes[i_face_nodes].parameters[0], NULL, face_nodes[i_face_nodes].parameters); face_nodes[i_face_nodes].entity_dim = 2; @@ -1173,7 +1173,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } } /* Abort if not all nodes are on the surface or if the surface is a plane */ - if (!all_nodes_on_surface || occ_geometry->t8_geom_is_plane (surface_index)) { + if (!all_nodes_on_surface || cad_geometry->t8_geom_is_plane (surface_index)) { continue; } /* If we have found a surface we link it to the face */ @@ -1200,14 +1200,14 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ for (int param_dim = 0; param_dim < 2; ++param_dim) { - if (occ_geometry->t8_geom_is_surface_closed (surface_index, param_dim)) { - t8_cmesh_correct_parameters_on_closed_geometry (2, surface_index, num_face_nodes, occ_geometry, + if (cad_geometry->t8_geom_is_surface_closed (surface_index, param_dim)) { + t8_cmesh_correct_parameters_on_closed_geometry (2, surface_index, num_face_nodes, cad_geometry, parameters); } } t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + i_tree_faces, parameters, + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + i_tree_faces, parameters, num_face_nodes * 2 * sizeof (double), 0); } } @@ -1256,19 +1256,19 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, int is_on_geom = 1; for (int i_edge = 0; i_edge < 2; ++i_edge) { if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 1) { - if (!occ_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { + if (!cad_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { is_on_geom = 0; break; } } else if (edge_geometry_dim == 2 && edge_nodes[i_edge].entity_dim == 0) { - if (!occ_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { + if (!cad_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { is_on_geom = 0; break; } } else if (edge_geometry_dim == 1 && edge_nodes[i_edge].entity_dim == 0) { - if (!occ_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { + if (!cad_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge].entity_tag, edge_geometry_tag)) { is_on_geom = 0; break; } @@ -1284,7 +1284,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, * If not we can skip this edge. */ if (edge_geometry_dim == 0 && edge_geometry_tag == 0) { int common_curve - = occ_geometry->t8_geom_get_common_edge (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); + = cad_geometry->t8_geom_get_common_edge (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); if (common_curve > 0) { edge_geometry_tag = common_curve; edge_geometry_dim = 1; @@ -1298,7 +1298,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, if (edge_nodes[0].entity_dim == 1 && edge_nodes[1].entity_dim == 1 && edge_nodes[0].entity_tag != edge_nodes[1].entity_tag) { int common_surface - = occ_geometry->t8_geom_get_common_face (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); + = cad_geometry->t8_geom_get_common_face (edge_nodes[0].entity_tag, edge_nodes[1].entity_tag); if (common_surface > 0) { edge_geometry_tag = common_surface; edge_geometry_dim = 2; @@ -1312,7 +1312,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, /* Check if adjacent faces carry a surface and if this edge lies on the surface */ for (int i_adjacent_face = 0; i_adjacent_face < 2; ++i_adjacent_face) { if (face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]] > 0) { - if (!occ_geometry->t8_geom_is_edge_on_face ( + if (!cad_geometry->t8_geom_is_edge_on_face ( edge_geometry_tag, face_geometries[t8_edge_to_face[eclass][i_tree_edges][i_adjacent_face]])) { t8_global_errorf ("Error: Adjacent edge and face of a tree carry " "incompatible geometries.\n"); @@ -1336,7 +1336,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, goto die_ele; } if (edge_nodes[i_edge_node].entity_dim == 0) { - if (!occ_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge_node].entity_tag, + if (!cad_geometry->t8_geom_is_vertex_on_edge (edge_nodes[i_edge_node].entity_tag, edge_geometry_tag)) { t8_global_errorf ("Error: Node %i should lie on a vertex which lies on an edge, " "but the vertex does not lie on that edge.\n", @@ -1347,14 +1347,14 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, /* If the node lies on a vertex we retrieve its parameter on the curve */ if (edge_nodes[i_edge_node].entity_dim == 0) { - occ_geometry->t8_geom_get_parameter_of_vertex_on_edge ( + cad_geometry->t8_geom_get_parameter_of_vertex_on_edge ( edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters); edge_nodes[i_edge_node].entity_dim = 1; } } /* Abort if the edge is a line */ - if (occ_geometry->t8_geom_is_line (edge_geometry_tag)) { + if (cad_geometry->t8_geom_is_line (edge_geometry_tag)) { continue; } @@ -1364,12 +1364,12 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, parameters[1] = edge_nodes[1].parameters[0]; /* Corrects the parameters on the edge if it is closed to prevent disorted elements. */ - if (occ_geometry->t8_geom_is_edge_closed (edge_geometry_tag)) { - t8_cmesh_correct_parameters_on_closed_geometry (1, edge_geometry_tag, 2, occ_geometry, parameters); + if (cad_geometry->t8_geom_is_edge_closed (edge_geometry_tag)) { + t8_cmesh_correct_parameters_on_closed_geometry (1, edge_geometry_tag, 2, cad_geometry, parameters); } t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, 2 * sizeof (double), 0); } /* If we have found a surface we can look for the parameters. @@ -1385,7 +1385,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, goto die_ele; } if (edge_nodes[i_edge_node].entity_dim == 0) { - if (!occ_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge_node].entity_tag, + if (!cad_geometry->t8_geom_is_vertex_on_face (edge_nodes[i_edge_node].entity_tag, edge_geometry_tag)) { t8_global_errorf ("Error: Node %i should lie on a vertex which lies on a face, " "but the vertex does not lie on that face.\n", @@ -1394,7 +1394,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } } if (edge_nodes[i_edge_node].entity_dim == 1) { - if (!occ_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge_node].entity_tag, edge_geometry_tag)) { + if (!cad_geometry->t8_geom_is_edge_on_face (edge_nodes[i_edge_node].entity_tag, edge_geometry_tag)) { t8_global_errorf ("Error: Node %i should lie on an edge which lies on a face, " "but the edge does not lie on that face.\n", edge_nodes[i_edge_node].index); @@ -1404,14 +1404,14 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, /* If the node lies on a vertex we retrieve its parameters on the surface */ if (edge_nodes[i_edge_node].entity_dim == 0) { - occ_geometry->t8_geom_get_parameters_of_vertex_on_face ( + cad_geometry->t8_geom_get_parameters_of_vertex_on_face ( edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, edge_nodes[i_edge_node].parameters); edge_nodes[i_edge_node].entity_dim = 2; } /* If the node lies on an edge we have to do the same */ if (edge_nodes[i_edge_node].entity_dim == 1) { const int num_face_nodes = t8_eclass_num_vertices[eclass]; - occ_geometry->t8_geom_edge_parameter_to_face_parameters ( + cad_geometry->t8_geom_edge_parameter_to_face_parameters ( edge_nodes[i_edge_node].entity_tag, edge_geometry_tag, num_face_nodes, edge_nodes[i_edge_node].parameters[0], parameters, edge_nodes[i_edge_node].parameters); edge_nodes[i_edge_node].entity_dim = 2; @@ -1419,7 +1419,7 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, } /* Abort if the edge is a line */ - if (occ_geometry->t8_geom_is_line (edge_geometry_tag)) { + if (cad_geometry->t8_geom_is_line (edge_geometry_tag)) { continue; } @@ -1432,13 +1432,13 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, /* Corrects the parameters on the surface if it is closed to prevent disorted elements. */ for (int param_dim = 0; param_dim < 2; ++param_dim) { - if (occ_geometry->t8_geom_is_surface_closed (edge_geometry_tag, param_dim)) { - t8_cmesh_correct_parameters_on_closed_geometry (2, edge_geometry_tag, 2, occ_geometry, parameters); + if (cad_geometry->t8_geom_is_surface_closed (edge_geometry_tag, param_dim)) { + t8_cmesh_correct_parameters_on_closed_geometry (2, edge_geometry_tag, 2, cad_geometry, parameters); } } t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), - T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_tree_edges, parameters, 4 * sizeof (double), 0); } } @@ -1448,15 +1448,15 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, edge_geometries[i_edge] = 0; } } - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, face_geometries, num_faces * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, + t8_cmesh_set_attribute (cmesh, tree_count, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edge_geometries, 2 * num_edges * sizeof (int), 0); /* Now we set the tree geometry according to the tree linkage status. */ const char *geom_name; if (tree_is_linked) { - geom_name = occ_geometry_base->t8_geom_get_name (); + geom_name = cad_geometry_base->t8_geom_get_name (); } else { geom_name = linear_geometry_base->t8_geom_get_name (); @@ -1725,28 +1725,28 @@ T8_EXTERN_C_BEGIN (); /* This is a helper function to properly register the * geometries for the cmesh created in t8_cmesh_from_msh_file. * It should be called by all processes of the cmesh. - * Returns 1 on success, 0 on OCC usage error: use_occ_geometry true, but occ not linked. + * Returns 1 on success, 0 on cad usage error: use_cad_geometry true, but OCC not linked. * The linear_geometry pointer will point to the newly created linear geometry. - * The occ_geometry pointer will point to the newly created occ geometry, or to NULL if - * no occ geometry is used. + * The cad_geometry pointer will point to the newly created cad geometry, or to NULL if + * no cad geometry is used. */ static int -t8_cmesh_from_msh_file_register_geometries (t8_cmesh_t cmesh, const int use_occ_geometry, const int dim, +t8_cmesh_from_msh_file_register_geometries (t8_cmesh_t cmesh, const int use_cad_geometry, const int dim, const char *fileprefix, const t8_geometry_c **linear_geometry, - const t8_geometry_c **occ_geometry) + const t8_geometry_c **cad_geometry) { const t8_geometry_c *linear_geom = new t8_geometry_linear (dim); /* Register linear geometry */ t8_cmesh_register_geometry (cmesh, linear_geom); *linear_geometry = linear_geom; - if (use_occ_geometry) { + if (use_cad_geometry) { #if T8_WITH_OCC - const t8_geometry_c *occ_geom = t8_geometry_occ_new (dim, fileprefix, "brep_geometry"); - t8_cmesh_register_geometry (cmesh, occ_geom); - *occ_geometry = occ_geom; + const t8_geometry_c *cad_geom = t8_geometry_cad_new (dim, fileprefix, "brep_geometry"); + t8_cmesh_register_geometry (cmesh, cad_geom); + *cad_geometry = cad_geom; #else /* !T8_WITH_OCC */ - *occ_geometry = NULL; + *cad_geometry = NULL; return 0; #endif } @@ -1755,7 +1755,7 @@ t8_cmesh_from_msh_file_register_geometries (t8_cmesh_t cmesh, const int use_occ_ t8_cmesh_t t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, int dim, int main_proc, - int use_occ_geometry) + int use_cad_geometry) { int mpirank, mpisize, mpiret; t8_cmesh_t cmesh; @@ -1769,7 +1769,7 @@ t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, t8_gloidx_t num_trees, first_tree, last_tree = -1; int main_proc_read_successful = 0; int msh_version; - const t8_geometry_c *occ_geometry = NULL; + const t8_geometry_c *cad_geometry = NULL; const t8_geometry_c *linear_geometry = NULL; mpiret = sc_MPI_Comm_size (comm, &mpisize); @@ -1791,10 +1791,10 @@ t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, /* Register the geometries for the cmesh. */ const int registered_geom_success = t8_cmesh_from_msh_file_register_geometries ( - cmesh, use_occ_geometry, dim, fileprefix, &linear_geometry, &occ_geometry); + cmesh, use_cad_geometry, dim, fileprefix, &linear_geometry, &cad_geometry); if (!registered_geom_success) { /* Registering failed */ - t8_errorf ("OCC is not linked. Cannot use OCC geometry.\n"); + t8_errorf ("cad is not linked. Cannot use cad geometry.\n"); t8_cmesh_destroy (&cmesh); return NULL; } @@ -1833,9 +1833,9 @@ t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, /* read nodes from the file */ switch (msh_version) { case 2: - if (use_occ_geometry) { + if (use_cad_geometry) { fclose (file); - t8_errorf ("WARNING: The occ geometry is only supported for msh files of version 4\n"); + t8_errorf ("WARNING: The cad geometry is only supported for msh files of version 4\n"); t8_cmesh_destroy (&cmesh); if (partition) { /* Communicate to the other processes that reading failed. */ @@ -1850,8 +1850,8 @@ t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, case 4: vertices = t8_msh_file_4_read_nodes (file, &num_vertices, &node_mempool); - t8_cmesh_msh_file_4_read_eles (cmesh, file, vertices, &vertex_indices, dim, linear_geometry, use_occ_geometry, - occ_geometry); + t8_cmesh_msh_file_4_read_eles (cmesh, file, vertices, &vertex_indices, dim, linear_geometry, use_cad_geometry, + cad_geometry); break; default: diff --git a/src/t8_cmesh/t8_cmesh_types.h b/src/t8_cmesh/t8_cmesh_types.h index b391658b30..e412d52392 100644 --- a/src/t8_cmesh/t8_cmesh_types.h +++ b/src/t8_cmesh/t8_cmesh_types.h @@ -52,16 +52,299 @@ typedef struct t8_cprofile t8_cprofile_t; /* Defined below */ * T8_CMESH_NEXT_POSSIBLE_KEY is the first unused key, hence it can be repurposed for different attributes.*/ #define T8_CMESH_VERTICES_ATTRIBUTE_KEY 0 /* Used to store vertex coordinates. */ #define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 1 /* Used to store the name of a tree's geometry. */ -#define T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY 2 /* Used to store which edge is linked to which geometry */ -#define T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY 3 /* Used to store edge parameters */ -#define T8_CMESH_OCC_FACE_ATTRIBUTE_KEY \ - T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY \ +#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 2 /* Used to store which edge is linked to which geometry */ +#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 3 /* Used to store edge parameters */ +#define T8_CMESH_CAD_FACE_ATTRIBUTE_KEY \ + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY \ +T8_ECLASS_MAX_EDGES /* Used to store which face is linked to which surface */ -#define T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY \ - T8_CMESH_OCC_FACE_ATTRIBUTE_KEY + 1 /* Used to store face parameters */ +#define T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY \ + T8_CMESH_CAD_FACE_ATTRIBUTE_KEY + 1 /* Used to store face parameters */ #define T8_CMESH_NEXT_POSSIBLE_KEY \ - T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY \ - +T8_ECLASS_MAX_FACES /* The next free value for a t8code attribute key */ + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES /* The next free value for a t8code attribute key */ + +/** This structure holds the connectivity data of the coarse mesh. + * It can either be replicated, then each process stores a copy of the whole + * mesh, or partitioned. In the latter case, each process only stores a local + * portion of the mesh plus information about ghost elements. + * + * The coarse mesh is a collection of coarse trees that can be identified + * along faces. + * TODO: this description is outdated. rewrite it. + * The array ctrees stores these coarse trees sorted by their (global) tree_id. + * If the mesh if partitioned it is partitioned according to an (possible only + * virtually existing) underlying fine mesh. Therefore the ctrees array can + * store duplicated trees on different processes, if each of these processes + * owns elements of the same tree in the fine mesh. + * + * Each tree stores information about its face-neighbours in an array of + * \ref t8_ctree_fneighbor. \see t8_ctree_fneighbor + * + * If partitioned the ghost trees are stored in a hash table that is backed up + * by an array. The hash value of a ghost tree is its tree_id modulo the number + * of ghosts on this process. + */ +typedef struct t8_cmesh +{ + /* TODO: make the comments more legible */ + int committed; /**< Flag that specifies whether the cmesh is committed or not. \ref t8_cmesh_commit */ + int dimension; /**< The dimension of the cmesh. It is set when the first tree is inserted. */ + + int set_partition; /**< If nonzero the cmesh is partitioned. + If zero each process has the whole cmesh. */ + int face_knowledge; /**< If partitioned the level of face knowledge that is expected. \ref t8_mesh_set_partitioned; + see \ref t8_cmesh_set_partition. +*/ + + t8_scheme_cxx_t *set_partition_scheme; /**< If the cmesh is to be partitioned according to a uniform level, + the scheme that describes the refinement pattern. See \ref t8_cmesh_set_partition. */ + int8_t set_partition_level; /**< Non-negative if the cmesh should be partitioned from an already existing cmesh + with an assumed \a level uniform mesh underneath. */ + struct t8_cmesh *set_from; /**< If this cmesh shall be derived from an + existing cmesh by copy or more elaborate + modification, we store a pointer to this + other cmesh here. */ + int mpirank; /**< Number of this MPI process. */ + int mpisize; /**< Number of MPI processes. */ + t8_refcount_t rc; /**< The reference count of the cmesh. */ + t8_gloidx_t num_trees; /**< The global number of trees */ + t8_locidx_t num_local_trees; /**< If partitioned the number of trees on this process. + Otherwise the global number of trees. */ + t8_locidx_t num_ghosts; /**< If partitioned the number of neighbor trees + owned by different processes. */ + /* TODO: wouldnt a local num_trees_per_eclass be better? + * only as an additional info. we need the global count. i.e. for forest_maxlevel computation. + */ + t8_locidx_t num_local_trees_per_eclass[T8_ECLASS_COUNT]; /**< After commit the number of local + trees for each eclass. + Stores the same entries as \a num_trees_per_eclass, + if the cmesh is replicated. */ + t8_gloidx_t num_trees_per_eclass[T8_ECLASS_COUNT]; /**< After commit the number of global + trees for each eclass. */ + + t8_cmesh_trees_t trees; /**< structure that holds all local trees and ghosts */ + + t8_gloidx_t first_tree; /**< The global index of the first local tree on this process. + Zero if the cmesh is not partitioned. -1 if this processor is empty. + See also https://github.com/DLR-AMR/t8code/wiki/Tree-indexing */ + int8_t first_tree_shared; /**< If partitioned true if the first tree on this process is also the last tree + on the next process. Always zero if num_local_trees = 0 */ + + t8_shmem_array_t tree_offsets; /**< If partitioned for each process the global index of its first local tree + or -(first local tree) - 1 + if the first tree on that process is shared. + Since this is very memory consuming we only fill it when needed. */ + + t8_geometry_handler_t *geometry_handler; /**< Handles all geometries that are used by trees in this cmesh. */ + +#ifdef T8_ENABLE_DEBUG + t8_locidx_t inserted_trees; /**< Count the number of inserted trees to + check at commit if it equals the total number. */ + t8_locidx_t inserted_ghosts; /**< Count the number of inserted ghosts to + check at commit if it equals the total number. */ +#endif + t8_stash_t stash; /**< Used as temporary storage for the trees before commit. */ + t8_cprofile_t *profile; /**< Used to measure runtimes and statistics of the cmesh algorithms. */ +} t8_cmesh_struct_t; + +/* TODO: cghost could be the same type as ctree. + * treeid for ghosts then negative?! + * 1. typedef cghost ctree + * 2. completely replace + */ +/* TODO: document */ +typedef struct t8_cghost +{ + t8_gloidx_t treeid; /**< The global number of this ghost. */ + t8_eclass_t eclass; /**< The eclass of this ghost. */ + size_t neigh_offset; /** Offset to the array of face neighbors of this ghost. + This count has to be added to the address of the ghost to get its face neighbors. */ + size_t att_offset; /**< Adding this offset to the address of the ghost + yields the array of attribute_info entries */ + /* TODO: Could be a size_t */ + int num_attributes; /**< The number of attributes at this ghost */ +} t8_cghost_struct_t; + +/** This structure holds the data of a local tree including the information + * about face neighbors. For those + * the tree_to_face index is computed as follows. + * Let F be the maximal number of faces of any eclass of the cmesh's dimension, then + * ttf % F is the face number and ttf / F is the orientation. (\ref t8_eclass_max_num_faces) + * The orientation is determined as follows. Let my_face and other_face + * be the two face numbers of the connecting trees. + * We chose a main_face from them as follows: Either both trees have the same + * element class, then the face with the lower face number is the main_face or + * the trees belong to different classes in which case the face belonging to the + * tree with the lower class according to the ordering + * triangle < square, + * hex < tet < prism < pyramid, + * is the main_face. + * Then face corner 0 of the main_face connects to a face + * corner k in the other face. The face orientation is defined as the number k. + * If the classes are equal and my_face == other_face, treating + * either of both faces as the main_face leads to the same result. + * See https://arxiv.org/pdf/1611.02929.pdf for more details. + */ +typedef struct t8_ctree +{ + t8_locidx_t treeid; /**< The local number of this tree. */ + /* TODO: The local id of a tree should be clear from context, the entry can + * be optimized out. */ + t8_eclass_t eclass; /**< The eclass of this tree. */ + size_t neigh_offset; /**< Adding this offset to the address of the tree + yields the array of face_neighbor entries */ + size_t att_offset; /**< Adding this offset to the address of the tree + yields the array of attribute_info entries */ + /* TODO: Could be a size_t */ + int num_attributes; /**< The number of attributes at this tree */ +} t8_ctree_struct_t; + +/** This structure holds the information associated to an attribute of a tree. + * The attributes of each are stored in a key-value storage, where the key consists + * of the two entries (package_id,key) both being integers. + * The package_id serves to identify the application layer that added the attribute + * and the key identifies the attribute within that application layer. + * + * All attribute info objects of one tree are stored in an array and adding + * a tree's att_offset entry to the tree's address yields this array. + * The attributes themselves are stored in an array directly behind the array of + * the attribute infos. + */ +typedef struct t8_attribute_info +{ + int package_id; + /**< The identifier of the application layer that added this attribute */ + int key; + /**< The (tree unique) key of the attribute within this AL. */ + size_t attribute_offset; + /**< The offset of the attribute data from the first + attribute info of the tree. + (Thus, the attribute is stored at address tree + tree->att_offset + attribute_offset) */ + /* TODO: eventually remove the size */ + size_t attribute_size; + /**< The size in bytes of the attribute */ +} t8_attribute_info_struct_t; + +/* TODO: document, process is a bad naming, since it does not refer to MPI ranks here */ +typedef struct t8_cmesh_trees +{ + sc_array_t *from_proc; /* array of t8_part_tree, one for each process */ + int *tree_to_proc; /* for each tree its process */ + int *ghost_to_proc; /* for each ghost its process */ + sc_hash_t *ghost_globalid_to_local_id; /* A hash table storing the map + global_id -> local_id for the ghost trees. + The local_id is the local ghost id starting at num_local_trees */ + sc_mempool_t *global_local_mempool; /* Memory pool for the entries in the hash table */ +} t8_cmesh_trees_struct_t; + +/* TODO: document */ +typedef struct t8_part_tree +{ + char *first_tree; /* Stores the trees, the ghosts and the attributes. + The last 2*sizeof(t8_locidx) bytes store num_trees and num_ghosts */ + t8_locidx_t first_tree_id; /* local tree_id of the first tree. -1 if num_trees = 0 */ + t8_locidx_t first_ghost_id; /* TODO: document. -1 if num_ghost=0, 0 for the first part, (not num_local_trees!) + 0 <= first_ghost_id < num_ghosts */ + t8_locidx_t num_trees; + t8_locidx_t num_ghosts; +} t8_part_tree_struct_t; + +/* TODO: Extend this structure with meaningful entries. + * Maybe the number of shipped trees per process is useful? + */ +/** This struct is used to profile cmesh algorithms. + * The cmesh struct stores a pointer to a profile struct, and if + * it is nonzero, various runtimes and data measurements are stored here. + * \see t8_cmesh_set_profiling and \see t8_cmesh_print_profile + */ +typedef struct t8_cprofile +{ + t8_locidx_t partition_trees_shipped; /**< The number of trees this process has + sent to other in the last partition call. */ + t8_locidx_t partition_ghosts_shipped; /**< The number of ghosts this process has + sent to other in the last partition call. */ + t8_locidx_t partition_trees_recv; /**< The number of trees this process has + received from other in the last partition call. */ + t8_locidx_t partition_ghosts_recv; /**< The number of ghosts this process has + received from other in the last partition call. */ + size_t partition_bytes_sent; /**< The total number of bytes sent to other processes in the + last partition call. */ + int partition_procs_sent; /**< The number of different processes this process has send + local trees or ghosts to in the last partition call. */ + int first_tree_shared; /**< 1 if this processes' first tree is shared. 0 if not. */ + double partition_runtime; /**< The runtime of the last call to \a t8_cmesh_partition. */ + double commit_runtime; /**< The runtime of the last call to \a t8_cmesh_commit. */ + double geometry_evaluate_num_calls; /**< The number of calls to \a t8_geometry_evaluate. */ + double geometry_evaluate_runtime; /**< The accumulated runtime of calls to \a t8_geometry_evaluate. */ +} t8_cprofile_struct_t; + +/** The number of entries in a cprofile struct */ +#define T8_CPROFILE_NUM_STATS 11 + +#endif /* !T8_CMESH_TYPES_H */ + +/* + 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. +*/ + +#ifndef T8_CMESH_TYPES_H +#define T8_CMESH_TYPES_H + +#include +#include +#include +#include +#include "t8_cmesh_stash.h" +#include "t8_element.h" + +/** \file t8_cmesh_types.h + * We define here the datatypes needed for internal cmesh routines. + */ + +typedef struct t8_part_tree *t8_part_tree_t; +typedef struct t8_cmesh_trees *t8_cmesh_trees_t; +typedef struct t8_cprofile t8_cprofile_t; /* Defined below */ + +/* TODO: no longer needed. + * User may use set_derived_from, then set_from is non-NULL. + * When refinement is desired, level shall be set positive. + * When partition is desired, we expect set_partition to be true. + * Any combination can be called. + * In t8_commit we check whether the parameters are consistent, + * and whether a combination is currently supported, + * and provide informative error messages both in debug and non-debug. + */ + +/* Definitions for attribute identifiers that are reserved for a special purpose. + * T8_CMESH_NEXT_POSSIBLE_KEY is the first unused key, hence it can be repurposed for different attributes.*/ +#define T8_CMESH_VERTICES_ATTRIBUTE_KEY 0 /* Used to store vertex coordinates. */ +#define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 1 /* Used to store the name of a tree's geometry. */ +#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 2 /* Used to store which edge is linked to which geometry */ +#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 3 /* Used to store edge parameters */ +#define T8_CMESH_CAD_FACE_ATTRIBUTE_KEY \ + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY \ + +T8_ECLASS_MAX_EDGES /* Used to store which face is linked to which surface */ +#define T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY \ + T8_CMESH_CAD_FACE_ATTRIBUTE_KEY + 1 /* Used to store face parameters */ +#define T8_CMESH_NEXT_POSSIBLE_KEY \ + T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + T8_ECLASS_MAX_FACES /* The next free value for a t8code attribute key */ /** This structure holds the connectivity data of the coarse mesh. * It can either be replicated, then each process stores a copy of the whole diff --git a/src/t8_cmesh/t8_cmesh_vtk_writer.c b/src/t8_cmesh/t8_cmesh_vtk_writer.c index 9008c2e369..53bf54b0f4 100644 --- a/src/t8_cmesh/t8_cmesh_vtk_writer.c +++ b/src/t8_cmesh/t8_cmesh_vtk_writer.c @@ -55,14 +55,12 @@ t8_cmesh_get_num_vertices (t8_cmesh_t cmesh, int count_ghosts) return num_vertices; } -/* TODO: implement for scale < 1 */ static int -t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double scale, int write_ghosts) +t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, int write_ghosts) { T8_ASSERT (cmesh != NULL); T8_ASSERT (t8_cmesh_is_committed (cmesh)); T8_ASSERT (fileprefix != NULL); - T8_ASSERT (scale == 1.); /* scale = 1 not implemented yet */ if (cmesh->mpirank == 0) { /* Write the pvtu header file. */ @@ -103,9 +101,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } fprintf (vtufile, "\n"); fprintf (vtufile, "\n"); #else @@ -122,7 +117,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc " NumberOfComponents=\"3\" format=\"%s\">\n", T8_VTK_FLOAT_NAME, T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII for (tree = t8_cmesh_get_first_tree (cmesh); tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree)) { /* TODO: Use new geometry here. Need cmesh_get_reference coords function. */ vertices = t8_cmesh_get_tree_vertices (cmesh, tree->treeid); @@ -163,9 +157,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } } /* end ghost loop */ } -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); fprintf (vtufile, " \n"); fprintf (vtufile, " \n"); @@ -175,7 +166,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc " \n", T8_VTK_LOCIDX, T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII for (tree = t8_cmesh_get_first_tree (cmesh), count_vertices = 0; tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree)) { fprintf (vtufile, " "); @@ -195,9 +185,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc fprintf (vtufile, "\n"); } } -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); /* write offset data */ @@ -205,7 +192,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc " \n", T8_VTK_LOCIDX, T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII fprintf (vtufile, " "); for (tree = t8_cmesh_get_first_tree (cmesh), sk = 1, offset = 0; tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree), ++sk) { @@ -225,16 +211,12 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } } fprintf (vtufile, "\n"); -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); /* write type data */ fprintf (vtufile, " \n", T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII fprintf (vtufile, " "); for (tree = t8_cmesh_get_first_tree (cmesh), sk = 1; tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree), ++sk) { @@ -252,9 +234,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } } fprintf (vtufile, "\n"); -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); fprintf (vtufile, " \n"); /* write treeif data */ @@ -263,7 +242,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc " \n", T8_VTK_GLOIDX, T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII fprintf (vtufile, " "); for (tree = t8_cmesh_get_first_tree (cmesh), sk = 1, offset = 0; tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree), ++sk) { @@ -292,16 +270,12 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } } fprintf (vtufile, "\n"); -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); /* write mpirank data */ fprintf (vtufile, " \n", "Int32", T8_VTK_FORMAT_STRING); -#ifdef T8_VTK_ASCII fprintf (vtufile, " "); for (tree = t8_cmesh_get_first_tree (cmesh), sk = 1, offset = 0; tree != NULL; tree = t8_cmesh_get_next_tree (cmesh, tree), ++sk) { @@ -318,9 +292,6 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } } fprintf (vtufile, "\n"); -#else - SC_ABORT ("Binary vtk file not implemented\n"); -#endif /* T8_VTK_ASCII */ fprintf (vtufile, " \n"); fprintf (vtufile, " \n"); /* write type data */ @@ -333,8 +304,7 @@ t8_cmesh_vtk_write_file_ext (t8_cmesh_t cmesh, const char *fileprefix, double sc } int -t8_cmesh_vtk_write_file (t8_cmesh_t cmesh, const char *fileprefix, double scale) +t8_cmesh_vtk_write_file (t8_cmesh_t cmesh, const char *fileprefix) { - T8_ASSERT (scale == 1.0); - return t8_cmesh_vtk_write_file_ext (cmesh, fileprefix, 1.0, 1); + return t8_cmesh_vtk_write_file_ext (cmesh, fileprefix, 1); } diff --git a/src/t8_cmesh_readmshfile.h b/src/t8_cmesh_readmshfile.h index e63f468dd3..5acfeaddc9 100644 --- a/src/t8_cmesh_readmshfile.h +++ b/src/t8_cmesh_readmshfile.h @@ -87,14 +87,14 @@ T8_EXTERN_C_BEGIN (); * dimension to read has to be set manually. * \param [in] master If partition is true, a valid MPI rank that will * read the file and store all the trees alone. - * \param [in] use_occ_geometry Read the parameters of a parametric msh file and use the - * occ geometry. + * \param [in] use_cad_geometry Read the parameters of a parametric msh file and use the + * cad geometry. * \return A committed cmesh holding the mesh of dimension \a dim in the * specified .msh file. */ t8_cmesh_t t8_cmesh_from_msh_file (const char *fileprefix, int partition, sc_MPI_Comm comm, int dim, int master, - int use_occ_geometry); + int use_cad_geometry); T8_EXTERN_C_END (); diff --git a/src/t8_cmesh_vtk_writer.h b/src/t8_cmesh_vtk_writer.h index cf1f14a5db..7283bc7471 100644 --- a/src/t8_cmesh_vtk_writer.h +++ b/src/t8_cmesh_vtk_writer.h @@ -36,7 +36,7 @@ T8_EXTERN_C_BEGIN (); /* TODO: document this function */ int -t8_cmesh_vtk_write_file (t8_cmesh_t cmesh, const char *fileprefix, double scale); +t8_cmesh_vtk_write_file (t8_cmesh_t cmesh, const char *fileprefix); T8_EXTERN_C_END (); diff --git a/src/t8_element_c_interface.cxx b/src/t8_element_c_interface.cxx index 1f0ee7a733..4dc8721a04 100644 --- a/src/t8_element_c_interface.cxx +++ b/src/t8_element_c_interface.cxx @@ -383,19 +383,19 @@ t8_element_vertex_reference_coords (const t8_eclass_scheme_c *ts, const t8_eleme } t8_gloidx_t -t8_element_count_leafs (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level) +t8_element_count_leaves (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level) { T8_ASSERT (ts != NULL); - return ts->t8_element_count_leafs (t, level); + return ts->t8_element_count_leaves (t, level); } t8_gloidx_t -t8_element_count_leafs_from_root (const t8_eclass_scheme_c *ts, int level) +t8_element_count_leaves_from_root (const t8_eclass_scheme_c *ts, int level) { T8_ASSERT (ts != NULL); - return ts->t8_element_count_leafs_from_root (level); + return ts->t8_element_count_leaves_from_root (level); } void diff --git a/src/t8_element_c_interface.h b/src/t8_element_c_interface.h index 52b11ab2c0..60eef83a43 100644 --- a/src/t8_element_c_interface.h +++ b/src/t8_element_c_interface.h @@ -507,7 +507,7 @@ t8_element_shape (const t8_eclass_scheme_c *ts, const t8_element_t *elem); * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ void t8_element_set_linear_id (const t8_eclass_scheme_c *ts, t8_element_t *elem, int level, t8_linearidx_t id); @@ -584,19 +584,19 @@ t8_element_vertex_reference_coords (const t8_eclass_scheme_c *ts, const t8_eleme * Thus, if \a t's level is 0, and \a level = 3, the return value is 2^3 = 8. */ t8_gloidx_t -t8_element_count_leafs (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level); +t8_element_count_leaves (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level); /** Count how many leaf descendants of a given uniform level the root element will produce. * \param [in] ts Implementation of a class scheme. * \param [in] level A refinement level. - * \return The value of \ref t8_element_count_leafs if the input element + * \return The value of \ref t8_element_count_leaves if the input element * is the root (level 0) element. * * This is a convenience function, and can be implemented via - * \ref t8_element_count_leafs. + * \ref t8_element_count_leaves. */ t8_gloidx_t -t8_element_count_leafs_from_root (const t8_eclass_scheme_c *ts, int level); +t8_element_count_leaves_from_root (const t8_eclass_scheme_c *ts, int level); /** This function has no defined effect but each implementation is free to * provide its own meaning of it. Thus this function can be used to compute or diff --git a/src/t8_element_cxx.hxx b/src/t8_element_cxx.hxx index 258c6dffc4..e2135a701c 100644 --- a/src/t8_element_cxx.hxx +++ b/src/t8_element_cxx.hxx @@ -547,7 +547,7 @@ struct t8_eclass_scheme * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const @@ -641,19 +641,19 @@ struct t8_eclass_scheme * Thus, if \a t's level is 0, and \a level = 3, the return value is 2^3 = 8. */ virtual t8_gloidx_t - t8_element_count_leafs (const t8_element_t *t, int level) const + t8_element_count_leaves (const t8_element_t *t, int level) const = 0; /** Count how many leaf descendants of a given uniform level the root element will produce. * \param [in] level A refinement level. - * \return The value of \ref t8_element_count_leafs if the input element + * \return The value of \ref t8_element_count_leaves if the input element * is the root (level 0) element. * * This is a convenience function, and can be implemented via - * \ref t8_element_count_leafs. + * \ref t8_element_count_leaves. */ virtual t8_gloidx_t - t8_element_count_leafs_from_root (int level) const + t8_element_count_leaves_from_root (int level) const = 0; /** This function has no defined effect but each implementation is free to diff --git a/src/t8_forest/t8_forest.c b/src/t8_forest/t8_forest.c index 0f414c220e..7a0a6c397c 100644 --- a/src/t8_forest/t8_forest.c +++ b/src/t8_forest/t8_forest.c @@ -837,7 +837,7 @@ t8_forest_get_tree_vertices (t8_forest_t forest, t8_locidx_t ltreeid) } t8_element_array_t * -t8_forest_tree_get_leafs (const t8_forest_t forest, const t8_locidx_t ltree_id) +t8_forest_tree_get_leaves (const t8_forest_t forest, const t8_locidx_t ltree_id) { T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (0 <= ltree_id && ltree_id < t8_forest_get_num_local_trees (forest)); @@ -1061,6 +1061,29 @@ t8_forest_get_local_id (const t8_forest_t forest, const t8_gloidx_t gtreeid) return -1; } } +t8_locidx_t +t8_forest_get_local_or_ghost_id (const t8_forest_t forest, const t8_gloidx_t gtreeid) +{ + t8_gloidx_t ltreeid; + T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (0 <= gtreeid && gtreeid < t8_forest_get_num_global_trees (forest)); + + /* If the tree is local then its local id is the global id minus the + * first global tree id on this forest. If this number is not in the + * range of local tree ids then the tree is not local. */ + /* we use a gloidx for ltreeid to prevent overflow and false positives */ + ltreeid = gtreeid - t8_forest_get_first_local_tree_id (forest); + /* Check if this tree is a local tree and if so return its local id */ + if (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (forest)) { + return ltreeid; + } + else { + t8_locidx_t ghost_id = t8_forest_ghost_get_ghost_treeid (forest, gtreeid); + if (ghost_id >= 0) + return t8_forest_get_num_local_trees (forest) + ghost_id; + return -1; + } +} t8_locidx_t t8_forest_ltreeid_to_cmesh_ltreeid (t8_forest_t forest, t8_locidx_t ltreeid) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index eca88d80c8..8c060c3c37 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -38,6 +38,7 @@ #include #if T8_ENABLE_DEBUG #include +#include #endif /* We want to export the whole implementation to be callable from "C" */ @@ -1088,325 +1089,16 @@ t8_forest_element_face_normal (t8_forest_t forest, t8_locidx_t ltreeid, const t8 } } -/** - * Check if a point lies inside a vertex - * - * \param[in] vertex_coords The coordinates of the vertex - * \param[in] point The coordinates of the point to check - * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. - */ -static int -t8_vertex_point_inside (const double vertex_coords[3], const double point[3], const double tolerance) -{ - T8_ASSERT (tolerance > 0); - if (t8_vec_dist (vertex_coords, point) > tolerance) { - return 0; - } - return 1; -} - -/** - * Check if a point is inside a line that is defined by a starting point \a p_0 - * and a vector \a vec - * - * \param[in] p_0 Starting point of the line - * \param[in] vec Direction of the line (not normalized) - * \param[in] point The coordinates of the point to check - * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. - */ -static int -t8_line_point_inside (const double *p_0, const double *vec, const double *point, const double tolerance) -{ - T8_ASSERT (tolerance > 0); - double b[3]; - /* b = p - p_0 */ - t8_vec_axpyz (p_0, point, b, -1); - double x = 0; /* Initialized to prevent compiler warning. */ - int i; - /* So x is the solution to - * vec * x = b. - * We can compute it as - * x = b[i] / vec[i] - * if any vec[i] is not 0. - * - * Otherwise the line is degenerated (which should not happen). - */ - for (i = 0; i < 3; ++i) { - if (vec[i] != 0) { - x = b[i] / vec[i]; - break; /* found a non-zero coordinate. We can stop now. */ - } - } - - /* If i == 3 here, then vec = 0 and hence the line is degenerated. */ - SC_CHECK_ABORT (i < 3, "Degenerated line element. Both endpoints are the same."); - - if (x < -tolerance || x > 1 + tolerance) { - /* x is not an admissible solution. */ - return 0; - } - - /* we can check whether x gives us a solution by - * checking whether - * vec * x = b - * is actually true. - */ - double vec_check[3] = { vec[0], vec[1], vec[2] }; - t8_vec_ax (vec_check, x); - if (t8_vec_dist (vec_check, b) > tolerance) { - /* Point does not lie on the line. */ - return 0; - } - /* The point is on the line. */ - return 1; -} - -/** - * Check if a point is inside of a triangle described by a point \a p_0 and two vectors \a v and \a w. - * - * \param[in] p_0 The first vertex of a triangle - * \param[in] v The vector from p_0 to p_1 (second vertex in the triangle) - * \param[in] w The vector from p_0 to p_2 (third vertex in the triangle) - * \param[in] point The coordinates of the point to check - * \param[in] tolerance A double > 0 defining the tolerance - * \return 0 if the point is outside, 1 otherwise. - */ -static int -t8_triangle_point_inside (const double p_0[3], const double v[3], const double w[3], const double point[3], - const double tolerance) -{ - /* A point p is inside the triangle that is spanned - * by the point p_0 and vectors v and w if and only if the linear system - * vx + wy = point - p_0 - * has a solution with 0 <= x,y and x + y <= 1. - * - * We check whether such a solution exists by computing - * certain determinants of 2x2 submatrizes of the 3x3 matrix - * - * | v w e_3 | with v = p_1 - p_0, w = p_2 - p_0, and e_3 = (0 0 1)^t (third unit vector) - */ - - T8_ASSERT (tolerance > 0); /* negative values and zero are not allowed */ - double b[3]; - /* b = point - p_0 */ - t8_vec_axpyz (p_0, point, b, -1); - - /* Let d = det (v w e_3) */ - const double det_vwe3 = v[0] * w[1] - v[1] * w[0]; - - /* The system has a solution, we need to compute it and - * check whether 0 <= x,y and x + y <= 1 */ - /* x = det (b w e_3) / d - * y = det (v b e_3) / d - */ - const double x = (b[0] * w[1] - b[1] * w[0]) / det_vwe3; - const double y = (v[0] * b[1] - v[1] * b[0]) / det_vwe3; - - if (x < -tolerance || y < -tolerance || x + y > 1 + tolerance) { - /* The solution is not admissible. - * x < 0 or y < 0 or x + y > 1 */ - return 0; - } - /* The solution may be admissible, but we have to - * check whether the result of - * (p_1 - p_0)x + (p_2 - p_0)y ( = vx + wy) - * is actually p - p_0. - * Since the system of equations is overrepresented (3 equations, 2 variables) - * this may actually break. - * If it breaks, it will break in the z coordinate of the result. - */ - const double z = v[2] * x + w[2] * y; - /* Must match the last coordinate of b = p - p_0 */ - if (fabs (z - b[2]) > tolerance) { - /* Does not match. Point lies outside. */ - return 0; - } - /* All checks passed. Point lies inside. */ - return 1; -} - -/** Check if a point lays on the inner side of a plane of a bilinearly interpolated volume element. - * the plane is described by a point and the normal of the face. - * \param[in] point_on_face A point on the plane - * \param[in] face_normal The normal of the face - * \param[in] point The point to check - * \return 0 if the point is outside, 1 otherwise. - */ -static int -t8_plane_point_inside (const double point_on_face[3], const double face_normal[3], const double point[3]) -{ - /* Set x = x - p */ - double pof[3] = { point_on_face[0], point_on_face[1], point_on_face[2] }; - t8_vec_axpy (point, pof, -1); - /* Compute */ - const double dot_product = t8_vec_dot (pof, face_normal); - if (dot_product < 0) { - /* The point is on the wrong side of the plane */ - return 0; - } - return 1; -} - void -t8_forest_element_point_batch_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, - const double *points, int num_points, int *is_inside, const double tolerance) +t8_forest_element_points_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, int num_points, int *is_inside, const double tolerance) { - const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); - t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); - const t8_element_shape_t element_shape = ts->t8_element_shape (element); - -#if T8_ENABLE_DEBUG /* Check whether the provided geometry is linear */ const t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); const t8_locidx_t cltreeid = t8_forest_ltreeid_to_cmesh_ltreeid (forest, ltreeid); const t8_gloidx_t cgtreeid = t8_cmesh_get_global_id (cmesh, cltreeid); - T8_ASSERT (t8_geometry_get_type (cmesh, cgtreeid) == T8_GEOMETRY_TYPE_LINEAR); -#endif - - switch (element_shape) { - case T8_ECLASS_VERTEX: { - /* A point is 'inside' a vertex if they have the same coordinates */ - double vertex_coords[3]; - /* Get the vertex coordinates */ - t8_forest_element_coordinate (forest, ltreeid, element, 0, vertex_coords); - /* Check whether the point and the vertex are within tolerance distance - * to each other */ - for (int ipoint = 0; ipoint < num_points; ipoint++) { - is_inside[ipoint] = t8_vertex_point_inside (vertex_coords, &points[ipoint * 3], tolerance); - } - return; - } - case T8_ECLASS_LINE: { - /* A point p is inside a line that is defined by the edge nodes - * p_0 and p_1 - * if and only if the linear system - * (p_1 - p_0)x = p - p_0 - * has a solution x with 0 <= x <= 1 - */ - double p_0[3], v[3]; - - /* Compute the vertex coordinates of the line */ - t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); - /* v = p_1 */ - t8_forest_element_coordinate (forest, ltreeid, element, 1, v); - /* v = p_1 - p_0 */ - t8_vec_axpy (p_0, v, -1); - for (int ipoint = 0; ipoint < num_points; ipoint++) { - is_inside[ipoint] = t8_line_point_inside (p_0, v, &points[ipoint * 3], tolerance); - } - return; - } - case T8_ECLASS_QUAD: { - /* We divide the quad in two triangles and use the triangle check. */ - double p_0[3], p_1[3], p_2[3], p_3[3]; - /* Compute the vertex coordinates of the quad */ - t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); - t8_forest_element_coordinate (forest, ltreeid, element, 1, p_1); - t8_forest_element_coordinate (forest, ltreeid, element, 2, p_2); - t8_forest_element_coordinate (forest, ltreeid, element, 3, p_3); - -#if T8_ENABLE_DEBUG - /* Issue a warning if the points of the quad do not lie in the same plane */ - if (!t8_four_points_coplanar (p_0, p_1, p_2, p_3, tolerance)) { - t8_debugf ("WARNING: Testing if point is inside a quad that is not coplanar. This test will be inaccurate.\n"); - } -#endif - double v[3]; - double w[3]; - /* v = v - p_0 = p_1 - p_0 */ - t8_vec_axpyz (p_0, p_1, v, -1); - /* w = w - p_0 = p_2 - p_0 */ - t8_vec_axpyz (p_0, p_2, w, -1); - /* Check whether the point is inside the first triangle. */ - for (int ipoint = 0; ipoint < num_points; ipoint++) { - is_inside[ipoint] = t8_triangle_point_inside (p_0, v, w, &points[ipoint * 3], tolerance); - } - /* If not, check whether the point is inside the second triangle. */ - /* v = v - p_0 = p_1 - p_0 */ - t8_vec_axpyz (p_1, p_2, v, -1); - /* w = w - p_0 = p_2 - p_0 */ - t8_vec_axpyz (p_1, p_3, w, -1); - for (int ipoint = 0; ipoint < num_points; ipoint++) { - if (!is_inside[ipoint]) { - /* point_inside is true if the point was inside the first or second triangle. Otherwise it is false. */ - is_inside[ipoint] = t8_triangle_point_inside (p_1, v, w, &points[ipoint * 3], tolerance); - } - } - return; - } - case T8_ECLASS_TRIANGLE: { - double p_0[3], p_1[3], p_2[3]; - - /* Compute the vertex coordinates of the triangle */ - t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); - t8_forest_element_coordinate (forest, ltreeid, element, 1, p_1); - t8_forest_element_coordinate (forest, ltreeid, element, 2, p_2); - double v[3]; - double w[3]; - /* v = v - p_0 = p_1 - p_0 */ - t8_vec_axpyz (p_0, p_1, v, -1); - /* w = w - p_0 = p_2 - p_0 */ - t8_vec_axpyz (p_0, p_2, w, -1); - - for (int ipoint = 0; ipoint < num_points; ipoint++) { - is_inside[ipoint] = t8_triangle_point_inside (p_0, v, w, &points[ipoint * 3], tolerance); - } - return; - } - case T8_ECLASS_TET: - case T8_ECLASS_HEX: - case T8_ECLASS_PRISM: - case T8_ECLASS_PYRAMID: { - /* For bilinearly interpolated volume elements, a point is inside an element - * if and only if it lies on the inner side of each face. - * The inner side is defined as the side where the outside normal vector does not - * point to. - * The point is on this inner side if and only if the scalar product of - * a point on the plane minus the point with the outer normal of the face - * is >= 0. - * - * In other words, let p be the point to check, n the outer normal and x a point - * on the plane, then p is on the inner side if and only if - * >= 0 - */ - - const int num_faces = ts->t8_element_num_faces (element); - /* Assume that every point is inside of the element */ - for (int ipoint = 0; ipoint < num_points; ipoint++) { - is_inside[ipoint] = 1; - } - for (int iface = 0; iface < num_faces; ++iface) { - double face_normal[3]; - /* Compute the outer normal n of the face */ - t8_forest_element_face_normal (forest, ltreeid, element, iface, face_normal); - /* Compute a point x on the face */ - const int afacecorner = ts->t8_element_get_face_corner (element, iface, 0); - double point_on_face[3]; - t8_forest_element_coordinate (forest, ltreeid, element, afacecorner, point_on_face); - for (int ipoint = 0; ipoint < num_points; ipoint++) { - const int is_inside_iface = t8_plane_point_inside (point_on_face, face_normal, &points[ipoint * 3]); - if (is_inside_iface == 0) { - /* Point is on the outside of face iface. Update is_inside */ - is_inside[ipoint] = 0; - } - } - } - return; - } - default: - SC_ABORT_NOT_REACHED (); - } -} - -int -t8_forest_element_point_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, - const double point[3], const double tolerance) -{ - int is_inside = 0; - t8_forest_element_point_batch_inside (forest, ltreeid, element, point, 1, &is_inside, tolerance); - return is_inside; + const t8_geometry_c *geometry = t8_cmesh_get_tree_geometry (cmesh, cgtreeid); + geometry->t8_geom_point_batch_inside_element (forest, ltreeid, element, points, num_points, is_inside, tolerance); } /* For each tree in a forest compute its first and last descendant */ @@ -1511,7 +1203,7 @@ t8_forest_populate (t8_forest_t forest) /* calculate first and last element on this tree */ start = (jt == forest->first_local_tree) ? child_in_tree_begin : 0; end = (jt == forest->last_local_tree) ? child_in_tree_end - : eclass_scheme->t8_element_count_leafs_from_root (forest->set_level); + : eclass_scheme->t8_element_count_leaves_from_root (forest->set_level); num_tree_elements = end - start; T8_ASSERT (num_tree_elements > 0); /* Allocate elements for this processor. */ @@ -2001,10 +1693,10 @@ t8_forest_element_half_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, } void -t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *leaf, - t8_element_t **pneighbor_leafs[], int face, int *dual_faces[], int *num_neighbors, - t8_locidx_t **pelement_indices, t8_eclass_scheme_c **pneigh_scheme, - int forest_is_balanced) +t8_forest_leaf_face_neighbors_ext (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *leaf, + t8_element_t **pneighbor_leaves[], int face, int *dual_faces[], int *num_neighbors, + t8_locidx_t **pelement_indices, t8_eclass_scheme_c **pneigh_scheme, + int forest_is_balanced, t8_gloidx_t *gneigh_tree) { t8_eclass_t neigh_class, eclass; t8_gloidx_t gneigh_treeid; @@ -2012,7 +1704,7 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 t8_locidx_t lghost_treeid = -1, *element_indices, element_index; t8_eclass_scheme_c *ts, *neigh_scheme; t8_element_array_t *element_array; - t8_element_t *ancestor, **neighbor_leafs; + t8_element_t *ancestor, **neighbor_leaves; t8_linearidx_t neigh_id; int num_children_at_face, at_maxlevel; int ineigh, *owners, different_owners, have_ghosts; @@ -2039,37 +1731,40 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 at_maxlevel = ts->t8_element_level (leaf) == t8_forest_get_maxlevel (forest); if (at_maxlevel) { num_children_at_face = 1; - neighbor_leafs = *pneighbor_leafs = T8_ALLOC (t8_element_t *, 1); + neighbor_leaves = *pneighbor_leaves = T8_ALLOC (t8_element_t *, 1); *dual_faces = T8_ALLOC (int, 1); - neigh_scheme->t8_element_new (num_children_at_face, neighbor_leafs); + neigh_scheme->t8_element_new (num_children_at_face, neighbor_leaves); /* Compute neighbor element and global treeid of the neighbor */ gneigh_treeid - = t8_forest_element_face_neighbor (forest, ltreeid, leaf, neighbor_leafs[0], neigh_scheme, face, *dual_faces); + = t8_forest_element_face_neighbor (forest, ltreeid, leaf, neighbor_leaves[0], neigh_scheme, face, *dual_faces); } else { /* Allocate neighbor element */ num_children_at_face = ts->t8_element_num_face_children (leaf, face); - neighbor_leafs = *pneighbor_leafs = T8_ALLOC (t8_element_t *, num_children_at_face); + neighbor_leaves = *pneighbor_leaves = T8_ALLOC (t8_element_t *, num_children_at_face); *dual_faces = T8_ALLOC (int, num_children_at_face); - neigh_scheme->t8_element_new (num_children_at_face, neighbor_leafs); + neigh_scheme->t8_element_new (num_children_at_face, neighbor_leaves); /* Compute neighbor elements and global treeid of the neighbor */ - gneigh_treeid = t8_forest_element_half_face_neighbors (forest, ltreeid, leaf, neighbor_leafs, neigh_scheme, face, + gneigh_treeid = t8_forest_element_half_face_neighbors (forest, ltreeid, leaf, neighbor_leaves, neigh_scheme, face, num_children_at_face, *dual_faces); } + if (gneigh_tree) { + *gneigh_tree = gneigh_treeid; + } if (gneigh_treeid < 0) { /* There exists no face neighbor across this face, we return with this info */ - neigh_scheme->t8_element_destroy (num_children_at_face, neighbor_leafs); - T8_FREE (neighbor_leafs); + neigh_scheme->t8_element_destroy (num_children_at_face, neighbor_leaves); + T8_FREE (neighbor_leaves); T8_FREE (*dual_faces); *dual_faces = NULL; *num_neighbors = 0; *pelement_indices = NULL; - *pneighbor_leafs = NULL; + *pneighbor_leaves = NULL; return; } T8_ASSERT (gneigh_treeid >= 0 && gneigh_treeid < forest->global_num_trees); /* We have computed the half face neighbor elements, we now compute their owners, - * if they differ, we know that the half face neighbors are the neighbor leafs. + * if they differ, we know that the half face neighbors are the neighbor leaves. * If the owners do not differ, we have to check if the neighbor leaf is their * parent or grandparent. */ owners = T8_ALLOC (int, num_children_at_face); @@ -2078,14 +1773,14 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 for (ineigh = 0; ineigh < num_children_at_face; ineigh++) { /* At first, we check whether the current rank owns the neighbor, since * this is a constant time check and it is the most common case */ - if (t8_forest_element_check_owner (forest, neighbor_leafs[ineigh], gneigh_treeid, neigh_class, forest->mpirank, + if (t8_forest_element_check_owner (forest, neighbor_leaves[ineigh], gneigh_treeid, neigh_class, forest->mpirank, at_maxlevel)) { owners[ineigh] = forest->mpirank; /* The neighbor tree is also a local tree. we store its local treeid */ lneigh_treeid = t8_forest_get_local_id (forest, gneigh_treeid); } else { - owners[ineigh] = t8_forest_element_find_owner (forest, gneigh_treeid, neighbor_leafs[ineigh], neigh_class); + owners[ineigh] = t8_forest_element_find_owner (forest, gneigh_treeid, neighbor_leaves[ineigh], neigh_class); /* Store that at least one neighbor is a ghost */ have_ghosts = 1; } @@ -2105,8 +1800,8 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 if (!different_owners) { /* The face neighbors belong to the same process, we thus need to determine - * if they are leafs or their parent or grandparent. */ - neigh_id = neigh_scheme->t8_element_get_linear_id (neighbor_leafs[0], forest->maxlevel); + * if they are leaves or their parent or grandparent. */ + neigh_id = neigh_scheme->t8_element_get_linear_id (neighbor_leaves[0], forest->maxlevel); if (owners[0] != forest->mpirank) { /* The elements are ghost elements of the same owner */ element_array = t8_forest_ghost_get_tree_elements (forest, lghost_treeid); @@ -2134,7 +1829,7 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 /* Add the element offset of this tree to the index */ element_index += t8_forest_get_tree_element_offset (forest, lneigh_treeid); } - if (neigh_scheme->t8_element_compare (ancestor, neighbor_leafs[0]) < 0) { + if (neigh_scheme->t8_element_compare (ancestor, neighbor_leaves[0]) < 0) { /* ancestor is a real ancestor, and thus the neighbor is either the parent * or the grandparent of the half neighbors. We can return it and the indices. */ /* We need to determine the dual face */ @@ -2142,27 +1837,27 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 /* The ancestor is the same-level neighbor of leaf */ if (!at_maxlevel) { /* its dual face is the face of the parent of the first neighbor leaf */ - *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leafs[0], *dual_faces[0]); + *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leaves[0], *dual_faces[0]); } } else { /* The ancestor is the parent of the parent */ T8_ASSERT (neigh_scheme->t8_element_level (ancestor) == ts->t8_element_level (leaf) - 1); - *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leafs[0], *dual_faces[0]); + *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leaves[0], *dual_faces[0]); if (!at_maxlevel) { /* We need to compute the dual face of the grandparent. */ /* Construct the parent of the grand child */ - neigh_scheme->t8_element_parent (neighbor_leafs[0], neighbor_leafs[0]); + neigh_scheme->t8_element_parent (neighbor_leaves[0], neighbor_leaves[0]); /* Compute the face id of the parent's face */ - *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leafs[0], *dual_faces[0]); + *dual_faces[0] = neigh_scheme->t8_element_face_parent_face (neighbor_leaves[0], *dual_faces[0]); } } /* free memory */ - neigh_scheme->t8_element_destroy (num_children_at_face - 1, neighbor_leafs + 1); + neigh_scheme->t8_element_destroy (num_children_at_face - 1, neighbor_leaves + 1); /* copy the ancestor */ - neigh_scheme->t8_element_copy (ancestor, neighbor_leafs[0]); + neigh_scheme->t8_element_copy (ancestor, neighbor_leaves[0]); /* set return values */ *num_neighbors = 1; *pelement_indices = T8_ALLOC (t8_locidx_t, 1); @@ -2172,18 +1867,18 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 return; } } - /* The leafs are the face neighbors that we are looking for. */ - /* The face neighbors either belong to different processes and thus must be leafs + /* The leaves are the face neighbors that we are looking for. */ + /* The face neighbors either belong to different processes and thus must be leaves * in the forest, or the ancestor leaf of the first half neighbor is the half - * neighbor itself and thus all half neighbors must be leafs. - * Since the forest is balanced, we found all neighbor leafs. + * neighbor itself and thus all half neighbors must be leaves. + * Since the forest is balanced, we found all neighbor leaves. * It remains to compute their local ids */ *num_neighbors = num_children_at_face; *pelement_indices = T8_ALLOC (t8_locidx_t, num_children_at_face); element_indices = *pelement_indices; for (ineigh = 0; ineigh < num_children_at_face; ineigh++) { /* Compute the linear id at maxlevel of the neighbor leaf */ - neigh_id = neigh_scheme->t8_element_get_linear_id (neighbor_leafs[ineigh], forest->maxlevel); + neigh_id = neigh_scheme->t8_element_get_linear_id (neighbor_leaves[ineigh], forest->maxlevel); /* Get a pointer to the element array in which the neighbor lies and search for the element's index in this array. * This is either the local leaf array of the local tree or the corresponding leaf array in the ghost structure */ if (owners[ineigh] == forest->mpirank) { @@ -2200,7 +1895,7 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 t8_locidx_t check_ltreeid; const t8_element_t *check_element = t8_forest_get_element (forest, element_indices[ineigh], &check_ltreeid); T8_ASSERT (check_ltreeid == lneigh_treeid); - T8_ASSERT (neigh_scheme->t8_element_equal (check_element, neighbor_leafs[ineigh])); + T8_ASSERT (neigh_scheme->t8_element_equal (check_element, neighbor_leaves[ineigh])); } #endif } @@ -2215,7 +1910,7 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 { t8_element_t *check_element; check_element = t8_forest_ghost_get_element (forest, lghost_treeid, element_indices[ineigh]); - T8_ASSERT (neigh_scheme->t8_element_equal (check_element, neighbor_leafs[ineigh])); + T8_ASSERT (neigh_scheme->t8_element_equal (check_element, neighbor_leaves[ineigh])); } #endif /* Add the element offset of previous ghosts to this index */ @@ -2223,7 +1918,7 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 /* Add the number of all local elements to this index */ element_indices[ineigh] += t8_forest_get_local_num_elements (forest); } - } /* End for loop over neighbor leafs */ + } /* End for loop over neighbor leaves */ T8_FREE (owners); } else { @@ -2232,11 +1927,21 @@ t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8 } } +void +t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *leaf, + t8_element_t **pneighbor_leaves[], int face, int *dual_faces[], int *num_neighbors, + t8_locidx_t **pelement_indices, t8_eclass_scheme_c **pneigh_scheme, + int forest_is_balanced) +{ + t8_forest_leaf_face_neighbors_ext (forest, ltreeid, leaf, pneighbor_leaves, face, dual_faces, num_neighbors, + pelement_indices, pneigh_scheme, forest_is_balanced, NULL); +} + void t8_forest_print_all_leaf_neighbors (t8_forest_t forest) { t8_locidx_t ltree, ielem; - t8_element_t **neighbor_leafs; + t8_element_t **neighbor_leaves; int iface, num_neighbors, ineigh; t8_eclass_t eclass; t8_eclass_scheme_c *ts, *neigh_scheme; @@ -2265,7 +1970,7 @@ t8_forest_print_all_leaf_neighbors (t8_forest_t forest) ts = t8_forest_get_eclass_scheme (forest, eclass); /* Iterate over all faces */ for (iface = 0; iface < ts->t8_element_num_faces (leaf); iface++) { - t8_forest_leaf_face_neighbors (forest, ltree, leaf, &neighbor_leafs, iface, &dual_faces, &num_neighbors, + t8_forest_leaf_face_neighbors (forest, ltree, leaf, &neighbor_leaves, iface, &dual_faces, &num_neighbors, &element_indices, &neigh_scheme, 1); t8_debugf ("Element %li across face %i has %i leaf neighbors (with dual faces).\n", (long) ielem, iface, num_neighbors); @@ -2276,10 +1981,10 @@ t8_forest_print_all_leaf_neighbors (t8_forest_t forest) } t8_debugf ("%s\n", buffer); if (num_neighbors > 0) { - neigh_scheme->t8_element_destroy (num_neighbors, neighbor_leafs); + neigh_scheme->t8_element_destroy (num_neighbors, neighbor_leaves); T8_FREE (element_indices); - T8_FREE (neighbor_leafs); + T8_FREE (neighbor_leaves); T8_FREE (dual_faces); } } diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index 8b06def117..9672f3db3f 100644 --- a/src/t8_forest/t8_forest_general.h +++ b/src/t8_forest/t8_forest_general.h @@ -448,6 +448,21 @@ t8_forest_get_eclass (const t8_forest_t forest, const t8_locidx_t ltreeid); t8_locidx_t t8_forest_get_local_id (const t8_forest_t forest, const t8_gloidx_t gtreeid); +/** Given a global tree id compute the forest local id of this tree. + * If the tree is a local tree, then the local id is between 0 and the number + * of local trees. If the tree is a ghost, then the local id is between num_local_trees and + * num_local_trees + num_ghost_trees. + * If the tree is neither a local tree nor a ghost tree, a negative number is returned. + * \param [in] forest The forest. + * \param [in] gtreeid The global id of a tree. + * \return The tree's local id in \a forest, if it is a local tree. + * num_local_trees + the ghosts id, if it is a ghost tree. + * A negative number if not. + * \see https://github.com/DLR-AMR/t8code/wiki/Tree-indexing for more details about tree indexing. + */ +t8_locidx_t +t8_forest_get_local_or_ghost_id (const t8_forest_t forest, const t8_gloidx_t gtreeid); + /** Given the local id of a tree in a forest, compute the tree's local id in the associated cmesh. * \param [in] forest The forest. * \param [in] ltreeid The local id of a tree or ghost in the forest. @@ -482,30 +497,36 @@ t8_forest_get_coarse_tree (t8_forest_t forest, t8_locidx_t ltreeid); * \param [in] forest The forest. Must have a valid ghost layer. * \param [in] ltreeid A local tree id. * \param [in] leaf A leaf in tree \a ltreeid of \a forest. - * \param [out] neighbor_leafs Unallocated on input. On output the neighbor - * leafs are stored here. + * \param [out] neighbor_leaves Unallocated on input. On output the neighbor + * leaves are stored here. * \param [in] face The index of the face across which the face neighbors * are searched. * \param [out] dual_face On output the face id's of the neighboring elements' faces. - * \param [out] num_neighbors On output the number of neighbor leafs. + * \param [out] num_neighbors On output the number of neighbor leaves. * \param [out] pelement_indices Unallocated on input. On output the element indices - * of the neighbor leafs are stored here. - * 0, 1, ... num_local_el - 1 for local leafs and + * of the neighbor leaves are stored here. + * 0, 1, ... num_local_el - 1 for local leaves and * num_local_el , ... , num_local_el + num_ghosts - 1 for ghosts. * \param [out] pneigh_scheme On output the eclass scheme of the neighbor elements. * \param [in] forest_is_balanced True if we know that \a forest is balanced, false * otherwise. - * \note If there are no face neighbors, then *neighbor_leafs = NULL, num_neighbors = 0, + * \note If there are no face neighbors, then *neighbor_leaves = NULL, num_neighbors = 0, * and *pelement_indices = NULL on output. * \note Currently \a forest must be balanced. * \note \a forest must be committed before calling this function. */ void t8_forest_leaf_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *leaf, - t8_element_t **pneighbor_leafs[], int face, int *dual_faces[], int *num_neighbors, + t8_element_t **pneighbor_leaves[], int face, int *dual_faces[], int *num_neighbors, t8_locidx_t **pelement_indices, t8_eclass_scheme_c **pneigh_scheme, int forest_is_balanced); +void +t8_forest_leaf_face_neighbors_ext (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *leaf, + t8_element_t **pneighbor_leaves[], int face, int *dual_faces[], int *num_neighbors, + t8_locidx_t **pelement_indices, t8_eclass_scheme_c **pneigh_scheme, + int forest_is_balanced, t8_gloidx_t *gneigh_tree); + /** 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 @@ -610,7 +631,7 @@ t8_forest_get_tree_vertices (t8_forest_t forest, t8_locidx_t ltreeid); * of this tree. */ t8_element_array_t * -t8_forest_tree_get_leafs (const t8_forest_t forest, const t8_locidx_t ltree_id); +t8_forest_tree_get_leaves (const t8_forest_t forest, const t8_locidx_t ltree_id); /** Return a cmesh associated to a forest. * \param [in] forest The forest. @@ -740,27 +761,6 @@ t8_forest_element_face_neighbor (t8_forest_t forest, t8_locidx_t ltreeid, const void t8_forest_iterate (t8_forest_t forest); -/** Query whether a given point lies inside an element or not. For bilinearly interpolated elements. - * \note For 2D quadrilateral elements this function is only an approximation. It is correct - * if the four vertices lie in the same plane, but it may produce only approximate results if - * the vertices do not lie in the same plane. - * \param [in] forest The forest. - * \param [in] ltree_id The forest local id of the tree in which the element is. - * \param [in] element The element. - * \param [in] point 3-dimensional coordinates of the point to check - * \param [in] tolerance tolerance that we allow the point to not exactly match the element. - * If this value is larger we detect more points. - * If it is zero we probably do not detect points even if they are inside - * due to rounding errors. - * \return True (non-zero) if \a point lies within \a element, false otherwise. - * The return value is also true if the point lies on the element boundary. - * Thus, this function may return true for different leaf elements, if they - * are neighbors and the point lies on the common boundary. - */ -int -t8_forest_element_point_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, - const double point[3], const double tolerance); - /** Query whether a batch of points lies inside an element. For bilinearly interpolated elements. * \note For 2D quadrilateral elements this function is only an approximation. It is correct * if the four vertices lie in the same plane, but it may produce only approximate results if @@ -780,8 +780,8 @@ t8_forest_element_point_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t * due to rounding errors. */ void -t8_forest_element_point_batch_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, - const double *points, int num_points, int *is_inside, const double tolerance); +t8_forest_element_points_inside (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, int num_points, int *is_inside, const double tolerance); /* TODO: if set level and partition/adapt/balance all give NULL, then * refine uniformly and partition/adapt/balance the unfiform forest. */ diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index 55c3ff2d17..64ba73fb77 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -506,7 +506,7 @@ typedef struct static int t8_forest_ghost_search_boundary (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, - const int is_leaf, const t8_element_array_t *leafs, const t8_locidx_t tree_leaf_index, + const int is_leaf, const t8_element_array_t *leaves, const t8_locidx_t tree_leaf_index, void *query, sc_array_t *query_indices, int *query_matches, const size_t num_active_queries) { @@ -596,7 +596,7 @@ t8_forest_ghost_search_boundary (t8_forest_t forest, t8_locidx_t ltreeid, const new_bounds[iface * 2] = lower; new_bounds[iface * 2 + 1] = upper; if (lower == upper && lower == forest->mpirank) { - /* All neighbor leafs at this face are owned by the current rank */ + /* All neighbor leaves at this face are owned by the current rank */ faces_totally_owned = faces_totally_owned && 1; } else { @@ -625,7 +625,7 @@ t8_forest_ghost_search_boundary (t8_forest_t forest, t8_locidx_t ltreeid, const * We do not continue the search */ #ifdef T8_ENABLE_DEBUG if (tree_leaf_index < 0) { - data->left_out += t8_element_array_get_count (leafs); + data->left_out += t8_element_array_get_count (leaves); } #endif return 0; diff --git a/src/t8_forest/t8_forest_iterate.cxx b/src/t8_forest/t8_forest_iterate.cxx index c4dd6facd3..606f7613b0 100644 --- a/src/t8_forest/t8_forest_iterate.cxx +++ b/src/t8_forest/t8_forest_iterate.cxx @@ -86,14 +86,14 @@ t8_forest_iterate_faces (t8_forest_t forest, t8_locidx_t ltreeid, const t8_eleme int child_face, num_face_children, iface; int *child_indices; size_t *split_offsets, indexa, indexb, elem_count; - t8_element_array_t face_child_leafs; + t8_element_array_t face_child_leaves; T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (forest)); elem_count = t8_element_array_get_count (leaf_elements); if (elem_count == 0) { - /* There are no leafs left, so we have nothing to do */ + /* There are no leaves left, so we have nothing to do */ return; } eclass = t8_forest_get_tree_class (forest, ltreeid); @@ -131,20 +131,20 @@ t8_forest_iterate_faces (t8_forest_t forest, t8_locidx_t ltreeid, const t8_eleme split_offsets = T8_ALLOC (size_t, ts->t8_element_num_children (element) + 1); /* Compute the face children */ ts->t8_element_children_at_face (element, face, face_children, num_face_children, child_indices); - /* Split the leafs array in portions belonging to the children of element */ + /* Split the leaves array in portions belonging to the children of element */ t8_forest_split_array (element, leaf_elements, split_offsets); for (iface = 0; iface < num_face_children; iface++) { /* Check if there are any leaf elements for this face child */ indexa = split_offsets[child_indices[iface]]; /* first leaf of this face child */ indexb = split_offsets[child_indices[iface] + 1]; /* first leaf of next child */ if (indexa < indexb) { - /* There exist leafs of this face child in leaf_elements, - * we construct an array of these leafs */ - t8_element_array_init_view (&face_child_leafs, leaf_elements, indexa, indexb - indexa); + /* There exist leaves of this face child in leaf_elements, + * we construct an array of these leaves */ + t8_element_array_init_view (&face_child_leaves, leaf_elements, indexa, indexb - indexa); /* Compute the corresponding face number of this face child */ child_face = ts->t8_element_face_child_face (element, face, iface); /* Enter the recursion */ - t8_forest_iterate_faces (forest, ltreeid, face_children[iface], child_face, &face_child_leafs, user_data, + t8_forest_iterate_faces (forest, ltreeid, face_children[iface], child_face, &face_child_leaves, user_data, indexa + tree_lindex_of_first_leaf, callback); } } @@ -185,7 +185,7 @@ t8_forest_search_recursion (t8_forest_t forest, const t8_locidx_t ltreeid, t8_el const size_t elem_count = t8_element_array_get_count (leaf_elements); if (elem_count == 0) { - /* There are no leafs left, so we have nothing to do */ + /* There are no leaves left, so we have nothing to do */ return; } const size_t num_active = queries == NULL ? 0 : active_queries->elem_count; @@ -260,19 +260,19 @@ t8_forest_search_recursion (t8_forest_t forest, const t8_locidx_t ltreeid, t8_el size_t *split_offsets = T8_ALLOC (size_t, num_children + 1); /* Compute the children */ ts->t8_element_children (element, num_children, children); - /* Split the leafs array in portions belonging to the children of element */ + /* 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_leafs; - /* There exist leafs of this child in leaf_elements, - * we construct an array of these leafs */ - t8_element_array_init_view (&child_leafs, leaf_elements, indexa, indexb - indexa); + 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 */ - t8_forest_search_recursion (forest, ltreeid, children[ichild], ts, &child_leafs, + t8_forest_search_recursion (forest, ltreeid, children[ichild], ts, &child_leaves, indexa + tree_lindex_of_first_leaf, search_fn, query_fn, queries, new_active_queries); } } @@ -294,7 +294,7 @@ t8_forest_search_tree (t8_forest_t forest, t8_locidx_t ltreeid, t8_forest_search /* Get the element class, scheme and leaf elements of this tree */ const t8_eclass_t eclass = t8_forest_get_eclass (forest, ltreeid); const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, eclass); - t8_element_array_t *leaf_elements = t8_forest_tree_get_leafs (forest, ltreeid); + t8_element_array_t *leaf_elements = t8_forest_tree_get_leaves (forest, ltreeid); /* assert for empty tree */ T8_ASSERT (t8_element_array_get_count (leaf_elements) >= 0); diff --git a/src/t8_forest/t8_forest_iterate.h b/src/t8_forest/t8_forest_iterate.h index 79f37c6fe6..b90537beb3 100644 --- a/src/t8_forest/t8_forest_iterate.h +++ b/src/t8_forest/t8_forest_iterate.h @@ -66,10 +66,10 @@ void t8_forest_split_array (const t8_element_t *element, t8_element_array_t *leaf_elements, size_t *offsets); /* TODO: comment */ -/* Iterate over all leafs of an element that touch a given face of the element */ +/* Iterate over all leaves of an element that touch a given face of the element */ /* Callback is called in each recursive step with element as input. * leaf_index is only not negative if element is a leaf, in which case it indicates - * the index of the leaf in the leafs of the tree. If it is negative, it is + * the index of the leaf in the leaves of the tree. If it is negative, it is * - (index + 1) */ /* Top-down iteration and callback is called on each intermediate level. * If it returns false, the current element is not traversed further */ diff --git a/src/t8_forest/t8_forest_private.h b/src/t8_forest/t8_forest_private.h index 09add74644..160c08d75d 100644 --- a/src/t8_forest/t8_forest_private.h +++ b/src/t8_forest/t8_forest_private.h @@ -299,7 +299,7 @@ t8_forest_element_owners_bounds (t8_forest_t forest, t8_gloidx_t gtreeid, const t8_eclass_t eclass, int *lower, int *upper); /** Constant time algorithm to compute lower and upper bounds for the owner - * processes of the face leafs of a given element. + * processes of the face leaves of a given element. * \param [in] forest The forest. * \param [in] gtreeid The global id of the tree in which the element lies. * \param [in] element The element to look for. @@ -381,8 +381,8 @@ t8_forest_element_half_face_neighbors (t8_forest_t forest, t8_locidx_t ltreeid, t8_element_t *neighs[], t8_eclass_scheme_c *neigh_scheme, int face, int num_neighs, int dual_faces[]); -/** Iterate over all leafs of a forest and for each face compute the face neighbor - * leafs with \ref t8_forest_leaf_face_neighbors and print their local element ids. +/** Iterate over all leaves of a forest and for each face compute the face neighbor + * leaves with \ref t8_forest_leaf_face_neighbors and print their local element ids. * This function is meant for debugging only. * \param [in] forest The forest. * \note Currently \a forest must be balanced. diff --git a/src/t8_forest/t8_forest_vtk.cxx b/src/t8_forest/t8_forest_vtk.cxx index 40a3372de6..aab57e42f3 100644 --- a/src/t8_forest/t8_forest_vtk.cxx +++ b/src/t8_forest/t8_forest_vtk.cxx @@ -151,8 +151,8 @@ const double t8_forest_vtk_point_to_element_ref_coords[T8_ECLASS_COUNT][T8_FORES { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 } }, { /* T8_ECLASS_PRISM */ - { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0.5, 1, 0 }, - { 1, 0.5, 0 }, { 0.5, 0.5, 0 }, { 0.5, 0, 1 }, { 1, 0.5, 1 }, { 0.5, 0.5, 1 }, { 0, 0, 0.5 }, { 0, 1, 0.5 }, + { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0.5, 0, 0 }, + { 1, 0.5, 0 }, { 0.5, 0.5, 0 }, { 0.5, 0, 1 }, { 1, 0.5, 1 }, { 0.5, 0.5, 1 }, { 0, 0, 0.5 }, { 1, 0, 0.5 }, { 1, 1, 0.5 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 } }, { /* T8_ECLASS_PYRAMID */ { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 1, 1, 1 }, @@ -1275,9 +1275,6 @@ t8_forest_vtk_write_file (t8_forest_t forest, const char *fileprefix, const int } T8_ASSERT (forest->ghosts != NULL || !write_ghosts); - /* Currently we only support output in ascii format, not binary */ - T8_ASSERT (T8_VTK_ASCII == 1); - /* process 0 creates the .pvtu file */ if (forest->mpirank == 0) { if (t8_write_pvtu (fileprefix, forest->mpisize, write_treeid, write_mpirank, write_level, write_element_id, diff --git a/src/t8_geometry/t8_geometry.cxx b/src/t8_geometry/t8_geometry.cxx index c4c61b6973..8ba392d219 100644 --- a/src/t8_geometry/t8_geometry.cxx +++ b/src/t8_geometry/t8_geometry.cxx @@ -260,7 +260,7 @@ t8_geom_handler_get_unique_geometry (const t8_geometry_handler_t *geom_handler) T8_ASSERT (t8_geom_handler_get_num_geometries (geom_handler) == 1); sc_array *geometries = (sc_array *) &geom_handler->registered_geometries; - return *(const t8_geometry_c **) sc_array_index_int (geometries, 0); + return *(t8_geometry_c **) sc_array_index_int (geometries, 0); } void diff --git a/src/t8_geometry/t8_geometry.h b/src/t8_geometry/t8_geometry.h index 9394fedf03..d42d78ac83 100644 --- a/src/t8_geometry/t8_geometry.h +++ b/src/t8_geometry/t8_geometry.h @@ -41,8 +41,8 @@ typedef enum t8_geometry_type { T8_GEOMETRY_TYPE_LINEAR_AXIS_ALIGNED, /** The analytic geometry uses a user-defined analytic function to map into the physical domain. */ T8_GEOMETRY_TYPE_ANALYTIC, - /** The OCC geometry uses OCC CAD shapes to map trees exactly to the underlying CAD model. */ - T8_GEOMETRY_TYPE_OCC, + /** The opencascade geometry uses CAD shapes to map trees exactly to the underlying CAD model. */ + T8_GEOMETRY_TYPE_CAD, /** This is no geometry type but can be used as the number of geometry types. */ T8_GEOMETRY_TYPE_COUNT, /** This is no geometry type but is used for every geometry, where no type is defined */ diff --git a/src/t8_geometry/t8_geometry_base.hxx b/src/t8_geometry/t8_geometry_base.hxx index ee3d47ef2b..e95564af11 100644 --- a/src/t8_geometry/t8_geometry_base.hxx +++ b/src/t8_geometry/t8_geometry_base.hxx @@ -30,6 +30,7 @@ #include #include +#include #include T8_EXTERN_C_BEGIN (); @@ -96,6 +97,52 @@ struct t8_geometry t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) = 0; + /** Query whether a batch of points lies inside an element. + * \param [in] forest The forest. + * \param [in] ltree_id The forest local id of the tree in which the element is. + * \param [in] element The element. + * \param [in] points 3-dimensional coordinates of the points to check + * \param [in] num_points The number of points to check + * \param [in, out] is_inside An array of length \a num_points, filled with 0/1 on output. True (non-zero) if a \a point + * lies within an \a element, false otherwise. The return value is also true if the point + * lies on the element boundary. Thus, this function may return true for different leaf + * elements, if they are neighbors and the point lies on the common boundary. + * \param [in] tolerance Tolerance that we allow the point to not exactly match the element. + * If this value is larger we detect more points. + * If it is zero we probably do not detect points even if they are inside + * due to rounding errors. + */ + virtual void + t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, int *is_inside, + const double tolerance) const + { + SC_ABORTF ("Function not yet implemented"); + }; + + /** Query whether a single points lies inside an element. + * \param [in] forest The forest. + * \param [in] ltree_id The forest local id of the tree in which the element is. + * \param [in] element The element. + * \param [in] points 3-dimensional coordinates of the points to check + * \param [in] num_points The number of points to check + * \param [in, out] is_inside An array of length \a num_points, filled with 0/1 on output. True (non-zero) if a \a point + * lies within an \a element, false otherwise. The return value is also true if the point + * lies on the element boundary. Thus, this function may return true for different leaf + * elements, if they are neighbors and the point lies on the common boundary. + * \param [in] tolerance Tolerance that we allow the point to not exactly match the element. + * If this value is larger we detect more points. + * If it is zero we probably do not detect points even if they are inside + * due to rounding errors. + */ + inline int + t8_geom_point_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, const double tolerance) const + { + int is_inside = 0; + t8_geom_point_batch_inside_element (forest, ltreeid, element, points, 1, &is_inside, tolerance); + return is_inside; + } /** * Get the dimension of this geometry. * \return The dimension. diff --git a/src/t8_geometry/t8_geometry_helpers.c b/src/t8_geometry/t8_geometry_helpers.c index 2a8738b5c3..d70a77771e 100644 --- a/src/t8_geometry/t8_geometry_helpers.c +++ b/src/t8_geometry/t8_geometry_helpers.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include void t8_geom_linear_interpolation (const double *coefficients, const double *corner_values, const int corner_value_dim, @@ -298,19 +298,16 @@ t8_geom_get_ref_intersection (int edge_index, const double *ref_coords, double r break; } else { - /* intersectionX = (x1y2-y1x2)(x3-x4)-(x1-x2)(x3y4-y3x4) - * /(x1-x2)(y3-y4)-(y1-y2)(x3-x4) - * intersectionY = (x1y2-y1x2)(y3-y4)-(y1-y2)(x3y4-y3x4) - * /(x1-x2)(y3-y4)-(y1-y2)(x3-x4) - * - * x1=0 y1=0 x2=1 y2=1 x3=ref_coords[0] y3=ref_coords[1] x4=ref_opposite_vertex[0] y4=ref_opposite_vertex[1] - * - * Since the intersection point lies on edge 2, which has a slope of 1, the x and the y value has to be equal - */ - ref_intersection[0] = ref_intersection[1] - = ((ref_coords[0] * ref_opposite_vertex[1] - ref_coords[1] * ref_opposite_vertex[0]) - / -(ref_coords[1] - ref_opposite_vertex[1]) - + (ref_coords[0] - ref_opposite_vertex[0])); + /* To find the ref_intersection for edge 1, we calculate the intersection of edge 1 with a stright line from + * vertex 1, through the reference point and reaching until x = 0. The y-axis intersect for that line is at + * slope * (-1). + * Since the the ref_intersection lies on edge 1, which has a slope of 1, + * the x and y coordinates have to be the same. + * The intersection is calculated via the line equations: + * edge 1: y = ax + c + * line: y = bx + d + * intersection: (d - c) / (a - b) */ + ref_intersection[0] = ref_intersection[1] = -ref_slope / (1 - ref_slope); break; } case 2: /* edge 2 */ @@ -373,3 +370,129 @@ t8_geom_get_triangle_scaling_factor (int edge_index, const double *tree_vertices double scaling_factor = dist_ref / dist_intersection; return scaling_factor; } + +int +t8_vertex_point_inside (const double vertex_coords[3], const double point[3], const double tolerance) +{ + T8_ASSERT (tolerance > 0); + if (t8_vec_dist (vertex_coords, point) > tolerance) { + return 0; + } + return 1; +} + +int +t8_line_point_inside (const double *p_0, const double *vec, const double *point, const double tolerance) +{ + T8_ASSERT (tolerance > 0); + double b[3]; + /* b = p - p_0 */ + t8_vec_axpyz (p_0, point, b, -1); + double x = 0; /* Initialized to prevent compiler warning. */ + int i; + /* So x is the solution to + * vec * x = b. + * We can compute it as + * x = b[i] / vec[i] + * if any vec[i] is not 0. + * + * Otherwise the line is degenerated (which should not happen). + */ + for (i = 0; i < 3; ++i) { + if (vec[i] != 0) { + x = b[i] / vec[i]; + break; /* found a non-zero coordinate. We can stop now. */ + } + } + + /* If i == 3 here, then vec = 0 and hence the line is degenerated. */ + SC_CHECK_ABORT (i < 3, "Degenerated line element. Both endpoints are the same."); + + if (x < -tolerance || x > 1 + tolerance) { + /* x is not an admissible solution. */ + return 0; + } + + /* we can check whether x gives us a solution by + * checking whether + * vec * x = b + * is actually true. + */ + double vec_check[3] = { vec[0], vec[1], vec[2] }; + t8_vec_ax (vec_check, x); + if (t8_vec_dist (vec_check, b) > tolerance) { + /* Point does not lie on the line. */ + return 0; + } + /* The point is on the line. */ + return 1; +} + +int +t8_triangle_point_inside (const double p_0[3], const double v[3], const double w[3], const double point[3], + const double tolerance) +{ + /* A point p is inside the triangle that is spanned + * by the point p_0 and vectors v and w if and only if the linear system + * vx + wy = point - p_0 + * has a solution with 0 <= x,y and x + y <= 1. + * + * We check whether such a solution exists by computing + * certain determinants of 2x2 submatrizes of the 3x3 matrix + * + * | v w e_3 | with v = p_1 - p_0, w = p_2 - p_0, and e_3 = (0 0 1)^t (third unit vector) + */ + + T8_ASSERT (tolerance > 0); /* negative values and zero are not allowed */ + double b[3]; + /* b = point - p_0 */ + t8_vec_axpyz (p_0, point, b, -1); + + /* Let d = det (v w e_3) */ + const double det_vwe3 = v[0] * w[1] - v[1] * w[0]; + + /* The system has a solution, we need to compute it and + * check whether 0 <= x,y and x + y <= 1 */ + /* x = det (b w e_3) / d + * y = det (v b e_3) / d + */ + const double x = (b[0] * w[1] - b[1] * w[0]) / det_vwe3; + const double y = (v[0] * b[1] - v[1] * b[0]) / det_vwe3; + + if (x < -tolerance || y < -tolerance || x + y > 1 + tolerance) { + /* The solution is not admissible. + * x < 0 or y < 0 or x + y > 1 */ + return 0; + } + /* The solution may be admissible, but we have to + * check whether the result of + * (p_1 - p_0)x + (p_2 - p_0)y ( = vx + wy) + * is actually p - p_0. + * Since the system of equations is overrepresented (3 equations, 2 variables) + * this may actually break. + * If it breaks, it will break in the z coordinate of the result. + */ + const double z = v[2] * x + w[2] * y; + /* Must match the last coordinate of b = p - p_0 */ + if (fabs (z - b[2]) > tolerance) { + /* Does not match. Point lies outside. */ + return 0; + } + /* All checks passed. Point lies inside. */ + return 1; +} + +int +t8_plane_point_inside (const double point_on_face[3], const double face_normal[3], const double point[3]) +{ + /* Set x = x - p */ + double pof[3] = { point_on_face[0], point_on_face[1], point_on_face[2] }; + t8_vec_axpy (point, pof, -1); + /* Compute */ + const double dot_product = t8_vec_dot (pof, face_normal); + if (dot_product < 0) { + /* The point is on the wrong side of the plane */ + return 0; + } + return 1; +} \ No newline at end of file diff --git a/src/t8_geometry/t8_geometry_helpers.h b/src/t8_geometry/t8_geometry_helpers.h index 5b3eac2d27..498ed9b8b3 100644 --- a/src/t8_geometry/t8_geometry_helpers.h +++ b/src/t8_geometry/t8_geometry_helpers.h @@ -132,6 +132,53 @@ double t8_geom_get_triangle_scaling_factor (int edge_index, const double *tree_vertices, const double *glob_intersection, const double *glob_ref_point); +/** Check if a point lies inside a vertex + * + * \param[in] vertex_coords The coordinates of the vertex + * \param[in] point The coordinates of the point to check + * \param[in] tolerance A double > 0 defining the tolerance + * \return 0 if the point is outside, 1 otherwise. + */ +int +t8_vertex_point_inside (const double vertex_coords[3], const double point[3], const double tolerance); + +/** + * Check if a point is inside a line that is defined by a starting point \a p_0 + * and a vector \a vec + * + * \param[in] p_0 Starting point of the line + * \param[in] vec Direction of the line (not normalized) + * \param[in] point The coordinates of the point to check + * \param[in] tolerance A double > 0 defining the tolerance + * \return 0 if the point is outside, 1 otherwise. + */ +int +t8_line_point_inside (const double *p_0, const double *vec, const double *point, const double tolerance); + +/** + * Check if a point is inside of a triangle described by a point \a p_0 and two vectors \a v and \a w. + * + * \param[in] p_0 The first vertex of a triangle + * \param[in] v The vector from p_0 to p_1 (second vertex in the triangle) + * \param[in] w The vector from p_0 to p_2 (third vertex in the triangle) + * \param[in] point The coordinates of the point to check + * \param[in] tolerance A double > 0 defining the tolerance + * \return 0 if the point is outside, 1 otherwise. + */ +int +t8_triangle_point_inside (const double p_0[3], const double v[3], const double w[3], const double point[3], + const double tolerance); + +/** Check if a point lays on the inner side of a plane of a bilinearly interpolated volume element. + * the plane is described by a point and the normal of the face. + * \param[in] point_on_face A point on the plane + * \param[in] face_normal The normal of the face + * \param[in] point The point to check + * \return 0 if the point is outside, 1 otherwise. + */ +int +t8_plane_point_inside (const double point_on_face[3], const double face_normal[3], const double point[3]); + T8_EXTERN_C_END (); #endif /* !T8_GEOMETRY_HELPERS_H! */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx index d0c56b332b..576e11bd36 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.cxx @@ -66,10 +66,32 @@ t8_geometry_analytic::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtre } } +T8_EXTERN_C_BEGIN (); + +void +t8_geometry_analytic_destroy (t8_geometry_c **geom) +{ + T8_ASSERT (geom != NULL); + + delete *geom; + *geom = NULL; +} + +t8_geometry_c * +t8_geometry_analytic_new (int dim, const char *name, t8_geom_analytic_fn analytical, + t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, + const void *user_data) +{ + t8_geometry_analytic *geom = new t8_geometry_analytic (dim, name, analytical, jacobian, load_tree_data, user_data); + return (t8_geometry_c *) geom; +} + void -t8_geom_load_tree_data_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **vertices_out) +t8_geom_load_tree_data_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **user_data) { T8_ASSERT (t8_cmesh_is_committed (cmesh)); t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); - *vertices_out = t8_cmesh_get_tree_vertices (cmesh, ltreeid); + *user_data = t8_cmesh_get_tree_vertices (cmesh, ltreeid); } + +T8_EXTERN_C_END (); diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h new file mode 100644 index 0000000000..72a3a26818 --- /dev/null +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.h @@ -0,0 +1,96 @@ +/* + 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_geometry_analytic.h + * This header provides the C interface to create an analytical geometry. + */ + +#ifndef T8_GEOMETRY_ANALYTIC_H +#define T8_GEOMETRY_ANALYTIC_H + +/** + * Definition of an analytic geometry function. + * This function maps reference coordinates to physical + * coordinates. + * \param [in] cmesh The cmesh. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. + * \param [in] num_coords + * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. + * \param [in] tree_data The data of the current tree as loaded by a \ref t8_geom_load_tree_data_fn. + * \param [in] user_data The user data pointer stored in the geometry. + */ +typedef void (*t8_geom_analytic_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, + const size_t num_coords, double *out_coords, const void *tree_data, + const void *user_data); + +/** + * Definition for the jacobian of an analytic geometry function. + * \param [in] cmesh The cmesh. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of \a dimension x \a num_coords many entries, specifying points in \f$ [0,1]^\mathrm{dim} \f$. + * \param [in] num_coords Amount of points of /f$ \mathrm{dim} /f$ to map. + * \param [out] jacobian The jacobian at \a ref_coords. Array of size \f$ \mathrm{dim} \cdot 3 \f$ x \a num_coords. Indices \f$ 3 \cdot i\f$ , \f$ 3 \cdot i+1 \f$ , \f$ 3 \cdot i+2 \f$ + * correspond to the \f$ i \f$-th column of the jacobian (Entry \f$ 3 \cdot i + j \f$ is \f$ \frac{\partial f_j}{\partial x_i} \f$). + * \param [in] tree_data The data of the current tree as loaded by a \ref t8_geom_load_tree_data_fn. + * \param [in] user_data The user data pointer stored in the geometry. + */ +typedef void (*t8_geom_analytic_jacobian_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, + const size_t num_coords, double *jacobian, const void *tree_data, + const void *user_data); + +/** + * Definition for the load tree data function. + * \param [in] cmesh The cmesh. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] tree_data The data of the trees. + */ +typedef void (*t8_geom_load_tree_data_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **tree_data); + +T8_EXTERN_C_BEGIN (); + +/** Destroy a geometry analytic object. + * \param [in,out] geom A pointer to a geometry object. Set to NULL on output. + */ +void +t8_geometry_analytic_destroy (t8_geometry_c **geom); + +/** Create a new analytical geometry. + * \return A pointer to an allocated geometry struct. + */ +t8_geometry_c * +t8_geometry_analytic_new (int dim, const char *name, t8_geom_analytic_fn analytical, + t8_geom_analytic_jacobian_fn jacobian, t8_geom_load_tree_data_fn load_tree_data, + const void *user_data); + +/** + * Load vertex data from given tree. + * \param [in] cmesh The cmesh. + * \param [in] gtreeid The global tree id (in the cmesh). + * \param [out] vertex_out The load tree vertices. + */ +void +t8_geom_load_tree_data_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **user_data); + +T8_EXTERN_C_END (); + +#endif /* T8_GEOMETRY_ANALYTIC_H */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx index 5927c53927..bf44ffe83c 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_analytic.hxx @@ -21,7 +21,9 @@ */ /** \file t8_geometry_analytic.hxx - * TODO: Add description + * This geometry implements analytic geometries. It provides an interface to + * define custom functions for evaluation, Jacobians and the loading of the + * tree data. */ #ifndef T8_GEOMETRY_ANALYTIC_HXX @@ -30,40 +32,7 @@ #include #include #include - -/** - * Definition of an analytic geometry function. - * This function maps reference coordinates to physical - * coordinates. - * \param [in] cmesh The cmesh. - * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. - * \param [in] ref_coords Array of dimension x \a num_coords many entries, specifying a point in \f$ [0,1]^\mathrm{dim} \f$. - * \param [in] num_coords - * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. - * \param [in] tree_data The data of the current tree as loaded by a \ref t8_geom_load_tree_data_fn. - * \param [in] user_data The user data pointer stored in the geometry. - */ -typedef void (*t8_geom_analytic_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, - const size_t num_coords, double *out_coords, const void *tree_data, - const void *user_data); - -/** - * Definition for the jacobian of an analytic geometry function. - * \param [in] cmesh The cmesh. - * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. - * \param [in] ref_coords Array of \a dimension x \a num_coords many entries, specifying points in \f$ [0,1]^\mathrm{dim} \f$. - * \param [in] num_coords Amount of points of /f$ \mathrm{dim} /f$ to map. - * \param [out] jacobian The jacobian at \a ref_coords. Array of size \f$ \mathrm{dim} \cdot 3 \f$ x \a num_coords. Indices \f$ 3 \cdot i\f$ , \f$ 3 \cdot i+1 \f$ , \f$ 3 \cdot i+2 \f$ - * correspond to the \f$ i \f$-th column of the jacobian (Entry \f$ 3 \cdot i + j \f$ is \f$ \frac{\partial f_j}{\partial x_i} \f$). - * \param [in] tree_data The data of the current tree as loaded by a \ref t8_geom_load_tree_data_fn. - * \param [in] user_data The user data pointer stored in the geometry. - */ -typedef void (*t8_geom_analytic_jacobian_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, - const size_t num_coords, double *jacobian, const void *tree_data, - const void *user_data); - -/* TODO: Document. */ -typedef void (*t8_geom_load_tree_data_fn) (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **tree_data); +#include struct t8_geometry_analytic: public t8_geometry { @@ -129,6 +98,23 @@ struct t8_geometry_analytic: public t8_geometry t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *jacobian) const; + /** + * \param[in] forest The forest of the element. + * \param[in] ltreeid The local tree id of the element's tree + * \param[in] element The element + * \param[in] points points to check + * \param[in] num_points Number of points to check + * \param[in, out] is_inside Array to fill with flags whether the point is inside or not + * \param[in] tolerance Tolerance of the inside-check + */ + virtual void + t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, int *is_inside, + const double tolerance) + { + SC_ABORTF ("Function not yet implemented"); + } + /** Update a possible internal data buffer for per tree data. * This function is called before the first coordinates in a new tree are * evaluated. You can use it for example to load the vertex coordinates of the @@ -159,8 +145,4 @@ struct t8_geometry_analytic: public t8_geometry * and modified via \ref t8_geom_analytic_get_user_data. */ }; -/* TODO: Document */ -void -t8_geom_load_tree_data_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const void **vertices_out); - #endif /* !T8_GEOMETRY_ANALYTICAL_HXX! */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx similarity index 82% rename from src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.cxx rename to src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx index a7f7b37a89..7b3afb315e 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx @@ -21,8 +21,8 @@ */ #include -#include -#include +#include +#include #include #include @@ -41,7 +41,7 @@ #include #include -t8_geometry_occ::t8_geometry_occ (int dim, const char *fileprefix, const char *name_in) +t8_geometry_cad::t8_geometry_cad (int dim, const char *fileprefix, const char *name_in) { T8_ASSERT (0 <= dim && dim <= 3); @@ -54,52 +54,52 @@ t8_geometry_occ::t8_geometry_occ (int dim, const char *fileprefix, const char *n if (is.is_open () == false) { SC_ABORTF ("Cannot find the file %s.brep.\n", fileprefix); } - BRepTools::Read (occ_shape, is, builder); + BRepTools::Read (cad_shape, is, builder); is.close (); - if (occ_shape.IsNull ()) { + if (cad_shape.IsNull ()) { SC_ABORTF ("Could not read brep file or brep file contains no shape. " - "The OCC file may be written with a newer OCC version. " - "Linked OCC version: %s", + "The cad file may be written with a newer cad version. " + "Linked cad version: %s", OCC_VERSION_COMPLETE); } - TopExp::MapShapes (occ_shape, TopAbs_VERTEX, occ_shape_vertex_map); - TopExp::MapShapes (occ_shape, TopAbs_EDGE, occ_shape_edge_map); - TopExp::MapShapes (occ_shape, TopAbs_FACE, occ_shape_face_map); - TopExp::MapShapesAndUniqueAncestors (occ_shape, TopAbs_VERTEX, TopAbs_EDGE, occ_shape_vertex2edge_map); - TopExp::MapShapesAndUniqueAncestors (occ_shape, TopAbs_EDGE, TopAbs_FACE, occ_shape_edge2face_map); + TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); + TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); + TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); } -t8_geometry_occ::t8_geometry_occ (int dim, const TopoDS_Shape occ_shape, const char *name_in) +t8_geometry_cad::t8_geometry_cad (int dim, const TopoDS_Shape cad_shape, const char *name_in) { T8_ASSERT (0 <= dim && dim <= 3); name = name_in; dimension = dim; - if (occ_shape.IsNull ()) { + if (cad_shape.IsNull ()) { SC_ABORTF ("Shape is null. \n"); } - TopExp::MapShapes (occ_shape, TopAbs_VERTEX, occ_shape_vertex_map); - TopExp::MapShapes (occ_shape, TopAbs_EDGE, occ_shape_edge_map); - TopExp::MapShapes (occ_shape, TopAbs_FACE, occ_shape_face_map); - TopExp::MapShapesAndUniqueAncestors (occ_shape, TopAbs_VERTEX, TopAbs_EDGE, occ_shape_vertex2edge_map); - TopExp::MapShapesAndUniqueAncestors (occ_shape, TopAbs_EDGE, TopAbs_FACE, occ_shape_edge2face_map); + TopExp::MapShapes (cad_shape, TopAbs_VERTEX, cad_shape_vertex_map); + TopExp::MapShapes (cad_shape, TopAbs_EDGE, cad_shape_edge_map); + TopExp::MapShapes (cad_shape, TopAbs_FACE, cad_shape_face_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); + TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); } void -t8_geometry_occ::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, +t8_geometry_cad::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const { if (num_coords != 1) SC_ABORT ("Error: Batch computation of geometry not yet supported."); switch (active_tree_class) { case T8_ECLASS_TRIANGLE: - t8_geometry_occ::t8_geom_evaluate_occ_triangle (cmesh, gtreeid, ref_coords, 1, out_coords); + t8_geometry_cad::t8_geom_evaluate_cad_triangle (cmesh, gtreeid, ref_coords, 1, out_coords); break; case T8_ECLASS_QUAD: - t8_geometry_occ::t8_geom_evaluate_occ_quad (cmesh, gtreeid, ref_coords, 1, out_coords); + t8_geometry_cad::t8_geom_evaluate_cad_quad (cmesh, gtreeid, ref_coords, 1, out_coords); break; case T8_ECLASS_HEX: - t8_geometry_occ::t8_geom_evaluate_occ_hex (cmesh, gtreeid, ref_coords, 1, out_coords); + t8_geometry_cad::t8_geom_evaluate_cad_hex (cmesh, gtreeid, ref_coords, 1, out_coords); break; default: SC_ABORTF ("Error: Curved %s geometry not yet implemented. \n", t8_eclass_to_string[active_tree_class]); @@ -107,7 +107,7 @@ t8_geometry_occ::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const } void -t8_geometry_occ::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, +t8_geometry_cad::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *jacobian_out) const { if (num_coords != 1) @@ -129,8 +129,8 @@ t8_geometry_occ::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreei in1[dim] -= 0.5 * h; in2[dim] += 0.5 * h; } - t8_geometry_occ::t8_geom_evaluate (cmesh, gtreeid, in1, 1, out1); - t8_geometry_occ::t8_geom_evaluate (cmesh, gtreeid, in2, 1, out2); + t8_geometry_cad::t8_geom_evaluate (cmesh, gtreeid, in1, 1, out1); + t8_geometry_cad::t8_geom_evaluate (cmesh, gtreeid, in2, 1, out2); for (int dim2 = 0; dim2 < 3; ++dim2) { jacobian_out[dim * 3 + dim2] = (out2[dim2] - out1[dim2]) / h; } @@ -138,17 +138,18 @@ t8_geometry_occ::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreei } inline void -t8_geometry_occ::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) +t8_geometry_cad::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid) { + const t8_locidx_t ltreeid = t8_cmesh_get_local_id (cmesh, gtreeid); t8_geometry_with_vertices::t8_geom_load_tree_data (cmesh, gtreeid); - edges = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, gtreeid); - faces = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, gtreeid); + edges = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, ltreeid); + faces = (const int *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, ltreeid); T8_ASSERT (edges != NULL); T8_ASSERT (faces != NULL); } void -t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, +t8_geometry_cad::t8_geom_evaluate_cad_triangle (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const { T8_ASSERT (active_tree_class == T8_ECLASS_TRIANGLE); @@ -192,7 +193,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt #endif /* T8_ENABLE_DEBUG */ /* Retrieve surface parameters */ const double *face_parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY, ltreeid); T8_ASSERT (face_parameters != NULL); /* Retrieve surface_parameter in global space by triangular interpolation from ref_coords to global space */ @@ -210,7 +211,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt glob_intersection); /* Get parameters of the current edge if the edge is curved */ const double *edge_parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (edge_parameters != NULL); /* Linear interpolation between parameters */ @@ -227,7 +228,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt double converted_edge_surface_parameters[2]; const int num_face_nodes = t8_eclass_num_vertices[active_tree_class]; - t8_geometry_occ::t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, + t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, interpolated_curve_parameter, face_parameters, converted_edge_surface_parameters); @@ -259,8 +260,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt } } /* Retrieve surface */ - T8_ASSERT (*faces <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (*faces))); + T8_ASSERT (*faces <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (*faces))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -280,7 +281,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt if (edges[i_edge] > 0 || edges[i_edge + num_edges] > 0) { /* Get parameters of the current edge if the edge is curved */ const double *parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (parameters != NULL); double ref_intersection[2]; @@ -302,8 +303,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt t8_geom_linear_interpolation (&ref_intersection[0], parameters, 1, 1, &interpolated_curve_parameter); } /* Retrieve curve */ - T8_ASSERT (edges[i_edge] <= occ_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey (edges[i_edge])), first, last); + T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); + curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); /* Check if curve is valid */ T8_ASSERT (!curve.IsNull ()); @@ -321,8 +322,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt t8_geom_linear_interpolation (&ref_intersection[0], parameters, 2, 1, interpolated_surface_parameters); } - T8_ASSERT (edges[i_edge + num_edges] <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (edges[i_edge + num_edges]))); + T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -348,7 +349,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gt } void -t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, +t8_geometry_cad::t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const { T8_ASSERT (active_tree_class == T8_ECLASS_QUAD); @@ -371,7 +372,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei #endif /* T8_ENABLE_DEBUG */ /* Retrieve surface parameters */ const double *face_parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY, ltreeid); T8_ASSERT (face_parameters != NULL); /* Interpolate between surface parameters */ @@ -396,11 +397,11 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei const int edge_direction = 1 - edge_orthogonal_direction; /* Retrieve edge parameters and interpolate */ const double *edge_parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (edge_parameters != NULL); - T8_ASSERT (edges[i_edge] <= occ_shape_edge_map.Size ()); + T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey (edges[i_edge])), first, last); + curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); /* Check if curve is valid */ T8_ASSERT (!curve.IsNull ()); @@ -412,7 +413,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei /* Convert edge parameter to surface parameters */ double converted_edge_surface_parameters[2]; const int num_face_nodes = t8_eclass_num_vertices[active_tree_class]; - t8_geometry_occ::t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, + t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters (edges[i_edge], *faces, num_face_nodes, interpolated_curve_parameter, face_parameters, converted_edge_surface_parameters); @@ -439,8 +440,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei } /* Retrieve surface */ - T8_ASSERT (*faces <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (*faces))); + T8_ASSERT (*faces <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (*faces))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -483,7 +484,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei t8_geom_linear_interpolation (&ref_coords[edge_direction], temp_edge_vertices, 3, 1, interpolated_coords); /* Interpolate parameters between edge vertices. Same procedure as above. */ const double *parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (parameters != NULL); /* Curves have only one parameter u, surfaces have two, u and v. * Therefore, we have to distinguish if the edge has a curve or surface linked to it. */ @@ -492,8 +493,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei double interpolated_curve_parameter; t8_geom_linear_interpolation (&ref_coords[edge_direction], parameters, 1, 1, &interpolated_curve_parameter); - T8_ASSERT (edges[i_edge] <= occ_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey (edges[i_edge])), first, last); + T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); + curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); /* Check if curve are valid */ T8_ASSERT (!curve.IsNull ()); @@ -506,8 +507,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&ref_coords[edge_direction], parameters, 2, 1, interpolated_surface_parameters); - T8_ASSERT (edges[i_edge + num_edges] <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (edges[i_edge + num_edges]))); + T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -534,7 +535,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreei } void -t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, +t8_geometry_cad::t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const { T8_ASSERT (active_tree_class == T8_ECLASS_HEX); @@ -588,7 +589,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid t8_geom_linear_interpolation (&ref_coords[edge_direction], temp_edge_vertices, 3, 1, interpolated_coords); /* Interpolate parameters between edge vertices. Same procedure as above. */ const double *parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + i_edge, ltreeid); T8_ASSERT (parameters != NULL); /* Curves have only one parameter u, surfaces have two, u and v. * Therefore, we have to distinguish if the edge has a curve or surface linked to it. */ @@ -596,8 +597,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&ref_coords[edge_direction], parameters, 1, 1, &interpolated_curve_param); - T8_ASSERT (edges[i_edge] <= occ_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey (edges[i_edge])), first, last); + T8_ASSERT (edges[i_edge] <= cad_shape_edge_map.Size ()); + curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (edges[i_edge])), first, last); /* Check if curve are valid */ T8_ASSERT (!curve.IsNull ()); @@ -609,8 +610,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Linear interpolation between parameters */ t8_geom_linear_interpolation (&ref_coords[edge_direction], parameters, 2, 1, interpolated_surface_params); - T8_ASSERT (edges[i_edge + num_edges] <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (edges[i_edge + num_edges]))); + T8_ASSERT (edges[i_edge + num_edges] <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (edges[i_edge + num_edges]))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -670,7 +671,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid surface_parameters_from_curve[2] = { 0 }; /* Retrieve surface parameters of nodes */ const double *surface_parameters = (double *) t8_cmesh_get_attribute ( - cmesh, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + i_faces, ltreeid); + cmesh, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + i_faces, ltreeid); T8_ASSERT (surface_parameters != NULL); /* Iterate over each edge of face */ for (int i_face_edge = 0; i_face_edge < 4; ++i_face_edge) { @@ -695,7 +696,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Retrieve parameters of nodes und curve */ const double *curve_parameters = (double *) t8_cmesh_get_attribute ( cmesh, t8_get_package_id (), - T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge], + T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge], ltreeid); T8_ASSERT (curve_parameters != NULL); /* Interpolate linearly between the parameters of the two nodes on the curve */ @@ -717,8 +718,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid /* Retrieve the curve of the edge */ T8_ASSERT (edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]] - <= occ_shape_edge_map.Size ()); - curve = BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey ( + <= cad_shape_edge_map.Size ()); + curve = BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey ( edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]])), first, last); /* Check if curve is valid */ @@ -741,7 +742,7 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid } /* Convert the interpolated parameter of the curve into the corresponding parameters on the surface */ const int num_face_nodes = t8_eclass_num_vertices[active_tree_class]; - t8_geometry_occ::t8_geom_edge_parameter_to_face_parameters ( + t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters ( edges[t8_face_edge_to_tree_edge[T8_ECLASS_HEX][i_faces][i_face_edge]], faces[i_faces], num_face_nodes, interpolated_curve_param, surface_parameters, surface_parameters_from_curve); @@ -805,8 +806,8 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid } /* Retrieve the surface of the edge */ - T8_ASSERT (faces[i_faces] <= occ_shape_face_map.Size ()); - surface = BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (faces[i_faces]))); + T8_ASSERT (faces[i_faces] <= cad_shape_face_map.Size ()); + surface = BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (faces[i_faces]))); /* Check if surface is valid */ T8_ASSERT (!surface.IsNull ()); @@ -831,71 +832,71 @@ t8_geometry_occ::t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid } int -t8_geometry_occ::t8_geom_is_line (const int curve_index) const +t8_geometry_cad::t8_geom_is_line (const int curve_index) const { - const Handle_Geom_Curve curve = t8_geom_get_occ_curve (curve_index); + const Handle_Geom_Curve curve = t8_geom_get_cad_curve (curve_index); const GeomAdaptor_Curve curve_adaptor (curve); return curve_adaptor.GetType () == GeomAbs_Line; } int -t8_geometry_occ::t8_geom_is_plane (const int surface_index) const +t8_geometry_cad::t8_geom_is_plane (const int surface_index) const { - const Handle_Geom_Surface surface = t8_geom_get_occ_surface (surface_index); + const Handle_Geom_Surface surface = t8_geom_get_cad_surface (surface_index); const GeomAdaptor_Surface surface_adaptor (surface); return surface_adaptor.GetType () == GeomAbs_Plane; } const gp_Pnt -t8_geometry_occ::t8_geom_get_occ_point (const int index) const +t8_geometry_cad::t8_geom_get_cad_point (const int index) const { - T8_ASSERT (index <= occ_shape_vertex_map.Size ()); - return BRep_Tool::Pnt (TopoDS::Vertex (occ_shape_vertex_map.FindKey (index))); + T8_ASSERT (index <= cad_shape_vertex_map.Size ()); + return BRep_Tool::Pnt (TopoDS::Vertex (cad_shape_vertex_map.FindKey (index))); } const Handle_Geom_Curve -t8_geometry_occ::t8_geom_get_occ_curve (const int index) const +t8_geometry_cad::t8_geom_get_cad_curve (const int index) const { - T8_ASSERT (index <= occ_shape_edge_map.Size ()); + T8_ASSERT (index <= cad_shape_edge_map.Size ()); Standard_Real first, last; - return BRep_Tool::Curve (TopoDS::Edge (occ_shape_edge_map.FindKey (index)), first, last); + return BRep_Tool::Curve (TopoDS::Edge (cad_shape_edge_map.FindKey (index)), first, last); } const Handle_Geom_Surface -t8_geometry_occ::t8_geom_get_occ_surface (const int index) const +t8_geometry_cad::t8_geom_get_cad_surface (const int index) const { - T8_ASSERT (index <= occ_shape_face_map.Size ()); - return BRep_Tool::Surface (TopoDS::Face (occ_shape_face_map.FindKey (index))); + T8_ASSERT (index <= cad_shape_face_map.Size ()); + return BRep_Tool::Surface (TopoDS::Face (cad_shape_face_map.FindKey (index))); } const TopTools_IndexedMapOfShape -t8_geometry_occ::t8_geom_get_occ_shape_vertex_map () const +t8_geometry_cad::t8_geom_get_cad_shape_vertex_map () const { - return occ_shape_vertex_map; + return cad_shape_vertex_map; } const TopTools_IndexedMapOfShape -t8_geometry_occ::t8_geom_get_occ_shape_edge_map () const +t8_geometry_cad::t8_geom_get_cad_shape_edge_map () const { - return occ_shape_edge_map; + return cad_shape_edge_map; } const TopTools_IndexedMapOfShape -t8_geometry_occ::t8_geom_get_occ_shape_face_map () const +t8_geometry_cad::t8_geom_get_cad_shape_face_map () const { - return occ_shape_face_map; + return cad_shape_face_map; } int -t8_geometry_occ::t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const +t8_geometry_cad::t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const { - const TopTools_ListOfShape collection1 = occ_shape_vertex2edge_map.FindFromIndex (vertex1_index); - const TopTools_ListOfShape collection2 = occ_shape_vertex2edge_map.FindFromIndex (vertex2_index); + const TopTools_ListOfShape collection1 = cad_shape_vertex2edge_map.FindFromIndex (vertex1_index); + const TopTools_ListOfShape collection2 = cad_shape_vertex2edge_map.FindFromIndex (vertex2_index); for (auto edge1 = collection1.begin (); edge1 != collection1.end (); ++edge1) { for (auto edge2 = collection2.begin (); edge2 != collection2.end (); ++edge2) { if (edge1->IsEqual (*edge2)) { - return occ_shape_edge2face_map.FindIndex (*edge1); + return cad_shape_edge2face_map.FindIndex (*edge1); } } } @@ -903,15 +904,15 @@ t8_geometry_occ::t8_geom_get_common_edge (const int vertex1_index, const int ver } int -t8_geometry_occ::t8_geom_get_common_face (const int edge1_index, const int edge2_index) const +t8_geometry_cad::t8_geom_get_common_face (const int edge1_index, const int edge2_index) const { - const TopTools_ListOfShape collection1 = occ_shape_edge2face_map.FindFromIndex (edge1_index); - const TopTools_ListOfShape collection2 = occ_shape_edge2face_map.FindFromIndex (edge2_index); + const TopTools_ListOfShape collection1 = cad_shape_edge2face_map.FindFromIndex (edge1_index); + const TopTools_ListOfShape collection2 = cad_shape_edge2face_map.FindFromIndex (edge2_index); for (auto face1 = collection1.begin (); face1 != collection1.end (); ++face1) { for (auto face2 = collection2.begin (); face2 != collection2.end (); ++face2) { if (face1->IsEqual (*face2)) { - return occ_shape_face_map.FindIndex (*face1); + return cad_shape_face_map.FindIndex (*face1); } } } @@ -919,26 +920,26 @@ t8_geometry_occ::t8_geom_get_common_face (const int edge1_index, const int edge2 } int -t8_geometry_occ::t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const +t8_geometry_cad::t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const { - const TopTools_ListOfShape collection = occ_shape_vertex2edge_map.FindFromIndex (vertex_index); - return collection.Contains (occ_shape_edge_map.FindKey (edge_index)); + const TopTools_ListOfShape collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); + return collection.Contains (cad_shape_edge_map.FindKey (edge_index)); } int -t8_geometry_occ::t8_geom_is_edge_on_face (const int edge_index, const int face_index) const +t8_geometry_cad::t8_geom_is_edge_on_face (const int edge_index, const int face_index) const { - const TopTools_ListOfShape collection = occ_shape_edge2face_map.FindFromIndex (edge_index); - return collection.Contains (occ_shape_face_map.FindKey (face_index)); + const TopTools_ListOfShape collection = cad_shape_edge2face_map.FindFromIndex (edge_index); + return collection.Contains (cad_shape_face_map.FindKey (face_index)); } int -t8_geometry_occ::t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const +t8_geometry_cad::t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const { - const TopTools_ListOfShape edge_collection = occ_shape_vertex2edge_map.FindFromIndex (vertex_index); + const TopTools_ListOfShape edge_collection = cad_shape_vertex2edge_map.FindFromIndex (vertex_index); for (auto edge = edge_collection.begin (); edge != edge_collection.end (); ++edge) { - const TopTools_ListOfShape face_collection = occ_shape_edge2face_map.FindFromKey (*edge); - if (face_collection.Contains (occ_shape_face_map.FindKey (face_index))) { + const TopTools_ListOfShape face_collection = cad_shape_edge2face_map.FindFromKey (*edge); + if (face_collection.Contains (cad_shape_face_map.FindKey (face_index))) { return 1; } } @@ -946,38 +947,38 @@ t8_geometry_occ::t8_geom_is_vertex_on_face (const int vertex_index, const int fa } void -t8_geometry_occ::t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, +t8_geometry_cad::t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, double *edge_param) const { - T8_ASSERT (t8_geometry_occ::t8_geom_is_vertex_on_edge (vertex_index, edge_index)); - TopoDS_Vertex vertex = TopoDS::Vertex (occ_shape_vertex_map.FindKey (vertex_index)); - TopoDS_Edge edge = TopoDS::Edge (occ_shape_edge_map.FindKey (edge_index)); + T8_ASSERT (t8_geometry_cad::t8_geom_is_vertex_on_edge (vertex_index, edge_index)); + TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); + TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); *edge_param = BRep_Tool::Parameter (vertex, edge); } void -t8_geometry_occ::t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, +t8_geometry_cad::t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, double *face_params) const { - T8_ASSERT (t8_geometry_occ::t8_geom_is_vertex_on_face (vertex_index, face_index)); + T8_ASSERT (t8_geometry_cad::t8_geom_is_vertex_on_face (vertex_index, face_index)); gp_Pnt2d uv; - TopoDS_Vertex vertex = TopoDS::Vertex (occ_shape_vertex_map.FindKey (vertex_index)); - TopoDS_Face face = TopoDS::Face (occ_shape_face_map.FindKey (face_index)); + TopoDS_Vertex vertex = TopoDS::Vertex (cad_shape_vertex_map.FindKey (vertex_index)); + TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); uv = BRep_Tool::Parameters (vertex, face); face_params[0] = uv.X (); face_params[1] = uv.Y (); } void -t8_geometry_occ::t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, +t8_geometry_cad::t8_geom_edge_parameter_to_face_parameters (const int edge_index, const int face_index, const int num_face_nodes, const double edge_param, const double *surface_params, double *face_params) const { - T8_ASSERT (t8_geometry_occ::t8_geom_is_edge_on_face (edge_index, face_index)); + T8_ASSERT (t8_geometry_cad::t8_geom_is_edge_on_face (edge_index, face_index)); Standard_Real first, last; gp_Pnt2d uv; - TopoDS_Edge edge = TopoDS::Edge (occ_shape_edge_map.FindKey (edge_index)); - TopoDS_Face face = TopoDS::Face (occ_shape_face_map.FindKey (face_index)); + TopoDS_Edge edge = TopoDS::Edge (cad_shape_edge_map.FindKey (edge_index)); + TopoDS_Face face = TopoDS::Face (cad_shape_face_map.FindKey (face_index)); Handle_Geom2d_Curve curve_on_surface = BRep_Tool::CurveOnSurface (edge, face, first, last); Handle_Geom_Surface surface = BRep_Tool::Surface (face); curve_on_surface->D0 (edge_param, uv); @@ -1022,37 +1023,37 @@ t8_geometry_occ::t8_geom_edge_parameter_to_face_parameters (const int edge_index } void -t8_geometry_occ::t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const +t8_geometry_cad::t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const { - const Handle_Geom_Surface occ_surface = t8_geom_get_occ_surface (surface_index); - occ_surface->Bounds (bounds[0], bounds[1], bounds[2], bounds[3]); + const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (surface_index); + cad_surface->Bounds (bounds[0], bounds[1], bounds[2], bounds[3]); } void -t8_geometry_occ::t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const +t8_geometry_cad::t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const { - const Handle_Geom_Curve occ_edge = t8_geom_get_occ_curve (edge_index); - bounds[0] = occ_edge->FirstParameter (); - bounds[1] = occ_edge->LastParameter (); + const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); + bounds[0] = cad_edge->FirstParameter (); + bounds[1] = cad_edge->LastParameter (); } int -t8_geometry_occ::t8_geom_is_edge_closed (int edge_index) const +t8_geometry_cad::t8_geom_is_edge_closed (int edge_index) const { - const Handle_Geom_Curve occ_edge = t8_geom_get_occ_curve (edge_index); - return occ_edge->IsClosed (); + const Handle_Geom_Curve cad_edge = t8_geom_get_cad_curve (edge_index); + return cad_edge->IsClosed (); } int -t8_geometry_occ::t8_geom_is_surface_closed (int geometry_index, int parameter) const +t8_geometry_cad::t8_geom_is_surface_closed (int geometry_index, int parameter) const { - const Handle_Geom_Surface occ_surface = t8_geom_get_occ_surface (geometry_index); + const Handle_Geom_Surface cad_surface = t8_geom_get_cad_surface (geometry_index); switch (parameter) { case 0: - return occ_surface->IsUClosed (); + return cad_surface->IsUClosed (); break; case 1: - return occ_surface->IsVClosed (); + return cad_surface->IsVClosed (); break; default: SC_ABORT_NOT_REACHED (); @@ -1063,20 +1064,20 @@ t8_geometry_occ::t8_geom_is_surface_closed (int geometry_index, int parameter) c /* This part should be callable from C */ T8_EXTERN_C_BEGIN (); -/* Satisfy the C interface from t8_geometry_occ.h. +/* Satisfy the C interface from t8_geometry_cad.h. * Create a new geometry with given dimension. */ -t8_geometry_occ_c * -t8_geometry_occ_new (int dimension, const char *fileprefix, const char *name_in) +t8_geometry_cad_c * +t8_geometry_cad_new (int dimension, const char *fileprefix, const char *name_in) { - t8_geometry_occ *geom = new t8_geometry_occ (dimension, fileprefix, name_in); - return (t8_geometry_occ_c *) geom; + t8_geometry_cad *geom = new t8_geometry_cad (dimension, fileprefix, name_in); + return (t8_geometry_cad_c *) geom; } void -t8_geometry_occ_destroy (t8_geometry_occ_c **geom) +t8_geometry_cad_destroy (t8_geometry_cad_c **geom) { T8_ASSERT (geom != NULL); - T8_ASSERT ((*geom)->t8_geom_get_type () == T8_GEOMETRY_TYPE_OCC); + T8_ASSERT ((*geom)->t8_geom_get_type () == T8_GEOMETRY_TYPE_CAD); delete *geom; *geom = NULL; diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.h b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h similarity index 73% rename from src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.h rename to src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h index 689d3938f2..40d2b278e3 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.h +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.h @@ -20,27 +20,27 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_geometry_occ.h - * This header provides the C interface to create a occ geometry. +/** \file t8_geometry_cad.h + * This header provides the C interface to create a cad geometry. */ -#ifndef T8_GEOMETRY_OCC_H -#define T8_GEOMETRY_OCC_H +#ifndef T8_GEOMETRY_cad_H +#define T8_GEOMETRY_cad_H #include #include #include /** This typedef holds virtual functions for a particular geometry. - * We need it so that we can use t8_geometry_occ_c pointers in .c files + * We need it so that we can use t8_geometry_cad_c pointers in .c files * without them seeing the actual C++ code (and then not compiling) */ -typedef struct t8_geometry_occ t8_geometry_occ_c; +typedef struct t8_geometry_cad t8_geometry_cad_c; T8_EXTERN_C_BEGIN (); /** - * Create a new occ geometry with a given dimension. The geometry + * Create a new cad geometry with a given dimension. The geometry * is currently viable with quad/hex and triangle trees. Tets will be supported soon. * The geometry uses as many vertices as the tree type has, as well as * additional geometry information, which is extracted from a .brep file. @@ -48,22 +48,22 @@ T8_EXTERN_C_BEGIN (); * Since the internals of this geometry are finely tuned to the .brep file * it is recommended to only use it with the \ref t8_cmesh_readmshfile function. * \param [in] dim 0 <= \a dimension <= 3. The dimension. - * \param [in] fileprefix Prefix of a .brep file from which to extract an occ geometry. + * \param [in] fileprefix Prefix of a .brep file from which to extract an cad geometry. * \param [in] name The name to give this geometry. - * \return A pointer to an allocated t8_geometry_occ struct, as - * if the \ref t8_geometry_occ (int dim, const *char fileprefix, + * \return A pointer to an allocated t8_geometry_cad struct, as + * if the \ref t8_geometry_cad (int dim, const *char fileprefix, * const char *name) * constructor was called. */ -t8_geometry_occ_c * -t8_geometry_occ_new (int dim, const char *fileprefix, const char *name_in); +t8_geometry_cad_c * +t8_geometry_cad_new (int dim, const char *fileprefix, const char *name_in); -/** Destroy a occ geometry that was created with \ref t8_geometry_occ_new. - * \param [in,out] geom A occ geometry. Set to NULL on output. +/** Destroy a cad geometry that was created with \ref t8_geometry_cad_new. + * \param [in,out] geom A cad geometry. Set to NULL on output. */ void -t8_geometry_occ_destroy (t8_geometry_occ_c **geom); +t8_geometry_cad_destroy (t8_geometry_cad_c **geom); T8_EXTERN_C_END (); -#endif /* !T8_GEOMETRY_OCC_H! */ +#endif /* !T8_GEOMETRY_cad_H! */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx similarity index 73% rename from src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.hxx rename to src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx index 077d43c632..3f97814b12 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_occ.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx @@ -20,20 +20,20 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file t8_geometry_occ.hxx +/** \file t8_geometry_cad.hxx * This geometry implements OpenCASCADE geometries. It enables the option to link different - * 1 and 2 dimensional occ geometries to the edges and faces of refinement trees. + * 1 and 2 dimensional cad geometries to the edges and faces of refinement trees. * The geometry of the refinement tree is extended into the volume accordingly. */ -#ifndef T8_GEOMETRY_OCC_HXX -#define T8_GEOMETRY_OCC_HXX +#ifndef T8_GEOMETRY_CAD_HXX +#define T8_GEOMETRY_CAD_HXX #include #include #include #include -#include +#include #if T8_WITH_OCC @@ -43,11 +43,11 @@ #include #include -struct t8_geometry_occ: public t8_geometry_with_vertices +struct t8_geometry_cad: public t8_geometry_with_vertices { public: /** - * Constructor of the occ geometry with a given dimension. The geometry + * Constructor of the cad geometry with a given dimension. The geometry * is currently viable with quad/hex and triangle trees. Tets will be supported soon. * The geometry uses as many vertices as the tree type has, as well as * additional geometry information, which is extracted from a .brep file. @@ -55,30 +55,30 @@ struct t8_geometry_occ: public t8_geometry_with_vertices * Since the internals of this geometry are finely tuned to the .brep file * it is recommended to only use it with the \ref t8_cmesh_readmshfile function. * \param [in] dim The dimension of this geometry. - * \param [in] fileprefix Prefix of a .brep file from which to extract an occ geometry. + * \param [in] fileprefix Prefix of a .brep file from which to extract an cad geometry. * \param [in] name The name to give this geometry. */ - t8_geometry_occ (int dim, const char *fileprefix, const char *name); + t8_geometry_cad (int dim, const char *fileprefix, const char *name); /** - * Constructor of the occ geometry with a given dimension. The geometry + * Constructor of the cad geometry with a given dimension. The geometry * is currently viable with quad/hex and triangle trees. Tets will be supported soon. * The geometry uses as many vertices as the tree type has, as well as - * additional geometry information, which is given via the \a occ_shape. + * additional geometry information, which is given via the \a cad_shape. * The vertices are saved via the \ref t8_cmesh_set_tree_vertices function. * This constructor can be used in short scripts or in combination with a * mesh generator, to omit the file IO of the - * \ref t8_geometry_occ (int dim, const char *fileprefix, const char *name) constructor. + * \ref t8_geometry_cad (int dim, const char *fileprefix, const char *name) constructor. * \param [in] dim The dimension of this geometry. - * \param [in] occ_shape Occ shape geometry. + * \param [in] cad_shape cad shape geometry. * \param [in] name The name to give this geometry. */ - t8_geometry_occ (int dim, const TopoDS_Shape occ_shape, const char *name); + t8_geometry_cad (int dim, const TopoDS_Shape cad_shape, const char *name); /** The destructor. * Clears the allocated memory. */ - virtual ~t8_geometry_occ () + virtual ~t8_geometry_cad () { /* Nothing to do. */ } @@ -90,7 +90,7 @@ struct t8_geometry_occ: public t8_geometry_with_vertices inline t8_geometry_type_t t8_geom_get_type () const { - return T8_GEOMETRY_TYPE_OCC; + return T8_GEOMETRY_TYPE_CAD; }; /** @@ -128,123 +128,123 @@ struct t8_geometry_occ: public t8_geometry_with_vertices virtual void t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); - /** Check if a occ_curve is a line. - * \param [in] curve_index The index of the occ_curve. + /** Check if a cad_curve is a line. + * \param [in] curve_index The index of the cad_curve. * \return 1 if curve is a line, 0 if curve is not a line. */ int t8_geom_is_line (const int curve_index) const; - /** Check if a occ_surface is a plane. - * \param [in] surface_index The index of the occ_surface. + /** Check if a cad_surface is a plane. + * \param [in] surface_index The index of the cad_surface. * \return 1 if surface is a plane linear, 0 if surface is not a plane. */ int t8_geom_is_plane (const int surface_index) const; - /** Get an occ point from the occ_shape. - * \param [in] index The index of the point in the occ_shape. - * \return The occ point. + /** Get an cad point from the cad_shape. + * \param [in] index The index of the point in the cad_shape. + * \return The cad point. */ const gp_Pnt - t8_geom_get_occ_point (const int index) const; + t8_geom_get_cad_point (const int index) const; - /** Get an occ curve from the occ_shape. - * \param [in] index The index of the curve in the occ_shape. - * \return The occ curve. + /** Get an cad curve from the cad_shape. + * \param [in] index The index of the curve in the cad_shape. + * \return The cad curve. */ const Handle_Geom_Curve - t8_geom_get_occ_curve (const int index) const; + t8_geom_get_cad_curve (const int index) const; - /** Get an occ surface from the occ_shape. - * \param [in] index The index of the surface in the occ_shape. - * \return The occ surface. + /** Get an cad surface from the cad_shape. + * \param [in] index The index of the surface in the cad_shape. + * \return The cad surface. */ const Handle_Geom_Surface - t8_geom_get_occ_surface (const int index) const; + t8_geom_get_cad_surface (const int index) const; - /** Get the occ_shape_vertex2edge_map. - * \return The occ_shape_vertex_map. + /** Get the cad_shape_vertex2edge_map. + * \return The cad_shape_vertex_map. */ const TopTools_IndexedMapOfShape - t8_geom_get_occ_shape_vertex_map () const; + t8_geom_get_cad_shape_vertex_map () const; - /** Get the occ_shape_edge2face_map. - * \return The occ_shape_edge_map. + /** Get the cad_shape_edge2face_map. + * \return The cad_shape_edge_map. */ const TopTools_IndexedMapOfShape - t8_geom_get_occ_shape_edge_map () const; + t8_geom_get_cad_shape_edge_map () const; - /** Get the occ_shape_face_map. - * \return The occ_shape_face_map. + /** Get the cad_shape_face_map. + * \return The cad_shape_face_map. */ const TopTools_IndexedMapOfShape - t8_geom_get_occ_shape_face_map () const; + t8_geom_get_cad_shape_face_map () const; - /** Check if two occ points share a common occ edge. - * \param [in] vertex1_index The index of the first occ point. - * \param [in] vertex2_index The index of the second occ point. + /** Check if two cad points share a common cad edge. + * \param [in] vertex1_index The index of the first cad point. + * \param [in] vertex2_index The index of the second cad point. * \return Index of the shared edge. 0 if there is no shared edge. */ int t8_geom_get_common_edge (const int vertex1_index, const int vertex2_index) const; - /** Check if two occ edges share a common occ face. - * \param [in] edge1_index The index of the first occ edge. - * \param [in] edge2_index The index of the second occ edge. + /** Check if two cad edges share a common cad face. + * \param [in] edge1_index The index of the first cad edge. + * \param [in] edge2_index The index of the second cad edge. * \return Index of the shared face. 0 if there is no shared face. */ int t8_geom_get_common_face (const int edge1_index, const int edge2_index) const; - /** Check if a occ vertex lies on an occ edge. - * \param [in] vertex_index The index of the occ vertex. - * \param [in] edge_index The index of the occ edge. + /** Check if a cad vertex lies on an cad edge. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] edge_index The index of the cad edge. * \return 1 if vertex lies on edge, otherwise 0. */ int t8_geom_is_vertex_on_edge (const int vertex_index, const int edge_index) const; - /** Check if a occ vertex lies on an occ edge. - * \param [in] edge_index The index of the occ vertex. - * \param [in] face_index The index of the occ edge. + /** Check if a cad vertex lies on an cad edge. + * \param [in] edge_index The index of the cad vertex. + * \param [in] face_index The index of the cad edge. * \return 1 if vertex lies on edge, otherwise 0. */ int t8_geom_is_edge_on_face (const int edge_index, const int face_index) const; - /** Check if a occ vertex lies on an occ face. - * \param [in] vertex_index The index of the occ vertex. - * \param [in] face_index The index of the occ face. + /** Check if a cad vertex lies on an cad face. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] face_index The index of the cad face. * \return 1 if vertex lies on face, otherwise 0. */ int t8_geom_is_vertex_on_face (const int vertex_index, const int face_index) const; - /** Retrieves the parameter of an occ vertex on an occ edge. + /** Retrieves the parameter of an cad vertex on an cad edge. * The vertex has to lie on the edge. - * \param [in] vertex_index The index of the occ vertex. - * \param [in] edge_index The index of the occ edge. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] edge_index The index of the cad edge. * \param [out] edge_param The parameter of the vertex on the edge. */ void t8_geom_get_parameter_of_vertex_on_edge (const int vertex_index, const int edge_index, double *edge_param) const; - /** Retrieves the parameters of an occ vertex on a occ face. + /** Retrieves the parameters of an cad vertex on a cad face. * The vertex has to lie on the face. - * \param [in] vertex_index The index of the occ vertex. - * \param [in] face_index The index of the occ face. + * \param [in] vertex_index The index of the cad vertex. + * \param [in] face_index The index of the cad face. * \param [out] face_params The parameters of the vertex on the face. */ void t8_geom_get_parameters_of_vertex_on_face (const int vertex_index, const int face_index, double *face_params) const; - /** Converts the parameters of an occ edge to the corresponding parameters on an occ face. + /** Converts the parameters of an cad edge to the corresponding parameters on an cad face. * The edge has to lie on the face. * For the conversion of edge parameters of mesh elements to topological face parameters of a closed surface, it is additionally * checked, whether the conversion was correct, to prevent disorted elements. - * \param [in] edge_index The index of the occ edge, which parameters should be converted to face parameters. - * \param [in] face_index The index of the occ face, on to which the edge parameters should be converted. + * \param [in] edge_index The index of the cad edge, which parameters should be converted to face parameters. + * \param [in] face_index The index of the cad face, on to which the edge parameters should be converted. * \param [in] num_face_nodes The number of the face nodes of the evaluated element. Only needed for closed surface check, otherwise NULL. * \param [in] edge_param The parameter on the edge. * \param [in] surface_param The parameters of the surface nodes. @@ -258,16 +258,16 @@ struct t8_geometry_occ: public t8_geometry_with_vertices const double edge_param, const double *surface_params, double *face_params) const; - /** Finds the parametric bounds of an occ face. - * \param [in] face_index The index of the occ face. - * \param [out] bounds The parametric bounds of the occ face. + /** Finds the parametric bounds of an cad face. + * \param [in] face_index The index of the cad face. + * \param [out] bounds The parametric bounds of the cad face. */ void t8_geom_get_face_parametric_bounds (const int surface_index, double *bounds) const; - /** Finds the parametric bounds of an occ edge. - * \param [in] edge_index The index of the occ edge. - * \param [out] bounds The parametric bounds of the occ edge. + /** Finds the parametric bounds of an cad edge. + * \param [in] edge_index The index of the cad edge. + * \param [out] bounds The parametric bounds of the cad edge. */ void t8_geom_get_edge_parametric_bounds (const int edge_index, double *bounds) const; @@ -298,7 +298,7 @@ struct t8_geometry_occ: public t8_geometry_with_vertices * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. */ void - t8_geom_evaluate_occ_triangle (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, + t8_geom_evaluate_cad_triangle (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; /** @@ -310,7 +310,7 @@ struct t8_geometry_occ: public t8_geometry_with_vertices * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. */ void - t8_geom_evaluate_occ_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + t8_geom_evaluate_cad_quad (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; /** @@ -322,21 +322,21 @@ struct t8_geometry_occ: public t8_geometry_with_vertices * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. */ void - t8_geom_evaluate_occ_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + t8_geom_evaluate_cad_hex (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const; const int *edges; /**< The linked edges of the currently active tree. */ const int *faces; /**< The linked faces of the currently active tree. */ - TopoDS_Shape occ_shape; /**< Occ geometry */ - TopTools_IndexedMapOfShape occ_shape_vertex_map; /**< Map of all TopoDS_Vertex in shape. */ - TopTools_IndexedMapOfShape occ_shape_edge_map; /**< Map of all TopoDS_Edge in shape. */ - TopTools_IndexedMapOfShape occ_shape_face_map; /**< Map of all TopoDS_Face in shape. */ + TopoDS_Shape cad_shape; /**< cad geometry */ + TopTools_IndexedMapOfShape cad_shape_vertex_map; /**< Map of all TopoDS_Vertex in shape. */ + TopTools_IndexedMapOfShape cad_shape_edge_map; /**< Map of all TopoDS_Edge in shape. */ + TopTools_IndexedMapOfShape cad_shape_face_map; /**< Map of all TopoDS_Face in shape. */ TopTools_IndexedDataMapOfShapeListOfShape - occ_shape_vertex2edge_map; /**< Maps all TopoDS_Vertex of shape to all its connected TopoDS_Edge */ + cad_shape_vertex2edge_map; /**< Maps all TopoDS_Vertex of shape to all its connected TopoDS_Edge */ TopTools_IndexedDataMapOfShapeListOfShape - occ_shape_edge2face_map; /**< Maps all TopoDS_Edge of shape to all its connected TopoDS_Face */ + cad_shape_edge2face_map; /**< Maps all TopoDS_Edge of shape to all its connected TopoDS_Face */ }; #endif /* T8_WITH_OCC */ -#endif /* !T8_GEOMETRY_OCC_HXX! */ +#endif /* !T8_GEOMETRY_CAD_HXX! */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx index 04bd567754..885c81877a 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.cxx @@ -110,184 +110,169 @@ t8_geometry_squared_disk::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreei } } -/** - * Map the faces of an oktaeder to a spherical surface. - * \param [in] cmesh The cmesh in which the point lies. - * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. - * \param [in] ref_coords Array of \a dimension many entries, specifying a point in [0,1]^dimension. - * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. - */ -void -t8_geometry_triangulated_spherical_surface::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, - const double *ref_coords, const size_t num_coords, - double *out_coords) const +/* Helper function for `t8_geom_evaluate_sphere_tri_prism`. */ +static inline void +t8_map_triangle_to_sphere (const double *active_tree_vertices, const double sphere_radius, const int shift, + const double u_ref[3], const double v_ref[3], const double w_ref[3], + const double *ref_coords, const size_t num_coords, double *out_coords) { - /* We average over the three corners of the triangle. */ - const double avg_factor = 1.0 / 3.0; - - /* Radius of the sphere scaled by the average factor. */ - const double radius = t8_vec_norm (active_tree_vertices) * avg_factor; - - /* The next three code blocks straighten out the elements near the triangle - * corners by averaging the rectification with all three corners. */ + double u[3]; /* Position vector. */ + double v[3]; /* First triangle side. */ + double w[3]; /* Second triangle side. */ + + /* `(3 - shift + 0) % 3)*3` circular rotates array indices according to `shift`. */ + for (size_t i = 0; i < 3; i++) { + u[i] = active_tree_vertices[((3 - shift + 0) % 3) * 3 + i]; + v[i] = active_tree_vertices[((3 - shift + 1) % 3) * 3 + i] - u[i]; + w[i] = active_tree_vertices[((3 - shift + 2) % 3) * 3 + i] - u[i]; + } - /* First triangle corner. */ - { - double u[3]; /* Position vector. */ - double v[3]; /* First triangle side. */ - double w[3]; /* Second triangle side. */ + for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { + const size_t offset = 3 * i_coord; - u[0] = active_tree_vertices[0]; - u[1] = active_tree_vertices[1]; - u[2] = active_tree_vertices[2]; + /* Shorthand for code readability. */ + const double x_ref = ref_coords[offset + 0]; + const double y_ref = ref_coords[offset + 1]; - v[0] = active_tree_vertices[3 + 0] - u[0]; - v[1] = active_tree_vertices[3 + 1] - u[1]; - v[2] = active_tree_vertices[3 + 2] - u[2]; + /* Compute local triangle coordinates in the new reference space. */ + const double vv_ref = u_ref[0] + x_ref * v_ref[0] + y_ref * w_ref[0]; + const double ww_ref = u_ref[1] + x_ref * v_ref[1] + y_ref * w_ref[1]; - w[0] = active_tree_vertices[6 + 0] - u[0]; - w[1] = active_tree_vertices[6 + 1] - u[1]; - w[2] = active_tree_vertices[6 + 2] - u[2]; + /* tldr: Correction in order to rectify elements near the corners. This + * is necessary, since due to the transformation from the cmesh triangle to the + * sphere elements near the face centers expand while near the corners they + * shrink. Following correction alleviates this. + * TODO: This correction is not general and probably not optimal in all cases. + * But it works good enough. Find a better one. This is not a trivial task, though. + */ + const double vv_corr = tan (0.5 * M_PI * (vv_ref - 0.5)) * 0.5 + 0.5; + const double ww_corr = tan (0.5 * M_PI * (ww_ref - 0.5)) * 0.5 + 0.5; - /* Reference coordinates from this particular triangle corner. */ - const double u_ref[3] = { 0.0, 0.0, 0.0 }; - const double v_ref[3] = { 1.0, 0.0, 0.0 }; - const double w_ref[3] = { -1.0, 1.0, 0.0 }; + /* Compute and apply the corrected mapping. The position vector `pos` pokes + * through the triangle plane. It then gets rescaled to the sphere's radius. */ + double pos[3]; + pos[0] = u[0] + vv_corr * v[0] + ww_corr * w[0]; + pos[1] = u[1] + vv_corr * v[1] + ww_corr * w[1]; + pos[2] = u[2] + vv_corr * v[2] + ww_corr * w[2]; - for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { - const size_t offset = 3 * i_coord; + t8_vec_rescale (pos, sphere_radius); - const double x = ref_coords[offset + 0]; - const double y = ref_coords[offset + 1]; + for (size_t i = 0; i < 3; i++) { + out_coords[offset + i] = out_coords[offset + i] + pos[i] * (1.0 / 3.0); + } + } +} - /* Compute local triangle coordinate. */ - const double vv = u_ref[0] + x * v_ref[0] + y * w_ref[0]; - const double ww = u_ref[1] + x * v_ref[1] + y * w_ref[1]; +static inline void +t8_geom_evaluate_sphere_tri_prism (const double *active_tree_vertices, const t8_eclass_t eclass, + const double *ref_coords, const size_t num_coords, double *out_coords) +{ + /* The next three code blocks straighten out the elements near the triangle + * corners by averaging the rectification with all three corners. */ - /* Correction in order to rectify elements near the corners. */ - const double vv_corr = tan (0.5 * M_PI * (vv - 0.5)) * 0.5 + 0.5; - const double ww_corr = tan (0.5 * M_PI * (ww - 0.5)) * 0.5 + 0.5; + /* Clear `out_coords`. */ + for (size_t i = 0; i < 3 * num_coords; i++) { + out_coords[i] = 0.0; + } - /* Compute and apply the corrected mapping. */ - double ray[3]; /* Ray vector pinning through the triangle at reference coordinates. */ - ray[0] = u[0] + vv_corr * v[0] + ww_corr * w[0]; - ray[1] = u[1] + vv_corr * v[1] + ww_corr * w[1]; - ray[2] = u[2] + vv_corr * v[2] + ww_corr * w[2]; + /* We derive the sphere's radius from the first corner of the triangle/prism. + * The averaging factor `1/3` is already included here. */ + const double sphere_radius = t8_vec_norm (active_tree_vertices); - t8_vec_normalize (ray); + { + /* Reference coordinates from first triangle corner. */ + const double u_ref[3] = { 0.0, 0.0, 0.0 }; + const double v_ref[3] = { 1.0, 0.0, 0.0 }; + const double w_ref[3] = { -1.0, 1.0, 0.0 }; - out_coords[offset + 0] = radius * ray[0]; - out_coords[offset + 1] = radius * ray[1]; - out_coords[offset + 2] = radius * ray[2]; - } + t8_map_triangle_to_sphere (active_tree_vertices, sphere_radius, 0, u_ref, v_ref, w_ref, ref_coords, num_coords, + out_coords); } - /* Second triangle corner. */ { - double u[3]; /* Position vector. */ - double v[3]; /* First triangle side. */ - double w[3]; /* Second triangle side. */ - - u[0] = active_tree_vertices[6 + 0]; - u[1] = active_tree_vertices[6 + 1]; - u[2] = active_tree_vertices[6 + 2]; - - v[0] = active_tree_vertices[0 + 0] - u[0]; - v[1] = active_tree_vertices[0 + 1] - u[1]; - v[2] = active_tree_vertices[0 + 2] - u[2]; - - w[0] = active_tree_vertices[3 + 0] - u[0]; - w[1] = active_tree_vertices[3 + 1] - u[1]; - w[2] = active_tree_vertices[3 + 2] - u[2]; - - /* Reference coordinates from this particular triangle corner. */ + /* Reference coordinates from second triangle corner. */ const double u_ref[3] = { 1.0, 0.0, 0.0 }; const double v_ref[3] = { -1.0, 1.0, 0.0 }; const double w_ref[3] = { 0.0, -1.0, 0.0 }; - for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { - const size_t offset = 3 * i_coord; - - const double x = ref_coords[offset + 0]; - const double y = ref_coords[offset + 1]; - - /* Compute local triangle coordinate. */ - const double vv = u_ref[0] + x * v_ref[0] + y * w_ref[0]; - const double ww = u_ref[1] + x * v_ref[1] + y * w_ref[1]; - - /* Correction in order to rectify elements near the corners. */ - const double vv_corr = tan (0.5 * M_PI * (vv - 0.5)) * 0.5 + 0.5; - const double ww_corr = tan (0.5 * M_PI * (ww - 0.5)) * 0.5 + 0.5; - - /* Compute and apply the corrected mapping. */ - double ray[3]; /* Ray vector pinning through the triangle at reference coordinates. */ - ray[0] = u[0] + vv_corr * v[0] + ww_corr * w[0]; - ray[1] = u[1] + vv_corr * v[1] + ww_corr * w[1]; - ray[2] = u[2] + vv_corr * v[2] + ww_corr * w[2]; - - t8_vec_normalize (ray); - - out_coords[offset + 0] = out_coords[offset + 0] + radius * ray[0]; - out_coords[offset + 1] = out_coords[offset + 1] + radius * ray[1]; - out_coords[offset + 2] = out_coords[offset + 2] + radius * ray[2]; - } + t8_map_triangle_to_sphere (active_tree_vertices, sphere_radius, 1, u_ref, v_ref, w_ref, ref_coords, num_coords, + out_coords); } - /* Third triangle corner. */ { - double u[3]; /* Position vector. */ - double v[3]; /* First triangle side. */ - double w[3]; /* Second triangle side. */ - - u[0] = active_tree_vertices[3 + 0]; - u[1] = active_tree_vertices[3 + 1]; - u[2] = active_tree_vertices[3 + 2]; - - v[0] = active_tree_vertices[6 + 0] - u[0]; - v[1] = active_tree_vertices[6 + 1] - u[1]; - v[2] = active_tree_vertices[6 + 2] - u[2]; - - w[0] = active_tree_vertices[0 + 0] - u[0]; - w[1] = active_tree_vertices[0 + 1] - u[1]; - w[2] = active_tree_vertices[0 + 2] - u[2]; - - /* Reference coordinates from this particular triangle corner. */ + /* Reference coordinates from third triangle corner. */ const double u_ref[3] = { 0.0, 1.0, 0.0 }; const double v_ref[3] = { 0.0, -1.0, 0.0 }; const double w_ref[3] = { 1.0, 0.0, 0.0 }; - for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { - const size_t offset = 3 * i_coord; + t8_map_triangle_to_sphere (active_tree_vertices, sphere_radius, 2, u_ref, v_ref, w_ref, ref_coords, num_coords, + out_coords); + } - const double x = ref_coords[offset + 0]; - const double y = ref_coords[offset + 1]; + /* For triangles we are done. */ + if (eclass == T8_ECLASS_TRIANGLE) + return; - /* Compute local triangle coordinate. */ - const double vv = u_ref[0] + x * v_ref[0] + y * w_ref[0]; - const double ww = u_ref[1] + x * v_ref[1] + y * w_ref[1]; + /* + * For prisms we must rescale along the radial direction to pad the shell thickness. + */ - /* Correction in order to rectify elements near the corners. */ - const double vv_corr = tan (0.5 * M_PI * (vv - 0.5)) * 0.5 + 0.5; - const double ww_corr = tan (0.5 * M_PI * (ww - 0.5)) * 0.5 + 0.5; + double n[3]; /* Normal vector of the prism's base triangle at the inner shell surface. */ + t8_vec_tri_normal (active_tree_vertices, active_tree_vertices + 3, active_tree_vertices + 6, n); + t8_vec_normalize (n); - /* Compute and apply the corrected mapping. */ - double ray[3]; /* Ray vector pinning through the triangle at reference coordinates. */ - ray[0] = u[0] + vv_corr * v[0] + ww_corr * w[0]; - ray[1] = u[1] + vv_corr * v[1] + ww_corr * w[1]; - ray[2] = u[2] + vv_corr * v[2] + ww_corr * w[2]; + double r[3]; /* Radial vector through the first base triangle corners. */ + r[0] = active_tree_vertices[0]; + r[1] = active_tree_vertices[1]; + r[2] = active_tree_vertices[2]; + t8_vec_normalize (r); - t8_vec_normalize (ray); + /* With this pre-computed denominator we determine the intersection of `r` and `p`. See below. */ + const double denominator = 1.0 / t8_vec_dot (r, n); - out_coords[offset + 0] = out_coords[offset + 0] + radius * ray[0]; - out_coords[offset + 1] = out_coords[offset + 1] + radius * ray[1]; - out_coords[offset + 2] = out_coords[offset + 2] + radius * ray[2]; - } + for (size_t i_coord = 0; i_coord < num_coords; i_coord++) { + const size_t offset = 3 * i_coord; + + /* Position vector `p` pointing to the reference location in the prism. */ + double p[3]; + t8_geom_compute_linear_geometry (T8_ECLASS_PRISM, active_tree_vertices, ref_coords + offset, 1, p); + t8_vec_rescale (out_coords + offset, t8_vec_dot (p, n) * denominator); } } +/** + * Map the faces of an octahedron to a spherical surface. + * \param [in] cmesh The cmesh in which the point lies. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of \a dimension many entries, specifying a point in [0,1]^dimension. + * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. + */ +void +t8_geometry_triangulated_spherical_surface::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, + const double *ref_coords, const size_t num_coords, + double *out_coords) const +{ + t8_geom_evaluate_sphere_tri_prism (active_tree_vertices, T8_ECLASS_TRIANGLE, ref_coords, num_coords, out_coords); +} + +/** + * Map the prismed faces of an octahedron to a spherical shell. + * \param [in] cmesh The cmesh in which the point lies. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of \a dimension many entries, specifying a point in [0,1]^dimension. + * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. + */ +void +t8_geometry_prismed_spherical_shell::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, + const size_t num_coords, double *out_coords) const + +{ + t8_geom_evaluate_sphere_tri_prism (active_tree_vertices, T8_ECLASS_PRISM, ref_coords, num_coords, out_coords); +} + static inline void -t8_geom_evaluate_sphere (const double *active_tree_vertices, const int ndims, const double *ref_coords, - const size_t num_coords, double *out_coords) +t8_geom_evaluate_sphere_quad_hex (const double *active_tree_vertices, const int ndims, const double *ref_coords, + const size_t num_coords, double *out_coords) { double n[3]; /* Normal vector. */ double r[3]; /* Radial vector. */ @@ -308,6 +293,7 @@ t8_geom_evaluate_sphere (const double *active_tree_vertices, const int ndims, co { double corr_ref_coords[3]; /* Corrected reference coordinates. */ + /* Shorthand for code readability. */ const double x = ref_coords[offset + 0]; const double y = ref_coords[offset + 1]; const double z = ref_coords[offset + 2]; @@ -324,13 +310,13 @@ t8_geom_evaluate_sphere (const double *active_tree_vertices, const int ndims, co t8_geom_linear_interpolation (corr_ref_coords, active_tree_vertices, 3, ndims, p); } - const double R = (p[0] * n[0] + p[1] * n[1] + p[2] * n[2]) / (r[0] * n[0] + r[1] * n[1] + r[2] * n[2]); + const double radius = t8_vec_dot (p, n) / t8_vec_dot (r, n); t8_vec_normalize (p); - out_coords[offset + 0] = R * p[0]; - out_coords[offset + 1] = R * p[1]; - out_coords[offset + 2] = R * p[2]; + out_coords[offset + 0] = radius * p[0]; + out_coords[offset + 1] = radius * p[1]; + out_coords[offset + 2] = radius * p[2]; } } @@ -346,8 +332,7 @@ t8_geometry_quadrangulated_spherical_surface::t8_geom_evaluate (t8_cmesh_t cmesh const double *ref_coords, const size_t num_coords, double *out_coords) const { - /* This routine works just fine for the quadrangulated spherical surface, too. */ - t8_geom_evaluate_sphere (active_tree_vertices, 2, ref_coords, num_coords, out_coords); + t8_geom_evaluate_sphere_quad_hex (active_tree_vertices, 2, ref_coords, num_coords, out_coords); } /** @@ -361,7 +346,7 @@ void t8_geometry_cubed_spherical_shell::t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *out_coords) const { - t8_geom_evaluate_sphere (active_tree_vertices, 3, ref_coords, num_coords, out_coords); + t8_geom_evaluate_sphere_quad_hex (active_tree_vertices, 3, ref_coords, num_coords, out_coords); } T8_EXTERN_C_BEGIN (); @@ -390,6 +375,13 @@ t8_geometry_triangulated_spherical_surface_new () return (t8_geometry_c *) geom; } +t8_geometry_c * +t8_geometry_prismed_spherical_shell_new () +{ + t8_geometry_prismed_spherical_shell *geom = new t8_geometry_prismed_spherical_shell (); + return (t8_geometry_c *) geom; +} + t8_geometry_c * t8_geometry_quadrangulated_spherical_surface_new () { diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.h b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.h index 1743d7c41b..d7933da542 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.h +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.h @@ -62,6 +62,12 @@ t8_geometry_quadrangulated_spherical_surface_new (); t8_geometry_c * t8_geometry_cubed_spherical_shell_new (); +/** Create a new spherical_shell geometry. + * \return A pointer to an allocated geometry struct. + */ +t8_geometry_c * +t8_geometry_prismed_spherical_shell_new (); + T8_EXTERN_C_END (); #endif /* T8_GEOMETRY_EXAMPLE_H */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx index eed4d423e5..0f979e3e09 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_examples.hxx @@ -88,7 +88,7 @@ struct t8_geometry_squared_disk: public t8_geometry_with_vertices /* Load tree data is inherited from t8_geometry_with_vertices. */ }; -/** This geometry maps the faces of an oktaeder to a spherical surface. +/** This geometry maps the faces of an octahedron/icosahedron to a spherical surface. */ struct t8_geometry_triangulated_spherical_surface: public t8_geometry_with_vertices { @@ -99,17 +99,50 @@ struct t8_geometry_triangulated_spherical_surface: public t8_geometry_with_verti } /** - * Map the faces of an oktaeder to a spherical surface. + * Map the faces of an octahedron/icosahedron to a spherical surface. * \param [in] cmesh The cmesh in which the point lies. * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. * \param [in] ref_coords Array of \a dimension x \a num_coords many entries, specifying a point in /f$ [0,1]^\mathrm{dim} /f$. * \param [in] num_coords The number of points to map. * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. * - * This routine expects an input mesh of eight triangles arranged into an - * oktaeder. That is two pyramids glued together at their quadratic bases. - * The z-axis goes through the the pyramid's peak and the x- and y-axis - * are aligned with the basis' diagonals. + * This routine expects an input mesh of triangles arranged into an + * octahedron/icosahedron. + * + */ + void + t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + double out_coords[3]) const; + + /* Jacobian, not implemented. */ + void + t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + double *jacobian) const + { + SC_ABORT_NOT_REACHED (); + } + + /* Load tree data is inherited from t8_geometry_with_vertices. */ +}; + +/** This geometry maps general 2D faces to a spherical surface. + */ +class t8_geometry_spherical_surface: public t8_geometry_with_vertices { + public: + /* Basic constructor that sets the dimension and the name. */ + t8_geometry_spherical_surface (): t8_geometry_with_vertices (2, "t8_spherical_surface") + { + } + + /** + * Maps general 2D faces to a spherical surface. + * \param [in] cmesh The cmesh in which the point lies. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of \a dimension x \a num_coords many entries, specifying a point in /f$ [0,1]^\mathrm{dim} /f$. + * \param [in] num_coords The number of points to map. + * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. + * + * This routine expects an input mesh of 2D elements with their vertices sitting on a sphere. * */ void @@ -197,4 +230,39 @@ class t8_geometry_cubed_spherical_shell: public t8_geometry_with_vertices { /* Load tree data is inherited from t8_geometry_with_vertices. */ }; +/** This geometry maps prisms arranged as octahedron (or similar) to a spherical shell. + */ +class t8_geometry_prismed_spherical_shell: public t8_geometry_with_vertices { + public: + /* Basic constructor that sets the dimension and the name. */ + t8_geometry_prismed_spherical_shell (): t8_geometry_with_vertices (3, "t8_prismed_spherical_shell") + { + } + + /** + * Map prism arranged as octahedron (or similar) to a spherical shell. + * \param [in] cmesh The cmesh in which the point lies. + * \param [in] gtreeid The global tree (of the cmesh) in which the reference point is. + * \param [in] ref_coords Array of \a dimension x \a num_coords many entries, specifying a point in /f$ [0,1]^\mathrm{dim} /f$. + * \param [in] num_coords The number of points to map. + * \param [out] out_coords The mapped coordinates in physical space of \a ref_coords. The length is \a num_coords * 3. + * + * This routine expects an input mesh of prism arranged as octahedron or similar. + * + */ + void + t8_geom_evaluate (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + double out_coords[3]) const; + + /* Jacobian, not implemented. */ + void + t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, + double *jacobian) const + { + SC_ABORT_NOT_REACHED (); + } + + /* Load tree data is inherited from t8_geometry_with_vertices. */ +}; + #endif /* T8_GEOMETRY_EXAMPLES_HXX */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx index f469a24707..242d3716d0 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.cxx @@ -23,6 +23,8 @@ #include #include #include +#include +#include t8_geometry_linear::t8_geometry_linear (int dim): t8_geometry_with_vertices (dim, "") { @@ -54,6 +56,196 @@ t8_geometry_linear::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtr SC_ABORT ("Not implemented."); } +#if T8_ENABLE_DEBUG +/* Test whether four given points in 3D are coplanar up to a given tolerance. + */ +static int +t8_four_points_coplanar (const double p_0[3], const double p_1[3], const double p_2[3], const double p_3[3], + const double tolerance) +{ + /* Let p0, p1, p2, p3 be the four points. + * The four points are coplanar if the normal vectors to the triangles + * p0, p1, p2 and p0, p2, p3 are pointing in the same direction. + * + * We build the vectors A = p1 - p0, B = p2 - p0 and C = p3 - p0. + * The normal vectors to the triangles are n1 = A x B and n2 = A x C. + * These are pointing in the same direction if their cross product is 0. + * Hence we check if || n1 x n2 || < tolerance. */ + + /* A = p1 - p0 */ + double A[3]; + t8_vec_axpyz (p_0, p_1, A, -1); + + /* B = p2 - p0 */ + double B[3]; + t8_vec_axpyz (p_0, p_2, B, -1); + + /* C = p3 - p0 */ + double C[3]; + t8_vec_axpyz (p_0, p_3, C, -1); + + /* n1 = A x B */ + double A_cross_B[3]; + t8_vec_cross (A, B, A_cross_B); + + /* n2 = A x C */ + double A_cross_C[3]; + t8_vec_cross (A, C, A_cross_C); + + /* n1 x n2 */ + double n1_cross_n2[3]; + t8_vec_cross (A_cross_B, A_cross_C, n1_cross_n2); + + /* || n1 x n2 || */ + const double norm = t8_vec_norm (n1_cross_n2); + return norm < tolerance; +} +#endif + +void +t8_geometry_linear::t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, + const t8_element_t *element, const double *points, + const int num_points, int *is_inside, + const double tolerance) const +{ + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); + t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); + const t8_element_shape_t element_shape = ts->t8_element_shape (element); + switch (element_shape) { + case T8_ECLASS_VERTEX: { + /* A point is 'inside' a vertex if they have the same coordinates */ + double vertex_coords[3]; + /* Get the vertex coordinates */ + t8_forest_element_coordinate (forest, ltreeid, element, 0, vertex_coords); + /* Check whether the point and the vertex are within tolerance distance + * to each other */ + for (int ipoint = 0; ipoint < num_points; ipoint++) { + is_inside[ipoint] = t8_vertex_point_inside (vertex_coords, &points[ipoint * 3], tolerance); + } + return; + } + case T8_ECLASS_LINE: { + /* A point p is inside a line that is defined by the edge nodes + * p_0 and p_1 + * if and only if the linear system + * (p_1 - p_0)x = p - p_0 + * has a solution x with 0 <= x <= 1 + */ + double p_0[3], v[3]; + + /* Compute the vertex coordinates of the line */ + t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); + /* v = p_1 */ + t8_forest_element_coordinate (forest, ltreeid, element, 1, v); + /* v = p_1 - p_0 */ + t8_vec_axpy (p_0, v, -1); + for (int ipoint = 0; ipoint < num_points; ipoint++) { + is_inside[ipoint] = t8_line_point_inside (p_0, v, &points[ipoint * 3], tolerance); + } + return; + } + case T8_ECLASS_QUAD: { + /* We divide the quad in two triangles and use the triangle check. */ + double p_0[3], p_1[3], p_2[3], p_3[3]; + /* Compute the vertex coordinates of the quad */ + t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); + t8_forest_element_coordinate (forest, ltreeid, element, 1, p_1); + t8_forest_element_coordinate (forest, ltreeid, element, 2, p_2); + t8_forest_element_coordinate (forest, ltreeid, element, 3, p_3); + +#if T8_ENABLE_DEBUG + /* Issue a warning if the points of the quad do not lie in the same plane */ + if (!t8_four_points_coplanar (p_0, p_1, p_2, p_3, tolerance)) { + t8_debugf ("WARNING: Testing if point is inside a quad that is not coplanar. This test will be inaccurate.\n"); + } +#endif + double v[3]; + double w[3]; + /* v = v - p_0 = p_1 - p_0 */ + t8_vec_axpyz (p_0, p_1, v, -1); + /* w = w - p_0 = p_2 - p_0 */ + t8_vec_axpyz (p_0, p_2, w, -1); + /* Check whether the point is inside the first triangle. */ + for (int ipoint = 0; ipoint < num_points; ipoint++) { + is_inside[ipoint] = t8_triangle_point_inside (p_0, v, w, &points[ipoint * 3], tolerance); + } + /* If not, check whether the point is inside the second triangle. */ + /* v = v - p_0 = p_1 - p_0 */ + t8_vec_axpyz (p_1, p_2, v, -1); + /* w = w - p_0 = p_2 - p_0 */ + t8_vec_axpyz (p_1, p_3, w, -1); + for (int ipoint = 0; ipoint < num_points; ipoint++) { + if (!is_inside[ipoint]) { + /* point_inside is true if the point was inside the first or second triangle. Otherwise it is false. */ + is_inside[ipoint] = t8_triangle_point_inside (p_1, v, w, &points[ipoint * 3], tolerance); + } + } + return; + } + case T8_ECLASS_TRIANGLE: { + double p_0[3], p_1[3], p_2[3]; + + /* Compute the vertex coordinates of the triangle */ + t8_forest_element_coordinate (forest, ltreeid, element, 0, p_0); + t8_forest_element_coordinate (forest, ltreeid, element, 1, p_1); + t8_forest_element_coordinate (forest, ltreeid, element, 2, p_2); + double v[3]; + double w[3]; + /* v = v - p_0 = p_1 - p_0 */ + t8_vec_axpyz (p_0, p_1, v, -1); + /* w = w - p_0 = p_2 - p_0 */ + t8_vec_axpyz (p_0, p_2, w, -1); + + for (int ipoint = 0; ipoint < num_points; ipoint++) { + is_inside[ipoint] = t8_triangle_point_inside (p_0, v, w, &points[ipoint * 3], tolerance); + } + return; + } + case T8_ECLASS_TET: + case T8_ECLASS_HEX: + case T8_ECLASS_PRISM: + case T8_ECLASS_PYRAMID: { + /* For bilinearly interpolated volume elements, a point is inside an element + * if and only if it lies on the inner side of each face. + * The inner side is defined as the side where the outside normal vector does not + * point to. + * The point is on this inner side if and only if the scalar product of + * a point on the plane minus the point with the outer normal of the face + * is >= 0. + * + * In other words, let p be the point to check, n the outer normal and x a point + * on the plane, then p is on the inner side if and only if + * >= 0 + */ + + const int num_faces = ts->t8_element_num_faces (element); + /* Assume that every point is inside of the element */ + for (int ipoint = 0; ipoint < num_points; ipoint++) { + is_inside[ipoint] = 1; + } + for (int iface = 0; iface < num_faces; ++iface) { + double face_normal[3]; + /* Compute the outer normal n of the face */ + t8_forest_element_face_normal (forest, ltreeid, element, iface, face_normal); + /* Compute a point x on the face */ + const int afacecorner = ts->t8_element_get_face_corner (element, iface, 0); + double point_on_face[3]; + t8_forest_element_coordinate (forest, ltreeid, element, afacecorner, point_on_face); + for (int ipoint = 0; ipoint < num_points; ipoint++) { + const int is_inside_iface = t8_plane_point_inside (point_on_face, face_normal, &points[ipoint * 3]); + if (is_inside_iface == 0) { + /* Point is on the outside of face iface. Update is_inside */ + is_inside[ipoint] = 0; + } + } + } + return; + } + default: + SC_ABORT_NOT_REACHED (); + } +} + T8_EXTERN_C_BEGIN (); /* Satisfy the C interface from t8_geometry_linear.h. diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx index b056dcd9eb..6840b9dc64 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear.hxx @@ -90,6 +90,20 @@ struct t8_geometry_linear: public t8_geometry_with_vertices t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *jacobian) const; + /** + * \param[in] forest The forest of the element. + * \param[in] ltreeid The local tree id of the element's tree + * \param[in] element The element + * \param[in] points points to check + * \param[in] num_points Number of points to check + * \param[in, out] is_inside Array to fill with flags whether the point is inside or not + * \param[in] tolerance Tolerance of the inside-check + */ + virtual void + t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, int *is_inside, + const double tolerance) const; + /* Load tree data is inherited from t8_geometry_with_vertices. */ }; diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx index 880d83362b..fc23664338 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.cxx @@ -56,6 +56,32 @@ t8_geometry_linear_axis_aligned::t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8 SC_ABORT ("Not implemented."); } +void +t8_geometry_linear_axis_aligned::t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, + const t8_element_t *element, const double *points, + const int num_points, int *is_inside, + const double tolerance) const +{ + double v_min[3]; + double v_max[3]; + + /*Geometry is fully described by v_min and v_max*/ + t8_forest_element_coordinate (forest, ltreeid, element, 0, v_min); + t8_forest_element_coordinate (forest, ltreeid, element, 1, v_max); + + for (int ipoint = 0; ipoint < num_points; ipoint++) { + /* A point is inside if it is inbetween the x/y/z-coordinates of v_min and v_max */ + /* check x-coordinate */ + /* check y-coordinate */ + /* check z-coordinate */ + is_inside[ipoint] + = v_min[0] - tolerance <= points[ipoint * 3] && points[ipoint * 3] <= v_max[0] + tolerance + && v_min[1] - tolerance <= points[ipoint * 3 + 1] && points[ipoint * 3 + 1] <= v_max[1] + tolerance + && v_min[2] - tolerance <= points[ipoint * 3 + 2] && points[ipoint * 3 + 2] <= v_max[2] + tolerance; + } + return; +} + T8_EXTERN_C_BEGIN (); /* Satisfy the C interface from t8_geometry_linear_axis_aligned.h. diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx index edcc973e74..339e8b446a 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.hxx @@ -92,6 +92,20 @@ struct t8_geometry_linear_axis_aligned: public t8_geometry_with_vertices virtual void t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *jacobian) const; + + /** + * \param[in] forest The forest of the element. + * \param[in] ltreeid The local tree id of the element's tree + * \param[in] element The element + * \param[in] points points to check + * \param[in] num_points Number of points to check + * \param[in, out] is_inside Array to fill with flags whether the point is inside or not + * \param[in] tolerance Tolerance of the inside-check + */ + virtual void + t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, int *is_inside, + const double tolerance) const; }; #endif /* !T8_GEOMETRY_LINEAR_AXIS_ALIGNED_HXX! */ diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx index f2e33d03ed..cfcd99cbba 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_zero.hxx @@ -31,6 +31,7 @@ #include #include +#include struct t8_geometry_zero: public t8_geometry { @@ -86,6 +87,27 @@ struct t8_geometry_zero: public t8_geometry t8_geom_evaluate_jacobian (t8_cmesh_t cmesh, t8_gloidx_t gtreeid, const double *ref_coords, const size_t num_coords, double *jacobian) const; + /** + * \param[in] forest The forest of the element. + * \param[in] ltreeid The local tree id of the element's tree + * \param[in] element The element + * \param[in] points points to check + * \param[in] num_points Number of points to check + * \param[in, out] is_inside Array to fill with flags whether the point is inside or not + * \param[in] tolerance Tolerance of the inside-check + */ + virtual void + t8_geom_point_batch_inside_element (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, + const double *points, const int num_points, int *is_inside, + const double tolerance) + { + const double zeros[3] = { 0 }; + for (int i_point = 0; i_point < num_points; ++i_point) { + const int offset = i_point * T8_ECLASS_MAX_DIM; + is_inside[i_point] = t8_vertex_point_inside (zeros, points + offset, tolerance); + } + } + /** Update a possible internal data buffer for per tree data. * This function is called before the first coordinates in a new tree are * evaluated. diff --git a/src/t8_geometry/t8_geometry_with_vertices.cxx b/src/t8_geometry/t8_geometry_with_vertices.cxx index 16c3824d5b..1e91171a82 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.cxx +++ b/src/t8_geometry/t8_geometry_with_vertices.cxx @@ -44,8 +44,6 @@ t8_geometry_with_vertices::t8_geom_load_tree_data (t8_cmesh_t cmesh, t8_gloidx_t /* Load this trees vertices. */ active_tree_vertices = t8_cmesh_get_tree_vertices (cmesh, ltreeid); - T8_ASSERT (t8_eclass_to_dimension[active_tree_class] == dimension); - /* Check whether we support this class */ T8_ASSERT (active_tree_class == T8_ECLASS_VERTEX || active_tree_class == T8_ECLASS_TRIANGLE || active_tree_class == T8_ECLASS_TET || active_tree_class == T8_ECLASS_QUAD diff --git a/src/t8_geometry/t8_geometry_with_vertices.h b/src/t8_geometry/t8_geometry_with_vertices.h index 48bf0e1702..4265a4df8e 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.h +++ b/src/t8_geometry/t8_geometry_with_vertices.h @@ -44,7 +44,8 @@ T8_EXTERN_C_BEGIN (); * match the number of corners of the tree. */ void -t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, t8_gloidx_t gtree_id, double *vertices, int num_vertices); +t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, const t8_gloidx_t gtree_id, const double *vertices, + const int num_vertices); T8_EXTERN_C_END (); diff --git a/src/t8_geometry/t8_geometry_with_vertices.hxx b/src/t8_geometry/t8_geometry_with_vertices.hxx index 2f39b76ddb..8dd2d8b1a4 100644 --- a/src/t8_geometry/t8_geometry_with_vertices.hxx +++ b/src/t8_geometry/t8_geometry_with_vertices.hxx @@ -29,6 +29,7 @@ #define T8_GEOMETRY_WITH_VERTICES_HXX #include +#include #include #include #include diff --git a/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.cxx b/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.cxx index ecbca7a8fd..64c3df7c4b 100644 --- a/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.cxx +++ b/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.cxx @@ -109,16 +109,16 @@ t8_default_scheme_common_c::t8_element_shape (const t8_element_t *elem) const return eclass; } -/* Given an element's level and dimension, return the number of leafs it +/* Given an element's level and dimension, return the number of leaves it * produces at a given uniform refinement level */ static inline t8_gloidx_t -count_leafs_from_level (int element_level, int refinement_level, int dimension) +count_leaves_from_level (int element_level, int refinement_level, int dimension) { return element_level > refinement_level ? 0 : sc_intpow64 (2, dimension * (refinement_level - element_level)); } t8_gloidx_t -t8_default_scheme_common_c::t8_element_count_leafs (const t8_element_t *t, int level) const +t8_default_scheme_common_c::t8_element_count_leaves (const t8_element_t *t, int level) const { int element_level = t8_element_level (t); @@ -129,7 +129,7 @@ t8_default_scheme_common_c::t8_element_count_leafs (const t8_element_t *t, int l int level_diff = level - element_level; return element_level > level ? 0 : 2 * sc_intpow64 (8, level_diff) - sc_intpow64 (6, level_diff); } - return count_leafs_from_level (element_level, level, dim); + return count_leaves_from_level (element_level, level, dim); } /* Count the number of siblings. @@ -144,13 +144,13 @@ t8_default_scheme_common_c::t8_element_num_siblings (const t8_element_t *elem) c } t8_gloidx_t -t8_default_scheme_common_c::t8_element_count_leafs_from_root (int level) const +t8_default_scheme_common_c::t8_element_count_leaves_from_root (int level) const { if (eclass == T8_ECLASS_PYRAMID) { return 2 * sc_intpow64u (8, level) - sc_intpow64u (6, level); } int dim = t8_eclass_to_dimension[eclass]; - return count_leafs_from_level (0, level, dim); + return count_leaves_from_level (0, level, dim); } void diff --git a/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.hxx b/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.hxx index b1041946ee..eb9fda8d31 100644 --- a/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_common/t8_default_common_cxx.hxx @@ -63,7 +63,7 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { * children. */ virtual t8_gloidx_t - t8_element_count_leafs (const t8_element_t *t, int level) const; + t8_element_count_leaves (const t8_element_t *t, int level) const; /** Compute the number of siblings of an element. That is the number of * Children of its parent. @@ -76,11 +76,11 @@ class t8_default_scheme_common_c: public t8_eclass_scheme_c { /** Count how many leaf descendants of a given uniform level the root element will produce. * \param [in] level A refinement level. - * \return The value of \ref t8_element_count_leafs if the input element + * \return The value of \ref t8_element_count_leaves if the input element * is the root (level 0) element. */ virtual t8_gloidx_t - t8_element_count_leafs_from_root (int level) const; + t8_element_count_leaves_from_root (int level) const; /** The common implementation of the general function for the default scheme * has no effect. This function literally does nothing. diff --git a/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex.h b/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex.h deleted file mode 100644 index a0d38b5aa2..0000000000 --- a/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex.h +++ /dev/null @@ -1,46 +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_default_hex.h - */ - -#ifndef T8_DEFAULT_HEX_H -#define T8_DEFAULT_HEX_H - -#include -#include - -T8_EXTERN_C_BEGIN (); - -/** The structure holding a hexahedral element in the default scheme. - * We make this definition public for interoperability of element classes. - * We might want to put this into a private, scheme-specific header file. - */ -typedef p8est_quadrant_t t8_phex_t; - -/** Provide an implementation for the hexahedral element class. */ -t8_eclass_scheme_t* -t8_default_scheme_new_hex (void); - -T8_EXTERN_C_END (); - -#endif /* !T8_DEFAULT_HEX_H */ diff --git a/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex_cxx.hxx b/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex_cxx.hxx index a8467e76b8..b93fd999a7 100644 --- a/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_hex/t8_default_hex_cxx.hxx @@ -468,7 +468,7 @@ struct t8_default_scheme_hex_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_line/t8_default_line_cxx.hxx b/src/t8_schemes/t8_default/t8_default_line/t8_default_line_cxx.hxx index 3bb49d3ef6..034bffb836 100644 --- a/src/t8_schemes/t8_default/t8_default_line/t8_default_line_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_line/t8_default_line_cxx.hxx @@ -475,7 +475,7 @@ struct t8_default_scheme_line_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism_cxx.hxx b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism_cxx.hxx index 3bd5d68249..86f2b55b1e 100644 --- a/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_prism/t8_default_prism_cxx.hxx @@ -455,7 +455,7 @@ struct t8_default_scheme_prism_c: public t8_default_scheme_common_c * given linear id in a uniform refinement. * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. - * \param [in] id The linear id. id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * \param [in] id The linear id. id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid_cxx.hxx b/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid_cxx.hxx index ebd1a7d389..3bcd0d3e8e 100644 --- a/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_pyramid/t8_default_pyramid_cxx.hxx @@ -448,7 +448,7 @@ struct t8_default_scheme_pyramid_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c index 5b543436ac..8e7ab7d24f 100644 --- a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c +++ b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_bits.c @@ -1401,7 +1401,7 @@ t8_dpyramid_get_face_corner (const t8_dpyramid_t *pyra, int face, int corner) return t8_dtet_face_corner[face][corner]; } else { - int corner_number = t8_dpyramid_face_corner[face][corner]; + const int corner_number = t8_dpyramid_face_corner[pyra->pyramid.type - T8_DPYRAMID_FIRST_TYPE][face][corner]; T8_ASSERT (0 <= corner_number && corner_number < T8_DPYRAMID_FACES); return corner_number; } diff --git a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c index 233dd84673..1eeb1964e5 100644 --- a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c +++ b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.c @@ -128,10 +128,19 @@ const int t8_dpyramid_tritype_rootface_to_face[2][4] = { { 2, 0, 2, 0 }, { 1, 0, 1, 0 } }; -const int t8_dpyramid_face_corner[5][4] = { +const int t8_dpyramid_face_corner[2][5][4] = { +{ { 0, 2, 4, -1 }, { 1, 3, 4, -1 }, { 0, 1, 4, -1 }, { 2, 3, 4, -1 }, - { 0, 1, 2, 3 } }; + { 0, 1, 2, 3 } +},{ + { 2, 3, 4, -1 }, + { 0, 1, 4, -1 }, + { 1, 3, 4, -1 }, + { 0, 2, 4, -1 }, + { 0, 1, 2, 3 } +} +}; /* clang-format on */ \ No newline at end of file diff --git a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.h b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.h index ef07d74d21..3360c7e137 100644 --- a/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.h +++ b/src/t8_schemes/t8_default/t8_default_pyramid/t8_dpyramid_connectivity.h @@ -111,8 +111,8 @@ extern const int t8_dpyramid_tritype_rootface_to_face[2][4]; extern const int t8_dtet_type_cid_to_pyramid_parenttype[6][8]; /** The corner numbers of the face of a pyramid - * corner_number = A(face, corner_number_at_face) + * corner_number = A(pyramid_type, face, corner_number_at_face) */ -extern const int t8_dpyramid_face_corner[5][4]; +extern const int t8_dpyramid_face_corner[2][5][4]; #endif // T8_DPYRAMID_CONNECTIVITY_H diff --git a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.h b/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.h deleted file mode 100644 index da00ddd958..0000000000 --- a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad.h +++ /dev/null @@ -1,80 +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_default_quad.h - * We use a p4est_quadrant_t object as storage for the T8 quadrant. - * To record if and if yes, how this quadrant is part of a 3D octant, we use - * the member pad8 for the surrounding toplevel dimension (2 or 3), pad16 for - * the direction of its normal relative to a toplevel octant (0, 1, or 2), and - * p.user_long for the p4est_qcoord_t coordinate in the normal direction. - */ - -#ifndef T8_DEFAULT_QUAD_H -#define T8_DEFAULT_QUAD_H - -#include -#include - -/** The structure holding a quadrilateral element in the default scheme. - * We make this definition public for interoperability of element classes. - * We might want to put this into a private, scheme-specific header file. - */ -typedef p4est_quadrant_t t8_pquad_t; - -/** Return the toplevel dimension. */ -#define T8_QUAD_GET_TDIM(quad) ((int) (quad)->pad8) - -/** Return the direction of the third dimension. - * This is only valid to call if the toplevel dimension is three. - */ -#define T8_QUAD_GET_TNORMAL(quad) (T8_ASSERT (T8_QUAD_GET_TDIM (quad) == 3), ((int) (quad)->pad16)) - -/** Return the coordinate in the third dimension. - * This is only valid to call if the toplevel dimension is three. - */ -#define T8_QUAD_GET_TCOORD(quad) (T8_ASSERT (T8_QUAD_GET_TDIM (quad) == 3), ((int) (quad)->p.user_long)) - -/** Set the toplevel dimension of a quadrilateral. */ -#define T8_QUAD_SET_TDIM(quad, dim) \ - do { \ - T8_ASSERT ((dim) == 2 || (dim) == 3); \ - (quad)->pad8 = (int8_t) (dim); \ - } while (0) - -/** Set the direction of the third dimension. */ -#define T8_QUAD_SET_TNORMAL(quad, normal) \ - do { \ - T8_ASSERT ((normal) >= 0 && (normal) < 3); \ - (quad)->pad16 = (int16_t) (normal); \ - } while (0) - -/** Set the coordinate in the third dimension. */ -#define T8_QUAD_SET_TCOORD(quad, coord) \ - do { \ - (quad)->p.user_long = (long) (coord); \ - } while (0) - -/** Provide an implementation for the quadrilateral element class. */ -t8_eclass_scheme_t* -t8_default_scheme_new_quad (void); - -#endif /* !T8_DEFAULT_QUAD_H */ diff --git a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad_cxx.hxx b/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad_cxx.hxx index ef149aa1a8..c4d6360fd9 100644 --- a/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_quad/t8_default_quad_cxx.hxx @@ -499,7 +499,7 @@ struct t8_default_scheme_quad_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.c b/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.c deleted file mode 100644 index 38d5dc0410..0000000000 --- a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.c +++ /dev/null @@ -1,219 +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. -*/ - -#include -#include -#include - -typedef t8_dtet_t t8_default_tet_t; - -/* This function is used by other element functions and we thus need to - * declare it up here */ -static t8_linearidx_t -t8_default_tet_get_linear_id (const t8_element_t *elem, int level); - -static size_t -t8_default_tet_size (void) -{ - return sizeof (t8_default_tet_t); -} - -static int -t8_default_tet_maxlevel (void) -{ - return T8_DTET_MAXLEVEL; -} - -static int -t8_default_tet_level (const t8_element_t *elem) -{ - return t8_dtet_get_level ((t8_dtet_t *) elem); -} - -static void -t8_default_tet_copy (const t8_element_t *source, t8_element_t *dest) -{ - t8_dtet_copy ((const t8_dtet_t *) source, (t8_dtet_t *) dest); -} - -static int -t8_default_tet_compare (const t8_element_t *elem1, const t8_element_t *elem2) -{ - int maxlvl; - t8_linearidx_t id1, id2; - - /* Compute the bigger level of the two */ - maxlvl = SC_MAX (t8_default_tet_level (elem1), t8_default_tet_level (elem2)); - /* Compute the linear ids of the elements */ - id1 = t8_default_tet_get_linear_id (elem1, maxlvl); - id2 = t8_default_tet_get_linear_id (elem2, maxlvl); - /* return negative if id1 < id2, zero if id1 = id2, positive if id1 > id2 */ - return id1 < id2 ? -1 : id1 != id2; -} - -static void -t8_default_tet_parent (const t8_element_t *elem, t8_element_t *parent) -{ - const t8_default_tet_t *t = (const t8_default_tet_t *) elem; - t8_default_tet_t *p = (t8_default_tet_t *) parent; - - t8_dtet_parent (t, p); -} - -static void -t8_default_tet_sibling (const t8_element_t *elem, int sibid, t8_element_t *sibling) -{ - const t8_default_tet_t *t = (const t8_default_tet_t *) elem; - t8_default_tet_t *s = (t8_default_tet_t *) sibling; - - t8_dtet_sibling (t, sibid, s); -} - -static void -t8_default_tet_child (const t8_element_t *elem, int childid, t8_element_t *child) -{ - const t8_default_tet_t *t = (const t8_default_tet_t *) elem; - t8_default_tet_t *c = (t8_default_tet_t *) child; - - t8_dtet_child (t, childid, c); -} - -static void -t8_default_tet_children (const t8_element_t *elem, int length, t8_element_t *c[]) -{ - T8_ASSERT (length == T8_DTET_CHILDREN); - - t8_dtet_childrenpv ((const t8_dtet_t *) elem, (t8_dtet_t **) c); -} - -static int -t8_default_tet_child_id (const t8_element_t *elem) -{ - return t8_dtet_child_id ((t8_dtet_t *) elem); -} - -static int -t8_default_tet_is_family (t8_element_t **fam) -{ - return t8_dtet_is_familypv ((const t8_dtet_t **) fam); -} - -static void -t8_default_tet_nca (const t8_element_t *elem1, const t8_element_t *elem2, t8_element_t *nca) -{ - const t8_default_tet_t *t1 = (const t8_default_tet_t *) elem1; - const t8_default_tet_t *t2 = (const t8_default_tet_t *) elem2; - t8_default_tet_t *c = (t8_default_tet_t *) nca; - - t8_dtet_nearest_common_ancestor (t1, t2, c); -} - -static void -t8_default_tet_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) -{ - T8_ASSERT (0 <= level && level <= T8_DTET_MAXLEVEL); - T8_ASSERT (0 <= id && id < ((t8_linearidx_t) 1) << 3 * level); - - t8_dtet_init_linear_id ((t8_default_tet_t *) elem, id, level); -} - -static t8_linearidx_t -t8_default_tet_get_linear_id (const t8_element_t *elem, int level) -{ - T8_ASSERT (0 <= level && level <= T8_DTET_MAXLEVEL); - - return t8_dtet_linear_id ((t8_default_tet_t *) elem, level); -} - -static void -t8_default_tet_successor (const t8_element_t *elem1, t8_element_t *elem2, int level) -{ - T8_ASSERT (0 <= level && level <= T8_DTET_MAXLEVEL); - - t8_dtet_successor ((const t8_default_tet_t *) elem1, (t8_default_tet_t *) elem2, level); -} - -static void -t8_default_tet_first_descendant (const t8_element_t *elem, t8_element_t *desc) -{ - t8_dtet_first_descendant ((t8_dtet_t *) elem, (t8_dtet_t *) desc); -} - -static void -t8_default_tet_last_descendant (const t8_element_t *elem, t8_element_t *desc) -{ - t8_dtet_last_descendant ((t8_dtet_t *) elem, (t8_dtet_t *) desc); -} - -static void -t8_default_tet_anchor (const t8_element_t *elem, int anchor[3]) -{ - t8_dtet_t *tet = (t8_dtet_t *) elem; - - anchor[0] = tet->x; - anchor[1] = tet->y; - anchor[2] = tet->z; -} - -static int -t8_default_tet_root_len (const t8_element_t *elem) -{ - return T8_DTET_ROOT_LEN; -} - -t8_eclass_scheme_t * -t8_default_scheme_new_tet (void) -{ - t8_eclass_scheme_t *ts; - - ts = T8_ALLOC_ZERO (t8_eclass_scheme_t, 1); - ts->eclass = T8_ECLASS_TET; - - ts->elem_size = t8_default_tet_size; - ts->elem_maxlevel = t8_default_tet_maxlevel; - - ts->elem_level = t8_default_tet_level; - ts->elem_copy = t8_default_tet_copy; - ts->elem_compare = t8_default_tet_compare; - ts->elem_parent = t8_default_tet_parent; - ts->elem_sibling = t8_default_tet_sibling; - ts->elem_child = t8_default_tet_child; - ts->elem_children = t8_default_tet_children; - ts->elem_child_id = t8_default_tet_child_id; - ts->elem_is_family = t8_default_tet_is_family; - ts->elem_nca = t8_default_tet_nca; - ts->elem_set_linear_id = t8_default_tet_set_linear_id; - ts->elem_get_linear_id = t8_default_tet_get_linear_id; - ts->elem_successor = t8_default_tet_successor; - ts->elem_first_desc = t8_default_tet_first_descendant; - ts->elem_last_desc = t8_default_tet_last_descendant; - ts->elem_anchor = t8_default_tet_anchor; - ts->elem_root_len = t8_default_tet_root_len; - - ts->elem_new = t8_default_mempool_alloc; - ts->elem_destroy = t8_default_mempool_free; - - ts->ts_destroy = t8_default_scheme_mempool_destroy; - ts->ts_context = sc_mempool_new (sizeof (t8_default_tet_t)); - - return ts; -} diff --git a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.h b/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.h deleted file mode 100644 index f7d66e9b10..0000000000 --- a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet.h +++ /dev/null @@ -1,42 +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_default_tet.h - * The default implementation for tetrahedra. - */ - -#ifndef T8_DEFAULT_TET_H -#define T8_DEFAULT_TET_H - -#include - -T8_EXTERN_C_BEGIN (); - -/** Provide an implementation for the tetrahedral element class. - * It is written as a self-contained library in the t8_dtet_* files. - */ -t8_eclass_scheme_t* -t8_default_scheme_new_tet (void); - -T8_EXTERN_C_END (); - -#endif /* !T8_DEFAULT_TET_H */ diff --git a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet_cxx.hxx b/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet_cxx.hxx index 5f1176fc30..cca15c893d 100644 --- a/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_tet/t8_default_tet_cxx.hxx @@ -419,7 +419,7 @@ struct t8_default_scheme_tet_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.h b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.h deleted file mode 100644 index f0e0e34db4..0000000000 --- a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri.h +++ /dev/null @@ -1,42 +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_default_tri.h - * The default implementation for triangles. - */ - -#ifndef T8_DEFAULT_TRI_H -#define T8_DEFAULT_TRI_H - -#include - -T8_EXTERN_C_BEGIN (); - -/** Provide an implementation for the triangle element class. It is written as a self-contained library in the - * t8_dtri_* files. - */ -t8_eclass_scheme_t * -t8_default_scheme_new_tri (void); - -T8_EXTERN_C_END (); - -#endif /* !T8_DEFAULT_TET_H */ diff --git a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri_cxx.hxx b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri_cxx.hxx index e708e8f6fa..8dffa6eddc 100644 --- a/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_tri/t8_default_tri_cxx.hxx @@ -413,7 +413,7 @@ struct t8_default_scheme_tri_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex_cxx.hxx b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex_cxx.hxx index d3325ed2bc..3be333a22c 100644 --- a/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex_cxx.hxx +++ b/src/t8_schemes/t8_default/t8_default_vertex/t8_default_vertex_cxx.hxx @@ -501,7 +501,7 @@ struct t8_default_scheme_vertex_c: public t8_default_scheme_common_c * \param [in,out] elem The element whose entries will be set. * \param [in] level The level of the uniform refinement to consider. * \param [in] id The linear id. - * id must fulfil 0 <= id < 'number of leafs in the uniform refinement' + * id must fulfil 0 <= id < 'number of leaves in the uniform refinement' */ virtual void t8_element_set_linear_id (t8_element_t *elem, int level, t8_linearidx_t id) const; diff --git a/src/t8_vec.h b/src/t8_vec.h index a2e9824c0e..94010cfeb7 100644 --- a/src/t8_vec.h +++ b/src/t8_vec.h @@ -29,8 +29,6 @@ #include -T8_EXTERN_C_BEGIN (); - /** Vector norm. * \param [in] vec A 3D vector. * \return The norm of \a vec. @@ -197,9 +195,57 @@ t8_vec_diff (const double vec_x[3], const double vec_y[3], double diff[3]) static inline int t8_vec_eq (const double vec_x[3], const double vec_y[3], const double eps) { - return fabs (vec_x[0] - vec_y[0]) < eps && fabs (vec_x[1] - vec_y[1]) < eps && fabs (vec_x[2] - vec_y[2]) < eps; + T8_ASSERT (eps > 0); + return fabs (vec_x[0] - vec_y[0]) <= eps && fabs (vec_x[1] - vec_y[1]) <= eps && fabs (vec_x[2] - vec_y[2]) <= eps; } -T8_EXTERN_C_END (); +/** Rescale a vector to a new length. + * \param [in,out] vec A 3D vector. + * \param [in] new_length New length of the vector. + */ +static inline void +t8_vec_rescale (double vec[3], const double new_length) +{ + t8_vec_normalize (vec); + t8_vec_ax (vec, new_length); +} + +/** Compute the normal of a triangle given by its three vertices. + * \param [in] p1 A 3D vector. + * \param [in] p2 A 3D vector. + * \param [in] p3 A 3D vector. + * \param [out] Normal vector of the triangle. (Not necessarily of length 1!) + */ +static inline void +t8_vec_tri_normal (const double p1[3], const double p2[3], const double p3[3], double normal[3]) +{ + double a[3]; /* First triangle side. */ + double b[3]; /* Second triangle side. */ + + a[0] = p2[0] - p1[0]; + a[1] = p2[1] - p1[1]; + a[2] = p2[2] - p1[2]; + + b[0] = p3[0] - p1[0]; + b[1] = p3[1] - p1[1]; + b[2] = p3[2] - p1[2]; + + t8_vec_cross (a, b, normal); +} + +/** Swap the components of two vectors. + * \param [in,out] p1 A 3D vector. + * \param [in,out] p2 A 3D vector. + */ +static inline void +t8_vec_swap (double p1[3], double p2[3]) +{ + double tmp; + for (int i = 0; i < 3; i++) { + tmp = p1[i]; + p1[i] = p2[i]; + p2[i] = tmp; + } +} #endif /* !T8_VEC_H! */ diff --git a/src/t8_version.h b/src/t8_version.h index 80b8c4b63e..fd9cea599f 100644 --- a/src/t8_version.h +++ b/src/t8_version.h @@ -47,7 +47,9 @@ #define T8_VERSION_H #include +#ifndef T8_CMAKE_BUILD #include +#endif /* In order to convert a macro to a string, we * need to pass it through these two helper macros. */ diff --git a/src/t8_vtk.h b/src/t8_vtk.h index c16896064c..f96ddc18ce 100644 --- a/src/t8_vtk.h +++ b/src/t8_vtk.h @@ -47,12 +47,7 @@ #define T8_VTK_FLOAT_TYPE double #endif -#ifndef T8_VTK_BINARY -#define T8_VTK_ASCII 1 #define T8_VTK_FORMAT_STRING "ascii" -#else -#define T8_VTK_FORMAT_STRING "binary" -#endif #if T8_WITH_VTK #define t8_vtk_locidx_array_type_t vtkTypeInt32Array diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..cacb44c8d1 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,86 @@ +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}/.. ) + +function( add_t8_test ) + set( options "" ) + set( oneValueArgs "NAME" ) + set( multiValueArgs "SOURCES" ) + cmake_parse_arguments( ADD_T8_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + add_executable( ${ADD_T8_TEST_NAME} ${ADD_T8_TEST_SOURCES} ) + target_link_libraries( ${ADD_T8_TEST_NAME} PRIVATE T8 gtest ) + add_test( NAME ${ADD_T8_TEST_NAME} COMMAND ./${ADD_T8_TEST_NAME} ) +endfunction() + +# Copy test files to build folder so that the t8_test programs can find them. +function( copy_test_file TEST_FILE_NAME ) + configure_file(${CMAKE_CURRENT_LIST_DIR}/testfiles/${TEST_FILE_NAME} ${CMAKE_CURRENT_BINARY_DIR}/test/testfiles/${TEST_FILE_NAME} COPYONLY) +endfunction() + +add_t8_test( NAME t8_gtest_cmesh_bcast SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_bcast.cxx ) +add_t8_test( NAME t8_gtest_eclass SOURCES t8_gtest_main.cxx t8_gtest_eclass.cxx ) +add_t8_test( NAME t8_gtest_vec SOURCES t8_gtest_main.cxx t8_gtest_vec.cxx ) +add_t8_test( NAME t8_gtest_mat SOURCES t8_gtest_main.cxx t8_gtest_mat.cxx ) +add_t8_test( NAME t8_gtest_refcount SOURCES t8_gtest_main.cxx t8_gtest_refcount.cxx ) +add_t8_test( NAME t8_gtest_cad_linkage SOURCES t8_gtest_main.cxx t8_gtest_cad_linkage.cxx ) +add_t8_test( NAME t8_gtest_version SOURCES t8_gtest_main.cxx t8_gtest_version.cxx ) +add_t8_test( NAME t8_gtest_basics SOURCES t8_gtest_main.cxx t8_gtest_basics.cxx ) +add_t8_test( NAME t8_gtest_netcdf_linkage SOURCES t8_gtest_main.cxx t8_gtest_netcdf_linkage.cxx ) +add_t8_test( NAME t8_gtest_vtk_linkage SOURCES t8_gtest_main.cxx t8_gtest_vtk_linkage.cxx ) + +add_t8_test( NAME t8_gtest_hypercube SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_hypercube.cxx ) +add_t8_test( NAME t8_gtest_cmesh_copy SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_copy.cxx ) +add_t8_test( NAME t8_gtest_cmesh_face_is_boundary SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx ) +add_t8_test( NAME t8_gtest_cmesh_partition SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_partition.cxx ) +add_t8_test( NAME t8_gtest_cmesh_set_partition_offsets SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_partition_offsets.cxx ) +add_t8_test( NAME t8_gtest_cmesh_set_join_by_vertices SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx ) +add_t8_test( NAME t8_gtest_multiple_attributes SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_multiple_attributes.cxx ) +add_t8_test( NAME t8_gtest_attribute_gloidx_array SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_attribute_gloidx_array.cxx ) + +add_t8_test( NAME t8_gtest_shmem SOURCES t8_gtest_main.cxx t8_data/t8_gtest_shmem.cxx ) + +add_t8_test( NAME t8_gtest_element_volume SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_volume.cxx ) +add_t8_test( NAME t8_gtest_search SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_search.cxx ) +add_t8_test( NAME t8_gtest_element_general_function SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_general_function.cxx ) +add_t8_test( NAME t8_gtest_half_neighbors SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_half_neighbors.cxx ) +add_t8_test( NAME t8_gtest_find_owner SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_find_owner.cxx ) +add_t8_test( NAME t8_gtest_user_data SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_user_data.cxx ) +add_t8_test( NAME t8_gtest_transform SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_transform.cxx ) +add_t8_test( NAME t8_gtest_ghost_exchange SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_exchange.cxx ) +add_t8_test( NAME t8_gtest_ghost_delete SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_delete.cxx ) +add_t8_test( NAME t8_gtest_ghost_and_owner SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_ghost_and_owner.cxx ) + +add_t8_test( NAME t8_gtest_permute_hole SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) +add_t8_test( NAME t8_gtest_recursive SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) +add_t8_test( NAME t8_gtest_iterate_replace SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_iterate_replace.cxx ) +add_t8_test( NAME t8_gtest_empty_local_tree SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_local_tree.cxx ) +add_t8_test( NAME t8_gtest_empty_global_tree SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_empty_global_tree.cxx ) + +add_t8_test( NAME t8_gtest_geometry_cad SOURCES t8_gtest_main.cxx t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx ) +add_t8_test( NAME t8_gtest_geometry SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_geometry.cxx ) +add_t8_test( NAME t8_gtest_point_inside SOURCES t8_gtest_main.cxx t8_geometry/t8_gtest_point_inside.cxx ) + +add_t8_test( NAME t8_gtest_vtk_reader SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_reader.cxx ) + +add_t8_test( NAME t8_gtest_nca SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) +add_t8_test( NAME t8_gtest_pyra_connectivity SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx ) +add_t8_test( NAME t8_gtest_face_neigh SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_neigh.cxx ) +add_t8_test( NAME t8_gtest_init_linear_id SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_init_linear_id.cxx ) +add_t8_test( NAME t8_gtest_ancestor SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_ancestor.cxx ) +add_t8_test( NAME t8_gtest_element_count_leaves SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_count_leaves.cxx ) +add_t8_test( NAME t8_gtest_element_ref_coords SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_element_ref_coords.cxx ) +add_t8_test( NAME t8_gtest_descendant SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_descendant.cxx ) +add_t8_test( NAME t8_gtest_find_parent SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_find_parent.cxx ) +add_t8_test( NAME t8_gtest_equal SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_equal.cxx ) +add_t8_test( NAME t8_gtest_successor SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_successor.cxx ) +add_t8_test( NAME t8_gtest_boundary_extrude SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_boundary_extrude.cxx ) +add_t8_test( NAME t8_gtest_face_descendant SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_face_descendant.cxx ) +add_t8_test( NAME t8_gtest_default SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_default.cxx ) +add_t8_test( NAME t8_gtest_child_parent_face SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_child_parent_face.cxx ) + +copy_test_file( test_cube_unstructured_1.inp ) +copy_test_file( test_cube_unstructured_2.inp ) +copy_test_file( test_vtk_tri.vtu ) +copy_test_file( test_vtk_cube.vtp ) +copy_test_file( test_parallel_file.pvtu ) +copy_test_file( test_polydata.pvtp ) diff --git a/test/Makefile.am b/test/Makefile.am index 68179fa3c8..aaf6bb0161 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,19 +20,18 @@ t8code_googletest_programs = \ test/t8_schemes/t8_gtest_face_neigh \ test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear \ test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear_axis_aligned \ - test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_occ \ + test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad \ test/t8_gtest_eclass \ test/t8_gtest_vec \ test/t8_gtest_mat \ test/t8_gtest_refcount \ - test/t8_gtest_occ_linkage \ + test/t8_gtest_cad_linkage \ test/t8_gtest_version \ test/t8_schemes/t8_gtest_init_linear_id \ test/t8_gtest_basics \ test/t8_schemes/t8_gtest_ancestor \ test/t8_cmesh/t8_gtest_hypercube \ - test/t8_cmesh/t8_gtest_cmesh_copy \ - test/t8_schemes/t8_gtest_element_count_leafs \ + test/t8_schemes/t8_gtest_element_count_leaves \ test/t8_schemes/t8_gtest_element_ref_coords \ test/t8_geometry/t8_gtest_geometry_handling \ test/t8_schemes/t8_gtest_descendant \ @@ -40,6 +39,7 @@ t8code_googletest_programs = \ test/t8_schemes/t8_gtest_equal \ test/t8_cmesh/t8_gtest_cmesh_face_is_boundary \ test/t8_cmesh/t8_gtest_cmesh_partition \ + test/t8_cmesh/t8_gtest_cmesh_copy \ test/t8_cmesh/t8_gtest_cmesh_set_partition_offsets \ test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices \ test/t8_forest/t8_gtest_element_volume \ @@ -54,6 +54,7 @@ t8code_googletest_programs = \ test/t8_data/t8_gtest_shmem \ test/t8_forest/t8_gtest_half_neighbors \ test/t8_forest/t8_gtest_find_owner \ + test/t8_forest/t8_gtest_forest_face_normal \ test/t8_schemes/t8_gtest_face_descendant \ test/t8_geometry/t8_gtest_point_inside \ test/t8_forest/t8_gtest_user_data \ @@ -67,8 +68,10 @@ t8code_googletest_programs = \ test/t8_forest_incomplete/t8_gtest_iterate_replace \ test/t8_forest_incomplete/t8_gtest_empty_local_tree \ test/t8_forest_incomplete/t8_gtest_empty_global_tree \ + test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume \ test/t8_schemes/t8_gtest_default \ - test/t8_schemes/t8_gtest_child_parent_face + test/t8_schemes/t8_gtest_child_parent_face \ + test/t8_cmesh_generator/t8_gtest_cmesh_generator_test test_t8_IO_t8_gtest_vtk_reader_SOURCES = \ test/t8_gtest_main.cxx \ @@ -98,9 +101,9 @@ test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_axis_align test/t8_gtest_main.cxx \ test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear_axis_aligned.cxx -test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_occ_SOURCES = \ +test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_cad_SOURCES = \ test/t8_gtest_main.cxx \ - test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_occ.cxx + test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx test_t8_gtest_eclass_SOURCES = \ test/t8_gtest_main.cxx \ @@ -118,9 +121,9 @@ test_t8_gtest_refcount_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_gtest_refcount.cxx -test_t8_gtest_occ_linkage_SOURCES = \ +test_t8_gtest_cad_linkage_SOURCES = \ test/t8_gtest_main.cxx \ - test/t8_gtest_occ_linkage.cxx + test/t8_gtest_cad_linkage.cxx test_t8_gtest_version_SOURCES = \ test/t8_gtest_main.cxx \ @@ -142,17 +145,13 @@ test_t8_cmesh_t8_gtest_hypercube_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_cmesh/t8_gtest_hypercube.cxx -test_t8_cmesh_t8_gtest_cmesh_copy_SOURCES = \ - test/t8_gtest_main.cxx \ - test/t8_cmesh/t8_gtest_cmesh_copy.cxx - test_t8_cmesh_t8_gtest_cmesh_set_join_by_vertices_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx -test_t8_schemes_t8_gtest_element_count_leafs_SOURCES = \ +test_t8_schemes_t8_gtest_element_count_leaves_SOURCES = \ test/t8_gtest_main.cxx \ - test/t8_schemes/t8_gtest_element_count_leafs.cxx + test/t8_schemes/t8_gtest_element_count_leaves.cxx test_t8_schemes_t8_gtest_element_ref_coords_SOURCES = \ test/t8_gtest_main.cxx \ @@ -234,6 +233,10 @@ test_t8_forest_t8_gtest_find_owner_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest/t8_gtest_find_owner.cxx +test_t8_forest_t8_gtest_forest_face_normal_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_forest/t8_gtest_forest_face_normal.cxx + test_t8_schemes_t8_gtest_face_descendant_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_schemes/t8_gtest_face_descendant.cxx @@ -282,6 +285,10 @@ test_t8_forest_incomplete_t8_gtest_empty_global_tree_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest_incomplete/t8_gtest_empty_global_tree.cxx +test_t8_cmesh_t8_gtest_cmesh_tree_vertices_negative_volume_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx + test_t8_schemes_t8_gtest_default_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_schemes/t8_gtest_default.cxx @@ -290,6 +297,14 @@ test_t8_schemes_t8_gtest_child_parent_face_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_schemes/t8_gtest_child_parent_face.cxx +test_t8_cmesh_generator_t8_gtest_cmesh_generator_test_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_cmesh_generator/t8_gtest_cmesh_generator_test.cxx + +test_t8_cmesh_t8_gtest_cmesh_copy_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_cmesh/t8_gtest_cmesh_copy.cxx + #define ld and cpp flags for all targets t8_gtest_target_ld_add = $(LDADD) test/libgtest.la t8_gtest_target_ld_flags = $(AM_LDFLAGS) -pthread @@ -322,9 +337,9 @@ test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_axis_align test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_axis_aligned_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_axis_aligned_CPPFLAGS = $(t8_gtest_target_cpp_flags) -test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_occ_LDADD = $(t8_gtest_target_ld_add) -test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_occ_LDFLAGS = $(t8_gtest_target_ld_flags) -test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_occ_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_cad_LDADD = $(t8_gtest_target_ld_add) +test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_cad_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_cad_CPPFLAGS = $(t8_gtest_target_cpp_flags) test_t8_gtest_eclass_LDADD = $(t8_gtest_target_ld_add) test_t8_gtest_eclass_LDFLAGS = $(t8_gtest_target_ld_flags) @@ -342,9 +357,9 @@ test_t8_gtest_refcount_LDADD = $(t8_gtest_target_ld_add) test_t8_gtest_refcount_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_gtest_refcount_CPPFLAGS = $(t8_gtest_target_cpp_flags) -test_t8_gtest_occ_linkage_LDADD = $(t8_gtest_target_ld_add) -test_t8_gtest_occ_linkage_LDFLAGS = $(t8_gtest_target_ld_flags) -test_t8_gtest_occ_linkage_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_gtest_cad_linkage_LDADD = $(t8_gtest_target_ld_add) +test_t8_gtest_cad_linkage_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_gtest_cad_linkage_CPPFLAGS = $(t8_gtest_target_cpp_flags) test_t8_gtest_version_LDADD = $(t8_gtest_target_ld_add) test_t8_gtest_version_LDFLAGS = $(t8_gtest_target_ld_flags) @@ -366,17 +381,13 @@ test_t8_cmesh_t8_gtest_hypercube_LDADD = $(t8_gtest_target_ld_add) test_t8_cmesh_t8_gtest_hypercube_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_cmesh_t8_gtest_hypercube_CPPFLAGS = $(t8_gtest_target_cpp_flags) -test_t8_cmesh_t8_gtest_cmesh_copy_LDADD = $(t8_gtest_target_ld_add) -test_t8_cmesh_t8_gtest_cmesh_copy_LDFLAGS = $(t8_gtest_target_ld_flags) -test_t8_cmesh_t8_gtest_cmesh_copy_CPPFLAGS = $(t8_gtest_target_cpp_flags) - test_t8_cmesh_t8_gtest_cmesh_set_join_by_vertices_LDADD = $(t8_gtest_target_ld_add) test_t8_cmesh_t8_gtest_cmesh_set_join_by_vertices_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_cmesh_t8_gtest_cmesh_set_join_by_vertices_CPPFLAGS = $(t8_gtest_target_cpp_flags) -test_t8_schemes_t8_gtest_element_count_leafs_LDADD = $(t8_gtest_target_ld_add) -test_t8_schemes_t8_gtest_element_count_leafs_LDFLAGS = $(t8_gtest_target_ld_flags) -test_t8_schemes_t8_gtest_element_count_leafs_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_schemes_t8_gtest_element_count_leaves_LDADD = $(t8_gtest_target_ld_add) +test_t8_schemes_t8_gtest_element_count_leaves_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_schemes_t8_gtest_element_count_leaves_CPPFLAGS = $(t8_gtest_target_cpp_flags) test_t8_schemes_t8_gtest_element_ref_coords_LDADD = $(t8_gtest_target_ld_add) test_t8_schemes_t8_gtest_element_ref_coords_LDFLAGS = $(t8_gtest_target_ld_flags) @@ -458,6 +469,10 @@ test_t8_forest_t8_gtest_find_owner_LDADD = $(t8_gtest_target_ld_add) test_t8_forest_t8_gtest_find_owner_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_forest_t8_gtest_find_owner_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_forest_t8_gtest_forest_face_normal_LDADD = $(t8_gtest_target_ld_add) +test_t8_forest_t8_gtest_forest_face_normal_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_forest_t8_gtest_forest_face_normal_CPPFLAGS = $(t8_gtest_target_cpp_flags) + test_t8_schemes_t8_gtest_face_descendant_LDADD = $(t8_gtest_target_ld_add) test_t8_schemes_t8_gtest_face_descendant_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_schemes_t8_gtest_face_descendant_CPPFLAGS = $(t8_gtest_target_cpp_flags) @@ -510,6 +525,10 @@ test_t8_forest_incomplete_t8_gtest_empty_global_tree_LDADD = $(t8_gtest_target_l test_t8_forest_incomplete_t8_gtest_empty_global_tree_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_forest_incomplete_t8_gtest_empty_global_tree_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_cmesh_t8_gtest_cmesh_tree_vertices_negative_volume_LDADD = $(t8_gtest_target_ld_add) +test_t8_cmesh_t8_gtest_cmesh_tree_vertices_negative_volume_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_cmesh_t8_gtest_cmesh_tree_vertices_negative_volume_CPPFLAGS = $(t8_gtest_target_cpp_flags) + test_t8_schemes_t8_gtest_default_LDADD = $(t8_gtest_target_ld_add) test_t8_schemes_t8_gtest_default_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_schemes_t8_gtest_default_CPPFLAGS = $(t8_gtest_target_cpp_flags) @@ -518,6 +537,14 @@ test_t8_schemes_t8_gtest_child_parent_face_LDADD = $(t8_gtest_target_ld_add) test_t8_schemes_t8_gtest_child_parent_face_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_schemes_t8_gtest_child_parent_face_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_cmesh_generator_t8_gtest_cmesh_generator_test_LDADD = $(t8_gtest_target_ld_add) +test_t8_cmesh_generator_t8_gtest_cmesh_generator_test_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_cmesh_generator_t8_gtest_cmesh_generator_test_CPPFLAGS = $(t8_gtest_target_cpp_flags) + +test_t8_cmesh_t8_gtest_cmesh_copy_LDADD = $(t8_gtest_target_ld_add) +test_t8_cmesh_t8_gtest_cmesh_copy_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_cmesh_t8_gtest_cmesh_copy_CPPFLAGS = $(t8_gtest_target_cpp_flags) + # If we did not configure t8code with MPI we need to build Googletest # without MPI support. if !T8_ENABLE_MPI @@ -527,20 +554,19 @@ test_t8_schemes_t8_gtest_pyra_connectivity_CPPFLAGS += $(t8_gtest_target_mpi_cpp test_t8_schemes_t8_gtest_face_neigh_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_linear_axis_aligned_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) -test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_occ_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_geometry_t8_geometry_implementations_t8_gtest_geometry_cad_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_eclass_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_vec_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_mat_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_refcount_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) -test_t8_gtest_occ_linkage_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_gtest_cad_linkage_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_version_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_init_linear_id_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_gtest_basics_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_ancestor_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_cmesh_t8_gtest_hypercube_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) -test_t8_cmesh_t8_gtest_cmesh_copy_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_cmesh_t8_gtest_cmesh_set_join_by_vertices_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) -test_t8_schemes_t8_gtest_element_count_leafs_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_schemes_t8_gtest_element_count_leaves_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_element_ref_coords_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_geometry_t8_gtest_geometry_handling_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_descendant_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) @@ -561,6 +587,7 @@ test_t8_gtest_vtk_linkage_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_data_t8_gtest_shmem_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_half_neighbors_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_find_owner_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_forest_t8_gtest_forest_face_normal_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_face_descendant_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_geometry_t8_gtest_point_inside_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_user_data_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) @@ -574,8 +601,12 @@ test_t8_forest_incomplete_t8_gtest_recursive_CPPFLAGS += $(t8_gtest_target_mpi_c test_t8_forest_incomplete_t8_gtest_iterate_replace_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_empty_local_tree_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_empty_global_tree_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_cmesh_t8_gtest_cmesh_tree_vertices_negative_volume_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_default_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_schemes_t8_gtest_child_parent_face_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_cmesh_generator_t8_gtest_cmesh_generator_test_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_cmesh_t8_gtest_cmesh_copy_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) + endif # Build Googletest library diff --git a/test/t8_IO/t8_gtest_vtk_reader.cxx b/test/t8_IO/t8_gtest_vtk_reader.cxx index 07ef84bc38..51c992e9e1 100644 --- a/test/t8_IO/t8_gtest_vtk_reader.cxx +++ b/test/t8_IO/t8_gtest_vtk_reader.cxx @@ -44,7 +44,9 @@ class vtk_reader: public testing::TestWithParam> { SC_CHECK_MPI (mpiret); mpiret = sc_MPI_Comm_rank (sc_MPI_COMM_WORLD, &mpirank); SC_CHECK_MPI (mpiret); - if (mpisize > T8_VTK_TEST_NUM_PROCS) { + + /* `mpisize` must match with the number of files that are read in. */ + if (mpisize != T8_VTK_TEST_NUM_PROCS) { GTEST_SKIP (); } file = std::get<0> (GetParam ()); diff --git a/test/t8_cmesh/t8_gtest_cmesh_copy.cxx b/test/t8_cmesh/t8_gtest_cmesh_copy.cxx index 11c54de28f..9c98806615 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_copy.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_copy.cxx @@ -22,57 +22,64 @@ #include #include +#include #include "t8_cmesh/t8_cmesh_trees.h" #include "t8_cmesh/t8_cmesh_partition.h" -#include -#include #include -/* Test if a cmesh is committed properly and perform the face consistency check. */ +#include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" -class cmesh_copy_equality: public testing::TestWithParam { +/* We create and commit a cmesh, then derive a new cmesh + * from it without any changes. + * We test whether the new and original cmesh are equal. + */ + +/* Note: This test currently fails on many cmeshes and is thus deavtivated. + * See: https://github.com/DLR-AMR/t8code/issues/920 + */ + +class t8_cmesh_copy: public testing::TestWithParam { protected: void SetUp () override { - cmesh_id = GetParam (); - - cmesh_original = t8_test_create_cmesh (cmesh_id); - /* Set up the cmesh copy */ - t8_cmesh_init (&cmesh_copy); - /* We need the original cmesh later, so we ref it */ - t8_cmesh_ref (cmesh_original); - t8_cmesh_set_derive (cmesh_copy, cmesh_original); - t8_cmesh_commit (cmesh_copy, sc_MPI_COMM_WORLD); + /* Skip test since cmesh copy is not yet working. See https://github.com/DLR-AMR/t8code/issues/920 */ + GTEST_SKIP (); + cmesh_original = GetParam ()->cmesh_create (); + + /* Initialized test cmesh that we derive in the test */ + t8_cmesh_init (&cmesh); } + void TearDown () override { - t8_cmesh_unref (&cmesh_original); - t8_cmesh_unref (&cmesh_copy); + /* Skip test since cmesh copy is not yet working. See https://github.com/DLR-AMR/t8code/issues/920 */ + GTEST_SKIP (); + /* Unref both cmeshes */ + t8_cmesh_unref (&cmesh); } + t8_cmesh_t cmesh; t8_cmesh_t cmesh_original; - t8_cmesh_t cmesh_copy; - int cmesh_id; }; -/* Test wheater the original cmaeh and its copy are committed and face consistent. Test will fail, if one of these is false. */ -TEST_P (cmesh_copy_equality, check_cmeshes_and_their_trees) +static void +test_cmesh_committed (t8_cmesh_t cmesh) { - - EXPECT_TRUE (t8_cmesh_is_committed (cmesh_original)); - EXPECT_TRUE (t8_cmesh_is_committed (cmesh_copy)); - EXPECT_TRUE (t8_cmesh_trees_is_face_consistent (cmesh_original, cmesh_original->trees)); - EXPECT_TRUE (t8_cmesh_trees_is_face_consistent (cmesh_copy, cmesh_copy->trees)); + ASSERT_TRUE (t8_cmesh_is_committed (cmesh)) << "Cmesh commit failed."; + ASSERT_TRUE (t8_cmesh_trees_is_face_consistent (cmesh, cmesh->trees)) << "Cmesh face consistency failed."; } -/* Test the equality of the original and copied cmeshs*/ -TEST_P (cmesh_copy_equality, check_equality_of_copied_cmesh_with_original) +TEST_P (t8_cmesh_copy, test_cmesh_copy) { + t8_cmesh_set_derive (cmesh, cmesh_original); + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + + test_cmesh_committed (cmesh); - EXPECT_TRUE (t8_cmesh_is_equal (cmesh_original, cmesh_copy)); + EXPECT_TRUE (t8_cmesh_is_equal (cmesh, cmesh_original)); } -/* Test all cmeshes over all different inputs we get through their id */ -INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_copy, cmesh_copy_equality, AllCmeshs); +/* Test all cmeshes over all different inputs*/ +INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_copy, t8_cmesh_copy, AllCmeshsParam, pretty_print_base_example); diff --git a/test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx b/test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx index da2e1ec13e..c680949354 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx @@ -243,8 +243,8 @@ TEST (t8_cmesh_set_join_by_vertices, test_cmesh_set_join_by_vertices) const double boundary_coords[24] = { 1, 0, 0, 4, 0, 0, 0, 6, 0, 5, 5, 0, -1, -2, 8, 9, 0, 10, 0, 8, 9, 10, 10, 10 }; t8_eclass_t eclass = T8_ECLASS_HEX; - t8_geometry_c *geometry = new t8_geometry_linear (3); - t8_cmesh_t cmesh = t8_cmesh_new_hypercube_pad (eclass, comm, boundary_coords, 2, 2, 2, geometry); + const int use_axis_aligned = 0; + t8_cmesh_t cmesh = t8_cmesh_new_hypercube_pad (eclass, comm, boundary_coords, 2, 2, 2, use_axis_aligned); test_with_cmesh (cmesh); t8_cmesh_destroy (&cmesh); } diff --git a/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx b/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx new file mode 100644 index 0000000000..af0e714bfd --- /dev/null +++ b/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx @@ -0,0 +1,153 @@ +/* +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) 2023 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_cmesh_tree_vertices_negative_volume.cxx +* Provide tests to check the functionality of the t8_cmesh_tree_vertices_negative_volume function +* for every eclass. +*/ + +#include +#include +#include + +/** + * Given an eclass fill \a vertices_ids with the corner_ids of a cube [0,1]^3, such that + * the volume is positive + * \param[in] eclass The eclass to use + * \param[in, out] 8 ints on input, filled with the corner ids to use for i-th vertex of the element on output + */ +static void +get_vertices_ids (const t8_eclass_t eclass, int vertices_ids[T8_ECLASS_MAX_CORNERS]) +{ + /* For Hex, Quads and Lines we set the remaining vertices by + * not breaking at the end of the case. + * The same is done for Prisms and Triangles. */ + switch (eclass) { + case T8_ECLASS_HEX: + vertices_ids[4] = 4; + vertices_ids[5] = 5; + vertices_ids[6] = 6; + vertices_ids[7] = 7; + case T8_ECLASS_QUAD: + vertices_ids[3] = 3; + vertices_ids[2] = 2; + case T8_ECLASS_LINE: + vertices_ids[1] = 1; + case T8_ECLASS_VERTEX: + vertices_ids[0] = 0; + break; + case T8_ECLASS_PRISM: + vertices_ids[3] = 4; + vertices_ids[4] = 5; + vertices_ids[5] = 7; + case T8_ECLASS_TRIANGLE: + vertices_ids[0] = 0; + vertices_ids[1] = 1; + vertices_ids[2] = 3; + break; + case T8_ECLASS_TET: + vertices_ids[0] = 0; + vertices_ids[1] = 1; + vertices_ids[2] = 5; + vertices_ids[3] = 7; + break; + case T8_ECLASS_PYRAMID: + vertices_ids[0] = 1; + vertices_ids[1] = 3; + vertices_ids[2] = 0; + vertices_ids[3] = 2; + vertices_ids[4] = 7; + break; + default: + break; + } +} + +class tree_vertices_negative_volume: public testing::TestWithParam { + protected: + void + SetUp () override + { + eclass = GetParam (); + num_vertices = t8_eclass_num_vertices[eclass]; + get_vertices_ids (eclass, vertices_ids); + } + void + TearDown () override + { + } + t8_eclass_t eclass; + int num_vertices; + int vertices_ids[T8_ECLASS_MAX_CORNERS]; +}; + +/* Test if positive volume is detected correctly */ +TEST_P (tree_vertices_negative_volume, positive_volume) +{ + /* clang-format off */ + const double vertices_coords[24] = { + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0, + 0, 0, 1, + 1, 0, 1, + 0, 1, 1, + 1, 1, 1 + }; + /* clang-format on */ + double *elem_vertices = T8_ALLOC (double, 3 * num_vertices); + t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices); + + EXPECT_FALSE (t8_cmesh_tree_vertices_negative_volume (eclass, elem_vertices, num_vertices)); + T8_FREE (elem_vertices); +} + +/* Test if negative volume is detected correctly */ +TEST_P (tree_vertices_negative_volume, negative_volume) +{ + /* clang-format off */ + /* Same nodes as above, but inverted. All 3D elements will have negative volume*/ + const double vertices_coords[24] = { + 0, 0, 1, + 1, 0, 1, + 0, 1, 1, + 1, 1, 1, + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0 + }; + /* clang-format on */ + double *elem_vertices = T8_ALLOC (double, 3 * num_vertices); + t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices); + if (t8_eclass_to_dimension[eclass] <= 2) { + EXPECT_FALSE (t8_cmesh_tree_vertices_negative_volume (eclass, elem_vertices, num_vertices)); + } + else { + EXPECT_TRUE (t8_cmesh_tree_vertices_negative_volume (eclass, elem_vertices, num_vertices)); + } + T8_FREE (elem_vertices); +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_tree_vertices_negative_volume, tree_vertices_negative_volume, + testing::Range (T8_ECLASS_ZERO, T8_ECLASS_PYRAMID)); diff --git a/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx b/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx new file mode 100644 index 0000000000..124ca3edc8 --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_example_sets.hxx @@ -0,0 +1,65 @@ +/* +This file is part of t8code. +t8code is a C library to manage a collection (a forest) of multiple +connected adaptive space-trees of general element 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_GTEST_CMESH_COMM_CREATOR_HXX +#define T8_GTEST_CMESH_COMM_CREATOR_HXX + +#include + +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_prism_cake_param.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_from_class_param.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_bigmesh_param.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_comm.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_pad.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_param.hxx" +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_gtest_cmesh_sum_of_sets.hxx" + +T8_EXTERN_C_BEGIN (); + +/** + * lambda to pass to an INSTANTIATE_TEST_SUITE_P to print the current cmesh_example_base + * + */ +auto pretty_print_base_example = [] (const testing::TestParamInfo &info) { + std::string name; + info.param->param_to_string (name); + return name; +}; + +namespace cmesh_list +{ +std::vector cart_prod_vec + = { new_from_class::cmesh_example, new_prism_cake::cmesh_example, new_bigmesh::cmesh_example, + new_cmesh_comm::cmesh_example, new_hypercube_pad::cmesh_example, new_hypercube_cmesh::cmesh_example, + new_hypercube_cmesh::cmesh_example_pyra }; + +cmesh_sum_of_sets cmesh_sums (cart_prod_vec); + +} // namespace cmesh_list + +#define AllCmeshsParam \ + ::testing::ValuesIn (cmesh_list::cmesh_sums.cmesh_examples.begin (), cmesh_list::cmesh_sums.cmesh_examples.end ()) + +T8_EXTERN_C_END (); + +#endif /* T8_GTEST_CMESH_COMM_CREATOR_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_bigmesh_param.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_bigmesh_param.hxx new file mode 100644 index 0000000000..060933cc06 --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_bigmesh_param.hxx @@ -0,0 +1,57 @@ +/* +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_CMESH_NEW_BIGMESH_PARAM_HXX +#define T8_CMESH_NEW_BIGMESH_PARAM_HXX + +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include "t8_cmesh/t8_cmesh_examples.h" +#include + +namespace new_bigmesh +{ +std::function bigmesh = t8_cmesh_new_bigmesh; + +std::string +make_param_string (const t8_eclass_t eclass, const int num_trees, const sc_MPI_Comm comm) +{ + std::string delimiter = std::string ("_"); + std::string params = delimiter + t8_eclass_to_string[eclass] + delimiter + std::to_string (num_trees) + delimiter + + cmesh_params::comm_to_string (comm); + return params; +} + +std::function make_param_string_wrapper + = make_param_string; + +example_set *cmesh_example + = (example_set *) new cmesh_cartesian_product_params ( + std::make_pair (cmesh_params::eclasses.begin (), cmesh_params::eclasses.end ()), + std::make_pair (cmesh_params::large_mesh.begin (), cmesh_params::large_mesh.end ()), + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), bigmesh, make_param_string_wrapper, + "t8_cmesh_new_bigmesh_"); +} // namespace new_bigmesh + +#endif /* T8_CMESH_NEW_BIGMESH_PARAM_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_comm.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_comm.hxx new file mode 100644 index 0000000000..01a20f709f --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_comm.hxx @@ -0,0 +1,74 @@ +/* +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_CMESH_NEW_COMM +#define T8_CMESH_NEW_COMM + +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include + +namespace new_cmesh_comm +{ +std::string +make_param_string (const sc_MPI_Comm &comm) +{ + std::string delimiter = std::string ("_"); + std::string params = delimiter + cmesh_params::comm_to_string (comm); + return params; +} + +std::function print_function = make_param_string; + +std::vector> cmesh_functions = { t8_cmesh_new_periodic_tri, + t8_cmesh_new_periodic_hybrid, + t8_cmesh_new_periodic_line_more_trees, + t8_cmesh_new_line_zigzag, + t8_cmesh_new_prism_deformed, + t8_cmesh_new_pyramid_deformed, + t8_cmesh_new_prism_cake_funny_oriented, + t8_cmesh_new_prism_geometry, + t8_cmesh_new_tet_orientation_test, + t8_cmesh_new_hybrid_gate, + t8_cmesh_new_hybrid_gate_deformed, + t8_cmesh_new_full_hybrid }; + +std::vector names = { "t8_cmesh_new_periodic_tri_", + "t8_cmesh_new_periodic_hybrid_", + "t8_cmesh_new_periodic_line_more_trees_", + "t8_cmesh_new_line_zigzag_", + "t8_cmesh_new_prism_deformed_", + "t8_cmesh_new_pyramid_deformed_", + "t8_cmesh_new_prism_cake_funny_oriented_", + "t8_cmesh_new_prism_geometry_", + "t8_cmesh_new_tet_orientation_test_", + "t8_cmesh_new_hybrid_gate_", + "t8_cmesh_new_hybrid_gate_deformed_", + "t8_cmesh_new_full_hybrid_" }; + +example_set *cmesh_example + = (example_set *) new cmesh_cartesian_product_params ( + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), cmesh_functions, print_function, + names); +} // namespace new_cmesh_comm + +#endif /* T8_CMESH_NEW_COMM */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_from_class_param.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_from_class_param.hxx new file mode 100644 index 0000000000..4b03c07f1e --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_from_class_param.hxx @@ -0,0 +1,56 @@ +/* +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 "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include +#include + +#ifndef T8_CMESH_NEW_FROM_CLASS_PARAM +#define T8_CMESH_NEW_FROM_CLASS_PARAM + +namespace new_from_class +{ + +std::string +make_param_string (const t8_eclass_t &eclass, const sc_MPI_Comm &comm) +{ + std::string delimiter = std::string ("_"); + std::string params + = delimiter + std::string (t8_eclass_to_string[eclass]) + delimiter + cmesh_params::comm_to_string (comm); + return params; +} + +std::function print_function = make_param_string; + +std::function new_from_class_wrapper = t8_cmesh_new_from_class; + +example_set *cmesh_example + = (example_set *) new cmesh_cartesian_product_params ( + std::make_pair (cmesh_params::eclasses.begin (), cmesh_params::eclasses.end ()), + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), new_from_class_wrapper, + print_function, "t8_cmesh_new_from_class_"); + +} // namespace new_from_class + +#endif /* T8_CMESH_NEW_FROM_CLASS_PARAM */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_pad.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_pad.hxx new file mode 100644 index 0000000000..231cb05d6b --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_pad.hxx @@ -0,0 +1,90 @@ +/* +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_CMESH_NEW_HYPERCUBE_PAD +#define T8_CMESH_NEW_HYPERCUBE_PAD + +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include + +namespace new_hypercube_pad +{ +std::function + hyper_pad = t8_cmesh_new_hypercube_pad; + +std::string +make_param_string (const t8_eclass_t eclass, sc_MPI_Comm comm, const double *boundary, t8_locidx_t polygons_x, + t8_locidx_t polygons_y, t8_locidx_t polygons_z, const int use_axis_aligned) +{ + std::string delimiter = std::string ("_"); + std::string geometry = use_axis_aligned ? std::string ("AxisAligned") : std::string ("LinearGeom"); + + std::string params = delimiter + t8_eclass_to_string[eclass] + delimiter + cmesh_params::comm_to_string (comm) + + delimiter + std::string ("BoundsNotPrinted") + delimiter + std::to_string (polygons_x) + + delimiter + std::to_string (polygons_y) + delimiter + std::to_string (polygons_z) + delimiter + + geometry; + + return params; +} +std::function + make_param_string_wrapper = make_param_string; + +inline bool +rule (const t8_eclass_t eclass, sc_MPI_Comm comm, const double *boundary, t8_locidx_t polygons_x, + t8_locidx_t polygons_y, t8_locidx_t polygons_z, const int use_axis_aligned) +{ + const int dim = t8_eclass_to_dimension[eclass]; + if (dim == 0 && (polygons_x > 1 || polygons_y > 1 || polygons_z > 1)) + return false; + if (dim == 1 && (polygons_y > 1 || polygons_z > 1)) + return false; + if (dim == 2 && polygons_z > 1) + return false; + if ((eclass != T8_ECLASS_HEX && use_axis_aligned) || (eclass != T8_ECLASS_QUAD && use_axis_aligned)) + return false; + if (eclass == T8_ECLASS_PYRAMID) + return false; + return true; +} + +std::function + rule_wrapper = rule; + +example_set *cmesh_example = (example_set *) new cmesh_cartesian_product_with_rules< + decltype (cmesh_params::all_eclasses.begin ()), decltype (cmesh_params::my_comms.begin ()), + decltype (cmesh_params::boundaries.begin ()), decltype (cmesh_params::elems_per_dim.begin ()), + decltype (cmesh_params::elems_per_dim.begin ()), decltype (cmesh_params::elems_per_dim.begin ()), + decltype (cmesh_params::use_axis_aligned.begin ())> ( + std::make_pair (cmesh_params::eclasses.begin (), cmesh_params::eclasses.end ()), + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), + std::make_pair (cmesh_params::boundaries.begin (), cmesh_params::boundaries.end ()), + std::make_pair (cmesh_params::elems_per_dim.begin (), cmesh_params::elems_per_dim.end ()), + std::make_pair (cmesh_params::elems_per_dim.begin (), cmesh_params::elems_per_dim.end ()), + std::make_pair (cmesh_params::elems_per_dim.begin (), cmesh_params::elems_per_dim.end ()), + std::make_pair (cmesh_params::use_axis_aligned.begin (), cmesh_params::use_axis_aligned.end ()), hyper_pad, + make_param_string_wrapper, rule_wrapper, "t8_cmesh_new_hypercube_pad_"); +} // namespace new_hypercube_pad + +#endif /* T8_CMESH_NEW_HYPERCUBE_PAD */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_param.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_param.hxx new file mode 100644 index 0000000000..a7a6b94afe --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_hypercube_param.hxx @@ -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) 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_CMESH_NEW_HYPERCUBE_PARAM_HXX +#define T8_CMESH_NEW_HYPERCUBE_PARAM_HXX + +#include +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include + +namespace new_hypercube_cmesh +{ +std::string +make_param_string (const t8_eclass_t eclass, const sc_MPI_Comm comm, const int do_bcast, const int do_partition, + const int periodic) +{ + std::string delimiter = std::string ("_"); + std::string bcast = do_bcast ? std::string ("bcast") : std::string ("noBcast"); + std::string partition = do_partition ? std::string ("partition") : std::string ("noPartition"); + std::string periodic_string = periodic ? std::string ("periodic") : std::string ("noPeriodic"); + std::string params + = delimiter + t8_eclass_to_string[eclass] + delimiter + bcast + delimiter + partition + delimiter + periodic_string; + + return params; +} + +std::function param_to_string + = make_param_string; + +std::vector periodic_eclasses = { T8_ECLASS_VERTEX, T8_ECLASS_LINE, T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE, + T8_ECLASS_HEX, T8_ECLASS_TET, T8_ECLASS_PRISM }; + +std::function cmesh_wrapper = t8_cmesh_new_hypercube; + +std::vector nonperiodic_eclasses = { T8_ECLASS_PYRAMID }; + +example_set *cmesh_example = (example_set *) new cmesh_cartesian_product_params< + decltype (periodic_eclasses.begin ()), decltype (cmesh_params::my_comms.begin ()), + decltype (cmesh_params::do_bcast.begin ()), decltype (cmesh_params::partition.begin ()), + decltype (cmesh_params::periodic.begin ())> ( + std::make_pair (periodic_eclasses.begin (), periodic_eclasses.end ()), + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), + std::make_pair (cmesh_params::do_bcast.begin (), cmesh_params::do_bcast.end ()), + std::make_pair (cmesh_params::partition.begin (), cmesh_params::partition.end ()), + std::make_pair (cmesh_params::periodic.begin (), cmesh_params::periodic.end ()), cmesh_wrapper, param_to_string, + "t8_cmesh_new_hypercube_"); + +example_set *cmesh_example_pyra = (example_set *) new cmesh_cartesian_product_params< + decltype (periodic_eclasses.begin ()), decltype (cmesh_params::my_comms.begin ()), + decltype (cmesh_params::do_bcast.begin ()), decltype (cmesh_params::partition.begin ()), + decltype (cmesh_params::no_periodic.begin ())> ( + std::make_pair (nonperiodic_eclasses.begin (), nonperiodic_eclasses.end ()), + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), + std::make_pair (cmesh_params::do_bcast.begin (), cmesh_params::do_bcast.end ()), + std::make_pair (cmesh_params::partition.begin (), cmesh_params::partition.end ()), + std::make_pair (cmesh_params::no_periodic.begin (), cmesh_params::no_periodic.end ()), cmesh_wrapper, param_to_string, + "t8_cmesh_new_hypercube_"); +} // namespace new_hypercube_cmesh + +#endif /* T8_CMESH_NEW_HYPERCUBE_PARAM_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_prism_cake_param.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_prism_cake_param.hxx new file mode 100644 index 0000000000..f4df7366ca --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_prism_cake_param.hxx @@ -0,0 +1,52 @@ +/* +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 "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx" +#include + +#ifndef T8_CMESH_NEW_PRISM_CAKE_PARAM_HXX +#define T8_CMESH_NEW_PRISM_CAKE_PARAM_HXX + +namespace new_prism_cake +{ +std::function prism_cake = t8_cmesh_new_prism_cake; + +std::string +make_param_string (const sc_MPI_Comm &comm, const int &num_prisms) +{ + std::string delimiter = std::string ("_"); + std::string params = delimiter + cmesh_params::comm_to_string (comm) + delimiter + std::to_string (num_prisms); + return params; +} + +std::function make_param_string_wrapper = make_param_string; + +example_set *cmesh_example + = (example_set *) new cmesh_cartesian_product_params ( + std::make_pair (cmesh_params::my_comms.begin (), cmesh_params::my_comms.end ()), + std::make_pair (cmesh_params::num_prisms.begin (), cmesh_params::num_prisms.end ()), prism_cake, + make_param_string_wrapper, "t8_cmesh_new_prism_cake_"); +} // namespace new_prism_cake + +#endif /* T8_CMESH_NEW_PRISM_CAKE_PARAM_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx new file mode 100644 index 0000000000..51975a8fa8 --- /dev/null +++ b/test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_params.hxx @@ -0,0 +1,88 @@ +/* +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 to store the parameters that are used for our parameterized cmesh-tests + */ + +#ifndef T8_CMESH_PARAMS_HXX +#define T8_CMESH_PARAMS_HXX +#include +#include +#include +#include +#include +#include +#include + +namespace cmesh_params +{ +std::string +comm_to_string (const sc_MPI_Comm &comm) +{ + int mpi_ret; + sc_MPI_Comm_compare (comm, sc_MPI_COMM_WORLD, &mpi_ret); + if (mpi_ret == sc_MPI_SUCCESS) { + return std::string ("sc_MPI_COMM_WORLD"); + } + return std::string ("No_String_for_this_communicator"); +} + +std::vector +filled_vector (const size_t size, int start) +{ + std::vector tmp (size); + std::iota (tmp.begin (), tmp.end (), start); + return tmp; +} + +const double cube_bounds[24] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1 }; + +std::vector boundaries = { cube_bounds }; + +std::vector use_axis_aligned = { 0, 1 }; + +std::vector large_mesh = filled_vector (20, 500); + +std::vector elems_per_dim = filled_vector (5, 1); + +std::vector my_comms = { sc_MPI_COMM_WORLD }; +std::vector eclasses = { T8_ECLASS_VERTEX, T8_ECLASS_LINE, T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE, + T8_ECLASS_HEX, T8_ECLASS_TET, T8_ECLASS_PRISM, T8_ECLASS_PYRAMID }; + +std::vector all_eclasses + = { T8_ECLASS_ZERO, T8_ECLASS_VERTEX, T8_ECLASS_LINE, T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE, T8_ECLASS_HEX, + T8_ECLASS_TET, T8_ECLASS_PRISM, T8_ECLASS_PYRAMID, T8_ECLASS_COUNT, T8_ECLASS_INVALID }; + +std::vector do_bcast = { 0, 1 }; +std::vector partition = { 0, 1 }; +/* Currently a dummy vector for examples that have partition argument but not fully support it yet */ +std::vector no_partition = { 0 }; + +std::vector periodic = { 0, 1 }; +/* Currently a dummy vector for examples that have periodic argument but not fully support it yet */ +std::vector no_periodic = { 0 }; + +std::vector num_prisms = filled_vector (50, 3); +} // namespace cmesh_params + +#endif /* T8_CMESH_PARAMS_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx b/test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx new file mode 100644 index 0000000000..4c3dbe0e0d --- /dev/null +++ b/test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx @@ -0,0 +1,285 @@ +/* +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_GTEST_CMESH_CREATOR_BASE_HXX +#define T8_GTEST_CMESH_CREATOR_BASE_HXX + +#include +#include +#include +#include +#include +#include + +/** + * A base class for cmesh examples. + * + * For pretty debug output a function to translate the parameters of the example to a string should be provided. + * + * The + * + */ +class cmesh_example_base { + public: + /** + * Construct a new base example. An example must have at least have a name. + * + * \param name + */ + cmesh_example_base (std::string name): name (name) {}; + + /** + * A function to create a cmesh. The class should not own the cmesh. + * + * \return t8_cmesh_t + */ + virtual t8_cmesh_t + cmesh_create () const + = 0; + + /** + * Copy the name and the parameters of this example into a string + * + * \param out + */ + virtual void + param_to_string (std::string& out) const + = 0; + + std::string name; +}; + +/** + * Class to hold cmesh example created by function with parameters as input + * + * @tparam Args + */ +template +class cmesh_example_with_parameter: cmesh_example_base { + public: + cmesh_example_with_parameter (std::function function, std::tuple parameter, + std::function parameter_to_string, std::string name) + : cmesh_example_base (name), cmesh_function (function), parameter (parameter), + parameter_to_string (parameter_to_string) {}; + + virtual t8_cmesh_t + cmesh_create () const + { + return std::apply (cmesh_function, parameter); + } + + virtual void + param_to_string (std::string& out) const + { + out = name + std::apply (parameter_to_string, parameter); + } + + std::function cmesh_function; + std::tuple parameter; + std::function parameter_to_string; +}; + +/** + * A base class to hold sets of examples that can be created in various ways. + * + */ +class example_set { + public: + /** + * Generate a cmesh according to a function + * + * \return t8_cmesh_t + */ + std::vector example_all_combination; +}; + +/** + * A helper functions that creates a pair of begin and end iterators from a vector. + * + * \tparam Args The type of elements in the vector + * \param[in] vec A vector + * \return A pair of begin and end of the vector. + */ +template +auto +vector_to_iter_pair (const std::vector& vec) +{ + return std::make_pair (vec.begin (), vec.end ()); +} + +/** + * A helper function to recursively create the next tuple of parameters in a cartesion product way + * + * @tparam Args + * @tparam B + * \param begins A tuple of begin-iterators + * \param r A pair of iterators, used to create the next parameter in a tuple. + * \return true + * \return false + */ +template +bool +increment (const B& begins, std::pair& r) +{ + ++r.first; + if (r.first == r.second) { + return true; + } + return false; +} + +/** + * A helper function to recursively create the next tuple of parameters in a cartesion product way + * + * @tparam T + * @tparam TT + * @tparam B + * \param begins A tuple of begin-iterators + * \param r A pair of iterators, where first will be increased + * \param rr Remaining iterators to create the tuple. + * \return true + * \return false + */ +template +bool +increment (const B& begins, std::pair& r, std::pair&... rr) +{ + ++r.first; + if (r.first == r.second) { + r.first = std::get::value - sizeof...(rr) - 1> (begins); + return increment (begins, rr...); + } + + return false; +} + +template +inline bool +no_rule (Args... params) +{ + return true; +} + +/** + * Fill a vector with tuples, based on pairs of iterators. The iterators are used + * to create the tuples according to the cartesian product. + * + * @tparam OutputIterator + * @tparam Iter + * \param[in, out] out An OutputIterator that will be filled + * \param[in] rule A function that returns true if a parameter combination is permissible, false otherwise + * \param[in] ranges Pairs of ranges + */ +template +void +cartesian_product (OutputIterator out, std::function rule, + std::pair... ranges) +{ + const auto begins = std::make_tuple (ranges.first...); + if (rule (*ranges.first...)) { + out = { *ranges.first... }; + } + while (!increment (begins, ranges...)) { + if (rule (*ranges.first...)) { + out = { *ranges.first... }; + } + } +} + +/** + * Variadic template class that creates \ref base_example based on the cartesian product + * of the input parameters. + * + * @tparam Iter + */ +template +class cmesh_cartesian_product_params: example_set { + public: + cmesh_cartesian_product_params () {}; + + cmesh_cartesian_product_params (std::pair... ranges, + std::function cmesh_function, + std::function param_to_string, + std::string name) + { + std::function no_rule_wrapper = no_rule; + std::vector> cart_prod; + cartesian_product (std::back_inserter (cart_prod), no_rule_wrapper, ranges...); + for (int iparam_set = 0; (long unsigned int) iparam_set < cart_prod.size (); iparam_set++) { + std::tuple param = cart_prod[iparam_set]; + cmesh_example_base* next_example + = (cmesh_example_base*) new cmesh_example_with_parameter (cmesh_function, param, + param_to_string, name); + example_all_combination.push_back (next_example); + } + } + + cmesh_cartesian_product_params (std::pair... ranges, + std::vector> cmesh_functions, + std::function param_to_string, + std::vector names) + { + std::function no_rule_wrapper = no_rule; + std::vector> cart_prod; + cartesian_product (std::back_inserter (cart_prod), no_rule_wrapper, ranges...); + T8_ASSERT (cmesh_functions.size () == names.size ()); + for (int ifunction = 0; (long unsigned int) ifunction < cmesh_functions.size (); ifunction++) { + for (int iparam_set = 0; (long unsigned int) iparam_set < cart_prod.size (); iparam_set++) { + std::tuple param = cart_prod[iparam_set]; + cmesh_example_base* next_example + = (cmesh_example_base*) new cmesh_example_with_parameter ( + cmesh_functions[ifunction], param, param_to_string, names[ifunction]); + example_all_combination.push_back (next_example); + } + } + } +}; + +/** + * Variadic template class that creates \ref base_example based on the cartesian product + * of the input parameters. + * + * @tparam Iter + */ +template +class cmesh_cartesian_product_with_rules: example_set { + public: + cmesh_cartesian_product_with_rules () {}; + + cmesh_cartesian_product_with_rules (std::pair... ranges, + std::function cmesh_function, + std::function param_to_string, + std::function rule, std::string name) + { + std::vector> cart_prod; + cartesian_product (std::back_inserter (cart_prod), rule, ranges...); + for (int iparam_set = 0; (long unsigned int) iparam_set < cart_prod.size (); iparam_set++) { + std::tuple param = cart_prod[iparam_set]; + cmesh_example_base* next_example + = (cmesh_example_base*) new cmesh_example_with_parameter (cmesh_function, param, + param_to_string, name); + example_all_combination.push_back (next_example); + } + } +}; + +#endif /* T8_GTEST_CMESH_CREATOR_BASE_HXX */ \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_gtest_cmesh_generator_test.cxx b/test/t8_cmesh_generator/t8_gtest_cmesh_generator_test.cxx new file mode 100644 index 0000000000..1a439f0f58 --- /dev/null +++ b/test/t8_cmesh_generator/t8_gtest_cmesh_generator_test.cxx @@ -0,0 +1,68 @@ +/* +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 "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" +#include "test/t8_cmesh_generator/t8_cmesh_parametrized_examples/t8_cmesh_new_bigmesh_param.hxx" +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" + +class t8_cmesh_iter: public testing::TestWithParam { + protected: + void + SetUp () override + { + cmesh_creator = GetParam (); + cmesh = cmesh_creator->cmesh_create (); + cmesh_creator->param_to_string (cmesh_param_string); + } + + void + TearDown () override + { + /* Unref both cmeshes */ + t8_cmesh_unref (&cmesh); + } + t8_cmesh_t cmesh; + cmesh_example_base *cmesh_creator; + std::string cmesh_param_string; +}; + +TEST_P (t8_cmesh_iter, cmesh_created) +{ + EXPECT_NE (cmesh, nullptr); +} + +TEST_P (t8_cmesh_iter, print_string) +{ + EXPECT_FALSE (cmesh_param_string.empty ()); +} + +TEST (param_generator, check_num_parameters_combination) +{ + const size_t num_combs_generated = new_bigmesh::cmesh_example->example_all_combination.size (); + const size_t num_expected + = cmesh_params::large_mesh.size () * cmesh_params::my_comms.size () * cmesh_params::eclasses.size (); + EXPECT_EQ (num_combs_generated, num_expected); +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_create_cmeshes, t8_cmesh_iter, AllCmeshsParam, pretty_print_base_example); \ No newline at end of file diff --git a/test/t8_cmesh_generator/t8_gtest_cmesh_sum_of_sets.hxx b/test/t8_cmesh_generator/t8_gtest_cmesh_sum_of_sets.hxx new file mode 100644 index 0000000000..d9ffc28675 --- /dev/null +++ b/test/t8_cmesh_generator/t8_gtest_cmesh_sum_of_sets.hxx @@ -0,0 +1,63 @@ +/* +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_GTEST_cmesh_sum_of_sets_HXX +#define T8_GTEST_cmesh_sum_of_sets_HXX + +#include "test/t8_cmesh_generator/t8_gtest_cmesh_cartestian_product.hxx" + +T8_EXTERN_C_BEGIN (); + +/** + * A class that holds multiple ways to create a cmesh. + * + */ +class cmesh_sum_of_sets { + public: + cmesh_sum_of_sets () {}; + /** + * Construct a new cmesh sum of sets object, that will generate cmeshes given by \ref cmesh_set + * + * \param[in] cmesh_set A vector of \ref parameter_cartesian_product + */ + cmesh_sum_of_sets (std::vector cmesh_set) + { + for (size_t icreator = 0; icreator < cmesh_set.size (); icreator++) { + cmesh_examples.insert (cmesh_examples.end (), cmesh_set[icreator]->example_all_combination.begin (), + cmesh_set[icreator]->example_all_combination.end ()); + } + } + + /** + * Destroy the cmesh generator cxx object + * + */ + ~cmesh_sum_of_sets () + { + } + + public: + std::vector cmesh_examples; +}; + +T8_EXTERN_C_END (); +#endif /* T8_GTEST_cmesh_sum_of_sets_HXX */ \ No newline at end of file diff --git a/test/t8_forest/t8_gtest_forest_commit.cxx b/test/t8_forest/t8_gtest_forest_commit.cxx index cffb78305f..2ce79d23ea 100644 --- a/test/t8_forest/t8_gtest_forest_commit.cxx +++ b/test/t8_forest/t8_gtest_forest_commit.cxx @@ -134,7 +134,7 @@ TEST_P (forest_commit, test_forest_commit) t8_forest_t forest_ada_bal_part; t8_forest_t forest_abp_3part; -#ifdef T8_ENABLE_DEBUG +#ifdef T8_ENABLE_LESS_TESTS int level_step = 2; #else int level_step = 3; diff --git a/test/t8_forest/t8_gtest_forest_face_normal.cxx b/test/t8_forest/t8_gtest_forest_face_normal.cxx new file mode 100644 index 0000000000..d97bfa99e3 --- /dev/null +++ b/test/t8_forest/t8_gtest_forest_face_normal.cxx @@ -0,0 +1,115 @@ +/* +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) 2023 the developers + +t8code is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +t8code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with t8code; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * This file tests the face normal computation of elements. + */ + +class class_forest_face_normal: public testing::TestWithParam> { + protected: + void + SetUp () override + { + eclass = std::get<0> (GetParam ()); + level = std::get<1> (GetParam ()); + scheme = t8_scheme_new_default_cxx (); + 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); + } + void + TearDown () override + { + t8_forest_unref (&forest); + } + t8_forest_t forest; + t8_scheme_cxx *scheme; + t8_eclass_t eclass; + int level; +}; + +TEST_P (class_forest_face_normal, back_and_forth) +{ + /** Iterate over all elements of a uniformly refined forest. For all faceneighbors elements, if they are local, + * check if their facenormal is the negative of the corresponding facenormal of the neighbor elements. + */ + const t8_locidx_t local_num_trees = t8_forest_get_num_local_trees (forest); + /* Iterate over all elements. */ + for (t8_locidx_t itree = 0; itree < local_num_trees; itree++) { + const t8_locidx_t tree_elements = t8_forest_get_tree_num_elements (forest, itree); + const t8_eclass_t tree_eclass = t8_forest_get_tree_class (forest, itree); + ASSERT_EQ (eclass, tree_eclass); + const t8_eclass_scheme_c *escheme = t8_forest_get_eclass_scheme (forest, tree_eclass); + for (t8_locidx_t ielement = 0; ielement < tree_elements; ielement++) { + const t8_element_t *element = t8_forest_get_element_in_tree (forest, itree, ielement); + const int num_faces = escheme->t8_element_num_faces (element); + for (int iface = 0; iface < num_faces; iface++) { + /* Compute facenormal */ + double face_normal[3] = { 0, 0, 0 }; + t8_forest_element_face_normal (forest, itree, element, iface, face_normal); + + /* Get all face neighbors */ + + t8_element_t **neighbors; + int num_neighbors; + const int forest_is_balanced = 1; + t8_eclass_scheme_c *neigh_scheme; + int *dual_faces; + t8_locidx_t *neigh_ids; + + t8_gloidx_t gneightree; + t8_forest_leaf_face_neighbors_ext (forest, itree, element, &neighbors, iface, &dual_faces, &num_neighbors, + &neigh_ids, &neigh_scheme, forest_is_balanced, &gneightree); + + /* Iterate and compute their facenormal */ + for (int ineigh = 0; ineigh < num_neighbors; ineigh++) { + t8_locidx_t lneightree = t8_forest_get_local_or_ghost_id (forest, gneightree); + double neigh_face_normal[3]; + t8_forest_element_face_normal (forest, lneightree, neighbors[ineigh], dual_faces[ineigh], neigh_face_normal); + EXPECT_NEAR (face_normal[0], -neigh_face_normal[0], 10 * T8_PRECISION_EPS); + EXPECT_NEAR (face_normal[1], -neigh_face_normal[1], 10 * T8_PRECISION_EPS); + EXPECT_NEAR (face_normal[2], -neigh_face_normal[2], 10 * T8_PRECISION_EPS); + } + + if (num_neighbors > 0) { + neigh_scheme->t8_element_destroy (num_neighbors, neighbors); + T8_FREE (neigh_ids); + T8_FREE (neighbors); + T8_FREE (dual_faces); + } + } + } + } +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_forest_face_normal, class_forest_face_normal, + testing::Combine (AllEclasses, testing::Range (0, 2))); diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 74fc1ad467..7b0f52620c 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -67,7 +67,7 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e { EXPECT_TRUE (queries == NULL) << "Search callback must not be called with query argument."; - sc_array_t *matched_leafs = (sc_array_t *) t8_forest_get_user_data (forest); + sc_array_t *matched_leaves = (sc_array_t *) t8_forest_get_user_data (forest); if (is_leaf) { t8_locidx_t tree_offset; t8_locidx_t test_ltreeid; @@ -78,7 +78,7 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); /* Set the corresponding entry to 1 */ - *(int *) t8_sc_array_index_locidx (matched_leafs, tree_offset + tree_leaf_index) = 1; + *(int *) t8_sc_array_index_locidx (matched_leaves, tree_offset + tree_leaf_index) = 1; /* Test whether tree_leaf_index is actually the index of the element */ test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); @@ -122,7 +122,7 @@ TEST_P (forest_search, test_search_one_query_matches_all) { const int query = 42; sc_array_t queries; - sc_array_t matched_leafs; + sc_array_t matched_leaves; /* set up a single query containing our query */ sc_array_init_size (&queries, sizeof (int), 1); @@ -131,27 +131,27 @@ TEST_P (forest_search, test_search_one_query_matches_all) 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_leafs, sizeof (int), num_elements); + 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_leafs, ielement) = 0; + *(int *) t8_sc_array_index_locidx (&matched_leaves, ielement) = 0; } /* Set the array as user data so that we can access it in the search callback */ - t8_forest_set_user_data (forest, &matched_leafs); + 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_leafs array to be set to 1. */ + * 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); - /* Check whether matched_leafs entries are all 1 */ + /* 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_leafs, ielement)) - << "Search did not match all leafs. First mismatch at leaf " << ielement; + ASSERT_TRUE (*(int *) t8_sc_array_index_locidx (&matched_leaves, ielement)) + << "Search did not match all leaves. First mismatch at leaf " << ielement; } t8_forest_unref (&forest); - sc_array_reset (&matched_leafs); + sc_array_reset (&matched_leaves); sc_array_reset (&queries); } diff --git a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_occ.cxx b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx similarity index 70% rename from test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_occ.cxx rename to test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx index afc2d161ea..4fbaff8f70 100644 --- a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_occ.cxx +++ b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_cad.cxx @@ -25,7 +25,9 @@ #include #include #include -#include +#include +#include +#include #if T8_WITH_OCC #include @@ -38,6 +40,8 @@ #include #include #include +#include +#include #endif /* In this file we collect tests for t8code's OpenCASCADE geometry module. @@ -94,12 +98,12 @@ t8_euler_rotation (double *pos_vec, double *rot_vec, double *res_vec, double *ro } } -/** Constructs an occ surface for testing purposes. Surface is build between vertex 0, 1, 4 and 5 of a unit hexahedron. +/** Constructs an cad surface for testing purposes. Surface is build between vertex 0, 1, 4 and 5 of a unit hexahedron. * Saves the surface in the geometry shape. * \return The geometry. */ -t8_geometry_occ * -t8_create_occ_surface_geometry () +t8_geometry_cad * +t8_create_cad_surface_geometry () { Handle_Geom_Surface surface; TopoDS_Shape shape; @@ -119,16 +123,16 @@ t8_create_occ_surface_geometry () surface = GeomAPI_PointsToBSplineSurface (point_array).Surface (); shape = BRepBuilderAPI_MakeFace (surface, 1e-6).Face (); - t8_geometry_occ *geometry = new t8_geometry_occ (3, shape, "occ dim=3"); + t8_geometry_cad *geometry = new t8_geometry_cad (3, shape, "cad dim=3"); return geometry; } -/** Constructs an occ curve for testing purpsoes. Curve is build between vertex 0, 1, 4 and 5 of a unit hexahedron. +/** Constructs an cad curve for testing purpsoes. Curve is build between vertex 0, 1, 4 and 5 of a unit hexahedron. * Saves the curve in the geometry shape. - * \return The occ geometry. + * \return The cad geometry. */ -t8_geometry_occ * -t8_create_occ_curve_geometry () +t8_geometry_cad * +t8_create_cad_curve_geometry () { Handle_Geom_Curve curve; TopoDS_Shape shape; @@ -142,12 +146,12 @@ t8_create_occ_curve_geometry () curve = GeomAPI_PointsToBSpline (point_array).Curve (); shape = BRepBuilderAPI_MakeEdge (curve).Edge (); - t8_geometry_occ *geometry = new t8_geometry_occ (3, shape, "occ dim=3"); + t8_geometry_cad *geometry = new t8_geometry_cad (3, shape, "cad dim=3"); return geometry; } #endif /* T8_WITH_OCC */ -/** Constructs a cmesh with an occ geometry linked hypercube. +/** Constructs a cmesh with an cad geometry linked hypercube. * \param [in] rot_vec The rotation vector to rotate the cube before linking a geometry to it. * \param [in] face The index of the face to link a surface to. -1 for no face. * \param [in] edge The index of the edge to link a curve to. -1 for no edge. @@ -155,7 +159,7 @@ t8_create_occ_curve_geometry () * \return A valid cmesh, as if _init and _commit had been called. */ t8_cmesh_t -t8_create_occ_hypercube (double *rot_vec, int face, int edge, double *parameters) +t8_create_cad_hypercube (double *rot_vec, int face, int edge, double *parameters) { #if T8_WITH_OCC if (edge >= 0 && face >= 0) { @@ -163,7 +167,7 @@ t8_create_occ_hypercube (double *rot_vec, int face, int edge, double *parameters } t8_cmesh_t cmesh; - t8_geometry_occ *geometry = NULL; + t8_geometry_cad *geometry = NULL; t8_cmesh_init (&cmesh); t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_HEX); @@ -179,25 +183,25 @@ t8_create_occ_hypercube (double *rot_vec, int face, int edge, double *parameters T8_ASSERT (face < 0 || edge < 0); if (face >= 0) { faces[face] = 1; - geometry = t8_create_occ_surface_geometry (); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_PARAMETERS_ATTRIBUTE_KEY + face, + geometry = t8_create_cad_surface_geometry (); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY + face, parameters, 8 * sizeof (double), 0); } else if (edge >= 0) { edges[edge] = 1; - geometry = t8_create_occ_curve_geometry (); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_PARAMETERS_ATTRIBUTE_KEY + edge, + geometry = t8_create_cad_curve_geometry (); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY + edge, parameters, 2 * sizeof (double), 0); } else { /* Even if we do not want to link any geometry to the edges or faces, - * we have to create a geometry. Hence an occ geometry can only be created + * we have to create a geometry. Hence an cad geometry can only be created * with an actual shape, we just create a geometry with a curve and do not * link the curve to any edge. */ - geometry = t8_create_occ_curve_geometry (); + geometry = t8_create_cad_curve_geometry (); } - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); - t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, 6 * sizeof (int), 0); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, 24 * sizeof (int), 0); t8_cmesh_register_geometry (cmesh, geometry); t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); return cmesh; @@ -207,7 +211,7 @@ t8_create_occ_hypercube (double *rot_vec, int face, int edge, double *parameters #endif /* T8_WITH_OCC */ } -/** Tests the occ geometry functions for hexahedra. +/** Tests the cad geometry functions for hexahedra. * \param [in] rot_vec The rotation vector to rotate the hypercube. * \param [in] face The face to test. -1 for no face. * \param [in] edge The edge to test. -1 for no edge. @@ -218,7 +222,7 @@ t8_create_occ_hypercube (double *rot_vec, int face, int edge, double *parameters * \return Returns 1 if passed, 0 if failed. */ void -t8_test_geometry_occ (double *rot_vec, int face, int edge, double *parameters, double *test_ref_coords, +t8_test_geometry_cad (double *rot_vec, int face, int edge, double *parameters, double *test_ref_coords, double *test_return_coords) { #if T8_WITH_OCC @@ -227,7 +231,7 @@ t8_test_geometry_occ (double *rot_vec, int face, int edge, double *parameters, d double rotation_origin[3] = { 0.5, 0.5, 0.5 }; double inversed_rot_vec[3]; double tol = T8_PRECISION_EPS > 1e-10 ? T8_PRECISION_EPS : 1e-10; - t8_cmesh_t cmesh = t8_create_occ_hypercube (rot_vec, face, edge, parameters); + t8_cmesh_t cmesh = t8_create_cad_hypercube (rot_vec, face, edge, parameters); for (int i_coord = 0; i_coord < 3; ++i_coord) { inversed_rot_vec[2 - i_coord] = -rot_vec[i_coord]; @@ -247,7 +251,7 @@ t8_test_geometry_occ (double *rot_vec, int face, int edge, double *parameters, d } #if T8_WITH_OCC -TEST (t8_gtest_geometry_occ, linked_faces) +TEST (t8_gtest_geometry_cad, linked_faces) { /* clang-format off */ double test_ref_coords[24] = { 0.1, 0.1, 0.1, @@ -285,12 +289,12 @@ TEST (t8_gtest_geometry_occ, linked_faces) 0, 0, 0, 1, 1, 0, 1, 1 /* Face 5 */ }; for (int i_faces = 0; i_faces < 6; ++i_faces) { - t8_test_geometry_occ (surface_rot_vecs + i_faces * 3, i_faces, -1, surface_parameters + i_faces * 8, + t8_test_geometry_cad (surface_rot_vecs + i_faces * 3, i_faces, -1, surface_parameters + i_faces * 8, test_ref_coords, surface_test_return_coords); } } -TEST (t8_gtest_geometry_occ, linked_edges) +TEST (t8_gtest_geometry_cad, linked_edges) { /* clang-format off */ double test_ref_coords[24] = { 0.1, 0.1, 0.1, @@ -340,14 +344,14 @@ TEST (t8_gtest_geometry_occ, linked_edges) 0, 1 // Edge 11 }; for (int i_edges = 0; i_edges < 12; ++i_edges) { - t8_test_geometry_occ (curve_rot_vecs + i_edges * 3, -1, i_edges, curve_parameters + i_edges * 2, test_ref_coords, + t8_test_geometry_cad (curve_rot_vecs + i_edges * 3, -1, i_edges, curve_parameters + i_edges * 2, test_ref_coords, curve_test_return_coords); } } #endif /* T8_WITH_OCC */ #if T8_WITH_OCC -TEST (t8_gtest_geometry_occ, jacobian) +TEST (t8_gtest_geometry_cad, jacobian) { t8_cmesh_t cmesh; double jacobian[9], rot_vec[3] = { 0, 0, 0 }, ref_coords[3] = { 0.5, 0.5, 0.5 }; @@ -356,7 +360,7 @@ TEST (t8_gtest_geometry_occ, jacobian) 0, 1, 0, 0, 0, 1 }; /* clang-format on */ - cmesh = t8_create_occ_hypercube (rot_vec, -1, -1, NULL); + cmesh = t8_create_cad_hypercube (rot_vec, -1, -1, NULL); t8_geometry_jacobian (cmesh, 0, ref_coords, 1, jacobian); for (int i = 0; i < 9; ++i) { EXPECT_FLOAT_EQ (jacobian[i], jacobian_expect[i]); @@ -364,3 +368,109 @@ TEST (t8_gtest_geometry_occ, jacobian) t8_cmesh_destroy (&cmesh); } #endif /* T8_WITH_OCC */ + +#if T8_WITH_OCC +/* The test checks if the mapping algorithms for curved 2d elements do not shift values on a surface which is not curved. + * In that case, the cad geometry should output the same out_coords as the linear geometry function. */ +class class_2d_element_linear_cad_surface: public testing::TestWithParam { + protected: + void + SetUp () override + { + eclass = GetParam (); + T8_ASSERT (0 <= eclass && eclass < T8_ECLASS_COUNT); + Handle_Geom_Surface cad_surface; + TColgp_Array2OfPnt point_array (1, 2, 1, 2); + TopoDS_Shape shape; + + /* x--> u-parameter + * | + * v v-parameter + * + * point_array 1 2 + * + * 1 ----------------- + * | | + * | | + * | plane surface | + * | | + * | | + * 2 ----------------- + */ + + point_array (1, 1) = gp_Pnt (0.0, 1.0, 0.0); + point_array (2, 1) = gp_Pnt (1.0, 1.0, 0.0); + + point_array (1, 2) = gp_Pnt (0.0, 0.0, 0.0); + point_array (2, 2) = gp_Pnt (1.0, 0.0, 0.0); + + cad_surface = GeomAPI_PointsToBSplineSurface (point_array).Surface (); + shape = BRepBuilderAPI_MakeFace (cad_surface, 1e-6).Face (); + + geometry_cad = new t8_geometry_cad (2, shape, "cad surface dim=2"); + + t8_cmesh_init (&cmesh); + t8_cmesh_set_tree_class (cmesh, 0, eclass); + } + + void + TearDown () override + { + t8_cmesh_destroy (&cmesh); + } + t8_cmesh_t cmesh; + t8_eclass_t eclass; + t8_geometry_cad *geometry_cad; + /* The arrays prescribe the linkage of the element. The face of the element is linked and all edges are not */ + int faces[1] = { 1 }; + int edges[8] = { 0 }; +}; + +TEST_P (class_2d_element_linear_cad_surface, t8_check_2d_element_linear_cad_surface) +{ + /* Saving the corner vertices for the given element class. */ + const int num_vertices = t8_eclass_num_vertices[eclass]; + const double *vertices = &(t8_element_corner_ref_coords[eclass][0][0]); + + t8_cmesh_set_tree_vertices (cmesh, 0, vertices, num_vertices); + + /* Surfaces are parametrized in two parameters u and v. The arrays contain the parameters + * each vertex of the element has on the linked surface. The parameters are stored in + * u0, v0, u1, v1... in order of the element vertices. */ + double params_quad[8] = { 0, 1, 1, 1, 0, 0, 1, 0 }; + double params_tri[6] = { 0, 1, 1, 1, 1, 0 }; + + /* Passing of the attributes to the element */ + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_ATTRIBUTE_KEY, faces, sizeof (int), 0); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY, edges, + 2 * num_vertices * sizeof (int), 0); + t8_cmesh_set_attribute (cmesh, 0, t8_get_package_id (), T8_CMESH_CAD_FACE_PARAMETERS_ATTRIBUTE_KEY, + (eclass == T8_ECLASS_QUAD ? params_quad : params_tri), 2 * num_vertices * sizeof (double), 0); + + /* Register the geometry */ + t8_cmesh_register_geometry (cmesh, geometry_cad); + /* Commit the cmesh */ + t8_cmesh_commit (cmesh, sc_MPI_COMM_WORLD); + + /* First 6 ref_coords for triangle and all 9 ref_coords for quad */ + double test_ref_coords[27] = { 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.5, 0.0, 0.5, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.5, 0.0 }; + + /* TODO: use randomised test_ref_coords, because the out_coords should be the same, no matter the test_ref_coord. */ + + double out_coords[3]; + + /* `out_coords` should be equal to the input `ref_coords`. */ + for (size_t i_coord = 0; i_coord < (eclass == T8_ECLASS_QUAD ? 9 : 6); ++i_coord) { + t8_geometry_evaluate (cmesh, 0, test_ref_coords + i_coord * 3, 1, out_coords); + + EXPECT_NEAR (test_ref_coords[0 + i_coord * 3], out_coords[0], T8_PRECISION_EPS); + EXPECT_NEAR (test_ref_coords[1 + i_coord * 3], out_coords[1], T8_PRECISION_EPS); + EXPECT_NEAR (test_ref_coords[2 + i_coord * 3], out_coords[2], T8_PRECISION_EPS); + } +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_check_2d_element_linear_cad_surface, class_2d_element_linear_cad_surface, + AllEclasses2D); + +#endif /* T8_WITH_OCC */ diff --git a/test/t8_geometry/t8_gtest_point_inside.cxx b/test/t8_geometry/t8_gtest_point_inside.cxx index 9c3b9abac3..1e1873abb2 100644 --- a/test/t8_geometry/t8_gtest_point_inside.cxx +++ b/test/t8_geometry/t8_gtest_point_inside.cxx @@ -33,6 +33,8 @@ #include #include #include +#include +#include /* In this test we define a triangle in the x-y plane * and a point that lies in a triangle that is parallel @@ -70,7 +72,8 @@ TEST (t8_point_inside, test_point_inside_specific_triangle) t8_element_t *element = t8_forest_get_element (forest, 0, NULL); - const int point_is_inside = t8_forest_element_point_inside (forest, 0, element, test_point, tolerance); + int point_is_inside; + t8_forest_element_points_inside (forest, 0, element, test_point, 1, &point_is_inside, tolerance); ASSERT_FALSE (point_is_inside) << "The point is wrongly detected as inside the triangle."; t8_forest_unref (&forest); } @@ -112,23 +115,43 @@ TEST (t8_point_inside, test_point_inside_specific_quad) t8_element_t *element = t8_forest_get_element (forest, 0, NULL); - const int point_is_inside = t8_forest_element_point_inside (forest, 0, element, test_point, tolerance); + int point_is_inside; + t8_forest_element_points_inside (forest, 0, element, test_point, 1, &point_is_inside, tolerance); ASSERT_FALSE (point_is_inside) << "The point is wrongly detected as inside the quad."; t8_forest_unref (&forest); } -class geometry_point_inside: public testing::TestWithParam> { +/* *INDENT-OFF* */ +class geometry_point_inside: public testing::TestWithParam> { protected: void SetUp () override { eclass = std::get<0> (GetParam ()); level = std::get<1> (GetParam ()); + use_axis_aligned_geom = std::get<2> (GetParam ()); /* Construct a cube coarse mesh */ - cmesh = t8_cmesh_new_from_class (eclass, sc_MPI_COMM_WORLD); + if (use_axis_aligned_geom && (eclass == T8_ECLASS_LINE || eclass == T8_ECLASS_QUAD || eclass == T8_ECLASS_HEX)) { + /* clang-format off */ + const double boundaries[24] = { + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0, + 0, 0, 1, + 1, 0, 1, + 0, 1, 1, + 1, 1, 1 + }; + /* clang-format on */ + cmesh = t8_cmesh_new_hypercube_pad (eclass, sc_MPI_COMM_WORLD, boundaries, 1, 1, 1, use_axis_aligned_geom); + } + else { + cmesh = t8_cmesh_new_from_class (eclass, sc_MPI_COMM_WORLD); + } } void TearDown () override @@ -136,6 +159,7 @@ class geometry_point_inside: public testing::TestWithParam 2) { - t8_cmesh_translate_coordinates (tree_vertices + 3, tree_vertices + 3, 1, translate_points_0_1); + if (!use_axis_aligned_geom) { + double translate_points_0_1[3] = { 0.1, -0.1, 0.3 }; + t8_cmesh_translate_coordinates (tree_vertices, tree_vertices, 1, translate_points_0_1); + if (num_vertices > 2) { + t8_cmesh_translate_coordinates (tree_vertices + 3, tree_vertices + 3, 1, translate_points_0_1); + } } /* Build a uniform forest */ t8_forest_t forest = t8_forest_new_uniform (cmesh, default_scheme, level, 1, sc_MPI_COMM_WORLD); const t8_locidx_t num_trees = t8_forest_get_num_local_trees (forest); - for (t8_locidx_t itree = 0; itree < num_trees; ++itree) { t8_log_indent_push (); const t8_locidx_t num_elements = t8_forest_get_tree_num_elements (forest, itree); @@ -191,7 +218,7 @@ TEST_P (geometry_point_inside, test_point_inside) const int num_corners = eclass_scheme->t8_element_num_corners (element); /* For each corner get its coordinates */ for (int icorner = 0; icorner < num_corners; ++icorner) { - t8_forest_element_coordinate (forest, 0, element, icorner, element_vertices[icorner]); + t8_forest_element_coordinate (forest, itree, element, icorner, element_vertices[icorner]); } /* Allocate the barycentric coordinates */ @@ -229,7 +256,7 @@ TEST_P (geometry_point_inside, test_point_inside) } /* Corrected number of points due to possible rounding errors in pow */ const int num_points = sc_intpow (num_steps, num_corners - 1); - double *test_point = T8_ALLOC (double, num_points * 3); + double *test_point = T8_ALLOC_ZERO (double, num_points * 3); int *point_is_inside = T8_ALLOC (int, num_points); int *point_is_recognized_as_inside = T8_ALLOC (int, num_points); double step = (barycentric_range_upper_bound - barycentric_range_lower_bound) / (num_steps - 1); @@ -250,7 +277,6 @@ TEST_P (geometry_point_inside, test_point_inside) } for (int icorner = 0; icorner < num_corners - 1; ++icorner) { int this_step = (ipoint / sc_intpow (num_steps, icorner)) % num_steps; - /* Set barycentric coordinates */ barycentric_coordinates[icorner] = barycentric_range_lower_bound + this_step * step; dampening = (1 - Sum) * (1 - Sum); @@ -265,7 +291,6 @@ TEST_P (geometry_point_inside, test_point_inside) /* The point is inside if and only if all barycentric coordinates are >= 0. */ point_is_inside[ipoint] = point_is_inside[ipoint] && barycentric_coordinates[icorner] >= 0; } - /* Ensure that sum over all bar. coordinates is 1 */ barycentric_coordinates[num_corners - 1] = 1 - Sum; @@ -274,6 +299,7 @@ TEST_P (geometry_point_inside, test_point_inside) test_point[ipoint * 3 + icoord] += barycentric_coordinates[num_corners - 1] * element_vertices[num_corners - 1][icoord]; } + /* The point is inside if and only if all barycentric coordinates are >= 0. */ point_is_inside[ipoint] = point_is_inside[ipoint] && barycentric_coordinates[num_corners - 1] >= 0; @@ -281,12 +307,12 @@ TEST_P (geometry_point_inside, test_point_inside) } /* We now check whether the point inside function correctly sees whether * the point is inside the element or not. */ - t8_forest_element_point_batch_inside (forest, 0, element, test_point, num_points, point_is_recognized_as_inside, - tolerance); + t8_forest_element_points_inside (forest, 0, element, test_point, num_points, point_is_recognized_as_inside, + tolerance); for (int ipoint = 0; ipoint < num_points; ipoint++) { ASSERT_EQ (!point_is_recognized_as_inside[ipoint], !point_is_inside[ipoint]) << "Testing point #" << ipoint << "(" << test_point[0] << "," << test_point[1] << "," << test_point[2] - << ") should " << (point_is_inside[ipoint] ? "" : "not") << "be inside the " << t8_eclass_to_string[eclass] + << ") should " << (point_is_inside[ipoint] ? "" : "not ") << "be inside the " << t8_eclass_to_string[eclass] << " element, but is not detected as such."; } /* End loop over points. */ t8_debugf ("%i (%.2f%%) test points are inside the element\n", num_in, (100.0 * num_in) / num_points); @@ -302,8 +328,11 @@ TEST_P (geometry_point_inside, test_point_inside) #if T8_ENABLE_LESS_TESTS INSTANTIATE_TEST_SUITE_P (t8_gtest_point_inside, geometry_point_inside, - testing::Combine (testing::Range (T8_ECLASS_LINE, T8_ECLASS_COUNT), testing::Range (0, 4))); + testing::Combine (testing::Range (T8_ECLASS_LINE, T8_ECLASS_COUNT), testing::Range (0, 4), + testing::Range (0, 2))); + #else INSTANTIATE_TEST_SUITE_P (t8_gtest_point_inside, geometry_point_inside, - testing::Combine (testing::Range (T8_ECLASS_LINE, T8_ECLASS_COUNT), testing::Range (0, 6))); + testing::Combine (testing::Range (T8_ECLASS_LINE, T8_ECLASS_COUNT), testing::Range (0, 6), + testing::Range (0, 2))); #endif diff --git a/test/t8_gtest_occ_linkage.cxx b/test/t8_gtest_cad_linkage.cxx similarity index 83% rename from test/t8_gtest_occ_linkage.cxx rename to test/t8_gtest_cad_linkage.cxx index 72609549d1..967c79ed34 100644 --- a/test/t8_gtest_occ_linkage.cxx +++ b/test/t8_gtest_cad_linkage.cxx @@ -20,10 +20,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* In this test we create an occ gp_Pnt object. +/* In this test we create an cad gp_Pnt object. * The purpose of this test is to check whether t8code successfully links - * against occ. - * If t8code was not configured with --with-occ then this test + * against cad. + * If t8code was not configured with --with-cad then this test * does nothing and is always passed. */ @@ -34,13 +34,13 @@ #endif /* Check whether we can successfully execute VTK code */ -TEST (t8_test_occ_linkage, test_gp_Pnt) +TEST (t8_test_cad_linkage, test_gp_Pnt) { #if T8_WITH_OCC EXPECT_NO_THROW (gp_Pnt pnt = gp_Pnt (); pnt.SetX (1);); - t8_global_productionf ("Successfully created occ gp_Pnt object.\n"); + t8_global_productionf ("Successfully created cad gp_Pnt object.\n"); #else - t8_global_productionf ("This version of t8code is not compiled with occ support.\n"); + t8_global_productionf ("This version of t8code is not compiled with cad support.\n"); #endif } diff --git a/test/t8_gtest_macros.hxx b/test/t8_gtest_macros.hxx index 6189557338..20d2e17105 100644 --- a/test/t8_gtest_macros.hxx +++ b/test/t8_gtest_macros.hxx @@ -24,13 +24,15 @@ along with t8code; if not, write to the Free Software Foundation, Inc., * Provide macros for instantiating parameterized tests */ -#include -#include - #ifndef T8_GTEST_MACROS_HXX #define T8_GTEST_MACROS_HXX +#include +#include +#include + #define AllEclasses testing::Range (T8_ECLASS_ZERO, T8_ECLASS_COUNT) +#define AllEclasses2D testing::Values (T8_ECLASS_QUAD, T8_ECLASS_TRIANGLE) #define AllCmeshs testing::Range (0, t8_get_number_of_all_testcases ()) #endif /* T8_GTEST_MACROS_HXX */ diff --git a/test/t8_gtest_vec.cxx b/test/t8_gtest_vec.cxx index cd7a85dbfc..395f82f838 100644 --- a/test/t8_gtest_vec.cxx +++ b/test/t8_gtest_vec.cxx @@ -250,3 +250,11 @@ TEST (t8_gtest_vec, cross) t8_vec_cross (e2, e3, cross); EXPECT_VEC3_EQ (cross, e1, T8_PRECISION_EPS); } + +TEST (t8_gtest_vec, check_less_or_equal) +{ + const t8_test_vec one = { 1.0, 1.0, 1.0 }; + const t8_test_vec one_minus_eps = { 1.0 - T8_PRECISION_EPS, 1.0 - T8_PRECISION_EPS, 1.0 - T8_PRECISION_EPS }; + + EXPECT_VEC3_EQ (one, one_minus_eps, T8_PRECISION_EPS); +} diff --git a/test/t8_schemes/t8_gtest_ancestor.cxx b/test/t8_schemes/t8_gtest_ancestor.cxx index f22c5630c2..6e2189866e 100644 --- a/test/t8_schemes/t8_gtest_ancestor.cxx +++ b/test/t8_schemes/t8_gtest_ancestor.cxx @@ -107,10 +107,10 @@ TEST_P (ancestor, multi_level_recursive_check) ts->t8_element_new (1, &parent); ts->t8_element_new (1, &correct_anc_high_level); - t8_gloidx_t leafs_on_level; + t8_gloidx_t leaves_on_level; for (i = recursion_depth; i < max_lvl; i++) { - leafs_on_level = ts->t8_element_count_leafs (correct_anc, i - recursion_depth); - ts->t8_element_set_linear_id (correct_anc_high_level, i - recursion_depth, leafs_on_level / 2); + leaves_on_level = ts->t8_element_count_leaves (correct_anc, i - recursion_depth); + ts->t8_element_set_linear_id (correct_anc_high_level, i - recursion_depth, leaves_on_level / 2); ts->t8_element_copy (correct_anc_high_level, parent); t8_recursive_ancestor (correct_anc, desc_a, parent, check, ts, i); } diff --git a/test/t8_schemes/t8_gtest_element_count_leafs.cxx b/test/t8_schemes/t8_gtest_element_count_leaves.cxx similarity index 86% rename from test/t8_schemes/t8_gtest_element_count_leafs.cxx rename to test/t8_schemes/t8_gtest_element_count_leaves.cxx index 94e7bfce85..07648197f5 100644 --- a/test/t8_schemes/t8_gtest_element_count_leafs.cxx +++ b/test/t8_schemes/t8_gtest_element_count_leaves.cxx @@ -25,7 +25,7 @@ #include /* - * In this file we test whether the t8_element_count_leafs{_from_root} + * In this file we test whether the t8_element_count_leaves{_from_root} * function return the correct values for the default scheme. * This value should be 2^(dim * (level - element_level)) for * level >= element_level (for eclass != T8_ECLASS_PYRAMID). @@ -34,7 +34,7 @@ /* Tests whether the leaf count for one additional level matches the number of children */ -class class_element_leafs: public testing::TestWithParam { +class class_element_leaves: public testing::TestWithParam { protected: void SetUp () override @@ -53,7 +53,7 @@ class class_element_leafs: public testing::TestWithParam { t8_scheme_cxx_t *ts = t8_scheme_new_default_cxx (); }; -TEST_P (class_element_leafs, test_element_count_leafs_root) +TEST_P (class_element_leaves, test_element_count_leaves_root) { const int maxlevel = class_scheme->t8_element_maxlevel (); t8_gloidx_t compare_value = 1; @@ -61,7 +61,7 @@ TEST_P (class_element_leafs, test_element_count_leafs_root) t8_gloidx_t sum2 = 1; for (int level = 0; level <= maxlevel; ++level) { - const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leafs_from_root (level); + const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leaves_from_root (level); ASSERT_EQ (leaf_count, compare_value) << "Incorrect leaf count " << leaf_count << " at eclass " << t8_eclass_to_string[eclass] << " and level " << level << " (expecting " << compare_value << ")"; @@ -81,7 +81,7 @@ TEST_P (class_element_leafs, test_element_count_leafs_root) /* Tests whether the leaf count for the same level is equal to 1 * and for smaller levels is 0 */ -TEST_P (class_element_leafs, test_element_count_leafs_less_level) +TEST_P (class_element_leaves, test_element_count_leaves_less_level) { t8_element_t *element; const int maxlevel = class_scheme->t8_element_maxlevel (); @@ -91,14 +91,14 @@ TEST_P (class_element_leafs, test_element_count_leafs_less_level) for (int level = 0; level <= maxlevel; ++level) { /* Create the first element on this level */ class_scheme->t8_element_set_linear_id (element, level, 0); - /* Count the leafs of this element */ - const t8_gloidx_t leaf_count_same_level = class_scheme->t8_element_count_leafs (element, level); + /* Count the leaves of this element */ + const t8_gloidx_t leaf_count_same_level = class_scheme->t8_element_count_leaves (element, level); /* Check if equals 1 */ ASSERT_EQ (leaf_count_same_level, 1); int lower_levels; for (lower_levels = level - 1; lower_levels >= 0; --lower_levels) { - /* Count the leafs of this element on the lower levels */ - const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leafs (element, lower_levels); + /* Count the leaves of this element on the lower levels */ + const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leaves (element, lower_levels); /* Check if equals 0 */ ASSERT_EQ (leaf_count, 0) << "Incorrect leaf count " << leaf_count << " at eclass " << t8_eclass_to_string[eclass] << " and level " << level << " for element level " << lower_levels << "(expecting 0)"; @@ -110,7 +110,7 @@ TEST_P (class_element_leafs, test_element_count_leafs_less_level) } /* Tests whether the leaf count for one additional level matches the number of children */ -TEST_P (class_element_leafs, test_element_count_leafs_one_level) +TEST_P (class_element_leaves, test_element_count_leaves_one_level) { t8_element_t *element; const int maxlevel = class_scheme->t8_element_maxlevel (); @@ -119,8 +119,8 @@ TEST_P (class_element_leafs, test_element_count_leafs_one_level) for (int level = 1; level < maxlevel; ++level) { /* Create the first element on the previous level */ class_scheme->t8_element_set_linear_id (element, level - 1, 0); - /* Count the leafs of this element */ - const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leafs (element, level); + /* Count the leaves of this element */ + const t8_gloidx_t leaf_count = class_scheme->t8_element_count_leaves (element, level); /* Compute the number of children of the element */ const int number_of_children = class_scheme->t8_element_num_children (element); /* Check both values for equality */ @@ -131,4 +131,4 @@ TEST_P (class_element_leafs, test_element_count_leafs_one_level) class_scheme->t8_element_destroy (1, &element); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_count_leafs, class_element_leafs, AllEclasses); +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_count_leaves, class_element_leaves, AllEclasses); diff --git a/test/t8_schemes/t8_gtest_face_descendant.cxx b/test/t8_schemes/t8_gtest_face_descendant.cxx index cfbd0b93ba..ff8c42a5a2 100644 --- a/test/t8_schemes/t8_gtest_face_descendant.cxx +++ b/test/t8_schemes/t8_gtest_face_descendant.cxx @@ -111,7 +111,7 @@ class class_descendant: public TestDFS { TEST_P (class_descendant, t8_check_face_desc) { -#ifdef T8_ENABLE_DEBUG +#ifdef T8_ENABLE_LESS_TESTS const int maxlvl = 3; #else const int maxlvl = 5; diff --git a/test/t8_schemes/t8_gtest_face_neigh.cxx b/test/t8_schemes/t8_gtest_face_neigh.cxx index ebc76cc6ab..318eaf9db8 100644 --- a/test/t8_schemes/t8_gtest_face_neigh.cxx +++ b/test/t8_schemes/t8_gtest_face_neigh.cxx @@ -60,7 +60,7 @@ class face_neigh: public testing::TestWithParam { t8_eclass_scheme_c *ts; t8_eclass_t eclass; -#ifdef T8_ENABLE_DEBUG +#ifdef T8_ENABLE_LESS_TESTS const int maxlvl = 3; #else const int maxlvl = 4; diff --git a/test/t8_schemes/t8_gtest_init_linear_id.cxx b/test/t8_schemes/t8_gtest_init_linear_id.cxx index db1341b274..a81cea5e2a 100644 --- a/test/t8_schemes/t8_gtest_init_linear_id.cxx +++ b/test/t8_schemes/t8_gtest_init_linear_id.cxx @@ -66,7 +66,7 @@ t8_test_init_linear_id_refine_everything (t8_forest_t forest, t8_forest_t forest return 1; } -/* Iterate over the leafs of a uniformly refined forest and check the id*/ +/* Iterate over the leaves of a uniformly refined forest and check the id*/ TEST_P (linear_id, uniform_forest) { t8_forest_t forest, forest_adapt; @@ -91,7 +91,7 @@ TEST_P (linear_id, uniform_forest) /*Manually compute the id of the first element*/ const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, tree_id); t8_eclass_scheme_c *tc_scheme = t8_forest_get_eclass_scheme (forest, tree_class); - const t8_locidx_t shift = tc_scheme->t8_element_count_leafs_from_root (level) - num_elements_in_tree; + const t8_locidx_t shift = tc_scheme->t8_element_count_leaves_from_root (level) - num_elements_in_tree; /*Iterate over elements */ for (t8_locidx_t id_iter = 0; id_iter < num_elements_in_tree; id_iter++) { /*Get the current element*/ @@ -126,14 +126,14 @@ TEST_P (linear_id, id_at_other_level) #endif for (int level = 0; level < max_lvl; level++) { /* Compute the number of elements at the current level */ - const t8_linearidx_t num_desc = ts->t8_element_count_leafs_from_root (level); + const t8_linearidx_t num_desc = ts->t8_element_count_leaves_from_root (level); for (t8_linearidx_t id = 0; id < num_desc; id++) { /* Set the child at the current level */ ts->t8_element_set_linear_id (child, level, id); /* Compute the id of child at a higher level. */ const t8_linearidx_t id_at_lvl = ts->t8_element_get_linear_id (child, level + add_lvl); - /* Compute how many leafs/descendants child has at level level+add_lvl */ - const t8_linearidx_t child_desc = ts->t8_element_count_leafs (child, level + add_lvl); + /* Compute how many leaves/descendants child has at level level+add_lvl */ + const t8_linearidx_t child_desc = ts->t8_element_count_leaves (child, level + add_lvl); /* Iterate over all descendants */ for (t8_linearidx_t leaf_id = 0; leaf_id < child_desc; leaf_id++) { /* Set the descendant (test) at level of the descendants and shift the diff --git a/test/t8_schemes/t8_gtest_nca.cxx b/test/t8_schemes/t8_gtest_nca.cxx index 84ff7a4839..b9dc02e405 100644 --- a/test/t8_schemes/t8_gtest_nca.cxx +++ b/test/t8_schemes/t8_gtest_nca.cxx @@ -263,7 +263,7 @@ TEST_P (nca, recursive_check_higher_level) t8_element_t *correct_nca_high_level; int num_children; int i, k, l; - t8_gloidx_t leafs_on_level; + t8_gloidx_t leaves_on_level; EXPECT_TRUE (max_lvl - recursion_depth >= 0); ts->t8_element_new (1, &parent_a); @@ -272,9 +272,9 @@ TEST_P (nca, recursive_check_higher_level) /* Test on different levels around the middle of the refinement tree */ for (i = recursion_depth; i < max_lvl; i++) { - leafs_on_level = ts->t8_element_count_leafs (correct_nca, i - recursion_depth); - /* middle = leafs/2 */ - ts->t8_element_set_linear_id (correct_nca_high_level, i - recursion_depth, leafs_on_level / 2); + leaves_on_level = ts->t8_element_count_leaves (correct_nca, i - recursion_depth); + /* middle = leaves/2 */ + ts->t8_element_set_linear_id (correct_nca_high_level, i - recursion_depth, leaves_on_level / 2); /* Initialization for recursive_nca_check */ num_children = ts->t8_element_num_children (correct_nca_high_level); diff --git a/test/t8_schemes/t8_gtest_successor.cxx b/test/t8_schemes/t8_gtest_successor.cxx index adff9684e7..9441a97e69 100644 --- a/test/t8_schemes/t8_gtest_successor.cxx +++ b/test/t8_schemes/t8_gtest_successor.cxx @@ -131,7 +131,7 @@ t8_deep_successor (t8_element_t *element, t8_element_t *successor, t8_element_t TEST_P (class_successor, test_recursive_and_deep_successor) { -#ifdef T8_ENABLE_DEBUG +#ifdef T8_ENABLE_LESS_TESTS const int maxlvl = 3; #else const int maxlvl = 4; diff --git a/thirdparty/googletest-mpi/gtest/gtest-all.cc b/thirdparty/googletest-mpi/gtest/gtest-all.cc index d11595ca74..caf137bab4 100644 --- a/thirdparty/googletest-mpi/gtest/gtest-all.cc +++ b/thirdparty/googletest-mpi/gtest/gtest-all.cc @@ -105,8 +105,8 @@ // GOOGLETEST_CM0004 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ -#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ @@ -306,10 +306,9 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 }\ } while (::testing::internal::AlwaysFalse()) -#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ #include -#include #include #include #include @@ -318,6 +317,9 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #include #include +#include // NOLINT +#include +#include #include #include #include @@ -328,8 +330,6 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #if GTEST_OS_LINUX -# define GTEST_HAS_GETTIMEOFDAY_ 1 - # include // NOLINT # include // NOLINT # include // NOLINT @@ -341,7 +341,6 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 # include #elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. @@ -357,24 +356,21 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 # include // NOLINT # undef min +#ifdef _MSC_VER # include // NOLINT -# include // NOLINT +#endif + # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW #else -// Assume other platforms have gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT @@ -426,8 +422,8 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. -#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ -#define GTEST_SRC_GTEST_INTERNAL_INL_H_ +#ifndef GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_ +#define GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_ #ifndef _WIN32_WCE # include @@ -437,6 +433,7 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #include // For memmove. #include +#include #include #include #include @@ -475,9 +472,11 @@ const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; +const char kFailFast[] = "fail_fast"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; +const char kBriefFlag[] = "brief"; const char kPrintTimeFlag[] = "print_time"; const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; @@ -515,11 +514,11 @@ GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); + const char* str, const char* flag, int32_t* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { +inline int GetRandomSeedFromFlag(int32_t random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); @@ -555,10 +554,12 @@ class GTestFlagSaver { color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + fail_fast_ = GTEST_FLAG(fail_fast); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); + brief_ = GTEST_FLAG(brief); print_time_ = GTEST_FLAG(print_time); print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); @@ -578,9 +579,11 @@ class GTestFlagSaver { GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; + GTEST_FLAG(fail_fast) = fail_fast_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; + GTEST_FLAG(brief) = brief_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; @@ -599,16 +602,18 @@ class GTestFlagSaver { std::string color_; std::string death_test_style_; bool death_test_use_fork_; + bool fail_fast_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; + bool brief_; bool print_time_; bool print_utf8_; - internal::Int32 random_seed_; - internal::Int32 repeat_; + int32_t random_seed_; + int32_t repeat_; bool shuffle_; - internal::Int32 stack_trace_depth_; + int32_t stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; @@ -619,7 +624,7 @@ class GTestFlagSaver { // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". -GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); +GTEST_API_ std::string CodePointToUtf8(uint32_t code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: @@ -652,10 +657,10 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and +// Parses the environment variable var as a 32-bit integer. If it is unset, +// returns default_val. If it is not a 32-bit integer, prints an error and // and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); +GTEST_API_ int32_t Int32FromEnvOrDie(const char* env_var, int32_t default_val); // Given the total number of shards, the shard index, and the test id, // returns true if and only if the test should be run on this shard. The test id @@ -715,7 +720,7 @@ void ShuffleRange(internal::Random* random, int begin, int end, const int last_in_range = begin + range_width - 1; const int selected = begin + - static_cast(random->Generate(static_cast(range_width))); + static_cast(random->Generate(static_cast(range_width))); std::swap((*v)[static_cast(selected)], (*v)[static_cast(last_in_range)]); } @@ -777,13 +782,6 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_filter flag. - // Returns true if and only if the wildcard pattern matches the string. - // The first ':' or '\0' character in pattern marks the end of it. - // - // This recursive algorithm isn't very efficient, but is clear and - // works well enough for matching test names, which are short. - static bool PatternMatchesString(const char *pattern, const char *str); - // Returns true if and only if the user-specified filter matches the test // suite name and the test name. static bool FilterMatchesTest(const std::string& test_suite_name, @@ -1038,10 +1036,10 @@ class GTEST_API_ UnitTestImpl { // Arguments: // // test_suite_name: name of the test suite - // type_param: the name of the test's type parameter, or NULL if - // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test suite - // tear_down_tc: pointer to the function that tears down the test suite + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc); @@ -1065,6 +1063,7 @@ class GTEST_API_ UnitTestImpl { void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc, TestInfo* test_info) { +#if GTEST_HAS_DEATH_TEST // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as @@ -1077,6 +1076,7 @@ class GTEST_API_ UnitTestImpl { GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } +#endif // GTEST_HAS_DEATH_TEST GetTestSuite(test_info->test_suite_name(), test_info->type_param(), set_up_tc, tear_down_tc) @@ -1089,6 +1089,17 @@ class GTEST_API_ UnitTestImpl { return parameterized_test_registry_; } + std::set* ignored_parameterized_test_suites() { + return &ignored_parameterized_test_suites_; + } + + // Returns TypeParameterizedTestSuiteRegistry object used to keep track of + // type-parameterized tests and instantiations of them. + internal::TypeParameterizedTestSuiteRegistry& + type_parameterized_test_registry() { + return type_parameterized_test_registry_; + } + // Sets the TestSuite object for the test that's currently running. void set_current_test_suite(TestSuite* a_current_test_suite) { current_test_suite_ = a_current_test_suite; @@ -1265,6 +1276,12 @@ class GTEST_API_ UnitTestImpl { // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; + internal::TypeParameterizedTestSuiteRegistry + type_parameterized_test_registry_; + + // The set holding the name of parameterized + // test suites that may go uninstantiated. + std::set ignored_parameterized_test_suites_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; @@ -1391,20 +1408,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. + using BiggestConvertible = unsigned long long; // NOLINT -# if GTEST_OS_WINDOWS && !defined(__GNUC__) - - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); - -# else - - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); - -# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); // NOLINT const bool parse_success = *end == '\0' && errno == 0; GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); @@ -1600,7 +1606,7 @@ class StreamingListener : public EmptyTestEventListener { GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 -#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#endif // GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf @@ -1690,6 +1696,21 @@ static const char* GetDefaultFilter() { return kUniversalFilter; } +// Bazel passes in the argument to '--test_runner_fail_fast' via the +// TESTBRIDGE_TEST_RUNNER_FAIL_FAST environment variable. +static bool GetDefaultFailFast() { + const char* const testbridge_test_runner_fail_fast = + internal::posix::GetEnv("TESTBRIDGE_TEST_RUNNER_FAIL_FAST"); + if (testbridge_test_runner_fail_fast != nullptr) { + return strcmp(testbridge_test_runner_fail_fast, "1") == 0; + } + return false; +} + +GTEST_DEFINE_bool_( + fail_fast, internal::BoolFromGTestEnv("fail_fast", GetDefaultFailFast()), + "True if and only if a test failure should stop further test execution."); + GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), @@ -1750,6 +1771,10 @@ GTEST_DEFINE_string_( "executable's name and, if necessary, made unique by adding " "digits."); +GTEST_DEFINE_bool_( + brief, internal::BoolFromGTestEnv("brief", false), + "True if only test failures should be displayed in text output."); + GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), "True if and only if " GTEST_NAME_ " should display elapsed time in text output."); @@ -1811,10 +1836,10 @@ namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. -UInt32 Random::Generate(UInt32 range) { +uint32_t Random::Generate(uint32_t range) { // These constants are the same as are used in glibc's rand(3). // Use wider types than necessary to prevent unsigned overflow diagnostics. - state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -1888,6 +1913,162 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } +namespace { + +// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P +// to creates test cases for it, a syntetic test case is +// inserted to report ether an error or a log message. +// +// This configuration bit will likely be removed at some point. +constexpr bool kErrorOnUninstantiatedParameterizedTest = true; +constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = true; + +// A test that fails at a given file/line location with a given message. +class FailureTest : public Test { + public: + explicit FailureTest(const CodeLocation& loc, std::string error_message, + bool as_error) + : loc_(loc), + error_message_(std::move(error_message)), + as_error_(as_error) {} + + void TestBody() override { + if (as_error_) { + AssertHelper(TestPartResult::kNonFatalFailure, loc_.file.c_str(), + loc_.line, "") = Message() << error_message_; + } else { + std::cout << error_message_ << std::endl; + } + } + + private: + const CodeLocation loc_; + const std::string error_message_; + const bool as_error_; +}; + + +} // namespace + +std::set* GetIgnoredParameterizedTestSuites() { + return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites(); +} + +// Add a given test_suit to the list of them allow to go un-instantiated. +MarkAsIgnored::MarkAsIgnored(const char* test_suite) { + GetIgnoredParameterizedTestSuites()->insert(test_suite); +} + +// If this parameterized test suite has no instantiations (and that +// has not been marked as okay), emit a test case reporting that. +void InsertSyntheticTestCase(const std::string& name, CodeLocation location, + bool has_test_p) { + const auto& ignored = *GetIgnoredParameterizedTestSuites(); + if (ignored.find(name) != ignored.end()) return; + + const char kMissingInstantiation[] = // + " is defined via TEST_P, but never instantiated. None of the test cases " + "will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only " + "ones provided expand to nothing." + "\n\n" + "Ideally, TEST_P definitions should only ever be included as part of " + "binaries that intend to use them. (As opposed to, for example, being " + "placed in a library that may be linked in to get other utilities.)"; + + const char kMissingTestCase[] = // + " is instantiated via INSTANTIATE_TEST_SUITE_P, but no tests are " + "defined via TEST_P . No test cases will run." + "\n\n" + "Ideally, INSTANTIATE_TEST_SUITE_P should only ever be invoked from " + "code that always depend on code that provides TEST_P. Failing to do " + "so is often an indication of dead code, e.g. the last TEST_P was " + "removed but the rest got left behind."; + + std::string message = + "Parameterized test suite " + name + + (has_test_p ? kMissingInstantiation : kMissingTestCase) + + "\n\n" + "To suppress this error for this test suite, insert the following line " + "(in a non-header) in the namespace it is defined in:" + "\n\n" + "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + name + ");"; + + std::string full_name = "UninstantiatedParameterizedTestSuite<" + name + ">"; + RegisterTest( // + "GoogleTestVerification", full_name.c_str(), + nullptr, // No type parameter. + nullptr, // No value parameter. + location.file.c_str(), location.line, [message, location] { + return new FailureTest(location, message, + kErrorOnUninstantiatedParameterizedTest); + }); +} + +void RegisterTypeParameterizedTestSuite(const char* test_suite_name, + CodeLocation code_location) { + GetUnitTestImpl()->type_parameterized_test_registry().RegisterTestSuite( + test_suite_name, code_location); +} + +void RegisterTypeParameterizedTestSuiteInstantiation(const char* case_name) { + GetUnitTestImpl() + ->type_parameterized_test_registry() + .RegisterInstantiation(case_name); +} + +void TypeParameterizedTestSuiteRegistry::RegisterTestSuite( + const char* test_suite_name, CodeLocation code_location) { + suites_.emplace(std::string(test_suite_name), + TypeParameterizedTestSuiteInfo(code_location)); +} + +void TypeParameterizedTestSuiteRegistry::RegisterInstantiation( + const char* test_suite_name) { + auto it = suites_.find(std::string(test_suite_name)); + if (it != suites_.end()) { + it->second.instantiated = true; + } else { + GTEST_LOG_(ERROR) << "Unknown type parameterized test suit '" + << test_suite_name << "'"; + } +} + +void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() { + const auto& ignored = *GetIgnoredParameterizedTestSuites(); + for (const auto& testcase : suites_) { + if (testcase.second.instantiated) continue; + if (ignored.find(testcase.first) != ignored.end()) continue; + + std::string message = + "Type parameterized test suite " + testcase.first + + " is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated " + "via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run." + "\n\n" + "Ideally, TYPED_TEST_P definitions should only ever be included as " + "part of binaries that intend to use them. (As opposed to, for " + "example, being placed in a library that may be linked in to get other " + "utilities.)" + "\n\n" + "To suppress this error for this test suite, insert the following line " + "(in a non-header) in the namespace it is defined in:" + "\n\n" + "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + + testcase.first + ");"; + + std::string full_name = + "UninstantiatedTypeParameterizedTestSuite<" + testcase.first + ">"; + RegisterTest( // + "GoogleTestVerification", full_name.c_str(), + nullptr, // No type parameter. + nullptr, // No value parameter. + testcase.second.code_location.file.c_str(), + testcase.second.code_location.line, [message, testcase] { + return new FailureTest(testcase.second.code_location, message, + kErrorOnUninstantiatedTypeParameterizedTest); + }); + } +} + // A copy of all command line arguments. Set by InitGoogleTest(). static ::std::vector g_argvs; @@ -1960,47 +2141,82 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { return result.string(); } -// Returns true if and only if the wildcard pattern matches the string. -// The first ':' or '\0' character in pattern marks the end of it. +// Returns true if and only if the wildcard pattern matches the string. Each +// pattern consists of regular characters, single-character wildcards (?), and +// multi-character wildcards (*). // -// This recursive algorithm isn't very efficient, but is clear and -// works well enough for matching test names, which are short. -bool UnitTestOptions::PatternMatchesString(const char *pattern, - const char *str) { - switch (*pattern) { - case '\0': - case ':': // Either ':' or '\0' marks the end of the pattern. - return *str == '\0'; - case '?': // Matches any single character. - return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); - case '*': // Matches any string (possibly empty) of characters. - return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); - default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); - } -} - -bool UnitTestOptions::MatchesFilter( - const std::string& name, const char* filter) { - const char *cur_pattern = filter; - for (;;) { - if (PatternMatchesString(cur_pattern, name.c_str())) { - return true; +// This function implements a linear-time string globbing algorithm based on +// https://research.swtch.com/glob. +static bool PatternMatchesString(const std::string& name_str, + const char* pattern, const char* pattern_end) { + const char* name = name_str.c_str(); + const char* const name_begin = name; + const char* const name_end = name + name_str.size(); + + const char* pattern_next = pattern; + const char* name_next = name; + + while (pattern < pattern_end || name < name_end) { + if (pattern < pattern_end) { + switch (*pattern) { + default: // Match an ordinary character. + if (name < name_end && *name == *pattern) { + ++pattern; + ++name; + continue; + } + break; + case '?': // Match any single character. + if (name < name_end) { + ++pattern; + ++name; + continue; + } + break; + case '*': + // Match zero or more characters. Start by skipping over the wildcard + // and matching zero characters from name. If that fails, restart and + // match one more character than the last attempt. + pattern_next = pattern; + name_next = name + 1; + ++pattern; + continue; + } } + // Failed to match a character. Restart if possible. + if (name_begin < name_next && name_next <= name_end) { + pattern = pattern_next; + name = name_next; + continue; + } + return false; + } + return true; +} - // Finds the next pattern in the filter. - cur_pattern = strchr(cur_pattern, ':'); +bool UnitTestOptions::MatchesFilter(const std::string& name_str, + const char* filter) { + // The filter is a list of patterns separated by colons (:). + const char* pattern = filter; + while (true) { + // Find the bounds of this pattern. + const char* const next_sep = strchr(pattern, ':'); + const char* const pattern_end = + next_sep != nullptr ? next_sep : pattern + strlen(pattern); - // Returns if no more pattern can be found. - if (cur_pattern == nullptr) { - return false; + // Check if this pattern matches name_str. + if (PatternMatchesString(name_str, pattern, pattern_end)) { + return true; } - // Skips the pattern separater (the ':' character). - cur_pattern++; + // Give up on this pattern. However, if we found a pattern separator (:), + // advance to the next pattern (skipping over the separator) and restart. + if (next_sep == nullptr) { + return false; + } + pattern = next_sep + 1; } + return true; } // Returns true if and only if the user-specified filter matches the test @@ -2310,44 +2526,30 @@ std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { ); // NOLINT } -// Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; +// A helper class for measuring elapsed times. +class Timer { + public: + Timer() : start_(std::chrono::steady_clock::now()) {} + + // Return time elapsed in milliseconds since the timer was created. + TimeInMillis Elapsed() { + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_) + .count(); } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; - - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - GTEST_DISABLE_MSC_DEPRECATED_PUSH_() - _ftime64(&now); - GTEST_DISABLE_MSC_DEPRECATED_POP_() - - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, nullptr); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -# error "Don't know how to get the current time on your system." -#endif + + private: + std::chrono::time_point start_; +}; + +// Returns a timestamp as milliseconds since the epoch. Note this time may jump +// around subject to adjustments by the system, to measure elapsed time use +// Timer instead. +TimeInMillis GetTimeInMillis() { + return std::chrono::duration_cast( + std::chrono::system_clock::now() - + std::chrono::system_clock::from_time_t(0)) + .count(); } // Utilities @@ -2902,6 +3104,31 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); + // Find the value which is closest to zero. + const double min_abs = std::min(fabs(val1), fabs(val2)); + // Find the distance to the next double from that value. + const double epsilon = + nextafter(min_abs, std::numeric_limits::infinity()) - min_abs; + // Detect the case where abs_error is so small that EXPECT_NEAR is + // effectively the same as EXPECT_EQUAL, and give an informative error + // message so that the situation can be more easily understood without + // requiring exotic floating-point knowledge. + // Don't do an epsilon check if abs_error is zero because that implies + // that an equality check was actually intended. + if (!(std::isnan)(val1) && !(std::isnan)(val2) && abs_error > 0 && + abs_error < epsilon) { + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 << " is " + << diff << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ".\nThe abs_error parameter " + << abs_error_expr << " evaluates to " << abs_error + << " which is smaller than the minimum distance between doubles for " + "numbers of this magnitude which is " + << epsilon + << ", thus making this EXPECT_NEAR check equivalent to " + "EXPECT_EQUAL. Consider using EXPECT_DOUBLE_EQ instead."; + } return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" @@ -3265,33 +3492,33 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; +constexpr uint32_t kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; +constexpr uint32_t kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; +constexpr uint32_t kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; +constexpr uint32_t kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); +inline uint32_t ChopLowBits(uint32_t* bits, int n) { + const uint32_t low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be +// code_point parameter is of type uint32_t because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". -std::string CodePointToUtf8(UInt32 code_point) { +std::string CodePointToUtf8(uint32_t code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } @@ -3332,11 +3559,11 @@ inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { } // Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const auto first_u = static_cast(first); - const auto second_u = static_cast(second); - const UInt32 mask = (1 << 10) - 1; +inline uint32_t CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const auto first_u = static_cast(first); + const auto second_u = static_cast(second); + const uint32_t mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 : @@ -3364,7 +3591,7 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; + uint32_t unicode_code_point; if (str[i] == L'\0') { break; @@ -3373,7 +3600,7 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { str[i + 1]); i++; } else { - unicode_code_point = static_cast(str[i]); + unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); @@ -3496,8 +3723,13 @@ bool String::EndsWithCaseInsensitive( // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { + return FormatIntWidthN(value, 2); +} + +// Formats an int value to given width with leading zeros. +std::string String::FormatIntWidthN(int value, int width) { std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << value; + ss << std::setfill('0') << std::setw(width) << value; return ss.str(); } @@ -3509,7 +3741,7 @@ std::string String::FormatInt(int value) { } // Formats an int value as "%X". -std::string String::FormatHexUInt32(UInt32 value) { +std::string String::FormatHexUInt32(uint32_t value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); @@ -3517,7 +3749,7 @@ std::string String::FormatHexUInt32(UInt32 value) { // Formats an int value as "%X". std::string String::FormatHexInt(int value) { - return FormatHexUInt32(static_cast(value)); + return FormatHexUInt32(static_cast(value)); } // Formats a byte as "%02X". @@ -3556,7 +3788,9 @@ std::string AppendUserMessage(const std::string& gtest_msg, if (user_msg_string.empty()) { return gtest_msg; } - + if (gtest_msg.empty()) { + return user_msg_string; + } return gtest_msg + "\n" + user_msg_string; } @@ -3639,7 +3873,8 @@ static const char* const kReservedTestSuitesAttributes[] = { // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { - "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; + "disabled", "errors", "failures", "name", + "tests", "time", "timestamp", "skipped"}; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { @@ -3652,7 +3887,7 @@ static const char* const kReservedOutputTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param", "file", "line", "result", "timestamp"}; -template +template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } @@ -4126,6 +4361,7 @@ TestInfo::TestInfo(const std::string& a_test_suite_name, should_run_(false), is_disabled_(false), matches_filter_(false), + is_in_another_shard_(false), factory_(factory), result_() {} @@ -4139,7 +4375,7 @@ namespace internal { // // Arguments: // -// test_suite_name: name of the test suite +// test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. @@ -4220,6 +4456,7 @@ namespace internal { void UnitTestImpl::RegisterParameterizedTests() { if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); + type_parameterized_test_registry_.CheckForInstantiations(); parameterized_tests_registered_ = true; } } @@ -4240,7 +4477,8 @@ void TestInfo::Run() { // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); - const TimeInMillis start = internal::GetTimeInMillis(); + result_.set_start_timestamp(internal::GetTimeInMillis()); + internal::Timer timer; impl->os_stack_trace_getter()->UponLeavingGTest(); @@ -4265,8 +4503,7 @@ void TestInfo::Run() { test, &Test::DeleteSelf_, "the test fixture's destructor"); } - result_.set_start_timestamp(start); - result_.set_elapsed_time(internal::GetTimeInMillis() - start); + result_.set_elapsed_time(timer.Elapsed()); #if GTEST_HAS_MPI result_.Synchronize (); #endif @@ -4279,6 +4516,28 @@ void TestInfo::Run() { impl->set_current_test_info(nullptr); } +// Skip and records a skipped test result for this object. +void TestInfo::Skip() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TestPartResult test_part_result = + TestPartResult(TestPartResult::kSkip, this->file(), this->line(), ""); + impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult( + test_part_result); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + impl->set_current_test_info(nullptr); +} + // class TestSuite // Gets the number of successful tests in this test suite. @@ -4325,7 +4584,7 @@ int TestSuite::total_test_count() const { // // Arguments: // -// name: name of the test suite +// a_name: name of the test suite // a_type_param: the name of the test suite's type parameter, or NULL if // this is not a typed or a type-parameterized test suite. // set_up_tc: pointer to the function that sets up the test suite @@ -4380,19 +4639,26 @@ void TestSuite::Run() { // Call both legacy and the new API repeater->OnTestSuiteStart(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseStart(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); start_timestamp_ = internal::GetTimeInMillis(); + internal::Timer timer; for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); + if (GTEST_FLAG(fail_fast) && GetMutableTestInfo(i)->result()->Failed()) { + for (int j = i + 1; j < total_test_count(); j++) { + GetMutableTestInfo(j)->Skip(); + } + break; + } } - elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; + elapsed_time_ = timer.Elapsed(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( @@ -4401,9 +4667,39 @@ void TestSuite::Run() { // Call both legacy and the new API repeater->OnTestSuiteEnd(*this); // Legacy API is deprecated but still available -#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ repeater->OnTestCaseEnd(*this); -#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + impl->set_current_test_suite(nullptr); +} + +// Skips all tests under this TestSuite. +void TestSuite::Skip() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_suite(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Skip(); + } + + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + repeater->OnTestCaseEnd(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ impl->set_current_test_suite(nullptr); } @@ -4455,7 +4751,7 @@ static std::string FormatTestSuiteCount(int test_suite_count) { static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSkip: - return "Skipped"; + return "Skipped\n"; case TestPartResult::kSuccess: return "Success"; @@ -4472,6 +4768,9 @@ static const char * TestPartResultTypeToString(TestPartResult::Type type) { } namespace internal { +namespace { +enum class GTestColor { kDefault, kRed, kGreen, kYellow }; +} // namespace // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( @@ -4509,9 +4808,12 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { // Returns the character attribute for the given color. static WORD GetColorAttribute(GTestColor color) { switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; - case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + case GTestColor::kRed: + return FOREGROUND_RED; + case GTestColor::kGreen: + return FOREGROUND_GREEN; + case GTestColor::kYellow: + return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } @@ -4549,13 +4851,16 @@ static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { #else -// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// Returns the ANSI color code for the given color. GTestColor::kDefault is // an invalid input. static const char* GetAnsiColorCode(GTestColor color) { switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; + case GTestColor::kRed: + return "1"; + case GTestColor::kGreen: + return "2"; + case GTestColor::kYellow: + return "3"; default: return nullptr; } @@ -4604,7 +4909,9 @@ bool ShouldUseColor(bool stdout_is_tty) { // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { + +GTEST_ATTRIBUTE_PRINTF_(2, 3) +static void ColoredPrintf(GTestColor color, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -4614,7 +4921,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); - const bool use_color = in_color_mode && (color != COLOR_DEFAULT); + const bool use_color = in_color_mode && (color != GTestColor::kDefault); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { @@ -4711,6 +5018,7 @@ class PrettyUnitTestResultPrinter : public TestEventListener { private: static void PrintFailedTests(const UnitTest& unit_test); + static void PrintFailedTestSuites(const UnitTest& unit_test); static void PrintSkippedTests(const UnitTest& unit_test); }; @@ -4725,25 +5033,24 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); + ColoredPrintf(GTestColor::kYellow, "Note: %s filter = %s\n", GTEST_NAME_, + filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %d of %s.\n", + const int32_t shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(GTestColor::kYellow, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { - ColoredPrintf(COLOR_YELLOW, + ColoredPrintf(GTestColor::kYellow, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } - ColoredPrintf(COLOR_GREEN, "[==========] "); + ColoredPrintf(GTestColor::kGreen, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); @@ -4752,7 +5059,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } @@ -4761,7 +5068,7 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == nullptr) { printf("\n"); @@ -4775,7 +5082,7 @@ void PrettyUnitTestResultPrinter::OnTestSuiteStart( const TestSuite& test_suite) { const std::string counts = FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("%s from %s", counts.c_str(), test_suite.name()); if (test_suite.type_param() == nullptr) { printf("\n"); @@ -4787,7 +5094,7 @@ void PrettyUnitTestResultPrinter::OnTestSuiteStart( #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + ColoredPrintf(GTestColor::kGreen, "[ RUN ] "); PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); @@ -4797,9 +5104,7 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { switch (result.type()) { - // If the test part succeeded, or was skipped, - // we don't need to do anything. - case TestPartResult::kSkip: + // If the test part succeeded, we don't need to do anything. case TestPartResult::kSuccess: return; default: @@ -4812,11 +5117,11 @@ void PrettyUnitTestResultPrinter::OnTestPartResult( void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { - ColoredPrintf(COLOR_GREEN, "[ OK ] "); + ColoredPrintf(GTestColor::kGreen, "[ OK ] "); } else if (test_info.result()->Skipped()) { - ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] "); } else { - ColoredPrintf(COLOR_RED, "[ FAILED ] "); + ColoredPrintf(GTestColor::kRed, "[ FAILED ] "); } PrintTestName(test_info.test_suite_name(), test_info.name()); if (test_info.result()->Failed()) @@ -4837,7 +5142,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); @@ -4848,7 +5153,7 @@ void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { const std::string counts = FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), internal::StreamableToString(test_suite.elapsed_time()).c_str()); fflush(stdout); @@ -4857,7 +5162,7 @@ void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); + ColoredPrintf(GTestColor::kGreen, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } @@ -4865,9 +5170,8 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } + ColoredPrintf(GTestColor::kRed, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { const TestSuite& test_suite = *unit_test.GetTestSuite(i); @@ -4879,12 +5183,36 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } - ColoredPrintf(COLOR_RED, "[ FAILED ] "); + ColoredPrintf(GTestColor::kRed, "[ FAILED ] "); printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } + printf("\n%2d FAILED %s\n", failed_test_count, + failed_test_count == 1 ? "TEST" : "TESTS"); +} + +// Internal helper for printing the list of test suite failures not covered by +// PrintFailedTests. +void PrettyUnitTestResultPrinter::PrintFailedTestSuites( + const UnitTest& unit_test) { + int suite_failure_count = 0; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run()) { + continue; + } + if (test_suite.ad_hoc_test_result().Failed()) { + ColoredPrintf(GTestColor::kRed, "[ FAILED ] "); + printf("%s: SetUpTestSuite or TearDownTestSuite\n", test_suite.name()); + ++suite_failure_count; + } + } + if (suite_failure_count > 0) { + printf("\n%2d FAILED TEST %s\n", suite_failure_count, + suite_failure_count == 1 ? "SUITE" : "SUITES"); + } } // Internal helper for printing the list of skipped tests. @@ -4904,7 +5232,7 @@ void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { if (!test_info.should_run() || !test_info.result()->Skipped()) { continue; } - ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] "); printf("%s.%s", test_suite.name(), test_info.name()); printf("\n"); } @@ -4913,7 +5241,7 @@ void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); + ColoredPrintf(GTestColor::kGreen, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); @@ -4922,35 +5250,28 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + ColoredPrintf(GTestColor::kGreen, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); const int skipped_test_count = unit_test.skipped_test_count(); if (skipped_test_count > 0) { - ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] "); printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); PrintSkippedTests(unit_test); } - int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); + PrintFailedTestSuites(unit_test); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { + if (unit_test.Passed()) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, - num_disabled == 1 ? "TEST" : "TESTS"); + ColoredPrintf(GTestColor::kYellow, " YOU HAVE %d DISABLED %s\n\n", + num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); @@ -4958,6 +5279,110 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // End PrettyUnitTestResultPrinter +// This class implements the TestEventListener interface. +// +// Class BriefUnitTestResultPrinter is copyable. +class BriefUnitTestResultPrinter : public TestEventListener { + public: + BriefUnitTestResultPrinter() {} + static void PrintTestName(const char* test_suite, const char* test) { + printf("%s.%s", test_suite, test); + } + + // The following methods override what's in the TestEventListener class. + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#else + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo& /*test_info*/) override {} + + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#else + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} +}; + +// Called after an assertion failure. +void BriefUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + switch (result.type()) { + // If the test part succeeded, we don't need to do anything. + case TestPartResult::kSuccess: + return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } +} + +void BriefUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Failed()) { + ColoredPrintf(GTestColor::kRed, "[ FAILED ] "); + PrintTestName(test_info.test_suite_name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", + internal::StreamableToString(test_info.result()->elapsed_time()) + .c_str()); + } else { + printf("\n"); + } + fflush(stdout); + } +} + +void BriefUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(GTestColor::kGreen, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(GTestColor::kGreen, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] "); + printf("%s.\n", FormatTestCount(skipped_test_count).c_str()); + } + + int num_disabled = unit_test.reportable_disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (unit_test.Passed()) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(GTestColor::kYellow, " YOU HAVE %d DISABLED %s\n\n", + num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End BriefUnitTestResultPrinter + // class TestEventRepeater // // This class forwards events to other event listeners. @@ -5141,6 +5566,10 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + // Streams an XML representation of a TestResult object. + static void OutputXmlTestResult(::std::ostream* stream, + const TestResult& result); + // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_suite_name, @@ -5312,13 +5741,14 @@ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { struct tm time_struct; if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) return ""; - // YYYY-MM-DDThh:mm:ss + // YYYY-MM-DDThh:mm:ss.sss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct.tm_mday) + "T" + String::FormatIntWidth2(time_struct.tm_hour) + ":" + String::FormatIntWidth2(time_struct.tm_min) + ":" + - String::FormatIntWidth2(time_struct.tm_sec); + String::FormatIntWidth2(time_struct.tm_sec) + "." + + String::FormatIntWidthN(static_cast(ms % 1000), 3); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -5400,11 +5830,17 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); + OutputXmlTestResult(stream, result); +} + +void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream, + const TestResult& result) { int failures = 0; + int skips = 0; for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { - if (++failures == 1) { + if (++failures == 1 && skips == 0) { *stream << ">\n"; } const std::string location = @@ -5412,18 +5848,31 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, part.line_number()); const std::string summary = location + "\n" + part.summary(); *stream << " "; const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; + } else if (part.skipped()) { + if (++skips == 1 && failures == 0) { + *stream << ">\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); + *stream << " "; + const std::string detail = location + "\n" + part.message(); + OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); + *stream << "\n"; } } - if (failures == 0 && result.test_property_count() == 0) { + if (failures == 0 && skips == 0 && result.test_property_count() == 0) { *stream << " />\n"; } else { - if (failures == 0) { + if (failures == 0 && skips == 0) { *stream << ">\n"; } OutputXmlTestProperties(stream, result); @@ -5452,7 +5901,11 @@ void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_suite.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "skipped", + StreamableToString(test_suite.skipped_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); OutputXmlAttribute( @@ -5600,6 +6053,10 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { const std::string& indent, bool comma = true); + // Streams a JSON representation of a TestResult object. + static void OutputJsonTestResult(::std::ostream* stream, + const TestResult& result); + // Streams a JSON representation of a TestInfo object. static void OutputJsonTestInfo(::std::ostream* stream, const char* test_suite_name, @@ -5792,6 +6249,13 @@ void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, false); *stream << TestPropertiesAsJson(result, kIndent); + OutputJsonTestResult(stream, result); +} + +void JsonUnitTestResultPrinter::OutputJsonTestResult(::std::ostream* stream, + const TestResult& result) { + const std::string kIndent = Indent(10); + int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); @@ -6110,6 +6574,7 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { +#if !defined GTEST_OS_ESP8266 if (!premature_exit_filepath_.empty() && rank_ == 0) { int retval = remove(premature_exit_filepath_.c_str()); if (retval) { @@ -6118,6 +6583,7 @@ class ScopedPrematureExitFile { << retval; } } +#endif } private: @@ -6511,7 +6977,6 @@ int UnitTest::Run() { _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -# endif // In debug mode, the Windows CRT can crash with an assertion over invalid // input (e.g. passing an invalid file descriptor). The default handling @@ -6522,6 +6987,7 @@ int UnitTest::Run() { _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); } +# endif } #endif // GTEST_OS_WINDOWS @@ -6802,10 +7268,10 @@ class TestSuiteNameIs { // Arguments: // // test_suite_name: name of the test suite -// type_param: the name of the test suite's type parameter, or NULL if -// this is not a typed or a type-parameterized test suite. -// set_up_tc: pointer to the function that sets up the test suite -// tear_down_tc: pointer to the function that tears down the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite TestSuite* UnitTestImpl::GetTestSuite( const char* test_suite_name, const char* type_param, internal::SetUpTestSuiteFunc set_up_tc, @@ -6923,11 +7389,11 @@ bool UnitTestImpl::RunAllTests() { // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); - const TimeInMillis start = GetTimeInMillis(); + Timer timer; // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(static_cast(random_seed_)); + random()->Reseed(static_cast(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. @@ -6964,6 +7430,21 @@ bool UnitTestImpl::RunAllTests() { for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { GetMutableSuiteCase(test_index)->Run(); + if (GTEST_FLAG(fail_fast) && + GetMutableSuiteCase(test_index)->Failed()) { + for (int j = test_index + 1; j < total_test_suite_count(); j++) { + GetMutableSuiteCase(j)->Skip(); + } + break; + } + } + } else if (Test::HasFatalFailure()) { + // If there was a fatal failure during the global setup then we know we + // aren't going to run any tests. Explicitly mark all of the tests as + // skipped to make this obvious in the output. + for (int test_index = 0; test_index < total_test_suite_count(); + test_index++) { + GetMutableSuiteCase(test_index)->Skip(); } } @@ -6974,7 +7455,7 @@ bool UnitTestImpl::RunAllTests() { repeater->OnEnvironmentsTearDownEnd(*parent_); } - elapsed_time_ = GetTimeInMillis() - start; + elapsed_time_ = timer.Elapsed(); // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); @@ -7010,14 +7491,14 @@ bool UnitTestImpl::RunAllTests() { #endif if (!gtest_is_initialized_before_run_all_tests) { ColoredPrintf( - COLOR_RED, + GTestColor::kRed, "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ " will start to enforce the valid usage. " "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT #if GTEST_FOR_GOOGLE_ - ColoredPrintf(COLOR_RED, + ColoredPrintf(GTestColor::kRed, "For more details, see http://wiki/Main/ValidGUnitMain.\n"); #endif // GTEST_FOR_GOOGLE_ } @@ -7043,7 +7524,7 @@ void WriteToShardStatusFileIfNeeded() { if (test_shard_file != nullptr) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == nullptr) { - ColoredPrintf(COLOR_RED, + ColoredPrintf(GTestColor::kRed, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); @@ -7067,8 +7548,8 @@ bool ShouldShard(const char* total_shards_env, return false; } - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + const int32_t total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const int32_t shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; @@ -7077,7 +7558,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { @@ -7085,7 +7566,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { @@ -7094,7 +7575,7 @@ bool ShouldShard(const char* total_shards_env, << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } @@ -7105,13 +7586,13 @@ bool ShouldShard(const char* total_shards_env, // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. -Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { +int32_t Int32FromEnvOrDie(const char* var, int32_t default_val) { const char* str_val = posix::GetEnv(var); if (str_val == nullptr) { return default_val; } - Int32 result; + int32_t result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); @@ -7135,9 +7616,9 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md // . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + const int32_t total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will @@ -7426,12 +7907,11 @@ static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { return true; } -// Parses a string for an Int32 flag, in the form of -// "--flag=value". +// Parses a string for an int32_t flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { +bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -7443,8 +7923,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { value_str, value); } -// Parses a string for a string flag, in the form of -// "--flag=value". +// Parses a string for a string flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. @@ -7486,7 +7965,7 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @D changes to the default terminal text color. // static void PrintColorEncoded(const char* str) { - GTestColor color = COLOR_DEFAULT; // The current color. + GTestColor color = GTestColor::kDefault; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of @@ -7506,13 +7985,13 @@ static void PrintColorEncoded(const char* str) { if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { - color = COLOR_DEFAULT; + color = GTestColor::kDefault; } else if (ch == 'R') { - color = COLOR_RED; + color = GTestColor::kRed; } else if (ch == 'G') { - color = COLOR_GREEN; + color = GTestColor::kGreen; } else if (ch == 'Y') { - color = COLOR_YELLOW; + color = GTestColor::kYellow; } else { --str; } @@ -7520,98 +7999,126 @@ static void PrintColorEncoded(const char* str) { } static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "This program contains tests written using " GTEST_NAME_ + ". You can use the\n" + "following command line flags to control its behavior:\n" + "\n" + "Test Selection:\n" + " @G--" GTEST_FLAG_PREFIX_ + "list_tests@D\n" + " List the names of all tests instead of running them. The name of\n" + " TEST(Foo, Bar) is \"Foo.Bar\".\n" + " @G--" GTEST_FLAG_PREFIX_ + "filter=@YPOSITIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate a JSON or XML report in the given directory or with the given\n" -" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" + " Run only the tests whose name matches one of the positive patterns " + "but\n" + " none of the negative patterns. '?' matches any single character; " + "'*'\n" + " matches any substring; ':' separates two patterns.\n" + " @G--" GTEST_FLAG_PREFIX_ + "also_run_disabled_tests@D\n" + " Run all disabled tests too.\n" + "\n" + "Test Execution:\n" + " @G--" GTEST_FLAG_PREFIX_ + "repeat=@Y[COUNT]@D\n" + " Run the tests repeatedly; use a negative count to repeat forever.\n" + " @G--" GTEST_FLAG_PREFIX_ + "shuffle@D\n" + " Randomize tests' orders on every iteration.\n" + " @G--" GTEST_FLAG_PREFIX_ + "random_seed=@Y[NUMBER]@D\n" + " Random number seed to use for shuffling test orders (between 1 and\n" + " 99999, or 0 to use a seed based on the current time).\n" + "\n" + "Test Output:\n" + " @G--" GTEST_FLAG_PREFIX_ + "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" + " Enable/disable colored output. The default is @Gauto@D.\n" + " @G--" GTEST_FLAG_PREFIX_ + "brief=1@D\n" + " Only print test failures.\n" + " @G--" GTEST_FLAG_PREFIX_ + "print_time=0@D\n" + " Don't print the elapsed time of each test.\n" + " @G--" GTEST_FLAG_PREFIX_ + "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ + "@Y|@G:@YFILE_PATH]@D\n" + " Generate a JSON or XML report in the given directory or with the " + "given\n" + " file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" # if GTEST_CAN_STREAM_RESULTS_ -" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" -" Stream test results to the given server.\n" + " @G--" GTEST_FLAG_PREFIX_ + "stream_result_to=@YHOST@G:@YPORT@D\n" + " Stream test results to the given server.\n" # endif // GTEST_CAN_STREAM_RESULTS_ -"\n" -"Assertion Behavior:\n" + "\n" + "Assertion Behavior:\n" # if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" + " @G--" GTEST_FLAG_PREFIX_ + "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" + " Set the default death test style.\n" # endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions for use by an external\n" -" test framework.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" -" Do not report exceptions as test failures. Instead, allow them\n" -" to crash the program or throw a pop-up (on Windows).\n" -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + " @G--" GTEST_FLAG_PREFIX_ + "break_on_failure@D\n" + " Turn assertion failures into debugger break-points.\n" + " @G--" GTEST_FLAG_PREFIX_ + "throw_on_failure@D\n" + " Turn assertion failures into C++ exceptions for use by an external\n" + " test framework.\n" + " @G--" GTEST_FLAG_PREFIX_ + "catch_exceptions=0@D\n" + " Do not report exceptions as test failures. Instead, allow them\n" + " to crash the program or throw a pop-up (on Windows).\n" + "\n" + "Except for @G--" GTEST_FLAG_PREFIX_ + "list_tests@D, you can alternatively set " "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "environment variable of a flag (all letters in upper-case). For example, " + "to\n" + "disable colored text output, you can either specify " + "@G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + "the @G" GTEST_FLAG_PREFIX_UPPER_ + "COLOR@D environment variable to @Gno@D.\n" + "\n" + "For more information, please read the " GTEST_NAME_ + " documentation at\n" + "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ + "\n" + "(not one in your own code or tests), please report it to\n" + "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; static bool ParseGoogleTestFlag(const char* const arg) { return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)); + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseBoolFlag(arg, kFailFast, >EST_FLAG(fail_fast)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kBriefFlag, >EST_FLAG(brief)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)); } #if GTEST_USE_OWN_FLAGFILE_FLAG_ @@ -7828,20 +8335,31 @@ void InitGoogleTest() { std::string TempDir() { #if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); -#endif - -#if GTEST_OS_WINDOWS_MOBILE +#elif GTEST_OS_WINDOWS_MOBILE return "\\temp\\"; #elif GTEST_OS_WINDOWS const char* temp_dir = internal::posix::GetEnv("TEMP"); - if (temp_dir == nullptr || temp_dir[0] == '\0') + if (temp_dir == nullptr || temp_dir[0] == '\0') { return "\\temp\\"; - else if (temp_dir[strlen(temp_dir) - 1] == '\\') + } else if (temp_dir[strlen(temp_dir) - 1] == '\\') { return temp_dir; - else + } else { return std::string(temp_dir) + "\\"; + } #elif GTEST_OS_LINUX_ANDROID - return "/sdcard/"; + const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR"); + if (temp_dir == nullptr || temp_dir[0] == '\0') { + return "/data/local/tmp/"; + } else { + return temp_dir; + } +#elif GTEST_OS_LINUX + const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR"); + if (temp_dir == nullptr || temp_dir[0] == '\0') { + return "/tmp/"; + } else { + return temp_dir; + } #else return "/tmp/"; #endif // GTEST_OS_WINDOWS_MOBILE @@ -7900,6 +8418,7 @@ ScopedTrace::~ScopedTrace() // This file implements death tests. +#include #include @@ -8110,7 +8629,7 @@ static std::string DeathTestThreadWarning(size_t thread_count) { msg << "detected " << thread_count << " threads."; } msg << " See " - "https://github.com/google/googletest/blob/master/googletest/docs/" + "https://github.com/google/googletest/blob/master/docs/" "advanced.md#death-tests-and-threads" << " for more explanation and suggested solutions, especially if" << " this is the last message you see before your test times out."; @@ -8753,18 +9272,17 @@ int FuchsiaDeathTest::Wait() { // Register to wait for the child process to terminate. status_zx = child_process_.wait_async( - port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); + port, kProcessKey, ZX_PROCESS_TERMINATED, 0); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for the socket to be readable or closed. status_zx = stderr_socket_.wait_async( - port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, - ZX_WAIT_ASYNC_ONCE); + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for an exception. status_zx = exception_channel_.wait_async( - port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + port, kExceptionKey, ZX_CHANNEL_READABLE, 0); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); bool process_terminated = false; @@ -8804,8 +9322,7 @@ int FuchsiaDeathTest::Wait() { } else { GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); status_zx = stderr_socket_.wait_async( - port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, - ZX_WAIT_ASYNC_ONCE); + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); } } else { @@ -9088,21 +9605,9 @@ struct ExecDeathTestArgs { int close_fd; // File descriptor to close; the read end of a pipe }; -# if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -# else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. +# if GTEST_OS_QNX extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC - -# if !GTEST_OS_QNX +# else // GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. @@ -9122,18 +9627,18 @@ static int ExecDeathTestChildMain(void* child_arg) { return EXIT_FAILURE; } - // We can safely call execve() as it's a direct system call. We + // We can safely call execv() as it's almost a direct system call. We // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must + // unsafe. Since execv() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + execv(args->argv[0], args->argv); + DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } -# endif // !GTEST_OS_QNX +# endif // GTEST_OS_QNX # if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack @@ -9147,19 +9652,24 @@ static int ExecDeathTestChildMain(void* child_arg) { // correct answer. static void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; +// Make sure sanitizers do not tamper with the stack here. +// Ideally, we want to use `__builtin_frame_address` instead of a local variable +// address with sanitizer disabled, but it does not work when the +// compiler optimizes the stack frame out, which happens on PowerPC targets. // HWAddressSanitizer add a random tag to the MSB of the local variable address, // making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static void StackLowerThanAddress(const void* ptr, bool* result) { - int dummy; - *result = (&dummy < ptr); + int dummy = 0; + *result = std::less()(&dummy, ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static bool StackGrowsDown() { - int dummy; + int dummy = 0; bool result; StackLowerThanAddress(&dummy, &result); return result; @@ -9202,8 +9712,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. - child_pid = - spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); + child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); @@ -9227,7 +9736,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); - const auto stack_size = static_cast(getpagesize()); + const auto stack_size = static_cast(getpagesize() * 2); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); @@ -9605,7 +10114,7 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ - GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM) + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); @@ -9850,6 +10359,9 @@ bool FilePath::CreateFolder() const { delete [] unicode; #elif GTEST_OS_WINDOWS result = _mkdir(pathname_.c_str()); +#elif GTEST_OS_ESP8266 + // do nothing + int result = 0; #else result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE @@ -9877,33 +10389,19 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". void FilePath::Normalize() { - if (pathname_.c_str() == nullptr) { - pathname_ = ""; - return; - } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.length() + 1); + auto out = pathname_.begin(); - while (*src != '\0') { - *dest_ptr = *src; - if (!IsPathSeparator(*src)) { - src++; + for (const char character : pathname_) { + if (!IsPathSeparator(character)) { + *(out++) = character; + } else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) { + *(out++) = kPathSeparator; } else { -#if GTEST_HAS_ALT_PATH_SEP_ - if (*dest_ptr == kAlternatePathSeparator) { - *dest_ptr = kPathSeparator; - } -#endif - while (IsPathSeparator(*src)) - src++; + continue; } - dest_ptr++; } - *dest_ptr = '\0'; - pathname_ = dest; - delete[] dest; + + pathname_.erase(out, pathname_.end()); } } // namespace internal @@ -9965,41 +10463,41 @@ Matcher::Matcher(const std::string& s) { *this = Eq(s); } // s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } -#if GTEST_HAS_ABSL -// Constructs a matcher that matches a const absl::string_view& whose value is +#if GTEST_INTERNAL_HAS_STRING_VIEW +// Constructs a matcher that matches a const StringView& whose value is // equal to s. -Matcher::Matcher(const std::string& s) { +Matcher::Matcher(const std::string& s) { *this = Eq(s); } -// Constructs a matcher that matches a const absl::string_view& whose value is +// Constructs a matcher that matches a const StringView& whose value is // equal to s. -Matcher::Matcher(const char* s) { +Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } -// Constructs a matcher that matches a const absl::string_view& whose value is +// Constructs a matcher that matches a const StringView& whose value is // equal to s. -Matcher::Matcher(absl::string_view s) { +Matcher::Matcher(internal::StringView s) { *this = Eq(std::string(s)); } -// Constructs a matcher that matches a absl::string_view whose value is equal to +// Constructs a matcher that matches a StringView whose value is equal to // s. -Matcher::Matcher(const std::string& s) { *this = Eq(s); } +Matcher::Matcher(const std::string& s) { *this = Eq(s); } -// Constructs a matcher that matches a absl::string_view whose value is equal to +// Constructs a matcher that matches a StringView whose value is equal to // s. -Matcher::Matcher(const char* s) { +Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } -// Constructs a matcher that matches a absl::string_view whose value is equal to +// Constructs a matcher that matches a StringView whose value is equal to // s. -Matcher::Matcher(absl::string_view s) { +Matcher::Matcher(internal::StringView s) { *this = Eq(std::string(s)); } -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_STRING_VIEW } // namespace testing // Copyright 2008, Google Inc. @@ -10037,6 +10535,7 @@ Matcher::Matcher(absl::string_view s) { #include #include #include +#include #include #include @@ -10195,7 +10694,8 @@ size_t GetThreadCount() { if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { return 0; } - mib[5] = size / mib[4]; + + mib[5] = static_cast(size / static_cast(mib[4])); // populate array of structs struct kinfo_proc info[mib[5]]; @@ -10204,8 +10704,8 @@ size_t GetThreadCount() { } // exclude empty members - int nthreads = 0; - for (int i = 0; i < size / mib[4]; i++) { + size_t nthreads = 0; + for (size_t i = 0; i < size / static_cast(mib[4]); i++) { if (info[i].p_tid != -1) nthreads++; } @@ -10534,6 +11034,9 @@ class ThreadLocalRegistryImpl { // Returns a value that can be used to identify the thread from other threads. static ThreadLocalValueHolderBase* GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance) { +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER DWORD current_thread = ::GetCurrentThreadId(); MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = @@ -11284,7 +11787,7 @@ static std::string FlagToEnvVar(const char* flag) { // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { +bool ParseInt32(const Message& src_text, const char* str, int32_t* value) { // Parses the environment variable as a decimal integer. char* end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT @@ -11301,13 +11804,13 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { return false; } - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); + // Is the parsed value in the range of an int32_t? + const auto result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value - // The parsed value overflows as an Int32. + // The parsed value overflows as an int32_t. ) { Message msg; msg << "WARNING: " << src_text @@ -11340,7 +11843,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +int32_t Int32FromGTestEnv(const char* flag, int32_t default_value) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); #else @@ -11351,7 +11854,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { return default_value; } - Int32 result = default_value; + int32_t result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", @@ -11440,6 +11943,7 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) { #include #include +#include #include #include // NOLINT #include @@ -11498,7 +12002,7 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, } // namespace -namespace internal2 { +namespace internal { // Delegates to PrintBytesInObjectToImpl() to print the bytes in the // given object. The delegation simplifies the implementation, which @@ -11510,10 +12014,6 @@ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, PrintBytesInObjectToImpl(obj_bytes, count, os); } -} // namespace internal2 - -namespace internal { - // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), @@ -11649,6 +12149,11 @@ void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } +void PrintTo(char32_t c, ::std::ostream* os) { + *os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4) + << static_cast(c); +} + // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters @@ -11867,6 +12372,7 @@ void PrintWideStringTo(const ::std::wstring& s, ostream* os) { // The Google C++ Testing and Mocking Framework (Google Test) + namespace testing { using internal::GetUnitTestImpl; @@ -11880,7 +12386,9 @@ std::string TestPartResult::ExtractSummary(const char* message) { // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os << result.file_name() << ":" << result.line_number() << ": " + return os << internal::FormatFileLocation(result.file_name(), + result.line_number()) + << " " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kSkip @@ -11971,8 +12479,6 @@ void HasNewFatalFailureHelper::ReportTestPartResult( namespace testing { namespace internal { -#if GTEST_HAS_TYPED_TEST_P - // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { @@ -11994,7 +12500,10 @@ static std::vector SplitIntoTestNames(const char* src) { // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestSuitePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { + const char* test_suite_name, const char* file, int line, + const char* registered_tests) { + RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line)); + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; @@ -12011,17 +12520,7 @@ const char* TypedTestSuitePState::VerifyRegisteredTestNames( continue; } - bool found = false; - for (RegisteredTestIter it = registered_tests_.begin(); - it != registered_tests_.end(); - ++it) { - if (name == it->first) { - found = true; - break; - } - } - - if (found) { + if (registered_tests_.count(name) != 0) { tests.insert(name); } else { errors << "No test named " << name @@ -12048,7 +12547,5 @@ const char* TypedTestSuitePState::VerifyRegisteredTestNames( return registered_tests; } -#endif // GTEST_HAS_TYPED_TEST_P - } // namespace internal } // namespace testing diff --git a/thirdparty/googletest-mpi/gtest/gtest.h b/thirdparty/googletest-mpi/gtest/gtest.h index 9ac2c2a229..60a6c18ec8 100644 --- a/thirdparty/googletest-mpi/gtest/gtest.h +++ b/thirdparty/googletest-mpi/gtest/gtest.h @@ -49,8 +49,8 @@ // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_ // Some MPI vendors require the mpi.h to be included before anything else, // hence we need to include the gtest-mpi header (that - if enabled - includes mpi.h) first. @@ -160,8 +160,8 @@ // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. @@ -205,8 +205,8 @@ // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // Environment-describing macros // ----------------------------- @@ -357,13 +357,27 @@ // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. -// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_ASSIGN_ - disables copy operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_DISALLOW_MOVE_ASSIGN_ - disables move operator=. +// GTEST_DISALLOW_MOVE_AND_ASSIGN_ - disables move ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. +// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter or +// UniversalPrinter specializations. +// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter +// or +// UniversalPrinter +// specializations. +// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or +// Matcher +// specializations. +// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter or +// UniversalPrinter +// specializations. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() @@ -390,8 +404,7 @@ // // Integer types: // TypeWithSize - maps an integer to a int type. -// Int32, UInt32, Int64, UInt64, TimeInMillis -// - integers of known sizes. +// TimeInMillis - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: @@ -402,7 +415,7 @@ // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. -// Int32FromGTestEnv() - parses an Int32 environment variable. +// Int32FromGTestEnv() - parses an int32_t environment variable. // StringFromGTestEnv() - parses a string environment variable. // // Deprecation warnings: @@ -420,7 +433,10 @@ #include #include #include -#include + +#include +#include +#include #include #ifndef _WIN32_WCE @@ -433,14 +449,50 @@ # include #endif -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT +#include // NOLINT +#include +#include +#include // NOLINT #include -#include #include // NOLINT +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ // Copyright 2015, Google Inc. // All rights reserved. // @@ -475,8 +527,8 @@ // This header file defines the GTEST_OS_* macro. // It is separate from gtest-port.h so that custom/gtest-port.h can include it. -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ @@ -511,6 +563,7 @@ # define GTEST_OS_OS2 1 #elif defined __APPLE__ # define GTEST_OS_MAC 1 +# include # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # endif @@ -545,46 +598,13 @@ # define GTEST_OS_QNX 1 #elif defined(__HAIKU__) #define GTEST_OS_HAIKU 1 +#elif defined ESP8266 +#define GTEST_OS_ESP8266 1 +#elif defined ESP32 +#define GTEST_OS_ESP32 1 #endif // __CYGWIN__ -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Injection point for custom user configurations. See README for details -// -// ** Custom implementation starts here ** - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ #if !defined(GTEST_DEV_EMAIL_) # define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" @@ -755,15 +775,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS -#if !defined(GTEST_HAS_STD_STRING) -// Even though we don't use this macro any longer, we keep it in case -// some clients still depend on it. -# define GTEST_HAS_STD_STRING 1 -#elif !GTEST_HAS_STD_STRING -// The user told us that ::std::string isn't available. -# error "::std::string isn't available." -#endif // !defined(GTEST_HAS_STD_STRING) - #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. @@ -772,7 +783,7 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // no support for it at least as recent as Froyo (2.2). #define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - GTEST_OS_HAIKU)) + GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266)) #endif // GTEST_HAS_STD_WSTRING @@ -896,7 +907,8 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 @@ -992,16 +1004,27 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #endif -// A macro to disallow operator= +// A macro to disallow copy operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type) \ - void operator=(type const &) = delete + type& operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ - type(type const &) = delete; \ - GTEST_DISALLOW_ASSIGN_(type) + type(type const&) = delete; \ + type& operator=(type const&) = delete + +// A macro to disallow move operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_ASSIGN_(type) \ + type& operator=(type &&) noexcept = delete + +// A macro to disallow move constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_AND_ASSIGN_(type) \ + type(type&&) noexcept = delete; \ + type& operator=(type&&) noexcept = delete // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations @@ -1172,9 +1195,6 @@ class Secret; // expression is false, compiler will issue an error containing this identifier. #define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -// Evaluates to the number of elements in 'array'. -#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) - // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); @@ -1231,8 +1251,6 @@ class GTEST_API_ RE { const char* full_pattern_; // For FullMatch(); # endif - - GTEST_DISALLOW_ASSIGN_(RE); }; #endif // GTEST_USES_PCRE @@ -1915,7 +1933,7 @@ class ThreadLocal : public ThreadLocalBase { class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); @@ -1924,7 +1942,7 @@ class ThreadLocal : public ThreadLocalBase { class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} - virtual ValueHolder* MakeNewHolder() const { + ValueHolder* MakeNewHolder() const override { return new ValueHolder(value_); } @@ -2124,7 +2142,7 @@ class GTEST_API_ ThreadLocal { class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); @@ -2133,7 +2151,7 @@ class GTEST_API_ ThreadLocal { class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} - virtual ValueHolder* MakeNewHolder() const { + ValueHolder* MakeNewHolder() const override { return new ValueHolder(value_); } @@ -2203,18 +2221,12 @@ class GTEST_API_ ThreadLocal { // we cannot detect it. GTEST_API_ size_t GetThreadCount(); -template -using bool_constant = std::integral_constant; - #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 -// The biggest signed integer type the compiler supports. -typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 -typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. @@ -2279,16 +2291,16 @@ namespace posix { typedef struct _stat StatStruct; # ifdef __BORLANDC__ -inline int IsATTY(int fd) { return isatty(fd); } +inline int DoIsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE -inline int IsATTY(int /* fd */) { return 0; } +inline int DoIsATTY(int /* fd */) { return 0; } # else -inline int IsATTY(int fd) { return _isatty(fd); } +inline int DoIsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); @@ -2309,12 +2321,28 @@ inline bool IsDir(const StatStruct& st) { } # endif // GTEST_OS_WINDOWS_MOBILE +#elif GTEST_OS_ESP8266 +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int DoIsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { + // stat function not implemented on ESP8266 + return 0; +} +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } +inline int DoIsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); @@ -2325,14 +2353,21 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS +inline int IsATTY(int fd) { + // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout + // to a file on Linux), which is unexpected, so save the previous value, and + // restore it after the call. + int savedErrno = errno; + int isAttyValue = DoIsATTY(fd); + errno = savedErrno; + + return isAttyValue; +} + // Functions deprecated by MSVC 8.0. GTEST_DISABLE_MSC_DEPRECATED_PUSH_() -inline const char* StrNCpy(char* dest, const char* src, size_t n) { - return strncpy(dest, src, n); -} - // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. @@ -2341,7 +2376,15 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) { inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + struct wchar_codecvt : public std::codecvt {}; + std::wstring_convert converter; + std::wstring wide_path = converter.from_bytes(path); + std::wstring wide_mode = converter.from_bytes(mode); + return _wfopen(wide_path.c_str(), wide_mode.c_str()); +#else // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW return fopen(path, mode); +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { @@ -2361,8 +2404,9 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - // We are on Windows CE, which has no environment variables. +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 + // We are on an embedded platform, which has no environment variables. static_cast(name); // To prevent 'unused argument' warning. return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) @@ -2404,15 +2448,13 @@ GTEST_DISABLE_MSC_DEPRECATED_POP_() # define GTEST_SNPRINTF_ snprintf #endif -// The maximum number a BiggestInt can represent. This definition -// works no matter BiggestInt is represented in one's complement or -// two's complement. +// The biggest signed integer type the compiler supports. // -// We cannot rely on numeric_limits in STL, as __int64 and long long -// are not part of standard C++ and numeric_limits doesn't need to be -// defined for them. -const BiggestInt kMaxBiggestInt = - ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); +// long long is guaranteed to be at least 64-bits in C++11. +using BiggestInt = long long; // NOLINT + +// The maximum number a BiggestInt can represent. +constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits::max)(); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that @@ -2437,40 +2479,27 @@ class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. - typedef void UInt; + using UInt = void; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: - // unsigned int has size 4 in both gcc and MSVC. - // - // As base/basictypes.h doesn't compile on Windows, we cannot use - // uint32, uint64, and etc here. - typedef int Int; - typedef unsigned int UInt; + using Int = std::int32_t; + using UInt = std::uint32_t; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: -#if GTEST_OS_WINDOWS - typedef __int64 Int; - typedef unsigned __int64 UInt; -#else - typedef long long Int; // NOLINT - typedef unsigned long long UInt; // NOLINT -#endif // GTEST_OS_WINDOWS + using Int = std::int64_t; + using UInt = std::uint64_t; }; // Integer types of known sizes. -typedef TypeWithSize<4>::Int Int32; -typedef TypeWithSize<4>::UInt UInt32; -typedef TypeWithSize<8>::Int Int64; -typedef TypeWithSize<8>::UInt UInt64; -typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. +using TimeInMillis = int64_t; // Represents time in milliseconds. // Utilities for command line flags and environment variables. @@ -2489,7 +2518,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Macros for declaring flags. # define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) # define GTEST_DECLARE_int32_(name) \ - GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) + GTEST_API_ extern std::int32_t GTEST_FLAG(name) # define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) @@ -2497,7 +2526,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. # define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) # define GTEST_DEFINE_int32_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) + GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val) # define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) @@ -2512,12 +2541,13 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value); +GTEST_API_ bool ParseInt32(const Message& src_text, const char* str, + int32_t* value); -// Parses a bool/Int32/string from the environment variable +// Parses a bool/int32_t/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); -GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +GTEST_API_ int32_t Int32FromGTestEnv(const char* flag, int32_t default_val); std::string OutputFlagAlsoCheckEnvVar(); const char* StringFromGTestEnv(const char* flag, const char* default_val); @@ -2544,7 +2574,122 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); #endif // !defined(GTEST_INTERNAL_DEPRECATED) -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#if GTEST_HAS_ABSL +// Always use absl::any for UniversalPrinter<> specializations if googletest +// is built with absl support. +#define GTEST_INTERNAL_HAS_ANY 1 +#include "absl/types/any.h" +namespace testing { +namespace internal { +using Any = ::absl::any; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::any for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_ANY 1 +#include +namespace testing { +namespace internal { +using Any = ::std::any; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::any is not +// supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::optional for UniversalPrinter<> specializations if +// googletest is built with absl support. +#define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include "absl/types/optional.h" +namespace testing { +namespace internal { +template +using Optional = ::absl::optional; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include +namespace testing { +namespace internal { +template +using Optional = ::std::optional; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::optional is not +// supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::string_view for Matcher<> specializations if googletest +// is built with absl support. +# define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include "absl/strings/string_view.h" +namespace testing { +namespace internal { +using StringView = ::absl::string_view; +} // namespace internal +} // namespace testing +#else +# ifdef __has_include +# if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::string_view for Matcher<> +// specializations. +# define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include +namespace testing { +namespace internal { +using StringView = ::std::string_view; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::string_view is not +// supported. +# endif // __has_include() && __cplusplus >= 201703L +# endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::variant for UniversalPrinter<> specializations if googletest +// is built with absl support. +#define GTEST_INTERNAL_HAS_VARIANT 1 +#include "absl/types/variant.h" +namespace testing { +namespace internal { +template +using Variant = ::absl::variant; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_VARIANT 1 +#include +namespace testing { +namespace internal { +template +using Variant = ::std::variant; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::variant is not supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #if GTEST_OS_LINUX # include @@ -2560,6 +2705,7 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); #include #include #include +#include #include #include #include @@ -2614,11 +2760,12 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include #include +#include GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ @@ -2784,7 +2931,7 @@ std::string StreamableToString(const T& streamable) { GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 -#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ // Copyright 2008, Google Inc. // All rights reserved. // @@ -2824,8 +2971,8 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // Copyright 2005, Google Inc. // All rights reserved. @@ -2867,8 +3014,8 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. @@ -2876,6 +3023,7 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif #include +#include #include @@ -2979,11 +3127,14 @@ class GTEST_API_ String { // Formats an int value as "%d". static std::string FormatInt(int value); + // Formats an int value to given width with leading zeros. + static std::string FormatIntWidthN(int value, int width); + // Formats an int value as "%X". static std::string FormatHexInt(int value); // Formats an int value as "%X". - static std::string FormatHexUInt32(UInt32 value); + static std::string FormatHexUInt32(uint32_t value); // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); @@ -2999,7 +3150,7 @@ GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) @@ -3167,11 +3318,7 @@ class GTEST_API_ FilePath { GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -// This file was GENERATED by command: -// pump.py gtest-type-util.h.pump -// DO NOT EDIT BY HAND!!! - +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // Copyright 2008 Google Inc. // All Rights Reserved. // @@ -3202,17 +3349,12 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test suite. -// Please contact googletestframework@googlegroups.com if you need -// more. +// tests. // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // #ifdef __GNUC__ is too general here. It is possible to use gcc without using @@ -3242,1556 +3384,43 @@ inline std::string CanonicalizeForStdLibVersioning(std::string s) { return s; } -// GetTypeName() returns a human-readable name of type T. -// NB: This function is also used in Google Mock, so don't move it inside of -// the typed-test-only section below. -template -std::string GetTypeName() { -# if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) +#if GTEST_HAS_RTTI +// GetTypeName(const std::type_info&) returns a human-readable name of type T. +inline std::string GetTypeName(const std::type_info& type) { + const char* const name = type.name(); +#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ +#if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ +#endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return CanonicalizeForStdLibVersioning(name_str); -# else +#else return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC - -# else +#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC +} +#endif // GTEST_HAS_RTTI +// GetTypeName() returns a human-readable name of type T if and only if +// RTTI is enabled, otherwise it returns a dummy type name. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +#if GTEST_HAS_RTTI + return GetTypeName(typeid(T)); +#else return ""; - -# endif // GTEST_HAS_RTTI +#endif // GTEST_HAS_RTTI } -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. +// A unique type indicating an empty node struct None {}; -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; -template -struct Types2 { - typedef T1 Head; - typedef Types1 Tail; -}; - -template -struct Types3 { - typedef T1 Head; - typedef Types2 Tail; -}; - -template -struct Types4 { - typedef T1 Head; - typedef Types3 Tail; -}; - -template -struct Types5 { - typedef T1 Head; - typedef Types4 Tail; -}; - -template -struct Types6 { - typedef T1 Head; - typedef Types5 Tail; -}; - -template -struct Types7 { - typedef T1 Head; - typedef Types6 Tail; -}; - -template -struct Types8 { - typedef T1 Head; - typedef Types7 Tail; -}; - -template -struct Types9 { - typedef T1 Head; - typedef Types8 Tail; -}; - -template -struct Types10 { - typedef T1 Head; - typedef Types9 Tail; -}; - -template -struct Types11 { - typedef T1 Head; - typedef Types10 Tail; -}; - -template -struct Types12 { - typedef T1 Head; - typedef Types11 Tail; -}; - -template -struct Types13 { - typedef T1 Head; - typedef Types12 Tail; -}; - -template -struct Types14 { - typedef T1 Head; - typedef Types13 Tail; -}; - -template -struct Types15 { - typedef T1 Head; - typedef Types14 Tail; -}; - -template -struct Types16 { - typedef T1 Head; - typedef Types15 Tail; -}; - -template -struct Types17 { - typedef T1 Head; - typedef Types16 Tail; -}; - -template -struct Types18 { - typedef T1 Head; - typedef Types17 Tail; -}; - -template -struct Types19 { - typedef T1 Head; - typedef Types18 Tail; -}; - -template -struct Types20 { - typedef T1 Head; - typedef Types19 Tail; -}; - -template -struct Types21 { - typedef T1 Head; - typedef Types20 Tail; -}; - -template -struct Types22 { - typedef T1 Head; - typedef Types21 Tail; -}; - -template -struct Types23 { - typedef T1 Head; - typedef Types22 Tail; -}; - -template -struct Types24 { - typedef T1 Head; - typedef Types23 Tail; -}; - -template -struct Types25 { - typedef T1 Head; - typedef Types24 Tail; -}; - -template -struct Types26 { - typedef T1 Head; - typedef Types25 Tail; -}; - -template -struct Types27 { - typedef T1 Head; - typedef Types26 Tail; -}; - -template -struct Types28 { - typedef T1 Head; - typedef Types27 Tail; -}; - -template -struct Types29 { - typedef T1 Head; - typedef Types28 Tail; -}; - -template -struct Types30 { - typedef T1 Head; - typedef Types29 Tail; -}; - -template -struct Types31 { - typedef T1 Head; - typedef Types30 Tail; -}; - -template -struct Types32 { - typedef T1 Head; - typedef Types31 Tail; -}; - -template -struct Types33 { - typedef T1 Head; - typedef Types32 Tail; -}; - -template -struct Types34 { - typedef T1 Head; - typedef Types33 Tail; -}; - -template -struct Types35 { - typedef T1 Head; - typedef Types34 Tail; -}; - -template -struct Types36 { - typedef T1 Head; - typedef Types35 Tail; -}; - -template -struct Types37 { - typedef T1 Head; - typedef Types36 Tail; -}; - -template -struct Types38 { - typedef T1 Head; - typedef Types37 Tail; -}; - -template -struct Types39 { - typedef T1 Head; - typedef Types38 Tail; -}; - -template -struct Types40 { - typedef T1 Head; - typedef Types39 Tail; -}; - -template -struct Types41 { - typedef T1 Head; - typedef Types40 Tail; -}; - -template -struct Types42 { - typedef T1 Head; - typedef Types41 Tail; -}; - -template -struct Types43 { - typedef T1 Head; - typedef Types42 Tail; -}; - -template -struct Types44 { - typedef T1 Head; - typedef Types43 Tail; -}; - -template -struct Types45 { - typedef T1 Head; - typedef Types44 Tail; -}; - -template -struct Types46 { - typedef T1 Head; - typedef Types45 Tail; -}; - -template -struct Types47 { - typedef T1 Head; - typedef Types46 Tail; -}; - -template -struct Types48 { - typedef T1 Head; - typedef Types47 Tail; -}; - -template -struct Types49 { - typedef T1 Head; - typedef Types48 Tail; -}; - -template -struct Types50 { - typedef T1 Head; - typedef Types49 Tail; -}; - - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. -template -struct Types { - typedef internal::Types50 type; -}; - -template <> -struct Types { - typedef internal::Types0 type; -}; -template -struct Types { - typedef internal::Types1 type; -}; -template -struct Types { - typedef internal::Types2 type; -}; -template -struct Types { - typedef internal::Types3 type; -}; -template -struct Types { - typedef internal::Types4 type; -}; -template -struct Types { - typedef internal::Types5 type; -}; -template -struct Types { - typedef internal::Types6 type; -}; -template -struct Types { - typedef internal::Types7 type; -}; -template -struct Types { - typedef internal::Types8 type; -}; -template -struct Types { - typedef internal::Types9 type; -}; -template -struct Types { - typedef internal::Types10 type; -}; -template -struct Types { - typedef internal::Types11 type; -}; -template -struct Types { - typedef internal::Types12 type; -}; -template -struct Types { - typedef internal::Types13 type; -}; -template -struct Types { - typedef internal::Types14 type; -}; -template -struct Types { - typedef internal::Types15 type; -}; -template -struct Types { - typedef internal::Types16 type; -}; -template -struct Types { - typedef internal::Types17 type; -}; -template -struct Types { - typedef internal::Types18 type; -}; -template -struct Types { - typedef internal::Types19 type; -}; -template -struct Types { - typedef internal::Types20 type; -}; -template -struct Types { - typedef internal::Types21 type; -}; -template -struct Types { - typedef internal::Types22 type; -}; -template -struct Types { - typedef internal::Types23 type; -}; -template -struct Types { - typedef internal::Types24 type; -}; -template -struct Types { - typedef internal::Types25 type; -}; -template -struct Types { - typedef internal::Types26 type; -}; -template -struct Types { - typedef internal::Types27 type; -}; -template -struct Types { - typedef internal::Types28 type; -}; -template -struct Types { - typedef internal::Types29 type; -}; -template -struct Types { - typedef internal::Types30 type; -}; -template -struct Types { - typedef internal::Types31 type; -}; -template -struct Types { - typedef internal::Types32 type; -}; -template -struct Types { - typedef internal::Types33 type; -}; -template -struct Types { - typedef internal::Types34 type; -}; -template -struct Types { - typedef internal::Types35 type; -}; -template -struct Types { - typedef internal::Types36 type; -}; -template -struct Types { - typedef internal::Types37 type; -}; -template -struct Types { - typedef internal::Types38 type; -}; -template -struct Types { - typedef internal::Types39 type; -}; -template -struct Types { - typedef internal::Types40 type; -}; -template -struct Types { - typedef internal::Types41 type; -}; -template -struct Types { - typedef internal::Types42 type; -}; -template -struct Types { - typedef internal::Types43 type; -}; -template -struct Types { - typedef internal::Types44 type; -}; -template -struct Types { - typedef internal::Types45 type; -}; -template -struct Types { - typedef internal::Types46 type; -}; -template -struct Types { - typedef internal::Types47 type; -}; -template -struct Types { - typedef internal::Types48 type; -}; -template -struct Types { - typedef internal::Types49 type; -}; - -namespace internal { - # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to @@ -4813,1695 +3442,65 @@ struct TemplateSel { # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; +template +struct Templates { + using Head = TemplateSel; + using Tail = Templates; +}; -// Template lists of length 1, 2, 3, and so on. +template +struct Templates { + using Head = TemplateSel; + using Tail = None; +}; -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; +// Tuple-like type lists +template +struct Types { + using Head = Head_; + using Tail = Types; }; -template -struct Templates2 { - typedef TemplateSel Head; - typedef Templates1 Tail; + +template +struct Types { + using Head = Head_; + using Tail = None; }; -template -struct Templates3 { - typedef TemplateSel Head; - typedef Templates2 Tail; -}; - -template -struct Templates4 { - typedef TemplateSel Head; - typedef Templates3 Tail; -}; - -template -struct Templates5 { - typedef TemplateSel Head; - typedef Templates4 Tail; -}; - -template -struct Templates6 { - typedef TemplateSel Head; - typedef Templates5 Tail; -}; - -template -struct Templates7 { - typedef TemplateSel Head; - typedef Templates6 Tail; -}; - -template -struct Templates8 { - typedef TemplateSel Head; - typedef Templates7 Tail; -}; - -template -struct Templates9 { - typedef TemplateSel Head; - typedef Templates8 Tail; -}; - -template -struct Templates10 { - typedef TemplateSel Head; - typedef Templates9 Tail; -}; - -template -struct Templates11 { - typedef TemplateSel Head; - typedef Templates10 Tail; -}; - -template -struct Templates12 { - typedef TemplateSel Head; - typedef Templates11 Tail; -}; - -template -struct Templates13 { - typedef TemplateSel Head; - typedef Templates12 Tail; -}; - -template -struct Templates14 { - typedef TemplateSel Head; - typedef Templates13 Tail; -}; - -template -struct Templates15 { - typedef TemplateSel Head; - typedef Templates14 Tail; -}; - -template -struct Templates16 { - typedef TemplateSel Head; - typedef Templates15 Tail; -}; - -template -struct Templates17 { - typedef TemplateSel Head; - typedef Templates16 Tail; -}; - -template -struct Templates18 { - typedef TemplateSel Head; - typedef Templates17 Tail; -}; - -template -struct Templates19 { - typedef TemplateSel Head; - typedef Templates18 Tail; -}; - -template -struct Templates20 { - typedef TemplateSel Head; - typedef Templates19 Tail; -}; - -template -struct Templates21 { - typedef TemplateSel Head; - typedef Templates20 Tail; -}; - -template -struct Templates22 { - typedef TemplateSel Head; - typedef Templates21 Tail; -}; - -template -struct Templates23 { - typedef TemplateSel Head; - typedef Templates22 Tail; -}; - -template -struct Templates24 { - typedef TemplateSel Head; - typedef Templates23 Tail; -}; - -template -struct Templates25 { - typedef TemplateSel Head; - typedef Templates24 Tail; -}; - -template -struct Templates26 { - typedef TemplateSel Head; - typedef Templates25 Tail; -}; - -template -struct Templates27 { - typedef TemplateSel Head; - typedef Templates26 Tail; -}; - -template -struct Templates28 { - typedef TemplateSel Head; - typedef Templates27 Tail; -}; - -template -struct Templates29 { - typedef TemplateSel Head; - typedef Templates28 Tail; -}; - -template -struct Templates30 { - typedef TemplateSel Head; - typedef Templates29 Tail; -}; - -template -struct Templates31 { - typedef TemplateSel Head; - typedef Templates30 Tail; -}; - -template -struct Templates32 { - typedef TemplateSel Head; - typedef Templates31 Tail; -}; - -template -struct Templates33 { - typedef TemplateSel Head; - typedef Templates32 Tail; -}; - -template -struct Templates34 { - typedef TemplateSel Head; - typedef Templates33 Tail; -}; - -template -struct Templates35 { - typedef TemplateSel Head; - typedef Templates34 Tail; -}; - -template -struct Templates36 { - typedef TemplateSel Head; - typedef Templates35 Tail; -}; - -template -struct Templates37 { - typedef TemplateSel Head; - typedef Templates36 Tail; -}; - -template -struct Templates38 { - typedef TemplateSel Head; - typedef Templates37 Tail; -}; - -template -struct Templates39 { - typedef TemplateSel Head; - typedef Templates38 Tail; -}; - -template -struct Templates40 { - typedef TemplateSel Head; - typedef Templates39 Tail; -}; - -template -struct Templates41 { - typedef TemplateSel Head; - typedef Templates40 Tail; -}; - -template -struct Templates42 { - typedef TemplateSel Head; - typedef Templates41 Tail; -}; - -template -struct Templates43 { - typedef TemplateSel Head; - typedef Templates42 Tail; -}; - -template -struct Templates44 { - typedef TemplateSel Head; - typedef Templates43 Tail; -}; - -template -struct Templates45 { - typedef TemplateSel Head; - typedef Templates44 Tail; -}; - -template -struct Templates46 { - typedef TemplateSel Head; - typedef Templates45 Tail; -}; - -template -struct Templates47 { - typedef TemplateSel Head; - typedef Templates46 Tail; -}; - -template -struct Templates48 { - typedef TemplateSel Head; - typedef Templates47 Tail; -}; - -template -struct Templates49 { - typedef TemplateSel Head; - typedef Templates48 Tail; -}; - -template -struct Templates50 { - typedef TemplateSel Head; - typedef Templates49 Tail; -}; - - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. -template -struct Templates { - typedef Templates50 type; +// Helper metafunctions to tell apart a single type from types +// generated by ::testing::Types +template +struct ProxyTypeList { + using type = Types; }; -template <> -struct Templates { - typedef Templates0 type; -}; -template -struct Templates { - typedef Templates1 type; -}; -template -struct Templates { - typedef Templates2 type; -}; -template -struct Templates { - typedef Templates3 type; -}; -template -struct Templates { - typedef Templates4 type; -}; -template -struct Templates { - typedef Templates5 type; -}; -template -struct Templates { - typedef Templates6 type; -}; -template -struct Templates { - typedef Templates7 type; -}; -template -struct Templates { - typedef Templates8 type; -}; -template -struct Templates { - typedef Templates9 type; -}; -template -struct Templates { - typedef Templates10 type; -}; -template -struct Templates { - typedef Templates11 type; -}; -template -struct Templates { - typedef Templates12 type; -}; -template -struct Templates { - typedef Templates13 type; -}; -template -struct Templates { - typedef Templates14 type; -}; -template -struct Templates { - typedef Templates15 type; -}; -template -struct Templates { - typedef Templates16 type; -}; -template -struct Templates { - typedef Templates17 type; -}; -template -struct Templates { - typedef Templates18 type; -}; -template -struct Templates { - typedef Templates19 type; -}; -template -struct Templates { - typedef Templates20 type; -}; -template -struct Templates { - typedef Templates21 type; -}; -template -struct Templates { - typedef Templates22 type; -}; -template -struct Templates { - typedef Templates23 type; -}; -template -struct Templates { - typedef Templates24 type; -}; -template -struct Templates { - typedef Templates25 type; -}; -template -struct Templates { - typedef Templates26 type; -}; -template -struct Templates { - typedef Templates27 type; -}; -template -struct Templates { - typedef Templates28 type; -}; -template -struct Templates { - typedef Templates29 type; -}; -template -struct Templates { - typedef Templates30 type; -}; -template -struct Templates { - typedef Templates31 type; -}; -template -struct Templates { - typedef Templates32 type; -}; -template -struct Templates { - typedef Templates33 type; -}; -template -struct Templates { - typedef Templates34 type; -}; -template -struct Templates { - typedef Templates35 type; -}; -template -struct Templates { - typedef Templates36 type; -}; -template -struct Templates { - typedef Templates37 type; -}; -template -struct Templates { - typedef Templates38 type; -}; -template -struct Templates { - typedef Templates39 type; -}; -template -struct Templates { - typedef Templates40 type; -}; -template -struct Templates { - typedef Templates41 type; -}; -template -struct Templates { - typedef Templates42 type; -}; -template -struct Templates { - typedef Templates43 type; -}; -template -struct Templates { - typedef Templates44 type; -}; -template -struct Templates { - typedef Templates45 type; -}; -template -struct Templates { - typedef Templates46 type; -}; -template -struct Templates { - typedef Templates47 type; -}; -template -struct Templates { - typedef Templates48 type; -}; -template -struct Templates { - typedef Templates49 type; -}; - -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_SUITE() and -// INSTANTIATE_TYPED_TEST_SUITE_P(). +template +struct is_proxy_type_list : std::false_type {}; + +template +struct is_proxy_type_list> : std::true_type {}; +// Generator which conditionally creates type lists. +// It recognizes if a requested type list should be created +// and prevents creating a new type list nested within another one. template -struct TypeList { - typedef Types1 type; -}; - -template -struct TypeList > { - typedef typename Types::type type; -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P +struct GenerateTypeList { + private: + using proxy = typename std::conditional::value, T, + ProxyTypeList>::type; + + public: + using type = typename proxy::type; +}; } // namespace internal + +template +using Types = internal::ProxyTypeList; + } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing @@ -6515,9 +3514,20 @@ struct TypeList RegisteredTestsMap; @@ -7100,7 +4121,7 @@ struct NameGeneratorSelector { }; template -void GenerateNamesRecursively(Types0, std::vector*, int) {} +void GenerateNamesRecursively(internal::None, std::vector*, int) {} template void GenerateNamesRecursively(Types, std::vector* result, int i) { @@ -7167,7 +4188,7 @@ class TypeParameterizedTest { // The base case for the compile time recursion. template -class TypeParameterizedTest { +class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const CodeLocation&, const char* /*case_name*/, const char* /*test_names*/, @@ -7178,6 +4199,11 @@ class TypeParameterizedTest { } }; +GTEST_API_ void RegisterTypeParameterizedTestSuite(const char* test_suite_name, + CodeLocation code_location); +GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation( + const char* case_name); + // TypeParameterizedTestSuite::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return @@ -7190,6 +4216,7 @@ class TypeParameterizedTestSuite { const char* test_names, const std::vector& type_names = GenerateNames()) { + RegisterTypeParameterizedTestSuiteInstantiation(case_name); std::string test_name = StripTrailingSpaces( GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { @@ -7219,7 +4246,7 @@ class TypeParameterizedTestSuite { // The base case for the compile time recursion. template -class TypeParameterizedTestSuite { +class TypeParameterizedTestSuite { public: static bool Register(const char* /*prefix*/, const CodeLocation&, const TypedTestSuitePState* /*state*/, @@ -7230,8 +4257,6 @@ class TypeParameterizedTestSuite { } }; -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by @@ -7263,6 +4288,16 @@ struct GTEST_API_ ConstCharPtr { const char* value; }; +// Helper for declaring std::string within 'if' statement +// in pre C++17 build environment. +struct TrueWithString { + TrueWithString() = default; + explicit TrueWithString(const char* str) : value(str) {} + explicit TrueWithString(const std::string& str) : value(str) {} + explicit operator bool() const { return true; } + std::string value; +}; + // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user @@ -7270,18 +4305,18 @@ struct GTEST_API_ ConstCharPtr { // but it's good enough for our purposes. class GTEST_API_ Random { public: - static const UInt32 kMaxRange = 1u << 31; + static const uint32_t kMaxRange = 1u << 31; - explicit Random(UInt32 seed) : state_(seed) {} + explicit Random(uint32_t seed) : state_(seed) {} - void Reseed(UInt32 seed) { state_ = seed; } + void Reseed(uint32_t seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. - UInt32 Generate(UInt32 range); + uint32_t Generate(uint32_t range); private: - UInt32 state_; + uint32_t state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; @@ -7289,12 +4324,34 @@ class GTEST_API_ Random { #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ typename std::remove_const::type>::type -// IsAProtocolMessage::value is a compile-time bool constant that's -// true if and only if T is type proto2::Message or a subclass of it. +// HasDebugStringAndShortDebugString::value is a compile-time bool constant +// that's true if and only if T has methods DebugString() and ShortDebugString() +// that return std::string. template -struct IsAProtocolMessage - : public bool_constant< - std::is_convertible::value> {}; +class HasDebugStringAndShortDebugString { + private: + template + static constexpr auto CheckDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().DebugString())>::type; + template + static constexpr std::false_type CheckDebugString(...); + + template + static constexpr auto CheckShortDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().ShortDebugString())>::type; + template + static constexpr std::false_type CheckShortDebugString(...); + + using HasDebugStringType = decltype(CheckDebugString(nullptr)); + using HasShortDebugStringType = decltype(CheckShortDebugString(nullptr)); + + public: + static constexpr bool value = + HasDebugStringType::value && HasShortDebugStringType::value; +}; + +template +constexpr bool HasDebugStringAndShortDebugString::value; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -7530,8 +4587,6 @@ class NativeArray { const Element* array_; size_t size_; void (NativeArray::*clone_)(const Element*, size_t); - - GTEST_DISALLOW_ASSIGN_(NativeArray); }; // Backport of std::index_sequence. @@ -7555,32 +4610,44 @@ struct DoubleSequence, sizeofT> { // Backport of std::make_index_sequence. // It uses O(ln(N)) instantiation depth. template -struct MakeIndexSequence - : DoubleSequence::type, +struct MakeIndexSequenceImpl + : DoubleSequence::type, N / 2>::type {}; template <> -struct MakeIndexSequence<0> : IndexSequence<> {}; +struct MakeIndexSequenceImpl<0> : IndexSequence<> {}; -// FIXME: This implementation of ElemFromList is O(1) in instantiation depth, -// but it is O(N^2) in total instantiations. Not sure if this is the best -// tradeoff, as it will make it somewhat slow to compile. -template -struct ElemFromListImpl {}; +template +using MakeIndexSequence = typename MakeIndexSequenceImpl::type; -template -struct ElemFromListImpl { - using type = T; +template +using IndexSequenceFor = typename MakeIndexSequence::type; + +template +struct Ignore { + Ignore(...); // NOLINT }; -// Get the Nth element from T... -// It uses O(1) instantiation depth. -template -struct ElemFromList; +template +struct ElemFromListImpl; +template +struct ElemFromListImpl> { + // We make Ignore a template to solve a problem with MSVC. + // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but + // MSVC doesn't understand how to deal with that pack expansion. + // Use `0 * I` to have a single instantiation of Ignore. + template + static R Apply(Ignore<0 * I>..., R (*)(), ...); +}; + +template +struct ElemFromList { + using type = + decltype(ElemFromListImpl::type>::Apply( + static_cast(nullptr)...)); +}; -template -struct ElemFromList, T...> - : ElemFromListImpl... {}; +struct FlatTupleConstructTag {}; template class FlatTuple; @@ -7590,11 +4657,11 @@ struct FlatTupleElemBase; template struct FlatTupleElemBase, I> { - using value_type = - typename ElemFromList::type, - T...>::type; + using value_type = typename ElemFromList::type; FlatTupleElemBase() = default; - explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + template + explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t) + : value(std::forward(t)) {} value_type value; }; @@ -7606,13 +4673,35 @@ struct FlatTupleBase, IndexSequence> : FlatTupleElemBase, Idx>... { using Indices = IndexSequence; FlatTupleBase() = default; - explicit FlatTupleBase(T... t) - : FlatTupleElemBase, Idx>(std::move(t))... {} + template + explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args) + : FlatTupleElemBase, Idx>(FlatTupleConstructTag{}, + std::forward(args))... {} + + template + const typename ElemFromList::type& Get() const { + return FlatTupleElemBase, I>::value; + } + + template + typename ElemFromList::type& Get() { + return FlatTupleElemBase, I>::value; + } + + template + auto Apply(F&& f) -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } + + template + auto Apply(F&& f) const -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } }; // Analog to std::tuple but with different tradeoffs. // This class minimizes the template instantiation depth, thus allowing more -// elements that std::tuple would. std::tuple has been seen to require an +// elements than std::tuple would. std::tuple has been seen to require an // instantiation depth of more than 10x the number of elements in some // implementations. // FlatTuple and ElemFromList are not recursive and have a fixed depth @@ -7623,21 +4712,17 @@ template class FlatTuple : private FlatTupleBase, typename MakeIndexSequence::type> { - using Indices = typename FlatTuple::FlatTupleBase::Indices; + using Indices = typename FlatTupleBase< + FlatTuple, typename MakeIndexSequence::type>::Indices; public: FlatTuple() = default; - explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + template + explicit FlatTuple(FlatTupleConstructTag tag, Args&&... args) + : FlatTuple::FlatTupleBase(tag, std::forward(args)...) {} - template - const typename ElemFromList::type& Get() const { - return static_cast*>(this)->value; - } - - template - typename ElemFromList::type& Get() { - return static_cast*>(this)->value; - } + using FlatTuple::FlatTupleBase::Apply; + using FlatTuple::FlatTupleBase::Get; }; // Utility functions to be called with static_assert to induce deprecation @@ -7670,6 +4755,22 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } // namespace internal } // namespace testing +namespace std { +// Some standard library implementations use `struct tuple_size` and some use +// `class tuple_size`. Clang warns about the mismatch. +// https://reviews.llvm.org/D55466 +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +struct tuple_size> + : std::integral_constant {}; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace std + #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() @@ -7692,48 +4793,122 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } // Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). +// NOTE: The "else" is important to keep this expansion to prevent a top-level +// "else" from attaching to our "if". #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ - if (::testing::internal::AlwaysTrue()) { statement; } + if (::testing::internal::AlwaysTrue()) { \ + statement; \ + } else /* NOLINT */ \ + static_assert(true, "") // User must have a semicolon after expansion. -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) +#if GTEST_HAS_EXCEPTIONS + +namespace testing { +namespace internal { + +class NeverThrown { + public: + const char* what() const noexcept { + return "this exception should never be thrown"; + } +}; + +} // namespace internal +} // namespace testing + +#if GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e)) + +#else // GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + std::string { "an std::exception-derived error" } + +#endif // GTEST_HAS_RTTI + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (typename std::conditional< \ + std::is_same::type>::type, \ + std::exception>::value, \ + const ::testing::internal::NeverThrown&, const std::exception&>::type \ + e) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (...) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else /*NOLINT*/ \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value.c_str()) + +#if GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (std::exception const& e) { \ + gtest_msg.value = "it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() + +#endif // GTEST_HAS_EXCEPTIONS #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ + GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ catch (...) { \ + gtest_msg.value = "it throws."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ - fail("Expected: " #statement " doesn't throw an exception.\n" \ - " Actual: it throws.") + fail(("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: " + gtest_msg.value).c_str()) #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ @@ -7807,13 +4982,16 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ : public parent_class { \ public: \ - GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \ + ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + GTEST_DISALLOW_MOVE_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ \ private: \ - virtual void TestBody(); \ + void TestBody() override; \ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ - test_name)); \ }; \ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ @@ -7829,7 +5007,7 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } test_suite_name, test_name)>); \ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // @@ -7867,8 +5045,8 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } // directly. // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // All rights reserved. @@ -7905,8 +5083,8 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } // death tests. They are subject to change without notice. // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ // Copyright 2007, Google Inc. // All rights reserved. @@ -7942,13 +5120,10 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } // This file implements just enough of the matcher interface to allow // EXPECT_DEATH and friends to accept a matcher argument. -// IWYU pragma: private, include "testing/base/public/gunit.h" -// IWYU pragma: friend third_party/googletest/googlemock/.* -// IWYU pragma: friend third_party/googletest/googletest/.* - -#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#include #include #include #include @@ -8053,10 +5228,11 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #include +#include #include // NOLINT #include #include @@ -8065,61 +5241,126 @@ constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } #include #include -#if GTEST_HAS_ABSL -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "absl/types/variant.h" -#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_RTTI +#include +#include +#endif // GTEST_HAS_RTTI namespace testing { -// Definitions in the 'internal' and 'internal2' name spaces are -// subject to change without notice. DO NOT USE THEM IN USER CODE! -namespace internal2 { +// Definitions in the internal* namespaces are subject to change without notice. +// DO NOT USE THEM IN USER CODE! +namespace internal { -// Prints the given number of bytes in the given object to the given -// ostream. -GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, - size_t count, - ::std::ostream* os); +template +void UniversalPrint(const T& value, ::std::ostream* os); -// For selecting which printer to use when a given type has neither << -// nor PrintTo(). -enum TypeKind { - kProtobuf, // a protobuf type - kConvertibleToInteger, // a type implicitly convertible to BiggestInt - // (e.g. a named or unnamed enum type) -#if GTEST_HAS_ABSL - kConvertibleToStringView, // a type implicitly convertible to - // absl::string_view -#endif - kOtherType // anything else +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +struct ContainerPrinter { + template (0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value>::type> + static void PrintValue(const T& container, std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (auto&& elem : container) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(elem, os) here as PrintTo() doesn't + // handle `elem` being a native array. + internal::UniversalPrint(elem, os); + ++count; + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; + } }; -// TypeWithoutFormatter::PrintValue(value, os) is called -// by the universal printer to print a value of type T when neither -// operator<< nor PrintTo() is defined for T, where kTypeKind is the -// "kind" of T as defined by enum TypeKind. -template -class TypeWithoutFormatter { - public: - // This default version is called when kTypeKind is kOtherType. +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +struct FunctionPointerPrinter { + template ::value>::type> + static void PrintValue(T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); + } + } +}; + +struct PointerPrinter { + template + static void PrintValue(T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } + } +}; + +namespace internal_stream_operator_without_lexical_name_lookup { + +// The presence of an operator<< here will terminate lexical scope lookup +// straight away (even though it cannot be a match because of its argument +// types). Thus, the two operator<< calls in StreamPrinter will find only ADL +// candidates. +struct LookupBlocker {}; +void operator<<(LookupBlocker, LookupBlocker); + +struct StreamPrinter { + template ::value>::type, + // Only accept types for which we can find a streaming operator via + // ADL (possibly involving implicit conversions). + typename = decltype(std::declval() + << std::declval())> static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo( - static_cast( - reinterpret_cast(std::addressof(value))), - sizeof(value), os); + // Call streaming operator found by ADL, possibly with implicit conversions + // of the arguments. + *os << value; } }; -// We print a protobuf using its ShortDebugString() when the string -// doesn't exceed this many characters; otherwise we print it using -// DebugString() for better readability. -const size_t kProtobufOneLinerMaxLength = 50; +} // namespace internal_stream_operator_without_lexical_name_lookup -template -class TypeWithoutFormatter { - public: +struct ProtobufPrinter { + // We print a protobuf using its ShortDebugString() when the string + // doesn't exceed this many characters; otherwise we print it using + // DebugString() for better readability. + static const size_t kProtobufOneLinerMaxLength = 50; + + template ::value>::type> static void PrintValue(const T& value, ::std::ostream* os) { std::string pretty_str = value.ShortDebugString(); if (pretty_str.length() > kProtobufOneLinerMaxLength) { @@ -8129,9 +5370,7 @@ class TypeWithoutFormatter { } }; -template -class TypeWithoutFormatter { - public: +struct ConvertibleToIntegerPrinter { // Since T has no << operator or PrintTo() but can be implicitly // converted to BiggestInt, we print it as a BiggestInt. // @@ -8139,112 +5378,73 @@ class TypeWithoutFormatter { // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. - static void PrintValue(const T& value, ::std::ostream* os) { - const internal::BiggestInt kBigInt = value; - *os << kBigInt; + static void PrintValue(internal::BiggestInt value, ::std::ostream* os) { + *os << value; } }; -#if GTEST_HAS_ABSL -template -class TypeWithoutFormatter { - public: - // Since T has neither operator<< nor PrintTo() but can be implicitly - // converted to absl::string_view, we print it as a absl::string_view. - // - // Note: the implementation is further below, as it depends on - // internal::PrintTo symbol which is defined later in the file. - static void PrintValue(const T& value, ::std::ostream* os); -}; -#endif - -// Prints the given value to the given ostream. If the value is a -// protocol message, its debug string is printed; if it's an enum or -// of a type implicitly convertible to BiggestInt, it's printed as an -// integer; otherwise the bytes in the value are printed. This is -// what UniversalPrinter::Print() does when it knows nothing about -// type T and T has neither << operator nor PrintTo(). -// -// A user can override this behavior for a class type Foo by defining -// a << operator in the namespace where Foo is defined. -// -// We put this operator in namespace 'internal2' instead of 'internal' -// to simplify the implementation, as much code in 'internal' needs to -// use << in STL, which would conflict with our own << were it defined -// in 'internal'. -// -// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream, const Foo&) is more -// specific. -template -::std::basic_ostream& operator<<( - ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value - ? kProtobuf - : std::is_convertible< - const T&, internal::BiggestInt>::value - ? kConvertibleToInteger - : -#if GTEST_HAS_ABSL - std::is_convertible< - const T&, absl::string_view>::value - ? kConvertibleToStringView - : +struct ConvertibleToStringViewPrinter { +#if GTEST_INTERNAL_HAS_STRING_VIEW + static void PrintValue(internal::StringView value, ::std::ostream* os) { + internal::UniversalPrint(value, os); + } #endif - kOtherType)>::PrintValue(x, &os); - return os; -} +}; -} // namespace internal2 -} // namespace testing -// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up -// magic needed for implementing UniversalPrinter won't work. -namespace testing_internal { +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); +struct RawBytesPrinter { + // SFINAE on `sizeof` to make sure we have a complete type. + template + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo( + static_cast( + // Load bearing cast to void* to support iOS + reinterpret_cast(std::addressof(value))), + sizeof(value), os); + } +}; -// Used to print a value that is not an STL-style container when the -// user doesn't define PrintTo() for it. -template -void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { - // With the following statement, during unqualified name lookup, - // testing::internal2::operator<< appears as if it was declared in - // the nearest enclosing namespace that contains both - // ::testing_internal and ::testing::internal2, i.e. the global - // namespace. For more details, refer to the C++ Standard section - // 7.3.4-1 [namespace.udir]. This allows us to fall back onto - // testing::internal2::operator<< in case T doesn't come with a << - // operator. - // - // We cannot write 'using ::testing::internal2::operator<<;', which - // gcc 3.3 fails to compile due to a compiler bug. - using namespace ::testing::internal2; // NOLINT +struct FallbackPrinter { + template + static void PrintValue(const T&, ::std::ostream* os) { + *os << "(incomplete type)"; + } +}; - // Assuming T is defined in namespace foo, in the next statement, - // the compiler will consider all of: - // - // 1. foo::operator<< (thanks to Koenig look-up), - // 2. ::operator<< (as the current namespace is enclosed in ::), - // 3. testing::internal2::operator<< (thanks to the using statement above). - // - // The operator<< whose type matches T best will be picked. - // - // We deliberately allow #2 to be a candidate, as sometimes it's - // impossible to define #1 (e.g. when foo is ::std, defining - // anything in it is undefined behavior unless you are a compiler - // vendor.). - *os << value; -} +// Try every printer in order and return the first one that works. +template +struct FindFirstPrinter : FindFirstPrinter {}; -} // namespace testing_internal +template +struct FindFirstPrinter< + T, decltype(Printer::PrintValue(std::declval(), nullptr)), + Printer, Printers...> { + using type = Printer; +}; -namespace testing { -namespace internal { +// Select the best printer in the following order: +// - Print containers (they have begin/end/etc). +// - Print function pointers. +// - Print object pointers. +// - Use the stream operator, if available. +// - Print protocol buffers. +// - Print types convertible to BiggestInt. +// - Print types convertible to StringView, if available. +// - Fallback to printing the raw bytes of the object. +template +void PrintWithFallback(const T& value, ::std::ostream* os) { + using Printer = typename FindFirstPrinter< + T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter, + internal_stream_operator_without_lexical_name_lookup::StreamPrinter, + ProtobufPrinter, ConvertibleToIntegerPrinter, + ConvertibleToStringViewPrinter, RawBytesPrinter, FallbackPrinter>::type; + Printer::PrintValue(value, os); +} // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion @@ -8294,6 +5494,14 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ @@ -8311,6 +5519,14 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string); #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); @@ -8343,85 +5559,6 @@ std::string FormatForComparisonFailureMessage( template class UniversalPrinter; -template -void UniversalPrint(const T& value, ::std::ostream* os); - -enum DefaultPrinterType { - kPrintContainer, - kPrintPointer, - kPrintFunctionPointer, - kPrintOther, -}; -template struct WrapPrinterType {}; - -// Used to print an STL-style container when the user doesn't define -// a PrintTo() for it. -template -void DefaultPrintTo(WrapPrinterType /* dummy */, - const C& container, ::std::ostream* os) { - const size_t kMaxCount = 32; // The maximum number of elements to print. - *os << '{'; - size_t count = 0; - for (typename C::const_iterator it = container.begin(); - it != container.end(); ++it, ++count) { - if (count > 0) { - *os << ','; - if (count == kMaxCount) { // Enough has been printed. - *os << " ..."; - break; - } - } - *os << ' '; - // We cannot call PrintTo(*it, os) here as PrintTo() doesn't - // handle *it being a native array. - internal::UniversalPrint(*it, os); - } - - if (count > 0) { - *os << ' '; - } - *os << '}'; -} - -// Used to print a pointer that is neither a char pointer nor a member -// pointer, when the user doesn't define PrintTo() for it. (A member -// variable pointer or member function pointer doesn't really point to -// a location in the address space. Their representation is -// implementation-defined. Therefore they will be printed as raw -// bytes.) -template -void DefaultPrintTo(WrapPrinterType /* dummy */, - T* p, ::std::ostream* os) { - if (p == nullptr) { - *os << "NULL"; - } else { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } -} -template -void DefaultPrintTo(WrapPrinterType /* dummy */, - T* p, ::std::ostream* os) { - if (p == nullptr) { - *os << "NULL"; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. - *os << reinterpret_cast(p); - } -} - -// Used to print a non-container, non-pointer value when the user -// doesn't define PrintTo() for it. -template -void DefaultPrintTo(WrapPrinterType /* dummy */, - const T& value, ::std::ostream* os) { - ::testing_internal::DefaultPrintNonContainerTo(value, os); -} - // Prints the given value using the << operator if it has one; // otherwise prints the bytes in it. This is what // UniversalPrinter::Print() does when PrintTo() is not specialized @@ -8435,36 +5572,7 @@ void DefaultPrintTo(WrapPrinterType /* dummy */, // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first argument - // determines which version will be picked. - // - // Note that we check for container types here, prior to we check - // for protocol message types in our operator<<. The rationale is: - // - // For protocol messages, we want to give people a chance to - // override Google Mock's format by defining a PrintTo() or - // operator<<. For STL containers, other formats can be - // incompatible with Google Mock's format for the container - // elements; therefore we check for container types here to ensure - // that our format is used. - // - // Note that MSVC and clang-cl do allow an implicit conversion from - // pointer-to-function to pointer-to-object, but clang-cl warns on it. - // So don't use ImplicitlyConvertible if it can be helped since it will - // cause this warning, and use a separate overload of DefaultPrintTo for - // function pointers so that the `*os << p` in the object pointer overload - // doesn't cause that warning either. - DefaultPrintTo( - WrapPrinterType < - (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && - !IsRecursiveContainer::value - ? kPrintContainer - : !std::is_pointer::value - ? kPrintOther - : std::is_function::type>::value - ? kPrintFunctionPointer - : kPrintPointer > (), - value, os); + internal::PrintWithFallback(value, os); } // The following list of PrintTo() overloads tells @@ -8495,6 +5603,16 @@ inline void PrintTo(bool x, ::std::ostream* os) { // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); +GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); +inline void PrintTo(char16_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_(c), os); +} +#ifdef __cpp_char8_t +inline void PrintTo(char8_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_(c), os); +} +#endif + // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { @@ -8515,6 +5633,26 @@ inline void PrintTo(const unsigned char* s, ::std::ostream* os) { inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } +#ifdef __cpp_char8_t +inline void PrintTo(const char8_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(char8_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif +inline void PrintTo(const char16_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(char16_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const char32_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(char32_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native @@ -8557,12 +5695,12 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_ABSL -// Overload for absl::string_view. -inline void PrintTo(absl::string_view sp, ::std::ostream* os) { +#if GTEST_INTERNAL_HAS_STRING_VIEW +// Overload for internal::StringView. +inline void PrintTo(internal::StringView sp, ::std::ostream* os) { PrintTo(::std::string(sp), os); } -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_STRING_VIEW inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } @@ -8571,6 +5709,43 @@ void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { UniversalPrinter::Print(ref.get(), os); } +inline const void* VoidifyPointer(const void* p) { return p; } +inline const void* VoidifyPointer(volatile const void* p) { + return const_cast(p); +} + +template +void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) { + if (ptr == nullptr) { + *os << "(nullptr)"; + } else { + // We can't print the value. Just print the pointer.. + *os << "(" << (VoidifyPointer)(ptr.get()) << ")"; + } +} +template ::value && + !std::is_array::value>::type> +void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) { + if (ptr == nullptr) { + *os << "(nullptr)"; + } else { + *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = "; + UniversalPrinter::Print(*ptr, os); + *os << ")"; + } +} + +template +void PrintTo(const std::unique_ptr& ptr, std::ostream* os) { + (PrintSmartPointer)(ptr, os, 0); +} + +template +void PrintTo(const std::shared_ptr& ptr, std::ostream* os) { + (PrintSmartPointer)(ptr, os, 0); +} + // Helper function for printing a tuple. T must be instantiated with // a tuple type. template @@ -8609,6 +5784,18 @@ void PrintTo(const ::std::pair& value, ::std::ostream* os) { *os << ')'; } +#if GTEST_HAS_RTTI +inline void PrintTo(const ::std::type_info& value, ::std::ostream* os) { + internal::PrintTo<::std::type_info>(value, os); + *os << " (\"" << value.name() << "\")"; +} + +inline void PrintTo(const ::std::type_index& value, ::std::ostream* os) { + internal::PrintTo<::std::type_index>(value, os); + *os << " (\"" << value.name() << "\")"; +} +#endif // GTEST_HAS_RTTI + // Implements printing a non-reference type T by letting the compiler // pick the right overload of PrintTo() for T. template @@ -8636,14 +5823,46 @@ class UniversalPrinter { GTEST_DISABLE_MSC_WARNINGS_POP_() }; -#if GTEST_HAS_ABSL +// Remove any const-qualifiers before passing a type to UniversalPrinter. +template +class UniversalPrinter : public UniversalPrinter {}; + +#if GTEST_INTERNAL_HAS_ANY + +// Printer for std::any / absl::any + +template <> +class UniversalPrinter { + public: + static void Print(const Any& value, ::std::ostream* os) { + if (value.has_value()) { + *os << "value of type " << GetTypeName(value); + } else { + *os << "no value"; + } + } + + private: + static std::string GetTypeName(const Any& value) { +#if GTEST_HAS_RTTI + return internal::GetTypeName(value.type()); +#else + static_cast(value); // possibly unused + return ""; +#endif // GTEST_HAS_RTTI + } +}; + +#endif // GTEST_INTERNAL_HAS_ANY + +#if GTEST_INTERNAL_HAS_OPTIONAL -// Printer for absl::optional +// Printer for std::optional / absl::optional template -class UniversalPrinter<::absl::optional> { +class UniversalPrinter> { public: - static void Print(const ::absl::optional& value, ::std::ostream* os) { + static void Print(const Optional& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; @@ -8654,14 +5873,22 @@ class UniversalPrinter<::absl::optional> { } }; -// Printer for absl::variant +#endif // GTEST_INTERNAL_HAS_OPTIONAL + +#if GTEST_INTERNAL_HAS_VARIANT + +// Printer for std::variant / absl::variant template -class UniversalPrinter<::absl::variant> { +class UniversalPrinter> { public: - static void Print(const ::absl::variant& value, ::std::ostream* os) { + static void Print(const Variant& value, ::std::ostream* os) { *os << '('; - absl::visit(Visitor{os}, value); +#if GTEST_HAS_ABSL + absl::visit(Visitor{os, value.index()}, value); +#else + std::visit(Visitor{os, value.index()}, value); +#endif // GTEST_HAS_ABSL *os << ')'; } @@ -8669,14 +5896,16 @@ class UniversalPrinter<::absl::variant> { struct Visitor { template void operator()(const U& u) const { - *os << "'" << GetTypeName() << "' with value "; + *os << "'" << GetTypeName() << "(index = " << index + << ")' with value "; UniversalPrint(u, os); } ::std::ostream* os; + std::size_t index; }; }; -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_VARIANT // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. @@ -8855,16 +6084,6 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { } // namespace internal -#if GTEST_HAS_ABSL -namespace internal2 { -template -void TypeWithoutFormatter::PrintValue( - const T& value, ::std::ostream* os) { - internal::PrintTo(absl::string_view(value), os); -} -} // namespace internal2 -#endif - template ::std::string PrintToString(const T& value) { ::std::stringstream ss; @@ -8915,12 +6134,12 @@ ::std::string PrintToString(const T& value) { // // ** Custom implementation starts here ** -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ -#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ -#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ // MSVC warning C5046 is new as of VS2017 version 15.8. #if defined(_MSC_VER) && _MSC_VER >= 1915 @@ -8937,20 +6156,16 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_( namespace testing { // To implement a matcher Foo for type T, define: -// 1. a class FooMatcherImpl that implements the -// MatcherInterface interface, and -// 2. a factory function that creates a Matcher object from a -// FooMatcherImpl*. +// 1. a class FooMatcherMatcher that implements the matcher interface: +// using is_gtest_matcher = void; +// bool MatchAndExplain(const T&, std::ostream*); +// (MatchResultListener* can also be used instead of std::ostream*) +// void DescribeTo(std::ostream*); +// void DescribeNegationTo(std::ostream*); // -// The two-level delegation design makes it possible to allow a user -// to write "v" instead of "Eq(v)" where a Matcher is expected, which -// is impossible if we pass matchers by pointers. It also eases -// ownership management as Matcher objects can now be copied like -// plain values. +// 2. a factory function that creates a Matcher object from a +// FooMatcherMatcher. -// MatchResultListener is an abstract class. Its << operator can be -// used by a matcher to explain why a value matches or doesn't match. -// class MatchResultListener { public: // Creates a listener object with the given underlying ostream. The @@ -9055,31 +6270,6 @@ class MatcherInterface : public MatcherDescriberInterface { namespace internal { -// Converts a MatcherInterface to a MatcherInterface. -template -class MatcherInterfaceAdapter : public MatcherInterface { - public: - explicit MatcherInterfaceAdapter(const MatcherInterface* impl) - : impl_(impl) {} - ~MatcherInterfaceAdapter() override { delete impl_; } - - void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } - - void DescribeNegationTo(::std::ostream* os) const override { - impl_->DescribeNegationTo(os); - } - - bool MatchAndExplain(const T& x, - MatchResultListener* listener) const override { - return impl_->MatchAndExplain(x, listener); - } - - private: - const MatcherInterface* const impl_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); -}; - struct AnyEq { template bool operator()(const A& a, const B& b) const { return a == b; } @@ -9122,20 +6312,39 @@ class StreamMatchResultListener : public MatchResultListener { explicit StreamMatchResultListener(::std::ostream* os) : MatchResultListener(os) {} - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +struct SharedPayloadBase { + std::atomic ref{1}; + void Ref() { ref.fetch_add(1, std::memory_order_relaxed); } + bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; } +}; + +template +struct SharedPayload : SharedPayloadBase { + explicit SharedPayload(const T& v) : value(v) {} + explicit SharedPayload(T&& v) : value(std::move(v)) {} + + static void Destroy(SharedPayloadBase* shared) { + delete static_cast(shared); + } + + T value; }; // An internal class for implementing Matcher, which will derive // from it. We put functionalities common to all Matcher // specializations here to avoid code duplication. template -class MatcherBase { +class MatcherBase : private MatcherDescriberInterface { public: // Returns true if and only if the matcher matches x; also explains the // match result to 'listener'. bool MatchAndExplain(const T& x, MatchResultListener* listener) const { - return impl_->MatchAndExplain(x, listener); + GTEST_CHECK_(vtable_ != nullptr); + return vtable_->match_and_explain(*this, x, listener); } // Returns true if and only if this matcher matches x. @@ -9145,11 +6354,15 @@ class MatcherBase { } // Describes this matcher to an ostream. - void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + void DescribeTo(::std::ostream* os) const final { + GTEST_CHECK_(vtable_ != nullptr); + vtable_->describe(*this, os, false); + } // Describes the negation of this matcher to an ostream. - void DescribeNegationTo(::std::ostream* os) const { - impl_->DescribeNegationTo(os); + void DescribeNegationTo(::std::ostream* os) const final { + GTEST_CHECK_(vtable_ != nullptr); + vtable_->describe(*this, os, true); } // Explains why x matches, or doesn't match, the matcher. @@ -9162,31 +6375,194 @@ class MatcherBase { // of the describer, which is only guaranteed to be alive when // this matcher object is alive. const MatcherDescriberInterface* GetDescriber() const { - return impl_.get(); + if (vtable_ == nullptr) return nullptr; + return vtable_->get_describer(*this); } protected: - MatcherBase() {} + MatcherBase() : vtable_(nullptr) {} // Constructs a matcher from its implementation. - explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} - template - explicit MatcherBase( - const MatcherInterface* impl, - typename std::enable_if::value>::type* = - nullptr) - : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + explicit MatcherBase(const MatcherInterface* impl) { + Init(impl); + } + + template ::type::is_gtest_matcher> + MatcherBase(M&& m) { // NOLINT + Init(std::forward(m)); + } + + MatcherBase(const MatcherBase& other) + : vtable_(other.vtable_), buffer_(other.buffer_) { + if (IsShared()) buffer_.shared->Ref(); + } + + MatcherBase& operator=(const MatcherBase& other) { + if (this == &other) return *this; + Destroy(); + vtable_ = other.vtable_; + buffer_ = other.buffer_; + if (IsShared()) buffer_.shared->Ref(); + return *this; + } - MatcherBase(const MatcherBase&) = default; - MatcherBase& operator=(const MatcherBase&) = default; - MatcherBase(MatcherBase&&) = default; - MatcherBase& operator=(MatcherBase&&) = default; + MatcherBase(MatcherBase&& other) + : vtable_(other.vtable_), buffer_(other.buffer_) { + other.vtable_ = nullptr; + } + + MatcherBase& operator=(MatcherBase&& other) { + if (this == &other) return *this; + Destroy(); + vtable_ = other.vtable_; + buffer_ = other.buffer_; + other.vtable_ = nullptr; + return *this; + } - virtual ~MatcherBase() {} + ~MatcherBase() override { Destroy(); } private: - std::shared_ptr> impl_; + struct VTable { + bool (*match_and_explain)(const MatcherBase&, const T&, + MatchResultListener*); + void (*describe)(const MatcherBase&, std::ostream*, bool negation); + // Returns the captured object if it implements the interface, otherwise + // returns the MatcherBase itself. + const MatcherDescriberInterface* (*get_describer)(const MatcherBase&); + // Called on shared instances when the reference count reaches 0. + void (*shared_destroy)(SharedPayloadBase*); + }; + + bool IsShared() const { + return vtable_ != nullptr && vtable_->shared_destroy != nullptr; + } + + // If the implementation uses a listener, call that. + template + static auto MatchAndExplainImpl(const MatcherBase& m, const T& value, + MatchResultListener* listener) + -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) { + return P::Get(m).MatchAndExplain(value, listener->stream()); + } + + template + static auto MatchAndExplainImpl(const MatcherBase& m, const T& value, + MatchResultListener* listener) + -> decltype(P::Get(m).MatchAndExplain(value, listener)) { + return P::Get(m).MatchAndExplain(value, listener); + } + + template + static void DescribeImpl(const MatcherBase& m, std::ostream* os, + bool negation) { + if (negation) { + P::Get(m).DescribeNegationTo(os); + } else { + P::Get(m).DescribeTo(os); + } + } + + template + static const MatcherDescriberInterface* GetDescriberImpl( + const MatcherBase& m) { + // If the impl is a MatcherDescriberInterface, then return it. + // Otherwise use MatcherBase itself. + // This allows us to implement the GetDescriber() function without support + // from the impl, but some users really want to get their impl back when + // they call GetDescriber(). + // We use std::get on a tuple as a workaround of not having `if constexpr`. + return std::get<( + std::is_convertible::value + ? 1 + : 0)>(std::make_tuple(&m, &P::Get(m))); + } + + template + const VTable* GetVTable() { + static constexpr VTable kVTable = {&MatchAndExplainImpl

, + &DescribeImpl

, &GetDescriberImpl

, + P::shared_destroy}; + return &kVTable; + } + + union Buffer { + // Add some types to give Buffer some common alignment/size use cases. + void* ptr; + double d; + int64_t i; + // And add one for the out-of-line cases. + SharedPayloadBase* shared; + }; + + void Destroy() { + if (IsShared() && buffer_.shared->Unref()) { + vtable_->shared_destroy(buffer_.shared); + } + } + + template + static constexpr bool IsInlined() { + return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) && + std::is_trivially_copy_constructible::value && + std::is_trivially_destructible::value; + } + + template ()> + struct ValuePolicy { + static const M& Get(const MatcherBase& m) { + // When inlined along with Init, need to be explicit to avoid violating + // strict aliasing rules. + const M *ptr = static_cast( + static_cast(&m.buffer_)); + return *ptr; + } + static void Init(MatcherBase& m, M impl) { + ::new (static_cast(&m.buffer_)) M(impl); + } + static constexpr auto shared_destroy = nullptr; + }; + + template + struct ValuePolicy { + using Shared = SharedPayload; + static const M& Get(const MatcherBase& m) { + return static_cast(m.buffer_.shared)->value; + } + template + static void Init(MatcherBase& m, Arg&& arg) { + m.buffer_.shared = new Shared(std::forward(arg)); + } + static constexpr auto shared_destroy = &Shared::Destroy; + }; + + template + struct ValuePolicy*, B> { + using M = const MatcherInterface; + using Shared = SharedPayload>; + static const M& Get(const MatcherBase& m) { + return *static_cast(m.buffer_.shared)->value; + } + static void Init(MatcherBase& m, M* impl) { + m.buffer_.shared = new Shared(std::unique_ptr(impl)); + } + + static constexpr auto shared_destroy = &Shared::Destroy; + }; + + template + void Init(M&& m) { + using MM = typename std::decay::type; + using Policy = ValuePolicy; + vtable_ = GetVTable(); + Policy::Init(*this, std::forward(m)); + } + + const VTable* vtable_; + Buffer buffer_; }; } // namespace internal @@ -9214,6 +6590,10 @@ class Matcher : public internal::MatcherBase { nullptr) : internal::MatcherBase(impl) {} + template ::type::is_gtest_matcher> + Matcher(M&& m) : internal::MatcherBase(std::forward(m)) {} // NOLINT + // Implicit constructor here allows people to write // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes Matcher(T value); // NOLINT @@ -9231,6 +6611,11 @@ class GTEST_API_ Matcher explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} + // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. Matcher(const std::string& s); // NOLINT @@ -9250,6 +6635,11 @@ class GTEST_API_ Matcher explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} + // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const std::string& s); // NOLINT @@ -9258,18 +6648,24 @@ class GTEST_API_ Matcher Matcher(const char* s); // NOLINT }; -#if GTEST_HAS_ABSL +#if GTEST_INTERNAL_HAS_STRING_VIEW // The following two specializations allow the user to write str // instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view // matcher is expected. template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { +class GTEST_API_ Matcher + : public internal::MatcherBase { public: Matcher() {} - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) { + } // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. @@ -9278,20 +6674,25 @@ class GTEST_API_ Matcher // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT - // Allows the user to pass absl::string_views directly. - Matcher(absl::string_view s); // NOLINT + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT }; template <> -class GTEST_API_ Matcher - : public internal::MatcherBase { +class GTEST_API_ Matcher + : public internal::MatcherBase { public: Matcher() {} - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} - explicit Matcher(const MatcherInterface* impl) - : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. @@ -9300,10 +6701,10 @@ class GTEST_API_ Matcher // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT - // Allows the user to pass absl::string_views directly. - Matcher(absl::string_view s); // NOLINT + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT }; -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_STRING_VIEW // Prints a matcher in a human-readable format. template @@ -9348,13 +6749,13 @@ class PolymorphicMatcher { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } + void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); } - virtual void DescribeNegationTo(::std::ostream* os) const { + void DescribeNegationTo(::std::ostream* os) const override { impl_.DescribeNegationTo(os); } - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + bool MatchAndExplain(T x, MatchResultListener* listener) const override { return impl_.MatchAndExplain(x, listener); } @@ -9403,37 +6804,32 @@ template class ComparisonBase { public: explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + + using is_gtest_matcher = void; + template - operator Matcher() const { - return Matcher(new Impl(rhs_)); + bool MatchAndExplain(const Lhs& lhs, std::ostream*) const { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(std::ostream* os) const { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(std::ostream* os) const { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); } private: template - static const T& Unwrap(const T& v) { return v; } + static const T& Unwrap(const T& v) { + return v; + } template - static const T& Unwrap(std::reference_wrapper v) { return v; } - - template - class Impl : public MatcherInterface { - public: - explicit Impl(const Rhs& rhs) : rhs_(rhs) {} - bool MatchAndExplain(Lhs lhs, - MatchResultListener* /* listener */) const override { - return Op()(lhs, Unwrap(rhs_)); - } - void DescribeTo(::std::ostream* os) const override { - *os << D::Desc() << " "; - UniversalPrint(Unwrap(rhs_), os); - } - void DescribeNegationTo(::std::ostream* os) const override { - *os << D::NegatedDesc() << " "; - UniversalPrint(Unwrap(rhs_), os); - } + static const T& Unwrap(std::reference_wrapper v) { + return v; + } - private: - Rhs rhs_; - }; Rhs rhs_; }; @@ -9486,6 +6882,10 @@ class GeMatcher : public ComparisonBase, Rhs, AnyGe> { static const char* NegatedDesc() { return "isn't >="; } }; +template ::value>::type> +using StringLike = T; + // Implements polymorphic matchers MatchesRegex(regex) and // ContainsRegex(regex), which can be used as a Matcher as long as // T can be converted to a string. @@ -9494,12 +6894,12 @@ class MatchesRegexMatcher { MatchesRegexMatcher(const RE* regex, bool full_match) : regex_(regex), full_match_(full_match) {} -#if GTEST_HAS_ABSL - bool MatchAndExplain(const absl::string_view& s, +#if GTEST_INTERNAL_HAS_STRING_VIEW + bool MatchAndExplain(const internal::StringView& s, MatchResultListener* listener) const { return MatchAndExplain(std::string(s), listener); } -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_STRING_VIEW // Accepts pointer types, particularly: // const char* @@ -9546,9 +6946,10 @@ inline PolymorphicMatcher MatchesRegex( const internal::RE* regex) { return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); } -inline PolymorphicMatcher MatchesRegex( - const std::string& regex) { - return MatchesRegex(new internal::RE(regex)); +template +PolymorphicMatcher MatchesRegex( + const internal::StringLike& regex) { + return MatchesRegex(new internal::RE(std::string(regex))); } // Matches a string that contains regular expression 'regex'. @@ -9557,9 +6958,10 @@ inline PolymorphicMatcher ContainsRegex( const internal::RE* regex) { return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); } -inline PolymorphicMatcher ContainsRegex( - const std::string& regex) { - return ContainsRegex(new internal::RE(regex)); +template +PolymorphicMatcher ContainsRegex( + const internal::StringLike& regex) { + return ContainsRegex(new internal::RE(std::string(regex))); } // Creates a polymorphic matcher that matches anything equal to x. @@ -9621,7 +7023,7 @@ inline internal::NeMatcher Ne(Rhs x) { GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 -#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ #include #include @@ -9885,7 +7287,7 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ namespace testing { @@ -10037,11 +7439,10 @@ GTEST_API_ bool InDeathTestChild(); class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); + ExitedWithCode(const ExitedWithCode&) = default; + void operator=(const ExitedWithCode& other) = delete; bool operator()(int exit_status) const; private: - // No implementation - assignment is unsupported. - void operator=(const ExitedWithCode& other); - const int exit_code_; }; @@ -10187,7 +7588,7 @@ class GTEST_API_ KilledBySignal { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2008, Google Inc. // All rights reserved. // @@ -10220,12 +7621,9 @@ class GTEST_API_ KilledBySignal { // Macros and functions for implementing parameterized tests // in Google C++ Testing and Mocking Framework (Google Test) // -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. @@ -10397,23 +7795,206 @@ TEST_P(DerivedTest, DoesBlah) { // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Type and function utilities for implementing parameterized tests. +// Type and function utilities for implementing parameterized tests. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name == nullptr ? "" : a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) {} + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { + return file_name_.empty() ? nullptr : file_name_.c_str(); + } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } + + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true if and only if the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true if and only if the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static std::string ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // "" if the source file is unknown. + std::string file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + std::string summary_; // The test failure summary. + std::string message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class GTEST_API_ TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; -// GOOGLETEST_CM0001 DO NOT DELETE + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +} // namespace internal -#include +} // namespace testing -#include -#include -#include -#include -#include -#include -#include +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ namespace testing { // Input to a parameterized test name generator, describing a test parameter. @@ -10823,7 +8404,7 @@ class ParameterizedTestSuiteInfoBase { // Base part of test suite name for display purposes. virtual const std::string& GetTestSuiteName() const = 0; - // Test case id to verify identity. + // Test suite id to verify identity. virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test suite right before running them in RUN_ALL_TESTS macro. @@ -10838,6 +8419,17 @@ class ParameterizedTestSuiteInfoBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Report a the name of a test_suit as safe to ignore +// as the side effect of construction of this type. +struct MarkAsIgnored { + explicit MarkAsIgnored(const char* test_suite); +}; + +GTEST_API_ void InsertSyntheticTestCase(const std::string& name, + CodeLocation location, bool has_test_p); + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P @@ -10860,11 +8452,11 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { CodeLocation code_location) : test_suite_name_(name), code_location_(code_location) {} - // Test case base name for display purposes. + // Test suite base name for display purposes. const std::string& GetTestSuiteName() const override { return test_suite_name_; } - // Test case id to verify identity. + // Test suite id to verify identity. TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. @@ -10873,9 +8465,10 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test suite base name and DoBar is test base name. void AddTestPattern(const char* test_suite_name, const char* test_base_name, - TestMetaFactoryBase* meta_factory) { - tests_.push_back(std::shared_ptr( - new TestInfo(test_suite_name, test_base_name, meta_factory))); + TestMetaFactoryBase* meta_factory, + CodeLocation code_location) { + tests_.push_back(std::shared_ptr(new TestInfo( + test_suite_name, test_base_name, meta_factory, code_location))); } // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. @@ -10888,11 +8481,13 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test suite - // test suites right before running tests in RUN_ALL_TESTS macro. + // right before running tests in RUN_ALL_TESTS macro. // This method should not be called more than once on any single // instance of a ParameterizedTestSuiteInfoBase derived class. // UnitTest has a guard to prevent from calling this method more than once. void RegisterTests() override { + bool generated_instantiations = false; + for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { std::shared_ptr test_info = *test_it; @@ -10915,6 +8510,8 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { + generated_instantiations = true; + Message test_name_stream; std::string param_name = name_func( @@ -10938,7 +8535,7 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { MakeAndRegisterTestInfo( test_suite_name.c_str(), test_name_stream.GetString().c_str(), nullptr, // No type parameter. - PrintToString(*param_it).c_str(), code_location_, + PrintToString(*param_it).c_str(), test_info->code_location, GetTestSuiteTypeId(), SuiteApiResolver::GetSetUpCaseOrSuite(file, line), SuiteApiResolver::GetTearDownCaseOrSuite(file, line), @@ -10946,6 +8543,12 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { } // for param_it } // for gen_it } // for test_it + + if (!generated_instantiations) { + // There are no generaotrs, or they all generate nothing ... + InsertSyntheticTestCase(GetTestSuiteName(), code_location_, + !tests_.empty()); + } } // RegisterTests private: @@ -10953,14 +8556,17 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) + TestMetaFactoryBase* a_test_meta_factory, + CodeLocation a_code_location) : test_suite_base_name(a_test_suite_base_name), test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} + test_meta_factory(a_test_meta_factory), + code_location(a_code_location) {} const std::string test_suite_base_name; const std::string test_base_name; const std::unique_ptr > test_meta_factory; + const CodeLocation code_location; }; using TestInfoContainer = ::std::vector >; // Records data received from INSTANTIATE_TEST_SUITE_P macros: @@ -11083,6 +8689,34 @@ class ParameterizedTestSuiteRegistry { GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); }; +// Keep track of what type-parameterized test suite are defined and +// where as well as which are intatiated. This allows susequently +// identifying suits that are defined but never used. +class TypeParameterizedTestSuiteRegistry { + public: + // Add a suite definition + void RegisterTestSuite(const char* test_suite_name, + CodeLocation code_location); + + // Add an instantiation of a suit. + void RegisterInstantiation(const char* test_suite_name); + + // For each suit repored as defined but not reported as instantiation, + // emit a test that reports that fact (configurably, as an error). + void CheckForInstantiations(); + + private: + struct TypeParameterizedTestSuiteInfo { + explicit TypeParameterizedTestSuiteInfo(CodeLocation c) + : code_location(c), instantiated(false) {} + + CodeLocation code_location; + bool instantiated; + }; + + std::map suites_; +}; + } // namespace internal // Forward declarations of ValuesIn(), which is implemented in @@ -11094,10 +8728,15 @@ internal::ParamGenerator ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template class ValueArray { public: - ValueArray(Ts... v) : v_{std::move(v)...} {} + explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {} template operator ParamGenerator() const { // NOLINT @@ -11113,6 +8752,10 @@ class ValueArray { FlatTuple v_; }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + template class CartesianProductGenerator : public ParamGeneratorInterface<::std::tuple> { @@ -11246,7 +8889,7 @@ class CartesianProductHolder { } // namespace internal } // namespace testing -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ namespace testing { @@ -11438,8 +9081,6 @@ inline internal::ParamGenerator Bool() { // std::tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // -// Combine can have up to 10 arguments. -// // Example: // // This will instantiate tests in test suite AnimalTest each one with @@ -11483,19 +9124,20 @@ internal::CartesianProductHolder Combine(const Generator&... g) { : public test_suite_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ - virtual void TestBody(); \ + void TestBody() override; \ \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance() \ ->parameterized_test_registry() \ .GetTestSuitePatternHolder( \ - #test_suite_name, \ + GTEST_STRINGIFY_(test_suite_name), \ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ ->AddTestPattern( \ GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ new ::testing::internal::TestMetaFactory()); \ + test_suite_name, test_name)>(), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)); \ return 0; \ } \ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ @@ -11550,13 +9192,21 @@ internal::CartesianProductHolder Combine(const Generator&... g) { ::testing::UnitTest::GetInstance() \ ->parameterized_test_registry() \ .GetTestSuitePatternHolder( \ - #test_suite_name, \ + GTEST_STRINGIFY_(test_suite_name), \ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ ->AddTestSuiteInstantiation( \ - #prefix, >est_##prefix##test_suite_name##_EvalGenerator_, \ + GTEST_STRINGIFY_(prefix), \ + >est_##prefix##test_suite_name##_EvalGenerator_, \ >est_##prefix##test_suite_name##_EvalGenerateName_, \ __FILE__, __LINE__) + +// Allow Marking a Parameterized test class as not needing to be instantiated. +#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \ + namespace gtest_do_not_use_outside_namespace_scope {} \ + static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \ + GTEST_STRINGIFY_(T)) + // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TEST_CASE_P \ @@ -11567,7 +9217,7 @@ internal::CartesianProductHolder Combine(const Generator&... g) { } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Copyright 2006, Google Inc. // All rights reserved. // @@ -11601,8 +9251,8 @@ internal::CartesianProductHolder Combine(const Generator&... g) { // Google C++ Testing and Mocking Framework definitions useful in production code. // GOOGLETEST_CM0003 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the @@ -11628,189 +9278,7 @@ internal::CartesianProductHolder Combine(const Generator&... g) { #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ - -#include -#include - -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ -/* class A needs to have dll-interface to be used by clients of class B */) - -namespace testing { - -// A copyable object representing the result of a test part (i.e. an -// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). -// -// Don't inherit from TestPartResult as its destructor is not virtual. -class GTEST_API_ TestPartResult { - public: - // The possible outcomes of a test part (i.e. an assertion or an - // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). - enum Type { - kSuccess, // Succeeded. - kNonFatalFailure, // Failed but the test can continue. - kFatalFailure, // Failed and the test should be terminated. - kSkip // Skipped. - }; - - // C'tor. TestPartResult does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestPartResult object. - TestPartResult(Type a_type, const char* a_file_name, int a_line_number, - const char* a_message) - : type_(a_type), - file_name_(a_file_name == nullptr ? "" : a_file_name), - line_number_(a_line_number), - summary_(ExtractSummary(a_message)), - message_(a_message) {} - - // Gets the outcome of the test part. - Type type() const { return type_; } - - // Gets the name of the source file where the test part took place, or - // NULL if it's unknown. - const char* file_name() const { - return file_name_.empty() ? nullptr : file_name_.c_str(); - } - - // Gets the line in the source file where the test part took place, - // or -1 if it's unknown. - int line_number() const { return line_number_; } - - // Gets the summary of the failure message. - const char* summary() const { return summary_.c_str(); } - - // Gets the message associated with the test part. - const char* message() const { return message_.c_str(); } - - // Returns true if and only if the test part was skipped. - bool skipped() const { return type_ == kSkip; } - - // Returns true if and only if the test part passed. - bool passed() const { return type_ == kSuccess; } - - // Returns true if and only if the test part non-fatally failed. - bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - - // Returns true if and only if the test part fatally failed. - bool fatally_failed() const { return type_ == kFatalFailure; } - - // Returns true if and only if the test part failed. - bool failed() const { return fatally_failed() || nonfatally_failed(); } - - private: - Type type_; - - // Gets the summary of the failure message by omitting the stack - // trace in it. - static std::string ExtractSummary(const char* message); - - // The name of the source file where the test part took place, or - // "" if the source file is unknown. - std::string file_name_; - // The line in the source file where the test part took place, or -1 - // if the line number is unknown. - int line_number_; - std::string summary_; // The test failure summary. - std::string message_; // The test failure message. -}; - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result); - -// An array of TestPartResult objects. -// -// Don't inherit from TestPartResultArray as its destructor is not -// virtual. -class GTEST_API_ TestPartResultArray { - public: - TestPartResultArray() {} - - // Appends the given TestPartResult to the array. - void Append(const TestPartResult& result); - - // Returns the TestPartResult at the given index (0-based). - const TestPartResult& GetTestPartResult(int index) const; - - // Returns the number of TestPartResult objects in the array. - int size() const; - - private: - std::vector array_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); -}; - -// This interface knows how to report a test part result. -class GTEST_API_ TestPartResultReporterInterface { - public: - virtual ~TestPartResultReporterInterface() {} - - virtual void ReportTestPartResult(const TestPartResult& result) = 0; -}; - -namespace internal { - -// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a -// statement generates new fatal failures. To do so it registers itself as the -// current test part result reporter. Besides checking if fatal failures were -// reported, it only delegates the reporting to the former result reporter. -// The original result reporter is restored in the destructor. -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -class GTEST_API_ HasNewFatalFailureHelper - : public TestPartResultReporterInterface { - public: - HasNewFatalFailureHelper(); - ~HasNewFatalFailureHelper() override; - void ReportTestPartResult(const TestPartResult& result) override; - bool has_new_fatal_failure() const { return has_new_fatal_failure_; } - private: - bool has_new_fatal_failure_; - TestPartResultReporterInterface* original_reporter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); -}; - -} // namespace internal - -} // namespace testing - -GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 - -#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ // Copyright 2008 Google Inc. // All Rights Reserved. // @@ -11840,11 +9308,10 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. @@ -11986,8 +9453,6 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // Implements typed tests. -#if GTEST_HAS_TYPED_TEST - // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the @@ -11999,24 +9464,25 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); #define GTEST_NAME_GENERATOR_(TestSuiteName) \ gtest_type_params_##TestSuiteName##_NameGenerator -#define TYPED_TEST_SUITE(CaseName, Types, ...) \ - typedef ::testing::internal::TypeList::type GTEST_TYPE_PARAMS_( \ - CaseName); \ - typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::GenerateTypeList::type \ + GTEST_TYPE_PARAMS_(CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ GTEST_NAME_GENERATOR_(CaseName) -# define TYPED_TEST(CaseName, TestName) \ +#define TYPED_TEST(CaseName, TestName) \ + static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \ + "test-name must not be empty"); \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ + void TestBody() override; \ }; \ static bool gtest_##CaseName##_##TestName##_registered_ \ - GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ + GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel, \ @@ -12024,7 +9490,8 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); CaseName)>::Register("", \ ::testing::internal::CodeLocation( \ __FILE__, __LINE__), \ - #CaseName, #TestName, 0, \ + GTEST_STRINGIFY_(CaseName), \ + GTEST_STRINGIFY_(TestName), 0, \ ::testing::internal::GenerateNames< \ GTEST_NAME_GENERATOR_(CaseName), \ GTEST_TYPE_PARAMS_(CaseName)>()); \ @@ -12039,12 +9506,8 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); TYPED_TEST_SUITE #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#endif // GTEST_HAS_TYPED_TEST - // Implements type-parameterized tests. -#if GTEST_HAS_TYPED_TEST_P - // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for @@ -12087,24 +9550,26 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); private: \ typedef SuiteName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ + void TestBody() override; \ }; \ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ - __FILE__, __LINE__, #SuiteName, #TestName); \ + __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ + GTEST_STRINGIFY_(TestName)); \ } \ template \ void GTEST_SUITE_NAMESPACE_( \ SuiteName)::TestName::TestBody() -#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ - namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_( \ - SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ - __FILE__, __LINE__, #__VA_ARGS__) +// Note: this won't work correctly if the trailing arguments are macros. +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ + GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ @@ -12115,18 +9580,21 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \ + "test-suit-prefix must not be empty"); \ static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestSuite< \ SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ - ::testing::internal::TypeList::type>:: \ - Register(#Prefix, \ + ::testing::internal::GenerateTypeList::type>:: \ + Register(GTEST_STRINGIFY_(Prefix), \ ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \ + GTEST_STRINGIFY_(SuiteName), \ GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ ::testing::internal::GenerateNames< \ ::testing::internal::NameGeneratorSelector< \ __VA_ARGS__>::type, \ - ::testing::internal::TypeList::type>()) + ::testing::internal::GenerateTypeList::type>()) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ @@ -12136,9 +9604,7 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); INSTANTIATE_TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#endif // GTEST_HAS_TYPED_TEST_P - -#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) @@ -12171,6 +9637,10 @@ GTEST_DECLARE_bool_(catch_exceptions); // to let Google Test decide. GTEST_DECLARE_string_(color); +// This flag controls whether the test runner should continue execution past +// first failure. +GTEST_DECLARE_bool_(fail_fast); + // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); @@ -12187,6 +9657,9 @@ GTEST_DECLARE_bool_(list_tests); // in addition to its normal textual output. GTEST_DECLARE_string_(output); +// This flags control whether Google Test prints only test failures. +GTEST_DECLARE_bool_(brief); + // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); @@ -12247,6 +9720,7 @@ class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); +std::set* GetIgnoredParameterizedTestSuites(); } // namespace internal @@ -12352,7 +9826,11 @@ class GTEST_API_ AssertionResult { // Used in EXPECT_TRUE/FALSE_MPI(assertion_result). AssertionResult(const AssertionResult& other, bool global); -#if defined(_MSC_VER) && _MSC_VER < 1910 +// C4800 is a level 3 warning in Visual Studio 2015 and earlier. +// This warning is not emitted in Visual Studio 2017. +// This warning is off by default starting in Visual Studio 2019 but can be +// enabled with command-line options. +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) #endif @@ -12385,7 +9863,7 @@ class GTEST_API_ AssertionResult { #endif } -#if defined(_MSC_VER) && _MSC_VER < 1910 +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) GTEST_DISABLE_MSC_WARNINGS_POP_() #endif @@ -12499,8 +9977,8 @@ GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // Implements a family of generic predicate assertion macros. // GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ namespace testing { @@ -12834,7 +10312,7 @@ AssertionResult AssertPred5Helper(const char* pred_text, } // namespace testing -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ namespace testing { @@ -12868,27 +10346,24 @@ class GTEST_API_ Test { // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); - // Sets up the stuff shared by all tests in this test case. + // Sets up the stuff shared by all tests in this test suite. // // Google Test will call Foo::SetUpTestSuite() before running the first - // test in test case Foo. Hence a sub-class can define its own + // test in test suite Foo. Hence a sub-class can define its own // SetUpTestSuite() method to shadow the one defined in the super // class. - // Failures that happen during SetUpTestSuite are logged but otherwise - // ignored. static void SetUpTestSuite() {} // Tears down the stuff shared by all tests in this test suite. // // Google Test will call Foo::TearDownTestSuite() after running the last - // test in test case Foo. Hence a sub-class can define its own + // test in test suite Foo. Hence a sub-class can define its own // TearDownTestSuite() method to shadow the one defined in the super // class. - // Failures that happen during TearDownTestSuite are logged but otherwise - // ignored. static void TearDownTestSuite() {} - // Legacy API is deprecated but still available + // Legacy API is deprecated but still available. Use SetUpTestSuite and + // TearDownTestSuite instead. #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} static void SetUpTestCase() {} @@ -13268,6 +10743,9 @@ class GTEST_API_ TestInfo { // deletes it. void Run(); + // Skip and records the test result for this object. + void Skip(); + static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } @@ -13363,7 +10841,9 @@ class GTEST_API_ TestSuite { bool Passed() const { return !Failed(); } // Returns true if and only if the test suite failed. - bool Failed() const { return failed_test_count() > 0; } + bool Failed() const { + return failed_test_count() > 0 || ad_hoc_test_result().Failed(); + } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } @@ -13414,6 +10894,9 @@ class GTEST_API_ TestSuite { // Runs every test in this TestSuite. void Run(); + // Skips the execution of tests under this TestSuite + void Skip(); + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed // for catching exceptions thrown from SetUpTestSuite(). void RunSetUpTestSuite() { @@ -13894,6 +11377,7 @@ class GTEST_API_ UnitTest { friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); + friend std::set* internal::GetIgnoredParameterizedTestSuites(); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, @@ -14008,14 +11492,6 @@ AssertionResult CmpHelperEQ(const char* lhs_expression, return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs, global); } -// With this overloaded version, we allow anonymous enums to be used -// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums -// can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, - const char* rhs_expression, - BiggestInt lhs, - BiggestInt rhs); - class EqHelper { public: // This templatized version is for the general case. @@ -14076,11 +11552,6 @@ AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // -// For each templatized helper function, we also define an overloaded -// version for BiggestInt in order to reduce code bloat and allow -// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled -// with gcc 4. -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ @@ -14093,21 +11564,19 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op, global);\ }\ }\ -GTEST_API_ AssertionResult CmpHelper##op_name(\ - const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2, bool global = false) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE -GTEST_IMPL_CMP_HELPER_(NE, !=); +GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE -GTEST_IMPL_CMP_HELPER_(LE, <=); +GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT -GTEST_IMPL_CMP_HELPER_(LT, <); +GTEST_IMPL_CMP_HELPER_(LT, <) // Implements the helper function for {ASSERT|EXPECT}_GE -GTEST_IMPL_CMP_HELPER_(GE, >=); +GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT -GTEST_IMPL_CMP_HELPER_(GT, >); +GTEST_IMPL_CMP_HELPER_(GT, >) #undef GTEST_IMPL_CMP_HELPER_ @@ -14298,12 +11767,6 @@ class GTEST_API_ AssertHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; -enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; - -GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, - const char* fmt, - ...); - } // namespace internal // The pure interface class that all value-parameterized tests inherit from. @@ -14384,7 +11847,7 @@ class TestWithParam : public Test, public WithParamInterface { // Skips test in runtime. // Skipping test aborts current function. // Skipped tests are neither successful nor failed. -#define GTEST_SKIP() GTEST_SKIP_("Skipped") +#define GTEST_SKIP() GTEST_SKIP_("") // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the @@ -14887,8 +12350,7 @@ class GTEST_API_ ScopedTrace { // to cause a compiler error. template constexpr bool StaticAssertTypeEq() noexcept { - static_assert(std::is_same::value, - "type1 and type2 are not the same type"); + static_assert(std::is_same::value, "T1 and T2 are not the same type"); return true; } @@ -14954,9 +12416,11 @@ constexpr bool StaticAssertTypeEq() noexcept { // } // // GOOGLETEST_CM0011 DO NOT DELETE +#if !GTEST_DONT_DEFINE_TEST #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +#endif // !GTEST_DONT_DEFINE_TEST // Returns a path to temporary directory. // Tries to determine an appropriate directory for the platform. @@ -15064,4 +12528,4 @@ inline int RUN_ALL_TESTS() { GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_ diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt new file mode 100644 index 0000000000..9d291eb3d3 --- /dev/null +++ b/tutorials/CMakeLists.txt @@ -0,0 +1,24 @@ +function( add_t8_tutorial ) + set( options "" ) + set( oneValueArgs "NAME" ) + set( multiValueArgs "SOURCES" ) + cmake_parse_arguments( ADD_T8_TUTORIAL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + add_executable( ${ADD_T8_TUTORIAL_NAME} ${ADD_T8_TUTORIAL_SOURCES} ) + target_link_libraries( ${ADD_T8_TUTORIAL_NAME} PRIVATE T8 SC::SC ) + target_include_directories( ${ADD_T8_TUTORIAL_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. ) + + install( TARGETS ${ADD_T8_TUTORIAL_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/tutorials ) +endfunction() + +add_t8_tutorial( NAME t8_step0_helloworld SOURCES general/t8_step0_helloworld.cxx ) +add_t8_tutorial( NAME t8_step1_coarsemesh SOURCES general/t8_step1_coarsemesh.cxx ) +add_t8_tutorial( NAME t8_step2_uniform_forest SOURCES general/t8_step2_uniform_forest.cxx ) +add_t8_tutorial( NAME t8_step3_adapt_forest SOURCES general/t8_step3_main.cxx general/t8_step3_adapt_forest.cxx ) +add_t8_tutorial( NAME t8_step4_partition_balance_ghost SOURCES general/t8_step4_main.cxx general/t8_step3_adapt_forest.cxx general/t8_step4_partition_balance_ghost.cxx ) +add_t8_tutorial( NAME t8_step5_element_data SOURCES general/t8_step5_main.cxx general/t8_step3_adapt_forest.cxx general/t8_step5_element_data.cxx ) +add_t8_tutorial( NAME t8_step6_stencil SOURCES general/t8_step6_main.cxx general/t8_step3_adapt_forest.cxx general/t8_step6_stencil.cxx ) +add_t8_tutorial( NAME t8_step7_interpolation SOURCES general/t8_step7_main.cxx general/t8_step7_interpolation.cxx ) +add_t8_tutorial( NAME t8_tutorial_build_cmesh SOURCES general/t8_tutorial_build_cmesh.cxx general/t8_tutorial_build_cmesh_main.cxx) +add_t8_tutorial( NAME t8_tutorial_search SOURCES general/t8_tutorial_search.cxx general/t8_step3_adapt_forest.cxx ) +add_t8_tutorial( NAME t8_features_curved_meshes SOURCES features/t8_features_curved_meshes.cxx) \ No newline at end of file diff --git a/tutorials/features/t8_features_curved_meshes.cxx b/tutorials/features/t8_features_curved_meshes.cxx index abb24370a6..acd428ef0e 100644 --- a/tutorials/features/t8_features_curved_meshes.cxx +++ b/tutorials/features/t8_features_curved_meshes.cxx @@ -43,7 +43,7 @@ #include /* geometrical information of the forest */ #include /* default refinement scheme. */ #include /* Linear geometry calculation of trees */ -#include /* Curved geometry calculation of trees */ +#include /* Curved geometry calculation of trees */ #include /* msh file reader */ #include /* std::string */ #include /* std::array */ @@ -109,7 +109,7 @@ t8_naca_geometry_adapt_callback (t8_forest_t forest, t8_forest_t forest_from, t8 const int element_dim = t8_eclass_to_dimension[ts->eclass]; /* We retrieve the geometry information of the tree. * In the 3D case, we look for linked surfaces, but in 2D, we look for linked edges. */ - const int attribute_key = element_dim == 3 ? T8_CMESH_OCC_FACE_ATTRIBUTE_KEY : T8_CMESH_OCC_EDGE_ATTRIBUTE_KEY; + const int attribute_key = element_dim == 3 ? T8_CMESH_CAD_FACE_ATTRIBUTE_KEY : T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY; const int *linked_geometries = (const int *) t8_cmesh_get_attribute ( t8_forest_get_cmesh (forest), t8_get_package_id (), attribute_key, cmesh_ltreeid); /* If the tree face has a linked surface and it is in the list we refine it */ @@ -346,7 +346,7 @@ main (int argc, char **argv) int geometry; /** Activates the geometry refinement mode */ int plane; /** Activates the plane refinement mode */ int steps; /** The amount of time steps the plane makes */ - int occ; /** Activates the curved mesh in the plane mode */ + int cad; /** Activates the curved mesh in the plane mode */ int dim; /** The dimension of the mesh */ double xmin; /** The starting x-coordinate of the refinement plane */ double xmax; /** The ending x-coordinate of the refinement plane */ @@ -414,8 +414,8 @@ main (int argc, char **argv) sc_options_add_int (opt, 'r', "plane_level", &rlevel_plane, 3, "The refinement level of the plane. Default: 3"); sc_options_add_int (opt, 'n', "timesteps", &steps, 10, "How many steps the plane takes to move through the airfoil. Default: 10"); - sc_options_add_switch (opt, 'o', "occ", &occ, - "Use the occ geometry. In the geometry mode this is enabled automatically."); + sc_options_add_switch (opt, 'o', "cad", &cad, + "Use the cad geometry. In the geometry mode this is enabled automatically."); parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); if (helpme) { /* display help message and usage */ @@ -437,7 +437,7 @@ main (int argc, char **argv) else { std::string fp (fileprefix); /* Read in the naca mesh from the msh file and the naca geometry from the brep file */ - cmesh = t8_cmesh_from_msh_file (fp.c_str (), 0, sc_MPI_COMM_WORLD, dim, 0, occ || geometry); + cmesh = t8_cmesh_from_msh_file (fp.c_str (), 0, sc_MPI_COMM_WORLD, dim, 0, cad || geometry); /* Construct a forest from the cmesh */ forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default_cxx (), level, 0, comm); T8_ASSERT (t8_forest_is_committed (forest)); @@ -445,7 +445,7 @@ main (int argc, char **argv) t8_naca_geometry_refinement (forest, fp, level, rlevel_dorsal, rlevel_ventral, dim); } if (plane) { - t8_naca_plane_refinement (forest, fp, level, rlevel_plane, steps, thickness, xmin, xmax, occ); + t8_naca_plane_refinement (forest, fp, level, rlevel_plane, steps, thickness, xmin, xmax, cad); } } sc_options_destroy (opt); diff --git a/tutorials/general/t8_step1_coarsemesh.cxx b/tutorials/general/t8_step1_coarsemesh.cxx index 093bd862b8..736439a94f 100644 --- a/tutorials/general/t8_step1_coarsemesh.cxx +++ b/tutorials/general/t8_step1_coarsemesh.cxx @@ -76,7 +76,7 @@ t8_step1_build_tetcube_coarse_mesh (sc_MPI_Comm comm) static void t8_step1_write_cmesh_vtk (t8_cmesh_t cmesh, const char *prefix) { - t8_cmesh_vtk_write_file (cmesh, prefix, 1.0); + t8_cmesh_vtk_write_file (cmesh, prefix); } /* Destroy a cmesh. This will free all allocated memory. diff --git a/tutorials/general/t8_tutorial_build_cmesh.cxx b/tutorials/general/t8_tutorial_build_cmesh.cxx index 3461e0f9ae..f3fa5d8ed5 100644 --- a/tutorials/general/t8_tutorial_build_cmesh.cxx +++ b/tutorials/general/t8_tutorial_build_cmesh.cxx @@ -492,9 +492,9 @@ t8_tutorial_build_cmesh_main (int argc, char **argv) t8_global_productionf ("[tutorial] A 3D hybrid cmesh (in style of a gate) has been created.\n"); /* Output the meshes to vtu files. */ - t8_cmesh_vtk_write_file (cmesh_2D, prefix_2D, 1.0); + t8_cmesh_vtk_write_file (cmesh_2D, prefix_2D); t8_global_productionf ("[tutorial] Wrote the 2D cmesh to vtu files.\n"); - t8_cmesh_vtk_write_file (cmesh_3D, prefix_3D, 1.0); + t8_cmesh_vtk_write_file (cmesh_3D, prefix_3D); t8_global_productionf ("[tutorial] Wrote the 3D cmesh to vtu files.\n"); /* diff --git a/tutorials/general/t8_tutorial_search.cxx b/tutorials/general/t8_tutorial_search.cxx index 3e0ab08d38..07064e08f7 100644 --- a/tutorials/general/t8_tutorial_search.cxx +++ b/tutorials/general/t8_tutorial_search.cxx @@ -96,7 +96,7 @@ * |_*|_*| * * The search continues with the children of the upper left element. - * Those are all leafs in the forest and hence the search will stop after + * 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. @@ -202,8 +202,9 @@ t8_tutorial_search_query_callback (t8_forest_t forest, const t8_locidx_t ltreeid T8_ASSERT (particles_per_element != NULL); T8_ASSERT (query != NULL); - /* Test whether the particles are inside this element. */ - t8_forest_element_point_batch_inside (forest, ltreeid, element, coords, num_active_queries, query_matches, tolerance); + /* Test whether this particle is inside this element. */ + t8_forest_element_points_inside (forest, ltreeid, element, coords, num_active_queries, query_matches, tolerance); + T8_FREE (coords); for (size_t matches_id = 0; matches_id < num_active_queries; matches_id++) { if (query_matches[matches_id]) {