diff --git a/benchmarks/time_forest_partition.cxx b/benchmarks/time_forest_partition.cxx index a8a11a0b0d..674ee56734 100644 --- a/benchmarks/time_forest_partition.cxx +++ b/benchmarks/time_forest_partition.cxx @@ -340,7 +340,7 @@ main (int argc, char *argv[]) int level, level_diff; int help = 0, no_vtk, do_ghost, do_balance, use_cad; int dim, num_files; - int test_tet, test_linear_cylinder, test_cad_cylinder; + int test_tet, test_linear_cylinder, test_cad_cylinder, test_hybrid_cube, test_hex_cube; int stride; int cmesh_level; double T, delta_t, cfl; @@ -390,6 +390,12 @@ main (int argc, char *argv[]) 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_switch (opt, 'C', "test-hybridcube", &test_hybrid_cube, + "Use a hypercube with Hybercube with Tets, Prism and Hex elements as cmesh." + " If this option is used -o is enabled automatically. Not allowed with -f and -c."); + sc_options_add_switch (opt, 'H', "test-hexcube", &test_hex_cube, + "Use a hypercube with Hex elements as cmesh." + " 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."); @@ -415,11 +421,12 @@ main (int argc, char *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_cad_cylinder == 0 - && test_linear_cylinder == 0) + && test_linear_cylinder == 0 && test_hybrid_cube == 0 && test_hex_cube == 0) || stride <= 0 || (num_files - 1) * stride >= mpisize || cfl < 0 || T <= 0 - || 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)) + || test_tet + test_linear_cylinder + test_cad_cylinder + test_hybrid_cube + test_hex_cube > 1 + || (cmesh_level >= 0 && (!test_linear_cylinder && !test_cad_cylinder && !test_hybrid_cube && !test_hex_cube)) + || ((mshfileprefix != NULL || cmeshfileprefix != NULL) + && (test_linear_cylinder || test_cad_cylinder || test_tet || test_hybrid_cube || test_hex_cube)) || (mshfileprefix == NULL && use_cad)) { sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); return 1; @@ -454,6 +461,14 @@ main (int argc, char *argv[]) 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 if (test_hybrid_cube) { + cmesh = t8_cmesh_new_hypercube_hybrid (sc_MPI_COMM_WORLD, 0, 0); + vtu_prefix = "test_hypercube_hybrid"; + } + else if (test_hex_cube) { + cmesh = t8_cmesh_new_hypercube (T8_ECLASS_HEX, sc_MPI_COMM_WORLD, 0, 0, 0); + vtu_prefix = "test_hypercube_hex"; + } else { T8_ASSERT (cmeshfileprefix != NULL); cmesh diff --git a/doc/author_henricpetri.txt b/doc/author_henricpetri.txt new file mode 100644 index 0000000000..6233a6ba6a --- /dev/null +++ b/doc/author_henricpetri.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Antje Henric-Petri (antje.henric-petri@dlr.de) diff --git a/src/Makefile.am b/src/Makefile.am index 00d6f18b19..58cbcc3342 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,12 @@ libt8_installed_headers_forest = \ src/t8_forest/t8_forest_profiling.h \ src/t8_forest/t8_forest_io.h \ src/t8_forest/t8_forest_adapt.h \ - src/t8_forest/t8_forest_iterate.h src/t8_forest/t8_forest_partition.h + src/t8_forest/t8_forest_iterate.h src/t8_forest/t8_forest_partition.h \ + src/t8_forest/t8_forest_ghost_interface_wrapper.h \ + src/t8_forest/t8_forest_ghost_interface.h \ + src/t8_forest/t8_forest_ghost_interface.hxx \ + src/t8_forest/t8_forest_ghost_search.hxx \ + src/t8_forest/t8_forest_ghost_stencil.hxx libt8_installed_headers_geometry = \ src/t8_geometry/t8_geometry.h \ src/t8_geometry/t8_geometry_handler.hxx \ diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index e120c0d6ae..c060586dc7 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 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 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #include #include #include +#include +#include #if T8_ENABLE_DEBUG #include #include @@ -2948,6 +2951,18 @@ t8_forest_set_balance (t8_forest_t forest, const t8_forest_t set_from, int no_re } } +void +t8_forest_set_ghost_ext_new (t8_forest_t forest, const int do_ghost, t8_forest_ghost_interface_c *ghost_interface) +{ + T8_ASSERT (t8_forest_is_initialized (forest)); + T8_ASSERT (!(do_ghost == 1 && ghost_interface == NULL)); + if (forest->ghost_interface != NULL) { + t8_forest_ghost_interface_unref (&(forest->ghost_interface)); + } + forest->do_ghost = do_ghost; + forest->ghost_interface = ghost_interface; +} + void t8_forest_set_ghost_ext (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type, int ghost_version) { @@ -2965,8 +2980,8 @@ t8_forest_set_ghost_ext (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost forest->do_ghost = (do_ghost != 0); /* True if and only if do_ghost != 0 */ } if (forest->do_ghost) { - forest->ghost_type = ghost_type; - forest->ghost_algorithm = ghost_version; + t8_forest_ghost_interface_c *ghost_interface = t8_forest_ghost_interface_face_new (ghost_version); + t8_forest_set_ghost_ext_new (forest, do_ghost, ghost_interface); } } @@ -3230,6 +3245,11 @@ t8_forest_commit (t8_forest_t forest) forest->scheme_cxx = forest->set_from->scheme_cxx; forest->global_num_trees = forest->set_from->global_num_trees; + if (forest->ghost_interface == NULL && forest->set_from->ghost_interface != NULL) { + forest->ghost_interface = forest->set_from->ghost_interface; + t8_forest_ghost_interface_ref (forest->ghost_interface); + } + /* Compute the maximum allowed refinement level */ t8_forest_compute_maxlevel (forest); if (forest->from_method == T8_FOREST_FROM_COPY) { @@ -3383,19 +3403,7 @@ t8_forest_commit (t8_forest_t forest) /* Construct a ghost layer, if desired */ if (forest->do_ghost) { /* TODO: ghost type */ - switch (forest->ghost_algorithm) { - case 1: - t8_forest_ghost_create_balanced_only (forest); - break; - case 2: - t8_forest_ghost_create (forest); - break; - case 3: - t8_forest_ghost_create_topdown (forest); - break; - default: - SC_ABORT ("Invalid choice of ghost algorithm"); - } + t8_forest_ghost_create_ext (forest); } forest->do_ghost = 0; } @@ -4257,6 +4265,10 @@ t8_forest_reset (t8_forest_t *pforest) if (forest->ghosts != NULL) { t8_forest_ghost_unref (&forest->ghosts); } + /* Destroy the ghost_interface class if it exist */ + if (forest->ghost_interface != NULL) { + t8_forest_ghost_interface_unref (&(forest->ghost_interface)); + } /* we have taken ownership on calling t8_forest_set_* */ if (forest->scheme_cxx != NULL) { t8_scheme_cxx_unref (&forest->scheme_cxx); diff --git a/src/t8_forest/t8_forest_balance.cxx b/src/t8_forest/t8_forest_balance.cxx index 53f6061bd5..fe1d948a5f 100644 --- a/src/t8_forest/t8_forest_balance.cxx +++ b/src/t8_forest/t8_forest_balance.cxx @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 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 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -137,6 +139,7 @@ t8_forest_balance (t8_forest_t forest, int repartition) int count_partition_stats = 0; double ada_time, ghost_time, part_time; sc_statinfo_t *adap_stats, *ghost_stats, *partition_stats; + int create_ghost_interface = 0; /* flag if create ghost_interface */ t8_global_productionf ("Into t8_forest_balance with %lli global elements.\n", (long long) t8_forest_get_global_num_elements (forest->set_from)); @@ -169,9 +172,21 @@ t8_forest_balance (t8_forest_t forest, int repartition) /* This function is reference neutral regarding forest_from */ t8_forest_ref (forest_from); + /* if the set_from forest of forest has no ghost layer computed, + * compute a ghost layer for the set_from forest */ if (forest->set_from->ghosts == NULL) { - forest->set_from->ghost_type = T8_GHOST_FACES; + /* If the forest does not yet have a ghost_interface */ + if (forest->set_from->ghost_interface == NULL) { + /* create a ghost_interface of type face with top-down-search */ + forest->set_from->ghost_interface = t8_forest_ghost_interface_face_new (3); + create_ghost_interface = 1; + } + /* compute ghost layer for set_from forest */ t8_forest_ghost_create_topdown (forest->set_from); + if (create_ghost_interface) { /* if a ghost_interface has been created, it will be deleted here */ + t8_forest_ghost_interface_unref (&(forest->set_from->ghost_interface)); + forest->set_from->ghost_interface = NULL; + } } while (!done_global) { diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index b8aed23f6f..13a41852d6 100644 --- a/src/t8_forest/t8_forest_general.h +++ b/src/t8_forest/t8_forest_general.h @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2024 the developers t8code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ #include #include #include +#include /** Opaque pointer to a forest implementation. */ typedef struct t8_forest *t8_forest_t; @@ -40,10 +41,11 @@ typedef struct t8_tree *t8_tree_t; /** This type controls, which neighbors count as ghost elements. * Currently, we support face-neighbors. Vertex and edge neighbors will eventually be added. */ typedef enum { - T8_GHOST_NONE = 0, /**< Do not create ghost layer. */ - T8_GHOST_FACES, /**< Consider all face (codimension 1) neighbors. */ - T8_GHOST_EDGES, /**< Consider all edge (codimension 2) and face neighbors. */ - T8_GHOST_VERTICES /**< Consider all vertex (codimension 3) and edge and face neighbors. */ + T8_GHOST_NONE = 0, /**< Do not create ghost layer. */ + T8_GHOST_FACES, /**< Consider all face (codimension 1) neighbors. */ + T8_GHOST_EDGES, /**< Consider all edge (codimension 2) and face neighbors. */ + T8_GHOST_VERTICES, /**< Consider all vertex (codimension 3) and edge and face neighbors. */ + T8_GHOST_USERDEFINED /**< for user-defined neighborhoods */ } t8_ghost_type_t; /** This typedef is needed as a helper construct to @@ -363,10 +365,22 @@ t8_forest_set_ghost (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_typ * If 2, the iterative algorithm for unbalanced forests. * If 3, the top-down search algorithm for unbalanced forests. * \see t8_forest_set_ghost + * \note this function creates an ghost_interface obcejct and call \ref t8_forest_set_ghost_ext_new */ void t8_forest_set_ghost_ext (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type, int ghost_version); +/** Set a ghost_interface + * In application schoud only used if the user creates its own ghost_interface class (type = userderdefined) + * \param [in] forest The forest + * \param [in] do_ghost If 0 no ghost layer will be computed + * \param [in] ghost_interface Pointer to an object of the class ghost_interface or a derived class + * The forest takes ownership of the ghost_interface + * \note if the forest has already a ghost_interface, the old one will be unref and the new one will be set. +*/ +void +t8_forest_set_ghost_ext_new (t8_forest_t forest, const int do_ghost, t8_forest_ghost_interface_c *ghost_interface); + /* TODO: use assertions and document that the forest_set (..., from) and * set_load are mutually exclusive. */ void diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index de868e1922..d731599744 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 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 @@ -31,6 +31,11 @@ #include #include +#include +#include +#include +#include + /* We want to export the whole implementation to be callable from "C" */ T8_EXTERN_C_BEGIN (); @@ -172,8 +177,7 @@ t8_forest_ghost_init (t8_forest_ghost_t *pghost, t8_ghost_type_t ghost_type) { t8_forest_ghost_t ghost; - /* We currently only support face-neighbor ghosts */ - T8_ASSERT (ghost_type == T8_GHOST_FACES); + T8_ASSERT (ghost_type != T8_GHOST_NONE); /* Allocate memory for ghost */ ghost = *pghost = T8_ALLOC_ZERO (t8_forest_ghost_struct_t, 1); @@ -634,7 +638,7 @@ t8_forest_ghost_search_boundary (t8_forest_t forest, t8_locidx_t ltreeid, const * remote_ghosts array of ghost. * We also fill the remote_processes here. */ -static void +void t8_forest_ghost_fill_remote_v3 (t8_forest_t forest) { t8_forest_ghost_boundary_data_t data; @@ -678,7 +682,7 @@ t8_forest_ghost_fill_remote_v3 (t8_forest_t forest) * construct the remote processes by looking at the half neighbors of an element. * Otherwise, we use the owners_at_face method. */ -static void +void t8_forest_ghost_fill_remote (t8_forest_t forest, t8_forest_ghost_t ghost, int ghost_method) { t8_element_t **half_neighbors = NULL; @@ -1382,15 +1386,15 @@ t8_forest_ghost_receive (t8_forest_t forest, t8_forest_ghost_t ghost) * for unbalanced_version = -1 */ void -t8_forest_ghost_create_ext (t8_forest_t forest, int unbalanced_version) +t8_forest_ghost_create_ext (t8_forest_t forest) { - t8_forest_ghost_t ghost = NULL; - t8_ghost_mpi_send_info_t *send_info; - sc_MPI_Request *requests; - int create_tree_array = 0, create_gfirst_desc_array = 0; - int create_element_array = 0; + t8_forest_ghost_t ghost; + t8_forest_ghost_interface_c *ghost_interface; T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (forest->ghost_interface != NULL); + + ghost_interface = forest->ghost_interface; t8_global_productionf ("Into t8_forest_ghost with %i local elements.\n", t8_forest_get_local_num_elements (forest)); @@ -1411,66 +1415,10 @@ t8_forest_ghost_create_ext (t8_forest_t forest, int unbalanced_version) * Only delete the line, if you know what you are doing. */ t8_global_productionf ("Start ghost at %f %f\n", sc_MPI_Wtime (), forest->profile->ghost_runtime); } + /* Call the dot_ghost function on the ghost_interface class of the forest to compute the ghost layer */ + ghost_interface->do_ghost (forest); - if (forest->element_offsets == NULL) { - /* create element offset array if not done already */ - create_element_array = 1; - t8_forest_partition_create_offsets (forest); - } - if (forest->tree_offsets == NULL) { - /* Create tree offset array if not done already */ - create_tree_array = 1; - t8_forest_partition_create_tree_offsets (forest); - } - if (forest->global_first_desc == NULL) { - /* Create global first desc array if not done already */ - create_gfirst_desc_array = 1; - t8_forest_partition_create_first_desc (forest); - } - - if (t8_forest_get_local_num_elements (forest) > 0) { - if (forest->ghost_type == T8_GHOST_NONE) { - t8_debugf ("WARNING: Trying to construct ghosts with ghost_type NONE. " - "Ghost layer is not constructed.\n"); - return; - } - /* Currently we only support face ghosts */ - T8_ASSERT (forest->ghost_type == T8_GHOST_FACES); - - /* Initialize the ghost structure */ - t8_forest_ghost_init (&forest->ghosts, forest->ghost_type); - ghost = forest->ghosts; - - if (unbalanced_version == -1) { - t8_forest_ghost_fill_remote_v3 (forest); - } - else { - /* Construct the remote elements and processes. */ - t8_forest_ghost_fill_remote (forest, ghost, unbalanced_version != 0); - } - - /* Start sending the remote elements */ - send_info = t8_forest_ghost_send_start (forest, ghost, &requests); - - /* Receive the ghost elements from the remote processes */ - t8_forest_ghost_receive (forest, ghost); - - /* End sending the remote elements */ - t8_forest_ghost_send_end (forest, ghost, send_info, requests); - } - - if (create_element_array) { - /* Free the offset memory, if created */ - t8_shmem_array_destroy (&forest->element_offsets); - } - if (create_tree_array) { - /* Free the offset memory, if created */ - t8_shmem_array_destroy (&forest->tree_offsets); - } - if (create_gfirst_desc_array) { - /* Free the offset memory, if created */ - t8_shmem_array_destroy (&forest->global_first_desc); - } + ghost = forest->ghosts; if (forest->profile != NULL) { /* If profiling is enabled, we measure the runtime of ghost_create */ @@ -1502,7 +1450,8 @@ t8_forest_ghost_create (t8_forest_t forest) T8_ASSERT (t8_forest_is_committed (forest)); if (forest->mpisize > 1) { /* call unbalanced version of ghost algorithm */ - t8_forest_ghost_create_ext (forest, 1); + T8_ASSERT (t8_forest_ghost_interface_face_version (forest->ghost_interface) == 2); + t8_forest_ghost_create_ext (forest); } } @@ -1513,7 +1462,8 @@ t8_forest_ghost_create_balanced_only (t8_forest_t forest) if (forest->mpisize > 1) { /* TODO: assert that forest is balanced */ /* Call balanced version of ghost algorithm */ - t8_forest_ghost_create_ext (forest, 0); + T8_ASSERT (t8_forest_ghost_interface_face_version (forest->ghost_interface) == 1); + t8_forest_ghost_create_ext (forest); } } @@ -1521,8 +1471,9 @@ void t8_forest_ghost_create_topdown (t8_forest_t forest) { T8_ASSERT (t8_forest_is_committed (forest)); - - t8_forest_ghost_create_ext (forest, -1); + T8_ASSERT (forest->ghost_interface != NULL); + T8_ASSERT (t8_forest_ghost_interface_face_version (forest->ghost_interface) == 3); + t8_forest_ghost_create_ext (forest); } /** Return the array of remote ranks. @@ -1929,4 +1880,343 @@ t8_forest_ghost_destroy (t8_forest_ghost_t *pghost) T8_ASSERT (*pghost == NULL); } +/** + * Implementation of the ghost-interface + * wrapper for the abstract base classes and + * implementation of the communication steps + * and implementation of the derived class search +*/ + +t8_ghost_type_t +t8_forest_ghost_interface_get_type (const t8_forest_ghost_interface_c *ghost_interface) +{ + T8_ASSERT (ghost_interface != NULL); + return ghost_interface->t8_ghost_get_type (); +} + +void +t8_forest_ghost_interface_ref (t8_forest_ghost_interface_c *ghost_interface) +{ + T8_ASSERT (ghost_interface != NULL); + ghost_interface->ref (); +} + +void +t8_forest_ghost_interface_unref (t8_forest_ghost_interface_c **pghost_interface) +{ + t8_forest_ghost_interface_c *ghost_interface; + + T8_ASSERT (pghost_interface != NULL); + ghost_interface = *pghost_interface; + T8_ASSERT (ghost_interface != NULL); + + ghost_interface->unref (); +} + +/** + * Abstract base class +*/ + +void +t8_forest_ghost_interface::communicate_ownerships (t8_forest_t forest) +{ + if (forest->element_offsets == NULL) { + /* create element offset array if not done already */ + memory_flag = memory_flag | CREATE_ELEMENT_ARRAY; + t8_forest_partition_create_offsets (forest); + } + if (forest->tree_offsets == NULL) { + /* Create tree offset array if not done already */ + memory_flag = memory_flag | CREATE_TREE_ARRAY; + t8_forest_partition_create_tree_offsets (forest); + } + if (forest->global_first_desc == NULL) { + /* Create global first desc array if not done already */ + memory_flag = memory_flag | CREATE_GFIRST_DESC_ARRAY; + t8_forest_partition_create_first_desc (forest); + } +} + +void +t8_forest_ghost_interface::communicate_ghost_elements (t8_forest_t forest) +{ + t8_forest_ghost_t ghost = forest->ghosts; + t8_ghost_mpi_send_info_t *send_info; + sc_MPI_Request *requests; + + /* Start sending the remote elements */ + send_info = t8_forest_ghost_send_start (forest, ghost, &requests); + + /* Receive the ghost elements from the remote processes */ + t8_forest_ghost_receive (forest, ghost); + + /* End sending the remote elements */ + t8_forest_ghost_send_end (forest, ghost, send_info, requests); +} + +void +t8_forest_ghost_interface::clean_up (t8_forest_t forest) +{ + if (memory_flag & CREATE_GFIRST_DESC_ARRAY) { + /* Free the offset memory, if created */ + t8_shmem_array_destroy (&forest->element_offsets); + } + if (memory_flag & CREATE_TREE_ARRAY) { + /* Free the offset memory, if created */ + t8_shmem_array_destroy (&forest->tree_offsets); + } + if (memory_flag & CREATE_GFIRST_DESC_ARRAY) { + /* Free the offset memory, if created */ + t8_shmem_array_destroy (&forest->global_first_desc); + } +} + +/** + * Derived class ghost_w_search +*/ + +t8_forest_ghost_w_search::t8_forest_ghost_w_search (const t8_ghost_type_t ghost_type) + : t8_forest_ghost_interface (ghost_type) +{ + T8_ASSERT (ghost_type != T8_GHOST_NONE); + T8_ASSERT (ghost_type == T8_GHOST_FACES); // currently no other types are supported + if (ghost_type == T8_GHOST_FACES) { + search_fn = t8_forest_ghost_search_boundary; + } + SC_CHECK_ABORT (ghost_type != T8_GHOST_USERDEFINED, + "use t8_forest_ghost_w_search(t8_forest_search_fn search_function) for userdefined ghost"); +} + +void +t8_forest_ghost_w_search::do_ghost (t8_forest_t forest) +{ + + communicate_ownerships (forest); + + if (t8_forest_get_local_num_elements (forest) > 0) { + if (t8_ghost_get_type () == T8_GHOST_NONE) { + t8_debugf ("WARNING: Trying to construct ghosts with ghost_type NONE. " + "Ghost layer is not constructed.\n"); + return; + } + + /* Initialize the ghost structure */ + t8_forest_ghost_init (&forest->ghosts, ghost_type); + + search_for_ghost_elements (forest); + + communicate_ghost_elements (forest); + } + clean_up (forest); +} + +void +t8_forest_ghost_w_search::search_for_ghost_elements (t8_forest_t forest) +{ + t8_forest_ghost_boundary_data_t data; + void *store_user_data = NULL; + + /* Start with invalid entries in the user data. + * These are set in t8_forest_ghost_search_boundary each time a new tree is entered */ + data.eclass = T8_ECLASS_COUNT; + data.gtreeid = -1; + data.ts = NULL; +#ifdef T8_ENABLE_DEBUG + data.left_out = 0; +#endif + sc_array_init (&data.face_owners, sizeof (int)); + /* This is a dummy init, since we call sc_array_reset in ghost_search_boundary + * and we should not call sc_array_reset on a non-initialized array */ + sc_array_init (&data.bounds_per_level, 1); + /* Store any user data that may reside on the forest */ + store_user_data = t8_forest_get_user_data (forest); + /* Set the user data for the search routine */ + t8_forest_set_user_data (forest, &data); + /* Loop over the trees of the forest */ + t8_forest_search (forest, search_fn, NULL, NULL); + + /* Reset the user data from before search */ + t8_forest_set_user_data (forest, store_user_data); + + /* Reset the data arrays */ + sc_array_reset (&data.face_owners); + sc_array_reset (&data.bounds_per_level); +} + +t8_forest_ghost_face::t8_forest_ghost_face (const int version) + : t8_forest_ghost_w_search (T8_GHOST_FACES, t8_forest_ghost_search_boundary), version (version) +{ + T8_ASSERT (1 <= version && version <= 3); +} + +void +t8_forest_ghost_face::search_for_ghost_elements (t8_forest_t forest) +{ + t8_global_productionf (" t8_forest_ghost_face::step_2 \n"); + T8_ASSERT (forest->ghosts != NULL); + t8_forest_ghost_t ghost = forest->ghosts; + if (version == 3) { + t8_global_productionf ("t8_forest_ghost_face::step_2: t8_forest_ghost_fill_remote_v3(forest)\n"); + t8_forest_ghost_fill_remote_v3 (forest); + } + else { + /* Construct the remote elements and processes. */ + t8_global_productionf ( + "t8_forest_ghost_face::step_2: t8_forest_ghost_fill_remote (forest, ghost, ghost_version != 1)\n"); + t8_forest_ghost_fill_remote (forest, ghost, version != 1); + } +} + +/* Wrapper for derived face class */ +t8_forest_ghost_interface_c * +t8_forest_ghost_interface_face_new (const int version) +{ + t8_debugf ("Call t8_forest_ghost_interface_face_new.\n"); + T8_ASSERT (1 <= version && version <= 3); + t8_forest_ghost_face *ghost_interface = new t8_forest_ghost_face (version); + return (t8_forest_ghost_interface_c *) ghost_interface; +} + +t8_forest_ghost_interface_c * +t8_forest_ghost_interface_stencil_new () +{ + t8_debugf ("Call t8_forest_ghost_interface_stencil_new.\n"); + t8_forest_ghost_stencil *ghost_interface = new t8_forest_ghost_stencil (); + return (t8_forest_ghost_interface_c *) ghost_interface; +} + +int +t8_forest_ghost_interface_face_version (t8_forest_ghost_interface_c *ghost_interface) +{ + T8_ASSERT (ghost_interface != NULL); + T8_ASSERT (ghost_interface->t8_ghost_get_type () == T8_GHOST_FACES); + t8_forest_ghost_face *ghost_interface_passed = (t8_forest_ghost_face *) ghost_interface; + + return ghost_interface_passed->get_version (); +} + +/** + * Derived class for a stencil on an uniform mesh. + */ + +void +t8_forest_ghost_stencil::do_ghost (t8_forest_t forest) +{ + t8_forest_ghost_init (&forest->ghosts, ghost_type); + + t8_locidx_t current_index; // counter over all local elements + t8_locidx_t ielement, num_elements_in_tree; // count over the local elements in a tree + const t8_element_t *element; + + SC_CHECK_ABORT (t8_forest_get_num_global_trees (forest) == 1, "more than one tree in ghost for stencil"); + + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, 0); + const t8_eclass_scheme_c *eclass_scheme = t8_forest_get_eclass_scheme (forest, tree_class); + SC_CHECK_ABORT (tree_class == T8_ECLASS_QUAD, "only forest with eclass quad are possible for ghost for stencil"); + num_elements_in_tree = t8_forest_get_tree_num_elements (forest, 0); + + for (ielement = 0; ielement < num_elements_in_tree; ++ielement, ++current_index) { + element = t8_forest_get_element_in_tree (forest, 0, ielement); + /** compute the stencil elements */ + add_stencil_to_ghost (forest, element, eclass_scheme, eclass_scheme->t8_element_level (element), tree_class, 0, + ielement); + } + + communicate_ghost_elements (forest); +} + +/** + * Function to compute the owner of an element + * \param [in] forest a commit uniform forest which is partitioned + * \param [in] eclass_scheme should fit to the element + * \param [in] element compute owner of this + * \return owner of element + * \note: the function use, that the linear id of the element is the same as the global index + * for example this is true for uniform meshes. + * the function also use, that the forest is partitioned. + * The owner is found in O(1) + */ +int +t8_forest_ghost_interface_stencil_get_remote_rank (t8_forest_t forest, const t8_eclass_scheme_c *eclass_scheme, + t8_element_t *element) +{ + const t8_gloidx_t global_num_elements = t8_forest_get_global_num_elements (forest); + const t8_linearidx_t lin_id + = eclass_scheme->t8_element_get_linear_id (element, eclass_scheme->t8_element_level (element)); + + const t8_linearidx_t b_0 = global_num_elements / forest->mpisize; + const t8_linearidx_t r = global_num_elements % forest->mpisize; + + const int p_guess = lin_id / b_0; + if (p_guess < 2 || r == 0) { + return p_guess; + } + const int x = (p_guess * r) / forest->mpisize; + + const int owner = (lin_id - x) / b_0; + + return owner; +} + +void +t8_forest_ghost_stencil::add_stencil_to_ghost (t8_forest_t forest, const t8_element_t *element, + const t8_eclass_scheme_c *eclass_scheme, const int level, + const t8_eclass_t tree_class, const t8_locidx_t ltreeid, + const t8_locidx_t ielement) +{ + + t8_locidx_t iface_neighbor, ineighbor; + t8_element_t *face_neighbor; + t8_element_t *neighbor; +#ifdef T8_ENABLE_DEBUG + const t8_eclass_t eclass = t8_forest_get_eclass (forest, 0); +#endif + + /** + * First loop over the F elements, this are the face-neighbors of E + */ + for (iface_neighbor = 0; iface_neighbor < eclass_scheme->t8_element_num_faces (element); ++iface_neighbor) { + eclass_scheme->t8_element_new (1, &face_neighbor); + eclass_scheme->t8_element_new (1, &neighbor); + /* Compute one F */ + int neighbor_face; + const int face_neighbor_exists + = eclass_scheme->t8_element_face_neighbor_inside (element, face_neighbor, iface_neighbor, &neighbor_face); + /* if the F exists */ + if (face_neighbor_exists) { + /* compute the mpirank for F, and if its not owns by this process, add it to ghost */ + int remote_rank = t8_forest_ghost_interface_stencil_get_remote_rank (forest, eclass_scheme, face_neighbor); + T8_ASSERT ( + remote_rank + == t8_forest_element_find_owner_ext (forest, 0, face_neighbor, eclass, 0, forest->mpisize - 1, remote_rank, 0)); + T8_ASSERT (0 <= remote_rank && remote_rank < forest->mpisize); + if (forest->mpirank != remote_rank) { + t8_ghost_add_remote (forest, forest->ghosts, remote_rank, ltreeid, element, ielement); + } + /* Loop over the face neighbors of F (except of E), this are the N */ + for (ineighbor = 0; ineighbor < eclass_scheme->t8_element_num_faces (face_neighbor); ++ineighbor) { + if (ineighbor != neighbor_face) { + /* Compute N */ + int neighbor_neighbor_face; + const int neighbor_exists = eclass_scheme->t8_element_face_neighbor_inside ( + face_neighbor, neighbor, ineighbor, &neighbor_neighbor_face); + if (neighbor_exists) { + /* compute the mpirank for N, and if its not owns by this process, add it to ghost */ + remote_rank = t8_forest_ghost_interface_stencil_get_remote_rank (forest, eclass_scheme, neighbor); + T8_ASSERT (remote_rank + == t8_forest_element_find_owner_ext (forest, 0, neighbor, eclass, 0, forest->mpisize - 1, + remote_rank, 0)); + T8_ASSERT (0 <= remote_rank && remote_rank < forest->mpisize); + if (forest->mpirank != remote_rank) { + t8_ghost_add_remote (forest, forest->ghosts, remote_rank, ltreeid, element, ielement); + } + } + } + } + } + eclass_scheme->t8_element_destroy (1, &face_neighbor); + eclass_scheme->t8_element_destroy (1, &neighbor); + } +} + T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_ghost.h b/src/t8_forest/t8_forest_ghost.h index 427a73109e..2054db14ff 100644 --- a/src/t8_forest/t8_forest_ghost.h +++ b/src/t8_forest/t8_forest_ghost.h @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2024 the developers t8code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -162,10 +162,37 @@ t8_forest_ghost_unref (t8_forest_ghost_t *pghost); void t8_forest_ghost_destroy (t8_forest_ghost_t *pghost); +/** Part of search_for_ghost_elements of the ghost_creat_ext + * for ghost_type face + * Is declared, so that ghost_interface_face can use it + * \see t8_forest_ghost_w_search::search_for_ghost_elements + * \param [in,out] forest The forest. + */ +void +t8_forest_ghost_fill_remote_v3 (t8_forest_t forest); + +/** Part of step search_for_ghost_elements of the ghost_creat_ext + * for ghost_type face + * Is declared, so that ghost_interface_face can use it + * \see t8_forest_ghost_face::search_for_ghost_elements + * \param [in,out] forest The forest. + */ +void +t8_forest_ghost_fill_remote (t8_forest_t forest, const t8_forest_ghost_t ghost, const int ghost_method); + +/** Create one layer of ghost elements for a forest. + * \see t8_forest_set_ghost + * \param [in,out] forest The forest. + * \a forest must be committed before calling this function. + */ +void +t8_forest_ghost_create_ext (t8_forest_t forest); + /** Create one layer of ghost elements for a forest. * \see t8_forest_set_ghost * \param [in,out] forest The forest. * \a forest must be committed before calling this function. + * \a forest->ghost_interface must have the \a type FACE and the \a version 2 */ void t8_forest_ghost_create (t8_forest_t forest); @@ -176,12 +203,18 @@ t8_forest_ghost_create (t8_forest_t forest); * Mesh Refinement On Forests of Octrees * \param [in,out] forest The balanced forest/ * \a forest must be committed before calling this function. + * \a forest->ghost_interface must have the \a type FACE and the \a version 1 * \note The user should prefer \ref t8_forest_ghost_create even for balanced forests. */ void t8_forest_ghost_create_balanced_only (t8_forest_t forest); -/* experimental version using the ghost_v3 algorithm */ +/** Creating one layer of ghost elements for a forest. + * experimental version using the ghost_v3 algorithm + * \param [in,out] forest The forest. + * \a forest must be committed before calling this function. + * \a forest->ghost_interface must have the \a type FACE and the \a version 1 + */ void t8_forest_ghost_create_topdown (t8_forest_t forest); diff --git a/src/t8_forest/t8_forest_ghost_interface.h b/src/t8_forest/t8_forest_ghost_interface.h new file mode 100644 index 0000000000..fc0df83a38 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_interface.h @@ -0,0 +1,38 @@ +/* + 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_FOREST_GHOST_INTERFACE_H +#define T8_FOREST_GHOST_INTERFACE_H + +#include + +T8_EXTERN_C_BEGIN (); + +/** This typedef holds virtual functions for a particular ghost interface. + * We need it so that we can use t8_ghost_interface_c pointers in .c files + * without them seeing the actual C++ code (and then not compiling) + */ +typedef struct t8_forest_ghost_interface t8_forest_ghost_interface_c; + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_INTERFACE_H */ diff --git a/src/t8_forest/t8_forest_ghost_interface.hxx b/src/t8_forest/t8_forest_ghost_interface.hxx new file mode 100644 index 0000000000..595093d892 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_interface.hxx @@ -0,0 +1,150 @@ +/* + 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_FOREST_GHOST_INTERFACE_HXX +#define T8_FOREST_GHOST_INTERFACE_HXX + +#include +#include +#include +#include +#include + +T8_EXTERN_C_BEGIN (); + +/** + * Flags for communicate_ownerships + * store in the flags which memory was allocated + */ +enum t8_ghost_interface_face_flag { CREATE_ELEMENT_ARRAY = 1, CREATE_TREE_ARRAY = 2, CREATE_GFIRST_DESC_ARRAY = 4 }; + +struct t8_forest_ghost_interface +{ + public: + /** + * Constructor: + * Creates t8_forest_ghost_interface of type non + * init the refcout + */ + t8_forest_ghost_interface () + { + t8_refcount_init (&rc); + t8_debugf ("Constructed the a None ghost_interface.\n"); + } + + /** + * Destructor. + * unref the refcout + */ + virtual ~t8_forest_ghost_interface () + { + if (sc_refcount_is_active (&rc)) { + T8_ASSERT (t8_refcount_is_last (&rc)); + t8_refcount_unref (&rc); + } + t8_debugf ("Deleted the ghost_interface.\n"); + } + + /** + * Get the type of the ghost_interface + * \return the type + */ + inline t8_ghost_type_t + t8_ghost_get_type () const + { + return ghost_type; + } + + /** + * Increase the reference count of the ghost interface. + */ + virtual inline void + ref () + { + t8_refcount_ref (&rc); + } + + /** + * Decrease the reference count of the ghost_interface. + * If the reference count reaches zero, the ghost_interface is deleted. + */ + virtual inline void + unref () + { + if (t8_refcount_unref (&rc)) { + t8_debugf ("Deleting the ghost_interface.\n"); + delete this; + } + } + + /** Create one layer of ghost elements for a forest. + * \param [in,out] forest The forest. + * \a forest must be committed before calling this function. + */ + virtual void + do_ghost (t8_forest_t forest) + = 0; + + protected: + /** + * Compute and collect ownerships to create the necessary offset + * for elements, trees and first descandance + * Use memory_flag to record the allocation of memory + * \note this function could be used in do_ghost + */ + virtual void + communicate_ownerships (t8_forest_t forest); + + /** + * Exchange the list of remote ghost elements between prozesses + * \note this function could be used in do_ghost + */ + virtual void + communicate_ghost_elements (t8_forest_t forest); + + /** + * If memory was allocated for the offset array in communicate_ownerships it is released here. + * Use memory_flag for this. + */ + virtual void + clean_up (t8_forest_t forest); + + /** + * Constructor for the derivided classes to set the correkt type for them. + * \param [in] g_type The type (faces, edges, userdefind, ...) of the ghost_interface + */ + explicit t8_forest_ghost_interface (t8_ghost_type_t g_type): ghost_type (g_type) + { + t8_refcount_init (&rc); + t8_debugf ("Constructed a ghost_interface.\n"); + }; + /** type of the ghost_interface */ + t8_ghost_type_t ghost_type { T8_GHOST_NONE }; + /** The reference count of the ghost_interface. TODO: Replace by shared_ptr when forest becomes a class. */ + t8_refcount_t rc; + /** Record allocated memory in communicate_ownerships for release in clean_up */ + int32_t memory_flag {}; +}; + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_INTERFACE_HXX */ diff --git a/src/t8_forest/t8_forest_ghost_interface_wrapper.h b/src/t8_forest/t8_forest_ghost_interface_wrapper.h new file mode 100644 index 0000000000..e22bbd33ae --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_interface_wrapper.h @@ -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_FOREST_GHOST_INTERFACE_WRAPPER_H +#define T8_FOREST_GHOST_INTERFACE_WRAPPER_H + +#include +#include +#include + +T8_EXTERN_C_BEGIN (); + +/** + * Satisfy the C interface of forest + * Create a new ghost_interface of type face with given version + */ +t8_forest_ghost_interface_c * +t8_forest_ghost_interface_face_new (const int version); + +/** + * Satisfy the C interface of forest + * Create a new ghost_interface of type stencil + */ +t8_forest_ghost_interface_c * +t8_forest_ghost_interface_stencil_new (); + +/** + * Satisfy the C interface of forest + * Return for a ghost_interface of Type FACE the ghost_algorithm / ghost_version (1, 2 or 3) + * \param [in] ghost_interface Pointer to object of class t8_forest_ghost_face + */ +int +t8_forest_ghost_interface_face_version (t8_forest_ghost_interface_c *ghost_interface); + +/** + * Satisfy the C interface of forest + * Return the type of a ghost_interface + * \param [in] ghost_interface Pointer to object of class t8_forest_ghost_interface or a derivet class + */ +t8_ghost_type_t +t8_forest_ghost_interface_get_type (const t8_forest_ghost_interface_c *ghost_interface); + +/** + * Satisfy the C interface of forest + * Do a ref on the ghost_interface + * Needed in t8_forest_commit + */ +void +t8_forest_ghost_interface_ref (t8_forest_ghost_interface_c *ghost_interface); + +/** + * Satisfy the C interface of forest + * Do a unref on the ghost_interface + * Needed in t8_forest_commit and t8_forest_set_ghost_ext_new + */ +void +t8_forest_ghost_interface_unref (t8_forest_ghost_interface_c **pghost_interface); + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_INTERFACE_WRAPPER_H */ diff --git a/src/t8_forest/t8_forest_ghost_search.hxx b/src/t8_forest/t8_forest_ghost_search.hxx new file mode 100644 index 0000000000..41de658418 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_search.hxx @@ -0,0 +1,127 @@ +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 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_GHOST_INTERFACE_FACE_H +#define T8_GHOST_INTERFACE_FACE_H + +#include +#include +#include // Definition of t8_forest_search_fn + +struct t8_forest_ghost_w_search: public t8_forest_ghost_interface +{ + public: + /** + * Constructors: + * there are three ways to construct a object of t8_forest_ghost_w_search + * t8_forest_ghost_w_search (), + * t8_forest_ghost_w_search (t8_forest_search_fn search_function), + * t8_forest_ghost_w_search (const t8_ghost_type_t ghost_type) + */ + t8_forest_ghost_w_search (); + + /** + * Constructr of t8_forest_ghost_w_search by search_function + * If do_ghost is called on this object, + * the ghost layer will be created by an treesearch (t8_forest_search) + * with search_function as callbackfunction. + * \note the t8_ghost_type_t of the object will we userdefined + */ + explicit t8_forest_ghost_w_search (t8_forest_search_fn search_function) + : t8_forest_ghost_interface (T8_GHOST_USERDEFINED), search_fn (search_function) + { + T8_ASSERT (search_function != nullptr); + } + + /** + * Constructr of t8_forest_ghost_w_search by type + * The search_function is chosen by the type + * \note currently only the type face is supported + */ + explicit t8_forest_ghost_w_search (const t8_ghost_type_t ghost_type); + + virtual ~t8_forest_ghost_w_search () + { + } + + /** Create one layer of ghost elements for a forest. + * \param [in,out] forest The forest. + * \a forest must be committed before calling this function. + */ + virtual void + do_ghost (t8_forest_t forest) override; + + protected: + /** + * Equal to t8_forest_ghost_fill_remote_v3 + * so no support for version 1 and 2 of face neighbors. + * Only the search_fn parameter for t8_forest_search + * is not the same as in t8_forest_ghost_fill_remote_v3. + * Use the member variable of the class. + */ + virtual void + search_for_ghost_elements (t8_forest_t forest); + + /** + * Constructor for the derivided classes to set the type and the search_function. + * \param [in] ghost_type The type (faces, edges, userdefind, ...) of the ghost_interface + * \param [in] search_function Function of type t8_forest_search_fn, used as callbackfunktion in search_for_ghost_elements + */ + t8_forest_ghost_w_search (const t8_ghost_type_t ghost_type, const t8_forest_search_fn search_function) + : t8_forest_ghost_interface (ghost_type), search_fn (search_function) + { + T8_ASSERT (ghost_type != T8_GHOST_NONE); + } + /** Callbackfunction for t8_forest_search in search_for_ghost_elements */ + t8_forest_search_fn search_fn {}; +}; + +struct t8_forest_ghost_face: public t8_forest_ghost_w_search +{ + public: + /** + * Constructor for the ghost class face. + * do_ghost will construct a ghost layer with face neighbors + * \param [in] version one of tree versions (1,2,3) can be used + * \note version 3 is the same treesearch as in t8_forest_ghost_w_search + */ + explicit t8_forest_ghost_face (const int version); + + inline int + get_version () const + { + return version; + } + + protected: + /** + * Equal to t8_forest_ghost_fill_remote_v3 for version = 3 + * and t8_forest_ghost_fill_remote for version 1 and 2 + */ + void + search_for_ghost_elements (t8_forest_t forest) override; + + private: + int version {}; +}; + +#endif /* !T8_GHOST_INTERFACE_FACE_H */ diff --git a/src/t8_forest/t8_forest_ghost_stencil.hxx b/src/t8_forest/t8_forest_ghost_stencil.hxx new file mode 100644 index 0000000000..fb8024faf4 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_stencil.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_FOREST_GHOST_STENCIL_HXX +#define T8_FOREST_GHOST_STENCIL_HXX + +#include +#include + +T8_EXTERN_C_BEGIN (); + +struct t8_forest_ghost_stencil: t8_forest_ghost_interface +{ + public: + /** + * Only constructor of t8_forest_ghost_stencil. + * Derived class of t8_forest_ghost_interface. + * Hase userdefined as type. + */ + t8_forest_ghost_stencil (): t8_forest_ghost_interface (T8_GHOST_USERDEFINED) {}; + + /** Create one layer of ghost elements for a forest. + * The neighborhood for this is defined by an stencil. + * \see add_stencil_to_ghost + * \param [in,out] forest The forest. + * \a forest must be committed before calling this function. + */ + void + do_ghost (t8_forest_t forest) override; + + protected: + /** + * Add this stencil (elements N and F) for element E to ghost. + * + * N + * | + * N - F - N + * | | | + * N - F - E - F - N + * | | | + * N - F - N + * | + * N + * \param[in] forest a commit uniform forest + * \param[in] element element E + * \param[in] eclass_scheme + * \param[in] level level of the uniform forest + * \param[in] tree_class expect T8_ECLASS_QUAD + * \param[in] ltreeid local tree id, expect 0 + * \param[in] ielement local index of element E + * \note some parameters currently expect specific values + */ + void + add_stencil_to_ghost (t8_forest_t forest, const t8_element_t *element, const t8_eclass_scheme_c *eclass_scheme, + const int level, const t8_eclass_t tree_class, const t8_locidx_t ltreeid, + const t8_locidx_t ielement); +}; + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_STENCIL_HXX */ diff --git a/src/t8_forest/t8_forest_types.h b/src/t8_forest/t8_forest_types.h index 10f4c84b72..675caaa634 100644 --- a/src/t8_forest/t8_forest_types.h +++ b/src/t8_forest/t8_forest_types.h @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2024 the developers t8code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,8 @@ #include #include #include +#include +// #include typedef struct t8_profile t8_profile_t; /* Defined below */ typedef struct t8_forest_ghost *t8_forest_ghost_t; /* Defined below */ @@ -98,15 +100,16 @@ typedef struct t8_forest If 0, no balance. If 1 balance with repartitioning, if 2 balance without repartitioning, \see t8_forest_balance */ int do_ghost; /**< If True, a ghost layer will be created when the forest is committed. */ - t8_ghost_type_t ghost_type; /**< If a ghost layer will be created, the type of neighbors that count as ghost. */ - int ghost_algorithm; /**< Controls the algorithm used for ghost. 1 = balanced only. 2 = also unbalanced - 3 = top-down search and unbalanced. */ - void *user_data; /**< Pointer for arbitrary user data. \see t8_forest_set_user_data. */ - void (*user_function) (); /**< Pointer for arbitrary user function. \see t8_forest_set_user_function. */ - void *t8code_data; /**< Pointer for arbitrary data that is used internally. */ - int committed; /**< \ref t8_forest_commit called? */ - int mpisize; /**< Number of MPI processes. */ - int mpirank; /**< Number of this MPI process. */ + // t8_ghost_type_t ghost_type; /**< If a ghost layer will be created, the type of neighbors that count as ghost. */ + // int ghost_algorithm; /**< Controls the algorithm used for ghost. 1 = balanced only. 2 = also unbalanced + // 3 = top-down search and unbalanced. */ + t8_forest_ghost_interface_c *ghost_interface; + void *user_data; /**< Pointer for arbitrary user data. \see t8_forest_set_user_data. */ + void (*user_function) (); /**< Pointer for arbitrary user function. \see t8_forest_set_user_function. */ + void *t8code_data; /**< Pointer for arbitrary data that is used internally. */ + int committed; /**< \ref t8_forest_commit called? */ + int mpisize; /**< Number of MPI processes. */ + int mpirank; /**< Number of this MPI process. */ t8_gloidx_t first_local_tree; /**< The global index of the first local tree on this process. If first_local_tree is larger than last_local_tree then