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