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 #include <petsc/private/viewerimpl.h> 10 #include <petsc/private/viewerexodusiiimpl.h> 11 #if defined(PETSC_HAVE_EXODUSII) 12 /* 13 PETSC_VIEWER_EXODUSII_ - Creates an ExodusII PetscViewer shared by all processors in a communicator. 14 15 Collective 16 17 Input Parameter: 18 . comm - the MPI communicator to share the ExodusII PetscViewer 19 20 Level: intermediate 21 22 Notes: 23 misses Fortran bindings 24 25 Notes: 26 Unlike almost all other PETSc routines, PETSC_VIEWER_EXODUSII_ does not return 27 an error code. The GLVIS PetscViewer is usually used in the form 28 $ XXXView(XXX object, PETSC_VIEWER_EXODUSII_(comm)); 29 30 .seealso: PetscViewerExodusIIOpen(), PetscViewerType, PetscViewerCreate(), PetscViewerDestroy() 31 */ 32 PetscViewer PETSC_VIEWER_EXODUSII_(MPI_Comm comm) 33 { 34 PetscViewer viewer; 35 PetscErrorCode ierr; 36 37 PetscFunctionBegin; 38 ierr = PetscViewerExodusIIOpen(comm, "mesh.exo", FILE_MODE_WRITE, &viewer); 39 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_EXODUSII_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 40 ierr = PetscObjectRegisterDestroy((PetscObject) viewer); 41 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_EXODUSII_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 42 PetscFunctionReturn(viewer); 43 } 44 45 static PetscErrorCode PetscViewerView_ExodusII(PetscViewer v, PetscViewer viewer) 46 { 47 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) v->data; 48 PetscErrorCode ierr; 49 50 PetscFunctionBegin; 51 if (exo->filename) {ierr = PetscViewerASCIIPrintf(viewer, "Filename: %s\n", exo->filename);CHKERRQ(ierr);} 52 if (exo->exoid) {ierr = PetscViewerASCIIPrintf(viewer, "exoid: %d\n", exo->exoid) ;CHKERRQ(ierr);} 53 if (exo->btype) {ierr = PetscViewerASCIIPrintf(viewer, "IO Mode: %d\n", exo->btype) ;CHKERRQ(ierr);} 54 if (exo->order) {ierr = PetscViewerASCIIPrintf(viewer, "Mesh order: %d\n", exo->order) ;CHKERRQ(ierr);} 55 PetscFunctionReturn(0); 56 } 57 58 static PetscErrorCode PetscViewerSetFromOptions_ExodusII(PetscOptionItems *PetscOptionsObject, PetscViewer v) 59 { 60 PetscErrorCode ierr; 61 62 PetscFunctionBegin; 63 ierr = PetscOptionsHead(PetscOptionsObject, "ExodusII PetscViewer Options");CHKERRQ(ierr); 64 ierr = PetscOptionsTail();CHKERRQ(ierr); 65 PetscFunctionReturn(0); 66 } 67 68 static PetscErrorCode PetscViewerSetUp_ExodusII(PetscViewer viewer) 69 { 70 PetscFunctionBegin; 71 PetscFunctionReturn(0); 72 } 73 74 static PetscErrorCode PetscViewerDestroy_ExodusII(PetscViewer viewer) 75 { 76 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 77 PetscErrorCode ierr; 78 79 PetscFunctionBegin; 80 if (exo->exoid >= 0) {PetscStackCallStandard(ex_close,(exo->exoid));} 81 ierr = PetscFree(exo->filename);CHKERRQ(ierr); 82 ierr = PetscFree(exo);CHKERRQ(ierr); 83 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr); 84 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileGetName_C",NULL);CHKERRQ(ierr); 85 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetMode_C",NULL);CHKERRQ(ierr); 86 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGetId_C",NULL);CHKERRQ(ierr); 87 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGetOrder_C",NULL);CHKERRQ(ierr); 88 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerSetOrder_C",NULL);CHKERRQ(ierr); 89 PetscFunctionReturn(0); 90 } 91 92 static PetscErrorCode PetscViewerFileSetName_ExodusII(PetscViewer viewer, const char name[]) 93 { 94 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 95 PetscMPIInt rank; 96 int CPU_word_size, IO_word_size, EXO_mode; 97 PetscErrorCode ierr; 98 MPI_Info mpi_info = MPI_INFO_NULL; 99 float EXO_version; 100 101 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRMPI(ierr); 102 CPU_word_size = sizeof(PetscReal); 103 IO_word_size = sizeof(PetscReal); 104 105 PetscFunctionBegin; 106 if (exo->exoid >= 0) { 107 PetscStackCallStandard(ex_close,(exo->exoid)); 108 exo->exoid = -1; 109 } 110 if (exo->filename) {ierr = PetscFree(exo->filename);CHKERRQ(ierr);} 111 ierr = PetscStrallocpy(name, &exo->filename);CHKERRQ(ierr); 112 switch (exo->btype) { 113 case FILE_MODE_READ: 114 EXO_mode = EX_READ; 115 break; 116 case FILE_MODE_APPEND: 117 case FILE_MODE_UPDATE: 118 case FILE_MODE_APPEND_UPDATE: 119 /* Will fail if the file does not already exist */ 120 EXO_mode = EX_WRITE; 121 break; 122 case FILE_MODE_WRITE: 123 /* 124 exodus only allows writing geometry upon file creation, so we will let DMView create the file. 125 */ 126 PetscFunctionReturn(0); 127 break; 128 default: 129 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()"); 130 } 131 #if defined(PETSC_USE_64BIT_INDICES) 132 EXO_mode += EX_ALL_INT64_API; 133 #endif 134 exo->exoid = ex_open_par(name,EXO_mode,&CPU_word_size,&IO_word_size,&EXO_version,PETSC_COMM_WORLD,mpi_info); 135 if (exo->exoid < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open_par failed for %s", name); 136 PetscFunctionReturn(0); 137 } 138 139 static PetscErrorCode PetscViewerFileGetName_ExodusII(PetscViewer viewer, const char **name) 140 { 141 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 142 143 PetscFunctionBegin; 144 *name = exo->filename; 145 PetscFunctionReturn(0); 146 } 147 148 static PetscErrorCode PetscViewerFileSetMode_ExodusII(PetscViewer viewer, PetscFileMode type) 149 { 150 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 151 152 PetscFunctionBegin; 153 exo->btype = type; 154 PetscFunctionReturn(0); 155 } 156 157 static PetscErrorCode PetscViewerFileGetMode_ExodusII(PetscViewer viewer, PetscFileMode *type) 158 { 159 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 160 161 PetscFunctionBegin; 162 *type = exo->btype; 163 PetscFunctionReturn(0); 164 } 165 166 static PetscErrorCode PetscViewerExodusIIGetId_ExodusII(PetscViewer viewer, int *exoid) 167 { 168 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 169 170 PetscFunctionBegin; 171 *exoid = exo->exoid; 172 PetscFunctionReturn(0); 173 } 174 175 static PetscErrorCode PetscViewerExodusIIGetOrder_ExodusII(PetscViewer viewer, PetscInt *order) 176 { 177 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 178 179 PetscFunctionBegin; 180 *order = exo->order; 181 PetscFunctionReturn(0); 182 } 183 184 static PetscErrorCode PetscViewerExodusIISetOrder_ExodusII(PetscViewer viewer, PetscInt order) 185 { 186 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 187 188 PetscFunctionBegin; 189 exo->order = order; 190 PetscFunctionReturn(0); 191 } 192 193 /*MC 194 PETSCVIEWEREXODUSII - A viewer that writes to an Exodus II file 195 196 .seealso: PetscViewerExodusIIOpen(), PetscViewerCreate(), PETSCVIEWERBINARY, PETSCVIEWERHDF5, DMView(), 197 PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType() 198 199 Level: beginner 200 M*/ 201 202 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ExodusII(PetscViewer v) 203 { 204 PetscViewer_ExodusII *exo; 205 PetscErrorCode ierr; 206 207 PetscFunctionBegin; 208 ierr = PetscNewLog(v,&exo);CHKERRQ(ierr); 209 210 v->data = (void*) exo; 211 v->ops->destroy = PetscViewerDestroy_ExodusII; 212 v->ops->setfromoptions = PetscViewerSetFromOptions_ExodusII; 213 v->ops->setup = PetscViewerSetUp_ExodusII; 214 v->ops->view = PetscViewerView_ExodusII; 215 v->ops->flush = 0; 216 exo->btype = (PetscFileMode) -1; 217 exo->filename = 0; 218 exo->exoid = -1; 219 220 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_ExodusII);CHKERRQ(ierr); 221 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_ExodusII);CHKERRQ(ierr); 222 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_ExodusII);CHKERRQ(ierr); 223 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetMode_C",PetscViewerFileGetMode_ExodusII);CHKERRQ(ierr); 224 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerGetId_C",PetscViewerExodusIIGetId_ExodusII);CHKERRQ(ierr); 225 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerSetOrder_C",PetscViewerExodusIISetOrder_ExodusII);CHKERRQ(ierr); 226 ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerGetOrder_C",PetscViewerExodusIIGetOrder_ExodusII);CHKERRQ(ierr); 227 PetscFunctionReturn(0); 228 } 229 230 /* 231 EXOGetVarIndex - Locate a result in an exodus file based on its name 232 233 Collective 234 235 Input Parameters: 236 + exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 237 . obj_type - the type of entity for instance EX_NODAL, EX_ELEM_BLOCK 238 - name - the name of the result 239 240 Output Parameters: 241 . varIndex - the location in the exodus file of the result 242 243 Notes: 244 The exodus variable index is obtained by comparing name and the 245 names of zonal variables declared in the exodus file. For instance if name is "V" 246 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 247 amongst all variables of type obj_type. 248 249 Level: beginner 250 251 .seealso: EXOGetVarIndex(),DMPlexView_ExodusII_Internal(),VecViewPlex_ExodusII_Nodal_Internal(),VecLoadNodal_PlexEXO(),VecLoadZonal_PlexEXO() 252 */ 253 PetscErrorCode EXOGetVarIndex_Internal(int exoid, ex_entity_type obj_type, const char name[], int *varIndex) 254 { 255 int num_vars, i, j; 256 char ext_name[MAX_STR_LENGTH+1], var_name[MAX_STR_LENGTH+1]; 257 const int num_suffix = 5; 258 char *suffix[5]; 259 PetscBool flg; 260 PetscErrorCode ierr; 261 262 PetscFunctionBegin; 263 suffix[0] = (char *) ""; 264 suffix[1] = (char *) "_X"; 265 suffix[2] = (char *) "_XX"; 266 suffix[3] = (char *) "_1"; 267 suffix[4] = (char *) "_11"; 268 269 *varIndex = -1; 270 PetscStackCallStandard(ex_get_variable_param,(exoid, obj_type, &num_vars)); 271 for (i = 0; i < num_vars; ++i) { 272 PetscStackCallStandard(ex_get_variable_name,(exoid, obj_type, i+1, var_name)); 273 for (j = 0; j < num_suffix; ++j){ 274 ierr = PetscStrncpy(ext_name, name, MAX_STR_LENGTH);CHKERRQ(ierr); 275 ierr = PetscStrlcat(ext_name, suffix[j], MAX_STR_LENGTH);CHKERRQ(ierr); 276 ierr = PetscStrcasecmp(ext_name, var_name, &flg); 277 if (flg) { 278 *varIndex = i+1; 279 } 280 } 281 } 282 PetscFunctionReturn(0); 283 } 284 285 /* 286 DMView_PlexExodusII - Write a DM to disk in exodus format 287 288 Collective on dm 289 290 Input Parameters: 291 + dm - The dm to be written 292 . viewer - an exodusII viewer 293 294 Notes: 295 Not all DM can be written to disk this way. For instance, exodus assume that element blocks (mapped to "Cell sets" labels) 296 consists of sequentially numbered cells. If this is not the case, the exodus file will be corrupted. 297 298 If the dm has been distributed, only the part of the DM on MPI rank 0 (including "ghost" cells and vertices) 299 will be written. 300 301 DMPlex only represents geometry while most post-processing software expect that a mesh also provides information 302 on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2. 303 The order of the mesh shall be set using PetscViewerExodusIISetOrder 304 It should be extended to use PetscFE objects. 305 306 This function will only handle TRI, TET, QUAD, and HEX cells. 307 Level: beginner 308 309 .seealso: 310 */ 311 PetscErrorCode DMView_PlexExodusII(DM dm, PetscViewer viewer) 312 { 313 enum ElemType {TRI, QUAD, TET, HEX}; 314 MPI_Comm comm; 315 PetscInt degree; /* the order of the mesh */ 316 /* Connectivity Variables */ 317 PetscInt cellsNotInConnectivity; 318 /* Cell Sets */ 319 DMLabel csLabel; 320 IS csIS; 321 const PetscInt *csIdx; 322 PetscInt num_cs, cs; 323 enum ElemType *type; 324 PetscBool hasLabel; 325 /* Coordinate Variables */ 326 DM cdm; 327 PetscSection coordSection; 328 Vec coord; 329 PetscInt **nodes; 330 PetscInt depth, d, dim, skipCells = 0; 331 PetscInt pStart, pEnd, p, cStart, cEnd, numCells, vStart, vEnd, numVertices, eStart, eEnd, numEdges, fStart, fEnd, numFaces, numNodes; 332 PetscInt num_vs, num_fs; 333 PetscMPIInt rank, size; 334 const char *dmName; 335 PetscInt nodesTriP1[4] = {3,0,0,0}; 336 PetscInt nodesTriP2[4] = {3,3,0,0}; 337 PetscInt nodesQuadP1[4] = {4,0,0,0}; 338 PetscInt nodesQuadP2[4] = {4,4,0,1}; 339 PetscInt nodesTetP1[4] = {4,0,0,0}; 340 PetscInt nodesTetP2[4] = {4,6,0,0}; 341 PetscInt nodesHexP1[4] = {8,0,0,0}; 342 PetscInt nodesHexP2[4] = {8,12,6,1}; 343 PetscErrorCode ierr; 344 345 int CPU_word_size, IO_word_size, EXO_mode; 346 float EXO_version; 347 348 PetscViewer_ExodusII *exo = (PetscViewer_ExodusII *) viewer->data; 349 350 PetscFunctionBegin; 351 ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr); 352 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 353 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 354 355 /* 356 Creating coordSection is a collective operation so we do it somewhat out of sequence 357 */ 358 ierr = PetscSectionCreate(comm, &coordSection);CHKERRQ(ierr); 359 ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr); 360 if (!rank) { 361 switch (exo->btype) { 362 case FILE_MODE_READ: 363 case FILE_MODE_APPEND: 364 case FILE_MODE_UPDATE: 365 case FILE_MODE_APPEND_UPDATE: 366 /* exodusII does not allow writing geometry to an existing file */ 367 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "cannot add geometry to existing file %s", exo->filename); 368 case FILE_MODE_WRITE: 369 /* Create an empty file if one already exists*/ 370 EXO_mode = EX_CLOBBER; 371 #if defined(PETSC_USE_64BIT_INDICES) 372 EXO_mode += EX_ALL_INT64_API; 373 #endif 374 CPU_word_size = sizeof(PetscReal); 375 IO_word_size = sizeof(PetscReal); 376 exo->exoid = ex_create(exo->filename, EXO_mode, &CPU_word_size, &IO_word_size); 377 if (exo->exoid < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_create failed for %s", exo->filename); 378 379 break; 380 default: 381 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()"); 382 } 383 384 /* --- Get DM info --- */ 385 ierr = PetscObjectGetName((PetscObject) dm, &dmName);CHKERRQ(ierr); 386 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 387 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 388 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 389 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 390 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 391 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr); 392 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 393 numCells = cEnd - cStart; 394 numEdges = eEnd - eStart; 395 numVertices = vEnd - vStart; 396 if (depth == 3) {numFaces = fEnd - fStart;} 397 else {numFaces = 0;} 398 ierr = DMGetLabelSize(dm, "Cell Sets", &num_cs);CHKERRQ(ierr); 399 ierr = DMGetLabelSize(dm, "Vertex Sets", &num_vs);CHKERRQ(ierr); 400 ierr = DMGetLabelSize(dm, "Face Sets", &num_fs);CHKERRQ(ierr); 401 ierr = DMGetCoordinatesLocal(dm, &coord);CHKERRQ(ierr); 402 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 403 if (num_cs > 0) { 404 ierr = DMGetLabel(dm, "Cell Sets", &csLabel);CHKERRQ(ierr); 405 ierr = DMLabelGetValueIS(csLabel, &csIS);CHKERRQ(ierr); 406 ierr = ISGetIndices(csIS, &csIdx);CHKERRQ(ierr); 407 } 408 ierr = PetscMalloc1(num_cs, &nodes);CHKERRQ(ierr); 409 /* Set element type for each block and compute total number of nodes */ 410 ierr = PetscMalloc1(num_cs, &type);CHKERRQ(ierr); 411 numNodes = numVertices; 412 413 ierr = PetscViewerExodusIIGetOrder(viewer, °ree);CHKERRQ(ierr); 414 if (degree == 2) {numNodes += numEdges;} 415 cellsNotInConnectivity = numCells; 416 for (cs = 0; cs < num_cs; ++cs) { 417 IS stratumIS; 418 const PetscInt *cells; 419 PetscScalar *xyz = NULL; 420 PetscInt csSize, closureSize; 421 422 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 423 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 424 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 425 ierr = DMPlexVecGetClosure(cdm, NULL, coord, cells[0], &closureSize, &xyz);CHKERRQ(ierr); 426 switch (dim) { 427 case 2: 428 if (closureSize == 3*dim) {type[cs] = TRI;} 429 else if (closureSize == 4*dim) {type[cs] = QUAD;} 430 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices %D in dimension %D has no ExodusII type", closureSize/dim, dim); 431 break; 432 case 3: 433 if (closureSize == 4*dim) {type[cs] = TET;} 434 else if (closureSize == 8*dim) {type[cs] = HEX;} 435 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices %D in dimension %D has no ExodusII type", closureSize/dim, dim); 436 break; 437 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not handled by ExodusII viewer", dim); 438 } 439 if ((degree == 2) && (type[cs] == QUAD)) {numNodes += csSize;} 440 if ((degree == 2) && (type[cs] == HEX)) {numNodes += csSize; numNodes += numFaces;} 441 ierr = DMPlexVecRestoreClosure(cdm, NULL, coord, cells[0], &closureSize, &xyz);CHKERRQ(ierr); 442 /* Set nodes and Element type */ 443 if (type[cs] == TRI) { 444 if (degree == 1) nodes[cs] = nodesTriP1; 445 else if (degree == 2) nodes[cs] = nodesTriP2; 446 } else if (type[cs] == QUAD) { 447 if (degree == 1) nodes[cs] = nodesQuadP1; 448 else if (degree == 2) nodes[cs] = nodesQuadP2; 449 } else if (type[cs] == TET) { 450 if (degree == 1) nodes[cs] = nodesTetP1; 451 else if (degree == 2) nodes[cs] = nodesTetP2; 452 } else if (type[cs] == HEX) { 453 if (degree == 1) nodes[cs] = nodesHexP1; 454 else if (degree == 2) nodes[cs] = nodesHexP2; 455 } 456 /* Compute the number of cells not in the connectivity table */ 457 cellsNotInConnectivity -= nodes[cs][3]*csSize; 458 459 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 460 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 461 } 462 if (num_cs > 0) {PetscStackCallStandard(ex_put_init,(exo->exoid, dmName, dim, numNodes, numCells, num_cs, num_vs, num_fs));} 463 /* --- Connectivity --- */ 464 for (cs = 0; cs < num_cs; ++cs) { 465 IS stratumIS; 466 const PetscInt *cells; 467 PetscInt *connect, off = 0; 468 PetscInt edgesInClosure = 0, facesInClosure = 0, verticesInClosure = 0; 469 PetscInt csSize, c, connectSize, closureSize; 470 char *elem_type = NULL; 471 char elem_type_tri3[] = "TRI3", elem_type_quad4[] = "QUAD4"; 472 char elem_type_tri6[] = "TRI6", elem_type_quad9[] = "QUAD9"; 473 char elem_type_tet4[] = "TET4", elem_type_hex8[] = "HEX8"; 474 char elem_type_tet10[] = "TET10", elem_type_hex27[] = "HEX27"; 475 476 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 477 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 478 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 479 /* Set Element type */ 480 if (type[cs] == TRI) { 481 if (degree == 1) elem_type = elem_type_tri3; 482 else if (degree == 2) elem_type = elem_type_tri6; 483 } else if (type[cs] == QUAD) { 484 if (degree == 1) elem_type = elem_type_quad4; 485 else if (degree == 2) elem_type = elem_type_quad9; 486 } else if (type[cs] == TET) { 487 if (degree == 1) elem_type = elem_type_tet4; 488 else if (degree == 2) elem_type = elem_type_tet10; 489 } else if (type[cs] == HEX) { 490 if (degree == 1) elem_type = elem_type_hex8; 491 else if (degree == 2) elem_type = elem_type_hex27; 492 } 493 connectSize = nodes[cs][0] + nodes[cs][1] + nodes[cs][2] + nodes[cs][3]; 494 ierr = PetscMalloc1(PetscMax(27,connectSize)*csSize, &connect);CHKERRQ(ierr); 495 PetscStackCallStandard(ex_put_block,(exo->exoid, EX_ELEM_BLOCK, csIdx[cs], elem_type, csSize, connectSize, 0, 0, 1)); 496 /* Find number of vertices, edges, and faces in the closure */ 497 verticesInClosure = nodes[cs][0]; 498 if (depth > 1) { 499 if (dim == 2) { 500 ierr = DMPlexGetConeSize(dm, cells[0], &edgesInClosure);CHKERRQ(ierr); 501 } else if (dim == 3) { 502 PetscInt *closure = NULL; 503 504 ierr = DMPlexGetConeSize(dm, cells[0], &facesInClosure);CHKERRQ(ierr); 505 ierr = DMPlexGetTransitiveClosure(dm, cells[0], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 506 edgesInClosure = closureSize - facesInClosure - 1 - verticesInClosure; 507 ierr = DMPlexRestoreTransitiveClosure(dm, cells[0], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 508 } 509 } 510 /* Get connectivity for each cell */ 511 for (c = 0; c < csSize; ++c) { 512 PetscInt *closure = NULL; 513 PetscInt temp, i; 514 515 ierr = DMPlexGetTransitiveClosure(dm, cells[c], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 516 for (i = 0; i < connectSize; ++i) { 517 if (i < nodes[cs][0]) {/* Vertices */ 518 connect[i+off] = closure[(i+edgesInClosure+facesInClosure+1)*2] + 1; 519 connect[i+off] -= cellsNotInConnectivity; 520 } else if (i < nodes[cs][0]+nodes[cs][1]) { /* Edges */ 521 connect[i+off] = closure[(i-verticesInClosure+facesInClosure+1)*2] + 1; 522 if (nodes[cs][2] == 0) connect[i+off] -= numFaces; 523 connect[i+off] -= cellsNotInConnectivity; 524 } else if (i < nodes[cs][0]+nodes[cs][1]+nodes[cs][3]){ /* Cells */ 525 connect[i+off] = closure[0] + 1; 526 connect[i+off] -= skipCells; 527 } else if (i < nodes[cs][0]+nodes[cs][1]+nodes[cs][3]+nodes[cs][2]){ /* Faces */ 528 connect[i+off] = closure[(i-edgesInClosure-verticesInClosure)*2] + 1; 529 connect[i+off] -= cellsNotInConnectivity; 530 } else { 531 connect[i+off] = -1; 532 } 533 } 534 /* Tetrahedra are inverted */ 535 if (type[cs] == TET) { 536 temp = connect[0+off]; connect[0+off] = connect[1+off]; connect[1+off] = temp; 537 if (degree == 2) { 538 temp = connect[5+off]; connect[5+off] = connect[6+off]; connect[6+off] = temp; 539 temp = connect[7+off]; connect[7+off] = connect[8+off]; connect[8+off] = temp; 540 } 541 } 542 /* Hexahedra are inverted */ 543 if (type[cs] == HEX) { 544 temp = connect[1+off]; connect[1+off] = connect[3+off]; connect[3+off] = temp; 545 if (degree == 2) { 546 temp = connect[8+off]; connect[8+off] = connect[11+off]; connect[11+off] = temp; 547 temp = connect[9+off]; connect[9+off] = connect[10+off]; connect[10+off] = temp; 548 temp = connect[16+off]; connect[16+off] = connect[17+off]; connect[17+off] = temp; 549 temp = connect[18+off]; connect[18+off] = connect[19+off]; connect[19+off] = temp; 550 551 temp = connect[12+off]; connect[12+off] = connect[16+off]; connect[16+off] = temp; 552 temp = connect[13+off]; connect[13+off] = connect[17+off]; connect[17+off] = temp; 553 temp = connect[14+off]; connect[14+off] = connect[18+off]; connect[18+off] = temp; 554 temp = connect[15+off]; connect[15+off] = connect[19+off]; connect[19+off] = temp; 555 556 temp = connect[23+off]; connect[23+off] = connect[26+off]; connect[26+off] = temp; 557 temp = connect[24+off]; connect[24+off] = connect[25+off]; connect[25+off] = temp; 558 temp = connect[25+off]; connect[25+off] = connect[26+off]; connect[26+off] = temp; 559 } 560 } 561 off += connectSize; 562 ierr = DMPlexRestoreTransitiveClosure(dm, cells[c], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 563 } 564 PetscStackCallStandard(ex_put_conn,(exo->exoid, EX_ELEM_BLOCK, csIdx[cs], connect, 0, 0)); 565 skipCells += (nodes[cs][3] == 0)*csSize; 566 ierr = PetscFree(connect);CHKERRQ(ierr); 567 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 568 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 569 } 570 ierr = PetscFree(type);CHKERRQ(ierr); 571 /* --- Coordinates --- */ 572 ierr = PetscSectionSetChart(coordSection, pStart, pEnd);CHKERRQ(ierr); 573 if (num_cs) { 574 for (d = 0; d < depth; ++d) { 575 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 576 for (p = pStart; p < pEnd; ++p) { 577 ierr = PetscSectionSetDof(coordSection, p, nodes[0][d] > 0);CHKERRQ(ierr); 578 } 579 } 580 } 581 for (cs = 0; cs < num_cs; ++cs) { 582 IS stratumIS; 583 const PetscInt *cells; 584 PetscInt csSize, c; 585 586 ierr = DMLabelGetStratumIS(csLabel, csIdx[cs], &stratumIS);CHKERRQ(ierr); 587 ierr = ISGetIndices(stratumIS, &cells);CHKERRQ(ierr); 588 ierr = ISGetSize(stratumIS, &csSize);CHKERRQ(ierr); 589 for (c = 0; c < csSize; ++c) { 590 ierr = PetscSectionSetDof(coordSection, cells[c], nodes[cs][3] > 0);CHKERRQ(ierr); 591 } 592 ierr = ISRestoreIndices(stratumIS, &cells);CHKERRQ(ierr); 593 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 594 } 595 if (num_cs > 0) { 596 ierr = ISRestoreIndices(csIS, &csIdx);CHKERRQ(ierr); 597 ierr = ISDestroy(&csIS);CHKERRQ(ierr); 598 } 599 ierr = PetscFree(nodes);CHKERRQ(ierr); 600 ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr); 601 if (numNodes > 0) { 602 const char *coordNames[3] = {"x", "y", "z"}; 603 PetscScalar *coords, *closure; 604 PetscReal *cval; 605 PetscInt hasDof, n = 0; 606 607 /* There can't be more than 24 values in the closure of a point for the coord coordSection */ 608 ierr = PetscCalloc3(numNodes*3, &coords, dim, &cval, 24, &closure);CHKERRQ(ierr); 609 ierr = DMGetCoordinatesLocalNoncollective(dm, &coord);CHKERRQ(ierr); 610 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 611 for (p = pStart; p < pEnd; ++p) { 612 ierr = PetscSectionGetDof(coordSection, p, &hasDof); 613 if (hasDof) { 614 PetscInt closureSize = 24, j; 615 616 ierr = DMPlexVecGetClosure(cdm, NULL, coord, p, &closureSize, &closure);CHKERRQ(ierr); 617 for (d = 0; d < dim; ++d) { 618 cval[d] = 0.0; 619 for (j = 0; j < closureSize/dim; j++) cval[d] += closure[j*dim+d]; 620 coords[d*numNodes+n] = cval[d] * dim / closureSize; 621 } 622 ++n; 623 } 624 } 625 PetscStackCallStandard(ex_put_coord,(exo->exoid, &coords[0*numNodes], &coords[1*numNodes], &coords[2*numNodes])); 626 ierr = PetscFree3(coords, cval, closure);CHKERRQ(ierr); 627 PetscStackCallStandard(ex_put_coord_names,(exo->exoid, (char **) coordNames)); 628 } 629 630 /* --- Node Sets/Vertex Sets --- */ 631 DMHasLabel(dm, "Vertex Sets", &hasLabel); 632 if (hasLabel) { 633 PetscInt i, vs, vsSize; 634 const PetscInt *vsIdx, *vertices; 635 PetscInt *nodeList; 636 IS vsIS, stratumIS; 637 DMLabel vsLabel; 638 ierr = DMGetLabel(dm, "Vertex Sets", &vsLabel);CHKERRQ(ierr); 639 ierr = DMLabelGetValueIS(vsLabel, &vsIS);CHKERRQ(ierr); 640 ierr = ISGetIndices(vsIS, &vsIdx);CHKERRQ(ierr); 641 for (vs=0; vs<num_vs; ++vs) { 642 ierr = DMLabelGetStratumIS(vsLabel, vsIdx[vs], &stratumIS);CHKERRQ(ierr); 643 ierr = ISGetIndices(stratumIS, &vertices);CHKERRQ(ierr); 644 ierr = ISGetSize(stratumIS, &vsSize);CHKERRQ(ierr); 645 ierr = PetscMalloc1(vsSize, &nodeList); 646 for (i=0; i<vsSize; ++i) { 647 nodeList[i] = vertices[i] - skipCells + 1; 648 } 649 PetscStackCallStandard(ex_put_set_param,(exo->exoid, EX_NODE_SET, vsIdx[vs], vsSize, 0)); 650 PetscStackCallStandard(ex_put_set,(exo->exoid, EX_NODE_SET, vsIdx[vs], nodeList, NULL)); 651 ierr = ISRestoreIndices(stratumIS, &vertices);CHKERRQ(ierr); 652 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 653 ierr = PetscFree(nodeList);CHKERRQ(ierr); 654 } 655 ierr = ISRestoreIndices(vsIS, &vsIdx);CHKERRQ(ierr); 656 ierr = ISDestroy(&vsIS);CHKERRQ(ierr); 657 } 658 /* --- Side Sets/Face Sets --- */ 659 ierr = DMHasLabel(dm, "Face Sets", &hasLabel);CHKERRQ(ierr); 660 if (hasLabel) { 661 PetscInt i, j, fs, fsSize; 662 const PetscInt *fsIdx, *faces; 663 IS fsIS, stratumIS; 664 DMLabel fsLabel; 665 PetscInt numPoints, *points; 666 PetscInt elem_list_size = 0; 667 PetscInt *elem_list, *elem_ind, *side_list; 668 669 ierr = DMGetLabel(dm, "Face Sets", &fsLabel);CHKERRQ(ierr); 670 /* Compute size of Node List and Element List */ 671 ierr = DMLabelGetValueIS(fsLabel, &fsIS);CHKERRQ(ierr); 672 ierr = ISGetIndices(fsIS, &fsIdx);CHKERRQ(ierr); 673 for (fs=0; fs<num_fs; ++fs) { 674 ierr = DMLabelGetStratumIS(fsLabel, fsIdx[fs], &stratumIS);CHKERRQ(ierr); 675 ierr = ISGetSize(stratumIS, &fsSize);CHKERRQ(ierr); 676 elem_list_size += fsSize; 677 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 678 } 679 ierr = PetscMalloc3(num_fs, &elem_ind, 680 elem_list_size, &elem_list, 681 elem_list_size, &side_list);CHKERRQ(ierr); 682 elem_ind[0] = 0; 683 for (fs=0; fs<num_fs; ++fs) { 684 ierr = DMLabelGetStratumIS(fsLabel, fsIdx[fs], &stratumIS);CHKERRQ(ierr); 685 ierr = ISGetIndices(stratumIS, &faces);CHKERRQ(ierr); 686 ierr = ISGetSize(stratumIS, &fsSize);CHKERRQ(ierr); 687 /* Set Parameters */ 688 PetscStackCallStandard(ex_put_set_param,(exo->exoid, EX_SIDE_SET, fsIdx[fs], fsSize, 0)); 689 /* Indices */ 690 if (fs<num_fs-1) { 691 elem_ind[fs+1] = elem_ind[fs] + fsSize; 692 } 693 694 for (i=0; i<fsSize; ++i) { 695 /* Element List */ 696 points = NULL; 697 ierr = DMPlexGetTransitiveClosure(dm, faces[i], PETSC_FALSE, &numPoints, &points);CHKERRQ(ierr); 698 elem_list[elem_ind[fs] + i] = points[2] +1; 699 ierr = DMPlexRestoreTransitiveClosure(dm, faces[i], PETSC_FALSE, &numPoints, &points);CHKERRQ(ierr); 700 701 /* Side List */ 702 points = NULL; 703 ierr = DMPlexGetTransitiveClosure(dm, elem_list[elem_ind[fs] + i]-1, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 704 for (j=1; j<numPoints; ++j) { 705 if (points[j*2]==faces[i]) {break;} 706 } 707 /* Convert HEX sides */ 708 if (numPoints == 27) { 709 if (j == 1) {j = 5;} 710 else if (j == 2) {j = 6;} 711 else if (j == 3) {j = 1;} 712 else if (j == 4) {j = 3;} 713 else if (j == 5) {j = 2;} 714 else if (j == 6) {j = 4;} 715 } 716 /* Convert TET sides */ 717 if (numPoints == 15) { 718 --j; 719 if (j == 0) {j = 4;} 720 } 721 side_list[elem_ind[fs] + i] = j; 722 ierr = DMPlexRestoreTransitiveClosure(dm, elem_list[elem_ind[fs] + i]-1, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 723 724 } 725 ierr = ISRestoreIndices(stratumIS, &faces);CHKERRQ(ierr); 726 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 727 } 728 ierr = ISRestoreIndices(fsIS, &fsIdx);CHKERRQ(ierr); 729 ierr = ISDestroy(&fsIS);CHKERRQ(ierr); 730 731 /* Put side sets */ 732 for (fs=0; fs<num_fs; ++fs) { 733 PetscStackCallStandard(ex_put_set,(exo->exoid, EX_SIDE_SET, fsIdx[fs], &elem_list[elem_ind[fs]], &side_list[elem_ind[fs]])); 734 } 735 ierr = PetscFree3(elem_ind,elem_list,side_list);CHKERRQ(ierr); 736 } 737 /* 738 close the exodus file 739 */ 740 ex_close(exo->exoid); 741 exo->exoid = -1; 742 } 743 ierr = PetscSectionDestroy(&coordSection);CHKERRQ(ierr); 744 745 /* 746 reopen the file in parallel 747 */ 748 EXO_mode = EX_WRITE; 749 #if defined(PETSC_USE_64BIT_INDICES) 750 EXO_mode += EX_ALL_INT64_API; 751 #endif 752 CPU_word_size = sizeof(PetscReal); 753 IO_word_size = sizeof(PetscReal); 754 exo->exoid = ex_open_par(exo->filename,EXO_mode,&CPU_word_size,&IO_word_size,&EXO_version,comm,MPI_INFO_NULL); 755 if (exo->exoid < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open_par failed for %s", exo->filename); 756 PetscFunctionReturn(0); 757 } 758 759 /* 760 VecView_PlexExodusII_Internal - Write a Vec corresponding in an exodus file 761 762 Collective on v 763 764 Input Parameters: 765 + v - The vector to be written 766 - viewer - The PetscViewerExodusII viewer associate to an exodus file 767 768 Notes: 769 The exodus result variable index is obtained by comparing the Vec name and the 770 names of variables declared in the exodus file. For instance for a Vec named "V" 771 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 772 amongst all variables. 773 In the event where a nodal and zonal variable both match, the function will return an error instead of 774 possibly corrupting the file 775 776 Level: beginner 777 778 .seealso: EXOGetVarIndex_Internal(),DMPlexView_ExodusII(),VecView_PlexExodusII() 779 @*/ 780 PetscErrorCode VecView_PlexExodusII_Internal(Vec v, PetscViewer viewer) 781 { 782 DM dm; 783 MPI_Comm comm; 784 PetscMPIInt rank; 785 786 int exoid,offsetN = 0, offsetZ = 0; 787 const char *vecname; 788 PetscInt step; 789 PetscErrorCode ierr; 790 791 PetscFunctionBegin; 792 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 793 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 794 ierr = PetscViewerExodusIIGetId(viewer,&exoid);CHKERRQ(ierr); 795 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 796 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 797 798 ierr = DMGetOutputSequenceNumber(dm,&step,NULL);CHKERRQ(ierr); 799 ierr = EXOGetVarIndex_Internal(exoid,EX_NODAL,vecname,&offsetN);CHKERRQ(ierr); 800 ierr = EXOGetVarIndex_Internal(exoid,EX_ELEM_BLOCK,vecname,&offsetZ);CHKERRQ(ierr); 801 if (offsetN <= 0 && offsetZ <= 0) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Found both nodal and zonal variable %s in exodus file. \n", vecname); 802 if (offsetN > 0) { 803 ierr = VecViewPlex_ExodusII_Nodal_Internal(v,exoid,(int) step+1,offsetN);CHKERRQ(ierr); 804 } else if (offsetZ > 0) { 805 ierr = VecViewPlex_ExodusII_Zonal_Internal(v,exoid,(int) step+1,offsetZ);CHKERRQ(ierr); 806 } else SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Could not find nodal or zonal variable %s in exodus file. \n", vecname); 807 PetscFunctionReturn(0); 808 } 809 810 /* 811 VecLoad_PlexExodusII_Internal - Write a Vec corresponding in an exodus file 812 813 Collective on v 814 815 Input Parameters: 816 + v - The vector to be written 817 - viewer - The PetscViewerExodusII viewer associate to an exodus file 818 819 Notes: 820 The exodus result variable index is obtained by comparing the Vec name and the 821 names of variables declared in the exodus file. For instance for a Vec named "V" 822 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 823 amongst all variables. 824 In the event where a nodal and zonal variable both match, the function will return an error instead of 825 possibly corrupting the file 826 827 Level: beginner 828 829 .seealso: EXOGetVarIndex_Internal(),DMPlexView_ExodusII(),VecView_PlexExodusII() 830 @*/ 831 PetscErrorCode VecLoad_PlexExodusII_Internal(Vec v, PetscViewer viewer) 832 { 833 DM dm; 834 MPI_Comm comm; 835 PetscMPIInt rank; 836 837 int exoid,offsetN = 0, offsetZ = 0; 838 const char *vecname; 839 PetscInt step; 840 PetscErrorCode ierr; 841 842 PetscFunctionBegin; 843 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 844 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 845 ierr = PetscViewerExodusIIGetId(viewer,&exoid);CHKERRQ(ierr); 846 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 847 ierr = PetscObjectGetName((PetscObject) v, &vecname);CHKERRQ(ierr); 848 849 ierr = DMGetOutputSequenceNumber(dm,&step,NULL);CHKERRQ(ierr); 850 ierr = EXOGetVarIndex_Internal(exoid,EX_NODAL,vecname,&offsetN);CHKERRQ(ierr); 851 ierr = EXOGetVarIndex_Internal(exoid,EX_ELEM_BLOCK,vecname,&offsetZ);CHKERRQ(ierr); 852 if (offsetN <= 0 && offsetZ <= 0) SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Found both nodal and zonal variable %s in exodus file. \n", vecname); 853 if (offsetN > 0) { 854 ierr = VecLoadPlex_ExodusII_Nodal_Internal(v,exoid,(int) step+1,offsetN);CHKERRQ(ierr); 855 } else if (offsetZ > 0) { 856 ierr = VecLoadPlex_ExodusII_Zonal_Internal(v,exoid,(int) step+1,offsetZ);CHKERRQ(ierr); 857 } else SETERRQ1(comm, PETSC_ERR_FILE_UNEXPECTED, "Could not find nodal or zonal variable %s in exodus file. \n", vecname); 858 PetscFunctionReturn(0); 859 } 860 861 /* 862 VecViewPlex_ExodusII_Nodal_Internal - Write a Vec corresponding to a nodal field to an exodus file 863 864 Collective on v 865 866 Input Parameters: 867 + v - The vector to be written 868 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 869 . step - the time step to write at (exodus steps are numbered starting from 1) 870 - offset - the location of the variable in the file 871 872 Notes: 873 The exodus result nodal variable index is obtained by comparing the Vec name and the 874 names of nodal variables declared in the exodus file. For instance for a Vec named "V" 875 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 876 amongst all nodal variables. 877 878 Level: beginner 879 880 .seealso: EXOGetVarIndex_Internal(),DMPlexView_ExodusII_Internal(),VecLoadNodal_PlexEXO(),VecViewZonal_PlexEXO(),VecLoadZonal_PlexEXO() 881 @*/ 882 PetscErrorCode VecViewPlex_ExodusII_Nodal_Internal(Vec v, int exoid, int step, int offset) 883 { 884 MPI_Comm comm; 885 PetscMPIInt size; 886 DM dm; 887 Vec vNatural, vComp; 888 const PetscScalar *varray; 889 PetscInt xs, xe, bs; 890 PetscBool useNatural; 891 PetscErrorCode ierr; 892 893 PetscFunctionBegin; 894 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 895 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 896 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 897 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 898 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 899 if (useNatural) { 900 ierr = DMGetGlobalVector(dm, &vNatural);CHKERRQ(ierr); 901 ierr = DMPlexGlobalToNaturalBegin(dm, v, vNatural);CHKERRQ(ierr); 902 ierr = DMPlexGlobalToNaturalEnd(dm, v, vNatural);CHKERRQ(ierr); 903 } else { 904 vNatural = v; 905 } 906 907 /* Write local chunk of the result in the exodus file 908 exodus stores each component of a vector-valued field as a separate variable. 909 We assume that they are stored sequentially */ 910 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 911 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 912 if (bs == 1) { 913 ierr = VecGetArrayRead(vNatural, &varray);CHKERRQ(ierr); 914 PetscStackCallStandard(ex_put_partial_var,(exoid, step, EX_NODAL, offset, 1, xs+1, xe-xs, varray)); 915 ierr = VecRestoreArrayRead(vNatural, &varray);CHKERRQ(ierr); 916 } else { 917 IS compIS; 918 PetscInt c; 919 920 ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr); 921 for (c = 0; c < bs; ++c) { 922 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 923 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 924 ierr = VecGetArrayRead(vComp, &varray);CHKERRQ(ierr); 925 PetscStackCallStandard(ex_put_partial_var,(exoid, step, EX_NODAL, offset+c, 1, xs/bs+1, (xe-xs)/bs, varray)); 926 ierr = VecRestoreArrayRead(vComp, &varray);CHKERRQ(ierr); 927 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 928 } 929 ierr = ISDestroy(&compIS);CHKERRQ(ierr); 930 } 931 if (useNatural) {ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr);} 932 PetscFunctionReturn(0); 933 } 934 935 /* 936 VecLoadPlex_ExodusII_Nodal_Internal - Read a Vec corresponding to a nodal field from an exodus file 937 938 Collective on v 939 940 Input Parameters: 941 + v - The vector to be written 942 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 943 . step - the time step to read at (exodus steps are numbered starting from 1) 944 - offset - the location of the variable in the file 945 946 Notes: 947 The exodus result nodal variable index is obtained by comparing the Vec name and the 948 names of nodal variables declared in the exodus file. For instance for a Vec named "V" 949 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 950 amongst all nodal variables. 951 952 Level: beginner 953 954 .seealso: EXOGetVarIndex_Internal(), DMPlexView_ExodusII_Internal(), VecViewPlex_ExodusII_Nodal_Internal(), VecViewZonal_PlexEXO(), VecLoadZonal_PlexEXO() 955 */ 956 PetscErrorCode VecLoadPlex_ExodusII_Nodal_Internal(Vec v, int exoid, int step, int offset) 957 { 958 MPI_Comm comm; 959 PetscMPIInt size; 960 DM dm; 961 Vec vNatural, vComp; 962 PetscScalar *varray; 963 PetscInt xs, xe, bs; 964 PetscBool useNatural; 965 PetscErrorCode ierr; 966 967 PetscFunctionBegin; 968 ierr = PetscObjectGetComm((PetscObject) v, &comm);CHKERRQ(ierr); 969 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 970 ierr = VecGetDM(v,&dm);CHKERRQ(ierr); 971 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 972 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 973 if (useNatural) {ierr = DMGetGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 974 else {vNatural = v;} 975 976 /* Read local chunk from the file */ 977 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 978 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 979 if (bs == 1) { 980 ierr = VecGetArray(vNatural, &varray);CHKERRQ(ierr); 981 PetscStackCallStandard(ex_get_partial_var,(exoid, step, EX_NODAL, offset, 1, xs+1, xe-xs, varray)); 982 ierr = VecRestoreArray(vNatural, &varray);CHKERRQ(ierr); 983 } else { 984 IS compIS; 985 PetscInt c; 986 987 ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr); 988 for (c = 0; c < bs; ++c) { 989 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 990 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 991 ierr = VecGetArray(vComp, &varray);CHKERRQ(ierr); 992 PetscStackCallStandard(ex_get_partial_var,(exoid, step, EX_NODAL, offset+c, 1, xs/bs+1, (xe-xs)/bs, varray)); 993 ierr = VecRestoreArray(vComp, &varray);CHKERRQ(ierr); 994 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 995 } 996 ierr = ISDestroy(&compIS);CHKERRQ(ierr); 997 } 998 if (useNatural) { 999 ierr = DMPlexNaturalToGlobalBegin(dm, vNatural, v);CHKERRQ(ierr); 1000 ierr = DMPlexNaturalToGlobalEnd(dm, vNatural, v);CHKERRQ(ierr); 1001 ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr); 1002 } 1003 PetscFunctionReturn(0); 1004 } 1005 1006 /* 1007 VecViewPlex_ExodusII_Zonal_Internal - Write a Vec corresponding to a zonal (cell based) field to an exodus file 1008 1009 Collective on v 1010 1011 Input Parameters: 1012 + v - The vector to be written 1013 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 1014 . step - the time step to write at (exodus steps are numbered starting from 1) 1015 - offset - the location of the variable in the file 1016 1017 Notes: 1018 The exodus result zonal variable index is obtained by comparing the Vec name and the 1019 names of zonal variables declared in the exodus file. For instance for a Vec named "V" 1020 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 1021 amongst all zonal variables. 1022 1023 Level: beginner 1024 1025 .seealso: EXOGetVarIndex_Internal(),DMPlexView_ExodusII_Internal(),VecViewPlex_ExodusII_Nodal_Internal(),VecLoadPlex_ExodusII_Nodal_Internal(),VecLoadPlex_ExodusII_Zonal_Internal() 1026 */ 1027 PetscErrorCode VecViewPlex_ExodusII_Zonal_Internal(Vec v, int exoid, int step, int offset) 1028 { 1029 MPI_Comm comm; 1030 PetscMPIInt size; 1031 DM dm; 1032 Vec vNatural, vComp; 1033 const PetscScalar *varray; 1034 PetscInt xs, xe, bs; 1035 PetscBool useNatural; 1036 IS compIS; 1037 PetscInt *csSize, *csID; 1038 PetscInt numCS, set, csxs = 0; 1039 PetscErrorCode ierr; 1040 1041 PetscFunctionBegin; 1042 ierr = PetscObjectGetComm((PetscObject)v, &comm);CHKERRQ(ierr); 1043 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 1044 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 1045 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 1046 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 1047 if (useNatural) { 1048 ierr = DMGetGlobalVector(dm, &vNatural);CHKERRQ(ierr); 1049 ierr = DMPlexGlobalToNaturalBegin(dm, v, vNatural);CHKERRQ(ierr); 1050 ierr = DMPlexGlobalToNaturalEnd(dm, v, vNatural);CHKERRQ(ierr); 1051 } else { 1052 vNatural = v; 1053 } 1054 1055 /* Write local chunk of the result in the exodus file 1056 exodus stores each component of a vector-valued field as a separate variable. 1057 We assume that they are stored sequentially 1058 Zonal variables are accessed one element block at a time, so we loop through the cell sets, 1059 but once the vector has been reordered to natural size, we cannot use the label informations 1060 to figure out what to save where. */ 1061 numCS = ex_inquire_int(exoid, EX_INQ_ELEM_BLK); 1062 ierr = PetscMalloc2(numCS, &csID, numCS, &csSize);CHKERRQ(ierr); 1063 PetscStackCallStandard(ex_get_ids,(exoid, EX_ELEM_BLOCK, csID)); 1064 for (set = 0; set < numCS; ++set) { 1065 ex_block block; 1066 1067 block.id = csID[set]; 1068 block.type = EX_ELEM_BLOCK; 1069 PetscStackCallStandard(ex_get_block_param,(exoid, &block)); 1070 csSize[set] = block.num_entry; 1071 } 1072 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 1073 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 1074 if (bs > 1) {ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr);} 1075 for (set = 0; set < numCS; set++) { 1076 PetscInt csLocalSize, c; 1077 1078 /* range of indices for set setID[set]: csxs:csxs + csSize[set]-1 1079 local slice of zonal values: xs/bs,xm/bs-1 1080 intersection: max(xs/bs,csxs),min(xm/bs-1,csxs + csSize[set]-1) */ 1081 csLocalSize = PetscMax(0, PetscMin(xe/bs, csxs+csSize[set]) - PetscMax(xs/bs, csxs)); 1082 if (bs == 1) { 1083 ierr = VecGetArrayRead(vNatural, &varray);CHKERRQ(ierr); 1084 PetscStackCallStandard(ex_put_partial_var,(exoid, step, EX_ELEM_BLOCK, offset, csID[set], PetscMax(xs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs)])); 1085 ierr = VecRestoreArrayRead(vNatural, &varray);CHKERRQ(ierr); 1086 } else { 1087 for (c = 0; c < bs; ++c) { 1088 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 1089 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 1090 ierr = VecGetArrayRead(vComp, &varray);CHKERRQ(ierr); 1091 PetscStackCallStandard(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)])); 1092 ierr = VecRestoreArrayRead(vComp, &varray);CHKERRQ(ierr); 1093 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 1094 } 1095 } 1096 csxs += csSize[set]; 1097 } 1098 ierr = PetscFree2(csID, csSize);CHKERRQ(ierr); 1099 if (bs > 1) {ierr = ISDestroy(&compIS);CHKERRQ(ierr);} 1100 if (useNatural) {ierr = DMRestoreGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 1101 PetscFunctionReturn(0); 1102 } 1103 1104 /* 1105 VecLoadPlex_ExodusII_Zonal_Internal - Read a Vec corresponding to a zonal (cell based) field from an exodus file 1106 1107 Collective on v 1108 1109 Input Parameters: 1110 + v - The vector to be written 1111 . exoid - the exodus id of a file (obtained from ex_open or ex_create for instance) 1112 . step - the time step to read at (exodus steps are numbered starting from 1) 1113 - offset - the location of the variable in the file 1114 1115 Notes: 1116 The exodus result zonal variable index is obtained by comparing the Vec name and the 1117 names of zonal variables declared in the exodus file. For instance for a Vec named "V" 1118 the location in the exodus file will be the first match of "V", "V_X", "V_XX", "V_1", or "V_11" 1119 amongst all zonal variables. 1120 1121 Level: beginner 1122 1123 .seealso: EXOGetVarIndex_Internal(), DMPlexView_ExodusII_Internal(), VecViewPlex_ExodusII_Nodal_Internal(), VecLoadPlex_ExodusII_Nodal_Internal(), VecLoadPlex_ExodusII_Zonal_Internal() 1124 */ 1125 PetscErrorCode VecLoadPlex_ExodusII_Zonal_Internal(Vec v, int exoid, int step, int offset) 1126 { 1127 MPI_Comm comm; 1128 PetscMPIInt size; 1129 DM dm; 1130 Vec vNatural, vComp; 1131 PetscScalar *varray; 1132 PetscInt xs, xe, bs; 1133 PetscBool useNatural; 1134 IS compIS; 1135 PetscInt *csSize, *csID; 1136 PetscInt numCS, set, csxs = 0; 1137 PetscErrorCode ierr; 1138 1139 PetscFunctionBegin; 1140 ierr = PetscObjectGetComm((PetscObject)v,&comm);CHKERRQ(ierr); 1141 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 1142 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 1143 ierr = DMGetUseNatural(dm, &useNatural);CHKERRQ(ierr); 1144 useNatural = useNatural && size > 1 ? PETSC_TRUE : PETSC_FALSE; 1145 if (useNatural) {ierr = DMGetGlobalVector(dm,&vNatural);CHKERRQ(ierr);} 1146 else {vNatural = v;} 1147 1148 /* Read local chunk of the result in the exodus file 1149 exodus stores each component of a vector-valued field as a separate variable. 1150 We assume that they are stored sequentially 1151 Zonal variables are accessed one element block at a time, so we loop through the cell sets, 1152 but once the vector has been reordered to natural size, we cannot use the label informations 1153 to figure out what to save where. */ 1154 numCS = ex_inquire_int(exoid, EX_INQ_ELEM_BLK); 1155 ierr = PetscMalloc2(numCS, &csID, numCS, &csSize);CHKERRQ(ierr); 1156 PetscStackCallStandard(ex_get_ids,(exoid, EX_ELEM_BLOCK, csID)); 1157 for (set = 0; set < numCS; ++set) { 1158 ex_block block; 1159 1160 block.id = csID[set]; 1161 block.type = EX_ELEM_BLOCK; 1162 PetscStackCallStandard(ex_get_block_param,(exoid, &block)); 1163 csSize[set] = block.num_entry; 1164 } 1165 ierr = VecGetOwnershipRange(vNatural, &xs, &xe);CHKERRQ(ierr); 1166 ierr = VecGetBlockSize(vNatural, &bs);CHKERRQ(ierr); 1167 if (bs > 1) {ierr = ISCreateStride(comm, (xe-xs)/bs, xs, bs, &compIS);CHKERRQ(ierr);} 1168 for (set = 0; set < numCS; ++set) { 1169 PetscInt csLocalSize, c; 1170 1171 /* range of indices for set setID[set]: csxs:csxs + csSize[set]-1 1172 local slice of zonal values: xs/bs,xm/bs-1 1173 intersection: max(xs/bs,csxs),min(xm/bs-1,csxs + csSize[set]-1) */ 1174 csLocalSize = PetscMax(0, PetscMin(xe/bs, csxs+csSize[set]) - PetscMax(xs/bs, csxs)); 1175 if (bs == 1) { 1176 ierr = VecGetArray(vNatural, &varray);CHKERRQ(ierr); 1177 PetscStackCallStandard(ex_get_partial_var,(exoid, step, EX_ELEM_BLOCK, offset, csID[set], PetscMax(xs-csxs, 0)+1, csLocalSize, &varray[PetscMax(0, csxs-xs)])); 1178 ierr = VecRestoreArray(vNatural, &varray);CHKERRQ(ierr); 1179 } else { 1180 for (c = 0; c < bs; ++c) { 1181 ierr = ISStrideSetStride(compIS, (xe-xs)/bs, xs+c, bs);CHKERRQ(ierr); 1182 ierr = VecGetSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 1183 ierr = VecGetArray(vComp, &varray);CHKERRQ(ierr); 1184 PetscStackCallStandard(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)])); 1185 ierr = VecRestoreArray(vComp, &varray);CHKERRQ(ierr); 1186 ierr = VecRestoreSubVector(vNatural, compIS, &vComp);CHKERRQ(ierr); 1187 } 1188 } 1189 csxs += csSize[set]; 1190 } 1191 ierr = PetscFree2(csID, csSize);CHKERRQ(ierr); 1192 if (bs > 1) {ierr = ISDestroy(&compIS);CHKERRQ(ierr);} 1193 if (useNatural) { 1194 ierr = DMPlexNaturalToGlobalBegin(dm, vNatural, v);CHKERRQ(ierr); 1195 ierr = DMPlexNaturalToGlobalEnd(dm, vNatural, v);CHKERRQ(ierr); 1196 ierr = DMRestoreGlobalVector(dm, &vNatural);CHKERRQ(ierr); 1197 } 1198 PetscFunctionReturn(0); 1199 } 1200 #endif 1201 1202 /*@ 1203 PetscViewerExodusIIGetId - Get the file id of the ExodusII file 1204 1205 Logically Collective on PetscViewer 1206 1207 Input Parameter: 1208 . viewer - the PetscViewer 1209 1210 Output Parameter: 1211 - exoid - The ExodusII file id 1212 1213 Level: intermediate 1214 1215 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen() 1216 @*/ 1217 PetscErrorCode PetscViewerExodusIIGetId(PetscViewer viewer, int *exoid) 1218 { 1219 PetscErrorCode ierr; 1220 1221 PetscFunctionBegin; 1222 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1223 ierr = PetscTryMethod(viewer, "PetscViewerGetId_C",(PetscViewer,int*),(viewer,exoid));CHKERRQ(ierr); 1224 PetscFunctionReturn(0); 1225 } 1226 1227 /*@ 1228 PetscViewerExodusIISetOrder - Set the elements order in the exodusII file. 1229 1230 Collective 1231 1232 Input Parameters: 1233 + viewer - the viewer 1234 - order - elements order 1235 1236 Output Parameter: 1237 1238 Level: beginner 1239 1240 Note: 1241 1242 .seealso: PetscViewerExodusIIGetId(), PetscViewerExodusIIGetOrder(), PetscViewerExodusIISetOrder() 1243 @*/ 1244 PetscErrorCode PetscViewerExodusIISetOrder(PetscViewer viewer, PetscInt order) 1245 { 1246 PetscErrorCode ierr; 1247 1248 PetscFunctionBegin; 1249 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1250 ierr = PetscTryMethod(viewer, "PetscViewerSetOrder_C",(PetscViewer,PetscInt),(viewer,order));CHKERRQ(ierr); 1251 PetscFunctionReturn(0); 1252 } 1253 1254 /*@ 1255 PetscViewerExodusIIGetOrder - Get the elements order in the exodusII file. 1256 1257 Collective 1258 1259 Input Parameters: 1260 + viewer - the viewer 1261 - order - elements order 1262 1263 Output Parameter: 1264 1265 Level: beginner 1266 1267 Note: 1268 1269 .seealso: PetscViewerExodusIIGetId(), PetscViewerExodusIIGetOrder(), PetscViewerExodusIISetOrder() 1270 @*/ 1271 PetscErrorCode PetscViewerExodusIIGetOrder(PetscViewer viewer, PetscInt *order) 1272 { 1273 PetscErrorCode ierr; 1274 1275 PetscFunctionBegin; 1276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1277 ierr = PetscTryMethod(viewer, "PetscViewerGetOrder_C",(PetscViewer,PetscInt*),(viewer,order));CHKERRQ(ierr); 1278 PetscFunctionReturn(0); 1279 } 1280 1281 /*@C 1282 PetscViewerExodusIIOpen - Opens a file for ExodusII input/output. 1283 1284 Collective 1285 1286 Input Parameters: 1287 + comm - MPI communicator 1288 . name - name of file 1289 - type - type of file 1290 $ FILE_MODE_WRITE - create new file for binary output 1291 $ FILE_MODE_READ - open existing file for binary input 1292 $ FILE_MODE_APPEND - open existing file for binary output 1293 1294 Output Parameter: 1295 . exo - PetscViewer for Exodus II input/output to use with the specified file 1296 1297 Level: beginner 1298 1299 Note: 1300 This PetscViewer should be destroyed with PetscViewerDestroy(). 1301 1302 .seealso: PetscViewerPushFormat(), PetscViewerDestroy(), 1303 DMLoad(), PetscFileMode, PetscViewer, PetscViewerSetType(), PetscViewerFileSetMode(), PetscViewerFileSetName() 1304 @*/ 1305 PetscErrorCode PetscViewerExodusIIOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *exo) 1306 { 1307 PetscErrorCode ierr; 1308 1309 PetscFunctionBegin; 1310 ierr = PetscViewerCreate(comm, exo);CHKERRQ(ierr); 1311 ierr = PetscViewerSetType(*exo, PETSCVIEWEREXODUSII);CHKERRQ(ierr); 1312 ierr = PetscViewerFileSetMode(*exo, type);CHKERRQ(ierr); 1313 ierr = PetscViewerFileSetName(*exo, name);CHKERRQ(ierr); 1314 ierr = PetscViewerSetFromOptions(*exo);CHKERRQ(ierr); 1315 PetscFunctionReturn(0); 1316 } 1317 1318 /*@C 1319 DMPlexCreateExodusFromFile - Create a DMPlex mesh from an ExodusII file. 1320 1321 Collective 1322 1323 Input Parameters: 1324 + comm - The MPI communicator 1325 . filename - The name of the ExodusII file 1326 - interpolate - Create faces and edges in the mesh 1327 1328 Output Parameter: 1329 . dm - The DM object representing the mesh 1330 1331 Level: beginner 1332 1333 .seealso: DMPLEX, DMCreate(), DMPlexCreateExodus() 1334 @*/ 1335 PetscErrorCode DMPlexCreateExodusFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 1336 { 1337 PetscMPIInt rank; 1338 PetscErrorCode ierr; 1339 #if defined(PETSC_HAVE_EXODUSII) 1340 int CPU_word_size = sizeof(PetscReal), IO_word_size = 0, exoid = -1; 1341 float version; 1342 #endif 1343 1344 PetscFunctionBegin; 1345 PetscValidCharPointer(filename, 2); 1346 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 1347 #if defined(PETSC_HAVE_EXODUSII) 1348 if (!rank) { 1349 exoid = ex_open(filename, EX_READ, &CPU_word_size, &IO_word_size, &version); 1350 if (exoid <= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "ex_open(\"%s\",...) did not return a valid file ID", filename); 1351 } 1352 ierr = DMPlexCreateExodus(comm, exoid, interpolate, dm);CHKERRQ(ierr); 1353 if (!rank) {PetscStackCallStandard(ex_close,(exoid));} 1354 PetscFunctionReturn(0); 1355 #else 1356 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 1357 #endif 1358 } 1359 1360 #if defined(PETSC_HAVE_EXODUSII) 1361 static PetscErrorCode ExodusGetCellType_Internal(const char *elem_type, DMPolytopeType *ct) 1362 { 1363 PetscBool flg; 1364 PetscErrorCode ierr; 1365 1366 PetscFunctionBegin; 1367 *ct = DM_POLYTOPE_UNKNOWN; 1368 ierr = PetscStrcmp(elem_type, "TRI", &flg);CHKERRQ(ierr); 1369 if (flg) {*ct = DM_POLYTOPE_TRIANGLE; goto done;} 1370 ierr = PetscStrcmp(elem_type, "TRI3", &flg);CHKERRQ(ierr); 1371 if (flg) {*ct = DM_POLYTOPE_TRIANGLE; goto done;} 1372 ierr = PetscStrcmp(elem_type, "QUAD", &flg);CHKERRQ(ierr); 1373 if (flg) {*ct = DM_POLYTOPE_QUADRILATERAL; goto done;} 1374 ierr = PetscStrcmp(elem_type, "QUAD4", &flg);CHKERRQ(ierr); 1375 if (flg) {*ct = DM_POLYTOPE_QUADRILATERAL; goto done;} 1376 ierr = PetscStrcmp(elem_type, "SHELL4", &flg);CHKERRQ(ierr); 1377 if (flg) {*ct = DM_POLYTOPE_QUADRILATERAL; goto done;} 1378 ierr = PetscStrcmp(elem_type, "TETRA", &flg);CHKERRQ(ierr); 1379 if (flg) {*ct = DM_POLYTOPE_TETRAHEDRON; goto done;} 1380 ierr = PetscStrcmp(elem_type, "TET4", &flg);CHKERRQ(ierr); 1381 if (flg) {*ct = DM_POLYTOPE_TETRAHEDRON; goto done;} 1382 ierr = PetscStrcmp(elem_type, "WEDGE", &flg);CHKERRQ(ierr); 1383 if (flg) {*ct = DM_POLYTOPE_TRI_PRISM; goto done;} 1384 ierr = PetscStrcmp(elem_type, "HEX", &flg);CHKERRQ(ierr); 1385 if (flg) {*ct = DM_POLYTOPE_HEXAHEDRON; goto done;} 1386 ierr = PetscStrcmp(elem_type, "HEX8", &flg);CHKERRQ(ierr); 1387 if (flg) {*ct = DM_POLYTOPE_HEXAHEDRON; goto done;} 1388 ierr = PetscStrcmp(elem_type, "HEXAHEDRON", &flg);CHKERRQ(ierr); 1389 if (flg) {*ct = DM_POLYTOPE_HEXAHEDRON; goto done;} 1390 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unrecognized element type %s", elem_type); 1391 done: 1392 PetscFunctionReturn(0); 1393 } 1394 #endif 1395 1396 /*@ 1397 DMPlexCreateExodus - Create a DMPlex mesh from an ExodusII file ID. 1398 1399 Collective 1400 1401 Input Parameters: 1402 + comm - The MPI communicator 1403 . exoid - The ExodusII id associated with a exodus file and obtained using ex_open 1404 - interpolate - Create faces and edges in the mesh 1405 1406 Output Parameter: 1407 . dm - The DM object representing the mesh 1408 1409 Level: beginner 1410 1411 .seealso: DMPLEX, DMCreate() 1412 @*/ 1413 PetscErrorCode DMPlexCreateExodus(MPI_Comm comm, PetscInt exoid, PetscBool interpolate, DM *dm) 1414 { 1415 #if defined(PETSC_HAVE_EXODUSII) 1416 PetscMPIInt num_proc, rank; 1417 PetscSection coordSection; 1418 Vec coordinates; 1419 PetscScalar *coords; 1420 PetscInt coordSize, v; 1421 PetscErrorCode ierr; 1422 /* Read from ex_get_init() */ 1423 char title[PETSC_MAX_PATH_LEN+1]; 1424 int dim = 0, dimEmbed = 0, numVertices = 0, numCells = 0, numHybridCells = 0; 1425 int num_cs = 0, num_vs = 0, num_fs = 0; 1426 #endif 1427 1428 PetscFunctionBegin; 1429 #if defined(PETSC_HAVE_EXODUSII) 1430 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 1431 ierr = MPI_Comm_size(comm, &num_proc);CHKERRMPI(ierr); 1432 ierr = DMCreate(comm, dm);CHKERRQ(ierr); 1433 ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr); 1434 /* Open EXODUS II file and read basic informations on rank 0, then broadcast to all processors */ 1435 if (!rank) { 1436 ierr = PetscMemzero(title,PETSC_MAX_PATH_LEN+1);CHKERRQ(ierr); 1437 PetscStackCallStandard(ex_get_init,(exoid, title, &dimEmbed, &numVertices, &numCells, &num_cs, &num_vs, &num_fs)); 1438 if (!num_cs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Exodus file does not contain any cell set\n"); 1439 } 1440 ierr = MPI_Bcast(title, PETSC_MAX_PATH_LEN+1, MPI_CHAR, 0, comm);CHKERRMPI(ierr); 1441 ierr = MPI_Bcast(&dim, 1, MPI_INT, 0, comm);CHKERRMPI(ierr); 1442 ierr = PetscObjectSetName((PetscObject) *dm, title);CHKERRQ(ierr); 1443 ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr); 1444 /* We do not want this label automatically computed, instead we compute it here */ 1445 ierr = DMCreateLabel(*dm, "celltype");CHKERRQ(ierr); 1446 1447 /* Read cell sets information */ 1448 if (!rank) { 1449 PetscInt *cone; 1450 int c, cs, ncs, c_loc, v, v_loc; 1451 /* Read from ex_get_elem_blk_ids() */ 1452 int *cs_id, *cs_order; 1453 /* Read from ex_get_elem_block() */ 1454 char buffer[PETSC_MAX_PATH_LEN+1]; 1455 int num_cell_in_set, num_vertex_per_cell, num_hybrid, num_attr; 1456 /* Read from ex_get_elem_conn() */ 1457 int *cs_connect; 1458 1459 /* Get cell sets IDs */ 1460 ierr = PetscMalloc2(num_cs, &cs_id, num_cs, &cs_order);CHKERRQ(ierr); 1461 PetscStackCallStandard(ex_get_ids,(exoid, EX_ELEM_BLOCK, cs_id)); 1462 /* Read the cell set connectivity table and build mesh topology 1463 EXO standard requires that cells in cell sets be numbered sequentially and be pairwise disjoint. */ 1464 /* Check for a hybrid mesh */ 1465 for (cs = 0, num_hybrid = 0; cs < num_cs; ++cs) { 1466 DMPolytopeType ct; 1467 char elem_type[PETSC_MAX_PATH_LEN]; 1468 1469 ierr = PetscArrayzero(elem_type, sizeof(elem_type));CHKERRQ(ierr); 1470 PetscStackCallStandard(ex_get_elem_type,(exoid, cs_id[cs], elem_type)); 1471 ierr = ExodusGetCellType_Internal(elem_type, &ct);CHKERRQ(ierr); 1472 dim = PetscMax(dim, DMPolytopeTypeGetDim(ct)); 1473 PetscStackCallStandard(ex_get_block,(exoid, EX_ELEM_BLOCK, cs_id[cs], buffer, &num_cell_in_set,&num_vertex_per_cell, 0, 0, &num_attr)); 1474 switch (ct) { 1475 case DM_POLYTOPE_TRI_PRISM: 1476 cs_order[cs] = cs; 1477 numHybridCells += num_cell_in_set; 1478 ++num_hybrid; 1479 break; 1480 default: 1481 for (c = cs; c > cs-num_hybrid; --c) cs_order[c] = cs_order[c-1]; 1482 cs_order[cs-num_hybrid] = cs; 1483 } 1484 } 1485 /* First set sizes */ 1486 for (ncs = 0, c = 0; ncs < num_cs; ++ncs) { 1487 DMPolytopeType ct; 1488 char elem_type[PETSC_MAX_PATH_LEN]; 1489 const PetscInt cs = cs_order[ncs]; 1490 1491 ierr = PetscArrayzero(elem_type, sizeof(elem_type));CHKERRQ(ierr); 1492 PetscStackCallStandard(ex_get_elem_type,(exoid, cs_id[cs], elem_type)); 1493 ierr = ExodusGetCellType_Internal(elem_type, &ct);CHKERRQ(ierr); 1494 PetscStackCallStandard(ex_get_block,(exoid, EX_ELEM_BLOCK, cs_id[cs], buffer, &num_cell_in_set,&num_vertex_per_cell, 0, 0, &num_attr)); 1495 for (c_loc = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 1496 ierr = DMPlexSetConeSize(*dm, c, num_vertex_per_cell);CHKERRQ(ierr); 1497 ierr = DMPlexSetCellType(*dm, c, ct);CHKERRQ(ierr); 1498 } 1499 } 1500 for (v = numCells; v < numCells+numVertices; ++v) {ierr = DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);} 1501 ierr = DMSetUp(*dm);CHKERRQ(ierr); 1502 for (ncs = 0, c = 0; ncs < num_cs; ++ncs) { 1503 const PetscInt cs = cs_order[ncs]; 1504 PetscStackCallStandard(ex_get_block,(exoid, EX_ELEM_BLOCK, cs_id[cs], buffer, &num_cell_in_set, &num_vertex_per_cell, 0, 0, &num_attr)); 1505 ierr = PetscMalloc2(num_vertex_per_cell*num_cell_in_set,&cs_connect,num_vertex_per_cell,&cone);CHKERRQ(ierr); 1506 PetscStackCallStandard(ex_get_conn,(exoid, EX_ELEM_BLOCK, cs_id[cs], cs_connect,NULL,NULL)); 1507 /* EXO uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */ 1508 for (c_loc = 0, v = 0; c_loc < num_cell_in_set; ++c_loc, ++c) { 1509 DMPolytopeType ct; 1510 1511 for (v_loc = 0; v_loc < num_vertex_per_cell; ++v_loc, ++v) { 1512 cone[v_loc] = cs_connect[v]+numCells-1; 1513 } 1514 ierr = DMPlexGetCellType(*dm, c, &ct);CHKERRQ(ierr); 1515 ierr = DMPlexInvertCell(ct, cone);CHKERRQ(ierr); 1516 ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr); 1517 ierr = DMSetLabelValue(*dm, "Cell Sets", c, cs_id[cs]);CHKERRQ(ierr); 1518 } 1519 ierr = PetscFree2(cs_connect,cone);CHKERRQ(ierr); 1520 } 1521 ierr = PetscFree2(cs_id, cs_order);CHKERRQ(ierr); 1522 } 1523 { 1524 PetscInt ints[] = {dim, dimEmbed}; 1525 1526 ierr = MPI_Bcast(ints, 2, MPIU_INT, 0, comm);CHKERRMPI(ierr); 1527 ierr = DMSetDimension(*dm, ints[0]);CHKERRQ(ierr); 1528 ierr = DMSetCoordinateDim(*dm, ints[1]);CHKERRQ(ierr); 1529 dim = ints[0]; 1530 dimEmbed = ints[1]; 1531 } 1532 ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr); 1533 ierr = DMPlexStratify(*dm);CHKERRQ(ierr); 1534 if (interpolate) { 1535 DM idm; 1536 1537 ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr); 1538 ierr = DMDestroy(dm);CHKERRQ(ierr); 1539 *dm = idm; 1540 } 1541 1542 /* Create vertex set label */ 1543 if (!rank && (num_vs > 0)) { 1544 int vs, v; 1545 /* Read from ex_get_node_set_ids() */ 1546 int *vs_id; 1547 /* Read from ex_get_node_set_param() */ 1548 int num_vertex_in_set; 1549 /* Read from ex_get_node_set() */ 1550 int *vs_vertex_list; 1551 1552 /* Get vertex set ids */ 1553 ierr = PetscMalloc1(num_vs, &vs_id);CHKERRQ(ierr); 1554 PetscStackCallStandard(ex_get_ids,(exoid, EX_NODE_SET, vs_id)); 1555 for (vs = 0; vs < num_vs; ++vs) { 1556 PetscStackCallStandard(ex_get_set_param,(exoid, EX_NODE_SET, vs_id[vs], &num_vertex_in_set, NULL)); 1557 ierr = PetscMalloc1(num_vertex_in_set, &vs_vertex_list);CHKERRQ(ierr); 1558 PetscStackCallStandard(ex_get_set,(exoid, EX_NODE_SET, vs_id[vs], vs_vertex_list, NULL)); 1559 for (v = 0; v < num_vertex_in_set; ++v) { 1560 ierr = DMSetLabelValue(*dm, "Vertex Sets", vs_vertex_list[v]+numCells-1, vs_id[vs]);CHKERRQ(ierr); 1561 } 1562 ierr = PetscFree(vs_vertex_list);CHKERRQ(ierr); 1563 } 1564 ierr = PetscFree(vs_id);CHKERRQ(ierr); 1565 } 1566 /* Read coordinates */ 1567 ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr); 1568 ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr); 1569 ierr = PetscSectionSetFieldComponents(coordSection, 0, dimEmbed);CHKERRQ(ierr); 1570 ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr); 1571 for (v = numCells; v < numCells+numVertices; ++v) { 1572 ierr = PetscSectionSetDof(coordSection, v, dimEmbed);CHKERRQ(ierr); 1573 ierr = PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed);CHKERRQ(ierr); 1574 } 1575 ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr); 1576 ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr); 1577 ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr); 1578 ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr); 1579 ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr); 1580 ierr = VecSetBlockSize(coordinates, dimEmbed);CHKERRQ(ierr); 1581 ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr); 1582 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 1583 if (!rank) { 1584 PetscReal *x, *y, *z; 1585 1586 ierr = PetscMalloc3(numVertices,&x,numVertices,&y,numVertices,&z);CHKERRQ(ierr); 1587 PetscStackCallStandard(ex_get_coord,(exoid, x, y, z)); 1588 if (dimEmbed > 0) { 1589 for (v = 0; v < numVertices; ++v) coords[v*dimEmbed+0] = x[v]; 1590 } 1591 if (dimEmbed > 1) { 1592 for (v = 0; v < numVertices; ++v) coords[v*dimEmbed+1] = y[v]; 1593 } 1594 if (dimEmbed > 2) { 1595 for (v = 0; v < numVertices; ++v) coords[v*dimEmbed+2] = z[v]; 1596 } 1597 ierr = PetscFree3(x,y,z);CHKERRQ(ierr); 1598 } 1599 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 1600 ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr); 1601 ierr = VecDestroy(&coordinates);CHKERRQ(ierr); 1602 1603 /* Create side set label */ 1604 if (!rank && interpolate && (num_fs > 0)) { 1605 int fs, f, voff; 1606 /* Read from ex_get_side_set_ids() */ 1607 int *fs_id; 1608 /* Read from ex_get_side_set_param() */ 1609 int num_side_in_set; 1610 /* Read from ex_get_side_set_node_list() */ 1611 int *fs_vertex_count_list, *fs_vertex_list; 1612 /* Read side set labels */ 1613 char fs_name[MAX_STR_LENGTH+1]; 1614 1615 /* Get side set ids */ 1616 ierr = PetscMalloc1(num_fs, &fs_id);CHKERRQ(ierr); 1617 PetscStackCallStandard(ex_get_ids,(exoid, EX_SIDE_SET, fs_id)); 1618 for (fs = 0; fs < num_fs; ++fs) { 1619 PetscStackCallStandard(ex_get_set_param,(exoid, EX_SIDE_SET, fs_id[fs], &num_side_in_set, NULL)); 1620 ierr = PetscMalloc2(num_side_in_set,&fs_vertex_count_list,num_side_in_set*4,&fs_vertex_list);CHKERRQ(ierr); 1621 PetscStackCallStandard(ex_get_side_set_node_list,(exoid, fs_id[fs], fs_vertex_count_list, fs_vertex_list)); 1622 /* Get the specific name associated with this side set ID. */ 1623 int fs_name_err = ex_get_name(exoid, EX_SIDE_SET, fs_id[fs], fs_name); 1624 for (f = 0, voff = 0; f < num_side_in_set; ++f) { 1625 const PetscInt *faces = NULL; 1626 PetscInt faceSize = fs_vertex_count_list[f], numFaces; 1627 PetscInt faceVertices[4], v; 1628 1629 if (faceSize > 4) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "ExodusII side cannot have %d > 4 vertices", faceSize); 1630 for (v = 0; v < faceSize; ++v, ++voff) { 1631 faceVertices[v] = fs_vertex_list[voff]+numCells-1; 1632 } 1633 ierr = DMPlexGetFullJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 1634 if (numFaces != 1) SETERRQ3(comm, PETSC_ERR_ARG_WRONG, "Invalid ExodusII side %d in set %d maps to %d faces", f, fs, numFaces); 1635 ierr = DMSetLabelValue(*dm, "Face Sets", faces[0], fs_id[fs]);CHKERRQ(ierr); 1636 /* Only add the label if one has been detected for this side set. */ 1637 if (!fs_name_err) { 1638 ierr = DMSetLabelValue(*dm, fs_name, faces[0], fs_id[fs]);CHKERRQ(ierr); 1639 } 1640 ierr = DMPlexRestoreJoin(*dm, faceSize, faceVertices, &numFaces, &faces);CHKERRQ(ierr); 1641 } 1642 ierr = PetscFree2(fs_vertex_count_list,fs_vertex_list);CHKERRQ(ierr); 1643 } 1644 ierr = PetscFree(fs_id);CHKERRQ(ierr); 1645 } 1646 PetscFunctionReturn(0); 1647 #else 1648 SETERRQ(comm, PETSC_ERR_SUP, "This method requires ExodusII support. Reconfigure using --download-exodusii"); 1649 #endif 1650 } 1651