Exemple #1
0
static void
p4est_coarsen_old (p4est_t * p4est, int coarsen_recursive,
                   p4est_coarsen_t coarsen_fn, p4est_init_t init_fn)
{
#ifdef P4EST_ENABLE_DEBUG
  size_t              data_pool_size;
#endif
  int                 i, maxlevel;
  int                 couldbegood;
  size_t              zz;
  size_t              incount, removed;
  size_t              cidz, first, last, rest, before;
  p4est_locidx_t      num_quadrants, prev_offset;
  p4est_topidx_t      jt;
  p4est_tree_t       *tree;
  p4est_quadrant_t   *c[P4EST_CHILDREN];
  p4est_quadrant_t   *cfirst, *clast;
  sc_array_t         *tquadrants;

  P4EST_GLOBAL_PRODUCTIONF ("Into " P4EST_STRING
                            "_coarsen_old with %lld total quadrants\n",
                            (long long) p4est->global_num_quadrants);
  p4est_log_indent_push ();
  P4EST_ASSERT (p4est_is_valid (p4est));

  /* loop over all local trees */
  prev_offset = 0;
  for (jt = p4est->first_local_tree; jt <= p4est->last_local_tree; ++jt) {
    tree = p4est_tree_array_index (p4est->trees, jt);
    tquadrants = &tree->quadrants;
#ifdef P4EST_ENABLE_DEBUG
    data_pool_size = 0;
    if (p4est->user_data_pool != NULL) {
      data_pool_size = p4est->user_data_pool->elem_count;
    }
#endif
    removed = 0;

    /* initial log message for this tree */
    P4EST_VERBOSEF ("Into coarsen tree %lld with %llu\n", (long long) jt,
                    (unsigned long long) tquadrants->elem_count);

    /* Initialize array indices.
       If children are coarsened, the array will have an empty window.
       first   index of the first child to be considered
       last    index of the last child before the hole in the array
       before  number of children before the hole in the array
       rest    index of the first child after the hole in the array
     */
    first = last = 0;
    before = rest = 1;

    /* run through the array and coarsen recursively */
    incount = tquadrants->elem_count;
    while (rest + P4EST_CHILDREN - 1 - before < incount) {
      couldbegood = 1;
      for (zz = 0; zz < P4EST_CHILDREN; ++zz) {
        if (zz < before) {
          c[zz] = p4est_quadrant_array_index (tquadrants, first + zz);
          if (zz != (size_t) p4est_quadrant_child_id (c[zz])) {
            couldbegood = 0;
            break;
          }
        }
        else {
          c[zz] = p4est_quadrant_array_index (tquadrants, rest + zz - before);
        }
      }
      if (couldbegood && p4est_quadrant_is_familypv (c) &&
          coarsen_fn (p4est, jt, c)) {
        /* coarsen now */
        for (zz = 0; zz < P4EST_CHILDREN; ++zz) {
          p4est_quadrant_free_data (p4est, c[zz]);
        }
        tree->quadrants_per_level[c[0]->level] -= P4EST_CHILDREN;
        cfirst = c[0];
        p4est_quadrant_parent (c[0], cfirst);
        p4est_quadrant_init_data (p4est, jt, cfirst, init_fn);
        tree->quadrants_per_level[cfirst->level] += 1;
        p4est->local_num_quadrants -= P4EST_CHILDREN - 1;
        removed += P4EST_CHILDREN - 1;

        rest += P4EST_CHILDREN - before;
        if (coarsen_recursive) {
          last = first;
          cidz = (size_t) p4est_quadrant_child_id (cfirst);
          if (cidz > first)
            first = 0;
          else
            first -= cidz;
        }
        else {
          /* don't coarsen again, move the counters and the hole */
          P4EST_ASSERT (first == last && before == 1);
          if (rest < incount) {
            ++first;
            cfirst = p4est_quadrant_array_index (tquadrants, first);
            clast = p4est_quadrant_array_index (tquadrants, rest);
            *cfirst = *clast;
            last = first;
            ++rest;
          }
        }
      }
      else {
        /* do nothing, just move the counters and the hole */
        ++first;
        if (first > last) {
          if (first != rest) {
            cfirst = p4est_quadrant_array_index (tquadrants, first);
            clast = p4est_quadrant_array_index (tquadrants, rest);
            *cfirst = *clast;
          }
          last = first;
          ++rest;
        }
      }
      before = last - first + 1;
    }

    /* adjust final array size */
    first = last;
    if (first + 1 < rest) {
      while (rest < incount) {
        ++first;
        cfirst = p4est_quadrant_array_index (tquadrants, first);
        clast = p4est_quadrant_array_index (tquadrants, rest);
        *cfirst = *clast;
        ++rest;
      }
      sc_array_resize (tquadrants, first + 1);
    }

    /* compute maximum level */
    maxlevel = 0;
    num_quadrants = 0;
    for (i = 0; i <= P4EST_QMAXLEVEL; ++i) {
      P4EST_ASSERT (tree->quadrants_per_level[i] >= 0);
      num_quadrants += tree->quadrants_per_level[i];    /* same type */
      if (tree->quadrants_per_level[i] > 0) {
        maxlevel = i;
      }
    }
    tree->maxlevel = (int8_t) maxlevel;
    tree->quadrants_offset = prev_offset;
    prev_offset += num_quadrants;

    /* do some sanity checks */
    P4EST_ASSERT (num_quadrants == (p4est_locidx_t) tquadrants->elem_count);
    P4EST_ASSERT (tquadrants->elem_count == incount - removed);
    if (p4est->user_data_pool != NULL) {
      P4EST_ASSERT (data_pool_size - removed ==
                    p4est->user_data_pool->elem_count);
    }
    P4EST_ASSERT (p4est_tree_is_sorted (tree));
    P4EST_ASSERT (p4est_tree_is_complete (tree));

    /* final log message for this tree */
    P4EST_VERBOSEF ("Done coarsen tree %lld now %llu\n", (long long) jt,
                    (unsigned long long) tquadrants->elem_count);
  }
  if (p4est->last_local_tree >= 0) {
    for (; jt < p4est->connectivity->num_trees; ++jt) {
      tree = p4est_tree_array_index (p4est->trees, jt);
      tree->quadrants_offset = p4est->local_num_quadrants;
    }
  }

  /* compute global number of quadrants */
  p4est_comm_count_quadrants (p4est);

  P4EST_ASSERT (p4est_is_valid (p4est));
  p4est_log_indent_pop ();
  P4EST_GLOBAL_PRODUCTIONF ("Done " P4EST_STRING
                            "_coarsen_old with %lld total quadrants\n",
                            (long long) p4est->global_num_quadrants);
}
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;
}
Exemple #3
0
p4est_t            *
p4est_new_points (sc_MPI_Comm mpicomm, p4est_connectivity_t * connectivity,
                  int maxlevel, p4est_quadrant_t * points,
                  p4est_locidx_t num_points, p4est_locidx_t max_points,
                  size_t data_size, p4est_init_t init_fn, void *user_pointer)
{
  int                 mpiret;
  int                 num_procs, rank;
  int                 i, isizet;
  size_t              lcount;
  size_t             *nmemb;
#ifdef P4EST_ENABLE_DEBUG
  size_t              zz;
#endif
  p4est_topidx_t      jt, num_trees;
  p4est_topidx_t      first_tree, last_tree, next_tree;
  p4est_quadrant_t   *first_quad, *next_quad, *quad;
  p4est_quadrant_t    a, b, c, f, l, n;
  p4est_tree_t       *tree;
  p4est_t            *p4est;
  p4est_points_state_t ppstate;

  P4EST_GLOBAL_PRODUCTIONF ("Into " P4EST_STRING
                            "_new_points with max level %d max points %lld\n",
                            maxlevel, (long long) max_points);
  p4est_log_indent_push ();
  P4EST_ASSERT (p4est_connectivity_is_valid (connectivity));
  P4EST_ASSERT (max_points >= -1);

  /* retrieve MPI information */
  mpiret = sc_MPI_Comm_size (mpicomm, &num_procs);
  SC_CHECK_MPI (mpiret);
  mpiret = sc_MPI_Comm_rank (mpicomm, &rank);
  SC_CHECK_MPI (mpiret);

  /* This implementation runs in O(P/p * maxlevel)
   * with P the total number of points, p the number of processors.
   * Two optimizations are possible:
   * 1. At startup remove points that lead to duplicate quadrants.
   * 2. Use complete_region between successive points instead of
   *    the call to refine. This should give O(N/p) * maxlevel
   *    with N the total number of quadrants.
   */

  /* parallel sort the incoming points */
  lcount = (size_t) num_points;
  nmemb = P4EST_ALLOC_ZERO (size_t, num_procs);
  isizet = (int) sizeof (size_t);
  mpiret = sc_MPI_Allgather (&lcount, isizet, sc_MPI_BYTE,
                             nmemb, isizet, sc_MPI_BYTE, mpicomm);
  SC_CHECK_MPI (mpiret);
  sc_psort (mpicomm, points, nmemb, sizeof (p4est_quadrant_t),
            p4est_quadrant_compare_piggy);
  P4EST_FREE (nmemb);
#ifdef P4EST_ENABLE_DEBUG
  first_quad = points;
  for (zz = 1; zz < lcount; ++zz) {
    next_quad = points + zz;
    P4EST_ASSERT (p4est_quadrant_compare_piggy (first_quad, next_quad) <= 0);
    first_quad = next_quad;
  }
#endif

  /* create the p4est */
  p4est = P4EST_ALLOC_ZERO (p4est_t, 1);
  ppstate.points = points;
  ppstate.num_points = num_points;
  ppstate.max_points = max_points;
  ppstate.current = 0;
  ppstate.maxlevel = maxlevel;

  /* assign some data members */
  p4est->data_size = 2 * sizeof (p4est_locidx_t);       /* temporary */
  p4est->user_pointer = &ppstate;
  p4est->connectivity = connectivity;
  num_trees = connectivity->num_trees;

  /* create parallel environment */
  p4est_comm_parallel_env_create (p4est, mpicomm);

  /* allocate memory pools */
  p4est->user_data_pool = sc_mempool_new (p4est->data_size);
  p4est->quadrant_pool = sc_mempool_new (sizeof (p4est_quadrant_t));

  P4EST_GLOBAL_PRODUCTIONF ("New " P4EST_STRING
                            " with %lld trees on %d processors\n",
                            (long long) num_trees, num_procs);

  /* allocate trees */
  p4est->trees = sc_array_new (sizeof (p4est_tree_t));
  sc_array_resize (p4est->trees, num_trees);
  for (jt = 0; jt < num_trees; ++jt) {
    tree = p4est_tree_array_index (p4est->trees, jt);
    sc_array_init (&tree->quadrants, sizeof (p4est_quadrant_t));
    P4EST_QUADRANT_INIT (&tree->first_desc);
    P4EST_QUADRANT_INIT (&tree->last_desc);
    tree->quadrants_offset = 0;
    for (i = 0; i <= P4EST_QMAXLEVEL; ++i) {
      tree->quadrants_per_level[i] = 0;
    }
    for (; i <= P4EST_MAXLEVEL; ++i) {
      tree->quadrants_per_level[i] = -1;
    }
    tree->maxlevel = 0;
  }
  p4est->local_num_quadrants = 0;
  p4est->global_num_quadrants = 0;

  /* create point based partition */
  P4EST_QUADRANT_INIT (&f);
  p4est->global_first_position =
    P4EST_ALLOC_ZERO (p4est_quadrant_t, num_procs + 1);
  if (num_points == 0) {
    P4EST_VERBOSE ("Empty processor");
    first_tree = p4est->first_local_tree = -1;
    first_quad = NULL;
  }
  else {
    /* we are probably not empty */
    if (rank == 0) {
      first_tree = p4est->first_local_tree = 0;
      p4est_quadrant_set_morton (&f, maxlevel, 0);
    }
    else {
      first_tree = p4est->first_local_tree = points->p.which_tree;
      p4est_node_to_quadrant (points, maxlevel, &f);
    }
    first_quad = &f;
  }
  last_tree = p4est->last_local_tree = -2;
  p4est_comm_global_partition (p4est, first_quad);
  first_quad = p4est->global_first_position + rank;
  next_quad = p4est->global_first_position + (rank + 1);
  next_tree = next_quad->p.which_tree;
  if (first_tree >= 0 &&
      p4est_quadrant_is_equal (first_quad, next_quad) &&
      first_quad->p.which_tree == next_quad->p.which_tree) {
    /* if all our points are consumed by the next processor we are empty */
    first_tree = p4est->first_local_tree = -1;
  }
  if (first_tree >= 0) {
    /* we are definitely not empty */
    if (next_quad->x == 0 && next_quad->y == 0
#ifdef P4_TO_P8
        && next_quad->z == 0
#endif
      ) {
      last_tree = p4est->last_local_tree = next_tree - 1;
    }
    else {
      last_tree = p4est->last_local_tree = next_tree;
    }
    P4EST_ASSERT (first_tree <= last_tree);
  }

  /* fill the local trees */
  P4EST_QUADRANT_INIT (&a);
  P4EST_QUADRANT_INIT (&b);
  P4EST_QUADRANT_INIT (&c);
  P4EST_QUADRANT_INIT (&l);
  n = *next_quad;
  n.level = (int8_t) maxlevel;
  for (jt = first_tree; jt <= last_tree; ++jt) {
    int                 onlyone = 0;
    int                 includeb = 0;

    tree = p4est_tree_array_index (p4est->trees, jt);

    /* determine first local quadrant of this tree */
    if (jt == first_tree) {
      a = *first_quad;
      a.level = (int8_t) maxlevel;
      first_quad = next_quad = NULL;    /* free to use further down */
      P4EST_ASSERT (p4est_quadrant_is_valid (&a));
    }
    else {
      p4est_quadrant_set_morton (&a, maxlevel, 0);
      P4EST_ASSERT (jt < next_tree || p4est_quadrant_compare (&a, &n) < 0);
    }

    /* enlarge first local quadrant if possible */
    if (jt < next_tree) {
      while (p4est_quadrant_child_id (&a) == 0 && a.level > 0) {
        p4est_quadrant_parent (&a, &a);
      }
      P4EST_ASSERT (jt == first_tree || a.level == 0);
    }
    else {
      for (c = a; p4est_quadrant_child_id (&c) == 0; a = c) {
        p4est_quadrant_parent (&c, &c);
        p4est_quadrant_last_descendant (&c, &l, maxlevel);
        if (p4est_quadrant_compare (&l, &n) >= 0) {
          break;
        }
      }
      P4EST_ASSERT (a.level > 0);
      P4EST_ASSERT ((p4est_quadrant_last_descendant (&a, &l, maxlevel),
                     p4est_quadrant_compare (&l, &n) < 0));
    }
    p4est_quadrant_first_descendant (&a, &tree->first_desc, P4EST_QMAXLEVEL);

    /* determine largest possible last quadrant of this tree */
    if (jt < next_tree) {
      p4est_quadrant_last_descendant (&a, &l, maxlevel);
      p4est_quadrant_set_morton (&b, 0, 0);
      p4est_quadrant_last_descendant (&b, &b, maxlevel);
      if (p4est_quadrant_is_equal (&l, &b)) {
        onlyone = 1;
      }
      else {
        includeb = 1;
        for (c = b; p4est_quadrant_child_id (&c) == P4EST_CHILDREN - 1; b = c) {
          p4est_quadrant_parent (&c, &c);
          p4est_quadrant_first_descendant (&c, &f, maxlevel);
          if (p4est_quadrant_compare (&l, &f) >= 0) {
            break;
          }
        }
      }
    }
    else {
      b = n;
    }

    /* create a complete tree */
    if (onlyone) {
      quad = p4est_quadrant_array_push (&tree->quadrants);
      *quad = a;
      p4est_quadrant_init_data (p4est, jt, quad, p4est_points_init);
      tree->maxlevel = a.level;
      ++tree->quadrants_per_level[a.level];
    }
    else {
      p4est_complete_region (p4est, &a, 1, &b, includeb,
                             tree, jt, p4est_points_init);
      quad = p4est_quadrant_array_index (&tree->quadrants,
                                         tree->quadrants.elem_count - 1);
    }
    tree->quadrants_offset = p4est->local_num_quadrants;
    p4est->local_num_quadrants += tree->quadrants.elem_count;
    p4est_quadrant_last_descendant (quad, &tree->last_desc, P4EST_QMAXLEVEL);

    /* verification */
#ifdef P4EST_ENABLE_DEBUG
    first_quad = p4est_quadrant_array_index (&tree->quadrants, 0);
    for (zz = 1; zz < tree->quadrants.elem_count; ++zz) {
      next_quad = p4est_quadrant_array_index (&tree->quadrants, zz);
      P4EST_ASSERT (((p4est_locidx_t *) first_quad->p.user_data)[1] ==
                    ((p4est_locidx_t *) next_quad->p.user_data)[0]);
      first_quad = next_quad;
    }
#endif
  }
  if (last_tree >= 0) {
    for (; jt < num_trees; ++jt) {
      tree = p4est_tree_array_index (p4est->trees, jt);
      tree->quadrants_offset = p4est->local_num_quadrants;
    }
  }

  /* compute some member variables */
  p4est->global_first_quadrant = P4EST_ALLOC (p4est_gloidx_t, num_procs + 1);
  p4est_comm_count_quadrants (p4est);

  /* print more statistics */
  P4EST_VERBOSEF ("total local quadrants %lld\n",
                  (long long) p4est->local_num_quadrants);

  P4EST_ASSERT (p4est_is_valid (p4est));
  p4est_log_indent_pop ();
  P4EST_GLOBAL_PRODUCTIONF ("Done " P4EST_STRING
                            "_new_points with %lld total quadrants\n",
                            (long long) p4est->global_num_quadrants);

  /* refine to have one point per quadrant */
  if (max_points >= 0) {
    p4est_refine_ext (p4est, 1, maxlevel, p4est_points_refine,
                      p4est_points_init, NULL);
#ifdef P4EST_ENABLE_DEBUG
    for (jt = first_tree; jt <= last_tree; ++jt) {
      tree = p4est_tree_array_index (p4est->trees, jt);
      first_quad = p4est_quadrant_array_index (&tree->quadrants, 0);
      for (zz = 1; zz < tree->quadrants.elem_count; ++zz) {
        next_quad = p4est_quadrant_array_index (&tree->quadrants, zz);
        P4EST_ASSERT (((p4est_locidx_t *) first_quad->p.user_data)[1] ==
                      ((p4est_locidx_t *) next_quad->p.user_data)[0]);
        first_quad = next_quad;
      }
    }
#endif
  }

  /* initialize user pointer and data size */
  p4est_reset_data (p4est, data_size, init_fn, user_pointer);

  return p4est;
}
Exemple #4
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;
}