fe_mesh_t* fe_mesh_from_mesh(mesh_t* fv_mesh, string_array_t* element_block_tags) { fe_mesh_t* fe_mesh = fe_mesh_new(fv_mesh->comm, fv_mesh->num_nodes); if ((element_block_tags != NULL) && (element_block_tags->size > 1)) { // Block-by-block construction. for (int b = 0; b < element_block_tags->size; ++b) { char* tag_name = element_block_tags->data[b]; size_t num_elem; int* block_tag = mesh_tag(fv_mesh->cell_tags, tag_name, &num_elem); int* num_elem_faces = polymec_malloc(sizeof(int) * num_elem); int elem_faces_size = 0; for (int i = 0; i < num_elem; ++i) { int nef = fv_mesh->cell_face_offsets[block_tag[i]+1] - fv_mesh->cell_face_offsets[block_tag[i]]; num_elem_faces[i] = nef; elem_faces_size += nef; } int* elem_faces = polymec_malloc(sizeof(int) * elem_faces_size); int offset = 0; for (int i = 0; i < num_elem; ++i) { for (int f = 0; f < num_elem_faces[i]; ++f, ++offset) elem_faces[offset+f] = fv_mesh->cell_faces[fv_mesh->cell_face_offsets[block_tag[i]+f]]; } fe_block_t* block = polyhedral_fe_block_new((int)num_elem, num_elem_faces, fv_mesh->cell_faces); fe_mesh_add_block(fe_mesh, tag_name, block); polymec_free(num_elem_faces); polymec_free(elem_faces); } } else { // One honking block. int num_elem = fv_mesh->num_cells; int* num_elem_faces = polymec_malloc(sizeof(int) * num_elem); for (int i = 0; i < num_elem; ++i) num_elem_faces[i] = fv_mesh->cell_face_offsets[i+1] - fv_mesh->cell_face_offsets[i]; fe_block_t* block = polyhedral_fe_block_new(num_elem, num_elem_faces, fv_mesh->cell_faces); fe_mesh_add_block(fe_mesh, "block_1", block); polymec_free(num_elem_faces); } // Copy coordinates. memcpy(fe_mesh_node_positions(fe_mesh), fv_mesh->nodes, sizeof(point_t) * fv_mesh->num_nodes); return fe_mesh; }
void test_write_poly_exodus_file(void** state) { fe_mesh_t* mesh = fe_mesh_new(MPI_COMM_WORLD, 14); int num_elem_faces[3] = {5, 5, 7}; int elem_face_indices[] = {0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 7, 9, 10, 11, 12, 13, 14}; fe_block_t* block = polyhedral_fe_block_new(3, num_elem_faces, elem_face_indices); fe_mesh_add_block(mesh, "nfaced_1", block); int num_face_nodes[15] = {2, 2, 3, 3, 3, 2, 2, 3, 3, 4, 4, 3, 3, 3, 3}; int face_nodes[] = {4, 5, 7, 1, 0, 3, 5, 1, 3, 7, 7, 3, 0, 4, 0, 1, 5, 4, 4, 7, 6, 0, 2, 3, 6, 7, 3, 2, 6, 2, 0, 4, 7, 3, 13, 9, 11, 6, 10, 8, 12, 2, 6, 7, 11, 10, 10, 11, 9, 8, 8, 9, 13, 12, 12, 13, 3, 2}; fe_mesh_set_face_nodes(mesh, 15, num_face_nodes, face_nodes); point_t* X = fe_mesh_node_positions(mesh); X[ 0].x = 0.0; X[ 0].y = 0.0; X[ 0].z = 0.0; X[ 1].x = 2.0; X[ 1].y = 0.0; X[ 1].z = 0.0; X[ 2].x = 0.0; X[ 2].y = 2.0; X[ 2].z = 0.0; X[ 3].x = 2.0; X[ 3].y = 2.0; X[ 3].z = 0.0; X[ 4].x = 0.0; X[ 4].y = 0.0; X[ 4].z = 2.0; X[ 5].x = 2.0; X[ 5].y = 0.0; X[ 5].z = 2.0; X[ 6].x = 0.0; X[ 6].y = 2.0; X[ 6].z = 2.0; X[ 7].x = 2.0; X[ 7].y = 2.0; X[ 7].z = 2.0; X[ 8].x = 0.0; X[ 8].y = 3.5; X[ 8].z = 1.0; X[ 9].x = 2.0; X[ 9].y = 3.5; X[ 9].z = 1.0; X[10].x = 0.0; X[10].y = 3.0; X[10].z = 1.0; X[11].x = 2.0; X[11].y = 3.0; X[11].z = 1.0; X[12].x = 0.0; X[12].y = 3.0; X[12].z = 0.5; X[13].x = 2.0; X[13].y = 3.0; X[13].z = 0.5; exodus_file_t* file = exodus_file_new(MPI_COMM_WORLD, "test-nfaced-2.exo"); assert_true(file != NULL); exodus_file_set_title(file, "This is a test"); exodus_file_write_mesh(file, mesh); exodus_file_close(file); fe_mesh_free(mesh); }
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; }
void test_write_exodus_file(void** state) { fe_mesh_t* mesh = fe_mesh_new(MPI_COMM_WORLD, 22); int elem1_node_indices[] = {0, 1, 2, 3, 4, 5, 6, 7}; fe_block_t* block = fe_block_new(1, FE_HEXAHEDRON, 8, elem1_node_indices); fe_mesh_add_block(mesh, "block_1", block); int elem2_node_indices[] = {8, 9, 10, 11}; block = fe_block_new(1, FE_TETRAHEDRON, 4, elem2_node_indices); fe_mesh_add_block(mesh, "block_2", block); int elem3_node_indices[] = {12, 13, 14, 15, 16, 17}; block = fe_block_new(1, FE_WEDGE, 6, elem3_node_indices); fe_mesh_add_block(mesh, "block_3", block); int elem4_node_indices[] = {18, 19, 20, 21}; block = fe_block_new(1, FE_TETRAHEDRON, 4, elem4_node_indices); fe_mesh_add_block(mesh, "block_4", block); point_t* X = fe_mesh_node_positions(mesh); X[ 0].x = 0.0; X[ 0].y = 0.0; X[ 0].z = 0.0; X[ 1].x = 10.0; X[ 1].y = 0.0; X[ 1].z = 0.0; X[ 2].x = 10.0; X[ 2].y = 0.0; X[ 2].z = -10.0; X[ 3].x = 1.0; X[ 3].y = 0.0; X[ 3].z = -10.0; X[ 4].x = 0.0; X[ 4].y = 10.0; X[ 4].z = 0.0; X[ 5].x = 10.0; X[ 5].y = 10.0; X[ 5].z = 0.0; X[ 6].x = 10.0; X[ 6].y = 10.0; X[ 6].z = -10.0; X[ 7].x = 1.0; X[ 7].y = 10.0; X[ 7].z = -10.0; X[ 8].x = 0.0; X[ 8].y = 0.0; X[ 8].z = 0.0; X[ 9].x = 1.0; X[ 9].y = 0.0; X[ 9].z = 5.0; X[10].x = 10.0; X[10].y = 0.0; X[10].z = 2.0; X[11].x = 7.0; X[11].y = 5.0; X[11].z = 3.0; X[12].x = 3.0; X[12].y = 0.0; X[12].z = 6.0; X[13].x = 6.0; X[13].y = 0.0; X[13].z = 0.0; X[14].x = 0.0; X[14].y = 0.0; X[14].z = 0.0; X[15].x = 3.0; X[15].y = 2.0; X[15].z = 6.0; X[16].x = 6.0; X[16].y = 2.0; X[16].z = 2.5; X[17].x = 2.0; X[17].y = 2.0; X[17].z = 0.0; X[18].x = 2.7; X[18].y = 1.7; X[18].z = 2.7; X[19].x = 6.0; X[19].y = 1.7; X[19].z = 3.3; X[20].x = 5.7; X[20].y = 1.7; X[20].z = 1.7; X[21].x = 3.7; X[21].y = 0.0; X[21].z = 2.3; // Node sets. int* ns1 = fe_mesh_create_node_set(mesh, "nset_1", 5); ns1[0] = 1; ns1[1] = 2; ns1[2] = 3; ns1[3] = 4; ns1[4] = 5; int* ns2 = fe_mesh_create_node_set(mesh, "nset_2", 3); ns2[0] = 11; ns2[1] = 12; ns2[2] = 13; // Side set. int* ss1 = fe_mesh_create_side_set(mesh, "sset_1", 1); ss1[0] = 0; ss1[1] = 5; exodus_file_t* file = exodus_file_new(MPI_COMM_WORLD, "test-3d.exo"); assert_true(file != NULL); exodus_file_set_title(file, "This is a test"); exodus_file_write_mesh(file, mesh); exodus_file_close(file); fe_mesh_free(mesh); }
fe_mesh_t* exodus_file_read_mesh(exodus_file_t* file) { // Create the "host" FE mesh. fe_mesh_t* mesh = fe_mesh_new(file->comm, file->num_nodes); // Count up the number of polyhedral blocks. int num_poly_blocks = 0; for (int i = 0; i < file->num_elem_blocks; ++i) { int elem_block = file->elem_block_ids[i]; char elem_type_name[MAX_NAME_LENGTH+1]; int num_elem, num_nodes_per_elem, num_faces_per_elem; ex_get_block(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_type_name, &num_elem, &num_nodes_per_elem, NULL, &num_faces_per_elem, NULL); fe_mesh_element_t elem_type = get_element_type(elem_type_name); if (elem_type == FE_POLYHEDRON) ++num_poly_blocks; } // If we have any polyhedral element blocks, we read a single face // block that incorporates all of the polyhedral elements. if (num_poly_blocks > 0) { // Dig up the face block corresponding to this element block. char face_type[MAX_NAME_LENGTH+1]; int num_faces, num_nodes; ex_get_block(file->ex_id, EX_FACE_BLOCK, file->face_block_ids[0], face_type, &num_faces, &num_nodes, NULL, NULL, NULL); if (string_ncasecmp(face_type, "nsided", 6) != 0) { fe_mesh_free(mesh); ex_close(file->ex_id); polymec_error("Invalid face type for polyhedral element block."); } // Find the number of nodes for each face in the block. int* num_face_nodes = polymec_malloc(sizeof(int) * num_faces); ex_get_entity_count_per_polyhedra(file->ex_id, EX_FACE_BLOCK, file->face_block_ids[0], num_face_nodes); // Read face->node connectivity information. int face_node_size = 0; for (int i = 0; i < num_faces; ++i) face_node_size += num_face_nodes[i]; int* face_nodes = polymec_malloc(sizeof(int) * face_node_size); ex_get_conn(file->ex_id, EX_FACE_BLOCK, 1, face_nodes, NULL, NULL); for (int i = 0; i < face_node_size; ++i) face_nodes[i] -= 1; fe_mesh_set_face_nodes(mesh, num_faces, num_face_nodes, face_nodes); // Clean up. polymec_free(num_face_nodes); } // Go over the element blocks and feel out the data. for (int i = 0; i < file->num_elem_blocks; ++i) { int elem_block = file->elem_block_ids[i]; char elem_type_name[MAX_NAME_LENGTH+1]; int num_elem, num_nodes_per_elem, num_faces_per_elem; ex_get_block(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_type_name, &num_elem, &num_nodes_per_elem, NULL, &num_faces_per_elem, NULL); // Get the type of element for this block. fe_mesh_element_t elem_type = get_element_type(elem_type_name); fe_block_t* block = NULL; char block_name[MAX_NAME_LENGTH+1]; if (elem_type == FE_POLYHEDRON) { // Find the number of faces for each element in the block. int* num_elem_faces = polymec_malloc(sizeof(int) * num_elem); ex_get_entity_count_per_polyhedra(file->ex_id, EX_ELEM_BLOCK, elem_block, num_elem_faces); // Get the element->face connectivity. int elem_face_size = 0; for (int j = 0; j < num_elem; ++j) elem_face_size += num_elem_faces[j]; int* elem_faces = polymec_malloc(sizeof(int) * elem_face_size); ex_get_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, NULL, NULL, elem_faces); // Subtract 1 from each element face. for (int j = 0; j < elem_face_size; ++j) elem_faces[j] -= 1; // Create the element block. block = polyhedral_fe_block_new(num_elem, num_elem_faces, elem_faces); } else if (elem_type != FE_INVALID) { // Get the element's nodal mapping. int* node_conn = polymec_malloc(sizeof(int) * num_elem * num_nodes_per_elem); ex_get_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, node_conn, NULL, NULL); // Subtract 1 from each element node. for (int j = 0; j < num_elem * num_nodes_per_elem; ++j) node_conn[j] -= 1; // Build the element block. block = fe_block_new(num_elem, elem_type, num_nodes_per_elem, node_conn); } else { fe_mesh_free(mesh); ex_close(file->ex_id); polymec_error("Block %d contains an invalid (3D) element type.", elem_block); } // Fish out the element block name if it has one, or make a default. ex_get_name(file->ex_id, EX_ELEM_BLOCK, elem_block, block_name); if (strlen(block_name) == 0) sprintf(block_name, "block_%d", elem_block); // Add the element block to the mesh. fe_mesh_add_block(mesh, block_name, block); } // Fetch node positions and compute geometry. real_t x[file->num_nodes], y[file->num_nodes], z[file->num_nodes]; ex_get_coord(file->ex_id, x, y, z); point_t* X = fe_mesh_node_positions(mesh); for (int n = 0; n < file->num_nodes; ++n) { X[n].x = x[n]; X[n].y = y[n]; X[n].z = z[n]; } // Fetch sets of entities. for (int i = 1; i <= file->num_elem_sets; ++i) fetch_set(file, EX_ELEM_SET, i, mesh, fe_mesh_create_element_set); for (int i = 1; i <= file->num_face_sets; ++i) fetch_set(file, EX_FACE_SET, i, mesh, fe_mesh_create_face_set); for (int i = 1; i <= file->num_edge_sets; ++i) fetch_set(file, EX_EDGE_SET, i, mesh, fe_mesh_create_edge_set); for (int i = 1; i <= file->num_node_sets; ++i) fetch_set(file, EX_NODE_SET, i, mesh, fe_mesh_create_node_set); for (int i = 1; i <= file->num_side_sets; ++i) fetch_set(file, EX_SIDE_SET, i, mesh, fe_mesh_create_side_set); return mesh; }
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); }