#include <sc_functions.h>
#include <sc_notify.h>
#include <sc_options.h>
#ifndef P4_TO_P8
#define SPHERES_DIM_G "%g %g"
#else
#define SPHERES_DIM_G "%g %g %g"
#endif
#include "spheres_global.h"
#if 0
#define SPHERES_CHATTY
#endif
#define SPHERES_xstr(s) SPHERES_str(s)
#define SPHERES_str(s) #s
#define SPHERES_48() SPHERES_xstr(P4EST_CHILDREN)
typedef enum
{
SPHERES_TAG_SPHERES = P4EST_COMM_TAG_LAST,
SPHERES_TAG_FIXED,
SPHERES_TAG_CUSTOM
}
spheres_tags;
typedef enum
{
STATS_ONCE_FIRST = 0,
STATS_ONCE_WALL = STATS_ONCE_FIRST,
STATS_ONCE_NEW,
STATS_ONCE_GENERATE,
STATS_ONCE_LAST
}
stats_once_t;
static const char *once_names[] = { "Walltime", "New", "Generate" };
typedef enum
{
STATS_LOOP_FIRST = 0,
STATS_LOOP_PSEARCH = STATS_LOOP_FIRST,
STATS_LOOP_SEND,
STATS_LOOP_NOTIFY,
STATS_LOOP_RECEIVE,
STATS_LOOP_WAITSEND,
STATS_LOOP_LSEARCH,
STATS_LOOP_REFINE,
STATS_LOOP_PARTITION,
STATS_LOOP_TRANSFER,
STATS_LOOP_LAST
}
stats_loop_t;
static const char *loop_names[] = { "Psearch", "Send", "Notify",
"Receive", "Waitsend", "Lsearch", "Refine", "Partition", "Transfer"
};
static sc_statinfo_t *
once_index (spheres_global_t * g, stats_once_t once)
{
P4EST_ASSERT (0 <= once && once < STATS_ONCE_LAST);
return (sc_statinfo_t *) sc_array_index_int (g->stats, once);
}
static sc_statinfo_t *
loop_index (spheres_global_t * g, int lev, stats_loop_t loop)
{
P4EST_ASSERT (g->minlevel <= lev && lev < g->maxlevel);
P4EST_ASSERT (0 <= loop && loop < STATS_LOOP_LAST);
return (sc_statinfo_t *)
sc_array_index_int (g->stats, STATS_ONCE_LAST +
(lev - g->minlevel) * STATS_LOOP_LAST + loop);
}
static void
accumulate_once (spheres_global_t * g, stats_once_t once, double t)
{
sc_stats_accumulate (once_index (g, once), sc_MPI_Wtime () - t);
}
static void
accumulate_loop (spheres_global_t * g, int lev, stats_loop_t loop, double t)
{
sc_stats_accumulate (loop_index (g, lev, loop), sc_MPI_Wtime () - t);
}
static void
{
qu_data_t *qud = (qu_data_t *) quadrant->
p.
user_data;
qud->set_refine = 0;
}
static int
{
qu_data_t *qud = (qu_data_t *) quadrant->
p.
user_data;
int set_refine;
g->lsph_offset +=
(*(int *) sc_array_index_int (g->lcounts_refined, g->lqindex_refined) =
*(int *) sc_array_index_int (g->lcounts, g->lqindex));
++g->lqindex;
++g->lqindex_refined;
set_refine = qud->set_refine;
qud->set_refine = 0;
return set_refine;
}
#ifdef P4EST_ENABLE_DEBUG
static int
center_in_box (const p4est_sphere_t * box, const p4est_sphere_t * sph)
{
int i;
if (fabs (box->center[i] - sph->center[i]) > box->radius) {
return 0;
}
}
return 1;
}
#endif
static void
{
int c;
p4est_sphere_t *sph;
#ifdef P4EST_ENABLE_DEBUG
p4est_sphere_t box;
#endif
P4EST_ASSERT (num_outgoing == 1);
#ifdef P4EST_ENABLE_DEBUG
p4est_quadrant_sphere_box (outgoing[0], &box);
#endif
discr[0] = incoming[1]->
x * irootlen;
discr[1] = incoming[2]->
y * irootlen;
#ifdef P4_TO_P8
discr[2] = incoming[4]->z * irootlen;
#endif
P4EST_ASSERT (!((qu_data_t *) outgoing[0]->p.user_data)->set_refine);
sc_array_init (&neworder[c], sizeof (p4est_sphere_t));
P4EST_ASSERT (!((qu_data_t *) incoming[c]->p.user_data)->set_refine);
}
P4EST_ASSERT (g->lqindex >= 1);
P4EST_ASSERT (g->lqindex_refined >= 1);
outg_spheres = *(int *) sc_array_index (g->lcounts, g->lqindex - 1);
prev_spheres = g->lsph_offset - outg_spheres;
P4EST_ASSERT (0 <= prev_spheres && prev_spheres <= g->lsph);
for (li = 0; li < outg_spheres; ++li) {
sph = (p4est_sphere_t *) sc_array_index_int (g->sphr, prev_spheres + li);
P4EST_ASSERT (center_in_box (&box, sph));
c = 0;
c += (sph->center[0] > discr[0]);
c += (sph->center[1] > discr[1]) << 1;
#ifdef P4_TO_P8
c += (sph->center[2] > discr[2]) << 2;
#endif
*(p4est_sphere_t *) sc_array_push (&neworder[c]) = *sph;
}
li = prev_spheres;
sc_array_copy_into (g->sphr, li, &neworder[c]);
li += (*(int *) sc_array_index_int (g->lcounts_refined,
g->lqindex_refined - 1 + c) =
(int) neworder[c].elem_count);
sc_array_reset (&neworder[c]);
}
P4EST_ASSERT (li == g->lsph_offset);
}
static void
spheres_write_vtk (spheres_global_t * g, const char *str, int lev)
{
char filename[BUFSIZ];
sc_array_t *sdata;
P4EST_ASSERT (g->minlevel <= lev && lev <= g->maxlevel);
P4EST_ASSERT (g->lcounts != NULL);
if (!g->write_vtk) {
return;
}
cont = NULL;
sdata = NULL;
do {
snprintf (filename, BUFSIZ, "%s_sph_%d_%d_%s_%d",
g->prefix, g->minlevel, g->maxlevel, str, lev);
P4EST_LERRORF ("Failed to write header for %s\n", filename);
break;
}
sdata = sc_array_new_count
(sizeof (double), g->p4est->local_num_quadrants);
for (lall = 0, tt = g->p4est->first_local_tree;
tree = p4est_tree_array_index (g->p4est->trees, tt);
*(double *) sc_array_index_int (sdata, lall) =
*(int *) sc_array_index_int (g->lcounts, lall);
++lall;
}
}
P4EST_ASSERT (lall == g->p4est->local_num_quadrants);
#if 1
(cont, 1, 1, 1, g->mpiwrap, 1, 0, "spheres", sdata, cont)) {
P4EST_LERRORF ("Failed to write cell data for %s\n", filename);
break;
}
#endif
sc_array_destroy_null (&sdata);
P4EST_LERRORF ("Failed to write footer for %s\n", filename);
break;
}
}
while (0);
if (sdata != NULL) {
sc_array_destroy_null (&sdata);
}
}
static void
sphere_offsets (spheres_global_t * g)
{
int p;
int mpiret;
P4EST_ASSERT (g != NULL && g->goffsets != NULL);
P4EST_ASSERT (g->goffsets->elem_count == (size_t) (g->mpisize + 1));
P4EST_ASSERT (g->sphr->elem_count == (size_t) g->lsph);
mpiret = sc_MPI_Allgather (&lg, 1, P4EST_MPI_GLOIDX,
sc_array_index (g->goffsets, 1),
1, P4EST_MPI_GLOIDX, g->mpicomm);
SC_CHECK_MPI (mpiret);
lg = 0;
for (p = 1; p <= g->mpisize; ++p) {
*gval = (lg += *gval);
}
P4EST_ASSERT
g->gsoff = *(
p4est_gloidx_t *) sc_array_index (g->goffsets, g->mpirank);
}
static void
create_forest (spheres_global_t * g)
{
int mpiret;
double rmin, rmax, rgeom2;
double coef, fact, vmult;
double Vexp, Nexp, r;
double vdensity, sumrd, gsrd;
double tnew, tgenerate;
char filename[BUFSIZ];
p4est_sphere_t *sph;
tnew = sc_MPI_Wtime ();
g->p4est =
p4est_new_ext (g->mpicomm, g->conn, 0, g->minlevel, 1,
sizeof (qu_data_t), spheres_init_zero, g);
accumulate_once (g, STATS_ONCE_NEW, tnew);
if (g->write_vtk) {
snprintf (filename, BUFSIZ, "%s_sph_%d_%d_%s_%d",
g->prefix, g->minlevel, g->maxlevel, "new", g->minlevel);
}
tgenerate = sc_MPI_Wtime ();
rmax = .5 * g->spherelems * sc_intpowf (.5, g->minlevel);
rmax = SC_MIN (rmax, g->rmax);
P4EST_ASSERT (0. < rmax);
rmin = .5 * g->spherelems * sc_intpowf (.5, g->maxlevel);
rmin = SC_MIN (rmin, g->rmax);
P4EST_ASSERT (0. < rmin && rmin <= rmax);
P4EST_GLOBAL_PRODUCTIONF
("Generating spheres with radii %g to %g\n", rmin, rmax);
rgeom2 = rmin * rmax;
#ifndef P4_TO_P8
Vexp = 4. * rgeom2;
coef = 1. - rmin / rmax;
#else
Vexp = 8. * rgeom2 * rgeom2 / (.5 * (rmin + rmax));
coef = 1. - rmin * rmin / (rmax * rmax);
#endif
vmult = vdensity / Vexp;
sumrd = 0.;
sph_excl = sph_incl = 0;
g->sphr = sc_array_new (sizeof (p4est_sphere_t));
g->lcounts = sc_array_new_count (sizeof (int),
g->p4est->local_num_quadrants);
for (which_tree = g->p4est->first_local_tree;
tree = p4est_tree_array_index (g->p4est->trees, which_tree);
P4EST_ASSERT (ntrel > 0);
for (tin = 0; tin < ntrel; ++tin) {
q = p4est_quadrant_array_index (&tree->
quadrants, tin);
(int) qunsph;
if (qunsph > 0) {
sph_incl = sph_excl + qunsph;
sph = (p4est_sphere_t *) sc_array_push_count (g->sphr, qunsph);
for (li = sph_excl; li < sph_incl; ++li, ++sph) {
sph->center[0] = (q->x + qh * sc_rand (&g->rstate)) * irootlen;
sph->center[1] = (q->
y + qh * sc_rand (&g->rstate)) * irootlen;
#ifdef P4_TO_P8
sph->center[2] = (q->z + qh * sc_rand (&g->rstate)) * irootlen;
#endif
if (coef <= 0.) {
r = rmin;
}
else {
fact = 1. / (1. - coef * sc_rand (&g->rstate));
#ifndef P4_TO_P8
r = rmin * fact;
#else
r = rmin * sqrt (fact);
#endif
}
P4EST_INFOF ("Created sphere at " SPHERES_DIM_G " radius %g\n",
sph->center[0], sph->center[1]
sph->radius = r;
}
sph_excl = sph_incl;
}
}
}
P4EST_ASSERT (sph_incl == sph_excl);
g->lsph = sph_incl;
g->goffsets = sc_array_new_count (
sizeof (
p4est_gloidx_t), g->mpisize + 1);
sphere_offsets (g);
P4EST_GLOBAL_PRODUCTIONF
("Expected volume %g count %.1f generated %lld\n",
Vexp, vmult * g->conn->num_trees, (long long)
mpiret = sc_MPI_Allreduce (&sumrd, &gsrd, 1, sc_MPI_DOUBLE,
sc_MPI_SUM, g->mpicomm);
SC_CHECK_MPI (mpiret);
P4EST_GLOBAL_PRODUCTIONF ("Total volume ideal %g achieved %g\n",
vdensity * g->conn->num_trees, gsrd);
accumulate_once (g, STATS_ONCE_GENERATE, tgenerate);
}
static int
int plast, void *point)
{
P4EST_ASSERT (g != NULL && g->p4est ==
p4est);
P4EST_ASSERT (0 <= pfirst && pfirst <= plast && plast < g->mpisize);
P4EST_ASSERT (point == NULL);
if (pfirst == plast && pfirst == g->mpirank) {
return 0;
}
p4est_quadrant_sphere_box (quadrant, &g->box);
return 1;
}
static int
void *point)
{
int last_sphere_proc;
p4est_sphere_t *sph;
sph_item_t *item;
sr_buf_t *to_proc;
P4EST_ASSERT (g != NULL && g->p4est ==
p4est);
P4EST_ASSERT (0 <= pfirst && pfirst <= plast && plast < g->mpisize);
P4EST_ASSERT (point != NULL);
P4EST_ASSERT (g->box.radius ==
sph = (p4est_sphere_t *) sc_array_index_int (g->sphr, li);
if (pfirst < plast) {
if (!p4est_sphere_match_approx (&g->box, sph, g->thickness)) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("No approx match in %d %d for %ld\n",
pfirst, plast, (long) li);
#endif
return 0;
}
return 1;
}
P4EST_ASSERT (pfirst == plast);
P4EST_ASSERT (pfirst != g->mpirank);
if (!p4est_sphere_match_exact (&g->box, sph, g->thickness)) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("No exact match in %d %d for %ld\n",
pfirst, plast, (long) li);
#endif
return 0;
}
#ifdef SPHERES_CHATTY
P4EST_INFOF ("Found in %d %d: %ld\n", pfirst, plast, (long) li);
#endif
last_sphere_proc = *(int *) sc_array_index_int (g->sphere_procs, li);
if (pfirst != g->last_to_rank) {
P4EST_ASSERT (g->last_to_rank < pfirst);
P4EST_ASSERT (last_sphere_proc <= g->last_to_rank);
*(int *) sc_array_push (g->notify) = pfirst;
*(g->last_payload = (int *) sc_array_push (g->payload)) = 1;
g->last_to_rank = pfirst;
g->last_to_proc = to_proc = (sr_buf_t *) sc_array_push (g->to_procs);
to_proc->rank = pfirst;
to_proc->items = sc_array_new_count (sizeof (sph_item_t), 1);
item = (sph_item_t *) sc_array_index (to_proc->items, 0);
}
else {
P4EST_ASSERT (last_sphere_proc <= pfirst);
if (last_sphere_proc == pfirst) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("Duplicate in %d %d: %ld\n", pfirst, plast, (long) li);
#endif
return 0;
}
to_proc = g->last_to_proc;
P4EST_ASSERT (to_proc->rank == pfirst);
P4EST_ASSERT (to_proc == (sr_buf_t *)
sc_array_index (g->to_procs, g->to_procs->elem_count - 1));
P4EST_ASSERT (to_proc->items->elem_count > 0);
item = (sph_item_t *) sc_array_push (to_proc->items);
++*g->last_payload;
}
*(int *) sc_array_index_int (g->sphere_procs, li) = pfirst;
item->sph = *sph;
return 0;
}
static int
void *point)
{
P4EST_ASSERT (g != NULL && g->p4est ==
p4est);
P4EST_ASSERT (point == NULL);
p4est_quadrant_sphere_box (quadrant, &g->box);
return 1;
}
static int
void *point)
{
qu_data_t *qud = (qu_data_t *) quadrant->
p.
user_data;
p4est_sphere_t *sph;
P4EST_ASSERT (g != NULL && g->p4est ==
p4est);
P4EST_ASSERT (point != NULL);
sph = *(p4est_sphere_t **) point;
sph->radius) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("No radius match %g %g in %ld\n",
g->box.radius, sph->radius, (long) local_num);
#endif
return 0;
}
if (local_num < 0) {
if (!p4est_sphere_match_approx (&g->box, sph, g->thickness)) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("No approx match in %ld\n", (long) local_num);
#endif
return 0;
}
return 1;
}
if (!p4est_sphere_match_exact (&g->box, sph, g->thickness)) {
#ifdef SPHERES_CHATTY
P4EST_INFOF ("No exact match in %ld\n", (long) local_num);
#endif
return 0;
}
#ifdef SPHERES_CHATTY
P4EST_INFOF ("Found in %ld\n", (long) local_num);
#endif
qud->set_refine = 1;
return 0;
}
static int
refine_spheres (spheres_global_t * g, int lev)
{
int mpiret;
int q;
int num_from_spheres;
int is_refined;
double tpsearch, tsend, tnotify, treceive, twaitsend;
double tlsearch, trefine, tpartition, ttransfer;
sc_array_t *points;
sc_array_t *pi;
sc_array_t *lcounts_partitioned;
sc_array_t *sphr_partitioned;
sc_notify_t *notifyc;
#ifdef P4EST_ENABLE_DEBUG
#endif
p4est_sphere_t **psph;
sph_item_t *item;
sr_buf_t *proc;
P4EST_ASSERT (g->minlevel <= lev && lev < g->maxlevel);
tpsearch = sc_MPI_Wtime ();
g->last_to_proc = NULL;
g->last_to_rank = -1;
g->to_procs = sc_array_new (sizeof (sr_buf_t));
g->notify = sc_array_new (sizeof (int));
g->payload = sc_array_new (sizeof (int));
g->last_payload = NULL;
g->sphere_procs = sc_array_new_count (sizeof (int), g->lsph);
sc_array_memset (g->sphere_procs, -1);
for (li = 0; li < g->lsph; ++li) {
}
P4EST_INFOF ("Searching partition for %ld local spheres\n", (long) g->lsph);
spheres_partition_point, points);
sc_array_destroy_null (&points);
accumulate_loop (g, lev, STATS_LOOP_PSEARCH, tpsearch);
tsend = sc_MPI_Wtime ();
P4EST_ASSERT (g->notify->elem_count == g->to_procs->elem_count);
P4EST_ASSERT (g->notify->elem_count == g->payload->elem_count);
g->num_to_procs = (int) g->notify->elem_count;
g->to_requests =
sc_array_new_count (sizeof (sc_MPI_Request), g->num_to_procs);
for (q = 0; q < g->num_to_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->to_procs, q);
P4EST_ASSERT (proc->rank != g->mpirank);
P4EST_ASSERT (proc->rank == *(int *) sc_array_index_int (g->notify, q));
P4EST_ASSERT (proc->items != NULL);
pi = proc->items;
P4EST_ASSERT (pi->elem_size == sizeof (sph_item_t));
mpiret = sc_MPI_Isend
(pi->array, pi->elem_count * pi->elem_size, sc_MPI_BYTE,
proc->rank, SPHERES_TAG_SPHERES, g->mpicomm,
(sc_MPI_Request *) sc_array_index_int (g->to_requests, q));
SC_CHECK_MPI (mpiret);
}
sc_array_destroy_null (&g->sphere_procs);
accumulate_loop (g, lev, STATS_LOOP_SEND, tsend);
tnotify = sc_MPI_Wtime ();
notifyc = sc_notify_new (g->mpicomm);
if (!g->notify_alltoall) {
sc_notify_set_type (notifyc, SC_NOTIFY_NARY);
sc_notify_nary_set_widths (notifyc, g->ntop, g->nint, g->nbot);
}
else {
sc_notify_set_type (notifyc, SC_NOTIFY_PEX);
}
sc_notify_payload (g->notify, NULL, g->payload, NULL, 1, notifyc);
sc_notify_destroy (notifyc);
accumulate_loop (g, lev, STATS_LOOP_NOTIFY, tnotify);
treceive = sc_MPI_Wtime ();
P4EST_ASSERT (g->notify->elem_count == g->payload->elem_count);
g->num_from_procs = (int) g->notify->elem_count;
g->from_requests =
sc_array_new_count (sizeof (sc_MPI_Request), g->num_from_procs);
g->from_procs = sc_array_new_count (sizeof (sr_buf_t), g->num_from_procs);
for (q = 0; q < g->num_from_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->from_procs, q);
proc->rank = *(int *) sc_array_index_int (g->notify, q);
P4EST_ASSERT (proc->rank != g->mpirank);
num_from_spheres = *(int *) sc_array_index_int (g->payload, q);
pi = proc->items =
sc_array_new_count (sizeof (sph_item_t), num_from_spheres);
mpiret = sc_MPI_Irecv
(pi->array, pi->elem_count * pi->elem_size, sc_MPI_BYTE,
proc->rank, SPHERES_TAG_SPHERES, g->mpicomm,
(sc_MPI_Request *) sc_array_index_int (g->from_requests, q));
SC_CHECK_MPI (mpiret);
}
sc_array_destroy_null (&g->payload);
sc_array_destroy_null (&g->notify);
mpiret = sc_MPI_Waitall
(g->num_from_procs, (sc_MPI_Request *) g->from_requests->array,
sc_MPI_STATUSES_IGNORE);
SC_CHECK_MPI (mpiret);
sc_array_destroy_null (&g->from_requests);
accumulate_loop (g, lev, STATS_LOOP_RECEIVE, treceive);
tlsearch = sc_MPI_Wtime ();
points = sc_array_new (sizeof (p4est_sphere_t *));
sri = 0;
for (q = 0; q < g->num_from_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->from_procs, q);
P4EST_ASSERT (proc->rank != g->mpirank);
if (proc->rank >= g->mpirank) {
break;
}
#ifdef P4EST_ENABLE_DEBUG
gcur = *(
p4est_gloidx_t *) sc_array_index_int (g->goffsets, proc->rank);
gnext =
#endif
psph = (p4est_sphere_t **) sc_array_push_count (points, snum);
for (li = 0; li < snum; ++li) {
item = (sph_item_t *) sc_array_index_int (proc->items, li);
P4EST_ASSERT (gcur <= item->gid && item->gid < gnext);
*psph++ = &item->sph;
}
sri += snum;
}
snum = g->lsph;
psph = (p4est_sphere_t **) sc_array_push_count (points, snum);
for (li = 0; li < snum; ++li) {
*psph++ = (p4est_sphere_t *) sc_array_index_int (g->sphr, li);
}
sri += snum;
for (; q < g->num_from_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->from_procs, q);
P4EST_ASSERT (proc->rank > g->mpirank);
#ifdef P4EST_ENABLE_DEBUG
gcur = *(
p4est_gloidx_t *) sc_array_index_int (g->goffsets, proc->rank);
gnext =
#endif
psph = (p4est_sphere_t **) sc_array_push_count (points, snum);
for (li = 0; li < snum; ++li) {
item = (sph_item_t *) sc_array_index_int (proc->items, li);
P4EST_ASSERT (gcur <= item->gid && item->gid < gnext);
*psph++ = &item->sph;
}
sri += snum;
}
mpiret = sc_MPI_Allreduce (&gsloc, &gsglo, 1, P4EST_MPI_GLOIDX,
sc_MPI_SUM, g->mpicomm);
SC_CHECK_MPI (mpiret);
P4EST_GLOBAL_PRODUCTIONF ("Sphere redundant sum %lld\n", (long long) gsglo);
P4EST_INFOF ("Searching elements for %ld local spheres\n", (long) sri);
spheres_local_point, points);
sc_array_destroy_null (&points);
for (q = 0; q < g->num_from_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->from_procs, q);
P4EST_ASSERT (proc->rank != g->mpirank);
P4EST_ASSERT (proc->items != NULL);
sc_array_destroy (proc->items);
}
sc_array_destroy_null (&g->from_procs);
accumulate_loop (g, lev, STATS_LOOP_LSEARCH, tlsearch);
trefine = sc_MPI_Wtime ();
g->lqindex = g->lqindex_refined = 0;
g->lsph_offset = 0;
g->p4est->local_num_quadrants);
g->lcounts_refined = sc_array_new_count (sizeof (int),
g->p4est->local_num_quadrants);
gnq = g->p4est->global_num_quadrants;
spheres_init_zero, spheres_replace_callback);
P4EST_ASSERT (g->lqindex_refined ==
g->p4est->local_num_quadrants);
P4EST_ASSERT (g->lsph_offset == g->lsph);
is_refined = (gnq < g->p4est->global_num_quadrants);
sc_array_destroy (g->lcounts);
g->lcounts = g->lcounts_refined;
accumulate_loop (g, lev, STATS_LOOP_REFINE, trefine);
if (is_refined) {
spheres_write_vtk (g, "refined", lev + 1);
}
twaitsend = sc_MPI_Wtime ();
mpiret = sc_MPI_Waitall
(g->num_to_procs, (sc_MPI_Request *) g->to_requests->array,
sc_MPI_STATUSES_IGNORE);
SC_CHECK_MPI (mpiret);
sc_array_destroy_null (&g->to_requests);
for (q = 0; q < g->num_to_procs; ++q) {
proc = (sr_buf_t *) sc_array_index_int (g->to_procs, q);
P4EST_ASSERT (proc->rank != g->mpirank);
P4EST_ASSERT (proc->items != NULL);
sc_array_destroy (proc->items);
}
sc_array_destroy_null (&g->to_procs);
accumulate_loop (g, lev, STATS_LOOP_WAITSEND, twaitsend);
if (is_refined) {
tpartition = sc_MPI_Wtime ();
accumulate_loop (g, lev, STATS_LOOP_PARTITION, tpartition);
ttransfer = sc_MPI_Wtime ();
lcounts_partitioned =
g->p4est->global_first_quadrant,
g->mpicomm, SPHERES_TAG_FIXED,
lcounts_partitioned->array, g->lcounts->array,
sizeof (int));
snum += *(int *) sc_array_index_int (lcounts_partitioned, li);
}
sphr_partitioned = sc_array_new_count (sizeof (p4est_sphere_t), snum);
g->p4est->global_first_quadrant,
g->mpicomm, SPHERES_TAG_CUSTOM,
sphr_partitioned->array,
(int *) lcounts_partitioned->array,
g->sphr->array, (int *) g->lcounts->array,
sizeof (p4est_sphere_t));
g->p4est = post;
sc_array_destroy (g->lcounts);
g->lcounts = lcounts_partitioned;
sc_array_destroy (g->sphr);
g->sphr = sphr_partitioned;
sphere_offsets (g);
accumulate_loop (g, lev, STATS_LOOP_TRANSFER, ttransfer);
spheres_write_vtk (g, "partitioned", lev + 1);
}
return is_refined;
}
static void
destroy_forest (spheres_global_t * g)
{
sc_array_destroy_null (&g->sphr);
sc_array_destroy_null (&g->lcounts);
sc_array_destroy_null (&g->goffsets);
}
static void
run (spheres_global_t * g)
{
int mpiret;
int i;
int lev;
double twall;
char name[BUFSIZ];
sc_statinfo_t *si;
mpiret = sc_MPI_Barrier (g->mpicomm);
SC_CHECK_MPI (mpiret);
twall = sc_MPI_Wtime ();
g->num_stats =
STATS_ONCE_LAST + (g->maxlevel - g->minlevel) * STATS_LOOP_LAST;
g->stats = sc_array_new_count (sizeof (sc_statinfo_t), g->num_stats);
for (i = 0; i < STATS_ONCE_LAST; ++i) {
sc_stats_init_ext (once_index (g, (stats_once_t) i), once_names[i],
1, sc_stats_group_all, sc_stats_prio_all);
}
for (lev = g->minlevel; lev < g->maxlevel; ++lev) {
for (i = 0; i < STATS_LOOP_LAST; ++i) {
snprintf (name, BUFSIZ, "%10s_%02d", loop_names[i], lev);
sc_stats_init_ext (loop_index (g, lev, (stats_loop_t) i), name,
1, sc_stats_group_all, sc_stats_prio_all);
}
}
create_forest (g);
for (lev = g->minlevel; lev < g->maxlevel; ++lev) {
P4EST_GLOBAL_PRODUCTIONF ("Trying refinement from level %d to %d\n",
lev, lev + 1);
if (!refine_spheres (g, lev)) {
P4EST_GLOBAL_PRODUCTIONF ("No refinement at level %d\n", lev);
break;
}
}
destroy_forest (g);
accumulate_once (g, STATS_ONCE_WALL, twall);
si = once_index (g, STATS_ONCE_FIRST);
sc_stats_compute (sc_MPI_COMM_WORLD, g->num_stats, si);
for (i = 0; i < g->num_stats; ++i) {
sc_stats_reset (si + i, 1);
}
sc_array_destroy (g->stats);
}
static int
usagerr (sc_options_t * opt, const char *msg)
{
P4EST_GLOBAL_LERRORF ("Usage required: %s\n", msg);
return 1;
}
int
main (int argc, char **argv)
{
int mpiret;
int j;
int ue;
int first_argc;
#if 0
const char *opt_notify, *opt_vtk, *opt_build;
#endif
sc_options_t *opt;
spheres_global_t global, *g = &global;
mpiret = sc_MPI_Init (&argc, &argv);
SC_CHECK_MPI (mpiret);
memset (g, 0, sizeof (*g));
g->mpicomm = sc_MPI_COMM_WORLD;
mpiret = sc_MPI_Comm_size (g->mpicomm, &g->mpisize);
SC_CHECK_MPI (mpiret);
mpiret = sc_MPI_Comm_rank (g->mpicomm, &g->mpirank);
SC_CHECK_MPI (mpiret);
sc_init (g->mpicomm, 1, 1, NULL, SC_LP_DEFAULT);
#ifdef SPHERES_CHATTY
P4EST_GLOBAL_INFOF ("Sizeof sphere %u item %u\n",
(unsigned) sizeof (p4est_sphere_t),
(unsigned) sizeof (sph_item_t));
#endif
opt = sc_options_new (argv[0]);
sc_options_add_int (opt, 'l', "minlevel", &g->minlevel, 2, "Lowest level");
sc_options_add_int (opt, 'L', "maxlevel", &g->maxlevel, g->minlevel + 5,
"Highest level");
sc_options_add_double (opt, 'r', "rmax", &g->rmax, .5, "Max sphere radius");
sc_options_add_double (opt, 't', "thickness", &g->thickness, .05,
"Relative sphere thickness");
sc_options_add_double (opt, 'f', "lfraction", &g->lfraction, .7,
"Length density of spheres");
sc_options_add_double (opt, 's', "spherequads", &g->spherelems, 20.,
"Min quadrants per sphere diameter");
sc_options_add_int (opt, 'N', "nbottom", &g->nbot, 24,
"Notify bottom multiplicator");
sc_options_add_bool (opt, 'A', "alltoall", &g->notify_alltoall, 0,
"Notify alltoall implementation");
sc_options_add_bool (opt, 'S', "scaling", &g->scaling, 0,
"Configure for scaling test");
sc_options_add_int (opt, 'R', "repetitions", &g->repetitions, 1,
"Repeat run multiple times");
sc_options_add_bool (opt, 'V', "write-vtk", &g->write_vtk, 0,
"Output VTK files");
sc_options_add_string (opt, 'P', "prefix", &g->prefix,
"sph" SPHERES_48 ()"res", "Prefix for file output");
g->mpiwrap = 16;
ue = 0;
do {
opt, argc, argv);
if (first_argc < 0 || first_argc != argc) {
ue = usagerr (opt, "Invalid option format or non-option arguments");
break;
}
P4EST_GLOBAL_PRODUCTIONF (
"Dimension is %d\n",
P4EST_DIM);
ue = usagerr (opt, "Minlevel between 0 and P4EST_QMAXLEVEL");
}
if (g->maxlevel == -1) {
g->maxlevel = g->minlevel;
P4EST_GLOBAL_ESSENTIALF ("Maxlevel set to %d\n", g->maxlevel);
}
ue = usagerr (opt, "Maxlevel between minlevel and P4EST_QMAXLEVEL");
}
if (g->rmax <= 0.) {
ue = usagerr (opt, "Maximum sphere radius positive");
}
if (g->lfraction < 0.) {
ue = usagerr (opt, "Length density non-negative");
}
if (g->spherelems < 1.) {
ue = usagerr (opt, "Elements per sphere no less than 1.");
}
if (ue) {
break;
}
if (g->scaling) {
sc_package_set_verbosity (sc_package_id, SC_LP_PRODUCTION);
}
for (j = 0; j < g->repetitions; ++j) {
P4EST_GLOBAL_PRODUCTIONF ("Spheres run repetition %d of %d\n",
j, g->repetitions);
run (g);
}
P4EST_GLOBAL_PRODUCTIONF ("Spheres run %d repetitions done\n",
g->repetitions);
}
while (0);
if (ue) {
}
sc_options_destroy (opt);
sc_finalize ();
mpiret = sc_MPI_Finalize ();
SC_CHECK_MPI (mpiret);
return ue ? EXIT_FAILURE : EXIT_SUCCESS;
}
void p4est_destroy(p4est_t *p4est)
Destroy a p4est.
#define P4EST_QMAXLEVEL
The finest level of the quadtree for representing quadrant corners.
Definition: p4est.h:59
p4est_t * p4est_copy(p4est_t *input, int copy_data)
Make a deep copy of a p4est.
#define P4EST_QUADRANT_LEN(l)
The length of a quadrant of level l.
Definition: p4est.h:65
#define P4EST_ROOT_LEN
The length of a side of the root quadrant.
Definition: p4est.h:62
int32_t p4est_qcoord_t
Typedef for quadrant coordinates.
Definition: p4est_base.h:81
SC_DLL_PUBLIC int p4est_package_id
The package id for p4est within libsc.
int32_t p4est_topidx_t
Typedef for counting topological entities (trees, tree vertices).
Definition: p4est_base.h:93
int32_t p4est_locidx_t
Typedef for processor-local indexing of quadrants and nodes.
Definition: p4est_base.h:106
void p4est_init(sc_log_handler_t log_handler, int log_threshold)
Registers p4est with the SC Library and sets the logging behavior.
int64_t p4est_gloidx_t
Typedef for globally unique indexing of quadrants.
Definition: p4est_base.h:118
Routines for manipulating quadrants (neighbors, parents, children, etc.)
void p4est_quadrant_srand(const p4est_quadrant_t *q, sc_rand_state_t *rstate)
Initialize a random number generator by quadrant coordinates.
Parallel messaging and support code.
void p4est_transfer_fixed(const p4est_gloidx_t *dest_gfq, const p4est_gloidx_t *src_gfq, sc_MPI_Comm mpicomm, int tag, void *dest_data, const void *src_data, size_t data_size)
Transfer data associated with one forest partition to another.
void p4est_transfer_items(const p4est_gloidx_t *dest_gfq, const p4est_gloidx_t *src_gfq, sc_MPI_Comm mpicomm, int tag, void *dest_data, const int *dest_counts, const void *src_data, const int *src_counts, size_t item_size)
Transfer variable-count item data between partitions.
void p4est_connectivity_destroy(p4est_connectivity_t *connectivity)
Destroy a connectivity structure.
#define P4EST_DIM
The spatial dimension.
Definition: p4est_connectivity.h:71
#define P4EST_DIM_POW(a)
Exponentiate with dimension.
Definition: p4est_connectivity.h:88
#define P4EST_CHILDREN
The number of children of a quadrant, also the number of corners.
Definition: p4est_connectivity.h:75
#define P4EST_ONLY_P8_COMMA(x)
Only use comma and expression in 3D.
Definition: p4est_connectivity.h:85
p4est_connectivity_t * p4est_connectivity_new_periodic(void)
Create a connectivity structure for an all-periodic unit square.
Interface routines with extended capabilities.
p4est_gloidx_t p4est_partition_ext(p4est_t *p4est, int partition_for_coarsening, p4est_weight_t weight_fn)
Repartition the forest.
void p4est_refine_ext(p4est_t *p4est, int refine_recursive, int maxlevel, p4est_refine_t refine_fn, p4est_init_t init_fn, p4est_replace_t replace_fn)
Refine a forest with a bounded refinement level and a replace option.
p4est_t * p4est_new_ext(sc_MPI_Comm mpicomm, p4est_connectivity_t *connectivity, p4est_locidx_t min_quadrants, int min_level, int fill_uniform, size_t data_size, p4est_init_t init_fn, void *user_pointer)
Create a new forest.
Search through quadrants, the local part of a forest, or the partition.
void p4est_search_local(p4est_t *p4est, int call_post, p4est_search_local_t quadrant_fn, p4est_search_local_t point_fn, sc_array_t *points)
Search through the local part of a forest.
void p4est_search_partition(p4est_t *p4est, int call_post, p4est_search_partition_t quadrant_fn, p4est_search_partition_t point_fn, sc_array_t *points)
Traverse the global partition top-down.
Routines for printing a forest and associated fields to VTK format.
p4est_vtk_context_t * p4est_vtk_write_header(p4est_vtk_context_t *cont)
Write the VTK header.
int p4est_vtk_write_footer(p4est_vtk_context_t *cont)
Write the VTU footer and clean up.
p4est_vtk_context_t * p4est_vtk_context_new(p4est_t *p4est, const char *filename)
The first call to write a VTK file using individual functions.
p4est_vtk_context_t * p4est_vtk_write_cell_dataf(p4est_vtk_context_t *cont, int write_tree, int write_level, int write_rank, int wrap_rank, int num_cell_scalars, int num_cell_vectors,...)
Write VTK cell data.
void p4est_vtk_write_file(p4est_t *p4est, p4est_geometry_t *geom, const char *filename)
Write the p4est in VTK format.
struct p4est_vtk_context p4est_vtk_context_t
Opaque context type for writing VTK output with multiple function calls.
Definition: p4est_vtk.h:42
Routines for manipulating quadrants (neighbors, parents, children, etc.)
Parallel messaging and support code.
Interface routines with extended capabilities.
Search through quadrants, the local part of a forest, or the partition.
Routines for printing a forest and associated fields to VTK format.
The 2D quadrant datatype.
Definition: p4est.h:76
int8_t level
level of refinement
Definition: p4est.h:80
union p4est_quadrant::p4est_quadrant_data p
a union of additional data attached to a quadrant
p4est_qcoord_t y
coordinates
Definition: p4est.h:78
The p4est tree datatype.
Definition: p4est.h:129
sc_array_t quadrants
locally stored quadrants
Definition: p4est.h:130
p4est_locidx_t quadrants_offset
cumulative sum over earlier trees on this processor (locals only)
Definition: p4est.h:133
The p4est forest datatype.
Definition: p4est.h:150
p4est_locidx_t local_num_quadrants
number of quadrants on all trees on this processor
Definition: p4est.h:167
void * user_pointer
convenience pointer for users, never touched by p4est
Definition: p4est.h:157
p4est_gloidx_t global_num_quadrants
number of quadrants on all trees on all processors
Definition: p4est.h:169
p4est_topidx_t last_local_tree
0-based index of last local tree, must be -2 for an empty processor
Definition: p4est.h:164
p4est_gloidx_t * global_first_quadrant
first global quadrant index for each process and 1 beyond
Definition: p4est.h:171
void * user_data
never changed by p4est
Definition: p4est.h:94