int MESH_Renumber_EntityGlobalIDs(Mesh_ptr mesh, MType mtype,
                                    int method, int *preassigned_gids,
                                    MSTK_Comm comm) {
    int i;

    if (method != 0) {
      MSTK_Report("MESH_Renumber_EntityGlobalIDs",
                  "Chosen renumbering scheme not implemented", MSTK_ERROR);
      return 0;
    }
    if (mtype == MALLTYPE) {
      MSTK_Report("MESH_Renumber_EntityGlobalIDs",
                  "Cannot call this routine for MALLTYPE", MSTK_ERROR);
      return 0;
    }

    MAttrib_ptr tmpatt = MAttrib_New(mesh, "tmpatt_renumber", INT, mtype);
 
    int nproc, rank;
    MPI_Comm_size(comm, &nproc);
    MPI_Comm_rank(comm, &rank);

    int idx = 0, nowned = 0;
    MEntity_ptr ment;
    switch (mtype) {
      case MVERTEX:
        while ((ment = MESH_Next_Vertex(mesh, &idx)))
          if (MV_PType(ment) != PGHOST)
            nowned++;
        break;
      case MEDGE:
        while ((ment = MESH_Next_Edge(mesh, &idx)))
          if (ME_PType(ment) != PGHOST)
            nowned++;
        break;
      case MFACE:
        while ((ment = MESH_Next_Face(mesh, &idx)))
          if (MF_PType(ment) != PGHOST)
            nowned++;
        break;
      case MREGION:
        while ((ment = MESH_Next_Region(mesh, &idx)))
          if (MR_PType(ment) != PGHOST)
            nowned++;
        break;
      default: {}
    }

    /* Gather the number of entities on every processor */

    int *nowned_all = NULL;
    if (rank == 0)
      nowned_all = (int *) calloc(nproc, sizeof(int));

    MPI_Gather(&nowned, 1, MPI_INT, nowned_all, 1, MPI_INT, 0, comm);

    int *offset_all = NULL;
    if (rank == 0) {      
      offset_all = (int *) malloc(nproc*sizeof(int));
      offset_all[0] = 0;
      int p;
      for (p = 1; p < nproc; p++)
        offset_all[p] = offset_all[p-1] + nowned_all[p-1];
    }

    int offset = 0;
    MPI_Scatter(offset_all, 1, MPI_INT, &offset, 1, MPI_INT, 0, comm);

    /* At this point if we had different methods for renumbering the
     * global set of entities, we would generate a Global ID map. For
     * now this is just a sequential map (method 0) */

    int *new_index = (int *) malloc(nowned*sizeof(int));
    if (method == 0) {
      for (i = 0; i < nowned; i++)
        new_index[i] = i+1;
    }

    /* Now assign global IDs to the entities */
    int new_gid;
    idx = 0; i = 0;
    switch (mtype) {
      case MVERTEX:
        while ((ment = MESH_Next_Vertex(mesh, &idx)))
          if (MV_PType(ment) != PGHOST) {
            new_gid = offset + new_index[i];
            MEnt_Set_AttVal(ment, tmpatt, new_gid, 0.0, NULL);
            i++;
          }
        break;
      case MEDGE:
        while ((ment = MESH_Next_Edge(mesh, &idx)))
          if (ME_PType(ment) != PGHOST) {
            new_gid = offset + new_index[i];
            MEnt_Set_AttVal(ment, tmpatt, new_gid, 0.0, NULL);
            i++;
          }
        break;
      case MFACE:
        while ((ment = MESH_Next_Face(mesh, &idx)))
          if (MF_PType(ment) != PGHOST) {
            new_gid = offset + new_index[i];
            MEnt_Set_AttVal(ment, tmpatt, new_gid, 0.0, NULL);
            i++;
          }
        break;
      case MREGION:
        while ((ment = MESH_Next_Region(mesh, &idx)))
          if (MR_PType(ment) != PGHOST) {
            new_gid = offset + new_index[i];
            MEnt_Set_AttVal(ment, tmpatt, new_gid, 0.0, NULL);
            i++;
          }
        break;
      default: {}
    }

    /* Now exchange the attribute across processors */
    MESH_Update1Attribute(mesh, tmpatt, comm);

    /* Now assign global IDs of the entities based on the values of
     * the gidatt attribute */
    idx = 0;
    double rval;
    void *pval;
    switch (mtype) {
      case MVERTEX:
        while ((ment = MESH_Next_Vertex(mesh, &idx))) {
          MEnt_Get_AttVal(ment, tmpatt, &new_gid, &rval, &pval);
          MV_Set_GlobalID(ment, new_gid);
        }
        break;
      case MEDGE:
        while ((ment = MESH_Next_Edge(mesh, &idx))) {
          MEnt_Get_AttVal(ment, tmpatt, &new_gid, &rval, &pval);
          ME_Set_GlobalID(ment, new_gid);
        }
        break;
      case MFACE:
        while ((ment = MESH_Next_Face(mesh, &idx))) {
          MEnt_Get_AttVal(ment, tmpatt, &new_gid, &rval, &pval);
          MF_Set_GlobalID(ment, new_gid);
        }
        break;
      case MREGION:
        while ((ment = MESH_Next_Region(mesh, &idx))) {
          MEnt_Get_AttVal(ment, tmpatt, &new_gid, &rval, &pval);
          MR_Set_GlobalID(ment, new_gid);
        }
        break;
      default: {}
    }

    free(nowned_all);
    free(offset_all);

    MAttrib_Delete(tmpatt);

    return 1;
  }
