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; }
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; }