Exemple #1
0
  int MESH_WriteToFile(Mesh_ptr mesh, const char *filename, RepType rtype, MSTK_Comm comm) {
  FILE *fp;
  char mesg[80], attname[256];
  int i, j, k, idx;
  int gdim, gid;
  int mvid, mvid0, mvid1, mvid2, mrid2, meid, mfid, mrid;
  int nav, nar, nfe, nfv, nrf, nrv, dir=0;
  int nv, ne, nf, nr;
  int natt, ncomp, ival, nent;
  double xyz[3], rval, rdummy, *rval_arr;
  void *pval, *pdummy;
  MVertex_ptr mv, mv0, mv1, mv2;
  MEdge_ptr me;
  MFace_ptr mf;
  MRegion_ptr mr, mr2;
  List_ptr adjverts, mfedges, mfverts, mrfaces, mrverts, adjregs;
  RepType reptype;
  MAttrib_ptr attrib, vidatt, eidatt, fidatt, ridatt;
  MType attentdim;
  MAttType atttype;

  char modfilename[256];
  strcpy(modfilename, filename);
  
  int rank = 0, numprocs = 1;
#ifdef MSTK_HAVE_MPI
  if (comm) {
    MPI_Comm_size((MPI_Comm)comm, &numprocs);
    MPI_Comm_rank((MPI_Comm)comm, &rank);
  }
  if (numprocs > 1) {
    int ndigits = 0;
    int div = 1;
    while (numprocs/div) {div *= 10; ndigits++;}
    sprintf(modfilename,"%s.%d.%0*d",filename,numprocs,ndigits,rank);
  }
#endif
  
  if (!(fp = fopen(modfilename,"w"))) {
    sprintf(mesg,"Cannot open file %-s for writing",modfilename);
    MSTK_Report("MESH_WriteToFile",mesg,MSTK_ERROR);
    return 0;
  }

  if (rtype != UNKNOWN_REP) {
    reptype = rtype;
  }
  else {
    reptype = MESH_RepType(mesh);
  }

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

  fprintf(fp,"MSTK %-2.1lf\n",MSTK_FILE_VER);
  fprintf(fp,"%s %d %d %d %d\n",
	  MESH_rtype_str[reptype], 
	  nv, 
	  (reptype >= R1 && reptype <= R4)?0:ne, 
	  (reptype >= R1 && reptype <= R2 && nr)?0:nf, 
	  nr);

  vidatt = MAttrib_New(mesh,"vidatt",INT,MVERTEX);
  eidatt = MAttrib_New(mesh,"eidatt",INT,MEDGE);
  fidatt = MAttrib_New(mesh,"fidatt",INT,MFACE);
  ridatt = MAttrib_New(mesh,"ridatt",INT,MREGION);

  idx = 0; i = 0;
  while ((mv = MESH_Next_Vertex(mesh,&idx)))
    MEnt_Set_AttVal(mv,vidatt,++i,0.0,NULL);

  idx = 0; i = 0;
  while ((me = MESH_Next_Edge(mesh,&idx)))
    MEnt_Set_AttVal(me,eidatt,++i,0.0,NULL);

  idx = 0; i = 0;
  while ((mf = MESH_Next_Face(mesh,&idx)))
    MEnt_Set_AttVal(mf,fidatt,++i,0.0,NULL);

  idx = 0; i = 0;
  while ((mr = MESH_Next_Region(mesh,&idx)))
    MEnt_Set_AttVal(mr,ridatt,++i,0.0,NULL);
  
  
  fprintf(fp,"vertices\n");
  idx = 0;
  while ((mv = MESH_Next_Vertex(mesh,&idx))) {

    MV_Coords(mv,xyz);

    gdim = MV_GEntDim(mv);
    gid = MV_GEntID(mv);

    fprintf(fp,"%24.16lf %24.16lf %24.16lf   %d %d\n",
	    xyz[0],xyz[1],xyz[2],gdim,gid);
    
  }

  if (reptype == R2 || reptype == R4) {
    fprintf(fp,"adjvertices\n");

    idx = 0;
    while ((mv = MESH_Next_Vertex(mesh,&idx))) {

      nav = MV_Num_AdjVertices(mv);
      fprintf(fp,"%d ",nav);
      
      adjverts = MV_AdjVertices(mv);
      for (j = 0; j < nav; j++) {
	mv2 = List_Entry(adjverts,j);
	MEnt_Get_AttVal(mv2,vidatt,&mvid2,&rval,&pval);
	fprintf(fp,"%d ",mvid2);
      }
      fprintf(fp,"\n");
      List_Delete(adjverts);
    }
  }



  if (reptype <= F4 && ne) {
    fprintf(fp,"edges\n");

    idx = 0;
    while ((me = MESH_Next_Edge(mesh,&idx))) {

      mv0 = ME_Vertex(me,0);
      MEnt_Get_AttVal(mv0,vidatt,&mvid0,&rval,&pval);
      mv1 = ME_Vertex(me,1);
      MEnt_Get_AttVal(mv1,vidatt,&mvid1,&rval,&pval);

      gdim = ME_GEntDim(me);
      gid = ME_GEntID(me);

      fprintf(fp,"%d %d \t%d %d\n",mvid0,mvid1,gdim,gid);
    }
  }



  if (reptype <= F4) {

    /* For full representations, always write out faces in terms of edges */

    fprintf(fp,"faces edge\n");
    
    idx = 0;
    while ((mf = MESH_Next_Face(mesh,&idx))) {
      
      nfe = MF_Num_Edges(mf);
      fprintf(fp,"%d ",nfe);
      
      mfedges = MF_Edges(mf,1,0);
      for (j = 0; j < nfe; j++) {
	me = List_Entry(mfedges,j);
	dir = MF_EdgeDir_i(mf,j);
	MEnt_Get_AttVal(me,eidatt,&meid,&rval,&pval);
	if (dir != 1) meid = -meid;
	fprintf(fp,"%d ",meid);
      }
      List_Delete(mfedges);
      
      gdim = MF_GEntDim(mf);
      /*
	gent = MF_GEntity(mf);
	gid = gent ? -99 : 0;
      */
      gid = MF_GEntID(mf);
      
      fprintf(fp,"\t%d %d\n",gdim,gid);
    }
  }
  else {

    /* For reduced representations, R3 and R4 always write out faces
       in terms of vertices. For reduced representations, R1 and R2
       write out faces in terms of vertices only when there are no
       regions (i.e. faces are the highest level mesh entities) */

    if ((reptype > R2) || (nr == 0)) {

      fprintf(fp,"faces vertex\n");

      idx = 0;
      while ((mf = MESH_Next_Face(mesh,&idx))) {
	
	nfv = MF_Num_Edges(mf);
	fprintf(fp,"%d ",nfv);
	
	mfverts = MF_Vertices(mf,1,0);
	for (j = 0; j < nfv; j++) {
	  mv = List_Entry(mfverts,j);
	  MEnt_Get_AttVal(mv,vidatt,&mvid,&rval,&pval);
	  fprintf(fp,"%d ",mvid);
	}
	List_Delete(mfverts);

	gdim = MF_GEntDim(mf);
	gid = MF_GEntID(mf);
	
	fprintf(fp,"\t%d %d\n",gdim,gid);
      }
    }
	
  }


  if (nr) {
    if (reptype <= F4 || reptype >= R2) {
      fprintf(fp,"regions face\n");

      idx = 0;
      while ((mr = MESH_Next_Region(mesh,&idx))) {

	nrf = MR_Num_Faces(mr);
	fprintf(fp,"%d ",nrf);

	mrfaces = MR_Faces(mr);
	for (j = 0; j < nrf; j++) {
	  mf = List_Entry(mrfaces,j);
	  dir = MR_FaceDir_i(mr,j);
	  MEnt_Get_AttVal(mf,fidatt,&mfid,&rval,&pval);
	  if (dir != 1) mfid = -mfid;
	  fprintf(fp,"%d ",mfid);
	}
	List_Delete(mrfaces);
	
	gdim = MF_GEntDim(mr);
	gid = MR_GEntID(mr);

	fprintf(fp,"\t%d %d\n",gdim,gid);
      }
    }
    else {
      fprintf(fp,"regions vertex\n");

      idx = 0;
      while ((mr = MESH_Next_Region(mesh,&idx))) {

	nrv = MR_Num_Vertices(mr);
	fprintf(fp,"%d ",nrv);

	mrverts = MR_Vertices(mr);
	for (j = 0; j < nrv; j++) {
	  mv = List_Entry(mrverts,j);
	  MEnt_Get_AttVal(mv,vidatt,&mvid,&rval,&pval);
	  fprintf(fp,"%d ",mvid);
	}
	List_Delete(mrverts);
	
	gdim = MR_GEntDim(mr);
	gid = MR_GEntID(mr);

	fprintf(fp,"\t%d %d\n",gdim,gid);
      }
    }

    if (reptype == R2 || reptype == R4) {
      fprintf(fp,"adjregions\n");
      
      idx = 0;
      while ((mr = MESH_Next_Region(mesh,&idx))) {

	nar = MR_Num_Faces(mr);
	fprintf(fp,"%d ",nar);

	adjregs = MR_AdjRegions(mr);

	for (j = 0; j < nar; j++) {
	  mr2 = List_Entry(adjregs,j);
	  if ((long) mr2 == -1) 
	    fprintf(fp,"%d ",0);
	  else {
	    MEnt_Get_AttVal(mr2,ridatt,&mrid2,&rval,&pval);
	    fprintf(fp,"%d ",mrid2);
	  }
	}
	fprintf(fp,"\n");
	List_Delete(adjregs);
      }
    }
  }


  /* Write out attributes if there are more than the 4 that we created 
    in this routine */


  if ((natt = MESH_Num_Attribs(mesh)) > 4) {

    fprintf(fp,"attributes\n");

    for (i = 0; i < natt; i++) {
      
      attrib = MESH_Attrib(mesh,i);

      /* Don't write out attribs we created for the internal use of 
	 this routine */
      if (attrib == vidatt || attrib == eidatt || attrib == fidatt || 
	  attrib == ridatt) continue;
      
      MAttrib_Get_Name(attrib,attname);

      atttype = MAttrib_Get_Type(attrib);
      if (atttype == POINTER) continue;  /* cannot write it out */

      ncomp = MAttrib_Get_NumComps(attrib);

      attentdim = MAttrib_Get_EntDim(attrib);


      /* First count how many entities actually have the attribute assigned */

      nent = 0;
      switch(attentdim) {
      case MVERTEX:
	idx = 0;
	while ((mv = MESH_Next_Vertex(mesh,&idx)))
	  if (MEnt_Get_AttVal(mv,attrib,&ival,&rval,&pval)) nent++;
	break;
      case MEDGE:
	idx = 0;
	while ((me = MESH_Next_Edge(mesh,&idx)))
	  if (MEnt_Get_AttVal(me,attrib,&ival,&rval,&pval)) nent++;
	break;
      case MFACE:
	idx = 0;
	while ((mf = MESH_Next_Face(mesh,&idx)))
	  if (MEnt_Get_AttVal(mf,attrib,&ival,&rval,&pval)) nent++;	    
	break;
      case MREGION: 
	idx = 0;
	while ((mr = MESH_Next_Region(mesh,&idx)))
	  if (MEnt_Get_AttVal(mr,attrib,&ival,&rval,&pval)) nent++;
	break;
      case MALLTYPE:
	idx = 0;
	while ((mv = MESH_Next_Vertex(mesh,&idx)))
	  if (MEnt_Get_AttVal(mv,attrib,&ival,&rval,&pval)) nent++;
	idx = 0;
	while ((me = MESH_Next_Edge(mesh,&idx)))
	  if (MEnt_Get_AttVal(me,attrib,&ival,&rval,&pval)) nent++;
	idx = 0;
	while ((mf = MESH_Next_Face(mesh,&idx)))
	  if (MEnt_Get_AttVal(mf,attrib,&ival,&rval,&pval)) nent++;	    
	idx = 0;
	while ((mr = MESH_Next_Region(mesh,&idx)))
	  if (MEnt_Get_AttVal(mr,attrib,&ival,&rval,&pval)) nent++;
	break;	
      default:
	break;
      } /* switch (attentdim) */


      /* No point in writing out attribute if no entity uses it! Or is there? */

      if (!nent) continue;



      fprintf(fp,"%-s\n",attname);

      switch(atttype) {
      case INT:
	fprintf(fp,"INT\n");
	break;
      case DOUBLE:
	fprintf(fp,"DOUBLE\n");
	break;
      case VECTOR:
	fprintf(fp,"VECTOR\n");
	break;
      case TENSOR:
	fprintf(fp,"TENSOR\n");
	break;
      default:
	MSTK_Report("MESH_WriteToFile",
		    "Unrecognizable or unprintable attribute type\n",MSTK_WARN);
	continue;	
      }

      fprintf(fp,"%-d\n",ncomp);

      switch(attentdim) {
      case MVERTEX:
	fprintf(fp,"MVERTEX\n");
	break;
      case MEDGE:
	fprintf(fp,"MEDGE\n");
	break;
      case MFACE:
	fprintf(fp,"MFACE\n");
	break;
      case MREGION:
	fprintf(fp,"MREGION\n");
	break;
      case MALLTYPE:
	fprintf(fp,"MALLTYPE\n");
	break;
      default:
	MSTK_Report("Mesh_WriteToFile","Unrecognized entity type",MSTK_WARN);
	break;
      }

      fprintf(fp,"%-d\n",nent);


      switch(attentdim) {
      case MVERTEX:
	idx = 0;
	while ((mv = MESH_Next_Vertex(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mv,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mv,vidatt,&mvid,&rdummy,&pdummy);
	    fprintf(fp,"0 %-d ",mvid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	break;
      case MEDGE:
	idx = 0;
	while ((me = MESH_Next_Edge(mesh,&idx))) {
	  if (MEnt_Get_AttVal(me,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(me,eidatt,&meid,&rdummy,&pdummy);
	    fprintf(fp,"1 %-d ",meid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	break;
      case MFACE:
	idx = 0;
	while ((mf = MESH_Next_Face(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mf,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mf,fidatt,&mfid,&rdummy,&pdummy);
	    fprintf(fp,"2 %-d ",mfid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	break;

      case MREGION: 
	idx = 0;
	while ((mr = MESH_Next_Region(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mr,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mr,ridatt,&mrid,&rdummy,&pdummy);
	    fprintf(fp,"3 %-d ",mrid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	break;

      case MALLTYPE:
	idx = 0;
	while ((mv = MESH_Next_Vertex(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mv,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mv,vidatt,&mvid,&rdummy,&pdummy);
	    fprintf(fp,"0 %-d ",mvid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	idx = 0;
	while ((me = MESH_Next_Edge(mesh,&idx))) {
	  if (MEnt_Get_AttVal(me,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(me,eidatt,&meid,&rdummy,&pdummy);
	    fprintf(fp,"1 %-d ",meid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	idx = 0;
	while ((mf = MESH_Next_Face(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mf,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mf,fidatt,&mfid,&rdummy,&pdummy);
	    fprintf(fp,"2 %-d ",mfid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	idx = 0;
	while ((mr = MESH_Next_Region(mesh,&idx))) {
	  if (MEnt_Get_AttVal(mr,attrib,&ival,&rval,&pval)) {
	    MEnt_Get_AttVal(mr,ridatt,&mrid,&rdummy,&pdummy);
	    fprintf(fp,"3 %-d ",mrid);
	    switch (atttype) {
	    case INT:
	      fprintf(fp," %-d",ival);
	      break;
	    case DOUBLE: 
	      fprintf(fp," %-lf ",rval);
	      break;
	    case VECTOR: case TENSOR:
	      rval_arr = (double *) pval;
	      for (k = 0; k < ncomp; k++)
		fprintf(fp," %-lf ",rval_arr[k]);
	      break;
	    default:
	      break;
	    }
	    fprintf(fp,"\n");
	  }
	}
	break;	
      default:
	break;
      } /* switch (attentdim) */

    } /* for (i = 0; i < natt) */
    
  } /* if (Mesh_Num_Attribs(mesh)) */
  

  idx = 0; i = 0;
  while ((mv = MESH_Next_Vertex(mesh,&idx)))
    MEnt_Rem_AttVal(mv,vidatt);

  idx = 0; i = 0;
  while ((me = MESH_Next_Edge(mesh,&idx)))
    MEnt_Rem_AttVal(me,eidatt);

  idx = 0; i = 0;
  while ((mf = MESH_Next_Face(mesh,&idx)))
    MEnt_Rem_AttVal(mf,fidatt);

  idx = 0; i = 0;
  while ((mr = MESH_Next_Region(mesh,&idx)))
    MEnt_Rem_AttVal(mr,ridatt);
  
  MAttrib_Delete(vidatt);
  MAttrib_Delete(eidatt);
  MAttrib_Delete(fidatt);
  MAttrib_Delete(ridatt);




  fclose(fp);

  return 1;
}
Exemple #2
0
int MESH_CopyAttr(Mesh_ptr mesh, int num, Mesh_ptr *submeshes, const char *attr_name) {
  int i, ncomp, ival, idx;
  double rval, *pval_arr=NULL;
  void *pval;
  MType mtype;
  MAttrib_ptr *local_attrib, global_attrib, g2latt;
  MAttType atttype;


  global_attrib = MESH_AttribByName(mesh,attr_name);
  if(!global_attrib) {
    MSTK_Report("MESH_CopyAttr","Root mesh has no attribute of given name",MSTK_WARN);
    return 0;
  }

  g2latt = MESH_AttribByName(mesh,"Global2Local");

  local_attrib = (MAttrib_ptr *) malloc(num*sizeof(MAttrib_ptr));
  for (i = 0; i < num; i++) {
    local_attrib[i] = MESH_AttribByName(submeshes[i],attr_name);
    /* if there is no such attribute */
    if(!local_attrib[i]) {
      MSTK_Report("MESH_CopyAttr","Submesh has no attribute of given name",MSTK_WARN);
      return 0;
    }
  }
    

  /* get attribute properties */
  ncomp = MAttrib_Get_NumComps(global_attrib);
  mtype = MAttrib_Get_EntDim(global_attrib);
  atttype = MAttrib_Get_Type(global_attrib);

  if (atttype == POINTER) {
    free(local_attrib);
    return 0; /* Don't see why one would want to
                 transmit pointer info to the submesh */
  }
  
  /* attribute entity type */
  
  if (mtype == MVERTEX || mtype == MALLTYPE) {
    MVertex_ptr gmv, lmv;
    List_ptr lmvlist;

    idx = 0;
    while ((gmv = MESH_Next_Vertex(mesh,&idx))) {

      MEnt_Get_AttVal(gmv,global_attrib,&ival,&rval,&pval);

      /* Don't copy null values */

      if ((atttype == INT && ival == 0) || 
          (atttype == DOUBLE  && rval == 0.0) ||
          (atttype == POINTER && pval == NULL))
        continue;

      int dummy_ival;
      double dummy_rval;
      MEnt_Get_AttVal(gmv,g2latt,&dummy_ival,&dummy_rval,&lmvlist);
      if (!lmvlist) continue;

      int idx2 = 0;
      while ((lmv = List_Next_Entry(lmvlist,&idx2))) {
        if (ncomp > 1) {
          pval_arr = (void *)malloc(ncomp*sizeof(double));
          memcpy(pval_arr,pval,ncomp*sizeof(double));
        }
        else
          pval_arr = NULL;

        Mesh_ptr entmesh = MEnt_Mesh(lmv);
        for (i = 0; i < num; i++)
          if (entmesh == submeshes[i]) {
            MEnt_Set_AttVal(lmv,local_attrib[i],ival,rval,(void *)pval_arr);
            break;
          }
      }
    }
  }

  if (mtype == MEDGE || mtype == MALLTYPE) {
    MVertex_ptr gme, lme;
    List_ptr lmelist;

    idx = 0;
    while ((gme = MESH_Next_Edge(mesh,&idx))) {

      MEnt_Get_AttVal(gme,global_attrib,&ival,&rval,&pval);

      /* Don't copy null values */

      if ((atttype == INT && ival == 0) || 
          (atttype == DOUBLE  && rval == 0.0) ||
          (atttype == POINTER && pval == NULL))
        continue;

      int dummy_ival;
      double dummy_rval;
      MEnt_Get_AttVal(gme,g2latt,&dummy_ival,&dummy_rval,&lmelist);
      if (!lmelist) continue;

      int idx2 = 0;
      while ((lme = List_Next_Entry(lmelist,&idx2))) {
        if (ncomp > 1) {
          pval_arr = (void *)malloc(ncomp*sizeof(double));
          memcpy(pval_arr,pval,ncomp*sizeof(double));
        }
        else
          pval_arr = NULL;

        Mesh_ptr entmesh = MEnt_Mesh(lme);
        for (i = 0; i < num; i++)
          if (entmesh == submeshes[i]) {
            MEnt_Set_AttVal(lme,local_attrib[i],ival,rval,(void *)pval_arr);
            break;
          }
      }
    }
  }

  if (mtype == MFACE || mtype == MALLTYPE) {
    MFace_ptr gmf, lmf;
    List_ptr lmflist;

    idx = 0;
    while ((gmf = MESH_Next_Face(mesh,&idx))) {

      MEnt_Get_AttVal(gmf,global_attrib,&ival,&rval,&pval);

      /* Don't copy null values */

      if ((atttype == INT && ival == 0) || 
          (atttype == DOUBLE  && rval == 0.0) ||
          (atttype == POINTER && pval == NULL))
        continue;

      int dummy_ival;
      double dummy_rval;
      MEnt_Get_AttVal(gmf,g2latt,&dummy_ival,&dummy_rval,&lmflist);
      if (!lmflist) continue;

      int idx2 = 0;
      while ((lmf = List_Next_Entry(lmflist,&idx2))) {
        if (ncomp > 1) {
          pval_arr = (void *)malloc(ncomp*sizeof(double));
          memcpy(pval_arr,pval,ncomp*sizeof(double));
        }
        else
          pval_arr = NULL;

        Mesh_ptr entmesh = MEnt_Mesh(lmf);
        for (i = 0; i < num; i++)
          if (entmesh == submeshes[i]) {
            MEnt_Set_AttVal(lmf,local_attrib[i],ival,rval,(void *)pval_arr);
            break;
          }
      }
    }
  }


  if (mtype == MREGION || mtype == MALLTYPE) {
    MRegion_ptr gmr, lmr;
    List_ptr lmrlist;

    idx = 0;
    while ((gmr = MESH_Next_Region(mesh,&idx))) {

      MEnt_Get_AttVal(gmr,global_attrib,&ival,&rval,&pval);

      /* Don't copy null values */

      if ((atttype == INT && ival == 0) || 
          (atttype == DOUBLE  && rval == 0.0) ||
          (atttype == POINTER && pval == NULL))
        continue;

      int dummy_ival;
      double dummy_rval;
      MEnt_Get_AttVal(gmr,g2latt,&dummy_ival,&dummy_rval,&lmrlist);
      if (!lmrlist) continue;

      int idx2 = 0;
      while ((lmr = List_Next_Entry(lmrlist,&idx2))) {
        if (ncomp > 1) {
          pval_arr = (void *)malloc(ncomp*sizeof(double));
          memcpy(pval_arr,pval,ncomp*sizeof(double));
        }
        else
          pval_arr = NULL;

        Mesh_ptr entmesh = MEnt_Mesh(lmr);
        for (i = 0; i < num; i++)
          if (entmesh == submeshes[i]) {
            MEnt_Set_AttVal(lmr,local_attrib[i],ival,rval,(void *)pval_arr);
            break;
          }
      }
    }
  }

  free(local_attrib);
  
  return 1;
}
  int MESH_Send_AttributeMetaData(Mesh_ptr mesh, int torank, MSTK_Comm comm,
                                  int *numreq, int *maxreq, 
                                  MPI_Request **requests,
                                  int *numptrs2free, int *maxptrs2free, 
                                  void ***ptrs2free) {
    int i, natt, mtype, att_type, ncomp;
    char attname[256];
    MAttrib_ptr attrib;
    int *list_attr_num, *list_attr_info;
    char *list_attr_names;
    MPI_Request mpirequest;
    
    if (requests == NULL)
      MSTK_Report("MSTK_SendMesh","Invalid MPI request buffer",MSTK_FATAL);
    
    if (*maxreq == 0) {
      *maxreq = 25;
      *requests = (MPI_Request *) malloc(*maxreq*sizeof(MPI_Request));
      *numreq = 0;
    }
    else if (*maxreq < (*numreq) + 3) {
      *maxreq = 2*(*maxreq) + 3;
      *requests = (MPI_Request *) realloc(*requests,*maxreq*sizeof(MPI_Request));
    }
    
    if (ptrs2free == NULL)
      MSTK_Report("MSTK_SendMesh","Invalid ptrs2free buffer",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) + 3;
      *ptrs2free = (void **) realloc(*ptrs2free,(*maxptrs2free)*sizeof(void *));
    }    

    /* Send info about how many attributes there are, what kind and
       what there names are in a packed fashion */

    natt = MESH_Num_Attribs(mesh);

    list_attr_num = (int *) malloc(sizeof(int));
    list_attr_info = (int *) malloc(natt*sizeof(int));
    list_attr_names = (char *) malloc(natt*256*sizeof(char));
    
    int nattsend = 0;
    for(i = 0; i < natt; i++) {
      attrib = MESH_Attrib(mesh,i);
      MAttrib_Get_Name(attrib,attname);
      att_type = MAttrib_Get_Type(attrib);
      if (att_type == POINTER) continue;
      
      ncomp = MAttrib_Get_NumComps(attrib);
      mtype = MAttrib_Get_EntDim(attrib);
      list_attr_info[nattsend] = (ncomp << 6) | (mtype << 3) | (att_type);
      strcpy(&list_attr_names[nattsend*256],attname);
      nattsend++;
    }

    list_attr_num[0] = nattsend;
    MPI_Isend(list_attr_num,1,MPI_INT,torank,torank,comm,&mpirequest);
    (*requests)[*numreq] = mpirequest;
    (*numreq)++;

    (*ptrs2free)[(*numptrs2free)++] = list_attr_num;

    if (!nattsend) {
      free(list_attr_info);
      free(list_attr_names);
      return 1;
    }
    
    MPI_Isend(list_attr_info,nattsend,MPI_INT,torank,torank,comm,&mpirequest);
    (*requests)[*numreq] = mpirequest;
    (*numreq)++;
    
    MPI_Isend(list_attr_names,nattsend*256,MPI_CHAR,torank,torank,comm,
              &mpirequest);
    (*requests)[*numreq] = mpirequest;
    (*numreq)++;


    (*ptrs2free)[(*numptrs2free)++] = list_attr_info;
    (*ptrs2free)[(*numptrs2free)++] = list_attr_names;

    return 1;
  }
  int MESH_Send_Attribute(Mesh_ptr mesh, MAttrib_ptr attrib, int torank, 
                          MSTK_Comm comm, int *numreq, int *maxreq, 
                          MPI_Request **requests,
                          int *numptrs2free, int *maxptrs2free,
                          void ***ptrs2free) {
    int j, k;
    int num, ncomp, ival;
    double rval;
    void *pval;
    double *rval_arr;
    int *list_info;

    MType mtype;
    MAttType att_type;
    MEntity_ptr ment;
    MPI_Request mpirequest;

    if (requests == NULL)
      MSTK_Report("MSTK_SendMSet","Invalid MPI request buffer",MSTK_FATAL);
  
    if (*maxreq == 0) {
      *maxreq = 25;
      *requests = (MPI_Request *) malloc(*maxreq*sizeof(MPI_Request));
      *numreq = 0;
    }
    else if (*maxreq < (*numreq) + 2) {
      *maxreq *= 2;
      *requests = (MPI_Request *) realloc(*requests,*maxreq*sizeof(MPI_Request));
    }
  

    /* get attribute properties */
    att_type = MAttrib_Get_Type(attrib);
    ncomp = MAttrib_Get_NumComps(attrib);
    mtype = MAttrib_Get_EntDim(attrib);
  
    /* attribute entity type, used before ghost list established, so no ghost */
    switch (mtype) {
    case MVERTEX:
      num = MESH_Num_Vertices(mesh);
      break;
    case MEDGE:
      num = MESH_Num_Edges(mesh);
      break;
    case MFACE:
      num = MESH_Num_Faces(mesh);
      break;
    case MREGION:
      num = MESH_Num_Regions(mesh);
      break;
    default:
      num = 0;
#ifdef DEBUG2
      MSTK_Report("MESH_SendAttr()","Cannot send attributes on entity type MALLTYPE",MSTK_WARN);
#endif
      return 0;
    }
    
    /* attribute index and global id */ 

    list_info = (int *) malloc(num*sizeof(int));

    /* attribute values */

    int *list_value_int = NULL;
    double *list_value_double = NULL;
    if (att_type == INT)
      list_value_int = (int *) malloc(num*ncomp*sizeof(int));
    else
      list_value_double = (double *) malloc(num*ncomp*sizeof(double));
  
    /* collect data */
    for(j = 0; j < num; j++) {
      switch (mtype) {
      case MVERTEX:
        ment = MESH_Vertex(mesh,j);
        break;
      case MEDGE:
        ment = MESH_Edge(mesh,j);
        break;
      case MFACE:
        ment = MESH_Face(mesh,j);
        break;
      case MREGION:
        ment = MESH_Region(mesh,j);
        break;
      default:
        MSTK_Report("MESH_SendAttr()","Invalid entity type",MSTK_WARN);
        return 0;
      }
    
      MEnt_Get_AttVal(ment,attrib,&ival,&rval,&pval);

      list_info[j] = MEnt_GlobalID(ment);
      if (att_type == INT)
        list_value_int[j] = ival;
      else {
        if(ncomp == 1)
          list_value_double[j] = rval;
        if(ncomp > 1) {
          rval_arr = (double *)pval;
          for(k = 0; k < ncomp; k++)
            list_value_double[ncomp*j+k] = rval_arr[k];
        }
      }
    }
  
    /* send entity global IDs */

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

    /* send values */

    if (att_type == INT) {
      MPI_Isend(list_value_int,num*ncomp,MPI_INT,torank,torank,comm,&mpirequest);
      (*requests)[*numreq] = mpirequest;
    }
    else {
      MPI_Isend(list_value_double,num*ncomp,MPI_DOUBLE,torank,torank,comm,
                &mpirequest);
      (*requests)[*numreq] = mpirequest;
    }
    (*numreq)++;

    /* track the buffers used for sending so that they can be released later */

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

    (*ptrs2free)[(*numptrs2free)++] = list_info;
    if (att_type == INT) 
      (*ptrs2free)[(*numptrs2free)++] = list_value_int;  
    else
      (*ptrs2free)[(*numptrs2free)++] = list_value_double;

    return 1;
  }