Beispiel #1
0
/** Compute the timestep.
 *
 * Find the smallest quadrant and scale the timestep based on that length and
 * the advection velocity.
 *
 * \param [in] p4est the forest
 * \return the timestep.
 */
static double
step3_get_timestep (p4est_t * p4est)
{
  step3_ctx_t        *ctx = (step3_ctx_t *) p4est->user_pointer;
  p4est_topidx_t      t, flt, llt;
  p4est_tree_t       *tree;
  int                 max_level, global_max_level;
  int                 mpiret, i;
  double              min_h, vnorm;
  double              dt;

  /* compute the timestep by finding the smallest quadrant */
  flt = p4est->first_local_tree;
  llt = p4est->last_local_tree;

  max_level = 0;
  for (t = flt; t <= llt; t++) {
    tree = p4est_tree_array_index (p4est->trees, t);
    max_level = SC_MAX (max_level, tree->maxlevel);

  }
  mpiret =
    sc_MPI_Allreduce (&max_level, &global_max_level, 1, sc_MPI_INT,
                      sc_MPI_MAX, p4est->mpicomm);
  SC_CHECK_MPI (mpiret);

  min_h =
    (double) P4EST_QUADRANT_LEN (global_max_level) / (double) P4EST_ROOT_LEN;

  vnorm = 0;
  for (i = 0; i < P4EST_DIM; i++) {
    vnorm += ctx->v[i] * ctx->v[i];
  }
  vnorm = sqrt (vnorm);

  dt = min_h / 2. / vnorm;

  return dt;
}
Beispiel #2
0
int
main (int argc, char **argv)
{
  sc_MPI_Comm         mpicomm;
  int                 mpiret;
  int                 found_total;
  p4est_locidx_t      jt, Al, Bl;
  p4est_locidx_t      local_count;
  p4est_connectivity_t *conn;
  p4est_quadrant_t   *A, *B;
  p4est_geometry_t   *geom;
  p4est_t            *p4est;
  sc_array_t         *points;
  test_point_t       *p;
  const char         *vtkname;

  /* Initialize MPI */
  mpiret = sc_MPI_Init (&argc, &argv);
  SC_CHECK_MPI (mpiret);
  mpicomm = sc_MPI_COMM_WORLD;

  /* Initialize packages */
  sc_init (mpicomm, 1, 1, NULL, SC_LP_DEFAULT);
  p4est_init (NULL, SC_LP_DEFAULT);

  /* Create forest */
#ifndef P4_TO_P8
  conn = p4est_connectivity_new_star ();
  geom = NULL;
  vtkname = "test_search2";
#else
  conn = p8est_connectivity_new_sphere ();
  geom = p8est_geometry_new_sphere (conn, 1., 0.191728, 0.039856);
  vtkname = "test_search3";
#endif
  p4est = p4est_new_ext (mpicomm, conn, 0, 0, 0, 0, NULL, &local_count);
  p4est_refine (p4est, 1, refine_fn, NULL);
  p4est_partition (p4est, 0, NULL);
  p4est_vtk_write_file (p4est, geom, vtkname);

  /* The following code should really be in a separate function. */

  /* Prepare a point search -- fix size so the memory is not relocated */
  points = sc_array_new_size (sizeof (test_point_t), 2);

  /* A */
  p = (test_point_t *) sc_array_index (points, 0);
  p->name = "A";
  A = &p->quad;
  P4EST_QUADRANT_INIT (A);
  p4est_quadrant_set_morton (A, 3, 23);
  A->p.piggy3.which_tree = 0;
  A->p.piggy3.local_num = -1;
  Al = -1;

  /* B */
  p = (test_point_t *) sc_array_index (points, 1);
  p->name = "B";
  B = &p->quad;
  P4EST_QUADRANT_INIT (B);
  p4est_quadrant_set_morton (B, 2, 13);
  B->p.piggy3.which_tree = conn->num_trees / 2;
  B->p.piggy3.local_num = -1;
  Bl = -1;

  /* Find quadrant numbers if existing */
  for (jt = p4est->first_local_tree; jt <= p4est->last_local_tree; ++jt) {
    size_t              zz;
    p4est_tree_t       *tree = p4est_tree_array_index (p4est->trees, jt);
    p4est_quadrant_t   *quad;
    sc_array_t         *tquadrants = &tree->quadrants;

    for (zz = 0; zz < tquadrants->elem_count; ++zz) {
      quad = p4est_quadrant_array_index (tquadrants, zz);
      if (A->p.piggy3.which_tree == jt && !p4est_quadrant_compare (quad, A)) {
        Al = tree->quadrants_offset + (p4est_locidx_t) zz;
        P4EST_VERBOSEF ("Searching for A at %lld\n", (long long) Al);
      }
      if (B->p.piggy3.which_tree == jt && !p4est_quadrant_compare (quad, B)) {
        Bl = tree->quadrants_offset + (p4est_locidx_t) zz;
        P4EST_VERBOSEF ("Searching for B at %lld\n", (long long) Bl);
      }
    }
  }

  /* Go */
  found_count = 0;
  p4est_search_local (p4est, 0, NULL, search_callback, points);
  mpiret = sc_MPI_Allreduce (&found_count, &found_total,
                             1, sc_MPI_INT, sc_MPI_SUM, mpicomm);
  SC_CHECK_MPI (mpiret);
  SC_CHECK_ABORT (found_total == (int) points->elem_count, "Point search");
  SC_CHECK_ABORT (A->p.piggy3.local_num == Al, "Search A");
  SC_CHECK_ABORT (B->p.piggy3.local_num == Bl, "Search B");

  /* Use another search to count local quadrants */
  local_count = 0;
  p4est_search_local (p4est, 0, count_callback, NULL, NULL);
  SC_CHECK_ABORT (local_count == p4est->local_num_quadrants, "Count search");

  /* Clear memory */
  sc_array_destroy (points);
  p4est_destroy (p4est);
  if (geom != NULL) {
    p4est_geometry_destroy (geom);
  }
  p4est_connectivity_destroy (conn);

  /* Test the build_local function and friends */
  test_build_local (mpicomm);

  /* Finalize */
  sc_finalize ();
  mpiret = sc_MPI_Finalize ();
  SC_CHECK_MPI (mpiret);

  return 0;
}
Beispiel #3
0
static void
mesh_run (mpi_context_t * mpi, p4est_connectivity_t * connectivity,
          int uniform, int compute_tree_index, int compute_level_lists,
          p4est_connect_type_t mesh_btype)
{
  int                 mpiret;
  unsigned            crc;
  long                local_used[4], global_used[4];
  p4est_t            *p4est;
  p4est_ghost_t      *ghost;
  p4est_mesh_t       *mesh;
  user_data_t        *ghost_data;

  p4est = p4est_new (mpi->mpicomm, connectivity,
                     sizeof (user_data_t), init_fn, NULL);
  if (!uniform)
    p4est_vtk_write_file (p4est, NULL, P4EST_STRING "_mesh_new");

  /* refinement */
  if (uniform) {
    p4est_refine (p4est, 1, refine_uniform, init_fn);
  }
  else {
    p4est_refine (p4est, 1, refine_normal, init_fn);
    p4est_vtk_write_file (p4est, NULL, P4EST_STRING "_mesh_refined");
  }

  /* balance */
  p4est_balance (p4est, P4EST_CONNECT_FULL, init_fn);
  if (!uniform)
    p4est_vtk_write_file (p4est, NULL, P4EST_STRING "_mesh_balanced");

  /* partition */
  p4est_partition (p4est, 0, NULL);
  if (!uniform) {
    p4est_vtk_write_file (p4est, NULL, P4EST_STRING "_mesh_partition");
  }
  crc = p4est_checksum (p4est);

  /* print and verify forest checksum */
  P4EST_GLOBAL_STATISTICSF ("Tree %s checksum 0x%08x\n",
                            uniform ? "uniform" : "adapted", crc);

  /* create ghost layer and mesh */
  ghost = p4est_ghost_new (p4est, P4EST_CONNECT_FULL);
  ghost_data = P4EST_ALLOC (user_data_t, ghost->ghosts.elem_count);
  p4est_ghost_exchange_data (p4est, ghost, ghost_data);
  mesh = p4est_mesh_new_ext (p4est, ghost,
                             compute_tree_index, compute_level_lists,
                             mesh_btype);
  test_mesh (p4est, ghost, mesh,
             compute_tree_index, compute_level_lists, mesh_btype,
             ghost_data, uniform);

  /* compute memory used */
  local_used[0] = (long) p4est_connectivity_memory_used (p4est->connectivity);
  local_used[1] = (long) p4est_memory_used (p4est);
  local_used[2] = (long) p4est_ghost_memory_used (ghost);
  local_used[3] = (long) p4est_mesh_memory_used (mesh);
  mpiret = sc_MPI_Allreduce (local_used, global_used, 4, sc_MPI_LONG,
                             sc_MPI_SUM, mpi->mpicomm);
  SC_CHECK_MPI (mpiret);
  P4EST_GLOBAL_PRODUCTIONF ("Total %s memory used %ld %ld %ld %ld\n",
                            uniform ? "uniform" : "adapted",
                            global_used[0], global_used[1],
                            global_used[2], global_used[3]);

  /* destroy ghost layer and mesh */
  P4EST_FREE (ghost_data);
  p4est_mesh_destroy (mesh);
  p4est_ghost_destroy (ghost);

  /* destroy the p4est structure */
  p4est_destroy (p4est);
}
Beispiel #4
0
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;
}
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);
    p4est_log_indent_push ();

    /* 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 = sc_MPI_Allreduce (local_counts, global_counts, 5,
                               sc_MPI_LONG_LONG_INT, sc_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_log_indent_pop ();
    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;
}
Beispiel #6
0
/** Timestep the advection problem.
 *
 * Update the state, refine, repartition, and write the solution to file.
 *
 * \param [in,out] p4est the forest, whose state is updated
 * \param [in] time      the end time
 */
