Date: 2026-07-30T21:14:01+00:00

Actual source code: forest.c

      1: #include <petsc/private/dmforestimpl.h>
      2: #include <petsc/private/dmimpl.h>
      3: #include <petsc/private/dmlabelimpl.h>
      4: #include <petscsf.h>

      6: PetscBool DMForestPackageInitialized = PETSC_FALSE;

      8: typedef struct _DMForestTypeLink *DMForestTypeLink;

     10: struct _DMForestTypeLink {
     11:   char            *name;
     12:   DMForestTypeLink next;
     13: };

     15: DMForestTypeLink DMForestTypeList;

     17: static PetscErrorCode DMForestPackageFinalize(void)
     18: {
     19:   DMForestTypeLink oldLink, link = DMForestTypeList;

     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: }

     31: static PetscErrorCode DMForestPackageInitialize(void)
     32: {
     33:   PetscFunctionBegin;
     34:   if (DMForestPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
     35:   DMForestPackageInitialized = PETSC_TRUE;

     37:   PetscCall(DMForestRegisterType(DMFOREST));
     38:   PetscCall(PetscRegisterFinalize(DMForestPackageFinalize));
     39:   PetscFunctionReturn(PETSC_SUCCESS);
     40: }

     42: /*@C
     43:   DMForestRegisterType - Registers a `DMType` as a subtype of `DMFOREST` (so that `DMIsForest()` will be correct)

     45:   Not Collective

     47:   Input Parameter:
     48: . name - the name of the type

     50:   Level: advanced

     52: .seealso: `DMFOREST`, `DMIsForest()`
     53: @*/
     54: PetscErrorCode DMForestRegisterType(DMType name)
     55: {
     56:   DMForestTypeLink link;

     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: }

     67: /*@
     68:   DMIsForest - Check whether a DM uses the DMFOREST interface for hierarchically-refined meshes

     70:   Not Collective

     72:   Input Parameter:
     73: . dm - the DM object

     75:   Output Parameter:
     76: . isForest - whether dm is a subtype of DMFOREST

     78:   Level: intermediate

     80: .seealso: `DMFOREST`, `DMForestRegisterType()`
     81: @*/
     82: PetscErrorCode DMIsForest(DM dm, PetscBool *isForest)
     83: {
     84:   DMForestTypeLink link = DMForestTypeList;

     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: }

    100: /*@
    101:   DMForestTemplate - Create a new `DM` that will be adapted from a source `DM`.

    103:   Collective

    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()`)

    109:   Output Parameter:
    110: . tedm - the new `DM` object

    112:   Level: intermediate

    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()`).

    120: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`
    121: @*/
    122: PetscErrorCode DMForestTemplate(DM dm, MPI_Comm comm, DM *tedm)
    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;

    135:   PetscFunctionBegin;
    137:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), tedm));
    138:   PetscCall(DMGetType(dm, &type));
    139:   PetscCall(DMSetType(*tedm, type));
    140:   PetscCall(DMForestGetBaseDM(dm, &base));
    141:   PetscCall(DMForestSetBaseDM(*tedm, base));
    142:   PetscCall(DMForestGetTopology(dm, &topology));
    143:   PetscCall(DMForestSetTopology(*tedm, topology));
    144:   PetscCall(DMForestGetAdjacencyDimension(dm, &dim));
    145:   PetscCall(DMForestSetAdjacencyDimension(*tedm, dim));
    146:   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
    147:   PetscCall(DMForestSetPartitionOverlap(*tedm, overlap));
    148:   PetscCall(DMForestGetMinimumRefinement(dm, &ref));
    149:   PetscCall(DMForestSetMinimumRefinement(*tedm, ref));
    150:   PetscCall(DMForestGetMaximumRefinement(dm, &ref));
    151:   PetscCall(DMForestSetMaximumRefinement(*tedm, ref));
    152:   PetscCall(DMForestGetAdaptivityStrategy(dm, &strat));
    153:   PetscCall(DMForestSetAdaptivityStrategy(*tedm, strat));
    154:   PetscCall(DMForestGetGradeFactor(dm, &factor));
    155:   PetscCall(DMForestSetGradeFactor(*tedm, factor));
    156:   PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
    157:   PetscCall(DMForestSetBaseCoordinateMapping(*tedm, map, mapCtx));
    158:   if (forest->ftemplate) PetscCall((*forest->ftemplate)(dm, *tedm));
    159:   PetscCall(DMForestSetAdaptivityForest(*tedm, dm));
    160:   PetscCall(DMCopyDisc(dm, *tedm));
    161:   PetscCall(DMGetApplicationContext(dm, &ctx));
    162:   PetscCall(DMSetApplicationContext(*tedm, &ctx));
    163:   {
    164:     const PetscReal *maxCell, *L, *Lstart;

    166:     PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
    167:     PetscCall(DMSetPeriodicity(*tedm, maxCell, Lstart, L));
    168:   }
    169:   PetscCall(DMGetMatType(dm, &mtype));
    170:   PetscCall(DMSetMatType(*tedm, mtype));
    171:   PetscFunctionReturn(PETSC_SUCCESS);
    172: }

    174: static PetscErrorCode DMInitialize_Forest(DM dm);

    176: PetscErrorCode DMClone_Forest(DM dm, DM *newdm)
    177: {
    178:   DM_Forest  *forest = (DM_Forest *)dm->data;
    179:   const char *type;

    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: }

    190: static PetscErrorCode DMDestroy_Forest(DM dm)
    191: {
    192:   DM_Forest *forest = (DM_Forest *)dm->data;

    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: }

    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()`.

    222:   Logically collectiv

    224:   Input Parameters:
    225: + dm       - the forest
    226: - topology - the topology of the forest

    228:   Level: intermediate

    230: .seealso: `DM`, `DMFOREST`, `DMForestGetTopology()`, `DMForestSetBaseDM()`
    231: @*/
    232: PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology)
    233: {
    234:   DM_Forest *forest = (DM_Forest *)dm->data;

    236:   PetscFunctionBegin;
    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: }

    244: /*@
    245:   DMForestGetTopology - Get a string describing the topology of a `DMFOREST`.

    247:   Not Collective

    249:   Input Parameter:
    250: . dm - the forest

    252:   Output Parameter:
    253: . topology - the topology of the forest (e.g., `cube`, `shell`)

    255:   Level: intermediate

    257: .seealso: `DM`, `DMFOREST`, `DMForestSetTopology()`
    258: @*/
    259: PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology)
    260: {
    261:   DM_Forest *forest = (DM_Forest *)dm->data;

    263:   PetscFunctionBegin;
    265:   PetscAssertPointer(topology, 2);
    266:   *topology = forest->topology;
    267:   PetscFunctionReturn(PETSC_SUCCESS);
    268: }

    270: /*@
    271:   DMForestSetBaseDM - During the pre-setup phase, set the `DM` that defines the base mesh of a
    272:   `DMFOREST` forest.

    274:   Logically Collective

    276:   Input Parameters:
    277: + dm   - the forest
    278: - base - the base `DM` of the forest

    280:   Level: intermediate

    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.

    287:   Currently the base `DM` must be a `DMPLEX`

    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;

    296:   PetscFunctionBegin;
    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;

    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: }

    316: /*@
    317:   DMForestGetBaseDM - Get the base `DM` of a `DMFOREST`

    319:   Not Collective

    321:   Input Parameter:
    322: . dm - the forest

    324:   Output Parameter:
    325: . base - the base `DM` of the forest

    327:   Level: intermediate

    329:   Notes:
    330:   After DMSetUp(), the base DM will be redundantly distributed across MPI processes

    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.

    336: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()`
    337: @*/
    338: PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
    339: {
    340:   DM_Forest *forest = (DM_Forest *)dm->data;

    342:   PetscFunctionBegin;
    344:   PetscAssertPointer(base, 2);
    345:   *base = forest->base;
    346:   PetscFunctionReturn(PETSC_SUCCESS);
    347: }

    349: /*@C
    350:   DMForestSetBaseCoordinateMapping - Set a user-supplied mapping that is applied to the base `DM`'s coordinates when the forest computes coordinates for refined cells.

    352:   Logically Collective

    354:   Input Parameters:
    355: + dm   - the `DMFOREST`
    356: . func - callback that maps reference coordinates to physical coordinates
    357: - ctx  - optional application context passed through to `func`

    359:   Calling sequence of `func`:
    360: + base        - the base `DM` of the forest
    361: . coarsePoint - the base-`DM` cell that owns the coordinate being mapped
    362: . dim         - the coordinate dimension (at most 3)
    363: . coordIn     - the input coordinate on the base `DM`
    364: . coordOut    - the mapped coordinate to be written
    365: - ctx         - optional application context

    367:   Level: intermediate

    369: .seealso: `DM`, `DMFOREST`, `DMForestGetBaseCoordinateMapping()`, `DMForestSetBaseDM()`
    370: @*/
    371: PetscErrorCode DMForestSetBaseCoordinateMapping(DM dm, PetscErrorCode (*func)(DM base, PetscInt coarsePoint, PetscInt dim, const PetscReal coordIn[], PetscReal coordOut[], PetscCtx ctx), PetscCtx ctx)
    372: {
    373:   DM_Forest *forest = (DM_Forest *)dm->data;

    375:   PetscFunctionBegin;
    377:   forest->mapcoordinates    = func;
    378:   forest->mapcoordinatesctx = ctx;
    379:   PetscFunctionReturn(PETSC_SUCCESS);
    380: }

    382: /*@C
    383:   DMForestGetBaseCoordinateMapping - Get the user-supplied coordinate mapping previously set with `DMForestSetBaseCoordinateMapping()`.

    385:   Not Collective

    387:   Input Parameter:
    388: . dm - the `DMFOREST`

    390:   Output Parameters:
    391: + func - the callback, or `NULL`
    392: - ctx  - the application context that was registered with the callback, or `NULL`

    394:   Calling sequence of `func`:
    395: + base        - the base `DM` of the forest
    396: . coarsePoint - the base-`DM` cell that owns the coordinate being mapped
    397: . dim         - the coordinate dimension (at most 3)
    398: . coordIn     - the input coordinate on the base `DM`
    399: . coordOut    - the mapped coordinate to be written
    400: - ctx         - optional application context

    402:   Level: intermediate

    404: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseCoordinateMapping()`
    405: @*/
    406: PetscErrorCode DMForestGetBaseCoordinateMapping(DM dm, PetscErrorCode (**func)(DM base, PetscInt coarsePoint, PetscInt dim, const PetscReal coordIn[], PetscReal coordOut[], PetscCtx ctx), PetscCtxRt ctx)
    407: {
    408:   DM_Forest *forest = (DM_Forest *)dm->data;

    410:   PetscFunctionBegin;
    412:   if (func) *func = forest->mapcoordinates;
    413:   if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
    414:   PetscFunctionReturn(PETSC_SUCCESS);
    415: }

    417: /*@
    418:   DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the
    419:   current forest will be adapted (e.g., the current forest will be
    420:   refined/coarsened/repartitioned from it) in `DMSetUp()`.

    422:   Logically Collective

    424:   Input Parameters:
    425: + dm    - the new forest, which will be constructed from adapt
    426: - adapt - the old forest

    428:   Level: intermediate

    430:   Note:
    431:   Usually not needed by users directly, `DMForestTemplate()` constructs a new forest to be
    432:   adapted from an old forest and calls this routine.

    434:   This can be called after setup with `adapt` = `NULL`, which will clear all internal data
    435:   related to the adaptivity forest from `dm`. This way, repeatedly adapting does not leave
    436:   stale `DM` objects in memory.

    438: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
    439: @*/
    440: PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
    441: {
    442:   DM_Forest *forest, *adaptForest, *oldAdaptForest;
    443:   DM         oldAdapt;
    444:   PetscBool  isForest;

    446:   PetscFunctionBegin;
    449:   PetscCall(DMIsForest(dm, &isForest));
    450:   if (!isForest) PetscFunctionReturn(PETSC_SUCCESS);
    451:   PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
    452:   forest = (DM_Forest *)dm->data;
    453:   PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt));
    454:   adaptForest    = (DM_Forest *)(adapt ? adapt->data : NULL);
    455:   oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
    456:   if (adaptForest != oldAdaptForest) {
    457:     PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
    458:     PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
    459:     if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm));
    460:   }
    461:   switch (forest->adaptPurpose) {
    462:   case DM_ADAPT_DETERMINE:
    463:     PetscCall(PetscObjectReference((PetscObject)adapt));
    464:     PetscCall(DMDestroy(&forest->adapt));
    465:     forest->adapt = adapt;
    466:     break;
    467:   case DM_ADAPT_REFINE:
    468:     PetscCall(DMSetCoarseDM(dm, adapt));
    469:     break;
    470:   case DM_ADAPT_COARSEN:
    471:   case DM_ADAPT_COARSEN_LAST:
    472:     PetscCall(DMSetFineDM(dm, adapt));
    473:     break;
    474:   default:
    475:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
    476:   }
    477:   PetscFunctionReturn(PETSC_SUCCESS);
    478: }

    480: /*@
    481:   DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.

    483:   Not Collective

    485:   Input Parameter:
    486: . dm - the forest

    488:   Output Parameter:
    489: . adapt - the forest from which `dm` is/was adapted

    491:   Level: intermediate

    493: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
    494: @*/
    495: PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
    496: {
    497:   DM_Forest *forest;

    499:   PetscFunctionBegin;
    501:   forest = (DM_Forest *)dm->data;
    502:   switch (forest->adaptPurpose) {
    503:   case DM_ADAPT_DETERMINE:
    504:     *adapt = forest->adapt;
    505:     break;
    506:   case DM_ADAPT_REFINE:
    507:     PetscCall(DMGetCoarseDM(dm, adapt));
    508:     break;
    509:   case DM_ADAPT_COARSEN:
    510:   case DM_ADAPT_COARSEN_LAST:
    511:     PetscCall(DMGetFineDM(dm, adapt));
    512:     break;
    513:   default:
    514:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
    515:   }
    516:   PetscFunctionReturn(PETSC_SUCCESS);
    517: }

    519: /*@
    520:   DMForestSetAdaptivityPurpose - During the pre-setup phase, set whether the current `DM` is being adapted from its
    521:   source (set with `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening
    522:   (`DM_ADAPT_COARSEN`), or undefined (`DM_ADAPT_DETERMINE`).

    524:   Logically Collective

    526:   Input Parameters:
    527: + dm      - the forest
    528: - purpose - the adaptivity purpose

    530:   Level: advanced

    532:   Notes:
    533:   This only matters for reference counting during `DMDestroy()`. Cyclic references
    534:   can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
    535:   (see `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and
    536:   the user does not maintain a reference to the post-adaptation forest (i.e., the one created
    537:   by `DMForestTemplate()`), this can cause a memory leak.  This method is used by subtypes
    538:   of `DMFOREST` when automatically constructing mesh hierarchies.

    540: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
    541: @*/
    542: PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
    543: {
    544:   DM_Forest *forest;

    546:   PetscFunctionBegin;
    547:   forest = (DM_Forest *)dm->data;
    548:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
    549:   if (purpose != forest->adaptPurpose) {
    550:     DM adapt;

    552:     PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
    553:     PetscCall(PetscObjectReference((PetscObject)adapt));
    554:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));

    556:     forest->adaptPurpose = purpose;

    558:     PetscCall(DMForestSetAdaptivityForest(dm, adapt));
    559:     PetscCall(DMDestroy(&adapt));
    560:   }
    561:   PetscFunctionReturn(PETSC_SUCCESS);
    562: }

    564: /*@
    565:   DMForestGetAdaptivityPurpose - Get whether the current `DM` is being adapted from its source (set with
    566:   `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening (`DM_ADAPT_COARSEN`),
    567:   coarsening only the last level (`DM_ADAPT_COARSEN_LAST`) or undefined (`DM_ADAPT_DETERMINE`).

    569:   Not Collective

    571:   Input Parameter:
    572: . dm - the forest

    574:   Output Parameter:
    575: . purpose - the adaptivity purpose

    577:   Level: advanced

    579:   Notes:
    580:   This only matters for reference counting: during `DMDestroy()`. Cyclic references
    581:   can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
    582:   (See `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and
    583:   the user does not maintain a reference to the post-adaptation forest (i.e., the one created
    584:   by `DMForestTemplate()`), this can cause a memory leak.  This method is used by subtypes
    585:   of `DMFOREST` when automatically constructing mesh hierarchies.

    587: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
    588: @*/
    589: PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
    590: {
    591:   DM_Forest *forest;

    593:   PetscFunctionBegin;
    594:   forest   = (DM_Forest *)dm->data;
    595:   *purpose = forest->adaptPurpose;
    596:   PetscFunctionReturn(PETSC_SUCCESS);
    597: }

    599: /*@
    600:   DMForestSetAdjacencyDimension - During the pre-setup phase, set the dimension of interface points that determine
    601:   cell adjacency (for the purposes of partitioning and overlap).

    603:   Logically Collective

    605:   Input Parameters:
    606: + dm     - the forest
    607: - adjDim - default 0 (i.e., vertices determine adjacency)

    609:   Level: intermediate

    611: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
    612: @*/
    613: PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
    614: {
    615:   PetscInt   dim;
    616:   DM_Forest *forest = (DM_Forest *)dm->data;

    618:   PetscFunctionBegin;
    620:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup");
    621:   PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim);
    622:   PetscCall(DMGetDimension(dm, &dim));
    623:   PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim);
    624:   forest->adjDim = adjDim;
    625:   PetscFunctionReturn(PETSC_SUCCESS);
    626: }

    628: /*@
    629:   DMForestSetAdjacencyCodimension - Like `DMForestSetAdjacencyDimension()`, but specified as a co-dimension (so that,
    630:   e.g., adjacency based on facets can be specified by codimension 1 in all cases)

    632:   Logically Collective

    634:   Input Parameters:
    635: + dm       - the forest
    636: - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices

    638:   Level: intermediate

    640: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
    641: @*/
    642: PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
    643: {
    644:   PetscInt dim;

    646:   PetscFunctionBegin;
    648:   PetscCall(DMGetDimension(dm, &dim));
    649:   PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim));
    650:   PetscFunctionReturn(PETSC_SUCCESS);
    651: }

    653: /*@
    654:   DMForestGetAdjacencyDimension - Get the dimension of interface points that determine cell adjacency (for the
    655:   purposes of partitioning and overlap).

    657:   Not Collective

    659:   Input Parameter:
    660: . dm - the forest

    662:   Output Parameter:
    663: . adjDim - default 0 (i.e., vertices determine adjacency)

    665:   Level: intermediate

    667: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
    668: @*/
    669: PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim)
    670: {
    671:   DM_Forest *forest = (DM_Forest *)dm->data;

    673:   PetscFunctionBegin;
    675:   PetscAssertPointer(adjDim, 2);
    676:   *adjDim = forest->adjDim;
    677:   PetscFunctionReturn(PETSC_SUCCESS);
    678: }

    680: /*@
    681:   DMForestGetAdjacencyCodimension - Like `DMForestGetAdjacencyDimension()`, but specified as a co-dimension (so that,
    682:   e.g., adjacency based on facets can be specified by codimension 1 in all cases)

    684:   Not Collective

    686:   Input Parameter:
    687: . dm - the forest

    689:   Output Parameter:
    690: . adjCodim - default isthe dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices

    692:   Level: intermediate

    694: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
    695: @*/
    696: PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
    697: {
    698:   DM_Forest *forest = (DM_Forest *)dm->data;
    699:   PetscInt   dim;

    701:   PetscFunctionBegin;
    703:   PetscAssertPointer(adjCodim, 2);
    704:   PetscCall(DMGetDimension(dm, &dim));
    705:   *adjCodim = dim - forest->adjDim;
    706:   PetscFunctionReturn(PETSC_SUCCESS);
    707: }

    709: /*@
    710:   DMForestSetPartitionOverlap - During the pre-setup phase, set the amount of cell-overlap present in parallel
    711:   partitions of a forest, with values > 0 indicating subdomains that are expanded by that many iterations of adding
    712:   adjacent cells

    714:   Logically Collective

    716:   Input Parameters:
    717: + dm      - the forest
    718: - overlap - default 0

    720:   Level: intermediate

    722: .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
    723: @*/
    724: PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
    725: {
    726:   DM_Forest *forest = (DM_Forest *)dm->data;

    728:   PetscFunctionBegin;
    730:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup");
    731:   PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap);
    732:   forest->overlap = overlap;
    733:   PetscFunctionReturn(PETSC_SUCCESS);
    734: }

    736: /*@
    737:   DMForestGetPartitionOverlap - Get the amount of cell-overlap present in parallel partitions of a forest, with values
    738:   > 0 indicating subdomains that are expanded by that many iterations of adding adjacent cells

    740:   Not Collective

    742:   Input Parameter:
    743: . dm - the forest

    745:   Output Parameter:
    746: . overlap - default 0

    748:   Level: intermediate

    750: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
    751: @*/
    752: PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
    753: {
    754:   DM_Forest *forest = (DM_Forest *)dm->data;

    756:   PetscFunctionBegin;
    758:   PetscAssertPointer(overlap, 2);
    759:   *overlap = forest->overlap;
    760:   PetscFunctionReturn(PETSC_SUCCESS);
    761: }

    763: /*@
    764:   DMForestSetMinimumRefinement - During the pre-setup phase, set the minimum level of refinement (relative to the base
    765:   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by coarsening a previous forest
    766:   (see `DMForestGetAdaptivityForest()`) this limits the amount of coarsening.

    768:   Logically Collective

    770:   Input Parameters:
    771: + dm            - the forest
    772: - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    774:   Level: intermediate

    776: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
    777: @*/
    778: PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
    779: {
    780:   DM_Forest *forest = (DM_Forest *)dm->data;

    782:   PetscFunctionBegin;
    784:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the minimum refinement after setup");
    785:   forest->minRefinement = minRefinement;
    786:   PetscFunctionReturn(PETSC_SUCCESS);
    787: }

    789: /*@
    790:   DMForestGetMinimumRefinement - Get the minimum level of refinement (relative to the base `DM`, see
    791:   `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by coarsening a previous forest (see
    792:   `DMForestGetAdaptivityForest()`), this limits the amount of coarsening.

    794:   Not Collective

    796:   Input Parameter:
    797: . dm - the forest

    799:   Output Parameter:
    800: . minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    802:   Level: intermediate

    804: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
    805: @*/
    806: PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
    807: {
    808:   DM_Forest *forest = (DM_Forest *)dm->data;

    810:   PetscFunctionBegin;
    812:   PetscAssertPointer(minRefinement, 2);
    813:   *minRefinement = forest->minRefinement;
    814:   PetscFunctionReturn(PETSC_SUCCESS);
    815: }

    817: /*@
    818:   DMForestSetInitialRefinement - During the pre-setup phase, set the initial level of refinement (relative to the base
    819:   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.

    821:   Logically Collective

    823:   Input Parameters:
    824: + dm             - the forest
    825: - initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    827:   Level: intermediate

    829: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
    830: @*/
    831: PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement)
    832: {
    833:   DM_Forest *forest = (DM_Forest *)dm->data;

    835:   PetscFunctionBegin;
    837:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup");
    838:   forest->initRefinement = initRefinement;
    839:   PetscFunctionReturn(PETSC_SUCCESS);
    840: }

    842: /*@
    843:   DMForestGetInitialRefinement - Get the initial level of refinement (relative to the base `DM`, see
    844:   `DMForestGetBaseDM()`) allowed in the forest.

    846:   Not Collective

    848:   Input Parameter:
    849: . dm - the forest

    851:   Output Parameter:
    852: . initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    854:   Level: intermediate

    856: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
    857: @*/
    858: PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement)
    859: {
    860:   DM_Forest *forest = (DM_Forest *)dm->data;

    862:   PetscFunctionBegin;
    864:   PetscAssertPointer(initRefinement, 2);
    865:   *initRefinement = forest->initRefinement;
    866:   PetscFunctionReturn(PETSC_SUCCESS);
    867: }

    869: /*@
    870:   DMForestSetMaximumRefinement - During the pre-setup phase, set the maximum level of refinement (relative to the base
    871:   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by refining a previous forest
    872:   (see `DMForestGetAdaptivityForest()`), this limits the amount of refinement.

    874:   Logically Collective

    876:   Input Parameters:
    877: + dm            - the forest
    878: - maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    880:   Level: intermediate

    882: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()`
    883: @*/
    884: PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement)
    885: {
    886:   DM_Forest *forest = (DM_Forest *)dm->data;

    888:   PetscFunctionBegin;
    890:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup");
    891:   forest->maxRefinement = maxRefinement;
    892:   PetscFunctionReturn(PETSC_SUCCESS);
    893: }

    895: /*@
    896:   DMForestGetMaximumRefinement - Get the maximum level of refinement (relative to the base `DM`, see
    897:   `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by refining a previous forest (see
    898:   `DMForestGetAdaptivityForest()`), this limits the amount of refinement.

    900:   Not Collective

    902:   Input Parameter:
    903: . dm - the forest

    905:   Output Parameter:
    906: . maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

    908:   Level: intermediate

    910: .seealso: `DM`, `DMFOREST`, `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
    911: @*/
    912: PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement)
    913: {
    914:   DM_Forest *forest = (DM_Forest *)dm->data;

    916:   PetscFunctionBegin;
    918:   PetscAssertPointer(maxRefinement, 2);
    919:   *maxRefinement = forest->maxRefinement;
    920:   PetscFunctionReturn(PETSC_SUCCESS);
    921: }

    923: /*@
    924:   DMForestSetAdaptivityStrategy - During the pre-setup phase, set the strategy for combining adaptivity labels from multiple processes.

    926:   Logically Collective

    928:   Input Parameters:
    929: + dm            - the forest
    930: - adaptStrategy - default `DMFORESTADAPTALL`

    932:   Level: advanced

    934:   Notes:
    935:   Subtypes of `DMFOREST` may define their own strategies.  Two default strategies are `DMFORESTADAPTALL`, which indicates that all processes must agree
    936:   for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only one process needs to
    937:   specify refinement/coarsening.

    939: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`
    940: @*/
    941: PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
    942: {
    943:   DM_Forest *forest = (DM_Forest *)dm->data;

    945:   PetscFunctionBegin;
    947:   PetscCall(PetscFree(forest->adaptStrategy));
    948:   PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy));
    949:   PetscFunctionReturn(PETSC_SUCCESS);
    950: }

    952: /*@
    953:   DMForestGetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.

    955:   Not Collective

    957:   Input Parameter:
    958: . dm - the forest

    960:   Output Parameter:
    961: . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`)

    963:   Level: advanced

    965:   Note:
    966:   Subtypes
    967:   of `DMFOREST` may define their own strategies.  Two default strategies are `DMFORESTADAPTALL`, which indicates that all
    968:   processes must agree for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only
    969:   one process needs to specify refinement/coarsening.

    971: .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()`
    972: @*/
    973: PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
    974: {
    975:   DM_Forest *forest = (DM_Forest *)dm->data;

    977:   PetscFunctionBegin;
    979:   PetscAssertPointer(adaptStrategy, 2);
    980:   *adaptStrategy = forest->adaptStrategy;
    981:   PetscFunctionReturn(PETSC_SUCCESS);
    982: }

    984: /*@
    985:   DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
    986:   etc.) was successful.

    988:   Collective

    990:   Input Parameter:
    991: . dm - the post-adaptation forest

    993:   Output Parameter:
    994: . success - `PETSC_TRUE` if the post-adaptation forest is different from the pre-adaptation forest.

    996:   Level: intermediate

    998:   Notes:
    999:   `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adaptation
    1000:   forest.  A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
    1001:   exceeded the maximum refinement level.

    1003: .seealso: `DM`, `DMFOREST`
    1004: @*/
    1005: PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
    1006: {
    1007:   DM_Forest *forest;

    1009:   PetscFunctionBegin;
    1011:   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet.");
    1012:   forest = (DM_Forest *)dm->data;
    1013:   PetscCall(forest->getadaptivitysuccess(dm, success));
    1014:   PetscFunctionReturn(PETSC_SUCCESS);
    1015: }

    1017: /*@
    1018:   DMForestSetComputeAdaptivitySF - During the pre-setup phase, set whether transfer `PetscSF`s should be computed
    1019:   relating the cells of the pre-adaptation forest to the post-adaptiation forest.

    1021:   Logically Collective

    1023:   Input Parameters:
    1024: + dm        - the post-adaptation forest
    1025: - computeSF - default `PETSC_TRUE`

    1027:   Level: advanced

    1029:   Note:
    1030:   After `DMSetUp()` is called, the transfer `PetscSF`s can be accessed with `DMForestGetAdaptivitySF()`.

    1032: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
    1033: @*/
    1034: PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
    1035: {
    1036:   DM_Forest *forest;

    1038:   PetscFunctionBegin;
    1040:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called");
    1041:   forest                 = (DM_Forest *)dm->data;
    1042:   forest->computeAdaptSF = computeSF;
    1043:   PetscFunctionReturn(PETSC_SUCCESS);
    1044: }

    1046: /*@
    1047:   DMForestTransferVec - Transfer a `Vec` between two related `DMFOREST` grids, e.g. before and after adaptation.

    1049:   Collective

    1051:   Input Parameters:
    1052: + dmIn   - source `DMFOREST`
    1053: . vecIn  - vector on `dmIn`
    1054: . dmOut  - destination `DMFOREST`
    1055: . useBCs - if `PETSC_TRUE`, apply boundary conditions during transfer
    1056: - time   - simulation time supplied to any time-dependent boundary conditions

    1058:   Output Parameter:
    1059: . vecOut - vector on `dmOut` that receives the transferred values

    1061:   Level: intermediate

    1063:   Note:
    1064:   Requires the forest implementation to provide a transfer routine; otherwise raises `PETSC_ERR_SUP`.

    1066: .seealso: `DM`, `DMFOREST`, `DMForestTransferVecFromBase()`, `DMForestSetAdaptivityForest()`
    1067: @*/
    1068: PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
    1069: {
    1070:   DM_Forest *forest;

    1072:   PetscFunctionBegin;
    1077:   forest = (DM_Forest *)dmIn->data;
    1078:   PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented");
    1079:   PetscCall(forest->transfervec(dmIn, vecIn, dmOut, vecOut, useBCs, time));
    1080:   PetscFunctionReturn(PETSC_SUCCESS);
    1081: }

    1083: /*@
    1084:   DMForestTransferVecFromBase - Transfer a `Vec` defined on the base `DM` of a `DMFOREST` onto the refined forest.

    1086:   Collective

    1088:   Input Parameters:
    1089: + dm    - the `DMFOREST`
    1090: - vecIn - vector defined on the base `DM` returned by `DMForestGetBaseDM()`

    1092:   Output Parameter:
    1093: . vecOut - vector on `dm` that receives the transferred values

    1095:   Level: intermediate

    1097:   Note:
    1098:   Requires the forest implementation to provide a base-to-forest transfer routine; otherwise raises `PETSC_ERR_SUP`.

    1100: .seealso: `DM`, `DMFOREST`, `DMForestTransferVec()`, `DMForestGetBaseDM()`
    1101: @*/
    1102: PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
    1103: {
    1104:   DM_Forest *forest;

    1106:   PetscFunctionBegin;
    1110:   forest = (DM_Forest *)dm->data;
    1111:   PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented");
    1112:   PetscCall(forest->transfervecfrombase(dm, vecIn, vecOut));
    1113:   PetscFunctionReturn(PETSC_SUCCESS);
    1114: }

    1116: /*@
    1117:   DMForestGetComputeAdaptivitySF - Get whether transfer `PetscSF`s should be computed relating the cells of the
    1118:   pre-adaptation forest to the post-adaptiation forest.  After `DMSetUp()` is called, these transfer PetscSFs can be
    1119:   accessed with `DMForestGetAdaptivitySF()`.

    1121:   Not Collective

    1123:   Input Parameter:
    1124: . dm - the post-adaptation forest

    1126:   Output Parameter:
    1127: . computeSF - default `PETSC_TRUE`

    1129:   Level: advanced

    1131: .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
    1132: @*/
    1133: PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
    1134: {
    1135:   DM_Forest *forest;

    1137:   PetscFunctionBegin;
    1139:   forest     = (DM_Forest *)dm->data;
    1140:   *computeSF = forest->computeAdaptSF;
    1141:   PetscFunctionReturn(PETSC_SUCCESS);
    1142: }

    1144: /*@
    1145:   DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the
    1146:   post-adaptation forest.

    1148:   Not Collective

    1150:   Input Parameter:
    1151: . dm - the post-adaptation forest

    1153:   Output Parameters:
    1154: + preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
    1155: - coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-

    1157:   Level: advanced

    1159:   Notes:
    1160:   Adaptation can be any combination of refinement, coarsening, repartition, and change of
    1161:   overlap, so there may be some cells of the pre-adaptation that are parents of post-adaptation
    1162:   cells, and vice versa.  Therefore there are two `PetscSF`s: one that relates pre-adaptation
    1163:   coarse cells to post-adaptation fine cells, and one that relates pre-adaptation fine cells to
    1164:   post-adaptation coarse cells.

    1166: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
    1167: @*/
    1168: PetscErrorCode DMForestGetAdaptivitySF(DM dm, PeOp PetscSF *preCoarseToFine, PeOp PetscSF *coarseToPreFine)
    1169: {
    1170:   DM_Forest *forest;

    1172:   PetscFunctionBegin;
    1174:   PetscCall(DMSetUp(dm));
    1175:   forest = (DM_Forest *)dm->data;
    1176:   if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
    1177:   if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
    1178:   PetscFunctionReturn(PETSC_SUCCESS);
    1179: }

    1181: /*@
    1182:   DMForestSetGradeFactor - During the pre-setup phase, set the desired amount of grading in the
    1183:   mesh, e.g. give 2 to indicate that the diameter of neighboring cells should differ by at most
    1184:   a factor of 2.

    1186:   Logically Collective

    1188:   Input Parameters:
    1189: + dm    - the forest
    1190: - grade - the grading factor

    1192:   Level: advanced

    1194:   Note:
    1195:   Subtypes of `DMFOREST` may only support one particular choice of grading factor.

    1197: .seealso: `DM`, `DMFOREST`, `DMForestGetGradeFactor()`
    1198: @*/
    1199: PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade)
    1200: {
    1201:   DM_Forest *forest = (DM_Forest *)dm->data;

    1203:   PetscFunctionBegin;
    1205:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup");
    1206:   forest->gradeFactor = grade;
    1207:   PetscFunctionReturn(PETSC_SUCCESS);
    1208: }

    1210: /*@
    1211:   DMForestGetGradeFactor - Get the desired amount of grading in the mesh, e.g. give 2 to indicate that the diameter of
    1212:   neighboring cells should differ by at most a factor of 2.  Subtypes of `DMFOREST` may only support one particular
    1213:   choice of grading factor.

    1215:   Not Collective

    1217:   Input Parameter:
    1218: . dm - the forest

    1220:   Output Parameter:
    1221: . grade - the grading factor

    1223:   Level: advanced

    1225: .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()`
    1226: @*/
    1227: PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
    1228: {
    1229:   DM_Forest *forest = (DM_Forest *)dm->data;

    1231:   PetscFunctionBegin;
    1233:   PetscAssertPointer(grade, 2);
    1234:   *grade = forest->gradeFactor;
    1235:   PetscFunctionReturn(PETSC_SUCCESS);
    1236: }

    1238: /*@
    1239:   DMForestSetCellWeightFactor - During the pre-setup phase, set the factor by which the level of refinement changes
    1240:   the cell weight (see `DMForestSetCellWeights()`) when calculating partitions.

    1242:   Logically Collective

    1244:   Input Parameters:
    1245: + dm            - the forest
    1246: - weightsFactor - default 1.

    1248:   Level: advanced

    1250:   Note:
    1251:   The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel).  A factor
    1252:   of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
    1253:   example, might be appropriate for sub-cycling time-stepping methods, when the computation
    1254:   associated with a cell is multiplied by a factor of 2 for each additional level of
    1255:   refinement.

    1257: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()`
    1258: @*/
    1259: PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor)
    1260: {
    1261:   DM_Forest *forest = (DM_Forest *)dm->data;

    1263:   PetscFunctionBegin;
    1265:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup");
    1266:   forest->weightsFactor = weightsFactor;
    1267:   PetscFunctionReturn(PETSC_SUCCESS);
    1268: }

    1270: /*@
    1271:   DMForestGetCellWeightFactor - Get the factor by which the level of refinement changes the cell weight (see
    1272:   `DMForestSetCellWeights()`) when calculating partitions.

    1274:   Not Collective

    1276:   Input Parameter:
    1277: . dm - the forest

    1279:   Output Parameter:
    1280: . weightsFactor - default 1.

    1282:   Level: advanced

    1284:   Note:
    1285:   The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel).  A factor
    1286:   of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
    1287:   example, might be appropriate for sub-cycling time-stepping methods, when the computation
    1288:   associated with a cell is multiplied by a factor of 2 for each additional level of
    1289:   refinement.

    1291: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
    1292: @*/
    1293: PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
    1294: {
    1295:   DM_Forest *forest = (DM_Forest *)dm->data;

    1297:   PetscFunctionBegin;
    1299:   PetscAssertPointer(weightsFactor, 2);
    1300:   *weightsFactor = forest->weightsFactor;
    1301:   PetscFunctionReturn(PETSC_SUCCESS);
    1302: }

    1304: /*@
    1305:   DMForestGetCellChart - After the setup phase, get the local half-open interval of the chart of cells on this process

    1307:   Not Collective

    1309:   Input Parameter:
    1310: . dm - the forest

    1312:   Output Parameters:
    1313: + cStart - the first cell on this process
    1314: - cEnd   - one after the final cell on this process

    1316:   Level: intermediate

    1318: .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()`
    1319: @*/
    1320: PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
    1321: {
    1322:   DM_Forest *forest = (DM_Forest *)dm->data;

    1324:   PetscFunctionBegin;
    1326:   PetscAssertPointer(cStart, 2);
    1327:   PetscAssertPointer(cEnd, 3);
    1328:   if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd));
    1329:   *cStart = forest->cStart;
    1330:   *cEnd   = forest->cEnd;
    1331:   PetscFunctionReturn(PETSC_SUCCESS);
    1332: }

    1334: /*@
    1335:   DMForestGetCellSF - After the setup phase, get the `PetscSF` for overlapping cells between processes

    1337:   Not Collective

    1339:   Input Parameter:
    1340: . dm - the forest

    1342:   Output Parameter:
    1343: . cellSF - the `PetscSF`

    1345:   Level: intermediate

    1347: .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()`
    1348: @*/
    1349: PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
    1350: {
    1351:   DM_Forest *forest = (DM_Forest *)dm->data;

    1353:   PetscFunctionBegin;
    1355:   PetscAssertPointer(cellSF, 2);
    1356:   if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF));
    1357:   *cellSF = forest->cellSF;
    1358:   PetscFunctionReturn(PETSC_SUCCESS);
    1359: }

    1361: /*@
    1362:   DMForestSetAdaptivityLabel - During the pre-setup phase, set the label of the pre-adaptation forest (see
    1363:   `DMForestGetAdaptivityForest()`) that holds the adaptation flags (refinement, coarsening, or some combination).

    1365:   Logically Collective

    1367:   Input Parameters:
    1368: + dm         - the forest
    1369: - adaptLabel - the label in the pre-adaptation forest

    1371:   Level: intermediate

    1373:   Note:
    1374:   The interpretation of the label values is up to the subtype of `DMFOREST`, but
    1375:   `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
    1376:   reserved as choices that should be accepted by all subtypes.

    1378: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()`
    1379: @*/
    1380: PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
    1381: {
    1382:   DM_Forest *forest = (DM_Forest *)dm->data;

    1384:   PetscFunctionBegin;
    1387:   PetscCall(PetscObjectReference((PetscObject)adaptLabel));
    1388:   PetscCall(DMLabelDestroy(&forest->adaptLabel));
    1389:   forest->adaptLabel = adaptLabel;
    1390:   PetscFunctionReturn(PETSC_SUCCESS);
    1391: }

    1393: /*@
    1394:   DMForestGetAdaptivityLabel - Get the label of the pre-adaptation forest (see `DMForestGetAdaptivityForest()`) that
    1395:   holds the adaptation flags (refinement, coarsening, or some combination).

    1397:   Not Collective

    1399:   Input Parameter:
    1400: . dm - the forest

    1402:   Output Parameter:
    1403: . adaptLabel - the name of the label in the pre-adaptation forest

    1405:   Level: intermediate

    1407:   Note:
    1408:   The interpretation of the label values is up to the subtype of `DMFOREST`, but
    1409:   `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
    1410:   reserved as choices that should be accepted by all subtypes.

    1412: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()`
    1413: @*/
    1414: PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
    1415: {
    1416:   DM_Forest *forest = (DM_Forest *)dm->data;

    1418:   PetscFunctionBegin;
    1420:   *adaptLabel = forest->adaptLabel;
    1421:   PetscFunctionReturn(PETSC_SUCCESS);
    1422: }

    1424: /*@
    1425:   DMForestSetCellWeights - Set the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
    1426:   process: weights are used to determine parallel partitioning.

    1428:   Logically Collective

    1430:   Input Parameters:
    1431: + dm       - the forest
    1432: . weights  - the array of weights (see `DMForestSetWeightCapacity()`) for all cells, or `NULL` to indicate each cell has weight 1.
    1433: - copyMode - how weights should reference weights

    1435:   Level: advanced

    1437: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
    1438: @*/
    1439: PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
    1440: {
    1441:   DM_Forest *forest = (DM_Forest *)dm->data;
    1442:   PetscInt   cStart, cEnd;

    1444:   PetscFunctionBegin;
    1446:   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
    1447:   PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd);
    1448:   if (copyMode == PETSC_COPY_VALUES) {
    1449:     if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights));
    1450:     PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart));
    1451:     forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
    1452:     PetscFunctionReturn(PETSC_SUCCESS);
    1453:   }
    1454:   if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights));
    1455:   forest->cellWeights         = weights;
    1456:   forest->cellWeightsCopyMode = copyMode;
    1457:   PetscFunctionReturn(PETSC_SUCCESS);
    1458: }

    1460: /*@
    1461:   DMForestGetCellWeights - Get the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
    1462:   process: weights are used to determine parallel partitioning.

    1464:   Not Collective

    1466:   Input Parameter:
    1467: . dm - the forest

    1469:   Output Parameter:
    1470: . weights - the array of weights for all cells, or `NULL` to indicate each cell has weight 1.

    1472:   Level: advanced

    1474: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
    1475: @*/
    1476: PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
    1477: {
    1478:   DM_Forest *forest = (DM_Forest *)dm->data;

    1480:   PetscFunctionBegin;
    1482:   PetscAssertPointer(weights, 2);
    1483:   *weights = forest->cellWeights;
    1484:   PetscFunctionReturn(PETSC_SUCCESS);
    1485: }

    1487: /*@
    1488:   DMForestSetWeightCapacity - During the pre-setup phase, set the capacity of the current process when repartitioning
    1489:   a pre-adaptation forest (see `DMForestGetAdaptivityForest()`).

    1491:   Logically Collective

    1493:   Input Parameters:
    1494: + dm       - the forest
    1495: - capacity - this process's capacity

    1497:   Level: advanced

    1499:   Note:
    1500:   After partitioning, the ratio of the weight of each process's cells to the process's capacity
    1501:   will be roughly equal for all processes.  A capacity of 0 indicates that the current process
    1502:   should not have any cells after repartitioning.

    1504: .seealso: `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
    1505: @*/
    1506: PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
    1507: {
    1508:   DM_Forest *forest = (DM_Forest *)dm->data;

    1510:   PetscFunctionBegin;
    1512:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup");
    1513:   PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity);
    1514:   forest->weightCapacity = capacity;
    1515:   PetscFunctionReturn(PETSC_SUCCESS);
    1516: }

    1518: /*@
    1519:   DMForestGetWeightCapacity - Set the capacity of the current process when repartitioning a pre-adaptation forest (see
    1520:   `DMForestGetAdaptivityForest()`).

    1522:   Not Collective

    1524:   Input Parameter:
    1525: . dm - the forest

    1527:   Output Parameter:
    1528: . capacity - this process's capacity

    1530:   Level: advanced

    1532:   Note:
    1533:   After partitioning, the ratio of the weight of each process's cells to the process's capacity
    1534:   will be roughly equal for all processes.  A capacity of 0 indicates that the current process
    1535:   should not have any cells after repartitioning.

    1537: .seealso: `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
    1538: @*/
    1539: PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
    1540: {
    1541:   DM_Forest *forest = (DM_Forest *)dm->data;

    1543:   PetscFunctionBegin;
    1545:   PetscAssertPointer(capacity, 2);
    1546:   *capacity = forest->weightCapacity;
    1547:   PetscFunctionReturn(PETSC_SUCCESS);
    1548: }

    1550: PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems PetscOptionsObject)
    1551: {
    1552:   PetscBool                  flg, flg1, flg2, flg3, flg4;
    1553:   DMForestTopology           oldTopo;
    1554:   char                       stringBuffer[256];
    1555:   PetscViewer                viewer;
    1556:   PetscViewerFormat          format;
    1557:   PetscInt                   adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
    1558:   PetscReal                  weightsFactor;
    1559:   DMForestAdaptivityStrategy adaptStrategy;

    1561:   PetscFunctionBegin;
    1562:   PetscCall(DMForestGetTopology(dm, &oldTopo));
    1563:   PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
    1564:   PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1));
    1565:   PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2));
    1566:   PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3));
    1567:   PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4));
    1568:   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}");
    1569:   if (flg1) {
    1570:     PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer));
    1571:     PetscCall(DMForestSetBaseDM(dm, NULL));
    1572:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
    1573:   }
    1574:   if (flg2) {
    1575:     DM base;

    1577:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base));
    1578:     PetscCall(PetscViewerPushFormat(viewer, format));
    1579:     PetscCall(DMLoad(base, viewer));
    1580:     PetscCall(PetscViewerDestroy(&viewer));
    1581:     PetscCall(DMForestSetBaseDM(dm, base));
    1582:     PetscCall(DMDestroy(&base));
    1583:     PetscCall(DMForestSetTopology(dm, NULL));
    1584:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
    1585:   }
    1586:   if (flg3) {
    1587:     DM coarse;

    1589:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse));
    1590:     PetscCall(PetscViewerPushFormat(viewer, format));
    1591:     PetscCall(DMLoad(coarse, viewer));
    1592:     PetscCall(PetscViewerDestroy(&viewer));
    1593:     PetscCall(DMForestSetAdaptivityForest(dm, coarse));
    1594:     PetscCall(DMDestroy(&coarse));
    1595:     PetscCall(DMForestSetTopology(dm, NULL));
    1596:     PetscCall(DMForestSetBaseDM(dm, NULL));
    1597:   }
    1598:   if (flg4) {
    1599:     DM fine;

    1601:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine));
    1602:     PetscCall(PetscViewerPushFormat(viewer, format));
    1603:     PetscCall(DMLoad(fine, viewer));
    1604:     PetscCall(PetscViewerDestroy(&viewer));
    1605:     PetscCall(DMForestSetAdaptivityForest(dm, fine));
    1606:     PetscCall(DMDestroy(&fine));
    1607:     PetscCall(DMForestSetTopology(dm, NULL));
    1608:     PetscCall(DMForestSetBaseDM(dm, NULL));
    1609:   }
    1610:   PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
    1611:   PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0));
    1612:   if (flg) {
    1613:     PetscCall(DMForestSetAdjacencyDimension(dm, adjDim));
    1614:   } else {
    1615:     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
    1616:     PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1));
    1617:     if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim));
    1618:   }
    1619:   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
    1620:   PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0));
    1621:   if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap));
    1622: #if 0
    1623:   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));
    1624:   if (flg) {
    1625:     PetscCall(DMForestSetMinimumRefinement(dm,minRefinement));
    1626:     PetscCall(DMForestSetInitialRefinement(dm,minRefinement));
    1627:   }
    1628:   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0));
    1629:   if (flg) {
    1630:     PetscCall(DMForestSetMinimumRefinement(dm,0));
    1631:     PetscCall(DMForestSetInitialRefinement(dm,initRefinement));
    1632:   }
    1633: #endif
    1634:   PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement));
    1635:   PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0));
    1636:   if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement));
    1637:   PetscCall(DMForestGetInitialRefinement(dm, &initRefinement));
    1638:   PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0));
    1639:   if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement));
    1640:   PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement));
    1641:   PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0));
    1642:   if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement));
    1643:   PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy));
    1644:   PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg));
    1645:   if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer));
    1646:   PetscCall(DMForestGetGradeFactor(dm, &grade));
    1647:   PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0));
    1648:   if (flg) PetscCall(DMForestSetGradeFactor(dm, grade));
    1649:   PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor));
    1650:   PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg));
    1651:   if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor));
    1652:   PetscOptionsHeadEnd();
    1653:   PetscFunctionReturn(PETSC_SUCCESS);
    1654: }

    1656: static PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1657: {
    1658:   PetscFunctionBegin;
    1659:   if (subdm) PetscCall(DMClone(dm, subdm));
    1660:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
    1661:   PetscFunctionReturn(PETSC_SUCCESS);
    1662: }

    1664: static PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
    1665: {
    1666:   DMLabel refine;
    1667:   DM      fineDM;

    1669:   PetscFunctionBegin;
    1670:   PetscCall(DMGetFineDM(dm, &fineDM));
    1671:   if (fineDM) {
    1672:     PetscCall(PetscObjectReference((PetscObject)fineDM));
    1673:     *dmRefined = fineDM;
    1674:     PetscFunctionReturn(PETSC_SUCCESS);
    1675:   }
    1676:   PetscCall(DMForestTemplate(dm, comm, dmRefined));
    1677:   PetscCall(DMGetLabel(dm, "refine", &refine));
    1678:   if (!refine) {
    1679:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine));
    1680:     PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE));
    1681:   } else PetscCall(PetscObjectReference((PetscObject)refine));
    1682:   PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine));
    1683:   PetscCall(DMLabelDestroy(&refine));
    1684:   PetscFunctionReturn(PETSC_SUCCESS);
    1685: }

    1687: static PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
    1688: {
    1689:   DMLabel coarsen;
    1690:   DM      coarseDM;

    1692:   PetscFunctionBegin;
    1693:   if (comm != MPI_COMM_NULL) {
    1694:     PetscMPIInt mpiComparison;
    1695:     MPI_Comm    dmcomm = PetscObjectComm((PetscObject)dm);

    1697:     PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison));
    1698:     PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet");
    1699:   }
    1700:   PetscCall(DMGetCoarseDM(dm, &coarseDM));
    1701:   if (coarseDM) {
    1702:     PetscCall(PetscObjectReference((PetscObject)coarseDM));
    1703:     *dmCoarsened = coarseDM;
    1704:     PetscFunctionReturn(PETSC_SUCCESS);
    1705:   }
    1706:   PetscCall(DMForestTemplate(dm, comm, dmCoarsened));
    1707:   PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN));
    1708:   PetscCall(DMGetLabel(dm, "coarsen", &coarsen));
    1709:   if (!coarsen) {
    1710:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
    1711:     PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
    1712:   } else PetscCall(PetscObjectReference((PetscObject)coarsen));
    1713:   PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen));
    1714:   PetscCall(DMLabelDestroy(&coarsen));
    1715:   PetscFunctionReturn(PETSC_SUCCESS);
    1716: }

    1718: PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
    1719: {
    1720:   PetscBool success;

    1722:   PetscFunctionBegin;
    1723:   PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM));
    1724:   PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label));
    1725:   PetscCall(DMSetUp(*adaptedDM));
    1726:   PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success));
    1727:   if (!success) {
    1728:     PetscCall(DMDestroy(adaptedDM));
    1729:     *adaptedDM = NULL;
    1730:   }
    1731:   PetscFunctionReturn(PETSC_SUCCESS);
    1732: }

    1734: static PetscErrorCode DMInitialize_Forest(DM dm)
    1735: {
    1736:   PetscFunctionBegin;
    1737:   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));

    1739:   dm->ops->clone          = DMClone_Forest;
    1740:   dm->ops->setfromoptions = DMSetFromOptions_Forest;
    1741:   dm->ops->destroy        = DMDestroy_Forest;
    1742:   dm->ops->createsubdm    = DMCreateSubDM_Forest;
    1743:   dm->ops->refine         = DMRefine_Forest;
    1744:   dm->ops->coarsen        = DMCoarsen_Forest;
    1745:   PetscFunctionReturn(PETSC_SUCCESS);
    1746: }

    1748: /*MC
    1749:   DMFOREST = "forest" - A DM object that encapsulates a hierarchically refined mesh.  Forests usually have a base `DM`
    1750:   (see `DMForestGetBaseDM()`), from which it is refined.  The refinement and partitioning of forests is considered
    1751:   immutable after `DMSetUp()` is called.  To adapt a mesh, one should call `DMForestTemplate()` to create a new mesh that
    1752:   will default to being identical to it, specify how that mesh should differ, and then calling `DMSetUp()` on the new
    1753:   mesh.

    1755:   To specify that a mesh should be refined or coarsened from the previous mesh, a label should be defined on the
    1756:   previous mesh whose values indicate which cells should be refined (`DM_ADAPT_REFINE`) or coarsened (`DM_ADAPT_COARSEN`)
    1757:   and how (subtypes are free to allow additional values for things like anisotropic refinement).  The label should be
    1758:   given to the *new* mesh with `DMForestSetAdaptivityLabel()`.

    1760:   Level: advanced

    1762: .seealso: `DMType`, `DM`, `DMCreate()`, `DMSetType()`, `DMForestGetBaseDM()`, `DMForestSetBaseDM()`, `DMForestTemplate()`, `DMForestSetAdaptivityLabel()`
    1763: M*/

    1765: PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
    1766: {
    1767:   DM_Forest *forest;

    1769:   PetscFunctionBegin;
    1771:   PetscCall(PetscNew(&forest));
    1772:   dm->dim                     = 0;
    1773:   dm->data                    = forest;
    1774:   forest->refct               = 1;
    1775:   forest->data                = NULL;
    1776:   forest->topology            = NULL;
    1777:   forest->adapt               = NULL;
    1778:   forest->base                = NULL;
    1779:   forest->adaptPurpose        = DM_ADAPT_DETERMINE;
    1780:   forest->adjDim              = PETSC_DEFAULT;
    1781:   forest->overlap             = PETSC_DEFAULT;
    1782:   forest->minRefinement       = PETSC_DEFAULT;
    1783:   forest->maxRefinement       = PETSC_DEFAULT;
    1784:   forest->initRefinement      = PETSC_DEFAULT;
    1785:   forest->cStart              = PETSC_DETERMINE;
    1786:   forest->cEnd                = PETSC_DETERMINE;
    1787:   forest->cellSF              = NULL;
    1788:   forest->adaptLabel          = NULL;
    1789:   forest->gradeFactor         = 2;
    1790:   forest->cellWeights         = NULL;
    1791:   forest->cellWeightsCopyMode = PETSC_USE_POINTER;
    1792:   forest->weightsFactor       = 1.;
    1793:   forest->weightCapacity      = 1.;
    1794:   PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL));
    1795:   PetscCall(DMInitialize_Forest(dm));
    1796:   PetscFunctionReturn(PETSC_SUCCESS);
    1797: }