void sc_memory_check (int package) { sc_package_t *p; if (package == -1) { SC_CHECK_ABORT (default_rc_active == 0, "Leftover references (default)"); if (default_abort_mismatch) { SC_CHECK_ABORT (default_malloc_count == default_free_count, "Memory balance (default)"); } else if (default_malloc_count != default_free_count) { SC_GLOBAL_LERROR ("Memory balance (default)\n"); } } else { SC_ASSERT (sc_package_is_registered (package)); p = sc_packages + package; SC_CHECK_ABORTF (p->rc_active == 0, "Leftover references (%s)", p->name); if (p->abort_mismatch) { SC_CHECK_ABORTF (p->malloc_count == p->free_count, "Memory balance (%s)", p->name); } else if (p->malloc_count != p->free_count) { SC_GLOBAL_LERRORF ("Memory balance (%s)\n", p->name); } } }
static void test_reduce (p4est_connectivity_t * conn, const char *which) { SC_GLOBAL_INFOF ("Testing standard connectivity %s\n", which); SC_CHECK_ABORTF (p4est_connectivity_is_valid (conn), "Invalid connectivity %s before reduce", which); p4est_connectivity_reduce (conn); SC_CHECK_ABORTF (p4est_connectivity_is_valid (conn), "Invalid connectivity %s after reduce", which); SC_GLOBAL_INFOF ("Testing completion for reduced connectivity %s\n", which); p4est_connectivity_complete (conn); SC_CHECK_ABORTF (p4est_connectivity_is_valid (conn), "Invalid connectivity %s after completion", which); p4est_connectivity_destroy (conn); }
void * sc_calloc (int package, size_t nmemb, size_t size) { void *ret; int *malloc_count = sc_malloc_count (package); /* allocate memory */ #if defined SC_ENABLE_MEMALIGN ret = sc_malloc_aligned (SC_MEMALIGN_BYTES, nmemb * size); memset (ret, 0, nmemb * size); #else ret = calloc (nmemb, size); if (nmemb * size > 0) { SC_CHECK_ABORTF (ret != NULL, "Allocation (calloc size %lli)", (long long int) size); } #endif /* count the allocations */ #ifdef SC_ENABLE_PTHREAD sc_package_lock (package); #endif if (nmemb * size > 0) { ++*malloc_count; } else { *malloc_count += ((ret == NULL) ? 0 : 1); } #ifdef SC_ENABLE_PTHREAD sc_package_unlock (package); #endif return ret; }
void sc_package_unregister (int package_id) { #ifdef SC_ENABLE_PTHREAD int i; #endif sc_package_t *p; SC_CHECK_ABORT (sc_package_is_registered (package_id), "Package not registered"); sc_memory_check (package_id); p = sc_packages + package_id; p->is_registered = 0; p->log_handler = NULL; p->log_threshold = SC_LP_DEFAULT; p->malloc_count = p->free_count = 0; p->rc_active = 0; #ifdef SC_ENABLE_PTHREAD i = pthread_mutex_destroy (&p->mutex); SC_CHECK_ABORTF (i == 0, "Mutex destroy failed for package %s", p->name); #endif p->name = p->full = NULL; --sc_num_packages; }
static void test_complete (p4est_connectivity_t * conn, const char *which, int test_p4est) { SC_GLOBAL_INFOF ("Testing standard connectivity %s\n", which); SC_CHECK_ABORTF (p4est_connectivity_is_valid (conn), "Invalid connectivity %s before completion", which); if (0 && test_p4est) { test_the_p4est (conn, 3); } SC_GLOBAL_INFOF ("Testing completion for connectivity %s\n", which); p4est_connectivity_complete (conn); SC_CHECK_ABORTF (p4est_connectivity_is_valid (conn), "Invalid connectivity %s after completion", which); if (test_p4est) { test_the_p4est (conn, 3); } p4est_connectivity_destroy (conn); }
void sc_memory_check (int package) { sc_package_t *p; if (package == -1) SC_CHECK_ABORT (default_malloc_count == default_free_count, "Memory balance (default)"); else { SC_ASSERT (sc_package_is_registered (package)); p = sc_packages + package; SC_CHECK_ABORTF (p->malloc_count == p->free_count, "Memory balance (%s)", p->name); } }
int sc_package_register (sc_log_handler_t log_handler, int log_threshold, const char *name, const char *full) { int i; sc_package_t *p; SC_CHECK_ABORT (sc_num_packages < SC_MAX_PACKAGES, "Too many packages"); SC_CHECK_ABORT (log_threshold == SC_LP_DEFAULT || (log_threshold >= SC_LP_ALWAYS && log_threshold <= SC_LP_SILENT), "Invalid package log threshold"); SC_CHECK_ABORT (strcmp (name, "default"), "Package default forbidden"); SC_CHECK_ABORT (strchr (name, ' ') == NULL, "Packages name contains spaces"); /* sc_packages is static and thus initialized to all zeros */ for (i = 0; i < SC_MAX_PACKAGES; ++i) { p = sc_packages + i; SC_CHECK_ABORTF (!p->is_registered || strcmp (p->name, name), "Package %s is already registered", name); } for (i = 0; i < SC_MAX_PACKAGES; ++i) { p = sc_packages + i; if (!p->is_registered) { p->is_registered = 1; p->log_handler = log_handler; p->log_threshold = log_threshold; p->malloc_count = p->free_count = 0; p->name = name; p->full = full; break; } } SC_ASSERT (i < SC_MAX_PACKAGES); ++sc_num_packages; SC_ASSERT (sc_num_packages <= SC_MAX_PACKAGES); return i; }
void * sc_realloc (int package, void *ptr, size_t size) { if (ptr == NULL) { return sc_malloc (package, size); } else if (size == 0) { sc_free (package, ptr); return NULL; } else { void *ret; #if defined SC_ENABLE_MEMALIGN ret = sc_realloc_aligned (ptr, SC_MEMALIGN_BYTES, size); #else ret = realloc (ptr, size); SC_CHECK_ABORTF (ret != NULL, "Reallocation (realloc size %lli)", (long long int) size); #endif return ret; } }
int main (int argc, char **argv) { int mpiret; int mpirank, mpisize; int i, j; char cvalue, cresult; int ivalue, iresult; unsigned short usvalue, usresult; long lvalue, lresult; float fvalue[3], fresult[3], fexpect[3]; double dvalue, dresult; MPI_Comm mpicomm; mpiret = MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); mpicomm = MPI_COMM_WORLD; mpiret = MPI_Comm_size (mpicomm, &mpisize); SC_CHECK_MPI (mpiret); mpiret = MPI_Comm_rank (mpicomm, &mpirank); SC_CHECK_MPI (mpiret); sc_init (mpicomm, 1, 1, NULL, SC_LP_DEFAULT); /* test allreduce int max */ ivalue = mpirank; sc_allreduce (&ivalue, &iresult, 1, MPI_INT, MPI_MAX, mpicomm); SC_CHECK_ABORT (iresult == mpisize - 1, "Allreduce mismatch"); /* test reduce float max */ fvalue[0] = (float) mpirank; fexpect[0] = (float) (mpisize - 1); fvalue[1] = (float) (mpirank % 9 - 4); fexpect[1] = (float) (mpisize >= 9 ? 4 : (mpisize - 1) % 9 - 4); fvalue[2] = (float) (mpirank % 6); fexpect[2] = (float) (mpisize >= 6 ? 5 : (mpisize - 1) % 6); for (i = 0; i < mpisize; ++i) { sc_reduce (fvalue, fresult, 3, MPI_FLOAT, MPI_MAX, i, mpicomm); if (i == mpirank) { for (j = 0; j < 3; ++j) { SC_CHECK_ABORTF (fresult[j] == fexpect[j], /* ok */ "Reduce mismatch in %d", j); } } } /* test allreduce char min */ cvalue = (char) (mpirank % 127); sc_allreduce (&cvalue, &cresult, 1, MPI_CHAR, MPI_MIN, mpicomm); SC_CHECK_ABORT (cresult == 0, "Allreduce mismatch"); /* test reduce unsigned short min */ usvalue = (unsigned short) (mpirank % 32767); for (i = 0; i < mpisize; ++i) { sc_reduce (&usvalue, &usresult, 1, MPI_UNSIGNED_SHORT, MPI_MIN, i, mpicomm); if (i == mpirank) { SC_CHECK_ABORT (usresult == 0, "Reduce mismatch"); } } /* test allreduce long sum */ lvalue = (long) mpirank; sc_allreduce (&lvalue, &lresult, 1, MPI_LONG, MPI_SUM, mpicomm); SC_CHECK_ABORT (lresult == ((long) (mpisize - 1)) * mpisize / 2, "Allreduce mismatch"); /* test reduce double sum */ dvalue = (double) mpirank; for (i = 0; i < mpisize; ++i) { sc_reduce (&dvalue, &dresult, 1, MPI_DOUBLE, MPI_SUM, i, mpicomm); if (i == mpirank) { SC_CHECK_ABORT (dresult == ((double) (mpisize - 1)) * mpisize / 2., /* ok */ "Reduce mismatch"); } } sc_finalize (); mpiret = MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }
static void * sc_malloc_aligned (size_t alignment, size_t size) { /* minimum requirements on alignment */ SC_ASSERT (sizeof (char **) == sizeof (void *)); SC_ASSERT (sizeof (char **) >= sizeof (size_t)); SC_ASSERT (alignment > 0 && alignment % sizeof (void *) == 0); SC_ASSERT (alignment == SC_MEMALIGN_BYTES); #if defined SC_HAVE_ANY_MEMALIGN && defined SC_HAVE_POSIX_MEMALIGN { void *data = NULL; int err = posix_memalign (&data, alignment, size); SC_CHECK_ABORTF (err != ENOMEM, "Insufficient memory (malloc size %llu)", (long long unsigned) size); SC_CHECK_ABORTF (err != EINVAL, "Alignment %llu is not a power of two" "or not a multiple of sizeof (void *)", (long long unsigned) alignment); SC_CHECK_ABORTF (err == 0, "Return of %d from posix_memalign", err); return data; } #elif defined SC_HAVE_ANY_MEMALIGN && defined SC_HAVE_ALIGNED_ALLOC { void *data = aligned_alloc (alignment, size); SC_CHECK_ABORT (data != NULL || size == 0, "Returned NULL from aligned_alloc"); return data; } #else { #if 0 /* adapted from PetscMallocAlign */ int *datastart = malloc (size + 2 * alignment); int shift = ((uintptr_t) datastart) % alignment; shift = (2 * alignment - shift) / sizeof (int); datastart[shift - 1] = shift; datastart += shift; return (void *) datastart; #endif /* We pad to achieve alignment, then write the original pointer and data * size up front, then the real data shifted by at most alignment - 1 * bytes. This way there is always at least one stop byte at the end that * we can use for debugging. */ const ptrdiff_t extrasize = (const ptrdiff_t) (2 * sizeof (char **)); const ptrdiff_t signalign = (const ptrdiff_t) alignment; const size_t alloc_size = extrasize + size + alignment; char *alloc_ptr = (char *) malloc (alloc_size); char *ptr; ptrdiff_t shift, modu; SC_CHECK_ABORT (alloc_ptr != NULL, "Returned NULL from malloc"); /* compute shift to the right where we put the actual data */ modu = ((ptrdiff_t) alloc_ptr + extrasize) % signalign; shift = (signalign - modu) % signalign; SC_ASSERT (0 <= shift && shift < signalign); /* make sure the resulting pointer is fine */ ptr = alloc_ptr + (extrasize + shift); SC_ASSERT ((ptrdiff_t) ptr % signalign == 0); /* memorize the original pointer that we got from malloc and fill up */ SC_ARG_ALIGN (ptr, char *, SC_MEMALIGN_BYTES); /* remember parameters of allocation for later use */ ((char **) ptr)[-1] = alloc_ptr; ((char **) ptr)[-2] = (char *) size; #ifdef SC_ENABLE_DEBUG memset (alloc_ptr, -2, shift); SC_ASSERT (ptr + ((ptrdiff_t) size + signalign - shift) == alloc_ptr + alloc_size); memset (ptr + size, -2, signalign - shift); #endif /* and we are done */ return (void *) ptr; } #endif }
int sc_package_register (sc_log_handler_t log_handler, int log_threshold, const char *name, const char *full) { int i; sc_package_t *p; sc_package_t *new_package = NULL; int new_package_id = -1; SC_CHECK_ABORT (log_threshold == SC_LP_DEFAULT || (log_threshold >= SC_LP_ALWAYS && log_threshold <= SC_LP_SILENT), "Invalid package log threshold"); SC_CHECK_ABORT (strcmp (name, "default"), "Package default forbidden"); SC_CHECK_ABORT (strchr (name, ' ') == NULL, "Packages name contains spaces"); /* sc_packages is static and thus initialized to all zeros */ for (i = 0; i < sc_num_packages_alloc; ++i) { p = sc_packages + i; SC_CHECK_ABORTF (!p->is_registered || strcmp (p->name, name), "Package %s is already registered", name); } /* Try to find unused space in sc_packages */ for (i = 0; i < sc_num_packages_alloc; ++i) { p = sc_packages + i; if (!p->is_registered) { new_package = p; new_package_id = i; break; } } /* realloc if the space in sc_packages is used up */ if (i == sc_num_packages_alloc) { sc_packages = (sc_package_t *) realloc (sc_packages, (2 * sc_num_packages_alloc + 1) * sizeof (sc_package_t)); SC_CHECK_ABORT (sc_packages, "Failed to allocate memory"); new_package = sc_packages + i; new_package_id = i; sc_num_packages_alloc = 2 * sc_num_packages_alloc + 1; /* initialize new packages */ for (; i < sc_num_packages_alloc; i++) { p = sc_packages + i; p->is_registered = 0; p->log_handler = NULL; p->log_threshold = SC_LP_SILENT; p->log_indent = 0; p->malloc_count = 0; p->free_count = 0; p->rc_active = 0; p->name = NULL; p->full = NULL; } } new_package->is_registered = 1; new_package->log_handler = log_handler; new_package->log_threshold = log_threshold; new_package->log_indent = 0; new_package->malloc_count = 0; new_package->free_count = 0; new_package->rc_active = 0; new_package->abort_mismatch = 1; new_package->name = name; new_package->full = full; #ifdef SC_ENABLE_PTHREAD i = pthread_mutex_init (&new_package->mutex, NULL); SC_CHECK_ABORTF (i == 0, "Mutex init failed for package %s", name); #endif ++sc_num_packages; SC_ASSERT (sc_num_packages <= sc_num_packages_alloc); SC_ASSERT (0 <= new_package_id && new_package_id < sc_num_packages); return new_package_id; }
static void test_periodic (p8est_connectivity_t * conn) { int i; int iface, nface; int iedge, icorner; int ft[9]; size_t zz; p4est_topidx_t itree, ntree; 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; itree = 0; for (iface = 0; iface < 6; ++iface) { ntree = p8est_find_face_transform (conn, itree, iface, ft); nface = p8est_face_dual[iface]; SC_CHECK_ABORT (ntree == itree, "PF tree"); for (i = 0; i < 3; ++i) { SC_CHECK_ABORTF (ft[i] == ft[i + 3], "PF axis %d", i); } SC_CHECK_ABORT (ft[6] == 0 && ft[7] == 0, "PF reverse"); SC_CHECK_ABORT (ft[8] == 2 * (iface % 2) + nface % 2, "PF code"); } eta = &ei.edge_transforms; sc_array_init (eta, sizeof (p8est_edge_transform_t)); for (iedge = 0; iedge < 12; ++iedge) { p8est_find_edge_transform (conn, itree, iedge, &ei); SC_CHECK_ABORT ((int) ei.iedge == iedge, "PE ei"); SC_CHECK_ABORT (eta->elem_count == 1, "PE count"); for (zz = 0; zz < eta->elem_count; ++zz) { et = p8est_edge_array_index (eta, zz); SC_CHECK_ABORT (et->ntree == itree, "PE tree"); SC_CHECK_ABORT ((int) et->nedge + iedge == 8 * (iedge / 4) + 3, "PE edge"); SC_CHECK_ABORT (et->nflip == 0, "PE flip"); SC_CHECK_ABORT (et->corners == et->nedge % 4, "PE corners"); SC_CHECK_ABORT ((int) et->naxis[0] == iedge / 4 && et->naxis[1] < et->naxis[2] && et->naxis[0] + et->naxis[1] + et->naxis[2] == 3, "PE axis"); } } sc_array_reset (eta); cta = &ci.corner_transforms; sc_array_init (cta, sizeof (p8est_corner_transform_t)); for (icorner = 0; icorner < 8; ++icorner) { p8est_find_corner_transform (conn, itree, icorner, &ci); SC_CHECK_ABORT ((int) ci.icorner == icorner, "PC ci"); SC_CHECK_ABORT (cta->elem_count == 1, "PC count"); for (zz = 0; zz < cta->elem_count; ++zz) { ct = p8est_corner_array_index (cta, zz); SC_CHECK_ABORT (ct->ntree == itree, "PC tree"); SC_CHECK_ABORT (ct->ncorner + icorner == 7, "PC corner"); } } sc_array_reset (cta); }
static void test_rotwrap (p8est_connectivity_t * conn) { int i; int iface, nface; int iedge, icorner; int ft[9]; size_t zz; p4est_topidx_t itree, ntree; 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; itree = 0; for (iface = 0; iface < 6; ++iface) { ntree = p8est_find_face_transform (conn, itree, iface, ft); if (iface == 2 || iface == 3) { SC_CHECK_ABORT (ntree == -1, "RF tree"); continue; } nface = p8est_face_dual[iface]; SC_CHECK_ABORT (ntree == itree, "RF tree"); if (iface == 0 || iface == 1) { for (i = 0; i < 3; ++i) { SC_CHECK_ABORTF (ft[i] == (i + 1) % 3, "RFA axis A%d", i); SC_CHECK_ABORTF (ft[i] == ft[i + 3], "RFA axis B%d", i); } SC_CHECK_ABORT (ft[6] == 0 && ft[7] == 0, "RFA reverse"); } else { for (i = 0; i < 3; ++i) { SC_CHECK_ABORTF (ft[i] == i, "RFB axis A%d", i); } SC_CHECK_ABORT (ft[0] == ft[4], "RFB axis B0"); SC_CHECK_ABORT (ft[1] == ft[3], "RFB axis B1"); SC_CHECK_ABORT (ft[2] == ft[5], "RFB axis B2"); SC_CHECK_ABORT (ft[6] == (iface != 4) && ft[7] == (iface != 5), "RFB reverse"); } SC_CHECK_ABORT (ft[8] == 2 * (iface % 2) + nface % 2, "RF code"); } eta = &ei.edge_transforms; sc_array_init (eta, sizeof (p8est_edge_transform_t)); for (iedge = 0; iedge < 12; ++iedge) { p8est_find_edge_transform (conn, itree, iedge, &ei); SC_CHECK_ABORT ((int) ei.iedge == iedge, "RE ei"); SC_CHECK_ABORT ((int) eta->elem_count == 2 - (iedge / 4), "RE count AB"); for (zz = 0; zz < eta->elem_count; ++zz) { et = p8est_edge_array_index (eta, zz); SC_CHECK_ABORT (et->ntree == itree, "RE tree"); SC_CHECK_ABORT ((int) et->nedge == rotwrap_edges[iedge][zz], "RE edge"); SC_CHECK_ABORT ((int) et->nflip == rotwrap_flip[iedge][zz], "RE flip"); SC_CHECK_ABORT (et->corners == et->nedge % 4, "RE corners"); SC_CHECK_ABORT ((int) et->naxis[0] == rotwrap_axes[iedge][zz] && et->naxis[1] < et->naxis[2] && et->naxis[0] + et->naxis[1] + et->naxis[2] == 3, "RE axis"); } } sc_array_reset (eta); cta = &ci.corner_transforms; sc_array_init (cta, sizeof (p8est_corner_transform_t)); for (icorner = 0; icorner < 8; ++icorner) { p8est_find_corner_transform (conn, itree, icorner, &ci); SC_CHECK_ABORT ((int) ci.icorner == icorner, "RC ci"); SC_CHECK_ABORT (cta->elem_count == 2, "RC count"); for (zz = 0; zz < cta->elem_count; ++zz) { ct = p8est_corner_array_index (cta, zz); SC_CHECK_ABORT (ct->ntree == itree, "RC tree"); SC_CHECK_ABORT ((int) ct->ncorner == rotwrap_corners[icorner][zz], "RC corner"); } } sc_array_reset (cta); }
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 } } }
static void test_tree (p8est_geometry_t * geom, p4est_topidx_t which_tree, const double bounds[6], int N) { const double epsilon = 1e-8; int i, j, k, l, m; double h[3]; double xyz[4][3], XYZ[4][3]; double Jgeom[3][3], Jdisc[3][3]; double detD, detJ, fd, fg; double diffD, diffJ, maxJ; for (l = 0; l < 3; ++l) { h[l] = bounds[2 * l + 1] - bounds[2 * l]; } for (i = 0; i < N; ++i) { xyz[3][2] = ((N - (i + .5)) * bounds[4] + (i + .5) * bounds[5]) / N; for (j = 0; j < N; ++j) { xyz[3][1] = ((N - (j + .5)) * bounds[2] + (j + .5) * bounds[3]) / N; for (k = 0; k < N; ++k) { xyz[3][0] = ((N - (k + .5)) * bounds[0] + (k + .5) * bounds[1]) / N; /* compute transformed point */ geom->X (geom, which_tree, xyz[3], XYZ[3]); /* offset point three times in the coordinate directions */ for (l = 0; l < 3; ++l) { /* l runs in domain */ memcpy (xyz[l], xyz[3], 3 * sizeof (double)); xyz[l][l] += epsilon * h[l]; geom->X (geom, which_tree, xyz[l], XYZ[l]); for (m = 0; m < 3; ++m) { /* m runs in image domain */ Jdisc[m][l] = (XYZ[l][m] - XYZ[3][m]) / (epsilon * h[l]); } } detJ = geom->J (geom, which_tree, xyz[3], Jgeom); detD = geom->D (geom, which_tree, xyz[3]); /* compare results */ diffD = fabs (detD - detJ) / SC_MAX (detD, detJ); SC_CHECK_ABORTF (diffD < 1e-8, "Determinant mismatch %lld %g %g %g", (long long) which_tree, xyz[3][0], xyz[3][1], xyz[3][2]); diffJ = maxJ = 0.; for (l = 0; l < 3; ++l) { for (m = 0; m < 3; ++m) { fd = fabs (Jdisc[m][l]); fg = fabs (Jgeom[m][l]); maxJ = SC_MAX (maxJ, fd); maxJ = SC_MAX (maxJ, fg); diffJ += fabs (Jdisc[m][l] - Jgeom[m][l]); } } diffJ /= 3 * 3 * maxJ; SC_CHECK_ABORTF (diffJ < 100. * epsilon, "Jacobian mismatch %lld %g %g %g", (long long) which_tree, xyz[3][0], xyz[3][1], xyz[3][2]); } } } }
int main (int argc, char **argv) { int mpiret, retval; int mpirank; const char *argbasename; char afilename[BUFSIZ]; p4est_topidx_t tnum_flips; p8est_tets_t *ptg; p8est_connectivity_t *connectivity; p8est_t *p8est; MPI_Comm mpicomm; mpiret = MPI_Init (&argc, &argv); SC_CHECK_MPI (mpiret); mpicomm = MPI_COMM_WORLD; mpiret = MPI_Comm_rank (mpicomm, &mpirank); sc_init (MPI_COMM_WORLD, 1, 1, NULL, SC_LP_DEFAULT); p4est_init (NULL, SC_LP_DEFAULT); if (argc != 2) { SC_GLOBAL_LERRORF ("Usage: %s <tetgen file base name>\n", argv[0]); sc_abort (); } argbasename = argv[1]; /* read tetgen nodes and tetrahedra from files */ ptg = p8est_tets_read (argbasename); SC_CHECK_ABORTF (ptg != NULL, "Failed to read tetgen %s", argbasename); P4EST_GLOBAL_STATISTICSF ("Read %d nodes and %d tets %s attributes\n", (int) ptg->nodes->elem_count / 3, (int) ptg->tets->elem_count / 4, ptg->tet_attributes != NULL ? "with" : "without"); /* flip orientation to right-handed */ tnum_flips = p8est_tets_make_righthanded (ptg); P4EST_GLOBAL_STATISTICSF ("Performed %ld orientation flip(s)\n", (long) tnum_flips); /* create a connectivity from the tet mesh and save it */ connectivity = p8est_connectivity_new_tets (ptg); if (mpirank == 0) { snprintf (afilename, BUFSIZ, "%s", "read_tetgen.p8c"); retval = p8est_connectivity_save (afilename, connectivity); SC_CHECK_ABORT (retval == 0, "Failed connectivity_save"); } /* create a forest and visualize */ p8est = p8est_new (mpicomm, connectivity, 0, NULL, NULL); snprintf (afilename, BUFSIZ, "%s", "read_tetgen"); p8est_vtk_write_file (p8est, NULL, afilename); /* clean up */ p8est_destroy (p8est); p8est_connectivity_destroy (connectivity); p8est_tets_destroy (ptg); sc_finalize (); mpiret = MPI_Finalize (); SC_CHECK_MPI (mpiret); return 0; }