1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 4 #if defined(PETSC_HAVE_EXODUSII) 5 #include <netcdf.h> 6 #include <exodusII.h> 7 #endif 8 9 /*@C 10 DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file. 11 12 Collective on comm 13 14 Input Parameters: 15 + comm - The MPI communicator 16 . filename - The name of the ExodusII file 17 - interpolate - Create faces and edges in the mesh 18 19 Output Parameter: 20 . dm - The DM object representing the mesh 21 22 Level: beginner 23 24 .keywords: mesh,ExodusII 25 .seealso: DMPLEX, DMCreate(), DMPlexCreateExodus() 26 @*/ 27 PetscErrorCode DMPlexCreateExodusFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 28 { 29 PetscMPIInt rank; 30 PetscErrorCode ierr; 31 #if defined(PETSC_HAVE_EXODUSII) 32 int CPU_word_size = 0, IO_word_size = 0, exoid = -1; 33 float version; 34 #endif 35 36 PetscFunctionBegin; 37 PetscValidCharPointer(filename, 2); 38 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 39 #if defined(PETSC_HAVE_EXODUSII) 40 if (!rank) { 41 exoid = ex_open(filename, EX_READ, &CPU_word_size, &IO_word_size, &version); 42 if (exoid <= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open(\"%s\",...) did not return a valid file ID", filename); 43 } 44 ierr = DMPlexCreateExodus(comm, exoid, interpolate, dm);CHKERRQ(ierr); 45 if (!rank) {ierr = ex_close(exoid);CHKERRQ(ierr);} 46 #else 47 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 48 #endif 49 PetscFunctionReturn(0); 50 } 51 52 /*@ 53 DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file ID. 54 55 Collective on comm 56 57 Input Parameters: 58 + comm - The MPI communicator 59 . exoid - The ExodusII id associated with a exodus file and obtained using ex_open 60 - interpolate - Create faces and edges in the mesh 61 62 Output Parameter: 63 . dm - The DM object representing the mesh 64 65 Level: beginner 66 67 .keywords: mesh,ExodusII 68 .seealso: DMPLEX, DMCreate() 69 @*/ 70 PetscErrorCode DMPlexCreateExodus(MPI_Comm comm, PetscInt exoid, PetscBool interpolate, DM *dm) 71 { 72 #if defined(PETSC_HAVE_EXODUSII) 73 PetscMPIInt num_proc, rank; 74 PetscSection coordSection; 75 Vec coordinates; 76 PetscScalar *coords; 77 PetscInt coordSize, v; 78 PetscErrorCode ierr; 79 /* Read from ex_get_init() */ 80 char title[PETSC_MAX_PATH_LEN+1]; 81 int dim = 0, numVertices = 0, numCells = 0; 82 int num_cs = 0, num_vs = 0, num_fs = 0; 83 #endif 84 85 PetscFunctionBegin; 86 #if defined(PETSC_HAVE_EXODUSII) 87 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 88 ierr = MPI_Comm_size(comm, &num_proc);CHKERRQ(ierr); 89 ierr = DMCreate(comm, dm);CHKERRQ(ierr); 90 ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr); 91 /* Open EXODUS II file and read basic informations on rank 0, then broadcast to all processors */ 92 if (!rank) { 93 ierr = PetscMemzero(title,(PETSC_MAX_PATH_LEN+1)*sizeof(char));CHKERRQ(ierr); 94 ierr = ex_get_init(exoid, title, &dim, &numVertices, &numCells, &num_cs, &num_vs, &num_fs); 95 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"ExodusII ex_get_init() failed with error code %D\n",ierr); 96 if (!num_cs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Exodus file does not contain any cell set\n"); 97 } 98 ierr = MPI_Bcast(title, PETSC_MAX_PATH_LEN+1, MPI_CHAR, 0, comm);CHKERRQ(ierr); 99 ierr = MPI_Bcast(&dim, 1, MPI_INT, 0, comm);CHKERRQ(ierr); 100 ierr = PetscObjectSetName((PetscObject) *dm, title);CHKERRQ(ierr); 101 ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr); 102 ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr); 103 104 /* Read cell sets information */ 105 if (!rank) { 106 PetscInt *cone; 107 int c, cs, c_loc, v, v_loc; 108 /* Read from ex_get_elem_blk_ids() */ 109 int *cs_id; 110 /* Read from ex_get_elem_block() */ 111 char buffer[PETSC_MAX_PATH_LEN+1]; 112 int num_cell_in_set, num_vertex_per_cell, num_attr; 113 /* Read from ex_get_elem_conn() */ 114 int *cs_connect; 115 116 /* Get cell sets IDs */ 117 ierr = PetscMalloc1(num_cs, &cs_id);CHKERRQ(ierr); 118 ierr = ex_get_ids (exoid, EX_ELEM_BLOCK, cs_id);CHKERRQ(ierr); 119 /* Read the cell set connectivity table and build mesh topology 120 EXO standard requires that cells in cell sets be numbered sequentially and be pairwise disjoint. */ 121 /* First set sizes */ 122 for (cs = 0, c = 0; cs < num_cs; cs++) { 123 ierr = ex_get_block(exoid, EX_ELEM_BLOCK, cs_id[cs], buffer, &num_cell_in_set,&num_vertex_per_cell, 0, 0, &num_attr);CHKERRQ(ierr); 124 for (c_loc = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 125 ierr = DMPlexSetConeSize(*dm, c, num_vertex_per_cell);CHKERRQ(ierr); 126 } 127 } 128 ierr = DMSetUp(*dm);CHKERRQ(ierr); 129 for (cs = 0, c = 0; cs < num_cs; cs++) { 130 ierr = ex_get_block(exoid, EX_ELEM_BLOCK, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, 0, 0, &num_attr);CHKERRQ(ierr); 131 ierr = PetscMalloc2(num_vertex_per_cell*num_cell_in_set,&cs_connect,num_vertex_per_cell,&cone);CHKERRQ(ierr); 132 ierr = ex_get_conn (exoid, EX_ELEM_BLOCK, cs_id[cs], cs_connect,NULL,NULL);CHKERRQ(ierr); 133 /* EXO uses Fortran-based indexing, sieve uses C-style and numbers cell first then vertices. */ 134 for (c_loc = 0, v = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 135 for (v_loc = 0; v_loc < num_vertex_per_cell; ++v_loc, ++v) { 136 cone[v_loc] = cs_connect[v]+numCells-1; 137 } 138 if (dim == 3) { 139 /* Tetrahedra are inverted */ 140 if (num_vertex_per_cell == 4) { 141 PetscInt tmp = cone[0]; 142 cone[0] = cone[1]; 143 cone[1] = tmp; 144 } 145 /* Hexahedra are inverted */ 146 if (num_vertex_per_cell == 8) { 147 PetscInt tmp = cone[1]; 148 cone[1] = cone[3]; 149 cone[3] = tmp; 150 } 151 } 152 ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr); 153 ierr = DMSetLabelValue(*dm, "Cell Sets", c, cs_id[cs]);CHKERRQ(ierr); 154 } 155 ierr = PetscFree2(cs_connect,cone);CHKERRQ(ierr); 156 } 157 ierr = PetscFree(cs_id);CHKERRQ(ierr); 158 } 159 ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr); 160 ierr = DMPlexStratify(*dm);CHKERRQ(ierr); 161 if (interpolate) { 162 DM idm = NULL; 163 164 ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr); 165 /* Maintain Cell Sets label */ 166 { 167 DMLabel label; 168 169 ierr = DMRemoveLabel(*dm, "Cell Sets", &label);CHKERRQ(ierr); 170 if (label) {ierr = DMAddLabel(idm, label);CHKERRQ(ierr);} 171 } 172 ierr = DMDestroy(dm);CHKERRQ(ierr); 173 *dm = idm; 174 } 175 176 /* Create vertex set label */ 177 if (!rank && (num_vs > 0)) { 178 int vs, v; 179 /* Read from ex_get_node_set_ids() */ 180 int *vs_id; 181 /* Read from ex_get_node_set_param() */ 182 int num_vertex_in_set; 183 /* Read from ex_get_node_set() */ 184 int *vs_vertex_list; 185 186 /* Get vertex set ids */ 187 ierr = PetscMalloc1(num_vs, &vs_id);CHKERRQ(ierr); 188 ierr = ex_get_ids(exoid, EX_NODE_SET, vs_id);CHKERRQ(ierr); 189 for (vs = 0; vs < num_vs; ++vs) { 190 ierr = ex_get_set_param(exoid, EX_NODE_SET, vs_id[vs], &num_vertex_in_set, NULL); 191 ierr = PetscMalloc1(num_vertex_in_set, &vs_vertex_list);CHKERRQ(ierr); 192 ierr = ex_get_set(exoid, EX_NODE_SET, vs_id[vs], vs_vertex_list, NULL);CHKERRQ(ierr); 193 for (v = 0; v < num_vertex_in_set; ++v) { 194 ierr = DMSetLabelValue(*dm, "Vertex Sets", vs_vertex_list[v]+numCells-1, vs_id[vs]);CHKERRQ(ierr); 195 } 196 ierr = PetscFree(vs_vertex_list);CHKERRQ(ierr); 197 } 198 ierr = PetscFree(vs_id);CHKERRQ(ierr); 199 } 200 /* Read coordinates */ 201 ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr); 202 ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr); 203 ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr); 204 ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr); 205 for (v = numCells; v < numCells+numVertices; ++v) { 206 ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr); 207 ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr); 208 } 209 ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr); 210 ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr); 211 ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr); 212 ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr); 213 ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr); 214 ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr); 215 ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr); 216 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 217 if (!rank) { 218 float *x, *y, *z; 219 220 ierr = PetscMalloc3(numVertices,&x,numVertices,&y,numVertices,&z);CHKERRQ(ierr); 221 ierr = ex_get_coord(exoid, x, y, z);CHKERRQ(ierr); 222 if (dim > 0) { 223 for (v = 0; v < numVertices; ++v) coords[v*dim+0] = x[v]; 224 } 225 if (dim > 1) { 226 for (v = 0; v < numVertices; ++v) coords[v*dim+1] = y[v]; 227 } 228 if (dim > 2) { 229 for (v = 0; v < numVertices; ++v) coords[v*dim+2] = z[v]; 230 } 231 ierr = PetscFree3(x,y,z);CHKERRQ(ierr); 232 } 233 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 234 ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr); 235 ierr = VecDestroy(&coordinates);CHKERRQ(ierr); 236 237 /* Create side set label */ 238 if (!rank && interpolate && (num_fs > 0)) { 239 int fs, f, voff; 240 /* Read from ex_get_side_set_ids() */ 241 int *fs_id; 242 /* Read from ex_get_side_set_param() */ 243 int num_side_in_set; 244 /* Read from ex_get_side_set_node_list() */ 245 int *fs_vertex_count_list, *fs_vertex_list; 246 /* Read side set labels */ 247 char fs_name[MAX_STR_LENGTH+1]; 248 249 /* Get side set ids */ 250 ierr = PetscMalloc1(num_fs, &fs_id);CHKERRQ(ierr); 251 ierr = ex_get_ids(exoid, EX_SIDE_SET, fs_id);CHKERRQ(ierr); 252 for (fs = 0; fs < num_fs; ++fs) { 253 ierr = ex_get_set_param(exoid, EX_SIDE_SET, fs_id[fs], &num_side_in_set, NULL);CHKERRQ(ierr); 254 ierr = PetscMalloc2(num_side_in_set,&fs_vertex_count_list,num_side_in_set*4,&fs_vertex_list);CHKERRQ(ierr); 255 ierr = ex_get_side_set_node_list(exoid, fs_id[fs], fs_vertex_count_list, fs_vertex_list);CHKERRQ(ierr); 256 /* Get the specific name associated with this side set ID. */ 257 int fs_name_err = ex_get_name(exoid, EX_SIDE_SET, fs_id[fs], fs_name); 258 for (f = 0, voff = 0; f < num_side_in_set; ++f) { 259 const PetscInt *faces = NULL; 260 PetscInt faceSize = fs_vertex_count_list[f], numFaces; 261 PetscInt faceVertices[4], v; 262 263 if (faceSize > 4) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "ExodusII side cannot have %d > 4 vertices", faceSize); 264 for (v = 0; v < faceSize; ++v, ++voff) { 265 faceVertices[v] = fs_vertex_list[voff]+numCells-1; 266 } 267 ierr = DMPlexGetFullJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 268 if (numFaces != 1) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Invalid ExodusII side %d in set %d maps to %d faces", f, fs, numFaces); 269 ierr = DMSetLabelValue(*dm, "Face Sets", faces[0], fs_id[fs]);CHKERRQ(ierr); 270 /* Only add the label if one has been detected for this side set. */ 271 if (!fs_name_err) { 272 ierr = DMSetLabelValue(*dm, fs_name, faces[0], fs_id[fs]);CHKERRQ(ierr); 273 } 274 ierr = DMPlexRestoreJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 275 } 276 ierr = PetscFree2(fs_vertex_count_list,fs_vertex_list);CHKERRQ(ierr); 277 } 278 ierr = PetscFree(fs_id);CHKERRQ(ierr); 279 } 280 #else 281 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 282 #endif 283 PetscFunctionReturn(0); 284 } 285