int p8est_connectivity_face_neighbor_edge_orientation (int e, int f, int nf, int o) { int fe, nfe, pref, pset; P4EST_ASSERT (0 <= e && e < P8EST_EDGES); P4EST_ASSERT (0 <= f && f < P4EST_FACES); P4EST_ASSERT (0 <= nf && nf < P4EST_FACES); P4EST_ASSERT (0 <= o && o < P4EST_HALF); fe = p8est_edge_face_edges[e][f]; P4EST_ASSERT (0 <= fe && fe < P4EST_HALF); pref = p8est_face_permutation_refs[f][nf]; pset = p8est_face_edge_permutation_sets[pref][o]; nfe = p8est_face_edge_permutations[pset][fe]; P4EST_ASSERT (0 <= nfe && nfe < P4EST_HALF); return p8est_face_edges[nf][nfe]; }
void p8est_find_edge_transform (p4est_connectivity_t * conn, p4est_topidx_t itree, int iedge, p8est_edge_info_t * ei) { int distinct; p4est_topidx_t edge_trees, aedge, ettae; sc_array_t *ta = &ei->edge_transforms; P4EST_ASSERT (0 <= itree && itree < conn->num_trees); P4EST_ASSERT (0 <= iedge && iedge < P8EST_EDGES); P4EST_ASSERT (ta->elem_size == sizeof (p8est_edge_transform_t)); /* check if this edge exists at all */ ei->iedge = (int8_t) iedge; sc_array_resize (ta, 0); if (conn->num_edges == 0) { return; } aedge = conn->tree_to_edge[P8EST_EDGES * itree + iedge]; if (aedge == -1) { return; } P4EST_ASSERT (0 <= aedge && aedge < conn->num_edges); /* retrieve connectivity information for this edge */ ettae = conn->ett_offset[aedge]; edge_trees = conn->ett_offset[aedge + 1] - ettae; P4EST_ASSERT (0 <= ettae && 1 <= edge_trees); /* loop through all edge neighbors and find edge connections */ distinct = p8est_find_edge_transform_internal (conn, itree, iedge, ei, conn->edge_to_tree + ettae, conn->edge_to_edge + ettae, edge_trees); P4EST_ASSERT (edge_trees == (p4est_topidx_t) ta->elem_count + distinct); }
int main (int argc, char **argv) { int mpiret; int wrongusage; unsigned crc; const char *usage; mpi_context_t mpi_context, *mpi = &mpi_context; p8est_t *p8est; p8est_connectivity_t *connectivity; p8est_geometry_t *geom; p8est_refine_t refine_fn; p8est_coarsen_t coarsen_fn; simple_config_t config; const simple_regression_t *r; /* initialize MPI and p4est internals */ mpiret = MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); mpi->mpicomm = MPI_COMM_WORLD; mpiret = MPI_Comm_size (mpi->mpicomm, &mpi->mpisize); SC_CHECK_MPI (mpiret); mpiret = MPI_Comm_rank (mpi->mpicomm, &mpi->mpirank); SC_CHECK_MPI (mpiret); sc_init (mpi->mpicomm, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); /* process command line arguments */ usage = "Arguments: <configuration> <level>\n" " Configuration can be any of\n" " unit|periodic|rotwrap|twocubes|twowrap|rotcubes|shell|sphere\n" " Level controls the maximum depth of refinement\n"; wrongusage = 0; config = P8EST_CONFIG_NULL; if (!wrongusage && argc != 3) { wrongusage = 1; } if (!wrongusage) { if (!strcmp (argv[1], "unit")) { config = P8EST_CONFIG_UNIT; } else if (!strcmp (argv[1], "periodic")) { config = P8EST_CONFIG_PERIODIC; } else if (!strcmp (argv[1], "rotwrap")) { config = P8EST_CONFIG_ROTWRAP; } else if (!strcmp (argv[1], "twocubes")) { config = P8EST_CONFIG_TWOCUBES; } else if (!strcmp (argv[1], "twowrap")) { config = P8EST_CONFIG_TWOWRAP; } else if (!strcmp (argv[1], "rotcubes")) { config = P8EST_CONFIG_ROTCUBES; } else if (!strcmp (argv[1], "shell")) { config = P8EST_CONFIG_SHELL; } else if (!strcmp (argv[1], "sphere")) { config = P8EST_CONFIG_SPHERE; } else { wrongusage = 1; } } if (wrongusage) { P4EST_GLOBAL_LERROR (usage); sc_abort_collective ("Usage error"); } /* assign variables based on configuration */ refine_level = atoi (argv[2]); refine_fn = refine_normal_fn; coarsen_fn = NULL; /* create connectivity and forest structures */ geom = NULL; if (config == P8EST_CONFIG_PERIODIC) { connectivity = p8est_connectivity_new_periodic (); } else if (config == P8EST_CONFIG_ROTWRAP) { connectivity = p8est_connectivity_new_rotwrap (); } else if (config == P8EST_CONFIG_TWOCUBES) { connectivity = p8est_connectivity_new_twocubes (); refine_fn = refine_sparse_fn; } else if (config == P8EST_CONFIG_TWOWRAP) { connectivity = p8est_connectivity_new_twowrap (); refine_fn = refine_sparse_fn; } else if (config == P8EST_CONFIG_ROTCUBES) { connectivity = p8est_connectivity_new_rotcubes (); } else if (config == P8EST_CONFIG_SHELL) { connectivity = p8est_connectivity_new_shell (); geom = p8est_geometry_new_shell (1., .55); } else if (config == P8EST_CONFIG_SPHERE) { connectivity = p8est_connectivity_new_sphere (); geom = p8est_geometry_new_sphere (1., 0.191728, 0.039856); } else { connectivity = p8est_connectivity_new_unitcube (); } p8est = p8est_new_ext (mpi->mpicomm, connectivity, 1, 0, 0, sizeof (user_data_t), init_fn, NULL); #ifdef VTK_OUTPUT p8est_vtk_write_file (p8est, geom, "simple3_new"); #endif /* refinement and coarsening */ p8est_refine (p8est, 1, refine_fn, init_fn); if (coarsen_fn != NULL) { p8est_coarsen (p8est, 1, coarsen_fn, init_fn); } #ifdef VTK_OUTPUT p8est_vtk_write_file (p8est, geom, "simple3_refined"); #endif /* balance */ p8est_balance (p8est, P8EST_CONNECT_FULL, init_fn); #ifdef VTK_OUTPUT p8est_vtk_write_file (p8est, geom, "simple3_balanced"); #endif crc = p8est_checksum (p8est); /* partition */ p8est_partition (p8est, NULL); #ifdef VTK_OUTPUT p8est_vtk_write_file (p8est, geom, "simple3_partition"); #endif #ifdef P4EST_DEBUG /* rebalance should not change checksum */ p8est_balance (p8est, P8EST_CONNECT_FULL, init_fn); P4EST_ASSERT (p8est_checksum (p8est) == crc); #endif /* print and verify forest checksum */ P4EST_GLOBAL_STATISTICSF ("Tree checksum 0x%08x\n", crc); if (mpi->mpirank == 0) { for (r = regression; r->config != P8EST_CONFIG_NULL; ++r) { if (r->config != config || r->mpisize != mpi->mpisize || r->level != refine_level) continue; SC_CHECK_ABORT (crc == r->checksum, "Checksum mismatch"); P4EST_GLOBAL_INFO ("Checksum regression OK\n"); break; } } /* destroy the p8est and its connectivity structure */ p8est_destroy (p8est); P4EST_FREE (geom); p8est_connectivity_destroy (connectivity); /* clean up and exit */ sc_finalize (); mpiret = MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
static void p4est_coarsen_old (p4est_t * p4est, int coarsen_recursive, p4est_coarsen_t coarsen_fn, p4est_init_t init_fn) { #ifdef P4EST_ENABLE_DEBUG size_t data_pool_size; #endif int i, maxlevel; int couldbegood; size_t zz; size_t incount, removed; size_t cidz, first, last, rest, before; p4est_locidx_t num_quadrants, prev_offset; p4est_topidx_t jt; p4est_tree_t *tree; p4est_quadrant_t *c[P4EST_CHILDREN]; p4est_quadrant_t *cfirst, *clast; sc_array_t *tquadrants; P4EST_GLOBAL_PRODUCTIONF ("Into " P4EST_STRING "_coarsen_old with %lld total quadrants\n", (long long) p4est->global_num_quadrants); p4est_log_indent_push (); P4EST_ASSERT (p4est_is_valid (p4est)); /* loop over all local trees */ prev_offset = 0; for (jt = p4est->first_local_tree; jt <= p4est->last_local_tree; ++jt) { tree = p4est_tree_array_index (p4est->trees, jt); tquadrants = &tree->quadrants; #ifdef P4EST_ENABLE_DEBUG data_pool_size = 0; if (p4est->user_data_pool != NULL) { data_pool_size = p4est->user_data_pool->elem_count; } #endif removed = 0; /* initial log message for this tree */ P4EST_VERBOSEF ("Into coarsen tree %lld with %llu\n", (long long) jt, (unsigned long long) tquadrants->elem_count); /* Initialize array indices. If children are coarsened, the array will have an empty window. first index of the first child to be considered last index of the last child before the hole in the array before number of children before the hole in the array rest index of the first child after the hole in the array */ first = last = 0; before = rest = 1; /* run through the array and coarsen recursively */ incount = tquadrants->elem_count; while (rest + P4EST_CHILDREN - 1 - before < incount) { couldbegood = 1; for (zz = 0; zz < P4EST_CHILDREN; ++zz) { if (zz < before) { c[zz] = p4est_quadrant_array_index (tquadrants, first + zz); if (zz != (size_t) p4est_quadrant_child_id (c[zz])) { couldbegood = 0; break; } } else { c[zz] = p4est_quadrant_array_index (tquadrants, rest + zz - before); } } if (couldbegood && p4est_quadrant_is_familypv (c) && coarsen_fn (p4est, jt, c)) { /* coarsen now */ for (zz = 0; zz < P4EST_CHILDREN; ++zz) { p4est_quadrant_free_data (p4est, c[zz]); } tree->quadrants_per_level[c[0]->level] -= P4EST_CHILDREN; cfirst = c[0]; p4est_quadrant_parent (c[0], cfirst); p4est_quadrant_init_data (p4est, jt, cfirst, init_fn); tree->quadrants_per_level[cfirst->level] += 1; p4est->local_num_quadrants -= P4EST_CHILDREN - 1; removed += P4EST_CHILDREN - 1; rest += P4EST_CHILDREN - before; if (coarsen_recursive) { last = first; cidz = (size_t) p4est_quadrant_child_id (cfirst); if (cidz > first) first = 0; else first -= cidz; } else { /* don't coarsen again, move the counters and the hole */ P4EST_ASSERT (first == last && before == 1); if (rest < incount) { ++first; cfirst = p4est_quadrant_array_index (tquadrants, first); clast = p4est_quadrant_array_index (tquadrants, rest); *cfirst = *clast; last = first; ++rest; } } } else { /* do nothing, just move the counters and the hole */ ++first; if (first > last) { if (first != rest) { cfirst = p4est_quadrant_array_index (tquadrants, first); clast = p4est_quadrant_array_index (tquadrants, rest); *cfirst = *clast; } last = first; ++rest; } } before = last - first + 1; } /* adjust final array size */ first = last; if (first + 1 < rest) { while (rest < incount) { ++first; cfirst = p4est_quadrant_array_index (tquadrants, first); clast = p4est_quadrant_array_index (tquadrants, rest); *cfirst = *clast; ++rest; } sc_array_resize (tquadrants, first + 1); } /* compute maximum level */ maxlevel = 0; num_quadrants = 0; for (i = 0; i <= P4EST_QMAXLEVEL; ++i) { P4EST_ASSERT (tree->quadrants_per_level[i] >= 0); num_quadrants += tree->quadrants_per_level[i]; /* same type */ if (tree->quadrants_per_level[i] > 0) { maxlevel = i; } } tree->maxlevel = (int8_t) maxlevel; tree->quadrants_offset = prev_offset; prev_offset += num_quadrants; /* do some sanity checks */ P4EST_ASSERT (num_quadrants == (p4est_locidx_t) tquadrants->elem_count); P4EST_ASSERT (tquadrants->elem_count == incount - removed); if (p4est->user_data_pool != NULL) { P4EST_ASSERT (data_pool_size - removed == p4est->user_data_pool->elem_count); } P4EST_ASSERT (p4est_tree_is_sorted (tree)); P4EST_ASSERT (p4est_tree_is_complete (tree)); /* final log message for this tree */ P4EST_VERBOSEF ("Done coarsen tree %lld now %llu\n", (long long) jt, (unsigned long long) tquadrants->elem_count); } if (p4est->last_local_tree >= 0) { for (; jt < p4est->connectivity->num_trees; ++jt) { tree = p4est_tree_array_index (p4est->trees, jt); tree->quadrants_offset = p4est->local_num_quadrants; } } /* compute global number of quadrants */ p4est_comm_count_quadrants (p4est); P4EST_ASSERT (p4est_is_valid (p4est)); p4est_log_indent_pop (); P4EST_GLOBAL_PRODUCTIONF ("Done " P4EST_STRING "_coarsen_old with %lld total quadrants\n", (long long) p4est->global_num_quadrants); }
int p6est_comm_parallel_env_reduce_ext (p6est_t ** p6est_supercomm, sc_MPI_Group group_add, int add_to_beginning, int **ranks_subcomm) { p6est_t *p6est = *p6est_supercomm; int mpisize = p6est->mpisize; int mpiret; p4est_gloidx_t *global_first_layer = p6est->global_first_layer; p4est_gloidx_t *n_quadrants; int submpisize; sc_MPI_Comm submpicomm; int *ranks; int i; int is_nonempty; /* reduce MPI communicator of column layout */ is_nonempty = p4est_comm_parallel_env_reduce_ext (&(p6est->columns), group_add, add_to_beginning, &ranks); /* destroy p4est and exit if this rank is empty */ if (!is_nonempty) { p6est->columns = NULL; p6est_destroy (p6est); *p6est_supercomm = NULL; if (ranks_subcomm) { *ranks_subcomm = NULL; } P4EST_ASSERT (ranks == NULL); return 0; } /* get sub-communicator */ submpicomm = p6est->columns->mpicomm; /* update size of new MPI communicator */ mpiret = sc_MPI_Comm_size (submpicomm, &submpisize); SC_CHECK_MPI (mpiret); if (submpisize == p6est->mpisize) { P4EST_ASSERT (ranks == NULL); return 1; } /* set new parallel environment */ p6est_comm_parallel_env_release (p6est); p6est_comm_parallel_env_assign (p6est, submpicomm); if (p6est->columns->mpicomm_owned) { p6est->columns->mpicomm_owned = 0; p6est->mpicomm_owned = 1; } P4EST_ASSERT (p6est->mpisize == submpisize); /* create array of non-empty processes that will be included to sub-comm */ n_quadrants = P4EST_ALLOC (p4est_gloidx_t, mpisize); for (i = 0; i < mpisize; i++) { n_quadrants[i] = global_first_layer[i + 1] - global_first_layer[i]; } /* allocate and set global layer count */ P4EST_FREE (p6est->global_first_layer); p6est->global_first_layer = P4EST_ALLOC (p4est_gloidx_t, submpisize + 1); p6est->global_first_layer[0] = 0; for (i = 0; i < submpisize; i++) { P4EST_ASSERT (ranks[i] != sc_MPI_UNDEFINED); P4EST_ASSERT (group_add != sc_MPI_GROUP_NULL || 0 < n_quadrants[ranks[i]]); p6est->global_first_layer[i + 1] = p6est->global_first_layer[i] + n_quadrants[ranks[i]]; } P4EST_FREE (n_quadrants); if (ranks_subcomm) { *ranks_subcomm = ranks; } else { P4EST_FREE (ranks); } /* return that p6est exists on this rank */ return 1; }
int p6est_vtk_write_header (p6est_t * p6est, double scale, int write_tree, int write_rank, int wrap_rank, const char *point_scalars, const char *point_vectors, const char *filename) { p6est_connectivity_t *connectivity = p6est->connectivity; p4est_t *p4est = p6est->columns; sc_array_t *layers = p6est->layers; sc_array_t *trees = p4est->trees; const int mpirank = p4est->mpirank; const double intsize = 1.0 / P4EST_ROOT_LEN; double v[24]; const p4est_topidx_t first_local_tree = p4est->first_local_tree; const p4est_topidx_t last_local_tree = p4est->last_local_tree; const p4est_locidx_t Ncells = (p4est_locidx_t) layers->elem_count; const p4est_locidx_t Ncorners = P8EST_CHILDREN * Ncells; #ifdef P4EST_VTK_ASCII double wx, wy, wz; p4est_locidx_t sk; #else int retval; uint8_t *uint8_data; p4est_locidx_t *locidx_data; #endif int xi, yi, j, k; int zi; double h2, h2z, eta_x, eta_y, eta_z = 0.; double xyz[3]; /* 3 not P4EST_DIM */ size_t num_cols, zz, zy, first, last; p4est_topidx_t jt; p4est_locidx_t quad_count, Ntotal; p4est_locidx_t il; P4EST_VTK_FLOAT_TYPE *float_data; sc_array_t *columns; p4est_tree_t *tree; p4est_quadrant_t *col; p2est_quadrant_t *layer; char vtufilename[BUFSIZ]; FILE *vtufile; SC_CHECK_ABORT (connectivity->conn4->num_vertices > 0, "Must provide connectivity with vertex information"); P4EST_ASSERT (0. <= scale && scale <= 1. && wrap_rank >= 0); Ntotal = Ncorners; if (scale == 1.) { scale = 1. - 2. * SC_EPS; P4EST_ASSERT (scale < 1.); } /* Have each proc write to its own file */ snprintf (vtufilename, BUFSIZ, "%s_%04d.vtu", filename, mpirank); /* Use "w" for writing the initial part of the file. * For further parts, use "r+" and fseek so write_compressed succeeds. */ vtufile = fopen (vtufilename, "wb"); if (vtufile == NULL) { P4EST_LERRORF ("Could not open %s for output\n", vtufilename); return -1; } fprintf (vtufile, "<?xml version=\"1.0\"?>\n"); fprintf (vtufile, "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\""); #if defined P4EST_VTK_BINARY && defined P4EST_VTK_COMPRESSION fprintf (vtufile, " compressor=\"vtkZLibDataCompressor\""); #endif #ifdef SC_IS_BIGENDIAN fprintf (vtufile, " byte_order=\"BigEndian\">\n"); #else fprintf (vtufile, " byte_order=\"LittleEndian\">\n"); #endif fprintf (vtufile, " <UnstructuredGrid>\n"); fprintf (vtufile, " <Piece NumberOfPoints=\"%lld\" NumberOfCells=\"%lld\">\n", (long long) Ntotal, (long long) Ncells); fprintf (vtufile, " <Points>\n"); float_data = P4EST_ALLOC (P4EST_VTK_FLOAT_TYPE, 3 * Ntotal); /* write point position data */ fprintf (vtufile, " <DataArray type=\"%s\" Name=\"Position\"" " NumberOfComponents=\"3\" format=\"%s\">\n", P4EST_VTK_FLOAT_NAME, P4EST_VTK_FORMAT_STRING); /* loop over the trees */ for (jt = first_local_tree, quad_count = 0; jt <= last_local_tree; ++jt) { tree = p4est_tree_array_index (trees, jt); columns = &tree->quadrants; num_cols = columns->elem_count; p6est_tree_get_vertices (connectivity, jt, v); /* loop over the elements in tree and calculated vertex coordinates */ for (zz = 0; zz < num_cols; ++zz) { col = p4est_quadrant_array_index (columns, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); for (zy = first; zy < last; zy++, quad_count++) { layer = p2est_quadrant_array_index (layers, zy); h2 = .5 * intsize * P4EST_QUADRANT_LEN (col->level); h2z = .5 * intsize * P4EST_QUADRANT_LEN (layer->level); k = 0; for (zi = 0; zi < 2; ++zi) { for (yi = 0; yi < 2; ++yi) { for (xi = 0; xi < 2; ++xi) { P4EST_ASSERT (0 <= k && k < P8EST_CHILDREN); eta_x = intsize * col->x + h2 * (1. + (xi * 2 - 1) * scale); eta_y = intsize * col->y + h2 * (1. + (yi * 2 - 1) * scale); eta_z = intsize * layer->z + h2z * (1. + (zi * 2 - 1) * scale); for (j = 0; j < 3; ++j) { /* *INDENT-OFF* */ xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * 0 + j] + eta_x * v[3 * 1 + j]) + eta_y * ((1. - eta_x) * v[3 * 2 + j] + eta_x * v[3 * 3 + j])) + eta_z * ((1. - eta_y) * ((1. - eta_x) * v[3 * 4 + j] + eta_x * v[3 * 5 + j]) + eta_y * ((1. - eta_x) * v[3 * 6 + j] + eta_x * v[3 * 7 + j])) ); /* *INDENT-ON* */ } for (j = 0; j < 3; ++j) { float_data[3 * (P8EST_CHILDREN * quad_count + k) + j] = (P4EST_VTK_FLOAT_TYPE) xyz[j]; } ++k; } } } P4EST_ASSERT (k == P8EST_CHILDREN); } } } P4EST_ASSERT (P8EST_CHILDREN * quad_count == Ntotal); #ifdef P4EST_VTK_ASCII for (il = 0; il < Ntotal; ++il) { wx = float_data[3 * il + 0]; wy = float_data[3 * il + 1]; wz = float_data[3 * il + 2]; #ifdef P4EST_VTK_DOUBLES fprintf (vtufile, " %24.16e %24.16e %24.16e\n", wx, wy, wz); #else fprintf (vtufile, " %16.8e %16.8e %16.8e\n", wx, wy, wz); #endif } #else fprintf (vtufile, " "); /* TODO: Don't allocate the full size of the array, only allocate * the chunk that will be passed to zlib and do this a chunk * at a time. */ retval = p6est_vtk_write_binary (vtufile, (char *) float_data, sizeof (*float_data) * 3 * Ntotal); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding points\n"); fclose (vtufile); return -1; } #endif P4EST_FREE (float_data); fprintf (vtufile, " </DataArray>\n"); fprintf (vtufile, " </Points>\n"); fprintf (vtufile, " <Cells>\n"); /* write connectivity data */ fprintf (vtufile, " <DataArray type=\"%s\" Name=\"connectivity\"" " format=\"%s\">\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); #ifdef P4EST_VTK_ASCII for (sk = 0, il = 0; il < Ncells; ++il) { fprintf (vtufile, " "); for (k = 0; k < P8EST_CHILDREN; ++sk, ++k) { fprintf (vtufile, " %lld", (long long) sk); } fprintf (vtufile, "\n"); } #else locidx_data = P4EST_ALLOC (p4est_locidx_t, Ncorners); fprintf (vtufile, " "); for (il = 0; il < Ncorners; ++il) { locidx_data[il] = il; } retval = p6est_vtk_write_binary (vtufile, (char *) locidx_data, sizeof (*locidx_data) * Ncorners); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding connectivity\n"); fclose (vtufile); return -1; } #endif fprintf (vtufile, " </DataArray>\n"); /* write offset data */ fprintf (vtufile, " <DataArray type=\"%s\" Name=\"offsets\"" " format=\"%s\">\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); #ifdef P4EST_VTK_ASCII fprintf (vtufile, " "); for (il = 1, sk = 1; il <= Ncells; ++il, ++sk) { fprintf (vtufile, " %lld", (long long) (P8EST_CHILDREN * il)); if (!(sk % 8) && il != Ncells) fprintf (vtufile, "\n "); } fprintf (vtufile, "\n"); #else for (il = 1; il <= Ncells; ++il) locidx_data[il - 1] = P8EST_CHILDREN * il; /* same type */ fprintf (vtufile, " "); retval = p6est_vtk_write_binary (vtufile, (char *) locidx_data, sizeof (*locidx_data) * Ncells); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding offsets\n"); fclose (vtufile); return -1; } #endif fprintf (vtufile, " </DataArray>\n"); /* write type data */ fprintf (vtufile, " <DataArray type=\"UInt8\" Name=\"types\"" " format=\"%s\">\n", P4EST_VTK_FORMAT_STRING); #ifdef P4EST_VTK_ASCII fprintf (vtufile, " "); for (il = 0, sk = 1; il < Ncells; ++il, ++sk) { fprintf (vtufile, " %d", P4EST_VTK_CELL_TYPE); if (!(sk % 20) && il != (Ncells - 1)) fprintf (vtufile, "\n "); } fprintf (vtufile, "\n"); #else uint8_data = P4EST_ALLOC (uint8_t, Ncells); for (il = 0; il < Ncells; ++il) uint8_data[il] = P4EST_VTK_CELL_TYPE; fprintf (vtufile, " "); retval = p6est_vtk_write_binary (vtufile, (char *) uint8_data, sizeof (*uint8_data) * Ncells); P4EST_FREE (uint8_data); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding types\n"); fclose (vtufile); return -1; } #endif fprintf (vtufile, " </DataArray>\n"); fprintf (vtufile, " </Cells>\n"); if (write_rank || write_tree) { fprintf (vtufile, " <CellData Scalars=\"%s\">\n", !write_tree ? "mpirank" : !write_rank ? "treeid" : "mpirank,treeid"); } if (write_rank) { const int wrapped_rank = wrap_rank > 0 ? mpirank % wrap_rank : mpirank; fprintf (vtufile, " <DataArray type=\"%s\" Name=\"mpirank\"" " format=\"%s\">\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); #ifdef P4EST_VTK_ASCII fprintf (vtufile, " "); for (il = 0, sk = 1; il < Ncells; ++il, ++sk) { fprintf (vtufile, " %d", wrapped_rank); if (!(sk % 20) && il != (Ncells - 1)) fprintf (vtufile, "\n "); } fprintf (vtufile, "\n"); #else for (il = 0; il < Ncells; ++il) locidx_data[il] = (p4est_locidx_t) wrapped_rank; fprintf (vtufile, " "); retval = p6est_vtk_write_binary (vtufile, (char *) locidx_data, sizeof (*locidx_data) * Ncells); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding types\n"); fclose (vtufile); return -1; } #endif fprintf (vtufile, " </DataArray>\n"); } if (write_tree) { fprintf (vtufile, " <DataArray type=\"%s\" Name=\"treeid\"" " format=\"%s\">\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); #ifdef P4EST_VTK_ASCII fprintf (vtufile, " "); for (il = 0, sk = 1, jt = first_local_tree; jt <= last_local_tree; ++jt) { tree = p4est_tree_array_index (trees, jt); num_cols = tree->quadrants.elem_count; columns = &tree->quadrants; for (zz = 0; zz < num_cols; ++zz) { col = p4est_quadrant_array_index (columns, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); for (zy = first; zy < last; zy++, sk++, il++) { fprintf (vtufile, " %lld", (long long) jt); if (!(sk % 20) && il != (Ncells - 1)) fprintf (vtufile, "\n "); } } } fprintf (vtufile, "\n"); #else for (il = 0, jt = first_local_tree; jt <= last_local_tree; ++jt) { tree = p4est_tree_array_index (trees, jt); num_cols = tree->quadrants.elem_count; columns = &tree->quadrants; for (zz = 0; zz < num_cols; ++zz) { col = p4est_quadrant_array_index (columns, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); for (zy = first; zy < last; zy++, il++) { locidx_data[il] = (p4est_locidx_t) jt; } } } fprintf (vtufile, " "); retval = p6est_vtk_write_binary (vtufile, (char *) locidx_data, sizeof (*locidx_data) * Ncells); fprintf (vtufile, "\n"); if (retval) { P4EST_LERROR ("p6est_vtk: Error encoding types\n"); fclose (vtufile); return -1; } #endif fprintf (vtufile, " </DataArray>\n"); P4EST_ASSERT (il == Ncells); } if (write_rank || write_tree) { fprintf (vtufile, " </CellData>\n"); } #ifndef P4EST_VTK_ASCII P4EST_FREE (locidx_data); #endif fprintf (vtufile, " <PointData"); if (point_scalars != NULL) fprintf (vtufile, " Scalars=\"%s\"", point_scalars); if (point_vectors != NULL) fprintf (vtufile, " Vectors=\"%s\"", point_vectors); fprintf (vtufile, ">\n"); if (ferror (vtufile)) { P4EST_LERROR ("p6est_vtk: Error writing header\n"); fclose (vtufile); return -1; } if (fclose (vtufile)) { P4EST_LERROR ("p6est_vtk: Error closing header\n"); return -1; } vtufile = NULL; /* Only have the root write to the parallel vtk file */ if (mpirank == 0) { char pvtufilename[BUFSIZ]; FILE *pvtufile; snprintf (pvtufilename, BUFSIZ, "%s.pvtu", filename); pvtufile = fopen (pvtufilename, "wb"); if (!pvtufile) { P4EST_LERRORF ("Could not open %s for output\n", vtufilename); return -1; } fprintf (pvtufile, "<?xml version=\"1.0\"?>\n"); fprintf (pvtufile, "<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\""); #if defined P4EST_VTK_BINARY && defined P4EST_VTK_COMPRESSION fprintf (pvtufile, " compressor=\"vtkZLibDataCompressor\""); #endif #ifdef SC_IS_BIGENDIAN fprintf (pvtufile, " byte_order=\"BigEndian\">\n"); #else fprintf (pvtufile, " byte_order=\"LittleEndian\">\n"); #endif fprintf (pvtufile, " <PUnstructuredGrid GhostLevel=\"0\">\n"); fprintf (pvtufile, " <PPoints>\n"); fprintf (pvtufile, " <PDataArray type=\"%s\" Name=\"Position\"" " NumberOfComponents=\"3\" format=\"%s\"/>\n", P4EST_VTK_FLOAT_NAME, P4EST_VTK_FORMAT_STRING); fprintf (pvtufile, " </PPoints>\n"); if (write_rank || write_tree) { fprintf (pvtufile, " <PCellData Scalars=\"%s\">\n", !write_tree ? "mpirank" : !write_rank ? "treeid" : "mpirank,treeid"); } if (write_rank) { fprintf (pvtufile, " " "<PDataArray type=\"%s\" Name=\"mpirank\" format=\"%s\"/>\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); } if (write_tree) { fprintf (pvtufile, " " "<PDataArray type=\"%s\" Name=\"treeid\" format=\"%s\"/>\n", P4EST_VTK_LOCIDX, P4EST_VTK_FORMAT_STRING); } if (write_rank || write_tree) { fprintf (pvtufile, " </PCellData>\n"); } fprintf (pvtufile, " <PPointData>\n"); if (ferror (pvtufile)) { P4EST_LERROR ("p6est_vtk: Error writing parallel header\n"); fclose (pvtufile); return -1; } if (fclose (pvtufile)) { P4EST_LERROR ("p6est_vtk: Error closing parallel header\n"); return -1; } } return 0; }
static void test_weird (void) { const p4est_topidx_t num_edges = 1, num_ett = 2; const p4est_topidx_t num_corners = 1, num_ctt = 4; int i; size_t zz; p8est_edge_info_t ei; p8est_edge_transform_t *et; p8est_corner_info_t ci; p8est_corner_transform_t *ct; sc_array_t *eta, *cta; p8est_connectivity_t *conn; conn = p8est_connectivity_new (0, 1, num_edges, num_ett, num_corners, num_ctt); for (i = 0; i < 6; ++i) { conn->tree_to_tree[i] = 0; conn->tree_to_face[i] = (int8_t) i; } conn->tree_to_face[4] = 5; conn->tree_to_face[5] = 4; for (i = 0; i < 12; ++i) { conn->tree_to_edge[i] = -1; } conn->tree_to_edge[5] = 0; conn->tree_to_edge[7] = 0; conn->edge_to_tree[0] = 0; conn->edge_to_tree[1] = 0; conn->edge_to_edge[0] = 5; conn->edge_to_edge[1] = 19; conn->ett_offset[0] = 0; for (i = 0; i < 8; ++i) { conn->tree_to_corner[i] = -1; } conn->tree_to_corner[0] = 0; conn->tree_to_corner[1] = 0; conn->tree_to_corner[4] = 0; conn->tree_to_corner[5] = 0; conn->corner_to_tree[0] = 0; conn->corner_to_tree[1] = 0; conn->corner_to_tree[2] = 0; conn->corner_to_tree[3] = 0; conn->corner_to_corner[0] = 0; conn->corner_to_corner[1] = 1; conn->corner_to_corner[2] = 4; conn->corner_to_corner[3] = 5; conn->ctt_offset[0] = 0; P4EST_ASSERT (p8est_connectivity_is_valid (conn)); eta = &ei.edge_transforms; sc_array_init (eta, sizeof (p8est_edge_transform_t)); for (i = 0; i < 2; ++i) { p8est_find_edge_transform (conn, 0, weird_edges[i][0], &ei); SC_CHECK_ABORT ((int) ei.iedge == weird_edges[i][0], "WE ei"); SC_CHECK_ABORT (eta->elem_count == 1, "WE count A"); for (zz = 0; zz < eta->elem_count; ++zz) { et = p8est_edge_array_index (eta, zz); SC_CHECK_ABORT (et->ntree == 0, "WE tree"); SC_CHECK_ABORT ((int) et->nedge == weird_edges[i][1], "WE edge"); SC_CHECK_ABORT (et->nflip == 1, "WE flip"); SC_CHECK_ABORT (et->corners == et->nedge % 4, "WE corners"); SC_CHECK_ABORT (et->naxis[0] == 1 && et->naxis[1] == 0 && et->naxis[2] == 2, "WE axis"); } } sc_array_reset (eta); cta = &ci.corner_transforms; sc_array_init (cta, sizeof (p8est_corner_transform_t)); for (i = 0; i < 8; ++i) { p8est_find_corner_transform (conn, 0, i, &ci); SC_CHECK_ABORT ((int) ci.icorner == i, "WC ci"); SC_CHECK_ABORT ((int) cta->elem_count == 2 - (i & 0x02), "WC count"); for (zz = 0; zz < cta->elem_count; ++zz) { ct = p8est_corner_array_index (cta, zz); SC_CHECK_ABORT (ct->ntree == 0, "WC tree"); SC_CHECK_ABORT ((size_t) ct->ncorner == 4 * zz + !(i % 2), "WC corner"); } } sc_array_reset (cta); p8est_connectivity_destroy (conn); }
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; }
/** * Runs all tests. */ int main (int argc, char **argv) { const char *this_fn_name = P4EST_STRING "_test_subcomm"; /* options */ const p4est_locidx_t min_quadrants = 15; const int min_level = 4; const int fill_uniform = 0; /* parallel environment */ sc_MPI_Comm mpicomm = sc_MPI_COMM_WORLD; int mpisize, submpisize; int mpiret; #ifdef P4EST_ENABLE_DEBUG int rank; #endif /* p4est */ p4est_connectivity_t *connectivity; p4est_t *p4est; p4est_locidx_t *partition; /* initialize MPI */ mpiret = sc_MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); /* exit if MPI communicator cannot be reduced */ mpiret = sc_MPI_Comm_size (mpicomm, &mpisize); SC_CHECK_MPI (mpiret); if (mpisize == 1) { mpiret = sc_MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; } /* initialize p4est */ sc_init (mpicomm, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); /* create connectivity */ #ifdef P4_TO_P8 connectivity = p8est_connectivity_new_unitcube (); #else connectivity = p4est_connectivity_new_unitsquare (); #endif /* create p4est object */ p4est = p4est_new_ext (mpicomm, connectivity, min_quadrants, min_level, fill_uniform, 0, NULL, NULL); /* write vtk: new */ p4est_vtk_write_file (p4est, NULL, P4EST_STRING "_subcomm_new"); /* set variables pertaining to the parallel environment */ #ifdef P4EST_ENABLE_DEBUG rank = p4est->mpirank; #endif submpisize = mpisize / 2; P4EST_ASSERT (submpisize <= p4est->global_num_quadrants); /* construct partitioning with empty ranks */ { p4est_locidx_t n_quads_per_proc, n_quads_leftover; int p; partition = P4EST_ALLOC (p4est_locidx_t, mpisize); n_quads_per_proc = p4est->global_num_quadrants / submpisize; n_quads_leftover = p4est->global_num_quadrants - (n_quads_per_proc * submpisize); for (p = 0; p < mpisize; p++) { if (p % 2) { /* if this rank will get quadrants */ partition[p] = n_quads_per_proc; } else { /* if this rank will be empty */ partition[p] = 0; } } partition[1] += n_quads_leftover; /* check partitioning */ #ifdef P4EST_ENABLE_DEBUG { p4est_gloidx_t sum = 0; for (p = 0; p < mpisize; p++) { sum += (p4est_gloidx_t) partition[p]; } P4EST_ASSERT (sum == p4est->global_num_quadrants); } #endif } /* * Test 1: Reduce MPI communicator to non-empty ranks */ P4EST_GLOBAL_INFOF ("%s: Into test 1\n", this_fn_name); { p4est_t *p4est_subcomm; int is_nonempty; /* create p4est copy and re-partition */ p4est_subcomm = p4est_copy_ext (p4est, 1, 1); (void) p4est_partition_given (p4est_subcomm, partition); /* write vtk: partitioned */ p4est_vtk_write_file (p4est_subcomm, NULL, P4EST_STRING "_subcomm_part"); /* reduce MPI communicator to non-empty ranks */ is_nonempty = p4est_comm_parallel_env_reduce (&p4est_subcomm); P4EST_ASSERT ((is_nonempty && 0 < partition[rank]) || (!is_nonempty && 0 == partition[rank])); if (is_nonempty) { /* write vtk: reduced communicator */ p4est_vtk_write_file (p4est_subcomm, NULL, P4EST_STRING "_subcomm_sub1"); /* destroy the p4est that has a reduced MPI communicator */ p4est_destroy (p4est_subcomm); } } mpiret = sc_MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); P4EST_GLOBAL_INFOF ("%s: Done test 1\n", this_fn_name); /* * Test 2: Reduce MPI communicator to non-empty ranks, but now the MPI * communicator is not owned */ P4EST_GLOBAL_INFOF ("%s: Into test 2\n", this_fn_name); { p4est_t *p4est_subcomm; int is_nonempty; /* create p4est copy and re-partition */ p4est_subcomm = p4est_copy_ext (p4est, 1, 0 /* don't dup. comm. */ ); (void) p4est_partition_given (p4est_subcomm, partition); /* reduce MPI communicator to non-empty ranks */ is_nonempty = p4est_comm_parallel_env_reduce (&p4est_subcomm); P4EST_ASSERT ((is_nonempty && 0 < partition[rank]) || (!is_nonempty && 0 == partition[rank])); if (is_nonempty) { /* destroy the p4est that has a reduced MPI communicator */ p4est_destroy (p4est_subcomm); } } mpiret = sc_MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); P4EST_GLOBAL_INFOF ("%s: Done test 2\n", this_fn_name); /* * Test 3: Reduce MPI communicator to non-empty ranks, but keep rank 0 */ P4EST_GLOBAL_INFOF ("%s: Into test 3\n", this_fn_name); { p4est_t *p4est_subcomm; int sub_exists; sc_MPI_Group group, group_reserve; int reserve_range[1][3]; /* create group of full MPI communicator */ mpiret = sc_MPI_Comm_group (mpicomm, &group); SC_CHECK_MPI (mpiret); /* create sub-group containing only rank 0 */ reserve_range[0][0] = 0; reserve_range[0][1] = 0; reserve_range[0][2] = 1; mpiret = sc_MPI_Group_range_incl (group, 1, reserve_range, &group_reserve); SC_CHECK_MPI (mpiret); /* create p4est copy and re-partition */ p4est_subcomm = p4est_copy_ext (p4est, 1, 1); (void) p4est_partition_given (p4est_subcomm, partition); /* reduce MPI communicator to non-empty ranks, but keep rank 0 */ sub_exists = p4est_comm_parallel_env_reduce_ext (&p4est_subcomm, group_reserve, 1, NULL); P4EST_ASSERT ((sub_exists && (0 < partition[rank] || rank == 0)) || (!sub_exists && 0 == partition[rank])); if (sub_exists) { /* write vtk: reduced communicator */ p4est_vtk_write_file (p4est_subcomm, NULL, P4EST_STRING "_subcomm_sub3"); /* destroy the p4est that has a reduced MPI communicator */ p4est_destroy (p4est_subcomm); } } mpiret = sc_MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); P4EST_GLOBAL_INFOF ("%s: Done test 3\n", this_fn_name); /* * Test 4: Reduce MPI communicator to non-empty ranks, but keep last 2 ranks */ P4EST_GLOBAL_INFOF ("%s: Into test 4\n", this_fn_name); { p4est_t *p4est_subcomm; int sub_exists; sc_MPI_Group group, group_reserve; int reserve_range[1][3]; /* create group of full MPI communicator */ mpiret = sc_MPI_Comm_group (mpicomm, &group); SC_CHECK_MPI (mpiret); /* create sub-group containing only last 2 ranks */ reserve_range[0][0] = SC_MAX (0, mpisize - 2); reserve_range[0][1] = mpisize - 1; reserve_range[0][2] = 1; mpiret = sc_MPI_Group_range_incl (group, 1, reserve_range, &group_reserve); SC_CHECK_MPI (mpiret); /* create p4est copy and re-partition */ p4est_subcomm = p4est_copy_ext (p4est, 1, 1); (void) p4est_partition_given (p4est_subcomm, partition); /* reduce MPI communicator to non-empty ranks, but keep last 2 ranks */ sub_exists = p4est_comm_parallel_env_reduce_ext (&p4est_subcomm, group_reserve, 0, NULL); P4EST_ASSERT ((sub_exists && (0 < partition[rank] || mpisize - 2 <= rank)) || (!sub_exists && 0 == partition[rank])); if (sub_exists) { /* write vtk: reduced communicator */ p4est_vtk_write_file (p4est_subcomm, NULL, P4EST_STRING "_subcomm_sub4"); /* destroy the p4est that has a reduced MPI communicator */ p4est_destroy (p4est_subcomm); } } mpiret = sc_MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); P4EST_GLOBAL_INFOF ("%s: Done test 4\n", this_fn_name); /* destroy */ P4EST_FREE (partition); p4est_destroy (p4est); p4est_connectivity_destroy (connectivity); /* finalize */ sc_finalize (); mpiret = sc_MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
static void run_bricks (MPI_Comm mpicomm, int per, int l, int rlevel) { int mpiret; int tcount; double elapsed_create, elapsed_partition, elapsed_balance; #ifdef BRICKS_VTK char filename[BUFSIZ]; #endif p4est_connectivity_t *conn; p4est_t *p4est; P4EST_GLOBAL_PRODUCTIONF ("Run bricks on level %d/%d\n", l, rlevel); P4EST_ASSERT (l <= rlevel); /* create and refine the forest */ mpiret = MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); elapsed_create = -MPI_Wtime (); tcount = 1 << l; #ifndef P4_TO_P8 conn = p4est_connectivity_new_brick (tcount, tcount, per, per); #else conn = p8est_connectivity_new_brick (tcount, tcount, tcount, per, per, per); #endif p4est = p4est_new_ext (mpicomm, conn, 0, rlevel - l, 1, 0, NULL, NULL); level_shift = 4; refine_level = rlevel - l + level_shift; p4est_refine (p4est, 1, refine_fractal, NULL); elapsed_create += MPI_Wtime (); /* partition the forest */ mpiret = MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); elapsed_partition = -MPI_Wtime (); p4est_partition (p4est, NULL); elapsed_partition += MPI_Wtime (); /* balance the forest */ mpiret = MPI_Barrier (mpicomm); SC_CHECK_MPI (mpiret); elapsed_balance = -MPI_Wtime (); p4est_balance (p4est, P4EST_CONNECT_FULL, NULL); elapsed_balance += MPI_Wtime (); /* postprocessing */ P4EST_GLOBAL_PRODUCTIONF ("Timings %g %g %g\n", elapsed_create, elapsed_partition, elapsed_balance); #ifdef BRICKS_VTK snprintf (filename, BUFSIZ, "brick_%02d_%02d_B", rlevel, l); p4est_vtk_write_file (p4est, NULL, filename); #endif p4est_destroy (p4est); p4est_connectivity_destroy (conn); }
p4est_gloidx_t * p6est_lnodes_get_column_labels (p6est_t * p6est, p8est_lnodes_t * lnodes) { p4est_gloidx_t *labels; p4est_gloidx_t num_cols = 0; p4est_gloidx_t global_num_cols = 0; p4est_topidx_t jt; p4est_tree_t *tree; sc_array_t *tquadrants; p4est_quadrant_t *col; size_t zz, first, last; p4est_locidx_t lfirst, llast, lk; int stride = lnodes->degree + 1; int vnodes = lnodes->vnodes; int mpiret, i; labels = P4EST_ALLOC (p4est_gloidx_t, lnodes->owned_count); memset (labels, -1, lnodes->owned_count * sizeof (*labels)); for (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) { col = p4est_quadrant_array_index (tquadrants, zz); P6EST_COLUMN_GET_RANGE (col, &first, &last); lfirst = (p4est_locidx_t) first; llast = (p4est_locidx_t) last; for (i = 0; i < vnodes; i += stride) { p4est_locidx_t fnid = lnodes->element_nodes[vnodes * lfirst + i]; p4est_locidx_t lnid = lnodes->element_nodes[vnodes * (llast - 1) + i + (stride - 1)]; P4EST_ASSERT (lnid >= 0); P4EST_ASSERT (lnid >= fnid); P4EST_ASSERT (fnid < lnodes->num_local_nodes); if (lnid < lnodes->owned_count) { P4EST_ASSERT (fnid < lnodes->owned_count); if (labels[fnid] < 0) { for (lk = fnid; lk <= lnid; lk++) { labels[lk] = num_cols; } num_cols++; } } } } } mpiret = sc_MPI_Exscan (&num_cols, &global_num_cols, 1, P4EST_MPI_GLOIDX, sc_MPI_SUM, lnodes->mpicomm); SC_CHECK_MPI (mpiret); if (!p6est->mpirank) { global_num_cols = 0; } for (lk = 0; lk < lnodes->owned_count; lk++) { labels[lk] += global_num_cols; } #if 0 { sc_array_t view; sc_array_init_data (&view, labels, sizeof (*labels), (size_t) lnodes->num_local_nodes); p6est_lnodes_share_owned (&view, lnodes); } #endif for (lk = 0; lk < lnodes->owned_count; lk++) { P4EST_ASSERT (labels[lk] >= 0); } return labels; }
p6est_lnodes_t * p6est_lnodes_new (p6est_t * p6est, p6est_ghost_t * ghost, int degree) { p6est_lnodes_t *lnodes; p6est_profile_t *profile; p4est_lnodes_t *clnodes; int nperelem = (degree + 1) * (degree + 1) * (degree + 1); /* int nperface = (degree - 1) * (degree - 1); */ /* int nperedge = (degree - 1); */ p4est_locidx_t ncid, cid, enid, *en; p4est_locidx_t nnodecols; p4est_locidx_t nelemcols; p4est_locidx_t nll; p4est_locidx_t nlayers; p4est_locidx_t *layernodecount; p4est_locidx_t *layernodeoffsets; p4est_locidx_t (*lr)[2]; p4est_locidx_t ncolnodes; p4est_locidx_t *global_owned_count; p4est_locidx_t num_owned, num_local; p4est_gloidx_t gnum_owned, offset; p4est_gloidx_t *owned_offsets; int i, j, k; int mpisize = p6est->mpisize; int mpiret; sc_array_t lnoview; size_t zz, nsharers; int Nrp = degree + 1; if (degree == 1) { p4est_locidx_t eid, nid, enid2, nid2; p4est_locidx_t *newnum, newlocal, newowned; P4EST_GLOBAL_PRODUCTION ("Into adapt p6est_lnodes_new for degree = 1\n"); p4est_log_indent_push (); /* adapt 2 to 1 */ lnodes = p6est_lnodes_new (p6est, ghost, 2); nll = p6est->layers->elem_count; num_local = lnodes->num_local_nodes; num_owned = lnodes->owned_count; en = lnodes->element_nodes; newnum = P4EST_ALLOC (p4est_locidx_t, P8EST_INSUL * nll); memset (newnum, -1, P8EST_INSUL * nll * sizeof (p4est_locidx_t)); for (enid = 0, eid = 0; eid < nll; eid++) { for (k = 0; k < 3; k++) { for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++, enid++) { if (k != 1 && j != 1 && i != 1) { newnum[en[enid]] = 0; } } } } } newlocal = 0; newowned = 0; for (nid = 0; nid < num_local; nid++) { if (newnum[nid] >= 0) { newnum[nid] = newlocal++; if (nid < num_owned) { newowned++; } } } /* compress en */ enid2 = 0; for (enid = 0, eid = 0; eid < nll; eid++) { for (k = 0; k < 3; k++) { for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++, enid++) { if (k != 1 && j != 1 && i != 1) { en[enid2++] = newnum[en[enid]]; } } } } } P4EST_ASSERT (enid2 == P8EST_CHILDREN * nll); lnodes->element_nodes = P4EST_REALLOC (en, p4est_locidx_t, P8EST_CHILDREN * nll); owned_offsets = P4EST_ALLOC (p4est_gloidx_t, mpisize + 1); mpiret = sc_MPI_Allgather (&newowned, 1, P4EST_MPI_LOCIDX, lnodes->global_owned_count, 1, P4EST_MPI_LOCIDX, p6est->mpicomm); owned_offsets[0] = 0; for (i = 0; i < mpisize; i++) { owned_offsets[i + 1] = owned_offsets[i] + lnodes->global_owned_count[i]; } lnodes->global_offset = owned_offsets[p6est->mpirank]; lnodes->num_local_nodes = newlocal; lnodes->owned_count = newowned; lnodes->degree = 1; lnodes->vnodes = P8EST_CHILDREN; lnodes->nonlocal_nodes = P4EST_REALLOC (lnodes->nonlocal_nodes, p4est_gloidx_t, newlocal - newowned); nsharers = lnodes->sharers->elem_count; for (zz = 0; zz < nsharers; zz++) { size_t nshared, zy, zw; p6est_lnodes_rank_t *rank = p6est_lnodes_rank_array_index (lnodes->sharers, zz); if (rank->owned_count) { if (rank->rank != p6est->mpirank) { p4est_locidx_t newrankowned = 0; p4est_locidx_t newrankoffset = -1; for (nid = rank->owned_offset; nid < rank->owned_offset + rank->owned_count; nid++) { if (newnum[nid] >= 0) { lnodes->nonlocal_nodes[newnum[nid] - newowned] = owned_offsets[rank->rank]; newrankowned++; if (newrankoffset < 0) { newrankoffset = newnum[nid]; } } } rank->owned_offset = newrankoffset; rank->owned_count = newrankowned; } else { rank->owned_offset = 0; rank->owned_count = newowned; } } rank->shared_mine_count = 0; rank->shared_mine_offset = -1; zw = 0; nshared = rank->shared_nodes.elem_count; for (zy = 0; zy < nshared; zy++) { nid = *((p4est_locidx_t *) sc_array_index (&rank->shared_nodes, zy)); if (newnum[nid] >= 0) { p4est_locidx_t *lp; lp = (p4est_locidx_t *) sc_array_index (&rank->shared_nodes, zw++); *lp = newnum[nid]; if (newnum[nid] < newowned) { rank->shared_mine_count++; if (rank->shared_mine_offset == -1) { rank->shared_mine_offset = zw - 1; } } } } sc_array_resize (&rank->shared_nodes, zw); } /* send local numbers to others */ { sc_array_t view; sc_array_init_data (&view, newnum, sizeof (p4est_locidx_t), newlocal); p6est_lnodes_share_owned (&view, lnodes); } nid2 = 0; for (nid = num_owned; nid < num_local; nid++) { if (newnum[nid] >= 0) { lnodes->nonlocal_nodes[nid2++] += (p4est_gloidx_t) newnum[nid]; } } P4EST_ASSERT (nid2 == newlocal - newowned); P4EST_FREE (owned_offsets); P4EST_FREE (newnum); p4est_log_indent_pop (); P4EST_GLOBAL_PRODUCTION ("Done adapt p6est_lnodes_new for degree = 1\n"); return lnodes; } P4EST_GLOBAL_PRODUCTION ("Into p6est_lnodes_new\n"); p4est_log_indent_push (); P4EST_ASSERT (degree >= 1); lnodes = P4EST_ALLOC (p6est_lnodes_t, 1); /* first get the profile */ profile = p6est_profile_new_local (p6est, ghost, P6EST_PROFILE_INTERSECTION, P8EST_CONNECT_FULL, degree); p6est_profile_sync (profile); lr = (p4est_locidx_t (*)[2]) profile->lnode_ranges; clnodes = profile->lnodes; nnodecols = clnodes->num_local_nodes; nelemcols = clnodes->num_local_elements; en = clnodes->element_nodes; layernodecount = P4EST_ALLOC_ZERO (p4est_locidx_t, nnodecols); layernodeoffsets = P4EST_ALLOC_ZERO (p4est_locidx_t, nnodecols + 1); for (cid = 0, enid = 0; cid < nelemcols; cid++) { for (j = 0; j < Nrp; j++) { for (i = 0; i < Nrp; i++, enid++) { ncid = en[enid]; nlayers = lr[ncid][1]; P4EST_ASSERT (nlayers); ncolnodes = nlayers * degree + 1; layernodecount[ncid] = ncolnodes; } } } num_owned = 0; num_local = 0; for (ncid = 0; ncid < nnodecols; ncid++) { num_local += layernodecount[ncid]; if (ncid < clnodes->owned_count) { num_owned += layernodecount[ncid]; } } P4EST_VERBOSEF ("p6est_lnodes: %d owned %d local\n", num_owned, num_local); if (nnodecols) { layernodeoffsets[0] = 0; for (ncid = 0; ncid < nnodecols; ncid++) { layernodeoffsets[ncid + 1] = layernodeoffsets[ncid] + layernodecount[ncid]; } } gnum_owned = num_owned; owned_offsets = P4EST_ALLOC (p4est_gloidx_t, mpisize + 1); global_owned_count = P4EST_ALLOC (p4est_locidx_t, mpisize); mpiret = sc_MPI_Allgather (&gnum_owned, 1, P4EST_MPI_GLOIDX, owned_offsets, 1, P4EST_MPI_GLOIDX, p6est->mpicomm); SC_CHECK_MPI (mpiret); offset = 0; for (i = 0; i < mpisize; i++) { global_owned_count[i] = (p4est_locidx_t) owned_offsets[i]; gnum_owned = owned_offsets[i]; owned_offsets[i] = offset; offset += gnum_owned; } owned_offsets[mpisize] = offset; nll = p6est->layers->elem_count; nsharers = clnodes->sharers->elem_count; lnodes->mpicomm = p6est->mpicomm; lnodes->num_local_nodes = num_local; lnodes->owned_count = num_owned; lnodes->global_offset = owned_offsets[p6est->mpirank]; lnodes->nonlocal_nodes = P4EST_ALLOC (p4est_gloidx_t, num_local - num_owned); lnodes->sharers = sc_array_new_size (sizeof (p6est_lnodes_rank_t), nsharers); lnodes->global_owned_count = global_owned_count; lnodes->degree = degree; lnodes->vnodes = nperelem; lnodes->num_local_elements = nll; lnodes->face_code = P4EST_ALLOC (p6est_lnodes_code_t, nll); lnodes->element_nodes = P4EST_ALLOC (p4est_locidx_t, nperelem * nll); p6est_profile_element_to_node (p6est, profile, layernodeoffsets, lnodes->element_nodes, lnodes->face_code); for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *crank = p4est_lnodes_rank_array_index (clnodes->sharers, zz); p6est_lnodes_rank_t *rank = p6est_lnodes_rank_array_index (lnodes->sharers, zz); size_t zy; size_t nshared; rank->rank = crank->rank; sc_array_init (&rank->shared_nodes, sizeof (p4est_locidx_t)); nshared = crank->shared_nodes.elem_count; rank->owned_offset = -1; rank->owned_count = 0; rank->shared_mine_count = 0; rank->shared_mine_offset = -1; for (zy = 0; zy < nshared; zy++) { p4est_locidx_t cnid = *((p4est_locidx_t *) sc_array_index (&crank->shared_nodes, zy)); p4est_locidx_t *lp; p4est_locidx_t nthis, il; p4est_locidx_t old_count = rank->shared_nodes.elem_count; nthis = layernodecount[cnid]; lp = (p4est_locidx_t *) sc_array_push_count (&rank->shared_nodes, nthis); for (il = 0; il < nthis; il++) { lp[il] = layernodeoffsets[cnid] + il; if (zy >= (size_t) crank->shared_mine_offset && (p4est_locidx_t) zy - crank->shared_mine_offset < crank->shared_mine_count) { rank->shared_mine_count++; if (rank->shared_mine_offset == -1) { rank->shared_mine_offset = old_count + il; } } if (cnid >= crank->owned_offset && cnid - crank->owned_offset < crank->owned_count) { rank->owned_count++; if (rank->owned_offset == -1) { rank->owned_offset = lp[il]; } } } } if (rank->rank == p6est->mpirank) { rank->owned_offset = 0; rank->owned_count = num_owned; } } memcpy (layernodecount, layernodeoffsets, nnodecols * sizeof (p4est_locidx_t)); sc_array_init_data (&lnoview, layernodecount, sizeof (p4est_locidx_t), (size_t) nnodecols); p4est_lnodes_share_owned (&lnoview, clnodes); for (zz = 0; zz < nsharers; zz++) { p4est_lnodes_rank_t *crank = p4est_lnodes_rank_array_index (clnodes->sharers, zz); if (crank->rank == p6est->mpirank) { continue; } for (ncid = crank->owned_offset; ncid < crank->owned_offset + crank->owned_count; ncid++) { p4est_gloidx_t owners_offset; p4est_locidx_t nid; P4EST_ASSERT (ncid >= clnodes->owned_count); owners_offset = owned_offsets[crank->rank] + layernodecount[ncid]; for (nid = layernodeoffsets[ncid]; nid < layernodeoffsets[ncid + 1]; nid++) { P4EST_ASSERT (nid >= num_owned); P4EST_ASSERT (nid < num_local); lnodes->nonlocal_nodes[nid - num_owned] = owners_offset++; } } } p6est_profile_destroy (profile); P4EST_FREE (owned_offsets); P4EST_FREE (layernodecount); P4EST_FREE (layernodeoffsets); p4est_log_indent_pop (); P4EST_GLOBAL_PRODUCTION ("Done p6est_lnodes_new\n"); return lnodes; }
/** For two quadrants on either side of a face, estimate the derivative normal * to the face. * * This function matches the p4est_iter_face_t prototype used by * p4est_iterate(). * * \param [in] info the information about this quadrant that has been * populated by p4est_iterate() * \param [in] user_data the user_data given to p4est_iterate(): in this case, * it points to the ghost_data array, which contains the * step3_data_t data for all of the ghost cells, which * was populated by p4est_ghost_exchange_data() */ static void step3_minmod_estimate (p4est_iter_face_info_t * info, void *user_data) { int i, j; p4est_iter_face_side_t *side[2]; sc_array_t *sides = &(info->sides); step3_data_t *ghost_data = (step3_data_t *) user_data; step3_data_t *udata; p4est_quadrant_t *quad; double uavg[2]; double h[2]; double du_est, du_old; int which_dir; /* because there are no boundaries, every face has two sides */ P4EST_ASSERT (sides->elem_count == 2); side[0] = p4est_iter_fside_array_index_int (sides, 0); side[1] = p4est_iter_fside_array_index_int (sides, 1); which_dir = side[0]->face / 2; /* 0 == x, 1 == y, 2 == z */ for (i = 0; i < 2; i++) { uavg[i] = 0; if (side[i]->is_hanging) { /* there are 2^(d-1) (P4EST_HALF) subfaces */ for (j = 0; j < P4EST_HALF; j++) { quad = side[i]->is.hanging.quad[j]; h[i] = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN; if (side[i]->is.hanging.is_ghost[j]) { udata = &ghost_data[side[i]->is.hanging.quadid[j]]; } else { udata = (step3_data_t *) side[i]->is.hanging.quad[j]->p.user_data; } uavg[i] += udata->u; } uavg[i] /= P4EST_HALF; } else { quad = side[i]->is.full.quad; h[i] = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN; if (side[i]->is.full.is_ghost) { udata = &ghost_data[side[i]->is.full.quadid]; } else { udata = (step3_data_t *) side[i]->is.full.quad->p.user_data; } uavg[i] = udata->u; } } du_est = (uavg[1] - uavg[0]) / ((h[0] + h[1]) / 2.); for (i = 0; i < 2; i++) { if (side[i]->is_hanging) { /* there are 2^(d-1) (P4EST_HALF) subfaces */ for (j = 0; j < P4EST_HALF; j++) { quad = side[i]->is.hanging.quad[j]; if (!side[i]->is.hanging.is_ghost[j]) { udata = (step3_data_t *) quad->p.user_data; du_old = udata->du[which_dir]; if (du_old == du_old) { /* there has already been an update */ if (du_est * du_old >= 0.) { if (fabs (du_est) < fabs (du_old)) { udata->du[which_dir] = du_est; } } else { udata->du[which_dir] = 0.; } } else { udata->du[which_dir] = du_est; } } } } else { quad = side[i]->is.full.quad; if (!side[i]->is.full.is_ghost) { udata = (step3_data_t *) quad->p.user_data; du_old = udata->du[which_dir]; if (du_old == du_old) { /* there has already been an update */ if (du_est * du_old >= 0.) { if (fabs (du_est) < fabs (du_old)) { udata->du[which_dir] = du_est; } } else { udata->du[which_dir] = 0.; } } else { udata->du[which_dir] = du_est; } } } } }
/** Approximate the flux across a boundary between quadrants. * * We use a very simple upwind numerical flux. * * This function matches the p4est_iter_face_t prototype used by * p4est_iterate(). * * \param [in] info the information about the quadrants on either side of the * interface, populated by p4est_iterate() * \param [in] user_data the user_data given to p4est_iterate(): in this case, * it points to the ghost_data array, which contains the * step3_data_t data for all of the ghost cells, which * was populated by p4est_ghost_exchange_data() */ static void step3_upwind_flux (p4est_iter_face_info_t * info, void *user_data) { int i, j; p4est_t *p4est = info->p4est; step3_ctx_t *ctx = (step3_ctx_t *) p4est->user_pointer; step3_data_t *ghost_data = (step3_data_t *) user_data; step3_data_t *udata; p4est_quadrant_t *quad; double vdotn = 0.; double uavg; double q; double h, facearea; int which_face; int upwindside; p4est_iter_face_side_t *side[2]; sc_array_t *sides = &(info->sides); /* because there are no boundaries, every face has two sides */ P4EST_ASSERT (sides->elem_count == 2); side[0] = p4est_iter_fside_array_index_int (sides, 0); side[1] = p4est_iter_fside_array_index_int (sides, 1); /* which of the quadrant's faces the interface touches */ which_face = side[0]->face; switch (which_face) { case 0: /* -x side */ vdotn = -ctx->v[0]; break; case 1: /* +x side */ vdotn = ctx->v[0]; break; case 2: /* -y side */ vdotn = -ctx->v[1]; break; case 3: /* +y side */ vdotn = ctx->v[1]; break; #ifdef P4_TO_P8 case 4: /* -z side */ vdotn = -ctx->v[2]; break; case 5: /* +z side */ vdotn = ctx->v[2]; break; #endif } upwindside = vdotn >= 0. ? 0 : 1; /* Because we have non-conforming boundaries, one side of an interface can * either have one large ("full") quadrant or 2^(d-1) small ("hanging") * quadrants: we have to compute the average differently in each case. The * info populated by p4est_iterate() gives us the context we need to * proceed. */ uavg = 0; if (side[upwindside]->is_hanging) { /* there are 2^(d-1) (P4EST_HALF) subfaces */ for (j = 0; j < P4EST_HALF; j++) { if (side[upwindside]->is.hanging.is_ghost[j]) { /* *INDENT-OFF* */ udata = (step3_data_t *) &ghost_data[side[upwindside]->is.hanging.quadid[j]]; /* *INDENT-ON* */ } else { udata = (step3_data_t *) side[upwindside]->is.hanging.quad[j]->p.user_data; } uavg += udata->u; } uavg /= P4EST_HALF; } else { if (side[upwindside]->is.full.is_ghost) { udata = (step3_data_t *) & ghost_data[side[upwindside]->is.full.quadid]; } else { udata = (step3_data_t *) side[upwindside]->is.full.quad->p.user_data; } uavg = udata->u; } /* flux from side 0 to side 1 */ q = vdotn * uavg; for (i = 0; i < 2; i++) { if (side[i]->is_hanging) { /* there are 2^(d-1) (P4EST_HALF) subfaces */ for (j = 0; j < P4EST_HALF; j++) { quad = side[i]->is.hanging.quad[j]; h = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN; #ifndef P4_TO_P8 facearea = h; #else facearea = h * h; #endif if (!side[i]->is.hanging.is_ghost[j]) { udata = (step3_data_t *) quad->p.user_data; if (i == upwindside) { udata->dudt += vdotn * udata->u * facearea * (i ? 1. : -1.); } else { udata->dudt += q * facearea * (i ? 1. : -1.); } } } } else { quad = side[i]->is.full.quad; h = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN; #ifndef P4_TO_P8 facearea = h; #else facearea = h * h; #endif if (!side[i]->is.full.is_ghost) { udata = (step3_data_t *) quad->p.user_data; udata->dudt += q * facearea * (i ? 1. : -1.); } } } }
static void p8est_bal_edge_con_internal (p4est_quadrant_t const *q, p4est_quadrant_t * p, int edge, int balance, int *consistent, p4est_quadrant_t * add) { int plevel = p->level; int qlevel = q->level; int blevel; int child; int recon; p4est_quadrant_t porig; p4est_quadrant_t temp; p4est_quadrant_t a; p4est_qcoord_t dx, dy; p4est_qcoord_t dist; p4est_qcoord_t qlen, plen, mask; p4est_qcoord_t b1len, pmask; int i; P4EST_ASSERT (p4est_quadrant_is_extended (q)); P4EST_ASSERT (p4est_quadrant_is_extended (p)); if (qlevel <= plevel) { if (consistent != NULL) { *consistent = 1; } return; } qlen = P4EST_QUADRANT_LEN (qlevel); plen = P4EST_QUADRANT_LEN (plevel); switch (edge / 4) { case 0: dx = (edge & 1) ? (q->y + qlen) - (p->y + plen) : p->y - q->y; dy = (edge & 2) ? (q->z + qlen) - (p->z + plen) : p->z - q->z; break; case 1: dx = (edge & 1) ? (q->x + qlen) - (p->x + plen) : p->x - q->x; dy = (edge & 2) ? (q->z + qlen) - (p->z + plen) : p->z - q->z; break; case 2: dx = (edge & 1) ? (q->x + qlen) - (p->x + plen) : p->x - q->x; dy = (edge & 2) ? (q->y + qlen) - (p->y + plen) : p->y - q->y; break; default: SC_ABORT_NOT_REACHED (); } P4EST_ASSERT (dx >= 0); P4EST_ASSERT (dy >= 0); if (balance) { dist = SC_MAX (dx, dy); blevel = p4est_balance_kernel_1d (dist, qlevel); } else { blevel = p4est_balance_kernel_2d (dx, dy, qlevel); } if (blevel <= plevel) { if (consistent != NULL) { *consistent = 1; } return; } if (consistent != NULL) { *consistent = 0; } porig = *p; *p = *q; switch (edge / 4) { case 0: p->y += (edge & 1) ? -dx : dx; p->z += (edge & 2) ? -dy : dy; break; case 1: p->x += (edge & 1) ? -dx : dx; p->z += (edge & 2) ? -dy : dy; break; case 2: p->x += (edge & 1) ? -dx : dx; p->y += (edge & 2) ? -dy : dy; break; default: SC_ABORT_NOT_REACHED (); } mask = -1 << (P4EST_MAXLEVEL - blevel); p->x &= mask; p->y &= mask; p->z &= mask; p->level = blevel; P4EST_ASSERT (p4est_quadrant_is_extended (p)); if (add != NULL) { add[1] = *p; /* this is the only quad needed if it is only one level smaller than the * original quadrant */ if (blevel == plevel - 1) { return; } mask = -1 << (P4EST_MAXLEVEL - (blevel - 1)); pmask = -1 << (P4EST_MAXLEVEL - (plevel)); a = *p; a.x &= mask; a.y &= mask; a.z &= mask; a.level = blevel - 1; b1len = P4EST_QUADRANT_LEN (blevel - 1); for (i = -1; i <= 1; i += 2) { temp = a; /* temp is in a family group one family group over from temp */ switch (edge / 4) { case 0: temp.x += i * b1len; break; case 1: temp.y += i * b1len; break; case 2: temp.z += i * b1len; break; default: SC_ABORT_NOT_REACHED (); } if ((temp.x & pmask) != porig.x || (temp.y & pmask) != porig.y || (temp.z & pmask) != porig.z) { /* only test other descendents of p */ continue; } child = p8est_edge_corners[edge][(1 - i) / 2]; p4est_bal_corner_con_internal (q, &temp, child, balance, &recon); if (!recon) { add[1 + i] = temp; } } } }
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 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; }
static void test_mesh (p4est_t * p4est, p4est_ghost_t * ghost, p4est_mesh_t * mesh, int compute_tree_index, int compute_level_lists, p4est_connect_type_t mesh_btype, user_data_t * ghost_data, int uniform) { const int HF = P4EST_HALF * P4EST_FACES; size_t i; int level; int f, nf; int c; int nface; int nrank; p4est_topidx_t which_tree; p4est_locidx_t K, kl; p4est_locidx_t ql, QpG, lnC; p4est_locidx_t qlid, qumid, quadrant_id, which_quad; p4est_mesh_face_neighbor_t mfn, mfn2; p4est_quadrant_t *q; p4est_tree_t *tree; K = mesh->local_num_quadrants; P4EST_ASSERT (K == p4est->local_num_quadrants); QpG = mesh->local_num_quadrants + mesh->ghost_num_quadrants; lnC = mesh->local_num_corners; P4EST_ASSERT (lnC >= 0); P4EST_ASSERT (compute_tree_index == (mesh->quad_to_tree != NULL)); P4EST_ASSERT (compute_level_lists == (mesh->quad_level != NULL)); P4EST_ASSERT ((mesh_btype == P4EST_CONNECT_CORNER) == (mesh->quad_to_corner != NULL)); /* TODO: test the mesh relations in more depth */ tree = NULL; for (kl = 0; kl < K; ++kl) { if (compute_tree_index) { tree = p4est_tree_array_index (p4est->trees, mesh->quad_to_tree[kl]); SC_CHECK_ABORTF (tree->quadrants_offset <= kl && kl < tree->quadrants_offset + (p4est_locidx_t) tree->quadrants.elem_count, "Tree index mismatch %lld", (long long) kl); } if (mesh_btype == P4EST_CONNECT_CORNER) { for (c = 0; c < P4EST_CHILDREN; ++c) { qlid = mesh->quad_to_corner[P4EST_CHILDREN * kl + c]; SC_CHECK_ABORTF (qlid >= -2 && qlid < QpG + lnC, "quad %lld corner %d mismatch", (long long) kl, c); } } for (f = 0; f < P4EST_FACES; ++f) { ql = mesh->quad_to_quad[P4EST_FACES * kl + f]; SC_CHECK_ABORTF (0 <= ql && ql < QpG, "quad %d face %d neighbor %d mismatch", kl, f, ql); nf = mesh->quad_to_face[P4EST_FACES * kl + f]; if (uniform) { SC_CHECK_ABORTF (0 <= nf && nf < HF, "quad %d face %d code %d mismatch", kl, f, nf); } else { SC_CHECK_ABORTF (-HF <= nf && nf < (P4EST_HALF + 1) * HF, "quad %d face %d code %d mismatch", kl, f, nf); } } } /* Test the level lists */ if (compute_tree_index && compute_level_lists) { for (level = 0; level < P4EST_QMAXLEVEL; ++level) { for (i = 0; i < mesh->quad_level[level].elem_count; ++i) { /* get the local quadrant id */ quadrant_id = *(p4est_locidx_t *) sc_array_index (&mesh->quad_level[level], i); /* get the tree it belongs to */ kl = mesh->quad_to_tree[quadrant_id]; tree = p4est_tree_array_index (p4est->trees, kl); /* and finally, get the actual quadrant from the tree quadrant list */ quadrant_id -= tree->quadrants_offset; q = p4est_quadrant_array_index (&tree->quadrants, (size_t) quadrant_id); SC_CHECK_ABORTF (q->level == level, "quad %d level %d mismatch", quadrant_id, level); } } } /* Test face neighbor iterator */ for (qumid = 0; qumid < mesh->local_num_quadrants; ++qumid) { which_tree = -1; q = p4est_mesh_quadrant_cumulative (p4est, qumid, &which_tree, &quadrant_id); p4est_mesh_face_neighbor_init2 (&mfn, p4est, ghost, mesh, which_tree, quadrant_id); p4est_mesh_face_neighbor_init (&mfn2, p4est, ghost, mesh, which_tree, q); P4EST_ASSERT (mfn2.quadrant_id == quadrant_id); while ((q = p4est_mesh_face_neighbor_next (&mfn, &which_tree, &which_quad, &nface, &nrank)) != NULL) { #ifdef P4EST_ENABLE_DEBUG user_data_t *data; data = (user_data_t *) p4est_mesh_face_neighbor_data (&mfn, ghost_data); P4EST_ASSERT (p4est_quadrant_is_equal (q, &(data->quad))); P4EST_ASSERT (data->quad.p.which_tree == which_tree); #endif } } }
int p4est_wrap_adapt (p4est_wrap_t * pp) { int changed; #ifdef P4EST_ENABLE_DEBUG p4est_locidx_t jl, local_num; #endif p4est_gloidx_t global_num; p4est_t *p4est = pp->p4est; P4EST_ASSERT (!pp->hollow); P4EST_ASSERT (pp->coarsen_delay >= 0); P4EST_ASSERT (pp->mesh != NULL); P4EST_ASSERT (pp->ghost != NULL); P4EST_ASSERT (pp->mesh_aux == NULL); P4EST_ASSERT (pp->ghost_aux == NULL); P4EST_ASSERT (pp->match_aux == 0); P4EST_ASSERT (pp->temp_flags == NULL); P4EST_ASSERT (pp->num_refine_flags >= 0 && pp->num_refine_flags <= p4est->local_num_quadrants); /* This allocation is optimistic when not all refine requests are honored */ pp->temp_flags = P4EST_ALLOC_ZERO (uint8_t, p4est->local_num_quadrants + (P4EST_CHILDREN - 1) * pp->num_refine_flags); /* Execute refinement */ pp->inside_counter = pp->num_replaced = 0; #ifdef P4EST_ENABLE_DEBUG local_num = p4est->local_num_quadrants; #endif global_num = p4est->global_num_quadrants; p4est_refine_ext (p4est, 0, -1, refine_callback, NULL, replace_on_refine); P4EST_ASSERT (pp->inside_counter == local_num); P4EST_ASSERT (p4est->local_num_quadrants - local_num == pp->num_replaced * (P4EST_CHILDREN - 1)); changed = global_num != p4est->global_num_quadrants; /* Execute coarsening */ pp->inside_counter = pp->num_replaced = 0; #ifdef P4EST_ENABLE_DEBUG local_num = p4est->local_num_quadrants; #endif global_num = p4est->global_num_quadrants; p4est_coarsen_ext (p4est, 0, 1, coarsen_callback, NULL, pp->coarsen_delay ? replace_on_coarsen : pp->replace_fn); P4EST_ASSERT (pp->inside_counter == local_num); P4EST_ASSERT (local_num - p4est->local_num_quadrants == pp->num_replaced * (P4EST_CHILDREN - 1)); changed = changed || global_num != p4est->global_num_quadrants; /* Free temporary flags */ P4EST_FREE (pp->temp_flags); pp->temp_flags = NULL; /* Only if refinement and/or coarsening happened do we need to balance */ if (changed) { P4EST_FREE (pp->flags); p4est_balance_ext (p4est, pp->btype, NULL, pp->coarsen_delay ? replace_on_balance : pp->replace_fn); pp->flags = P4EST_ALLOC_ZERO (uint8_t, p4est->local_num_quadrants); pp->ghost_aux = p4est_ghost_new (p4est, pp->btype); pp->mesh_aux = p4est_mesh_new_ext (p4est, pp->ghost_aux, 1, 1, pp->btype); pp->match_aux = 1; } #ifdef P4EST_ENABLE_DEBUG else { for (jl = 0; jl < p4est->local_num_quadrants; ++jl) { P4EST_ASSERT (pp->flags[jl] == 0); } } #endif pp->num_refine_flags = 0; return changed; }
static void p4est_check_local_order (p4est_t * p4est, p4est_connectivity_t * connectivity) { const double intsize = 1.0 / P4EST_ROOT_LEN; double *vertices; double h, eta1, eta2; double v0x, v0y, v0z, v1x, v1y, v1z; double v2x, v2y, v2z, v3x, v3y, v3z; double w0x, w0y, w0z, w1x, w1y, w1z; double w2x, w2y, w2z, w3x, w3y, w3z; size_t iz; size_t num_quads; size_t quad_count; p4est_topidx_t jt; p4est_topidx_t *tree_to_vertex; p4est_topidx_t first_local_tree; p4est_topidx_t last_local_tree; p4est_topidx_t v0, v1, v2, v3; p4est_locidx_t kl; p4est_locidx_t lv0, lv1, lv2, lv3; p4est_locidx_t num_uniq_local_vertices; p4est_locidx_t *quadrant_to_local_vertex; p4est_qcoord_t inth; p4est_tree_t *tree; p4est_quadrant_t *quad; p4est_vert_t *vert_locations; p4est_nodes_t *nodes; sc_array_t *trees; sc_array_t *quadrants; nodes = p4est_nodes_new (p4est, NULL); quadrant_to_local_vertex = nodes->local_nodes; num_uniq_local_vertices = nodes->num_owned_indeps; SC_CHECK_ABORT ((size_t) num_uniq_local_vertices == nodes->indep_nodes.elem_count, "Node count mismatch"); P4EST_INFOF ("Unique local vertices %lld\n", (long long) num_uniq_local_vertices); vert_locations = P4EST_ALLOC (p4est_vert_t, num_uniq_local_vertices); for (kl = 0; kl < num_uniq_local_vertices; ++kl) { vert_locations[kl].treeid = -1; } tree_to_vertex = connectivity->tree_to_vertex; vertices = connectivity->vertices; first_local_tree = p4est->first_local_tree; last_local_tree = p4est->last_local_tree; trees = p4est->trees; for (jt = first_local_tree, quad_count = 0; jt <= last_local_tree; ++jt) { tree = p4est_tree_array_index (trees, jt); P4EST_ASSERT (0 <= jt && jt < connectivity->num_trees); v0 = tree_to_vertex[jt * 4 + 0]; v1 = tree_to_vertex[jt * 4 + 1]; v2 = tree_to_vertex[jt * 4 + 2]; v3 = tree_to_vertex[jt * 4 + 3]; P4EST_ASSERT (0 <= v0 && v0 < connectivity->num_vertices); P4EST_ASSERT (0 <= v1 && v1 < connectivity->num_vertices); P4EST_ASSERT (0 <= v2 && v2 < connectivity->num_vertices); P4EST_ASSERT (0 <= v3 && v3 < connectivity->num_vertices); v0x = vertices[v0 * 3 + 0]; v0y = vertices[v0 * 3 + 1]; v0z = vertices[v0 * 3 + 2]; v1x = vertices[v1 * 3 + 0]; v1y = vertices[v1 * 3 + 1]; v1z = vertices[v1 * 3 + 2]; v2x = vertices[v2 * 3 + 0]; v2y = vertices[v2 * 3 + 1]; v2z = vertices[v2 * 3 + 2]; v3x = vertices[v3 * 3 + 0]; v3y = vertices[v3 * 3 + 1]; v3z = vertices[v3 * 3 + 2]; quadrants = &tree->quadrants; num_quads = quadrants->elem_count; /* loop over the elements in the tree */ for (iz = 0; iz < num_quads; ++iz, ++quad_count) { quad = p4est_quadrant_array_index (quadrants, iz); inth = P4EST_QUADRANT_LEN (quad->level); h = intsize * inth; eta1 = intsize * quad->x; eta2 = intsize * quad->y; w0x = v0x * (1.0 - eta1) * (1.0 - eta2) + v1x * (eta1) * (1.0 - eta2) + v2x * (1.0 - eta1) * (eta2) + v3x * (eta1) * (eta2); w0y = v0y * (1.0 - eta1) * (1.0 - eta2) + v1y * (eta1) * (1.0 - eta2) + v2y * (1.0 - eta1) * (eta2) + v3y * (eta1) * (eta2); w0z = v0z * (1.0 - eta1) * (1.0 - eta2) + v1z * (eta1) * (1.0 - eta2) + v2z * (1.0 - eta1) * (eta2) + v3z * (eta1) * (eta2); w1x = v0x * (1.0 - eta1 - h) * (1.0 - eta2) + v1x * (eta1 + h) * (1.0 - eta2) + v2x * (1.0 - eta1 - h) * (eta2) + v3x * (eta1 + h) * (eta2); w1y = v0y * (1.0 - eta1 - h) * (1.0 - eta2) + v1y * (eta1 + h) * (1.0 - eta2) + v2y * (1.0 - eta1 - h) * (eta2) + v3y * (eta1 + h) * (eta2); w1z = v0z * (1.0 - eta1 - h) * (1.0 - eta2) + v1z * (eta1 + h) * (1.0 - eta2) + v2z * (1.0 - eta1 - h) * (eta2) + v3z * (eta1 + h) * (eta2); w2x = v0x * (1.0 - eta1) * (1.0 - eta2 - h) + v1x * (eta1) * (1.0 - eta2 - h) + v2x * (1.0 - eta1) * (eta2 + h) + v3x * (eta1) * (eta2 + h); w2y = v0y * (1.0 - eta1) * (1.0 - eta2 - h) + v1y * (eta1) * (1.0 - eta2 - h) + v2y * (1.0 - eta1) * (eta2 + h) + v3y * (eta1) * (eta2 + h); w2z = v0z * (1.0 - eta1) * (1.0 - eta2 - h) + v1z * (eta1) * (1.0 - eta2 - h) + v2z * (1.0 - eta1) * (eta2 + h) + v3z * (eta1) * (eta2 + h); w3x = v0x * (1.0 - eta1 - h) * (1.0 - eta2 - h) + v1x * (eta1 + h) * (1.0 - eta2 - h) + v2x * (1.0 - eta1 - h) * (eta2 + h) + v3x * (eta1 + h) * (eta2 + h); w3y = v0y * (1.0 - eta1 - h) * (1.0 - eta2 - h) + v1y * (eta1 + h) * (1.0 - eta2 - h) + v2y * (1.0 - eta1 - h) * (eta2 + h) + v3y * (eta1 + h) * (eta2 + h); w3z = v0z * (1.0 - eta1 - h) * (1.0 - eta2 - h) + v1z * (eta1 + h) * (1.0 - eta2 - h) + v2z * (1.0 - eta1 - h) * (eta2 + h) + v3z * (eta1 + h) * (eta2 + h); P4EST_ASSERT ((p4est_locidx_t) quad_count < p4est->local_num_quadrants); lv0 = quadrant_to_local_vertex[4 * quad_count + 0]; lv1 = quadrant_to_local_vertex[4 * quad_count + 1]; lv2 = quadrant_to_local_vertex[4 * quad_count + 2]; lv3 = quadrant_to_local_vertex[4 * quad_count + 3]; P4EST_ASSERT (0 <= lv0 && lv0 < num_uniq_local_vertices); P4EST_ASSERT (0 <= lv1 && lv1 < num_uniq_local_vertices); P4EST_ASSERT (0 <= lv2 && lv2 < num_uniq_local_vertices); P4EST_ASSERT (0 <= lv3 && lv3 < num_uniq_local_vertices); vert_locations[lv0].x = w0x; vert_locations[lv0].y = w0y; vert_locations[lv0].z = w0z; P4EST_ASSERT (vert_locations[lv0].treeid == -1 || vert_locations[lv0].treeid == jt); vert_locations[lv0].treeid = jt; vert_locations[lv1].x = w1x; vert_locations[lv1].y = w1y; vert_locations[lv1].z = w1z; P4EST_ASSERT (vert_locations[lv1].treeid == -1 || vert_locations[lv1].treeid == jt); vert_locations[lv1].treeid = jt; vert_locations[lv2].x = w2x; vert_locations[lv2].y = w2y; vert_locations[lv2].z = w2z; P4EST_ASSERT (vert_locations[lv2].treeid == -1 || vert_locations[lv2].treeid == jt); vert_locations[lv2].treeid = jt; vert_locations[lv3].x = w3x; vert_locations[lv3].y = w3y; vert_locations[lv3].z = w3z; P4EST_ASSERT (vert_locations[lv3].treeid == -1 || vert_locations[lv3].treeid == jt); vert_locations[lv3].treeid = jt; } } qsort (vert_locations, num_uniq_local_vertices, sizeof (p4est_vert_t), p4est_vert_compare); /* Check to make sure that we don't have any duplicates in the list */ for (kl = 0; kl < num_uniq_local_vertices - 1; ++kl) { SC_CHECK_ABORT (p4est_vert_compare (vert_locations + kl, vert_locations + kl + 1) != 0, "local ordering not unique"); } P4EST_FREE (vert_locations); p4est_nodes_destroy (nodes); }
int p4est_wrap_partition (p4est_wrap_t * pp, int weight_exponent, p4est_locidx_t * unchanged_first, p4est_locidx_t * unchanged_length, p4est_locidx_t * unchanged_old_first) { int changed; p4est_gloidx_t pre_me, pre_next; p4est_gloidx_t post_me, post_next; P4EST_ASSERT (!pp->hollow); P4EST_ASSERT (pp->ghost != NULL); P4EST_ASSERT (pp->mesh != NULL); P4EST_ASSERT (pp->ghost_aux != NULL); P4EST_ASSERT (pp->mesh_aux != NULL); P4EST_ASSERT (pp->match_aux == 1); p4est_mesh_destroy (pp->mesh); p4est_ghost_destroy (pp->ghost); pp->match_aux = 0; /* Remember the window onto global quadrant sequence before partition */ pre_me = pp->p4est->global_first_quadrant[pp->p4est->mpirank]; pre_next = pp->p4est->global_first_quadrant[pp->p4est->mpirank + 1]; /* Initialize output for the case that the partition does not change */ if (unchanged_first != NULL) { *unchanged_first = 0; } if (unchanged_length != NULL) { *unchanged_length = pp->p4est->local_num_quadrants; } if (unchanged_old_first != NULL) { *unchanged_old_first = 0; } /* In the future the flags could be used to pass partition weights */ /* We need to lift the restriction on 64 bits for the global weight sum */ P4EST_ASSERT (weight_exponent == 0 || weight_exponent == 1); pp->weight_exponent = weight_exponent; changed = p4est_partition_ext (pp->p4est, 1, weight_exponent ? partition_weight : NULL) > 0; if (changed) { P4EST_FREE (pp->flags); pp->flags = P4EST_ALLOC_ZERO (uint8_t, pp->p4est->local_num_quadrants); pp->ghost = p4est_ghost_new (pp->p4est, pp->btype); pp->mesh = p4est_mesh_new_ext (pp->p4est, pp->ghost, 1, 1, pp->btype); /* Query the window onto global quadrant sequence after partition */ if (unchanged_first != NULL || unchanged_length != NULL || unchanged_old_first != NULL) { /* compute new windof of local quadrants */ post_me = pp->p4est->global_first_quadrant[pp->p4est->mpirank]; post_next = pp->p4est->global_first_quadrant[pp->p4est->mpirank + 1]; /* compute the range of quadrants that have stayed on this processor */ p4est_wrap_partition_unchanged (pre_me, pre_next, post_me, post_next, unchanged_first, unchanged_length, unchanged_old_first); } } else { memset (pp->flags, 0, sizeof (uint8_t) * pp->p4est->local_num_quadrants); pp->ghost = pp->ghost_aux; pp->mesh = pp->mesh_aux; pp->ghost_aux = NULL; pp->mesh_aux = NULL; } return changed; }
void p6est_vtk_write_all (p6est_t * p6est, double scale, int write_tree, int write_rank, int wrap_rank, int num_scalars, int num_vectors, const char *filename, ...) { int retval; int i, all; int scalar_strlen, vector_strlen; char point_scalars[BUFSIZ], point_vectors[BUFSIZ]; const char *name, **names; double **values; va_list ap; P4EST_ASSERT (num_scalars >= 0 && num_vectors >= 0); values = P4EST_ALLOC (double *, num_scalars + num_vectors); names = P4EST_ALLOC (const char *, num_scalars + num_vectors); va_start (ap, filename); all = 0; scalar_strlen = 0; point_scalars[0] = '\0'; for (i = 0; i < num_scalars; ++all, ++i) { name = names[all] = va_arg (ap, const char *); retval = snprintf (point_scalars + scalar_strlen, BUFSIZ - scalar_strlen, "%s%s", i == 0 ? "" : ",", name); SC_CHECK_ABORT (retval > 0, "p6est_vtk: Error collecting point scalars"); scalar_strlen += retval; values[all] = va_arg (ap, double *); } vector_strlen = 0; point_vectors[0] = '\0'; for (i = 0; i < num_vectors; ++all, ++i) { name = names[all] = va_arg (ap, const char *); retval = snprintf (point_vectors + vector_strlen, BUFSIZ - vector_strlen, "%s%s", i == 0 ? "" : ",", name); SC_CHECK_ABORT (retval > 0, "p6est_vtk: Error collecting point vectors"); vector_strlen += retval; values[all] = va_arg (ap, double *); } va_end (ap); retval = p6est_vtk_write_header (p6est, scale, write_tree, write_rank, wrap_rank, num_scalars > 0 ? point_scalars : NULL, num_vectors > 0 ? point_vectors : NULL, filename); SC_CHECK_ABORT (!retval, "p6est_vtk: Error writing header"); all = 0; for (i = 0; i < num_scalars; ++all, ++i) { retval = p6est_vtk_write_point_scalar (p6est, filename, names[all], values[all]); SC_CHECK_ABORT (!retval, "p6est_vtk: Error writing point scalars"); } for (i = 0; i < num_vectors; ++all, ++i) { retval = p6est_vtk_write_point_vector (p6est, filename, names[all], values[all]); SC_CHECK_ABORT (!retval, "p6est_vtk: Error writing point vectors"); } retval = p6est_vtk_write_footer (p6est, filename); SC_CHECK_ABORT (!retval, "p6est_vtk: Error writing footer"); P4EST_FREE (values); P4EST_FREE (names); }
static p4est_wrap_leaf_t * p4est_wrap_leaf_info (p4est_wrap_leaf_t * leaf) { #ifdef P4EST_ENABLE_DEBUG p4est_t *p4est = leaf->pp->p4est; #endif #if 0 p4est_quadrant_t corner; #endif p4est_quadrant_t *mirror; /* complete information on current quadrant */ leaf->local_quad = leaf->tree->quadrants_offset + leaf->which_quad; leaf->quad = p4est_quadrant_array_index (leaf->tquadrants, leaf->which_quad); #if 0 p4est_qcoord_to_vertex (leaf->pp->conn, leaf->which_tree, leaf->quad->x, leaf->quad->y, #ifdef P4_TO_P8 leaf->quad->z, #endif leaf->lowerleft); p4est_quadrant_corner_node (leaf->quad, P4EST_CHILDREN - 1, &corner); p4est_qcoord_to_vertex (leaf->pp->conn, leaf->which_tree, corner.x, corner.y, #ifdef P4_TO_P8 corner.z, #endif leaf->upperright); #endif #if 0 #ifdef P4EST_ENABLE_DEBUG printf ("C: Leaf level %d tree %d tree_leaf %d local_leaf %d\n", (int) leaf->quad->level, leaf->which_tree, leaf->which_quad, leaf->local_quad); #endif #endif /* track parallel mirror quadrants */ if (leaf->mirrors != NULL) { if (leaf->local_quad == leaf->next_mirror_quadrant) { if (++leaf->nm + 1 < (p4est_locidx_t) leaf->mirrors->elem_count) { mirror = p4est_quadrant_array_index (leaf->mirrors, leaf->nm + 1); leaf->next_mirror_quadrant = mirror->p.piggy3.local_num; P4EST_ASSERT (leaf->next_mirror_quadrant > leaf->local_quad); P4EST_ASSERT (leaf->next_mirror_quadrant < p4est->local_num_quadrants); } else { leaf->next_mirror_quadrant = -1; } leaf->is_mirror = 1; } else { leaf->is_mirror = 0; } } return leaf; }
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; }
trilinear_mesh_t * p8est_trilinear_mesh_new_from_nodes (p4est_t * p4est, p4est_nodes_t * nodes) { const int num_procs = p4est->mpisize; const int rank = p4est->mpirank; int mpiret; int k, owner; #ifdef P4EST_DEBUG int prev_owner = 0; int64_t prev_fvnid = -1; #endif int *sharers; size_t current, zz, num_sharers; int32_t e, n, local_owned_end; int64_t global_borrowed, global_shared; int64_t local_counts[5], global_counts[5]; int32link_t *lynk, **tail; p4est_topidx_t which_tree; p4est_locidx_t *local_node, *shared_offsets; p4est_tree_t *tree; p4est_quadrant_t *q; p4est_indep_t *in; p8est_hang4_t *fh; p8est_hang2_t *eh; trilinear_elem_t *elem; trilinear_anode_t *anode; trilinear_dnode_t *dnode; trilinear_mesh_t *mesh; trilinear_mesh_pid_t *elem_pids; trilinear_mesh_pid_t *node_pids; sc_recycle_array_t *rarr; P4EST_GLOBAL_PRODUCTIONF ("Into trilinear_mesh_extract with %lld total elements\n", (long long) p4est->global_num_quadrants); /* Allocate output data structure. */ mesh = P4EST_ALLOC_ZERO (trilinear_mesh_t, 1); memset (mesh, -1, sizeof (*mesh)); shared_offsets = nodes->shared_offsets; /* Assign local counts. */ P4EST_ASSERT (nodes->num_local_quadrants == p4est->local_num_quadrants); mesh->local_elem_num = p4est->local_num_quadrants; mesh->local_anode_num = nodes->indep_nodes.elem_count; mesh->local_dnode_num = nodes->face_hangings.elem_count + nodes->edge_hangings.elem_count; mesh->local_onode_num = nodes->num_owned_indeps; mesh->local_owned_offset = nodes->offset_owned_indeps; mesh->local_node_num = mesh->local_anode_num + mesh->local_dnode_num; local_owned_end = mesh->local_owned_offset + mesh->local_onode_num; /* Communicate global counts. */ local_counts[0] = mesh->local_elem_num; local_counts[1] = mesh->local_anode_num; local_counts[2] = mesh->local_onode_num; local_counts[3] = mesh->local_dnode_num; local_counts[4] = nodes->num_owned_shared; mpiret = MPI_Allreduce (local_counts, global_counts, 5, MPI_LONG_LONG_INT, MPI_SUM, p4est->mpicomm); SC_CHECK_MPI (mpiret); P4EST_ASSERT (global_counts[0] == p4est->global_num_quadrants); mesh->total_elem_num = global_counts[0]; global_borrowed = global_counts[1] - global_counts[2]; mesh->total_anode_num = global_counts[2]; mesh->total_dnode_num = global_counts[3]; global_shared = global_counts[4]; mesh->total_node_num = mesh->total_anode_num + mesh->total_dnode_num; /* Allocate the mesh memory. */ mesh->elem_table = P4EST_ALLOC (trilinear_elem_t, mesh->local_elem_num); mesh->node_table = P4EST_ALLOC (trilinear_node_t, mesh->local_node_num); mesh->fvnid_count_table = P4EST_ALLOC (int64_t, num_procs + 1); mesh->fvnid_interval_table = P4EST_ALLOC (int64_t, num_procs + 1); mesh->all_fvnid_start = mesh->fvnid_interval_table; mesh->sharer_pool = sc_mempool_new (sizeof (int32link_t)); mesh->elem_pids = P4EST_ALLOC (trilinear_mesh_pid_t, mesh->local_node_num); mesh->node_pids = P4EST_ALLOC (trilinear_mesh_pid_t, mesh->local_node_num); /* Assign global free variable information. */ mesh->fvnid_interval_table[0] = 0; for (k = 0; k < num_procs; ++k) { mesh->fvnid_interval_table[k + 1] = mesh->fvnid_interval_table[k] + (mesh->fvnid_count_table[k] = nodes->global_owned_indeps[k]); } mesh->fvnid_count_table[num_procs] = -1; mesh->global_fvnid_num = mesh->fvnid_interval_table[num_procs]; mesh->global_fvnid_start = 0; mesh->global_fvnid_end = mesh->global_fvnid_num - 1; P4EST_ASSERT (mesh->global_fvnid_num == mesh->total_anode_num); /* Assign element information. */ local_node = nodes->local_nodes; which_tree = p4est->first_local_tree; elem_pids = mesh->elem_pids; if (which_tree >= 0) { tree = p4est_tree_array_index (p4est->trees, which_tree); current = 0; for (e = 0; e < mesh->local_elem_num; ++e) { if (current == tree->quadrants.elem_count) { ++which_tree; tree = p4est_tree_array_index (p4est->trees, which_tree); current = 0; } q = p4est_quadrant_array_index (&tree->quadrants, current); elem = mesh->elem_table + e; for (k = 0; k < P4EST_CHILDREN; ++k) { elem->local_node_id[k] = *local_node++; } elem->lx = (tick_t) q->x; elem->ly = (tick_t) q->y; elem->lz = (tick_t) q->z; elem->size = P4EST_QUADRANT_LEN (q->level); elem->data = q->p.user_data; elem_pids[e] = (trilinear_mesh_pid_t) which_tree; ++current; } P4EST_ASSERT (which_tree == p4est->last_local_tree); P4EST_ASSERT (current == tree->quadrants.elem_count); } /* Assign anchored node information. */ mesh->anode_table = mesh->node_table; mesh->onode_table = mesh->node_table + mesh->local_owned_offset; mesh->dnode_table = mesh->node_table + mesh->local_anode_num; node_pids = mesh->node_pids; for (n = 0; n < mesh->local_anode_num; ++n) { anode = &mesh->node_table[n].anchored; in = (p4est_indep_t *) sc_array_index (&nodes->indep_nodes, (size_t) n); anode->point.x = in->x; anode->point.y = in->y; anode->point.z = in->z; node_pids[n] = (trilinear_mesh_pid_t) in->p.piggy3.which_tree; if (n < mesh->local_owned_offset) { owner = nodes->nonlocal_ranks[n]; P4EST_ASSERT (owner < rank && owner >= prev_owner); } else if (n >= local_owned_end) { owner = nodes->nonlocal_ranks[n - mesh->local_onode_num]; P4EST_ASSERT (owner > rank && owner >= prev_owner); } else { owner = rank; } anode->fvnid = mesh->all_fvnid_start[owner] + in->p.piggy3.local_num; P4EST_ASSERT (anode->fvnid > prev_fvnid); if (in->pad8 == 0) { P4EST_ASSERT (in->pad16 == -1); P4EST_ASSERT (shared_offsets == NULL || shared_offsets[n] == -1); anode->share = NULL; } else { P4EST_ASSERT (in->pad8 > 0); num_sharers = (size_t) in->pad8; rarr = (sc_recycle_array_t *) sc_array_index (&nodes->shared_indeps, num_sharers - 1); if (nodes->shared_offsets == NULL) { P4EST_ASSERT (in->pad16 >= 0); zz = (size_t) in->pad16; } else { P4EST_ASSERT (in->pad16 == -1); zz = (size_t) shared_offsets[n]; } sharers = (int *) sc_array_index (&rarr->a, zz); tail = &anode->share; for (zz = 0; zz < num_sharers; ++zz) { *tail = lynk = (int32link_t *) sc_mempool_alloc (mesh->sharer_pool); lynk->id = (int32_t) sharers[zz]; tail = &lynk->next; } *tail = NULL; } #ifdef P4EST_DEBUG prev_owner = owner; prev_fvnid = anode->fvnid; #endif } /* Assign face hanging node information. */ for (zz = 0; zz < nodes->face_hangings.elem_count; ++n, ++zz) { dnode = &mesh->node_table[n].dangling; fh = (p8est_hang4_t *) sc_array_index (&nodes->face_hangings, zz); dnode->point.x = fh->x; dnode->point.y = fh->y; dnode->point.z = fh->z; dnode->type = 0; /* Not used in Rhea. */ dnode->local_anode_id[0] = fh->p.piggy.depends[0]; dnode->local_anode_id[1] = fh->p.piggy.depends[1]; dnode->local_anode_id[2] = fh->p.piggy.depends[2]; dnode->local_anode_id[3] = fh->p.piggy.depends[3]; node_pids[n] = (trilinear_mesh_pid_t) fh->p.piggy.which_tree; } /* Assign edge hanging node information. */ for (zz = 0; zz < nodes->edge_hangings.elem_count; ++n, ++zz) { dnode = &mesh->node_table[n].dangling; eh = (p8est_hang2_t *) sc_array_index (&nodes->edge_hangings, zz); dnode->point.x = eh->x; dnode->point.y = eh->y; dnode->point.z = eh->z; dnode->type = 0; /* Not used in Rhea. */ dnode->local_anode_id[0] = eh->p.piggy.depends[0]; dnode->local_anode_id[1] = eh->p.piggy.depends[1]; dnode->local_anode_id[2] = dnode->local_anode_id[3] = -1; node_pids[n] = (trilinear_mesh_pid_t) eh->p.piggy.which_tree; } P4EST_ASSERT (n == mesh->local_node_num); /* Assign the remaining variables. */ mesh->mpicomm = p4est->mpicomm; mesh->mpisize = (int32_t) num_procs; mesh->mpirank = (int32_t) rank; mesh->recsize = (int32_t) p4est->data_size; mesh->destructor = p8est_trilinear_mesh_destroy; /* These members are incomplete and need to be filled later. */ memset (mesh->bounds, 0, 6 * sizeof (int)); memset (mesh->sizes, 0, 3 * sizeof (int)); mesh->minsize = mesh->maxsize = 0; mesh->ticksize = 0.; mesh->extra_info = NULL; mesh->gid = -1; /* We are done */ P4EST_GLOBAL_PRODUCTIONF ("Done trilinear_mesh_extract" " with %lld anodes %lld %lld\n", (long long) mesh->total_anode_num, (long long) global_borrowed, (long long) global_shared); return mesh; }
int main (int argc, char **argv) { sc_MPI_Comm mpicomm; int mpiret; int mpisize, mpirank; unsigned crc; #ifndef P4_TO_P8 size_t kz; int8_t l; p4est_quadrant_t *q; p4est_tree_t stree, *tree = &stree; #endif p4est_t *p4est; p4est_connectivity_t *connectivity; /* 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 connectivity = p4est_connectivity_new_star (); #else connectivity = p8est_connectivity_new_rotcubes (); #endif p4est = p4est_new_ext (mpicomm, connectivity, 0, 0, 0, 4, NULL, NULL); #ifndef P4_TO_P8 /* build empty tree */ sc_array_init (&tree->quadrants, sizeof (p4est_quadrant_t)); for (l = 0; l <= P4EST_MAXLEVEL; ++l) { tree->quadrants_per_level[l] = 0; } tree->maxlevel = 0; /* insert two quadrants */ sc_array_resize (&tree->quadrants, 4); q = p4est_quadrant_array_index (&tree->quadrants, 0); p4est_quadrant_set_morton (q, 3, 13); q = p4est_quadrant_array_index (&tree->quadrants, 1); p4est_quadrant_set_morton (q, 1, 1); q = p4est_quadrant_array_index (&tree->quadrants, 2); p4est_quadrant_set_morton (q, 1, 2); q = p4est_quadrant_array_index (&tree->quadrants, 3); p4est_quadrant_set_morton (q, 1, 3); for (kz = 0; kz < tree->quadrants.elem_count; ++kz) { q = p4est_quadrant_array_index (&tree->quadrants, kz); q->p.user_data = sc_mempool_alloc (p4est->user_data_pool); ++tree->quadrants_per_level[q->level]; tree->maxlevel = (int8_t) SC_MAX (tree->maxlevel, q->level); } /* balance the tree, print and destroy */ #if 0 p4est_balance_subtree (p4est, P4EST_CONNECT_FULL, 0, NULL); p4est_tree_print (SC_LP_INFO, tree); #endif for (kz = 0; kz < tree->quadrants.elem_count; ++kz) { q = p4est_quadrant_array_index (&tree->quadrants, kz); sc_mempool_free (p4est->user_data_pool, q->p.user_data); } sc_array_reset (&tree->quadrants); #endif /* !P4_TO_P8 */ /* check reset data function */ p4est_reset_data (p4est, 0, init_fn, NULL); p4est_reset_data (p4est, 0, NULL, NULL); /* refine and balance the forest */ SC_CHECK_ABORT (p4est_is_balanced (p4est, P4EST_CONNECT_FULL), "Balance 1"); p4est_refine (p4est, 1, refine_fn, NULL); SC_CHECK_ABORT (!p4est_is_balanced (p4est, P4EST_CONNECT_FULL), "Balance 2"); p4est_balance (p4est, P4EST_CONNECT_FULL, NULL); SC_CHECK_ABORT (p4est_is_balanced (p4est, P4EST_CONNECT_FULL), "Balance 3"); /* check reset data function */ p4est_reset_data (p4est, 17, NULL, NULL); p4est_reset_data (p4est, 8, init_fn, NULL); /* checksum and partition */ crc = p4est_checksum (p4est); p4est_partition (p4est, 0, NULL); SC_CHECK_ABORT (p4est_checksum (p4est) == crc, "Partition"); SC_CHECK_ABORT (p4est_is_balanced (p4est, P4EST_CONNECT_FULL), "Balance 4"); /* check reset data function */ p4est_reset_data (p4est, 3, NULL, NULL); p4est_reset_data (p4est, 3, NULL, NULL); /* checksum and rebalance */ crc = p4est_checksum (p4est); p4est_balance (p4est, P4EST_CONNECT_FULL, NULL); SC_CHECK_ABORT (p4est_checksum (p4est) == crc, "Rebalance"); /* clean up and exit */ P4EST_ASSERT (p4est->user_data_pool->elem_count == (size_t) p4est->local_num_quadrants); p4est_destroy (p4est); p4est_connectivity_destroy (connectivity); 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 main (int argc, char **argv) { int my_face, target_face, orientation; int face_ref, face_perm; int low[2], high[2], swap; int i, reverse; int ft[9], gt[9]; int *my_axis = &ft[0]; int *target_axis = &ft[3]; int *edge_reverse = &ft[6]; sc_init (sc_MPI_COMM_NULL, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); for (my_face = 0; my_face < 2 * P4EST_DIM; ++my_face) { for (target_face = 0; target_face < 2 * P4EST_DIM; ++target_face) { for (orientation = 0; orientation < 4; ++orientation) { /* find if my edges 0 and 2 are parallel to the x, y, or z-axis */ my_axis[0] = p8est_face_edges[my_face][0] / 4; my_axis[1] = p8est_face_edges[my_face][2] / 4; target_axis[0] = target_axis[1] = -1; edge_reverse[0] = edge_reverse[1] = 0; /* find matching target vertices */ face_ref = p8est_face_permutation_refs[my_face][target_face]; face_perm = p8est_face_permutation_sets[face_ref][orientation]; low[0] = low[1] = p8est_face_corners[target_face][p8est_face_permutations[face_perm] [0]]; high[0] = p8est_face_corners[target_face][p8est_face_permutations[face_perm] [1]]; high[1] = p8est_face_corners[target_face][p8est_face_permutations[face_perm] [2]]; if (low[0] > high[0]) { swap = low[0]; low[0] = high[0]; high[0] = swap; edge_reverse[0] = 1; } if (low[1] > high[1]) { swap = low[1]; low[1] = high[1]; high[1] = swap; edge_reverse[1] = 1; } /* find matching target edges */ for (i = 0; i < 12; ++i) { if (low[0] == p8est_edge_corners[i][0] && high[0] == p8est_edge_corners[i][1]) { P4EST_ASSERT (target_axis[0] == -1); target_axis[0] = i / 4; #ifndef P4EST_ENABLE_DEBUG if (target_axis[1] >= 0) break; #endif } else if (low[1] == p8est_edge_corners[i][0] && high[1] == p8est_edge_corners[i][1]) { P4EST_ASSERT (target_axis[1] == -1); target_axis[1] = i / 4; #ifndef P4EST_ENABLE_DEBUG if (target_axis[0] >= 0) break; #endif } } /* find what axis is normal to the faces */ my_axis[2] = my_face / 2; target_axis[2] = target_face / 2; edge_reverse[2] = 2 * (my_face % 2) + target_face % 2; #ifdef P4EST_ENABLE_DEBUG for (i = 0; i < 3; ++i) { P4EST_ASSERT (0 <= my_axis[i] && my_axis[i] < 3); P4EST_ASSERT (0 <= target_axis[i] && target_axis[i] < 3); } P4EST_ASSERT (my_axis[0] != my_axis[1] && my_axis[0] != my_axis[2] && my_axis[1] != my_axis[2]); P4EST_ASSERT (target_axis[0] != target_axis[1] && target_axis[0] != target_axis[2] && target_axis[1] != target_axis[2]); #endif /* output the results */ P4EST_LDEBUGF ("Results for %d %d %d are %d %d %d %d %d %d %d %d %d\n", my_face, target_face, orientation, ft[0], ft[1], ft[2], ft[3], ft[4], ft[5], ft[6], ft[7], ft[8]); /* compute the transformation code in a faster way and compare */ gt[0] = my_face < 2 ? 1 : 0; gt[1] = my_face < 4 ? 2 : 1; gt[2] = my_face / 2; reverse = p8est_face_permutation_refs[0][my_face] ^ p8est_face_permutation_refs[0][target_face] ^ (orientation == 0 || orientation == 3); gt[3 + reverse] = target_face < 2 ? 1 : 0; gt[3 + !reverse] = target_face < 4 ? 2 : 1; gt[5] = target_face / 2; reverse = p8est_face_permutation_refs[my_face][target_face] == 1; gt[6 + reverse] = orientation % 2; gt[6 + !reverse] = orientation / 2; gt[8] = 2 * (my_face % 2) + target_face % 2; /* ensure that both computations yield the same result */ SC_CHECK_ABORT (!memcmp (ft, gt, 9 * sizeof (int)), "Mismatch"); } } } sc_finalize (); return 0; }
static void p6est_profile_element_to_node_col (p6est_profile_t * profile, p4est_locidx_t cid, p4est_locidx_t * offsets, p4est_locidx_t * e_to_n, p6est_lnodes_code_t * fc) { p4est_locidx_t (*lr)[2] = (p4est_locidx_t (*)[2]) profile->lnode_ranges; p4est_locidx_t nelem; p4est_locidx_t **elem_to_node; int i, j, k; p4est_locidx_t ll; sc_array_t elem, node; sc_array_t *lc = profile->lnode_columns; p4est_locidx_t ncid, nid; p4est_lnodes_code_t fc4 = profile->lnodes->face_code[cid]; p4est_locidx_t *en = profile->lnodes->element_nodes; int degree = profile->lnodes->degree; int Nrp = degree + 1; int Nfp = (degree + 1) * (degree + 1); P4EST_ASSERT (degree > 1); ncid = en[Nfp * cid + Nrp * (Nrp / 2) + (Nrp / 2)]; nelem = lr[ncid][1]; sc_array_init_view (&elem, lc, lr[ncid][0], nelem); elem_to_node = P4EST_ALLOC (p4est_locidx_t *, nelem); for (ll = 0; ll < nelem; ll++) { fc[ll] = (p6est_lnodes_code_t) fc4; } for (k = 0, j = 0; j < Nrp; j++) { for (i = 0; i < Nrp; i++, k++) { nid = en[Nfp * cid + k]; sc_array_init_view (&node, lc, lr[nid][0], lr[nid][1]); for (ll = 0; ll < nelem; ll++) { elem_to_node[ll] = e_to_n + (degree + 1) * (degree + 1) * (degree + 1) * ll + (degree + 1) * k; } if (!(i % degree) && !(j % degree)) { int c = 2 * (! !j) + (! !i); p6est_profile_element_to_node_single (&elem, &node, degree, offsets[nid], elem_to_node, fc, 4 + c); } else if ((i % degree) && (j % degree)) { p6est_profile_element_to_node_single (&elem, &elem, degree, offsets[nid], elem_to_node, NULL, -1); } else { int f = 2 * !(j % degree) + (i == degree || j == degree); p6est_profile_element_to_node_single (&elem, &node, degree, offsets[nid], elem_to_node, fc, f); } } } P4EST_FREE (elem_to_node); }