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 #if defined(PETSC_HAVE_EXODUSII) 10 /* 11 EXOGetVarIndex - Locate a result in an exodus file based on its name 12 13 Not collective 14 15 Input Parameters: 16 + exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 17 . obj_type - the type of entity for instance EX_NODAL, EX_ELEM_BLOCK 18 - name - the name of the result 19 20 Output Parameters: 21 . varIndex - the location in the exodus file of the result 22 23 Notes: 24 The exodus variable index is obtained by comparing name and the 25 names of zonal variables declared in the exodus file. For instance if name is "V" 26 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 27 amongst all variables of type obj_type. 28 29 Level: beginner 30 31 .keywords: mesh,ExodusII 32 .seealso: EXOGetVarIndex(),DMView_Exodus(),VecViewPlex_ExodusII_Nodal_Internal(),VecLoadNodal_PlexEXO(),VecLoadZonal_PlexEXO() 33 */ 34 static PetscErrorCode EXOGetVarIndex_Private(int exoid, ex_entity_type obj_type, const char name[], int *varIndex) 35 { 36 int exoerr, num_vars, i, j; 37 char ext_name[MAX_STR_LENGTH+1], var_name[MAX_STR_LENGTH+1]; 38 const int num_suffix = 5; 39 char *suffix[5]; 40 PetscBool flg; 41 PetscErrorCode ierr; 42 43 PetscFunctionBegin; 44 suffix[0] = (char *) ""; 45 suffix[1] = (char *) "_X"; 46 suffix[2] = (char *) "_XX"; 47 suffix[3] = (char *) "_1"; 48 suffix[4] = (char *) "_11"; 49 50 *varIndex = 0; 51 exoerr = ex_get_variable_param(exoid, obj_type, &num_vars); 52 for (i = 0; i < num_vars; ++i) { 53 exoerr = ex_get_variable_name(exoid, obj_type, i+1, var_name); 54 for (j = 0; j < num_suffix; ++j){ 55 ierr = PetscStrncpy(ext_name, name, MAX_STR_LENGTH);CHKERRQ(ierr); 56 ierr = PetscStrncat(ext_name, suffix[j], MAX_STR_LENGTH);CHKERRQ(ierr); 57 ierr = PetscStrcasecmp(ext_name, var_name, &flg); 58 if (flg) { 59 *varIndex = i+1; 60 PetscFunctionReturn(0); 61 } 62 } 63 } 64 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to locate variable %s in ExodusII file.", name); 65 PetscFunctionReturn(-1); 66 } 67 68 /* 69 DMPlexView_ExodusII_Internal - Write a DM to disk in exodus format 70 71 Collective on dm 72 73 Input Parameters: 74 + dm - The dm to be written 75 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 76 - degree - the degree of the interpolation space 77 78 Notes: 79 Not all DM can be written to disk this way. For instance, exodus assume that element blocks (mapped to "Cell sets" labels) 80 consists of sequentially numbered cells. If this is not the case, the exodus file will be corrupted. 81 82 If the dm has been distributed and exoid points to different files on each MPI rank, only the "local" part of the DM 83 (including "ghost" cells and vertices) will be written. If all exoid points to the same file, the resulting file will 84 probably be corrupted. 85 86 DMPlex only represents geometry while most post-processing software expect that a mesh also provides information 87 on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2. 88 It should be extended to use PetscFE objects. 89 90 This function will only handle TRI, TET, QUAD and HEX cells. 91 Level: beginner 92 93 .keywords: mesh, ExodusII 94 .seealso: EXOGetVarIndex_Private(), VecViewPlex_ExodusII_Nodal_Internal(), VecLoadNodal_PlexEXO(), VecViewZonal_PlexEXO(), VecLoadZonal_PlexEXO() 95 */ 96 PetscErrorCode DMPlexView_ExodusII_Internal(DM dm, int exoid, PetscInt degree) 97 { 98 enum ElemType {TRI, QUAD, TET, HEX}; 99 MPI_Comm comm; 100 /* Connectivity Variables */ 101 PetscInt cellsNotInConnectivity; 102 /* Cell Sets */ 103 DMLabel csLabel; 104 IS csIS; 105 const PetscInt *csIdx; 106 PetscInt num_cs, cs; 107 enum ElemType *type; 108 /* Coordinate Variables */ 109 DM cdm; 110 PetscSection section; 111 Vec coord; 112 PetscInt **nodes; 113 PetscInt depth, d, dim, skipCells = 0; 114 PetscInt pStart, pEnd, p, cStart, cEnd, numCells, vStart, vEnd, numVertices, eStart, eEnd, numEdges, fStart, fEnd, numFaces, numNodes; 115 PetscInt num_vs, num_fs; 116 PetscMPIInt rank, size; 117 const char *dmName; 118 PetscErrorCode ierr; 119 120 PetscFunctionBegin; 121 ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr); 122 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 123 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 124 /* --- Get DM info --- */ 125 ierr = PetscObjectGetName((PetscObject) dm, &dmName);CHKERRQ(ierr); 126 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 127 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 128 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 129 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 130 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 131 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr); 132 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 133 numCells = cEnd - cStart; 134 numEdges = eEnd - eStart; 135 numVertices = vEnd - vStart; 136 if (depth == 3) {numFaces = fEnd - fStart;} 137 else {numFaces = 0;} 138 ierr = DMGetLabelSize(dm, "Cell Sets", &num_cs);CHKERRQ(ierr); 139 ierr = DMGetLabelSize(dm, "Vertex Sets", &num_vs);CHKERRQ(ierr); 140 ierr = DMGetLabelSize(dm, "Face Sets", &num_fs);CHKERRQ(ierr); 141 ierr = DMGetCoordinatesLocal(dm, &coord);CHKERRQ(ierr); 142 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 143 if (num_cs > 0) { 144 ierr = DMGetLabel(dm, "Cell Sets", &csLabel);CHKERRQ(ierr); 145 ierr = DMLabelGetValueIS(csLabel, &csIS);CHKERRQ(ierr); 146 ierr = ISGetIndices(csIS, &csIdx);CHKERRQ(ierr); 147 } 148 ierr = PetscMalloc1(num_cs, &nodes);CHKERRQ(ierr); 149 /* Set element type for each block and compute total number of nodes */ 150 ierr = PetscMalloc1(num_cs, &type);CHKERRQ(ierr); 151 numNodes = numVertices; 152 if (degree == 2) {numNodes += numEdges;} 153 cellsNotInConnectivity = numCells; 154 for (cs = 0; cs < num_cs; ++cs) { 155 IS stratumIS; 156 const PetscInt *cells; 157 PetscScalar *xyz = NULL; 158 PetscInt csSize, closureSize; 159 PetscInt nodesTriP1[4] = {3,0,0,0}; 160 PetscInt nodesTriP2[4] = {3,3,0,0}; 161 PetscInt nodesQuadP1[4] = {4,0,0,0}; 162 PetscInt nodesQuadP2[4] = {4,4,0,1}; 163 PetscInt nodesTetP1[4] = {4,0,0,0}; 164 PetscInt nodesTetP2[4] = {4,6,0,0}; 165 PetscInt nodesHexP1[4] = {8,0,0,0}; 166 PetscInt nodesHexP2[4] = {8,12,6,1}; 167 168 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 169 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 170 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 171 ierr = DMPlexVecGetClosure(cdm, NULL, coord, cells[0], &closureSize, &xyz);CHKERRQ(ierr); 172 switch (dim) { 173 case 2: 174 if (closureSize == 3*dim) {type[cs] = TRI;} 175 else if (closureSize == 4*dim) {type[cs] = QUAD;} 176 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices %D in dimension %D has no ExodusII type", closureSize/dim, dim); 177 break; 178 case 3: 179 if (closureSize == 4*dim) {type[cs] = TET;} 180 else if (closureSize == 8*dim) {type[cs] = HEX;} 181 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices %D in dimension %D has no ExodusII type", closureSize/dim, dim); 182 break; 183 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not handled by ExodusII viewer", dim); 184 } 185 if ((degree == 2) && (type[cs] == QUAD)) {numNodes += csSize;} 186 if ((degree == 2) && (type[cs] == HEX)) {numNodes += csSize; numNodes += numFaces;} 187 ierr = DMPlexVecRestoreClosure(cdm, NULL, coord, cells[0], &closureSize, &xyz);CHKERRQ(ierr); 188 /* Set nodes and Element type */ 189 if (type[cs] == TRI) { 190 if (degree == 1) nodes[cs] = nodesTriP1; 191 else if (degree == 2) nodes[cs] = nodesTriP2; 192 } else if (type[cs] == QUAD) { 193 if (degree == 1) nodes[cs] = nodesQuadP1; 194 else if (degree == 2) nodes[cs] = nodesQuadP2; 195 } else if (type[cs] == TET) { 196 if (degree == 1) nodes[cs] = nodesTetP1; 197 else if (degree == 2) nodes[cs] = nodesTetP2; 198 } else if (type[cs] == HEX) { 199 if (degree == 1) nodes[cs] = nodesHexP1; 200 else if (degree == 2) nodes[cs] = nodesHexP2; 201 } 202 /* Compute the number of cells not in the connectivity table */ 203 cellsNotInConnectivity -= nodes[cs][3]*csSize; 204 205 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 206 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 207 } 208 if (num_cs > 0) {ierr = ex_put_init(exoid, dmName, dim, numNodes, numCells, num_cs, num_vs, num_fs);CHKERRQ(ierr);} 209 /* --- Connectivity --- */ 210 for (cs = 0; cs < num_cs; ++cs) { 211 IS stratumIS; 212 const PetscInt *cells; 213 PetscInt *connect; 214 PetscInt edgesInClosure = 0, facesInClosure = 0, verticesInClosure = 0; 215 PetscInt csSize, c, connectSize, closureSize; 216 char *elem_type = NULL; 217 char elem_type_tri3[] = "TRI3", elem_type_quad4[] = "QUAD4"; 218 char elem_type_tri6[] = "TRI6", elem_type_quad9[] = "QUAD9"; 219 char elem_type_tet4[] = "TET4", elem_type_hex8[] = "HEX8"; 220 char elem_type_tet10[] = "TET10", elem_type_hex27[] = "HEX27"; 221 222 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 223 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 224 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 225 /* Set Element type */ 226 if (type[cs] == TRI) { 227 if (degree == 1) elem_type = elem_type_tri3; 228 else if (degree == 2) elem_type = elem_type_tri6; 229 } else if (type[cs] == QUAD) { 230 if (degree == 1) elem_type = elem_type_quad4; 231 else if (degree == 2) elem_type = elem_type_quad9; 232 } else if (type[cs] == TET) { 233 if (degree == 1) elem_type = elem_type_tet4; 234 else if (degree == 2) elem_type = elem_type_tet10; 235 } else if (type[cs] == HEX) { 236 if (degree == 1) elem_type = elem_type_hex8; 237 else if (degree == 2) elem_type = elem_type_hex27; 238 } 239 connectSize = nodes[cs][0] + nodes[cs][1] + nodes[cs][2] + nodes[cs][3]; 240 ierr = PetscMalloc1(connectSize, &connect);CHKERRQ(ierr); 241 ierr = ex_put_block(exoid, EX_ELEM_BLOCK, cs, elem_type, csSize, connectSize, 0, 0, 1); 242 /* Find number of vertices, edges, and faces in the closure */ 243 verticesInClosure = nodes[cs][0]; 244 if (depth > 1) { 245 if (dim == 2) { 246 ierr = DMPlexGetConeSize(dm, cells[0], &edgesInClosure);CHKERRQ(ierr); 247 } else if (dim == 3) { 248 PetscInt *closure = NULL; 249 250 ierr = DMPlexGetConeSize(dm, cells[0], &facesInClosure);CHKERRQ(ierr); 251 ierr = DMPlexGetTransitiveClosure(dm, cells[0], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 252 edgesInClosure = closureSize - facesInClosure - 1 - verticesInClosure; 253 ierr = DMPlexRestoreTransitiveClosure(dm, cells[0], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 254 } 255 } 256 /* Get connectivity for each cell */ 257 for (c = 0; c < csSize; ++c) { 258 PetscInt *closure = NULL; 259 PetscInt temp, i; 260 261 ierr = DMPlexGetTransitiveClosure(dm, cells[c], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 262 for (i = 0; i < connectSize; ++i) { 263 if (i < nodes[cs][0]) {/* Vertices */ 264 connect[i] = closure[(i+edgesInClosure+facesInClosure+1)*2] + 1; 265 connect[i] -= cellsNotInConnectivity; 266 } else if (i < nodes[cs][0]+nodes[cs][1]) { /* Edges */ 267 connect[i] = closure[(i-verticesInClosure+facesInClosure+1)*2] + 1; 268 if (nodes[cs][2] == 0) connect[i] -= numFaces; 269 connect[i] -= cellsNotInConnectivity; 270 } else if (i < nodes[cs][0]+nodes[cs][1]+nodes[cs][3]){ /* Cells */ 271 connect[i] = closure[0] + 1; 272 connect[i] -= skipCells; 273 } else if (i < nodes[cs][0]+nodes[cs][1]+nodes[cs][3]+nodes[cs][2]){ /* Faces */ 274 connect[i] = closure[(i-edgesInClosure-verticesInClosure)*2] + 1; 275 connect[i] -= cellsNotInConnectivity; 276 } else { 277 connect[i] = -1; 278 } 279 } 280 /* Tetrahedra are inverted */ 281 if (type[cs] == TET) { 282 temp = connect[0]; connect[0] = connect[1]; connect[1] = temp; 283 if (degree == 2) { 284 temp = connect[5]; connect[5] = connect[6]; connect[6] = temp; 285 temp = connect[7]; connect[7] = connect[8]; connect[8] = temp; 286 } 287 } 288 /* Hexahedra are inverted */ 289 if (type[cs] == HEX) { 290 temp = connect[1]; connect[1] = connect[3]; connect[3] = temp; 291 if (degree == 2) { 292 temp = connect[8]; connect[8] = connect[11]; connect[11] = temp; 293 temp = connect[9]; connect[9] = connect[10]; connect[10] = temp; 294 temp = connect[16]; connect[16] = connect[17]; connect[17] = temp; 295 temp = connect[18]; connect[18] = connect[19]; connect[19] = temp; 296 297 temp = connect[12]; connect[12] = connect[16]; connect[16] = temp; 298 temp = connect[13]; connect[13] = connect[17]; connect[17] = temp; 299 temp = connect[14]; connect[14] = connect[18]; connect[18] = temp; 300 temp = connect[15]; connect[15] = connect[19]; connect[19] = temp; 301 302 temp = connect[23]; connect[23] = connect[26]; connect[26] = temp; 303 temp = connect[24]; connect[24] = connect[25]; connect[25] = temp; 304 temp = connect[25]; connect[25] = connect[26]; connect[26] = temp; 305 } 306 } 307 ierr = ex_put_partial_conn(exoid, EX_ELEM_BLOCK, cs, c+1, 1, connect, NULL, NULL); 308 ierr = DMPlexRestoreTransitiveClosure(dm, cells[c], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 309 } 310 skipCells += (nodes[cs][3] == 0)*csSize; 311 ierr = PetscFree(connect);CHKERRQ(ierr); 312 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 313 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 314 } 315 ierr = PetscFree(type);CHKERRQ(ierr); 316 /* --- Coordinates --- */ 317 ierr = PetscSectionCreate(comm, §ion);CHKERRQ(ierr); 318 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 319 for (d = 0; d < depth; ++d) { 320 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 321 for (p = pStart; p < pEnd; ++p) { 322 ierr = PetscSectionSetDof(section, p, nodes[0][d] > 0);CHKERRQ(ierr); 323 } 324 } 325 for (cs = 0; cs < num_cs; ++cs) { 326 IS stratumIS; 327 const PetscInt *cells; 328 PetscInt csSize, c; 329 330 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 331 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 332 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 333 for (c = 0; c < csSize; ++c) { 334 ierr = PetscSectionSetDof(section, cells[c], nodes[cs][3] > 0);CHKERRQ(ierr); 335 } 336 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 337 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 338 } 339 if (num_cs > 0) { 340 ierr = ISRestoreIndices(csIS, &csIdx);CHKERRQ(ierr); 341 ierr = ISDestroy(&csIS);CHKERRQ(ierr); 342 } 343 ierr = PetscFree(nodes);CHKERRQ(ierr); 344 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 345 if (numNodes > 0) { 346 const char *coordNames[3] = {"x", "y", "z"}; 347 PetscScalar *coords, *closure; 348 PetscReal *cval; 349 PetscInt hasDof, n = 0; 350 351 /* There can't be more than 24 values in the closure of a point for the coord section */ 352 ierr = PetscMalloc3(numNodes*3, &coords, dim, &cval, 24, &closure);CHKERRQ(ierr); 353 ierr = DMGetCoordinatesLocal(dm, &coord);CHKERRQ(ierr); 354 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 355 for (p = pStart; p < pEnd; ++p) { 356 ierr = PetscSectionGetDof(section, p, &hasDof); 357 if (hasDof) { 358 PetscInt closureSize = 24, j; 359 360 ierr = DMPlexVecGetClosure(cdm, NULL, coord, p, &closureSize, &closure);CHKERRQ(ierr); 361 for (d = 0; d < dim; ++d) { 362 cval[d] = 0.0; 363 for (j = 0; j < closureSize/dim; j++) cval[d] += closure[j*dim+d]; 364 coords[d*numNodes+n] = cval[d] * dim / closureSize; 365 } 366 ++n; 367 } 368 } 369 ierr = ex_put_coord(exoid, &coords[0*numNodes], &coords[1*numNodes], &coords[2*numNodes]);CHKERRQ(ierr); 370 ierr = PetscFree3(coords, cval, closure);CHKERRQ(ierr); 371 ierr = ex_put_coord_names(exoid, (char **) coordNames);CHKERRQ(ierr); 372 } 373 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 374 PetscFunctionReturn(0); 375 } 376 377 /* 378 VecViewPlex_ExodusII_Nodal_Internal - Write a Vec corresponding to a nodal field to an exodus file 379 380 Collective on v 381 382 Input Parameters: 383 + v - The vector to be written 384 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 385 - step - the time step to write at (exodus steps are numbered starting from 1) 386 387 Notes: 388 The exodus result nodal variable index is obtained by comparing the Vec name and the 389 names of nodal variables declared in the exodus file. For instance for a Vec named "V" 390 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 391 amongst all nodal variables. 392 393 Level: beginner 394 395 .keywords: mesh,ExodusII 396 .seealso: EXOGetVarIndex_Private(),DMPlexView_ExodusII_Internal(),VecLoadNodal_PlexEXO(),VecViewZonal_PlexEXO(),VecLoadZonal_PlexEXO() 397 @*/ 398 PetscErrorCode VecViewPlex_ExodusII_Nodal_Internal(Vec v, int exoid, int step) 399 { 400 MPI_Comm comm; 401 PetscMPIInt size; 402 DM dm; 403 Vec vNatural, vComp; 404 const PetscReal *varray; 405 const char *vecname; 406 PetscInt xs, xe, bs; 407 PetscBool useNatural; 408 int offset; 409 PetscErrorCode ierr; 410 411 PetscFunctionBegin; 412 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 413 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 414 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 415 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 416 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 417 if (useNatural) { 418 ierr = DMGetGlobalVector(dm, &vNatural);CHKERRQ(ierr); 419 ierr = DMPlexGlobalToNaturalBegin(dm, v, vNatural);CHKERRQ(ierr); 420 ierr = DMPlexGlobalToNaturalEnd(dm, v, vNatural);CHKERRQ(ierr); 421 } else { 422 vNatural = v; 423 } 424 /* Get the location of the variable in the exodus file */ 425 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 426 ierr = EXOGetVarIndex_Private(exoid, EX_NODAL, vecname, &offset);CHKERRQ(ierr); 427 if (!offset) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Cannot locate nodal variable %s in exodus file\n", vecname); 428 /* Write local chunk of the result in the exodus file 429 exodus stores each component of a vector-valued field as a separate variable. 430 We assume that they are stored sequentially */ 431 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 432 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 433 if (bs == 1) { 434 ierr = VecGetArrayRead(vNatural, &varray);CHKERRQ(ierr); 435 ierr = ex_put_partial_var(exoid, step, EX_NODAL, offset, 1, xs+1, xe-xs, varray);CHKERRQ(ierr); 436 ierr = VecRestoreArrayRead(vNatural, &varray);CHKERRQ(ierr); 437 } else { 438 IS compIS; 439 PetscInt c; 440 441 ierr = ISCreateStride(PETSC_COMM_SELF, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr); 442 for (c = 0; c < bs; ++c) { 443 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 444 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 445 ierr = VecGetArrayRead(vComp, &varray);CHKERRQ(ierr); 446 ierr = ex_put_partial_var(exoid, step, EX_NODAL, offset+c, 1, xs/bs+1, (xe-xs)/bs, varray);CHKERRQ(ierr); 447 ierr = VecRestoreArrayRead(vComp, &varray);CHKERRQ(ierr); 448 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 449 } 450 ierr = ISDestroy(&compIS);CHKERRQ(ierr); 451 } 452 if (useNatural) {ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr);} 453 PetscFunctionReturn(0); 454 } 455 456 /* 457 VecLoadPlex_ExodusII_Nodal_Internal - Read a Vec corresponding to a nodal field from an exodus file 458 459 Collective on v 460 461 Input Parameters: 462 + v - The vector to be written 463 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 464 - step - the time step to read at (exodus steps are numbered starting from 1) 465 466 Notes: 467 The exodus result nodal variable index is obtained by comparing the Vec name and the 468 names of nodal variables declared in the exodus file. For instance for a Vec named "V" 469 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 470 amongst all nodal variables. 471 472 Level: beginner 473 474 .keywords: mesh, ExodusII 475 .seealso: EXOGetVarIndex_Private(), DMPlexView_ExodusII_Internal(), VecViewPlex_ExodusII_Nodal_Internal(), VecViewZonal_PlexEXO(), VecLoadZonal_PlexEXO() 476 */ 477 PetscErrorCode VecLoadPlex_ExodusII_Nodal_Internal(Vec v, int exoid, int step) 478 { 479 MPI_Comm comm; 480 PetscMPIInt size; 481 DM dm; 482 Vec vNatural, vComp; 483 PetscReal *varray; 484 const char *vecname; 485 PetscInt xs, xe, bs; 486 PetscBool useNatural; 487 int offset; 488 PetscErrorCode ierr; 489 490 PetscFunctionBegin; 491 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 492 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 493 ierr = VecGetDM(v,&dm);CHKERRQ(ierr); 494 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 495 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 496 if (useNatural) {ierr = DMGetGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 497 else {vNatural = v;} 498 /* Get the location of the variable in the exodus file */ 499 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 500 ierr = EXOGetVarIndex_Private(exoid, EX_NODAL, vecname, &offset);CHKERRQ(ierr); 501 if (!offset) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Cannot locate nodal variable %s in exodus file", vecname); 502 /* Read local chunk from the file */ 503 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 504 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 505 if (bs == 1) { 506 ierr = VecGetArray(vNatural, &varray);CHKERRQ(ierr); 507 ierr = ex_get_partial_var(exoid, step, EX_NODAL, offset, 1, xs+1, xe-xs, varray);CHKERRQ(ierr); 508 ierr = VecRestoreArray(vNatural, &varray);CHKERRQ(ierr); 509 } else { 510 IS compIS; 511 PetscInt c; 512 513 ierr = ISCreateStride(PETSC_COMM_SELF, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr); 514 for (c = 0; c < bs; ++c) { 515 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 516 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 517 ierr = VecGetArray(vComp, &varray);CHKERRQ(ierr); 518 ierr = ex_get_partial_var(exoid, step, EX_NODAL, offset+c, 1, xs/bs+1, (xe-xs)/bs, varray);CHKERRQ(ierr); 519 ierr = VecRestoreArray(vComp, &varray);CHKERRQ(ierr); 520 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 521 } 522 ierr = ISDestroy(&compIS);CHKERRQ(ierr); 523 } 524 if (useNatural) { 525 ierr = DMPlexNaturalToGlobalBegin(dm, vNatural, v);CHKERRQ(ierr); 526 ierr = DMPlexNaturalToGlobalEnd(dm, vNatural, v);CHKERRQ(ierr); 527 ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr); 528 } 529 PetscFunctionReturn(0); 530 } 531 532 /* 533 VecViewPlex_ExodusII_Zonal_Internal - Write a Vec corresponding to a zonal (cell based) field to an exodus file 534 535 Collective on v 536 537 Input Parameters: 538 + v - The vector to be written 539 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 540 - step - the time step to write at (exodus steps are numbered starting from 1) 541 542 Notes: 543 The exodus result zonal variable index is obtained by comparing the Vec name and the 544 names of zonal variables declared in the exodus file. For instance for a Vec named "V" 545 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 546 amongst all zonal variables. 547 548 Level: beginner 549 550 .keywords: mesh,ExodusII 551 .seealso: EXOGetVarIndex_Private(),DMPlexView_ExodusII_Internal(),VecViewPlex_ExodusII_Nodal_Internal(),VecLoadPlex_ExodusII_Nodal_Internal(),VecLoadPlex_ExodusII_Zonal_Internal() 552 */ 553 PetscErrorCode VecViewPlex_ExodusII_Zonal_Internal(Vec v, int exoid, int step) 554 { 555 MPI_Comm comm; 556 PetscMPIInt size; 557 DM dm; 558 Vec vNatural, vComp; 559 const PetscReal *varray; 560 const char *vecname; 561 PetscInt xs, xe, bs; 562 PetscBool useNatural; 563 int offset; 564 IS compIS; 565 PetscInt *csSize, *csID; 566 PetscInt numCS, set, csxs = 0; 567 PetscErrorCode ierr; 568 569 PetscFunctionBegin; 570 ierr = PetscObjectGetComm((PetscObject)v, &comm);CHKERRQ(ierr); 571 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 572 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 573 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 574 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 575 if (useNatural) { 576 ierr = DMGetGlobalVector(dm, &vNatural);CHKERRQ(ierr); 577 ierr = DMPlexGlobalToNaturalBegin(dm, v, vNatural);CHKERRQ(ierr); 578 ierr = DMPlexGlobalToNaturalEnd(dm, v, vNatural);CHKERRQ(ierr); 579 } else { 580 vNatural = v; 581 } 582 /* Get the location of the variable in the exodus file */ 583 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 584 ierr = EXOGetVarIndex_Private(exoid, EX_ELEM_BLOCK, vecname, &offset);CHKERRQ(ierr); 585 if (!offset) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Cannot locate zonal variable %s in exodus file\n", vecname); 586 /* Write local chunk of the result in the exodus file 587 exodus stores each component of a vector-valued field as a separate variable. 588 We assume that they are stored sequentially 589 Zonal variables are accessed one element block at a time, so we loop through the cell sets, 590 but once the vector has been reordered to natural size, we cannot use the label informations 591 to figure out what to save where. */ 592 numCS = ex_inquire_int(exoid, EX_INQ_ELEM_BLK); 593 ierr = PetscMalloc2(numCS, &csID, numCS, &csSize);CHKERRQ(ierr); 594 ierr = ex_get_ids(exoid, EX_ELEM_BLOCK, csID);CHKERRQ(ierr); 595 for (set = 0; set < numCS; ++set) { 596 ex_block block; 597 598 block.id = csID[set]; 599 block.type = EX_ELEM_BLOCK; 600 ierr = ex_get_block_param(exoid, &block);CHKERRQ(ierr); 601 csSize[set] = block.num_entry; 602 } 603 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 604 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 605 if (bs > 1) {ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr);} 606 for (set = 0; set < numCS; set++) { 607 PetscInt csLocalSize, c; 608 609 /* range of indices for set setID[set]: csxs:csxs + csSize[set]-1 610 local slice of zonal values: xs/bs,xm/bs-1 611 intersection: max(xs/bs,csxs),min(xm/bs-1,csxs + csSize[set]-1) */ 612 csLocalSize = PetscMax(0, PetscMin(xe/bs, csxs+csSize[set]) - PetscMax(xs/bs, csxs)); 613 if (bs == 1) { 614 ierr = VecGetArrayRead(vNatural, &varray);CHKERRQ(ierr); 615 ierr = ex_put_partial_var(exoid, step, EX_ELEM_BLOCK, offset, csID[set], PetscMax(xs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs)]);CHKERRQ(ierr); 616 ierr = VecRestoreArrayRead(vNatural, &varray);CHKERRQ(ierr); 617 } else { 618 for (c = 0; c < bs; ++c) { 619 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 620 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 621 ierr = VecGetArrayRead(vComp, &varray);CHKERRQ(ierr); 622 ierr = ex_put_partial_var(exoid, step, EX_ELEM_BLOCK, offset+c, csID[set], PetscMax(xs/bs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs/bs)]); 623 ierr = VecRestoreArrayRead(vComp, &varray);CHKERRQ(ierr); 624 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 625 } 626 } 627 csxs += csSize[set]; 628 } 629 ierr = PetscFree2(csID, csSize);CHKERRQ(ierr); 630 if (bs > 1) {ierr = ISDestroy(&compIS);CHKERRQ(ierr);} 631 if (useNatural) {ierr = DMRestoreGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 632 PetscFunctionReturn(0); 633 } 634 635 /* 636 VecLoadPlex_ExodusII_Zonal_Internal - Read a Vec corresponding to a zonal (cell based) field from an exodus file 637 638 Collective on v 639 640 Input Parameters: 641 + v - The vector to be written 642 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 643 - step - the time step to read at (exodus steps are numbered starting from 1) 644 645 Notes: 646 The exodus result zonal variable index is obtained by comparing the Vec name and the 647 names of zonal variables declared in the exodus file. For instance for a Vec named "V" 648 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 649 amongst all zonal variables. 650 651 Level: beginner 652 653 .keywords: mesh,ExodusII 654 .seealso: EXOGetVarIndex_Private(), DMPlexView_ExodusII_Internal(), VecViewPlex_ExodusII_Nodal_Internal(), VecLoadPlex_ExodusII_Nodal_Internal(), VecLoadPlex_ExodusII_Zonal_Internal() 655 */ 656 PetscErrorCode VecLoadPlex_ExodusII_Zonal_Internal(Vec v, int exoid, int step) 657 { 658 MPI_Comm comm; 659 PetscMPIInt size; 660 DM dm; 661 Vec vNatural, vComp; 662 PetscReal *varray; 663 const char *vecname; 664 PetscInt xs, xe, bs; 665 PetscBool useNatural; 666 int offset; 667 IS compIS; 668 PetscInt *csSize, *csID; 669 PetscInt numCS, set, csxs = 0; 670 PetscErrorCode ierr; 671 672 PetscFunctionBegin; 673 ierr = PetscObjectGetComm((PetscObject)v,&comm);CHKERRQ(ierr); 674 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 675 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 676 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 677 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 678 if (useNatural) {ierr = DMGetGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 679 else {vNatural = v;} 680 /* Get the location of the variable in the exodus file */ 681 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 682 ierr = EXOGetVarIndex_Private(exoid, EX_ELEM_BLOCK, vecname, &offset);CHKERRQ(ierr); 683 if (!offset) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Cannot locate zonal variable %s in exodus file\n", vecname); 684 /* Read local chunk of the result in the exodus file 685 exodus stores each component of a vector-valued field as a separate variable. 686 We assume that they are stored sequentially 687 Zonal variables are accessed one element block at a time, so we loop through the cell sets, 688 but once the vector has been reordered to natural size, we cannot use the label informations 689 to figure out what to save where. */ 690 numCS = ex_inquire_int(exoid, EX_INQ_ELEM_BLK); 691 ierr = PetscMalloc2(numCS, &csID, numCS, &csSize);CHKERRQ(ierr); 692 ierr = ex_get_ids(exoid, EX_ELEM_BLOCK, csID);CHKERRQ(ierr); 693 for (set = 0; set < numCS; ++set) { 694 ex_block block; 695 696 block.id = csID[set]; 697 block.type = EX_ELEM_BLOCK; 698 ierr = ex_get_block_param(exoid, &block);CHKERRQ(ierr); 699 csSize[set] = block.num_entry; 700 } 701 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 702 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 703 if (bs > 1) {ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr);} 704 for (set = 0; set < numCS; ++set) { 705 PetscInt csLocalSize, c; 706 707 /* range of indices for set setID[set]: csxs:csxs + csSize[set]-1 708 local slice of zonal values: xs/bs,xm/bs-1 709 intersection: max(xs/bs,csxs),min(xm/bs-1,csxs + csSize[set]-1) */ 710 csLocalSize = PetscMax(0, PetscMin(xe/bs, csxs+csSize[set]) - PetscMax(xs/bs, csxs)); 711 if (bs == 1) { 712 ierr = VecGetArray(vNatural, &varray);CHKERRQ(ierr); 713 ierr = ex_get_partial_var(exoid, step, EX_ELEM_BLOCK, offset, csID[set], PetscMax(xs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs)]);CHKERRQ(ierr); 714 ierr = VecRestoreArray(vNatural, &varray);CHKERRQ(ierr); 715 } else { 716 for (c = 0; c < bs; ++c) { 717 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 718 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 719 ierr = VecGetArray(vComp, &varray);CHKERRQ(ierr); 720 ierr = ex_get_partial_var(exoid, step, EX_ELEM_BLOCK, offset+c, csID[set], PetscMax(xs/bs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs/bs)]); 721 ierr = VecRestoreArray(vComp, &varray);CHKERRQ(ierr); 722 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 723 } 724 } 725 csxs += csSize[set]; 726 } 727 ierr = PetscFree2(csID, csSize);CHKERRQ(ierr); 728 if (bs > 1) {ierr = ISDestroy(&compIS);CHKERRQ(ierr);} 729 if (useNatural) { 730 ierr = DMPlexNaturalToGlobalBegin(dm, vNatural, v);CHKERRQ(ierr); 731 ierr = DMPlexNaturalToGlobalEnd(dm, vNatural, v);CHKERRQ(ierr); 732 ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr); 733 } 734 PetscFunctionReturn(0); 735 } 736 #endif 737 738 /*@C 739 DMPlexCreateExodusFromFile - Create a DMPlex mesh from an ExodusII file. 740 741 Collective on comm 742 743 Input Parameters: 744 + comm - The MPI communicator 745 . filename - The name of the ExodusII file 746 - interpolate - Create faces and edges in the mesh 747 748 Output Parameter: 749 . dm - The DM object representing the mesh 750 751 Level: beginner 752 753 .keywords: mesh,ExodusII 754 .seealso: DMPLEX, DMCreate(), DMPlexCreateExodus() 755 @*/ 756 PetscErrorCode DMPlexCreateExodusFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 757 { 758 PetscMPIInt rank; 759 PetscErrorCode ierr; 760 #if defined(PETSC_HAVE_EXODUSII) 761 int CPU_word_size = sizeof(PetscReal), IO_word_size = 0, exoid = -1; 762 float version; 763 #endif 764 765 PetscFunctionBegin; 766 PetscValidCharPointer(filename, 2); 767 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 768 #if defined(PETSC_HAVE_EXODUSII) 769 if (!rank) { 770 exoid = ex_open(filename, EX_READ, &CPU_word_size, &IO_word_size, &version); 771 if (exoid <= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open(\"%s\",...) did not return a valid file ID", filename); 772 } 773 ierr = DMPlexCreateExodus(comm, exoid, interpolate, dm);CHKERRQ(ierr); 774 if (!rank) {ierr = ex_close(exoid);CHKERRQ(ierr);} 775 #else 776 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 777 #endif 778 PetscFunctionReturn(0); 779 } 780 781 /*@ 782 DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file ID. 783 784 Collective on comm 785 786 Input Parameters: 787 + comm - The MPI communicator 788 . exoid - The ExodusII id associated with a exodus file and obtained using ex_open 789 - interpolate - Create faces and edges in the mesh 790 791 Output Parameter: 792 . dm - The DM object representing the mesh 793 794 Level: beginner 795 796 .keywords: mesh,ExodusII 797 .seealso: DMPLEX, DMCreate() 798 @*/ 799 PetscErrorCode DMPlexCreateExodus(MPI_Comm comm, PetscInt exoid, PetscBool interpolate, DM *dm) 800 { 801 #if defined(PETSC_HAVE_EXODUSII) 802 PetscMPIInt num_proc, rank; 803 PetscSection coordSection; 804 Vec coordinates; 805 PetscScalar *coords; 806 PetscInt coordSize, v; 807 PetscErrorCode ierr; 808 /* Read from ex_get_init() */ 809 char title[PETSC_MAX_PATH_LEN+1]; 810 int dim = 0, numVertices = 0, numCells = 0; 811 int num_cs = 0, num_vs = 0, num_fs = 0; 812 #endif 813 814 PetscFunctionBegin; 815 #if defined(PETSC_HAVE_EXODUSII) 816 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 817 ierr = MPI_Comm_size(comm, &num_proc);CHKERRQ(ierr); 818 ierr = DMCreate(comm, dm);CHKERRQ(ierr); 819 ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr); 820 /* Open EXODUS II file and read basic informations on rank 0, then broadcast to all processors */ 821 if (!rank) { 822 ierr = PetscMemzero(title,(PETSC_MAX_PATH_LEN+1)*sizeof(char));CHKERRQ(ierr); 823 ierr = ex_get_init(exoid, title, &dim, &numVertices, &numCells, &num_cs, &num_vs, &num_fs); 824 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"ExodusII ex_get_init() failed with error code %D\n",ierr); 825 if (!num_cs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Exodus file does not contain any cell set\n"); 826 } 827 ierr = MPI_Bcast(title, PETSC_MAX_PATH_LEN+1, MPI_CHAR, 0, comm);CHKERRQ(ierr); 828 ierr = MPI_Bcast(&dim, 1, MPI_INT, 0, comm);CHKERRQ(ierr); 829 ierr = PetscObjectSetName((PetscObject) *dm, title);CHKERRQ(ierr); 830 ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr); 831 ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr); 832 833 /* Read cell sets information */ 834 if (!rank) { 835 PetscInt *cone; 836 int c, cs, c_loc, v, v_loc; 837 /* Read from ex_get_elem_blk_ids() */ 838 int *cs_id; 839 /* Read from ex_get_elem_block() */ 840 char buffer[PETSC_MAX_PATH_LEN+1]; 841 int num_cell_in_set, num_vertex_per_cell, num_attr; 842 /* Read from ex_get_elem_conn() */ 843 int *cs_connect; 844 845 /* Get cell sets IDs */ 846 ierr = PetscMalloc1(num_cs, &cs_id);CHKERRQ(ierr); 847 ierr = ex_get_ids (exoid, EX_ELEM_BLOCK, cs_id);CHKERRQ(ierr); 848 /* Read the cell set connectivity table and build mesh topology 849 EXO standard requires that cells in cell sets be numbered sequentially and be pairwise disjoint. */ 850 /* First set sizes */ 851 for (cs = 0, c = 0; cs < num_cs; cs++) { 852 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); 853 for (c_loc = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 854 ierr = DMPlexSetConeSize(*dm, c, num_vertex_per_cell);CHKERRQ(ierr); 855 } 856 } 857 ierr = DMSetUp(*dm);CHKERRQ(ierr); 858 for (cs = 0, c = 0; cs < num_cs; cs++) { 859 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); 860 ierr = PetscMalloc2(num_vertex_per_cell*num_cell_in_set,&cs_connect,num_vertex_per_cell,&cone);CHKERRQ(ierr); 861 ierr = ex_get_conn (exoid, EX_ELEM_BLOCK, cs_id[cs], cs_connect,NULL,NULL);CHKERRQ(ierr); 862 /* EXO uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */ 863 for (c_loc = 0, v = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 864 for (v_loc = 0; v_loc < num_vertex_per_cell; ++v_loc, ++v) { 865 cone[v_loc] = cs_connect[v]+numCells-1; 866 } 867 if (dim == 3) { 868 /* Tetrahedra are inverted */ 869 if (num_vertex_per_cell == 4) { 870 PetscInt tmp = cone[0]; 871 cone[0] = cone[1]; 872 cone[1] = tmp; 873 } 874 /* Hexahedra are inverted */ 875 if (num_vertex_per_cell == 8) { 876 PetscInt tmp = cone[1]; 877 cone[1] = cone[3]; 878 cone[3] = tmp; 879 } 880 } 881 ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr); 882 ierr = DMSetLabelValue(*dm, "Cell Sets", c, cs_id[cs]);CHKERRQ(ierr); 883 } 884 ierr = PetscFree2(cs_connect,cone);CHKERRQ(ierr); 885 } 886 ierr = PetscFree(cs_id);CHKERRQ(ierr); 887 } 888 ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr); 889 ierr = DMPlexStratify(*dm);CHKERRQ(ierr); 890 if (interpolate) { 891 DM idm; 892 893 ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr); 894 ierr = DMDestroy(dm);CHKERRQ(ierr); 895 *dm = idm; 896 } 897 898 /* Create vertex set label */ 899 if (!rank && (num_vs > 0)) { 900 int vs, v; 901 /* Read from ex_get_node_set_ids() */ 902 int *vs_id; 903 /* Read from ex_get_node_set_param() */ 904 int num_vertex_in_set; 905 /* Read from ex_get_node_set() */ 906 int *vs_vertex_list; 907 908 /* Get vertex set ids */ 909 ierr = PetscMalloc1(num_vs, &vs_id);CHKERRQ(ierr); 910 ierr = ex_get_ids(exoid, EX_NODE_SET, vs_id);CHKERRQ(ierr); 911 for (vs = 0; vs < num_vs; ++vs) { 912 ierr = ex_get_set_param(exoid, EX_NODE_SET, vs_id[vs], &num_vertex_in_set, NULL); 913 ierr = PetscMalloc1(num_vertex_in_set, &vs_vertex_list);CHKERRQ(ierr); 914 ierr = ex_get_set(exoid, EX_NODE_SET, vs_id[vs], vs_vertex_list, NULL);CHKERRQ(ierr); 915 for (v = 0; v < num_vertex_in_set; ++v) { 916 ierr = DMSetLabelValue(*dm, "Vertex Sets", vs_vertex_list[v]+numCells-1, vs_id[vs]);CHKERRQ(ierr); 917 } 918 ierr = PetscFree(vs_vertex_list);CHKERRQ(ierr); 919 } 920 ierr = PetscFree(vs_id);CHKERRQ(ierr); 921 } 922 /* Read coordinates */ 923 ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr); 924 ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr); 925 ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr); 926 ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr); 927 for (v = numCells; v < numCells+numVertices; ++v) { 928 ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr); 929 ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr); 930 } 931 ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr); 932 ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr); 933 ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr); 934 ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr); 935 ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr); 936 ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr); 937 ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr); 938 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 939 if (!rank) { 940 PetscReal *x, *y, *z; 941 942 ierr = PetscMalloc3(numVertices,&x,numVertices,&y,numVertices,&z);CHKERRQ(ierr); 943 ierr = ex_get_coord(exoid, x, y, z);CHKERRQ(ierr); 944 if (dim > 0) { 945 for (v = 0; v < numVertices; ++v) coords[v*dim+0] = x[v]; 946 } 947 if (dim > 1) { 948 for (v = 0; v < numVertices; ++v) coords[v*dim+1] = y[v]; 949 } 950 if (dim > 2) { 951 for (v = 0; v < numVertices; ++v) coords[v*dim+2] = z[v]; 952 } 953 ierr = PetscFree3(x,y,z);CHKERRQ(ierr); 954 } 955 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 956 ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr); 957 ierr = VecDestroy(&coordinates);CHKERRQ(ierr); 958 959 /* Create side set label */ 960 if (!rank && interpolate && (num_fs > 0)) { 961 int fs, f, voff; 962 /* Read from ex_get_side_set_ids() */ 963 int *fs_id; 964 /* Read from ex_get_side_set_param() */ 965 int num_side_in_set; 966 /* Read from ex_get_side_set_node_list() */ 967 int *fs_vertex_count_list, *fs_vertex_list; 968 /* Read side set labels */ 969 char fs_name[MAX_STR_LENGTH+1]; 970 971 /* Get side set ids */ 972 ierr = PetscMalloc1(num_fs, &fs_id);CHKERRQ(ierr); 973 ierr = ex_get_ids(exoid, EX_SIDE_SET, fs_id);CHKERRQ(ierr); 974 for (fs = 0; fs < num_fs; ++fs) { 975 ierr = ex_get_set_param(exoid, EX_SIDE_SET, fs_id[fs], &num_side_in_set, NULL);CHKERRQ(ierr); 976 ierr = PetscMalloc2(num_side_in_set,&fs_vertex_count_list,num_side_in_set*4,&fs_vertex_list);CHKERRQ(ierr); 977 ierr = ex_get_side_set_node_list(exoid, fs_id[fs], fs_vertex_count_list, fs_vertex_list);CHKERRQ(ierr); 978 /* Get the specific name associated with this side set ID. */ 979 int fs_name_err = ex_get_name(exoid, EX_SIDE_SET, fs_id[fs], fs_name); 980 for (f = 0, voff = 0; f < num_side_in_set; ++f) { 981 const PetscInt *faces = NULL; 982 PetscInt faceSize = fs_vertex_count_list[f], numFaces; 983 PetscInt faceVertices[4], v; 984 985 if (faceSize > 4) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "ExodusII side cannot have %d > 4 vertices", faceSize); 986 for (v = 0; v < faceSize; ++v, ++voff) { 987 faceVertices[v] = fs_vertex_list[voff]+numCells-1; 988 } 989 ierr = DMPlexGetFullJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 990 if (numFaces != 1) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Invalid ExodusII side %d in set %d maps to %d faces", f, fs, numFaces); 991 ierr = DMSetLabelValue(*dm, "Face Sets", faces[0], fs_id[fs]);CHKERRQ(ierr); 992 /* Only add the label if one has been detected for this side set. */ 993 if (!fs_name_err) { 994 ierr = DMSetLabelValue(*dm, fs_name, faces[0], fs_id[fs]);CHKERRQ(ierr); 995 } 996 ierr = DMPlexRestoreJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 997 } 998 ierr = PetscFree2(fs_vertex_count_list,fs_vertex_list);CHKERRQ(ierr); 999 } 1000 ierr = PetscFree(fs_id);CHKERRQ(ierr); 1001 } 1002 #else 1003 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 1004 #endif 1005 PetscFunctionReturn(0); 1006 } 1007