static void
step3_timestep (p4est_t * p4est, double time)
{
  double              t = 0.;
  double              dt = 0.;
  int                 i;
  step3_data_t       *ghost_data;
  step3_ctx_t        *ctx = (step3_ctx_t *) p4est->user_pointer;
  int                 refine_period = ctx->refine_period;
  int                 repartition_period = ctx->repartition_period;
  int                 write_period = ctx->write_period;
  int                 recursive = 0;
  int                 allowed_level = P4EST_QMAXLEVEL;
  int                 allowcoarsening = 1;
  int                 callbackorphans = 0;
  int                 mpiret;
  double              orig_max_err = ctx->max_err;
  double              umax, global_umax;
  p4est_ghost_t      *ghost;

  /* create the ghost quadrants */
  ghost = p4est_ghost_new (p4est, P4EST_CONNECT_FULL);
  /* create space for storing the ghost data */
  ghost_data = P4EST_ALLOC (step3_data_t, ghost->ghosts.elem_count);
  /* synchronize the ghost data */
  p4est_ghost_exchange_data (p4est, ghost, ghost_data);

  /* initialize du/dx estimates */
  p4est_iterate (p4est, ghost, (void *) ghost_data,     /* pass in ghost data that we just exchanged */
                 step3_reset_derivatives,       /* blank the previously calculated derivatives */
                 step3_minmod_estimate, /* compute the minmod estimate of each cell's derivative */
#ifdef P4_TO_P8
                 NULL,          /* there is no callback for the edges between quadrants */
#endif
                 NULL);         /* there is no callback for the corners between quadrants */

  for (t = 0., i = 0; t < time; t += dt, i++) {
    P4EST_GLOBAL_PRODUCTIONF ("time %f\n", t);

    /* refine */
    if (!(i % refine_period)) {
      if (i) {
        /* compute umax */
        umax = 0.;
        /* initialize derivative estimates */
        p4est_iterate (p4est, NULL, (void *) &umax,     /* pass in ghost data that we just exchanged */
                       step3_compute_max,       /* blank the previously calculated derivatives */
                       NULL,    /* there is no callback for the faces between quadrants */
#ifdef P4_TO_P8
                       NULL,    /* there is no callback for the edges between quadrants */
#endif
                       NULL);   /* there is no callback for the corners between quadrants */

        mpiret =
          sc_MPI_Allreduce (&umax, &global_umax, 1, sc_MPI_DOUBLE, sc_MPI_MAX,
                            p4est->mpicomm);
        SC_CHECK_MPI (mpiret);
        ctx->max_err = orig_max_err * global_umax;
        P4EST_GLOBAL_PRODUCTIONF ("u_max %f\n", global_umax);

        /* adapt */
        p4est_refine_ext (p4est, recursive, allowed_level,
                          step3_refine_err_estimate, NULL,
                          step3_replace_quads);
        p4est_coarsen_ext (p4est, recursive, callbackorphans,
                           step3_coarsen_err_estimate, NULL,
                           step3_replace_quads);
        p4est_balance_ext (p4est, P4EST_CONNECT_FACE, NULL,
                           step3_replace_quads);

        p4est_ghost_destroy (ghost);
        P4EST_FREE (ghost_data);
        ghost = NULL;
        ghost_data = NULL;
      }
      dt = step3_get_timestep (p4est);
    }

    /* repartition */
    if (i && !(i % repartition_period)) {
      p4est_partition (p4est, allowcoarsening, NULL);

      if (ghost) {
        p4est_ghost_destroy (ghost);
        P4EST_FREE (ghost_data);
        ghost = NULL;
        ghost_data = NULL;
      }
    }

    /* write out solution */
    if (!(i % write_period)) {
      step3_write_solution (p4est, i);
    }

    /* synchronize the ghost data */
    if (!ghost) {
      ghost = p4est_ghost_new (p4est, P4EST_CONNECT_FULL);
      ghost_data = P4EST_ALLOC (step3_data_t, ghost->ghosts.elem_count);
      p4est_ghost_exchange_data (p4est, ghost, ghost_data);
    }

    /* compute du/dt */
    /* *INDENT-OFF* */
    p4est_iterate (p4est,                 /* the forest */
                   ghost,                 /* the ghost layer */
                   (void *) ghost_data,   /* the synchronized ghost data */
                   step3_quad_divergence, /* callback to compute each quad's
                                             interior contribution to du/dt */
                   step3_upwind_flux,     /* callback to compute each quads'
                                             faces' contributions to du/du */
#ifdef P4_TO_P8
                   NULL,                  /* there is no callback for the
                                             edges between quadrants */
#endif
                   NULL);                 /* there is no callback for the
                                             corners between quadrants */
    /* *INDENT-ON* */

    /* update u */
    p4est_iterate (p4est, NULL, /* ghosts are not needed for this loop */
                   (void *) &dt,        /* pass in dt */
                   step3_timestep_update,       /* update each cell */
                   NULL,        /* there is no callback for the faces between quadrants */
#ifdef P4_TO_P8
                   NULL,        /* there is no callback for the edges between quadrants */
#endif
                   NULL);       /* there is no callback for the corners between quadrants */

    /* synchronize the ghost data */
    p4est_ghost_exchange_data (p4est, ghost, ghost_data);

    /* update du/dx estimate */
    p4est_iterate (p4est, ghost, (void *) ghost_data,   /* pass in ghost data that we just exchanged */
                   step3_reset_derivatives,     /* blank the previously calculated derivatives */
                   step3_minmod_estimate,       /* compute the minmod estimate of each cell's derivative */
#ifdef P4_TO_P8
                   NULL,        /* there is no callback for the edges between quadrants */
#endif
                   NULL);       /* there is no callback for the corners between quadrants */
  }

  P4EST_FREE (ghost_data);
  p4est_ghost_destroy (ghost);
}