示例#1
0
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;
}
示例#2
0
文件: sam_perea.c 项目: goma/brkfix
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;
}