1 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/ 2 3 #include <petscdmplex.h> 4 5 /*@C 6 DMGetPeriodicity - Get the description of mesh periodicity 7 8 Input Parameter: 9 . dm - The `DM` object 10 11 Output Parameters: 12 + maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates 13 . Lstart - If we assume the mesh is a torus, this is the start of each coordinate, or `NULL` for 0.0 14 - L - If we assume the mesh is a torus, this is the length of each coordinate, otherwise it is < 0.0 15 16 Level: developer 17 18 .seealso: `DM` 19 @*/ 20 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **Lstart, const PetscReal **L) 21 { 22 PetscFunctionBegin; 23 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 24 if (maxCell) *maxCell = dm->maxCell; 25 if (Lstart) *Lstart = dm->Lstart; 26 if (L) *L = dm->L; 27 PetscFunctionReturn(PETSC_SUCCESS); 28 } 29 30 /*@C 31 DMSetPeriodicity - Set the description of mesh periodicity 32 33 Input Parameters: 34 + dm - The `DM` object 35 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass `NULL` to remove such information. 36 . Lstart - If we assume the mesh is a torus, this is the start of each coordinate, or `NULL` for 0.0 37 - L - If we assume the mesh is a torus, this is the length of each coordinate, otherwise it is < 0.0 38 39 Level: developer 40 41 .seealso: `DM`, `DMGetPeriodicity()` 42 @*/ 43 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal Lstart[], const PetscReal L[]) 44 { 45 PetscInt dim, d; 46 47 PetscFunctionBegin; 48 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 49 if (maxCell) PetscAssertPointer(maxCell, 2); 50 if (Lstart) PetscAssertPointer(Lstart, 3); 51 if (L) PetscAssertPointer(L, 4); 52 PetscCall(DMGetDimension(dm, &dim)); 53 if (maxCell) { 54 if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell)); 55 for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d]; 56 } else { /* remove maxCell information to disable automatic computation of localized vertices */ 57 PetscCall(PetscFree(dm->maxCell)); 58 dm->maxCell = NULL; 59 } 60 if (Lstart) { 61 if (!dm->Lstart) PetscCall(PetscMalloc1(dim, &dm->Lstart)); 62 for (d = 0; d < dim; ++d) dm->Lstart[d] = Lstart[d]; 63 } else { /* remove L information to disable automatic computation of localized vertices */ 64 PetscCall(PetscFree(dm->Lstart)); 65 dm->Lstart = NULL; 66 } 67 if (L) { 68 if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L)); 69 for (d = 0; d < dim; ++d) dm->L[d] = L[d]; 70 } else { /* remove L information to disable automatic computation of localized vertices */ 71 PetscCall(PetscFree(dm->L)); 72 dm->L = NULL; 73 } 74 PetscCheck((dm->maxCell && dm->L) || (!dm->maxCell && !dm->L), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot set only one of maxCell/L"); 75 PetscFunctionReturn(PETSC_SUCCESS); 76 } 77 78 /*@ 79 DMLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension. 80 81 Input Parameters: 82 + dm - The `DM` 83 . in - The input coordinate point (dim numbers) 84 - endpoint - Include the endpoint L_i 85 86 Output Parameter: 87 . out - The localized coordinate point (dim numbers) 88 89 Level: developer 90 91 .seealso: `DM`, `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()` 92 @*/ 93 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[]) 94 { 95 PetscInt dim, d; 96 97 PetscFunctionBegin; 98 PetscCall(DMGetCoordinateDim(dm, &dim)); 99 if (!dm->maxCell) { 100 for (d = 0; d < dim; ++d) out[d] = in[d]; 101 } else { 102 if (endpoint) { 103 for (d = 0; d < dim; ++d) { 104 if ((PetscAbsReal(PetscRealPart(in[d]) / dm->L[d] - PetscFloorReal(PetscRealPart(in[d]) / dm->L[d])) < PETSC_SMALL) && (PetscRealPart(in[d]) / dm->L[d] > PETSC_SMALL)) { 105 out[d] = in[d] - dm->L[d] * (PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]) - 1); 106 } else { 107 out[d] = in[d] - dm->L[d] * PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]); 108 } 109 } 110 } else { 111 for (d = 0; d < dim; ++d) out[d] = in[d] - dm->L[d] * PetscFloorReal(PetscRealPart(in[d]) / dm->L[d]); 112 } 113 } 114 PetscFunctionReturn(PETSC_SUCCESS); 115 } 116 117 /* 118 DMLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer. 119 120 Input Parameters: 121 + dm - The `DM` 122 . dim - The spatial dimension 123 . anchor - The anchor point, the input point can be no more than maxCell away from it 124 - in - The input coordinate point (dim numbers) 125 126 Output Parameter: 127 . out - The localized coordinate point (dim numbers) 128 129 Level: developer 130 131 Note: 132 This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell 133 134 .seealso: `DM`, `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()` 135 */ 136 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 137 { 138 PetscInt d; 139 140 PetscFunctionBegin; 141 if (!dm->maxCell) { 142 for (d = 0; d < dim; ++d) out[d] = in[d]; 143 } else { 144 for (d = 0; d < dim; ++d) { 145 if ((dm->L[d] > 0.0) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) { 146 out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 147 } else { 148 out[d] = in[d]; 149 } 150 } 151 } 152 PetscFunctionReturn(PETSC_SUCCESS); 153 } 154 155 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[]) 156 { 157 PetscInt d; 158 159 PetscFunctionBegin; 160 if (!dm->maxCell) { 161 for (d = 0; d < dim; ++d) out[d] = in[d]; 162 } else { 163 for (d = 0; d < dim; ++d) { 164 if ((dm->L[d] > 0.0) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) { 165 out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d]; 166 } else { 167 out[d] = in[d]; 168 } 169 } 170 } 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 /* 175 DMLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer. 176 177 Input Parameters: 178 + dm - The `DM` 179 . dim - The spatial dimension 180 . anchor - The anchor point, the input point can be no more than maxCell away from it 181 . in - The input coordinate delta (dim numbers) 182 - out - The input coordinate point (dim numbers) 183 184 Output Parameter: 185 . out - The localized coordinate in + out 186 187 Level: developer 188 189 Note: 190 This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually one of the vertices on a containing cell 191 192 .seealso: `DM`, `DMLocalizeCoordinates()`, `DMLocalizeCoordinate()` 193 */ 194 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 195 { 196 PetscInt d; 197 198 PetscFunctionBegin; 199 if (!dm->maxCell) { 200 for (d = 0; d < dim; ++d) out[d] += in[d]; 201 } else { 202 for (d = 0; d < dim; ++d) { 203 const PetscReal maxC = dm->maxCell[d]; 204 205 if ((dm->L[d] > 0.0) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) { 206 const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 207 208 if (PetscAbsScalar(newCoord - anchor[d]) > maxC) 209 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT "-Coordinate %g more than %g away from anchor %g", d, (double)PetscRealPart(in[d]), (double)maxC, (double)PetscRealPart(anchor[d])); 210 out[d] += newCoord; 211 } else { 212 out[d] += in[d]; 213 } 214 } 215 } 216 PetscFunctionReturn(PETSC_SUCCESS); 217 } 218 219 /*@ 220 DMGetCoordinatesLocalizedLocal - Check if the `DM` coordinates have been localized for cells on this process 221 222 Not Collective 223 224 Input Parameter: 225 . dm - The `DM` 226 227 Output Parameter: 228 . areLocalized - `PETSC_TRUE` if localized 229 230 Level: developer 231 232 .seealso: `DM`, `DMLocalizeCoordinates()`, `DMGetCoordinatesLocalized()`, `DMSetPeriodicity()` 233 @*/ 234 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm, PetscBool *areLocalized) 235 { 236 PetscFunctionBegin; 237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 238 PetscAssertPointer(areLocalized, 2); 239 *areLocalized = dm->coordinates[1].dim < 0 ? PETSC_FALSE : PETSC_TRUE; 240 PetscFunctionReturn(PETSC_SUCCESS); 241 } 242 243 /*@ 244 DMGetCoordinatesLocalized - Check if the `DM` coordinates have been localized for cells 245 246 Collective 247 248 Input Parameter: 249 . dm - The `DM` 250 251 Output Parameter: 252 . areLocalized - `PETSC_TRUE` if localized 253 254 Level: developer 255 256 .seealso: `DM`, `DMLocalizeCoordinates()`, `DMSetPeriodicity()`, `DMGetCoordinatesLocalizedLocal()` 257 @*/ 258 PetscErrorCode DMGetCoordinatesLocalized(DM dm, PetscBool *areLocalized) 259 { 260 PetscBool localized; 261 262 PetscFunctionBegin; 263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 264 PetscAssertPointer(areLocalized, 2); 265 PetscCall(DMGetCoordinatesLocalizedLocal(dm, &localized)); 266 PetscCall(MPIU_Allreduce(&localized, areLocalized, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 267 PetscFunctionReturn(PETSC_SUCCESS); 268 } 269 270 /*@ 271 DMGetSparseLocalize - Check if the `DM` coordinates should be localized only for cells near the periodic boundary. 272 273 Not collective 274 275 Input Parameter: 276 . dm - The `DM` 277 278 Output Parameter: 279 . sparse - `PETSC_TRUE` if ony cells near the periodic boundary are localized 280 281 Level: intermediate 282 283 .seealso: `DMSetSparseLocalize()`, `DMLocalizeCoordinates()`, `DMSetPeriodicity()` 284 @*/ 285 PetscErrorCode DMGetSparseLocalize(DM dm, PetscBool *sparse) 286 { 287 PetscFunctionBegin; 288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 289 PetscAssertPointer(sparse, 2); 290 *sparse = dm->sparseLocalize; 291 PetscFunctionReturn(PETSC_SUCCESS); 292 } 293 294 /*@ 295 DMSetSparseLocalize - Set the flag indicating that `DM` coordinates should be localized only for cells near the periodic boundary. 296 297 Logically collective 298 299 Input Parameters: 300 + dm - The `DM` 301 - sparse - `PETSC_TRUE` if ony cells near the periodic boundary are localized 302 303 Level: intermediate 304 305 .seealso: `DMGetSparseLocalize()`, `DMLocalizeCoordinates()`, `DMSetPeriodicity()` 306 @*/ 307 PetscErrorCode DMSetSparseLocalize(DM dm, PetscBool sparse) 308 { 309 PetscFunctionBegin; 310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 311 PetscValidLogicalCollectiveBool(dm, sparse, 2); 312 dm->sparseLocalize = sparse; 313 PetscFunctionReturn(PETSC_SUCCESS); 314 } 315 316 /*@ 317 DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces 318 319 Collective 320 321 Input Parameter: 322 . dm - The `DM` 323 324 Level: developer 325 326 .seealso: `DM`, `DMSetPeriodicity()`, `DMLocalizeCoordinate()`, `DMLocalizeAddCoordinate()` 327 @*/ 328 PetscErrorCode DMLocalizeCoordinates(DM dm) 329 { 330 DM cdm, cdgdm, cplex, plex; 331 PetscSection cs, csDG; 332 Vec coordinates, cVec; 333 PetscScalar *coordsDG, *anchor, *localized; 334 const PetscReal *Lstart, *L; 335 PetscInt Nc, vStart, vEnd, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, bs, coordSize; 336 PetscBool isLocalized, sparseLocalize, useDG = PETSC_FALSE, useDGGlobal; 337 PetscInt maxHeight = 0, h; 338 PetscInt *pStart = NULL, *pEnd = NULL; 339 MPI_Comm comm; 340 341 PetscFunctionBegin; 342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 343 PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L)); 344 PetscCall(DMGetSparseLocalize(dm, &sparseLocalize)); 345 /* Cannot automatically localize without L and maxCell right now */ 346 if (!L) PetscFunctionReturn(PETSC_SUCCESS); 347 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 348 PetscCall(DMGetCoordinatesLocalized(dm, &isLocalized)); 349 if (isLocalized) PetscFunctionReturn(PETSC_SUCCESS); 350 351 PetscCall(DMGetCoordinateDM(dm, &cdm)); 352 PetscCall(DMConvert(dm, DMPLEX, &plex)); 353 PetscCall(DMConvert(cdm, DMPLEX, &cplex)); 354 if (cplex) { 355 PetscCall(DMPlexGetDepthStratum(cplex, 0, &vStart, &vEnd)); 356 PetscCall(DMPlexGetMaxProjectionHeight(cplex, &maxHeight)); 357 PetscCall(DMGetWorkArray(dm, 2 * (maxHeight + 1), MPIU_INT, &pStart)); 358 pEnd = &pStart[maxHeight + 1]; 359 newStart = vStart; 360 newEnd = vEnd; 361 for (h = 0; h <= maxHeight; h++) { 362 PetscCall(DMPlexGetHeightStratum(cplex, h, &pStart[h], &pEnd[h])); 363 newStart = PetscMin(newStart, pStart[h]); 364 newEnd = PetscMax(newEnd, pEnd[h]); 365 } 366 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM"); 367 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 368 PetscCheck(coordinates, comm, PETSC_ERR_SUP, "Missing local coordinate vector"); 369 PetscCall(DMGetCoordinateSection(dm, &cs)); 370 PetscCall(VecGetBlockSize(coordinates, &bs)); 371 PetscCall(PetscSectionGetChart(cs, &sStart, &sEnd)); 372 373 PetscCall(PetscSectionCreate(comm, &csDG)); 374 PetscCall(PetscSectionSetNumFields(csDG, 1)); 375 PetscCall(PetscSectionGetFieldComponents(cs, 0, &Nc)); 376 PetscCall(PetscSectionSetFieldComponents(csDG, 0, Nc)); 377 PetscCall(PetscSectionSetChart(csDG, newStart, newEnd)); 378 PetscCheck(bs == Nc, comm, PETSC_ERR_ARG_INCOMP, "Coordinate block size %" PetscInt_FMT " != %" PetscInt_FMT " number of components", bs, Nc); 379 380 PetscCall(DMGetWorkArray(dm, 2 * Nc, MPIU_SCALAR, &anchor)); 381 localized = &anchor[Nc]; 382 for (h = 0; h <= maxHeight; h++) { 383 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 384 385 for (c = cStart; c < cEnd; ++c) { 386 PetscScalar *cellCoords = NULL; 387 DMPolytopeType ct; 388 PetscInt dof, d, p; 389 390 PetscCall(DMPlexGetCellType(plex, c, &ct)); 391 if (ct == DM_POLYTOPE_FV_GHOST) continue; 392 PetscCall(DMPlexVecGetClosure(cplex, cs, coordinates, c, &dof, &cellCoords)); 393 PetscCheck(!(dof % Nc), comm, PETSC_ERR_ARG_INCOMP, "Coordinate size on cell %" PetscInt_FMT " closure %" PetscInt_FMT " not divisible by %" PetscInt_FMT " number of components", c, dof, Nc); 394 for (d = 0; d < Nc; ++d) anchor[d] = cellCoords[d]; 395 for (p = 0; p < dof / Nc; ++p) { 396 PetscCall(DMLocalizeCoordinate_Internal(dm, Nc, anchor, &cellCoords[p * Nc], localized)); 397 for (d = 0; d < Nc; ++d) 398 if (cellCoords[p * Nc + d] != localized[d]) break; 399 if (d < Nc) break; 400 } 401 if (p < dof / Nc) useDG = PETSC_TRUE; 402 if (p < dof / Nc || !sparseLocalize) { 403 PetscCall(PetscSectionSetDof(csDG, c, dof)); 404 PetscCall(PetscSectionSetFieldDof(csDG, c, 0, dof)); 405 } 406 PetscCall(DMPlexVecRestoreClosure(cplex, cs, coordinates, c, &dof, &cellCoords)); 407 } 408 } 409 PetscCall(MPIU_Allreduce(&useDG, &useDGGlobal, 1, MPIU_BOOL, MPI_LOR, comm)); 410 if (!useDGGlobal) goto end; 411 412 PetscCall(PetscSectionSetUp(csDG)); 413 PetscCall(PetscSectionGetStorageSize(csDG, &coordSize)); 414 PetscCall(VecCreate(PETSC_COMM_SELF, &cVec)); 415 PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates")); 416 PetscCall(VecSetBlockSize(cVec, bs)); 417 PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE)); 418 PetscCall(VecSetType(cVec, VECSTANDARD)); 419 PetscCall(VecGetArray(cVec, &coordsDG)); 420 for (h = 0; h <= maxHeight; h++) { 421 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 422 423 for (c = cStart; c < cEnd; ++c) { 424 PetscScalar *cellCoords = NULL; 425 PetscInt p = 0, q, dof, cdof, d, offDG; 426 427 PetscCall(PetscSectionGetDof(csDG, c, &cdof)); 428 if (!cdof) continue; 429 PetscCall(DMPlexVecGetClosure(cplex, cs, coordinates, c, &dof, &cellCoords)); 430 PetscCall(PetscSectionGetOffset(csDG, c, &offDG)); 431 // TODO The coordinates are set in closure order, which might not be the tensor order 432 for (q = 0; q < dof / Nc; ++q) { 433 // Select a trial anchor 434 for (d = 0; d < Nc; ++d) anchor[d] = cellCoords[q * Nc + d]; 435 for (p = 0; p < dof / Nc; ++p) { 436 PetscCall(DMLocalizeCoordinate_Internal(dm, Nc, anchor, &cellCoords[p * Nc], &coordsDG[offDG + p * Nc])); 437 // We need the cell to fit into the torus [lower, lower+L) 438 for (d = 0; d < Nc; ++d) 439 if (L[d] > 0. && ((PetscRealPart(coordsDG[offDG + p * Nc + d]) < (Lstart ? Lstart[d] : 0.)) || (PetscRealPart(coordsDG[offDG + p * Nc + d]) > (Lstart ? Lstart[d] : 0.) + L[d]))) break; 440 if (d < Nc) break; 441 } 442 if (p == dof / Nc) break; 443 } 444 PetscCheck(p == dof / Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " does not fit into the torus %s[0, L]", c, Lstart ? "Lstart + " : ""); 445 PetscCall(DMPlexVecRestoreClosure(cplex, cs, coordinates, c, &dof, &cellCoords)); 446 } 447 } 448 PetscCall(VecRestoreArray(cVec, &coordsDG)); 449 PetscCall(DMClone(cdm, &cdgdm)); 450 PetscCall(DMSetCellCoordinateDM(dm, cdgdm)); 451 PetscCall(DMSetCellCoordinateSection(dm, PETSC_DETERMINE, csDG)); 452 PetscCall(DMSetCellCoordinatesLocal(dm, cVec)); 453 PetscCall(VecDestroy(&cVec)); 454 // Convert the discretization 455 { 456 PetscFE fe, dgfe; 457 PetscSpace P; 458 PetscDualSpace Q, dgQ; 459 PetscQuadrature q, fq; 460 PetscClassId id; 461 462 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 463 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 464 if (id == PETSCFE_CLASSID) { 465 PetscCall(PetscFEGetBasisSpace(fe, &P)); 466 PetscCall(PetscObjectReference((PetscObject)P)); 467 PetscCall(PetscFEGetDualSpace(fe, &Q)); 468 PetscCall(PetscDualSpaceDuplicate(Q, &dgQ)); 469 PetscCall(PetscDualSpaceLagrangeSetContinuity(dgQ, PETSC_FALSE)); 470 PetscCall(PetscDualSpaceSetUp(dgQ)); 471 PetscCall(PetscFEGetQuadrature(fe, &q)); 472 PetscCall(PetscObjectReference((PetscObject)q)); 473 PetscCall(PetscFEGetFaceQuadrature(fe, &fq)); 474 PetscCall(PetscObjectReference((PetscObject)fq)); 475 PetscCall(PetscFECreateFromSpaces(P, dgQ, q, fq, &dgfe)); 476 PetscCall(DMSetField(cdgdm, 0, NULL, (PetscObject)dgfe)); 477 PetscCall(PetscFEDestroy(&dgfe)); 478 PetscCall(DMCreateDS(cdgdm)); 479 } 480 } 481 PetscCall(DMDestroy(&cdgdm)); 482 483 end: 484 PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 485 PetscCall(DMRestoreWorkArray(dm, 2 * (maxHeight + 1), MPIU_INT, &pStart)); 486 PetscCall(PetscSectionDestroy(&csDG)); 487 PetscCall(DMDestroy(&plex)); 488 PetscCall(DMDestroy(&cplex)); 489 PetscFunctionReturn(PETSC_SUCCESS); 490 } 491