void test_read_poly_exodus_file(void** state) { exodus_file_t* file = exodus_file_open(MPI_COMM_WORLD, "test-nfaced.exo"); assert_true(file != NULL); assert_true(strcmp(exodus_file_title(file), "This is a test") == 0); fe_mesh_t* mesh = exodus_file_read_mesh(file); assert_int_equal(14, fe_mesh_num_nodes(mesh)); assert_int_equal(1, fe_mesh_num_blocks(mesh)); assert_int_equal(3, fe_mesh_num_elements(mesh)); assert_int_equal(0, fe_mesh_num_element_sets(mesh)); assert_int_equal(0, fe_mesh_num_face_sets(mesh)); assert_int_equal(0, fe_mesh_num_edge_sets(mesh)); assert_int_equal(0, fe_mesh_num_node_sets(mesh)); assert_int_equal(0, fe_mesh_num_side_sets(mesh)); int elem_faces[10]; assert_int_equal(5, fe_mesh_num_element_faces(mesh, 0)); fe_mesh_get_element_faces(mesh, 0, elem_faces); assert_int_equal(0, elem_faces[0]); assert_int_equal(1, elem_faces[1]); assert_int_equal(2, elem_faces[2]); assert_int_equal(3, elem_faces[3]); assert_int_equal(4, elem_faces[4]); assert_int_equal(5, fe_mesh_num_element_faces(mesh, 1)); fe_mesh_get_element_faces(mesh, 1, elem_faces); assert_int_equal(3, elem_faces[0]); assert_int_equal(5, elem_faces[1]); assert_int_equal(6, elem_faces[2]); assert_int_equal(7, elem_faces[3]); assert_int_equal(8, elem_faces[4]); assert_int_equal(7, fe_mesh_num_element_faces(mesh, 2)); fe_mesh_get_element_faces(mesh, 2, elem_faces); assert_int_equal(7, elem_faces[0]); assert_int_equal(9, elem_faces[1]); assert_int_equal(10, elem_faces[2]); assert_int_equal(11, elem_faces[3]); assert_int_equal(12, elem_faces[4]); assert_int_equal(13, elem_faces[5]); assert_int_equal(14, elem_faces[6]); int pos = 0; char* block_name; fe_block_t* block; assert_true(fe_mesh_next_block(mesh, &pos, &block_name, &block)); assert_true(strcmp(block_name, "nfaced_1") == 0); assert_int_equal(5, fe_block_num_element_faces(block, 0)); fe_mesh_free(mesh); exodus_file_close(file); }
int fe_mesh_num_element_faces(fe_mesh_t* mesh, int elem_index) { // Find the block that houses this element. int b = 0; if (mesh->blocks->size > 1) { while ((mesh->block_elem_offsets->data[b] < elem_index) && ((b+1) <= mesh->block_elem_offsets->size)) ++b; if (b == mesh->block_elem_offsets->size-1) return -1; } // Now ask the block about the element. fe_block_t* block = mesh->blocks->data[b]; int e = elem_index - mesh->block_elem_offsets->data[b]; return fe_block_num_element_faces(block, e); }
void exodus_file_write_mesh(exodus_file_t* file, fe_mesh_t* mesh) { ASSERT(file->writing); // See whether we have polyhedral blocks, and whether the non-polyhedral // blocks have supported element types. int num_blocks = fe_mesh_num_blocks(mesh); bool is_polyhedral = false; int pos = 0; char* block_name; fe_block_t* block; while (fe_mesh_next_block(mesh, &pos, &block_name, &block)) { fe_mesh_element_t elem_type = fe_block_element_type(block); if (elem_type == FE_POLYHEDRON) { is_polyhedral = true; break; } else if (elem_type != FE_INVALID) { // Check the number of nodes for the element. if (!element_is_supported(elem_type, fe_block_num_element_nodes(block, 0))) polymec_error("exodus_file_write_mesh: Element type in block %s has invalid number of nodes.", block_name); } else polymec_error("exodus_file_write_mesh: Invalid element type for block %s.", block_name); } // Write out information about elements, faces, edges, nodes. file->num_nodes = fe_mesh_num_nodes(mesh); ex_init_params params; strcpy(params.title, file->title); params.num_dim = 3; params.num_nodes = file->num_nodes; int num_edges = fe_mesh_num_edges(mesh); params.num_edge = num_edges; params.num_edge_blk = 0; int num_faces = fe_mesh_num_faces(mesh); params.num_face = num_faces; params.num_face_blk = (is_polyhedral) ? 1 : 0; int num_elem = fe_mesh_num_elements(mesh); params.num_elem = num_elem; params.num_elem_blk = num_blocks; params.num_elem_sets = file->num_elem_sets = fe_mesh_num_element_sets(mesh); params.num_face_sets = file->num_face_sets = fe_mesh_num_face_sets(mesh); params.num_edge_sets = file->num_edge_sets = fe_mesh_num_edge_sets(mesh); params.num_node_sets = file->num_node_sets = fe_mesh_num_node_sets(mesh); params.num_side_sets = file->num_side_sets = fe_mesh_num_side_sets(mesh); params.num_elem_maps = 0; params.num_face_maps = 0; params.num_edge_maps = 0; params.num_node_maps = 0; ex_put_init_ext(file->ex_id, ¶ms); // If we have any polyhedral element blocks, we write out a single face // block that incorporates all of the polyhedral elements. if (is_polyhedral) { // Generate face->node connectivity information. int num_pfaces = fe_mesh_num_faces(mesh); int face_node_size = 0; int num_face_nodes[num_pfaces]; for (int f = 0; f < num_pfaces; ++f) { int num_nodes = fe_mesh_num_face_nodes(mesh, f); num_face_nodes[f] = num_nodes; face_node_size += num_nodes; } int* face_nodes = polymec_malloc(sizeof(int) * face_node_size); int offset = 0; for (int f = 0; f < num_pfaces; ++f) { fe_mesh_get_face_nodes(mesh, f, &face_nodes[offset]); offset += num_face_nodes[f]; } for (int i = 0; i < face_node_size; ++i) face_nodes[i] += 1; // Write an "nsided" face block. ex_put_block(file->ex_id, EX_FACE_BLOCK, 1, "nsided", num_pfaces, face_node_size, 0, 0, 0); ex_put_name(file->ex_id, EX_FACE_BLOCK, 1, "face_block"); ex_put_conn(file->ex_id, EX_FACE_BLOCK, 1, face_nodes, NULL, NULL); // Clean up. polymec_free(face_nodes); // Number of nodes per face. ex_put_entity_count_per_polyhedra(file->ex_id, EX_FACE_BLOCK, 1, num_face_nodes); } // Go over the element blocks and write out the data. pos = 0; while (fe_mesh_next_block(mesh, &pos, &block_name, &block)) { int elem_block = pos; int num_e = fe_block_num_elements(block); fe_mesh_element_t elem_type = fe_block_element_type(block); if (elem_type == FE_POLYHEDRON) { // Count up the faces in the block and write the block information. int tot_num_elem_faces = 0; int faces_per_elem[num_e]; for (int i = 0; i < num_e; ++i) { faces_per_elem[i] = fe_block_num_element_faces(block, i); tot_num_elem_faces += faces_per_elem[i]; } ex_put_block(file->ex_id, EX_ELEM_BLOCK, elem_block, "nfaced", num_e, 0, 0, tot_num_elem_faces, 0); // Write elem->face connectivity information. int elem_faces[tot_num_elem_faces], offset = 0; for (int i = 0; i < num_e; ++i) { fe_block_get_element_faces(block, i, &elem_faces[offset]); offset += faces_per_elem[i]; } for (int i = 0; i < tot_num_elem_faces; ++i) elem_faces[i] += 1; ex_put_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, NULL, NULL, elem_faces); ex_put_entity_count_per_polyhedra(file->ex_id, EX_ELEM_BLOCK, elem_block, faces_per_elem); } else if (elem_type != FE_INVALID) { // Get element information. char elem_type_name[MAX_NAME_LENGTH+1]; get_elem_name(elem_type, elem_type_name); int num_nodes_per_elem = fe_block_num_element_nodes(block, 0); // Write the block. ex_put_block(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_type_name, num_e, num_nodes_per_elem, 0, 0, 0); // Write the elem->node connectivity. int elem_nodes[num_e* num_nodes_per_elem], offset = 0; for (int i = 0; i < num_e; ++i) { fe_block_get_element_nodes(block, i, &elem_nodes[offset]); offset += num_nodes_per_elem; } for (int i = 0; i < num_e* num_nodes_per_elem; ++i) elem_nodes[i] += 1; ex_put_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_nodes, NULL, NULL); } // Set the element block name. ex_put_name(file->ex_id, EX_ELEM_BLOCK, elem_block, block_name); } // Set node positions. real_t x[file->num_nodes], y[file->num_nodes], z[file->num_nodes]; point_t* X = fe_mesh_node_positions(mesh); for (int n = 0; n < file->num_nodes; ++n) { x[n] = X[n].x; y[n] = X[n].y; z[n] = X[n].z; } ex_put_coord(file->ex_id, x, y, z); char* coord_names[3] = {"x", "y", "z"}; ex_put_coord_names(file->ex_id, coord_names); // Write sets of entities. int *set, set_id = 0; size_t set_size; char* set_name; pos = set_id = 0; while (fe_mesh_next_element_set(mesh, &pos, &set_name, &set, &set_size)) write_set(file, EX_ELEM_SET, ++set_id, set_name, set, set_size); pos = set_id = 0; while (fe_mesh_next_face_set(mesh, &pos, &set_name, &set, &set_size)) write_set(file, EX_FACE_SET, ++set_id, set_name, set, set_size); pos = set_id = 0; while (fe_mesh_next_edge_set(mesh, &pos, &set_name, &set, &set_size)) write_set(file, EX_EDGE_SET, ++set_id, set_name, set, set_size); pos = set_id = 0; while (fe_mesh_next_node_set(mesh, &pos, &set_name, &set, &set_size)) write_set(file, EX_NODE_SET, ++set_id, set_name, set, set_size); pos = set_id = 0; while (fe_mesh_next_side_set(mesh, &pos, &set_name, &set, &set_size)) write_set(file, EX_SIDE_SET, ++set_id, set_name, set, set_size); }