int read_mesh(const std::string &exo_file, Problem_Description* problem, Mesh_Description<INT>* mesh, Weight_Description<INT>* weight ) { float version, *xptr, *yptr, *zptr; char elem_type[MAX_STR_LENGTH+1]; E_Type blk_elem_type; /*---------------------------Execution Begins--------------------------------*/ /* Open the ExodusII file */ int exoid, cpu_ws=0, io_ws=0; int mode = EX_READ | problem->int64api; if((exoid=ex_open(exo_file.c_str(), mode, &cpu_ws, &io_ws, &version)) < 0) { Gen_Error(0, "fatal: unable to open ExodusII mesh file"); return 0; } /* Read the coordinates, if desired */ xptr = yptr = zptr = NULL; if(problem->read_coords == ELB_TRUE) { switch(mesh->num_dims) { case 3: zptr = (mesh->coords)+2*(mesh->num_nodes); /* FALLTHRU */ case 2: yptr = (mesh->coords)+(mesh->num_nodes); /* FALLTHRU */ case 1: xptr = mesh->coords; } if(ex_get_coord(exoid, xptr, yptr, zptr) < 0) { Gen_Error(0, "fatal: unable to read coordinate values for mesh"); return 0; } } /* End "if(problem->read_coords == ELB_TRUE)" */ /* Read the element block IDs */ std::vector<INT> el_blk_ids(mesh->num_el_blks); std::vector<INT> el_blk_cnts(mesh->num_el_blks); if(ex_get_elem_blk_ids(exoid, &el_blk_ids[0]) < 0) { Gen_Error(0, "fatal: unable to read element block IDs"); return 0; } /* Read the element connectivity */ size_t gelem_cnt=0; for(size_t cnt=0; cnt < mesh->num_el_blks; cnt++) { INT nodes_per_elem, num_attr; if(ex_get_elem_block(exoid, el_blk_ids[cnt], elem_type, &(el_blk_cnts[cnt]), &nodes_per_elem, &num_attr) < 0) { Gen_Error(0, "fatal: unable to read element block"); return 0; } blk_elem_type = get_elem_type(elem_type, nodes_per_elem, mesh->num_dims); INT *blk_connect = (INT*)malloc(sizeof(INT)*el_blk_cnts[cnt]*nodes_per_elem); if(!blk_connect) { Gen_Error(0, "fatal: insufficient memory"); return 0; } /* Get the connectivity for this element block */ if(ex_get_elem_conn(exoid, el_blk_ids[cnt], blk_connect) < 0) { Gen_Error(0, "fatal: failed to get element connectivity"); return 0; } /* find out if this element block is weighted */ int wgt = -1; if (weight->type & EL_BLK) wgt = in_list(el_blk_ids[cnt], weight->elemblk); /* Fill the 2D global connectivity array */ if (((problem->type == ELEMENTAL) && (weight->type & EL_BLK)) || ((problem->type == NODAL) && (weight->type & EL_BLK))) { for(int64_t cnt2=0; cnt2 < el_blk_cnts[cnt]; cnt2++) { mesh->elem_type[gelem_cnt] = blk_elem_type; /* while going through the blocks, take care of the weighting */ if ((problem->type == ELEMENTAL) && (weight->type & EL_BLK)) { /* is this block weighted */ if (wgt >= 0) { /* check if there is a read value */ if (weight->vertices[gelem_cnt] >= 1) { /* and if it should be overwritten */ if (weight->ow_read) weight->vertices[gelem_cnt] = weight->elemblk_wgt[wgt]; } else weight->vertices[gelem_cnt] = weight->elemblk_wgt[wgt]; } else { /* now check if this weight has been initialized */ if (weight->vertices[gelem_cnt] < 1) weight->vertices[gelem_cnt] = 1; } } for(int64_t cnt3=0; cnt3 < nodes_per_elem; cnt3++) { INT node = blk_connect[cnt3 + cnt2*nodes_per_elem] - 1; assert(node >= 0); mesh->connect[gelem_cnt][cnt3] = node; /* deal with the weighting if necessary */ if ((problem->type == NODAL) && (weight->type & EL_BLK)) { /* is this block weighted */ if (wgt >= 0) { /* check if I read an exodus file */ if (weight->type & READ_EXO) { /* check if it can be overwritten */ if (weight->ow_read) { /* check if it has been overwritten already */ if (weight->ow[node]) { weight->vertices[node] = MAX(weight->vertices[node], weight->elemblk_wgt[wgt]); } else { weight->vertices[node] = weight->elemblk_wgt[wgt]; weight->ow[node] = 1; /* read value has been overwritten */ } } } else { weight->vertices[node] = MAX(weight->vertices[node], weight->elemblk_wgt[wgt]); } } else { /* now check if this weight has been initialized */ if (weight->vertices[node] < 1) weight->vertices[node] = 1; } } } gelem_cnt++; } } else { // No weights... for (int64_t cnt2=0; cnt2 < el_blk_cnts[cnt]; cnt2++) { mesh->elem_type[gelem_cnt] = blk_elem_type; for (int64_t cnt3=0; cnt3 < nodes_per_elem; cnt3++) { INT node = blk_connect[cnt2*nodes_per_elem + cnt3] - 1; assert(node >= 0); mesh->connect[gelem_cnt][cnt3] = node; } gelem_cnt++; } } /* Free up memory */ free(blk_connect); } /* End "for(cnt=0; cnt < mesh->num_el_blks; cnt++)" */ /* if there is a group designator, then parse it here */ if (problem->groups != NULL) { if (!parse_groups(&el_blk_ids[0], &el_blk_cnts[0], mesh, problem)) { Gen_Error(0, "fatal: unable to parse group designator"); ex_close(exoid); return 0; } } else problem->num_groups = 1; /* there is always one group */ /* Close the ExodusII file */ if(ex_close(exoid) < 0) Gen_Error(0, "warning: failed to close ExodusII mesh file"); return 1; } /*---------------------------End read_mesh()-------------------------------*/
int write_vis(std::string &nemI_out_file, std::string &exoII_inp_file, Machine_Description* machine, Problem_Description* prob, Mesh_Description<INT>* mesh, LB_Description<INT>* lb) { int exid_vis, exid_inp; char title[MAX_LINE_LENGTH+1]; const char *coord_names[] = {"X", "Y", "Z"}; /*-----------------------------Execution Begins------------------------------*/ /* Generate the file name for the visualization file */ std::string vis_file_name = remove_extension(nemI_out_file); vis_file_name += "-vis.exoII"; /* Generate the title for the file */ strcpy(title, UTIL_NAME); strcat(title, " "); strcat(title, ELB_VERSION); strcat(title, " load balance visualization file"); /* * If the vis technique is to be by element block then calculate the * number of element blocks. */ int vis_nelem_blks; if(prob->type == ELEMENTAL) vis_nelem_blks = machine->num_procs; else vis_nelem_blks = machine->num_procs + 1; /* Create the ExodusII file */ std::cout << "Outputting load balance visualization file " << vis_file_name.c_str() << "\n"; int cpu_ws = 0; int io_ws = 0; int mode = EX_CLOBBER; if (prob->int64db|prob->int64api) { mode |= EX_NETCDF4|EX_NOCLASSIC|prob->int64db|prob->int64api; } if((exid_vis=ex_create(vis_file_name.c_str(), mode, &cpu_ws, &io_ws)) < 0) { Gen_Error(0, "fatal: unable to create visualization output file"); return 0; } ON_BLOCK_EXIT(ex_close, exid_vis); /* * Open the original input ExodusII file, read the values for the * element blocks and output them to the visualization file. */ int icpu_ws=0; int iio_ws=0; float vers=0.0; mode = EX_READ | prob->int64api; if((exid_inp=ex_open(exoII_inp_file.c_str(), mode, &icpu_ws, &iio_ws, &vers)) < 0) { Gen_Error(0, "fatal: unable to open input ExodusII file"); return 0; } ON_BLOCK_EXIT(ex_close, exid_inp); char **elem_type = (char**)array_alloc(2, mesh->num_el_blks, MAX_STR_LENGTH+1, sizeof(char)); if(!elem_type) { Gen_Error(0, "fatal: insufficient memory"); return 0; } ON_BLOCK_EXIT(free, elem_type); std::vector<INT> el_blk_ids(mesh->num_el_blks); std::vector<INT> el_cnt_blk(mesh->num_el_blks); std::vector<INT> node_pel_blk(mesh->num_el_blks); std::vector<INT> nattr_el_blk(mesh->num_el_blks); if(ex_get_elem_blk_ids(exid_inp, TOPTR(el_blk_ids)) < 0) { Gen_Error(0, "fatal: unable to get element block IDs"); return 0; } int acc_vis = ELB_TRUE; // Output a different element block per processor if (prob->vis_out == 2) acc_vis = ELB_FALSE; // Output a nodal/element variable showing processor size_t nsize = 0; /* * Find out if the mesh consists of mixed elements. If not then * element blocks will be used to visualize the partitioning. Otherwise * nodal/element results will be used. */ for(size_t ecnt=0; ecnt < mesh->num_el_blks; ecnt++) { if(ex_get_elem_block(exid_inp, el_blk_ids[ecnt], elem_type[ecnt], &el_cnt_blk[ecnt], &node_pel_blk[ecnt], &nattr_el_blk[ecnt]) < 0) { Gen_Error(0, "fatal: unable to get element block parameters"); return 0; } nsize += el_cnt_blk[ecnt]*node_pel_blk[ecnt]; if(strcmp(elem_type[0], elem_type[ecnt]) == 0) { if(node_pel_blk[0] != node_pel_blk[ecnt]) acc_vis = ELB_FALSE; } else acc_vis = ELB_FALSE; } if(acc_vis == ELB_TRUE) { /* Output the initial information */ if(ex_put_init(exid_vis, title, mesh->num_dims, mesh->num_nodes, mesh->num_elems, vis_nelem_blks, 0, 0) < 0) { Gen_Error(0, "fatal: unable to output initial params to vis file"); return 0; } /* Output the nodal coordinates */ float *xptr = nullptr; float *yptr = nullptr; float *zptr = nullptr; switch(mesh->num_dims) { case 3: zptr = (mesh->coords) + 2*mesh->num_nodes; /* FALLTHRU */ case 2: yptr = (mesh->coords) + mesh->num_nodes; /* FALLTHRU */ case 1: xptr = mesh->coords; } if(ex_put_coord(exid_vis, xptr, yptr, zptr) < 0) { Gen_Error(0, "fatal: unable to output coords to vis file"); return 0; } if(ex_put_coord_names(exid_vis, (char**)coord_names) < 0) { Gen_Error(0, "fatal: unable to output coordinate names"); return 0; } std::vector<INT> elem_block(mesh->num_elems); std::vector<INT> elem_map(mesh->num_elems); std::vector<INT> tmp_connect(nsize); for(size_t ecnt=0; ecnt < mesh->num_elems; ecnt++) { elem_map[ecnt] = ecnt+1; if(prob->type == ELEMENTAL) elem_block[ecnt] = lb->vertex2proc[ecnt]; else { int proc = lb->vertex2proc[mesh->connect[ecnt][0]]; int nnodes = get_elem_info(NNODES, mesh->elem_type[ecnt]); elem_block[ecnt] = proc; for(int ncnt=1; ncnt < nnodes; ncnt++) { if(lb->vertex2proc[mesh->connect[ecnt][ncnt]] != proc) { elem_block[ecnt] = machine->num_procs; break; } } } } int ccnt = 0; std::vector<INT> vis_el_blk_ptr(vis_nelem_blks+1); for(INT bcnt=0; bcnt < vis_nelem_blks; bcnt++) { vis_el_blk_ptr[bcnt] = ccnt; int pos = 0; int old_pos = 0; INT* el_ptr = TOPTR(elem_block); size_t ecnt = mesh->num_elems; while(pos != -1) { pos = in_list(bcnt, ecnt, el_ptr); if(pos != -1) { old_pos += pos + 1; ecnt = mesh->num_elems - old_pos; el_ptr = TOPTR(elem_block) + old_pos; int nnodes = get_elem_info(NNODES, mesh->elem_type[old_pos-1]); for(int ncnt=0; ncnt < nnodes; ncnt++) tmp_connect[ccnt++] = mesh->connect[old_pos-1][ncnt] + 1; } } } vis_el_blk_ptr[vis_nelem_blks] = ccnt; /* Output the element map */ if(ex_put_map(exid_vis, TOPTR(elem_map)) < 0) { Gen_Error(0, "fatal: unable to output element number map"); return 0; } /* Output the visualization element blocks */ for(int bcnt=0; bcnt < vis_nelem_blks; bcnt++) { /* * Note this assumes all the blocks contain the same type * element. */ int ecnt = (vis_el_blk_ptr[bcnt+1]-vis_el_blk_ptr[bcnt])/node_pel_blk[0]; if(ex_put_elem_block(exid_vis, bcnt+1, elem_type[0], ecnt, node_pel_blk[0], 0) < 0) { Gen_Error(0, "fatal: unable to output element block params"); return 0; } /* Output the connectivity */ if(ex_put_elem_conn(exid_vis, bcnt+1, &tmp_connect[vis_el_blk_ptr[bcnt]]) < 0) { Gen_Error(0, "fatal: unable to output element connectivity"); return 0; } } } else { /* For nodal/element results visualization of the partioning. */ // Copy the mesh portion to the vis file. ex_copy(exid_inp, exid_vis); /* Set up the file for nodal/element results */ float time_val = 0.0; if(ex_put_time(exid_vis, 1, &time_val) < 0) { Gen_Error(0, "fatal: unable to output time to vis file"); return 0; } const char *var_names[] = {"proc"}; if(prob->type == NODAL) { /* Allocate memory for the nodal values */ std::vector<float> proc_vals(mesh->num_nodes); if(ex_put_variable_param(exid_vis, EX_NODAL, 1) < 0) { Gen_Error(0, "fatal: unable to output var params to vis file"); return 0; } if(ex_put_variable_names(exid_vis, EX_NODAL, 1, (char**)var_names) < 0) { Gen_Error(0, "fatal: unable to output variable name"); return 0; } /* Do some problem specific assignment */ for(size_t ncnt=0; ncnt < mesh->num_nodes; ncnt++) proc_vals[ncnt] = lb->vertex2proc[ncnt]; for(int pcnt=0; pcnt < machine->num_procs; pcnt++) { for(auto & elem : lb->bor_nodes[pcnt]) proc_vals[elem] = machine->num_procs + 1; } /* Output the nodal variables */ if(ex_put_nodal_var(exid_vis, 1, 1, mesh->num_nodes, TOPTR(proc_vals)) < 0) { Gen_Error(0, "fatal: unable to output nodal variables"); return 0; } } else if(prob->type == ELEMENTAL) { /* Allocate memory for the element values */ std::vector<float> proc_vals(mesh->num_elems); if(ex_put_variable_param(exid_vis, EX_ELEM_BLOCK, 1) < 0) { Gen_Error(0, "fatal: unable to output var params to vis file"); return 0; } if(ex_put_variable_names(exid_vis, EX_ELEM_BLOCK, 1, (char**)var_names) < 0) { Gen_Error(0, "fatal: unable to output variable name"); return 0; } /* Do some problem specific assignment */ for(int proc=0; proc < machine->num_procs; proc++) { for (size_t e = 0; e < lb->int_elems[proc].size(); e++) { size_t ecnt = lb->int_elems[proc][e]; proc_vals[ecnt] = proc; } for (size_t e = 0; e < lb->bor_elems[proc].size(); e++) { size_t ecnt = lb->bor_elems[proc][e]; proc_vals[ecnt] = proc; } } /* Output the element variables */ size_t offset = 0; for (size_t i=0; i < mesh->num_el_blks; i++) { if(ex_put_var(exid_vis, 1, EX_ELEM_BLOCK, 1, el_blk_ids[i], el_cnt_blk[i], &proc_vals[offset]) < 0) { Gen_Error(0, "fatal: unable to output nodal variables"); return 0; } offset += el_cnt_blk[i]; } } } return 1; } /*---------------------------End write_vis()-------------------------------*/
int read_mesh_params(const std::string &exo_file, Problem_Description* problem, Mesh_Description<INT>* mesh, Sphere_Info* sphere ) { int exoid, cpu_ws=0, io_ws=0; float version; char elem_type[MAX_STR_LENGTH+1]; /*---------------------------Execution Begins--------------------------------*/ /* Open the ExodusII geometry file */ int mode = EX_READ | problem->int64api; if((exoid=ex_open(exo_file.c_str(), mode, &cpu_ws, &io_ws, &version)) < 0) { Gen_Error(0, "fatal: unable to open ExodusII file for mesh params"); return 0; } /* Get the init info */ ex_init_params exo; if(ex_get_init_ext(exoid, &exo)) { Gen_Error(0, "fatal: unable to get init info from ExodusII file"); ex_close(exoid); return 0; } strcpy(mesh->title, exo.title); mesh->num_dims = exo.num_dim; mesh->num_nodes = exo.num_nodes; mesh->num_elems = exo.num_elem; mesh->num_el_blks = exo.num_elem_blk; mesh->num_node_sets = exo.num_node_sets; mesh->num_side_sets = exo.num_side_sets; /* Get the length of the concatenated node set node list */ if(mesh->num_node_sets > 0) { mesh->ns_list_len = ex_inquire_int(exoid, EX_INQ_NS_NODE_LEN); } else mesh->ns_list_len = 0; /* Allocate and initialize memory for the sphere adjustment */ sphere->adjust = (int*)malloc(sizeof(int)*3*(mesh->num_el_blks)); if(!(sphere->adjust)) { Gen_Error(0, "fatal: insufficient memory"); ex_close(exoid); return 0; } else { sphere->begin = sphere->adjust + mesh->num_el_blks; sphere->end = sphere->begin + mesh->num_el_blks; for(size_t cnt=0; cnt < mesh->num_el_blks; cnt++) { sphere->adjust[cnt] = 0; sphere->begin[cnt] = 0; sphere->end[cnt] = 0; } } std::vector<INT> el_blk_ids(mesh->num_el_blks); /* Read the element block IDs */ if(ex_get_elem_blk_ids(exoid, &el_blk_ids[0]) < 0) { Gen_Error(0, "fatal: unable to get element block IDs"); ex_close(exoid); return 0; } /* Determine the maximum number of nodes per element */ mesh->max_np_elem = 0; for(size_t cnt=0; cnt < mesh->num_el_blks; cnt++) { INT num_elems, idum; INT nodes_in_elem; if(ex_get_elem_block(exoid, el_blk_ids[cnt], elem_type, &num_elems, &nodes_in_elem, &idum) < 0) { Gen_Error(0, "fatal: unable to get element block"); ex_close(exoid); return 0; } if(cnt == 0) sphere->end[0] = num_elems; if(get_elem_type(elem_type, nodes_in_elem, mesh->num_dims) == SPHERE && problem->no_sph != 1) { sphere->num += num_elems; sphere->adjust[cnt] = 0; } else sphere->adjust[cnt] = sphere->num; if(cnt != 0) { sphere->begin[cnt] = sphere->end[cnt-1]; sphere->end[cnt] = sphere->begin[cnt] + num_elems; } mesh->max_np_elem = MAX(mesh->max_np_elem, (size_t)nodes_in_elem); } /* Close the ExodusII file */ if(ex_close(exoid) < 0) Gen_Error(1, "warning: unable to close ExodusII file"); printf("ExodusII mesh information\n"); if(strlen(mesh->title) > 0) printf("\ttitle: %s\n", mesh->title); printf("\tgeometry dimension: "ST_ZU"\n", mesh->num_dims); printf("\tnumber of nodes: "ST_ZU"\tnumber of elements: "ST_ZU"\n", mesh->num_nodes, mesh->num_elems); printf("\tnumber of element blocks: "ST_ZU"\n", mesh->num_el_blks); printf("\tnumber of node sets: "ST_ZU"\tnumber of side sets: "ST_ZU"\n", mesh->num_node_sets, mesh->num_side_sets); return 1; } /*--------------------------End read_mesh_params()-------------------------*/