Exemple #1
0
static void
coords_double_to_PetscScalar (sc_array_t * array)
{
  sc_array_t         *newarray;
  size_t              zz, count = array->elem_count;
  P4EST_ASSERT (array->elem_size == 3 * sizeof (double));

  if (sizeof (double) == sizeof (PetscScalar)) {
    return;
  }

  newarray = sc_array_new_size (3 * sizeof (PetscScalar), array->elem_count);
  for (zz = 0; zz < count; zz++) {
    double             *id = (double *) sc_array_index (array, zz);
    PetscScalar        *ip = (PetscScalar *) sc_array_index (newarray, zz);

    ip[0] = (PetscScalar) id[0];
    ip[1] = (PetscScalar) id[1];
    ip[2] = (PetscScalar) id[2];
  }

  sc_array_reset (array);
  sc_array_init_size (array, 3 * sizeof (PetscScalar), count);
  sc_array_copy (array, newarray);
  sc_array_destroy (newarray);
}
static void
p6est_profile_compress (p6est_profile_t * profile)
{
  p4est_locidx_t      nidx, il, old_off, nln =
    profile->lnodes->num_local_nodes;
  p4est_locidx_t (*lr)[2] = (p4est_locidx_t (*)[2]) profile->lnode_ranges;
  sc_array_t         *lc = profile->lnode_columns;
  size_t              old_count = lc->elem_count;
  size_t              new_count;
  sc_array_t         *perm;
  size_t             *newindex;
  size_t              zz, offset;

  if (!old_count) {
    return;
  }
  perm = sc_array_new_size (sizeof (size_t), old_count);
  newindex = (size_t *) sc_array_index (perm, 0);

  for (zz = 0; zz < old_count; zz++) {
    newindex[zz] = old_count;
  }

  offset = 0;

  for (nidx = 0; nidx < nln; nidx++) {
    old_off = lr[nidx][0];
    if (lr[nidx][1]) {
      lr[nidx][0] = offset;
    }
    else {
      P4EST_ASSERT (!lr[nidx][0]);
    }
    for (il = 0; il < lr[nidx][1]; il++) {
      newindex[il + old_off] = offset++;
    }
  }
  new_count = offset;

  for (zz = 0; zz < old_count; zz++) {
    if (newindex[zz] == old_count) {
      newindex[zz] = offset++;
    }
  }

  sc_array_permute (lc, perm, 0);
  sc_array_destroy (perm);
  sc_array_resize (lc, new_count);
}
Exemple #3
0
static void
locidx_pair_to_PetscSFNode (sc_array_t * array)
{
  sc_array_t         *newarray;
  size_t              zz, count = array->elem_count;
  P4EST_ASSERT (array->elem_size == 2 * sizeof (p4est_locidx_t));

  newarray = sc_array_new_size (sizeof (PetscSFNode), array->elem_count);
  for (zz = 0; zz < count; zz++) {
    p4est_locidx_t     *il = (p4est_locidx_t *) sc_array_index (array, zz);
    PetscSFNode        *ip = (PetscSFNode *) sc_array_index (newarray, zz);

    ip->rank = (PetscInt) il[0];
    ip->index = (PetscInt) il[1];
  }

  sc_array_reset (array);
  sc_array_init_size (array, sizeof (PetscSFNode), count);
  sc_array_copy (array, newarray);
  sc_array_destroy (newarray);
}
Exemple #4
0
static void
locidx_to_PetscInt (sc_array_t * array)
{
  sc_array_t         *newarray;
  size_t              zz, count = array->elem_count;
  P4EST_ASSERT (array->elem_size == sizeof (p4est_locidx_t));

  if (sizeof (p4est_locidx_t) == sizeof (PetscInt)) {
    return;
  }

  newarray = sc_array_new_size (sizeof (PetscInt), array->elem_count);
  for (zz = 0; zz < count; zz++) {
    p4est_locidx_t      il = *((p4est_locidx_t *) sc_array_index (array, zz));
    PetscInt           *ip = (PetscInt *) sc_array_index (newarray, zz);

    *ip = (PetscInt) il;
  }

  sc_array_reset (array);
  sc_array_init_size (array, sizeof (PetscInt), count);
  sc_array_copy (array, newarray);
  sc_array_destroy (newarray);
}
Exemple #5
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;
}
Exemple #6
0
static void
test_build_local (sc_MPI_Comm mpicomm)
{
  sc_array_t         *points;
  p4est_connectivity_t *conn;
  p4est_t            *p4est, *built, *copy;
  test_build_t        stb, *tb = &stb;

  /* 0. prepare data that we will reuse */
  tb->maxlevel = 7 - P4EST_DIM;
  tb->counter = -1;
  tb->wrapper = 3;
  tb->init_default = -1;
  tb->init_add = -1;
  tb->count_add = -1;
  tb->last_tree = -1;
  tb->build = NULL;
#ifndef P4_TO_P8
  conn = p4est_connectivity_new_moebius ();
#else
  conn = p8est_connectivity_new_rotcubes ();
#endif /* P4_TO_P8 */
  p4est = p4est_new_ext (mpicomm, conn, 0, 0, 2, 0, NULL, tb);
  p4est_refine (p4est, 1, test_build_refine, NULL);
  p4est_partition (p4est, 0, NULL);

  /* TODO: enrich tests with quadrant data */

  /* 1. Create a p4est that shall be identical to the old one. */

  tb->build = p4est_build_new (p4est, 0, NULL, NULL);
  p4est_search_local (p4est, 0, test_search_local_1, NULL, NULL);
  built = p4est_build_complete (tb->build);
  SC_CHECK_ABORT (p4est_is_equal (p4est, built, 0), "Mismatch build_local 1");
  p4est_destroy (built);

  /* 2. Create a p4est that is as coarse as possible.
   *    Coarsen recursively, compare. */

  tb->build = p4est_build_new (p4est, 4, NULL, NULL);
  p4est_search_local (p4est, 0, test_search_local_2, NULL, NULL);
  built = p4est_build_complete (tb->build);
  copy = p4est_copy (p4est, 0);
  p4est_coarsen (copy, 1, test_build_coarsen, NULL);
  SC_CHECK_ABORT (p4est_is_equal (copy, built, 0), "Mismatch build_local 2");
  p4est_destroy (copy);
  p4est_destroy (built);

  /* 3. Create a p4est with some random pattern for demonstration */

  tb->init_default = 0;
  tb->init_add = 0;
  tb->count_add = 0;
  tb->build = p4est_build_new (p4est, 0, test_search_init_3, tb);
  p4est_build_init_add (tb->build, test_search_init_add_3);
  p4est_search_local (p4est, 1, test_search_local_3, NULL, NULL);
  built = p4est_build_complete (tb->build);
  p4est_build_verify_3 (built);
  SC_CHECK_ABORT (p4est_is_valid (built), "Invalid build_local 3");
  p4est_destroy (built);

  /* 4. Create a p4est from a search with one quadrant per tree */

  tb->init_default = 0;
  tb->init_add = 0;
  tb->count_add = 0;
  tb->last_tree = -1;
  tb->build = p4est_build_new (p4est, sizeof (long), test_search_init_4, tb);
  p4est_build_init_add (tb->build, test_search_init_add_4);
  p4est_search_local (p4est, 0, test_search_local_4, NULL, NULL);
  built = p4est_build_complete (tb->build);
  p4est_build_verify_4 (built);
  SC_CHECK_ABORT (p4est_is_valid (built), "Invalid build_local 4");
  p4est_destroy (built);

  /* 5. Create a p4est from a multiple-item search */

  points = sc_array_new_size (sizeof (int8_t), 2);
  *(int8_t *) sc_array_index (points, 0) = 0;
  *(int8_t *) sc_array_index (points, 1) = 1;
  tb->wrapper = 5;
  tb->init_default = 0;
  tb->init_add = 0;
  tb->build = p4est_build_new (p4est, 0, NULL, tb);
  p4est_search_local (p4est, 0, NULL, test_search_point_5, points);
  built = p4est_build_complete (tb->build);
#if 0
  p4est_build_verify_5 (built);
#endif
  SC_CHECK_ABORT (p4est_is_valid (built), "Invalid build_local 5");
  p4est_destroy (built);
  sc_array_destroy (points);

  /* clean up */
  p4est_destroy (p4est);
  p4est_connectivity_destroy (conn);
}
Exemple #7
0
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;
}