Example #1
0
mesh_t* mesh_from_fe_mesh(fe_mesh_t* fe_mesh)
{
  // Feel out the faces for the finite element mesh. Do we need to create 
  // them ourselves, or are they already all there?
  int num_cells = fe_mesh_num_elements(fe_mesh);
  int num_faces = fe_mesh_num_faces(fe_mesh);
  int* cell_face_offsets = polymec_malloc(sizeof(int) * (num_cells + 1));
  cell_face_offsets[0] = 0;
  int* cell_faces = NULL;
  int* face_node_offsets = NULL;
  int* face_nodes = NULL;
  if (num_faces == 0)
  {
    // Traverse the element blocks and figure out the number of faces per cell.
    int pos = 0, elem_offset = 0;
    char* block_name;
    fe_block_t* block;
    while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block))
    {
      int num_block_elem = fe_block_num_elements(block);
      fe_mesh_element_t elem_type = fe_block_element_type(block);
      int num_elem_faces = get_num_cell_faces(elem_type);
      for (int i = 0; i < num_block_elem; ++i)
        cell_face_offsets[elem_offset+i+1] = cell_face_offsets[elem_offset+i] + num_elem_faces;
      elem_offset += num_block_elem;
    }

    // Now assemble the faces for each cell.
    int_tuple_int_unordered_map_t* node_face_map = int_tuple_int_unordered_map_new();
    cell_faces = polymec_malloc(sizeof(int) * cell_face_offsets[num_cells]);

    // We build the face->node connectivity data on-the-fly.
    int_array_t* face_node_offsets_array = int_array_new();
    int_array_append(face_node_offsets_array, 0);
    int_array_t* face_nodes_array = int_array_new();

    pos = 0, elem_offset = 0;
    while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block))
    {
      int num_block_elem = fe_block_num_elements(block);
      fe_mesh_element_t elem_type = fe_block_element_type(block);
      int num_elem_nodes = fe_block_num_element_nodes(block, 0);
      int elem_nodes[num_elem_nodes];
      for (int i = 0; i < num_block_elem; ++i)
      {
        fe_block_get_element_nodes(block, i, elem_nodes);
        int offset = cell_face_offsets[elem_offset+i];
        get_cell_faces(elem_type, elem_nodes, node_face_map, 
                       &cell_faces[offset], face_node_offsets_array,
                       face_nodes_array);
      }
      elem_offset += num_block_elem;
    }

    // Record the total number of faces and discard the map.
    num_faces = node_face_map->size;
    int_tuple_int_unordered_map_free(node_face_map);

    // Gift the contents of the arrays to our pointers.
    face_node_offsets = face_node_offsets_array->data;
    int_array_release_data_and_free(face_node_offsets_array);
    face_nodes = face_nodes_array->data;
    int_array_release_data_and_free(face_nodes_array);
  }
  else
  {
    // Fill in these arrays block by block.
    int pos = 0;
    char* block_name;
    fe_block_t* block;
    int block_cell_offset = 0;
    while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block))
    {
      int num_block_elem = fe_block_num_elements(block);
      for (int i = 0; i < num_block_elem; ++i)
        cell_face_offsets[block_cell_offset+i] = cell_face_offsets[block_cell_offset+i-1] + block->elem_face_offsets[i];
      block_cell_offset += num_block_elem;
    }

    cell_faces = polymec_malloc(sizeof(int) * cell_face_offsets[num_cells]);
    pos = 0, block_cell_offset = 0;
    while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block))
    {
      int num_block_elem = fe_block_num_elements(block);
      memcpy(&cell_faces[cell_face_offsets[block_cell_offset]], block->elem_faces, sizeof(int) * block->elem_face_offsets[num_block_elem]);
      block_cell_offset += num_block_elem;
    }

    // We just borrow these from the mesh. Theeenks!
    face_node_offsets = fe_mesh->face_node_offsets;
    face_nodes = fe_mesh->face_nodes;
  }
  ASSERT(cell_faces != NULL);
  ASSERT(face_node_offsets != NULL);
  ASSERT(face_nodes != NULL);

  // Create the finite volume mesh and set up its cell->face and face->node 
  // connectivity.
  int num_ghost_cells = 0; // FIXME!
  mesh_t* mesh = mesh_new(fe_mesh_comm(fe_mesh), 
                          num_cells, num_ghost_cells, 
                          num_faces,
                          fe_mesh_num_nodes(fe_mesh));
  memcpy(mesh->cell_face_offsets, cell_face_offsets, sizeof(int) * (mesh->num_cells+1));
  memcpy(mesh->face_node_offsets, face_node_offsets, sizeof(int) * (mesh->num_faces+1));
  mesh_reserve_connectivity_storage(mesh);
  memcpy(mesh->cell_faces, cell_faces, sizeof(int) * (mesh->cell_face_offsets[mesh->num_cells]));
  memcpy(mesh->face_nodes, face_nodes, sizeof(int) * (mesh->face_node_offsets[mesh->num_faces]));

  // Set up face->cell connectivity.
  for (int c = 0; c < mesh->num_cells; ++c)
  {
    for (int f = mesh->cell_face_offsets[c]; f < mesh->cell_face_offsets[c+1]; ++f)
    {
      int face = mesh->cell_faces[f];
      if (mesh->face_cells[2*face] == -1)
        mesh->face_cells[2*face] = c;
      else
        mesh->face_cells[2*face+1] = c;
    }
  }

  // Set up face->edge connectivity and edge->node connectivity (if provided).
  if (fe_mesh->face_edges != NULL)
  {
    memcpy(mesh->face_edge_offsets, fe_mesh->face_edge_offsets, sizeof(int) * (mesh->num_faces+1));
    mesh->face_edges = polymec_malloc(sizeof(int) * fe_mesh->face_edge_offsets[mesh->num_faces]);
    memcpy(mesh->face_edges, fe_mesh->face_edges, sizeof(int) * fe_mesh->face_edge_offsets[mesh->num_faces]);
  }
  else
  {
    // Construct edges if we didn't find them.
    mesh_construct_edges(mesh);
  }

  // Copy the node positions into place.
  memcpy(mesh->nodes, fe_mesh_node_positions(fe_mesh), sizeof(point_t) * mesh->num_nodes);

  // Calculate geometry.
  mesh_compute_geometry(mesh);

  // Sets -> tags.
  int pos = 0, *set;
  size_t set_size;
  char* set_name;
  while (fe_mesh_next_element_set(fe_mesh, &pos, &set_name, &set, &set_size))
  {
    int* tag = mesh_create_tag(mesh->cell_tags, set_name, set_size);
    memcpy(tag, set, sizeof(int) * set_size);
  }
  pos = 0;
  while (fe_mesh_next_face_set(fe_mesh, &pos, &set_name, &set, &set_size))
  {
    int* tag = mesh_create_tag(mesh->face_tags, set_name, set_size);
    memcpy(tag, set, sizeof(int) * set_size);
  }
  pos = 0;
  while (fe_mesh_next_edge_set(fe_mesh, &pos, &set_name, &set, &set_size))
  {
    int* tag = mesh_create_tag(mesh->edge_tags, set_name, set_size);
    memcpy(tag, set, sizeof(int) * set_size);
  }
  pos = 0;
  while (fe_mesh_next_node_set(fe_mesh, &pos, &set_name, &set, &set_size))
  {
    int* tag = mesh_create_tag(mesh->node_tags, set_name, set_size);
    memcpy(tag, set, sizeof(int) * set_size);
  }

  // Clean up.
  polymec_free(cell_face_offsets);
  polymec_free(cell_faces);
  if (fe_mesh_num_faces(fe_mesh) == 0)
  {
    polymec_free(face_node_offsets);
    polymec_free(face_nodes);
  }

  return mesh;
}
Example #2
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;
}