Esempio n. 1
0
static void project_nodes(mesh_t* mesh, sp_func_t* boundary_func)
{
  ASSERT(sp_func_has_deriv(boundary_func, 1));

  // Go over the boundary faces and project each of the nodes.
  int_unordered_set_t* projected_nodes = int_unordered_set_new();
  int nfaces;
  int* faces = mesh_tag(mesh->face_tags, sp_func_name(boundary_func), &nfaces);
  for (int f = 0; f < nfaces; ++f)
  {
    int face = faces[f];
    int pos = 0, node;
    while (mesh_face_next_node(mesh, face, &pos, &node))
    {
      if (!int_unordered_set_contains(projected_nodes, node))
      {
        point_t* x = &mesh->nodes[node];
        real_t D, grad[3];
        sp_func_eval(boundary_func, x, &D);
        sp_func_eval_deriv(boundary_func, 1, x, grad);
        real_t G = sqrt(grad[0]*grad[0] + grad[1]*grad[1] + grad[2]*grad[2]);
        if ((D != 0.0) && (G != 0.0))
        {
          x->x -= D * grad[0]/G;
          x->y -= D * grad[1]/G;
          x->z -= D * grad[2]/G;
        }
        int_unordered_set_insert(projected_nodes, node);
      }
    }
  }
  int_unordered_set_free(projected_nodes);
}
Esempio n. 2
0
static mesh_t* create_dual_mesh_from_tet_mesh(MPI_Comm comm, 
                                              mesh_t* tet_mesh,
                                              char** external_model_face_tags,
                                              int num_external_model_face_tags,
                                              char** internal_model_face_tags,
                                              int num_internal_model_face_tags,
                                              char** model_edge_tags,
                                              int num_model_edge_tags,
                                              char** model_vertex_tags,
                                              int num_model_vertex_tags)
{
  // Build sets containing the indices of mesh elements identifying 
  // geometric structure (for ease of querying).

  // External model faces, their edges, and attached tetrahedra.
  int_unordered_set_t* external_boundary_tets = int_unordered_set_new();
  int_unordered_set_t* external_model_faces = int_unordered_set_new();
  int_unordered_set_t* external_model_face_edges = int_unordered_set_new();
  int_unordered_set_t* model_face_nodes = int_unordered_set_new();
  for (int i = 0; i < num_external_model_face_tags; ++i)
  {
    int num_faces;
    int* tag = mesh_tag(tet_mesh->face_tags, external_model_face_tags[i], &num_faces);
    for (int f = 0; f < num_faces; ++f)
    {
      int face = tag[f];
      int_unordered_set_insert(external_model_faces, face);

      int btet1 = tet_mesh->face_cells[2*face];
      int_unordered_set_insert(external_boundary_tets, btet1);
      int btet2 = tet_mesh->face_cells[2*face+1];
      if (btet2 != -1)
        int_unordered_set_insert(external_boundary_tets, btet2);

      int pos = 0, edge, node;
      while (mesh_face_next_edge(tet_mesh, face, &pos, &edge))
        int_unordered_set_insert(external_model_face_edges, edge);
      pos = 0;
      while (mesh_face_next_node(tet_mesh, face, &pos, &node))
        int_unordered_set_insert(model_face_nodes, node);
    }
  }

  // Internal model faces, their edges, and attached tetrahedra.
  int_unordered_set_t* internal_boundary_tets = int_unordered_set_new();
  int_unordered_set_t* internal_model_faces = int_unordered_set_new();
  int_unordered_set_t* internal_model_face_edges = int_unordered_set_new();
  for (int i = 0; i < num_internal_model_face_tags; ++i)
  {
    int num_faces;
    int* tag = mesh_tag(tet_mesh->face_tags, internal_model_face_tags[i], &num_faces);
    for (int f = 0; f < num_faces; ++f)
    {
      int face = tag[f];
      int_unordered_set_insert(internal_model_faces, face);

      int btet1 = tet_mesh->face_cells[2*face];
      int_unordered_set_insert(internal_boundary_tets, btet1);
      int btet2 = tet_mesh->face_cells[2*face+1];
      if (btet2 != -1)
        int_unordered_set_insert(internal_boundary_tets, btet2);

      int pos = 0, edge, node;
      while (mesh_face_next_edge(tet_mesh, face, &pos, &edge))
        int_unordered_set_insert(internal_model_face_edges, edge);
      pos = 0;
      while (mesh_face_next_node(tet_mesh, face, &pos, &node))
        int_unordered_set_insert(model_face_nodes, node);
    }
  }

  // Model edges and nodes belonging to them.
  int_unordered_set_t* model_edges = int_unordered_set_new();
  int_unordered_set_t* model_edge_nodes = int_unordered_set_new();
  for (int i = 0; i < num_model_edge_tags; ++i)
  {
    int num_edges;
    int* tag = mesh_tag(tet_mesh->edge_tags, model_edge_tags[i], &num_edges);
    for (int e = 0; e < num_edges; ++e)
    {
      int edge = tag[e];
      int_unordered_set_insert(model_edges, edge);
      int_unordered_set_insert(model_edge_nodes, tet_mesh->edge_nodes[2*edge]);
      int_unordered_set_insert(model_edge_nodes, tet_mesh->edge_nodes[2*edge+1]);
    }
  }
  int_unordered_set_t* model_vertices = int_unordered_set_new();
  for (int i = 0; i < num_model_vertex_tags; ++i)
  {
    int num_vertices;
    int* tag = mesh_tag(tet_mesh->node_tags, model_vertex_tags[i], &num_vertices);
    for (int v = 0; v < num_vertices; ++v)
    {
      int vertex = tag[v];
      int_unordered_set_insert(model_vertices, vertex);

      // A model vertex should not obey the same rules as a vertex that is 
      // attached to a model edge/face, so remove this vertex from those sets.
      int_unordered_set_delete(model_edge_nodes, vertex);
      int_unordered_set_delete(model_face_nodes, vertex);
    }
  }

  // Each primal edge is surrounded by primal cells and faces, 
  // so we build lists of these cells/faces with which the edges are 
  // associated.
  int_unordered_set_t** primal_cells_for_edge = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_edges);
  int_unordered_set_t** primal_faces_for_edge = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_edges);
  int_unordered_set_t** primal_boundary_faces_for_node = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_nodes);
  memset(primal_cells_for_edge, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_edges);
  memset(primal_faces_for_edge, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_edges);
  memset(primal_boundary_faces_for_node, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_nodes);
  for (int cell = 0; cell < tet_mesh->num_cells; ++cell)
  {
    int pos = 0, face;
    while (mesh_cell_next_face(tet_mesh, cell, &pos, &face))
    {
      int pos1 = 0, edge;
      while (mesh_face_next_edge(tet_mesh, face, &pos1, &edge))
      {
        // Associate the cell with this edge.
        int_unordered_set_t* cells_for_edge = primal_cells_for_edge[edge];
        if (cells_for_edge == NULL)
        {
          cells_for_edge = int_unordered_set_new();
          primal_cells_for_edge[edge] = cells_for_edge;
        }
        int_unordered_set_insert(cells_for_edge, cell);

        // Associate the face with this edge.
        int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge];
        if (faces_for_edge == NULL)
        {
          faces_for_edge = int_unordered_set_new();
          primal_faces_for_edge[edge] = faces_for_edge;
        }
        int_unordered_set_insert(faces_for_edge, face);
      }

      // If the face is on an internal or external boundary, 
      // associate it with each of the edge's nodes.
      if (int_unordered_set_contains(external_model_faces, face) || 
          int_unordered_set_contains(internal_model_faces, face))
      {
        int pos1 = 0, node;
        while (mesh_face_next_node(tet_mesh, face, &pos1, &node))
        {
          int_unordered_set_t* faces_for_node = primal_boundary_faces_for_node[node];
          if (faces_for_node == NULL)
          {
            faces_for_node = int_unordered_set_new();
            primal_boundary_faces_for_node[node] = faces_for_node;
          }
          int_unordered_set_insert(faces_for_node, face);
        }
      }
    }
  }

  // Count up the dual mesh entities.
  int num_dual_nodes = external_model_faces->size + 
                       internal_model_faces->size + tet_mesh->num_cells + 
                       model_edges->size + model_vertices->size;
  int num_dual_faces_from_boundary_vertices = 0;
  // Dual faces for boundary faces attached to primal nodes.
  for (int n = 0; n < tet_mesh->num_nodes; ++n)
  {
    int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[n];
    if (boundary_faces_for_node != NULL)
      num_dual_faces_from_boundary_vertices += boundary_faces_for_node->size;
  }
  {
    // Dual faces for model edges attached to primal nodes.
    int pos = 0, edge;
    while (int_unordered_set_next(model_edges, &pos, &edge))
    {
      int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge];
      int pos1 = 0, face;
      while (int_unordered_set_next(faces_for_edge, &pos1, &face))
      {
        if (int_unordered_set_contains(external_model_faces, face) || 
            int_unordered_set_contains(internal_model_faces, face))
          ++num_dual_faces_from_boundary_vertices;
      }
    }

    // Dual faces for primal nodes that are model vertices.
    int node;
    pos = 0;
    while (int_unordered_set_next(model_vertices, &pos, &node))
    {
      int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node];
      ASSERT(boundary_faces_for_node != NULL);
      num_dual_faces_from_boundary_vertices += boundary_faces_for_node->size;
    }
  }
  int num_dual_faces = tet_mesh->num_edges + external_model_face_edges->size +
                       num_dual_faces_from_boundary_vertices;
  int num_dual_cells = tet_mesh->num_nodes;
  int num_dual_ghost_cells = 0; 
  // FIXME: Figuring out ghost dual cells probably requires parallel communication.

  // Now that we know the various populations, build the dual mesh.
  mesh_t* dual_mesh = mesh_new(comm, num_dual_cells, num_dual_ghost_cells, 
                               num_dual_faces, num_dual_nodes);

  // Generate dual vertices for each of the interior tetrahedra.
  tetrahedron_t* tet = tetrahedron_new();
  int dv_offset = 0;
  for (int c = 0; c < tet_mesh->num_cells; ++c, ++dv_offset)
  {
    // The dual vertex is located at the circumcenter of the tetrahedral 
    // cell, or the point in the cell closest to it.
    point_t xc;
    tetrahedron_compute_circumcenter(tet, &xc);
    tetrahedron_compute_nearest_point(tet, &xc, &dual_mesh->nodes[dv_offset]);
  }

  // Generate dual vertices for each of the model faces. Keep track of which 
  // faces generated which vertices.
  int_int_unordered_map_t* dual_node_for_model_face = int_int_unordered_map_new();
  for (int i = 0; i < num_external_model_face_tags; ++i)
  {
    int num_faces;
    int* tag = mesh_tag(tet_mesh->face_tags, external_model_face_tags[i], &num_faces);
    for (int f = 0; f < num_faces; ++f, ++dv_offset)
    {
      int face = tag[f];
      dual_mesh->nodes[dv_offset] = tet_mesh->face_centers[face];
      int_int_unordered_map_insert(dual_node_for_model_face, face, dv_offset);
    }
  }
  for (int i = 0; i < num_internal_model_face_tags; ++i)
  {
    int num_faces;
    int* tag = mesh_tag(tet_mesh->face_tags, internal_model_face_tags[i], &num_faces);
    for (int f = 0; f < num_faces; ++f, ++dv_offset)
    {
      int face = tag[f];
      dual_mesh->nodes[dv_offset] = tet_mesh->face_centers[face];
      int_int_unordered_map_insert(dual_node_for_model_face, face, dv_offset);
    }
  }

  // Generate a dual vertex at the midpoint of each model edge.
  int_int_unordered_map_t* dual_node_for_edge = int_int_unordered_map_new();
  for (int i = 0; i < num_model_edge_tags; ++i)
  {
    int num_edges;
    int* tag = mesh_tag(tet_mesh->edge_tags, model_edge_tags[i], &num_edges);
    for (int e = 0; e < num_edges; ++e, ++dv_offset)
    {
      int edge = tag[e];
      point_t* x1 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge]];
      point_t* x2 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge+1]];
      point_t* n = &dual_mesh->nodes[dv_offset];
      n->x = 0.5 * (x1->x + x2->x);
      n->y = 0.5 * (x1->y + x2->y);
      n->z = 0.5 * (x1->z + x2->z);
      int_int_unordered_map_insert(dual_node_for_edge, e, dv_offset);
    }
  }

  // Generate a dual vertex for each model vertex.
  for (int i = 0; i < num_model_vertex_tags; ++i)
  {
    int num_vertices;
    int* tag = mesh_tag(tet_mesh->node_tags, model_vertex_tags[i], &num_vertices);
    for (int v = 0; v < num_vertices; ++v, ++dv_offset)
    {
      int vertex = tag[v];
      dual_mesh->nodes[dv_offset] = tet_mesh->nodes[vertex];
    }
  }
  ASSERT(dv_offset == num_dual_nodes);

  // Now generate dual faces corresponding to primal edges. 
  int df_offset = 0;
  dual_mesh->face_node_offsets[0] = 0;
  int_array_t** nodes_for_dual_face = polymec_malloc(sizeof(int_array_t*) * num_dual_faces);
  memset(nodes_for_dual_face, 0, sizeof(int_array_t*) * num_dual_faces);
  for (int edge = 0; edge < tet_mesh->num_edges; ++edge)
  {
    int_unordered_set_t* cells_for_edge = primal_cells_for_edge[edge];
    ASSERT(cells_for_edge != NULL);

    // Is this edge a model edge?
    bool is_external_face_edge = int_unordered_set_contains(external_model_face_edges, edge);
    bool is_internal_face_edge = int_unordered_set_contains(internal_model_face_edges, edge);
    bool is_model_edge = int_unordered_set_contains(model_edges, edge);

    if (is_external_face_edge)
    {
      // This primal edge belongs to an external model face,
      // so it lies on the outside of the domain. The corresponding dual 
      // face is bounded by dual nodes created from the primal cells 
      // bounding the edge. We want to order these dual nodes starting at 
      // one boundary cell and finishing at the other. So we extract the 
      // indices of the dual nodes and then pick out the endpoints.
      int num_nodes = cells_for_edge->size;
      int pos = 0, cell, c = 0;
      point_t dual_nodes[num_nodes];
      int dual_node_indices[num_nodes];
      int endpoint_indices[] = {-1, -1};
      while (int_unordered_set_next(cells_for_edge, &pos, &cell))
      {
        dual_nodes[c] = tet_mesh->cell_centers[cell];
        dual_node_indices[c] = cell;
        if (int_unordered_set_contains(external_boundary_tets, cell))
        {
          if (endpoint_indices[0] == -1)
            endpoint_indices[0] = c;
          else
            endpoint_indices[1] = c;
        }
        ++c;
      }

      // Find a vector connecting the nodes of this edge. This orients 
      // the face.
      vector_t edge_vector;
      point_t* x1 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge]];
      point_t* x2 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge+1]];
      point_displacement(x1, x2, &edge_vector);

      // Order the nodes of this dual face.
      sp_func_t* edge_plane = plane_sp_func_new(&edge_vector, x1);
      order_nodes_of_dual_face(edge_plane, endpoint_indices, dual_nodes, 
          num_nodes, dual_node_indices);

      // Update the dual mesh's face->node connectivity metadata.
      int num_face_nodes = (is_model_edge) ? num_nodes + 1 : num_nodes;
      ASSERT(num_face_nodes >= 3);
      dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_face_nodes;
      int_array_t* face_nodes = int_array_new();
      nodes_for_dual_face[df_offset] = face_nodes;
      int_array_resize(face_nodes, num_face_nodes);
      memcpy(face_nodes->data, dual_node_indices, sizeof(int)*num_nodes);

      // If the edge is a model edge, stick the primal edge's node at the end 
      // of the list of dual face nodes.
      if (is_model_edge)
      {
        int* dual_node_from_edge_p = int_int_unordered_map_get(dual_node_for_edge, edge);
        ASSERT(dual_node_from_edge_p != NULL);
        int dual_node_from_edge = *dual_node_from_edge_p;
        face_nodes->data[num_nodes] = dual_node_from_edge;
      }
      ++df_offset;
    }
    else if (is_internal_face_edge)
    {
      // This primal edge belongs to an internal model face,
      // so it lies on an interface between two regions within the domain. 
      // We create two dual faces for this edge (one for each region), 
      // using a procedure very similar to the one we used for external 
      // edges above.

      // Dump the IDs of the cells attached to the edge into a single array.
      int num_cells = cells_for_edge->size;
      int pos = 0, cell, c = 0;
      point_t dual_nodes[num_cells];
      int dual_node_indices[num_cells];
      while (int_unordered_set_next(cells_for_edge, &pos, &cell))
      {
        dual_nodes[c] = tet_mesh->cell_centers[cell];
        dual_node_indices[c] = cell;
        ++c;
      }

      // Since this is an internal interface edge, the dual nodes 
      // corresponding to these cells form a polygon around the edge. We can 
      // arrange the nodes for the two faces (stuck together) into a polygon 
      // using the "star" algorithm and then retrieve them (in order) from 
      // the polygon.
      polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_cells);
      //        polygon_t* dual_polygon = polygon_star(x0, dual_nodes, num_cells);
      int* ordering = polygon_ordering(dual_polygon);

      // Now we just need to apportion the right nodes to the right faces.
      int start_index1 = -1, start_index2 = -1, stop_index1 = -1, stop_index2 = -1;
      for (int i = 0; i < num_cells; ++i)
      {
        // Follow the cells around the face.
        int this_cell = dual_node_indices[ordering[i]];
        int next_cell = dual_node_indices[ordering[(i+1)%num_cells]];
        if (int_unordered_set_contains(internal_boundary_tets, this_cell) && 
            int_unordered_set_contains(internal_boundary_tets, next_cell))
        {
          // If this_cell and next_cell share a face that is an internal 
          // model face, they are on the opposite side of the interface.
          int shared_face = mesh_cell_face_for_neighbor(tet_mesh, this_cell, next_cell);
          if ((shared_face != -1) && 
              int_unordered_set_contains(internal_model_faces, shared_face))
          {
            if (start_index1 == -1)
            {
              // Face 1 starts on the "next cell," and face 2 ends on 
              // "this cell."
              start_index1 = next_cell;
              stop_index2 = this_cell;
            }
            else
            {
              // Face 2 starts on the "next cell," and face 1 ends on 
              // "this cell."
              start_index2 = next_cell;
              stop_index1 = this_cell;
            }
          }
        }
      }

      // Update the dual mesh's face->node connectivity metadata for 
      // both faces.
      int num_nodes1 = stop_index1 - start_index1 + 1;
      int num_face1_nodes = (is_model_edge) ? num_nodes1 + 1 : num_nodes1;
      ASSERT(num_face1_nodes >= 3);
      dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_face1_nodes;
      int_array_t* face1_nodes = int_array_new();
      nodes_for_dual_face[df_offset] = face1_nodes;
      int_array_resize(face1_nodes, num_nodes1);
      for (int i = start_index1; i <= stop_index1; ++i)
      {
        int j = (start_index1 + i) % num_cells;
        face1_nodes->data[i] = dual_node_indices[ordering[j]];
      }

      int num_nodes2 = stop_index2 - start_index2 + 1;
      int num_face2_nodes = (is_model_edge) ? num_nodes2 + 1 : num_nodes2;
      ASSERT(num_face2_nodes >= 3);
      dual_mesh->face_node_offsets[df_offset+2] = dual_mesh->face_node_offsets[df_offset+1] + num_face2_nodes;
      int_array_t* face2_nodes = int_array_new();
      nodes_for_dual_face[df_offset+1] = face2_nodes;
      int_array_resize(face2_nodes, num_nodes2);
      for (int i = 0; i <= num_nodes2; ++i)
      {
        int j = (start_index2 + i) % num_cells;
        face1_nodes->data[i] = dual_node_indices[ordering[j]];
      }

      // If the edge is a model edge, stick the primal edge's node at the end 
      // of each of the lists of dual face nodes.
      if (is_model_edge)
      {
        int* dual_node_from_edge_p = int_int_unordered_map_get(dual_node_for_edge, edge);
        ASSERT(dual_node_from_edge_p != NULL);
        int dual_node_from_edge = *dual_node_from_edge_p;
        face1_nodes->data[num_nodes1] = dual_node_from_edge;
        face2_nodes->data[num_nodes2] = dual_node_from_edge;
      }
      df_offset += 2;
    }
    else
    {
      // This edge is on the interior of the domain, so it is only bounded 
      // by cells.

      // Dump the cell centers into an array.
      int num_cells = cells_for_edge->size;
      int pos = 0, cell, c = 0;
      point_t dual_nodes[num_cells];
      while (int_unordered_set_next(cells_for_edge, &pos, &cell))
        dual_nodes[c++] = tet_mesh->cell_centers[cell];

      // Update the dual mesh's connectivity metadata.
      dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_cells;

      // Since this is an interior edge, the dual nodes corresponding to 
      // these cells form a convex polygon around the edge. We can arrange 
      // the nodes into a convex polygon using the gift-wrapping algorithm.
      polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_cells);
      int_array_t* face_nodes = int_array_new();
      int_array_resize(face_nodes, num_cells);
      memcpy(face_nodes->data, polygon_ordering(dual_polygon), sizeof(int)*num_cells);
      nodes_for_dual_face[df_offset] = face_nodes;
      dual_polygon = NULL;
      ++df_offset;
    }
  }
  ASSERT(df_offset == num_dual_faces);

  // Create dual faces corresponding to model vertices.
  {
    // Add dual faces for primal nodes attached to model faces.
    int pos = 0, node;
    while (int_unordered_set_next(model_face_nodes, &pos, &node))
    {
      // This rule does not apply to nodes on model edges.
      if (!int_unordered_set_contains(model_edge_nodes, node))
      {
        // Traverse the model faces attached to this node and hook up their 
        // corresponding dual vertices to a new dual face.
        int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node];
        ASSERT(boundary_faces_for_node != NULL);
        int num_dual_nodes = boundary_faces_for_node->size;
        point_t dual_nodes[num_dual_nodes];
        int pos1 = 0, bface, i = 0;
        while (int_unordered_set_next(boundary_faces_for_node, &pos1, &bface))
        {
          // Retrieve the dual node index for this boundary face.
          int* dual_node_p = int_int_unordered_map_get(dual_node_for_model_face, bface);
          ASSERT(dual_node_p != NULL);
          dual_nodes[i] = dual_mesh->nodes[*dual_node_p];
          ++i;
        }

        // Order the dual nodes by constructing a polygonal face.
        polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_dual_nodes);
        int_array_t* face_nodes = int_array_new();
        int_array_resize(face_nodes, num_dual_nodes);
        memcpy(face_nodes->data, polygon_ordering(dual_polygon), sizeof(int)*num_dual_nodes);
        nodes_for_dual_face[df_offset] = face_nodes;
        dual_polygon = NULL;
        ++df_offset;
      }
    }

    // Add dual faces for primal nodes attached to model edges.
    // This can be gross, since some edges may be non-manifold.
    int edge;
    pos = 0;
    while (int_unordered_set_next(model_edges, &pos, &edge))
    { 
      // Traverse the boundary faces attached to this edge.
      int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge];
      int pos1 = 0, face;
      while (int_unordered_set_next(faces_for_edge, &pos1, &face))
      {
        if (int_unordered_set_contains(external_model_faces, face) || 
            int_unordered_set_contains(internal_model_faces, face))
        {
          // FIXME
        }
      }
    }

    // Add dual faces for primal nodes which are model vertices.
    pos = 0;
    while (int_unordered_set_next(model_vertices, &pos, &node))
    { 
      // Traverse the boundary faces attached to this node.
      int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node];
      int pos1 = 0, face;
      while (int_unordered_set_next(boundary_faces_for_node, &pos1, &face))
      {
        // FIXME
      }
    }
  }

  // Create dual cells.
  int dc_offset = 0;
  int_array_t** faces_for_dual_cell = polymec_malloc(sizeof(int_array_t*) * num_dual_cells);
  memset(faces_for_dual_cell, 0, sizeof(int_array_t*) * num_dual_cells);
  // FIXME
  ASSERT(dc_offset == num_dual_cells);

  // Allocate mesh connectivity storage and move all the data into place.
  mesh_reserve_connectivity_storage(dual_mesh);
  for (int c = 0; c < num_dual_cells; ++c)
  {
    int_array_t* cell_faces = faces_for_dual_cell[c];
    memcpy(&dual_mesh->cell_faces[dual_mesh->cell_face_offsets[c]], cell_faces->data, sizeof(int)*cell_faces->size);
    for (int f = 0; f < cell_faces->size; ++f)
    {
      int face = cell_faces->data[f];
      if (dual_mesh->face_cells[2*face] == -1)
        dual_mesh->face_cells[2*face] = c;
      else
        dual_mesh->face_cells[2*face+1] = c;
    }
  }
  for (int f = 0; f < num_dual_faces; ++f)
  {
    int_array_t* face_nodes = nodes_for_dual_face[f];
    memcpy(&dual_mesh->face_nodes[dual_mesh->face_node_offsets[f]], face_nodes->data, sizeof(int)*face_nodes->size);
  }

  // Clean up.
  for (int c = 0; c < num_dual_cells; ++c)
    int_array_free(faces_for_dual_cell[c]);
  polymec_free(faces_for_dual_cell);
  for (int f = 0; f < num_dual_faces; ++f)
    int_array_free(nodes_for_dual_face[f]);
  polymec_free(nodes_for_dual_face);
  for (int e = 0; e < tet_mesh->num_edges; ++e)
  {
    int_unordered_set_free(primal_cells_for_edge[e]);
    int_unordered_set_free(primal_faces_for_edge[e]);
  }
  polymec_free(primal_cells_for_edge);
  polymec_free(primal_faces_for_edge);
  for (int n = 0; n < tet_mesh->num_nodes; ++n)
  {
    if (primal_boundary_faces_for_node[n] != NULL)
      int_unordered_set_free(primal_boundary_faces_for_node[n]);
  }
  polymec_free(primal_boundary_faces_for_node);
  int_int_unordered_map_free(dual_node_for_edge);
  int_int_unordered_map_free(dual_node_for_model_face);
  int_unordered_set_free(model_vertices);
  int_unordered_set_free(model_edges);
  int_unordered_set_free(model_edge_nodes);
  int_unordered_set_free(external_boundary_tets);
  int_unordered_set_free(external_model_faces);
  int_unordered_set_free(external_model_face_edges);
  int_unordered_set_free(model_face_nodes);
  int_unordered_set_free(internal_boundary_tets);
  int_unordered_set_free(internal_model_faces);
  int_unordered_set_free(internal_model_face_edges);

  // Compute mesh geometry.
  mesh_compute_geometry(dual_mesh);

  return dual_mesh;
}
Esempio n. 3
0
mesh_t* crop_mesh(mesh_t* mesh, sp_func_t* boundary_func, mesh_crop_t crop_type)
{
  // Mark the cells whose centers fall outside the boundary.
  int_unordered_set_t* outside_cells = int_unordered_set_new();
  for (int cell = 0; cell < mesh->num_cells; ++cell)
  {
    real_t dist;
    sp_func_eval(boundary_func, &mesh->cell_centers[cell], &dist);
    if (dist > 0.0)
      int_unordered_set_insert(outside_cells, cell);
  }

  // Count up the remaining faces and nodes, and make a list of boundary faces.
  int_unordered_set_t* remaining_ghosts = int_unordered_set_new();
  int_unordered_set_t* boundary_faces = int_unordered_set_new();
  int_int_unordered_map_t* remaining_nodes = int_int_unordered_map_new();
  int_int_unordered_map_t* remaining_faces = int_int_unordered_map_new();
  int new_face_index = 0, new_node_index = 0;
  for (int cell = 0; cell < mesh->num_cells; ++cell)
  {
    if (int_unordered_set_contains(outside_cells, cell)) continue;

    int pos = 0, face;
    while (mesh_cell_next_face(mesh, cell, &pos, &face))
    {
      // This face is still in the mesh.
      if (!int_int_unordered_map_contains(remaining_faces, face))
        int_int_unordered_map_insert(remaining_faces, face, new_face_index++);

      // A boundary face is a face with only one cell attached to it.
      int opp_cell = mesh_face_opp_cell(mesh, face, cell);
      if ((opp_cell == -1) || int_unordered_set_contains(outside_cells, opp_cell))
        int_unordered_set_insert(boundary_faces, face);
      else if (opp_cell >= mesh->num_cells)
        int_unordered_set_insert(remaining_ghosts, opp_cell);
      int pos1 = 0, node;
      while (mesh_face_next_node(mesh, face, &pos1, &node))
      {
        if (!int_int_unordered_map_contains(remaining_nodes, node))
          int_int_unordered_map_insert(remaining_nodes, node, new_node_index++);
      }
    }
  }

  // Convert the face and node maps to arrays.
  int* face_map = polymec_malloc(sizeof(int) * mesh->num_faces);
  for (int i = 0; i < mesh->num_faces; ++i)
    face_map[i] = -1;
  {
    int pos = 0, old_face, new_face;
    while (int_int_unordered_map_next(remaining_faces, &pos, &old_face, &new_face))
      face_map[old_face] = new_face;
  }
  int* node_map = polymec_malloc(sizeof(int) * mesh->num_nodes);
  for (int i = 0; i < mesh->num_nodes; ++i)
    node_map[i] = -1;
  {
    int pos = 0, old_node, new_node;
    while (int_int_unordered_map_next(remaining_nodes, &pos, &old_node, &new_node))
      node_map[old_node] = new_node;
  }

  // Do a partial clean up.
  int num_new_faces = remaining_faces->size;
  int num_new_nodes = remaining_nodes->size;
  int num_new_ghosts = remaining_ghosts->size;
  int_int_unordered_map_free(remaining_nodes);
  int_int_unordered_map_free(remaining_faces);
  int_unordered_set_free(remaining_ghosts);

  // Make a new mesh.
  mesh_t* cropped_mesh = mesh_new(mesh->comm, 
                                  mesh->num_cells - outside_cells->size,
                                  num_new_ghosts, num_new_faces, num_new_nodes);

  // Reserve storage.
  int new_cell = 0;
  cropped_mesh->cell_face_offsets[0] = 0;
  for (int cell = 0; cell < mesh->num_cells; ++cell)
  {
    if (int_unordered_set_contains(outside_cells, cell)) continue;
    int num_cell_faces = mesh_cell_num_faces(mesh, cell);
    cropped_mesh->cell_face_offsets[new_cell+1] = cropped_mesh->cell_face_offsets[new_cell] + num_cell_faces;
    ++new_cell;
  }
  cropped_mesh->face_node_offsets[0] = 0;
  for (int f = 0; f < mesh->num_faces; ++f)
  {
    int new_face = face_map[f];
    if (new_face != -1)
    {
      int num_face_nodes = mesh_face_num_nodes(mesh, f);
      cropped_mesh->face_node_offsets[new_face+1] = num_face_nodes;
    }
  }
  for (int f = 0; f < cropped_mesh->num_faces; ++f)
    cropped_mesh->face_node_offsets[f+1] += cropped_mesh->face_node_offsets[f];
  mesh_reserve_connectivity_storage(cropped_mesh);

  // Hook up the faces and cells.
  new_cell = 0;
  for (int cell = 0; cell < mesh->num_cells; ++cell)
  {
    if (int_unordered_set_contains(outside_cells, cell)) continue;
    int num_cell_faces = mesh_cell_num_faces(mesh, cell);
    for (int f = 0; f < num_cell_faces; ++f)
    {
      int old_face = mesh->cell_faces[mesh->cell_face_offsets[cell]+f];
      int pos_old_face = (old_face >= 0) ? old_face : ~old_face;
      int new_face = face_map[pos_old_face];
      if (cropped_mesh->face_cells[2*new_face] == -1)
        cropped_mesh->face_cells[2*new_face] = new_cell;
      else
        cropped_mesh->face_cells[2*new_face+1] = new_cell;
      if (old_face < 0) new_face = ~new_face;
      cropped_mesh->cell_faces[cropped_mesh->cell_face_offsets[new_cell]+f] = new_face;
    }
    ++new_cell;
  }
  ASSERT(new_cell == cropped_mesh->num_cells);

  // Hook up faces and nodes.
  for (int f = 0; f < mesh->num_faces; ++f)
  {
    int new_face = face_map[f];
    if (new_face != -1)
    {
      int num_face_nodes = mesh_face_num_nodes(mesh, f);
      for (int n = 0; n < num_face_nodes; ++n)
      {
        int old_node = mesh->face_nodes[mesh->face_node_offsets[f]+n];
        int new_node = node_map[old_node];
        cropped_mesh->face_nodes[cropped_mesh->face_node_offsets[new_face]+n] = new_node;
      }
    }
  }

  // Copy node positions.
  for (int n = 0; n < mesh->num_nodes; ++n)
  {
    if (node_map[n] != -1)
      cropped_mesh->nodes[node_map[n]] = mesh->nodes[n];
  }

  // Construct edges.
  mesh_construct_edges(cropped_mesh);
  
  // Create the boundary faces tag.
  int* bf_tag = mesh_create_tag(cropped_mesh->face_tags, sp_func_name(boundary_func), boundary_faces->size);
  int pos = 0, i = 0, face;
  while (int_unordered_set_next(boundary_faces, &pos, &face))
    bf_tag[i++] = face_map[face];

  // Create a new exchanger from the old one.
  {
    exchanger_t* old_ex = mesh_exchanger(mesh);
    exchanger_t* new_ex = mesh_exchanger(cropped_mesh);
    int pos = 0, remote, *indices, num_indices;
    while (exchanger_next_send(old_ex, &pos, &remote, &indices, &num_indices))
    {
      int send_indices[num_indices], j = 0;
      for (int i = 0; i < num_indices; ++i)
        if (!int_unordered_set_contains(outside_cells, indices[i]))
          send_indices[j++] = indices[i];
      exchanger_set_send(new_ex, remote, send_indices, j, true);
    }
    pos = 0;
    while (exchanger_next_receive(old_ex, &pos, &remote, &indices, &num_indices))
    {
      int recv_indices[num_indices], j = 0;
      for (int i = 0; i < num_indices; ++i)
        if (!int_unordered_set_contains(outside_cells, indices[i]))
          recv_indices[j++] = indices[i];
      exchanger_set_receive(new_ex, remote, recv_indices, j, true);
    }
  }

  // Clean up.
  polymec_free(node_map);
  polymec_free(face_map);
  int_unordered_set_free(boundary_faces);
  int_unordered_set_free(outside_cells);

  // Now it remains just to project node positions.
  if (crop_type == PROJECT_NODES)
    project_nodes(cropped_mesh, boundary_func);
  else if (crop_type == PROJECT_FACES)
    project_faces(cropped_mesh, boundary_func);

  // Finally, compute the mesh geometry.
  mesh_compute_geometry(cropped_mesh);

  return cropped_mesh;
}