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