void build_elem_elem(Exo_DB *exo) { int ce; int count; int e; int ebi; int elem; int ename; int face; //int his_dim, her_dim; int i, j; int index; int len_curr; int len_prev; int len_intr; int length, length_new, num_faces; int iel; int ioffset; int n; int neighbor_name = -1; int node; int num_elem_sides; int num_nodes; int snl[MAX_NODES_PER_SIDE]; /* Side Node List - NOT Saturday Night Live! */ char err_msg[MAX_CHAR_ERR_MSG]; /* * Integer arrays used to find intersection sets of node->element lists. */ int prev_set[MAX_EPN]; /* list of elements attached to previous node*/ int curr_set[MAX_EPN]; /* list of elements attached to "this" node */ int interset[MAX_EPN]; /* values of hits between */ int ip[MAX_EPN]; /* indeces of hits for prev_set[] */ int ic[MAX_EPN]; /* indeces of hits for curr_set[] */ /* * If the element->node and node->element connectivities have not been * built, then we won't be able to do this task. */ if ( ! exo->elem_node_conn_exists || ! exo->node_elem_conn_exists ) { EH(-1, "Build elem->node before node->elem."); return; } /* * The number of elements connected via conventional faces may be deduced * from the number of elements and their type. */ exo->elem_elem_pntr = (int *) smalloc((exo->num_elems+1)*sizeof(int)); length = 0; for ( i=0; i<exo->num_elem_blocks; i++) { length += exo->eb_num_elems[i] * get_num_faces(exo->eb_elem_type[i]); } exo->elem_elem_list = (int *) smalloc(length*sizeof(int)); /* * Initialize... */ for ( i=0; i<length; i++) { exo->elem_elem_list[i] = UNASSIGNED_YET; } /* elem = 0; for ( ebi=0; ebi<exo->num_elem_blocks; ebi++) { num_elem_sides = get_num_faces(exo->eb_elem_type[ebi]); for ( e=0; e<exo->eb_num_elems[ebi]; e++) { exo->elem_elem_pntr[elem] = count; elem++; count += num_elem_sides; } } */ /* * Walk through the elements, block by block. */ count = 0; elem = 0; for ( ebi=0; ebi<exo->num_elem_blocks; ebi++) { num_elem_sides = get_num_faces(exo->eb_elem_type[ebi]); for ( e=0; e<exo->eb_num_elems[ebi]; e++,elem++) { exo->elem_elem_pntr[elem] = count; count += num_elem_sides; /* * Look at each side of the element, collecting a unique * list of integers corresponding to the minimum number of nodes * needed to identify an entire side. * * Typically, the same number of nodes as space dimensions are * needed, with exceptions being the various "sides" of shells, * beams and trusses... */ for ( face=0; face<num_elem_sides; face++) { /* * Given the element and the face construct the * list of node numbers that determine that side. */ /* * Later, we might not need *all* the nodes on a side, * particularly for high order elements. It may suffice * to check only as many nodes as space dimensions that * the element lives in... */ num_nodes = build_side_node_list(elem, face, ebi, exo, snl); #ifdef DEBUG fprintf(stderr, "Elem %d, face %d has %d nodes: ", elem, face, num_nodes); for ( i=0; i<num_nodes; i++) { fprintf(stderr, " %d", snl[i]); } fprintf(stderr, "\n"); #endif /* DEBUG */ /* * Cross check: for each node in the side there is a list * of elements connected to it. Beginning with all the * elements connected to the first node (except for this given * element), cross check with all the elements connected with * the 2nd node to build an intersection set of one element. */ for ( i=0; i<MAX_EPN; i++) { prev_set[i] = -1; curr_set[i] = -1; interset[i] = -1; } len_prev = 0; len_curr = 0; len_intr = 0; for ( n=0; n<num_nodes; n++) { /* * Copy this node's element list into a clean "curr_set" array * that will be intersected with any previously gathered * lists of elements that qualify as promiscuously in * contact with nodes... */ node = snl[n]; for ( i=0; i<MAX_EPN; i++) { curr_set[i] = -1; } len_curr = 0; #ifdef DEBUG fprintf(stderr, "Traversing n->e connectivity of node %d\n", node); #endif /* DEBUG */ for ( ce=exo->node_elem_pntr[node]; ce<exo->node_elem_pntr[node+1]; ce++) { ename = exo->node_elem_list[ce]; #ifdef DEBUG fprintf(stderr, "\telem %d\n", ename); #endif /* DEBUG */ /* * Go ahead and accumulate the self element name * just as a consistency check.... */ /* if ( ename != e ) { } */ /* * PKN: The current Goma use of ->elem_elem... * is such that this connectivity should list * connections like QUAD-BAR or HEX-SHELL. * So, I'll add this dimension matching conditional */ /* PRS (Summer 2012): Need to change this for shell stacks which have the same dim*/ /* We need however to consider a special case (as of 8/30/2012 * this is a SHELL-on-SHELL stack. Viz. two materials, each a shell material * which share not a side but a face. Since faces of shells are sides * in patran speak, we need some special logic. We need to avoid adding * the friend shell element (neighboring material) to the current shell element * even though each material has the same number of sides. * Here goes (BTW, I cannot find max-nodes-per-element anywhere!!!!) */ int shell_on_shell = 0; int flippy_flop = 0; int nbr_ebid; int nbr_num_elem_sides; nbr_ebid = fence_post(ename, exo->eb_ptr, exo->num_elem_blocks+1); EH(nbr_ebid, "Bad element block ID!"); nbr_num_elem_sides = get_num_faces(exo->eb_elem_type[nbr_ebid]); shell_on_shell = 0; flippy_flop = 0; if (exo->eb_id[ebi] < 100 && exo->eb_id[nbr_ebid] >= 100) flippy_flop=1; if (exo->eb_id[ebi] >= 100 && exo->eb_id[nbr_ebid] < 100) flippy_flop=1; if ((nbr_ebid != ebi) && (strstr(exo->eb_elem_type[nbr_ebid], "SHELL")) && (strstr(exo->eb_elem_type[ebi], "SHELL")) && flippy_flop) shell_on_shell = 1; // his_dim = elem_info(NDIM, exo->eb_elem_itype[ebi]); // her_dim = elem_info(NDIM, exo->eb_elem_itype[exo->elem_eb[ename]]); // if( his_dim == her_dim ) if (nbr_num_elem_sides == num_elem_sides && !shell_on_shell) { curr_set[len_curr] = ename; len_curr++; } } /* * The first node is special - we'll just compare * it with itself by making the "previous set" just the * same as the current set... */ if ( n == 0 ) { for ( i=0; i<MAX_EPN; i++) { prev_set[i] = curr_set[i]; } len_prev = len_curr; } #ifdef DEBUG fprintf(stderr, "\ncurr_set: "); for ( i=0; i<len_curr; i++) { fprintf(stderr, "%d ", curr_set[i]); } fprintf(stderr, "\nprev_set: "); for ( i=0; i<len_prev; i++) { fprintf(stderr, "%d ", prev_set[i]); } #endif /* DEBUG */ /* * First, clean the intersection list and the list of * hit indeces in the previous and current lists. * * Then find the intersection of the previous and current * sets of elements attached to the previous and current * nodes... */ for ( i=0; i<MAX_EPN; i++) { interset[i] = -1; ip[i] = -1; ic[i] = -1; } len_intr = 0; len_intr = int_intersect(prev_set, curr_set, len_prev, len_curr, ip, ic); #ifdef DEBUG fprintf(stderr, "num_hits = %d\n", len_intr); #endif /* DEBUG */ /* * Now, let's make the intersection set the next previous * set of elements, a standard for comparison. We should * eventually boil down to either one or zero elements * that qualify... */ for ( i=0; i<MAX_EPN; i++) { prev_set[i] = -1; } for ( i=0; i<len_intr; i++) { prev_set[i] = curr_set[ic[i]]; } len_prev = len_intr; } #ifdef DEBUG fprintf(stderr, "Element [%d], face [%d], local_node [%d]\n", elem, face, n); fprintf(stderr, "Intersection set length = %d\n", len_intr); #endif /* DEBUG */ /* * Now consider the different cases. */ if ( len_intr == 2 ) { /* * The boiled list contains self and one other element. */ if ( prev_set[0] == elem ) { neighbor_name = prev_set[1]; } else { neighbor_name = prev_set[0]; if ( prev_set[1] != elem ) { sr = sprintf(err_msg, "2 elems ( %d %d ) 1 should be %d!", prev_set[0], prev_set[1], elem); EH(-1, err_msg); } } } else if ( len_intr == 1 && prev_set[0] == elem ) { /* * The boiled list has one member, this element. * * The face must connect either to outer space or to * another processor. */ if ( Num_Proc == 1 ) { neighbor_name = -1; } else { neighbor_name = -1; /* * I am going to punt for now. Later, revisit this * condition and insert code to check for neighbor * processors containing all the same face nodes. * * EH(-1, "Not done yet..."); * */ /* * Check if ALL the nodes on this face belong * to another processors list of nodes. I.e., the * node must all be in the external node list of * and belong to the same external processor. */ } } /* * Pathological cases that normally should not occur.... */ else if ( len_intr == 0 ) { sr = sprintf(err_msg, "Elem %d, face %d should self contain!", elem, face); EH(-1, err_msg); } else if ( len_intr == 1 && prev_set[0] != elem ) { sr = sprintf(err_msg, "Elem %d, face %d only connects with elem %d ?", elem, face, prev_set[0]); EH(-1, err_msg); } else { sr = sprintf(err_msg, "Unknown elem-elem connection elem %d, face %d, len_intr=%d", elem, face, len_intr); WH(-1, err_msg); } /* * Now we know how to assign the neighbor name for this face * of the element. */ index = exo->elem_elem_pntr[elem] + face; exo->elem_elem_list[index] = neighbor_name; } /* end face loop this elem */ } /* end elem loop this elemblock */ } /* end elem block loop */ exo->elem_elem_pntr[exo->num_elems] = count; /* last fencepost */ exo->elem_elem_conn_exists = TRUE; if (Linear_Solver == FRONT) { /* * Now that we have elem_elem_pntr and elem_elem_list for our parallel * world, we are going to use them also for optimal element bandwidth * reduction ordering. We will use METIS, but METIS requires the CSR * format, which is compressed, viz. we need to remove the -1s. Here * we go */ /* First check for the assumption that all blocks have same number of element faces. Stop if they don't and issue an error to the next aspiring developer */ for ( i=0; i<exo->num_elem_blocks; i++) { if(get_num_faces(exo->eb_elem_type[0]) != get_num_faces(exo->eb_elem_type[i]) ) { EH(-1,"Stop! We cannot reorder these elements with METIS with elemement type changes"); } } /* Now begin */ exo->elem_elem_xadj = (int *) smalloc((exo->num_elems+1)*sizeof(int)); /*initialize */ for(e=0; e<exo->num_elems+1 ; e++) { exo->elem_elem_xadj[e] = exo->elem_elem_pntr[e]; } /* Recompute length of adjacency list by removing external edges */ length_new = 0; for (i = 0; i < length; i++) { if(exo->elem_elem_list[i] != -1) length_new++; } exo->elem_elem_adjncy = alloc_int_1(length_new, -1); /* Now convert */ ioffset=0; for(iel = 0; iel < exo->num_elems; iel++) { /* Big assumption here that all blocks have the same */ /* element type. Can be furbished later since this is */ /* just for the frontal solver */ num_faces = get_num_faces(exo->eb_elem_type[0]); for (i= iel*num_faces; i < (iel+1)*num_faces; i++) { j = i - ioffset; if(exo->elem_elem_list[i] == -1) { ioffset++; for(e=iel +1; e <exo->num_elems+1; e++)exo->elem_elem_xadj[e]--; } else { exo->elem_elem_adjncy[j] = exo->elem_elem_list[i]; } } } /* convert to Fortran style */ for(e=0; e<exo->num_elems+1 ; e++) exo->elem_elem_xadj[e]++; for ( i=0; i<length_new; i++) exo->elem_elem_adjncy[i]++; } /* End FRONTAL_SOLVER if */ /* * Verification that every element/face has assigned something besides * the initial default value of "unassigned". * * For your convenience - FORTRAN 1-based numbering. */ #ifdef DEBUG for ( e=0; e<exo->num_elems; e++) { fprintf(stdout, "Elem %3d:", e+1); for ( ce=exo->elem_elem_pntr[e]; ce<exo->elem_elem_pntr[e+1]; ce++) { if ( exo->elem_elem_list[ce] == -1 ) { fprintf(stdout, " spc"); } else if ( exo->elem_elem_list[ce] < -1 ) { fprintf(stdout, " prc"); } else { fprintf(stdout, " %3d", exo->elem_elem_list[ce] + 1); } if ( exo->elem_elem_list[ce] == UNASSIGNED_YET ) { sr = sprintf(err_msg, "You need to plug a leak at elem (%d) face (%d)", exo->elem_elem_list[ce] + 1, ce - exo->elem_elem_pntr[e] + 1); EH(-1, err_msg); } } fprintf(stdout, "\n"); } #endif /* DEBUG */ #if FALSE demo_elem_elem_conn(exo); #endif return; }
void build_elem_elem_xtra(Exo_DB *exo) /* monolith FE db w/ connectivity (in) */ { int length; int e; int f; int face; int hi; int i; int lo; int n1; int n2; int neighbor; int snl_this[MAX_NODES_PER_SIDE]; /* Side Node List */ int snl_other[MAX_NODES_PER_SIDE]; /* Side Node List */ int twist; int where; if ( ! exo->elem_elem_conn_exists ) { EH(-1, "Cannot build xtra w/o basic info."); } /* * Allocate some space... */ length = exo->elem_elem_pntr[exo->num_elems]; exo->elem_elem_face = (int *) smalloc(length*sizeof(int)); exo->elem_elem_twst = (int *) smalloc(length*sizeof(int)); /* * Initialize... */ for ( i=0; i<length; i++) { exo->elem_elem_face[i] = -1; exo->elem_elem_twst[i] = -1; } /* * The names of the neighbor's face can be built by find the neighbor * and searching for which of its faces connects to the originating * element. */ for ( e=0; e<exo->num_elems; e++) { /* * Clean out the side node lists... */ for ( i=0; i<MAX_NODES_PER_SIDE; i++) { snl_this[i] = -1; snl_other[i] = -1; } /* * Look at each face of this element and the neighbor, if any, that * is there. */ for ( f=exo->elem_elem_pntr[e],face=0; f<exo->elem_elem_pntr[e+1]; f++,face++) { neighbor = exo->elem_elem_list[f]; if ( neighbor > -1 ) { /* * Now, go the neighbor and find out the index of this element * in its list! */ lo = exo->elem_elem_pntr[neighbor]; hi = exo->elem_elem_pntr[neighbor+1]; where = in_list(e, exo->elem_elem_list + lo, hi-lo); EH(where, "Didn't find my recipricol element!"); /* * Record where originating element was found! */ exo->elem_elem_face[f] = where; /* * Now load up the nodes on this element, this face and compare * to other element, other face collection of same nodes. How * much cyclic twist of the OTHER element is required to get * the low nodes coincident? */ n1 = build_side_node_list(e, face, exo, snl_this); n2 = build_side_node_list(neighbor, where, exo, snl_other); if ( n1 != n2 ) { EH(-1, "Difft number of nodes on facing elems!?!"); } twist = in_list(snl_this[0], snl_other, n2); EH(twist, "Low node not found in facing neighbor!"); exo->elem_elem_twst[f] = twist; } } } return; }