int* diffWaysToCompute(char* input, int* returnSize) { IntArray operands = int_array(); IntArray operators = int_array(); int count = 0; /* normalize the string into operands and operators */ normalize(input, &operands, &operators, &count); /* use the normalized data to compute */ int* result = diffWaysToCompute2(&operands, &operators, count, 0, returnSize); int_array_free(&operands); int_array_free(&operators); return result; }
neighbor_pairing_t* create_simple_pairing(point_cloud_t* cloud, real_t h) { point_weight_function_t* W = hat_function_new(h); // Toss all the points into a kd-tree. kd_tree_t* tree = kd_tree_new(cloud->points, cloud->num_points); // Now do a neighbor search -- everything that falls within h of a point // is a neighbor. int_array_t* pairs = int_array_new(); real_array_t* weights = real_array_new(); for (int i = 0; i < cloud->num_points; ++i) { point_t* xi = &cloud->points[i]; int_array_t* neighbors = kd_tree_within_radius(tree, &cloud->points[i], h); for (int j = 0; j < neighbors->size; ++j) { int k = neighbors->data[j]; if (k > i) { int_array_append(pairs, i); int_array_append(pairs, k); point_t* xk = &cloud->points[k]; vector_t y; point_displacement(xk, xi, &y); real_array_append(weights, point_weight_function_value(W, &y)); } } int_array_free(neighbors); } kd_tree_free(tree); point_weight_function_free(W); exchanger_t* ex = exchanger_new(MPI_COMM_SELF); neighbor_pairing_t* pairing = neighbor_pairing_new("simple pairing", pairs->size/2, pairs->data, weights->data, ex); int_array_release_data_and_free(pairs); real_array_release_data_and_free(weights); return pairing; }
void fe_mesh_free(fe_mesh_t* mesh) { tagger_free(mesh->elem_sets); tagger_free(mesh->face_sets); tagger_free(mesh->edge_sets); tagger_free(mesh->node_sets); tagger_free(mesh->side_sets); if (mesh->face_nodes != NULL) { polymec_free(mesh->face_nodes); polymec_free(mesh->face_node_offsets); } ptr_array_free(mesh->blocks); string_array_free(mesh->block_names); int_array_free(mesh->block_elem_offsets); polymec_free(mesh->node_coords); polymec_free(mesh); }
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; }
neighbor_pairing_t* distance_based_neighbor_pairing_new(point_cloud_t* points, real_t* R, int* num_ghost_points) { ASSERT(R != NULL); ASSERT(num_ghost_points != NULL); #ifndef NDEBUG for (int i = 0; i < points->num_points; ++i) ASSERT(R[i] > 0.0); #endif // Stick all the points into a kd-tree so that we can pair them up. kd_tree_t* tree = kd_tree_new(points->points, points->num_points); // Find the maximum radius of interaction. real_t R_max = -FLT_MAX; for (int i = 0; i < points->num_points; ++i) R_max = MAX(R_max, R[i]); // Add ghost points to the kd-tree and fetch an exchanger. This may add // too many ghost points, but hopefully that won't be an issue. exchanger_t* ex = kd_tree_find_ghost_points(tree, points->comm, R_max); // We'll toss neighbor pairs into this expandable array. int_array_t* pair_array = int_array_new(); for (int i = 0; i < points->num_points; ++i) { // Find all the neighbors for this point. We only count those // neighbors {j} for which j > i. point_t* xi = &points->points[i]; int_array_t* neighbors = kd_tree_within_radius(tree, xi, R_max); for (int k = 0; k < neighbors->size; ++k) { int j = neighbors->data[k]; if (j > i) { real_t D = point_distance(xi, &points->points[j]); if (D < MAX(R[i], R[j])) { int_array_append(pair_array, i); int_array_append(pair_array, j); } } } int_array_free(neighbors); } // Create a neighbor pairing. int num_pairs = pair_array->size/2; neighbor_pairing_t* neighbors = unweighted_neighbor_pairing_new("Distance-based point pairs", num_pairs, pair_array->data, ex); // Set the number of ghost points referred to within the neighbor pairing. *num_ghost_points = kd_tree_size(tree) - points->num_points; // Clean up. int_array_release_data_and_free(pair_array); // Release control of data. kd_tree_free(tree); return neighbors; }