diff --git a/benchmarks/t8_time_forest_partition.cxx b/benchmarks/t8_time_forest_partition.cxx index b38a562d6d..a9791bbf9c 100644 --- a/benchmarks/t8_time_forest_partition.cxx +++ b/benchmarks/t8_time_forest_partition.cxx @@ -341,7 +341,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; @@ -391,6 +391,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 Tet, 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."); @@ -416,11 +422,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; @@ -455,6 +462,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/example/forest/t8_test_ghost.cxx b/example/forest/t8_test_ghost.cxx index 1e053ff2c6..bb8cdda1c3 100644 --- a/example/forest/t8_test_ghost.cxx +++ b/example/forest/t8_test_ghost.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -187,7 +188,7 @@ t8_test_ghost_refine_and_partition (t8_cmesh_t cmesh, const int level, sc_MPI_Co /* Set the forest for partitioning */ t8_forest_set_partition (forest_ghost, forest, 0); /* Activate ghost creation */ - t8_forest_set_ghost_ext (forest_ghost, 1, T8_GHOST_FACES, ghost_version); + t8_forest_set_ghost_ext (forest_ghost, 1, new t8_forest_ghost_face (ghost_version)); /* Activate timers */ t8_forest_set_profiling (forest_ghost, 1); diff --git a/example/forest/t8_test_ghost_large_level_diff.cxx b/example/forest/t8_test_ghost_large_level_diff.cxx index d9586d7ea6..8cb49ce009 100644 --- a/example/forest/t8_test_ghost_large_level_diff.cxx +++ b/example/forest/t8_test_ghost_large_level_diff.cxx @@ -44,6 +44,7 @@ #include #include #include +#include #include /* The refinement criterion @@ -179,7 +180,7 @@ t8_ghost_large_level_diff (const char *prefix, int dim, int level, int refine, i /* Partition */ t8_forest_init (&forest_partition); t8_forest_set_partition (forest_partition, forest_adapt, 0); - t8_forest_set_ghost_ext (forest_partition, 1, T8_GHOST_FACES, 3); + t8_forest_set_ghost_ext (forest_partition, 1, new t8_forest_ghost_face (3)); t8_forest_set_profiling (forest_partition, 1); t8_forest_commit (forest_partition); if (!no_vtk) { diff --git a/src/Makefile.am b/src/Makefile.am index b0c31b0bbf..b6327501b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,8 +53,13 @@ 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_definition_wrapper.h \ + src/t8_forest/t8_forest_ghost_definition.h \ + src/t8_forest/t8_forest_ghost_definition.hxx \ src/t8_forest/t8_forest_search/t8_forest_search.hxx libt8_installed_headers_geometry = \ src/t8_geometry/t8_geometry.h \ diff --git a/src/t8.h b/src/t8.h index 232a597534..fe34c87eed 100644 --- a/src/t8.h +++ b/src/t8.h @@ -277,6 +277,10 @@ t8_init (int log_threshold); void * t8_sc_array_index_locidx (const sc_array_t *array, const t8_locidx_t it); +/** Return values for subroutines, if they failed */ +#define T8_SUBROUTINE_SUCCESS 1 /* true */ +#define T8_SUBROUTINE_FAILED 0 /* false */ + /* call this at the end of a header file to match T8_EXTERN_C_BEGIN (). */ T8_EXTERN_C_END (); diff --git a/src/t8_cmesh/t8_cmesh_readmshfile.cxx b/src/t8_cmesh/t8_cmesh_readmshfile.cxx index 034b4139be..d995395b0a 100644 --- a/src/t8_cmesh/t8_cmesh_readmshfile.cxx +++ b/src/t8_cmesh/t8_cmesh_readmshfile.cxx @@ -1759,7 +1759,7 @@ 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 cad usage error: use_cad_geometry true, but OCC not linked. + * Returns T8_SUBROUTINE_SUCCESS on success, T8_SUBROUTINE_FAILED 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 cad_geometry pointer will point to the newly created cad geometry, or to NULL if * no cad geometry is used. @@ -1775,10 +1775,10 @@ t8_cmesh_from_msh_file_register_geometries (t8_cmesh_t cmesh, const int use_cad_ *cad_geometry = t8_cmesh_register_geometry (cmesh, std::string (fileprefix)); #else /* !T8_WITH_OCC */ *cad_geometry = NULL; - return 0; + return T8_SUBROUTINE_FAILED; #endif } - return 1; + return T8_SUBROUTINE_SUCCESS; } t8_cmesh_t diff --git a/src/t8_cmesh/t8_cmesh_triangle.cxx b/src/t8_cmesh/t8_cmesh_triangle.cxx index 63badde55c..26b2703a1f 100644 --- a/src/t8_cmesh/t8_cmesh_triangle.cxx +++ b/src/t8_cmesh/t8_cmesh_triangle.cxx @@ -290,8 +290,8 @@ t8_cmesh_triangle_read_eles (t8_cmesh_t cmesh, int corner_offset, char *filename } /* Open .neigh file and read element neighbor information - * On success 0 is returned. - * On failure -1 is returned. */ + * On success T8_SUBROUTINE_SUCCESS is returned. + * On failure T8_SUBROUTINE_FAILED is returned. */ static int t8_cmesh_triangle_read_neigh (t8_cmesh_t cmesh, int element_offset, char *filename, int dim) { @@ -497,7 +497,7 @@ t8_cmesh_triangle_read_neigh (t8_cmesh_t cmesh, int element_offset, char *filena } T8_FREE (tneighbors); free (line); - return 0; + return T8_SUBROUTINE_SUCCESS; die_neigh: /* Clean up on error. */ T8_FREE (tneighbors); @@ -506,7 +506,7 @@ t8_cmesh_triangle_read_neigh (t8_cmesh_t cmesh, int element_offset, char *filena fclose (fp); } free (line); - return -1; + return T8_SUBROUTINE_FAILED; } /* TODO: remove do_dup argument */ @@ -559,7 +559,7 @@ t8_cmesh_from_tetgen_or_triangle_file (char *fileprefix, int partition, sc_MPI_C /* read .neigh file */ snprintf (current_file, BUFSIZ, "%s.neigh", fileprefix); retval = t8_cmesh_triangle_read_neigh (cmesh, corner_offset, current_file, dim); - if (retval != 0) { + if (retval == T8_SUBROUTINE_FAILED) { t8_global_errorf ("Error while parsing file %s.\n", current_file); t8_cmesh_unref (&cmesh); return NULL; @@ -639,7 +639,7 @@ t8_cmesh_from_tetgen_or_triangle_file_time (char *fileprefix, int partition, sc_ /* read .neigh file */ snprintf (current_file, BUFSIZ, "%s.neigh", fileprefix); retval = t8_cmesh_triangle_read_neigh (cmesh, corner_offset, current_file, dim); - if (retval != 0) { + if (retval == T8_SUBROUTINE_FAILED) { t8_global_errorf ("Error while parsing file %s.\n", current_file); t8_cmesh_unref (&cmesh); } diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index e79d7fff5d..5d34ecc2f5 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include #if T8_ENABLE_DEBUG #include #include @@ -2895,14 +2898,41 @@ t8_forest_set_balance (t8_forest_t forest, const t8_forest_t set_from, int no_re } void -t8_forest_set_ghost_ext (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type, int ghost_version) +t8_forest_set_ghost_ext (t8_forest_t forest, const int do_ghost, t8_forest_ghost_definition_c *ghost_definition) { T8_ASSERT (t8_forest_is_initialized (forest)); - /* We currently only support face ghosts */ + + if (do_ghost != 0) { + if (ghost_definition == NULL) { + /* If forest has a ghost_definition, activate ghost, otherwise abort. */ + if (forest->ghost_definition != NULL) { + forest->do_ghost = 1; + } + else { + SC_ABORT ("Want to aktivat ghost, without ghost_definition.\n"); + } + } + else { + /* Unref the old ghost_definition (if it exists) and set the new one. */ + if (forest->ghost_definition != NULL) { + t8_forest_ghost_definition_unref (&(forest->ghost_definition)); + } + forest->do_ghost = 1; + forest->ghost_definition = ghost_definition; + } + } + else { + /* Deactivate ghost for the forest, but do not overwrite an old ghost_definition of the forest. */ + forest->do_ghost = 0; + } +} + +void +t8_forest_set_ghost (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type) +{ + /* Use ghost version 3, top-down search and for unbalanced forests. */ SC_CHECK_ABORT (do_ghost == 0 || ghost_type == T8_GHOST_FACES, "Ghost neighbors other than face-neighbors are not supported.\n"); - SC_CHECK_ABORT (1 <= ghost_version && ghost_version <= 3, "Invalid choice for ghost version. Choose 1, 2, or 3.\n"); - if (ghost_type == T8_GHOST_NONE) { /* none type disables ghost */ forest->do_ghost = 0; @@ -2911,18 +2941,10 @@ 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_set_ghost_ext (forest, do_ghost, new t8_forest_ghost_face (3)); } } -void -t8_forest_set_ghost (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type) -{ - /* Use ghost version 3, top-down search and for unbalanced forests. */ - t8_forest_set_ghost_ext (forest, do_ghost, ghost_type, 3); -} - void t8_forest_set_adapt (t8_forest_t forest, const t8_forest_t set_from, t8_forest_adapt_t adapt_fn, int recursive) { @@ -3201,6 +3223,11 @@ t8_forest_commit (t8_forest_t forest) forest->scheme = forest->set_from->scheme; forest->global_num_trees = forest->set_from->global_num_trees; + if (forest->ghost_definition == NULL && forest->set_from->ghost_definition != NULL) { + forest->ghost_definition = forest->set_from->ghost_definition; + forest->ghost_definition->ref (); + } + /* Compute the maximum allowed refinement level */ t8_forest_compute_maxlevel (forest); if (forest->from_method == T8_FOREST_FROM_COPY) { @@ -3355,19 +3382,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; } @@ -4217,6 +4232,11 @@ t8_forest_reset (t8_forest_t *pforest) if (forest->ghosts != NULL) { t8_forest_ghost_unref (&forest->ghosts); } + /* Unref the ghost_definition class if it exist */ + if (forest->ghost_definition != NULL) { + forest->ghost_definition->unref (); + forest->ghost_definition = NULL; + } /* we have taken ownership on calling t8_forest_set_* */ if (forest->scheme != NULL) { forest->scheme->unref (); diff --git a/src/t8_forest/t8_forest_balance.cxx b/src/t8_forest/t8_forest_balance.cxx index 7a12fed8e1..2269b0785a 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_definition = 0; /* flag if create ghost_definition */ 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 the current 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_definition */ + if (forest->set_from->ghost_definition == NULL) { + /* create a ghost_definition of type face with top-down-search */ + forest->set_from->ghost_definition = t8_forest_ghost_definition_face_new (3); + create_ghost_definition = 1; + } + /* compute ghost layer for set_from forest */ t8_forest_ghost_create_topdown (forest->set_from); + if (create_ghost_definition) { /* if a ghost_definition has been created, it will be deleted here */ + t8_forest_ghost_definition_unref (&(forest->set_from->ghost_definition)); + forest->set_from->ghost_definition = NULL; + } } while (!done_global) { diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index a8d4b93753..8ac0fa8ce9 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 @@ -358,16 +360,16 @@ t8_forest_set_balance (t8_forest_t forest, const t8_forest_t set_from, int no_re void t8_forest_set_ghost (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type); -/** Like \ref t8_forest_set_ghost but with the additional options to change the - * ghost algorithm. This is used for debugging and timing the algorithm. - * An application should almost always use \ref t8_forest_set_ghost. - * \param [in] ghost_version If 1, the iterative ghost algorithm for balanced forests is used. - * If 2, the iterative algorithm for unbalanced forests. - * If 3, the top-down search algorithm for unbalanced forests. - * \see t8_forest_set_ghost - */ +/** Set a ghost_definition + * In application schoud only used if the user creates its own ghost_definition class (type = userderdefined) + * \param [in] forest The forest + * \param [in] do_ghost If 0 no ghost layer will be computed + * \param [in] ghost_definition Pointer to an object of the class ghost_definition or a derived class + * The forest takes ownership of the ghost_definition + * \note Only if do_ghost is not 0 and ghost_definition is not NULL would an old ghost_definition of the forest be overwritten. +*/ void -t8_forest_set_ghost_ext (t8_forest_t forest, int do_ghost, t8_ghost_type_t ghost_type, int ghost_version); +t8_forest_set_ghost_ext (t8_forest_t forest, const int do_ghost, t8_forest_ghost_definition_c *ghost_definition); /* TODO: use assertions and document that the forest_set (..., from) and * set_load are mutually exclusive. */ diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index 1ce40f6ca0..40abe445bb 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,10 @@ #include #include +#include +#include +#include + /* We want to export the whole implementation to be callable from "C" */ T8_EXTERN_C_BEGIN (); @@ -172,8 +176,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); @@ -631,7 +634,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; @@ -675,7 +678,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; @@ -1375,15 +1378,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_definition_c *ghost_definition; T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (forest->ghost_definition != NULL); + + ghost_definition = forest->ghost_definition; t8_global_productionf ("Into t8_forest_ghost with %i local elements.\n", t8_forest_get_local_num_elements (forest)); @@ -1404,53 +1407,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_definition class of the forest to compute the ghost layer */ + ghost_definition->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); - } + ghost = forest->ghosts; if (forest->profile != NULL) { /* If profiling is enabled, we measure the runtime of ghost_create */ @@ -1471,19 +1431,6 @@ t8_forest_ghost_create_ext (t8_forest_t forest, int unbalanced_version) t8_global_productionf ("End ghost at %f %f\n", sc_MPI_Wtime (), forest->profile->ghost_runtime); } - 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); - } - t8_global_productionf ("Done t8_forest_ghost with %i local elements and %i" " ghost elements.\n", t8_forest_get_local_num_elements (forest), t8_forest_get_num_ghosts (forest)); @@ -1495,7 +1442,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_definition_face_get_version (forest->ghost_definition) == 2); + t8_forest_ghost_create_ext (forest); } } @@ -1506,7 +1454,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_definition_face_get_version (forest->ghost_definition) == 1); + t8_forest_ghost_create_ext (forest); } } @@ -1514,8 +1463,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_definition != NULL); + T8_ASSERT (t8_forest_ghost_definition_face_get_version (forest->ghost_definition) == 3); + t8_forest_ghost_create_ext (forest); } /** Return the array of remote ranks. @@ -1922,4 +1872,210 @@ 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_definition_get_type (const t8_forest_ghost_definition_c *ghost_definition) +{ + T8_ASSERT (ghost_definition != NULL); + return ghost_definition->t8_ghost_get_type (); +} + +void +t8_forest_ghost_definition_ref (t8_forest_ghost_definition_c *ghost_definition) +{ + T8_ASSERT (ghost_definition != NULL); + ghost_definition->ref (); +} + +void +t8_forest_ghost_definition_unref (t8_forest_ghost_definition_c **pghost_definition) +{ + t8_forest_ghost_definition_c *ghost_definition; + + T8_ASSERT (pghost_definition != NULL); + ghost_definition = *pghost_definition; + T8_ASSERT (ghost_definition != NULL); + + if (ghost_definition->unref () == 0) { + ghost_definition = NULL; + } +} + +/** + * Abstract base class +*/ + +void +t8_forest_ghost_definition::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_definition::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_definition::clean_up (t8_forest_t forest) +{ + if (memory_flag & CREATE_GFIRST_DESC_ARRAY) { + /* Free the offset memory, if allocated */ + t8_shmem_array_destroy (&forest->element_offsets); + } + if (memory_flag & CREATE_TREE_ARRAY) { + /* Free the offset memory, if allocated */ + t8_shmem_array_destroy (&forest->tree_offsets); + } + if (memory_flag & CREATE_GFIRST_DESC_ARRAY) { + /* Free the offset memory, if allocated */ + 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_definition (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"); +} + +bool +t8_forest_ghost_w_search::do_ghost (t8_forest_t forest) +{ + + 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 T8_SUBROUTINE_FAILED; + } + + communicate_ownerships (forest); + + if (t8_forest_get_local_num_elements (forest) > 0) { + + /* Initialize the ghost structure */ + t8_forest_ghost_init (&forest->ghosts, ghost_type); + + search_for_ghost_elements (forest); + + communicate_ghost_elements (forest); + } + clean_up (forest); + + return T8_SUBROUTINE_SUCCESS; +} + +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.scheme = 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_ASSERT (forest->ghosts != NULL); + t8_forest_ghost_t ghost = forest->ghosts; + if (version == 3) { + t8_forest_ghost_fill_remote_v3 (forest); + } + else { + /* Construct the remote elements and processes. */ + t8_forest_ghost_fill_remote (forest, ghost, version != 1); + } +} + +/* Wrapper for derived face class */ +t8_forest_ghost_definition_c * +t8_forest_ghost_definition_face_new (const int version) +{ + T8_ASSERT (1 <= version && version <= 3); + return new t8_forest_ghost_face (version); +} + +int +t8_forest_ghost_definition_face_get_version (t8_forest_ghost_definition_c *ghost_definition) +{ + T8_ASSERT (ghost_definition != NULL); + T8_ASSERT (ghost_definition->t8_ghost_get_type () == T8_GHOST_FACES); + t8_forest_ghost_face *ghost_definition_passed = (t8_forest_ghost_face *) ghost_definition; + + return ghost_definition_passed->get_version (); +} + T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_ghost.h b/src/t8_forest/t8_forest_ghost.h index 427a73109e..a15afe94bb 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 @@ -65,7 +65,11 @@ t8_forest_ghost_num_trees (const t8_forest_t forest); t8_locidx_t t8_forest_ghost_get_tree_element_offset (t8_forest_t forest, t8_locidx_t lghost_tree); -/* TODO: document */ +/** Given an index in the ghost_tree array, return this tree's number of elements + * \param [in] forest The forest with constructed ghost layer. + * \param [in] lghost_tree A local ghost id of a ghost tree. + * \return The number of ghost elements in this tree. +*/ t8_locidx_t t8_forest_ghost_tree_num_elements (t8_forest_t forest, t8_locidx_t lghost_tree); @@ -162,12 +166,39 @@ 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_definition_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_definition_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_definition must have the \a type FACE and the \a version 2 + */ +void t8_forest_ghost_create (t8_forest_t forest); /** Create one layer of ghost elements for a forest. @@ -176,12 +207,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_definition 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_definition 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_definition.h b/src/t8_forest/t8_forest_ghost_definition.h new file mode 100644 index 0000000000..c0e19ac287 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_definition.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_DEFINITION_H +#define T8_FOREST_GHOST_DEFINITION_H + +#include + +T8_EXTERN_C_BEGIN (); + +/** This typedef holds virtual functions for a particular ghost definition. + * We need it so that we can use t8_ghost_definition_c pointers in .c files + * without them seeing the actual C++ code (and then not compiling) + */ +typedef struct t8_forest_ghost_definition t8_forest_ghost_definition_c; + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_DEFINITION_H */ diff --git a/src/t8_forest/t8_forest_ghost_definition.hxx b/src/t8_forest/t8_forest_ghost_definition.hxx new file mode 100644 index 0000000000..d670367978 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_definition.hxx @@ -0,0 +1,152 @@ +/* + 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_DEFINITION_HXX +#define T8_FOREST_GHOST_DEFINITION_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_definition_face_flag { CREATE_ELEMENT_ARRAY = 1, CREATE_TREE_ARRAY = 2, CREATE_GFIRST_DESC_ARRAY = 4 }; + +struct t8_forest_ghost_definition +{ + public: + /** + * Constructor: + * Creates t8_forest_ghost_definition of type non + * init the refcout + */ + t8_forest_ghost_definition () + { + t8_refcount_init (&rc); + t8_debugf ("Constructed the a None ghost_definition.\n"); + } + + /** + * Destructor. + * unref the refcout + */ + virtual ~t8_forest_ghost_definition () + { + if (sc_refcount_is_active (&rc)) { + T8_ASSERT (t8_refcount_is_last (&rc)); + t8_refcount_unref (&rc); + } + t8_debugf ("Deleted the ghost_definition.\n"); + } + + /** + * Get the type of the ghost_definition + * \return the type + */ + inline t8_ghost_type_t + t8_ghost_get_type () const + { + return ghost_type; + } + + /** + * Increase the reference count of the ghost_definition. + */ + inline void + ref () + { + t8_refcount_ref (&rc); + } + + /** + * Decrease the reference count of the ghost_definition. + * If the reference count reaches zero, the ghost_definition is deleted. + */ + inline const int + unref () + { + const int remaining = rc.refcount - 1; + if (t8_refcount_unref (&rc)) { + t8_debugf ("Deleting the ghost_definition.\n"); + delete this; + } + return remaining; + } + + /** 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 bool + 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 processes + * \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_definition + */ + explicit t8_forest_ghost_definition (t8_ghost_type_t g_type): ghost_type (g_type) + { + t8_refcount_init (&rc); + t8_debugf ("Constructed a ghost_definition.\n"); + }; + /** type of the ghost_definition */ + t8_ghost_type_t ghost_type { T8_GHOST_NONE }; + /** The reference count of the ghost_definition. 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_DEFINITION_HXX */ diff --git a/src/t8_forest/t8_forest_ghost_definition_wrapper.h b/src/t8_forest/t8_forest_ghost_definition_wrapper.h new file mode 100644 index 0000000000..b53e74f618 --- /dev/null +++ b/src/t8_forest/t8_forest_ghost_definition_wrapper.h @@ -0,0 +1,73 @@ +/* + 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_DEFINITION_WRAPPER_H +#define T8_FOREST_GHOST_DEFINITION_WRAPPER_H + +#include +#include +#include + +T8_EXTERN_C_BEGIN (); + +/** + * Satisfy the C interface of forest + * Create a new ghost_definition of type face with given version + */ +t8_forest_ghost_definition_c * +t8_forest_ghost_definition_face_new (const int version); + +/** + * Satisfy the C interface of forest + * Return for a ghost_definition of Type FACE the ghost_algorithm / ghost_version (1, 2 or 3) + * \param [in] ghost_definition Pointer to object of class t8_forest_ghost_face + */ +int +t8_forest_ghost_definition_face_get_version (t8_forest_ghost_definition_c *ghost_definition); + +/** + * Satisfy the C interface of forest + * Return the type of a ghost_definition + * \param [in] ghost_definition Pointer to object of class t8_forest_ghost_definition or a derivet class + */ +t8_ghost_type_t +t8_forest_ghost_definition_get_type (const t8_forest_ghost_definition_c *ghost_definition); + +/** + * Satisfy the C interface of forest + * Do a ref on the ghost_definition + * Needed in t8_forest_commit + */ +void +t8_forest_ghost_definition_ref (t8_forest_ghost_definition_c *ghost_definition); + +/** + * Satisfy the C interface of forest + * Do a unref on the ghost_definition + * Needed in t8_forest_commit and t8_forest_set_ghost_ext + */ +void +t8_forest_ghost_definition_unref (t8_forest_ghost_definition_c **pghost_definition); + +T8_EXTERN_C_END (); + +#endif /* !T8_FOREST_GHOST_DEFINITION_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..d86a36025f --- /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_DEFINITION_FACE_H +#define T8_GHOST_DEFINITION_FACE_H + +#include +#include +#include // Definition of t8_forest_search_fn + +struct t8_forest_ghost_w_search: public t8_forest_ghost_definition +{ + 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_definition (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 bool + 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_definition + * \param [in] search_function Function of type t8_forest_search_fn, used as callback function 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_definition (ghost_type), search_fn (search_function) + { + T8_ASSERT (ghost_type != T8_GHOST_NONE); + } + /** Callback function 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_DEFINITION_FACE_H */ diff --git a/src/t8_forest/t8_forest_io.h b/src/t8_forest/t8_forest_io.h index 3311e9eddf..7ff86f1ba3 100644 --- a/src/t8_forest/t8_forest_io.h +++ b/src/t8_forest/t8_forest_io.h @@ -67,7 +67,7 @@ t8_forest_save (t8_forest_t forest); * providing the user defined per element data. * If scalar and vector fields are used, all scalar fields * must come first in the array. - * \return True if successful, false if not (process local). + * \return T8_SUBROUTINE_SUCCESS if successful, T8_SUBROUTINE_FAILED if not (process local). * See also \ref t8_forest_write_vtk . */ int @@ -88,7 +88,7 @@ t8_forest_write_vtk_ext (t8_forest_t forest, const char *fileprefix, const int w * be stored. The master file is then fileprefix.pvtu * and the process with rank r writes in the file * fileprefix_r.vtu. - * \return True if successful, false if not (process local). + * \return T8_SUBROUTINE_SUCCESS if successful, T8_SUBROUTINE_FAILED if not (process local). */ int t8_forest_write_vtk (t8_forest_t forest, const char *fileprefix); diff --git a/src/t8_forest/t8_forest_types.h b/src/t8_forest/t8_forest_types.h index 5f9ca23481..3db4ef45a5 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,7 @@ #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 +99,13 @@ 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_forest_ghost_definition_c *ghost_definition; /**< The definition of the ghost as class, with a ghost_type > */ + 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 diff --git a/src/t8_vtk.c b/src/t8_vtk.c index 065ab5e9ae..09d190f329 100644 --- a/src/t8_vtk.c +++ b/src/t8_vtk.c @@ -24,7 +24,7 @@ /* Writes the pvtu header file that links to the processor local files. * This function should only be called by one process. - * Return 0 on success. */ + * Return T8_SUBROUTINE_SUCCESS on success. */ int t8_write_pvtu (const char *filename, int num_procs, int write_tree, int write_rank, int write_level, int write_id, int num_data, t8_vtk_data_field_t *data) @@ -50,7 +50,7 @@ t8_write_pvtu (const char *filename, int num_procs, int write_tree, int write_ra pvtufile = fopen (pvtufilename, "wb"); if (!pvtufile) { t8_global_errorf ("Could not open %s for output\n", pvtufilename); - return -1; + return T8_SUBROUTINE_FAILED; } fprintf (pvtufile, "\n"); @@ -261,11 +261,11 @@ t8_write_pvtu (const char *filename, int num_procs, int write_tree, int write_ra if (ferror (pvtufile)) { t8_global_errorf ("t8_vtk: Error writing parallel footer\n"); fclose (pvtufile); - return -1; + return T8_SUBROUTINE_FAILED; } if (fclose (pvtufile)) { t8_global_errorf ("t8_vtk: Error closing parallel footer\n"); - return -1; + return T8_SUBROUTINE_FAILED; } - return 0; + return T8_SUBROUTINE_SUCCESS; } diff --git a/src/t8_vtk.h b/src/t8_vtk.h index f96ddc18ce..250f5c7598 100644 --- a/src/t8_vtk.h +++ b/src/t8_vtk.h @@ -75,7 +75,7 @@ T8_EXTERN_C_BEGIN (); /* Writes the pvtu header file that links to the processor local files. * It is used by the cmesh and forest vtk routines. * This function should only be called by one process. - * Return 0 on success. */ + * Return T8_SUBROUTINE_SUCCESS on success. */ /* TODO: document */ int t8_write_pvtu (const char *filename, int num_procs, int write_tree, int write_rank, int write_level, int write_id, diff --git a/src/t8_vtk/t8_vtk_write_ASCII.cxx b/src/t8_vtk/t8_vtk_write_ASCII.cxx index 1f345ed60e..8997249604 100644 --- a/src/t8_vtk/t8_vtk_write_ASCII.cxx +++ b/src/t8_vtk/t8_vtk_write_ASCII.cxx @@ -692,11 +692,11 @@ t8_forest_vtk_write_cells (t8_forest_t forest, FILE *vtufile, const int write_tr } /* Function completed successfully */ - return 1; + return T8_SUBROUTINE_SUCCESS; t8_forest_vtk_cell_failure: /* Something went wrong */ t8_errorf ("Error when writing cell data to forest vtk file.\n"); - return 0; + return T8_SUBROUTINE_FAILED; } /* Write the cell data to an open file stream. @@ -772,11 +772,11 @@ t8_forest_vtk_write_points (t8_forest_t forest, FILE *vtufile, const int write_g freturn = fprintf (vtufile, " \n"); } /* Function completed successfully */ - return 1; + return T8_SUBROUTINE_SUCCESS; t8_forest_vtk_cell_failure: /* Something went wrong */ t8_errorf ("Error when writing cell data to forest vtk file.\n"); - return 0; + return T8_SUBROUTINE_FAILED; } int @@ -800,8 +800,8 @@ t8_forest_vtk_write_ASCII (t8_forest_t forest, const char *fileprefix, const int /* 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, - num_data, data)) { + if (!t8_write_pvtu (fileprefix, forest->mpisize, write_treeid, write_mpirank, write_level, write_element_id, + num_data, data)) { t8_errorf ("Error when writing file %s.pvtu\n", fileprefix); goto t8_forest_vtk_failure; } @@ -885,13 +885,13 @@ t8_forest_vtk_write_ASCII (t8_forest_t forest, const char *fileprefix, const int goto t8_forest_vtk_failure; } /* Writing was successful */ - return 1; + return T8_SUBROUTINE_SUCCESS; t8_forest_vtk_failure: if (vtufile != NULL) { fclose (vtufile); } t8_errorf ("Error when writing vtk file.\n"); - return 0; + return T8_SUBROUTINE_FAILED; } /* Return the local number of vertices in a cmesh. @@ -934,7 +934,7 @@ t8_cmesh_vtk_write_file_ext (const t8_cmesh_t cmesh, const char *fileprefix, con if (cmesh->mpirank == 0) { /* Write the pvtu header file. */ int num_ranks_that_write = cmesh->set_partition ? cmesh->mpisize : 1; - if (t8_write_pvtu (fileprefix, num_ranks_that_write, 1, 1, 0, 0, 0, NULL)) { + if (!t8_write_pvtu (fileprefix, num_ranks_that_write, 1, 1, 0, 0, 0, NULL)) { SC_ABORTF ("Error when writing file %s.pvtu\n", fileprefix); } } diff --git a/src/t8_vtk/t8_vtk_writer.hxx b/src/t8_vtk/t8_vtk_writer.hxx index 8f0f9dfef9..e416c3bce1 100644 --- a/src/t8_vtk/t8_vtk_writer.hxx +++ b/src/t8_vtk/t8_vtk_writer.hxx @@ -119,8 +119,8 @@ class vtk_writer { * A vtk-writer function that uses the vtk API. * * \param[in] grid The forest or cmesh that is translated. - * \return true, if writing was successful. - * \return false if writing was not successful. + * \return T8_SUBROUTINE_SUCCESS, if writing was successful. + * \return T8_SUBROUTINE_FAILED if writing was not successful. */ bool write_with_API (const grid_t grid) @@ -496,8 +496,8 @@ class vtk_writer { * Write a vtk file given a forest or a cmesh. * * \param[in] grid a forest or a cmesh that will be translated into a vtk-file. - * \return true if writing was successful. - * \return false if writing was not successful. + * \return T8_SUBROUTINE_SUCCESS if writing was successful. + * \return T8_SUBROUTINE_FAILED if writing was not successful. */ bool write_vtk (const grid_t grid) @@ -573,19 +573,19 @@ class vtk_writer { pwriterObj->SetInputData (unstructuredGrid); pwriterObj->Update (); if (pwriterObj->Write ()) { - return true; + return T8_SUBROUTINE_SUCCESS; } else { t8_errorf ("Error when writing vtk file.\n"); } /* Return whether writing was successful */ - return false; + return T8_SUBROUTINE_FAILED; #else t8_global_errorf ("Warning: t8code is not linked against vtk library. Vtk output will not be generated.\n"); t8_global_productionf ("Consider calling 't8_forest_write_vtk' or 't8_forest_vtk_write_file' instead.\n"); - return false; + return T8_SUBROUTINE_FAILED; #endif }