1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 #include <petsc/private/hashseti.h> 4 #include <petscsf.h> 5 #include <petscdmplextransform.h> /*I "petscdmplextransform.h" I*/ 6 #include <petscdmlabelephemeral.h> 7 #include <petsc/private/kernels/blockmatmult.h> 8 #include <petsc/private/kernels/blockinvert.h> 9 10 #ifdef PETSC_HAVE_UNISTD_H 11 #include <unistd.h> 12 #endif 13 #include <errno.h> 14 15 PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList; 16 17 /* External function declarations here */ 18 static PetscErrorCode DMInitialize_Plex(DM dm); 19 20 PETSC_EXTERN PetscErrorCode DMPlexCheckEGADS_Private(DM dm) 21 { 22 PetscObject modelObj; 23 24 PetscFunctionBegin; 25 PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", &modelObj)); 26 PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model"); 27 PetscFunctionReturn(PETSC_SUCCESS); 28 } 29 30 static PetscErrorCode DMPlexCopyContext_Private(DM dmin, const char name[], DM dmout) 31 { 32 PetscObject obj; 33 34 PetscFunctionBegin; 35 PetscCall(PetscObjectQuery((PetscObject)dmin, name, &obj)); 36 if (obj) PetscCall(PetscObjectCompose((PetscObject)dmout, name, obj)); 37 PetscFunctionReturn(PETSC_SUCCESS); 38 } 39 40 static PetscErrorCode DMPlexSwapContext_Private(DM dmA, const char name[], DM dmB) 41 { 42 PetscObject objA, objB; 43 44 PetscFunctionBegin; 45 PetscCall(PetscObjectQuery((PetscObject)dmA, name, &objA)); 46 PetscCall(PetscObjectQuery((PetscObject)dmB, name, &objB)); 47 PetscCall(PetscObjectReference(objA)); 48 PetscCall(PetscObjectReference(objB)); 49 PetscCall(PetscObjectCompose((PetscObject)dmA, name, objB)); 50 PetscCall(PetscObjectCompose((PetscObject)dmB, name, objA)); 51 PetscCall(PetscObjectDereference(objA)); 52 PetscCall(PetscObjectDereference(objB)); 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 PetscErrorCode DMPlexCopyEGADSInfo_Internal(DM dmin, DM dmout) 57 { 58 PetscFunctionBegin; 59 PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Model", dmout)); 60 PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Context", dmout)); 61 PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Model", dmout)); 62 PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Context", dmout)); 63 PetscFunctionReturn(PETSC_SUCCESS); 64 } 65 66 static PetscErrorCode DMPlexSwapEGADSInfo_Private(DM dmA, DM dmB) 67 { 68 PetscFunctionBegin; 69 PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Model", dmB)); 70 PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Context", dmB)); 71 PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Model", dmB)); 72 PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Context", dmB)); 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 76 /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */ 77 PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout) 78 { 79 const PetscReal *maxCell, *Lstart, *L; 80 VecType vecType; 81 MatType matType; 82 PetscBool dist, useCeed, balance_partition; 83 DMReorderDefaultFlag reorder; 84 85 PetscFunctionBegin; 86 if (dmin == dmout) PetscFunctionReturn(PETSC_SUCCESS); 87 PetscCall(DMGetVecType(dmin, &vecType)); 88 PetscCall(DMSetVecType(dmout, vecType)); 89 PetscCall(DMGetMatType(dmin, &matType)); 90 PetscCall(DMSetMatType(dmout, matType)); 91 if (copyPeriodicity) { 92 PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L)); 93 PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L)); 94 PetscCall(DMLocalizeCoordinates(dmout)); 95 } 96 PetscCall(DMPlexDistributeGetDefault(dmin, &dist)); 97 PetscCall(DMPlexDistributeSetDefault(dmout, dist)); 98 PetscCall(DMPlexReorderGetDefault(dmin, &reorder)); 99 PetscCall(DMPlexReorderSetDefault(dmout, reorder)); 100 PetscCall(DMPlexGetUseCeed(dmin, &useCeed)); 101 PetscCall(DMPlexSetUseCeed(dmout, useCeed)); 102 PetscCall(DMPlexGetPartitionBalance(dmin, &balance_partition)); 103 PetscCall(DMPlexSetPartitionBalance(dmout, balance_partition)); 104 ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation; 105 ((DM_Plex *)dmout->data)->printSetValues = ((DM_Plex *)dmin->data)->printSetValues; 106 ((DM_Plex *)dmout->data)->printFEM = ((DM_Plex *)dmin->data)->printFEM; 107 ((DM_Plex *)dmout->data)->printFVM = ((DM_Plex *)dmin->data)->printFVM; 108 ((DM_Plex *)dmout->data)->printL2 = ((DM_Plex *)dmin->data)->printL2; 109 ((DM_Plex *)dmout->data)->printLocate = ((DM_Plex *)dmin->data)->printLocate; 110 ((DM_Plex *)dmout->data)->printProject = ((DM_Plex *)dmin->data)->printProject; 111 ((DM_Plex *)dmout->data)->printTol = ((DM_Plex *)dmin->data)->printTol; 112 if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0)); 113 PetscCall(DMPlexCopyEGADSInfo_Internal(dmin, dmout)); 114 PetscFunctionReturn(PETSC_SUCCESS); 115 } 116 117 /* Replace dm with the contents of ndm, and then destroy ndm 118 - Share the DM_Plex structure 119 - Share the coordinates 120 - Share the SF 121 */ 122 PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm) 123 { 124 PetscSF sf; 125 DM dmNew = *ndm, coordDM, coarseDM; 126 Vec coords; 127 PetscPointFunc coordFunc; 128 const PetscReal *maxCell, *Lstart, *L; 129 PetscInt dim, cdim; 130 PetscBool use_natural; 131 132 PetscFunctionBegin; 133 if (dm == dmNew) { 134 PetscCall(DMDestroy(ndm)); 135 PetscFunctionReturn(PETSC_SUCCESS); 136 } 137 dm->setupcalled = dmNew->setupcalled; 138 if (!dm->hdr.name) { 139 const char *name; 140 141 PetscCall(PetscObjectGetName((PetscObject)*ndm, &name)); 142 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 143 } 144 { 145 PetscInt ndim; 146 147 // If topological dimensions are the same, we retain the old coordinate map, 148 // otherwise we overwrite with the new one 149 PetscCall(DMGetDimension(dm, &dim)); 150 PetscCall(DMGetDimension(dmNew, &ndim)); 151 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 152 if (dim == ndim) PetscCall(DMPlexSetCoordinateMap(dmNew, coordFunc)); 153 } 154 PetscCall(DMGetDimension(dmNew, &dim)); 155 PetscCall(DMSetDimension(dm, dim)); 156 PetscCall(DMGetCoordinateDim(dmNew, &cdim)); 157 PetscCall(DMSetCoordinateDim(dm, cdim)); 158 PetscCall(DMGetPointSF(dmNew, &sf)); 159 PetscCall(DMSetPointSF(dm, sf)); 160 PetscCall(DMGetCoordinateDM(dmNew, &coordDM)); 161 PetscCall(DMGetCoordinatesLocal(dmNew, &coords)); 162 PetscCall(DMSetCoordinateDM(dm, coordDM)); 163 PetscCall(DMSetCoordinatesLocal(dm, coords)); 164 PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM)); 165 PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords)); 166 PetscCall(DMSetCellCoordinateDM(dm, coordDM)); 167 PetscCall(DMSetCellCoordinatesLocal(dm, coords)); 168 /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */ 169 PetscCall(DMFieldDestroy(&dm->coordinates[0].field)); 170 dm->coordinates[0].field = dmNew->coordinates[0].field; 171 PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L)); 172 PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L)); 173 PetscCall(DMGetNaturalSF(dmNew, &sf)); 174 PetscCall(DMSetNaturalSF(dm, sf)); 175 PetscCall(DMGetUseNatural(dmNew, &use_natural)); 176 PetscCall(DMSetUseNatural(dm, use_natural)); 177 PetscCall(DMDestroy_Plex(dm)); 178 PetscCall(DMInitialize_Plex(dm)); 179 dm->data = dmNew->data; 180 ((DM_Plex *)dmNew->data)->refct++; 181 { 182 PetscInt num_face_sfs; 183 const PetscSF *sfs; 184 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &sfs)); 185 PetscCall(DMPlexSetIsoperiodicFaceSF(dm, num_face_sfs, (PetscSF *)sfs)); // for the compose function effect on dm 186 } 187 PetscCall(DMDestroyLabelLinkList_Internal(dm)); 188 PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL)); 189 PetscCall(DMGetCoarseDM(dmNew, &coarseDM)); 190 PetscCall(DMSetCoarseDM(dm, coarseDM)); 191 PetscCall(DMPlexCopyEGADSInfo_Internal(dmNew, dm)); 192 PetscCall(DMDestroy(ndm)); 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 /* Swap dm with the contents of dmNew 197 - Swap the DM_Plex structure 198 - Swap the coordinates 199 - Swap the point PetscSF 200 */ 201 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB) 202 { 203 DM coordDMA, coordDMB; 204 Vec coordsA, coordsB; 205 PetscSF sfA, sfB; 206 DMField fieldTmp; 207 void *tmp; 208 DMLabelLink listTmp; 209 DMLabel depthTmp; 210 PetscInt tmpI; 211 212 PetscFunctionBegin; 213 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 214 PetscCall(DMGetPointSF(dmA, &sfA)); 215 PetscCall(DMGetPointSF(dmB, &sfB)); 216 PetscCall(PetscObjectReference((PetscObject)sfA)); 217 PetscCall(DMSetPointSF(dmA, sfB)); 218 PetscCall(DMSetPointSF(dmB, sfA)); 219 PetscCall(PetscObjectDereference((PetscObject)sfA)); 220 221 PetscCall(DMGetCoordinateDM(dmA, &coordDMA)); 222 PetscCall(DMGetCoordinateDM(dmB, &coordDMB)); 223 PetscCall(PetscObjectReference((PetscObject)coordDMA)); 224 PetscCall(DMSetCoordinateDM(dmA, coordDMB)); 225 PetscCall(DMSetCoordinateDM(dmB, coordDMA)); 226 PetscCall(PetscObjectDereference((PetscObject)coordDMA)); 227 228 PetscCall(DMGetCoordinatesLocal(dmA, &coordsA)); 229 PetscCall(DMGetCoordinatesLocal(dmB, &coordsB)); 230 PetscCall(PetscObjectReference((PetscObject)coordsA)); 231 PetscCall(DMSetCoordinatesLocal(dmA, coordsB)); 232 PetscCall(DMSetCoordinatesLocal(dmB, coordsA)); 233 PetscCall(PetscObjectDereference((PetscObject)coordsA)); 234 235 PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA)); 236 PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB)); 237 PetscCall(PetscObjectReference((PetscObject)coordDMA)); 238 PetscCall(DMSetCellCoordinateDM(dmA, coordDMB)); 239 PetscCall(DMSetCellCoordinateDM(dmB, coordDMA)); 240 PetscCall(PetscObjectDereference((PetscObject)coordDMA)); 241 242 PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA)); 243 PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB)); 244 PetscCall(PetscObjectReference((PetscObject)coordsA)); 245 PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB)); 246 PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA)); 247 PetscCall(PetscObjectDereference((PetscObject)coordsA)); 248 249 PetscCall(DMPlexSwapEGADSInfo_Private(dmA, dmB)); 250 251 fieldTmp = dmA->coordinates[0].field; 252 dmA->coordinates[0].field = dmB->coordinates[0].field; 253 dmB->coordinates[0].field = fieldTmp; 254 fieldTmp = dmA->coordinates[1].field; 255 dmA->coordinates[1].field = dmB->coordinates[1].field; 256 dmB->coordinates[1].field = fieldTmp; 257 tmp = dmA->data; 258 dmA->data = dmB->data; 259 dmB->data = tmp; 260 listTmp = dmA->labels; 261 dmA->labels = dmB->labels; 262 dmB->labels = listTmp; 263 depthTmp = dmA->depthLabel; 264 dmA->depthLabel = dmB->depthLabel; 265 dmB->depthLabel = depthTmp; 266 depthTmp = dmA->celltypeLabel; 267 dmA->celltypeLabel = dmB->celltypeLabel; 268 dmB->celltypeLabel = depthTmp; 269 tmpI = dmA->levelup; 270 dmA->levelup = dmB->levelup; 271 dmB->levelup = tmpI; 272 PetscFunctionReturn(PETSC_SUCCESS); 273 } 274 275 PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm) 276 { 277 DM idm; 278 279 PetscFunctionBegin; 280 PetscCall(DMPlexInterpolate(dm, &idm)); 281 PetscCall(DMPlexCopyCoordinates(dm, idm)); 282 PetscCall(DMPlexReplace_Internal(dm, &idm)); 283 PetscFunctionReturn(PETSC_SUCCESS); 284 } 285 286 /*@C 287 DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates 288 289 Collective 290 291 Input Parameters: 292 + dm - The `DMPLEX` 293 . degree - The degree of the finite element or `PETSC_DECIDE` 294 . project - Flag to project current coordinates into the space 295 - coordFunc - An optional function to map new points from refinement to the surface 296 297 Level: advanced 298 299 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFunc`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()` 300 @*/ 301 PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool project, PetscPointFunc coordFunc) 302 { 303 PetscFE fe = NULL; 304 DM cdm; 305 PetscInt dim, cdim, dE, qorder, height; 306 307 PetscFunctionBegin; 308 PetscCall(DMGetDimension(dm, &dim)); 309 cdim = dim; 310 PetscCall(DMGetCoordinateDim(dm, &dE)); 311 qorder = degree; 312 PetscCall(DMGetCoordinateDM(dm, &cdm)); 313 if (!coordFunc) PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 314 PetscObjectOptionsBegin((PetscObject)cdm); 315 PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0)); 316 PetscCall(PetscOptionsBoundedInt("-dm_plex_coordinate_dim", "Set the coordinate dimension", "DMPlexCreateCoordinateSpace", cdim, &cdim, NULL, dim)); 317 PetscOptionsEnd(); 318 PetscCall(DMPlexGetVTKCellHeight(dm, &height)); 319 if (cdim > dim) { 320 DM cdm; 321 PetscSection cs, csNew; 322 Vec coordinates, coordinatesNew; 323 VecType vectype; 324 IS idx; 325 PetscInt *indices; 326 PetscInt bs, n; 327 328 // Recreate coordinate section 329 { 330 const char *fieldName = NULL, *compName = NULL; 331 PetscInt Nc, pStart, pEnd; 332 333 PetscCall(DMGetCoordinateDM(dm, &cdm)); 334 PetscCall(DMGetLocalSection(cdm, &cs)); 335 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cs), &csNew)); 336 PetscCall(PetscSectionSetNumFields(csNew, 1)); 337 PetscCall(PetscSectionGetFieldName(cs, 0, &fieldName)); 338 PetscCall(PetscSectionSetFieldName(csNew, 0, fieldName)); 339 PetscCall(PetscSectionGetFieldComponents(cs, 0, &Nc)); 340 PetscCall(PetscSectionSetFieldComponents(csNew, 0, cdim)); 341 for (PetscInt c = 0; c < Nc; ++c) { 342 PetscCall(PetscSectionGetComponentName(cs, 0, c, &compName)); 343 PetscCall(PetscSectionSetComponentName(csNew, 0, c, compName)); 344 } 345 PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd)); 346 PetscCall(PetscSectionSetChart(csNew, pStart, pEnd)); 347 for (PetscInt p = pStart; p < pEnd; ++p) { 348 PetscInt dof; 349 350 PetscCall(PetscSectionGetDof(cs, p, &dof)); 351 if (dof) { 352 PetscCall(PetscSectionSetDof(csNew, p, cdim)); 353 PetscCall(PetscSectionSetFieldDof(csNew, p, 0, cdim)); 354 } 355 } 356 PetscCall(PetscSectionSetUp(csNew)); 357 } 358 PetscCall(DMSetLocalSection(cdm, csNew)); 359 PetscCall(PetscSectionDestroy(&csNew)); 360 // Reset coordinate dimension for coordinate DM 361 PetscCall(DMSetCoordinateDim(cdm, cdim)); 362 PetscCall(DMSetCoordinateField(cdm, NULL)); 363 // Inject coordinates into higher dimension 364 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 365 PetscCall(VecGetBlockSize(coordinates, &bs)); 366 PetscCheck(bs == dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension"); 367 PetscCall(VecCreate(PetscObjectComm((PetscObject)coordinates), &coordinatesNew)); 368 PetscCall(VecGetType(coordinates, &vectype)); 369 PetscCall(VecSetType(coordinatesNew, vectype)); 370 PetscCall(VecGetLocalSize(coordinates, &n)); 371 PetscCheck(!(n % bs), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension"); 372 n /= bs; 373 PetscCall(VecSetSizes(coordinatesNew, n * cdim, PETSC_DETERMINE)); 374 PetscCall(VecSetUp(coordinatesNew)); 375 PetscCall(PetscMalloc1(n * bs, &indices)); 376 for (PetscInt i = 0; i < n; ++i) 377 for (PetscInt b = 0; b < bs; ++b) indices[i * bs + b] = i * cdim + b; 378 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n * bs, indices, PETSC_OWN_POINTER, &idx)); 379 PetscCall(VecISCopy(coordinatesNew, idx, SCATTER_FORWARD, coordinates)); 380 PetscCall(ISDestroy(&idx)); 381 PetscCall(DMSetCoordinatesLocal(dm, coordinatesNew)); 382 PetscCall(VecDestroy(&coordinatesNew)); 383 PetscCall(DMSetCoordinateDim(dm, cdim)); 384 { 385 PetscInt gn; 386 387 PetscCall(DMGetCoordinates(dm, &coordinatesNew)); 388 PetscCall(VecGetLocalSize(coordinatesNew, &gn)); 389 PetscCheck(gn == n * cdim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Global coordinate size %" PetscInt_FMT " != %" PetscInt_FMT "local coordinate size", gn, n * cdim); 390 } 391 dE = cdim; 392 project = PETSC_FALSE; 393 } 394 if (degree >= 0) { 395 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 396 PetscInt cStart, cEnd, gct; 397 398 PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd)); 399 if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 400 gct = (PetscInt)ct; 401 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm))); 402 ct = (DMPolytopeType)gct; 403 // Work around current bug in PetscDualSpaceSetUp_Lagrange() 404 // Can be seen in plex_tutorials-ex10_1 405 if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe)); 406 } 407 PetscCall(DMSetCoordinateDisc(dm, fe, project)); 408 PetscCall(PetscFEDestroy(&fe)); 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 /*@ 413 DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement. 414 415 Collective 416 417 Input Parameters: 418 + comm - The communicator for the `DM` object 419 . dim - The spatial dimension 420 . simplex - Flag for simplicial cells, otherwise they are tensor product cells 421 . interpolate - Flag to create intermediate mesh pieces (edges, faces) 422 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell 423 424 Output Parameter: 425 . newdm - The `DM` object 426 427 Level: beginner 428 429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()` 430 @*/ 431 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm) 432 { 433 DM dm; 434 PetscMPIInt rank; 435 436 PetscFunctionBegin; 437 PetscCall(DMCreate(comm, &dm)); 438 PetscCall(DMSetType(dm, DMPLEX)); 439 PetscCall(DMSetDimension(dm, dim)); 440 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 441 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 442 switch (dim) { 443 case 2: 444 if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular")); 445 else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral")); 446 break; 447 case 3: 448 if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral")); 449 else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral")); 450 break; 451 default: 452 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim); 453 } 454 if (rank) { 455 PetscInt numPoints[2] = {0, 0}; 456 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL)); 457 } else { 458 switch (dim) { 459 case 2: 460 if (simplex) { 461 PetscInt numPoints[2] = {4, 2}; 462 PetscInt coneSize[6] = {3, 3, 0, 0, 0, 0}; 463 PetscInt cones[6] = {2, 3, 4, 5, 4, 3}; 464 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 465 PetscScalar vertexCoords[8] = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5}; 466 467 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 468 } else { 469 PetscInt numPoints[2] = {6, 2}; 470 PetscInt coneSize[8] = {4, 4, 0, 0, 0, 0, 0, 0}; 471 PetscInt cones[8] = {2, 3, 4, 5, 3, 6, 7, 4}; 472 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 473 PetscScalar vertexCoords[12] = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5}; 474 475 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 476 } 477 break; 478 case 3: 479 if (simplex) { 480 PetscInt numPoints[2] = {5, 2}; 481 PetscInt coneSize[7] = {4, 4, 0, 0, 0, 0, 0}; 482 PetscInt cones[8] = {4, 3, 5, 2, 5, 3, 4, 6}; 483 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 484 PetscScalar vertexCoords[15] = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0}; 485 486 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 487 } else { 488 PetscInt numPoints[2] = {12, 2}; 489 PetscInt coneSize[14] = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 490 PetscInt cones[16] = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8}; 491 PetscInt coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 492 PetscScalar vertexCoords[36] = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5}; 493 494 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 495 } 496 break; 497 default: 498 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim); 499 } 500 } 501 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 502 *newdm = dm; 503 if (refinementLimit > 0.0) { 504 DM rdm; 505 const char *name; 506 507 PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE)); 508 PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit)); 509 PetscCall(DMRefine(*newdm, comm, &rdm)); 510 PetscCall(PetscObjectGetName((PetscObject)*newdm, &name)); 511 PetscCall(PetscObjectSetName((PetscObject)rdm, name)); 512 PetscCall(DMDestroy(newdm)); 513 *newdm = rdm; 514 } 515 if (interpolate) { 516 DM idm; 517 518 PetscCall(DMPlexInterpolate(*newdm, &idm)); 519 PetscCall(DMDestroy(newdm)); 520 *newdm = idm; 521 } 522 PetscFunctionReturn(PETSC_SUCCESS); 523 } 524 525 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[]) 526 { 527 const PetscInt numVertices = 2; 528 PetscInt markerRight = 1; 529 PetscInt markerLeft = 1; 530 PetscBool markerSeparate = PETSC_FALSE; 531 Vec coordinates; 532 PetscSection coordSection; 533 PetscScalar *coords; 534 PetscInt coordSize; 535 PetscMPIInt rank; 536 PetscInt cdim = 1, v; 537 538 PetscFunctionBegin; 539 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 540 if (markerSeparate) { 541 markerRight = 2; 542 markerLeft = 1; 543 } 544 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 545 if (rank == 0) { 546 PetscCall(DMPlexSetChart(dm, 0, numVertices)); 547 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 548 PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft)); 549 PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight)); 550 } 551 PetscCall(DMPlexSymmetrize(dm)); 552 PetscCall(DMPlexStratify(dm)); 553 /* Build coordinates */ 554 PetscCall(DMSetCoordinateDim(dm, cdim)); 555 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 556 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 557 PetscCall(PetscSectionSetChart(coordSection, 0, numVertices)); 558 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 559 for (v = 0; v < numVertices; ++v) { 560 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 561 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 562 } 563 PetscCall(PetscSectionSetUp(coordSection)); 564 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 565 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 566 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 567 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 568 PetscCall(VecSetBlockSize(coordinates, cdim)); 569 PetscCall(VecSetType(coordinates, VECSTANDARD)); 570 PetscCall(VecGetArray(coordinates, &coords)); 571 coords[0] = lower[0]; 572 coords[1] = upper[0]; 573 PetscCall(VecRestoreArray(coordinates, &coords)); 574 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 575 PetscCall(VecDestroy(&coordinates)); 576 PetscFunctionReturn(PETSC_SUCCESS); 577 } 578 579 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[]) 580 { 581 const PetscInt numVertices = (edges[0] + 1) * (edges[1] + 1); 582 const PetscInt numEdges = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1]; 583 PetscInt markerTop = 1; 584 PetscInt markerBottom = 1; 585 PetscInt markerRight = 1; 586 PetscInt markerLeft = 1; 587 PetscBool markerSeparate = PETSC_FALSE; 588 Vec coordinates; 589 PetscSection coordSection; 590 PetscScalar *coords; 591 PetscInt coordSize; 592 PetscMPIInt rank; 593 PetscInt v, vx, vy; 594 595 PetscFunctionBegin; 596 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 597 if (markerSeparate) { 598 markerTop = 3; 599 markerBottom = 1; 600 markerRight = 2; 601 markerLeft = 4; 602 } 603 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 604 if (rank == 0) { 605 PetscInt e, ex, ey; 606 607 PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices)); 608 for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 609 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 610 for (vx = 0; vx <= edges[0]; vx++) { 611 for (ey = 0; ey < edges[1]; ey++) { 612 PetscInt edge = vx * edges[1] + ey + edges[0] * (edges[1] + 1); 613 PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges; 614 PetscInt cone[2]; 615 616 cone[0] = vertex; 617 cone[1] = vertex + edges[0] + 1; 618 PetscCall(DMPlexSetCone(dm, edge, cone)); 619 if (vx == edges[0]) { 620 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 621 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 622 if (ey == edges[1] - 1) { 623 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 624 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight)); 625 } 626 } else if (vx == 0) { 627 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 628 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 629 if (ey == edges[1] - 1) { 630 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 631 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft)); 632 } 633 } 634 } 635 } 636 for (vy = 0; vy <= edges[1]; vy++) { 637 for (ex = 0; ex < edges[0]; ex++) { 638 PetscInt edge = vy * edges[0] + ex; 639 PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges; 640 PetscInt cone[2]; 641 642 cone[0] = vertex; 643 cone[1] = vertex + 1; 644 PetscCall(DMPlexSetCone(dm, edge, cone)); 645 if (vy == edges[1]) { 646 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 647 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 648 if (ex == edges[0] - 1) { 649 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 650 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop)); 651 } 652 } else if (vy == 0) { 653 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 654 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 655 if (ex == edges[0] - 1) { 656 PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 657 PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom)); 658 } 659 } 660 } 661 } 662 } 663 PetscCall(DMPlexSymmetrize(dm)); 664 PetscCall(DMPlexStratify(dm)); 665 /* Build coordinates */ 666 PetscCall(DMSetCoordinateDim(dm, 2)); 667 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 668 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 669 PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices)); 670 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2)); 671 for (v = numEdges; v < numEdges + numVertices; ++v) { 672 PetscCall(PetscSectionSetDof(coordSection, v, 2)); 673 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2)); 674 } 675 PetscCall(PetscSectionSetUp(coordSection)); 676 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 677 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 678 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 679 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 680 PetscCall(VecSetBlockSize(coordinates, 2)); 681 PetscCall(VecSetType(coordinates, VECSTANDARD)); 682 PetscCall(VecGetArray(coordinates, &coords)); 683 for (vy = 0; vy <= edges[1]; ++vy) { 684 for (vx = 0; vx <= edges[0]; ++vx) { 685 coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx; 686 coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy; 687 } 688 } 689 PetscCall(VecRestoreArray(coordinates, &coords)); 690 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 691 PetscCall(VecDestroy(&coordinates)); 692 PetscFunctionReturn(PETSC_SUCCESS); 693 } 694 695 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[]) 696 { 697 PetscInt vertices[3], numVertices; 698 PetscInt numFaces = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2]; 699 PetscInt markerTop = 1; 700 PetscInt markerBottom = 1; 701 PetscInt markerFront = 1; 702 PetscInt markerBack = 1; 703 PetscInt markerRight = 1; 704 PetscInt markerLeft = 1; 705 PetscBool markerSeparate = PETSC_FALSE; 706 Vec coordinates; 707 PetscSection coordSection; 708 PetscScalar *coords; 709 PetscInt coordSize; 710 PetscMPIInt rank; 711 PetscInt v, vx, vy, vz; 712 PetscInt voffset, iface = 0, cone[4]; 713 714 PetscFunctionBegin; 715 PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side"); 716 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 717 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 718 if (markerSeparate) { 719 markerBottom = 1; 720 markerTop = 2; 721 markerFront = 3; 722 markerBack = 4; 723 markerRight = 5; 724 markerLeft = 6; 725 } 726 vertices[0] = faces[0] + 1; 727 vertices[1] = faces[1] + 1; 728 vertices[2] = faces[2] + 1; 729 numVertices = vertices[0] * vertices[1] * vertices[2]; 730 if (rank == 0) { 731 PetscInt f; 732 733 PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices)); 734 for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4)); 735 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 736 737 /* Side 0 (Top) */ 738 for (vy = 0; vy < faces[1]; vy++) { 739 for (vx = 0; vx < faces[0]; vx++) { 740 voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx; 741 cone[0] = voffset; 742 cone[1] = voffset + 1; 743 cone[2] = voffset + vertices[0] + 1; 744 cone[3] = voffset + vertices[0]; 745 PetscCall(DMPlexSetCone(dm, iface, cone)); 746 PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop)); 747 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop)); 748 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop)); 749 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop)); 750 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop)); 751 iface++; 752 } 753 } 754 755 /* Side 1 (Bottom) */ 756 for (vy = 0; vy < faces[1]; vy++) { 757 for (vx = 0; vx < faces[0]; vx++) { 758 voffset = numFaces + vy * (faces[0] + 1) + vx; 759 cone[0] = voffset + 1; 760 cone[1] = voffset; 761 cone[2] = voffset + vertices[0]; 762 cone[3] = voffset + vertices[0] + 1; 763 PetscCall(DMPlexSetCone(dm, iface, cone)); 764 PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom)); 765 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom)); 766 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom)); 767 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom)); 768 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom)); 769 iface++; 770 } 771 } 772 773 /* Side 2 (Front) */ 774 for (vz = 0; vz < faces[2]; vz++) { 775 for (vx = 0; vx < faces[0]; vx++) { 776 voffset = numFaces + vz * vertices[0] * vertices[1] + vx; 777 cone[0] = voffset; 778 cone[1] = voffset + 1; 779 cone[2] = voffset + vertices[0] * vertices[1] + 1; 780 cone[3] = voffset + vertices[0] * vertices[1]; 781 PetscCall(DMPlexSetCone(dm, iface, cone)); 782 PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront)); 783 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront)); 784 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront)); 785 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront)); 786 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront)); 787 iface++; 788 } 789 } 790 791 /* Side 3 (Back) */ 792 for (vz = 0; vz < faces[2]; vz++) { 793 for (vx = 0; vx < faces[0]; vx++) { 794 voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx; 795 cone[0] = voffset + vertices[0] * vertices[1]; 796 cone[1] = voffset + vertices[0] * vertices[1] + 1; 797 cone[2] = voffset + 1; 798 cone[3] = voffset; 799 PetscCall(DMPlexSetCone(dm, iface, cone)); 800 PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack)); 801 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack)); 802 PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack)); 803 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack)); 804 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack)); 805 iface++; 806 } 807 } 808 809 /* Side 4 (Left) */ 810 for (vz = 0; vz < faces[2]; vz++) { 811 for (vy = 0; vy < faces[1]; vy++) { 812 voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0]; 813 cone[0] = voffset; 814 cone[1] = voffset + vertices[0] * vertices[1]; 815 cone[2] = voffset + vertices[0] * vertices[1] + vertices[0]; 816 cone[3] = voffset + vertices[0]; 817 PetscCall(DMPlexSetCone(dm, iface, cone)); 818 PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft)); 819 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft)); 820 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft)); 821 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft)); 822 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft)); 823 iface++; 824 } 825 } 826 827 /* Side 5 (Right) */ 828 for (vz = 0; vz < faces[2]; vz++) { 829 for (vy = 0; vy < faces[1]; vy++) { 830 voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0]; 831 cone[0] = voffset + vertices[0] * vertices[1]; 832 cone[1] = voffset; 833 cone[2] = voffset + vertices[0]; 834 cone[3] = voffset + vertices[0] * vertices[1] + vertices[0]; 835 PetscCall(DMPlexSetCone(dm, iface, cone)); 836 PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight)); 837 PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight)); 838 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight)); 839 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight)); 840 PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight)); 841 iface++; 842 } 843 } 844 } 845 PetscCall(DMPlexSymmetrize(dm)); 846 PetscCall(DMPlexStratify(dm)); 847 /* Build coordinates */ 848 PetscCall(DMSetCoordinateDim(dm, 3)); 849 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 850 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 851 PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices)); 852 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3)); 853 for (v = numFaces; v < numFaces + numVertices; ++v) { 854 PetscCall(PetscSectionSetDof(coordSection, v, 3)); 855 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3)); 856 } 857 PetscCall(PetscSectionSetUp(coordSection)); 858 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 859 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 860 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 861 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 862 PetscCall(VecSetBlockSize(coordinates, 3)); 863 PetscCall(VecSetType(coordinates, VECSTANDARD)); 864 PetscCall(VecGetArray(coordinates, &coords)); 865 for (vz = 0; vz <= faces[2]; ++vz) { 866 for (vy = 0; vy <= faces[1]; ++vy) { 867 for (vx = 0; vx <= faces[0]; ++vx) { 868 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx; 869 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy; 870 coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz; 871 } 872 } 873 } 874 PetscCall(VecRestoreArray(coordinates, &coords)); 875 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 876 PetscCall(VecDestroy(&coordinates)); 877 PetscFunctionReturn(PETSC_SUCCESS); 878 } 879 880 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate) 881 { 882 PetscFunctionBegin; 883 PetscValidLogicalCollectiveInt(dm, dim, 2); 884 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 885 PetscCall(DMSetDimension(dm, dim - 1)); 886 PetscCall(DMSetCoordinateDim(dm, dim)); 887 switch (dim) { 888 case 1: 889 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces)); 890 break; 891 case 2: 892 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces)); 893 break; 894 case 3: 895 PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces)); 896 break; 897 default: 898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim); 899 } 900 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 901 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 902 PetscFunctionReturn(PETSC_SUCCESS); 903 } 904 905 /*@C 906 DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra). 907 908 Collective 909 910 Input Parameters: 911 + comm - The communicator for the `DM` object 912 . dim - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1 913 . faces - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 914 . lower - The lower left corner, or `NULL` for (0, 0, 0) 915 . upper - The upper right corner, or `NULL` for (1, 1, 1) 916 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 917 918 Output Parameter: 919 . dm - The `DM` object 920 921 Level: beginner 922 923 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()` 924 @*/ 925 PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm) 926 { 927 PetscInt fac[3] = {1, 1, 1}; 928 PetscReal low[3] = {0, 0, 0}; 929 PetscReal upp[3] = {1, 1, 1}; 930 931 PetscFunctionBegin; 932 PetscCall(DMCreate(comm, dm)); 933 PetscCall(DMSetType(*dm, DMPLEX)); 934 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate)); 935 PetscFunctionReturn(PETSC_SUCCESS); 936 } 937 938 static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd) 939 { 940 PetscInt i, fStart, fEnd, numCells = 0, numVerts = 0; 941 PetscInt numPoints[2], *coneSize, *cones, *coneOrientations; 942 PetscScalar *vertexCoords; 943 PetscReal L, maxCell; 944 PetscBool markerSeparate = PETSC_FALSE; 945 PetscInt markerLeft = 1, faceMarkerLeft = 1; 946 PetscInt markerRight = 1, faceMarkerRight = 2; 947 PetscBool wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE; 948 PetscMPIInt rank; 949 950 PetscFunctionBegin; 951 PetscAssertPointer(dm, 1); 952 953 PetscCall(DMSetDimension(dm, 1)); 954 PetscCall(DMCreateLabel(dm, "marker")); 955 PetscCall(DMCreateLabel(dm, "Face Sets")); 956 957 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 958 if (rank == 0) numCells = segments; 959 if (rank == 0) numVerts = segments + (wrap ? 0 : 1); 960 961 numPoints[0] = numVerts; 962 numPoints[1] = numCells; 963 PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords)); 964 PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts)); 965 for (i = 0; i < numCells; ++i) coneSize[i] = 2; 966 for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0; 967 for (i = 0; i < numCells; ++i) { 968 cones[2 * i] = numCells + i % numVerts; 969 cones[2 * i + 1] = numCells + (i + 1) % numVerts; 970 } 971 for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells); 972 PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 973 PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords)); 974 975 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 976 if (markerSeparate) { 977 markerLeft = faceMarkerLeft; 978 markerRight = faceMarkerRight; 979 } 980 if (!wrap && rank == 0) { 981 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 982 PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft)); 983 PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight)); 984 PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft)); 985 PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight)); 986 } 987 if (wrap) { 988 L = upper - lower; 989 maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments)); 990 PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L)); 991 } 992 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 993 PetscFunctionReturn(PETSC_SUCCESS); 994 } 995 996 // Creates "Face Sets" label based on the standard box labeling conventions 997 static PetscErrorCode DMPlexSetBoxLabel_Internal(DM dm, const DMBoundaryType periodicity[]) 998 { 999 DM cdm; 1000 PetscSection csection; 1001 Vec coordinates; 1002 DMLabel label; 1003 IS faces_is; 1004 PetscInt dim, num_face = 0; 1005 const PetscInt *faces; 1006 PetscInt faceMarkerBottom, faceMarkerTop, faceMarkerFront, faceMarkerBack, faceMarkerRight, faceMarkerLeft; 1007 1008 PetscFunctionBeginUser; 1009 PetscCall(DMGetDimension(dm, &dim)); 1010 PetscCheck((dim == 2) || (dim == 3), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex box labeling only supports 2D and 3D meshes, received DM of dimension %" PetscInt_FMT, dim); 1011 // Get Face Sets label 1012 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 1013 if (label) { 1014 PetscCall(DMLabelReset(label)); 1015 } else { 1016 PetscCall(DMCreateLabel(dm, "Face Sets")); 1017 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 1018 } 1019 PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label)); 1020 PetscCall(DMGetStratumIS(dm, "Face Sets", 1, &faces_is)); 1021 1022 switch (dim) { 1023 case 2: 1024 faceMarkerTop = 3; 1025 faceMarkerBottom = 1; 1026 faceMarkerRight = 2; 1027 faceMarkerLeft = 4; 1028 break; 1029 case 3: 1030 faceMarkerBottom = 1; 1031 faceMarkerTop = 2; 1032 faceMarkerFront = 3; 1033 faceMarkerBack = 4; 1034 faceMarkerRight = 5; 1035 faceMarkerLeft = 6; 1036 break; 1037 default: 1038 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim); 1039 } 1040 1041 if (faces_is) PetscCall(ISGetLocalSize(faces_is, &num_face)); 1042 if (faces_is) PetscCall(ISGetIndices(faces_is, &faces)); 1043 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1044 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1045 PetscCall(DMGetLocalSection(cdm, &csection)); 1046 for (PetscInt f = 0; f < num_face; ++f) { 1047 PetscScalar *coords = NULL; 1048 PetscInt face = faces[f], flip = 1, label_value = -1, coords_size; 1049 1050 { // Determine if orientation of face is flipped 1051 PetscInt num_cells_support, num_faces, start = -1; 1052 const PetscInt *orients, *cell_faces, *cells; 1053 1054 PetscCall(DMPlexGetSupport(dm, face, &cells)); 1055 PetscCall(DMPlexGetSupportSize(dm, face, &num_cells_support)); 1056 PetscCheck(num_cells_support == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Expected one cell in support of exterior face, but got %" PetscInt_FMT " cells", num_cells_support); 1057 PetscCall(DMPlexGetCone(dm, cells[0], &cell_faces)); 1058 PetscCall(DMPlexGetConeSize(dm, cells[0], &num_faces)); 1059 for (PetscInt i = 0; i < num_faces; i++) { 1060 if (cell_faces[i] == face) start = i; 1061 } 1062 PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Could not find face %" PetscInt_FMT " in cone of its support", face); 1063 PetscCall(DMPlexGetConeOrientation(dm, cells[0], &orients)); 1064 if (orients[start] < 0) flip = -1; 1065 } 1066 1067 // Cannot use DMPlexComputeCellGeometryFVM() for high-order geometry, so must calculate normal vectors manually 1068 // Use the vertices (depth 0) of coordinate DM to calculate normal vector 1069 PetscCall(DMPlexVecGetClosureAtDepth_Internal(cdm, csection, coordinates, face, 0, &coords_size, &coords)); 1070 switch (dim) { 1071 case 2: { 1072 PetscScalar vec[2]; 1073 1074 for (PetscInt d = 0; d < dim; ++d) vec[d] = flip * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d])); 1075 PetscScalar normal[] = {vec[1], -vec[0]}; 1076 if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) { 1077 label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft; 1078 } else { 1079 label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerTop : faceMarkerBottom; 1080 } 1081 } break; 1082 case 3: { 1083 PetscScalar vec1[3], vec2[3], normal[3]; 1084 1085 for (PetscInt d = 0; d < dim; ++d) { 1086 vec1[d] = PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]); 1087 vec2[d] = PetscRealPart(coords[2 * dim + d]) - PetscRealPart(coords[1 * dim + d]); 1088 } 1089 1090 // Calculate normal vector via cross-product 1091 normal[0] = flip * ((vec1[1] * vec2[2]) - (vec1[2] * vec2[1])); 1092 normal[1] = flip * ((vec1[2] * vec2[0]) - (vec1[0] * vec2[2])); 1093 normal[2] = flip * ((vec1[0] * vec2[1]) - (vec1[1] * vec2[0])); 1094 1095 if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) { 1096 if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[2])) { 1097 label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft; 1098 } else { 1099 label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom; 1100 } 1101 } else { 1102 if (PetscAbsScalar(normal[1]) > PetscAbsScalar(normal[2])) { 1103 label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerBack : faceMarkerFront; 1104 } else { 1105 label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom; 1106 } 1107 } 1108 } break; 1109 } 1110 1111 PetscInt previous_label_value; // always 1 due to DMPlexMarkBoundaryFaces call above 1112 PetscCall(DMGetLabelValue(dm, "Face Sets", face, &previous_label_value)); 1113 PetscCall(DMClearLabelValue(dm, "Face Sets", face, previous_label_value)); 1114 PetscCall(DMSetLabelValue(dm, "Face Sets", face, label_value)); 1115 PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords)); 1116 } 1117 if (faces_is) PetscCall(ISRestoreIndices(faces_is, &faces)); 1118 PetscCall(ISDestroy(&faces_is)); 1119 1120 // Create Isoperiodic SF from newly-created face labels 1121 PetscSF periodicsfs[3]; 1122 PetscInt periodic_sf_index = 0; 1123 PetscScalar transform[3][4][4] = {{{0.}}}; 1124 for (PetscInt d = 0; d < dim; d++) { 1125 IS donor_is, periodic_is; 1126 const PetscInt *donor_faces = NULL, *periodic_faces = NULL; 1127 PetscInt num_donor = 0, num_periodic = 0; 1128 PetscSF centroidsf; 1129 PetscReal donor_to_periodic_distance; 1130 const PetscInt face_pairings[2][3][2] = { 1131 // 2D face pairings, {donor, periodic} 1132 {{4, 2}, {1, 3}}, 1133 // 3D face pairings 1134 {{5, 6}, {3, 4}, {1, 2}} 1135 }; 1136 1137 if (periodicity[d] != DM_BOUNDARY_PERIODIC) continue; 1138 { 1139 // Compute centroidsf, which is the mapping from donor faces to periodic faces 1140 // Matches the centroid of the faces together, ignoring the periodic direction component (which should not match between donor and periodic face) 1141 PetscInt coords_size, centroid_comps = dim - 1; 1142 PetscScalar *coords = NULL; 1143 PetscReal *donor_centroids, *periodic_centroids; 1144 PetscReal loc_periodic[2] = {PETSC_MIN_REAL, PETSC_MIN_REAL}, loc_periodic_global[2]; // Location of donor (0) and periodic (1) faces in periodic direction 1145 1146 PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][0], &donor_is)); 1147 PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][1], &periodic_is)); 1148 if (donor_is) { 1149 PetscCall(ISGetLocalSize(donor_is, &num_donor)); 1150 PetscCall(ISGetIndices(donor_is, &donor_faces)); 1151 } 1152 if (periodic_is) { 1153 PetscCall(ISGetLocalSize(periodic_is, &num_periodic)); 1154 PetscCall(ISGetIndices(periodic_is, &periodic_faces)); 1155 } 1156 PetscCall(PetscCalloc2(num_donor * centroid_comps, &donor_centroids, num_periodic * centroid_comps, &periodic_centroids)); 1157 for (PetscInt f = 0; f < num_donor; f++) { 1158 PetscInt face = donor_faces[f], num_coords; 1159 PetscCall(DMPlexVecGetClosureAtDepth_Internal(cdm, csection, coordinates, face, 0, &coords_size, &coords)); 1160 num_coords = coords_size / dim; 1161 for (PetscInt c = 0; c < num_coords; c++) { 1162 PetscInt comp_index = 0; 1163 loc_periodic[0] = PetscRealPart(coords[c * dim + d]); 1164 for (PetscInt i = 0; i < dim; i++) { 1165 if (i == d) continue; // Periodic direction not used for centroid calculation 1166 donor_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords; 1167 comp_index++; 1168 } 1169 } 1170 PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords)); 1171 } 1172 1173 for (PetscInt f = 0; f < num_periodic; f++) { 1174 PetscInt face = periodic_faces[f], num_coords; 1175 PetscCall(DMPlexVecGetClosureAtDepth_Internal(cdm, csection, coordinates, face, 0, &coords_size, &coords)); 1176 num_coords = coords_size / dim; 1177 for (PetscInt c = 0; c < num_coords; c++) { 1178 PetscInt comp_index = 0; 1179 loc_periodic[1] = PetscRealPart(coords[c * dim + d]); 1180 for (PetscInt i = 0; i < dim; i++) { 1181 if (i == d) continue; // Periodic direction not used for centroid calculation 1182 periodic_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords; 1183 comp_index++; 1184 } 1185 } 1186 PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords)); 1187 } 1188 PetscCallMPI(MPIU_Allreduce(loc_periodic, loc_periodic_global, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1189 donor_to_periodic_distance = loc_periodic_global[1] - loc_periodic_global[0]; 1190 1191 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), ¢roidsf)); 1192 PetscCall(PetscSFSetGraphFromCoordinates(centroidsf, num_donor, num_periodic, centroid_comps, 1e-10, donor_centroids, periodic_centroids)); 1193 PetscCall(PetscSFViewFromOptions(centroidsf, NULL, "-dm_plex_box_label_centroid_sf_view")); 1194 PetscCall(PetscFree2(donor_centroids, periodic_centroids)); 1195 } 1196 1197 { // Create Isoperiodic SF using centroidsSF 1198 PetscInt pStart, pEnd; 1199 PetscInt *leaf_faces; 1200 const PetscSFNode *firemote; 1201 PetscSFNode *isoperiodic_leaves; 1202 1203 PetscCall(PetscMalloc1(num_periodic, &leaf_faces)); 1204 PetscCall(PetscSFBcastBegin(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE)); 1205 PetscCall(PetscSFBcastEnd(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE)); 1206 1207 PetscCall(PetscMalloc1(num_periodic, &isoperiodic_leaves)); 1208 PetscCall(PetscSFGetGraph(centroidsf, NULL, NULL, NULL, &firemote)); 1209 for (PetscInt l = 0; l < num_periodic; ++l) { 1210 isoperiodic_leaves[l].index = leaf_faces[l]; 1211 isoperiodic_leaves[l].rank = firemote[l].rank; 1212 } 1213 1214 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1215 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &periodicsfs[periodic_sf_index])); 1216 PetscCall(PetscSFSetGraph(periodicsfs[periodic_sf_index], pEnd - pStart, num_periodic, (PetscInt *)periodic_faces, PETSC_COPY_VALUES, isoperiodic_leaves, PETSC_OWN_POINTER)); 1217 PetscCall(PetscSFViewFromOptions(periodicsfs[periodic_sf_index], NULL, "-dm_plex_box_label_periodic_sf_view")); 1218 PetscCall(PetscFree(leaf_faces)); 1219 } 1220 1221 transform[periodic_sf_index][0][0] = 1; 1222 transform[periodic_sf_index][1][1] = 1; 1223 transform[periodic_sf_index][2][2] = 1; 1224 transform[periodic_sf_index][3][3] = 1; 1225 transform[periodic_sf_index][d][3] = donor_to_periodic_distance; 1226 1227 periodic_sf_index++; 1228 PetscCall(PetscSFDestroy(¢roidsf)); 1229 if (donor_is) { 1230 PetscCall(ISRestoreIndices(donor_is, &donor_faces)); 1231 PetscCall(ISDestroy(&donor_is)); 1232 } 1233 if (periodic_is) { 1234 PetscCall(ISRestoreIndices(periodic_is, &periodic_faces)); 1235 PetscCall(ISDestroy(&periodic_is)); 1236 } 1237 PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][0])); 1238 PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][1])); 1239 } 1240 PetscCall(DMPlexSetIsoperiodicFaceSF(dm, periodic_sf_index, periodicsfs)); 1241 PetscCall(DMPlexSetIsoperiodicFaceTransform(dm, periodic_sf_index, (const PetscScalar *)transform)); 1242 for (PetscInt p = 0; p < periodic_sf_index; p++) PetscCall(PetscSFDestroy(&periodicsfs[p])); 1243 1244 { // Update coordinate DM with new Face Sets label 1245 DM cdm; 1246 DMLabel oldFaceSets, newFaceSets; 1247 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1248 PetscCall(DMGetLabel(cdm, "Face Sets", &oldFaceSets)); 1249 if (oldFaceSets) PetscCall(DMRemoveLabelBySelf(cdm, &oldFaceSets, PETSC_FALSE)); 1250 PetscCall(DMLabelDuplicate(label, &newFaceSets)); 1251 PetscCall(DMAddLabel(cdm, newFaceSets)); 1252 PetscCall(DMLabelDestroy(&newFaceSets)); 1253 } 1254 PetscFunctionReturn(PETSC_SUCCESS); 1255 } 1256 1257 static PetscErrorCode DMPlexCreateSquareMesh_Simplex_CrissCross(DM dm, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType bd[]) 1258 { 1259 PetscInt markerTop = 1, faceMarkerTop = 3; 1260 PetscInt markerBottom = 1, faceMarkerBottom = 1; 1261 PetscInt markerRight = 1, faceMarkerRight = 2; 1262 PetscInt markerLeft = 1, faceMarkerLeft = 4; 1263 PetscBool markerSeparate = PETSC_FALSE; 1264 DMBoundaryType bdX = bd[0], bdY = bd[1]; 1265 PetscMPIInt rank; 1266 1267 PetscFunctionBegin; 1268 PetscCheck(bdX == DM_BOUNDARY_NONE || bdX == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdX]); 1269 PetscCheck(bdY == DM_BOUNDARY_NONE || bdY == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdY]); 1270 PetscCall(DMSetDimension(dm, 2)); 1271 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1272 PetscCall(DMCreateLabel(dm, "marker")); 1273 PetscCall(DMCreateLabel(dm, "Face Sets")); 1274 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 1275 if (markerSeparate) { 1276 markerBottom = faceMarkerBottom; 1277 markerTop = faceMarkerTop; 1278 markerRight = faceMarkerRight; 1279 markerLeft = faceMarkerLeft; 1280 } 1281 { 1282 const PetscInt numXEdges = rank == 0 ? edges[0] : 0; 1283 const PetscInt numYEdges = rank == 0 ? edges[1] : 0; 1284 const PetscInt numZEdges = rank == 0 ? 4 * edges[0] * edges[1] : 0; /* Z-edges are the 4 internal edges per cell */ 1285 const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC ? edges[0] : edges[0] + 1) : 0; 1286 const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC ? edges[1] : edges[1] + 1) : 0; 1287 const PetscInt numZVertices = rank == 0 ? edges[0] * edges[1] : 0; 1288 const PetscInt numCells = 4 * numXEdges * numYEdges; 1289 const PetscInt numTotXEdges = numXEdges * numYVertices; 1290 const PetscInt numTotYEdges = numYEdges * numXVertices; 1291 const PetscInt numVertices = numXVertices * numYVertices + numZVertices; 1292 const PetscInt numEdges = numTotXEdges + numTotYEdges + numZEdges; 1293 const PetscInt firstVertex = numCells; 1294 const PetscInt firstXEdge = numCells + numVertices; 1295 const PetscInt firstYEdge = firstXEdge + numTotXEdges; 1296 const PetscInt firstZEdge = firstYEdge + numTotYEdges; 1297 Vec coordinates; 1298 PetscSection coordSection; 1299 PetscScalar *coords; 1300 PetscInt coordSize; 1301 PetscInt v, vx, vy; 1302 PetscInt c, e, ex, ey; 1303 1304 PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVertices)); 1305 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 3)); 1306 for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 1307 PetscCall(DMSetUp(dm)); 1308 1309 /* Build cells and Z-edges */ 1310 for (ey = 0; ey < numYEdges; ++ey) { 1311 for (ex = 0; ex < numXEdges; ++ex) { 1312 const PetscInt exp1 = (ex + 1) % numXVertices; 1313 const PetscInt eyp1 = (ey + 1) % numYVertices; 1314 const PetscInt ez = firstZEdge + 4 * (ey * numXEdges + ex); 1315 const PetscInt vc = firstVertex + numXVertices * numYVertices + ey * numXEdges + ex; 1316 const PetscInt v0 = firstVertex + ey * numXVertices + ex; 1317 const PetscInt v1 = firstVertex + ey * numXVertices + exp1; 1318 const PetscInt v2 = firstVertex + eyp1 * numXVertices + exp1; 1319 const PetscInt v3 = firstVertex + eyp1 * numXVertices + ex; 1320 const PetscInt e0 = firstXEdge + ey * numXEdges + ex; 1321 const PetscInt e1 = firstYEdge + exp1 * numYEdges + ey; 1322 const PetscInt e2 = firstXEdge + eyp1 * numXEdges + ex; 1323 const PetscInt e3 = firstYEdge + ex * numYEdges + ey; 1324 1325 const PetscInt cones[] = {ez, e0, ez + 1, ez + 1, e1, ez + 2, ez + 2, e2, ez + 3, ez + 3, e3, ez}; 1326 const PetscInt ornts[] = {-1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0}; 1327 const PetscInt verts[] = {v0, vc, v1, vc, v2, vc, v3, vc}; 1328 1329 for (c = 0; c < 4; c++) { 1330 PetscInt cell = 4 * (ey * numXEdges + ex) + c; 1331 PetscInt edge = ez + c; 1332 1333 PetscCall(DMPlexSetCone(dm, cell, cones + 3 * c)); 1334 PetscCall(DMPlexSetConeOrientation(dm, cell, ornts + 3 * c)); 1335 PetscCall(DMPlexSetCone(dm, edge, verts + 2 * c)); 1336 } 1337 } 1338 } 1339 1340 /* Build Y edges*/ 1341 for (vx = 0; vx < numXVertices; vx++) { 1342 for (ey = 0; ey < numYEdges; ey++) { 1343 const PetscInt edge = firstYEdge + vx * numYEdges + ey; 1344 const PetscInt v0 = firstVertex + ey * numXVertices + vx; 1345 const PetscInt v1 = firstVertex + ((ey + 1) % numYVertices) * numXVertices + vx; 1346 const PetscInt cone[] = {v0, v1}; 1347 1348 PetscCall(DMPlexSetCone(dm, edge, cone)); 1349 if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) { 1350 if (vx == numXVertices - 1) { 1351 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight)); 1352 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1353 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1354 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1355 } else if (vx == 0) { 1356 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft)); 1357 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1358 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1359 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1360 } 1361 } 1362 } 1363 } 1364 1365 /* Build X edges*/ 1366 for (vy = 0; vy < numYVertices; vy++) { 1367 for (ex = 0; ex < numXEdges; ex++) { 1368 const PetscInt edge = firstXEdge + vy * numXEdges + ex; 1369 const PetscInt v0 = firstVertex + vy * numXVertices + ex; 1370 const PetscInt v1 = firstVertex + vy * numXVertices + (ex + 1) % numXVertices; 1371 const PetscInt cone[] = {v0, v1}; 1372 1373 PetscCall(DMPlexSetCone(dm, edge, cone)); 1374 if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) { 1375 if (vy == numYVertices - 1) { 1376 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop)); 1377 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1378 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1379 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1380 } else if (vy == 0) { 1381 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom)); 1382 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1383 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1384 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1385 } 1386 } 1387 } 1388 } 1389 1390 /* Compute support, stratify, and celltype label */ 1391 PetscCall(DMPlexSymmetrize(dm)); 1392 PetscCall(DMPlexStratify(dm)); 1393 PetscCall(DMPlexComputeCellTypes(dm)); 1394 1395 /* Build coordinates */ 1396 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1397 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1398 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2)); 1399 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices)); 1400 for (v = firstVertex; v < firstVertex + numVertices; ++v) { 1401 PetscCall(PetscSectionSetDof(coordSection, v, 2)); 1402 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2)); 1403 } 1404 PetscCall(PetscSectionSetUp(coordSection)); 1405 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1406 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1407 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1408 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1409 PetscCall(VecSetBlockSize(coordinates, 2)); 1410 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1411 PetscCall(VecGetArray(coordinates, &coords)); 1412 for (vy = 0; vy < numYVertices; ++vy) { 1413 for (vx = 0; vx < numXVertices; ++vx) { 1414 coords[2 * (vy * numXVertices + vx) + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx; 1415 coords[2 * (vy * numXVertices + vx) + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy; 1416 } 1417 } 1418 for (ey = 0; ey < numYEdges; ++ey) { 1419 for (ex = 0; ex < numXEdges; ++ex) { 1420 const PetscInt c = ey * numXEdges + ex + numYVertices * numXVertices; 1421 1422 coords[2 * c + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * (ex + 0.5); 1423 coords[2 * c + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * (ey + 0.5); 1424 } 1425 } 1426 PetscCall(VecRestoreArray(coordinates, &coords)); 1427 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1428 PetscCall(VecDestroy(&coordinates)); 1429 1430 /* handle periodic BC */ 1431 if (bdX == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_PERIODIC) { 1432 PetscReal L[2] = {-1., -1.}; 1433 PetscReal maxCell[2] = {-1., -1.}; 1434 1435 for (PetscInt d = 0; d < 2; ++d) { 1436 if (bd[d] != DM_BOUNDARY_NONE) { 1437 L[d] = upper[d] - lower[d]; 1438 maxCell[d] = 1.1 * (L[d] / PetscMax(1, edges[d])); 1439 } 1440 } 1441 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 1442 } 1443 } 1444 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 1445 PetscFunctionReturn(PETSC_SUCCESS); 1446 } 1447 1448 static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate) 1449 { 1450 DM boundary, vol; 1451 DMLabel bdlabel; 1452 PetscBool crisscross = PETSC_FALSE; 1453 1454 PetscFunctionBegin; 1455 PetscAssertPointer(dm, 1); 1456 if (dim == 2) PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_box_crisscross", &crisscross, NULL)); 1457 if (crisscross) { 1458 PetscCall(DMPlexCreateSquareMesh_Simplex_CrissCross(dm, faces, lower, upper, periodicity)); 1459 } else { 1460 for (PetscInt i = 0; i < dim; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes"); 1461 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary)); 1462 PetscCall(DMSetType(boundary, DMPLEX)); 1463 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)boundary, ((PetscObject)dm)->prefix)); 1464 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE)); 1465 PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol)); 1466 PetscCall(DMGetLabel(vol, "marker", &bdlabel)); 1467 if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel)); 1468 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol)); 1469 PetscCall(DMPlexReplace_Internal(dm, &vol)); 1470 PetscCall(DMDestroy(&boundary)); 1471 } 1472 if (interpolate) { 1473 PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 1474 PetscCall(DMPlexSetBoxLabel_Internal(dm, periodicity)); 1475 } 1476 PetscFunctionReturn(PETSC_SUCCESS); 1477 } 1478 1479 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ) 1480 { 1481 DMLabel cutLabel = NULL; 1482 PetscInt markerTop = 1, faceMarkerTop = 1; 1483 PetscInt markerBottom = 1, faceMarkerBottom = 1; 1484 PetscInt markerFront = 1, faceMarkerFront = 1; 1485 PetscInt markerBack = 1, faceMarkerBack = 1; 1486 PetscInt markerRight = 1, faceMarkerRight = 1; 1487 PetscInt markerLeft = 1, faceMarkerLeft = 1; 1488 PetscInt dim; 1489 PetscBool markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE; 1490 PetscMPIInt rank; 1491 1492 PetscFunctionBegin; 1493 PetscCall(DMGetDimension(dm, &dim)); 1494 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1495 PetscCall(DMCreateLabel(dm, "marker")); 1496 PetscCall(DMCreateLabel(dm, "Face Sets")); 1497 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 1498 if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST || bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST || bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) { 1499 if (cutMarker) { 1500 PetscCall(DMCreateLabel(dm, "periodic_cut")); 1501 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1502 } 1503 } 1504 switch (dim) { 1505 case 2: 1506 faceMarkerTop = 3; 1507 faceMarkerBottom = 1; 1508 faceMarkerRight = 2; 1509 faceMarkerLeft = 4; 1510 break; 1511 case 3: 1512 faceMarkerBottom = 1; 1513 faceMarkerTop = 2; 1514 faceMarkerFront = 3; 1515 faceMarkerBack = 4; 1516 faceMarkerRight = 5; 1517 faceMarkerLeft = 6; 1518 break; 1519 default: 1520 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim); 1521 } 1522 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL)); 1523 if (markerSeparate) { 1524 markerBottom = faceMarkerBottom; 1525 markerTop = faceMarkerTop; 1526 markerFront = faceMarkerFront; 1527 markerBack = faceMarkerBack; 1528 markerRight = faceMarkerRight; 1529 markerLeft = faceMarkerLeft; 1530 } 1531 { 1532 const PetscInt numXEdges = rank == 0 ? edges[0] : 0; 1533 const PetscInt numYEdges = rank == 0 ? edges[1] : 0; 1534 const PetscInt numZEdges = rank == 0 ? edges[2] : 0; 1535 const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0; 1536 const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0; 1537 const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0; 1538 const PetscInt numCells = numXEdges * numYEdges * numZEdges; 1539 const PetscInt numXFaces = numYEdges * numZEdges; 1540 const PetscInt numYFaces = numXEdges * numZEdges; 1541 const PetscInt numZFaces = numXEdges * numYEdges; 1542 const PetscInt numTotXFaces = numXVertices * numXFaces; 1543 const PetscInt numTotYFaces = numYVertices * numYFaces; 1544 const PetscInt numTotZFaces = numZVertices * numZFaces; 1545 const PetscInt numFaces = numTotXFaces + numTotYFaces + numTotZFaces; 1546 const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices; 1547 const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices; 1548 const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices; 1549 const PetscInt numVertices = numXVertices * numYVertices * numZVertices; 1550 const PetscInt numEdges = numTotXEdges + numTotYEdges + numTotZEdges; 1551 const PetscInt firstVertex = (dim == 2) ? numFaces : numCells; 1552 const PetscInt firstXFace = (dim == 2) ? 0 : numCells + numVertices; 1553 const PetscInt firstYFace = firstXFace + numTotXFaces; 1554 const PetscInt firstZFace = firstYFace + numTotYFaces; 1555 const PetscInt firstXEdge = numCells + numFaces + numVertices; 1556 const PetscInt firstYEdge = firstXEdge + numTotXEdges; 1557 const PetscInt firstZEdge = firstYEdge + numTotYEdges; 1558 Vec coordinates; 1559 PetscSection coordSection; 1560 PetscScalar *coords; 1561 PetscInt coordSize; 1562 PetscInt v, vx, vy, vz; 1563 PetscInt c, f, fx, fy, fz, e, ex, ey, ez; 1564 1565 PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices)); 1566 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 1567 for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4)); 1568 for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 1569 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 1570 /* Build cells */ 1571 for (fz = 0; fz < numZEdges; ++fz) { 1572 for (fy = 0; fy < numYEdges; ++fy) { 1573 for (fx = 0; fx < numXEdges; ++fx) { 1574 PetscInt cell = (fz * numYEdges + fy) * numXEdges + fx; 1575 PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz; 1576 PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices); 1577 PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy; 1578 PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices); 1579 PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx; 1580 PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices); 1581 /* B, T, F, K, R, L */ 1582 PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */ 1583 PetscInt cone[6]; 1584 1585 /* no boundary twisting in 3D */ 1586 cone[0] = faceB; 1587 cone[1] = faceT; 1588 cone[2] = faceF; 1589 cone[3] = faceK; 1590 cone[4] = faceR; 1591 cone[5] = faceL; 1592 PetscCall(DMPlexSetCone(dm, cell, cone)); 1593 PetscCall(DMPlexSetConeOrientation(dm, cell, ornt)); 1594 if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 1595 if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 1596 if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2)); 1597 } 1598 } 1599 } 1600 /* Build x faces */ 1601 for (fz = 0; fz < numZEdges; ++fz) { 1602 for (fy = 0; fy < numYEdges; ++fy) { 1603 for (fx = 0; fx < numXVertices; ++fx) { 1604 PetscInt face = firstXFace + (fz * numYEdges + fy) * numXVertices + fx; 1605 PetscInt edgeL = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz; 1606 PetscInt edgeR = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz; 1607 PetscInt edgeB = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy; 1608 PetscInt edgeT = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy; 1609 PetscInt ornt[4] = {0, 0, -1, -1}; 1610 PetscInt cone[4]; 1611 1612 if (dim == 3) { 1613 /* markers */ 1614 if (bdX != DM_BOUNDARY_PERIODIC) { 1615 if (fx == numXVertices - 1) { 1616 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight)); 1617 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight)); 1618 } else if (fx == 0) { 1619 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft)); 1620 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft)); 1621 } 1622 } 1623 } 1624 cone[0] = edgeB; 1625 cone[1] = edgeR; 1626 cone[2] = edgeT; 1627 cone[3] = edgeL; 1628 PetscCall(DMPlexSetCone(dm, face, cone)); 1629 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 1630 } 1631 } 1632 } 1633 /* Build y faces */ 1634 for (fz = 0; fz < numZEdges; ++fz) { 1635 for (fx = 0; fx < numXEdges; ++fx) { 1636 for (fy = 0; fy < numYVertices; ++fy) { 1637 PetscInt face = firstYFace + (fz * numXEdges + fx) * numYVertices + fy; 1638 PetscInt edgeL = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz; 1639 PetscInt edgeR = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz; 1640 PetscInt edgeB = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx; 1641 PetscInt edgeT = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx; 1642 PetscInt ornt[4] = {0, 0, -1, -1}; 1643 PetscInt cone[4]; 1644 1645 if (dim == 3) { 1646 /* markers */ 1647 if (bdY != DM_BOUNDARY_PERIODIC) { 1648 if (fy == numYVertices - 1) { 1649 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack)); 1650 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack)); 1651 } else if (fy == 0) { 1652 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront)); 1653 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront)); 1654 } 1655 } 1656 } 1657 cone[0] = edgeB; 1658 cone[1] = edgeR; 1659 cone[2] = edgeT; 1660 cone[3] = edgeL; 1661 PetscCall(DMPlexSetCone(dm, face, cone)); 1662 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 1663 } 1664 } 1665 } 1666 /* Build z faces */ 1667 for (fy = 0; fy < numYEdges; ++fy) { 1668 for (fx = 0; fx < numXEdges; ++fx) { 1669 for (fz = 0; fz < numZVertices; fz++) { 1670 PetscInt face = firstZFace + (fy * numXEdges + fx) * numZVertices + fz; 1671 PetscInt edgeL = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy; 1672 PetscInt edgeR = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy; 1673 PetscInt edgeB = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx; 1674 PetscInt edgeT = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx; 1675 PetscInt ornt[4] = {0, 0, -1, -1}; 1676 PetscInt cone[4]; 1677 1678 if (dim == 2) { 1679 if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) { 1680 edgeR += numYEdges - 1 - 2 * fy; 1681 ornt[1] = -1; 1682 } 1683 if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) { 1684 edgeT += numXEdges - 1 - 2 * fx; 1685 ornt[2] = 0; 1686 } 1687 if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2)); 1688 if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2)); 1689 } else { 1690 /* markers */ 1691 if (bdZ != DM_BOUNDARY_PERIODIC) { 1692 if (fz == numZVertices - 1) { 1693 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop)); 1694 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop)); 1695 } else if (fz == 0) { 1696 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom)); 1697 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom)); 1698 } 1699 } 1700 } 1701 cone[0] = edgeB; 1702 cone[1] = edgeR; 1703 cone[2] = edgeT; 1704 cone[3] = edgeL; 1705 PetscCall(DMPlexSetCone(dm, face, cone)); 1706 PetscCall(DMPlexSetConeOrientation(dm, face, ornt)); 1707 } 1708 } 1709 } 1710 /* Build Z edges*/ 1711 for (vy = 0; vy < numYVertices; vy++) { 1712 for (vx = 0; vx < numXVertices; vx++) { 1713 for (ez = 0; ez < numZEdges; ez++) { 1714 const PetscInt edge = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez; 1715 const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx; 1716 const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx; 1717 PetscInt cone[2]; 1718 1719 cone[0] = vertexB; 1720 cone[1] = vertexT; 1721 PetscCall(DMPlexSetCone(dm, edge, cone)); 1722 if (dim == 3) { 1723 if (bdX != DM_BOUNDARY_PERIODIC) { 1724 if (vx == numXVertices - 1) { 1725 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1726 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1727 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1728 } else if (vx == 0) { 1729 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1730 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1731 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1732 } 1733 } 1734 if (bdY != DM_BOUNDARY_PERIODIC) { 1735 if (vy == numYVertices - 1) { 1736 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack)); 1737 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack)); 1738 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack)); 1739 } else if (vy == 0) { 1740 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront)); 1741 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront)); 1742 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront)); 1743 } 1744 } 1745 } 1746 } 1747 } 1748 } 1749 /* Build Y edges*/ 1750 for (vz = 0; vz < numZVertices; vz++) { 1751 for (vx = 0; vx < numXVertices; vx++) { 1752 for (ey = 0; ey < numYEdges; ey++) { 1753 const PetscInt nextv = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx; 1754 const PetscInt edge = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey; 1755 const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx; 1756 const PetscInt vertexK = firstVertex + nextv; 1757 PetscInt cone[2]; 1758 1759 cone[0] = vertexF; 1760 cone[1] = vertexK; 1761 PetscCall(DMPlexSetCone(dm, edge, cone)); 1762 if (dim == 2) { 1763 if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) { 1764 if (vx == numXVertices - 1) { 1765 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight)); 1766 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1767 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1768 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1769 } else if (vx == 0) { 1770 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft)); 1771 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1772 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1773 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1774 } 1775 } else { 1776 if (vx == 0 && cutLabel) { 1777 PetscCall(DMLabelSetValue(cutLabel, edge, 1)); 1778 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1)); 1779 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1)); 1780 } 1781 } 1782 } else { 1783 if (bdX != DM_BOUNDARY_PERIODIC) { 1784 if (vx == numXVertices - 1) { 1785 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight)); 1786 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight)); 1787 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight)); 1788 } else if (vx == 0) { 1789 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft)); 1790 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft)); 1791 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft)); 1792 } 1793 } 1794 if (bdZ != DM_BOUNDARY_PERIODIC) { 1795 if (vz == numZVertices - 1) { 1796 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1797 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1798 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1799 } else if (vz == 0) { 1800 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1801 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1802 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1803 } 1804 } 1805 } 1806 } 1807 } 1808 } 1809 /* Build X edges*/ 1810 for (vz = 0; vz < numZVertices; vz++) { 1811 for (vy = 0; vy < numYVertices; vy++) { 1812 for (ex = 0; ex < numXEdges; ex++) { 1813 const PetscInt nextv = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices; 1814 const PetscInt edge = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex; 1815 const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex; 1816 const PetscInt vertexR = firstVertex + nextv; 1817 PetscInt cone[2]; 1818 1819 cone[0] = vertexL; 1820 cone[1] = vertexR; 1821 PetscCall(DMPlexSetCone(dm, edge, cone)); 1822 if (dim == 2) { 1823 if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) { 1824 if (vy == numYVertices - 1) { 1825 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop)); 1826 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1827 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1828 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1829 } else if (vy == 0) { 1830 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom)); 1831 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1832 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1833 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1834 } 1835 } else { 1836 if (vy == 0 && cutLabel) { 1837 PetscCall(DMLabelSetValue(cutLabel, edge, 1)); 1838 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1)); 1839 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1)); 1840 } 1841 } 1842 } else { 1843 if (bdY != DM_BOUNDARY_PERIODIC) { 1844 if (vy == numYVertices - 1) { 1845 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack)); 1846 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack)); 1847 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack)); 1848 } else if (vy == 0) { 1849 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront)); 1850 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront)); 1851 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront)); 1852 } 1853 } 1854 if (bdZ != DM_BOUNDARY_PERIODIC) { 1855 if (vz == numZVertices - 1) { 1856 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop)); 1857 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop)); 1858 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop)); 1859 } else if (vz == 0) { 1860 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom)); 1861 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom)); 1862 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom)); 1863 } 1864 } 1865 } 1866 } 1867 } 1868 } 1869 PetscCall(DMPlexSymmetrize(dm)); 1870 PetscCall(DMPlexStratify(dm)); 1871 /* Build coordinates */ 1872 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1873 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 1874 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 1875 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices)); 1876 for (v = firstVertex; v < firstVertex + numVertices; ++v) { 1877 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 1878 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 1879 } 1880 PetscCall(PetscSectionSetUp(coordSection)); 1881 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 1882 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 1883 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 1884 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 1885 PetscCall(VecSetBlockSize(coordinates, dim)); 1886 PetscCall(VecSetType(coordinates, VECSTANDARD)); 1887 PetscCall(VecGetArray(coordinates, &coords)); 1888 for (vz = 0; vz < numZVertices; ++vz) { 1889 for (vy = 0; vy < numYVertices; ++vy) { 1890 for (vx = 0; vx < numXVertices; ++vx) { 1891 coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx; 1892 coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy; 1893 if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz; 1894 } 1895 } 1896 } 1897 PetscCall(VecRestoreArray(coordinates, &coords)); 1898 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1899 PetscCall(VecDestroy(&coordinates)); 1900 } 1901 PetscFunctionReturn(PETSC_SUCCESS); 1902 } 1903 1904 static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[]) 1905 { 1906 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 1907 PetscInt fac[3] = {0, 0, 0}, d; 1908 1909 PetscFunctionBegin; 1910 PetscAssertPointer(dm, 1); 1911 PetscValidLogicalCollectiveInt(dm, dim, 2); 1912 PetscCall(DMSetDimension(dm, dim)); 1913 for (d = 0; d < dim; ++d) { 1914 fac[d] = faces[d]; 1915 bdt[d] = periodicity[d]; 1916 } 1917 PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2])); 1918 if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST || periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST || (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) { 1919 PetscReal L[3] = {-1., -1., 0.}; 1920 PetscReal maxCell[3] = {-1., -1., 0.}; 1921 1922 for (d = 0; d < dim; ++d) { 1923 if (periodicity[d] != DM_BOUNDARY_NONE) { 1924 L[d] = upper[d] - lower[d]; 1925 maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d])); 1926 } 1927 } 1928 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 1929 } 1930 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 1931 PetscFunctionReturn(PETSC_SUCCESS); 1932 } 1933 1934 static PetscErrorCode DMPlexCreateBoxMesh_Internal(DM dm, DMPlexShape shape, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate) 1935 { 1936 PetscFunctionBegin; 1937 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 1938 if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1939 else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0])); 1940 else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate)); 1941 else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity)); 1942 if (!interpolate && dim > 1 && !simplex) { 1943 DM udm; 1944 1945 PetscCall(DMPlexUninterpolate(dm, &udm)); 1946 PetscCall(DMPlexCopyCoordinates(dm, udm)); 1947 PetscCall(DMPlexReplace_Internal(dm, &udm)); 1948 } 1949 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 1950 PetscFunctionReturn(PETSC_SUCCESS); 1951 } 1952 1953 /*@ 1954 DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra). 1955 1956 Collective 1957 1958 Input Parameters: 1959 + comm - The communicator for the `DM` object 1960 . dim - The spatial dimension 1961 . simplex - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells 1962 . faces - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 1963 . lower - The lower left corner, or `NULL` for (0, 0, 0) 1964 . upper - The upper right corner, or `NULL` for (1, 1, 1) 1965 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE` 1966 . interpolate - Flag to create intermediate mesh pieces (edges, faces) 1967 . localizationHeight - Flag to localize edges and faces in addition to cells; only significant for periodic meshes 1968 - sparseLocalize - Flag to localize coordinates only for cells near the periodic boundary; only significant for periodic meshes 1969 1970 Output Parameter: 1971 . dm - The `DM` object 1972 1973 Level: beginner 1974 1975 Note: 1976 To customize this mesh using options, use 1977 .vb 1978 DMCreate(comm, &dm); 1979 DMSetType(dm, DMPLEX); 1980 DMSetFromOptions(dm); 1981 .ve 1982 and use the options in `DMSetFromOptions()`. 1983 1984 Here is the numbering returned for 2 faces in each direction for tensor cells\: 1985 .vb 1986 10---17---11---18----12 1987 | | | 1988 | | | 1989 20 2 22 3 24 1990 | | | 1991 | | | 1992 7---15----8---16----9 1993 | | | 1994 | | | 1995 19 0 21 1 23 1996 | | | 1997 | | | 1998 4---13----5---14----6 1999 .ve 2000 and for simplicial cells 2001 .vb 2002 14----8---15----9----16 2003 |\ 5 |\ 7 | 2004 | \ | \ | 2005 13 2 14 3 15 2006 | 4 \ | 6 \ | 2007 | \ | \ | 2008 11----6---12----7----13 2009 |\ |\ | 2010 | \ 1 | \ 3 | 2011 10 0 11 1 12 2012 | 0 \ | 2 \ | 2013 | \ | \ | 2014 8----4----9----5----10 2015 .ve 2016 2017 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 2018 @*/ 2019 PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, PetscInt localizationHeight, PetscBool sparseLocalize, DM *dm) 2020 { 2021 PetscInt fac[3] = {1, 1, 1}; 2022 PetscReal low[3] = {0, 0, 0}; 2023 PetscReal upp[3] = {1, 1, 1}; 2024 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 2025 2026 PetscFunctionBegin; 2027 PetscCall(DMCreate(comm, dm)); 2028 PetscCall(DMSetType(*dm, DMPLEX)); 2029 PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate)); 2030 if (periodicity) { 2031 DM cdm; 2032 2033 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 2034 PetscCall(DMPlexSetMaxProjectionHeight(cdm, localizationHeight)); 2035 PetscCall(DMSetSparseLocalize(*dm, sparseLocalize)); 2036 PetscCall(DMLocalizeCoordinates(*dm)); 2037 } 2038 PetscFunctionReturn(PETSC_SUCCESS); 2039 } 2040 2041 static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[]) 2042 { 2043 DM bdm, vol; 2044 PetscInt i; 2045 2046 PetscFunctionBegin; 2047 // TODO Now we can support periodicity 2048 for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported"); 2049 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm)); 2050 PetscCall(DMSetType(bdm, DMPLEX)); 2051 PetscCall(DMSetDimension(bdm, 2)); 2052 PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0)); 2053 PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE)); 2054 PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, &vol)); 2055 PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0)); 2056 PetscCall(DMDestroy(&bdm)); 2057 PetscCall(DMPlexReplace_Internal(dm, &vol)); 2058 if (lower[2] != 0.0) { 2059 Vec v; 2060 PetscScalar *x; 2061 PetscInt cDim, n; 2062 2063 PetscCall(DMGetCoordinatesLocal(dm, &v)); 2064 PetscCall(VecGetBlockSize(v, &cDim)); 2065 PetscCall(VecGetLocalSize(v, &n)); 2066 PetscCall(VecGetArray(v, &x)); 2067 x += cDim; 2068 for (i = 0; i < n; i += cDim) x[i] += lower[2]; 2069 PetscCall(VecRestoreArray(v, &x)); 2070 PetscCall(DMSetCoordinatesLocal(dm, v)); 2071 } 2072 PetscFunctionReturn(PETSC_SUCCESS); 2073 } 2074 2075 /*@ 2076 DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tessellating the (x,y) plane and extruding in the third direction using wedge cells. 2077 2078 Collective 2079 2080 Input Parameters: 2081 + comm - The communicator for the `DM` object 2082 . faces - Number of faces per dimension, or `NULL` for (1, 1, 1) 2083 . lower - The lower left corner, or `NULL` for (0, 0, 0) 2084 . upper - The upper right corner, or `NULL` for (1, 1, 1) 2085 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE` 2086 . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first 2087 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 2088 2089 Output Parameter: 2090 . dm - The `DM` object 2091 2092 Level: beginner 2093 2094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 2095 @*/ 2096 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm) 2097 { 2098 PetscInt fac[3] = {1, 1, 1}; 2099 PetscReal low[3] = {0, 0, 0}; 2100 PetscReal upp[3] = {1, 1, 1}; 2101 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 2102 2103 PetscFunctionBegin; 2104 PetscCall(DMCreate(comm, dm)); 2105 PetscCall(DMSetType(*dm, DMPLEX)); 2106 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt)); 2107 if (!interpolate) { 2108 DM udm; 2109 2110 PetscCall(DMPlexUninterpolate(*dm, &udm)); 2111 PetscCall(DMPlexReplace_Internal(*dm, &udm)); 2112 } 2113 if (periodicity) PetscCall(DMLocalizeCoordinates(*dm)); 2114 PetscFunctionReturn(PETSC_SUCCESS); 2115 } 2116 2117 /* 2118 DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension. 2119 2120 Input Parameters: 2121 + len - The length of the tuple 2122 . max - The maximum for each dimension, so values are in [0, max) 2123 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition 2124 2125 Output Parameter: 2126 . tup - A tuple of `len` integers whose entries are at most `max` 2127 2128 Level: developer 2129 2130 Note: 2131 Ordering is lexicographic with lowest index as least significant in ordering. 2132 e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}. 2133 2134 .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal() 2135 */ 2136 static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[]) 2137 { 2138 PetscInt i; 2139 2140 PetscFunctionBegin; 2141 for (i = 0; i < len; ++i) { 2142 if (tup[i] < max[i] - 1) { 2143 break; 2144 } else { 2145 tup[i] = 0; 2146 } 2147 } 2148 if (i == len) tup[i - 1] = max[i - 1]; 2149 else ++tup[i]; 2150 PetscFunctionReturn(PETSC_SUCCESS); 2151 } 2152 2153 static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[]) 2154 { 2155 PetscInt idx = tup[len - 1]; 2156 2157 for (PetscInt i = len - 2; i >= 0; --i) { 2158 idx *= max[i]; 2159 idx += tup[i]; 2160 } 2161 return idx; 2162 } 2163 2164 static void IndexToTuple_Private(PetscInt len, const PetscInt max[], PetscInt idx, PetscInt tup[]) 2165 { 2166 for (PetscInt i = 0; i < len; ++i) { 2167 tup[i] = idx % max[i]; 2168 idx = (idx - tup[i]) / max[i]; 2169 } 2170 } 2171 2172 static void TupleToRanks_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt tup[], PetscInt ranks[]) 2173 { 2174 for (PetscInt i = 0; i < len; ++i) { 2175 const PetscInt div = max[i] / procs[i]; 2176 const PetscInt rem = max[i] % procs[i]; 2177 const PetscInt idx = (tup[i] < 0 ? max[i] + tup[i] : tup[i]) % max[i]; 2178 2179 if (idx < rem * (div + 1)) ranks[i] = idx / (div + 1); 2180 else ranks[i] = rem + (idx - rem * (div + 1)) / div; 2181 } 2182 } 2183 2184 static void RanksToSizes_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt ranks[], PetscInt sizes[]) 2185 { 2186 for (PetscInt i = 0; i < len; ++i) { 2187 const PetscInt div = max[i] / procs[i]; 2188 const PetscInt rem = max[i] % procs[i]; 2189 2190 sizes[i] = ranks[i] < rem ? div + 1 : div; 2191 } 2192 } 2193 2194 /* 2195 In serial, the mesh is completely periodic. In parallel, we will include a layer of ghost vertices around the patch, so our edges will not wrap around in parallel. This will instead be handled by the SF. 2196 2197 The cone for all edges will always be complete. Even in the presence of boundaries, we will keep all support sizes constant. When an edge would not exist in the support, we will create one to wrap back periodically. This allows for uniform stencils, and that edge will not be used for computation. 2198 2199 All point which do not attain the vertex lower or upper bound in any dimension are owned, the rest are leaves owned by another process and present in the SF. 2200 2201 Parallel Layout: 2202 2203 We create a cubic process grid of dimension P^{1/d} on each side. The IndexToTuple_Private() function maps the global rank to the local rank in each dimension. We divide edges using the PETSc distribution rule in each dimension, and then add overlap. TupleToRanks_Private() returns the local rank in ech dimension for a tuple. RanksToSizes_Private() gives the size in each dimension for the domain with those local ranks. 2204 */ 2205 static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], PetscInt overlap, const DMBoundaryType bd[]) 2206 { 2207 const PetscInt debug = ((DM_Plex *)dm->data)->printAdj; 2208 PetscSF sf; 2209 Vec coordinates; 2210 PetscSection coordSection; 2211 DMLabel cutLabel = NULL; 2212 PetscBool cutMarker = PETSC_FALSE; 2213 PetscBool periodic = PETSC_FALSE; 2214 PetscInt numCells = 1; 2215 PetscInt numVertices = 1; 2216 PetscSFNode *remotes; 2217 PetscScalar *coords; 2218 PetscInt *procs; // The number of processes along each dimension 2219 PetscInt *lrank; // Rank in each dimension, lrank[d] \in [0, procs[d]) 2220 PetscInt *ledges; // The number of edges along each dimension for this process 2221 PetscInt *vstart; // The first vertex along each dimension on this processes 2222 PetscInt *vertices; // The number of vertices along each dimension on this process 2223 PetscInt *rvert; // The global (not local) vertex number along each dimension 2224 PetscInt *rrank; // The rank along each dimension for the process owning rvert[] 2225 PetscInt *rvertices; // The number of vertices along each dimension for the process rrank[] 2226 PetscInt *vert, *vtmp, *supp, cone[2], *leaves; 2227 PetscInt cell = 0, coordSize, Nl = 0, Nl2 = 0; 2228 PetscMPIInt rank, size; 2229 MPI_Comm comm; 2230 2231 PetscFunctionBegin; 2232 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2233 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2234 PetscCallMPI(MPI_Comm_size(comm, &size)); 2235 PetscCall(DMSetDimension(dm, dim)); 2236 PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE)); 2237 PetscCall(PetscCalloc4(dim, &procs, dim, &lrank, dim, &rrank, 2 * dim, &supp)); 2238 PetscCall(PetscCalloc7(dim, &ledges, dim, &vertices, dim, &rvertices, dim, &vert, dim, &rvert, dim, &vstart, dim, &vtmp)); 2239 PetscCall(DMCreateLabel(dm, "marker")); 2240 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL)); 2241 for (PetscInt d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE; 2242 if (periodic && cutMarker) { 2243 PetscCall(DMCreateLabel(dm, "periodic_cut")); 2244 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 2245 } 2246 for (PetscInt d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, comm, PETSC_ERR_SUP, "Hypercubic mesh must be periodic now"); 2247 overlap = overlap == PETSC_DETERMINE ? 1 : overlap; 2248 PetscCheck(overlap >= 1, comm, PETSC_ERR_SUP, "Overlap %" PetscInt_FMT " must be greater than 0", overlap); 2249 if (size > 1) { 2250 PetscInt Npr = 1; 2251 2252 // Make process grid 2253 if (debug) PetscCall(PetscPrintf(comm, "Process grid:")); 2254 for (PetscInt d = 0; d < dim; ++d) { 2255 procs[d] = PetscRintReal(PetscPowReal(size, 1. / dim)); 2256 Npr *= procs[d]; 2257 if (debug) PetscCall(PetscPrintf(comm, " %" PetscInt_FMT, procs[d])); 2258 } 2259 if (debug) PetscCall(PetscPrintf(comm, "\n")); 2260 PetscCheck(Npr == size, comm, PETSC_ERR_PLIB, "Process grid size %" PetscInt_FMT " != %d comm size", Npr, size); 2261 IndexToTuple_Private(dim, procs, rank, lrank); 2262 for (PetscInt d = 0; d < dim; ++d) { 2263 ledges[d] = edges[d] / procs[d] + (edges[d] % procs[d] > lrank[d] ? 1 : 0); 2264 vstart[d] = 0; 2265 for (PetscInt r = 0; r < lrank[d]; ++r) vstart[d] += edges[d] / procs[d] + (edges[d] % procs[d] > r ? 1 : 0); 2266 vstart[d] -= overlap; // For halo 2267 } 2268 } else { 2269 for (PetscInt d = 0; d < dim; ++d) { 2270 procs[d] = 1; 2271 ledges[d] = edges[d]; 2272 } 2273 } 2274 // Calculate local patch size 2275 for (PetscInt d = 0; d < dim; ++d) { 2276 vertices[d] = ledges[d] + (procs[d] > 1 ? 2 * overlap : 0); 2277 numVertices *= vertices[d]; 2278 } 2279 numCells = numVertices * dim; 2280 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 2281 for (PetscInt c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2)); 2282 for (PetscInt v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim)); 2283 PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */ 2284 /* Build cell cones and vertex supports */ 2285 PetscCall(DMCreateLabel(dm, "celltype")); 2286 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Topology for rank %d:\n", rank)); 2287 while (vert[dim - 1] < vertices[dim - 1]) { 2288 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells; 2289 PetscInt s = 0; 2290 PetscBool leaf = PETSC_FALSE; 2291 2292 if (debug) { 2293 PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex)); 2294 for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d])); 2295 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 2296 } 2297 PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT)); 2298 // Define edge cones 2299 for (PetscInt d = 0; d < dim; ++d) { 2300 for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e]; 2301 vtmp[d] = (vert[d] + 1) % vertices[d]; 2302 cone[0] = vertex; 2303 cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells; 2304 if (debug) { 2305 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ":", cone[1])); 2306 for (PetscInt e = 0; e < dim; ++e) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vtmp[e])); 2307 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 2308 } 2309 PetscCall(DMPlexSetCone(dm, cell, cone)); 2310 PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT)); 2311 if (debug) PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1])); 2312 ++cell; 2313 // Shared vertices are any in the first or last overlap layers 2314 if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE; 2315 } 2316 if (size > 1 && leaf) ++Nl; 2317 // Define vertex supports 2318 for (PetscInt d = 0; d < dim; ++d) { 2319 for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e]; 2320 vtmp[d] = (vert[d] + vertices[d] - 1) % vertices[d]; 2321 supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d; 2322 supp[s++] = (vertex - numCells) * dim + d; 2323 PetscCall(DMPlexSetSupport(dm, vertex, supp)); 2324 } 2325 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 2326 } 2327 if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 2328 PetscCall(DMPlexStratify(dm)); 2329 // Allocate for SF 2330 PetscCall(PetscMalloc1(Nl, &leaves)); 2331 PetscCall(PetscMalloc1(Nl, &remotes)); 2332 // Build coordinates 2333 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2334 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2335 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2336 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2337 for (PetscInt v = numCells; v < numCells + numVertices; ++v) { 2338 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2339 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2340 } 2341 PetscCall(PetscSectionSetUp(coordSection)); 2342 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2343 PetscCall(VecCreate(comm, &coordinates)); 2344 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2345 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2346 PetscCall(VecSetBlockSize(coordinates, dim)); 2347 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2348 PetscCall(VecGetArray(coordinates, &coords)); 2349 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Geometry for rank %d:\n", rank)); 2350 for (PetscInt d = 0; d < dim; ++d) vert[d] = 0; 2351 while (vert[dim - 1] < vertices[dim - 1]) { 2352 const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert); 2353 PetscBool leaf = PETSC_FALSE; 2354 2355 for (PetscInt d = 0; d < dim; ++d) { 2356 coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / edges[d]) * (vert[d] + vstart[d]); 2357 if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE; 2358 } 2359 if (size > 1 && leaf) { 2360 PetscInt rnumCells = 1; 2361 2362 for (PetscInt d = 0; d < dim; ++d) rvert[d] = vert[d] + vstart[d]; 2363 TupleToRanks_Private(dim, edges, procs, rvert, rrank); 2364 leaves[Nl2] = vertex + numCells; 2365 remotes[Nl2].rank = TupleToIndex_Private(dim, procs, rrank); 2366 RanksToSizes_Private(dim, edges, procs, rrank, rvertices); 2367 for (PetscInt d = 0; d < dim; ++d) { 2368 rvertices[d] += 2 * overlap; // Add halo 2369 rnumCells *= rvertices[d]; 2370 } 2371 rnumCells *= dim; 2372 for (PetscInt d = 0; d < dim; ++d) { 2373 const PetscInt diff = rrank[d] - lrank[d]; 2374 2375 if (!diff) rvert[d] = vert[d]; // Vertex is local 2376 else if (rvert[d] < 0) rvert[d] = rvertices[d] - 1 + rvert[d]; // Wrap around at the bottom 2377 else if (rvert[d] >= edges[d]) rvert[d] = rvert[d] - edges[d] + 1; // Wrap around at the top 2378 else if (diff == -1) rvert[d] = rvertices[d] - 1 + (vert[d] - overlap); 2379 else if (diff == 1) rvert[d] = (vertices[d] - vert[d] - 1) + overlap; 2380 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Process distance %" PetscInt_FMT " in direction %" PetscInt_FMT " should not be possible", diff, d); 2381 } 2382 remotes[Nl2].index = TupleToIndex_Private(dim, rvertices, rvert) + rnumCells; 2383 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Shared Vertex %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", leaves[Nl2], remotes[Nl2].rank, remotes[Nl2].index)); 2384 ++Nl2; 2385 } 2386 if (debug) { 2387 PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex)); 2388 for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d] + vstart[d])); 2389 for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %g", (double)PetscRealPart(coords[vertex * dim + d]))); 2390 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 2391 } 2392 PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert)); 2393 } 2394 if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 2395 PetscCall(VecRestoreArray(coordinates, &coords)); 2396 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2397 PetscCall(VecDestroy(&coordinates)); 2398 // Build SF 2399 PetscCheck(Nl == Nl2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Initial number of leaves %" PetscInt_FMT " != %" PetscInt_FMT " final number", Nl, Nl2); 2400 PetscCall(DMGetPointSF(dm, &sf)); 2401 PetscCall(PetscSFSetGraph(sf, numCells + numVertices, Nl, leaves, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER)); 2402 if (debug) PetscCall(PetscSFView(sf, PETSC_VIEWER_STDOUT_WORLD)); 2403 //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper)); 2404 // Attach the extent 2405 { 2406 PetscContainer c; 2407 PetscInt *extent, *lextent; 2408 2409 PetscCall(PetscMalloc1(dim, &extent)); 2410 PetscCall(PetscMalloc1(dim, &lextent)); 2411 for (PetscInt d = 0; d < dim; ++d) { 2412 extent[d] = edges[d]; 2413 lextent[d] = ledges[d]; 2414 } 2415 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 2416 PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault)); 2417 PetscCall(PetscContainerSetPointer(c, extent)); 2418 PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c)); 2419 PetscCall(PetscContainerDestroy(&c)); 2420 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 2421 PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault)); 2422 PetscCall(PetscContainerSetPointer(c, lextent)); 2423 PetscCall(PetscObjectCompose((PetscObject)dm, "_lextent", (PetscObject)c)); 2424 PetscCall(PetscContainerDestroy(&c)); 2425 } 2426 PetscCall(PetscFree4(procs, lrank, rrank, supp)); 2427 PetscCall(PetscFree7(ledges, vertices, rvertices, vert, rvert, vstart, vtmp)); 2428 PetscFunctionReturn(PETSC_SUCCESS); 2429 } 2430 2431 /*@C 2432 DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges. 2433 2434 Collective 2435 2436 Input Parameters: 2437 + comm - The communicator for the `DM` object 2438 . dim - The spatial dimension 2439 . edges - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D 2440 . lower - The lower left corner, or `NULL` for (0, 0, 0) 2441 . upper - The upper right corner, or `NULL` for (1, 1, 1) 2442 - overlap - The number of vertices in each direction to include in the overlap (default is 1) 2443 2444 Output Parameter: 2445 . dm - The DM object 2446 2447 Level: beginner 2448 2449 Note: 2450 If you want to customize this mesh using options, you just need to 2451 .vb 2452 DMCreate(comm, &dm); 2453 DMSetType(dm, DMPLEX); 2454 DMSetFromOptions(dm); 2455 .ve 2456 and use the options on the `DMSetFromOptions()` page. 2457 2458 The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively, 2459 .vb 2460 18--0-19--2-20--4-18 2461 | | | | 2462 13 15 17 13 2463 | | | | 2464 24-12-25-14-26-16-24 2465 | | | | 2466 7 9 11 7 2467 | | | | 2468 21--6-22--8-23-10-21 2469 | | | | 2470 1 3 5 1 2471 | | | | 2472 18--0-19--2-20--4-18 2473 .ve 2474 2475 .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()` 2476 @*/ 2477 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], PetscInt overlap, DM *dm) 2478 { 2479 PetscInt *edg; 2480 PetscReal *low, *upp; 2481 DMBoundaryType *bdt; 2482 PetscInt d; 2483 2484 PetscFunctionBegin; 2485 PetscCall(DMCreate(comm, dm)); 2486 PetscCall(DMSetType(*dm, DMPLEX)); 2487 PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt)); 2488 for (d = 0; d < dim; ++d) { 2489 edg[d] = edges ? edges[d] : 1; 2490 low[d] = lower ? lower[d] : 0.; 2491 upp[d] = upper ? upper[d] : 1.; 2492 bdt[d] = DM_BOUNDARY_PERIODIC; 2493 } 2494 PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, overlap, bdt)); 2495 PetscCall(PetscFree4(edg, low, upp, bdt)); 2496 PetscFunctionReturn(PETSC_SUCCESS); 2497 } 2498 2499 /*@ 2500 DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database. 2501 2502 Logically Collective 2503 2504 Input Parameters: 2505 + dm - the `DM` context 2506 - prefix - the prefix to prepend to all option names 2507 2508 Level: advanced 2509 2510 Note: 2511 A hyphen (-) must NOT be given at the beginning of the prefix name. 2512 The first character of all runtime options is AUTOMATICALLY the hyphen. 2513 2514 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()` 2515 @*/ 2516 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[]) 2517 { 2518 DM_Plex *mesh = (DM_Plex *)dm->data; 2519 2520 PetscFunctionBegin; 2521 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2522 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix)); 2523 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix)); 2524 PetscFunctionReturn(PETSC_SUCCESS); 2525 } 2526 2527 /* Remap geometry to cylinder 2528 TODO: This only works for a single refinement, then it is broken 2529 2530 Interior square: Linear interpolation is correct 2531 The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing 2532 such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance 2533 2534 phi = arctan(y/x) 2535 d_close = sqrt(1/8 + 1/4 sin^2(phi)) 2536 d_far = sqrt(1/2 + sin^2(phi)) 2537 2538 so we remap them using 2539 2540 x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close) 2541 y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close) 2542 2543 If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y. 2544 */ 2545 static void snapToCylinder(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 2546 { 2547 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 2548 const PetscReal ds2 = 0.5 * dis; 2549 2550 if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) { 2551 f0[0] = u[0]; 2552 f0[1] = u[1]; 2553 } else { 2554 PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc; 2555 2556 x = PetscRealPart(u[0]); 2557 y = PetscRealPart(u[1]); 2558 phi = PetscAtan2Real(y, x); 2559 sinp = PetscSinReal(phi); 2560 cosp = PetscCosReal(phi); 2561 if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) { 2562 dc = PetscAbsReal(ds2 / sinp); 2563 df = PetscAbsReal(dis / sinp); 2564 xc = ds2 * x / PetscAbsReal(y); 2565 yc = ds2 * PetscSignReal(y); 2566 } else { 2567 dc = PetscAbsReal(ds2 / cosp); 2568 df = PetscAbsReal(dis / cosp); 2569 xc = ds2 * PetscSignReal(x); 2570 yc = ds2 * y / PetscAbsReal(x); 2571 } 2572 f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc); 2573 f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc); 2574 } 2575 f0[2] = u[2]; 2576 } 2577 2578 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ, PetscInt Nr) 2579 { 2580 const PetscInt dim = 3; 2581 PetscInt numCells, numVertices; 2582 PetscMPIInt rank; 2583 2584 PetscFunctionBegin; 2585 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 2586 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2587 PetscCall(DMSetDimension(dm, dim)); 2588 /* Create topology */ 2589 { 2590 PetscInt cone[8], c; 2591 2592 numCells = rank == 0 ? 5 : 0; 2593 numVertices = rank == 0 ? 16 : 0; 2594 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2595 numCells *= 3; 2596 numVertices = rank == 0 ? 24 : 0; 2597 } 2598 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 2599 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8)); 2600 PetscCall(DMSetUp(dm)); 2601 if (rank == 0) { 2602 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2603 cone[0] = 15; 2604 cone[1] = 18; 2605 cone[2] = 17; 2606 cone[3] = 16; 2607 cone[4] = 31; 2608 cone[5] = 32; 2609 cone[6] = 33; 2610 cone[7] = 34; 2611 PetscCall(DMPlexSetCone(dm, 0, cone)); 2612 cone[0] = 16; 2613 cone[1] = 17; 2614 cone[2] = 24; 2615 cone[3] = 23; 2616 cone[4] = 32; 2617 cone[5] = 36; 2618 cone[6] = 37; 2619 cone[7] = 33; /* 22 25 26 21 */ 2620 PetscCall(DMPlexSetCone(dm, 1, cone)); 2621 cone[0] = 18; 2622 cone[1] = 27; 2623 cone[2] = 24; 2624 cone[3] = 17; 2625 cone[4] = 34; 2626 cone[5] = 33; 2627 cone[6] = 37; 2628 cone[7] = 38; 2629 PetscCall(DMPlexSetCone(dm, 2, cone)); 2630 cone[0] = 29; 2631 cone[1] = 27; 2632 cone[2] = 18; 2633 cone[3] = 15; 2634 cone[4] = 35; 2635 cone[5] = 31; 2636 cone[6] = 34; 2637 cone[7] = 38; 2638 PetscCall(DMPlexSetCone(dm, 3, cone)); 2639 cone[0] = 29; 2640 cone[1] = 15; 2641 cone[2] = 16; 2642 cone[3] = 23; 2643 cone[4] = 35; 2644 cone[5] = 36; 2645 cone[6] = 32; 2646 cone[7] = 31; 2647 PetscCall(DMPlexSetCone(dm, 4, cone)); 2648 2649 cone[0] = 31; 2650 cone[1] = 34; 2651 cone[2] = 33; 2652 cone[3] = 32; 2653 cone[4] = 19; 2654 cone[5] = 22; 2655 cone[6] = 21; 2656 cone[7] = 20; 2657 PetscCall(DMPlexSetCone(dm, 5, cone)); 2658 cone[0] = 32; 2659 cone[1] = 33; 2660 cone[2] = 37; 2661 cone[3] = 36; 2662 cone[4] = 22; 2663 cone[5] = 25; 2664 cone[6] = 26; 2665 cone[7] = 21; 2666 PetscCall(DMPlexSetCone(dm, 6, cone)); 2667 cone[0] = 34; 2668 cone[1] = 38; 2669 cone[2] = 37; 2670 cone[3] = 33; 2671 cone[4] = 20; 2672 cone[5] = 21; 2673 cone[6] = 26; 2674 cone[7] = 28; 2675 PetscCall(DMPlexSetCone(dm, 7, cone)); 2676 cone[0] = 35; 2677 cone[1] = 38; 2678 cone[2] = 34; 2679 cone[3] = 31; 2680 cone[4] = 30; 2681 cone[5] = 19; 2682 cone[6] = 20; 2683 cone[7] = 28; 2684 PetscCall(DMPlexSetCone(dm, 8, cone)); 2685 cone[0] = 35; 2686 cone[1] = 31; 2687 cone[2] = 32; 2688 cone[3] = 36; 2689 cone[4] = 30; 2690 cone[5] = 25; 2691 cone[6] = 22; 2692 cone[7] = 19; 2693 PetscCall(DMPlexSetCone(dm, 9, cone)); 2694 2695 cone[0] = 19; 2696 cone[1] = 20; 2697 cone[2] = 21; 2698 cone[3] = 22; 2699 cone[4] = 15; 2700 cone[5] = 16; 2701 cone[6] = 17; 2702 cone[7] = 18; 2703 PetscCall(DMPlexSetCone(dm, 10, cone)); 2704 cone[0] = 22; 2705 cone[1] = 21; 2706 cone[2] = 26; 2707 cone[3] = 25; 2708 cone[4] = 16; 2709 cone[5] = 23; 2710 cone[6] = 24; 2711 cone[7] = 17; 2712 PetscCall(DMPlexSetCone(dm, 11, cone)); 2713 cone[0] = 20; 2714 cone[1] = 28; 2715 cone[2] = 26; 2716 cone[3] = 21; 2717 cone[4] = 18; 2718 cone[5] = 17; 2719 cone[6] = 24; 2720 cone[7] = 27; 2721 PetscCall(DMPlexSetCone(dm, 12, cone)); 2722 cone[0] = 30; 2723 cone[1] = 28; 2724 cone[2] = 20; 2725 cone[3] = 19; 2726 cone[4] = 29; 2727 cone[5] = 15; 2728 cone[6] = 18; 2729 cone[7] = 27; 2730 PetscCall(DMPlexSetCone(dm, 13, cone)); 2731 cone[0] = 30; 2732 cone[1] = 19; 2733 cone[2] = 22; 2734 cone[3] = 25; 2735 cone[4] = 29; 2736 cone[5] = 23; 2737 cone[6] = 16; 2738 cone[7] = 15; 2739 PetscCall(DMPlexSetCone(dm, 14, cone)); 2740 } else { 2741 cone[0] = 5; 2742 cone[1] = 8; 2743 cone[2] = 7; 2744 cone[3] = 6; 2745 cone[4] = 9; 2746 cone[5] = 12; 2747 cone[6] = 11; 2748 cone[7] = 10; 2749 PetscCall(DMPlexSetCone(dm, 0, cone)); 2750 cone[0] = 6; 2751 cone[1] = 7; 2752 cone[2] = 14; 2753 cone[3] = 13; 2754 cone[4] = 12; 2755 cone[5] = 15; 2756 cone[6] = 16; 2757 cone[7] = 11; 2758 PetscCall(DMPlexSetCone(dm, 1, cone)); 2759 cone[0] = 8; 2760 cone[1] = 17; 2761 cone[2] = 14; 2762 cone[3] = 7; 2763 cone[4] = 10; 2764 cone[5] = 11; 2765 cone[6] = 16; 2766 cone[7] = 18; 2767 PetscCall(DMPlexSetCone(dm, 2, cone)); 2768 cone[0] = 19; 2769 cone[1] = 17; 2770 cone[2] = 8; 2771 cone[3] = 5; 2772 cone[4] = 20; 2773 cone[5] = 9; 2774 cone[6] = 10; 2775 cone[7] = 18; 2776 PetscCall(DMPlexSetCone(dm, 3, cone)); 2777 cone[0] = 19; 2778 cone[1] = 5; 2779 cone[2] = 6; 2780 cone[3] = 13; 2781 cone[4] = 20; 2782 cone[5] = 15; 2783 cone[6] = 12; 2784 cone[7] = 9; 2785 PetscCall(DMPlexSetCone(dm, 4, cone)); 2786 } 2787 } 2788 PetscCall(DMPlexSymmetrize(dm)); 2789 PetscCall(DMPlexStratify(dm)); 2790 } 2791 /* Create cube geometry */ 2792 { 2793 Vec coordinates; 2794 PetscSection coordSection; 2795 PetscScalar *coords; 2796 PetscInt coordSize, v; 2797 const PetscReal dis = 1.0 / PetscSqrtReal(2.0); 2798 const PetscReal ds2 = dis / 2.0; 2799 2800 /* Build coordinates */ 2801 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2802 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2803 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 2804 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 2805 for (v = numCells; v < numCells + numVertices; ++v) { 2806 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 2807 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 2808 } 2809 PetscCall(PetscSectionSetUp(coordSection)); 2810 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 2811 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 2812 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2813 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 2814 PetscCall(VecSetBlockSize(coordinates, dim)); 2815 PetscCall(VecSetType(coordinates, VECSTANDARD)); 2816 PetscCall(VecGetArray(coordinates, &coords)); 2817 if (rank == 0) { 2818 coords[0 * dim + 0] = -ds2; 2819 coords[0 * dim + 1] = -ds2; 2820 coords[0 * dim + 2] = 0.0; 2821 coords[1 * dim + 0] = ds2; 2822 coords[1 * dim + 1] = -ds2; 2823 coords[1 * dim + 2] = 0.0; 2824 coords[2 * dim + 0] = ds2; 2825 coords[2 * dim + 1] = ds2; 2826 coords[2 * dim + 2] = 0.0; 2827 coords[3 * dim + 0] = -ds2; 2828 coords[3 * dim + 1] = ds2; 2829 coords[3 * dim + 2] = 0.0; 2830 coords[4 * dim + 0] = -ds2; 2831 coords[4 * dim + 1] = -ds2; 2832 coords[4 * dim + 2] = 1.0; 2833 coords[5 * dim + 0] = -ds2; 2834 coords[5 * dim + 1] = ds2; 2835 coords[5 * dim + 2] = 1.0; 2836 coords[6 * dim + 0] = ds2; 2837 coords[6 * dim + 1] = ds2; 2838 coords[6 * dim + 2] = 1.0; 2839 coords[7 * dim + 0] = ds2; 2840 coords[7 * dim + 1] = -ds2; 2841 coords[7 * dim + 2] = 1.0; 2842 coords[8 * dim + 0] = dis; 2843 coords[8 * dim + 1] = -dis; 2844 coords[8 * dim + 2] = 0.0; 2845 coords[9 * dim + 0] = dis; 2846 coords[9 * dim + 1] = dis; 2847 coords[9 * dim + 2] = 0.0; 2848 coords[10 * dim + 0] = dis; 2849 coords[10 * dim + 1] = -dis; 2850 coords[10 * dim + 2] = 1.0; 2851 coords[11 * dim + 0] = dis; 2852 coords[11 * dim + 1] = dis; 2853 coords[11 * dim + 2] = 1.0; 2854 coords[12 * dim + 0] = -dis; 2855 coords[12 * dim + 1] = dis; 2856 coords[12 * dim + 2] = 0.0; 2857 coords[13 * dim + 0] = -dis; 2858 coords[13 * dim + 1] = dis; 2859 coords[13 * dim + 2] = 1.0; 2860 coords[14 * dim + 0] = -dis; 2861 coords[14 * dim + 1] = -dis; 2862 coords[14 * dim + 2] = 0.0; 2863 coords[15 * dim + 0] = -dis; 2864 coords[15 * dim + 1] = -dis; 2865 coords[15 * dim + 2] = 1.0; 2866 if (periodicZ == DM_BOUNDARY_PERIODIC) { 2867 /* 15 31 19 */ coords[16 * dim + 0] = -ds2; 2868 coords[16 * dim + 1] = -ds2; 2869 coords[16 * dim + 2] = 0.5; 2870 /* 16 32 22 */ coords[17 * dim + 0] = ds2; 2871 coords[17 * dim + 1] = -ds2; 2872 coords[17 * dim + 2] = 0.5; 2873 /* 17 33 21 */ coords[18 * dim + 0] = ds2; 2874 coords[18 * dim + 1] = ds2; 2875 coords[18 * dim + 2] = 0.5; 2876 /* 18 34 20 */ coords[19 * dim + 0] = -ds2; 2877 coords[19 * dim + 1] = ds2; 2878 coords[19 * dim + 2] = 0.5; 2879 /* 29 35 30 */ coords[20 * dim + 0] = -dis; 2880 coords[20 * dim + 1] = -dis; 2881 coords[20 * dim + 2] = 0.5; 2882 /* 23 36 25 */ coords[21 * dim + 0] = dis; 2883 coords[21 * dim + 1] = -dis; 2884 coords[21 * dim + 2] = 0.5; 2885 /* 24 37 26 */ coords[22 * dim + 0] = dis; 2886 coords[22 * dim + 1] = dis; 2887 coords[22 * dim + 2] = 0.5; 2888 /* 27 38 28 */ coords[23 * dim + 0] = -dis; 2889 coords[23 * dim + 1] = dis; 2890 coords[23 * dim + 2] = 0.5; 2891 } 2892 } 2893 PetscCall(VecRestoreArray(coordinates, &coords)); 2894 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 2895 PetscCall(VecDestroy(&coordinates)); 2896 } 2897 /* Create periodicity */ 2898 if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) { 2899 PetscReal L[3] = {-1., -1., 0.}; 2900 PetscReal maxCell[3] = {-1., -1., 0.}; 2901 PetscReal lower[3] = {0.0, 0.0, 0.0}; 2902 PetscReal upper[3] = {1.0, 1.0, 1.5}; 2903 PetscInt numZCells = 3; 2904 2905 L[2] = upper[2] - lower[2]; 2906 maxCell[2] = 1.1 * (L[2] / numZCells); 2907 PetscCall(DMSetPeriodicity(dm, maxCell, lower, L)); 2908 } 2909 { 2910 DM cdm; 2911 PetscDS cds; 2912 PetscScalar c[2] = {1.0, 1.0}; 2913 2914 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 2915 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2916 PetscCall(DMGetDS(cdm, &cds)); 2917 PetscCall(PetscDSSetConstants(cds, 2, c)); 2918 } 2919 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 2920 2921 /* Wait for coordinate creation before doing in-place modification */ 2922 PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 2923 2924 char oldprefix[PETSC_MAX_PATH_LEN]; 2925 const char *prefix; 2926 2927 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 2928 PetscCall(PetscStrncpy(oldprefix, prefix, PETSC_MAX_PATH_LEN)); 2929 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, "petsc_cyl_ref_")); 2930 for (PetscInt r = 0; r < PetscMax(0, Nr); ++r) { 2931 DM rdm; 2932 2933 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 2934 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 2935 } 2936 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldprefix)); 2937 PetscCall(DMPlexRemapGeometry(dm, 0.0, snapToCylinder)); 2938 2939 DMLabel bdlabel, edgelabel; 2940 IS faceIS; 2941 const PetscInt *faces; 2942 PetscInt Nf; 2943 2944 PetscCall(DMCreateLabel(dm, "marker")); 2945 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 2946 PetscCall(DMCreateLabel(dm, "generatrix")); 2947 PetscCall(DMGetLabel(dm, "generatrix", &edgelabel)); 2948 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 2949 // Remove faces on top and bottom 2950 PetscCall(DMLabelGetStratumIS(bdlabel, 1, &faceIS)); 2951 if (faceIS) { 2952 PetscCall(ISGetLocalSize(faceIS, &Nf)); 2953 PetscCall(ISGetIndices(faceIS, &faces)); 2954 for (PetscInt f = 0; f < Nf; ++f) { 2955 PetscReal vol, normal[3]; 2956 2957 PetscCall(DMPlexComputeCellGeometryFVM(dm, faces[f], &vol, NULL, normal)); 2958 if (PetscAbsReal(normal[2]) < PETSC_SMALL) PetscCall(DMLabelSetValue(edgelabel, faces[f], 1)); 2959 } 2960 PetscCall(ISRestoreIndices(faceIS, &faces)); 2961 PetscCall(ISDestroy(&faceIS)); 2962 } 2963 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 2964 PetscCall(DMPlexLabelComplete(dm, edgelabel)); 2965 PetscFunctionReturn(PETSC_SUCCESS); 2966 } 2967 2968 /*@ 2969 DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra. 2970 2971 Collective 2972 2973 Input Parameters: 2974 + comm - The communicator for the `DM` object 2975 . periodicZ - The boundary type for the Z direction 2976 - Nr - The number of refinements to carry out 2977 2978 Output Parameter: 2979 . dm - The `DM` object 2980 2981 Level: beginner 2982 2983 Note: 2984 Here is the output numbering looking from the bottom of the cylinder\: 2985 .vb 2986 17-----14 2987 | | 2988 | 2 | 2989 | | 2990 17-----8-----7-----14 2991 | | | | 2992 | 3 | 0 | 1 | 2993 | | | | 2994 19-----5-----6-----13 2995 | | 2996 | 4 | 2997 | | 2998 19-----13 2999 3000 and up through the top 3001 3002 18-----16 3003 | | 3004 | 2 | 3005 | | 3006 18----10----11-----16 3007 | | | | 3008 | 3 | 0 | 1 | 3009 | | | | 3010 20-----9----12-----15 3011 | | 3012 | 4 | 3013 | | 3014 20-----15 3015 .ve 3016 3017 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3018 @*/ 3019 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, PetscInt Nr, DM *dm) 3020 { 3021 PetscFunctionBegin; 3022 PetscAssertPointer(dm, 4); 3023 PetscCall(DMCreate(comm, dm)); 3024 PetscCall(DMSetType(*dm, DMPLEX)); 3025 PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ, Nr)); 3026 PetscFunctionReturn(PETSC_SUCCESS); 3027 } 3028 3029 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate) 3030 { 3031 const PetscInt dim = 3; 3032 PetscInt numCells, numVertices, v; 3033 PetscMPIInt rank; 3034 3035 PetscFunctionBegin; 3036 PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n); 3037 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 3038 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3039 PetscCall(DMSetDimension(dm, dim)); 3040 /* Must create the celltype label here so that we do not automatically try to compute the types */ 3041 PetscCall(DMCreateLabel(dm, "celltype")); 3042 /* Create topology */ 3043 { 3044 PetscInt cone[6], c; 3045 3046 numCells = rank == 0 ? n : 0; 3047 numVertices = rank == 0 ? 2 * (n + 1) : 0; 3048 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 3049 for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6)); 3050 PetscCall(DMSetUp(dm)); 3051 for (c = 0; c < numCells; c++) { 3052 cone[0] = c + n * 1; 3053 cone[1] = (c + 1) % n + n * 1; 3054 cone[2] = 0 + 3 * n; 3055 cone[3] = c + n * 2; 3056 cone[4] = (c + 1) % n + n * 2; 3057 cone[5] = 1 + 3 * n; 3058 PetscCall(DMPlexSetCone(dm, c, cone)); 3059 PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR)); 3060 } 3061 PetscCall(DMPlexSymmetrize(dm)); 3062 PetscCall(DMPlexStratify(dm)); 3063 } 3064 for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT)); 3065 /* Create cylinder geometry */ 3066 { 3067 Vec coordinates; 3068 PetscSection coordSection; 3069 PetscScalar *coords; 3070 PetscInt coordSize, c; 3071 3072 /* Build coordinates */ 3073 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3074 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 3075 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim)); 3076 PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 3077 for (v = numCells; v < numCells + numVertices; ++v) { 3078 PetscCall(PetscSectionSetDof(coordSection, v, dim)); 3079 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim)); 3080 } 3081 PetscCall(PetscSectionSetUp(coordSection)); 3082 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 3083 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 3084 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 3085 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 3086 PetscCall(VecSetBlockSize(coordinates, dim)); 3087 PetscCall(VecSetType(coordinates, VECSTANDARD)); 3088 PetscCall(VecGetArray(coordinates, &coords)); 3089 for (c = 0; c < numCells; c++) { 3090 coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 3091 coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 3092 coords[(c + 0 * n) * dim + 2] = 1.0; 3093 coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n); 3094 coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n); 3095 coords[(c + 1 * n) * dim + 2] = 0.0; 3096 } 3097 if (rank == 0) { 3098 coords[(2 * n + 0) * dim + 0] = 0.0; 3099 coords[(2 * n + 0) * dim + 1] = 0.0; 3100 coords[(2 * n + 0) * dim + 2] = 1.0; 3101 coords[(2 * n + 1) * dim + 0] = 0.0; 3102 coords[(2 * n + 1) * dim + 1] = 0.0; 3103 coords[(2 * n + 1) * dim + 2] = 0.0; 3104 } 3105 PetscCall(VecRestoreArray(coordinates, &coords)); 3106 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 3107 PetscCall(VecDestroy(&coordinates)); 3108 } 3109 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 3110 /* Interpolate */ 3111 if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 3112 PetscFunctionReturn(PETSC_SUCCESS); 3113 } 3114 3115 /*@ 3116 DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges. 3117 3118 Collective 3119 3120 Input Parameters: 3121 + comm - The communicator for the `DM` object 3122 . n - The number of wedges around the origin 3123 - interpolate - Create edges and faces 3124 3125 Output Parameter: 3126 . dm - The `DM` object 3127 3128 Level: beginner 3129 3130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 3131 @*/ 3132 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm) 3133 { 3134 PetscFunctionBegin; 3135 PetscAssertPointer(dm, 4); 3136 PetscCall(DMCreate(comm, dm)); 3137 PetscCall(DMSetType(*dm, DMPLEX)); 3138 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate)); 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 3143 { 3144 PetscReal prod = 0.0; 3145 PetscInt i; 3146 for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]); 3147 return PetscSqrtReal(prod); 3148 } 3149 3150 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[]) 3151 { 3152 PetscReal prod = 0.0; 3153 PetscInt i; 3154 for (i = 0; i < dim; ++i) prod += x[i] * y[i]; 3155 return prod; 3156 } 3157 3158 /* The first constant is the sphere radius */ 3159 static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 3160 { 3161 PetscReal r = PetscRealPart(constants[0]); 3162 PetscReal norm2 = 0.0, fac; 3163 PetscInt n = uOff[1] - uOff[0], d; 3164 3165 for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d])); 3166 fac = r / PetscSqrtReal(norm2); 3167 for (d = 0; d < n; ++d) f0[d] = u[d] * fac; 3168 } 3169 3170 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R) 3171 { 3172 const PetscInt embedDim = dim + 1; 3173 PetscSection coordSection; 3174 Vec coordinates; 3175 PetscScalar *coords; 3176 PetscReal *coordsIn; 3177 PetscInt numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e; 3178 PetscMPIInt rank; 3179 3180 PetscFunctionBegin; 3181 PetscValidLogicalCollectiveBool(dm, simplex, 3); 3182 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 3183 PetscCall(DMSetDimension(dm, dim)); 3184 PetscCall(DMSetCoordinateDim(dm, dim + 1)); 3185 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3186 switch (dim) { 3187 case 1: 3188 numCells = 16; 3189 numVerts = numCells; 3190 3191 // Build Topology 3192 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 3193 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 3194 PetscCall(DMSetUp(dm)); 3195 for (PetscInt c = 0; c < numCells; ++c) { 3196 PetscInt cone[2]; 3197 3198 cone[0] = c + numCells; 3199 cone[1] = (c + 1) % numVerts + numCells; 3200 PetscCall(DMPlexSetCone(dm, c, cone)); 3201 } 3202 PetscCall(DMPlexSymmetrize(dm)); 3203 PetscCall(DMPlexStratify(dm)); 3204 PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn)); 3205 for (PetscInt v = 0; v < numVerts; ++v) { 3206 const PetscReal rad = 2. * PETSC_PI * v / numVerts; 3207 3208 coordsIn[v * embedDim + 0] = PetscCosReal(rad); 3209 coordsIn[v * embedDim + 1] = PetscSinReal(rad); 3210 } 3211 break; 3212 case 2: 3213 if (simplex) { 3214 const PetscReal radius = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI); 3215 const PetscReal edgeLen = 2.0 / (1.0 + PETSC_PHI) * (R / radius); 3216 const PetscInt degree = 5; 3217 PetscReal vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)}; 3218 PetscInt s[3] = {1, 1, 1}; 3219 PetscInt cone[3]; 3220 PetscInt *graph; 3221 3222 vertex[0] *= R / radius; 3223 vertex[1] *= R / radius; 3224 vertex[2] *= R / radius; 3225 numCells = rank == 0 ? 20 : 0; 3226 numVerts = rank == 0 ? 12 : 0; 3227 firstVertex = numCells; 3228 /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of 3229 3230 (0, \pm 1/\phi+1, \pm \phi/\phi+1) 3231 3232 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 3233 length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393. 3234 */ 3235 /* Construct vertices */ 3236 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 3237 if (rank == 0) { 3238 for (PetscInt p = 0, i = 0; p < embedDim; ++p) { 3239 for (s[1] = -1; s[1] < 2; s[1] += 2) { 3240 for (s[2] = -1; s[2] < 2; s[2] += 2) { 3241 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim]; 3242 ++i; 3243 } 3244 } 3245 } 3246 } 3247 /* Construct graph */ 3248 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 3249 for (PetscInt i = 0; i < numVerts; ++i) { 3250 PetscInt k = 0; 3251 for (PetscInt j = 0; j < numVerts; ++j) { 3252 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 3253 graph[i * numVerts + j] = 1; 3254 ++k; 3255 } 3256 } 3257 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 3258 } 3259 /* Build Topology */ 3260 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 3261 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 3262 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 3263 /* Cells */ 3264 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 3265 for (PetscInt j = 0; j < i; ++j) { 3266 for (PetscInt k = 0; k < j; ++k) { 3267 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) { 3268 cone[0] = firstVertex + i; 3269 cone[1] = firstVertex + j; 3270 cone[2] = firstVertex + k; 3271 /* Check orientation */ 3272 { 3273 const PetscInt epsilon[3][3][3] = { 3274 {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 3275 {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 3276 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 3277 }; 3278 PetscReal normal[3]; 3279 PetscInt e, f; 3280 3281 for (d = 0; d < embedDim; ++d) { 3282 normal[d] = 0.0; 3283 for (e = 0; e < embedDim; ++e) { 3284 for (f = 0; f < embedDim; ++f) normal[d] += epsilon[d][e][f] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]); 3285 } 3286 } 3287 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 3288 PetscInt tmp = cone[1]; 3289 cone[1] = cone[2]; 3290 cone[2] = tmp; 3291 } 3292 } 3293 PetscCall(DMPlexSetCone(dm, c++, cone)); 3294 } 3295 } 3296 } 3297 } 3298 PetscCall(DMPlexSymmetrize(dm)); 3299 PetscCall(DMPlexStratify(dm)); 3300 PetscCall(PetscFree(graph)); 3301 } else { 3302 /* 3303 12-21--13 3304 | | 3305 25 4 24 3306 | | 3307 12-25--9-16--8-24--13 3308 | | | | 3309 23 5 17 0 15 3 22 3310 | | | | 3311 10-20--6-14--7-19--11 3312 | | 3313 20 1 19 3314 | | 3315 10-18--11 3316 | | 3317 23 2 22 3318 | | 3319 12-21--13 3320 */ 3321 PetscInt cone[4], ornt[4]; 3322 3323 numCells = rank == 0 ? 6 : 0; 3324 numEdges = rank == 0 ? 12 : 0; 3325 numVerts = rank == 0 ? 8 : 0; 3326 firstVertex = numCells; 3327 firstEdge = numCells + numVerts; 3328 /* Build Topology */ 3329 PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts)); 3330 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4)); 3331 for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2)); 3332 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 3333 if (rank == 0) { 3334 /* Cell 0 */ 3335 cone[0] = 14; 3336 cone[1] = 15; 3337 cone[2] = 16; 3338 cone[3] = 17; 3339 PetscCall(DMPlexSetCone(dm, 0, cone)); 3340 ornt[0] = 0; 3341 ornt[1] = 0; 3342 ornt[2] = 0; 3343 ornt[3] = 0; 3344 PetscCall(DMPlexSetConeOrientation(dm, 0, ornt)); 3345 /* Cell 1 */ 3346 cone[0] = 18; 3347 cone[1] = 19; 3348 cone[2] = 14; 3349 cone[3] = 20; 3350 PetscCall(DMPlexSetCone(dm, 1, cone)); 3351 ornt[0] = 0; 3352 ornt[1] = 0; 3353 ornt[2] = -1; 3354 ornt[3] = 0; 3355 PetscCall(DMPlexSetConeOrientation(dm, 1, ornt)); 3356 /* Cell 2 */ 3357 cone[0] = 21; 3358 cone[1] = 22; 3359 cone[2] = 18; 3360 cone[3] = 23; 3361 PetscCall(DMPlexSetCone(dm, 2, cone)); 3362 ornt[0] = 0; 3363 ornt[1] = 0; 3364 ornt[2] = -1; 3365 ornt[3] = 0; 3366 PetscCall(DMPlexSetConeOrientation(dm, 2, ornt)); 3367 /* Cell 3 */ 3368 cone[0] = 19; 3369 cone[1] = 22; 3370 cone[2] = 24; 3371 cone[3] = 15; 3372 PetscCall(DMPlexSetCone(dm, 3, cone)); 3373 ornt[0] = -1; 3374 ornt[1] = -1; 3375 ornt[2] = 0; 3376 ornt[3] = -1; 3377 PetscCall(DMPlexSetConeOrientation(dm, 3, ornt)); 3378 /* Cell 4 */ 3379 cone[0] = 16; 3380 cone[1] = 24; 3381 cone[2] = 21; 3382 cone[3] = 25; 3383 PetscCall(DMPlexSetCone(dm, 4, cone)); 3384 ornt[0] = -1; 3385 ornt[1] = -1; 3386 ornt[2] = -1; 3387 ornt[3] = 0; 3388 PetscCall(DMPlexSetConeOrientation(dm, 4, ornt)); 3389 /* Cell 5 */ 3390 cone[0] = 20; 3391 cone[1] = 17; 3392 cone[2] = 25; 3393 cone[3] = 23; 3394 PetscCall(DMPlexSetCone(dm, 5, cone)); 3395 ornt[0] = -1; 3396 ornt[1] = -1; 3397 ornt[2] = -1; 3398 ornt[3] = -1; 3399 PetscCall(DMPlexSetConeOrientation(dm, 5, ornt)); 3400 /* Edges */ 3401 cone[0] = 6; 3402 cone[1] = 7; 3403 PetscCall(DMPlexSetCone(dm, 14, cone)); 3404 cone[0] = 7; 3405 cone[1] = 8; 3406 PetscCall(DMPlexSetCone(dm, 15, cone)); 3407 cone[0] = 8; 3408 cone[1] = 9; 3409 PetscCall(DMPlexSetCone(dm, 16, cone)); 3410 cone[0] = 9; 3411 cone[1] = 6; 3412 PetscCall(DMPlexSetCone(dm, 17, cone)); 3413 cone[0] = 10; 3414 cone[1] = 11; 3415 PetscCall(DMPlexSetCone(dm, 18, cone)); 3416 cone[0] = 11; 3417 cone[1] = 7; 3418 PetscCall(DMPlexSetCone(dm, 19, cone)); 3419 cone[0] = 6; 3420 cone[1] = 10; 3421 PetscCall(DMPlexSetCone(dm, 20, cone)); 3422 cone[0] = 12; 3423 cone[1] = 13; 3424 PetscCall(DMPlexSetCone(dm, 21, cone)); 3425 cone[0] = 13; 3426 cone[1] = 11; 3427 PetscCall(DMPlexSetCone(dm, 22, cone)); 3428 cone[0] = 10; 3429 cone[1] = 12; 3430 PetscCall(DMPlexSetCone(dm, 23, cone)); 3431 cone[0] = 13; 3432 cone[1] = 8; 3433 PetscCall(DMPlexSetCone(dm, 24, cone)); 3434 cone[0] = 12; 3435 cone[1] = 9; 3436 PetscCall(DMPlexSetCone(dm, 25, cone)); 3437 } 3438 PetscCall(DMPlexSymmetrize(dm)); 3439 PetscCall(DMPlexStratify(dm)); 3440 /* Build coordinates */ 3441 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 3442 if (rank == 0) { 3443 coordsIn[0 * embedDim + 0] = -R; 3444 coordsIn[0 * embedDim + 1] = R; 3445 coordsIn[0 * embedDim + 2] = -R; 3446 coordsIn[1 * embedDim + 0] = R; 3447 coordsIn[1 * embedDim + 1] = R; 3448 coordsIn[1 * embedDim + 2] = -R; 3449 coordsIn[2 * embedDim + 0] = R; 3450 coordsIn[2 * embedDim + 1] = -R; 3451 coordsIn[2 * embedDim + 2] = -R; 3452 coordsIn[3 * embedDim + 0] = -R; 3453 coordsIn[3 * embedDim + 1] = -R; 3454 coordsIn[3 * embedDim + 2] = -R; 3455 coordsIn[4 * embedDim + 0] = -R; 3456 coordsIn[4 * embedDim + 1] = R; 3457 coordsIn[4 * embedDim + 2] = R; 3458 coordsIn[5 * embedDim + 0] = R; 3459 coordsIn[5 * embedDim + 1] = R; 3460 coordsIn[5 * embedDim + 2] = R; 3461 coordsIn[6 * embedDim + 0] = -R; 3462 coordsIn[6 * embedDim + 1] = -R; 3463 coordsIn[6 * embedDim + 2] = R; 3464 coordsIn[7 * embedDim + 0] = R; 3465 coordsIn[7 * embedDim + 1] = -R; 3466 coordsIn[7 * embedDim + 2] = R; 3467 } 3468 } 3469 break; 3470 case 3: 3471 if (simplex) { 3472 const PetscReal edgeLen = 1.0 / PETSC_PHI; 3473 PetscReal vertexA[4] = {0.5, 0.5, 0.5, 0.5}; 3474 PetscReal vertexB[4] = {1.0, 0.0, 0.0, 0.0}; 3475 PetscReal vertexC[4] = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0}; 3476 const PetscInt degree = 12; 3477 PetscInt s[4] = {1, 1, 1}; 3478 PetscInt evenPerm[12][4] = { 3479 {0, 1, 2, 3}, 3480 {0, 2, 3, 1}, 3481 {0, 3, 1, 2}, 3482 {1, 0, 3, 2}, 3483 {1, 2, 0, 3}, 3484 {1, 3, 2, 0}, 3485 {2, 0, 1, 3}, 3486 {2, 1, 3, 0}, 3487 {2, 3, 0, 1}, 3488 {3, 0, 2, 1}, 3489 {3, 1, 0, 2}, 3490 {3, 2, 1, 0} 3491 }; 3492 PetscInt cone[4]; 3493 PetscInt *graph, p, i, j, k, l; 3494 3495 vertexA[0] *= R; 3496 vertexA[1] *= R; 3497 vertexA[2] *= R; 3498 vertexA[3] *= R; 3499 vertexB[0] *= R; 3500 vertexB[1] *= R; 3501 vertexB[2] *= R; 3502 vertexB[3] *= R; 3503 vertexC[0] *= R; 3504 vertexC[1] *= R; 3505 vertexC[2] *= R; 3506 vertexC[3] *= R; 3507 numCells = rank == 0 ? 600 : 0; 3508 numVerts = rank == 0 ? 120 : 0; 3509 firstVertex = numCells; 3510 /* Use the 600-cell, which for a unit sphere has coordinates which are 3511 3512 1/2 (\pm 1, \pm 1, \pm 1, \pm 1) 16 3513 (\pm 1, 0, 0, 0) all cyclic permutations 8 3514 1/2 (\pm 1, \pm phi, \pm 1/phi, 0) all even permutations 96 3515 3516 where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge 3517 length is then given by 1/\phi = 0.61803. 3518 3519 http://buzzard.pugetsound.edu/sage-practice/ch03s03.html 3520 http://mathworld.wolfram.com/600-Cell.html 3521 */ 3522 /* Construct vertices */ 3523 PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn)); 3524 i = 0; 3525 if (rank == 0) { 3526 for (s[0] = -1; s[0] < 2; s[0] += 2) { 3527 for (s[1] = -1; s[1] < 2; s[1] += 2) { 3528 for (s[2] = -1; s[2] < 2; s[2] += 2) { 3529 for (s[3] = -1; s[3] < 2; s[3] += 2) { 3530 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d]; 3531 ++i; 3532 } 3533 } 3534 } 3535 } 3536 for (p = 0; p < embedDim; ++p) { 3537 s[1] = s[2] = s[3] = 1; 3538 for (s[0] = -1; s[0] < 2; s[0] += 2) { 3539 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim]; 3540 ++i; 3541 } 3542 } 3543 for (p = 0; p < 12; ++p) { 3544 s[3] = 1; 3545 for (s[0] = -1; s[0] < 2; s[0] += 2) { 3546 for (s[1] = -1; s[1] < 2; s[1] += 2) { 3547 for (s[2] = -1; s[2] < 2; s[2] += 2) { 3548 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]]; 3549 ++i; 3550 } 3551 } 3552 } 3553 } 3554 } 3555 PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts); 3556 /* Construct graph */ 3557 PetscCall(PetscCalloc1(numVerts * numVerts, &graph)); 3558 for (i = 0; i < numVerts; ++i) { 3559 for (j = 0, k = 0; j < numVerts; ++j) { 3560 if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) { 3561 graph[i * numVerts + j] = 1; 3562 ++k; 3563 } 3564 } 3565 PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree); 3566 } 3567 /* Build Topology */ 3568 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts)); 3569 for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim)); 3570 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 3571 /* Cells */ 3572 if (rank == 0) { 3573 for (PetscInt i = 0, c = 0; i < numVerts; ++i) { 3574 for (j = 0; j < i; ++j) { 3575 for (k = 0; k < j; ++k) { 3576 for (l = 0; l < k; ++l) { 3577 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i] && graph[l * numVerts + i] && graph[l * numVerts + j] && graph[l * numVerts + k]) { 3578 cone[0] = firstVertex + i; 3579 cone[1] = firstVertex + j; 3580 cone[2] = firstVertex + k; 3581 cone[3] = firstVertex + l; 3582 /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */ 3583 { 3584 const PetscInt epsilon[4][4][4][4] = { 3585 {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, -1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 0, 0}, {0, 1, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 1, 0}, {0, -1, 0, 0}, {0, 0, 0, 0}}}, 3586 3587 {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}}, {{0, 0, -1, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}}}, 3588 3589 {{{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}, {0, -1, 0, 0}}, {{0, 0, 0, -1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 1, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}}, 3590 3591 {{{0, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 1, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}}, {{0, -1, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} } 3592 }; 3593 PetscReal normal[4]; 3594 PetscInt e, f, g; 3595 3596 for (d = 0; d < embedDim; ++d) { 3597 normal[d] = 0.0; 3598 for (e = 0; e < embedDim; ++e) { 3599 for (f = 0; f < embedDim; ++f) { 3600 for (g = 0; g < embedDim; ++g) { 3601 normal[d] += epsilon[d][e][f][g] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]) * (coordsIn[l * embedDim + f] - coordsIn[i * embedDim + f]); 3602 } 3603 } 3604 } 3605 } 3606 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) { 3607 PetscInt tmp = cone[1]; 3608 cone[1] = cone[2]; 3609 cone[2] = tmp; 3610 } 3611 } 3612 PetscCall(DMPlexSetCone(dm, c++, cone)); 3613 } 3614 } 3615 } 3616 } 3617 } 3618 } 3619 PetscCall(DMPlexSymmetrize(dm)); 3620 PetscCall(DMPlexStratify(dm)); 3621 PetscCall(PetscFree(graph)); 3622 } 3623 break; 3624 default: 3625 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim); 3626 } 3627 /* Create coordinates */ 3628 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3629 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 3630 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim)); 3631 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts)); 3632 for (v = firstVertex; v < firstVertex + numVerts; ++v) { 3633 PetscCall(PetscSectionSetDof(coordSection, v, embedDim)); 3634 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim)); 3635 } 3636 PetscCall(PetscSectionSetUp(coordSection)); 3637 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 3638 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 3639 PetscCall(VecSetBlockSize(coordinates, embedDim)); 3640 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 3641 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 3642 PetscCall(VecSetType(coordinates, VECSTANDARD)); 3643 PetscCall(VecGetArray(coordinates, &coords)); 3644 for (v = 0; v < numVerts; ++v) 3645 for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d]; 3646 PetscCall(VecRestoreArray(coordinates, &coords)); 3647 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 3648 PetscCall(VecDestroy(&coordinates)); 3649 PetscCall(PetscFree(coordsIn)); 3650 { 3651 DM cdm; 3652 PetscDS cds; 3653 PetscScalar c = R; 3654 3655 PetscCall(DMPlexSetCoordinateMap(dm, snapToSphere)); 3656 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 3657 PetscCall(DMGetCoordinateDM(dm, &cdm)); 3658 PetscCall(DMGetDS(cdm, &cds)); 3659 PetscCall(PetscDSSetConstants(cds, 1, &c)); 3660 } 3661 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 3662 /* Wait for coordinate creation before doing in-place modification */ 3663 if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm)); 3664 PetscFunctionReturn(PETSC_SUCCESS); 3665 } 3666 3667 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]); 3668 3669 /* 3670 The Schwarz P implicit surface is 3671 3672 f(x) = cos(x0) + cos(x1) + cos(x2) = 0 3673 */ 3674 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 3675 { 3676 PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)}; 3677 PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)}; 3678 f[0] = c[0] + c[1] + c[2]; 3679 for (PetscInt i = 0; i < 3; i++) { 3680 grad[i] = PETSC_PI * g[i]; 3681 for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.; 3682 } 3683 } 3684 3685 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 3686 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 3687 { 3688 for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI); 3689 return PETSC_SUCCESS; 3690 } 3691 3692 /* 3693 The Gyroid implicit surface is 3694 3695 f(x,y,z) = sin(pi * x) * cos (pi * (y + 1/2)) + sin(pi * (y + 1/2)) * cos(pi * (z + 1/4)) + sin(pi * (z + 1/4)) * cos(pi * x) 3696 3697 */ 3698 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3]) 3699 { 3700 PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))}; 3701 PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))}; 3702 f[0] = s[0] * c[1] + s[1] * c[2] + s[2] * c[0]; 3703 grad[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 3704 grad[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 3705 grad[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 3706 hess[0][0] = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]); 3707 hess[0][1] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 3708 hess[0][2] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 3709 hess[1][0] = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]); 3710 hess[1][1] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 3711 hess[2][2] = -PetscSqr(PETSC_PI) * (c[0] * s[1]); 3712 hess[2][0] = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]); 3713 hess[2][1] = -PetscSqr(PETSC_PI) * (c[2] * s[0]); 3714 hess[2][2] = -PetscSqr(PETSC_PI) * (c[1] * s[2]); 3715 } 3716 3717 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction 3718 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx) 3719 { 3720 PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))}; 3721 PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))}; 3722 u[0] = PETSC_PI * (c[0] * c[1] - s[2] * s[0]); 3723 u[1] = PETSC_PI * (c[1] * c[2] - s[0] * s[1]); 3724 u[2] = PETSC_PI * (c[2] * c[0] - s[1] * s[2]); 3725 return PETSC_SUCCESS; 3726 } 3727 3728 /* 3729 We wish to solve 3730 3731 min_y || y - x ||^2 subject to f(y) = 0 3732 3733 Let g(y) = grad(f). The minimization problem is equivalent to asking to satisfy 3734 f(y) = 0 and (y-x) is parallel to g(y). We do this by using Householder QR to obtain a basis for the 3735 tangent space and ask for both components in the tangent space to be zero. 3736 3737 Take g to be a column vector and compute the "full QR" factorization Q R = g, 3738 where Q = I - 2 n n^T is a symmetric orthogonal matrix. 3739 The first column of Q is parallel to g so the remaining two columns span the null space. 3740 Let Qn = Q[:,1:] be those remaining columns. Then Qn Qn^T is an orthogonal projector into the tangent space. 3741 Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries. 3742 In total, we have a system of 3 equations in 3 unknowns: 3743 3744 f(y) = 0 1 equation 3745 Qn^T (y - x) = 0 2 equations 3746 3747 Here, we compute the residual and Jacobian of this system. 3748 */ 3749 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[]) 3750 { 3751 PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])}; 3752 PetscReal d[3] = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])}; 3753 PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign; 3754 PetscReal n_y[3][3] = { 3755 {0, 0, 0}, 3756 {0, 0, 0}, 3757 {0, 0, 0} 3758 }; 3759 3760 feval(yreal, &f, grad, n_y); 3761 3762 for (PetscInt i = 0; i < 3; i++) n[i] = grad[i]; 3763 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 3764 for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i]; 3765 3766 // Define the Householder reflector 3767 sign = n[0] >= 0 ? 1. : -1.; 3768 n[0] += norm * sign; 3769 for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign; 3770 3771 norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2])); 3772 norm_y[0] = 1. / norm * (n[0] * n_y[0][0]); 3773 norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]); 3774 norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]); 3775 3776 for (PetscInt i = 0; i < 3; i++) { 3777 n[i] /= norm; 3778 for (PetscInt j = 0; j < 3; j++) { 3779 // note that n[i] is n_old[i]/norm when executing the code below 3780 n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j]; 3781 } 3782 } 3783 3784 nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2]; 3785 for (PetscInt i = 0; i < 3; i++) nd_y[i] = n[i] + n_y[0][i] * d[0] + n_y[1][i] * d[1] + n_y[2][i] * d[2]; 3786 3787 res[0] = f; 3788 res[1] = d[1] - 2 * n[1] * nd; 3789 res[2] = d[2] - 2 * n[2] * nd; 3790 // J[j][i] is J_{ij} (column major) 3791 for (PetscInt j = 0; j < 3; j++) { 3792 J[0 + j * 3] = grad[j]; 3793 J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]); 3794 J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]); 3795 } 3796 } 3797 3798 /* 3799 Project x to the nearest point on the implicit surface using Newton's method. 3800 */ 3801 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[]) 3802 { 3803 PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess 3804 3805 PetscFunctionBegin; 3806 for (PetscInt iter = 0; iter < 10; iter++) { 3807 PetscScalar res[3], J[9]; 3808 PetscReal resnorm; 3809 TPSNearestPointResJac(feval, x, y, res, J); 3810 resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2]))); 3811 if (0) { // Turn on this monitor if you need to confirm quadratic convergence 3812 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%" PetscInt_FMT "] res [%g %g %g]\n", iter, (double)PetscRealPart(res[0]), (double)PetscRealPart(res[1]), (double)PetscRealPart(res[2]))); 3813 } 3814 if (resnorm < PETSC_SMALL) break; 3815 3816 // Take the Newton step 3817 PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL)); 3818 PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res); 3819 } 3820 for (PetscInt i = 0; i < 3; i++) x[i] = y[i]; 3821 PetscFunctionReturn(PETSC_SUCCESS); 3822 } 3823 3824 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL}; 3825 3826 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness) 3827 { 3828 PetscMPIInt rank; 3829 PetscInt topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0; 3830 PetscInt (*edges)[2] = NULL, *edgeSets = NULL; 3831 PetscInt *cells_flat = NULL; 3832 PetscReal *vtxCoords = NULL; 3833 TPSEvaluateFunc evalFunc = NULL; 3834 PetscSimplePointFn *normalFunc = NULL; 3835 DMLabel label; 3836 3837 PetscFunctionBegin; 3838 PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0)); 3839 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3840 PetscCheck((layers != 0) ^ (thickness == 0.), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Layers %" PetscInt_FMT " must be nonzero iff thickness %g is nonzero", layers, (double)thickness); 3841 switch (tpstype) { 3842 case DMPLEX_TPS_SCHWARZ_P: 3843 PetscCheck(!periodic || (periodic[0] == DM_BOUNDARY_NONE && periodic[1] == DM_BOUNDARY_NONE && periodic[2] == DM_BOUNDARY_NONE), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Schwarz P does not support periodic meshes"); 3844 if (rank == 0) { 3845 PetscInt (*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn] 3846 PetscInt Njunctions = 0, Ncuts = 0, Npipes[3], vcount; 3847 PetscReal L = 1; 3848 3849 Npipes[0] = (extent[0] + 1) * extent[1] * extent[2]; 3850 Npipes[1] = extent[0] * (extent[1] + 1) * extent[2]; 3851 Npipes[2] = extent[0] * extent[1] * (extent[2] + 1); 3852 Njunctions = extent[0] * extent[1] * extent[2]; 3853 Ncuts = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]); 3854 numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions; 3855 PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords)); 3856 PetscCall(PetscMalloc1(Njunctions, &cells)); 3857 PetscCall(PetscMalloc1(Ncuts * 4, &edges)); 3858 PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets)); 3859 // x-normal pipes 3860 vcount = 0; 3861 for (PetscInt i = 0; i < extent[0] + 1; i++) { 3862 for (PetscInt j = 0; j < extent[1]; j++) { 3863 for (PetscInt k = 0; k < extent[2]; k++) { 3864 for (PetscInt l = 0; l < 4; l++) { 3865 vtxCoords[vcount++] = (2 * i - 1) * L; 3866 vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3867 vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3868 } 3869 } 3870 } 3871 } 3872 // y-normal pipes 3873 for (PetscInt i = 0; i < extent[0]; i++) { 3874 for (PetscInt j = 0; j < extent[1] + 1; j++) { 3875 for (PetscInt k = 0; k < extent[2]; k++) { 3876 for (PetscInt l = 0; l < 4; l++) { 3877 vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3878 vtxCoords[vcount++] = (2 * j - 1) * L; 3879 vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3880 } 3881 } 3882 } 3883 } 3884 // z-normal pipes 3885 for (PetscInt i = 0; i < extent[0]; i++) { 3886 for (PetscInt j = 0; j < extent[1]; j++) { 3887 for (PetscInt k = 0; k < extent[2] + 1; k++) { 3888 for (PetscInt l = 0; l < 4; l++) { 3889 vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3890 vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2; 3891 vtxCoords[vcount++] = (2 * k - 1) * L; 3892 } 3893 } 3894 } 3895 } 3896 // junctions 3897 for (PetscInt i = 0; i < extent[0]; i++) { 3898 for (PetscInt j = 0; j < extent[1]; j++) { 3899 for (PetscInt k = 0; k < extent[2]; k++) { 3900 const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8; 3901 PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count"); 3902 for (PetscInt ii = 0; ii < 2; ii++) { 3903 for (PetscInt jj = 0; jj < 2; jj++) { 3904 for (PetscInt kk = 0; kk < 2; kk++) { 3905 double Ls = (1 - sqrt(2) / 4) * L; 3906 vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls; 3907 vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls; 3908 vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls; 3909 } 3910 } 3911 } 3912 const PetscInt jfaces[3][2][4] = { 3913 {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned 3914 {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned 3915 {{6, 2, 0, 4}, {7, 3, 1, 5}} // z-aligned 3916 }; 3917 const PetscInt pipe_lo[3] = {// vertex numbers of pipes 3918 ((i * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + Npipes[0] + Npipes[1]) * 4}; 3919 const PetscInt pipe_hi[3] = {// vertex numbers of pipes 3920 (((i + 1) * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j + 1) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + 1 + Npipes[0] + Npipes[1]) * 4}; 3921 for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z 3922 const PetscInt ijk[3] = {i, j, k}; 3923 for (PetscInt l = 0; l < 4; l++) { // rotations 3924 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l; 3925 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l]; 3926 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4]; 3927 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4; 3928 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l]; 3929 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l; 3930 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4; 3931 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4]; 3932 if (ijk[dir] == 0) { 3933 edges[numEdges][0] = pipe_lo[dir] + l; 3934 edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4; 3935 edgeSets[numEdges] = dir * 2 + 1; 3936 numEdges++; 3937 } 3938 if (ijk[dir] + 1 == extent[dir]) { 3939 edges[numEdges][0] = pipe_hi[dir] + l; 3940 edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4; 3941 edgeSets[numEdges] = dir * 2 + 2; 3942 numEdges++; 3943 } 3944 } 3945 } 3946 } 3947 } 3948 } 3949 PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts); 3950 numFaces = 24 * Njunctions; 3951 cells_flat = cells[0][0][0]; 3952 } 3953 evalFunc = TPSEvaluate_SchwarzP; 3954 normalFunc = TPSExtrudeNormalFunc_SchwarzP; 3955 break; 3956 case DMPLEX_TPS_GYROID: 3957 if (rank == 0) { 3958 // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set 3959 // 3960 // sin(pi*x)*cos(pi*(y+1/2)) + sin(pi*(y+1/2))*cos(pi*(z+1/4)) + sin(pi*(z+1/4))*cos(x) 3961 // 3962 // on the cell [0,2]^3. 3963 // 3964 // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2]. 3965 // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins 3966 // like a boomerang: 3967 // 3968 // z = 0 z = 1/4 z = 1/2 z = 3/4 // 3969 // ----- ------- ------- ------- // 3970 // // 3971 // + + + + + + + \ + // 3972 // \ / \ // 3973 // \ `-_ _-' / } // 3974 // *-_ `-' _-' / // 3975 // + `-+ + + +-' + + / + // 3976 // // 3977 // // 3978 // z = 1 z = 5/4 z = 3/2 z = 7/4 // 3979 // ----- ------- ------- ------- // 3980 // // 3981 // +-_ + + + + _-+ + / + // 3982 // `-_ _-_ _-` / // 3983 // \ _-' `-_ / { // 3984 // \ / \ // 3985 // + + + + + + + \ + // 3986 // 3987 // 3988 // This course mesh approximates each of these slices by two line segments, 3989 // and then connects the segments in consecutive layers with quadrilateral faces. 3990 // All of the end points of the segments are multiples of 1/4 except for the 3991 // point * in the picture for z = 0 above and the similar points in other layers. 3992 // That point is at (gamma, gamma, 0), where gamma is calculated below. 3993 // 3994 // The column [1,2]x[1,2]x[0,2] looks the same as this column; 3995 // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images. 3996 // 3997 // As for how this method turned into the names given to the vertices: 3998 // that was not systematic, it was just the way it worked out in my handwritten notes. 3999 4000 PetscInt facesPerBlock = 64; 4001 PetscInt vertsPerBlock = 56; 4002 PetscInt extentPlus[3]; 4003 PetscInt numBlocks, numBlocksPlus; 4004 const PetscInt A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, II = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15, Q = 16, R = 17, S = 18, T = 19, U = 20, V = 21, W = 22, X = 23, Y = 24, Z = 25, Ap = 26, Bp = 27, Cp = 28, Dp = 29, Ep = 30, Fp = 31, Gp = 32, Hp = 33, Ip = 34, Jp = 35, Kp = 36, Lp = 37, Mp = 38, Np = 39, Op = 40, Pp = 41, Qp = 42, Rp = 43, Sp = 44, Tp = 45, Up = 46, Vp = 47, Wp = 48, Xp = 49, Yp = 50, Zp = 51, Aq = 52, Bq = 53, Cq = 54, Dq = 55; 4005 const PetscInt pattern[64][4] = { 4006 /* face to vertex within the coarse discretization of a single gyroid block */ 4007 /* layer 0 */ 4008 {A, C, K, G }, 4009 {C, B, II, K }, 4010 {D, A, H, L }, 4011 {B + 56 * 1, D, L, J }, 4012 {E, B + 56 * 1, J, N }, 4013 {A + 56 * 2, E, N, H + 56 * 2 }, 4014 {F, A + 56 * 2, G + 56 * 2, M }, 4015 {B, F, M, II }, 4016 /* layer 1 */ 4017 {G, K, Q, O }, 4018 {K, II, P, Q }, 4019 {L, H, O + 56 * 1, R }, 4020 {J, L, R, P }, 4021 {N, J, P, S }, 4022 {H + 56 * 2, N, S, O + 56 * 3 }, 4023 {M, G + 56 * 2, O + 56 * 2, T }, 4024 {II, M, T, P }, 4025 /* layer 2 */ 4026 {O, Q, Y, U }, 4027 {Q, P, W, Y }, 4028 {R, O + 56 * 1, U + 56 * 1, Ap }, 4029 {P, R, Ap, W }, 4030 {S, P, X, Bp }, 4031 {O + 56 * 3, S, Bp, V + 56 * 1 }, 4032 {T, O + 56 * 2, V, Z }, 4033 {P, T, Z, X }, 4034 /* layer 3 */ 4035 {U, Y, Ep, Dp }, 4036 {Y, W, Cp, Ep }, 4037 {Ap, U + 56 * 1, Dp + 56 * 1, Gp }, 4038 {W, Ap, Gp, Cp }, 4039 {Bp, X, Cp + 56 * 2, Fp }, 4040 {V + 56 * 1, Bp, Fp, Dp + 56 * 1}, 4041 {Z, V, Dp, Hp }, 4042 {X, Z, Hp, Cp + 56 * 2}, 4043 /* layer 4 */ 4044 {Dp, Ep, Mp, Kp }, 4045 {Ep, Cp, Ip, Mp }, 4046 {Gp, Dp + 56 * 1, Lp, Np }, 4047 {Cp, Gp, Np, Jp }, 4048 {Fp, Cp + 56 * 2, Jp + 56 * 2, Pp }, 4049 {Dp + 56 * 1, Fp, Pp, Lp }, 4050 {Hp, Dp, Kp, Op }, 4051 {Cp + 56 * 2, Hp, Op, Ip + 56 * 2}, 4052 /* layer 5 */ 4053 {Kp, Mp, Sp, Rp }, 4054 {Mp, Ip, Qp, Sp }, 4055 {Np, Lp, Rp, Tp }, 4056 {Jp, Np, Tp, Qp + 56 * 1}, 4057 {Pp, Jp + 56 * 2, Qp + 56 * 3, Up }, 4058 {Lp, Pp, Up, Rp }, 4059 {Op, Kp, Rp, Vp }, 4060 {Ip + 56 * 2, Op, Vp, Qp + 56 * 2}, 4061 /* layer 6 */ 4062 {Rp, Sp, Aq, Yp }, 4063 {Sp, Qp, Wp, Aq }, 4064 {Tp, Rp, Yp, Cq }, 4065 {Qp + 56 * 1, Tp, Cq, Wp + 56 * 1}, 4066 {Up, Qp + 56 * 3, Xp + 56 * 1, Dq }, 4067 {Rp, Up, Dq, Zp }, 4068 {Vp, Rp, Zp, Bq }, 4069 {Qp + 56 * 2, Vp, Bq, Xp }, 4070 /* layer 7 (the top is the periodic image of the bottom of layer 0) */ 4071 {Yp, Aq, C + 56 * 4, A + 56 * 4 }, 4072 {Aq, Wp, B + 56 * 4, C + 56 * 4 }, 4073 {Cq, Yp, A + 56 * 4, D + 56 * 4 }, 4074 {Wp + 56 * 1, Cq, D + 56 * 4, B + 56 * 5 }, 4075 {Dq, Xp + 56 * 1, B + 56 * 5, E + 56 * 4 }, 4076 {Zp, Dq, E + 56 * 4, A + 56 * 6 }, 4077 {Bq, Zp, A + 56 * 6, F + 56 * 4 }, 4078 {Xp, Bq, F + 56 * 4, B + 56 * 4 } 4079 }; 4080 const PetscReal gamma = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI; 4081 const PetscReal patternCoords[56][3] = { 4082 {1., 0., 0. }, /* A */ 4083 {0., 1., 0. }, /* B */ 4084 {gamma, gamma, 0. }, /* C */ 4085 {1 + gamma, 1 - gamma, 0. }, /* D */ 4086 {2 - gamma, 2 - gamma, 0. }, /* E */ 4087 {1 - gamma, 1 + gamma, 0. }, /* F */ 4088 4089 {.5, 0, .25 }, /* G */ 4090 {1.5, 0., .25 }, /* H */ 4091 {.5, 1., .25 }, /* II */ 4092 {1.5, 1., .25 }, /* J */ 4093 {.25, .5, .25 }, /* K */ 4094 {1.25, .5, .25 }, /* L */ 4095 {.75, 1.5, .25 }, /* M */ 4096 {1.75, 1.5, .25 }, /* N */ 4097 4098 {0., 0., .5 }, /* O */ 4099 {1., 1., .5 }, /* P */ 4100 {gamma, 1 - gamma, .5 }, /* Q */ 4101 {1 + gamma, gamma, .5 }, /* R */ 4102 {2 - gamma, 1 + gamma, .5 }, /* S */ 4103 {1 - gamma, 2 - gamma, .5 }, /* T */ 4104 4105 {0., .5, .75 }, /* U */ 4106 {0., 1.5, .75 }, /* V */ 4107 {1., .5, .75 }, /* W */ 4108 {1., 1.5, .75 }, /* X */ 4109 {.5, .75, .75 }, /* Y */ 4110 {.5, 1.75, .75 }, /* Z */ 4111 {1.5, .25, .75 }, /* Ap */ 4112 {1.5, 1.25, .75 }, /* Bp */ 4113 4114 {1., 0., 1. }, /* Cp */ 4115 {0., 1., 1. }, /* Dp */ 4116 {1 - gamma, 1 - gamma, 1. }, /* Ep */ 4117 {1 + gamma, 1 + gamma, 1. }, /* Fp */ 4118 {2 - gamma, gamma, 1. }, /* Gp */ 4119 {gamma, 2 - gamma, 1. }, /* Hp */ 4120 4121 {.5, 0., 1.25}, /* Ip */ 4122 {1.5, 0., 1.25}, /* Jp */ 4123 {.5, 1., 1.25}, /* Kp */ 4124 {1.5, 1., 1.25}, /* Lp */ 4125 {.75, .5, 1.25}, /* Mp */ 4126 {1.75, .5, 1.25}, /* Np */ 4127 {.25, 1.5, 1.25}, /* Op */ 4128 {1.25, 1.5, 1.25}, /* Pp */ 4129 4130 {0., 0., 1.5 }, /* Qp */ 4131 {1., 1., 1.5 }, /* Rp */ 4132 {1 - gamma, gamma, 1.5 }, /* Sp */ 4133 {2 - gamma, 1 - gamma, 1.5 }, /* Tp */ 4134 {1 + gamma, 2 - gamma, 1.5 }, /* Up */ 4135 {gamma, 1 + gamma, 1.5 }, /* Vp */ 4136 4137 {0., .5, 1.75}, /* Wp */ 4138 {0., 1.5, 1.75}, /* Xp */ 4139 {1., .5, 1.75}, /* Yp */ 4140 {1., 1.5, 1.75}, /* Zp */ 4141 {.5, .25, 1.75}, /* Aq */ 4142 {.5, 1.25, 1.75}, /* Bq */ 4143 {1.5, .75, 1.75}, /* Cq */ 4144 {1.5, 1.75, 1.75}, /* Dq */ 4145 }; 4146 PetscInt (*cells)[64][4] = NULL; 4147 PetscBool *seen; 4148 PetscInt *vertToTrueVert; 4149 PetscInt count; 4150 4151 for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1; 4152 numBlocks = 1; 4153 for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i]; 4154 numBlocksPlus = 1; 4155 for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i]; 4156 numFaces = numBlocks * facesPerBlock; 4157 PetscCall(PetscMalloc1(numBlocks, &cells)); 4158 PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen)); 4159 for (PetscInt k = 0; k < extent[2]; k++) { 4160 for (PetscInt j = 0; j < extent[1]; j++) { 4161 for (PetscInt i = 0; i < extent[0]; i++) { 4162 for (PetscInt f = 0; f < facesPerBlock; f++) { 4163 for (PetscInt v = 0; v < 4; v++) { 4164 PetscInt vertRaw = pattern[f][v]; 4165 PetscInt blockidx = vertRaw / 56; 4166 PetscInt patternvert = vertRaw % 56; 4167 PetscInt xplus = (blockidx & 1); 4168 PetscInt yplus = (blockidx & 2) >> 1; 4169 PetscInt zplus = (blockidx & 4) >> 2; 4170 PetscInt zcoord = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus); 4171 PetscInt ycoord = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus); 4172 PetscInt xcoord = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus); 4173 PetscInt vert = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert; 4174 4175 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert; 4176 seen[vert] = PETSC_TRUE; 4177 } 4178 } 4179 } 4180 } 4181 } 4182 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) 4183 if (seen[i]) numVertices++; 4184 count = 0; 4185 PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert)); 4186 PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords)); 4187 for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1; 4188 for (PetscInt k = 0; k < extentPlus[2]; k++) { 4189 for (PetscInt j = 0; j < extentPlus[1]; j++) { 4190 for (PetscInt i = 0; i < extentPlus[0]; i++) { 4191 for (PetscInt v = 0; v < vertsPerBlock; v++) { 4192 PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v; 4193 4194 if (seen[vIdx]) { 4195 PetscInt thisVert; 4196 4197 vertToTrueVert[vIdx] = thisVert = count++; 4198 4199 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d]; 4200 vtxCoords[3 * thisVert + 0] += i * 2; 4201 vtxCoords[3 * thisVert + 1] += j * 2; 4202 vtxCoords[3 * thisVert + 2] += k * 2; 4203 } 4204 } 4205 } 4206 } 4207 } 4208 for (PetscInt i = 0; i < numBlocks; i++) { 4209 for (PetscInt f = 0; f < facesPerBlock; f++) { 4210 for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]]; 4211 } 4212 } 4213 PetscCall(PetscFree(vertToTrueVert)); 4214 PetscCall(PetscFree(seen)); 4215 cells_flat = cells[0][0]; 4216 numEdges = 0; 4217 for (PetscInt i = 0; i < numFaces; i++) { 4218 for (PetscInt e = 0; e < 4; e++) { 4219 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 4220 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 4221 4222 for (PetscInt d = 0; d < 3; d++) { 4223 if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) { 4224 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++; 4225 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++; 4226 } 4227 } 4228 } 4229 } 4230 PetscCall(PetscMalloc1(numEdges, &edges)); 4231 PetscCall(PetscMalloc1(numEdges, &edgeSets)); 4232 for (PetscInt edge = 0, i = 0; i < numFaces; i++) { 4233 for (PetscInt e = 0; e < 4; e++) { 4234 PetscInt ev[] = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]}; 4235 const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]}; 4236 4237 for (PetscInt d = 0; d < 3; d++) { 4238 if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) { 4239 if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) { 4240 edges[edge][0] = ev[0]; 4241 edges[edge][1] = ev[1]; 4242 edgeSets[edge++] = 2 * d; 4243 } 4244 if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) { 4245 edges[edge][0] = ev[0]; 4246 edges[edge][1] = ev[1]; 4247 edgeSets[edge++] = 2 * d + 1; 4248 } 4249 } 4250 } 4251 } 4252 } 4253 } 4254 evalFunc = TPSEvaluate_Gyroid; 4255 normalFunc = TPSExtrudeNormalFunc_Gyroid; 4256 break; 4257 } 4258 4259 PetscCall(DMSetDimension(dm, topoDim)); 4260 if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat)); 4261 else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL)); 4262 PetscCall(PetscFree(cells_flat)); 4263 { 4264 DM idm; 4265 PetscCall(DMPlexInterpolate(dm, &idm)); 4266 PetscCall(DMPlexReplace_Internal(dm, &idm)); 4267 } 4268 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords)); 4269 else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL)); 4270 PetscCall(PetscFree(vtxCoords)); 4271 4272 PetscCall(DMCreateLabel(dm, "Face Sets")); 4273 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 4274 for (PetscInt e = 0; e < numEdges; e++) { 4275 PetscInt njoin; 4276 const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]}; 4277 PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join)); 4278 PetscCheck(njoin == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected unique join of vertices %" PetscInt_FMT " and %" PetscInt_FMT, edges[e][0], edges[e][1]); 4279 PetscCall(DMLabelSetValue(label, join[0], edgeSets[e])); 4280 PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join)); 4281 } 4282 PetscCall(PetscFree(edges)); 4283 PetscCall(PetscFree(edgeSets)); 4284 if (tps_distribute) { 4285 DM pdm = NULL; 4286 PetscPartitioner part; 4287 4288 PetscCall(DMPlexGetPartitioner(dm, &part)); 4289 PetscCall(PetscPartitionerSetFromOptions(part)); 4290 PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm)); 4291 if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm)); 4292 // Do not auto-distribute again 4293 PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE)); 4294 } 4295 4296 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4297 for (PetscInt refine = 0; refine < refinements; refine++) { 4298 PetscInt m; 4299 DM dmf, cdm, cdmf; 4300 Vec X; 4301 PetscScalar *x; 4302 4303 PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf)); 4304 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4305 PetscCall(DMGetCoordinateDM(dmf, &cdmf)); 4306 PetscCall(DMCopyDisc(cdm, cdmf)); 4307 PetscCall(DMPlexReplace_Internal(dm, &dmf)); 4308 4309 PetscCall(DMGetCoordinatesLocal(dm, &X)); 4310 PetscCall(VecGetLocalSize(X, &m)); 4311 PetscCall(VecGetArray(X, &x)); 4312 for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i])); 4313 PetscCall(VecRestoreArray(X, &x)); 4314 } 4315 4316 // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices. 4317 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 4318 PetscCall(DMPlexLabelComplete(dm, label)); 4319 4320 PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0)); 4321 4322 if (thickness > 0) { 4323 DM edm, cdm, ecdm; 4324 DMPlexTransform tr; 4325 const char *prefix; 4326 PetscOptions options; 4327 // Code from DMPlexExtrude 4328 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 4329 PetscCall(DMPlexTransformSetDM(tr, dm)); 4330 PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDETYPE)); 4331 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 4332 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 4333 PetscCall(PetscObjectGetOptions((PetscObject)dm, &options)); 4334 PetscCall(PetscObjectSetOptions((PetscObject)tr, options)); 4335 PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers)); 4336 PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness)); 4337 PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE)); 4338 PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE)); 4339 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 4340 PetscCall(DMPlexTransformSetFromOptions(tr)); 4341 PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL)); 4342 PetscCall(DMPlexTransformSetUp(tr)); 4343 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view")); 4344 PetscCall(DMPlexTransformApply(tr, dm, &edm)); 4345 PetscCall(DMCopyDisc(dm, edm)); 4346 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4347 PetscCall(DMGetCoordinateDM(edm, &ecdm)); 4348 PetscCall(DMCopyDisc(cdm, ecdm)); 4349 PetscCall(DMPlexTransformCreateDiscLabels(tr, edm)); 4350 PetscCall(DMPlexTransformDestroy(&tr)); 4351 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, edm)); 4352 PetscCall(DMPlexReplace_Internal(dm, &edm)); 4353 } 4354 PetscFunctionReturn(PETSC_SUCCESS); 4355 } 4356 4357 /*@ 4358 DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface 4359 4360 Collective 4361 4362 Input Parameters: 4363 + comm - The communicator for the `DM` object 4364 . tpstype - Type of triply-periodic surface 4365 . extent - Array of length 3 containing number of periods in each direction 4366 . periodic - array of length 3 with periodicity, or `NULL` for non-periodic 4367 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable) 4368 . refinements - Number of factor-of-2 refinements of 2D manifold mesh 4369 . layers - Number of cell layers extruded in normal direction 4370 - thickness - Thickness in normal direction 4371 4372 Output Parameter: 4373 . dm - The `DM` object 4374 4375 Level: beginner 4376 4377 Notes: 4378 This meshes the surface of the Schwarz P or Gyroid surfaces. Schwarz P is the simplest member of the triply-periodic minimal surfaces. 4379 <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries. 4380 The Gyroid <https://en.wikipedia.org/wiki/Gyroid> is another triply-periodic minimal surface with applications in additive manufacturing; it is much more difficult to "cut" since there are no planes of symmetry. 4381 Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested. 4382 On each refinement, all vertices are projected to their nearest point on the surface. 4383 This projection could readily be extended to related surfaces. 4384 4385 See {cite}`maskery2018insights` 4386 4387 The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$. 4388 When the mesh is refined, "Face Sets" contain the new vertices (created during refinement). 4389 Use `DMPlexLabelComplete()` to propagate to coarse-level vertices. 4390 4391 Developer Notes: 4392 The Gyroid mesh does not currently mark boundary sets. 4393 4394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()` 4395 @*/ 4396 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm) 4397 { 4398 PetscFunctionBegin; 4399 PetscCall(DMCreate(comm, dm)); 4400 PetscCall(DMSetType(*dm, DMPLEX)); 4401 PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness)); 4402 PetscFunctionReturn(PETSC_SUCCESS); 4403 } 4404 4405 /*@ 4406 DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d. 4407 4408 Collective 4409 4410 Input Parameters: 4411 + comm - The communicator for the `DM` object 4412 . dim - The dimension 4413 . simplex - Use simplices, or tensor product cells 4414 - R - The radius 4415 4416 Output Parameter: 4417 . dm - The `DM` object 4418 4419 Level: beginner 4420 4421 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 4422 @*/ 4423 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm) 4424 { 4425 PetscFunctionBegin; 4426 PetscAssertPointer(dm, 5); 4427 PetscCall(DMCreate(comm, dm)); 4428 PetscCall(DMSetType(*dm, DMPLEX)); 4429 PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R)); 4430 PetscFunctionReturn(PETSC_SUCCESS); 4431 } 4432 4433 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R) 4434 { 4435 DM sdm, vol; 4436 DMLabel bdlabel; 4437 const char *prefix; 4438 4439 PetscFunctionBegin; 4440 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 4441 PetscCall(DMSetType(sdm, DMPLEX)); 4442 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 4443 PetscCall(DMSetOptionsPrefix(sdm, prefix)); 4444 PetscCall(DMAppendOptionsPrefix(sdm, "bd_")); 4445 PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE)); 4446 PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R)); 4447 PetscCall(DMSetFromOptions(sdm)); 4448 PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view")); 4449 PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol)); 4450 PetscCall(DMDestroy(&sdm)); 4451 PetscCall(DMPlexReplace_Internal(dm, &vol)); 4452 PetscCall(DMCreateLabel(dm, "marker")); 4453 PetscCall(DMGetLabel(dm, "marker", &bdlabel)); 4454 PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel)); 4455 PetscCall(DMPlexLabelComplete(dm, bdlabel)); 4456 PetscFunctionReturn(PETSC_SUCCESS); 4457 } 4458 4459 /*@ 4460 DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d. 4461 4462 Collective 4463 4464 Input Parameters: 4465 + comm - The communicator for the `DM` object 4466 . dim - The dimension 4467 - R - The radius 4468 4469 Output Parameter: 4470 . dm - The `DM` object 4471 4472 Options Database Key: 4473 . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry 4474 4475 Level: beginner 4476 4477 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()` 4478 @*/ 4479 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm) 4480 { 4481 PetscFunctionBegin; 4482 PetscCall(DMCreate(comm, dm)); 4483 PetscCall(DMSetType(*dm, DMPLEX)); 4484 PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R)); 4485 PetscFunctionReturn(PETSC_SUCCESS); 4486 } 4487 4488 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct) 4489 { 4490 PetscFunctionBegin; 4491 switch (ct) { 4492 case DM_POLYTOPE_POINT: { 4493 PetscInt numPoints[1] = {1}; 4494 PetscInt coneSize[1] = {0}; 4495 PetscInt cones[1] = {0}; 4496 PetscInt coneOrientations[1] = {0}; 4497 PetscScalar vertexCoords[1] = {0.0}; 4498 4499 PetscCall(DMSetDimension(rdm, 0)); 4500 PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4501 } break; 4502 case DM_POLYTOPE_SEGMENT: { 4503 PetscInt numPoints[2] = {2, 1}; 4504 PetscInt coneSize[3] = {2, 0, 0}; 4505 PetscInt cones[2] = {1, 2}; 4506 PetscInt coneOrientations[2] = {0, 0}; 4507 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 4508 4509 PetscCall(DMSetDimension(rdm, 1)); 4510 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4511 } break; 4512 case DM_POLYTOPE_POINT_PRISM_TENSOR: { 4513 PetscInt numPoints[2] = {2, 1}; 4514 PetscInt coneSize[3] = {2, 0, 0}; 4515 PetscInt cones[2] = {1, 2}; 4516 PetscInt coneOrientations[2] = {0, 0}; 4517 PetscScalar vertexCoords[2] = {-1.0, 1.0}; 4518 4519 PetscCall(DMSetDimension(rdm, 1)); 4520 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4521 } break; 4522 case DM_POLYTOPE_TRIANGLE: { 4523 PetscInt numPoints[2] = {3, 1}; 4524 PetscInt coneSize[4] = {3, 0, 0, 0}; 4525 PetscInt cones[3] = {1, 2, 3}; 4526 PetscInt coneOrientations[3] = {0, 0, 0}; 4527 PetscScalar vertexCoords[6] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0}; 4528 4529 PetscCall(DMSetDimension(rdm, 2)); 4530 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4531 } break; 4532 case DM_POLYTOPE_QUADRILATERAL: { 4533 PetscInt numPoints[2] = {4, 1}; 4534 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4535 PetscInt cones[4] = {1, 2, 3, 4}; 4536 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4537 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0}; 4538 4539 PetscCall(DMSetDimension(rdm, 2)); 4540 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4541 } break; 4542 case DM_POLYTOPE_SEG_PRISM_TENSOR: { 4543 PetscInt numPoints[2] = {4, 1}; 4544 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4545 PetscInt cones[4] = {1, 2, 3, 4}; 4546 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4547 PetscScalar vertexCoords[8] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; 4548 4549 PetscCall(DMSetDimension(rdm, 2)); 4550 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4551 } break; 4552 case DM_POLYTOPE_TETRAHEDRON: { 4553 PetscInt numPoints[2] = {4, 1}; 4554 PetscInt coneSize[5] = {4, 0, 0, 0, 0}; 4555 PetscInt cones[4] = {1, 2, 3, 4}; 4556 PetscInt coneOrientations[4] = {0, 0, 0, 0}; 4557 PetscScalar vertexCoords[12] = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0}; 4558 4559 PetscCall(DMSetDimension(rdm, 3)); 4560 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4561 } break; 4562 case DM_POLYTOPE_HEXAHEDRON: { 4563 PetscInt numPoints[2] = {8, 1}; 4564 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 4565 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 4566 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4567 PetscScalar vertexCoords[24] = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0}; 4568 4569 PetscCall(DMSetDimension(rdm, 3)); 4570 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4571 } break; 4572 case DM_POLYTOPE_TRI_PRISM: { 4573 PetscInt numPoints[2] = {6, 1}; 4574 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 4575 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 4576 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 4577 PetscScalar vertexCoords[18] = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0}; 4578 4579 PetscCall(DMSetDimension(rdm, 3)); 4580 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4581 } break; 4582 case DM_POLYTOPE_TRI_PRISM_TENSOR: { 4583 PetscInt numPoints[2] = {6, 1}; 4584 PetscInt coneSize[7] = {6, 0, 0, 0, 0, 0, 0}; 4585 PetscInt cones[6] = {1, 2, 3, 4, 5, 6}; 4586 PetscInt coneOrientations[6] = {0, 0, 0, 0, 0, 0}; 4587 PetscScalar vertexCoords[18] = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0}; 4588 4589 PetscCall(DMSetDimension(rdm, 3)); 4590 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4591 } break; 4592 case DM_POLYTOPE_QUAD_PRISM_TENSOR: { 4593 PetscInt numPoints[2] = {8, 1}; 4594 PetscInt coneSize[9] = {8, 0, 0, 0, 0, 0, 0, 0, 0}; 4595 PetscInt cones[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 4596 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4597 PetscScalar vertexCoords[24] = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0}; 4598 4599 PetscCall(DMSetDimension(rdm, 3)); 4600 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4601 } break; 4602 case DM_POLYTOPE_PYRAMID: { 4603 PetscInt numPoints[2] = {5, 1}; 4604 PetscInt coneSize[6] = {5, 0, 0, 0, 0, 0}; 4605 PetscInt cones[5] = {1, 2, 3, 4, 5}; 4606 PetscInt coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 4607 PetscScalar vertexCoords[24] = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0}; 4608 4609 PetscCall(DMSetDimension(rdm, 3)); 4610 PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords)); 4611 } break; 4612 default: 4613 SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]); 4614 } 4615 { 4616 PetscInt Nv, v; 4617 4618 /* Must create the celltype label here so that we do not automatically try to compute the types */ 4619 PetscCall(DMCreateLabel(rdm, "celltype")); 4620 PetscCall(DMPlexSetCellType(rdm, 0, ct)); 4621 PetscCall(DMPlexGetChart(rdm, NULL, &Nv)); 4622 for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT)); 4623 } 4624 PetscCall(DMPlexInterpolateInPlace_Internal(rdm)); 4625 PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct])); 4626 PetscFunctionReturn(PETSC_SUCCESS); 4627 } 4628 4629 /*@ 4630 DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell 4631 4632 Collective 4633 4634 Input Parameters: 4635 + comm - The communicator 4636 - ct - The cell type of the reference cell 4637 4638 Output Parameter: 4639 . refdm - The reference cell 4640 4641 Level: intermediate 4642 4643 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()` 4644 @*/ 4645 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm) 4646 { 4647 PetscFunctionBegin; 4648 PetscCall(DMCreate(comm, refdm)); 4649 PetscCall(DMSetType(*refdm, DMPLEX)); 4650 PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct)); 4651 PetscFunctionReturn(PETSC_SUCCESS); 4652 } 4653 4654 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[]) 4655 { 4656 DM plex; 4657 DMLabel label; 4658 PetscBool hasLabel; 4659 4660 PetscFunctionBegin; 4661 PetscCall(DMHasLabel(dm, name, &hasLabel)); 4662 if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS); 4663 PetscCall(DMCreateLabel(dm, name)); 4664 PetscCall(DMGetLabel(dm, name, &label)); 4665 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4666 PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label)); 4667 PetscCall(DMPlexLabelComplete(plex, label)); 4668 PetscCall(DMDestroy(&plex)); 4669 PetscFunctionReturn(PETSC_SUCCESS); 4670 } 4671 4672 /* 4673 We use the last coordinate as the radius, the inner radius is lower[dim-1] and the outer radius is upper[dim-1]. Then we map the first coordinate around the circle. 4674 4675 (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0])) 4676 */ 4677 static void boxToAnnulus(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 4678 { 4679 const PetscReal low = PetscRealPart(constants[0]); 4680 const PetscReal upp = PetscRealPart(constants[1]); 4681 const PetscReal r = PetscRealPart(u[1]); 4682 const PetscReal th = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low); 4683 4684 f0[0] = r * PetscCosReal(th); 4685 f0[1] = r * PetscSinReal(th); 4686 } 4687 4688 // Insert vertices and their joins, marked by depth 4689 static PetscErrorCode ProcessCohesiveLabel_Vertices(DM dm, DMLabel label, DMLabel vlabel, PetscInt val, PetscInt n, const PetscInt vertices[]) 4690 { 4691 PetscFunctionBegin; 4692 PetscCall(DMPlexMarkSubmesh_Interpolated(dm, vlabel, val, PETSC_FALSE, PETSC_FALSE, label, NULL)); 4693 PetscFunctionReturn(PETSC_SUCCESS); 4694 } 4695 4696 // Insert faces and their closures, marked by depth 4697 static PetscErrorCode ProcessCohesiveLabel_Faces(DM dm, DMLabel label, PetscInt n, const PetscInt faces[]) 4698 { 4699 PetscFunctionBegin; 4700 for (PetscInt p = 0; p < n; ++p) { 4701 const PetscInt point = faces[p]; 4702 PetscInt *closure = NULL; 4703 PetscInt clSize, pdepth; 4704 4705 PetscCall(DMPlexGetPointDepth(dm, point, &pdepth)); 4706 PetscCall(DMLabelSetValue(label, point, pdepth)); 4707 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4708 for (PetscInt cl = 0; cl < clSize * 2; cl += 2) { 4709 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth)); 4710 PetscCall(DMLabelSetValue(label, closure[cl], pdepth)); 4711 } 4712 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure)); 4713 } 4714 PetscFunctionReturn(PETSC_SUCCESS); 4715 } 4716 4717 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg); 4718 4719 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL}; 4720 4721 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems PetscOptionsObject, PetscBool *useCoordSpace, DM dm) 4722 { 4723 DMPlexShape shape = DM_SHAPE_BOX; 4724 DMPolytopeType cell = DM_POLYTOPE_TRIANGLE; 4725 PetscInt dim = 2; 4726 PetscBool simplex = PETSC_TRUE, interpolate = PETSC_TRUE, orient = PETSC_FALSE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE; 4727 PetscBool flg, flg2, fflg, strflg, bdfflg, nameflg; 4728 MPI_Comm comm; 4729 char filename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4730 char bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>"; 4731 char plexname[PETSC_MAX_PATH_LEN] = ""; 4732 const char *option; 4733 4734 PetscFunctionBegin; 4735 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 4736 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4737 /* TODO Turn this into a registration interface */ 4738 PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg)); 4739 PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg)); 4740 PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg)); 4741 PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg)); 4742 PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL)); 4743 PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL)); 4744 PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg)); 4745 PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0)); 4746 PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg)); 4747 PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg)); 4748 PetscCall(PetscOptionsBool("-dm_plex_orient", "Orient the constructed mesh", "DMPlexOrient", orient, &orient, &flg)); 4749 PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg)); 4750 PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2)); 4751 if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure)); 4752 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_adj", "Debug output level all adjacency computations", "", 0, &((DM_Plex *)dm->data)->printAdj, NULL, 0)); 4753 4754 switch (cell) { 4755 case DM_POLYTOPE_POINT: 4756 case DM_POLYTOPE_SEGMENT: 4757 case DM_POLYTOPE_POINT_PRISM_TENSOR: 4758 case DM_POLYTOPE_TRIANGLE: 4759 case DM_POLYTOPE_QUADRILATERAL: 4760 case DM_POLYTOPE_TETRAHEDRON: 4761 case DM_POLYTOPE_HEXAHEDRON: 4762 *useCoordSpace = PETSC_TRUE; 4763 break; 4764 default: 4765 *useCoordSpace = PETSC_FALSE; 4766 break; 4767 } 4768 4769 if (fflg) { 4770 DM dmnew; 4771 const char *name; 4772 4773 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4774 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew)); 4775 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4776 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4777 } else if (refDomain) { 4778 PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell)); 4779 } else if (bdfflg) { 4780 DM bdm, dmnew; 4781 const char *name; 4782 4783 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 4784 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm)); 4785 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_")); 4786 PetscCall(DMSetFromOptions(bdm)); 4787 PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew)); 4788 PetscCall(DMDestroy(&bdm)); 4789 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4790 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4791 } else if (strflg) { 4792 DM dmnew; 4793 PetscViewer viewer; 4794 const char *contents; 4795 char *strname; 4796 char tmpdir[PETSC_MAX_PATH_LEN]; 4797 char tmpfilename[PETSC_MAX_PATH_LEN]; 4798 char name[PETSC_MAX_PATH_LEN]; 4799 MPI_Comm comm; 4800 PetscMPIInt rank; 4801 4802 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4803 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 4804 PetscCall(PetscStrchr(filename, ':', &strname)); 4805 PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename); 4806 strname[0] = '\0'; 4807 ++strname; 4808 PetscCall(PetscDLSym(NULL, strname, (void **)&contents)); 4809 PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname); 4810 PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN)); 4811 PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN)); 4812 PetscCall(PetscMkdtemp(tmpdir)); 4813 PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename)); 4814 PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer)); 4815 PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents)); 4816 PetscCall(PetscViewerDestroy(&viewer)); 4817 PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew)); 4818 PetscCall(PetscRMTree(tmpdir)); 4819 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname)); 4820 PetscCall(PetscObjectSetName((PetscObject)dm, name)); 4821 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4822 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4823 } else { 4824 PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape])); 4825 switch (shape) { 4826 case DM_SHAPE_BOX: 4827 case DM_SHAPE_ZBOX: 4828 case DM_SHAPE_ANNULUS: { 4829 PetscInt faces[3] = {0, 0, 0}; 4830 PetscReal lower[3] = {0, 0, 0}; 4831 PetscReal upper[3] = {1, 1, 1}; 4832 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4833 PetscBool isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE; 4834 PetscInt i, n; 4835 4836 n = dim; 4837 for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim); 4838 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4839 n = 3; 4840 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4841 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4842 n = 3; 4843 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4844 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4845 n = 3; 4846 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4847 PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4848 4849 PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented"); 4850 if (isAnnular) 4851 for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC; 4852 4853 switch (cell) { 4854 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4855 PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt)); 4856 if (!interpolate) { 4857 DM udm; 4858 4859 PetscCall(DMPlexUninterpolate(dm, &udm)); 4860 PetscCall(DMPlexReplace_Internal(dm, &udm)); 4861 } 4862 break; 4863 default: 4864 PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate)); 4865 break; 4866 } 4867 if (isAnnular) { 4868 DM cdm; 4869 PetscDS cds; 4870 PetscScalar bounds[2] = {lower[0], upper[0]}; 4871 4872 // Fix coordinates for annular region 4873 PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 4874 PetscCall(DMSetCellCoordinatesLocal(dm, NULL)); 4875 PetscCall(DMSetCellCoordinates(dm, NULL)); 4876 PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL)); 4877 PetscCall(DMGetCoordinateDM(dm, &cdm)); 4878 PetscCall(DMGetDS(cdm, &cds)); 4879 PetscCall(PetscDSSetConstants(cds, 2, bounds)); 4880 PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus)); 4881 } 4882 } break; 4883 case DM_SHAPE_BOX_SURFACE: { 4884 PetscInt faces[3] = {0, 0, 0}; 4885 PetscReal lower[3] = {0, 0, 0}; 4886 PetscReal upper[3] = {1, 1, 1}; 4887 PetscInt i, n; 4888 4889 n = dim + 1; 4890 for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1)); 4891 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg)); 4892 n = 3; 4893 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4894 PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1); 4895 n = 3; 4896 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4897 PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1); 4898 PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate)); 4899 } break; 4900 case DM_SHAPE_SPHERE: { 4901 PetscReal R = 1.0; 4902 4903 PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg)); 4904 PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R)); 4905 } break; 4906 case DM_SHAPE_BALL: { 4907 PetscReal R = 1.0; 4908 4909 PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg)); 4910 PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R)); 4911 } break; 4912 case DM_SHAPE_CYLINDER: { 4913 DMBoundaryType bdt = DM_BOUNDARY_NONE; 4914 PetscInt Nw = 6; 4915 PetscInt Nr = 0; 4916 4917 PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL)); 4918 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL)); 4919 PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_refine", "Number of refinements before projection", "", Nr, &Nr, NULL)); 4920 switch (cell) { 4921 case DM_POLYTOPE_TRI_PRISM_TENSOR: 4922 PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate)); 4923 break; 4924 default: 4925 PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt, Nr)); 4926 break; 4927 } 4928 } break; 4929 case DM_SHAPE_SCHWARZ_P: // fallthrough 4930 case DM_SHAPE_GYROID: { 4931 PetscInt extent[3] = {1, 1, 1}, refine = 0, layers = 0, three; 4932 PetscReal thickness = 0.; 4933 DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 4934 DMPlexTPSType tps_type = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID; 4935 PetscBool tps_distribute; 4936 PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL)); 4937 PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL)); 4938 PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL)); 4939 PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL)); 4940 PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL)); 4941 PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute)); 4942 PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL)); 4943 PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness)); 4944 } break; 4945 case DM_SHAPE_DOUBLET: { 4946 DM dmnew; 4947 PetscReal rl = 0.0; 4948 4949 PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL)); 4950 PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew)); 4951 PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew)); 4952 PetscCall(DMPlexReplace_Internal(dm, &dmnew)); 4953 } break; 4954 case DM_SHAPE_HYPERCUBIC: { 4955 PetscInt *edges, overlap = 1; 4956 PetscReal *lower, *upper; 4957 DMBoundaryType *bdt; 4958 PetscInt n, d; 4959 4960 *useCoordSpace = PETSC_FALSE; 4961 PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt)); 4962 for (d = 0; d < dim; ++d) { 4963 edges[d] = 1; 4964 lower[d] = 0.; 4965 upper[d] = 1.; 4966 bdt[d] = DM_BOUNDARY_PERIODIC; 4967 } 4968 n = dim; 4969 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg)); 4970 n = dim; 4971 PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg)); 4972 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4973 n = dim; 4974 PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg)); 4975 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4976 n = dim; 4977 PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 4978 PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 4979 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", overlap, &overlap, NULL, 0)); 4980 PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, overlap, bdt)); 4981 PetscCall(PetscFree4(edges, lower, upper, bdt)); 4982 } break; 4983 default: 4984 SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]); 4985 } 4986 } 4987 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 4988 if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname)); 4989 if (orient) PetscCall(DMPlexOrient(dm)); 4990 // Allow label creation 4991 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg)); 4992 if (flg) { 4993 DMLabel label; 4994 PetscInt points[1024], n = 1024; 4995 char fulloption[PETSC_MAX_PATH_LEN]; 4996 const char *name = &option[14]; 4997 4998 PetscCall(DMCreateLabel(dm, name)); 4999 PetscCall(DMGetLabel(dm, name, &label)); 5000 fulloption[0] = '-'; 5001 fulloption[1] = 0; 5002 PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN)); 5003 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL)); 5004 for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1)); 5005 } 5006 // Allow cohesive label creation 5007 // Faces are input, completed, and all points are marked with their depth 5008 PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg)); 5009 if (flg) { 5010 DMLabel label; 5011 PetscInt points[1024], n, pStart, pEnd, Nl = 1; 5012 PetscBool noCreate = PETSC_FALSE; 5013 char fulloption[PETSC_MAX_PATH_LEN]; 5014 char name[PETSC_MAX_PATH_LEN]; 5015 size_t len; 5016 5017 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5018 PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN)); 5019 PetscCall(PetscStrlen(name, &len)); 5020 if (name[len - 1] == '0') Nl = 10; 5021 for (PetscInt l = 0; l < Nl; ++l) { 5022 if (l > 0) name[len - 1] = (char)('0' + l); 5023 fulloption[0] = 0; 5024 PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32)); 5025 PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32)); 5026 n = 1024; 5027 PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg)); 5028 if (!flg) break; 5029 PetscCall(DMHasLabel(dm, name, &noCreate)); 5030 if (noCreate) { 5031 DMLabel inlabel; 5032 IS pointIS; 5033 const PetscInt *lpoints; 5034 PetscInt pdep, ln, inval = points[0]; 5035 char newname[PETSC_MAX_PATH_LEN]; 5036 5037 PetscCheck(n == 1, comm, PETSC_ERR_ARG_WRONG, "Must specify a label value with this option"); 5038 PetscCall(DMGetLabel(dm, name, &inlabel)); 5039 PetscCall(DMLabelGetStratumIS(inlabel, inval, &pointIS)); 5040 PetscCall(ISGetLocalSize(pointIS, &ln)); 5041 PetscCall(ISGetIndices(pointIS, &lpoints)); 5042 PetscCall(DMPlexGetPointDepth(dm, lpoints[0], &pdep)); 5043 PetscCall(PetscSNPrintf(newname, PETSC_MAX_PATH_LEN, "%s%" PetscInt_FMT, name, points[0])); 5044 PetscCall(DMCreateLabel(dm, newname)); 5045 PetscCall(DMGetLabel(dm, newname, &label)); 5046 if (!pdep) PetscCall(ProcessCohesiveLabel_Vertices(dm, label, inlabel, inval, ln, lpoints)); 5047 else PetscCall(ProcessCohesiveLabel_Faces(dm, label, ln, lpoints)); 5048 PetscCall(ISRestoreIndices(pointIS, &lpoints)); 5049 PetscCall(ISDestroy(&pointIS)); 5050 } else { 5051 PetscCall(DMCreateLabel(dm, name)); 5052 PetscCall(DMGetLabel(dm, name, &label)); 5053 if (pStart >= pEnd) n = 0; 5054 PetscCall(ProcessCohesiveLabel_Faces(dm, label, n, points)); 5055 } 5056 PetscCall(DMPlexOrientLabel(dm, label)); 5057 PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL)); 5058 } 5059 } 5060 PetscCall(DMViewFromOptions(dm, NULL, "-created_dm_view")); 5061 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0)); 5062 PetscFunctionReturn(PETSC_SUCCESS); 5063 } 5064 5065 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems PetscOptionsObject) 5066 { 5067 DM_Plex *mesh = (DM_Plex *)dm->data; 5068 PetscBool flg, flg2; 5069 char bdLabel[PETSC_MAX_PATH_LEN]; 5070 char method[PETSC_MAX_PATH_LEN]; 5071 5072 PetscFunctionBegin; 5073 /* Handle viewing */ 5074 PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL)); 5075 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0)); 5076 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0)); 5077 PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL)); 5078 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0)); 5079 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0)); 5080 PetscCall(PetscOptionsBoundedInt("-dm_plex_print_project", "Debug output level all projection computations", "DMPlexProject", 0, &mesh->printProject, NULL, 0)); 5081 PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg)); 5082 if (flg) PetscCall(PetscLogDefaultBegin()); 5083 // Interpolation 5084 PetscCall(PetscOptionsBool("-dm_plex_interpolate_prefer_tensor", "When different orderings exist, prefer the tensor order", "DMPlexSetInterpolationPreferTensor", mesh->interpolatePreferTensor, &mesh->interpolatePreferTensor, NULL)); 5085 /* Labeling */ 5086 PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg)); 5087 if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel)); 5088 /* Point Location */ 5089 PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL)); 5090 /* Partitioning and distribution */ 5091 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL)); 5092 /* Reordering */ 5093 PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg)); 5094 if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE)); 5095 PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg)); 5096 if (flg) PetscCall(DMReorderSectionSetType(dm, method)); 5097 /* Generation and remeshing */ 5098 PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL)); 5099 PetscCall(PetscOptionsBool("-dm_plex_save_transform", "Save the transform producing this mesh", "DMAdapt", PETSC_FALSE, &mesh->saveTransform, NULL)); 5100 /* Projection behavior */ 5101 PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0)); 5102 PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL)); 5103 /* Checking structure */ 5104 { 5105 PetscBool all = PETSC_FALSE; 5106 5107 PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL)); 5108 if (all) { 5109 PetscCall(DMPlexCheck(dm)); 5110 } else { 5111 PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2)); 5112 if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm)); 5113 PetscCall(PetscOptionsBool("-dm_plex_check_skeleton", "Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes)", "DMPlexCheckSkeleton", PETSC_FALSE, &flg, &flg2)); 5114 if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0)); 5115 PetscCall(PetscOptionsBool("-dm_plex_check_faces", "Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type", "DMPlexCheckFaces", PETSC_FALSE, &flg, &flg2)); 5116 if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0)); 5117 PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2)); 5118 if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm)); 5119 PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2)); 5120 if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 5121 PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2)); 5122 if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm)); 5123 } 5124 PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2)); 5125 if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE)); 5126 } 5127 { 5128 PetscReal scale = 1.0; 5129 5130 PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg)); 5131 if (flg) { 5132 Vec coordinates, coordinatesLocal; 5133 5134 PetscCall(DMGetCoordinates(dm, &coordinates)); 5135 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 5136 PetscCall(VecScale(coordinates, scale)); 5137 PetscCall(VecScale(coordinatesLocal, scale)); 5138 } 5139 } 5140 PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner)); 5141 PetscFunctionReturn(PETSC_SUCCESS); 5142 } 5143 5144 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems PetscOptionsObject, PetscInt *overlap) 5145 { 5146 PetscInt numOvLabels = 16, numOvExLabels = 16; 5147 char *ovLabelNames[16], *ovExLabelNames[16]; 5148 PetscInt numOvValues = 16, numOvExValues = 16, l; 5149 PetscBool flg; 5150 5151 PetscFunctionBegin; 5152 PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0)); 5153 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg)); 5154 if (!flg) numOvLabels = 0; 5155 if (numOvLabels) { 5156 ((DM_Plex *)dm->data)->numOvLabels = numOvLabels; 5157 for (l = 0; l < numOvLabels; ++l) { 5158 PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l])); 5159 PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]); 5160 PetscCall(PetscFree(ovLabelNames[l])); 5161 } 5162 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg)); 5163 if (!flg) numOvValues = 0; 5164 PetscCheck(numOvLabels == numOvValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvLabels, numOvValues); 5165 5166 PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg)); 5167 if (!flg) numOvExLabels = 0; 5168 ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels; 5169 for (l = 0; l < numOvExLabels; ++l) { 5170 PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l])); 5171 PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]); 5172 PetscCall(PetscFree(ovExLabelNames[l])); 5173 } 5174 PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg)); 5175 if (!flg) numOvExValues = 0; 5176 PetscCheck(numOvExLabels == numOvExValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of exclude labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvExLabels, numOvExValues); 5177 } 5178 PetscFunctionReturn(PETSC_SUCCESS); 5179 } 5180 5181 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems PetscOptionsObject) 5182 { 5183 PetscFunctionList ordlist; 5184 char oname[256]; 5185 char sublabelname[PETSC_MAX_PATH_LEN] = ""; 5186 DMReorderDefaultFlag reorder; 5187 PetscReal volume = -1.0; 5188 PetscInt prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim; 5189 PetscBool uniformOrig = PETSC_FALSE, uniform = PETSC_TRUE, distribute, saveSF = PETSC_FALSE, interpolate = PETSC_TRUE, coordSpace = PETSC_FALSE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, flg; 5190 5191 PetscFunctionBegin; 5192 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options"); 5193 if (dm->cloneOpts) goto non_refine; 5194 /* Handle automatic creation */ 5195 PetscCall(DMGetDimension(dm, &dim)); 5196 if (dim < 0) PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm)); 5197 PetscCall(DMGetDimension(dm, &dim)); 5198 /* Handle interpolation before distribution */ 5199 PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg)); 5200 if (flg) { 5201 DMPlexInterpolatedFlag interpolated; 5202 5203 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 5204 if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) { 5205 DM udm; 5206 5207 PetscCall(DMPlexUninterpolate(dm, &udm)); 5208 PetscCall(DMPlexReplace_Internal(dm, &udm)); 5209 } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) { 5210 DM idm; 5211 5212 PetscCall(DMPlexInterpolate(dm, &idm)); 5213 PetscCall(DMPlexReplace_Internal(dm, &idm)); 5214 } 5215 } 5216 // Handle submesh selection before distribution 5217 PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg)); 5218 if (flg) { 5219 DM subdm; 5220 DMLabel label; 5221 IS valueIS, pointIS; 5222 const PetscInt *values, *points; 5223 PetscBool markedFaces = PETSC_FALSE; 5224 PetscInt Nv, value, Np; 5225 5226 PetscCall(DMGetLabel(dm, sublabelname, &label)); 5227 PetscCall(DMLabelGetNumValues(label, &Nv)); 5228 PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv); 5229 PetscCall(DMLabelGetValueIS(label, &valueIS)); 5230 PetscCall(ISGetIndices(valueIS, &values)); 5231 value = values[0]; 5232 PetscCall(ISRestoreIndices(valueIS, &values)); 5233 PetscCall(ISDestroy(&valueIS)); 5234 PetscCall(DMLabelGetStratumSize(label, value, &Np)); 5235 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 5236 PetscCall(ISGetIndices(pointIS, &points)); 5237 for (PetscInt p = 0; p < Np; ++p) { 5238 PetscInt pdepth; 5239 5240 PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth)); 5241 if (pdepth) { 5242 markedFaces = PETSC_TRUE; 5243 break; 5244 } 5245 } 5246 PetscCall(ISRestoreIndices(pointIS, &points)); 5247 PetscCall(ISDestroy(&pointIS)); 5248 PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm)); 5249 PetscCall(DMPlexReplace_Internal(dm, &subdm)); 5250 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5251 } 5252 /* Handle DMPlex refinement before distribution */ 5253 PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig)); 5254 PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0)); 5255 PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 5256 PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg)); 5257 if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform)); 5258 PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg)); 5259 if (flg) { 5260 PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE)); 5261 PetscCall(DMPlexSetRefinementLimit(dm, volume)); 5262 prerefine = PetscMax(prerefine, 1); 5263 } 5264 if (prerefine) PetscCall(DMLocalizeCoordinates(dm)); 5265 for (r = 0; r < prerefine; ++r) { 5266 DM rdm; 5267 PetscPointFunc coordFunc; 5268 5269 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5270 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5271 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 5272 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5273 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5274 if (coordFunc && remap) { 5275 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5276 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5277 } 5278 } 5279 PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig)); 5280 /* Handle DMPlex extrusion before distribution */ 5281 PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0)); 5282 if (extLayers) { 5283 DM edm; 5284 5285 PetscCall(DMExtrude(dm, extLayers, &edm)); 5286 PetscCall(DMPlexReplace_Internal(dm, &edm)); 5287 PetscCall(DMPlexSetCoordinateMap(dm, NULL)); 5288 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5289 extLayers = 0; 5290 PetscCall(DMGetDimension(dm, &dim)); 5291 } 5292 /* Handle DMPlex reordering before distribution */ 5293 PetscCall(DMPlexReorderGetDefault(dm, &reorder)); 5294 PetscCall(MatGetOrderingList(&ordlist)); 5295 PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname))); 5296 PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg)); 5297 if (reorder == DM_REORDER_DEFAULT_TRUE || flg) { 5298 DM pdm; 5299 IS perm; 5300 5301 PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm)); 5302 PetscCall(DMPlexPermute(dm, perm, &pdm)); 5303 PetscCall(ISDestroy(&perm)); 5304 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 5305 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5306 } 5307 /* Handle DMPlex distribution */ 5308 PetscCall(DMPlexDistributeGetDefault(dm, &distribute)); 5309 PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL)); 5310 PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL)); 5311 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 5312 if (distribute) { 5313 DM pdm = NULL; 5314 PetscPartitioner part; 5315 PetscSF sfMigration; 5316 PetscBool use_partition_balance; 5317 5318 PetscCall(DMPlexGetPartitioner(dm, &part)); 5319 PetscCall(PetscPartitionerSetFromOptions(part)); 5320 PetscCall(DMPlexGetPartitionBalance(dm, &use_partition_balance)); 5321 PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", use_partition_balance, &use_partition_balance, &flg)); 5322 if (flg) PetscCall(DMPlexSetPartitionBalance(dm, use_partition_balance)); 5323 PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm)); 5324 if (pdm) { 5325 // Delete the local section to force the existing one to be rebuilt with the distributed DM 5326 PetscCall(DMSetLocalSection(dm, pdm->localSection)); 5327 PetscCall(DMPlexReplace_Internal(dm, &pdm)); 5328 } 5329 if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration)); 5330 PetscCall(PetscSFDestroy(&sfMigration)); 5331 } 5332 5333 { 5334 PetscBool useBoxLabel = PETSC_FALSE; 5335 PetscCall(PetscOptionsBool("-dm_plex_box_label", "Create 'Face Sets' assuming boundary faces align with cartesian directions", "DMCreate", useBoxLabel, &useBoxLabel, NULL)); 5336 if (useBoxLabel) { 5337 PetscInt n = 3; 5338 DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE}; 5339 5340 PetscCall(PetscOptionsEnumArray("-dm_plex_box_label_bd", "Boundary type for each dimension when using -dm_plex_box_label", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg)); 5341 PetscCheck(!flg || !(n != dim), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim); 5342 PetscCall(DMPlexSetBoxLabel_Internal(dm, bdt)); 5343 } 5344 } 5345 /* Must check CEED options before creating function space for coordinates */ 5346 { 5347 PetscBool useCeed = PETSC_FALSE, flg; 5348 5349 PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg)); 5350 if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed)); 5351 } 5352 /* Create coordinate space */ 5353 PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, NULL)); 5354 if (coordSpace) { 5355 PetscInt degree = 1, deg; 5356 PetscInt height = 0; 5357 DM cdm; 5358 PetscBool localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE; 5359 5360 PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, °ree, NULL)); 5361 PetscCall(DMGetCoordinateDegree_Internal(dm, °)); 5362 if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, NULL)); 5363 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5364 if (!coordSpace) { 5365 PetscDS cds; 5366 PetscObject obj; 5367 PetscClassId id; 5368 5369 PetscCall(DMGetDS(cdm, &cds)); 5370 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 5371 PetscCall(PetscObjectGetClassId(obj, &id)); 5372 if (id == PETSCFE_CLASSID) { 5373 PetscContainer dummy; 5374 5375 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy)); 5376 PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates")); 5377 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy)); 5378 PetscCall(PetscContainerDestroy(&dummy)); 5379 PetscCall(DMClearDS(cdm)); 5380 } 5381 PetscCall(DMPlexSetCoordinateMap(dm, NULL)); 5382 } 5383 PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL)); 5384 PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg)); 5385 if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize)); 5386 PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg)); 5387 if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height)); 5388 if (localize) PetscCall(DMLocalizeCoordinates(dm)); 5389 } 5390 /* Handle DMPlex refinement */ 5391 remap = PETSC_TRUE; 5392 PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0)); 5393 PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL)); 5394 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0)); 5395 if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE)); 5396 if (refine && isHierarchy) { 5397 DM *dms, coarseDM; 5398 5399 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 5400 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 5401 PetscCall(PetscMalloc1(refine, &dms)); 5402 PetscCall(DMRefineHierarchy(dm, refine, dms)); 5403 /* Total hack since we do not pass in a pointer */ 5404 PetscCall(DMPlexSwap_Static(dm, dms[refine - 1])); 5405 if (refine == 1) { 5406 PetscCall(DMSetCoarseDM(dm, dms[0])); 5407 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 5408 } else { 5409 PetscCall(DMSetCoarseDM(dm, dms[refine - 2])); 5410 PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE)); 5411 PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1])); 5412 PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE)); 5413 } 5414 PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM)); 5415 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 5416 /* Free DMs */ 5417 for (r = 0; r < refine; ++r) { 5418 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 5419 PetscCall(DMDestroy(&dms[r])); 5420 } 5421 PetscCall(PetscFree(dms)); 5422 } else { 5423 for (r = 0; r < refine; ++r) { 5424 DM rdm; 5425 PetscPointFunc coordFunc; 5426 5427 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5428 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm)); 5429 /* Total hack since we do not pass in a pointer */ 5430 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5431 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5432 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5433 if (coordFunc && remap) { 5434 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5435 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5436 } 5437 } 5438 } 5439 /* Handle DMPlex coarsening */ 5440 PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0)); 5441 PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0)); 5442 if (coarsen && isHierarchy) { 5443 DM *dms; 5444 5445 PetscCall(PetscMalloc1(coarsen, &dms)); 5446 PetscCall(DMCoarsenHierarchy(dm, coarsen, dms)); 5447 /* Free DMs */ 5448 for (r = 0; r < coarsen; ++r) { 5449 PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject)); 5450 PetscCall(DMDestroy(&dms[r])); 5451 } 5452 PetscCall(PetscFree(dms)); 5453 } else { 5454 for (r = 0; r < coarsen; ++r) { 5455 DM cdm; 5456 PetscPointFunc coordFunc; 5457 5458 PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc)); 5459 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5460 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm)); 5461 /* Total hack since we do not pass in a pointer */ 5462 PetscCall(DMPlexReplace_Internal(dm, &cdm)); 5463 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5464 if (coordFunc) { 5465 PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc)); 5466 PetscCall(DMPlexSetCoordinateMap(dm, coordFunc)); 5467 } 5468 } 5469 } 5470 // Handle coordinate remapping 5471 remap = PETSC_FALSE; 5472 PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL)); 5473 if (remap) { 5474 DMPlexCoordMap map = DM_COORD_MAP_NONE; 5475 PetscPointFunc mapFunc = NULL; 5476 PetscScalar params[16]; 5477 PetscInt Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim; 5478 MPI_Comm comm; 5479 5480 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5481 PetscCall(DMGetCoordinateDim(dm, &cdim)); 5482 PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg)); 5483 if (!flg) Np = 0; 5484 // TODO Allow user to pass a map function by name 5485 PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg)); 5486 if (flg) { 5487 switch (map) { 5488 case DM_COORD_MAP_NONE: 5489 mapFunc = coordMap_identity; 5490 break; 5491 case DM_COORD_MAP_SHEAR: 5492 mapFunc = coordMap_shear; 5493 if (!Np) { 5494 Np = cdim + 1; 5495 params[0] = 0; 5496 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 5497 } 5498 PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The shear coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np); 5499 break; 5500 case DM_COORD_MAP_FLARE: 5501 mapFunc = coordMap_flare; 5502 if (!Np) { 5503 Np = cdim + 1; 5504 params[0] = 0; 5505 for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0; 5506 } 5507 PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The flare coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np); 5508 break; 5509 case DM_COORD_MAP_ANNULUS: 5510 mapFunc = coordMap_annulus; 5511 if (!Np) { 5512 Np = 2; 5513 params[0] = 1.; 5514 params[1] = 2.; 5515 } 5516 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 5517 break; 5518 case DM_COORD_MAP_SHELL: 5519 mapFunc = coordMap_shell; 5520 if (!Np) { 5521 Np = 2; 5522 params[0] = 1.; 5523 params[1] = 2.; 5524 } 5525 PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np); 5526 break; 5527 case DM_COORD_MAP_SINUSOID: 5528 mapFunc = coordMap_sinusoid; 5529 if (!Np) { 5530 Np = 3; 5531 params[0] = 1.; 5532 params[1] = 1.; 5533 params[2] = 1.; 5534 } 5535 PetscCheck(Np == 3, comm, PETSC_ERR_ARG_WRONG, "The sinusoidal coordinate map must have 3 parameters, not %" PetscInt_FMT, Np); 5536 break; 5537 default: 5538 mapFunc = coordMap_identity; 5539 } 5540 } 5541 if (Np) { 5542 DM cdm; 5543 PetscDS cds; 5544 5545 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5546 PetscCall(DMGetDS(cdm, &cds)); 5547 PetscCall(PetscDSSetConstants(cds, Np, params)); 5548 } 5549 PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc)); 5550 } 5551 /* Handle ghost cells */ 5552 PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL)); 5553 if (ghostCells) { 5554 DM gdm; 5555 char lname[PETSC_MAX_PATH_LEN]; 5556 5557 lname[0] = '\0'; 5558 PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg)); 5559 PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm)); 5560 PetscCall(DMPlexReplace_Internal(dm, &gdm)); 5561 } 5562 /* Handle 1D order */ 5563 if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) { 5564 DM cdm, rdm; 5565 PetscDS cds; 5566 PetscObject obj; 5567 PetscClassId id = PETSC_OBJECT_CLASSID; 5568 IS perm; 5569 PetscInt Nf; 5570 PetscBool distributed; 5571 5572 PetscCall(DMPlexIsDistributed(dm, &distributed)); 5573 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5574 PetscCall(DMGetDS(cdm, &cds)); 5575 PetscCall(PetscDSGetNumFields(cds, &Nf)); 5576 if (Nf) { 5577 PetscCall(PetscDSGetDiscretization(cds, 0, &obj)); 5578 PetscCall(PetscObjectGetClassId(obj, &id)); 5579 } 5580 if (!distributed && id != PETSCFE_CLASSID) { 5581 PetscCall(DMPlexGetOrdering1D(dm, &perm)); 5582 PetscCall(DMPlexPermute(dm, perm, &rdm)); 5583 PetscCall(DMPlexReplace_Internal(dm, &rdm)); 5584 PetscCall(ISDestroy(&perm)); 5585 } 5586 } 5587 /* Handle */ 5588 non_refine: 5589 PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject)); 5590 char *phases[16]; 5591 PetscInt Nphases = 16; 5592 PetscCall(PetscOptionsStringArray("-dm_plex_option_phases", "Option phase prefixes", "DMSetFromOptions", phases, &Nphases, &flg)); 5593 PetscOptionsHeadEnd(); 5594 5595 // Phases 5596 if (flg) { 5597 DM cdm; 5598 char *oldPrefix, *oldCoordPrefix; 5599 const char *tmp; 5600 5601 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5602 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &tmp)); 5603 PetscCall(PetscStrallocpy(tmp, &oldPrefix)); 5604 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdm, &tmp)); 5605 PetscCall(PetscStrallocpy(tmp, &oldCoordPrefix)); 5606 for (PetscInt ph = 0; ph < Nphases; ++ph) { 5607 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, phases[ph])); 5608 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)cdm, phases[ph])); 5609 PetscCall(PetscInfo(dm, "Options phase %s for DM %s\n", phases[ph], dm->hdr.name)); 5610 PetscCall(DMSetFromOptions(dm)); 5611 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix)); 5612 PetscCall(DMGetCoordinateDM(dm, &cdm)); 5613 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdm, oldCoordPrefix)); 5614 PetscCall(PetscFree(phases[ph])); 5615 } 5616 PetscCall(PetscFree(oldPrefix)); 5617 PetscCall(PetscFree(oldCoordPrefix)); 5618 } 5619 PetscFunctionReturn(PETSC_SUCCESS); 5620 } 5621 5622 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec) 5623 { 5624 PetscFunctionBegin; 5625 PetscCall(DMCreateGlobalVector_Section_Private(dm, vec)); 5626 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 5627 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex)); 5628 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native)); 5629 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex)); 5630 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native)); 5631 PetscFunctionReturn(PETSC_SUCCESS); 5632 } 5633 5634 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec) 5635 { 5636 PetscFunctionBegin; 5637 PetscCall(DMCreateLocalVector_Section_Private(dm, vec)); 5638 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local)); 5639 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local)); 5640 PetscFunctionReturn(PETSC_SUCCESS); 5641 } 5642 5643 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 5644 { 5645 PetscInt depth, d; 5646 5647 PetscFunctionBegin; 5648 PetscCall(DMPlexGetDepth(dm, &depth)); 5649 if (depth == 1) { 5650 PetscCall(DMGetDimension(dm, &d)); 5651 if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 5652 else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd)); 5653 else { 5654 *pStart = 0; 5655 *pEnd = 0; 5656 } 5657 } else { 5658 PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd)); 5659 } 5660 PetscFunctionReturn(PETSC_SUCCESS); 5661 } 5662 5663 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 5664 { 5665 PetscSF sf; 5666 PetscMPIInt niranks, njranks; 5667 PetscInt n; 5668 const PetscMPIInt *iranks, *jranks; 5669 DM_Plex *data = (DM_Plex *)dm->data; 5670 5671 PetscFunctionBegin; 5672 PetscCall(DMGetPointSF(dm, &sf)); 5673 if (!data->neighbors) { 5674 PetscCall(PetscSFSetUp(sf)); 5675 PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL)); 5676 PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL)); 5677 PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors)); 5678 PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks)); 5679 PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks)); 5680 n = njranks + niranks; 5681 PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1)); 5682 /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */ 5683 PetscCall(PetscMPIIntCast(n, data->neighbors)); 5684 } 5685 if (nranks) *nranks = data->neighbors[0]; 5686 if (ranks) { 5687 if (data->neighbors[0]) *ranks = data->neighbors + 1; 5688 else *ranks = NULL; 5689 } 5690 PetscFunctionReturn(PETSC_SUCCESS); 5691 } 5692 5693 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec); 5694 5695 static PetscErrorCode DMInitialize_Plex(DM dm) 5696 { 5697 PetscFunctionBegin; 5698 dm->ops->view = DMView_Plex; 5699 dm->ops->load = DMLoad_Plex; 5700 dm->ops->setfromoptions = DMSetFromOptions_Plex; 5701 dm->ops->clone = DMClone_Plex; 5702 dm->ops->setup = DMSetUp_Plex; 5703 dm->ops->createlocalsection = DMCreateLocalSection_Plex; 5704 dm->ops->createsectionpermutation = DMCreateSectionPermutation_Plex; 5705 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_Plex; 5706 dm->ops->createglobalvector = DMCreateGlobalVector_Plex; 5707 dm->ops->createlocalvector = DMCreateLocalVector_Plex; 5708 dm->ops->getlocaltoglobalmapping = NULL; 5709 dm->ops->createfieldis = NULL; 5710 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Plex; 5711 dm->ops->createcoordinatefield = DMCreateCoordinateField_Plex; 5712 dm->ops->getcoloring = NULL; 5713 dm->ops->creatematrix = DMCreateMatrix_Plex; 5714 dm->ops->createinterpolation = DMCreateInterpolation_Plex; 5715 dm->ops->createmassmatrix = DMCreateMassMatrix_Plex; 5716 dm->ops->createmassmatrixlumped = DMCreateMassMatrixLumped_Plex; 5717 dm->ops->createinjection = DMCreateInjection_Plex; 5718 dm->ops->refine = DMRefine_Plex; 5719 dm->ops->coarsen = DMCoarsen_Plex; 5720 dm->ops->refinehierarchy = DMRefineHierarchy_Plex; 5721 dm->ops->coarsenhierarchy = DMCoarsenHierarchy_Plex; 5722 dm->ops->extrude = DMExtrude_Plex; 5723 dm->ops->globaltolocalbegin = NULL; 5724 dm->ops->globaltolocalend = NULL; 5725 dm->ops->localtoglobalbegin = NULL; 5726 dm->ops->localtoglobalend = NULL; 5727 dm->ops->destroy = DMDestroy_Plex; 5728 dm->ops->createsubdm = DMCreateSubDM_Plex; 5729 dm->ops->createsuperdm = DMCreateSuperDM_Plex; 5730 dm->ops->getdimpoints = DMGetDimPoints_Plex; 5731 dm->ops->locatepoints = DMLocatePoints_Plex; 5732 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_Plex; 5733 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex; 5734 dm->ops->projectfieldlocal = DMProjectFieldLocal_Plex; 5735 dm->ops->projectfieldlabellocal = DMProjectFieldLabelLocal_Plex; 5736 dm->ops->projectbdfieldlabellocal = DMProjectBdFieldLabelLocal_Plex; 5737 dm->ops->computel2diff = DMComputeL2Diff_Plex; 5738 dm->ops->computel2gradientdiff = DMComputeL2GradientDiff_Plex; 5739 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_Plex; 5740 dm->ops->getneighbors = DMGetNeighbors_Plex; 5741 dm->ops->getlocalboundingbox = DMGetLocalBoundingBox_Coordinates; 5742 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex; 5743 dm->ops->createddscatters = DMCreateDomainDecompositionScatters_Plex; 5744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex)); 5745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex)); 5746 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", DMPlexInsertBounds_Plex)); 5747 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex)); 5748 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex)); 5749 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex)); 5750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex)); 5751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex)); 5752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex)); 5753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex)); 5754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex)); 5755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex)); 5756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex)); 5757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex)); 5758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex)); 5759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex)); 5760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex)); 5761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex)); 5762 PetscFunctionReturn(PETSC_SUCCESS); 5763 } 5764 5765 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm) 5766 { 5767 DM_Plex *mesh = (DM_Plex *)dm->data; 5768 const PetscSF *face_sfs; 5769 PetscInt num_face_sfs; 5770 5771 PetscFunctionBegin; 5772 mesh->refct++; 5773 (*newdm)->data = mesh; 5774 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs)); 5775 PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs)); 5776 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX)); 5777 PetscCall(DMInitialize_Plex(*newdm)); 5778 PetscFunctionReturn(PETSC_SUCCESS); 5779 } 5780 5781 /*MC 5782 DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh (or grid), or CW Complex {cite}`cwcomplex`, 5783 which can be expressed using a Hasse Diagram {cite}`hassediagram`. 5784 In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is 5785 specified by a `PetscSection` object. Ownership in the global representation is determined by 5786 ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object. 5787 5788 Options Database Keys: 5789 + -dm_refine_pre - Refine mesh before distribution 5790 + -dm_refine_uniform_pre - Choose uniform or generator-based refinement 5791 + -dm_refine_volume_limit_pre - Cell volume limit after pre-refinement using generator 5792 . -dm_distribute - Distribute mesh across processes 5793 . -dm_distribute_overlap - Number of cells to overlap for distribution 5794 . -dm_refine - Refine mesh after distribution 5795 . -dm_localize <bool> - Whether to localize coordinates for periodic meshes 5796 . -dm_sparse_localize <bool> - Whether to only localize cells on the periodic boundary 5797 . -dm_plex_hash_location - Use grid hashing for point location 5798 . -dm_plex_hash_box_faces <n,m,p> - The number of divisions in each direction of the grid hash 5799 . -dm_plex_partition_balance - Attempt to evenly divide points on partition boundary between processes 5800 . -dm_plex_remesh_bd - Allow changes to the boundary on remeshing 5801 . -dm_plex_max_projection_height - Maximum mesh point height used to project locally 5802 . -dm_plex_regular_refinement - Use special nested projection algorithm for regular refinement 5803 . -dm_plex_reorder_section - Use specialized blocking if available 5804 . -dm_plex_check_all - Perform all checks below 5805 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric 5806 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices 5807 . -dm_plex_check_faces <celltype> - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 5808 . -dm_plex_check_geometry - Check that cells have positive volume 5809 . -dm_view :mesh.tex:ascii_latex - View the mesh in LaTeX/TikZ 5810 . -dm_plex_view_scale <num> - Scale the TikZ 5811 . -dm_plex_print_fem <num> - View FEM assembly information, such as element vectors and matrices 5812 - -dm_plex_print_fvm <num> - View FVM assembly information, such as flux updates 5813 5814 Level: intermediate 5815 5816 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection` 5817 M*/ 5818 5819 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm) 5820 { 5821 DM_Plex *mesh; 5822 PetscInt unit; 5823 5824 PetscFunctionBegin; 5825 PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite)); 5826 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5827 PetscCall(PetscNew(&mesh)); 5828 dm->reorderSection = DM_REORDER_DEFAULT_NOTSET; 5829 dm->data = mesh; 5830 5831 mesh->refct = 1; 5832 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection)); 5833 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection)); 5834 mesh->refinementUniform = PETSC_TRUE; 5835 mesh->refinementLimit = -1.0; 5836 mesh->distDefault = PETSC_TRUE; 5837 mesh->reorderDefault = DM_REORDER_DEFAULT_NOTSET; 5838 mesh->distributionName = NULL; 5839 mesh->interpolated = DMPLEX_INTERPOLATED_INVALID; 5840 mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID; 5841 mesh->interpolatePreferTensor = PETSC_TRUE; 5842 5843 PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner)); 5844 mesh->remeshBd = PETSC_FALSE; 5845 5846 for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0; 5847 5848 mesh->depthState = -1; 5849 mesh->celltypeState = -1; 5850 mesh->printTol = 1.0e-10; 5851 mesh->nonempty_comm = MPI_COMM_SELF; 5852 5853 PetscCall(DMInitialize_Plex(dm)); 5854 PetscFunctionReturn(PETSC_SUCCESS); 5855 } 5856 5857 /*@ 5858 DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram. 5859 5860 Collective 5861 5862 Input Parameter: 5863 . comm - The communicator for the `DMPLEX` object 5864 5865 Output Parameter: 5866 . mesh - The `DMPLEX` object 5867 5868 Level: beginner 5869 5870 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()` 5871 @*/ 5872 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh) 5873 { 5874 PetscFunctionBegin; 5875 PetscAssertPointer(mesh, 2); 5876 PetscCall(DMCreate(comm, mesh)); 5877 PetscCall(DMSetType(*mesh, DMPLEX)); 5878 PetscFunctionReturn(PETSC_SUCCESS); 5879 } 5880 5881 /*@C 5882 DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 5883 5884 Collective; No Fortran Support 5885 5886 Input Parameters: 5887 + dm - The `DM` 5888 . numCells - The number of cells owned by this process 5889 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 5890 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 5891 . numCorners - The number of vertices for each cell 5892 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 5893 5894 Output Parameters: 5895 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 5896 - verticesAdjSaved - (Optional) vertex adjacency array 5897 5898 Level: advanced 5899 5900 Notes: 5901 Two triangles sharing a face 5902 .vb 5903 5904 2 5905 / | \ 5906 / | \ 5907 / | \ 5908 0 0 | 1 3 5909 \ | / 5910 \ | / 5911 \ | / 5912 1 5913 .ve 5914 would have input 5915 .vb 5916 numCells = 2, numVertices = 4 5917 cells = [0 1 2 1 3 2] 5918 .ve 5919 which would result in the `DMPLEX` 5920 .vb 5921 5922 4 5923 / | \ 5924 / | \ 5925 / | \ 5926 2 0 | 1 5 5927 \ | / 5928 \ | / 5929 \ | / 5930 3 5931 .ve 5932 5933 Vertices are implicitly numbered consecutively 0,...,NVertices. 5934 Each rank owns a chunk of numVertices consecutive vertices. 5935 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 5936 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 5937 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 5938 5939 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 5940 5941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 5942 `PetscSF` 5943 @*/ 5944 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[]) 5945 { 5946 PetscSF sfPoint; 5947 PetscLayout layout; 5948 PetscInt numVerticesAdj, *verticesAdj, *cones, c, p; 5949 5950 PetscFunctionBegin; 5951 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 5952 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 5953 /* Get/check global number of vertices */ 5954 { 5955 PetscInt NVerticesInCells, i; 5956 const PetscInt len = numCells * numCorners; 5957 5958 /* NVerticesInCells = max(cells) + 1 */ 5959 NVerticesInCells = PETSC_INT_MIN; 5960 for (i = 0; i < len; i++) 5961 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 5962 ++NVerticesInCells; 5963 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 5964 5965 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 5966 else 5967 PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells); 5968 } 5969 /* Count locally unique vertices */ 5970 { 5971 PetscHSetI vhash; 5972 PetscInt off = 0; 5973 5974 PetscCall(PetscHSetICreate(&vhash)); 5975 for (c = 0; c < numCells; ++c) { 5976 for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p])); 5977 } 5978 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 5979 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 5980 else verticesAdj = *verticesAdjSaved; 5981 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 5982 PetscCall(PetscHSetIDestroy(&vhash)); 5983 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 5984 } 5985 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 5986 /* Create cones */ 5987 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 5988 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 5989 PetscCall(DMSetUp(dm)); 5990 PetscCall(DMPlexGetCones(dm, &cones)); 5991 for (c = 0; c < numCells; ++c) { 5992 for (p = 0; p < numCorners; ++p) { 5993 const PetscInt gv = cells[c * numCorners + p]; 5994 PetscInt lv; 5995 5996 /* Positions within verticesAdj form 0-based local vertex numbering; 5997 we need to shift it by numCells to get correct DAG points (cells go first) */ 5998 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 5999 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 6000 cones[c * numCorners + p] = lv + numCells; 6001 } 6002 } 6003 /* Build point sf */ 6004 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 6005 PetscCall(PetscLayoutSetSize(layout, NVertices)); 6006 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 6007 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 6008 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 6009 PetscCall(PetscLayoutDestroy(&layout)); 6010 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 6011 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 6012 if (dm->sf) { 6013 const char *prefix; 6014 6015 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 6016 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 6017 } 6018 PetscCall(DMSetPointSF(dm, sfPoint)); 6019 PetscCall(PetscSFDestroy(&sfPoint)); 6020 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 6021 /* Fill in the rest of the topology structure */ 6022 PetscCall(DMPlexSymmetrize(dm)); 6023 PetscCall(DMPlexStratify(dm)); 6024 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6025 PetscFunctionReturn(PETSC_SUCCESS); 6026 } 6027 6028 /*@C 6029 DMPlexBuildFromCellSectionParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) allowing multiple celltypes 6030 6031 Collective; No Fortran Support 6032 6033 Input Parameters: 6034 + dm - The `DM` 6035 . numCells - The number of cells owned by this process 6036 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE` 6037 . NVertices - The global number of vertices, or `PETSC_DETERMINE` 6038 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 6039 - cells - An array of the global vertex numbers for each cell 6040 6041 Output Parameters: 6042 + vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6043 - verticesAdjSaved - (Optional) vertex adjacency array 6044 6045 Level: advanced 6046 6047 Notes: 6048 A triangle and quadrilateral sharing a face 6049 .vb 6050 2----------3 6051 / | | 6052 / | | 6053 / | | 6054 0 0 | 1 | 6055 \ | | 6056 \ | | 6057 \ | | 6058 1----------4 6059 .ve 6060 would have input 6061 .vb 6062 numCells = 2, numVertices = 5 6063 cells = [0 1 2 1 4 3 2] 6064 .ve 6065 which would result in the `DMPLEX` 6066 .vb 6067 4----------5 6068 / | | 6069 / | | 6070 / | | 6071 2 0 | 1 | 6072 \ | | 6073 \ | | 6074 \ | | 6075 3----------6 6076 .ve 6077 6078 Vertices are implicitly numbered consecutively 0,...,NVertices. 6079 Each rank owns a chunk of numVertices consecutive vertices. 6080 If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout. 6081 If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1. 6082 If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks. 6083 6084 The cell distribution is arbitrary non-overlapping, independent of the vertex distribution. 6085 6086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexCreateFromCellSectionParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, 6087 `PetscSF` 6088 @*/ 6089 PetscErrorCode DMPlexBuildFromCellSectionParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[]) 6090 { 6091 PetscSF sfPoint; 6092 PetscLayout layout; 6093 PetscInt numVerticesAdj, *verticesAdj, *cones, cStart, cEnd, len; 6094 6095 PetscFunctionBegin; 6096 PetscValidLogicalCollectiveInt(dm, NVertices, 4); 6097 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6098 PetscCall(PetscSectionGetChart(cellSection, &cStart, &cEnd)); 6099 PetscCall(PetscSectionGetStorageSize(cellSection, &len)); 6100 PetscCheck(cStart == 0 && cEnd == numCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section chart [%" PetscInt_FMT ", %" PetscInt_FMT ") should be [0, %" PetscInt_FMT ")", cStart, cEnd, numCells); 6101 /* Get/check global number of vertices */ 6102 { 6103 PetscInt NVerticesInCells; 6104 6105 /* NVerticesInCells = max(cells) + 1 */ 6106 NVerticesInCells = PETSC_MIN_INT; 6107 for (PetscInt i = 0; i < len; i++) 6108 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 6109 ++NVerticesInCells; 6110 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 6111 6112 if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells; 6113 else 6114 PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells); 6115 } 6116 /* Count locally unique vertices */ 6117 { 6118 PetscHSetI vhash; 6119 PetscInt off = 0; 6120 6121 PetscCall(PetscHSetICreate(&vhash)); 6122 for (PetscInt i = 0; i < len; i++) PetscCall(PetscHSetIAdd(vhash, cells[i])); 6123 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 6124 if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 6125 else verticesAdj = *verticesAdjSaved; 6126 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 6127 PetscCall(PetscHSetIDestroy(&vhash)); 6128 PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj); 6129 } 6130 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 6131 /* Create cones */ 6132 PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj)); 6133 for (PetscInt c = 0; c < numCells; ++c) { 6134 PetscInt dof; 6135 6136 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 6137 PetscCall(DMPlexSetConeSize(dm, c, dof)); 6138 } 6139 PetscCall(DMSetUp(dm)); 6140 PetscCall(DMPlexGetCones(dm, &cones)); 6141 for (PetscInt c = 0; c < numCells; ++c) { 6142 PetscInt dof, off; 6143 6144 PetscCall(PetscSectionGetDof(cellSection, c, &dof)); 6145 PetscCall(PetscSectionGetOffset(cellSection, c, &off)); 6146 for (PetscInt p = off; p < off + dof; ++p) { 6147 const PetscInt gv = cells[p]; 6148 PetscInt lv; 6149 6150 /* Positions within verticesAdj form 0-based local vertex numbering; 6151 we need to shift it by numCells to get correct DAG points (cells go first) */ 6152 PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv)); 6153 PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv); 6154 cones[p] = lv + numCells; 6155 } 6156 } 6157 /* Build point sf */ 6158 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout)); 6159 PetscCall(PetscLayoutSetSize(layout, NVertices)); 6160 PetscCall(PetscLayoutSetLocalSize(layout, numVertices)); 6161 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 6162 PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint)); 6163 PetscCall(PetscLayoutDestroy(&layout)); 6164 if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj)); 6165 PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF")); 6166 if (dm->sf) { 6167 const char *prefix; 6168 6169 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix)); 6170 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix)); 6171 } 6172 PetscCall(DMSetPointSF(dm, sfPoint)); 6173 PetscCall(PetscSFDestroy(&sfPoint)); 6174 if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF")); 6175 /* Fill in the rest of the topology structure */ 6176 PetscCall(DMPlexSymmetrize(dm)); 6177 PetscCall(DMPlexStratify(dm)); 6178 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6179 PetscFunctionReturn(PETSC_SUCCESS); 6180 } 6181 6182 /*@ 6183 DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 6184 6185 Collective; No Fortran Support 6186 6187 Input Parameters: 6188 + dm - The `DM` 6189 . spaceDim - The spatial dimension used for coordinates 6190 . sfVert - `PetscSF` describing complete vertex ownership 6191 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6192 6193 Level: advanced 6194 6195 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()` 6196 @*/ 6197 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[]) 6198 { 6199 PetscSection coordSection; 6200 Vec coordinates; 6201 PetscScalar *coords; 6202 PetscInt numVertices, numVerticesAdj, coordSize, v, vStart, vEnd; 6203 PetscMPIInt spaceDimi; 6204 6205 PetscFunctionBegin; 6206 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6207 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6208 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 6209 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 6210 PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL)); 6211 PetscCheck(vEnd - vStart == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Supplied sfVert has wrong number of leaves = %" PetscInt_FMT " != %" PetscInt_FMT " = vEnd - vStart", numVerticesAdj, vEnd - vStart); 6212 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6213 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6214 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 6215 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 6216 for (v = vStart; v < vEnd; ++v) { 6217 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 6218 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 6219 } 6220 PetscCall(PetscSectionSetUp(coordSection)); 6221 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6222 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 6223 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 6224 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6225 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6226 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6227 PetscCall(VecGetArray(coordinates, &coords)); 6228 { 6229 MPI_Datatype coordtype; 6230 6231 /* Need a temp buffer for coords if we have complex/single */ 6232 PetscCall(PetscMPIIntCast(spaceDim, &spaceDimi)); 6233 PetscCallMPI(MPI_Type_contiguous(spaceDimi, MPIU_SCALAR, &coordtype)); 6234 PetscCallMPI(MPI_Type_commit(&coordtype)); 6235 #if defined(PETSC_USE_COMPLEX) 6236 { 6237 PetscScalar *svertexCoords; 6238 PetscInt i; 6239 PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords)); 6240 for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i]; 6241 PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 6242 PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE)); 6243 PetscCall(PetscFree(svertexCoords)); 6244 } 6245 #else 6246 PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 6247 PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE)); 6248 #endif 6249 PetscCallMPI(MPI_Type_free(&coordtype)); 6250 } 6251 PetscCall(VecRestoreArray(coordinates, &coords)); 6252 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6253 PetscCall(VecDestroy(&coordinates)); 6254 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6255 PetscFunctionReturn(PETSC_SUCCESS); 6256 } 6257 6258 /*@ 6259 DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype 6260 6261 Collective 6262 6263 Input Parameters: 6264 + comm - The communicator 6265 . dim - The topological dimension of the mesh 6266 . numCells - The number of cells owned by this process 6267 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 6268 . NVertices - The global number of vertices, or `PETSC_DECIDE` 6269 . numCorners - The number of vertices for each cell 6270 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6271 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell 6272 . spaceDim - The spatial dimension used for coordinates 6273 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6274 6275 Output Parameters: 6276 + dm - The `DM` 6277 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6278 - verticesAdj - (Optional) vertex adjacency array 6279 6280 Level: intermediate 6281 6282 Notes: 6283 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 6284 `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 6285 6286 See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters. 6287 6288 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 6289 6290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6291 @*/ 6292 PetscErrorCode DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm) 6293 { 6294 PetscSF sfVert; 6295 6296 PetscFunctionBegin; 6297 PetscCall(DMCreate(comm, dm)); 6298 PetscCall(DMSetType(*dm, DMPLEX)); 6299 PetscValidLogicalCollectiveInt(*dm, dim, 2); 6300 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 6301 PetscCall(DMSetDimension(*dm, dim)); 6302 PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj)); 6303 if (interpolate) { 6304 DM idm; 6305 6306 PetscCall(DMPlexInterpolate(*dm, &idm)); 6307 PetscCall(DMDestroy(dm)); 6308 *dm = idm; 6309 } 6310 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 6311 if (vertexSF) *vertexSF = sfVert; 6312 else PetscCall(PetscSFDestroy(&sfVert)); 6313 PetscFunctionReturn(PETSC_SUCCESS); 6314 } 6315 6316 /*@ 6317 DMPlexCreateFromCellSectionParallel - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) and supports multiple celltypes 6318 6319 Collective 6320 6321 Input Parameters: 6322 + comm - The communicator 6323 . dim - The topological dimension of the mesh 6324 . numCells - The number of cells owned by this process 6325 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE` 6326 . NVertices - The global number of vertices, or `PETSC_DECIDE` 6327 . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells) 6328 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6329 . cells - An array of the global vertex numbers for each cell 6330 . spaceDim - The spatial dimension used for coordinates 6331 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6332 6333 Output Parameters: 6334 + dm - The `DM` 6335 . vertexSF - (Optional) `PetscSF` describing complete vertex ownership 6336 - verticesAdj - (Optional) vertex adjacency array 6337 6338 Level: intermediate 6339 6340 Notes: 6341 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, 6342 `DMPlexBuildFromCellSectionParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()` 6343 6344 See `DMPlexBuildFromCellSectionParallel()` for an example and details about the topology-related parameters. 6345 6346 See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters. 6347 6348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6349 @*/ 6350 PetscErrorCode DMPlexCreateFromCellSectionParallel(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm) 6351 { 6352 PetscSF sfVert; 6353 6354 PetscFunctionBegin; 6355 PetscCall(DMCreate(comm, dm)); 6356 PetscCall(DMSetType(*dm, DMPLEX)); 6357 PetscValidLogicalCollectiveInt(*dm, dim, 2); 6358 PetscValidLogicalCollectiveInt(*dm, spaceDim, 9); 6359 PetscCall(DMSetDimension(*dm, dim)); 6360 PetscCall(DMPlexBuildFromCellSectionParallel(*dm, numCells, numVertices, NVertices, cellSection, cells, &sfVert, verticesAdj)); 6361 if (interpolate) { 6362 DM idm; 6363 6364 PetscCall(DMPlexInterpolate(*dm, &idm)); 6365 PetscCall(DMDestroy(dm)); 6366 *dm = idm; 6367 } 6368 PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords)); 6369 if (vertexSF) *vertexSF = sfVert; 6370 else PetscCall(PetscSFDestroy(&sfVert)); 6371 PetscFunctionReturn(PETSC_SUCCESS); 6372 } 6373 6374 /*@ 6375 DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) 6376 6377 Collective; No Fortran Support 6378 6379 Input Parameters: 6380 + dm - The `DM` 6381 . numCells - The number of cells owned by this process 6382 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE` 6383 . numCorners - The number of vertices for each cell 6384 - cells - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell 6385 6386 Level: advanced 6387 6388 Notes: 6389 Two triangles sharing a face 6390 .vb 6391 6392 2 6393 / | \ 6394 / | \ 6395 / | \ 6396 0 0 | 1 3 6397 \ | / 6398 \ | / 6399 \ | / 6400 1 6401 .ve 6402 would have input 6403 .vb 6404 numCells = 2, numVertices = 4 6405 cells = [0 1 2 1 3 2] 6406 .ve 6407 which would result in the `DMPLEX` 6408 .vb 6409 6410 4 6411 / | \ 6412 / | \ 6413 / | \ 6414 2 0 | 1 5 6415 \ | / 6416 \ | / 6417 \ | / 6418 3 6419 .ve 6420 6421 If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1. 6422 6423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()` 6424 @*/ 6425 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[]) 6426 { 6427 PetscInt *cones, c, p, dim; 6428 6429 PetscFunctionBegin; 6430 PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6431 PetscCall(DMGetDimension(dm, &dim)); 6432 /* Get/check global number of vertices */ 6433 { 6434 PetscInt NVerticesInCells, i; 6435 const PetscInt len = numCells * numCorners; 6436 6437 /* NVerticesInCells = max(cells) + 1 */ 6438 NVerticesInCells = PETSC_INT_MIN; 6439 for (i = 0; i < len; i++) 6440 if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i]; 6441 ++NVerticesInCells; 6442 6443 if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells; 6444 else 6445 PetscCheck(numVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, numVertices, NVerticesInCells); 6446 } 6447 PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices)); 6448 for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners)); 6449 PetscCall(DMSetUp(dm)); 6450 PetscCall(DMPlexGetCones(dm, &cones)); 6451 for (c = 0; c < numCells; ++c) { 6452 for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells; 6453 } 6454 PetscCall(DMPlexSymmetrize(dm)); 6455 PetscCall(DMPlexStratify(dm)); 6456 PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0)); 6457 PetscFunctionReturn(PETSC_SUCCESS); 6458 } 6459 6460 /*@ 6461 DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output) 6462 6463 Collective 6464 6465 Input Parameters: 6466 + dm - The `DM` 6467 . spaceDim - The spatial dimension used for coordinates 6468 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex 6469 6470 Level: advanced 6471 6472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()` 6473 @*/ 6474 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[]) 6475 { 6476 PetscSection coordSection; 6477 Vec coordinates; 6478 DM cdm; 6479 PetscScalar *coords; 6480 PetscInt v, vStart, vEnd, d; 6481 6482 PetscFunctionBegin; 6483 PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6484 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6485 PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first."); 6486 PetscCall(DMSetCoordinateDim(dm, spaceDim)); 6487 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6488 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6489 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim)); 6490 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 6491 for (v = vStart; v < vEnd; ++v) { 6492 PetscCall(PetscSectionSetDof(coordSection, v, spaceDim)); 6493 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim)); 6494 } 6495 PetscCall(PetscSectionSetUp(coordSection)); 6496 6497 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6498 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 6499 PetscCall(VecSetBlockSize(coordinates, spaceDim)); 6500 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6501 PetscCall(VecGetArrayWrite(coordinates, &coords)); 6502 for (v = 0; v < vEnd - vStart; ++v) { 6503 for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d]; 6504 } 6505 PetscCall(VecRestoreArrayWrite(coordinates, &coords)); 6506 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6507 PetscCall(VecDestroy(&coordinates)); 6508 PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0)); 6509 PetscFunctionReturn(PETSC_SUCCESS); 6510 } 6511 6512 /*@ 6513 DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input 6514 6515 Collective 6516 6517 Input Parameters: 6518 + comm - The communicator 6519 . dim - The topological dimension of the mesh 6520 . numCells - The number of cells, only on process 0 6521 . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0 6522 . numCorners - The number of vertices for each cell, only on process 0 6523 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically 6524 . cells - An array of $ numCells \times numCorners$ numbers, the vertices for each cell, only on process 0 6525 . spaceDim - The spatial dimension used for coordinates 6526 - vertexCoords - An array of $ numVertices \times spaceDim$ numbers, the coordinates of each vertex, only on process 0 6527 6528 Output Parameter: 6529 . dm - The `DM`, which only has points on process 0 6530 6531 Level: intermediate 6532 6533 Notes: 6534 This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`, 6535 `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()` 6536 6537 See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters. 6538 See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters. 6539 See `DMPlexCreateFromCellListParallelPetsc()` for parallel input 6540 6541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()` 6542 @*/ 6543 PetscErrorCode DMPlexCreateFromCellListPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], DM *dm) 6544 { 6545 PetscMPIInt rank; 6546 6547 PetscFunctionBegin; 6548 PetscCheck(dim, comm, PETSC_ERR_ARG_OUTOFRANGE, "This is not appropriate for 0-dimensional meshes. Consider either creating the DM using DMPlexCreateFromDAG(), by hand, or using DMSwarm."); 6549 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6550 PetscCall(DMCreate(comm, dm)); 6551 PetscCall(DMSetType(*dm, DMPLEX)); 6552 PetscCall(DMSetDimension(*dm, dim)); 6553 if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells)); 6554 else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL)); 6555 if (interpolate) { 6556 DM idm; 6557 6558 PetscCall(DMPlexInterpolate(*dm, &idm)); 6559 PetscCall(DMDestroy(dm)); 6560 *dm = idm; 6561 } 6562 if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords)); 6563 else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL)); 6564 PetscFunctionReturn(PETSC_SUCCESS); 6565 } 6566 6567 /*@ 6568 DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM` 6569 6570 Input Parameters: 6571 + dm - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()` 6572 . depth - The depth of the DAG 6573 . numPoints - Array of size $ depth + 1 $ containing the number of points at each `depth` 6574 . coneSize - The cone size of each point 6575 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point 6576 . coneOrientations - The orientation of each cone point 6577 - vertexCoords - An array of $ numPoints[0] \times spacedim $ numbers representing the coordinates of each vertex, with `spacedim` the value set via `DMSetCoordinateDim()` 6578 6579 Output Parameter: 6580 . dm - The `DM` 6581 6582 Level: advanced 6583 6584 Note: 6585 Two triangles sharing a face would have input 6586 .vb 6587 depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0] 6588 cones = [2 3 4 3 5 4], coneOrientations = [0 0 0 0 0 0] 6589 vertexCoords = [-1.0 0.0 0.0 -1.0 0.0 1.0 1.0 0.0] 6590 .ve 6591 which would result in the DMPlex 6592 .vb 6593 4 6594 / | \ 6595 / | \ 6596 / | \ 6597 2 0 | 1 5 6598 \ | / 6599 \ | / 6600 \ | / 6601 3 6602 .ve 6603 Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()` 6604 6605 Developer Note: 6606 This does not create anything so should not have create in the name. 6607 6608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 6609 @*/ 6610 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[]) 6611 { 6612 Vec coordinates; 6613 PetscSection coordSection; 6614 PetscScalar *coords; 6615 PetscInt coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off; 6616 6617 PetscFunctionBegin; 6618 PetscCall(DMGetDimension(dm, &dim)); 6619 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 6620 PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim); 6621 for (d = 0; d <= depth; ++d) pEnd += numPoints[d]; 6622 PetscCall(DMPlexSetChart(dm, pStart, pEnd)); 6623 for (p = pStart; p < pEnd; ++p) { 6624 PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart])); 6625 if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart; 6626 } 6627 PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]); 6628 PetscCall(DMSetUp(dm)); /* Allocate space for cones */ 6629 for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) { 6630 PetscCall(DMPlexSetCone(dm, p, &cones[off])); 6631 PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off])); 6632 } 6633 PetscCall(DMPlexSymmetrize(dm)); 6634 PetscCall(DMPlexStratify(dm)); 6635 /* Build coordinates */ 6636 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6637 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6638 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed)); 6639 PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0])); 6640 for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) { 6641 PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed)); 6642 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed)); 6643 } 6644 PetscCall(PetscSectionSetUp(coordSection)); 6645 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6646 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6647 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6648 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6649 PetscCall(VecSetBlockSize(coordinates, PetscMax(dimEmbed, 1))); 6650 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6651 if (vertexCoords) { 6652 PetscCall(VecGetArray(coordinates, &coords)); 6653 for (v = 0; v < numPoints[0]; ++v) { 6654 PetscInt off; 6655 6656 PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off)); 6657 for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d]; 6658 } 6659 } 6660 PetscCall(VecRestoreArray(coordinates, &coords)); 6661 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 6662 PetscCall(VecDestroy(&coordinates)); 6663 PetscFunctionReturn(PETSC_SUCCESS); 6664 } 6665 6666 /* 6667 DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file. 6668 6669 Collective 6670 6671 + comm - The MPI communicator 6672 . filename - Name of the .dat file 6673 - interpolate - Create faces and edges in the mesh 6674 6675 Output Parameter: 6676 . dm - The `DM` object representing the mesh 6677 6678 Level: beginner 6679 6680 Note: 6681 The format is the simplest possible: 6682 .vb 6683 dim Ne Nv Nc Nl 6684 v_1 v_2 ... v_Nc 6685 ... 6686 x y z marker_1 ... marker_Nl 6687 .ve 6688 6689 Developer Note: 6690 Should use a `PetscViewer` not a filename 6691 6692 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 6693 */ 6694 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 6695 { 6696 DMLabel marker; 6697 PetscViewer viewer; 6698 Vec coordinates; 6699 PetscSection coordSection; 6700 PetscScalar *coords; 6701 char line[PETSC_MAX_PATH_LEN]; 6702 PetscInt cdim, coordSize, v, c, d; 6703 PetscMPIInt rank; 6704 int snum, dim, Nv, Nc, Ncn, Nl; 6705 6706 PetscFunctionBegin; 6707 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6708 PetscCall(PetscViewerCreate(comm, &viewer)); 6709 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII)); 6710 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6711 PetscCall(PetscViewerFileSetName(viewer, filename)); 6712 if (rank == 0) { 6713 PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING)); 6714 snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl); 6715 PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6716 } else { 6717 Nc = Nv = Ncn = Nl = 0; 6718 } 6719 PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm)); 6720 cdim = dim; 6721 PetscCall(DMCreate(comm, dm)); 6722 PetscCall(DMSetType(*dm, DMPLEX)); 6723 PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv)); 6724 PetscCall(DMSetDimension(*dm, dim)); 6725 PetscCall(DMSetCoordinateDim(*dm, cdim)); 6726 /* Read topology */ 6727 if (rank == 0) { 6728 char format[PETSC_MAX_PATH_LEN]; 6729 PetscInt cone[8]; 6730 int vbuf[8], v; 6731 6732 for (c = 0; c < Ncn; ++c) { 6733 format[c * 3 + 0] = '%'; 6734 format[c * 3 + 1] = 'd'; 6735 format[c * 3 + 2] = ' '; 6736 } 6737 format[Ncn * 3 - 1] = '\0'; 6738 for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn)); 6739 PetscCall(DMSetUp(*dm)); 6740 for (c = 0; c < Nc; ++c) { 6741 PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING)); 6742 switch (Ncn) { 6743 case 2: 6744 snum = sscanf(line, format, &vbuf[0], &vbuf[1]); 6745 break; 6746 case 3: 6747 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]); 6748 break; 6749 case 4: 6750 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]); 6751 break; 6752 case 6: 6753 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]); 6754 break; 6755 case 8: 6756 snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]); 6757 break; 6758 default: 6759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn); 6760 } 6761 PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6762 for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc; 6763 /* Hexahedra are inverted */ 6764 if (Ncn == 8) { 6765 PetscInt tmp = cone[1]; 6766 cone[1] = cone[3]; 6767 cone[3] = tmp; 6768 } 6769 PetscCall(DMPlexSetCone(*dm, c, cone)); 6770 } 6771 } 6772 PetscCall(DMPlexSymmetrize(*dm)); 6773 PetscCall(DMPlexStratify(*dm)); 6774 /* Read coordinates */ 6775 PetscCall(DMGetCoordinateSection(*dm, &coordSection)); 6776 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 6777 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim)); 6778 PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv)); 6779 for (v = Nc; v < Nc + Nv; ++v) { 6780 PetscCall(PetscSectionSetDof(coordSection, v, cdim)); 6781 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim)); 6782 } 6783 PetscCall(PetscSectionSetUp(coordSection)); 6784 PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize)); 6785 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates)); 6786 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 6787 PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE)); 6788 PetscCall(VecSetBlockSize(coordinates, cdim)); 6789 PetscCall(VecSetType(coordinates, VECSTANDARD)); 6790 PetscCall(VecGetArray(coordinates, &coords)); 6791 if (rank == 0) { 6792 char format[PETSC_MAX_PATH_LEN]; 6793 double x[3]; 6794 int l, val[3]; 6795 6796 if (Nl) { 6797 for (l = 0; l < Nl; ++l) { 6798 format[l * 3 + 0] = '%'; 6799 format[l * 3 + 1] = 'd'; 6800 format[l * 3 + 2] = ' '; 6801 } 6802 format[Nl * 3 - 1] = '\0'; 6803 PetscCall(DMCreateLabel(*dm, "marker")); 6804 PetscCall(DMGetLabel(*dm, "marker", &marker)); 6805 } 6806 for (v = 0; v < Nv; ++v) { 6807 PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING)); 6808 snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]); 6809 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6810 switch (Nl) { 6811 case 0: 6812 snum = 0; 6813 break; 6814 case 1: 6815 snum = sscanf(line, format, &val[0]); 6816 break; 6817 case 2: 6818 snum = sscanf(line, format, &val[0], &val[1]); 6819 break; 6820 case 3: 6821 snum = sscanf(line, format, &val[0], &val[1], &val[2]); 6822 break; 6823 default: 6824 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl); 6825 } 6826 PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line); 6827 for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d]; 6828 for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l])); 6829 } 6830 } 6831 PetscCall(VecRestoreArray(coordinates, &coords)); 6832 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 6833 PetscCall(VecDestroy(&coordinates)); 6834 PetscCall(PetscViewerDestroy(&viewer)); 6835 if (interpolate) { 6836 DM idm; 6837 DMLabel bdlabel; 6838 6839 PetscCall(DMPlexInterpolate(*dm, &idm)); 6840 PetscCall(DMDestroy(dm)); 6841 *dm = idm; 6842 6843 if (!Nl) { 6844 PetscCall(DMCreateLabel(*dm, "marker")); 6845 PetscCall(DMGetLabel(*dm, "marker", &bdlabel)); 6846 PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel)); 6847 PetscCall(DMPlexLabelComplete(*dm, bdlabel)); 6848 } 6849 } 6850 PetscFunctionReturn(PETSC_SUCCESS); 6851 } 6852 6853 /*@ 6854 DMPlexCreateFromFile - This takes a filename and produces a `DM` 6855 6856 Collective 6857 6858 Input Parameters: 6859 + comm - The communicator 6860 . filename - A file name 6861 . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats 6862 - interpolate - Flag to create intermediate mesh pieces (edges, faces) 6863 6864 Output Parameter: 6865 . dm - The `DM` 6866 6867 Options Database Key: 6868 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5 6869 6870 Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. `-dm_plex_create_viewer_hdf5_collective` 6871 6872 Level: beginner 6873 6874 Notes: 6875 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 6876 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 6877 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 6878 The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally 6879 calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats. 6880 6881 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()` 6882 @*/ 6883 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm) 6884 { 6885 const char extGmsh[] = ".msh"; 6886 const char extGmsh2[] = ".msh2"; 6887 const char extGmsh4[] = ".msh4"; 6888 const char extCGNS[] = ".cgns"; 6889 const char extExodus[] = ".exo"; 6890 const char extExodus_e[] = ".e"; 6891 const char extGenesis[] = ".gen"; 6892 const char extFluent[] = ".cas"; 6893 const char extHDF5[] = ".h5"; 6894 const char extXDMFHDF5[] = ".xdmf.h5"; 6895 const char extPLY[] = ".ply"; 6896 const char extEGADSlite[] = ".egadslite"; 6897 const char extEGADS[] = ".egads"; 6898 const char extIGES[] = ".igs"; 6899 const char extIGES2[] = ".iges"; 6900 const char extSTEP[] = ".stp"; 6901 const char extSTEP2[] = ".step"; 6902 const char extBREP[] = ".brep"; 6903 const char extCV[] = ".dat"; 6904 size_t len; 6905 PetscBool isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSlite, isEGADS, isIGES, isIGES2, isSTEP, isSTEP2, isBREP, isCV, isXDMFHDF5; 6906 PetscMPIInt rank; 6907 6908 PetscFunctionBegin; 6909 PetscAssertPointer(filename, 2); 6910 if (plexname) PetscAssertPointer(plexname, 3); 6911 PetscAssertPointer(dm, 5); 6912 PetscCall(DMInitializePackage()); 6913 PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 6914 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 6915 PetscCall(PetscStrlen(filename, &len)); 6916 PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path"); 6917 6918 #define CheckExtension(extension__, is_extension__) \ 6919 do { \ 6920 PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \ 6921 /* don't count the null-terminator at the end */ \ 6922 const size_t ext_len = sizeof(extension__) - 1; \ 6923 if (len < ext_len) { \ 6924 is_extension__ = PETSC_FALSE; \ 6925 } else { \ 6926 PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \ 6927 } \ 6928 } while (0) 6929 6930 CheckExtension(extGmsh, isGmsh); 6931 CheckExtension(extGmsh2, isGmsh2); 6932 CheckExtension(extGmsh4, isGmsh4); 6933 CheckExtension(extCGNS, isCGNS); 6934 CheckExtension(extExodus, isExodus); 6935 if (!isExodus) CheckExtension(extExodus_e, isExodus); 6936 CheckExtension(extGenesis, isGenesis); 6937 CheckExtension(extFluent, isFluent); 6938 CheckExtension(extHDF5, isHDF5); 6939 CheckExtension(extPLY, isPLY); 6940 CheckExtension(extEGADSlite, isEGADSlite); 6941 CheckExtension(extEGADS, isEGADS); 6942 CheckExtension(extIGES, isIGES); 6943 CheckExtension(extIGES2, isIGES2); 6944 CheckExtension(extSTEP, isSTEP); 6945 CheckExtension(extSTEP2, isSTEP2); 6946 CheckExtension(extBREP, isBREP); 6947 CheckExtension(extCV, isCV); 6948 CheckExtension(extXDMFHDF5, isXDMFHDF5); 6949 6950 #undef CheckExtension 6951 6952 if (isGmsh || isGmsh2 || isGmsh4) { 6953 PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm)); 6954 } else if (isCGNS) { 6955 PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm)); 6956 } else if (isExodus || isGenesis) { 6957 PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm)); 6958 } else if (isFluent) { 6959 PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm)); 6960 } else if (isHDF5) { 6961 PetscViewer viewer; 6962 6963 /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */ 6964 PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL)); 6965 PetscCall(PetscViewerCreate(comm, &viewer)); 6966 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5)); 6967 PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_")); 6968 PetscCall(PetscViewerSetFromOptions(viewer)); 6969 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 6970 PetscCall(PetscViewerFileSetName(viewer, filename)); 6971 6972 PetscCall(DMCreate(comm, dm)); 6973 PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 6974 PetscCall(DMSetType(*dm, DMPLEX)); 6975 if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF)); 6976 PetscCall(DMLoad(*dm, viewer)); 6977 if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer)); 6978 PetscCall(PetscViewerDestroy(&viewer)); 6979 6980 if (interpolate) { 6981 DM idm; 6982 6983 PetscCall(DMPlexInterpolate(*dm, &idm)); 6984 PetscCall(DMDestroy(dm)); 6985 *dm = idm; 6986 } 6987 } else if (isPLY) { 6988 PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm)); 6989 } else if (isEGADSlite || isEGADS || isIGES || isIGES2 || isSTEP || isSTEP2 || isBREP) { 6990 PetscCall(DMPlexCreateGeomFromFile(comm, filename, dm, isEGADSlite)); 6991 6992 if (!interpolate) { 6993 DM udm; 6994 6995 PetscCall(DMPlexUninterpolate(*dm, &udm)); 6996 PetscCall(DMDestroy(dm)); 6997 *dm = udm; 6998 } 6999 } else if (isCV) { 7000 PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm)); 7001 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename); 7002 PetscCall(PetscStrlen(plexname, &len)); 7003 if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname)); 7004 PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0)); 7005 PetscFunctionReturn(PETSC_SUCCESS); 7006 } 7007 7008 /*@ 7009 DMPlexCreateEphemeral - This takes a `DMPlexTransform` and a base `DMPlex` and produces an ephemeral `DM`, meaning one that is created on the fly in response to queries. 7010 7011 Input Parameters: 7012 + tr - The `DMPlexTransform` 7013 - prefix - An options prefix, or NULL 7014 7015 Output Parameter: 7016 . dm - The `DM` 7017 7018 Level: beginner 7019 7020 Notes: 7021 An emphemeral mesh is one that is not stored concretely, as in the default `DMPLEX` implementation, but rather is produced on the fly in response to queries, using information from the transform and the base mesh. 7022 7023 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()` 7024 @*/ 7025 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm) 7026 { 7027 DM bdm, bcdm, cdm; 7028 Vec coordinates, coordinatesNew; 7029 PetscSection cs; 7030 PetscInt cdim, Nl; 7031 7032 PetscFunctionBegin; 7033 PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm)); 7034 PetscCall(DMSetType(*dm, DMPLEX)); 7035 ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL; 7036 // Handle coordinates 7037 PetscCall(DMPlexTransformGetDM(tr, &bdm)); 7038 PetscCall(DMPlexTransformSetDimensions(tr, bdm, *dm)); 7039 PetscCall(DMGetCoordinateDim(*dm, &cdim)); 7040 PetscCall(DMGetCoordinateDM(bdm, &bcdm)); 7041 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 7042 PetscCall(DMCopyDisc(bcdm, cdm)); 7043 PetscCall(DMGetLocalSection(cdm, &cs)); 7044 PetscCall(PetscSectionSetNumFields(cs, 1)); 7045 PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim)); 7046 PetscCall(DMGetCoordinatesLocal(bdm, &coordinates)); 7047 PetscCall(VecDuplicate(coordinates, &coordinatesNew)); 7048 PetscCall(VecCopy(coordinates, coordinatesNew)); 7049 PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew)); 7050 PetscCall(VecDestroy(&coordinatesNew)); 7051 7052 PetscCall(PetscObjectReference((PetscObject)tr)); 7053 PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr)); 7054 ((DM_Plex *)(*dm)->data)->tr = tr; 7055 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 7056 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix)); 7057 PetscCall(DMSetFromOptions(*dm)); 7058 7059 PetscCall(DMGetNumLabels(bdm, &Nl)); 7060 for (PetscInt l = 0; l < Nl; ++l) { 7061 DMLabel label, labelNew; 7062 const char *lname; 7063 PetscBool isDepth, isCellType; 7064 7065 PetscCall(DMGetLabelName(bdm, l, &lname)); 7066 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 7067 if (isDepth) continue; 7068 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 7069 if (isCellType) continue; 7070 PetscCall(DMCreateLabel(*dm, lname)); 7071 PetscCall(DMGetLabel(bdm, lname, &label)); 7072 PetscCall(DMGetLabel(*dm, lname, &labelNew)); 7073 PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL)); 7074 PetscCall(DMLabelEphemeralSetLabel(labelNew, label)); 7075 PetscCall(DMLabelEphemeralSetTransform(labelNew, tr)); 7076 PetscCall(DMLabelSetUp(labelNew)); 7077 } 7078 PetscFunctionReturn(PETSC_SUCCESS); 7079 } 7080