/* 
     test if a vertex is on partition boundary, for volume mesh
     a vertex is on boundary if one of its incident faces has less than 2 neighboring regions
 */
static int vertex_on_boundary3D(MVertex_ptr mv) {
  int i, nrf, ok = 0;
  MFace_ptr mf;
  List_ptr vfaces = MV_Faces(mv);
  nrf = List_Num_Entries(vfaces);
  for(i = 0; (i < nrf) && !ok; i++) {
    List_ptr fregs;
    mf = List_Entry(vfaces,i);
    fregs = MF_Regions(mf);
    if(List_Num_Entries(fregs) <= 1)
      ok = 1;
    List_Delete(fregs);
  }
  List_Delete(vfaces);
  return ok;
}
Beispiel #2
0
MVertex_ptr ME_Collapse(MEdge_ptr e, MVertex_ptr vkeep_in, int topoflag,
                        List_ptr *deleted_entities) {
  MVertex_ptr vdel, vkeep, ev00, ev01, ev10, ev11, vert;
  MEdge_ptr edge, edge2, oldedges[3], nuedges[2];
  MFace_ptr face, face2, rface1, rface2;
  MRegion_ptr reg, reg2;
  List_ptr vedges, efaces, eregs, fedges, rfaces, fverts1, fverts2, vfaces;
  int idx1, idx2, idx3, dir, status, nfe, nrf, allfound, degenerate;
  int i, j, nfe2, nfv1, nfv2;

  status = 1;

  if (vkeep_in == NULL) {
    vdel = ME_Vertex(e,0);
    vkeep = ME_Vertex(e,1);
  }
  else {
    vkeep = vkeep_in;
    vdel = ME_OppVertex(e,vkeep);
  }

  int dimkeep, dimdel;
    
  dimkeep = MV_GEntDim(vkeep); /* Model entity dim of vertex to keep */
  dimdel = MV_GEntDim(vdel);   /* Model entity dim  of vertex to delete */
  
  if (topoflag == 1) {
    if (dimkeep == dimdel) {
      
      if (MV_GEntID(vkeep) != MV_GEntID(vdel))
        status = 0;                 /* cannot allow since it will cause 
                                       a dimensional reduction in mesh */
    }
    else if (dimdel < dimkeep) {
      
      if (vkeep_in == NULL) {
        /* If no preference was indicated on which vertex to retain,
	   we can collapse in the other direction */
        MVertex_ptr vtemp = vdel;
	vdel = vkeep;
	vkeep = vtemp;
      }
      else
        status = 0; /* can't reverse order or vertices and boundary of
                       mesh will get messed up if we go through as is */
    }
  }
  else if (vkeep_in == NULL) { 

    /* If no preference was indicated for the kept vertex and
       topological conformity with the underlying geometric model was
       not requested, we prefer to keep an external boundary vertex
       over an interior vertex or interior boundary vertex. This is
       because it is more likely that the external boundary vertex
       would have a boundary condition applied to it. If a preference
       was indicated, we just have to respect that. */

    int vdel_external = 0;

    /* Check if any edges connected to vdel have only one connected face */

    vedges = MV_Edges(vdel);    

    idx1 = 0;
    while ((edge = (MEdge_ptr) List_Next_Entry(vedges,&idx1))) {
      List_ptr efaces = ME_Faces(edge);
      int nef = List_Num_Entries(efaces);
      List_Delete(efaces);
      if (nef < 2) {
        vdel_external = 1;
        break;
      }
    }                                          
    
    List_Delete(vedges);

    /* check if any face connected to vdel has only one region
       connected to it */

    if (!vdel_external) {
      vfaces = MV_Faces(vdel);

      idx1 = 0;
      while ((face = (MFace_ptr) List_Next_Entry(vfaces,&idx1))) {
        List_ptr fregs = MF_Regions(face);
        int nfr = fregs ? List_Num_Entries(fregs) : 0;
        if (fregs) List_Delete(fregs);

        if (nfr == 1) {
          vdel_external = 0;
          break;
        }
      }

      List_Delete(vfaces);
    }

    if (vdel_external) {
      /* swap the vertices in the hope that vkeep is not also on an
         external boundary. Since we have to go through with the
         collapse anyway, there is no use of doing a detailed check
         for whether vkeep is also on an external boundary */

      MVertex_ptr vtemp = vdel;
      vdel = vkeep;
      vkeep = vtemp;
    }
    
  }


  if (status == 0)
    return NULL;   /* Cannot collapse due to constraints of topological
		   conformity with geometric model */

  *deleted_entities = List_New(10);

  /* Need to collect this in advance because the info gets messed up later */

  efaces = ME_Faces(e);
  eregs = ME_Regions(e);


  /* Replace vdel with vkeep in all edges connected to vdel */

  vedges = MV_Edges(vdel);
  idx1 = 0;
  while ((edge = List_Next_Entry(vedges,&idx1))) {
    ME_Replace_Vertex(edge,vdel,vkeep);
  }
  List_Delete(vedges);

  /* Remove edge 'e' from all faces connected to e */
  /* This part of the code is using some reliance on the internal
     implementation of MF_Edges. While unlikely, it _might_ break if
     the innards of MF_Edges are changed */

  
  idx1 = 0;
  while ((face = List_Next_Entry(efaces,&idx1))) {

    fedges = MF_Edges(face,1,0);
    nfe = List_Num_Entries(fedges);

    /* Find the edge before and after e in the face */

    oldedges[0] = oldedges[2] = NULL;
    for (i = 0; i < nfe; i++) {
      edge = List_Entry(fedges,i);
      if (edge == e) continue;

      dir = MF_EdgeDir_i(face,i);

      if (ME_Vertex(edge,dir) == vkeep)
	oldedges[0] = edge;
      else if (ME_Vertex(edge,!dir) == vkeep)
	oldedges[2] = edge;
    }
    oldedges[1] = e;

    nuedges[0] = oldedges[0];
    nuedges[1] = oldedges[2];


    /* Replace oldedges[0], oldedges[1] (=e), oldedges[2] with 
       oldedges[0], oldedges[2] since e is degenerate */

    MF_Replace_Edges(face,3,oldedges,2,nuedges);

    List_Delete(fedges);
  }



  /* Delete topologically degenerate regions */
  /* Defined as two faces of the regions having the same vertices */

  if (eregs) {
    idx1 = 0;
    while ((reg = List_Next_Entry(eregs,&idx1))) {

      rfaces = MR_Faces(reg);
      nrf = List_Num_Entries(rfaces);

      if (nrf == 4) {      
        List_ptr rverts = MR_Vertices(reg);
        if (List_Num_Entries(rverts) == 4) {
          MR_Delete(reg,0);    /* This is a tet - it will become degenerate */
        }
        List_Delete(rverts);
      }
      else {

	degenerate = 0;

	for (i = 0; i < nrf; i++) {

	  rface1 = List_Entry(rfaces,i);
	
	  fverts1 = MF_Vertices(rface1,1,0);
	  nfv1 = List_Num_Entries(fverts1);
		
	  for (j = i+1; j < nrf; j++) {
	  
	    rface2 = List_Entry(rfaces,j);

	    fverts2 = MF_Vertices(rface2,1,0);
	    nfv2 = List_Num_Entries(fverts2);
	  
	    if (nfv1 != nfv2) {
	      List_Delete(fverts2);
	      continue;             /* can't be exactly coincident */
	    }

	    allfound = 1;
	    idx2 = 0;
	    while ((vert = List_Next_Entry(fverts2,&idx2))) {
	      if (!List_Contains(fverts1,vert)) {
		allfound = 0;
		break;
	      }
	    }
	  
	    List_Delete(fverts2);
	  
	    if (allfound) {
	      degenerate = 1;
	      break;
	    }
	  
	  } /* for (j = i+1 ... */

	  List_Delete(fverts1);

	  if (degenerate) break;

	} /* for (i = 0; i < nrf;.... */

	if (degenerate) {
          List_Add(*deleted_entities,reg);
	  MR_Delete(reg,0);
        }

      } /* if (nrf == 4) .. else ... */

      List_Delete(rfaces);

    } /* while ((reg = ...)) */
  }


  /* Delete topologically degenerate faces */

  if (efaces) {
    idx1 = 0;
    while ((face = List_Next_Entry(efaces,&idx1))) {

      fedges = MF_Edges(face,1,0);

      if (List_Num_Entries(fedges) == 2) {

	/* Disconnect the regions from the face before deleting */

	List_ptr fregs = MF_Regions(face);
        if (fregs) {
          idx2 = 0;
          while ((reg = List_Next_Entry(fregs,&idx2)))
            MR_Rem_Face(reg,face);
          
          List_Delete(fregs);
        }

        List_Add(*deleted_entities,face);
	MF_Delete(face,0);
      }

      List_Delete(fedges);
    }
    List_Delete(efaces);
  }



  /* Now merge edges which have the same end vertices */
  /* Prefer to preserve edges on external boundaries over internal edges */

  vedges = MV_Edges(vkeep);
  idx1 = 0; 
  while ((edge = List_Next_Entry(vedges,&idx1))) {
    if (edge == e) continue;
    
    ev00 = ME_Vertex(edge,0);
    ev01 = ME_Vertex(edge,1);

    idx2 = 0;
    while ((edge2 = List_Next_Entry(vedges,&idx2))) {
      if (edge == e || edge == edge2) continue;

      ev10 = ME_Vertex(edge2,0);
      ev11 = ME_Vertex(edge2,1);

      if ((ev00 == ev10 && ev01 == ev11) ||
	  (ev00 == ev11 && ev10 == ev01)) {

        int external_edge, external_edge2;
        int edim = 4;
	    
        external_edge = 0;
        edim = ME_GEntDim(edge);
        if (edim == 1 || edim == 2 || edim == 4) { /* check if external edge */
          
          efaces = ME_Faces(edge);
          int nef = List_Num_Entries(efaces);
          if (nef == 1) {
            external_edge = 1;
          }
          else {
            idx3 = 0;
            while ((face = List_Next_Entry(efaces,&idx2))) {
              List_ptr fregs = MF_Regions(face);
              int nfr = fregs ? List_Num_Entries(fregs) : 0;
              if (fregs) List_Delete(fregs);
              if (nfr == 1) {
                external_edge = 1;
                break;
              }
            }
          }
          List_Delete(efaces);
          
        }
    
        external_edge2 = 0;
        edim = ME_GEntDim(edge2);
        if (edim == 1 || edim == 2 || edim == 4) { /* check if external edge */

          efaces = ME_Faces(edge2);
          int nef = List_Num_Entries(efaces);
          if (nef == 1) {
            external_edge2 = 1;
          }
          else {
            idx3 = 0;
            while ((face = List_Next_Entry(efaces,&idx2))) {
              List_ptr fregs = MF_Regions(face);
              int nfr = fregs ? List_Num_Entries(fregs) : 0;
              if (fregs) List_Delete(fregs);
              if (nfr == 1) {
                external_edge2 = 1;
                break;
              }
            }
          }
          List_Delete(efaces);
          
        }

        /* If edge2 is not external or both edges are external, go
           ahead and merge (edge2 will be deleted subject to
           topological checks if topoflag is 1) */

        if (!external_edge2 || (external_edge && external_edge2)) {
          MEs_Merge(edge,edge2,topoflag);	
          List_Rem(vedges,edge2);	
          List_Add(*deleted_entities,edge2);
          break;
        }
      }
    }
  }
  List_Delete(vedges);


  /* Merge faces with the same set of edges */
      
  vfaces = MV_Faces(vkeep);

  if (vfaces) {
    idx1 = 0;
    while ((face = List_Next_Entry(vfaces,&idx1))) {
    
      fedges = MF_Edges(face,1,0);
      nfe = List_Num_Entries(fedges);
    
      idx2 = 0;
      while ((face2 = List_Next_Entry(vfaces,&idx2))) {
	List_ptr fedges2;

	if (face2 == face) continue;

	fedges2 = MF_Edges(face2,1,0);
	nfe2 = List_Num_Entries(fedges2);

	if (nfe != nfe2) {
	  List_Delete(fedges2);
	  continue;
	}

	allfound = 1;

	for (i = 0; i < nfe2; i++) {
	  edge = List_Entry(fedges2,i);
	  if (!List_Contains(fedges,edge)) {
	    allfound = 0;
	    break;
	  }
	}
	List_Delete(fedges2);

	if (allfound) {

          List_ptr fregs = MF_Regions(face);
          int external_face = fregs ? (List_Num_Entries(fregs) == 1) : 0;
          if (fregs) List_Delete(fregs);

          List_ptr fregs2 = MF_Regions(face2);
          int external_face2 = fregs2 ? (List_Num_Entries(fregs2) == 1) : 0;
          if (fregs2) List_Delete(fregs2);

          /* Proceed with merge (which will delete face2) only if face2 is
             not an external face or both face and face2 are external */

          if (!external_face2 || (external_face && external_face2)) {
            MFs_Merge(face,face2,topoflag);	
            List_Rem(vfaces,face2);
            List_Add(*deleted_entities,face2);
            break;
          }

        }
	
      } /* while (face2 = List_Next_Entry(vfaces,... */

      List_Delete(fedges);

    } /* while (face = List_Next_Entry(vfaces,... */
    List_Delete(vfaces);
  }

  /* Now actually delete the collapse edge and the to-be-merged vertex */

  ME_Delete(e,0);
  List_Add(*deleted_entities,e);

  MV_Delete(vdel,0);
  List_Add(*deleted_entities,vdel);

  if (eregs) {
    idx1 = 0;
    while ((reg = List_Next_Entry(eregs,&idx1)))
      MR_Update_ElementType(reg);
    
    List_Delete(eregs);
  }

  return vkeep;
}
Beispiel #3
0
void MESH_Renumber(Mesh_ptr mesh, int renum_type, MType mtype) {
  MVertex_ptr mv, v0=NULL;
  MEdge_ptr me, e0=NULL;
  MFace_ptr mf, f0=NULL;
  MRegion_ptr mr, r0=NULL;
  int idx, idx2, idx3;
  int i, j;
  int done;
  MAttrib_ptr vidatt;
  List_ptr vlist;
  double xyz[3];
  double rval;
  int bandwidth, maxbandwidth1, maxbandwidth2;
  double avebandwidth1, avebandwidth2;
  void *pval;

  if (renum_type == 0) {
    if (mtype == MVERTEX || mtype == MALLTYPE) {
      int nv = 0;
      idx = 0; 
      while ((mv = MESH_Next_Vertex(mesh,&idx)))
	MV_Set_ID(mv,++nv);
    }
    
    if (mtype == MEDGE || mtype == MALLTYPE) {
      int ne = 0;
      idx = 0; 
      while ((me = MESH_Next_Edge(mesh,&idx)))
	ME_Set_ID(me,++ne);
    }
    
    if (mtype == MFACE || mtype == MALLTYPE) {
      int nf = 0;
      idx = 0; 
      while ((mf = MESH_Next_Face(mesh,&idx)))
	MF_Set_ID(mf,++nf);
    }
    
    if (mtype == MREGION || mtype == MALLTYPE) {
      int nr = 0;
      idx = 0; 
      while ((mr = MESH_Next_Region(mesh,&idx)))
	MR_Set_ID(mr,++nr);
    }
  }
  else if (renum_type == 1) {
    double minx, miny, minz;
    int minid, maxid;
    int *nadj, *newmap, *adj, *offset, nconn;
    int nalloc, depth, maxwidth;
        
#ifdef MSTK_USE_MARKERS
    int mkid = MSTK_GetMarker();
#else
    MAttrib_ptr mkatt = MAttrib_New(mesh, "mkatt", INT, MALLTYPE);
#endif

    if (mtype == MVERTEX || mtype == MALLTYPE) { 
      int nv = MESH_Num_Vertices(mesh);      
      
      /* Compute a graph of vertex connections across elements (faces
	 for surface meshes, regions for solid meshes */

      /* Start with the vertex in the lower leftmost corner */
      
      minx = miny = minz = 1.0e+12;
      v0 = NULL;
      idx = 0;
      while ((mv = MESH_Next_Vertex(mesh,&idx))) {
	MV_Coords(mv,xyz);
	if (xyz[0] <= minx && xyz[1] <= miny && xyz[2] <= minz) {
	  minx = xyz[0];
	  miny = xyz[1];
	  minz = xyz[2];
	  v0 = mv;
	}
      }


      nadj = (int *) malloc(nv*sizeof(int));
      nalloc = nv*5;
      adj = (int *) malloc(nalloc*sizeof(int));

      if (!MESH_Num_Regions(mesh)) {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((mv = MESH_Next_Vertex(mesh,&idx))) {
          List_ptr vfaces, adjvlist;
          MFace_ptr vf;
          MVertex_ptr adjv;

          adjvlist = List_New(0);
          vfaces = MV_Faces(mv);
          idx2 = 0;
          while ((vf = List_Next_Entry(vfaces,&idx2))) {
            List_ptr fverts = MF_Vertices(vf,1,0);
            idx3 = 0;
            while ((adjv = List_Next_Entry(fverts,&idx3))) {
              if (adjv != mv) {
                int vmarked;
#ifdef MSTK_USE_MARKERS
                vmarked = MEnt_IsMarked(adjv,mkid);
#else
                MEnt_Get_AttVal(adjv, mkatt, &vmarked, &rval, &pval);
#endif
                if (!vmarked) {
                  List_Add(adjvlist,adjv);
#ifdef MSTK_USE_MARKERS
                  MEnt_Mark(adjv,mkid);
#else
                  MEnt_Set_AttVal(adjv, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }
            List_Delete(fverts);
          }
          List_Delete(vfaces);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjvlist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjvlist);
          
          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adjv = List_Next_Entry(adjvlist,&idx2)))
            adj[nentries++] = MV_ID(adjv)-1;

          List_Delete(adjvlist);
          i++;
        }
      }
      else {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((mv = MESH_Next_Vertex(mesh,&idx))) {
          List_ptr vregions, adjvlist;
          MRegion_ptr vr;
          MVertex_ptr adjv;

          adjvlist = List_New(0);
          vregions = MV_Regions(mv);
          idx2 = 0;
          while ((vr = List_Next_Entry(vregions,&idx2))) {
            List_ptr rverts = MR_Vertices(vr);
            idx3 = 0;
            while ((adjv = List_Next_Entry(rverts,&idx3))) {
              if (adjv != mv) {
                int vmarked;
#ifdef MSTK_USE_MARKERS
                vmarked = MEnt_IsMarked(adjv,mkid);
#else
                MEnt_Get_AttVal(adjv, mkatt, &vmarked, &rval, &pval);
#endif
                if (!vmarked) {
                  List_Add(adjvlist,adjv);
#ifdef MSTK_USE_MARKERS
                  MEnt_Mark(adjv,mkid);
#else
                  MEnt_Set_AttVal(adjv, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }
            List_Delete(rverts);
          }
          List_Delete(vregions);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjvlist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjvlist);

          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adjv = List_Next_Entry(adjvlist,&idx2)))
            adj[nentries++] = MV_ID(adjv)-1;

          List_Delete(adjvlist);
          i++;
        }
      }

      /* Compute offsets into adj array */

      offset = (int *) malloc(nv*sizeof(int));
      offset[0] = 0;
      for (i = 1; i < nv; i++)
	offset[i] = offset[i-1] + nadj[i-1];

      /* Compute maximum bandwidth before renumbering */

      maxbandwidth1 = 0;
      avebandwidth1 = 0;
      for (i = 0; i < nv; i++) {
	int off = offset[i];
	int curid = i;
	for (j = 0; j < nadj[i]; j++) {
	  int adjid = adj[off+j];
	  int diff = abs(adjid-curid);
	  maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1;
	  avebandwidth1 += diff;
	  nconn++;
	}
      }
      nconn = offset[nv-1]+nadj[nv-1];
      avebandwidth1 /= nconn;

      fprintf(stderr,
	      "Ave vertex ID difference on elements before renumbering: %-lf\n",
	      avebandwidth1);
      fprintf(stderr,
	      "Max vertex ID difference on elements before renumbering: %-d\n",
	      maxbandwidth1);
    
      fprintf(stderr,"\n");

      newmap = (int *) malloc(nv*sizeof(int));
      Graph_Renumber_GPS(nv, MV_ID(v0)-1, nadj, adj, newmap, &depth, &maxwidth);


      /* Compute bandwidth after renumbering */

      maxbandwidth2 = 0;
      avebandwidth2 = 0;
      for (i = 0; i < nv; i++) {
	int off = offset[i];
	int curid = newmap[i];
	for (j = 0; j < nadj[i]; j++) {
	  int adjid = newmap[adj[off+j]];
	  int diff = abs(adjid-curid);
	  maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2;
	  avebandwidth2 += diff;
	  nconn++;
	}
      }
      nconn = offset[nv-1]+nadj[nv-1];
      avebandwidth2 /= nconn;


      if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) {

        /* Renumber */
      
        idx = 0; i = 0;
        while ((mv = MESH_Next_Vertex(mesh,&idx))) {
          MV_Set_ID(mv,newmap[i]+1);
          i++;
        }

        fprintf(stderr,
                "Ave vertex ID difference on elements after renumbering: %-lf\n",
                avebandwidth2);
        fprintf(stderr,
                "Max vertex ID difference on elements after renumbering: %-d\n",
                maxbandwidth2);    
      }
      else {
        nv = 0;
        idx = 0; 
        while ((mv = MESH_Next_Vertex(mesh,&idx)))
          MV_Set_ID(mv,++nv);

        fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n");
      }
      fprintf(stderr,"\n\n\n");
      
      free(nadj);
      free(adj);
      free(offset);
      free(newmap);

    }
 



    /* Reorder edges according to a breadth first algorithm applied to
       edges (differs from RCM in that it does not add adjacent nodes
       in ascending order of their valence) */

    if (mtype == MEDGE || mtype == MALLTYPE) {
      int ne = MESH_Num_Edges(mesh);
      MEdge_ptr ve;
      List_ptr elist;

      /************************* renumbering code ****************************/

      ne = MESH_Num_Edges(mesh);

      if (mtype == MALLTYPE) { 

	/* RCM algorithm already applied on the vertices. Use an edge
	   connected to the starting vertex as the first edge */

	List_ptr vedges = MV_Edges(v0);
	e0 = List_Entry(vedges,0);
	List_Delete(vedges);
      }
      else {
	/* Find the edge whose mid point is a minimum point */
	minx = miny = minz = 1.0e+12;
	e0 = NULL;
	idx = 0;
	while ((me = MESH_Next_Edge(mesh,&idx))) {
          double exyz[2][3];

	  MV_Coords(ME_Vertex(me,0),exyz[0]);
	  MV_Coords(ME_Vertex(me,1),exyz[1]);
	  xyz[0] = (exyz[0][0]+exyz[1][0])/2.0;
	  xyz[1] = (exyz[0][1]+exyz[1][1])/2.0;
	  xyz[2] = (exyz[0][2]+exyz[1][2])/2.0;
	  if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) {
	    minx = xyz[0];
	    miny = xyz[1];
	    minz = xyz[2];
	    e0 = me;
	  }
	}
      }


      nadj = (int *) malloc(ne*sizeof(int));
      nalloc = ne*5;
      adj = (int *) malloc(nalloc*sizeof(int));

      if (!MESH_Num_Regions(mesh)) {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((me = MESH_Next_Edge(mesh,&idx))) {
          List_ptr efaces, adjelist;
          MFace_ptr ef;
          MEdge_ptr adje;

          adjelist = List_New(0);
          efaces = ME_Faces(me);
          idx2 = 0;
          while ((ef = List_Next_Entry(efaces,&idx2))) {
            List_ptr fedges = MF_Edges(ef,1,0);
            idx3 = 0;
            while ((adje = List_Next_Entry(fedges,&idx3))) {
              if (adje != me) {
                int emarked;
#ifdef MSTK_USE_MARKERS
                emarked = MEnt_IsMarked(adje,mkid);
#else
                MEnt_Get_AttVal(adje, mkatt, &emarked, &rval, &pval);
#endif
                if (!emarked) {
                  List_Add(adjelist,adje);
#ifdef MSTK_USE_MARKERS
                  MEnt_Mark(adje,mkid);
#else
                  MEnt_Set_AttVal(adje, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }
            List_Delete(fedges);
          }
          List_Delete(efaces);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjelist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjelist);

          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adje = List_Next_Entry(adjelist,&idx2)))
            adj[nentries++] = ME_ID(adje)-1;

          List_Delete(adjelist);
          i++;
        }
      }
      else {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((me = MESH_Next_Edge(mesh,&idx))) {
          List_ptr eregions, adjelist;
          MRegion_ptr er;
          MEdge_ptr adje;

          adjelist = List_New(0);
          eregions = ME_Regions(me);
          idx2 = 0;
          while ((er = List_Next_Entry(eregions,&idx2))) {
            List_ptr redges = MR_Edges(er);
            idx3 = 0;
            while ((adje = List_Next_Entry(redges,&idx3))) {
              if (adje != me) {
                int emarked;
#ifdef MSTK_USE_MARKERS
                emarked = MEnt_IsMarked(adje,mkid);
#else
                MEnt_Get_AttVal(adje, mkatt, &emarked, &rval, &pval);
#endif
                if (!emarked) {
                  List_Add(adjelist,adje);
#ifdef MSTK_USE_MARKERS
                  MEnt_Mark(adje,mkid);
#else
                  MEnt_Set_AttVal(adje, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }
            List_Delete(redges);
          }
          List_Delete(eregions);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjelist,mkid);
#endif
          
          nadj[i] = List_Num_Entries(adjelist);
          
          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }
          
          idx2 = 0;
          while ((adje = List_Next_Entry(adjelist,&idx2)))
            adj[nentries++] = ME_ID(adje)-1;
          
          List_Delete(adjelist);
          i++;
        }
      }

      /* Compute offsets into adj array */

      offset = (int *) malloc(ne*sizeof(int));
      offset[0] = 0;
      for (i = 1; i < ne; i++)
        offset[i] = offset[i-1] + nadj[i-1];


      /* Compute maximum bandwidth before renumbering */

      maxbandwidth1 = 0;
      avebandwidth1 = 0;
      for (i = 0; i < ne; i++) {
        int off = offset[i];
        int curid = i;
        for (j = 0; j < nadj[i]; j++) {
          int adjid = adj[off+j];
          int diff = abs(adjid-curid);
          maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1;
          avebandwidth1 += diff;
          nconn++;
        }
      }
      nconn = offset[ne-1]+nadj[ne-1];
      avebandwidth1 /= nconn;

      fprintf(stderr,
              "Ave edge ID difference on elements before renumbering: %-lf\n",
              avebandwidth1);
      fprintf(stderr,
              "Max edge ID difference on elements before renumbering: %-d\n",
              maxbandwidth1);
    
      fprintf(stderr,"\n");


      /* Call Graph Renumbering algorithm */

      newmap = (int *) malloc(ne*sizeof(int));
      Graph_Renumber_GPS(ne, ME_ID(e0)-1, nadj, adj, newmap, &depth, &maxwidth);


      /* Compute bandwidth after renumbering */

      maxbandwidth2 = 0;
      avebandwidth2 = 0;
      for (i = 0; i < ne; i++) {
        int off = offset[i];
        int curid = newmap[i];
        for (j = 0; j < nadj[i]; j++) {
          int adjid = newmap[adj[off+j]];
          int diff = abs(adjid-curid);
          maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2;
          avebandwidth2 += diff;
          nconn++;
        }
      }
      nconn = offset[ne-1]+nadj[ne-1];
      avebandwidth2 /= nconn;

      if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) {
        /* Renumber */
      
        idx = 0; i = 0;
        while ((me = MESH_Next_Edge(mesh,&idx))) {
          ME_Set_ID(me,newmap[i]+1);
          i++;
        }

        fprintf(stderr,
                "Ave edge ID difference on elements after renumbering: %-lf\n",
                avebandwidth2);
        fprintf(stderr,
                "Max edge ID difference on elements after renumbering: %-d\n",
                maxbandwidth2);
        
      }
      else {
        ne = 0;
        idx = 0; 
        while ((me = MESH_Next_Edge(mesh,&idx)))
          ME_Set_ID(me,++ne);

        fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n");
      }
      fprintf(stderr,"\n\n\n");


      free(nadj);
      free(adj);
      free(offset);
      free(newmap);

    }


    /* Reorder faces according to a breadth first algorithm applied to
       edges (differs from RCM in that it does not add adjacent graph nodes
       in ascending order of their valence) */

    if (mtype == MFACE || mtype == MALLTYPE) {      
      int nf = MESH_Num_Faces(mesh);

      if (mtype == MALLTYPE) { 

        /* RCM algorithm already applied on the vertices. Use an edge
           connected to the starting vertex as the first edge */

        List_ptr vfaces = MV_Faces(v0);
        f0 = List_Entry(vfaces,0);
        List_Delete(vfaces);
      }
      else {
        /* Find the face whose mid point is a minimum point */
        minx = miny = minz = 1.0e+12;
        f0 = NULL;
        idx = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          double fxyz[MAXPV2][3];
          int nfv;

          MF_Coords(mf,&nfv,fxyz);
          xyz[0] = fxyz[0][0];
          xyz[1] = fxyz[0][1];
          xyz[2] = fxyz[0][2];
          for (i = 1; i < nfv; i++) {
            xyz[0] += fxyz[i][0];
            xyz[1] += fxyz[i][1];
            xyz[2] += fxyz[i][2];
          }
          xyz[0] /= nfv; xyz[1] /= nfv; xyz[2] /= nfv;
          if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) {
            minx = xyz[0];
            miny = xyz[1];
            minz = xyz[2];
            f0 = mf;
          }
        }
      }


      nadj = (int *) malloc(nf*sizeof(int));
      nalloc = nf*5;
      adj = (int *) malloc(nalloc*sizeof(int));

      if (!MESH_Num_Regions(mesh)) {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          List_ptr vfaces, fverts, adjflist;
          MFace_ptr vf, adjf;
          MVertex_ptr fv;

          adjflist = List_New(0);
          fverts = MF_Vertices(mf,1,0);
          idx2 = 0;
          while ((fv = List_Next_Entry(fverts,&idx2))) {
            List_ptr vfaces = MV_Faces(fv);
            idx3 = 0;
            while ((adjf = List_Next_Entry(vfaces,&idx3))) {
              if (adjf != mf) {
                int fmarked;
#ifdef MSTK_USE_MARKERS
                fmarked = MEnt_IsMarked(adjf,mkid);
#else
                MEnt_Get_AttVal(adjf, mkatt, &fmarked, &rval, &pval);
#endif
                if (fmarked) {
                  List_Add(adjflist,adjf);
#ifdef MSTK_USE_MARKERS                  
                  MEnt_Mark(adjf,mkid);
#else
                  MEnt_Set_AttVal(adjf, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }	    
            List_Delete(vfaces);
          }
          List_Delete(fverts);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjflist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjflist);

          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adjf = List_Next_Entry(adjflist,&idx2)))
            adj[nentries++] = MF_ID(adjf)-1;

          List_Delete(adjflist);
          i++;
        }
      }
      else {
        int nentries = 0;
        i = 0;
        idx = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          List_ptr fregions, adjflist;
          MRegion_ptr fr;
          MFace_ptr adjf;

          adjflist = List_New(0);
          fregions = MF_Regions(mf);
          idx2 = 0;
          while ((fr = List_Next_Entry(fregions,&idx2))) {
            List_ptr rfaces = MR_Faces(fr);
            idx3 = 0;
            while ((adjf = List_Next_Entry(rfaces,&idx3))) {
              if (adjf != mf) {
                int fmarked;
#ifdef MSTK_USE_MARKERS
                fmarked = MEnt_IsMarked(adjf,mkid);
#else
                MEnt_Get_AttVal(adjf, mkatt, &fmarked, &rval, &pval);
#endif
                if (fmarked) {
                  List_Add(adjflist,adjf);
#ifdef MSTK_USE_MARKERS                  
                  MEnt_Mark(adjf,mkid);
#else
                  MEnt_Set_AttVal(adjf, mkatt, 1, 0.0, NULL);
#endif
                }
              }
            }
            List_Delete(rfaces);
          }
          List_Delete(fregions);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjflist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjflist);

          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adjf = List_Next_Entry(adjflist,&idx2)))
            adj[nentries++] = MF_ID(adjf)-1;

          List_Delete(adjflist);
          i++;
        }
      }

      /* Compute offsets into adj array */

      offset = (int *) malloc(nf*sizeof(int));
      offset[0] = 0;
      for (i = 1; i < nf; i++)
        offset[i] = offset[i-1] + nadj[i-1];


      /* Compute maximum bandwidth before renumbering */

      maxbandwidth1 = 0;
      avebandwidth1 = 0;
      for (i = 0; i < nf; i++) {
        int off = offset[i];
        int curid = i;
        for (j = 0; j < nadj[i]; j++) {
          int adjid = adj[off+j];
          int diff = abs(adjid-curid);
          maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1;
          avebandwidth1 += diff;
          nconn++;
        }
      }
      nconn = offset[nf-1]+nadj[nf-1];
      avebandwidth1 /= nconn;

      if (MESH_Num_Regions(mesh)) {
        fprintf(stderr,
                "Ave face ID difference on elements before renumbering: %-lf\n",
                avebandwidth1);
        fprintf(stderr,
                "Max face ID difference on elements before renumbering: %-d\n",
                maxbandwidth1);
      }
      else {
        fprintf(stderr,
                "Ave face ID difference before renumbering: %-lf\n",
                avebandwidth1);
        fprintf(stderr,
                "Max face ID difference before renumbering: %-d\n",
                maxbandwidth1);
      }
    
      fprintf(stderr,"\n");


      /* Call Graph Renumbering algorithm */

      newmap = (int *) malloc(nf*sizeof(int));
      Graph_Renumber_GPS(nf, MF_ID(f0)-1, nadj, adj, newmap, &depth, &maxwidth);


      /* Compute bandwidth after renumbering */

      maxbandwidth2 = 0;
      avebandwidth2 = 0;
      for (i = 0; i < nf; i++) {
        int off = offset[i];
        int curid = newmap[i];
        for (j = 0; j < nadj[i]; j++) {
          int adjid = newmap[adj[off+j]];
          int diff = abs(adjid-curid);
          maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2;
          avebandwidth2 += diff;
          nconn++;
        }
      }
      nconn = offset[nf-1]+nadj[nf-1];
      avebandwidth2 /= nconn;


      if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) {
        /* Renumber */
      
        idx = 0; i = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          MF_Set_ID(mf,newmap[i]+1);
          i++;
        }

        if (MESH_Num_Regions(mesh)) {
          fprintf(stderr,
                  "Ave face ID difference on elements after renumbering: %-lf\n",
                  avebandwidth2);
          fprintf(stderr,
                  "Max face ID difference on elements after renumbering: %-d\n",
                  maxbandwidth2);
        }
        else {
          fprintf(stderr,
                  "Ave face ID difference after renumbering: %-lf\n",
                  avebandwidth2);
          fprintf(stderr,
                  "Max face ID difference after renumbering: %-d\n",
                  maxbandwidth2);
        }
    
      }
      else {
        nf = 0;
        idx = 0; 
        while ((mf = MESH_Next_Face(mesh,&idx)))
          MF_Set_ID(mf,++nf);

        fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n");
      }
      fprintf(stderr,"\n\n\n");

      free(nadj);
      free(adj);
      free(offset);
      free(newmap);
    }


    if (mtype == MREGION || mtype == MALLTYPE) {
      int nr = MESH_Num_Regions(mesh);

      if (nr) {

        if (mtype == MALLTYPE) { 

          /* Renumbering algorithm already applied on the vertices. Use
             a region connected to the starting vertex as the first
             region */

          List_ptr vregions = MV_Regions(v0);
          r0 = List_Entry(vregions,0);
          List_Delete(vregions);
        }
        else {
          /* Find the region whose center point is a minimum point */
          minx = miny = minz = 1.0e+12;
          r0 = NULL;
          idx = 0;
          while ((mr = MESH_Next_Region(mesh,&idx))) {
            double rxyz[MAXPV3][3];
            int nrv;

            MR_Coords(mr,&nrv,rxyz);
            xyz[0] = rxyz[0][0];
            xyz[1] = rxyz[0][1];
            xyz[2] = rxyz[0][2];
            for (i = 1; i < nrv; i++) {
              xyz[0] += rxyz[i][0];
              xyz[1] += rxyz[i][1];
              xyz[2] += rxyz[i][2];
            }
            xyz[0] /= nrv; xyz[1] /= nrv; xyz[2] /= nrv;
            if (xyz[0] < minx && xyz[1] < miny && xyz[2] < minz) {
              minx = xyz[0];
              miny = xyz[1];
              minz = xyz[2];
              r0 = mr;
            }
          }
        }


        nadj = (int *) malloc(nr*sizeof(int));
        nalloc = nr*5;
        adj = (int *) malloc(nalloc*sizeof(int));

        int nentries = 0;
        i = 0;
        idx = 0;
        while ((mr = MESH_Next_Region(mesh,&idx))) {
          List_ptr vregions, rverts, adjrlist;
          MRegion_ptr vr, adjr;
          MVertex_ptr rv;

          adjrlist = List_New(0);
          rverts = MR_Vertices(mr);
          idx2 = 0;
          while ((rv = List_Next_Entry(rverts,&idx2))) {
            List_ptr vregions = MV_Regions(rv);
            idx3 = 0;
            while ((adjr = List_Next_Entry(vregions,&idx3))) {
              if (adjr != mr) {
                int rmarked;
#ifdef MSTK_USE_MARKERS
                rmarked = MEnt_IsMarked(adjr,mkid);
#else
                MEnt_Get_AttVal(adjr, mkatt, &rmarked, &rval, &pval);
#endif
                List_Add(adjrlist,adjr);
#ifdef MSTK_USE_MARKERS
                MEnt_Mark(adjr,mkid);
#else
                MEnt_Set_AttVal(adjr, mkatt, 1, 0.0, NULL);
#endif
              }
            }	    
            List_Delete(vregions);
          }
          List_Delete(rverts);
#ifdef MSTK_USE_MARKERS
          List_Unmark(adjrlist,mkid);
#endif

          nadj[i] = List_Num_Entries(adjrlist);

          if (nentries+nadj[i] > nalloc) {
            nalloc *= 2;
            adj = (int *) realloc(adj,nalloc*sizeof(int));
          }

          idx2 = 0;
          while ((adjr = List_Next_Entry(adjrlist,&idx2)))
            adj[nentries++] = MR_ID(adjr)-1;

          List_Delete(adjrlist);
          i++;
        }

        /* Compute offsets into adj array */

        offset = (int *) malloc(nr*sizeof(int));
        offset[0] = 0;
        for (i = 1; i < nr; i++)
          offset[i] = offset[i-1] + nadj[i-1];


        /* Compute maximum bandwidth before renumbering */

        maxbandwidth1 = 0;
        avebandwidth1 = 0;
        for (i = 0; i < nr; i++) {
          int off = offset[i];
          int curid = i;
          for (j = 0; j < nadj[i]; j++) {
            int adjid = adj[off+j];
            int diff = abs(adjid-curid);
            maxbandwidth1 = (diff > maxbandwidth1) ? diff : maxbandwidth1;
            avebandwidth1 += diff;
            nconn++;
          }
        }
        nconn = offset[nr-1]+nadj[nr-1];
        avebandwidth1 /= nconn;

        fprintf(stderr,
                "Ave region ID difference before renumbering: %-lf\n",
                avebandwidth1);
        fprintf(stderr,
                "Max region ID difference before renumbering: %-d\n",
                maxbandwidth1);
    
        fprintf(stderr,"\n");


        /* Call Graph Renumbering algorithm */

        newmap = (int *) malloc(nr*sizeof(int));
        Graph_Renumber_GPS(nr, MR_ID(r0)-1, nadj, adj, newmap, &depth, &maxwidth);

        /* Compute bandwidth after renumbering */

        maxbandwidth2 = 0;
        avebandwidth2 = 0;
        for (i = 0; i < nr; i++) {
          int off = offset[i];
          int curid = newmap[i];
          for (j = 0; j < nadj[i]; j++) {
            int adjid = newmap[adj[off+j]];
            int diff = abs(adjid-curid);
            maxbandwidth2 = (diff > maxbandwidth2) ? diff : maxbandwidth2;
            avebandwidth2 += diff;
            nconn++;
          }
        }
        nconn = offset[nr-1]+nadj[nr-1];
        avebandwidth2 /= nconn;

        if (maxbandwidth2 < maxbandwidth1 && avebandwidth2 < avebandwidth1) {

          /* Renumber */
      
          idx = 0; i = 0;
          while ((mr = MESH_Next_Region(mesh,&idx))) {
            MR_Set_ID(mr,newmap[i]+1);
            i++;
          }

          fprintf(stderr,
                  "Ave region ID difference after renumbering: %-lf\n",
                  avebandwidth2);
          fprintf(stderr,
                  "Max region ID difference after renumbering: %-d\n",
                  maxbandwidth2);
    
        }
        else {
          nr = 0;
          idx = 0; 
          while ((mr = MESH_Next_Region(mesh,&idx)))
            MR_Set_ID(mr,++nr);

          fprintf(stderr,"Bandwidth did not improve. Keeping old numbering with gaps eliminated\n");
        }
        fprintf(stderr,"\n\n\n");


        free(nadj);
        free(adj);
        free(offset);
        free(newmap);
      }
    }

