Skip to content

Commit

Permalink
Merge pull request #196 from hannesbrandt/develop
Browse files Browse the repository at this point in the history
Introduce p4est_search_partition_gfp
  • Loading branch information
cburstedde authored Dec 7, 2023
2 parents 436780c + 176b92a commit 0b3402b
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 15 deletions.
9 changes: 9 additions & 0 deletions src/p4est_communication.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 13 additions & 3 deletions src/p4est_communication.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
39 changes: 36 additions & 3 deletions src/p4est_search.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
#endif
#include <sc_search.h>

#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
Expand Down Expand Up @@ -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) ==
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
39 changes: 38 additions & 1 deletion src/p4est_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions src/p4est_to_p8est.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions src/p8est_communication.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
47 changes: 42 additions & 5 deletions src/p8est_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 0b3402b

Please sign in to comment.