Actual source code: plexexodusii.c

petsc-3.4.5 2014-06-29
  1: #define PETSCDM_DLL
  2: #include <petsc-private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/

  4: #if defined(PETSC_HAVE_EXODUSII)
  5: #include <netcdf.h>
  6: #include <exodusII.h>
  7: #endif

 11: /*@
 12:   DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file.

 14:   Collective on comm

 16:   Input Parameters:
 17: + comm  - The MPI communicator
 18: . exoid - The ExodusII id associated with a exodus file and obtained using ex_open
 19: - interpolate - Create faces and edges in the mesh

 21:   Output Parameter:
 22: . dm  - The DM object representing the mesh

 24:   Level: beginner

 26: .keywords: mesh,ExodusII
 27: .seealso: DMPLEX, DMCreate()
 28: @*/
 29: PetscErrorCode DMPlexCreateExodus(MPI_Comm comm, PetscInt exoid, PetscBool interpolate, DM *dm)
 30: {
 31: #if defined(PETSC_HAVE_EXODUSII)
 32:   PetscMPIInt    num_proc, rank;
 33:   PetscSection   coordSection;
 34:   Vec            coordinates;
 35:   PetscScalar    *coords;
 36:   PetscInt       coordSize, v;
 38:   /* Read from ex_get_init() */
 39:   char title[PETSC_MAX_PATH_LEN+1];
 40:   int  dim    = 0, numVertices = 0, numCells = 0;
 41:   int  num_cs = 0, num_vs = 0, num_fs = 0;
 42: #endif

 45: #if defined(PETSC_HAVE_EXODUSII)
 46:   MPI_Comm_rank(comm, &rank);
 47:   MPI_Comm_size(comm, &num_proc);
 48:   DMCreate(comm, dm);
 49:   DMSetType(*dm, DMPLEX);
 50:   /* Open EXODUS II file and read basic informations on rank 0, then broadcast to all processors */
 51:   if (!rank) {
 52:     PetscMemzero(title,(PETSC_MAX_PATH_LEN+1)*sizeof(char));
 53:     ex_get_init(exoid, title, &dim, &numVertices, &numCells, &num_cs, &num_vs, &num_fs);
 54:     if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"ExodusII ex_get_init() failed with error code %D\n",ierr);
 55:     if (!num_cs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Exodus file does not contain any cell set\n");
 56:   }
 57:   MPI_Bcast(title, PETSC_MAX_PATH_LEN+1, MPI_CHAR, 0, comm);
 58:   MPI_Bcast(&dim, 1, MPI_INT, 0, comm);
 59:   PetscObjectSetName((PetscObject) *dm, title);
 60:   DMPlexSetDimension(*dm, dim);
 61:   DMPlexSetChart(*dm, 0, numCells+numVertices);

 63:   /* Read cell sets information */
 64:   if (!rank) {
 65:     PetscInt *cone;
 66:     int      c, cs, c_loc, v, v_loc;
 67:     /* Read from ex_get_elem_blk_ids() */
 68:     int *cs_id;
 69:     /* Read from ex_get_elem_block() */
 70:     char buffer[PETSC_MAX_PATH_LEN+1];
 71:     int  num_cell_in_set, num_vertex_per_cell, num_attr;
 72:     /* Read from ex_get_elem_conn() */
 73:     int *cs_connect;

 75:     /* Get cell sets IDs */
 76:     PetscMalloc(num_cs * sizeof(int), &cs_id);
 77:     ex_get_elem_blk_ids(exoid, cs_id);
 78:     /* Read the cell set connectivity table and build mesh topology
 79:        EXO standard requires that cells in cell sets be numbered sequentially and be pairwise disjoint. */
 80:     /* First set sizes */
 81:     for (cs = 0, c = 0; cs < num_cs; cs++) {
 82:       ex_get_elem_block(exoid, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, &num_attr);
 83:       for (c_loc = 0; c_loc < num_cell_in_set; ++c_loc, ++c) {
 84:         DMPlexSetConeSize(*dm, c, num_vertex_per_cell);
 85:       }
 86:     }
 87:     DMSetUp(*dm);
 88:     for (cs = 0, c = 0; cs < num_cs; cs++) {
 89:       ex_get_elem_block(exoid, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, &num_attr);
 90:       PetscMalloc2(num_vertex_per_cell*num_cell_in_set,int,&cs_connect,num_vertex_per_cell,PetscInt,&cone);
 91:       ex_get_elem_conn(exoid, cs_id[cs], cs_connect);
 92:       /* EXO uses Fortran-based indexing, sieve uses C-style and numbers cell first then vertices. */
 93:       for (c_loc = 0, v = 0; c_loc < num_cell_in_set; ++c_loc, ++c) {
 94:         for (v_loc = 0; v_loc < num_vertex_per_cell; ++v_loc, ++v) {
 95:           cone[v_loc] = cs_connect[v]+numCells-1;
 96:         }
 97:         if (dim == 3) {
 98:           /* Tetrahedra are inverted */
 99:           if (num_vertex_per_cell == 4) {
100:             PetscInt tmp = cone[0];
101:             cone[0] = cone[1];
102:             cone[1] = tmp;
103:           }
104:           /* Hexahedra are inverted */
105:           if (num_vertex_per_cell == 8) {
106:             PetscInt tmp = cone[1];
107:             cone[1] = cone[3];
108:             cone[3] = tmp;
109:           }
110:         }
111:         DMPlexSetCone(*dm, c, cone);
112:         DMPlexSetLabelValue(*dm, "Cell Sets", c, cs_id[cs]);
113:       }
114:       PetscFree2(cs_connect,cone);
115:     }
116:     PetscFree(cs_id);
117:   }
118:   DMPlexSymmetrize(*dm);
119:   DMPlexStratify(*dm);
120:   if (interpolate) {
121:     DM idm;

123:     DMPlexInterpolate(*dm, &idm);
124:     /* Maintain Cell Sets label */
125:     {
126:       DMLabel label;

128:       DMPlexRemoveLabel(*dm, "Cell Sets", &label);
129:       if (label) {DMPlexAddLabel(idm, label);}
130:     }
131:     DMDestroy(dm);
132:     *dm  = idm;
133:   }

135:   /* Create vertex set label */
136:   if (!rank && (num_vs > 0)) {
137:     int vs, v;
138:     /* Read from ex_get_node_set_ids() */
139:     int *vs_id;
140:     /* Read from ex_get_node_set_param() */
141:     int num_vertex_in_set, num_attr;
142:     /* Read from ex_get_node_set() */
143:     int *vs_vertex_list;

145:     /* Get vertex set ids */
146:     PetscMalloc(num_vs * sizeof(int), &vs_id);
147:     ex_get_node_set_ids(exoid, vs_id);
148:     for (vs = 0; vs < num_vs; ++vs) {
149:       ex_get_node_set_param(exoid, vs_id[vs], &num_vertex_in_set, &num_attr);
150:       PetscMalloc(num_vertex_in_set * sizeof(int), &vs_vertex_list);
151:       ex_get_node_set(exoid, vs_id[vs], vs_vertex_list);
152:       for (v = 0; v < num_vertex_in_set; ++v) {
153:         DMPlexSetLabelValue(*dm, "Vertex Sets", vs_vertex_list[v]+numCells-1, vs_id[vs]);
154:       }
155:       PetscFree(vs_vertex_list);
156:     }
157:     PetscFree(vs_id);
158:   }
159:   /* Read coordinates */
160:   DMPlexGetCoordinateSection(*dm, &coordSection);
161:   PetscSectionSetNumFields(coordSection, 1);
162:   PetscSectionSetFieldComponents(coordSection, 0, dim);
163:   PetscSectionSetChart(coordSection, numCells, numCells + numVertices);
164:   for (v = numCells; v < numCells+numVertices; ++v) {
165:     PetscSectionSetDof(coordSection, v, dim);
166:     PetscSectionSetFieldDof(coordSection, v, 0, dim);
167:   }
168:   PetscSectionSetUp(coordSection);
169:   PetscSectionGetStorageSize(coordSection, &coordSize);
170:   VecCreate(comm, &coordinates);
171:   PetscObjectSetName((PetscObject) coordinates, "coordinates");
172:   VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);
173:   VecSetFromOptions(coordinates);
174:   VecGetArray(coordinates, &coords);
175:   if (!rank) {
176:     float *x, *y, *z;

178:     PetscMalloc3(numVertices,float,&x,numVertices,float,&y,numVertices,float,&z);
179:     ex_get_coord(exoid, x, y, z);
180:     if (dim > 0) {
181:       for (v = 0; v < numVertices; ++v) coords[v*dim+0] = x[v];
182:     }
183:     if (dim > 1) {
184:       for (v = 0; v < numVertices; ++v) coords[v*dim+1] = y[v];
185:     }
186:     if (dim > 2) {
187:       for (v = 0; v < numVertices; ++v) coords[v*dim+2] = z[v];
188:     }
189:     PetscFree3(x,y,z);
190:   }
191:   VecRestoreArray(coordinates, &coords);
192:   DMSetCoordinatesLocal(*dm, coordinates);
193:   VecDestroy(&coordinates);

