diff --git a/src/p4est_communication.c b/src/p4est_communication.c index 27fe8c349..92c737b30 100644 --- a/src/p4est_communication.c +++ b/src/p4est_communication.c @@ -595,6 +595,15 @@ p4est_comm_is_empty_gfq (const p4est_gloidx_t *gfq, int num_procs, int p) return gfq[p] == gfq[p + 1]; } +int +p4est_comm_is_empty_gfp (const p4est_quadrant_t *gfp, int num_procs, int p) +{ + P4EST_ASSERT (gfp != NULL); + P4EST_ASSERT (0 <= p && p < num_procs); + + return p4est_quadrant_is_equal_piggy (&gfp[p], &gfp[p + 1]); +} + int p4est_comm_is_contained (p4est_t * p4est, p4est_locidx_t which_tree, const p4est_quadrant_t * q, int rank) diff --git a/src/p4est_communication.h b/src/p4est_communication.h index 08e51e68d..2c37545c7 100644 --- a/src/p4est_communication.h +++ b/src/p4est_communication.h @@ -151,14 +151,24 @@ void p4est_comm_count_pertree (p4est_t * p4est, */ int p4est_comm_is_empty (p4est_t *p4est, int p); +/** Query whether a processor has no quadrants. + * \param [in] gfq An array encoding the partition offsets in the + * global quadrant array; length \a num_procs + 1. + * \param [in] num_procs Number of processes in the partition. + * \param [in] p Valid 0 <= \a p < \a num_procs. + * \return True if and only if processor \a p is empty. + */ +int p4est_comm_is_empty_gfq (const p4est_gloidx_t *gfq, + int num_procs, int p); + /** Query whether a processor has no quadrants. * \param [in] gfp An array encoding the partition shape. * Non-decreasing; length \a num_procs + 1. * \param [in] num_procs Number of processes in the partition. - * \param [in] p Valid 0 < \a p < \a num_procs. - * \return True if and only if processor \p is empty. + * \param [in] p Valid 0 <= \a p < \a num_procs. + * \return True if and only if processor \a p is empty. */ -int p4est_comm_is_empty_gfq (const p4est_gloidx_t *gfq, +int p4est_comm_is_empty_gfp (const p4est_quadrant_t *gfp, int num_procs, int p); /** Test whether a quadrant is fully contained in a rank's owned region. diff --git a/src/p4est_search.c b/src/p4est_search.c index 6297137b5..06bbcbce9 100644 --- a/src/p4est_search.c +++ b/src/p4est_search.c @@ -33,6 +33,11 @@ #endif #include +#define P4EST_COMM_IS_EMPTY_GFQ_GFP(gfq, gfp, num_procs, p) \ + (((gfq) != NULL) ? \ + p4est_comm_is_empty_gfq ((gfq), (num_procs), (p)) :\ + p4est_comm_is_empty_gfp ((gfp), (num_procs), (p))) + /** A callback function that describes the search window. * The idea is to define the type of an array entry as type 1, if * my_begin <= array[i], my_end > array[i] and as type 2, if the entry @@ -1347,7 +1352,8 @@ p4est_partition_recursion (const p4est_partition_recursion_t * rec, (rec->gfp, rec->num_procs, rec->num_trees, &child, cpfirst)) { /* cpfirst starts at the tree's first descendant but may be empty */ P4EST_ASSERT (i > 0); - while (p4est_comm_is_empty_gfq (rec->gfq, rec->num_procs, cpfirst)) { + while (P4EST_COMM_IS_EMPTY_GFQ_GFP + (rec->gfq, rec->gfp, rec->num_procs, cpfirst)) { ++cpfirst; P4EST_ASSERT (p4est_traverse_type_childid (rec->position_array, cpfirst, quadrant) == @@ -1454,6 +1460,33 @@ p4est_search_partition_gfx (const p4est_gloidx_t *gfq, quadrant_fn, point_fn, points); } +void +p4est_search_partition_gfp (const p4est_quadrant_t *gfp, int nmemb, + p4est_topidx_t num_trees, int call_post, + void *user, p4est_search_partition_t quadrant_fn, + p4est_search_partition_t point_fn, + sc_array_t *points) +{ + p4est_t p, *user_p4est = &p; + + /* sanity checks on global first position */ + P4EST_ASSERT (gfp != NULL); + P4EST_ASSERT (gfp[0].p.which_tree == 0); + P4EST_ASSERT (gfp[nmemb].x == 0); + P4EST_ASSERT (gfp[nmemb].y == 0); +#ifdef P4_TO_P8 + P4EST_ASSERT (gfp[nmemb].z == 0); +#endif + P4EST_ASSERT (gfp[nmemb].p.which_tree == num_trees); + + /* conjure up call convention for partition search */ + memset (user_p4est, 0, sizeof (p4est_t)); + user_p4est->user_pointer = user; + p4est_search_partition_internal + (NULL, gfp, nmemb, num_trees, call_post, user_p4est, + quadrant_fn, point_fn, points); +} + void p4est_search_partition_internal (const p4est_gloidx_t *gfq, const p4est_quadrant_t *gfp, int nmemb, p4est_topidx_t num_trees, int call_post, p4est_t *user_p4est, @@ -1469,7 +1502,6 @@ void p4est_search_partition_internal p4est_partition_recursion_t srec, *rec = &srec; /* we do nothing if there is nothing to be done */ - P4EST_ASSERT (gfq != NULL); P4EST_ASSERT (gfp != NULL); P4EST_ASSERT (points == NULL || point_fn != NULL); if (quadrant_fn == NULL && points == NULL) { @@ -1526,7 +1558,8 @@ void p4est_search_partition_internal if (p4est_traverse_is_clean_start (rec->gfp, rec->num_procs, rec->num_trees, &root, pfirst)) { /* pfirst starts at the tree's first descendant but may be empty */ - while (p4est_comm_is_empty_gfq (rec->gfq, rec->num_procs, pfirst)) { + while (P4EST_COMM_IS_EMPTY_GFQ_GFP + (rec->gfq, rec->gfp, rec->num_procs, pfirst)) { ++pfirst; P4EST_ASSERT (p4est_traverse_type_tree (&position_array, pfirst, NULL) == (size_t) tt); diff --git a/src/p4est_search.h b/src/p4est_search.h index 2dfd3f5eb..a68101a86 100644 --- a/src/p4est_search.h +++ b/src/p4est_search.h @@ -311,7 +311,7 @@ typedef int (*p4est_search_reorder_t) (p4est_t * p4est, sc_array_t * indices); /** Run a depth-first traversal, optionally filtering search points. - * There are three main differences to \ref p4est_search_local: + * There are three main differences to \ref p4est_search_local : * * * Before beginning the recursion, we call the \a reorder_fn callback * with an index array enumerating the local tree roots. The callback @@ -452,6 +452,43 @@ void p4est_search_partition_gfx p4est_search_partition_t quadrant_fn, p4est_search_partition_t point_fn, sc_array_t *points); +/** Traverse some given global partition top-down. + * The partition can be that of any p4est, not necessarily known to the + * caller. This is not a collective function. It does not communicate. + * We proceed top-down through the partition, identically on all processors + * except for the results of two user-provided callbacks. The recursion will only + * go down branches that are split between multiple processors. The callback + * functions can be used to stop a branch recursion even for split branches. + * This function offers the option to search for arbitrary user-defined points + * analogously to \ref p4est_search_local. + * This function is similar to \ref p4est_search_partition_gfx, but does not + * require the \ref p4est_gloidx_t array gfq. If gfq is available, using + * \ref p4est_search_partition_gfx is recommended, because it is slightly faster. + * \note Traversing the whole given partition will be at least O(P), + * so sensible use of the callback function is advised to cut it short. + * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. + * \param [in] nmemb Number of processors encoded in \a gfp (plus one). + * \param [in] num_trees Tree number must match the contents of \a gfp. + * \param [in] call_post If true, call quadrant callback both pre and post + * point callback, in both cases before recursion (!). + * \param [in] user We pass a dummy p4est to the callbacks whose only + * valid element is its user_pointer set to \a user. + * \param [in] quadrant_fn This function controls the recursion, + * which only continues deeper if this + * callback returns true for a branch quadrant. + * It is allowed to set this to NULL. + * \param [in] point_fn This function decides per-point whether it is + * followed down the recursion. + * Must be non-NULL if \b points are not NULL. + * \param [in] points User-provided array of \b points that are + * passed to the callback \b point_fn. + * See \ref p4est_search_local for details. + */ +void p4est_search_partition_gfp + (const p4est_quadrant_t *gfp, int nmemb, p4est_topidx_t num_trees, + int call_post, void *user, p4est_search_partition_t quadrant_fn, + p4est_search_partition_t point_fn, sc_array_t *points); + /** Callback function for the top-down search through the whole forest. * \param [in] p4est The forest to search. * We recurse through the trees one after another. diff --git a/src/p4est_to_p8est.h b/src/p4est_to_p8est.h index 649110854..07df7980a 100644 --- a/src/p4est_to_p8est.h +++ b/src/p4est_to_p8est.h @@ -412,6 +412,7 @@ #define p4est_search_reorder p8est_search_reorder #define p4est_search_partition p8est_search_partition #define p4est_search_partition_gfx p8est_search_partition_gfx +#define p4est_search_partition_gfp p8est_search_partition_gfp #define p4est_search_all p8est_search_all #define p4est_build_new p8est_build_new #define p4est_build_init_add p8est_build_init_add @@ -461,6 +462,7 @@ #define p4est_comm_count_pertree p8est_comm_count_pertree #define p4est_comm_is_empty p8est_comm_is_empty #define p4est_comm_is_empty_gfq p8est_comm_is_empty_gfq +#define p4est_comm_is_empty_gfp p8est_comm_is_empty_gfp #define p4est_comm_is_contained p8est_comm_is_contained #define p4est_comm_is_owner p8est_comm_is_owner #define p4est_comm_is_owner_gfp p8est_comm_is_owner_gfp diff --git a/src/p8est_communication.h b/src/p8est_communication.h index 062a4341e..12d4cf841 100644 --- a/src/p8est_communication.h +++ b/src/p8est_communication.h @@ -151,14 +151,24 @@ void p8est_comm_count_pertree (p8est_t * p8est, */ int p8est_comm_is_empty (p8est_t *p8est, int p); +/** Query whether a processor has no quadrants. + * \param [in] gfq An array encoding the partition offsets in the + * global quadrant array; length \a num_procs + 1. + * \param [in] num_procs Number of processes in the partition. + * \param [in] p Valid 0 <= \a p < \a num_procs. + * \return True if and only if processor \a p is empty. + */ +int p8est_comm_is_empty_gfq (const p4est_gloidx_t *gfq, + int num_procs, int p); + /** Query whether a processor has no quadrants. * \param [in] gfp An array encoding the partition shape. * Non-decreasing; length \a num_procs + 1. * \param [in] num_procs Number of processes in the partition. - * \param [in] p Valid 0 < \a p < \a num_procs. - * \return True if and only if processor \p is empty. + * \param [in] p Valid 0 <= \a p < \a num_procs. + * \return True if and only if processor \a p is empty. */ -int p8est_comm_is_empty_gfq (const p4est_gloidx_t *gfq, +int p8est_comm_is_empty_gfp (const p8est_quadrant_t *gfp, int num_procs, int p); /** Test whether a quadrant is fully contained in a rank's owned region. diff --git a/src/p8est_search.h b/src/p8est_search.h index 69f00d4a9..0d32b1009 100644 --- a/src/p8est_search.h +++ b/src/p8est_search.h @@ -314,7 +314,7 @@ typedef int (*p8est_search_reorder_t) (p8est_t * p4est, sc_array_t * indices); /** Run a depth-first traversal, optionally filtering search points. - * There are three main differences to \ref p4est_search_local: + * There are three main differences to \ref p8est_search_local : * * * Before beginning the recursion, we call the \a reorder_fn callback * with an index array enumerating the local tree roots. The callback @@ -394,7 +394,7 @@ typedef int (*p8est_search_partition_t) (p8est_t * p4est, * go down branches that are split between multiple processors. The callback * functions can be used to stop a branch recursion even for split branches. * This function offers the option to search for arbitrary user-defined points - * analogously to \ref p4est_search_local. + * analogously to \ref p8est_search_local. * \note Traversing the whole processor partition will be at least O(P), * so sensible use of the callback function is advised to cut it short. * \param [in] p4est The forest to traverse. @@ -454,6 +454,43 @@ void p8est_search_partition_gfx p8est_search_partition_t quadrant_fn, p8est_search_partition_t point_fn, sc_array_t *points); +/** Traverse some given global partition top-down. + * The partition can be that of any p4est, not necessarily known to the + * caller. This is not a collective function. It does not communicate. + * We proceed top-down through the partition, identically on all processors + * except for the results of two user-provided callbacks. The recursion will only + * go down branches that are split between multiple processors. The callback + * functions can be used to stop a branch recursion even for split branches. + * This function offers the option to search for arbitrary user-defined points + * analogously to \ref p8est_search_local. + * This function is similar to \ref p8est_search_partition_gfx, but does not + * require the \ref p4est_gloidx_t array gfq. If gfq is available, using + * \ref p8est_search_partition_gfx is recommended, because it is slightly faster. + * \note Traversing the whole given partition will be at least O(P), + * so sensible use of the callback function is advised to cut it short. + * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. + * \param [in] nmemb Number of processors encoded in \a gfp (plus one). + * \param [in] num_trees Tree number must match the contents of \a gfp. + * \param [in] call_post If true, call quadrant callback both pre and post + * point callback, in both cases before recursion (!). + * \param [in] user We pass a dummy p4est to the callbacks whose only + * valid element is its user_pointer set to \a user. + * \param [in] quadrant_fn This function controls the recursion, + * which only continues deeper if this + * callback returns true for a branch quadrant. + * It is allowed to set this to NULL. + * \param [in] point_fn This function decides per-point whether it is + * followed down the recursion. + * Must be non-NULL if \b points are not NULL. + * \param [in] points User-provided array of \b points that are + * passed to the callback \b point_fn. + * See \ref p8est_search_local for details. + */ +void p8est_search_partition_gfp + (const p8est_quadrant_t *gfp, int nmemb, p4est_topidx_t num_trees, + int call_post, void *user, p8est_search_partition_t quadrant_fn, + p8est_search_partition_t point_fn, sc_array_t *points); + /** Callback function for the top-down search through the whole forest. * \param [in] p4est The forest to search. * We recurse through the trees one after another. @@ -512,8 +549,8 @@ typedef int (*p8est_search_all_t) (p8est_t * p8est, /** Perform a top-down search on the whole forest. * - * This function combines the functionality of \ref p4est_search_local and \ref - * p4est_search_partition; their documentation applies for the most part. + * This function combines the functionality of \ref p8est_search_local and \ref + * p8est_search_partition; their documentation applies for the most part. * * The recursion proceeds from the root quadrant of each tree until * (a) we encounter a remote quadrant that covers only one processor, or @@ -544,7 +581,7 @@ typedef int (*p8est_search_all_t) (p8est_t * p8est, * \note * This function works fine when used for the special cases that either the * partition or the local quadrants are not of interest. However, in the case - * of querying only local information we expect that \ref p4est_search_local + * of querying only local information we expect that \ref p8est_search_local * will be faster since it employs specific local optimizations. * * \param [in] p4est The forest to be searched.