Beispiel #2
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 */
  int MESH_AssignGlobalIDs_Region(Mesh_ptr submesh, MSTK_Comm comm) {
  int i, j, k, nfv, nbf, nof, ngf, nf, nr, mesh_info[10], global_id;
  MVertex_ptr mv;
  MFace_ptr mf;
  MRegion_ptr mr;
  List_ptr boundary_faces, mfverts;
  int *loc, face_id[MAXPV2+3],index_nbf, max_nbf, iloc, is_boundary;
  int *global_mesh_info, *list_face, *recv_list_face, *face_ov_label, *id_on_ov_list;

  int rank, num;
  MPI_Comm_rank(comm,&rank);
  MPI_Comm_size(comm,&num);

  for (i = 0; i < 10; i++) mesh_info[i] = 0;
  nf = MESH_Num_Faces(submesh);
  nr = MESH_Num_Regions(submesh);
  mesh_info[3] = nf;
  mesh_info[4] = nr;
  /* 
     collect 'boundary' faces
     if endpoints are either GHOST or OVERLAP, then it is a boundary face 
  */
  nbf = 0;  boundary_faces = List_New(10);
  for(i = 0; i < nf; i++) {
    is_boundary = 1;       
    mf = MESH_Face(submesh,i);
    mfverts = MF_Vertices(mf,1,0);
    nfv = List_Num_Entries(mfverts);
    for(j = 0; j < nfv; j++) {
      mv = List_Entry(mfverts,j);
      if(MV_PType(mv)!=PGHOST && MV_PType(mv)!=POVERLAP)
	is_boundary = 0;
    }
    if(is_boundary) {
      MF_Flag_OnParBoundary(mf);
      List_Add(boundary_faces,mf);
      nbf++;
    }
    List_Delete(mfverts);
  }
  /* printf("num of boundary faces %d, on rank %d\n", nbf,rank); */
  mesh_info[6] = nbf;

  List_Sort(boundary_faces,nbf,sizeof(MFace_ptr),compareFaceID);

  global_mesh_info = (int *)malloc(10*num*sizeof(int));
  MPI_Allgather(mesh_info,10,MPI_INT,global_mesh_info,10,MPI_INT,comm);

  max_nbf = 0;
  for(i = 0; i < num; i++)
    if(max_nbf < global_mesh_info[10*i+6])
      max_nbf = global_mesh_info[10*i+6];

  list_face = (int *)malloc(max_nbf*(MAXPV2+1)*sizeof(int));
  recv_list_face = (int *)malloc(num*max_nbf*(MAXPV2+1)*sizeof(int));

  /* indicate if a face is overlapped */
  face_ov_label = (int *)malloc(num*max_nbf*sizeof(int));
  for (i = 0; i < num*max_nbf; i++)
    face_ov_label[i] = 0;
  id_on_ov_list = (int *)malloc(max_nbf*sizeof(int));
  /* pack face information to send  */
  index_nbf = 0;
  for(i = 0; i < nbf; i++) {
    mf = List_Entry(boundary_faces,i);
    mfverts = MF_Vertices(mf,1,0);
    nfv = List_Num_Entries(mfverts);
    list_face[index_nbf] = nfv;
    for(j = 0; j < nfv; j++) 
      list_face[index_nbf+j+1] = MV_GlobalID(List_Entry(mfverts,j));
    index_nbf += MAXPV2+1;
    List_Delete(mfverts);
  }

  MPI_Allgather(list_face,(MAXPV2+1)*max_nbf,MPI_INT,recv_list_face,(MAXPV2+1)*max_nbf,MPI_INT,comm);

  ngf = 0;
  /* for processor other than 0 */
  if(rank > 0) {
    for(i = 0; i < nbf; i++) {
      mf = List_Entry(boundary_faces,i);
      if(MF_GlobalID(mf) > 0) continue;  /* if already assigned */
      mfverts = MF_Vertices(mf,1,0);
      nfv = List_Num_Entries(mfverts);
      face_id[0] = nfv;                           
      for(k = 0; k < nfv; k++) 
	face_id[k+1] = MV_GlobalID(List_Entry(mfverts,k));
      List_Delete(mfverts);
      for(j = 0; j < rank; j++) {
	loc = (int *)bsearch(&face_id,
			     &recv_list_face[(MAXPV2+1)*max_nbf*j],
			     global_mesh_info[10*j+6],
			     (MAXPV2+1)*sizeof(int),
			     compareFaceINT);
	if(loc) {
	  iloc = (int)(loc - &recv_list_face[(MAXPV2+1)*max_nbf*j])/(MAXPV2+1);
	  MF_Set_PType(mf,PGHOST);
	  MF_Set_MasterParID(mf,j);
	  face_ov_label[max_nbf*j+iloc] |= 1;
	  id_on_ov_list[i] = iloc;
	  ngf++;
	  break;
	}
      }
    }
  }

 
  /* num of ghost verts */
  mesh_info[9] = ngf;
  MPI_Allgather(mesh_info,10,MPI_INT,global_mesh_info,10,MPI_INT,comm);
  /* since this is a OR reduction, we can use MPI_IN_PLACE, send buffer same as recv buffer */
  MPI_Allreduce(MPI_IN_PLACE,face_ov_label,num*max_nbf,MPI_INT,MPI_LOR,comm);    

  /* Assign global ID for non ghost face */
  global_id = 1;
  for(i = 0; i < rank; i++) 
    global_id = global_id + global_mesh_info[10*i+3] - global_mesh_info[10*i+9];
  for(i = 0; i < nf; i++) {
    mf = MESH_Face(submesh,i);
    if (MF_PType(mf) == PGHOST) continue;
    if (!MF_GlobalID(mf)) MF_Set_GlobalID(mf,global_id++);
    MF_Set_MasterParID(mf,rank);
  }

  /* label OVERLAP face */
  nof = 0;
  for(i = 0; i < nbf; i++) 
    if(face_ov_label[rank*max_nbf+i]) {
      mf = List_Entry(boundary_faces,i);
      MF_Set_PType(mf,POVERLAP);
      nof++;
  }
  /* printf("num of ghost faces %d, overlap faces %d on rank %d\n", ngf, nof, rank);  */

  /* this time only global id are sent */
  for(i = 0; i < nbf; i++) {
    mf = List_Entry(boundary_faces,i);
    list_face[i] = MF_GlobalID(mf);
  }

  MPI_Allgather(list_face,max_nbf,MPI_INT,recv_list_face,max_nbf,MPI_INT,comm);

  for(i = 0; i < nbf; i++) {
    mf = List_Entry(boundary_faces,i);
    if(MF_PType(mf)==PGHOST) {
      int gid = recv_list_face[MF_MasterParID(mf)*max_nbf+id_on_ov_list[i]];
#ifdef DEBUG
      if (MF_GlobalID(mf) && MF_GlobalID(mf) != gid)
	MSTK_Report("MESH_AssignGlobalIDs_region",
		    "Ghost face already has different global ID", MSTK_WARN);
#endif
      MF_Set_GlobalID(mf, gid);
    }
  }

  /* assign region global id */
  global_id = 1;
  for(i = 0; i < rank; i++) 
    global_id = global_id + global_mesh_info[10*i+4];
  for(i = 0; i < nr; i++) {
    mr = MESH_Region(submesh,i);
    MR_Set_PType(mr,PINTERIOR);
    if (!MR_GlobalID(mr)) MR_Set_GlobalID(mr,global_id++);
    MR_Set_MasterParID(mr,rank);
  }


  List_Delete(boundary_faces);
  free(global_mesh_info);
  free(face_ov_label);
  free(id_on_ov_list);
  free(list_face);
  free(recv_list_face);


  return 1;
}
Beispiel #4
0
  int MESH_ConcatSubMesh_Region(Mesh_ptr mesh, int num, Mesh_ptr *submeshes) {
    int nrf, nre, nrv, nfe, i, j, k, num_parbndry_verts, num_parbndry_edges, num_parbndry_faces, ival;
    MVertex_ptr mv, new_mv, sub_mv;
    MEdge_ptr me, new_me, sub_me;
    MFace_ptr mf, new_mf, sub_mf;
    MRegion_ptr new_mr, sub_mr;
    List_ptr mrfaces, mredges, mrverts, mfedges;
    int add_region, idx, global_id, iloc, *loc;
    double coor[3], rval;
    void *pval;
    Mesh_ptr submesh;

    List_ptr parbndry_verts = List_New(10);        
    List_ptr parbndry_edges = List_New(10);
    List_ptr parbndry_faces = List_New(10);

    MFace_ptr *rfaces = (MFace_ptr *) malloc(MAXPF3*sizeof(MFace_ptr));
    int *rfdirs = (int *) malloc(MAXPF3*sizeof(int));
    MEdge_ptr *fedges = (MEdge_ptr *) malloc(MAXPV2*sizeof(MEdge_ptr));
    int *fedirs = (int *) malloc(MAXPV2*sizeof(int));

    MAttrib_ptr parbndryatt = MAttrib_New(mesh, "on_parbndry", INT, MVERTEX);
    
    /* collect faces, edges and vertices on the partition boundary */
    idx = 0; num_parbndry_faces = 0;
    while ((mf = MESH_Next_Face(mesh,&idx))) 
      if (MF_PType(mf) != PINTERIOR) {
        List_Add(parbndry_faces,mf);
        num_parbndry_faces++;
      }
    idx = 0; num_parbndry_edges = 0;
    while ((me = MESH_Next_Edge(mesh,&idx))) 
      if (ME_PType(me) != PINTERIOR) {
        List_Add(parbndry_edges,me);
        num_parbndry_edges++;
      }
    idx = 0; num_parbndry_verts = 0;
    while ((mv = MESH_Next_Vertex(mesh,&idx)))
      if (MV_PType(mv) != PINTERIOR) {
        List_Add(parbndry_verts,mv);
        MEnt_Set_AttVal(mv, parbndryatt, 1, 0.0, NULL);
        num_parbndry_verts++;
      }
    
    /* sort based on global ID */
    List_Sort(parbndry_faces,num_parbndry_faces,sizeof(MFace_ptr),compareGlobalID);
    List_Sort(parbndry_edges,num_parbndry_edges,sizeof(MEdge_ptr),compareGlobalID);
    List_Sort(parbndry_verts,num_parbndry_verts,sizeof(MVertex_ptr),compareGlobalID);

    int *parbndry_vert_gids = (int *)malloc(num_parbndry_verts*sizeof(int));
    int *parbndry_edge_gids = (int *)malloc(num_parbndry_edges*sizeof(int));
    int *parbndry_face_gids = (int *)malloc(num_parbndry_faces*sizeof(int));

    /* store them in array for binary search */
    for (i = 0; i < num_parbndry_faces; i++) {
      mf = List_Entry(parbndry_faces,i);
      parbndry_face_gids[i] = MF_GlobalID(mf);
    }
    for (i = 0; i < num_parbndry_edges; i++) {
      me = List_Entry(parbndry_edges,i);
      parbndry_edge_gids[i] = ME_GlobalID(me);
    }
    for (i = 0; i < num_parbndry_verts; i++) {
      mv = List_Entry(parbndry_verts,i);
      parbndry_vert_gids[i] = MV_GlobalID(mv);
    }

   /* Make list of new edges and vertices which will be updated
       with each mesh that is concatenated */
    int max_vnew = 0, max_enew = 0, max_fnew = 0;
    for (i = 0; i < num; i++) {
      max_vnew += MESH_Num_Vertices(submeshes[i]);
      max_enew += MESH_Num_Edges(submeshes[i]);
      max_fnew += MESH_Num_Faces(submeshes[i]);
    }

    int num_new_verts = 0, num_new_edges = 0, num_new_faces = 0; 
    int *new_vert_gids = (int *) malloc(max_vnew*sizeof(int));
    int *new_edge_gids = (int *) malloc(max_enew*sizeof(int));
    int *new_face_gids = (int *) malloc(max_fnew*sizeof(int));

    List_ptr new_verts = List_New(max_vnew);
    List_ptr new_edges = List_New(max_enew);
    List_ptr new_faces = List_New(max_fnew);
  

    /* Now process each mesh and add a layer of ghost elements from
       each of them to the main partition */
       
    for (i = 0; i < num; i++) {
      submesh = submeshes[i];

      MAttrib_ptr vidatt = MAttrib_New(submesh, "tempvid", POINTER, MVERTEX);
      MAttrib_ptr eidatt = MAttrib_New(submesh, "tempeid", POINTER, MEDGE);
      MAttrib_ptr fidatt = MAttrib_New(submesh, "tempfid", POINTER, MFACE);

      idx = 0;
      while ((sub_mr = MESH_Next_Region(submesh, &idx))) {
        add_region = 0;

        /* Find matching vertices between submesh and main mesh */

        mrverts = MR_Vertices(sub_mr);
        nrv = List_Num_Entries(mrverts);
        for (j = 0; j < nrv; j++) {
          sub_mv = List_Entry(mrverts,j);

          MEnt_Get_AttVal(sub_mv, &vidatt, &ival, &rval, &mv);

          if (mv) {
            int on_parbndry=0;
            MEnt_Get_AttVal(mv, &parbndryatt, &on_parbndry, &rval, &pval);
            if (on_parbndry)
              add_region = 1; 
          } else {

            /* Does the global ID of this vertex of the sub mesh region
             * match the global ID of a boundary vertex in the main
             * mesh? */
            
            global_id = MV_GlobalID(sub_mv);
            loc = (int *) bsearch(&global_id, parbndry_vert_gids, num_parbndry_verts, sizeof(int),
                                  compareINT);
            if (loc) {
              add_region = 1; 
              iloc = loc - parbndry_vert_gids;
              mv = List_Entry(parbndry_verts,iloc); 
              /* here set the ghost vertex property, only necessary when the input submeshes are not consistent */
              if(MV_PType(mv) == PGHOST && MV_PType(sub_mv) != PGHOST) {
                MV_Set_GEntDim(mv,MV_GEntDim(sub_mv));
                MV_Set_GEntID(mv,MV_GEntID(sub_mv));
              }
              
              MEnt_Set_AttVal(sub_mv, vidatt, 0, 0.0, mv);
            }
          }
        }
        List_Delete(mrverts);

        /* Find matching edges between submesh and main mesh */

        mredges = MR_Edges(sub_mr);
        nre = List_Num_Entries(mredges);
        for (j = 0; j < nre; j++) {
          sub_me = List_Entry(mredges,j);
          
          /* Does the edge already have a counterpart in the main mesh? */
          MEnt_Get_AttVal(sub_me, eidatt, &ival, &rval, &me);

          if (!me) {
            /* Does the global ID of this edge of the sub mesh region
             * match the global ID of a boundary edge in the main
             * mesh? */
            
            global_id = ME_GlobalID(sub_me);
            loc = (int *) bsearch(&global_id, parbndry_edge_gids, num_parbndry_edges, sizeof(int),
                                  compareINT);
            if (loc) {
              add_region = 1; 
              iloc = loc - parbndry_edge_gids;
              me = List_Entry(parbndry_edges,iloc); 
              /* here set the ghost edge property, only necessary when the input submeshes are not consistent */
              if(ME_PType(me) == PGHOST && ME_PType(sub_me) != PGHOST) {
                ME_Set_GEntDim(me,ME_GEntDim(sub_me));
                ME_Set_GEntID(me,ME_GEntID(sub_me));
              }

              MEnt_Set_AttVal(sub_me, eidatt, 0, 0.0, me);
            }
          }
        }
        List_Delete(mredges);
          
        /* Find matching faces between submesh and main mesh */

        mrfaces = MR_Faces(sub_mr);
        nrf = List_Num_Entries(mrfaces);
        for (j = 0; j < nrf; j++) {
          sub_mf = List_Entry(mrfaces,j);

          MEnt_Get_AttVal(sub_mf, fidatt, &ival, &rval, &mf);

          if (!mf) {
            /* Does the global ID of this face of the sub mesh region
             * match the global ID of a boundary face in the main
             * mesh? */
            
            global_id = MF_GlobalID(sub_mf);
            loc = (int *) bsearch(&global_id, parbndry_face_gids, num_parbndry_faces, sizeof(int),
                                  compareINT);
            if (loc) {
              iloc = loc - parbndry_face_gids;
              mf = List_Entry(parbndry_faces,iloc); 
              /* here set the ghost edge property, only necessary when the input submeshes are not consistent */
              if (MF_PType(mf) == PGHOST && MF_PType(sub_mf) != PGHOST) {
                MF_Set_GEntDim(mf,MF_GEntDim(sub_mf));
                MF_Set_GEntID(mf,MF_GEntID(sub_mf));
              }

              MEnt_Set_AttVal(sub_mf, fidatt, 0, 0.0, mf);
            }
          }
        }

        if (!add_region) {
          List_Delete(mrfaces);
          continue;
        }
        
        new_mr = MR_New(mesh);                  /* add region */
        MR_Set_GEntDim(new_mr,MR_GEntDim(sub_mr));
        MR_Set_GEntID(new_mr,MR_GEntID(sub_mr));
        MR_Set_PType(new_mr,PGHOST);
        MR_Set_MasterParID(new_mr,MR_MasterParID(sub_mr));
        MR_Set_GlobalID(new_mr,MR_GlobalID(sub_mr));
	
        nrf = List_Num_Entries(mrfaces);
        int i2;
        for(i2 = 0; i2 < nrf; i2++) {
          sub_mf = List_Entry(mrfaces,i2);
          global_id = MF_GlobalID(sub_mf);
          rfdirs[i2] = MR_FaceDir_i(sub_mr,i2) == 1 ? 1 : 0;

          new_mf = NULL;
          MEnt_Get_AttVal(sub_mf, fidatt, &ival, &rval, &new_mf);

          if (!new_mf) {
            /* search in the ghost layer if another face with
             * this global ID has been added */
            loc = (int *) bsearch(&global_id, new_face_gids, num_new_faces,
                                  sizeof(int), compareINT);
            if (loc) {
              iloc = loc - new_face_gids;
              new_mf = List_Entry(new_faces, iloc);
              MEnt_Set_AttVal(sub_mf, fidatt, 0, 0.0, new_mf);
            }
          }

          if (new_mf) {
            List_ptr mfverts = MF_Vertices(sub_mf,1,0);
            int fvgid0[2];
            fvgid0[0] = MF_GlobalID(List_Entry(mfverts,0));
            fvgid0[1] = MF_GlobalID(List_Entry(mfverts,1));
            List_Delete(mfverts);

            mfverts = MF_Vertices(new_mf,1,0);
            int nfv = List_Num_Entries(mfverts);
            int fvgid1[MAXPV2];
            for (j = 0; j < nfv; j++)
              fvgid1[j] = MF_GlobalID(List_Entry(mfverts,j));
            List_Delete(mfverts);

            for (j = 0; j < nfv; j++) {
              if (fvgid1[j] == fvgid0[0]) {
                if (fvgid1[(j+nfv-1)%nfv] == fvgid0[1]) /* reverse dir */
                  rfdirs[i2] = !rfdirs[i2];
                break;
              }
            }                  
          }
          else {  /* add a new face to main mesh */
            new_mf = MF_New(mesh); /* add face */
            MF_Set_GEntDim(new_mf,MF_GEntDim(sub_mf));
            MF_Set_GEntID(new_mf,MF_GEntID(sub_mf));
            MF_Set_PType(new_mf,PGHOST);
            MF_Set_MasterParID(new_mf,MF_MasterParID(sub_mf));
            MF_Set_GlobalID(new_mf,MF_GlobalID(sub_mf));
	    
            MEnt_Set_AttVal(sub_mf, fidatt, 0, 0.0, new_mf);
            List_Add(new_faces, new_mf);
	    
            mfedges = MF_Edges(sub_mf,1,0);
            nfe = List_Num_Entries(mfedges);
            for(j = 0; j < nfe; j++) {
              sub_me = List_Entry(mfedges,j);
              global_id = ME_GlobalID(sub_me);
              
              fedirs[j] = MF_EdgeDir_i(sub_mf,j) == 1 ? 1 : 0;

              new_me = NULL;
              MEnt_Get_AttVal(sub_me, eidatt, &ival, &rval, &new_me);

              if (!new_me) {
                /* search in the ghost layer if another edge with
                 * this global ID has been added */
                loc = (int *) bsearch(&global_id, new_edge_gids, num_new_edges,
                                      sizeof(int), compareINT);
                if (loc) {
                  iloc = loc - new_edge_gids;
                  new_me = List_Entry(new_edges, iloc);
                  MEnt_Set_AttVal(sub_me, eidatt, 0, 0.0, new_me);
                }
              }
              
              if (new_me) {
                if(MV_GlobalID(ME_Vertex(new_me,0)) != MV_GlobalID(ME_Vertex(sub_me,0)))
                  fedirs[j] = 1 - fedirs[j];  /* if the edge dir is not the same, reverse the edge dir */
	      
              } else {  /* add a new edge to main mesh */
                new_me = ME_New(mesh);      /* add new edge and copy information */
                ME_Set_GEntDim(new_me,ME_GEntDim(sub_me));
                ME_Set_GEntID(new_me,ME_GEntID(sub_me));
                ME_Set_PType(new_me,PGHOST);
                ME_Set_MasterParID(new_me,ME_MasterParID(sub_me));
                ME_Set_GlobalID(new_me,ME_GlobalID(sub_me));
		
                MEnt_Set_AttVal(sub_me, eidatt, 0, 0.0, new_me);
                List_Add(new_edges, new_me);

                for(k = 0; k < 2; k++) {
                  sub_mv = ME_Vertex(sub_me,k);
                  global_id = MV_GlobalID(sub_mv);

                  new_mv = NULL;
                  MEnt_Get_AttVal(sub_mv, vidatt, &ival, &rval, &new_mv);

                  if (!new_mv) {
                    /* search in the ghost layer if another vertex with
                     * this global ID has been added */
                    loc = (int *) bsearch(&global_id, new_vert_gids, num_new_verts,
                                          sizeof(int), compareINT);
                    if (loc) {
                      iloc = loc - new_vert_gids;
                      new_mv = List_Entry(new_verts, iloc);
                      MEnt_Set_AttVal(sub_mv, vidatt, 0, 0.0, new_mv);
                    }
                  }
              
                  if (!new_mv) {  /* add new vertex to main mesh */
                    new_mv = MV_New(mesh);  /* add new vertex and copy information */
                    MV_Set_GEntDim(new_mv,MV_GEntDim(sub_mv));
                    MV_Set_GEntID(new_mv,MV_GEntID(sub_mv));
                    MV_Set_PType(new_mv,PGHOST);
                    MV_Set_MasterParID(new_mv,MV_MasterParID(sub_mv));
                    MV_Set_GlobalID(new_mv,MV_GlobalID(sub_mv));
                    MV_Coords(sub_mv,coor);
                    MV_Set_Coords(new_mv,coor);
		    
                    MEnt_Set_AttVal(sub_mv, vidatt, 0, 0.0, new_mv);
                    List_Add(new_verts, new_mv);
                  }
                  ME_Set_Vertex(new_me,k,new_mv);  /* set edge-vertex */
                }
              }							
              fedges[j] = new_me;
            }
            MF_Set_Edges(new_mf,nfe,fedges,fedirs); /* set face-edge */
            List_Delete(mfedges);
          }
          rfaces[i2] = new_mf;
        }
        MR_Set_Faces(new_mr,nrf,rfaces,rfdirs); /* set region-face */

        List_Delete(mrfaces);
      }

      idx = 0;
      while ((sub_mv = MESH_Next_Vertex(submesh, &idx)))
	MEnt_Rem_AttVal(sub_mv, vidatt);
      MAttrib_Delete(vidatt);
      idx = 0;
      while ((sub_me = MESH_Next_Edge(submesh, &idx)))
	MEnt_Rem_AttVal(sub_me, eidatt);
      MAttrib_Delete(eidatt);
      idx = 0;
      while ((sub_mf = MESH_Next_Face(submesh, &idx)))
	MEnt_Rem_AttVal(sub_mf, fidatt);
      MAttrib_Delete(fidatt);

      /* Sort the added entity lists by GlobalID */
      num_new_faces = List_Num_Entries(new_faces);
      List_Sort(new_faces, num_new_faces, sizeof(MFace_ptr), compareGlobalID);
      for (j = 0; j < num_new_faces; j++)
        new_face_gids[j] = MF_GlobalID(List_Entry(new_faces, j));

      num_new_edges = List_Num_Entries(new_edges);
      List_Sort(new_edges, num_new_edges, sizeof(MEdge_ptr), compareGlobalID);
      for (j = 0; j < num_new_edges; j++)
        new_edge_gids[j] = ME_GlobalID(List_Entry(new_edges, j));

      num_new_verts = List_Num_Entries(new_verts);
      List_Sort(new_verts, num_new_verts, sizeof(MVertex_ptr), compareGlobalID);
      for (j = 0; j < num_new_verts; j++)
        new_vert_gids[j] = MV_GlobalID(List_Entry(new_verts, j));
      
    }      

    idx = 0;
    while ((mv = List_Next_Entry(parbndry_verts, &idx)))
      MEnt_Rem_AttVal(mv, parbndryatt);
    MAttrib_Delete(parbndryatt);
    
    List_Delete(parbndry_faces);
    List_Delete(parbndry_edges);
    List_Delete(parbndry_verts);
    List_Delete(new_faces);
    List_Delete(new_edges);
    List_Delete(new_verts);

    free(parbndry_vert_gids);
    free(parbndry_edge_gids);
    free(parbndry_face_gids);
    free(new_face_gids);
    free(new_edge_gids);
    free(new_vert_gids);
    free(fedges);
    free(fedirs);
    free(rfaces);
    free(rfdirs);

    return 1;
  }
  int MESH_Send_NonVertexEntities_FN(Mesh_ptr mesh, int torank, MSTK_Comm comm,
                           int *numreq, int *maxreq, MPI_Request **requests,
                           int *numptrs2free, int *maxptrs2free,
                           void ***ptrs2free) {
    int i, j, nv, ne, nf, nr;
    int nevs, nfes, nrfs, nfe, nrv, nrf, dir;
    int maxnfe, maxnrf;
    int *mesh_info;
    int *list_edge=NULL, *list_face=NULL, *list_region=NULL;
    MVertex_ptr mv;
    MEdge_ptr me;
    MFace_ptr mf;
    MRegion_ptr mr;
    List_ptr mfedges, mrfaces, mrverts;
    RepType rtype;
    double coor[3];
    MPI_Request mpirequest;

    if (requests == NULL)
      MSTK_Report("MESH_Surf_SendMesh","MPI requests array is NULL",MSTK_FATAL);

    if (*maxreq == 0) {
      *maxreq = 25;
      *requests = (MPI_Request *) malloc(*maxreq*sizeof(MPI_Request));
      *numreq = 0;
    }
    else if (*maxreq < (*numreq) + 13) {
      *maxreq = 2*(*maxreq) + 11;
      *requests = (MPI_Request *) realloc(*requests,*maxreq*sizeof(MPI_Request));
    }
  

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

    /* some other known quantitites - 5 items per edge (2 for verts
       and 3 for extra data), maxnfe+4 items per face (1 for number of
       edges, maxnfe for edge indices, anad 3 for extra data),
       maxnrf+4 items per region (1 for number of faces, maxnrf for
       face indices and 3 for extra data */


    maxnfe = 0;
    for (i = 0; i < nf; i++) {
      mf = MESH_Face(mesh,i);
      nfe = MF_Num_Edges(mf);
      if (nfe > maxnfe)
        maxnfe = nfe;
    }

    maxnrf = 0;
    for (i = 0; i < nr; i++) {
      mr = MESH_Region(mesh,i);
      nrf = MR_Num_Faces(mr);
      if (nrf > maxnrf)
        maxnrf = nrf;
    }

    // The amount of extra info we are sending and their meaning is obviously
    // known on the receiving side too. So nevs, nfes and nrfs can be 
    // calculated without us sending it


    nevs = (2+3)*ne;    
    nfes = (1 + maxnfe + 3)*nf;
    nrfs = (1 + maxnrf + 3)*nr;
    
    /* Reserve nevs spots for each edge */

    list_edge = (int *) malloc(5*ne*sizeof(int));

    nevs = 0;

    /* Store the vertex ids, then the 3 auxilliary data fields */

    for(i = 0; i < ne; i++) {
      me = MESH_Edge(mesh,i);
      list_edge[nevs]   = MV_ID(ME_Vertex(me,0));
      list_edge[nevs+1] = MV_ID(ME_Vertex(me,1));
      list_edge[nevs+2] = (ME_GEntID(me)<<3) | (ME_GEntDim(me));
      list_edge[nevs+3] = (ME_MasterParID(me) <<3) | (ME_OnParBoundary(me)<<2) | (ME_PType(me));
      list_edge[nevs+4] = ME_GlobalID(me);
      nevs += 5;
    }

    /* send detailed edge info */

    MPI_Isend(list_edge,nevs,MPI_INT,torank,torank,comm,&mpirequest);
    (*requests)[*numreq] = mpirequest;
    (*numreq)++;
  

    /* Reserve nfes spots for each face */

    list_face = (int *) malloc(nfes*sizeof(int));

    nfes = 0;

    /* first store nfe, then the edge ids, then the 3 auxilliary data fields */

    for(i = 0; i < nf; i++) {
      mf = MESH_Face(mesh,i);
      mfedges = MF_Edges(mf,1,0);
      nfe = List_Num_Entries(mfedges);
      list_face[nfes] = nfe;
      for(j = 0; j < nfe; j++) {
        dir = MF_EdgeDir_i(mf,j) ? 1 : -1;
        list_face[nfes+j+1] = dir*ME_ID(List_Entry(mfedges,j));
      }
      list_face[nfes+nfe+1] = (MF_GEntID(mf)<<3) | (MF_GEntDim(mf));
      list_face[nfes+nfe+2] = (MF_MasterParID(mf)<<3) | (MF_OnParBoundary(mf)<<2) | (MF_PType(mf));
      list_face[nfes+nfe+3] = MF_GlobalID(mf);
      nfes += (nfe + 4);
      List_Delete(mfedges);
    }


    /* send detailed face info */

    MPI_Isend(list_face,nfes,MPI_INT,torank,torank,comm,&mpirequest);
    (*requests)[*numreq] = mpirequest;
    (*numreq)++;

    
    if (nr) {

      list_region = (int *) malloc(nrfs*sizeof(int));
      
      nrfs = 0;
      
      /* first store nrf, then the face ids, then the 3 auxilliary data fields */
      
      for(i = 0; i < nr; i++) {
        mr = MESH_Region(mesh,i);
        mrfaces = MR_Faces(mr);
        nrf = List_Num_Entries(mrfaces);
        list_region[nrfs] = nrf;
        for(j = 0; j < nrf; j++) {
          dir = MR_FaceDir_i(mr,j) == 1 ? 1 : -1;
          list_region[nrfs+j+1] = dir*MF_ID(List_Entry(mrfaces,j));
        }
        list_region[nrfs+nrf+1] = (MR_GEntID(mr)<<3) | (MR_GEntDim(mr));
        list_region[nrfs+nrf+2] = (MR_MasterParID(mr)<<3) | (MR_PType(mr)); /* MR_PType is 2 bits; 3 bit is 0 */
        list_region[nrfs+nrf+3] = MR_GlobalID(mr);
        nrfs += (nrf + 4);
        List_Delete(mrfaces);
      }
      
      /* send detailed region info */
      
      MPI_Isend(list_region,nrfs,MPI_INT,torank,torank,comm,&mpirequest);
      (*requests)[*numreq] = mpirequest;
      (*numreq)++;
      
    }
      

    /* collect allocated memory so it can be freed in a higher level
       routine after MPI_Waitall or MPI_Test has ensured that the send
       has been completed */

    if (ptrs2free == NULL) 
      MSTK_Report("MESH_Surf_SendMesh_FN","ptrs2free array is NULL",MSTK_FATAL);

    int nptrs = 3;

    if (*maxptrs2free == 0) {
      *maxptrs2free = 25;
      *ptrs2free = (void **) malloc(*maxptrs2free*sizeof(void *));
      *numptrs2free = 0;
    }
    else if (*maxptrs2free < (*numptrs2free) + nptrs) {
      *maxptrs2free = 2*(*maxptrs2free) + nptrs;
      *ptrs2free = (void **) realloc(*ptrs2free,(*maxptrs2free)*sizeof(void *));
    }

    if (ne)
      (*ptrs2free)[(*numptrs2free)++] = list_edge;
    if (nf)
      (*ptrs2free)[(*numptrs2free)++] = list_face;
    if (nr)
      (*ptrs2free)[(*numptrs2free)++] = list_region;

    return 1;
  }