#ifdef MSTK_USE_MARKERS
    MSTK_FreeMarker(mkid);
#endif
  }
  

  vidatt = MAttrib_New(mesh,"vidrcm",INT,MVERTEX);
  idx = 0;
  while ((mv = MESH_Next_Vertex(mesh,&idx))) {
    MEnt_Set_AttVal(mv,vidatt,MV_ID(mv),0.0,NULL);
  }
 

  /* We have to reset the max IDs stored in the mesh so that we can correctly
     assign IDs to new entities */

  MESH_Reset_Cached_MaxIDs(mesh);

  return;
}
Beispiel #4
0
  int MESH_BuildFaceClassfn(Mesh_ptr mesh, int use_geometry) {
  int i, j, k, idx, idx2, fnd, gfid, gfid2, gdim;
  int ngfaces, ngfalloc, grid0, grid1;
  int max_gface_id, processedmk, submk;
  int nfe, nef, nbf, nfr, nsub, *gfids, (*gfregids)[2];
  double PI=3.141592, ang, COSSHARPANG;
  MEdge_ptr edge;
  MFace_ptr face, subface, adjface;
  MRegion_ptr freg0, freg1;
  List_ptr fregs, fedges, efaces, ebfaces, gffaces, subfaces;

  COSSHARPANG = cos(9*PI/12);  /* 135 degrees */


  /* Verify that mesh faces on the boundary have classification
     information; if not, assign all faces to the same model faces */

  ngfaces = 0; ngfalloc = 10;
  gfids = (int *) malloc(ngfalloc*sizeof(int));
  gfregids = (int (*)[2]) malloc(ngfalloc*sizeof(int [2]));


  /* Take stock of existing model face information */

  max_gface_id = 0;
  idx = 0;
  while ((face = MESH_Next_Face(mesh,&idx))) {
    gdim = MF_GEntDim(face);
    if (gdim != 2)
      continue;

    gfid = MF_GEntID(face);
    if (gfid) {

      /* Has this model face been encountered? If not, add it to list
	 of model faces */

      for (i = 0, fnd = 0; i < ngfaces; i++)
	if (gfids[i] == gfid) {
	  fnd = 1;
	  break;
	}

      if (!fnd) {
	if (gfid > max_gface_id)
	  max_gface_id = gfid;

	if (ngfalloc == ngfaces) {
	  ngfalloc *= 2;
	  gfids = (int *) realloc(gfids,ngfalloc*sizeof(int));
	  gfregids = (int (*)[2])realloc(gfregids,ngfalloc*sizeof(int [2]));
	}

	gfids[ngfaces] = gfid;
	gfregids[ngfaces][0] = gfregids[ngfaces][1] = 0;
	fregs = MF_Regions(face);
	if (fregs) {
	  nfr = List_Num_Entries(fregs);
      
	  freg0 = List_Entry(fregs,0);
	  gfregids[ngfaces][0] = MR_GEntID(freg0); /* NOTE 1 (see EOF) */
      
	  if (nfr == 2) {
	    freg1 = List_Entry(fregs,1); 
	    gfregids[ngfaces][1] = MR_GEntID(freg1);
	  }	  
	  
	  List_Delete(fregs);
	}

	ngfaces++;
      }

    }
  }


  /* Build new model face information based on adjacent model region info */

  idx = 0;
  while ((face = MESH_Next_Face(mesh,&idx))) {
    
    gdim = MF_GEntDim(face);
    gfid = MF_GEntID(face);

    /* Face has no classification? Assign classification info */
    /* Face classified as interior face? Verify */
    
    freg0 = freg1 = NULL;
    grid0 = grid1 = 0;
    fregs = MF_Regions(face);
    if (fregs) {
      nfr = List_Num_Entries(fregs);
      
      freg0 = List_Entry(fregs,0);
      grid0 = MR_GEntID(freg0);
      
      if (nfr == 2) {
	freg1 = List_Entry(fregs,1); 
	grid1 = MR_GEntID(freg1);
      }
      
      List_Delete(fregs);
    }
    else
      nfr = 0;
    
    if (nfr == 2 && (grid0 == grid1)) {
      /* Interior face */
      
      MF_Set_GEntDim(face,3);
      MF_Set_GEntID(face,grid0);
    }
    else {
      /* Boundary face */
      
      if (gdim > 2 || (gdim == 2 && gfid <= 0)) { 
	MF_Set_GEntDim(face,2);

	/* Check if this type of face with these adjacent regions has
	   been encountered before; if it has, we just use the
	   existing model face id */

	for (i = 0, fnd = 0; i < ngfaces; i++)
	  if ((gfregids[i][0] == grid0 && gfregids[i][1] == grid1) ||
	      (gfregids[i][0] == grid1 && gfregids[i][1] == grid0)) {
	    fnd = 1;
	    break;
	  }

	if (fnd)
	  MF_Set_GEntID(face,gfids[i]);
	else {
	  max_gface_id++;
	  MF_Set_GEntID(face,max_gface_id);

	  if (ngfalloc == ngfaces) {
	    ngfalloc *= 2;
	    gfids = (int *) realloc(gfids,ngfalloc*sizeof(int));
	    gfregids = (int (*)[2]) realloc(gfregids,ngfalloc*sizeof(int [2]));
	  }

	  gfids[ngfaces] = max_gface_id;
	  gfregids[ngfaces][0] = grid0;
	  gfregids[ngfaces][1] = grid1;
	  ngfaces++;
	}
      }
    }
  }

  if (use_geometry == 1) {

    /* Now assign model face IDs based on whether a sharp set of edges
       enclose a set of faces */

    for (i = 0; i < ngfaces; i++) {

      /* Find all mesh faces with this model face id */

      gffaces = List_New(10);
      idx = 0; 
      while ((face = MESH_Next_Face(mesh,&idx))) {
        if (MF_GEntDim(face) == 2 && MF_GEntID(face) == gfids[i])
          List_Add(gffaces,face);
      }

      /* Process faces of this list and subdivide them into subfaces */
      /* The way we do that is 
       
         1) we put an unprocessed face from the original list in a subface
         list

         2) we then add its neighboring faces to subface list if they are
         of the same color (same model face id) and do not have a sharp
         edge separating them from the current face

         3) we then process the next face in the subface list 

         4) we are done if we cannot find any more neighbors of faces in
         the subface list to add to the subface list

         5) we then repeat steps 1 through 4 until we are left with no
         more faces to process from the original list
       
      */

      processedmk = MSTK_GetMarker();

      nsub = 0;
      idx = 0;
      while ((face = List_Next_Entry(gffaces,&idx))) {
        if (MEnt_IsMarked(face,processedmk))
          continue;

        /* Found a face in gffaces that has not been processed */
        MEnt_Mark(face,processedmk);

        submk = MSTK_GetMarker();
        subfaces = List_New(10);
        List_Add(subfaces,face);
        MEnt_Mark(face,submk);

        idx2 = 0;
        while ((subface = List_Next_Entry(subfaces,&idx2))) {
          gfid = MF_GEntID(subface);

          fedges = MF_Edges(subface,1,0);
          nfe = List_Num_Entries(fedges);

          for (j = 0; j < nfe; j++) {
            edge = List_Entry(fedges,j);
            efaces = ME_Faces(edge);
            nef = List_Num_Entries(efaces);

            ebfaces = List_New(nef); /* list of boundary faces cnctd 2 edge */
            for (k = 0; k < nef; k++) {
              adjface = List_Entry(efaces,k);
              if (MF_GEntDim(adjface) == 2)
                List_Add(ebfaces,adjface);
            }
            List_Delete(efaces);

            nbf = List_Num_Entries(ebfaces);
            if (nbf == 2) {
              /* we might be on a model face or on a model edge */
            
              adjface = List_Entry(ebfaces,0);
              if (adjface == subface)
                adjface = List_Entry(ebfaces,1);
              gfid2 = MF_GEntID(adjface);

            
              if (gfid == gfid2) {
                /* The two faces are of the same ID. If the angle
                   between them is not sharp they can be classified as
                   being on the same subface */
	      
                ang = MFs_DihedralAngle(subface,adjface,edge);
              
                if (ang <= COSSHARPANG) {
                  /* Add face2 to subface list unless its already there */
                  if (!MEnt_IsMarked(adjface,submk)) {
                    List_Add(subfaces,adjface);
                    MEnt_Mark(adjface,submk);
                  }
                }
                else {
                  /* The two faces make a very sharp angle. We will
                     consider the edge b/w them to be a model edge */
                  /* Tag the edge as being on a model edge (we don't
                     know the model edge ID as yet) and continue */
                
                  ME_Set_GEntDim(edge,1);
                  ME_Set_GEntID(edge,0);
                }
              }
              else {
                /* we reached a model edge */
                /* Tag the edge as being on a model edge (we don't know
                   the model edge ID as yet) and continue */

                ME_Set_GEntDim(edge,1);
                ME_Set_GEntID(edge,0);
              }
            }
            else {
              /* we reached a a model edge */
              /* Tag the edge as being on a model edge (we don't know
                 the model edge ID as yet) and continue */

              ME_Set_GEntDim(edge,1);
              ME_Set_GEntID(edge,0);
            }
            List_Delete(ebfaces);
          }

          /* Finished processing all neighbors of the face */
          List_Delete(fedges);
        }

        /* Now we have a list of faces which we believe constitutes a
           model face by itself. If this is the first subface (which
           means it could also be the entire model face originally
           considered), leave the model face tag as it is. If not,
           assign the faces in the subface a new model face ID */

        if (nsub != 0) {
          max_gface_id++;
          idx2 = 0;
          while ((subface = List_Next_Entry(subfaces,&idx2))) 
            MF_Set_GEntID(subface,max_gface_id);
        }
        nsub++;

        /* Done with this subface */

        idx2 = 0;
        while ((subface = List_Next_Entry(subfaces,&idx2))) {
          MEnt_Mark(subface,processedmk);
          MEnt_Unmark(subface,submk);
        }
        MSTK_FreeMarker(submk);
        List_Delete(subfaces);
      }

      List_Unmark(gffaces,processedmk);
      MSTK_FreeMarker(processedmk);
      List_Delete(gffaces);
    }
  
  } /* if use_geometry == 1 */

  free(gfids);
  free(gfregids);
       
  return 1;
}
Beispiel #5
0
  int MESH_CheckTopo(Mesh_ptr mesh) {
    int valid = 1;
    char mesg[256], funcname[32] = "MESH_CheckTopo";
    int idx1, idx2, idx3, idx4;
    MVertex_ptr mv;
    MEdge_ptr me, ve, fe, re;
    MFace_ptr mf, vf, ef, rf;
    MRegion_ptr mr, vr, er, fr;
    int found, done;
    int dir;
    int i, j, k;
    int nfe;
    int vid, eid, fid, rid;
    int gvid, geid, gfid, grid;
    int gvdim, gedim, gfdim, grdim;
    int maxiter = 1000;
    List_ptr vedges, vfaces, vregions;
    List_ptr efaces;
    List_ptr fverts, fedges, fregs, fregs1;
    List_ptr rverts, redges, rfaces;



    /*****************************************************************/
    /* Vertices                                                      */
    /*****************************************************************/    

    
    /* Check that edges connected to vertices reference the vertices */
    /* Also check that the classification of the vertex is consistent
       with respect to the edge */

    int first_unknown_classfn = 1;
    idx1 = 0;
    while ((mv = MESH_Next_Vertex(mesh,&idx1))) {

#ifdef MSTK_HAVE_MPI
      if (MV_PType(mv) == PGHOST) continue;
#endif      

      vid = MV_ID(mv);
      gvdim = MV_GEntDim(mv);
      gvid  = MV_GEntID(mv);

      if (gvdim == 4 && first_unknown_classfn) {
        sprintf(mesg, "Vertex %-d - classification unknown\n", vid);
        MSTK_Report(funcname, mesg, MSTK_WARN);
        first_unknown_classfn = 0;
      }
      vedges = MV_Edges(mv);
      if (!vedges) {
        sprintf(mesg,"Vertex %-d does not have any connected edges\n",vid);
        MSTK_Report(funcname,mesg,MSTK_WARN);
        continue;
      }

      idx2 = 0;
      while ((ve = List_Next_Entry(vedges,&idx2))) {
	
	eid = ME_ID(ve);
	     
	if (ME_Vertex(ve,0) != mv && ME_Vertex(ve,1) != mv) {
	  sprintf(mesg,"Vertex %-d connected to edge %-d but edge does not use vertex",vid,eid);
	  MSTK_Report(funcname,mesg,MSTK_ERROR);
	  valid = 0;
	}

      }


      if (gvdim == 1) {

	/* If vertex is classified on a model edge, then it should be
	   connected to two and only two edges that are classified on
	   the same model edge */

	int ne = 0;
	idx2 = 0;
	while ((ve = List_Next_Entry(vedges,&idx2))) {	  
	  gedim = ME_GEntDim(ve);
	  geid  = ME_GEntID(ve);	  
	  if (gedim == 1 && geid == gvid) ne++;
	}
	  
	if (ne != 2) {
	  sprintf(mesg,"Vertex %-d classified on model edge %-d but it is not \n connected to two edges classified on this model edge",vid,gvid);
	  MSTK_Report(funcname,mesg,MSTK_WARN);
	}
      }

      List_Delete(vedges);



      if (gvdim == 2) {
	MEdge_ptr e0, ecur, enxt;
	MFace_ptr fcur;
        int flipped = 0;

	/* If vertex is classified on a model face, then we should be
	   able to find a ring of faces classified on that model
	   face */

	vfaces = MV_Faces(mv);

	found = 0;
	idx2 = 0;
	while ((vf = List_Next_Entry(vfaces,&idx2))) {
	  if (MF_GEntDim(vf) == 2) {
	    found = 1;
	    break;
	  }
	}
        List_Delete(vfaces);

	if (!found) {
	  sprintf(mesg,"Vertex %-d classified on model face %-d but could not \n find connected face classified on this model face",vid,gvid);
	  MSTK_Report(funcname,mesg,MSTK_WARN);
	  valid = 0;
	}

	fcur = vf;

	fedges = MF_Edges(fcur,1,mv);
	nfe = List_Num_Entries(fedges);
	e0 = List_Entry(fedges,0);
	ecur = e0;
	enxt = List_Entry(fedges,nfe-1);
	List_Delete(fedges);
	
	done = 0; i = 0;
	while (!done) {
	  ecur = enxt;
	  efaces = ME_Faces(ecur);
	  found = 0;
	  idx3 = 0;
	  while ((ef = List_Next_Entry(efaces,&idx3))) {
	    if (ef != fcur && MF_GEntDim(ef) == 2 && MF_GEntID(ef) == gvid) {
	      fcur = ef;
	      found = 1;
	      break;
	    }
	  }
	  List_Delete(efaces);

	  if (!found) {
	    sprintf(mesg,"Could not find next boundary face connected to vertex %-d",vid);
	    MSTK_Report(funcname,mesg,MSTK_WARN);
	    valid = 0;
	    break;
	  }
	   
	  fedges = MF_Edges(fcur,1,mv);
	  nfe = List_Num_Entries(fedges);

          if (List_Entry(fedges,0) == ecur)
            enxt = List_Entry(fedges,nfe-1);
          else if (List_Entry(fedges,nfe-1) == ecur) {
            enxt = List_Entry(fedges,0);
            flipped = 1;
          }
          else {
            sprintf(mesg,"Could not find next edge while traversing around vertex %-d on model face %-d",vid,gvid);
            MSTK_Report(funcname,mesg,MSTK_ERROR);
          }

	  List_Delete(fedges);

	  if (enxt == e0)
	    done = 1;

	  if (++i > maxiter)
	    break;
	}

	if (!done) {
	  sprintf(mesg,"Vertex %-d classified on model face %-d but could not  find ring of faces classified on this model face",vid,gvid);
	  MSTK_Report(funcname,mesg,MSTK_WARN);
	}

        if (done && flipped) {
          List_ptr fregs = MF_Regions(fcur);
          if (List_Num_Entries(fregs) < 2) {
            sprintf(mesg,"Inconsistent orientations of boundary faces around vertex %-d",vid);
            MSTK_Report(funcname,mesg,MSTK_WARN);
          }
          if (fregs) List_Delete(fregs);
        }
      }


    } /* while ((mv = MESH_Next_Vertex(mesh,&idx1))) */




    /*****************************************************************/
    /* Edges                                                      */
    /*****************************************************************/    

    first_unknown_classfn = 1;
    idx1 = 0;
    while ((me = MESH_Next_Edge(mesh,&idx1))) {

#ifdef MSTK_HAVE_MPI
      if (ME_PType(me) == PGHOST) continue;
#endif

      eid = ME_ID(me);
      gedim = ME_GEntDim(me);
      geid = ME_GEntID(me);

      if (gedim == 4 && first_unknown_classfn) {
        sprintf(mesg, "Edge %-d - unknown classification", eid);
        MSTK_Report(funcname, mesg, MSTK_WARN);
        first_unknown_classfn = 0;
      }

      if (ME_Vertex(me,0) == ME_Vertex(me,1)) {
        sprintf(mesg,"Edge %-d has repeated vertices",eid);
        MSTK_Report(funcname,mesg,MSTK_ERROR);
      }

      for (i = 0; i < 2; i++) {
	MVertex_ptr ev = ME_Vertex(me,i);

	vid = MV_ID(ev);
	gvid = MV_GEntID(ev);
	gvdim = MV_GEntDim(ev);

        if (gvdim != 4 && gvdim != 4) {  /* vertex and edge classifn is known */
          if (gedim < gvdim) {
            sprintf(mesg,"Edge %-d classified on lower dimensional entity than  connected vertex %-d",eid,vid);
            MSTK_Report(funcname,mesg,MSTK_WARN);
            valid = 0;
          }
          else if (gedim == gvdim && geid != gvid) {
            sprintf(mesg,"Edge %-d and its vertex %-d classified on different entities of the same dimension",eid,vid);
            MSTK_Report(funcname,mesg,MSTK_WARN);
            valid = 0;
          }
        }

	vedges = MV_Edges(ev);
	if (!List_Contains(vedges,me)) {
	  sprintf(mesg,"Edge %-d sees vertex %-d but not vice versa",eid,vid);
	  MSTK_Report(funcname,mesg,MSTK_ERROR);
	  valid = 0;
	}
	List_Delete(vedges);

	if (gedim == 2) {
	  MFace_ptr ebf[2], fcur, fnxt;
	  MRegion_ptr rcur;
	  int nf, nfr;
	  List_ptr eregs;

	  /* Edge is classified on model face - it should be connected
	     to two and only two faces also classified on this model
	     face */

	  ebf[0] = ebf[1] = NULL;
	  nf = 0;
	  efaces = ME_Faces(me);
	  idx2 = 0;
	  while ((ef = List_Next_Entry(efaces,&idx2))) {
	    fid = MF_ID(ef);

	    if (MF_GEntDim(ef) == 2) {
	      nf++;
	      if (gedim == 2 && MF_GEntID(ef) != geid) {
		sprintf(mesg,"Face %-d connected to edge %-d classified on different model face",fid,eid);
		MSTK_Report(funcname,mesg,MSTK_WARN);
		valid = 0;
	      }

	      if (ebf[0] == NULL)
		ebf[0] = ef;
	      else
		ebf[1] = ef;
	    }
	  }
	  List_Delete(efaces);

	  if (nf != 2) {
	    sprintf(mesg,"Boundary edge %-d is not connected to exactly two\n  faces classified on the boundary",eid);
	    MSTK_Report(funcname,mesg,MSTK_ERROR);
	    valid = 0;
	  }


	  eregs = ME_Regions(me);
	  if (!eregs) 
	    continue;
	  else
	    List_Delete(eregs);

	  /* Can we go from f0 to f1 in one or two dirs? */

	  fcur = ebf[0];
          fnxt = NULL;
	  fregs = MF_Regions(fcur);
	  if (!fregs) {
	    fid = MF_ID(fcur);
	    sprintf(mesg,"Edge %-d connected to regions but face %-d is not",eid,fid);
	    MSTK_Report(funcname,mesg,MSTK_ERROR);
	    valid = 0;
	  }

	  nfr = List_Num_Entries(fregs);
	  for (i = 0; i < nfr; i++) {
	    rcur = List_Entry(fregs,i);
	  
	    rfaces = MR_Faces(rcur);
	    idx3 = 0;
	    found = 0;
	    while ((rf = List_Next_Entry(rfaces,&idx3))) {
	      if (rf != fcur && MF_UsesEntity(rf,me,1)) {
		found = 1;
		fnxt = rf;
		break;
	      }
	    }
	    List_Delete(rfaces);
	    
	    if (!found) {
	      rid = MR_ID(rcur);
	      sprintf(mesg,"Could not find second face in region %-d using edge %-d",rid,eid);
	    }
	    
	    
	    done = 0; j = 0;
	    while (!done) {
	      fcur = fnxt;
	      fid = MF_ID(fcur);
	      
	      if (fnxt == ebf[1]) {
		done = 1;
		break;
	      }
	      
	      fregs1 = MF_Regions(fcur);
	      idx3 = 0;
	      while ((fr = List_Next_Entry(fregs1,&idx3))) {
		if (fr != rcur) {
		  rcur = fr;
		  found = 1;
		  break;
		}
	      }
	      List_Delete(fregs1);

	      if (!found) {
		sprintf(mesg,"Could not find next region around edge %-d",eid);
		MSTK_Report(funcname,mesg,MSTK_ERROR);
		valid = 0;
		break;
	      }
	      
	      
	      rfaces = MR_Faces(rcur);
	      idx3 = 0;
	      found = 0;
	      while ((rf = List_Next_Entry(rfaces,&idx3))) {
		if (rf != fcur && MF_UsesEntity(rf,me,1)) {
		  found = 1;
		  fnxt = rf;
		  break;
		}
	      }
	      List_Delete(rfaces);
	      
	      if (!found) {
		rid = MR_ID(rcur);
		sprintf(mesg,"Could not find second face in region %-d using edge %-d",rid,eid);
	      }
	      
	      if (++j > maxiter)
		break;
	    } /* while (!done) */

	    if (!done) {
	      sprintf(mesg,"Could not traverse around edge %-d from face %-d to face %-d",eid,MF_ID(ebf[0]),MF_ID(ebf[1]));
	      MSTK_Report(funcname,mesg,MSTK_ERROR);
	      valid = 0;
	    }
	  } /* for (i = 0; i < nfr; i++) */
          List_Delete(fregs);

	} /* if (geid == 2) */

      } /* for (i = 0; i < 2; i++) */

    } /* while ((me = MESH_Next_Edge(mesh,&idx1))) */



    /*****************************************************************/
    /* Faces                                                      */
    /*****************************************************************/    

    first_unknown_classfn = 1;
    idx1 = 0;
    while ((mf = MESH_Next_Face(mesh,&idx1))) {

#ifdef MSTK_HAVE_MPI
      if (MF_PType(mf) == PGHOST) continue;
#endif

      fid = MF_ID(mf);
      gfid = MF_GEntID(mf);
      gfdim = MF_GEntDim(mf);

      if (gfdim == 4 && first_unknown_classfn) {
        sprintf(mesg, "Face %-d - unknown classification", fid);
        MSTK_Report(funcname, mesg, MSTK_WARN);
        first_unknown_classfn = 0;
      }

      fedges = MF_Edges(mf,1,0);

      if (List_Num_Entries(fedges) < 3) {
        sprintf(mesg,"Face %-d has less than 3 edges",fid);
        MSTK_Report(funcname,mesg,MSTK_ERROR);
      }

      idx2 = 0;
      while ((fe = List_Next_Entry(fedges,&idx2))) {
	eid = ME_ID(fe);
	geid = ME_GEntID(fe);
	gedim = ME_GEntDim(fe);

        if (gedim != 4 && gfdim != 4) {  /* Edge, Face classfn is known */
          if (gfdim < gedim) {
            sprintf(mesg,"Face %-d classified on lower order entity than edge %-d",fid,ME_ID(fe));
            MSTK_Report(funcname,mesg,MSTK_WARN);
            valid = 0;
          }
          else if (gedim == gfdim && geid != gfid) {
            sprintf(mesg,"Face %-d and edge %-d classified on different\n entities of the same dimension",fid,eid);
            MSTK_Report(funcname,mesg,MSTK_WARN);
          }
        }

	efaces = ME_Faces(fe);
	if (!List_Contains(efaces,mf)) {
	  sprintf(mesg,"Face %-d refers to edge %-d but not vice versa",fid,ME_ID(fe));
	  MSTK_Report(funcname,mesg,MSTK_ERROR);
	  valid = 0;
	}
	List_Delete(efaces);
      }
      List_Delete(fedges);
      

      fregs = MF_Regions(mf);

      if (gfdim == 3) {
	if (!fregs || List_Num_Entries(fregs) != 2) {
	  sprintf(mesg,"Interior face %-d does not have two connected regions",fid);
	  MSTK_Report(funcname,mesg,MSTK_ERROR);
	  valid = 0;
	}
      }


      if (fregs) {
	if (List_Num_Entries(fregs) == 2) {
	  if (MR_FaceDir(List_Entry(fregs,0),mf) == MR_FaceDir(List_Entry(fregs,1),mf)) {
	    sprintf(mesg,"Both regions using face %-d in the same sense",fid);
	    MSTK_Report(funcname,mesg,MSTK_ERROR);
	    valid = 0;
	  }
	}
	List_Delete(fregs);      
      }


    } /* while ((mf = MESH_Next_Face(mesh,&idx1))) */



    /*****************************************************************/
    /* Regions                                                      */
    /*****************************************************************/    

    idx1 = 0;
    while ((mr = MESH_Next_Region(mesh,&idx1))) {
      
#ifdef MSTK_HAVE_MPI
      if (MR_PType(mr) == PGHOST) continue;
#endif

      rid = MR_ID(mr);
      grid = MR_GEntID(mr);

      rfaces = MR_Faces(mr);
      int nrf = List_Num_Entries(rfaces);

      if (nrf < 4) {
        sprintf(mesg,"Region %-d has less than 4 faces",rid);
        MSTK_Report(funcname,mesg,MSTK_ERROR);
      }

      /* Check that face to region and region to face links are consistent
         with each other */
      int *rfdirs = (int *) malloc(nrf*sizeof(int));

      i = 0;
      idx2 = 0;
      while ((rf = List_Next_Entry(rfaces,&idx2))) {
	rfdirs[i] = MR_FaceDir_i(mr,i);
	if (mr != MF_Region(rf,!rfdirs[i])) {
	  sprintf(mesg,"Region %-d to face %-d dir inconsistent with \n face to region dir",rid,MF_ID(rf));
	  MSTK_Report(funcname,mesg,MSTK_ERROR);
	  valid = 0;
	}

        i++;
      }


      /* Check that faces of a region have consistent orientation in
         the region with respect to each other */
      
      for (i = 0; i < nrf; i++) {
        MFace_ptr rf, rf2;

        rf = List_Entry(rfaces,i);

        fedges = MF_Edges(rf,1,0);
        nfe = List_Num_Entries(fedges);
        
        for (j = 0; j < nfe; j++) {
          fe = List_Entry(fedges,j);
          int fedir = MF_EdgeDir_i(rf,j);
          
          /* Find adjacent face in the region */
          found = 0;
          for (k = 0; k < nrf; k++) {
            rf2 = List_Entry(rfaces,k);
            if (rf != rf2 && MF_UsesEntity(rf2,fe,MEDGE)) {
              found = 1;
              break;
            }
          }

          if (!found) {
            sprintf(mesg,"Cannot find another face in region %-d sharing edge %-d (ID = %-d) of face with ID = %-d",MR_ID(mr),j,ME_ID(fe),MF_ID(rf));
            MSTK_Report(funcname,mesg,MSTK_ERROR);
            valid = 0;
          }
          
          int fedir_adj = MF_EdgeDir(rf2,fe);
          
          /* If the two faces use the edge in opposite directions then
             the region should use the faces in the same direction and
             vice versa */

          if (((fedir_adj == fedir) && (rfdirs[i] == rfdirs[k])) ||
              ((fedir_adj != fedir) && (rfdirs[i] != rfdirs[k]))) {
            sprintf(mesg,"Region %-d faces are inconsistently oriented",MR_ID(mr));
            MSTK_Report(funcname,mesg,MSTK_ERROR);
            valid = 0;
          }
        }
        List_Delete(fedges);
           
      }
      List_Delete(rfaces);
      free(rfdirs);
    }

    return valid;

  } /* int MESH_CheckTopo */
