int read_exoII_file(int Proc, int Num_Proc, PROB_INFO_PTR prob, PARIO_INFO_PTR pio_info, MESH_INFO_PTR mesh) { #ifndef ZOLTAN_NEMESIS Gen_Error(0, "Fatal: Nemesis requested but not linked with driver."); return 0; #else /* ZOLTAN_NEMESIS */ /* Local declarations. */ char *yo = "read_exoII_mesh"; char par_nem_fname[FILENAME_MAX+1], title[MAX_LINE_LENGTH+1]; char cmesg[256]; float ver; int i, pexoid, cpu_ws = 0, io_ws = 0; int *nnodes = NULL, *etypes = NULL; #ifdef DEBUG_EXO int j, k, elem; #endif FILE *fdtmp; /***************************** BEGIN EXECUTION ******************************/ DEBUG_TRACE_START(Proc, yo); /* since this is a test driver, set error reporting in exodus */ ex_opts(EX_VERBOSE | EX_DEBUG); /* generate the parallel filename for this processor */ gen_par_filename(pio_info->pexo_fname, par_nem_fname, pio_info, Proc, Num_Proc); /* * check whether parallel file exists. do the check with fopen * as ex_open coredumps on the paragon when files do not exist. */ if ((fdtmp = fopen(par_nem_fname, "r")) == NULL) { sprintf(cmesg,"fatal: parallel Exodus II file %s does not exist", par_nem_fname); Gen_Error(0, cmesg); return 0; } else fclose(fdtmp); /* * now open the existing parallel file using Exodus calls. */ if ((pexoid = ex_open(par_nem_fname, EX_READ, &cpu_ws, &io_ws, &ver)) < 0) { sprintf(cmesg,"fatal: could not open parallel Exodus II file %s", par_nem_fname); Gen_Error(0, cmesg); return 0; } /* and get initial information */ if (ex_get_init(pexoid, title, &(mesh->num_dims), &(mesh->num_nodes), &(mesh->num_elems), &(mesh->num_el_blks), &(mesh->num_node_sets), &(mesh->num_side_sets)) < 0) { Gen_Error(0, "fatal: Error returned from ex_get_init"); return 0; } /* alocate some memory for the element blocks */ mesh->data_type = MESH; mesh->vwgt_dim = 1; /* One weight for now. */ mesh->ewgt_dim = 1; /* One weight for now. */ mesh->eb_etypes = (int *) malloc (5 * mesh->num_el_blks * sizeof(int)); if (!mesh->eb_etypes) { Gen_Error(0, "fatal: insufficient memory"); return 0; } mesh->eb_ids = mesh->eb_etypes + mesh->num_el_blks; mesh->eb_cnts = mesh->eb_ids + mesh->num_el_blks; mesh->eb_nnodes = mesh->eb_cnts + mesh->num_el_blks; mesh->eb_nattrs = mesh->eb_nnodes + mesh->num_el_blks; mesh->eb_names = (char **) malloc (mesh->num_el_blks * sizeof(char *)); if (!mesh->eb_names) { Gen_Error(0, "fatal: insufficient memory"); return 0; } mesh->hindex = (int *) malloc(sizeof(int)); mesh->hindex[0] = 0; if (ex_get_elem_blk_ids(pexoid, mesh->eb_ids) < 0) { Gen_Error(0, "fatal: Error returned from ex_get_elem_blk_ids"); return 0; } /* allocate temporary storage for items needing global reduction. */ /* nemesis does not store most element block info about blocks for */ /* which the processor owns no elements. */ /* we, however, use this information in migration, so we need to */ /* accumulate it for all element blocks. kdd 2/2001 */ if (mesh->num_el_blks > 0) { nnodes = (int *) malloc(2 * mesh->num_el_blks * sizeof(int)); if (!nnodes) { Gen_Error(0, "fatal: insufficient memory"); return 0; } etypes = nnodes + mesh->num_el_blks; } /* get the element block information */ for (i = 0; i < mesh->num_el_blks; i++) { /* allocate space for name */ mesh->eb_names[i] = (char *) malloc((MAX_STR_LENGTH+1) * sizeof(char)); if (!mesh->eb_names[i]) { Gen_Error(0, "fatal: insufficient memory"); return 0; } if (ex_get_elem_block(pexoid, mesh->eb_ids[i], mesh->eb_names[i], &(mesh->eb_cnts[i]), &(nnodes[i]), &(mesh->eb_nattrs[i])) < 0) { Gen_Error(0, "fatal: Error returned from ex_get_elem_block"); return 0; } if (mesh->eb_cnts[i] > 0) { if ((etypes[i] = (int) get_elem_type(mesh->eb_names[i], nnodes[i], mesh->num_dims)) == E_TYPE_ERROR) { Gen_Error(0, "fatal: could not get element type"); return 0; } } else etypes[i] = (int) NULL_EL; } /* Perform reduction on necessary fields of element blocks. kdd 2/2001 */ MPI_Allreduce(nnodes, mesh->eb_nnodes, mesh->num_el_blks, MPI_INT, MPI_MAX, MPI_COMM_WORLD); MPI_Allreduce(etypes, mesh->eb_etypes, mesh->num_el_blks, MPI_INT, MPI_MIN, MPI_COMM_WORLD); for (i = 0; i < mesh->num_el_blks; i++) { strcpy(mesh->eb_names[i], get_elem_name(mesh->eb_etypes[i])); } free(nnodes); /* * allocate memory for the elements * allocate a little extra for element migration latter */ mesh->elem_array_len = mesh->num_elems + 5; mesh->elements = (ELEM_INFO_PTR) malloc (mesh->elem_array_len * sizeof(ELEM_INFO)); if (!(mesh->elements)) { Gen_Error(0, "fatal: insufficient memory"); return 0; } /* * intialize all of the element structs as unused by * setting the globalID to -1 */ for (i = 0; i < mesh->elem_array_len; i++) initialize_element(&(mesh->elements[i])); /* read the information for the individual elements */ if (!read_elem_info(pexoid, Proc, prob, mesh)) { Gen_Error(0, "fatal: Error returned from read_elem_info"); return 0; } /* read the communication information */ if (!read_comm_map_info(pexoid, Proc, prob, mesh)) { Gen_Error(0, "fatal: Error returned from read_comm_map_info"); return 0; } /* Close the parallel file */ if(ex_close (pexoid) < 0) { Gen_Error(0, "fatal: Error returned from ex_close"); return 0; } /* print out the distributed mesh */ if (Debug_Driver > 3) print_distributed_mesh(Proc, Num_Proc, mesh); DEBUG_TRACE_END(Proc, yo); return 1; #endif /* ZOLTAN_NEMESIS */ }
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); }