/* * Copyright (c) 2005 Sandia Corporation. Under the terms of Contract * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Governement * retains certain rights in this software. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * * Neither the name of Sandia Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include "exodusII.h" #include "exodusII_int.h" /*! The function ex_cvt_nodes_to_sides() is used to convert a side set node list to a side set side list. This routine is provided for application programs that utilize side sets defined by nodes (as was done previous to release 2.0) rather than local faces or edges. The application program must allocate memory for the returned array of sides. The length of this array is the same as the length of the concatenated side sets element list, which can be determined with a call to ex_inquire() or ex_inquire_int(). \return In case of an error, ex_cvt_nodes_to_sides() returns a negative number; a warning will return a positive number. Possible causes of errors include: - a warning value is returned if no side sets are stored in the file. - because the faces of a wedge require a different number of nodes to describe them (quadrilateral vs. triangular faces), the function will abort with a fatal return code if a wedge is encountered in the side set element list. \param[in] exoid exodus file ID returned from a previous call to ex_create() or ex_open(). \param[in] num_elem_per_set Array containing the number of sides for each set. The number of sides is equal to the number of elements for each set. \param[in] num_nodes_per_set Array containing the number of nodes for each set. \param[in] side_sets_elem_index Array containing indices into the \c side_sets_elem_list which are the locations of the first element for each set. These indices are 0-based. Unused. \param[in] side_sets_node_index Array containing indices into the \c side_sets_node_list which are the locations of the first node for each set. These indices are 0-based. Unused. \param[in] side_sets_elem_list Array containing the elements for all side sets. Internal element IDs are used in this list (see Section LocalElementIds). \param[in] side_sets_node_list Array containing the nodes for all side sets. Internal node IDs are used in this list (see Section LocalNodeIds). \param[out] side_sets_side_list Returned array containing the sides for all side sets. The following code segment will convert side sets described by nodes to side sets described by local side numbers: \code int error, exoid, ids[2], num_side_per_set[2], num_nodes_per_set[2], elem_ind[2], node_ind[2], elem_list[4], node_list[8], el_lst_len, *side_list; ids[0] = 30 ; ids[1] = 31; num_side_per_set[0] = 2; num_side_per_set[1] = 2; num_nodes_per_set[0] = 4; num_nodes_per_set[1] = 4; elem_ind[0] = 0; elem_ind[1] = 2; node_ind[0] = 0; node_ind[1] = 4; \comment{side set #1} elem_list[0] = 2; elem_list[1] = 2; node_list[0] = 8; node_list[1] = 5; node_list[2] = 6; node_list[3] = 7; \comment{side set #2} elem_list[2] = 1; elem_list[3] = 2; node_list[4] = 2; node_list[5] = 3; node_list[6] = 7; node_list[7] = 8; el_lst_len = ex_inquire_int(exoid, EX_INQ_SS_ELEM_LEN); \comment{side set element list is same length as side list} side_list = (int *) calloc (el_lst_len, sizeof(int)); ex_cvt_nodes_to_sides(exoid, num_side_per_set, num_nodes_per_set, elem_ind, node_ind, elem_list, node_list, side_list); \endcode Algorithm: \verbatim Read elem_block_ids --> elem_blk_id[array] Read element block parameters --> elem_blk_parms[array] Determine total number of elements in side set by summing num_elem_per_set Build side set element to side set node list index --> ss_elem_node_ndx[array] For each element in the side_set_elem_list { If Jth element is not in current element block (e.g. J>elem_ctr) { get element block parameters (num_elem_in_blk, ...) elem_ctr += num_elem_in_blk free old connectity array space allocate connectivity array: size=num_elem_in_blk*num_nodes_per_elem get connectivity array } If Jth element is in current element block (e.g. J<=elem_ctr) { For each node in element (linear search of up to num_nodes_per_elem) { If side set element node[1] == element node[i] { Case element type = Hex { If side set element node[2] == element node[Hex_table[i,1]] Jth side = Hex_table[i,2] break } Case element type = Wedge { If side set element node[2] == element node[Wedge_table[i,1]] Jth side = Wedge_table[i,2] break } } } } } \endverbatim */ int ex_cvt_nodes_to_sides(int exoid, int *num_elem_per_set, int *num_nodes_per_set, int *side_sets_elem_index, /* unused */ int *side_sets_node_index, /* unused */ int *side_sets_elem_list, int *side_sets_node_list, int *side_sets_side_list) { size_t m; int i, j, k, n; int num_side_sets, num_elem_blks; int tot_num_elem = 0, tot_num_ss_elem = 0, elem_num = 0, ndim; int *elem_blk_ids = NULL; int *connect = NULL; int *ss_elem_ndx, *ss_elem_node_ndx, *ss_parm_ndx; int elem_ctr, node_ctr, elem_num_pos; int num_elem_in_blk, num_nodes_per_elem, num_node_per_side, num_attr; int *same_elem_type = NULL; int el_type = 0; float fdum; char *cdum, elem_type[MAX_STR_LENGTH+1]; struct elem_blk_parm *elem_blk_parms; /* node to side translation tables - These tables are used to look up the side number based on the first and second node in the side/face list. The side node order is found in the original Exodus document, SAND87-2997. The element node order is found in the ExodusII document, SAND92-2137. These tables were generated by following the right-hand rule for determining the outward normal. Note: Only the more complex 3-D shapes require these tables, the simple shapes are trivial - the first node found is also the side number. */ /* 1 2 3 4 node 1 */ static int shell_table[2][8] = { {2,4, 3,1, 4,2, 1,3}, /* node 2 */ {1,2, 1,2, 1,2, 1,2} /* side # */ }; /* 1 2 3 4 node 1 */ static int shell_edge_table[2][8] = { {2,4, 3,1, 4,2, 1,3}, /* node 2 */ {3,6, 4,3, 5,4, 6,5} /* side # */ }; /* 1 2 3 node 1 */ static int trishell_table[2][6] = { {2,3, 3,1, 1,2}, /* node 2 */ {1,2, 1,2, 1,2} /* side # */ }; /* 1 2 3 4 node 1 */ static int tetra_table[2][12] = { {2,3,4, 1,3,4, 4,1,2, 1,2,3}, /* node 2 */ {1,4,3, 4,2,1, 2,3,4, 1,2,3} /* side # */ }; #if 0 static int wedge_table[2][18] = { /* 1 2 3 4 5 6 node 1 */ {2,4,3, 5,1,3, 6,1,2, 1,6,5, 6,2,4, 4,3,5}, /* node 2 */ {1,3,4, 1,4,2, 2,3,4, 1,3,5, 5,2,1, 5,3,2} /* side # */ }; #endif static int hex_table[2][24] = { /* 1 2 3 4 5 6 7 8 node 1 */ {4,2,5, 1,3,6, 7,4,2, 3,1,8, 6,8,1, 5,2,7, 8,6,3, 7,5,4},/* node 2 */ {5,1,4, 5,2,1, 2,3,5, 5,4,3, 6,4,1, 1,2,6, 6,2,3, 3,6,4} /* side # */ }; char errmsg[MAX_ERR_LENGTH]; exerrval = 0; /* clear error code */ cdum = 0; /* initialize even though it is not used */ /* first check if any side sets are specified */ /* inquire how many side sets have been stored */ if ((ex_inquire(exoid, EX_INQ_SIDE_SETS, &num_side_sets, &fdum, cdum)) == -1) { sprintf(errmsg, "Error: failed to get number of side sets in file id %d",exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); return(EX_FATAL); } if (num_side_sets == 0) { sprintf(errmsg, "Warning: no side sets defined in file id %d",exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,EX_WARN); return(EX_WARN); } if ((ex_inquire(exoid, EX_INQ_ELEM_BLK, &num_elem_blks, &fdum, cdum)) == -1) { sprintf(errmsg, "Error: failed to get number of element blocks in file id %d",exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); return(EX_FATAL); } if ((ex_inquire(exoid, EX_INQ_ELEM, &tot_num_elem, &fdum, cdum)) == -1) { sprintf(errmsg, "Error: failed to get total number of elements in file id %d",exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); return(EX_FATAL); } /* get the dimensionality of the coordinates; this is necessary to distinguish between 2d TRIs and 3d TRIs */ if ((ex_inquire(exoid, EX_INQ_DIM, &ndim, &fdum, cdum)) == -1) { sprintf(errmsg, "Error: failed to get dimensionality in file id %d",exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); return(EX_FATAL); } /* First count up # of elements in the side sets*/ for (i=0;i= elem_ctr) { elem_ctr += num_elem_per_set[++k]; el_type = elem_blk_parms[j].elem_type_val; same_elem_type[k] = TRUE; } if (el_type != elem_blk_parms[j].elem_type_val) same_elem_type[k] = FALSE; } /* Build side set element to node list index and side set element parameter index. */ node_ctr = 0; elem_ctr = num_elem_per_set[0]; for (i=0,k=0;i= elem_ctr) { /* skip over NULL side sets */ while (num_elem_per_set[++k] == 0); elem_ctr += num_elem_per_set[k]; } /* determine number of nodes per side */ if (((num_nodes_per_set[k] % num_elem_per_set[k]) == 0) && (same_elem_type[k])) { /* all side set elements are same type */ node_ctr += num_nodes_per_set[k] /num_elem_per_set[k]; } else { node_ctr += elem_blk_parms[j].num_nodes_per_side[0]; } } ss_elem_node_ndx[i] = node_ctr; /* assign node list index */ free(same_elem_type); /* All setup, ready to go ... */ elem_ctr=0; for (j=0; j < tot_num_ss_elem; j++) { if (side_sets_elem_list[ss_elem_ndx[j]] > elem_ctr) { /* release connectivity array space and get next one */ if (elem_ctr > 0) free(connect); /* Allocate space for the connectivity array for new element block */ if (!(connect= malloc(elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].num_elem_in_blk* elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].num_nodes_per_elem* sizeof(int)))) { exerrval = EX_MEMFAIL; sprintf(errmsg, "Error: failed to allocate space for connectivity array for file id %d", exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } /* get connectivity array */ if (ex_get_elem_conn( exoid, elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, connect) == -1) { sprintf(errmsg, "Error: failed to get connectivity array for elem blk %d for file id %d", elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } elem_ctr = elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_ctr; } /* For the first node of each side in side set, using a linear search (of up to num_nodes_per_elem) of the connectivity array, locate the node position in the element. The first node position and the second node position are used with a element type specific table to determine the side. */ elem_num = side_sets_elem_list[ss_elem_ndx[j]]-1;/* element number 0-based*/ /* calculate the relative element number position in it's block*/ elem_num_pos = elem_num - (elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_ctr - elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].num_elem_in_blk); /* calculate the beginning of the node list for this element by using the ss_elem_node_ndx index into the side_sets_node_index and adding the element number position * number of nodes per elem */ num_nodes_per_elem = elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].num_nodes_per_elem; for (n=0; n= 4) /* 4- or 8-node side (front or back face) */ side_sets_side_list[ss_elem_ndx[j]] = shell_table[1][2*n]; else /* 2- or 3-node side (edge of shell) */ side_sets_side_list[ss_elem_ndx[j]] = shell_edge_table[1][2*n]; } else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (shell_table[0][2*n+1]-1)]) { if (num_node_per_side >= 4) /* 4- or 8-node side (front or back face) */ side_sets_side_list[ss_elem_ndx[j]] = shell_table[1][2*n+1]; else /* 2- or 3-node side (edge of shell) */ side_sets_side_list[ss_elem_ndx[j]]=shell_edge_table[1][2*n+1]; } else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (shell_table[0][2*n+2]-1)]) { if (num_node_per_side >= 4) /* 4- or 8-node side (front or back face) */ side_sets_side_list[ss_elem_ndx[j]] = shell_table[1][2*n+2]; else /* 2- or 3-node side (edge of shell) */ side_sets_side_list[ss_elem_ndx[j]]=shell_edge_table[1][2*n+2]; } else { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: failed to find SHELL element %d, node %d in connectivity array %d for file id %d", side_sets_elem_list[ss_elem_ndx[j]], side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1], elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } break; } case EX_EL_HEX: { /* use table to find which node to compare to next */ if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (hex_table[0][3*n]-1)]) side_sets_side_list[ss_elem_ndx[j]] = hex_table[1][3*n]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (hex_table[0][3*n+1]-1)]) side_sets_side_list[ss_elem_ndx[j]] = hex_table[1][3*n+1]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (hex_table[0][3*n+2]-1)]) side_sets_side_list[ss_elem_ndx[j]] = hex_table[1][3*n+2]; else { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: failed to find HEX element %d, node %d in connectivity array %d for file id %d", side_sets_elem_list[ss_elem_ndx[j]], side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1], elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } break; } case EX_EL_TETRA: { /* use table to find which node to compare to next */ if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (tetra_table[0][3*n]-1)]) side_sets_side_list[ss_elem_ndx[j]] = tetra_table[1][3*n]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (tetra_table[0][3*n+1]-1)]) side_sets_side_list[ss_elem_ndx[j]] = tetra_table[1][3*n+1]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (tetra_table[0][3*n+2]-1)]) side_sets_side_list[ss_elem_ndx[j]] = tetra_table[1][3*n+2]; else { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: failed to find TETRA element %d, node %d in connectivity array %d for file id %d", side_sets_elem_list[ss_elem_ndx[j]], side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1], elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } break; } case EX_EL_PYRAMID: { /* NOTE: PYRAMID elements in side set node lists are currently not supported */ exerrval = EX_BADPARAM; sprintf(errmsg, "ERROR: unsupported PYRAMID element found in side set node list in file id %d", exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } case EX_EL_WEDGE: { #if 1 /* NOTE: WEDGE elements in side set node lists are currently not supported */ exerrval = EX_BADPARAM; sprintf(errmsg, "ERROR: unsupported WEDGE element found in side set node list in file id %d", exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); #else /* use wedge_table to find which node to compare to next */ /* This section is commented out because Wedges are no longer supported !!!*/ if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (wedge_table[0][3*n]-1)]) side_sets_side_list[ss_elem_ndx[j]] = wedge_table[1][3*n]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (wedge_table[0][3*n+1]-1)]) side_sets_side_list[ss_elem_ndx[j]] = wedge_table[1][3*n+1]; else if (side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1] == connect[num_nodes_per_elem*(elem_num_pos)+ (wedge_table[0][3*n+2]-1)]) side_sets_side_list[ss_elem_ndx[j]] = wedge_table[1][3*n+2]; else { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: failed to find WEDGE element %d, node %d in connectivity array %d for file id %d", side_sets_elem_list[ss_elem_ndx[j]], side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]+1], elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } break; #endif } default: { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: %s is an unsupported element type", elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_type); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); return(EX_FATAL); } } break; /* done with this element */ } } if (n >= num_nodes_per_elem) /* did we find the node? */ { exerrval = EX_BADPARAM; sprintf(errmsg, "Error: failed to find element %d, node %d in element block %d for file id %d", side_sets_elem_list[ss_elem_ndx[j]], side_sets_node_list[ss_elem_node_ndx[ss_elem_ndx[j]]], elem_blk_parms[ss_parm_ndx[ss_elem_ndx[j]]].elem_blk_id, exoid); ex_err("ex_cvt_nodes_to_sides",errmsg,exerrval); free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_FATAL); } } /* All done: release connectivity array space, element block ids array, element block parameters array, and side set element index array */ free(connect); free(ss_elem_node_ndx); free(ss_parm_ndx); free(elem_blk_parms); free(elem_blk_ids); free(ss_elem_ndx); return (EX_NOERR); }