Beispiel #6
0
MVertex_ptr MF_Split(MFace_ptr fsplit, double *splitxyz) {
  Mesh_ptr mesh;
  MVertex_ptr vsplit, fv[3];
  MEdge_ptr enew, *fedges0, *fedges1, fe;
  MFace_ptr fnew[MAXPV2];
  MRegion_ptr fr;
  int gid, gdim, i, j, idx, nnew;
  int nfv, fnewdir[MAXPV2], rfdir;
  List_ptr fregs, fverts;

  gdim = MF_GEntDim(fsplit);
  gid = MF_GEntID(fsplit);
 
  /* Collect information */

  mesh = MF_Mesh(fsplit);
  
  /* Regions connected to face */
  
  fregs = MF_Regions(fsplit);

  /* Vertices of face */

  fverts = MF_Vertices(fsplit,1,0);
  nfv = List_Num_Entries(fverts);

  /* Create the splitting vertex */

  vsplit = MV_New(mesh);
  MV_Set_Coords(vsplit,splitxyz);
  MV_Set_GEntDim(vsplit,gdim);
  MV_Set_GEntID(vsplit,gid);

  /* Create the 'nfe' faces */

  for (i = 0; i < nfv; i++) {
    fv[0] = vsplit;
    fv[1] = List_Entry(fverts,i);
    fv[2] = List_Entry(fverts,(i+1)%nfv);
    
    fnew[i] = MF_New(mesh);
    MF_Set_GEntDim(fnew[i],gdim);
    MF_Set_GEntID(fnew[i],gid);
    MF_Set_Vertices(fnew[i],3,fv);
  }
  List_Delete(fverts);
  nnew = nfv;


  if (fregs) {
    for (i = 0; i < List_Num_Entries(fregs); i++) {
      fr = List_Entry(fregs,i);
      rfdir = MR_FaceDir(fr,fsplit);
      for (j = 0; j < nnew; j++)
        fnewdir[j] = rfdir;
      MR_Replace_Faces(fr,1,&fsplit,nnew,fnew,fnewdir);
    }
    List_Delete(fregs);
  }

  MF_Delete(fsplit,0);

  return vsplit;
}
  int MESH_PartitionWithZoltan(Mesh_ptr mesh, int nparts, int **part, int noptions, 
                               char **options, MSTK_Comm comm) { 

  MEdge_ptr fedge;
  MFace_ptr mf, oppf, rface;
  MRegion_ptr mr, oppr;
  List_ptr fedges, efaces, rfaces, fregions;
  int  i, j, k, id;
  int  nv, ne, nf, nr=0, nfe, nef, nfr, nrf, idx, idx2;
  int  numflag, nedgecut, ipos;
  int  wtflag;

  int rc;
  float ver;
  struct Zoltan_Struct *zz;
  GRAPH_DATA graph;
  int changes, numGidEntries, numLidEntries, numImport, numExport;
  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
  int *importProcs, *importToPart, *exportProcs, *exportToPart;

  int rank;
  MPI_Comm_rank(comm,&rank);
 
  rc = Zoltan_Initialize(0, NULL, &ver);

  if (rc != ZOLTAN_OK){
    MSTK_Report("MESH_PartitionWithZoltan","Could not initialize Zoltan",MSTK_FATAL);
    MPI_Finalize();
    exit(0);
  }

  /******************************************************************
  ** Create a Zoltan library structure for this instance of partition 
  ********************************************************************/
  zz = Zoltan_Create(comm);

  /*****************************************************************
   ** Figure out partitioning method
   *****************************************************************/
  
  char partition_method_str[32];
  strcpy(partition_method_str,"RCB");  /* Default - Recursive Coordinate Bisection */
  if (noptions) {
    for (i = 0; i < noptions; i++) {
      if (strncmp(options[i],"LB_PARTITION",12) == 0) {
        char *result = NULL, instring[256];
        strcpy(instring,options[i]);
        result = strtok(instring,"=");
        result = strtok(NULL," ");
        strcpy(partition_method_str,result);
      }
    }
  }
  
  if (rank == 0) {
    char mesg[256];
    sprintf(mesg,"Using partitioning method %s for ZOLTAN\n",partition_method_str);
    MSTK_Report("MESH_PartitionWithZoltan",mesg,MSTK_MESG);
  }

  /* General parameters for Zoltan */
  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
  Zoltan_Set_Param(zz, "LB_METHOD", partition_method_str);
  Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");
  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");


  graph.numMyNodes = 0;
  graph.numAllNbors = 0;
  graph.nodeGID = NULL;
  graph.nodeCoords = NULL;
  graph.nborIndex = NULL;
  graph.nborGID = NULL;
  graph.nborProc = NULL;

  if (strcmp(partition_method_str,"RCB") == 0) {
    if (rank == 0) {
      nr = MESH_Num_Regions(mesh);
      nf = MESH_Num_Faces(mesh);

      if (!nf && !nr)
        MSTK_Report("MESH_PartitionWithZoltan","Cannot partition wire meshes",
                    MSTK_FATAL);

      if (nr == 0) { /* Surface or planar mesh */

        int ndim = 2;       /* assume mesh is planar */
        idx = 0;
        MVertex_ptr mv;
        while ((mv = MESH_Next_Vertex(mesh,&idx))) {
          double vxyz[3];
          MV_Coords(mv,vxyz);
          if (vxyz[2] != 0.0) {
            ndim = 3;  /* non-planar or planar with non-zero z */
            break;
          }
        }
        NDIM_4_ZOLTAN = ndim-1;  /* ignore last dimension to avoid partitioning in that dimension */

        graph.numMyNodes = nf;

        graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nf);
        graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nf);

        idx = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          double fxyz[MAXPV2][3], cen[3];
          int nfv;

          MF_Coords(mf,&nfv,fxyz);
          cen[0] = cen[1] = cen[2] = 0.0;
          for (j = 0; j < nfv; j++)
            for (k = 0; k < NDIM_4_ZOLTAN; k++) 
              cen[k] += fxyz[j][k];              
          for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nfv;

          id = MF_ID(mf);
          graph.nodeGID[id-1] = id;
          memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double));
        }

      }
      else { /* Volume mesh */

        int ndim = 3;
        NDIM_4_ZOLTAN = ndim-1;  /* ignore last dimension  to avoid partitioning in that dimension */
        graph.numMyNodes = nr;

        graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nr);
        graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nr);

        idx = 0;
        while ((mr = MESH_Next_Region(mesh,&idx))) {
          double rxyz[MAXPV3][3], cen[3];
          int nrv;
          
          MR_Coords(mr,&nrv,rxyz);
          cen[0] = cen[1] = cen[2] = 0.0;
          for (j = 0; j < nrv; j++)
            for (k = 0; k < NDIM_4_ZOLTAN; k++)
              cen[k] += rxyz[j][k];
          for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nrv;
          for (k = 0; k < NDIM_4_ZOLTAN; k++) 
            if (fabs(cen[k]) < 1.0e-10) cen[k] = 0.0; 

          id = MR_ID(mr);
          graph.nodeGID[id-1] = id;
          memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double));
        }

      }
    }

    MPI_Bcast(&NDIM_4_ZOLTAN,1,MPI_INT,0,comm);

    /* Set some default values */
    Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS","1");
    //    Zoltan_Set_Param(zz, "AVERAGE_CUTS", "1");

    if (noptions > 1) {
      for (i = 1; i < noptions; i++) {
        char *paramstr = NULL, *valuestr = NULL, instring[256];
        strcpy(instring,options[i]);
        paramstr = strtok(instring,"=");
        valuestr = strtok(NULL," ");
        Zoltan_Set_Param(zz,paramstr,valuestr);
      }
    }

    /* Query functions - defined in simpleQueries.h */

    Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph);
    Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph);
    Zoltan_Set_Num_Geom_Fn(zz, get_num_dimensions_reduced, &graph);    /* reduced dimensions */
    Zoltan_Set_Geom_Multi_Fn(zz, get_element_centers_reduced, &graph); /* reduced dimension centers */

  }
  else if (strcmp(partition_method_str,"GRAPH") == 0) {

    if(rank == 0) {
      nv = MESH_Num_Vertices(mesh);
      ne = MESH_Num_Edges(mesh);
      nf = MESH_Num_Faces(mesh);
      nr = MESH_Num_Regions(mesh);
      
      ipos = 0;
      
      /* build nodes and neighbors list, similar as in partition with metis
         Assign processor 0 the whole mesh, assign other processors a NULL mesh */
  
      if (nr == 0) {
        if (nf == 0) {
          MSTK_Report("MESH_PartitionWithZoltan",
                      "Cannot partition wire meshes with Zoltan",MSTK_FATAL);
          exit(-1);
      
        }

        graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nf);
        graph.nborIndex = (int *)malloc(sizeof(int) * (nf + 1));
        graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*ne);
        graph.nborProc = (int *)malloc(sizeof(int) * 2*ne);
      
        graph.nborIndex[0] = 0;
      
        /* Surface mesh */
        idx = 0; i = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          graph.nodeGID[i] = MF_ID(mf);
          fedges = MF_Edges(mf,1,0);
          nfe = List_Num_Entries(fedges);
	
          idx2 = 0;
          while ((fedge = List_Next_Entry(fedges,&idx2))) {
	  
            efaces = ME_Faces(fedge);
            nef = List_Num_Entries(efaces);
	  
            if (nef == 1) {
              continue;          /* boundary edge; nothing to do */
            } else {
              int j;
              for (j = 0; j < nef; j++) {
                oppf = List_Entry(efaces,j);
                if (oppf == mf) {
                  graph.nborGID[ipos] = MF_ID(oppf);
                  /* initially set all nodes on processor 0 */
                  graph.nborProc[ipos] = 0;
                  ipos++;
                }
              }
            }
	  
            List_Delete(efaces);
	  
          }
	
          List_Delete(fedges);
          i++;
          graph.nborIndex[i] = ipos;
        }
        graph.numMyNodes = i;
        graph.numAllNbors = ipos;
      }
      else {
        graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nr);
        graph.nborIndex = (int *)malloc(sizeof(int) * (nr + 1));
        graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*nf);
        graph.nborProc = (int *)malloc(sizeof(int) * 2*nf);
      
        graph.nborIndex[0] = 0;
      
        /* Volume mesh */
      
        idx = 0; i = 0;
        while ((mr = MESH_Next_Region(mesh,&idx))) {
          graph.nodeGID[i] = MR_ID(mr);
          rfaces = MR_Faces(mr);
          nrf = List_Num_Entries(rfaces);
      
          idx2 = 0;
          while ((rface = List_Next_Entry(rfaces,&idx2))) {
	  
            fregions = MF_Regions(rface);
            nfr = List_Num_Entries(fregions);
	  
            if (nfr > 1) {
              oppr = List_Entry(fregions,0);
              if (oppr == mr)
                oppr = List_Entry(fregions,1);
	    
              graph.nborGID[ipos] = MR_ID(oppr);
              /* initially set all nodes on processor 0 */
              graph.nborProc[ipos] = 0;
              ipos++;
            }
	  
            List_Delete(fregions);
	  
          }
	
          List_Delete(rfaces);
	
          i++;
          graph.nborIndex[i] = ipos;
        }
        graph.numMyNodes = i;
        graph.numAllNbors = ipos;
      }
    }

    /* Graph parameters */

    /* Zoltan_Set_Param(zz, "CHECK_GRAPH", "2"); */
    Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35");  /* 0-remove all, 1-remove none */

    /* Query functions - defined in simpleQueries.h */

    Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph);
    Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph);
    Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &graph);
    Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &graph);    
  }

  /* Partition the graph */
  /******************************************************************                                                                             
   ** Zoltan can now partition the graph.                                                                                                   
   ** We assume the number of partitions is                                                                                
   ** equal to the number of processes.  Process rank 0 will own                                                                                   
   ** partition 0, process rank 1 will own partition 1, and so on.                                                                                 
   ******************************************************************/
  rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
			   &changes,        /* 1 if partitioning was changed, 0 otherwise */
			   &numGidEntries,  /* Number of integers used for a global ID */
			   &numLidEntries,  /* Number of integers used for a local ID */
			   &numImport,      /* Number of nodes to be sent to me */
			   &importGlobalGids,  /* Global IDs of nodes to be sent to me */
			   &importLocalGids,   /* Local IDs of nodes to be sent to me */
			   &importProcs,    /* Process rank for source of each incoming node */
			   &importToPart,   /* New partition for each incoming node */
			   &numExport,      /* Number of nodes I must send to other processes*/
			   &exportGlobalGids,  /* Global IDs of the nodes I must send */
			   &exportLocalGids,   /* Local IDs of the nodes I must send */
			   &exportProcs,    /* Process to which I send each of the nodes */
			   &exportToPart);  /* Partition to which each node will belong */

  if (rc != ZOLTAN_OK){
    if (rank == 0)
      MSTK_Report("MESH_PartitionWithZoltan","Could not partition mesh with ZOLTAN",
                  MSTK_ERROR);
    Zoltan_Destroy(&zz);
    MPI_Finalize();
    return 0;
  }

  if(rank == 0) {
    *part = (int *) calloc(graph.numMyNodes,sizeof(int));
    for ( i = 0; i < numExport; i++ ) {
      (*part)[exportGlobalGids[i]-1] = exportToPart[i];
    }
    if (graph.nodeGID) free(graph.nodeGID);
    if (graph.nodeCoords) free(graph.nodeCoords);
    if (graph.nborIndex) free(graph.nborIndex);
    if (graph.nborGID) free(graph.nborGID);
    if (graph.nborProc) free(graph.nborProc);
  }
  else { 
    *part = NULL;
  }


  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, &exportProcs, &exportToPart);
  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, &importProcs, &importToPart);
  Zoltan_Destroy(&zz);                

  return 1;
}
int MESH_PartitionWithMetis(Mesh_ptr mesh, int nparts, int **part) {

  MEdge_ptr fedge;
  MFace_ptr mf, oppf, rface;
  MRegion_ptr mr, oppr;
  List_ptr fedges, efaces, rfaces, fregions;
  int  i, ncells, ipos;
  int  nv, ne, nf, nr, nfe, nef, nfr, nrf, idx, idx2;
#ifdef METIS_5
  idx_t ngraphvtx, numflag, nedgecut, numparts, ncons;
  idx_t wtflag, metisopts[METIS_NOPTIONS];
  idx_t *vsize, *idxpart;
  idx_t  *xadj, *adjncy, *vwgt, *adjwgt;
  real_t *tpwgts, *ubvec;
#else
  idxtype ngraphvtx, numflag, nedgecut, numparts;
  idxtype  wtflag, metisopts[5] = {0,0,0,0,0};
  idxtype  *xadj, *adjncy, *vwgt, *adjwgt, *idxpart;
#endif
  

  /* First build a nodal graph of the mesh in the format required by
     metis */

  nv = MESH_Num_Vertices(mesh);
  ne = MESH_Num_Edges(mesh);
  nf = MESH_Num_Faces(mesh);
  nr = MESH_Num_Regions(mesh);

  ipos = 0;
  
  if (nr == 0) {
    
    if (nf == 0) {
      fprintf(stderr,"Cannot partition wire meshes\n");
      exit(-1);
    }

#ifdef METIS_5
    xadj = (idx_t *) malloc((nf+1)*sizeof(idx_t));
    adjncy = (idx_t *) malloc(2*ne*sizeof(idx_t));
#else    
    xadj = (idxtype *) malloc((nf+1)*sizeof(idxtype));
    adjncy = (idxtype *) malloc(2*ne*sizeof(idxtype));
#endif
    ncells = nf;

    /* Surface mesh */

    idx = 0; i = 0;
    xadj[i] = ipos;
    while ((mf = MESH_Next_Face(mesh,&idx))) {
      
      fedges = MF_Edges(mf,1,0);
      nfe = List_Num_Entries(fedges);
      
      idx2 = 0;
      while ((fedge = List_Next_Entry(fedges,&idx2))) {
	
	efaces = ME_Faces(fedge);
	nef = List_Num_Entries(efaces);
	
	if (nef == 1) {
	  continue;          /* boundary edge; nothing to do */
	}
	else {
          int j;
          for (j = 0; j < nef; j++) {
            oppf = List_Entry(efaces,j);
            if (oppf != mf) {
              adjncy[ipos] = MF_ID(oppf)-1;
              ipos++;
            }
          }
	}
	
	List_Delete(efaces);
	
      }
      
      List_Delete(fedges);
      
      i++;
      xadj[i] = ipos;
    }

  }
  else {

#ifdef METIS_5
    xadj = (idx_t *) malloc((nr+1)*sizeof(idx_t));
    adjncy = (idx_t *) malloc(2*nf*sizeof(idx_t));
#else
    xadj = (idxtype *) malloc((nr+1)*sizeof(idxtype));
    adjncy = (idxtype *) malloc(2*nf*sizeof(idxtype));
#endif
    ncells = nr;

    /* Volume mesh */

    idx = 0; i = 0;
    xadj[i] = ipos;
    while ((mr = MESH_Next_Region(mesh,&idx))) {
      
      rfaces = MR_Faces(mr);
      nrf = List_Num_Entries(rfaces);
      
      idx2 = 0;
      while ((rface = List_Next_Entry(rfaces,&idx2))) {
	
	fregions = MF_Regions(rface);
	nfr = List_Num_Entries(fregions);
	
	if (nfr > 1) {
	  oppr = List_Entry(fregions,0);
	  if (oppr == mr)
	    oppr = List_Entry(fregions,1);
	  
	  adjncy[ipos] = MR_ID(oppr)-1;
	  ipos++;
	}
        List_Delete(fregions);	
	
      }
      
      List_Delete(rfaces);
      
      i++;
      xadj[i] = ipos;
    }

  }
  


  /* Partition the graph */
  
  wtflag = 0;        /* No weights are specified */
  vwgt = adjwgt = NULL;

  numflag = 0;    /* C style numbering of elements (nodes of the dual graph) */
  ngraphvtx = ncells; /* we want the variable to be of type idxtype or idx_t */
  numparts = nparts;  /* we want the variable to be of type idxtype or idx_t */

#ifdef METIS_5
  idxpart = (idx_t *) malloc(ncells*sizeof(idx_t));

  ncons = 1;  /* Number of constraints */
  vsize = NULL;  
  tpwgts = NULL;
  ubvec = NULL;

  METIS_SetDefaultOptions(metisopts);
  metisopts[METIS_OPTION_NUMBERING] = 0;

  if (nparts <= 8)
    METIS_PartGraphRecursive(&ngraphvtx,&ncons,xadj,adjncy,vwgt,vsize,adjwgt,
			     &numparts,tpwgts,ubvec,metisopts,&nedgecut,
                             idxpart);
  else
    METIS_PartGraphKway(&ngraphvtx,&ncons,xadj,adjncy,vwgt,vsize,adjwgt,
                        &numparts,tpwgts,ubvec,metisopts,&nedgecut,idxpart);

#else

  idxpart = (idxtype *) malloc(ncells*sizeof(idxtype));

  if (nparts <= 8)
    METIS_PartGraphRecursive(&ngraphvtx,xadj,adjncy,vwgt,adjwgt,&wtflag,
			     &numflag,&numparts,metisopts,&nedgecut,idxpart);
  else
    METIS_PartGraphKway(&ngraphvtx,xadj,adjncy,vwgt,adjwgt,&wtflag,&numflag,
			&numparts,metisopts,&nedgecut,idxpart);
#endif

  free(xadj);
  free(adjncy);


  
  *part = (int *) malloc(ncells*sizeof(int));
  for (i = 0; i < ncells; i++)
    (*part)[i] = (int) idxpart[i];

  free(idxpart);
  return 1;

}
Beispiel #9
0
  int MF_Set_GInfo_Auto_R2(MFace_ptr f) {
    int i, same, nv, fgdim, fgid, vgdim, vgid, vgdim0, vgid0;
    MVertex_ptr v;
    MFace_Adj_R2 *adj;

    adj = (MFace_Adj_R2 *) f->adj;
    nv = List_Num_Entries(adj->fvertices);

    same = 1;
    fgdim = -1;
    fgid = -1;
    vgid = -1;

    v = List_Entry(adj->fvertices,0);    
    vgid0 = MV_GEntID(v);
    vgdim0 = MV_GEntDim(v);

    for (i = 1; i < nv; i++) {
      v = List_Entry(adj->fvertices,i);
      vgid = MV_GEntID(v);
      vgdim = MV_GEntDim(v);
      if (vgdim == vgdim0 && vgid == vgid0)
	continue; /* all vertices have same classification so far */
      else {
	same = 0;
	break;
      }
    }
    if (same) {
      fgdim = vgdim0;
      fgid = vgid;
    }
     
    if (fgdim == -1 || fgdim < 2) {
      List_ptr fregions;

      /* We are unable to find proper classification info from the
	 vertices. Lets look at the number of regions connected to the
	 face and their classification */

      fregions = MF_Regions(f);
      
      if (fregions == NULL || List_Num_Entries(fregions) == 1) {
	
	/* In a complete mesh, this face must be on a model face */

	fgdim = 2;

      }
      else {
	MRegion_ptr fregion0, fregion1;
	int rgid0, rgid1;

	/* Internal face. Check if it is a mesh region or on an
	   interior interface */

	fregion0 = List_Entry(fregions,0); rgid0 = MEnt_GEntID(fregion0);
	fregion1 = List_Entry(fregions,1); rgid1 = MEnt_GEntID(fregion1);

	if (rgid0 == -1 || rgid1 == -1) {
	  
	  /* One of the regions is not classified properly. Just
	     assume this is an internal face */

	  fgdim = 3;	  

	}
	else {

	  fgdim = (rgid0 == rgid1) ? 3 : 2;

	}
      }

      if (fregions) List_Delete(fregions);
    }

    MEnt_Set_GEntDim((MEntity_ptr) f,fgdim);
    MEnt_Set_GEntID((MEntity_ptr) f,fgid);

    if (fgdim == 4)
      return 0;
    else
      return 1;
  }
