static void mesh_iter_face (p4est_iter_face_info_t * info, void *user_data) { int h; int swapsides; p4est_mesh_t *mesh = (p4est_mesh_t *) user_data; p4est_locidx_t jl, jl2, jls[P4EST_HALF]; p4est_locidx_t in_qtoq, halfindex; p4est_locidx_t *halfentries; p4est_tree_t *tree; p4est_iter_face_side_t *side, *side2, *tempside; if (info->sides.elem_count == 1) { /* this face is on an outside boundary of the forest */ P4EST_ASSERT (info->orientation == 0); P4EST_ASSERT (info->tree_boundary); side = (p4est_iter_face_side_t *) sc_array_index (&info->sides, 0); P4EST_ASSERT (0 <= side->treeid && side->treeid < info->p4est->connectivity->num_trees); P4EST_ASSERT (0 <= side->face && side->face < P4EST_FACES); P4EST_ASSERT (!side->is_hanging && !side->is.full.is_ghost); tree = p4est_tree_array_index (info->p4est->trees, side->treeid); jl = side->is.full.quadid + tree->quadrants_offset; P4EST_ASSERT (0 <= jl && jl < mesh->local_num_quadrants); in_qtoq = P4EST_FACES * jl + side->face; mesh->quad_to_quad[in_qtoq] = jl; /* put in myself and my own face */ mesh->quad_to_face[in_qtoq] = side->face; } else { /* this face is between two quadrants */ P4EST_ASSERT (info->orientation == 0 || info->tree_boundary); P4EST_ASSERT (info->sides.elem_count == 2); side = (p4est_iter_face_side_t *) sc_array_index (&info->sides, 0); side2 = (p4est_iter_face_side_t *) sc_array_index (&info->sides, 1); P4EST_ASSERT (info->tree_boundary || side->treeid == side2->treeid); P4EST_ASSERT (!side->is_hanging || !side2->is_hanging); if (!side->is_hanging && !side2->is_hanging) { /* same-size face neighbors */ P4EST_ASSERT (!side->is.full.is_ghost || !side2->is.full.is_ghost); /* determine both quadrant numbers */ if (!side->is.full.is_ghost) { tree = p4est_tree_array_index (info->p4est->trees, side->treeid); jl = side->is.full.quadid + tree->quadrants_offset; P4EST_ASSERT (0 <= jl && jl < mesh->local_num_quadrants); } else { P4EST_ASSERT (side->is.full.quad != NULL); P4EST_ASSERT (side->is.full.quadid >= 0); jl = mesh->local_num_quadrants + side->is.full.quadid; } if (!side2->is.full.is_ghost) { tree = p4est_tree_array_index (info->p4est->trees, side2->treeid); jl2 = side2->is.full.quadid + tree->quadrants_offset; P4EST_ASSERT (0 <= jl2 && jl2 < mesh->local_num_quadrants); } else { P4EST_ASSERT (side2->is.full.quad != NULL); P4EST_ASSERT (side2->is.full.quadid >= 0); jl2 = mesh->local_num_quadrants + side2->is.full.quadid; } /* encode quadrant neighborhood */ if (!side->is.full.is_ghost) { in_qtoq = P4EST_FACES * jl + side->face; P4EST_ASSERT (mesh->quad_to_quad[in_qtoq] == -1); P4EST_ASSERT (mesh->quad_to_face[in_qtoq] == -25); mesh->quad_to_quad[in_qtoq] = jl2; mesh->quad_to_face[in_qtoq] = P4EST_FACES * info->orientation + side2->face; } if (!side2->is.full.is_ghost) { in_qtoq = P4EST_FACES * jl2 + side2->face; P4EST_ASSERT (mesh->quad_to_quad[in_qtoq] == -1); P4EST_ASSERT (mesh->quad_to_face[in_qtoq] == -25); mesh->quad_to_quad[in_qtoq] = jl; mesh->quad_to_face[in_qtoq] = P4EST_FACES * info->orientation + side->face; } } else { /* one of the faces is hanging, rename so it's always side2 */ swapsides = side->is_hanging; if (swapsides) { tempside = side; side = side2; side2 = tempside; } P4EST_ASSERT (!side->is_hanging && side2->is_hanging); /* determine quadrant number for non-hanging large face */ if (!side->is.full.is_ghost) { tree = p4est_tree_array_index (info->p4est->trees, side->treeid); jl = side->is.full.quadid + tree->quadrants_offset; P4EST_ASSERT (0 <= jl && jl < mesh->local_num_quadrants); } else { P4EST_ASSERT (side->is.full.quad != NULL); P4EST_ASSERT (side->is.full.quadid >= 0); jl = mesh->local_num_quadrants + side->is.full.quadid; } /* determine quadrant numbers for all hanging faces */ for (h = 0; h < P4EST_HALF; ++h) { if (!side2->is.hanging.is_ghost[h]) { tree = p4est_tree_array_index (info->p4est->trees, side2->treeid); jls[h] = side2->is.hanging.quadid[h] + tree->quadrants_offset; P4EST_ASSERT (0 <= jls[h] && jls[h] < mesh->local_num_quadrants); } else { P4EST_ASSERT (side2->is.hanging.quad[h] != NULL); P4EST_ASSERT (side2->is.hanging.quadid[h] >= 0); jls[h] = mesh->local_num_quadrants + side2->is.hanging.quadid[h]; } } /* encode quadrant neighborhood */ if (!side->is.full.is_ghost) { in_qtoq = P4EST_FACES * jl + side->face; P4EST_ASSERT (mesh->quad_to_quad[in_qtoq] == -1); P4EST_ASSERT (mesh->quad_to_face[in_qtoq] == -25); halfindex = (p4est_locidx_t) mesh->quad_to_half->elem_count; mesh->quad_to_quad[in_qtoq] = halfindex; mesh->quad_to_face[in_qtoq] = P4EST_FACES * (info->orientation - P4EST_HALF) + side2->face; halfentries = (p4est_locidx_t *) sc_array_push (mesh->quad_to_half); for (h = 0; h < P4EST_HALF; ++h) { halfentries[h] = jls[h]; } } for (h = 0; h < P4EST_HALF; ++h) { if (!side2->is.hanging.is_ghost[h]) { in_qtoq = P4EST_FACES * jls[h] + side2->face; P4EST_ASSERT (mesh->quad_to_quad[in_qtoq] == -1); P4EST_ASSERT (mesh->quad_to_face[in_qtoq] == -25); mesh->quad_to_quad[in_qtoq] = jl; mesh->quad_to_face[in_qtoq] = P4EST_FACES * (info->orientation + (h + 1) * P4EST_HALF) + side->face; } } } } }
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; }