195:   /* Create side set label */
196:   if (!rank && interpolate && (num_fs > 0)) {
197:     int fs, f, voff;
198:     /* Read from ex_get_side_set_ids() */
199:     int *fs_id;
200:     /* Read from ex_get_side_set_param() */
201:     int num_side_in_set, num_dist_fact_in_set;
202:     /* Read from ex_get_side_set_node_list() */
203:     int *fs_vertex_count_list, *fs_vertex_list;

205:     /* Get side set ids */
206:     PetscMalloc(num_fs * sizeof(int), &fs_id);
207:     ex_get_side_set_ids(exoid, fs_id);
208:     for (fs = 0; fs < num_fs; ++fs) {
209:       ex_get_side_set_param(exoid, fs_id[fs], &num_side_in_set, &num_dist_fact_in_set);
210:       PetscMalloc2(num_side_in_set,int,&fs_vertex_count_list,num_side_in_set*4,int,&fs_vertex_list);
211:       ex_get_side_set_node_list(exoid, fs_id[fs], fs_vertex_count_list, fs_vertex_list);
212:       for (f = 0, voff = 0; f < num_side_in_set; ++f) {
213:         const PetscInt *faces   = NULL;
214:         PetscInt       faceSize = fs_vertex_count_list[f], numFaces;
215:         PetscInt       faceVertices[4], v;

217:         if (faceSize > 4) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "ExodusII side cannot have %d > 4 vertices", faceSize);
218:         for (v = 0; v < faceSize; ++v, ++voff) {
219:           faceVertices[v] = fs_vertex_list[voff]+numCells-1;
220:         }
221:         DMPlexGetFullJoin(*dm, faceSize, faceVertices, &numFaces, &faces);
222:         if (numFaces != 1) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Invalid ExodusII side %d in set %d maps to %d faces", f, fs, numFaces);
223:         DMPlexSetLabelValue(*dm, "Face Sets", faces[0], fs_id[fs]);
224:         DMPlexRestoreJoin(*dm, faceSize, faceVertices, &numFaces, &faces);
225:       }
226:       PetscFree2(fs_vertex_count_list,fs_vertex_list);
227:     }
228:     PetscFree(fs_id);
229:   }
230: #else
231:   SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii");
232: #endif
233:   return(0);
234: }