int p6est_profile_sync (p6est_profile_t * profile) { p4est_lnodes_t *lnodes = profile->lnodes; p4est_locidx_t nln = lnodes->num_local_nodes; sc_array_t lrview; p4est_lnodes_buffer_t *countbuf; sc_array_t *sharers; size_t zz, nsharers; int nleft; int8_t *recv, *send; int *array_of_indices; p4est_locidx_t recv_total; p4est_locidx_t *recv_offsets, recv_offset; p4est_locidx_t send_total; p4est_locidx_t *send_offsets, send_offset; p4est_locidx_t (*lr)[2]; sc_array_t *lc = profile->lnode_columns; sc_MPI_Request *recv_request, *send_request; sc_array_t *work; int any_change = 0; int any_global_change; int mpiret, mpirank; int evenodd = profile->evenodd; lr = (p4est_locidx_t (*)[2]) profile->lnode_ranges; sharers = lnodes->sharers; nsharers = sharers->elem_count; mpiret = sc_MPI_Comm_rank (lnodes->mpicomm, &mpirank); SC_CHECK_MPI (mpiret); sc_array_init_data (&lrview, lr, 2 * sizeof (p4est_locidx_t), nln); countbuf = p4est_lnodes_share_all_begin (&lrview, lnodes); send_offsets = P4EST_ALLOC (p4est_locidx_t, nsharers + 1); send_offset = 0; for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *sharer; sc_array_t *send_buf; size_t zy, nnodes; send_offsets[zz] = send_offset; sharer = p4est_lnodes_rank_array_index (sharers, zz); if (sharer->rank == mpirank) { continue; } send_buf = (sc_array_t *) sc_array_index (countbuf->send_buffers, zz); nnodes = sharer->shared_nodes.elem_count; P4EST_ASSERT (nnodes == send_buf->elem_count); P4EST_ASSERT (send_buf->elem_size == 2 * sizeof (p4est_locidx_t)); for (zy = 0; zy < nnodes; zy++) { p4est_locidx_t *lp = (p4est_locidx_t *) sc_array_index (send_buf, zy); P4EST_ASSERT (lp[0] >= 0); P4EST_ASSERT (lp[1] >= 0); send_offset += lp[1]; } } send_total = send_offsets[nsharers] = send_offset; p4est_lnodes_share_all_end (countbuf); recv_offsets = P4EST_ALLOC (p4est_locidx_t, nsharers + 1); recv_offset = 0; for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *sharer; sc_array_t *recv_buf; size_t zy, nnodes; recv_offsets[zz] = recv_offset; sharer = p4est_lnodes_rank_array_index (sharers, zz); if (sharer->rank == mpirank) { continue; } recv_buf = (sc_array_t *) sc_array_index (countbuf->recv_buffers, zz); nnodes = sharer->shared_nodes.elem_count; P4EST_ASSERT (nnodes == recv_buf->elem_count); P4EST_ASSERT (recv_buf->elem_size == 2 * sizeof (p4est_locidx_t)); for (zy = 0; zy < nnodes; zy++) { p4est_locidx_t *lp = (p4est_locidx_t *) sc_array_index (recv_buf, zy); P4EST_ASSERT (lp[0] >= 0); P4EST_ASSERT (lp[1] >= 0); recv_offset += lp[1]; } } recv_total = recv_offsets[nsharers] = recv_offset; recv = P4EST_ALLOC (int8_t, recv_total); recv_request = P4EST_ALLOC (sc_MPI_Request, nsharers); send = P4EST_ALLOC (int8_t, send_total); send_request = P4EST_ALLOC (sc_MPI_Request, nsharers); /* post receives */ nleft = 0; for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *sharer; int icount = recv_offsets[zz + 1] - recv_offsets[zz]; sharer = p4est_lnodes_rank_array_index (sharers, zz); if (sharer->rank == mpirank) { recv_request[zz] = sc_MPI_REQUEST_NULL; continue; } if (icount) { mpiret = sc_MPI_Irecv (recv + recv_offsets[zz], icount * sizeof (int8_t), sc_MPI_BYTE, sharer->rank, P6EST_COMM_BALANCE, lnodes->mpicomm, recv_request + zz); SC_CHECK_MPI (mpiret); nleft++; } else { recv_request[zz] = sc_MPI_REQUEST_NULL; } } /* post sends */ for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *sharer; size_t zy, nnodes; int icount; sc_array_t *shared_nodes; sharer = p4est_lnodes_rank_array_index (sharers, zz); if (sharer->rank == mpirank) { send_request[zz] = sc_MPI_REQUEST_NULL; continue; } shared_nodes = &sharer->shared_nodes; nnodes = shared_nodes->elem_count; icount = 0; for (zy = 0; zy < nnodes; zy++) { p4est_locidx_t nidx; int8_t *c; nidx = *((p4est_locidx_t *) sc_array_index (shared_nodes, zy)); if (lr[nidx][1]) { c = (int8_t *) sc_array_index (lc, lr[nidx][0]); memcpy (send + send_offsets[zz] + icount, c, lr[nidx][1] * sizeof (int8_t)); icount += lr[nidx][1]; } else { P4EST_ASSERT (!lr[nidx][0]); } } P4EST_ASSERT (icount == send_offsets[zz + 1] - send_offsets[zz]); if (icount) { mpiret = sc_MPI_Isend (send + send_offsets[zz], icount * sizeof (int8_t), sc_MPI_BYTE, sharer->rank, P6EST_COMM_BALANCE, lnodes->mpicomm, send_request + zz); SC_CHECK_MPI (mpiret); } else { send_request[zz] = sc_MPI_REQUEST_NULL; } } work = sc_array_new (sizeof (int8_t)); array_of_indices = P4EST_ALLOC (int, nsharers); while (nleft) { int outcount; int i; mpiret = sc_MPI_Waitsome (nsharers, recv_request, &outcount, array_of_indices, sc_MPI_STATUSES_IGNORE); SC_CHECK_MPI (mpiret); for (i = 0; i < outcount; i++) { p4est_lnodes_rank_t *sharer; size_t zy, nnode; sc_array_t *shared_nodes; sc_array_t *recv_buf; zz = array_of_indices[i]; sharer = p4est_lnodes_rank_array_index (sharers, zz); shared_nodes = &sharer->shared_nodes; recv_buf = (sc_array_t *) sc_array_index (countbuf->recv_buffers, zz); nnode = shared_nodes->elem_count; P4EST_ASSERT (nnode == recv_buf->elem_count); recv_offset = recv_offsets[zz]; for (zy = 0; zy < nnode; zy++) { p4est_locidx_t *lp; p4est_locidx_t nidx; sc_array_t oldview, newview; nidx = *((p4est_locidx_t *) sc_array_index (shared_nodes, zy)); lp = (p4est_locidx_t *) sc_array_index (recv_buf, zy); sc_array_init_view (&oldview, lc, lr[nidx][0], lr[nidx][1]); sc_array_init_data (&newview, recv + recv_offset, sizeof (int8_t), lp[1]); if (profile->ptype == P6EST_PROFILE_UNION) { p6est_profile_union (&oldview, &newview, work); if (work->elem_count > oldview.elem_count) { int8_t *c; any_change = 1; lr[nidx][0] = lc->elem_count; lr[nidx][1] = work->elem_count; profile->lnode_changed[evenodd][nidx] = 1; c = (int8_t *) sc_array_push_count (lc, work->elem_count); memcpy (c, work->array, work->elem_count * work->elem_size); } } else { p6est_profile_intersection (&oldview, &newview, work); P4EST_ASSERT (work->elem_count <= oldview.elem_count); if (work->elem_count < oldview.elem_count) { lr[nidx][1] = work->elem_count; memcpy (oldview.array, work->array, work->elem_count * work->elem_size); } } recv_offset += lp[1]; } P4EST_ASSERT (recv_offset == recv_offsets[zz + 1]); } nleft -= outcount; P4EST_ASSERT (nleft >= 0); } P4EST_FREE (array_of_indices); sc_array_destroy (work); p6est_profile_compress (profile); p4est_lnodes_buffer_destroy (countbuf); P4EST_FREE (recv_request); P4EST_FREE (recv_offsets); P4EST_FREE (recv); { mpiret = sc_MPI_Waitall (nsharers, send_request, sc_MPI_STATUSES_IGNORE); SC_CHECK_MPI (mpiret); P4EST_FREE (send_request); P4EST_FREE (send_offsets); P4EST_FREE (send); any_global_change = any_change; mpiret = sc_MPI_Allreduce (&any_change, &any_global_change, 1, sc_MPI_INT, sc_MPI_LOR, lnodes->mpicomm); SC_CHECK_MPI (mpiret); } return any_global_change; }
p4est_t * p4est_new_points (sc_MPI_Comm mpicomm, p4est_connectivity_t * connectivity, int maxlevel, p4est_quadrant_t * points, p4est_locidx_t num_points, p4est_locidx_t max_points, size_t data_size, p4est_init_t init_fn, void *user_pointer) { int mpiret; int num_procs, rank; int i, isizet; size_t lcount; size_t *nmemb; #ifdef P4EST_ENABLE_DEBUG size_t zz; #endif p4est_topidx_t jt, num_trees; p4est_topidx_t first_tree, last_tree, next_tree; p4est_quadrant_t *first_quad, *next_quad, *quad; p4est_quadrant_t a, b, c, f, l, n; p4est_tree_t *tree; p4est_t *p4est; p4est_points_state_t ppstate; P4EST_GLOBAL_PRODUCTIONF ("Into " P4EST_STRING "_new_points with max level %d max points %lld\n", maxlevel, (long long) max_points); p4est_log_indent_push (); P4EST_ASSERT (p4est_connectivity_is_valid (connectivity)); P4EST_ASSERT (max_points >= -1); /* retrieve MPI information */ mpiret = sc_MPI_Comm_size (mpicomm, &num_procs); SC_CHECK_MPI (mpiret); mpiret = sc_MPI_Comm_rank (mpicomm, &rank); SC_CHECK_MPI (mpiret); /* This implementation runs in O(P/p * maxlevel) * with P the total number of points, p the number of processors. * Two optimizations are possible: * 1. At startup remove points that lead to duplicate quadrants. * 2. Use complete_region between successive points instead of * the call to refine. This should give O(N/p) * maxlevel * with N the total number of quadrants. */ /* parallel sort the incoming points */ lcount = (size_t) num_points; nmemb = P4EST_ALLOC_ZERO (size_t, num_procs); isizet = (int) sizeof (size_t); mpiret = sc_MPI_Allgather (&lcount, isizet, sc_MPI_BYTE, nmemb, isizet, sc_MPI_BYTE, mpicomm); SC_CHECK_MPI (mpiret); sc_psort (mpicomm, points, nmemb, sizeof (p4est_quadrant_t), p4est_quadrant_compare_piggy); P4EST_FREE (nmemb); #ifdef P4EST_ENABLE_DEBUG first_quad = points; for (zz = 1; zz < lcount; ++zz) { next_quad = points + zz; P4EST_ASSERT (p4est_quadrant_compare_piggy (first_quad, next_quad) <= 0); first_quad = next_quad; } #endif /* create the p4est */ p4est = P4EST_ALLOC_ZERO (p4est_t, 1); ppstate.points = points; ppstate.num_points = num_points; ppstate.max_points = max_points; ppstate.current = 0; ppstate.maxlevel = maxlevel; /* assign some data members */ p4est->data_size = 2 * sizeof (p4est_locidx_t); /* temporary */ p4est->user_pointer = &ppstate; p4est->connectivity = connectivity; num_trees = connectivity->num_trees; /* create parallel environment */ p4est_comm_parallel_env_create (p4est, mpicomm); /* allocate memory pools */ p4est->user_data_pool = sc_mempool_new (p4est->data_size); p4est->quadrant_pool = sc_mempool_new (sizeof (p4est_quadrant_t)); P4EST_GLOBAL_PRODUCTIONF ("New " P4EST_STRING " with %lld trees on %d processors\n", (long long) num_trees, num_procs); /* allocate trees */ p4est->trees = sc_array_new (sizeof (p4est_tree_t)); sc_array_resize (p4est->trees, num_trees); for (jt = 0; jt < num_trees; ++jt) { tree = p4est_tree_array_index (p4est->trees, jt); sc_array_init (&tree->quadrants, sizeof (p4est_quadrant_t)); P4EST_QUADRANT_INIT (&tree->first_desc); P4EST_QUADRANT_INIT (&tree->last_desc); tree->quadrants_offset = 0; for (i = 0; i <= P4EST_QMAXLEVEL; ++i) { tree->quadrants_per_level[i] = 0; } for (; i <= P4EST_MAXLEVEL; ++i) { tree->quadrants_per_level[i] = -1; } tree->maxlevel = 0; } p4est->local_num_quadrants = 0; p4est->global_num_quadrants = 0; /* create point based partition */ P4EST_QUADRANT_INIT (&f); p4est->global_first_position = P4EST_ALLOC_ZERO (p4est_quadrant_t, num_procs + 1); if (num_points == 0) { P4EST_VERBOSE ("Empty processor"); first_tree = p4est->first_local_tree = -1; first_quad = NULL; } else { /* we are probably not empty */ if (rank == 0) { first_tree = p4est->first_local_tree = 0; p4est_quadrant_set_morton (&f, maxlevel, 0); } else { first_tree = p4est->first_local_tree = points->p.which_tree; p4est_node_to_quadrant (points, maxlevel, &f); } first_quad = &f; } last_tree = p4est->last_local_tree = -2; p4est_comm_global_partition (p4est, first_quad); first_quad = p4est->global_first_position + rank; next_quad = p4est->global_first_position + (rank + 1); next_tree = next_quad->p.which_tree; if (first_tree >= 0 && p4est_quadrant_is_equal (first_quad, next_quad) && first_quad->p.which_tree == next_quad->p.which_tree) { /* if all our points are consumed by the next processor we are empty */ first_tree = p4est->first_local_tree = -1; } if (first_tree >= 0) { /* we are definitely not empty */ if (next_quad->x == 0 && next_quad->y == 0 #ifdef P4_TO_P8 && next_quad->z == 0 #endif ) { last_tree = p4est->last_local_tree = next_tree - 1; } else { last_tree = p4est->last_local_tree = next_tree; } P4EST_ASSERT (first_tree <= last_tree); } /* fill the local trees */ P4EST_QUADRANT_INIT (&a); P4EST_QUADRANT_INIT (&b); P4EST_QUADRANT_INIT (&c); P4EST_QUADRANT_INIT (&l); n = *next_quad; n.level = (int8_t) maxlevel; for (jt = first_tree; jt <= last_tree; ++jt) { int onlyone = 0; int includeb = 0; tree = p4est_tree_array_index (p4est->trees, jt); /* determine first local quadrant of this tree */ if (jt == first_tree) { a = *first_quad; a.level = (int8_t) maxlevel; first_quad = next_quad = NULL; /* free to use further down */ P4EST_ASSERT (p4est_quadrant_is_valid (&a)); } else { p4est_quadrant_set_morton (&a, maxlevel, 0); P4EST_ASSERT (jt < next_tree || p4est_quadrant_compare (&a, &n) < 0); } /* enlarge first local quadrant if possible */ if (jt < next_tree) { while (p4est_quadrant_child_id (&a) == 0 && a.level > 0) { p4est_quadrant_parent (&a, &a); } P4EST_ASSERT (jt == first_tree || a.level == 0); } else { for (c = a; p4est_quadrant_child_id (&c) == 0; a = c) { p4est_quadrant_parent (&c, &c); p4est_quadrant_last_descendant (&c, &l, maxlevel); if (p4est_quadrant_compare (&l, &n) >= 0) { break; } } P4EST_ASSERT (a.level > 0); P4EST_ASSERT ((p4est_quadrant_last_descendant (&a, &l, maxlevel), p4est_quadrant_compare (&l, &n) < 0)); } p4est_quadrant_first_descendant (&a, &tree->first_desc, P4EST_QMAXLEVEL); /* determine largest possible last quadrant of this tree */ if (jt < next_tree) { p4est_quadrant_last_descendant (&a, &l, maxlevel); p4est_quadrant_set_morton (&b, 0, 0); p4est_quadrant_last_descendant (&b, &b, maxlevel); if (p4est_quadrant_is_equal (&l, &b)) { onlyone = 1; } else { includeb = 1; for (c = b; p4est_quadrant_child_id (&c) == P4EST_CHILDREN - 1; b = c) { p4est_quadrant_parent (&c, &c); p4est_quadrant_first_descendant (&c, &f, maxlevel); if (p4est_quadrant_compare (&l, &f) >= 0) { break; } } } } else { b = n; } /* create a complete tree */ if (onlyone) { quad = p4est_quadrant_array_push (&tree->quadrants); *quad = a; p4est_quadrant_init_data (p4est, jt, quad, p4est_points_init); tree->maxlevel = a.level; ++tree->quadrants_per_level[a.level]; } else { p4est_complete_region (p4est, &a, 1, &b, includeb, tree, jt, p4est_points_init); quad = p4est_quadrant_array_index (&tree->quadrants, tree->quadrants.elem_count - 1); } tree->quadrants_offset = p4est->local_num_quadrants; p4est->local_num_quadrants += tree->quadrants.elem_count; p4est_quadrant_last_descendant (quad, &tree->last_desc, P4EST_QMAXLEVEL); /* verification */ #ifdef P4EST_ENABLE_DEBUG first_quad = p4est_quadrant_array_index (&tree->quadrants, 0); for (zz = 1; zz < tree->quadrants.elem_count; ++zz) { next_quad = p4est_quadrant_array_index (&tree->quadrants, zz); P4EST_ASSERT (((p4est_locidx_t *) first_quad->p.user_data)[1] == ((p4est_locidx_t *) next_quad->p.user_data)[0]); first_quad = next_quad; } #endif } if (last_tree >= 0) { for (; jt < num_trees; ++jt) { tree = p4est_tree_array_index (p4est->trees, jt); tree->quadrants_offset = p4est->local_num_quadrants; } } /* compute some member variables */ p4est->global_first_quadrant = P4EST_ALLOC (p4est_gloidx_t, num_procs + 1); p4est_comm_count_quadrants (p4est); /* print more statistics */ P4EST_VERBOSEF ("total local quadrants %lld\n", (long long) p4est->local_num_quadrants); P4EST_ASSERT (p4est_is_valid (p4est)); p4est_log_indent_pop (); P4EST_GLOBAL_PRODUCTIONF ("Done " P4EST_STRING "_new_points with %lld total quadrants\n", (long long) p4est->global_num_quadrants); /* refine to have one point per quadrant */ if (max_points >= 0) { p4est_refine_ext (p4est, 1, maxlevel, p4est_points_refine, p4est_points_init, NULL); #ifdef P4EST_ENABLE_DEBUG for (jt = first_tree; jt <= last_tree; ++jt) { tree = p4est_tree_array_index (p4est->trees, jt); first_quad = p4est_quadrant_array_index (&tree->quadrants, 0); for (zz = 1; zz < tree->quadrants.elem_count; ++zz) { next_quad = p4est_quadrant_array_index (&tree->quadrants, zz); P4EST_ASSERT (((p4est_locidx_t *) first_quad->p.user_data)[1] == ((p4est_locidx_t *) next_quad->p.user_data)[0]); first_quad = next_quad; } } #endif } /* initialize user pointer and data size */ p4est_reset_data (p4est, data_size, init_fn, user_pointer); return p4est; }
p6est_profile_t * p6est_profile_new_local (p6est_t * p6est, p6est_ghost_t * ghost, p6est_profile_type_t ptype, p8est_connect_type_t btype, int degree) { p6est_profile_t *profile = P4EST_ALLOC (p6est_profile_t, 1); p4est_lnodes_t *lnodes; p4est_locidx_t nln, nle; p4est_topidx_t jt; p4est_t *columns = p6est->columns; p4est_tree_t *tree; sc_array_t *tquadrants; p4est_quadrant_t *col; p4est_qcoord_t diff = P4EST_ROOT_LEN - p6est->root_len; size_t first, last, count, zz, zy; p4est_locidx_t *en, (*lr)[2]; sc_array_t *lc; int i, j; p2est_quadrant_t *layer; sc_array_t *layers = p6est->layers; p4est_locidx_t nidx, enidx; p4est_connect_type_t hbtype; int8_t *c; sc_array_t *thisprof; sc_array_t *selfprof; sc_array_t *faceprof; sc_array_t *cornerprof; sc_array_t *work; sc_array_t oldprof; const int Nrp = degree + 1; P4EST_ASSERT (degree > 1); profile->ptype = ptype; profile->btype = btype; profile->lnode_changed[0] = NULL; profile->lnode_changed[1] = NULL; profile->enode_counts = NULL; profile->diff = diff; if (btype == P8EST_CONNECT_FACE) { hbtype = P4EST_CONNECT_FACE; } else { hbtype = P4EST_CONNECT_FULL; } if (ghost == NULL) { profile->cghost = p4est_ghost_new (p6est->columns, P4EST_CONNECT_FULL); profile->ghost_owned = 1; } else { P4EST_ASSERT (ghost->column_ghost->btype == P4EST_CONNECT_FULL); profile->cghost = ghost->column_ghost; profile->ghost_owned = 0; } if (ptype == P6EST_PROFILE_UNION) { P4EST_ASSERT (degree == 2); } profile->lnodes = lnodes = p4est_lnodes_new (p6est->columns, profile->cghost, degree); en = lnodes->element_nodes; nln = lnodes->num_local_nodes; nle = lnodes->num_local_elements; profile->lnode_ranges = P4EST_ALLOC_ZERO (p4est_locidx_t, 2 * nln); lr = (p4est_locidx_t (*)[2]) profile->lnode_ranges; profile->lnode_columns = lc = sc_array_new (sizeof (int8_t)); selfprof = sc_array_new (sizeof (int8_t)); work = sc_array_new (sizeof (int8_t)); faceprof = sc_array_new (sizeof (int8_t)); cornerprof = sc_array_new (sizeof (int8_t)); if (ptype == P6EST_PROFILE_UNION) { profile->lnode_changed[0] = P4EST_ALLOC (p4est_locidx_t, nln); profile->lnode_changed[1] = P4EST_ALLOC (p4est_locidx_t, nln); profile->enode_counts = P4EST_ALLOC (p4est_locidx_t, P4EST_INSUL * nle); profile->evenodd = 0; memset (profile->lnode_changed[0], -1, nln * sizeof (int)); } /* create the profiles for each node: layers are reduced to just their level * */ for (enidx = 0, jt = columns->first_local_tree; jt <= columns->last_local_tree; ++jt) { tree = p4est_tree_array_index (columns->trees, jt); tquadrants = &tree->quadrants; for (zz = 0; zz < tquadrants->elem_count; ++zz) { col = p4est_quadrant_array_index (tquadrants, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); count = last - first; sc_array_truncate (selfprof); c = (int8_t *) sc_array_push_count (selfprof, count); for (zy = first; zy < last; zy++) { layer = p2est_quadrant_array_index (layers, zy); *(c++) = layer->level; } if (ptype == P6EST_PROFILE_UNION) { p6est_profile_balance_self (selfprof, work); if (btype == P8EST_CONNECT_FACE) { p6est_profile_balance_face (selfprof, faceprof, work, diff); } else { p6est_profile_balance_full (selfprof, faceprof, work, diff); } if (btype == P8EST_CONNECT_EDGE) { p6est_profile_balance_face (selfprof, cornerprof, work, diff); } else if (btype == P8EST_CONNECT_FULL) { p6est_profile_balance_full (selfprof, cornerprof, work, diff); } } for (j = 0; j < Nrp; j++) { for (i = 0; i < Nrp; i++, enidx++) { nidx = en[enidx]; if (ptype == P6EST_PROFILE_UNION) { thisprof = NULL; if (!(i % degree) && !(j % degree)) { if (hbtype == P4EST_CONNECT_FACE) { /* skip corners if we don't need to balance them */ P4EST_ASSERT (!lr[nidx][0]); P4EST_ASSERT (!lr[nidx][1]); continue; } else { thisprof = cornerprof; } } else if ((i % degree) && (j % degree)) { thisprof = selfprof; } else { thisprof = faceprof; } count = thisprof->elem_count; profile->enode_counts[enidx] = count; if (!lr[nidx][1]) { /* if this node has not yet been initialized, initialize it */ lr[nidx][0] = lc->elem_count; lr[nidx][1] = count; c = (int8_t *) sc_array_push_count (lc, count); memcpy (c, thisprof->array, count * sizeof (int8_t)); } else { /* if this node has been initialized, combine the two profiles, * taking the finer layers from each */ sc_array_init_view (&oldprof, lc, lr[nidx][0], lr[nidx][1]); p6est_profile_union (thisprof, &oldprof, work); if (work->elem_count > oldprof.elem_count) { lr[nidx][0] = lc->elem_count; lr[nidx][1] = work->elem_count; c = (int8_t *) sc_array_push_count (lc, work->elem_count); memcpy (c, work->array, work->elem_count * work->elem_size); } } } else { count = selfprof->elem_count; if (!lr[nidx][1]) { /* if this node has not yet been initialized, initialize it */ lr[nidx][0] = lc->elem_count; lr[nidx][1] = count; c = (int8_t *) sc_array_push_count (lc, count); memcpy (c, selfprof->array, count * sizeof (int8_t)); } else { /* if this node has been initialized, combine the two profiles, * taking the coarser layers from each */ sc_array_init_view (&oldprof, lc, lr[nidx][0], lr[nidx][1]); p6est_profile_intersection (selfprof, &oldprof, work); P4EST_ASSERT (work->elem_count <= oldprof.elem_count); if (work->elem_count < oldprof.elem_count) { lr[nidx][1] = work->elem_count; memcpy (oldprof.array, work->array, work->elem_count * work->elem_size); } } } } } } } p6est_profile_compress (profile); sc_array_destroy (selfprof); sc_array_destroy (faceprof); sc_array_destroy (cornerprof); sc_array_destroy (work); return profile; }
void p6est_profile_balance_local (p6est_profile_t * profile) { p4est_lnodes_t *lnodes = profile->lnodes; p4est_locidx_t nln, nle; p4est_locidx_t *en, (*lr)[2]; sc_array_t *lc; int i, j; p4est_locidx_t nidx, enidx, eidx; p8est_connect_type_t btype = profile->btype; p4est_connect_type_t hbtype; int8_t *c; sc_array_t *thisprof; sc_array_t *selfprof; sc_array_t *faceprof; sc_array_t *cornerprof; sc_array_t *work; sc_array_t oldprof; sc_array_t testprof; int any_prof_change; int any_local_change; int evenodd = profile->evenodd; p4est_qcoord_t diff = profile->diff; P4EST_ASSERT (profile->lnodes->degree == 2); if (btype == P8EST_CONNECT_FACE) { hbtype = P4EST_CONNECT_FACE; } else { hbtype = P4EST_CONNECT_FULL; } en = lnodes->element_nodes; nln = lnodes->num_local_nodes; nle = lnodes->num_local_elements; lr = (p4est_locidx_t (*)[2]) profile->lnode_ranges; lc = profile->lnode_columns; selfprof = sc_array_new (sizeof (int8_t)); work = sc_array_new (sizeof (int8_t)); faceprof = sc_array_new (sizeof (int8_t)); cornerprof = sc_array_new (sizeof (int8_t)); do { /* We read from evenodd and write to evenodd ^ 1 */ memset (&(profile->lnode_changed[evenodd ^ 1][0]), 0, sizeof (int) * nln); P4EST_GLOBAL_VERBOSE ("p6est_balance local loop\n"); any_local_change = 0; for (eidx = 0, enidx = 0; eidx < nle; eidx++) { p4est_locidx_t start_enidx = enidx; nidx = en[start_enidx + P4EST_INSUL / 2]; P4EST_ASSERT (lr[nidx][1]); sc_array_init_view (&oldprof, lc, lr[nidx][0], lr[nidx][1]); thisprof = &oldprof; any_prof_change = 0; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++, enidx++) { nidx = en[enidx]; if (!profile->lnode_changed[evenodd][nidx]) { /* if the profile hasn't changed since I wrote to it, there's no * need to balance against it */ continue; } if (i != 1 && j != 1) { if (hbtype == P4EST_CONNECT_FACE) { /* skip corners if we don't need to balance them */ P4EST_ASSERT (!lr[nidx][0]); P4EST_ASSERT (!lr[nidx][1]); continue; } } if (i == 1 && j == 1) { /* no need to further balance against oneself */ continue; } P4EST_ASSERT (lr[nidx][1]); P4EST_ASSERT (profile->enode_counts[enidx] <= lr[nidx][1]); if (profile->enode_counts[enidx] == lr[nidx][1]) { /* if the profile hasn't changed since I wrote to it, there's no * need to balance against it */ continue; } sc_array_init_view (&testprof, lc, lr[nidx][0], lr[nidx][1]); p6est_profile_union (thisprof, &testprof, work); if (work->elem_count > thisprof->elem_count) { P4EST_ASSERT (profile->lnode_changed[evenodd][nidx]); any_prof_change = 1; sc_array_copy (selfprof, work); thisprof = selfprof; } } } if (any_prof_change) { P4EST_ASSERT (thisprof == selfprof); P4EST_ASSERT (selfprof->elem_count > oldprof.elem_count); /* update */ if (btype == P8EST_CONNECT_FACE) { p6est_profile_balance_face (selfprof, faceprof, work, diff); } else { p6est_profile_balance_full (selfprof, faceprof, work, diff); } if (btype == P8EST_CONNECT_EDGE) { p6est_profile_balance_face (selfprof, cornerprof, work, diff); } else if (btype == P8EST_CONNECT_FULL) { p6est_profile_balance_full (selfprof, cornerprof, work, diff); } enidx = start_enidx; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++, enidx++) { thisprof = NULL; nidx = en[enidx]; if (i != 1 && j != 1) { if (hbtype == P4EST_CONNECT_FACE) { /* skip corners if we don't need to balance them */ P4EST_ASSERT (!lr[nidx][0]); P4EST_ASSERT (!lr[nidx][1]); continue; } else { thisprof = cornerprof; } } else if (i == 1 && j == 1) { thisprof = selfprof; } else { thisprof = faceprof; } P4EST_ASSERT (lr[nidx][1]); /* if this node has been initialized, combine the two profiles, * taking the finer layers from each */ sc_array_init_view (&oldprof, lc, lr[nidx][0], lr[nidx][1]); if (i == 1 && j == 1) { sc_array_copy (work, thisprof); } else { p6est_profile_union (thisprof, &oldprof, work); } if (work->elem_count > oldprof.elem_count) { if (!(i == 1 && j == 1)) { /* we don't count changing self */ profile->lnode_changed[evenodd ^ 1][nidx] = 1; any_local_change = 1; } lr[nidx][0] = lc->elem_count; lr[nidx][1] = work->elem_count; c = (int8_t *) sc_array_push_count (lc, work->elem_count); memcpy (c, work->array, work->elem_count * work->elem_size); } profile->enode_counts[enidx] = lr[nidx][1]; } } } } p6est_profile_compress (profile); evenodd ^= 1; } while (any_local_change); profile->evenodd = evenodd; sc_array_destroy (selfprof); sc_array_destroy (faceprof); sc_array_destroy (cornerprof); sc_array_destroy (work); }
int main (int argc, char **argv) { sc_MPI_Comm mpicomm; int mpiret; int mpisize, mpirank; p4est_t *p4est; p4est_connectivity_t *conn; sc_array_t *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes; p4est_locidx_t first_local_quad = -1; /* initialize MPI */ mpiret = sc_MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); mpicomm = sc_MPI_COMM_WORLD; mpiret = sc_MPI_Comm_size (mpicomm, &mpisize); SC_CHECK_MPI (mpiret); mpiret = sc_MPI_Comm_rank (mpicomm, &mpirank); SC_CHECK_MPI (mpiret); sc_init (mpicomm, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); #ifndef P4_TO_P8 conn = p4est_connectivity_new_moebius (); #else conn = p8est_connectivity_new_rotcubes (); #endif p4est = p4est_new_ext (mpicomm, conn, 0, 1, 1, 0, NULL, NULL); p4est_refine (p4est, 1, refine_fn, NULL); p4est_balance (p4est, P4EST_CONNECT_FULL, NULL); p4est_partition (p4est, 0, NULL); points_per_dim = sc_array_new (sizeof (p4est_locidx_t)); cone_sizes = sc_array_new (sizeof (p4est_locidx_t)); cones = sc_array_new (sizeof (p4est_locidx_t)); cone_orientations = sc_array_new (sizeof (p4est_locidx_t)); coords = sc_array_new (3 * sizeof (double)); children = sc_array_new (sizeof (p4est_locidx_t)); parents = sc_array_new (sizeof (p4est_locidx_t)); childids = sc_array_new (sizeof (p4est_locidx_t)); leaves = sc_array_new (sizeof (p4est_locidx_t)); remotes = sc_array_new (2 * sizeof (p4est_locidx_t)); p4est_get_plex_data (p4est, P4EST_CONNECT_FULL, (mpisize > 1) ? 2 : 0, &first_local_quad, points_per_dim, cone_sizes, cones, cone_orientations, coords, children, parents, childids, leaves, remotes); #ifdef P4EST_WITH_PETSC { PetscErrorCode ierr; DM plex, refTree; PetscInt pStart, pEnd; PetscSection parentSection; PetscSF pointSF; size_t zz, count; locidx_to_PetscInt (points_per_dim); locidx_to_PetscInt (cone_sizes); locidx_to_PetscInt (cones); locidx_to_PetscInt (cone_orientations); coords_double_to_PetscScalar (coords); locidx_to_PetscInt (children); locidx_to_PetscInt (parents); locidx_to_PetscInt (childids); locidx_to_PetscInt (leaves); locidx_pair_to_PetscSFNode (remotes); P4EST_GLOBAL_PRODUCTION ("Begin PETSc routines\n"); ierr = PetscInitialize (&argc, &argv, 0, help); CHKERRQ (ierr); ierr = DMPlexCreate (mpicomm, &plex); CHKERRQ (ierr); ierr = DMSetDimension (plex, P4EST_DIM); CHKERRQ (ierr); ierr = DMSetCoordinateDim (plex, 3); CHKERRQ (ierr); ierr = DMPlexCreateFromDAG (plex, P4EST_DIM, (PetscInt *) points_per_dim->array, (PetscInt *) cone_sizes->array, (PetscInt *) cones->array, (PetscInt *) cone_orientations->array, (PetscScalar *) coords->array); CHKERRQ (ierr); ierr = PetscSFCreate (mpicomm, &pointSF); CHKERRQ (ierr); ierr = DMPlexCreateDefaultReferenceTree (mpicomm, P4EST_DIM, PETSC_FALSE, &refTree); CHKERRQ (ierr); ierr = DMPlexSetReferenceTree (plex, refTree); CHKERRQ (ierr); ierr = DMDestroy (&refTree); CHKERRQ (ierr); ierr = PetscSectionCreate (mpicomm, &parentSection); CHKERRQ (ierr); ierr = DMPlexGetChart (plex, &pStart, &pEnd); CHKERRQ (ierr); ierr = PetscSectionSetChart (parentSection, pStart, pEnd); CHKERRQ (ierr); count = children->elem_count; for (zz = 0; zz < count; zz++) { PetscInt child = *((PetscInt *) sc_array_index (children, zz)); ierr = PetscSectionSetDof (parentSection, child, 1); CHKERRQ (ierr); } ierr = PetscSectionSetUp (parentSection); CHKERRQ (ierr); ierr = DMPlexSetTree (plex, parentSection, (PetscInt *) parents->array, (PetscInt *) childids->array); CHKERRQ (ierr); ierr = PetscSectionDestroy (&parentSection); CHKERRQ (ierr); ierr = PetscSFSetGraph (pointSF, pEnd - pStart, (PetscInt) leaves->elem_count, (PetscInt *) leaves->array, PETSC_COPY_VALUES, (PetscSFNode *) remotes->array, PETSC_COPY_VALUES); CHKERRQ (ierr); ierr = DMViewFromOptions (plex, NULL, "-dm_view"); CHKERRQ (ierr); /* TODO: test with rigid body modes as in plex ex3 */ ierr = DMDestroy (&plex); CHKERRQ (ierr); ierr = PetscFinalize (); P4EST_GLOBAL_PRODUCTION ("End PETSc routines\n"); } #endif sc_array_destroy (points_per_dim); sc_array_destroy (cone_sizes); sc_array_destroy (cones); sc_array_destroy (cone_orientations); sc_array_destroy (coords); sc_array_destroy (children); sc_array_destroy (parents); sc_array_destroy (childids); sc_array_destroy (leaves); sc_array_destroy (remotes); p4est_destroy (p4est); p4est_connectivity_destroy (conn); sc_finalize (); mpiret = sc_MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
void p6est_refine_to_profile (p6est_t * p6est, p6est_profile_t * profile, p6est_init_t init_fn, p6est_replace_t replace_fn) { size_t zz, zy, first, last; p4est_topidx_t jt; p4est_quadrant_t *col; p4est_tree_t *tree; sc_array_t *tquadrants; p4est_locidx_t eidx; p4est_locidx_t *en = profile->lnodes->element_nodes; p4est_locidx_t (*lr)[2]; p4est_locidx_t nidx, pidx, pfirst, plast; sc_array_t *layers = p6est->layers; sc_array_t *lc = profile->lnode_columns; sc_array_t *work; P4EST_ASSERT (profile->lnodes->degree == 2); lr = (p4est_locidx_t (*)[2]) profile->lnode_ranges; work = sc_array_new (sizeof (p2est_quadrant_t)); for (eidx = 0, jt = p6est->columns->first_local_tree; jt <= p6est->columns->last_local_tree; ++jt) { tree = p4est_tree_array_index (p6est->columns->trees, jt); tquadrants = &tree->quadrants; for (zz = 0; zz < tquadrants->elem_count; ++zz, eidx++) { col = p4est_quadrant_array_index (tquadrants, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); nidx = en[P4EST_INSUL * eidx + P4EST_INSUL / 2]; P4EST_ASSERT ((size_t) lr[nidx][1] >= last - first); pfirst = lr[nidx][0]; plast = pfirst + lr[nidx][1]; if ((size_t) lr[nidx][1] > last - first) { p2est_quadrant_t stack[P4EST_QMAXLEVEL]; p2est_quadrant_t *q, *r, s, t; int stackcount; sc_array_truncate (work); stackcount = 0; zy = first; for (pidx = pfirst; pidx < plast; pidx++) { int8_t p; P4EST_ASSERT (stackcount || zy < last); p = *((int8_t *) sc_array_index (lc, pidx)); if (stackcount) { q = &(stack[--stackcount]); } else { q = p2est_quadrant_array_index (layers, zy++); } P4EST_ASSERT (q->level <= p); while (q->level < p) { p2est_quadrant_t *child[2]; t = *q; s = *q; s.level++; stack[stackcount] = s; stack[stackcount].z += P4EST_QUADRANT_LEN (s.level); child[0] = &s; child[1] = &stack[stackcount++]; p6est_layer_init_data (p6est, jt, col, child[0], init_fn); p6est_layer_init_data (p6est, jt, col, child[1], init_fn); q = &t; if (replace_fn) { replace_fn (p6est, jt, 1, 1, &col, &q, 1, 2, &col, child); } p6est_layer_free_data (p6est, &t); q = &s; } r = p2est_quadrant_array_push (work); *r = *q; } P4EST_ASSERT (work->elem_count == (size_t) lr[nidx][1]); first = layers->elem_count; last = first + work->elem_count; P6EST_COLUMN_SET_RANGE (col, first, last); q = (p2est_quadrant_t *) sc_array_push_count (layers, work->elem_count); memcpy (q, work->array, work->elem_count * work->elem_size); } } } sc_array_destroy (work); p6est_compress_columns (p6est); p6est_update_offsets (p6est); }
int check_balance_seeds (p4est_quadrant_t * q, p4est_quadrant_t * p, p4est_connect_type_t b, sc_array_t * seeds) { int ib; int level = q->level; p4est_quadrant_t *s, *t; sc_array_t *thislevel = sc_array_new (sizeof (p4est_quadrant_t)); sc_array_t *nextlevel = sc_array_new (sizeof (p4est_quadrant_t)); sc_array_t *temparray; p4est_quadrant_t temp1, temp2; int f, c; #ifdef P4_TO_P8 int e; #endif int stop = 0; sc_array_resize (seeds, 0); s = (p4est_quadrant_t *) sc_array_push (thislevel); p4est_quadrant_sibling (q, s, 0); #ifndef P4_TO_P8 if (b == P4EST_CONNECT_FACE) { ib = 0; } else { ib = 1; } #else if (b == P8EST_CONNECT_FACE) { ib = 0; } else if (b == P8EST_CONNECT_EDGE) { ib = 1; } else { ib = 2; } #endif while (level > p->level + 1) { size_t nlast = thislevel->elem_count; size_t zz; stop = 0; for (zz = 0; zz < nlast; zz++) { s = p4est_quadrant_array_index (thislevel, zz); P4EST_ASSERT (p4est_quadrant_child_id (s) == 0); p4est_quadrant_parent (s, &temp1); for (f = 0; f < P4EST_FACES; f++) { p4est_quadrant_face_neighbor (&temp1, f, &temp2); if (is_farther (&temp1, p, &temp2)) { continue; } if (p4est_quadrant_is_ancestor (p, &temp2)) { stop = 1; sc_array_resize (seeds, seeds->elem_count + 1); t = p4est_quadrant_array_index (seeds, seeds->elem_count - 1); p4est_quadrant_sibling (&temp2, t, 0); } else if (p4est_quadrant_is_inside_root (&temp2)) { t = (p4est_quadrant_t *) sc_array_push (nextlevel); p4est_quadrant_sibling (&temp2, t, 0); } } if (ib == 0) { continue; } #ifdef P4_TO_P8 for (e = 0; e < P8EST_EDGES; e++) { p8est_quadrant_edge_neighbor (&temp1, e, &temp2); if (is_farther (&temp1, p, &temp2)) { continue; } if (p4est_quadrant_is_ancestor (p, &temp2)) { stop = 1; sc_array_resize (seeds, seeds->elem_count + 1); t = p4est_quadrant_array_index (seeds, seeds->elem_count - 1); p4est_quadrant_sibling (&temp2, t, 0); } else if (p4est_quadrant_is_inside_root (&temp2)) { t = (p4est_quadrant_t *) sc_array_push (nextlevel); p4est_quadrant_sibling (&temp2, t, 0); } } if (ib == 1) { continue; } #endif for (c = 0; c < P4EST_CHILDREN; c++) { p4est_quadrant_corner_neighbor (&temp1, c, &temp2); if (is_farther (&temp1, p, &temp2)) { continue; } if (p4est_quadrant_is_ancestor (p, &temp2)) { stop = 1; sc_array_resize (seeds, seeds->elem_count + 1); t = p4est_quadrant_array_index (seeds, seeds->elem_count - 1); p4est_quadrant_sibling (&temp2, t, 0); } else if (p4est_quadrant_is_inside_root (&temp2)) { t = (p4est_quadrant_t *) sc_array_push (nextlevel); p4est_quadrant_sibling (&temp2, t, 0); } } } if (stop) { sc_array_sort (seeds, p4est_quadrant_compare); sc_array_uniq (seeds, p4est_quadrant_compare); #ifdef P4_TO_P8 if (!ib && seeds->elem_count == 1) { sc_array_sort (nextlevel, p4est_quadrant_compare); sc_array_uniq (nextlevel, p4est_quadrant_compare); temparray = thislevel; thislevel = nextlevel; nextlevel = temparray; sc_array_reset (nextlevel); level--; nlast = thislevel->elem_count; for (zz = 0; zz < nlast; zz++) { s = p4est_quadrant_array_index (thislevel, zz); P4EST_ASSERT (p4est_quadrant_child_id (s) == 0); p4est_quadrant_parent (s, &temp1); for (f = 0; f < P4EST_FACES; f++) { p4est_quadrant_face_neighbor (&temp1, f, &temp2); if (p4est_quadrant_is_ancestor (p, &temp2)) { int f2; p4est_quadrant_t a; p4est_quadrant_t u; t = p4est_quadrant_array_index (seeds, 0); p8est_quadrant_parent (t, &a); for (f2 = 0; f2 < P8EST_FACES; f2++) { if (f2 / 2 == f / 2) { continue; } p8est_quadrant_face_neighbor (&a, f2, &u); if (p8est_quadrant_is_equal (&temp2, &u) || p8est_quadrant_is_sibling (&temp2, &u)) { break; } } if (f2 == P8EST_FACES) { sc_array_resize (seeds, seeds->elem_count + 1); t = p4est_quadrant_array_index (seeds, seeds->elem_count - 1); p4est_quadrant_sibling (&temp2, t, 0); } } } } } #endif sc_array_sort (seeds, p4est_quadrant_compare); sc_array_uniq (seeds, p4est_quadrant_compare); break; } sc_array_sort (nextlevel, p4est_quadrant_compare); sc_array_uniq (nextlevel, p4est_quadrant_compare); temparray = thislevel; thislevel = nextlevel; nextlevel = temparray; sc_array_reset (nextlevel); level--; } sc_array_destroy (thislevel); sc_array_destroy (nextlevel); return stop; }
int main (int argc, char **argv) { p4est_quadrant_t root; p4est_quadrant_t p; p4est_quadrant_t q; p4est_quadrant_t desc; int face, corner; #ifndef P4_TO_P8 int maxlevel = 9; #else int edge; int maxlevel = 6; #endif int mpiret, mpisize, mpirank; sc_MPI_Comm mpicomm; uint64_t i, ifirst, ilast; int level; sc_array_t *seeds, *seeds_check; int testval; int checkval; int j, nrand = 1000; /* initialize MPI */ mpiret = sc_MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); mpicomm = sc_MPI_COMM_WORLD; mpiret = sc_MPI_Comm_size (mpicomm, &mpisize); SC_CHECK_MPI (mpiret); mpiret = sc_MPI_Comm_rank (mpicomm, &mpirank); SC_CHECK_MPI (mpiret); srandom (9212007); sc_init (mpicomm, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); seeds = sc_array_new (sizeof (p4est_quadrant_t)); seeds_check = sc_array_new (sizeof (p4est_quadrant_t)); memset (&root, 0, sizeof (p4est_quadrant_t)); root.level = 2; root.x = P4EST_QUADRANT_LEN (2); root.y = P4EST_QUADRANT_LEN (2); #ifdef P4_TO_P8 root.z = P4EST_QUADRANT_LEN (2); #endif P4EST_QUADRANT_INIT (&p); P4EST_QUADRANT_INIT (&q); #if 1 for (face = 0; face < P4EST_FACES; face++) { p4est_quadrant_face_neighbor (&root, face ^ 1, &p); P4EST_GLOBAL_VERBOSEF ("Testing face %d\n", face); for (level = 4; level <= maxlevel; level++) { P4EST_GLOBAL_VERBOSEF (" level %d\n", level); p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); for (i = ifirst; i <= ilast; i += P4EST_CHILDREN) { p4est_quadrant_set_morton (&q, level, i); #ifndef P4_TO_P8 testval = p4est_balance_seeds_face (&q, &p, face, P4EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); #else testval = p4est_balance_seeds_face (&q, &p, face, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); testval = p4est_balance_seeds_face (&q, &p, face, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); #endif testval = p4est_balance_seeds_face (&q, &p, face, P4EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); } } if (!face) { P4EST_GLOBAL_VERBOSE (" random levels\n"); for (j = 0; j < (int) nrand; j++) { level = ((random ()) % (P4EST_QMAXLEVEL - maxlevel)) + maxlevel + 1; p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); i = ((random ()) % (ilast + 1 - ifirst)) + ifirst; p4est_quadrant_set_morton (&q, level, i); #ifndef P4_TO_P8 testval = p4est_balance_seeds_face (&q, &p, face, P4EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); #else testval = p4est_balance_seeds_face (&q, &p, face, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); testval = p4est_balance_seeds_face (&q, &p, face, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); #endif testval = p4est_balance_seeds_face (&q, &p, face, P4EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_face error"); compare_seeds (seeds, seeds_check); } } } #ifdef P4_TO_P8 for (edge = 0; edge < P8EST_EDGES; edge++) { p8est_quadrant_edge_neighbor (&root, edge ^ 3, &p); P4EST_GLOBAL_VERBOSEF ("Testing edge %d\n", edge); for (level = 4; level <= maxlevel; level++) { P4EST_GLOBAL_VERBOSEF (" level %d\n", level); p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); for (i = ifirst; i <= ilast; i += P4EST_CHILDREN) { p4est_quadrant_set_morton (&q, level, i); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); } } if (!edge) { P4EST_GLOBAL_VERBOSE (" random levels\n"); for (j = 0; j < (int) nrand; j++) { level = ((random ()) % (P4EST_QMAXLEVEL - maxlevel)) + maxlevel + 1; p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); i = ((random ()) % (ilast + 1 - ifirst)) + ifirst; p4est_quadrant_set_morton (&q, level, i); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); testval = p8est_balance_seeds_edge (&q, &p, edge, P8EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_edge error"); compare_seeds (seeds, seeds_check); } } } #endif #endif for (corner = 0; corner < P4EST_FACES; corner++) { p4est_quadrant_corner_neighbor (&root, corner ^ (P4EST_CHILDREN - 1), &p); P4EST_GLOBAL_VERBOSEF ("Testing corner %d\n", corner); for (level = 4; level <= maxlevel; level++) { P4EST_GLOBAL_VERBOSEF (" level %d\n", level); p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); for (i = ifirst; i <= ilast; i += P4EST_CHILDREN) { p4est_quadrant_set_morton (&q, level, i); #ifndef P4_TO_P8 testval = p4est_balance_seeds_corner (&q, &p, corner, P4EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); #else testval = p4est_balance_seeds_corner (&q, &p, corner, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); testval = p4est_balance_seeds_corner (&q, &p, corner, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); #endif testval = p4est_balance_seeds_corner (&q, &p, corner, P4EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); } } if (!corner) { P4EST_GLOBAL_VERBOSE (" random levels\n"); for (j = 0; j < (int) nrand; j++) { level = ((random ()) % (P4EST_QMAXLEVEL - maxlevel)) + maxlevel + 1; p4est_quadrant_first_descendant (&root, &desc, level); ifirst = p4est_quadrant_linear_id (&desc, level); p4est_quadrant_last_descendant (&root, &desc, level); ilast = p4est_quadrant_linear_id (&desc, level); i = ((random ()) % (ilast + 1 - ifirst)) + ifirst; p4est_quadrant_set_morton (&q, level, i); #ifndef P4_TO_P8 testval = p4est_balance_seeds_corner (&q, &p, corner, P4EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); #else testval = p4est_balance_seeds_corner (&q, &p, corner, P8EST_CONNECT_FACE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_FACE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); testval = p4est_balance_seeds_corner (&q, &p, corner, P8EST_CONNECT_EDGE, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P8EST_CONNECT_EDGE, seeds_check); SC_CHECK_ABORT (testval == checkval, "p8est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); #endif testval = p4est_balance_seeds_corner (&q, &p, corner, P4EST_CONNECT_FULL, seeds); standard_seeds (seeds); checkval = check_balance_seeds (&q, &p, P4EST_CONNECT_FULL, seeds_check); SC_CHECK_ABORT (testval == checkval, "p4est_balance_seeds_corner error"); compare_seeds (seeds, seeds_check); } } } sc_array_destroy (seeds); sc_array_destroy (seeds_check); sc_finalize (); mpiret = sc_MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
int main (int argc, char **argv) { int i, i1, i2, i3, i3last, i4, i4last, temp, count; size_t s, swaps1, swaps2, swaps3, total1, total2, total3; ssize_t searched; int *pi; sc_array_t *a1, *a2, *a3, *a4; int mpiret; double start, elapsed_pqueue, elapsed_qsort; mpiret = sc_MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); sc_init (sc_MPI_COMM_WORLD, 1, 1, NULL, SC_LP_DEFAULT); a1 = sc_array_new (sizeof (int)); a2 = sc_array_new (sizeof (int)); a3 = sc_array_new (sizeof (int)); a4 = sc_array_new (sizeof (int)); #ifdef THEBIGTEST count = 325323; #else count = 3251; #endif SC_INFOF ("Test pqueue with count %d\n", count); start = -sc_MPI_Wtime (); swaps1 = swaps2 = swaps3 = 0; total1 = total2 = total3 = 0; for (i = 0; i < count; ++i) { *(int *) sc_array_push (a1) = i; s = sc_array_pqueue_add (a1, &temp, compar); swaps1 += ((s > 0) ? 1 : 0); total1 += s; *(int *) sc_array_push (a2) = count - i - 1; s = sc_array_pqueue_add (a2, &temp, compar); swaps2 += ((s > 0) ? 1 : 0); total2 += s; *(int *) sc_array_push (a3) = (15 * i) % 172; s = sc_array_pqueue_add (a3, &temp, compar); swaps3 += ((s > 0) ? 1 : 0); total3 += s; } SC_CHECK_ABORT (swaps1 == 0 && total1 == 0, "pqueue_add"); SC_VERBOSEF (" Swaps %lld %lld %lld Total %lld %lld %lld\n", (long long) swaps1, (long long) swaps2, (long long) swaps3, (long long) total1, (long long) total2, (long long) total3); temp = 52; searched = sc_array_bsearch (a1, &temp, compar); SC_CHECK_ABORT (searched != -1, "array_bsearch_index"); pi = (int *) sc_array_index_ssize_t (a1, searched); SC_CHECK_ABORT (*pi == temp, "array_bsearch"); i3last = -1; swaps1 = swaps2 = swaps3 = 0; total1 = total2 = total3 = 0; for (i = 0; i < count; ++i) { s = sc_array_pqueue_pop (a1, &i1, compar); swaps1 += ((s > 0) ? 1 : 0); total1 += s; s = sc_array_pqueue_pop (a2, &i2, compar); swaps2 += ((s > 0) ? 1 : 0); total2 += s; s = sc_array_pqueue_pop (a3, &i3, compar); swaps3 += ((s > 0) ? 1 : 0); total3 += s; SC_CHECK_ABORT (i == i1 && i == i2, "pqueue_pop"); SC_CHECK_ABORT (i3 >= i3last, "pqueue_pop"); i3last = i3; } SC_VERBOSEF (" Swaps %lld %lld %lld Total %lld %lld %lld\n", (long long) swaps1, (long long) swaps2, (long long) swaps3, (long long) total1, (long long) total2, (long long) total3); elapsed_pqueue = start + sc_MPI_Wtime (); sc_array_destroy (a1); sc_array_destroy (a2); sc_array_destroy (a3); SC_INFOF ("Test array sort with count %d\n", count); start = -sc_MPI_Wtime (); /* the resize is done to be comparable with the above procedure */ for (i = 0; i < count; ++i) { *(int *) sc_array_push (a4) = (15 * i) % 172; } sc_array_sort (a4, compar); i4last = -1; for (i = 0; i < count; ++i) { i4 = *(int *) sc_array_index_int (a4, i); SC_CHECK_ABORT (i4 >= i4last, "array_sort"); i4last = i4; } sc_array_resize (a4, 0); elapsed_qsort = start + sc_MPI_Wtime (); SC_STATISTICSF ("Test timings pqueue %g qsort %g\n", elapsed_pqueue, 3. * elapsed_qsort); sc_array_destroy (a4); sc_finalize (); mpiret = sc_MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
p4est_mesh_t * p4est_mesh_new_ext (p4est_t * p4est, p4est_ghost_t * ghost, int compute_tree_index, int compute_level_lists, p4est_connect_type_t btype) { int do_corner = 0; int do_volume = 0; int rank; p4est_locidx_t lq, ng; p4est_locidx_t jl; p4est_mesh_t *mesh; P4EST_ASSERT (p4est_is_balanced (p4est, btype)); mesh = P4EST_ALLOC_ZERO (p4est_mesh_t, 1); lq = mesh->local_num_quadrants = p4est->local_num_quadrants; ng = mesh->ghost_num_quadrants = (p4est_locidx_t) ghost->ghosts.elem_count; if (btype == P4EST_CONNECT_FULL) { do_corner = 1; } do_volume = (compute_tree_index || compute_level_lists ? 1 : 0); /* Optional map of tree index for each quadrant */ if (compute_tree_index) { mesh->quad_to_tree = P4EST_ALLOC (p4est_topidx_t, lq); } mesh->ghost_to_proc = P4EST_ALLOC (int, ng); mesh->quad_to_quad = P4EST_ALLOC (p4est_locidx_t, P4EST_FACES * lq); mesh->quad_to_face = P4EST_ALLOC (int8_t, P4EST_FACES * lq); mesh->quad_to_half = sc_array_new (P4EST_HALF * sizeof (p4est_locidx_t)); /* Optional per-level lists of quadrants */ if (compute_level_lists) { mesh->quad_level = P4EST_ALLOC (sc_array_t, P4EST_QMAXLEVEL + 1); for (jl = 0; jl <= P4EST_QMAXLEVEL; ++jl) { sc_array_init (mesh->quad_level + jl, sizeof (p4est_locidx_t)); } } /* Populate ghost information */ rank = 0; for (jl = 0; jl < ng; ++jl) { while (ghost->proc_offsets[rank + 1] <= jl) { ++rank; P4EST_ASSERT (rank < p4est->mpisize); } mesh->ghost_to_proc[jl] = rank; } /* Fill face arrays with default values */ memset (mesh->quad_to_quad, -1, P4EST_FACES * lq * sizeof (p4est_locidx_t)); memset (mesh->quad_to_face, -25, P4EST_FACES * lq * sizeof (int8_t)); if (do_corner) { /* Initialize corner information to a consistent state */ mesh->quad_to_corner = P4EST_ALLOC (p4est_locidx_t, P4EST_CHILDREN * lq); memset (mesh->quad_to_corner, -1, P4EST_CHILDREN * lq * sizeof (p4est_locidx_t)); mesh->corner_offset = sc_array_new (sizeof (p4est_locidx_t)); *(p4est_locidx_t *) sc_array_push (mesh->corner_offset) = 0; mesh->corner_quad = sc_array_new (sizeof (p4est_locidx_t)); mesh->corner_corner = sc_array_new (sizeof (int8_t)); } /* Call the forest iterator to collect face connectivity */ p4est_iterate (p4est, ghost, mesh, (do_volume ? mesh_iter_volume : NULL), mesh_iter_face, #ifdef P4_TO_P8 NULL, #endif do_corner ? mesh_iter_corner : NULL); return mesh; }
int main (int argc, char *argv[]) { MPI_Comm comm = MPI_COMM_WORLD; p4est_t *p4est; p4est_connectivity_t *conn; p4est_ghost_t *ghost_layer; p4est_lnodes_t *lnodes; int rank; const int degree = 1; BFAM_MPI_CHECK(MPI_Init(&argc,&argv)); BFAM_MPI_CHECK(MPI_Comm_rank(comm, &rank)); bfam_log_init(rank, stdout, BFAM_LL_DEFAULT); bfam_signal_handler_set(); sc_init(comm, 0, 0, NULL, SC_LP_DEFAULT); p4est_init(NULL, SC_LP_DEFAULT); conn = p4est_connectivity_new_corner(); p4est = p4est_new_ext(comm, conn, 0, 0, 0, 0, NULL, NULL); refine_level = 1; p4est_refine(p4est, 1, refine_fn, NULL); p4est_balance(p4est, P4EST_CONNECT_FACE, NULL); p4est_partition(p4est, 1, NULL); p4est_vtk_write_file(p4est, NULL, "mesh"); ghost_layer = p4est_ghost_new(p4est, P4EST_CONNECT_FULL); lnodes = p4est_lnodes_new(p4est, ghost_layer, degree); /* * Output the mesh. It can be read using something like following command: * * mpirun -np 3 ./bfam_exam_p4est | grep MESH | sort -n -k 2 | sort -n -k 5 | gvim - */ fflush(stdout); BFAM_MPI_CHECK(MPI_Barrier(comm)); BFAM_ROOT_INFO("MESH 0 ------------ Mesh Begin ------------"); BFAM_ROOT_INFO("MESH 1 degree = %d", lnodes->degree); BFAM_ROOT_INFO("MESH 2 vnodes = %d", lnodes->vnodes); BFAM_INFO("MESH 3 num_local_elements = %jd", (intmax_t)lnodes->num_local_elements); BFAM_INFO("MESH 4 num_local_nodes = %jd", (intmax_t)lnodes->num_local_nodes); BFAM_INFO("MESH 5 owned_count = %jd", (intmax_t)lnodes->owned_count); BFAM_INFO("MESH 6 global_offset = %jd", (intmax_t)lnodes->global_offset); sc_array_t *global_nodes = sc_array_new(sizeof (p4est_gloidx_t)); sc_array_resize(global_nodes, lnodes->num_local_nodes); for(size_t zz = 0; zz < global_nodes->elem_count; ++zz) { *((p4est_gloidx_t *) sc_array_index(global_nodes, zz)) = p4est_lnodes_global_index(lnodes, zz); } p4est_lnodes_share_owned(global_nodes, lnodes); for(size_t zz = 0; zz < global_nodes->elem_count; ++zz) { const p4est_gloidx_t gn = *((p4est_gloidx_t *)sc_array_index(global_nodes, zz)); SC_CHECK_ABORT (gn == p4est_lnodes_global_index(lnodes, zz), "Lnodes: bad global index across procesors"); BFAM_INFO("MESH 7 global_nodes[%zu] = %jd", zz, (intmax_t)gn); } sc_array_destroy(global_nodes); p4est_topidx_t flt = p4est->first_local_tree; p4est_topidx_t llt = p4est->last_local_tree; p4est_locidx_t elid, elnid; p4est_topidx_t t; const double *v = conn->vertices; const p4est_topidx_t *tree_to_vertex = conn->tree_to_vertex; for(elid = 0, elnid = 0, t = flt; t <= llt; ++t) { p4est_tree_t *tree = p4est_tree_array_index(p4est->trees, t); const size_t count = tree->quadrants.elem_count; p4est_topidx_t vt[P4EST_CHILDREN]; for (int c = 0; c < P4EST_CHILDREN; ++c) { vt[c] = tree_to_vertex[t * P4EST_CHILDREN + c]; } for (size_t zz = 0; zz < count; ++zz, ++elid) { p4est_quadrant_t *q = p4est_quadrant_array_index(&tree->quadrants, zz); for(int jind = 0; jind < degree + 1; ++jind) { for(int iind = 0; iind < degree + 1; ++iind, ++elnid) { double xyz[3]; for (int j = 0; j < 3; ++j) { const p4est_qcoord_t len = P4EST_QUADRANT_LEN(q->level); const double rlen = (double) P4EST_ROOT_LEN; const double deg = (double) degree; const double qlen = ((double) len) / rlen; const double eta_x = ((double) q->x) / rlen + (((double) iind) / deg) * qlen; const double eta_y = ((double) q->y) / rlen + (((double) jind) / deg) * qlen; xyz[j] = ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] + eta_x * v[3 * vt[1] + j]) + eta_y * ((1. - eta_x) * v[3 * vt[2] + j] + eta_x * v[3 * vt[3] + j])); } const p4est_locidx_t nid = lnodes->element_nodes[elnid]; BFAM_INFO( "MESH 8 local_node[%03jd] = %03jd ( %25.16e %25.16e %25.16e )", (intmax_t)elnid, (intmax_t)nid, xyz[0], xyz[1], xyz[2]); } } } } BFAM_ROOT_INFO("MESH 9 ------------ Mesh End ------------"); p4est_lnodes_destroy(lnodes); p4est_ghost_destroy(ghost_layer); p4est_destroy(p4est); p4est_connectivity_destroy(conn); sc_finalize(); BFAM_MPI_CHECK(MPI_Finalize()); return EXIT_SUCCESS; }