Beispiel #10
0
MVertex_ptr MF_Split_SimplexMesh(MFace_ptr fsplit, double *splitxyz) {
  int i, j, k, rfdir=1, ntets=0, ntris=0, *rid=NULL, fgdim, fgid, found;
  MVertex_ptr vsplit, ev[2], (*tetverts)[4]=NULL, triverts[3], fv;
  MVertex_ptr fvarr[3], rvarr[4];
  MFace_ptr f;
  MRegion_ptr r;
  List_ptr fedges, ftets, rfaces, fverts;
  Mesh_ptr mesh = MF_Mesh(fsplit);

  /* point is not on the boundary of the face */
    
  ftets = MF_Regions(fsplit);
  if (ftets) {
    ntets = List_Num_Entries(ftets);   
    tetverts = (MVertex_ptr (*)[4]) malloc(ntets*sizeof(MVertex_ptr [4]));
    rid = (int *) malloc(ntets*sizeof(int));
  }

  for (i = 0; i < ntets; i++) {

    r = List_Entry(ftets,i);

    rfaces = MR_Faces(r);

    /* Find the face to be split and get the first three vertices
       in a suitable order from it. Also, find another face and 
       get a vertex that is not in the face to be split. This vertex
       forms the fourth vertex of the tet */

    for (j = 0; j < 4; j++) {
      f = List_Entry(rfaces,j);

      if (f == fsplit) {
        rfdir = MR_FaceDir_i(r,j);        
        fverts = MF_Vertices(f,!rfdir,0);

        for (k = 0; k < 3; k++) {
          tetverts[i][0] = List_Entry(fverts,0);
          tetverts[i][1] = List_Entry(fverts,1);
          tetverts[i][2] = List_Entry(fverts,2);
        }
        List_Delete(fverts);
        break;
      }
    }

    found = 0;
    for (j = 0; j < 4; j++) {
      f = List_Entry(rfaces,j);
      if (f != fsplit) {
        fverts = MF_Vertices(f,!rfdir,0);
        for (k = 0; k < 3; k++) {
          fv = List_Entry(fverts,k);
          if (!MF_UsesEntity(fsplit,fv,MVERTEX)) {
            tetverts[i][3] = fv;
            found = 1;
            break;
          }
        }
        List_Delete(fverts);
      }
      if (found) break;
    }

    List_Delete(rfaces);
  }

  /* Now that we finished collecting info about the connected tets we
     can delete them */

  if (ftets) {
    for (i = 0; i < ntets; i++)
      MR_Delete(List_Entry(ftets,i),0);

    List_Delete(ftets);
  }

  /* Delete the face itself */

  fverts = MF_Vertices(fsplit,1,0);
  for (i = 0; i < 3; i++)
    triverts[i] = List_Entry(fverts,i);
  List_Delete(fverts);

  fgdim = MF_GEntDim(fsplit);
  fgid  = MF_GEntID(fsplit);


  /* Split the face */

  vsplit = MF_Split(fsplit, splitxyz);

  
  /* Create three tets for each tet that was deleted */

  for (i = 0; i < ntets; i++) {
    for (j = 0; j < 3; j++) {
      r = MR_New(mesh);
      rvarr[0] = vsplit;
      rvarr[1] = tetverts[i][j];
      rvarr[2] = tetverts[i][(j+1)%3];
      rvarr[3] = tetverts[i][3];
      MR_Set_Vertices(r, 4, rvarr, 0, NULL);
      MR_Set_GEntID(r,rid[i]);
    }
  }

  if (ntets) {
    free(tetverts);
    free(rid);
  }

  return vsplit;
}