1 #include <petsc/private/dmforestimpl.h> /*I "petscdmforest.h" I*/ 2 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/ 3 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/ 4 #include <petscsf.h> 5 6 PetscBool DMForestPackageInitialized = PETSC_FALSE; 7 8 typedef struct _DMForestTypeLink *DMForestTypeLink; 9 10 struct _DMForestTypeLink { 11 char *name; 12 DMForestTypeLink next; 13 }; 14 15 DMForestTypeLink DMForestTypeList; 16 17 static PetscErrorCode DMForestPackageFinalize(void) 18 { 19 DMForestTypeLink oldLink, link = DMForestTypeList; 20 21 PetscFunctionBegin; 22 while (link) { 23 oldLink = link; 24 PetscCall(PetscFree(oldLink->name)); 25 link = oldLink->next; 26 PetscCall(PetscFree(oldLink)); 27 } 28 PetscFunctionReturn(PETSC_SUCCESS); 29 } 30 31 static PetscErrorCode DMForestPackageInitialize(void) 32 { 33 PetscFunctionBegin; 34 if (DMForestPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS); 35 DMForestPackageInitialized = PETSC_TRUE; 36 37 PetscCall(DMForestRegisterType(DMFOREST)); 38 PetscCall(PetscRegisterFinalize(DMForestPackageFinalize)); 39 PetscFunctionReturn(PETSC_SUCCESS); 40 } 41 42 /*@C 43 DMForestRegisterType - Registers a `DMType` as a subtype of `DMFOREST` (so that `DMIsForest()` will be correct) 44 45 Not Collective 46 47 Input Parameter: 48 . name - the name of the type 49 50 Level: advanced 51 52 .seealso: `DMFOREST`, `DMIsForest()` 53 @*/ 54 PetscErrorCode DMForestRegisterType(DMType name) 55 { 56 DMForestTypeLink link; 57 58 PetscFunctionBegin; 59 PetscCall(DMForestPackageInitialize()); 60 PetscCall(PetscNew(&link)); 61 PetscCall(PetscStrallocpy(name, &link->name)); 62 link->next = DMForestTypeList; 63 DMForestTypeList = link; 64 PetscFunctionReturn(PETSC_SUCCESS); 65 } 66 67 /*@ 68 DMIsForest - Check whether a DM uses the DMFOREST interface for hierarchically-refined meshes 69 70 Not Collective 71 72 Input Parameter: 73 . dm - the DM object 74 75 Output Parameter: 76 . isForest - whether dm is a subtype of DMFOREST 77 78 Level: intermediate 79 80 .seealso: `DMFOREST`, `DMForestRegisterType()` 81 @*/ 82 PetscErrorCode DMIsForest(DM dm, PetscBool *isForest) 83 { 84 DMForestTypeLink link = DMForestTypeList; 85 86 PetscFunctionBegin; 87 while (link) { 88 PetscBool sameType; 89 PetscCall(PetscObjectTypeCompare((PetscObject)dm, link->name, &sameType)); 90 if (sameType) { 91 *isForest = PETSC_TRUE; 92 PetscFunctionReturn(PETSC_SUCCESS); 93 } 94 link = link->next; 95 } 96 *isForest = PETSC_FALSE; 97 PetscFunctionReturn(PETSC_SUCCESS); 98 } 99 100 /*@ 101 DMForestTemplate - Create a new `DM` that will be adapted from a source `DM`. 102 103 Collective 104 105 Input Parameters: 106 + dm - the source `DM` object 107 - comm - the communicator for the new `DM` (this communicator is currently ignored, but is present so that `DMForestTemplate()` can be used within `DMCoarsen()`) 108 109 Output Parameter: 110 . tdm - the new `DM` object 111 112 Level: intermediate 113 114 Notes: 115 The new `DM` reproduces the configuration of the source, but is not yet setup, so that the 116 user can then define only the ways that the new `DM` should differ (by, e.g., refinement or 117 repartitioning). The source `DM` is also set as the adaptivity source `DM` of the new `DM` 118 (see `DMForestSetAdaptivityForest()`). 119 120 .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()` 121 @*/ 122 PetscErrorCode DMForestTemplate(DM dm, MPI_Comm comm, DM *tdm) 123 { 124 DM_Forest *forest = (DM_Forest *)dm->data; 125 DMType type; 126 DM base; 127 DMForestTopology topology; 128 MatType mtype; 129 PetscInt dim, overlap, ref, factor; 130 DMForestAdaptivityStrategy strat; 131 void *ctx; 132 PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *); 133 void *mapCtx; 134 135 PetscFunctionBegin; 136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 137 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), tdm)); 138 PetscCall(DMGetType(dm, &type)); 139 PetscCall(DMSetType(*tdm, type)); 140 PetscCall(DMForestGetBaseDM(dm, &base)); 141 PetscCall(DMForestSetBaseDM(*tdm, base)); 142 PetscCall(DMForestGetTopology(dm, &topology)); 143 PetscCall(DMForestSetTopology(*tdm, topology)); 144 PetscCall(DMForestGetAdjacencyDimension(dm, &dim)); 145 PetscCall(DMForestSetAdjacencyDimension(*tdm, dim)); 146 PetscCall(DMForestGetPartitionOverlap(dm, &overlap)); 147 PetscCall(DMForestSetPartitionOverlap(*tdm, overlap)); 148 PetscCall(DMForestGetMinimumRefinement(dm, &ref)); 149 PetscCall(DMForestSetMinimumRefinement(*tdm, ref)); 150 PetscCall(DMForestGetMaximumRefinement(dm, &ref)); 151 PetscCall(DMForestSetMaximumRefinement(*tdm, ref)); 152 PetscCall(DMForestGetAdaptivityStrategy(dm, &strat)); 153 PetscCall(DMForestSetAdaptivityStrategy(*tdm, strat)); 154 PetscCall(DMForestGetGradeFactor(dm, &factor)); 155 PetscCall(DMForestSetGradeFactor(*tdm, factor)); 156 PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx)); 157 PetscCall(DMForestSetBaseCoordinateMapping(*tdm, map, mapCtx)); 158 if (forest->ftemplate) PetscCall((*forest->ftemplate)(dm, *tdm)); 159 PetscCall(DMForestSetAdaptivityForest(*tdm, dm)); 160 PetscCall(DMCopyDisc(dm, *tdm)); 161 PetscCall(DMGetApplicationContext(dm, &ctx)); 162 PetscCall(DMSetApplicationContext(*tdm, &ctx)); 163 { 164 const PetscReal *maxCell, *L, *Lstart; 165 166 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 167 PetscCall(DMSetPeriodicity(*tdm, maxCell, Lstart, L)); 168 } 169 PetscCall(DMGetMatType(dm, &mtype)); 170 PetscCall(DMSetMatType(*tdm, mtype)); 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 static PetscErrorCode DMInitialize_Forest(DM dm); 175 176 PetscErrorCode DMClone_Forest(DM dm, DM *newdm) 177 { 178 DM_Forest *forest = (DM_Forest *)dm->data; 179 const char *type; 180 181 PetscFunctionBegin; 182 forest->refct++; 183 (*newdm)->data = forest; 184 PetscCall(PetscObjectGetType((PetscObject)dm, &type)); 185 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, type)); 186 PetscCall(DMInitialize_Forest(*newdm)); 187 PetscFunctionReturn(PETSC_SUCCESS); 188 } 189 190 static PetscErrorCode DMDestroy_Forest(DM dm) 191 { 192 DM_Forest *forest = (DM_Forest *)dm->data; 193 194 PetscFunctionBegin; 195 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_plex_p4est_C", NULL)); 196 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_p4est_plex_C", NULL)); 197 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_plex_p8est_C", NULL)); 198 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_p8est_plex_C", NULL)); 199 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 200 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 201 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 202 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 203 if (--forest->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 204 if (forest->destroy) PetscCall((*forest->destroy)(dm)); 205 PetscCall(PetscSFDestroy(&forest->cellSF)); 206 PetscCall(PetscSFDestroy(&forest->preCoarseToFine)); 207 PetscCall(PetscSFDestroy(&forest->coarseToPreFine)); 208 PetscCall(DMLabelDestroy(&forest->adaptLabel)); 209 PetscCall(PetscFree(forest->adaptStrategy)); 210 PetscCall(DMDestroy(&forest->base)); 211 PetscCall(DMDestroy(&forest->adapt)); 212 PetscCall(PetscFree(forest->topology)); 213 PetscCall(PetscFree(forest)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 /*@ 218 DMForestSetTopology - Set the topology of a `DMFOREST` during the pre-setup phase. The topology is a string (e.g. 219 "cube", "shell") and can be interpreted by subtypes of `DMFOREST`) to construct the base DM of a forest during 220 `DMSetUp()`. 221 222 Logically collectiv 223 224 Input Parameters: 225 + dm - the forest 226 - topology - the topology of the forest 227 228 Level: intermediate 229 230 .seealso: `DM`, `DMFOREST`, `DMForestGetTopology()`, `DMForestSetBaseDM()` 231 @*/ 232 PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology) 233 { 234 DM_Forest *forest = (DM_Forest *)dm->data; 235 236 PetscFunctionBegin; 237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 238 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the topology after setup"); 239 PetscCall(PetscFree(forest->topology)); 240 PetscCall(PetscStrallocpy((const char *)topology, (char **)&forest->topology)); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 /*@ 245 DMForestGetTopology - Get a string describing the topology of a `DMFOREST`. 246 247 Not Collective 248 249 Input Parameter: 250 . dm - the forest 251 252 Output Parameter: 253 . topology - the topology of the forest (e.g., 'cube', 'shell') 254 255 Level: intermediate 256 257 .seealso: `DM`, `DMFOREST`, `DMForestSetTopology()` 258 @*/ 259 PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology) 260 { 261 DM_Forest *forest = (DM_Forest *)dm->data; 262 263 PetscFunctionBegin; 264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 265 PetscAssertPointer(topology, 2); 266 *topology = forest->topology; 267 PetscFunctionReturn(PETSC_SUCCESS); 268 } 269 270 /*@ 271 DMForestSetBaseDM - During the pre-setup phase, set the `DM` that defines the base mesh of a 272 `DMFOREST` forest. 273 274 Logically Collective 275 276 Input Parameters: 277 + dm - the forest 278 - base - the base `DM` of the forest 279 280 Level: intermediate 281 282 Notes: 283 The forest will be hierarchically refined from the base, and all refinements/coarsenings of 284 the forest will share its base. In general, two forest must share a base to be comparable, 285 to do things like construct interpolators. 286 287 Currently the base `DM` must be a `DMPLEX` 288 289 .seealso: `DM`, `DMFOREST`, `DMForestGetBaseDM()` 290 @*/ 291 PetscErrorCode DMForestSetBaseDM(DM dm, DM base) 292 { 293 DM_Forest *forest = (DM_Forest *)dm->data; 294 PetscInt dim, dimEmbed; 295 296 PetscFunctionBegin; 297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 298 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the base after setup"); 299 PetscCall(PetscObjectReference((PetscObject)base)); 300 PetscCall(DMDestroy(&forest->base)); 301 forest->base = base; 302 if (base) { 303 const PetscReal *maxCell, *Lstart, *L; 304 305 PetscValidHeaderSpecific(base, DM_CLASSID, 2); 306 PetscCall(DMGetDimension(base, &dim)); 307 PetscCall(DMSetDimension(dm, dim)); 308 PetscCall(DMGetCoordinateDim(base, &dimEmbed)); 309 PetscCall(DMSetCoordinateDim(dm, dimEmbed)); 310 PetscCall(DMGetPeriodicity(base, &maxCell, &Lstart, &L)); 311 PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L)); 312 } else PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL)); 313 PetscFunctionReturn(PETSC_SUCCESS); 314 } 315 316 /*@ 317 DMForestGetBaseDM - Get the base `DM` of a `DMFOREST` 318 319 Not Collective 320 321 Input Parameter: 322 . dm - the forest 323 324 Output Parameter: 325 . base - the base `DM` of the forest 326 327 Level: intermediate 328 329 Notes: 330 After DMSetUp(), the base DM will be redundantly distributed across MPI processes 331 332 The forest will be hierarchically refined from the base, and all refinements/coarsenings of 333 the forest will share its base. In general, two forest must share a base to be comparable, 334 to do things like construct interpolators. 335 336 .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()` 337 @*/ 338 PetscErrorCode DMForestGetBaseDM(DM dm, DM *base) 339 { 340 DM_Forest *forest = (DM_Forest *)dm->data; 341 342 PetscFunctionBegin; 343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 344 PetscAssertPointer(base, 2); 345 *base = forest->base; 346 PetscFunctionReturn(PETSC_SUCCESS); 347 } 348 349 PetscErrorCode DMForestSetBaseCoordinateMapping(DM dm, PetscErrorCode (*func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx) 350 { 351 DM_Forest *forest = (DM_Forest *)dm->data; 352 353 PetscFunctionBegin; 354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 355 forest->mapcoordinates = func; 356 forest->mapcoordinatesctx = ctx; 357 PetscFunctionReturn(PETSC_SUCCESS); 358 } 359 360 PetscErrorCode DMForestGetBaseCoordinateMapping(DM dm, PetscErrorCode (**func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx) 361 { 362 DM_Forest *forest = (DM_Forest *)dm->data; 363 364 PetscFunctionBegin; 365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 366 if (func) *func = forest->mapcoordinates; 367 if (ctx) *((void **)ctx) = forest->mapcoordinatesctx; 368 PetscFunctionReturn(PETSC_SUCCESS); 369 } 370 371 /*@ 372 DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the 373 current forest will be adapted (e.g., the current forest will be 374 refined/coarsened/repartitioned from it) in `DMSetUp()`. 375 376 Logically Collective 377 378 Input Parameters: 379 + dm - the new forest, which will be constructed from adapt 380 - adapt - the old forest 381 382 Level: intermediate 383 384 Note: 385 Usually not needed by users directly, `DMForestTemplate()` constructs a new forest to be 386 adapted from an old forest and calls this routine. 387 388 This can be called after setup with `adapt` = `NULL`, which will clear all internal data 389 related to the adaptivity forest from `dm`. This way, repeatedly adapting does not leave 390 stale `DM` objects in memory. 391 392 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()` 393 @*/ 394 PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt) 395 { 396 DM_Forest *forest, *adaptForest, *oldAdaptForest; 397 DM oldAdapt; 398 PetscBool isForest; 399 400 PetscFunctionBegin; 401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 402 if (adapt) PetscValidHeaderSpecific(adapt, DM_CLASSID, 2); 403 PetscCall(DMIsForest(dm, &isForest)); 404 if (!isForest) PetscFunctionReturn(PETSC_SUCCESS); 405 PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup"); 406 forest = (DM_Forest *)dm->data; 407 PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt)); 408 adaptForest = (DM_Forest *)(adapt ? adapt->data : NULL); 409 oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL); 410 if (adaptForest != oldAdaptForest) { 411 PetscCall(PetscSFDestroy(&forest->preCoarseToFine)); 412 PetscCall(PetscSFDestroy(&forest->coarseToPreFine)); 413 if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm)); 414 } 415 switch (forest->adaptPurpose) { 416 case DM_ADAPT_DETERMINE: 417 PetscCall(PetscObjectReference((PetscObject)adapt)); 418 PetscCall(DMDestroy(&forest->adapt)); 419 forest->adapt = adapt; 420 break; 421 case DM_ADAPT_REFINE: 422 PetscCall(DMSetCoarseDM(dm, adapt)); 423 break; 424 case DM_ADAPT_COARSEN: 425 case DM_ADAPT_COARSEN_LAST: 426 PetscCall(DMSetFineDM(dm, adapt)); 427 break; 428 default: 429 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose"); 430 } 431 PetscFunctionReturn(PETSC_SUCCESS); 432 } 433 434 /*@ 435 DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted. 436 437 Not Collective 438 439 Input Parameter: 440 . dm - the forest 441 442 Output Parameter: 443 . adapt - the forest from which `dm` is/was adapted 444 445 Level: intermediate 446 447 .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()` 448 @*/ 449 PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt) 450 { 451 DM_Forest *forest; 452 453 PetscFunctionBegin; 454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 455 forest = (DM_Forest *)dm->data; 456 switch (forest->adaptPurpose) { 457 case DM_ADAPT_DETERMINE: 458 *adapt = forest->adapt; 459 break; 460 case DM_ADAPT_REFINE: 461 PetscCall(DMGetCoarseDM(dm, adapt)); 462 break; 463 case DM_ADAPT_COARSEN: 464 case DM_ADAPT_COARSEN_LAST: 465 PetscCall(DMGetFineDM(dm, adapt)); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose"); 469 } 470 PetscFunctionReturn(PETSC_SUCCESS); 471 } 472 473 /*@ 474 DMForestSetAdaptivityPurpose - During the pre-setup phase, set whether the current `DM` is being adapted from its 475 source (set with `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening 476 (`DM_ADAPT_COARSEN`), or undefined (`DM_ADAPT_DETERMINE`). 477 478 Logically Collective 479 480 Input Parameters: 481 + dm - the forest 482 - purpose - the adaptivity purpose 483 484 Level: advanced 485 486 Notes: 487 This only matters for reference counting during `DMDestroy()`. Cyclic references 488 can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship 489 (see `DMSetFineDM()`/`DMSetCoarseDM()`). If the purpose is not refinement or coarsening, and 490 the user does not maintain a reference to the post-adaptation forest (i.e., the one created 491 by `DMForestTemplate()`), this can cause a memory leak. This method is used by subtypes 492 of `DMFOREST` when automatically constructing mesh hierarchies. 493 494 .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag` 495 @*/ 496 PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose) 497 { 498 DM_Forest *forest; 499 500 PetscFunctionBegin; 501 forest = (DM_Forest *)dm->data; 502 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup"); 503 if (purpose != forest->adaptPurpose) { 504 DM adapt; 505 506 PetscCall(DMForestGetAdaptivityForest(dm, &adapt)); 507 PetscCall(PetscObjectReference((PetscObject)adapt)); 508 PetscCall(DMForestSetAdaptivityForest(dm, NULL)); 509 510 forest->adaptPurpose = purpose; 511 512 PetscCall(DMForestSetAdaptivityForest(dm, adapt)); 513 PetscCall(DMDestroy(&adapt)); 514 } 515 PetscFunctionReturn(PETSC_SUCCESS); 516 } 517 518 /*@ 519 DMForestGetAdaptivityPurpose - Get whether the current `DM` is being adapted from its source (set with 520 `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening (`DM_ADAPT_COARSEN`), 521 coarsening only the last level (`DM_ADAPT_COARSEN_LAST`) or undefined (`DM_ADAPT_DETERMINE`). 522 523 Not Collective 524 525 Input Parameter: 526 . dm - the forest 527 528 Output Parameter: 529 . purpose - the adaptivity purpose 530 531 Level: advanced 532 533 Notes: 534 This only matters for reference counting: during `DMDestroy()`. Cyclic references 535 can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship 536 (See `DMSetFineDM()`/`DMSetCoarseDM()`). If the purpose is not refinement or coarsening, and 537 the user does not maintain a reference to the post-adaptation forest (i.e., the one created 538 by `DMForestTemplate()`), this can cause a memory leak. This method is used by subtypes 539 of `DMFOREST` when automatically constructing mesh hierarchies. 540 541 .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag` 542 @*/ 543 PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose) 544 { 545 DM_Forest *forest; 546 547 PetscFunctionBegin; 548 forest = (DM_Forest *)dm->data; 549 *purpose = forest->adaptPurpose; 550 PetscFunctionReturn(PETSC_SUCCESS); 551 } 552 553 /*@ 554 DMForestSetAdjacencyDimension - During the pre-setup phase, set the dimension of interface points that determine 555 cell adjacency (for the purposes of partitioning and overlap). 556 557 Logically Collective 558 559 Input Parameters: 560 + dm - the forest 561 - adjDim - default 0 (i.e., vertices determine adjacency) 562 563 Level: intermediate 564 565 .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()` 566 @*/ 567 PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim) 568 { 569 PetscInt dim; 570 DM_Forest *forest = (DM_Forest *)dm->data; 571 572 PetscFunctionBegin; 573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 574 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup"); 575 PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim); 576 PetscCall(DMGetDimension(dm, &dim)); 577 PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim); 578 forest->adjDim = adjDim; 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 /*@ 583 DMForestSetAdjacencyCodimension - Like `DMForestSetAdjacencyDimension()`, but specified as a co-dimension (so that, 584 e.g., adjacency based on facets can be specified by codimension 1 in all cases) 585 586 Logically Collective 587 588 Input Parameters: 589 + dm - the forest 590 - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices 591 592 Level: intermediate 593 594 .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()` 595 @*/ 596 PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim) 597 { 598 PetscInt dim; 599 600 PetscFunctionBegin; 601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 602 PetscCall(DMGetDimension(dm, &dim)); 603 PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim)); 604 PetscFunctionReturn(PETSC_SUCCESS); 605 } 606 607 /*@ 608 DMForestGetAdjacencyDimension - Get the dimension of interface points that determine cell adjacency (for the 609 purposes of partitioning and overlap). 610 611 Not Collective 612 613 Input Parameter: 614 . dm - the forest 615 616 Output Parameter: 617 . adjDim - default 0 (i.e., vertices determine adjacency) 618 619 Level: intermediate 620 621 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()` 622 @*/ 623 PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim) 624 { 625 DM_Forest *forest = (DM_Forest *)dm->data; 626 627 PetscFunctionBegin; 628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 629 PetscAssertPointer(adjDim, 2); 630 *adjDim = forest->adjDim; 631 PetscFunctionReturn(PETSC_SUCCESS); 632 } 633 634 /*@ 635 DMForestGetAdjacencyCodimension - Like `DMForestGetAdjacencyDimension()`, but specified as a co-dimension (so that, 636 e.g., adjacency based on facets can be specified by codimension 1 in all cases) 637 638 Not Collective 639 640 Input Parameter: 641 . dm - the forest 642 643 Output Parameter: 644 . adjCodim - default isthe dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices 645 646 Level: intermediate 647 648 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()` 649 @*/ 650 PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim) 651 { 652 DM_Forest *forest = (DM_Forest *)dm->data; 653 PetscInt dim; 654 655 PetscFunctionBegin; 656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 657 PetscAssertPointer(adjCodim, 2); 658 PetscCall(DMGetDimension(dm, &dim)); 659 *adjCodim = dim - forest->adjDim; 660 PetscFunctionReturn(PETSC_SUCCESS); 661 } 662 663 /*@ 664 DMForestSetPartitionOverlap - During the pre-setup phase, set the amount of cell-overlap present in parallel 665 partitions of a forest, with values > 0 indicating subdomains that are expanded by that many iterations of adding 666 adjacent cells 667 668 Logically Collective 669 670 Input Parameters: 671 + dm - the forest 672 - overlap - default 0 673 674 Level: intermediate 675 676 .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()` 677 @*/ 678 PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap) 679 { 680 DM_Forest *forest = (DM_Forest *)dm->data; 681 682 PetscFunctionBegin; 683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 684 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup"); 685 PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap); 686 forest->overlap = overlap; 687 PetscFunctionReturn(PETSC_SUCCESS); 688 } 689 690 /*@ 691 DMForestGetPartitionOverlap - Get the amount of cell-overlap present in parallel partitions of a forest, with values 692 > 0 indicating subdomains that are expanded by that many iterations of adding adjacent cells 693 694 Not Collective 695 696 Input Parameter: 697 . dm - the forest 698 699 Output Parameter: 700 . overlap - default 0 701 702 Level: intermediate 703 704 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()` 705 @*/ 706 PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap) 707 { 708 DM_Forest *forest = (DM_Forest *)dm->data; 709 710 PetscFunctionBegin; 711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 712 PetscAssertPointer(overlap, 2); 713 *overlap = forest->overlap; 714 PetscFunctionReturn(PETSC_SUCCESS); 715 } 716 717 /*@ 718 DMForestSetMinimumRefinement - During the pre-setup phase, set the minimum level of refinement (relative to the base 719 `DM`, see `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by coarsening a previous forest 720 (see `DMForestGetAdaptivityForest()`) this limits the amount of coarsening. 721 722 Logically Collective 723 724 Input Parameters: 725 + dm - the forest 726 - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 727 728 Level: intermediate 729 730 .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()` 731 @*/ 732 PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement) 733 { 734 DM_Forest *forest = (DM_Forest *)dm->data; 735 736 PetscFunctionBegin; 737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 738 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the minimum refinement after setup"); 739 forest->minRefinement = minRefinement; 740 PetscFunctionReturn(PETSC_SUCCESS); 741 } 742 743 /*@ 744 DMForestGetMinimumRefinement - Get the minimum level of refinement (relative to the base `DM`, see 745 `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by coarsening a previous forest (see 746 `DMForestGetAdaptivityForest()`), this limits the amount of coarsening. 747 748 Not Collective 749 750 Input Parameter: 751 . dm - the forest 752 753 Output Parameter: 754 . minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 755 756 Level: intermediate 757 758 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()` 759 @*/ 760 PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement) 761 { 762 DM_Forest *forest = (DM_Forest *)dm->data; 763 764 PetscFunctionBegin; 765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 766 PetscAssertPointer(minRefinement, 2); 767 *minRefinement = forest->minRefinement; 768 PetscFunctionReturn(PETSC_SUCCESS); 769 } 770 771 /*@ 772 DMForestSetInitialRefinement - During the pre-setup phase, set the initial level of refinement (relative to the base 773 `DM`, see `DMForestGetBaseDM()`) allowed in the forest. 774 775 Logically Collective 776 777 Input Parameters: 778 + dm - the forest 779 - initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 780 781 Level: intermediate 782 783 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()` 784 @*/ 785 PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement) 786 { 787 DM_Forest *forest = (DM_Forest *)dm->data; 788 789 PetscFunctionBegin; 790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 791 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup"); 792 forest->initRefinement = initRefinement; 793 PetscFunctionReturn(PETSC_SUCCESS); 794 } 795 796 /*@ 797 DMForestGetInitialRefinement - Get the initial level of refinement (relative to the base `DM`, see 798 `DMForestGetBaseDM()`) allowed in the forest. 799 800 Not Collective 801 802 Input Parameter: 803 . dm - the forest 804 805 Output Parameter: 806 . initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 807 808 Level: intermediate 809 810 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()` 811 @*/ 812 PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement) 813 { 814 DM_Forest *forest = (DM_Forest *)dm->data; 815 816 PetscFunctionBegin; 817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 818 PetscAssertPointer(initRefinement, 2); 819 *initRefinement = forest->initRefinement; 820 PetscFunctionReturn(PETSC_SUCCESS); 821 } 822 823 /*@ 824 DMForestSetMaximumRefinement - During the pre-setup phase, set the maximum level of refinement (relative to the base 825 `DM`, see `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by refining a previous forest 826 (see `DMForestGetAdaptivityForest()`), this limits the amount of refinement. 827 828 Logically Collective 829 830 Input Parameters: 831 + dm - the forest 832 - maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 833 834 Level: intermediate 835 836 .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()` 837 @*/ 838 PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement) 839 { 840 DM_Forest *forest = (DM_Forest *)dm->data; 841 842 PetscFunctionBegin; 843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 844 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup"); 845 forest->maxRefinement = maxRefinement; 846 PetscFunctionReturn(PETSC_SUCCESS); 847 } 848 849 /*@ 850 DMForestGetMaximumRefinement - Get the maximum level of refinement (relative to the base `DM`, see 851 `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by refining a previous forest (see 852 `DMForestGetAdaptivityForest()`), this limits the amount of refinement. 853 854 Not Collective 855 856 Input Parameter: 857 . dm - the forest 858 859 Output Parameter: 860 . maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`) 861 862 Level: intermediate 863 864 .seealso: `DM`, `DMFOREST`, `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()` 865 @*/ 866 PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement) 867 { 868 DM_Forest *forest = (DM_Forest *)dm->data; 869 870 PetscFunctionBegin; 871 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 872 PetscAssertPointer(maxRefinement, 2); 873 *maxRefinement = forest->maxRefinement; 874 PetscFunctionReturn(PETSC_SUCCESS); 875 } 876 877 /*@ 878 DMForestSetAdaptivityStrategy - During the pre-setup phase, set the strategy for combining adaptivity labels from multiple processes. 879 880 Logically Collective 881 882 Input Parameters: 883 + dm - the forest 884 - adaptStrategy - default `DMFORESTADAPTALL` 885 886 Level: advanced 887 888 Notes: 889 Subtypes of `DMFOREST` may define their own strategies. Two default strategies are `DMFORESTADAPTALL`, which indicates that all processes must agree 890 for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only one process needs to 891 specify refinement/coarsening. 892 893 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY` 894 @*/ 895 PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy) 896 { 897 DM_Forest *forest = (DM_Forest *)dm->data; 898 899 PetscFunctionBegin; 900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 901 PetscCall(PetscFree(forest->adaptStrategy)); 902 PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy)); 903 PetscFunctionReturn(PETSC_SUCCESS); 904 } 905 906 /*@ 907 DMForestGetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes. 908 909 Not Collective 910 911 Input Parameter: 912 . dm - the forest 913 914 Output Parameter: 915 . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`) 916 917 Level: advanced 918 919 Note: 920 Subtypes 921 of `DMFOREST` may define their own strategies. Two default strategies are `DMFORESTADAPTALL`, which indicates that all 922 processes must agree for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only 923 one process needs to specify refinement/coarsening. 924 925 .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()` 926 @*/ 927 PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy) 928 { 929 DM_Forest *forest = (DM_Forest *)dm->data; 930 931 PetscFunctionBegin; 932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 933 PetscAssertPointer(adaptStrategy, 2); 934 *adaptStrategy = forest->adaptStrategy; 935 PetscFunctionReturn(PETSC_SUCCESS); 936 } 937 938 /*@ 939 DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning, 940 etc.) was successful. 941 942 Collective 943 944 Input Parameter: 945 . dm - the post-adaptation forest 946 947 Output Parameter: 948 . success - `PETSC_TRUE` if the post-adaptation forest is different from the pre-adaptation forest. 949 950 Level: intermediate 951 952 Notes: 953 `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adaptation 954 forest. A requested adaptation may have been unsuccessful if, for example, the requested refinement would have 955 exceeded the maximum refinement level. 956 957 .seealso: `DM`, `DMFOREST` 958 @*/ 959 PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success) 960 { 961 DM_Forest *forest; 962 963 PetscFunctionBegin; 964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 965 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet."); 966 forest = (DM_Forest *)dm->data; 967 PetscCall(forest->getadaptivitysuccess(dm, success)); 968 PetscFunctionReturn(PETSC_SUCCESS); 969 } 970 971 /*@ 972 DMForestSetComputeAdaptivitySF - During the pre-setup phase, set whether transfer `PetscSF`s should be computed 973 relating the cells of the pre-adaptation forest to the post-adaptiation forest. 974 975 Logically Collective 976 977 Input Parameters: 978 + dm - the post-adaptation forest 979 - computeSF - default `PETSC_TRUE` 980 981 Level: advanced 982 983 Note: 984 After `DMSetUp()` is called, the transfer `PetscSF`s can be accessed with `DMForestGetAdaptivitySF()`. 985 986 .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()` 987 @*/ 988 PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF) 989 { 990 DM_Forest *forest; 991 992 PetscFunctionBegin; 993 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 994 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called"); 995 forest = (DM_Forest *)dm->data; 996 forest->computeAdaptSF = computeSF; 997 PetscFunctionReturn(PETSC_SUCCESS); 998 } 999 1000 PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time) 1001 { 1002 DM_Forest *forest; 1003 1004 PetscFunctionBegin; 1005 PetscValidHeaderSpecific(dmIn, DM_CLASSID, 1); 1006 PetscValidHeaderSpecific(vecIn, VEC_CLASSID, 2); 1007 PetscValidHeaderSpecific(dmOut, DM_CLASSID, 3); 1008 PetscValidHeaderSpecific(vecOut, VEC_CLASSID, 4); 1009 forest = (DM_Forest *)dmIn->data; 1010 PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented"); 1011 PetscCall(forest->transfervec(dmIn, vecIn, dmOut, vecOut, useBCs, time)); 1012 PetscFunctionReturn(PETSC_SUCCESS); 1013 } 1014 1015 PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut) 1016 { 1017 DM_Forest *forest; 1018 1019 PetscFunctionBegin; 1020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1021 PetscValidHeaderSpecific(vecIn, VEC_CLASSID, 2); 1022 PetscValidHeaderSpecific(vecOut, VEC_CLASSID, 3); 1023 forest = (DM_Forest *)dm->data; 1024 PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented"); 1025 PetscCall(forest->transfervecfrombase(dm, vecIn, vecOut)); 1026 PetscFunctionReturn(PETSC_SUCCESS); 1027 } 1028 1029 /*@ 1030 DMForestGetComputeAdaptivitySF - Get whether transfer `PetscSF`s should be computed relating the cells of the 1031 pre-adaptation forest to the post-adaptiation forest. After `DMSetUp()` is called, these transfer PetscSFs can be 1032 accessed with `DMForestGetAdaptivitySF()`. 1033 1034 Not Collective 1035 1036 Input Parameter: 1037 . dm - the post-adaptation forest 1038 1039 Output Parameter: 1040 . computeSF - default `PETSC_TRUE` 1041 1042 Level: advanced 1043 1044 .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()` 1045 @*/ 1046 PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF) 1047 { 1048 DM_Forest *forest; 1049 1050 PetscFunctionBegin; 1051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1052 forest = (DM_Forest *)dm->data; 1053 *computeSF = forest->computeAdaptSF; 1054 PetscFunctionReturn(PETSC_SUCCESS); 1055 } 1056 1057 /*@ 1058 DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the 1059 post-adaptation forest. 1060 1061 Not Collective 1062 1063 Input Parameter: 1064 . dm - the post-adaptation forest 1065 1066 Output Parameters: 1067 + preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post- 1068 - coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre- 1069 1070 Level: advanced 1071 1072 Notes: 1073 Adaptation can be any combination of refinement, coarsening, repartition, and change of 1074 overlap, so there may be some cells of the pre-adaptation that are parents of post-adaptation 1075 cells, and vice versa. Therefore there are two `PetscSF`s: one that relates pre-adaptation 1076 coarse cells to post-adaptation fine cells, and one that relates pre-adaptation fine cells to 1077 post-adaptation coarse cells. 1078 1079 .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()` 1080 @*/ 1081 PetscErrorCode DMForestGetAdaptivitySF(DM dm, PeOp PetscSF *preCoarseToFine, PeOp PetscSF *coarseToPreFine) 1082 { 1083 DM_Forest *forest; 1084 1085 PetscFunctionBegin; 1086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1087 PetscCall(DMSetUp(dm)); 1088 forest = (DM_Forest *)dm->data; 1089 if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine; 1090 if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine; 1091 PetscFunctionReturn(PETSC_SUCCESS); 1092 } 1093 1094 /*@ 1095 DMForestSetGradeFactor - During the pre-setup phase, set the desired amount of grading in the 1096 mesh, e.g. give 2 to indicate that the diameter of neighboring cells should differ by at most 1097 a factor of 2. 1098 1099 Logically Collective 1100 1101 Input Parameters: 1102 + dm - the forest 1103 - grade - the grading factor 1104 1105 Level: advanced 1106 1107 Note: 1108 Subtypes of `DMFOREST` may only support one particular choice of grading factor. 1109 1110 .seealso: `DM`, `DMFOREST`, `DMForestGetGradeFactor()` 1111 @*/ 1112 PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade) 1113 { 1114 DM_Forest *forest = (DM_Forest *)dm->data; 1115 1116 PetscFunctionBegin; 1117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1118 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup"); 1119 forest->gradeFactor = grade; 1120 PetscFunctionReturn(PETSC_SUCCESS); 1121 } 1122 1123 /*@ 1124 DMForestGetGradeFactor - Get the desired amount of grading in the mesh, e.g. give 2 to indicate that the diameter of 1125 neighboring cells should differ by at most a factor of 2. Subtypes of `DMFOREST` may only support one particular 1126 choice of grading factor. 1127 1128 Not Collective 1129 1130 Input Parameter: 1131 . dm - the forest 1132 1133 Output Parameter: 1134 . grade - the grading factor 1135 1136 Level: advanced 1137 1138 .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()` 1139 @*/ 1140 PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade) 1141 { 1142 DM_Forest *forest = (DM_Forest *)dm->data; 1143 1144 PetscFunctionBegin; 1145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1146 PetscAssertPointer(grade, 2); 1147 *grade = forest->gradeFactor; 1148 PetscFunctionReturn(PETSC_SUCCESS); 1149 } 1150 1151 /*@ 1152 DMForestSetCellWeightFactor - During the pre-setup phase, set the factor by which the level of refinement changes 1153 the cell weight (see `DMForestSetCellWeights()`) when calculating partitions. 1154 1155 Logically Collective 1156 1157 Input Parameters: 1158 + dm - the forest 1159 - weightsFactor - default 1. 1160 1161 Level: advanced 1162 1163 Note: 1164 The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel). A factor 1165 of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for 1166 example, might be appropriate for sub-cycling time-stepping methods, when the computation 1167 associated with a cell is multiplied by a factor of 2 for each additional level of 1168 refinement. 1169 1170 .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()` 1171 @*/ 1172 PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor) 1173 { 1174 DM_Forest *forest = (DM_Forest *)dm->data; 1175 1176 PetscFunctionBegin; 1177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1178 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup"); 1179 forest->weightsFactor = weightsFactor; 1180 PetscFunctionReturn(PETSC_SUCCESS); 1181 } 1182 1183 /*@ 1184 DMForestGetCellWeightFactor - Get the factor by which the level of refinement changes the cell weight (see 1185 `DMForestSetCellWeights()`) when calculating partitions. 1186 1187 Not Collective 1188 1189 Input Parameter: 1190 . dm - the forest 1191 1192 Output Parameter: 1193 . weightsFactor - default 1. 1194 1195 Level: advanced 1196 1197 Note: 1198 The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel). A factor 1199 of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for 1200 example, might be appropriate for sub-cycling time-stepping methods, when the computation 1201 associated with a cell is multiplied by a factor of 2 for each additional level of 1202 refinement. 1203 1204 .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()` 1205 @*/ 1206 PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor) 1207 { 1208 DM_Forest *forest = (DM_Forest *)dm->data; 1209 1210 PetscFunctionBegin; 1211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1212 PetscAssertPointer(weightsFactor, 2); 1213 *weightsFactor = forest->weightsFactor; 1214 PetscFunctionReturn(PETSC_SUCCESS); 1215 } 1216 1217 /*@ 1218 DMForestGetCellChart - After the setup phase, get the local half-open interval of the chart of cells on this process 1219 1220 Not Collective 1221 1222 Input Parameter: 1223 . dm - the forest 1224 1225 Output Parameters: 1226 + cStart - the first cell on this process 1227 - cEnd - one after the final cell on this process 1228 1229 Level: intermediate 1230 1231 .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()` 1232 @*/ 1233 PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd) 1234 { 1235 DM_Forest *forest = (DM_Forest *)dm->data; 1236 1237 PetscFunctionBegin; 1238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1239 PetscAssertPointer(cStart, 2); 1240 PetscAssertPointer(cEnd, 3); 1241 if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd)); 1242 *cStart = forest->cStart; 1243 *cEnd = forest->cEnd; 1244 PetscFunctionReturn(PETSC_SUCCESS); 1245 } 1246 1247 /*@ 1248 DMForestGetCellSF - After the setup phase, get the `PetscSF` for overlapping cells between processes 1249 1250 Not Collective 1251 1252 Input Parameter: 1253 . dm - the forest 1254 1255 Output Parameter: 1256 . cellSF - the `PetscSF` 1257 1258 Level: intermediate 1259 1260 .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()` 1261 @*/ 1262 PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF) 1263 { 1264 DM_Forest *forest = (DM_Forest *)dm->data; 1265 1266 PetscFunctionBegin; 1267 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1268 PetscAssertPointer(cellSF, 2); 1269 if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF)); 1270 *cellSF = forest->cellSF; 1271 PetscFunctionReturn(PETSC_SUCCESS); 1272 } 1273 1274 /*@ 1275 DMForestSetAdaptivityLabel - During the pre-setup phase, set the label of the pre-adaptation forest (see 1276 `DMForestGetAdaptivityForest()`) that holds the adaptation flags (refinement, coarsening, or some combination). 1277 1278 Logically Collective 1279 1280 Input Parameters: 1281 + dm - the forest 1282 - adaptLabel - the label in the pre-adaptation forest 1283 1284 Level: intermediate 1285 1286 Note: 1287 The interpretation of the label values is up to the subtype of `DMFOREST`, but 1288 `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been 1289 reserved as choices that should be accepted by all subtypes. 1290 1291 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()` 1292 @*/ 1293 PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel) 1294 { 1295 DM_Forest *forest = (DM_Forest *)dm->data; 1296 1297 PetscFunctionBegin; 1298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1299 if (adaptLabel) PetscValidHeaderSpecific(adaptLabel, DMLABEL_CLASSID, 2); 1300 PetscCall(PetscObjectReference((PetscObject)adaptLabel)); 1301 PetscCall(DMLabelDestroy(&forest->adaptLabel)); 1302 forest->adaptLabel = adaptLabel; 1303 PetscFunctionReturn(PETSC_SUCCESS); 1304 } 1305 1306 /*@ 1307 DMForestGetAdaptivityLabel - Get the label of the pre-adaptation forest (see `DMForestGetAdaptivityForest()`) that 1308 holds the adaptation flags (refinement, coarsening, or some combination). 1309 1310 Not Collective 1311 1312 Input Parameter: 1313 . dm - the forest 1314 1315 Output Parameter: 1316 . adaptLabel - the name of the label in the pre-adaptation forest 1317 1318 Level: intermediate 1319 1320 Note: 1321 The interpretation of the label values is up to the subtype of `DMFOREST`, but 1322 `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been 1323 reserved as choices that should be accepted by all subtypes. 1324 1325 .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()` 1326 @*/ 1327 PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel) 1328 { 1329 DM_Forest *forest = (DM_Forest *)dm->data; 1330 1331 PetscFunctionBegin; 1332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1333 *adaptLabel = forest->adaptLabel; 1334 PetscFunctionReturn(PETSC_SUCCESS); 1335 } 1336 1337 /*@ 1338 DMForestSetCellWeights - Set the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current 1339 process: weights are used to determine parallel partitioning. 1340 1341 Logically Collective 1342 1343 Input Parameters: 1344 + dm - the forest 1345 . weights - the array of weights (see `DMForestSetWeightCapacity()`) for all cells, or `NULL` to indicate each cell has weight 1. 1346 - copyMode - how weights should reference weights 1347 1348 Level: advanced 1349 1350 .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()` 1351 @*/ 1352 PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode) 1353 { 1354 DM_Forest *forest = (DM_Forest *)dm->data; 1355 PetscInt cStart, cEnd; 1356 1357 PetscFunctionBegin; 1358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1359 PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd)); 1360 PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd); 1361 if (copyMode == PETSC_COPY_VALUES) { 1362 if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights)); 1363 PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart)); 1364 forest->cellWeightsCopyMode = PETSC_OWN_POINTER; 1365 PetscFunctionReturn(PETSC_SUCCESS); 1366 } 1367 if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights)); 1368 forest->cellWeights = weights; 1369 forest->cellWeightsCopyMode = copyMode; 1370 PetscFunctionReturn(PETSC_SUCCESS); 1371 } 1372 1373 /*@ 1374 DMForestGetCellWeights - Get the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current 1375 process: weights are used to determine parallel partitioning. 1376 1377 Not Collective 1378 1379 Input Parameter: 1380 . dm - the forest 1381 1382 Output Parameter: 1383 . weights - the array of weights for all cells, or `NULL` to indicate each cell has weight 1. 1384 1385 Level: advanced 1386 1387 .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()` 1388 @*/ 1389 PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights) 1390 { 1391 DM_Forest *forest = (DM_Forest *)dm->data; 1392 1393 PetscFunctionBegin; 1394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1395 PetscAssertPointer(weights, 2); 1396 *weights = forest->cellWeights; 1397 PetscFunctionReturn(PETSC_SUCCESS); 1398 } 1399 1400 /*@ 1401 DMForestSetWeightCapacity - During the pre-setup phase, set the capacity of the current process when repartitioning 1402 a pre-adaptation forest (see `DMForestGetAdaptivityForest()`). 1403 1404 Logically Collective 1405 1406 Input Parameters: 1407 + dm - the forest 1408 - capacity - this process's capacity 1409 1410 Level: advanced 1411 1412 Note: 1413 After partitioning, the ratio of the weight of each process's cells to the process's capacity 1414 will be roughly equal for all processes. A capacity of 0 indicates that the current process 1415 should not have any cells after repartitioning. 1416 1417 .seealso: `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()` 1418 @*/ 1419 PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity) 1420 { 1421 DM_Forest *forest = (DM_Forest *)dm->data; 1422 1423 PetscFunctionBegin; 1424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1425 PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup"); 1426 PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity); 1427 forest->weightCapacity = capacity; 1428 PetscFunctionReturn(PETSC_SUCCESS); 1429 } 1430 1431 /*@ 1432 DMForestGetWeightCapacity - Set the capacity of the current process when repartitioning a pre-adaptation forest (see 1433 `DMForestGetAdaptivityForest()`). 1434 1435 Not Collective 1436 1437 Input Parameter: 1438 . dm - the forest 1439 1440 Output Parameter: 1441 . capacity - this process's capacity 1442 1443 Level: advanced 1444 1445 Note: 1446 After partitioning, the ratio of the weight of each process's cells to the process's capacity 1447 will be roughly equal for all processes. A capacity of 0 indicates that the current process 1448 should not have any cells after repartitioning. 1449 1450 .seealso: `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()` 1451 @*/ 1452 PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity) 1453 { 1454 DM_Forest *forest = (DM_Forest *)dm->data; 1455 1456 PetscFunctionBegin; 1457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1458 PetscAssertPointer(capacity, 2); 1459 *capacity = forest->weightCapacity; 1460 PetscFunctionReturn(PETSC_SUCCESS); 1461 } 1462 1463 PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems PetscOptionsObject) 1464 { 1465 PetscBool flg, flg1, flg2, flg3, flg4; 1466 DMForestTopology oldTopo; 1467 char stringBuffer[256]; 1468 PetscViewer viewer; 1469 PetscViewerFormat format; 1470 PetscInt adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade; 1471 PetscReal weightsFactor; 1472 DMForestAdaptivityStrategy adaptStrategy; 1473 1474 PetscFunctionBegin; 1475 PetscCall(DMForestGetTopology(dm, &oldTopo)); 1476 PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options"); 1477 PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1)); 1478 PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2)); 1479 PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3)); 1480 PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4)); 1481 PetscCheck((PetscInt)flg1 + (PetscInt)flg2 + (PetscInt)flg3 + (PetscInt)flg4 <= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Specify only one of -dm_forest_{topology,base_dm,coarse_forest,fine_forest}"); 1482 if (flg1) { 1483 PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer)); 1484 PetscCall(DMForestSetBaseDM(dm, NULL)); 1485 PetscCall(DMForestSetAdaptivityForest(dm, NULL)); 1486 } 1487 if (flg2) { 1488 DM base; 1489 1490 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base)); 1491 PetscCall(PetscViewerPushFormat(viewer, format)); 1492 PetscCall(DMLoad(base, viewer)); 1493 PetscCall(PetscViewerDestroy(&viewer)); 1494 PetscCall(DMForestSetBaseDM(dm, base)); 1495 PetscCall(DMDestroy(&base)); 1496 PetscCall(DMForestSetTopology(dm, NULL)); 1497 PetscCall(DMForestSetAdaptivityForest(dm, NULL)); 1498 } 1499 if (flg3) { 1500 DM coarse; 1501 1502 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse)); 1503 PetscCall(PetscViewerPushFormat(viewer, format)); 1504 PetscCall(DMLoad(coarse, viewer)); 1505 PetscCall(PetscViewerDestroy(&viewer)); 1506 PetscCall(DMForestSetAdaptivityForest(dm, coarse)); 1507 PetscCall(DMDestroy(&coarse)); 1508 PetscCall(DMForestSetTopology(dm, NULL)); 1509 PetscCall(DMForestSetBaseDM(dm, NULL)); 1510 } 1511 if (flg4) { 1512 DM fine; 1513 1514 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine)); 1515 PetscCall(PetscViewerPushFormat(viewer, format)); 1516 PetscCall(DMLoad(fine, viewer)); 1517 PetscCall(PetscViewerDestroy(&viewer)); 1518 PetscCall(DMForestSetAdaptivityForest(dm, fine)); 1519 PetscCall(DMDestroy(&fine)); 1520 PetscCall(DMForestSetTopology(dm, NULL)); 1521 PetscCall(DMForestSetBaseDM(dm, NULL)); 1522 } 1523 PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim)); 1524 PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0)); 1525 if (flg) { 1526 PetscCall(DMForestSetAdjacencyDimension(dm, adjDim)); 1527 } else { 1528 PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim)); 1529 PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1)); 1530 if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim)); 1531 } 1532 PetscCall(DMForestGetPartitionOverlap(dm, &overlap)); 1533 PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0)); 1534 if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap)); 1535 #if 0 1536 PetscCall(PetscOptionsBoundedInt("-dm_refine","equivalent to -dm_forest_set_minimum_refinement and -dm_forest_set_initial_refinement with the same value",NULL,minRefinement,&minRefinement,&flg,0)); 1537 if (flg) { 1538 PetscCall(DMForestSetMinimumRefinement(dm,minRefinement)); 1539 PetscCall(DMForestSetInitialRefinement(dm,minRefinement)); 1540 } 1541 PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0)); 1542 if (flg) { 1543 PetscCall(DMForestSetMinimumRefinement(dm,0)); 1544 PetscCall(DMForestSetInitialRefinement(dm,initRefinement)); 1545 } 1546 #endif 1547 PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement)); 1548 PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0)); 1549 if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement)); 1550 PetscCall(DMForestGetInitialRefinement(dm, &initRefinement)); 1551 PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0)); 1552 if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement)); 1553 PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement)); 1554 PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0)); 1555 if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement)); 1556 PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy)); 1557 PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg)); 1558 if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer)); 1559 PetscCall(DMForestGetGradeFactor(dm, &grade)); 1560 PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0)); 1561 if (flg) PetscCall(DMForestSetGradeFactor(dm, grade)); 1562 PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor)); 1563 PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg)); 1564 if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor)); 1565 PetscOptionsHeadEnd(); 1566 PetscFunctionReturn(PETSC_SUCCESS); 1567 } 1568 1569 static PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 1570 { 1571 PetscFunctionBegin; 1572 if (subdm) PetscCall(DMClone(dm, subdm)); 1573 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 1574 PetscFunctionReturn(PETSC_SUCCESS); 1575 } 1576 1577 static PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined) 1578 { 1579 DMLabel refine; 1580 DM fineDM; 1581 1582 PetscFunctionBegin; 1583 PetscCall(DMGetFineDM(dm, &fineDM)); 1584 if (fineDM) { 1585 PetscCall(PetscObjectReference((PetscObject)fineDM)); 1586 *dmRefined = fineDM; 1587 PetscFunctionReturn(PETSC_SUCCESS); 1588 } 1589 PetscCall(DMForestTemplate(dm, comm, dmRefined)); 1590 PetscCall(DMGetLabel(dm, "refine", &refine)); 1591 if (!refine) { 1592 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine)); 1593 PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE)); 1594 } else PetscCall(PetscObjectReference((PetscObject)refine)); 1595 PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine)); 1596 PetscCall(DMLabelDestroy(&refine)); 1597 PetscFunctionReturn(PETSC_SUCCESS); 1598 } 1599 1600 static PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened) 1601 { 1602 DMLabel coarsen; 1603 DM coarseDM; 1604 1605 PetscFunctionBegin; 1606 if (comm != MPI_COMM_NULL) { 1607 PetscMPIInt mpiComparison; 1608 MPI_Comm dmcomm = PetscObjectComm((PetscObject)dm); 1609 1610 PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison)); 1611 PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet"); 1612 } 1613 PetscCall(DMGetCoarseDM(dm, &coarseDM)); 1614 if (coarseDM) { 1615 PetscCall(PetscObjectReference((PetscObject)coarseDM)); 1616 *dmCoarsened = coarseDM; 1617 PetscFunctionReturn(PETSC_SUCCESS); 1618 } 1619 PetscCall(DMForestTemplate(dm, comm, dmCoarsened)); 1620 PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN)); 1621 PetscCall(DMGetLabel(dm, "coarsen", &coarsen)); 1622 if (!coarsen) { 1623 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen)); 1624 PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN)); 1625 } else PetscCall(PetscObjectReference((PetscObject)coarsen)); 1626 PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen)); 1627 PetscCall(DMLabelDestroy(&coarsen)); 1628 PetscFunctionReturn(PETSC_SUCCESS); 1629 } 1630 1631 PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM) 1632 { 1633 PetscBool success; 1634 1635 PetscFunctionBegin; 1636 PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM)); 1637 PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label)); 1638 PetscCall(DMSetUp(*adaptedDM)); 1639 PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success)); 1640 if (!success) { 1641 PetscCall(DMDestroy(adaptedDM)); 1642 *adaptedDM = NULL; 1643 } 1644 PetscFunctionReturn(PETSC_SUCCESS); 1645 } 1646 1647 static PetscErrorCode DMInitialize_Forest(DM dm) 1648 { 1649 PetscFunctionBegin; 1650 PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops))); 1651 1652 dm->ops->clone = DMClone_Forest; 1653 dm->ops->setfromoptions = DMSetFromOptions_Forest; 1654 dm->ops->destroy = DMDestroy_Forest; 1655 dm->ops->createsubdm = DMCreateSubDM_Forest; 1656 dm->ops->refine = DMRefine_Forest; 1657 dm->ops->coarsen = DMCoarsen_Forest; 1658 PetscFunctionReturn(PETSC_SUCCESS); 1659 } 1660 1661 /*MC 1662 1663 DMFOREST = "forest" - A DM object that encapsulates a hierarchically refined mesh. Forests usually have a base `DM` 1664 (see `DMForestGetBaseDM()`), from which it is refined. The refinement and partitioning of forests is considered 1665 immutable after `DMSetUp()` is called. To adapt a mesh, one should call `DMForestTemplate()` to create a new mesh that 1666 will default to being identical to it, specify how that mesh should differ, and then calling `DMSetUp()` on the new 1667 mesh. 1668 1669 To specify that a mesh should be refined or coarsened from the previous mesh, a label should be defined on the 1670 previous mesh whose values indicate which cells should be refined (`DM_ADAPT_REFINE`) or coarsened (`DM_ADAPT_COARSEN`) 1671 and how (subtypes are free to allow additional values for things like anisotropic refinement). The label should be 1672 given to the *new* mesh with `DMForestSetAdaptivityLabel()`. 1673 1674 Level: advanced 1675 1676 .seealso: `DMType`, `DM`, `DMCreate()`, `DMSetType()`, `DMForestGetBaseDM()`, `DMForestSetBaseDM()`, `DMForestTemplate()`, `DMForestSetAdaptivityLabel()` 1677 M*/ 1678 1679 PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm) 1680 { 1681 DM_Forest *forest; 1682 1683 PetscFunctionBegin; 1684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1685 PetscCall(PetscNew(&forest)); 1686 dm->dim = 0; 1687 dm->data = forest; 1688 forest->refct = 1; 1689 forest->data = NULL; 1690 forest->topology = NULL; 1691 forest->adapt = NULL; 1692 forest->base = NULL; 1693 forest->adaptPurpose = DM_ADAPT_DETERMINE; 1694 forest->adjDim = PETSC_DEFAULT; 1695 forest->overlap = PETSC_DEFAULT; 1696 forest->minRefinement = PETSC_DEFAULT; 1697 forest->maxRefinement = PETSC_DEFAULT; 1698 forest->initRefinement = PETSC_DEFAULT; 1699 forest->cStart = PETSC_DETERMINE; 1700 forest->cEnd = PETSC_DETERMINE; 1701 forest->cellSF = NULL; 1702 forest->adaptLabel = NULL; 1703 forest->gradeFactor = 2; 1704 forest->cellWeights = NULL; 1705 forest->cellWeightsCopyMode = PETSC_USE_POINTER; 1706 forest->weightsFactor = 1.; 1707 forest->weightCapacity = 1.; 1708 PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL)); 1709 PetscCall(DMInitialize_Forest(dm)); 1710 PetscFunctionReturn(PETSC_SUCCESS); 1711 } 1712