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