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 assess_weights(Exo_DB *x, Bevm ***mult, int ***evd, int *ebl, int *np, int *el, int *ep, int *nl, int *node_kind, Node_Description **pnd, int *num_basic_eqnvars, int *eqn_node_names, int *var_node_names, int *nnz_contribute, int *nat_contribute, int *ccs_contribute) { int col; int column_max; int *common_elements; int e; int eb_index; int elem; int eqn_node; int evid; int ewt; int i; int ieb; int ii; int inn; int iv; int j; int jj; int l; int m; int map_e_index[MAX_EQNVARS]; int map_v_index[MAX_EQNVARS]; int n; int nbev; /* int ne;*/ int neb; int *neighbor_nodes; int nelems_this_node; int nn; /* int nns;*/ int node; /* int nss;*/ int *nn_eids; int *nn_ewts; int *nn_vids; int *nn_vwts; int **nn_or; int **nn_add; int num_connecting_elems; int num_neighbor_nodes; int num_assembled_terms; int num_comm_chunks; int num_matrix_nonzeroes; int max_common_elements; int row; int var_node; int vwt; int where; char err_msg[MAX_CHAR_ERR_MSG]; Spfrtn sr=0; Node_Description *end; Node_Description *vnd; /* * Convenience variables... */ /* * ne = x->num_elems; */ nn = x->num_nodes; neb = x->num_elem_blocks; /* * nns = x->num_node_sets; * nss = x->num_side_sets; */ /* * Allocate space for the little matrices used for each node-node * interaction. For a given eqn-node to var-node interaction, we'll * need to have the following information compiled: * * the columns of the interaction matrix need to be identified with * the variable ID's at the var-node, as well as the corresponding * weights for each of these variables. The weights are just * products of all of the three kinds of multiplicities for an eqn: * (i) vector/tensor/etc., (ii) concentration, (iii) nodal dof * * the rows of the interaction matrix need to be identified with the * equation ID's at the eqn-node, as well as their weights. * * Finally, the little AND and OR matrix entries may be computed * by considering the equation-variable dependency matrix for * each of the elements through which the eqn-node depends upon the * var-node. */ nn_eids = (int *) smalloc(MAX_EQNVARS * SZ_INT); nn_ewts = (int *) smalloc(MAX_EQNVARS * SZ_INT); nn_vids = (int *) smalloc(MAX_EQNVARS * SZ_INT); nn_vwts = (int *) smalloc(MAX_EQNVARS * SZ_INT); nn_or = (int **) smalloc(MAX_EQNVARS * sizeof(int *)); nn_or[0] = (int *) smalloc(MAX_EQNVARS * MAX_EQNVARS * sizeof(int)); for ( i=1; i<MAX_EQNVARS; i++) { nn_or[i] = nn_or[i-1] + MAX_EQNVARS; } nn_add = (int **) smalloc(MAX_EQNVARS * sizeof(int *)); nn_add[0] = (int *) smalloc(MAX_EQNVARS * MAX_EQNVARS * sizeof(int)); for ( i=1; i<MAX_EQNVARS; i++) { nn_add[i] = nn_add[i-1] + MAX_EQNVARS; } /* * The maximum number of elements connecting any given eqn node with * any given var node will likely be the maximum number of elements * to which any *single* node belongs. (The worse case scenario will * be if the eqn node and the var node are the same.) */ max_common_elements = -1; for ( n=0; n<nn; n++) { nelems_this_node = np[n+1] - np[n]; if ( nelems_this_node > max_common_elements ) { max_common_elements = nelems_this_node; } } neighbor_nodes = (int *) smalloc(MAX_NEIGHBOR_NODES* SZ_INT); #ifdef DEBUG fprintf(stderr, "max common elements = %d\n", max_common_elements); #endif common_elements = (int *) smalloc(max_common_elements * SZ_INT); inn = 0; /* 0 < inn < length_node_node */ for ( eqn_node=0; eqn_node<nn; eqn_node++) { /* if ( inn >= length_node_node ) { EH(-1, "Abnormal lack of space!"); } */ /* * 0. First, figure out how many *other* nodes interact with this one. * * 1. Determine interaction based solely on the mesh topology. Every * node connected to the given node by an element is a candidate * for interaction. * * 2. Find out how many equations(dofs) associated at this given node * there are. * * 3. Find out how many variables(dofs) are associate with each of the * interacting nodes. Don't forget that a node interacts with itself. * We'll remove the self loop so it doesn't become a graph edge, but * properly account for the computational load of computing the * self-interaction terms. * * 4. Cross check the potential interactions using the appropriate * Equation Variable Dependency description that was read in for * each element block into the "evd" array. * * 5. Do not forget that two nodes may interact through more * than one element and that, therefore, the interaction matrices * can differ betweent the eqns and vars of the two nodes, or the * node and itself. The interactions need to be "or"-ed together * and added together. */ /* * Initialize the equation info. It will stay the same for * every var_node of the interaction. */ for ( i=0; i<MAX_EQNVARS; i++) { nn_eids[i] = UNDEFINED_EQNVARID; nn_ewts[i] = 0; } end = pnd[node_kind[eqn_node]]; for ( i=0; i<end->num_basic_eqnvars; i++) { nn_eids[i] = end->eqnvar_ids[i]; nn_ewts[i] = ( end->eqnvar_wts[i][0] * end->eqnvar_wts[i][1] * end->eqnvar_wts[i][2] ); } #ifdef DEBUG fprintf(stderr, "enode = (%d) has active eids = ", eqn_node+1); for ( i=0; i<end->num_basic_eqnvars; i++) { fprintf(stderr, "%d (x%d) ", nn_eids[i], nn_ewts[i]); } fprintf(stderr, "\n\n"); #endif /* * Initialize, then load up names of every connecting var_node to * this eqn_node. */ num_neighbor_nodes = 0; for ( i=0; i<MAX_NEIGHBOR_NODES; i++) { neighbor_nodes[i] = -1; } /* * Examine every element containing this eqn node. */ for ( l=np[eqn_node]; l<np[eqn_node+1]; l++) { elem = el[l]; /* * This element may belong to an element block where the * interaction is much weaker than might be supposed from * looking at a large impressive list of active equations at * the eqn_node or the large impressive list of active variables * at the var_node. Fortunately, insofar as this connecting element * is concerned, we need only check the interactions for the * element block concerned. */ /* * Look at every node that this element contains. */ for ( m=ep[elem]; m<ep[elem+1]; m++ ) { var_node = nl[m]; /* * If this variable node is not already in the list of * neighbor nodes, add it. */ BULL(var_node, neighbor_nodes, num_neighbor_nodes); if ( num_neighbor_nodes > MAX_NEIGHBOR_NODES ) { sr = sprintf(err_msg, "@ n = %d too many neighbors.", eqn_node); EH(-1, err_msg); } } } #ifdef DEBUG fprintf(stderr, "node (%d) has %d neighbor_nodes\n", eqn_node+1, num_neighbor_nodes); fprintf(stderr, "and they are:"); for ( i=0; i<num_neighbor_nodes; i++) { fprintf(stderr, " %d", neighbor_nodes[i]+1); } fprintf(stderr, "\n"); #endif for ( iv=0; iv<num_neighbor_nodes; iv++) { var_node = neighbor_nodes[iv]; /* * Gather together a list of all elements that connect * this var_node with the eqn_node. First, initialize to * the empty list. */ num_connecting_elems = 0; for ( i=0; i<max_common_elements; i++) { common_elements[i] = -1; } /* * Look through all the elements this eqn_node touches. * If any of those elements contain var_node, then this * element is common. */ for ( l=np[eqn_node]; l<np[eqn_node+1]; l++) { elem = el[l]; for ( m=ep[elem]; m<ep[elem+1]; m++) { node = nl[m]; if ( node == var_node ) { /* * Assume this will only happen once per element. */ common_elements[num_connecting_elems] = elem; num_connecting_elems++; } } } #ifdef DEBUG fprintf(stderr, "en=(%d),vn=(%d) thru %d elems: ", eqn_node+1, var_node+1, num_connecting_elems); for ( i=0; i<num_connecting_elems; i++) { fprintf(stderr, "%d ", common_elements[i]+1); } fprintf(stderr, "\n"); #endif /* * At the var_node, find eqnvar_IDs and weights. */ for ( i=0; i<MAX_EQNVARS; i++) { nn_vids[i] = UNDEFINED_EQNVARID; nn_vwts[i] = 0; } vnd = pnd[node_kind[var_node]]; for ( i=0; i<vnd->num_basic_eqnvars; i++) { nn_vids[i] = vnd->eqnvar_ids[i]; nn_vwts[i] = ( vnd->eqnvar_wts[i][0] * vnd->eqnvar_wts[i][1] * vnd->eqnvar_wts[i][2] ); } #ifdef DEBUG fprintf(stderr, "vnode = (%d) has active vids = ", var_node+1); for ( i=0; i<vnd->num_basic_eqnvars; i++) { fprintf(stderr, "%d (x%d) ", nn_vids[i], nn_vwts[i]); } fprintf(stderr, "\n\n"); #endif /* * Now, construct the ADD and OR matrices for this particular * eqn_node -> var_node interaction using the Equation Variable * Dependencies for each element participating in the interaction. * * Initially, empty the matrix. */ for ( row=0; row<MAX_EQNVARS; row++) { for ( col=0; col<MAX_EQNVARS; col++) { nn_or[row][col] = 0; nn_add[row][col] = 0; } } for ( e=0; e<num_connecting_elems; e++) { elem = common_elements[e]; eb_index = fence_post(elem, ebl, neb+1); nbev = num_basic_eqnvars[eb_index]; /* * For this element block index, what are the indeces * corresponding to the active eqns and vars? * * There might be fewer eqnvars known in this eb_index than * are known at either node. * * Construct a map from the ev_indeces in the * elem block into the ev_indeces of the nodes weight matrices. */ /* for ( ieb=0; ieb<end->num_basic_eqnvars; ieb++)*/ for ( ieb=0; ieb<nbev; ieb++) { evid = mult[eb_index][ieb]->eqnvar_id; where = in_list(evid, nn_eids, end->num_basic_eqnvars); /* * If this evid is not at this particular node, OK. * Just make the map = -1 and check later */ map_e_index[ieb] = where; where = in_list(evid, nn_vids, vnd->num_basic_eqnvars); map_v_index[ieb] = where; } /* * Combine this elements idea of interaction strength * into the OR and ADD matrices built to express the * eqn_node - var_node interaction through all connecting * elements. */ for ( i=0; i<nbev; i++) { ii = map_e_index[i]; if ( ii != -1 ) { ewt = nn_ewts[ii]; for ( j=0; j<nbev; j++) { jj = map_v_index[j]; if ( jj != -1 ) { vwt = nn_vwts[jj]; if ( evd[eb_index][i][j] != 0 ) { nn_or[ii][jj] = MAX( nn_or[ii][jj], vwt); nn_add[ii][jj] += ewt * vwt; } } } } } } #ifdef DEBUG /* * Dump the interaction matrices for this eqn_node-var_node * interaction. */ fprintf(stderr, "(%d)-(%d) ", eqn_node+1, var_node+1); fprintf(stderr, "eqn_ids @ (%d): ", eqn_node+1); for ( i=0; i<end->num_basic_eqnvars; i++) { fprintf(stderr, "%d ", nn_eids[i]); } fprintf(stderr, "var_ids @ (%d): ", var_node+1); for ( i=0; i<vnd->num_basic_eqnvars; i++) { fprintf(stderr, "%d ", nn_vids[i]); } fprintf(stderr, "\n"); fprintf(stderr, "OR\n"); for ( i=0; i<end->num_basic_eqnvars; i++) { for ( j=0; j<vnd->num_basic_eqnvars; j++) { fprintf(stderr, "%8d", nn_or[i][j]); } fprintf(stderr, "\n"); } fprintf(stderr, "ADD\n"); for ( i=0; i<end->num_basic_eqnvars; i++) { for ( j=0; j<vnd->num_basic_eqnvars; j++) { fprintf(stderr, "%8d", nn_add[i][j]); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); #endif /* * All dependencies have been accumulated. Distill into scalars * for the eqn_node/var_node interaction strength. */ num_matrix_nonzeroes = 0; num_assembled_terms = 0; for ( i=0; i<end->num_basic_eqnvars; i++) { for ( j=0; j<vnd->num_basic_eqnvars; j++) { num_assembled_terms += nn_add[i][j]; num_matrix_nonzeroes += nn_or[i][j]; } } num_comm_chunks = 0; for ( j=0; j<vnd->num_basic_eqnvars; j++) { column_max = 0; for ( i=0; i<end->num_basic_eqnvars; i++) { if ( nn_or[i][j] > column_max ) { column_max = nn_or[i][j]; } } num_comm_chunks += column_max; } eqn_node_names[inn] = eqn_node; var_node_names[inn] = var_node; nnz_contribute[inn] = num_matrix_nonzeroes; nat_contribute[inn] = num_assembled_terms; ccs_contribute[inn] = num_comm_chunks; inn++; } } free(nn_eids); free(nn_ewts); free(nn_vids); free(nn_vwts); free(nn_or[0]); free(nn_add[0]); free(nn_or); free(nn_add); free(common_elements); free(neighbor_nodes); if ( sr < 0 ) exit(2); return; }