static int map_nodes_to_face(int_tuple_int_unordered_map_t* node_face_map, int* nodes, int num_nodes, int_array_t* face_node_offsets, int_array_t* face_nodes) { // Sort the nodes and see if they appear in the node face map. int* sorted_nodes = int_tuple_new(num_nodes); memcpy(sorted_nodes, nodes, sizeof(int) * num_nodes); int_qsort(sorted_nodes, num_nodes); int* entry = int_tuple_int_unordered_map_get(node_face_map, sorted_nodes); int face_index; if (entry == NULL) { // Add a new face! face_index = node_face_map->size; int_tuple_int_unordered_map_insert_with_k_dtor(node_face_map, sorted_nodes, face_index, int_tuple_free); // Record the face->node connectivity. int last_offset = face_node_offsets->data[face_node_offsets->size-1]; int_array_append(face_node_offsets, last_offset + num_nodes); for (int n = 0; n < num_nodes; ++n) int_array_append(face_nodes, nodes[n]); } else { face_index = *entry; int_tuple_free(sorted_nodes); } return face_index; }
///<summary> Processes a request from a service to connect to the given peer. </summary> void connectServiceToPeer(POLYM_CONNECTION_INFO *service, uint32_t address, uint16_t port, uint8_t protocol) { // check to see if the peer is already connected int peerID = intAddressConnected(address, port, protocol); // peer is already connected to this client if (peerID != -1) { void *connectionPointer = getConnectionFromPeerID(peerID); POLYM_CONNECTION_INFO *peer = getInfoFromConnection(connectionPointer); // check to see if the peer is already connected to this service if (int_array_find(&service->realm_info.service.status.connectedPeers, peerID) > -1) { // TODO: send PEER_CONNECTION command to service to remind it of the existing peer id it is already associated with } // if not, add it to the service's list of connected peers and vice versa int_array_append(&service->realm_info.service.status.connectedPeers, peerID); lockConnectionMutexByInfo(peer); int_array_append(&peer->realm_info.service.status.connectedPeers, service->connectionID); unlockConnectionMutexByInfo(peer); // TODO: send PEER_CONNECTION command to service to inform it that it is now associated with the peer id } else { // TODO: initiate new connection } }
fe_mesh_t* fe_mesh_new(MPI_Comm comm, int num_nodes) { ASSERT(num_nodes >= 4); fe_mesh_t* mesh = polymec_malloc(sizeof(fe_mesh_t)); mesh->comm = comm; mesh->num_nodes = num_nodes; mesh->blocks = ptr_array_new(); mesh->block_names = string_array_new(); mesh->block_elem_offsets = int_array_new(); int_array_append(mesh->block_elem_offsets, 0); mesh->node_coords = polymec_malloc(sizeof(point_t) * mesh->num_nodes); memset(mesh->node_coords, 0, sizeof(point_t) * mesh->num_nodes); mesh->num_faces = 0; mesh->face_node_offsets = NULL; mesh->face_nodes = NULL; mesh->face_edge_offsets = NULL; mesh->face_edges = NULL; mesh->num_edges = 0; mesh->edge_node_offsets = NULL; mesh->edge_nodes = NULL; mesh->elem_sets = tagger_new(); mesh->face_sets = tagger_new(); mesh->edge_sets = tagger_new(); mesh->node_sets = tagger_new(); mesh->side_sets = tagger_new(); return mesh; }
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; }
int str_grid_cell_filler_start(str_grid_cell_filler_t* cell_filler, str_grid_cell_data_t* data) { ASSERT(str_grid_cell_data_grid(data) == cell_filler->grid); // Dream up a new token for ghost fills. int token = 0; while (int_ptr_unordered_map_contains(cell_filler->tokens, token)) ++token; // Map our token to a list of underlying operation tokens.` int_array_t* op_tokens = int_array_new(); int_ptr_unordered_map_insert_with_v_dtor(cell_filler->tokens, token, op_tokens, DTOR(int_array_free)); // Begin the ghost fill operations and gather tokens. int pos = 0, patch_index; ptr_array_t* fillers; while (int_ptr_unordered_map_next(cell_filler->patch_fillers, &pos, &patch_index, (void**)&fillers)) { int i, j, k; get_patch_indices(cell_filler, patch_index, &i, &j, &k); // Go through all the fillers for this patch. for (int l = 0; l < fillers->size; ++l) { str_grid_patch_filler_t* filler = fillers->data[l]; int op_token = str_grid_patch_filler_start(filler, i, j, k, data); ASSERT((op_token >= 0) || (op_token == -1)); if (op_token != -1) // -1 <-> no finish operation. { // We stash both the patch index and the op token. int_array_append(op_tokens, patch_index); int_array_append(op_tokens, op_token); } } } return token; }
fe_mesh_t* fe_mesh_clone(fe_mesh_t* mesh) { fe_mesh_t* copy = polymec_malloc(sizeof(fe_mesh_t)); copy->comm = mesh->comm; copy->num_nodes = mesh->num_nodes; copy->blocks = ptr_array_new(); for (int i = 0; i < mesh->blocks->size; ++i) copy->blocks->data[i] = fe_block_clone(mesh->blocks->data[i]); copy->block_names = string_array_new(); for (int i = 0; i < mesh->block_names->size; ++i) copy->block_names->data[i] = string_dup(mesh->block_names->data[i]); copy->block_elem_offsets = int_array_new(); for (int i = 0; i < mesh->block_elem_offsets->size; ++i) int_array_append(copy->block_elem_offsets, mesh->block_elem_offsets->data[i]); copy->node_coords = polymec_malloc(sizeof(point_t) * copy->num_nodes); memcpy(copy->node_coords, mesh->node_coords, sizeof(point_t) * copy->num_nodes); return copy; }
void fe_mesh_add_block(fe_mesh_t* mesh, const char* name, fe_block_t* block) { ptr_array_append_with_dtor(mesh->blocks, block, DTOR(fe_block_free)); string_array_append_with_dtor(mesh->block_names, string_dup(name), string_free); int num_block_elements = fe_block_num_elements(block); int num_elements = mesh->block_elem_offsets->data[mesh->block_elem_offsets->size-1] + num_block_elements; int_array_append(mesh->block_elem_offsets, num_elements); // If we are adding a polyhedral block, read off the maximum face and use // that to infer the number of faces in the mesh. if (block->elem_faces != NULL) { int max_face = mesh->num_faces - 1; for (int i = 0; i < block->elem_face_offsets[num_block_elements]; ++i) max_face = MAX(max_face, block->elem_faces[i]); mesh->num_faces = max_face + 1; } }
void create_boundary_generators(ptr_array_t* surface_points, ptr_array_t* surface_normals, ptr_array_t* surface_tags, point_t** boundary_generators, int* num_boundary_generators, char*** tag_names, int_array_t*** tags, int* num_tags) { ASSERT(surface_points->size >= 4); // surface must be closed! ASSERT(surface_points->size == surface_normals->size); ASSERT(surface_points->size == surface_tags->size); int num_surface_points = surface_points->size; // Compute the minimum distance from each surface point to its neighbors. real_t* h_min = polymec_malloc(sizeof(real_t) * num_surface_points); { // Dump the surface points into a kd-tree. point_t* surf_points = polymec_malloc(sizeof(point_t) * num_surface_points); for (int i = 0; i < num_surface_points; ++i) surf_points[i] = *((point_t*)surface_points->data[i]); kd_tree_t* tree = kd_tree_new(surf_points, num_surface_points); int neighbors[2]; for (int i = 0; i < num_surface_points; ++i) { // Find the "nearest 2" points to the ith surface point--the first is // the point itself, and the second is its nearest neighbor. // FIXME: Serious memory error within here. We work around it for // FIXME: the moment by freshing the tree pointer, which is // FIXME: corrupted. ICK! kd_tree_t* tree_p = tree; kd_tree_nearest_n(tree, &surf_points[i], 2, neighbors); tree = tree_p; ASSERT(neighbors[0] == i); ASSERT(neighbors[1] >= 0); ASSERT(neighbors[1] < num_surface_points); h_min[i] = point_distance(&surf_points[i], &surf_points[neighbors[1]]); } // Clean up. kd_tree_free(tree); polymec_free(surf_points); } // Generate boundary points for each surface point based on how many // surfaces it belongs to. ptr_array_t* boundary_points = ptr_array_new(); string_int_unordered_map_t* tag_indices = string_int_unordered_map_new(); ptr_array_t* boundary_tags = ptr_array_new(); for (int i = 0; i < num_surface_points; ++i) { // Add any tags from this point to the set of existing boundary tags. string_slist_t* tags = surface_tags->data[i]; for (string_slist_node_t* t_iter = tags->front; t_iter != NULL; t_iter = t_iter->next) string_int_unordered_map_insert(tag_indices, t_iter->value, tag_indices->size); // Retrieve the surface point. point_t* x_surf = surface_points->data[i]; // Retrieve the list of normal vectors for this surface point. ptr_slist_t* normal_list = surface_normals->data[i]; int num_normals = normal_list->size; vector_t normals[num_normals]; int n_offset = 0; for (ptr_slist_node_t* n_iter = normal_list->front; n_iter != NULL; n_iter = n_iter->next) normals[n_offset++] = *((vector_t*)n_iter->value); // For now, let's keep things relatively simple. if (num_normals > 2) { polymec_error("create_boundary_generators: Too many normal vectors (%d) for surface point %d at (%g, %g, %g)", num_normals, i, x_surf->x, x_surf->y, x_surf->z); } // Create boundary points based on this list of normals. if (num_normals == 1) { // This point only belongs to one surface, so we create boundary points // on either side of it. point_t* x_out = polymec_malloc(sizeof(point_t)); x_out->x = x_surf->x + h_min[i]*normals[0].x; x_out->y = x_surf->y + h_min[i]*normals[0].y; x_out->z = x_surf->z + h_min[i]*normals[0].z; ptr_array_append_with_dtor(boundary_points, x_out, polymec_free); point_t* x_in = polymec_malloc(sizeof(point_t)); x_in->x = x_surf->x - h_min[i]*normals[0].x; x_in->y = x_surf->y - h_min[i]*normals[0].y; x_in->z = x_surf->z - h_min[i]*normals[0].z; ptr_array_append_with_dtor(boundary_points, x_in, polymec_free); } else if (num_normals == 2) { // This point appears at the interface between two surfaces. // (Or so it seems.) ASSERT(vector_dot(&normals[0], &normals[1]) < 0.0); point_t* x1 = polymec_malloc(sizeof(point_t)); x1->x = x_surf->x + h_min[i]*normals[0].x; x1->y = x_surf->y + h_min[i]*normals[0].y; x1->z = x_surf->z + h_min[i]*normals[0].z; ptr_array_append_with_dtor(boundary_points, x1, polymec_free); point_t* x2 = polymec_malloc(sizeof(point_t)); x2->x = x_surf->x - h_min[i]*normals[1].x; x2->y = x_surf->y - h_min[i]*normals[1].y; x2->z = x_surf->z - h_min[i]*normals[1].z; ptr_array_append_with_dtor(boundary_points, x2, polymec_free); } // Tag the boundary point appropriately. ptr_array_append(boundary_tags, tags); // Borrowed ref to tags. } // Move the surface points into a contiguous array. *boundary_generators = polymec_malloc(sizeof(point_t) * boundary_points->size); *num_boundary_generators = boundary_points->size; for (int i = 0; i < boundary_points->size; ++i) { (*boundary_generators)[i] = *((point_t*)boundary_points->data[i]); } // Transcribe the tags. *tag_names = polymec_malloc(sizeof(char*) * tag_indices->size); *tags = polymec_malloc(sizeof(int_array_t*) * tag_indices->size); *num_tags = tag_indices->size; char* tag_name; int pos = 0, tag_index; while (string_int_unordered_map_next(tag_indices, &pos, &tag_name, &tag_index)) { (*tag_names)[tag_index] = string_dup(tag_name); (*tags)[tag_index] = int_array_new(); for (int j = 0; j < *num_boundary_generators; ++j) int_array_append((*tags)[tag_index], tag_index); } // Clean up. string_int_unordered_map_free(tag_indices); polymec_free(h_min); }
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; }
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; }